/* ============================================================================
   SR MEDIA — site.css
   Single stylesheet, ordered top to bottom the way the page renders.

   READ THIS FIRST
   ---------------
   Every size on this site is expressed in `rem`. The root font-size is fluid
   (see "FLUID ROOT SCALE" below), so the entire page scales as one unit. That
   is what makes a 27" 1440p or 32" 4K display show a *bigger* page rather than
   the same small page with huge empty margins.

   Rule for anyone editing this file: use rem for anything that should scale
   (type, spacing, radii, widths, max-widths). Reserve px for hairlines only.
   Never size layout with vh — viewport height varies independently of width
   and breaks the "identical at every size" behaviour.
   ============================================================================ */


/* ============================================================================
   1. RESET
   ============================================================================ */

*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  /* Hero decoration bleeds sideways by design. `clip` on the root propagates to
     the viewport and kills the horizontal scrollbar without making anything a
     scroll container — `overflow-x: hidden` on body does not stop the document
     from growing, which is what let the dot field add 49px of scroll. */
  overflow-x: clip;
}

img, svg, video {
  display: block;
  max-width: 100%;
}

button { font: inherit; color: inherit; background: none; border: 0; }

ul, ol { list-style: none; padding: 0; }

a { color: inherit; text-decoration: none; }


/* ============================================================================
   2. DESIGN TOKENS
   Sampled from the approved hero mockup. Change a colour here, not inline.
   ============================================================================ */

:root {
  /* --- Brand ------------------------------------------------------------- */
  --yellow:        #FFC629;
  --yellow-deep:   #F0B000;   /* hover / pressed */
  --yellow-tint:   #FFF6DE;   /* soft fills, glow */

  /* --- Neutrals ---------------------------------------------------------- */
  --ink:           #16161B;   /* headlines, dark sections */
  --ink-soft:      #3B3B44;   /* nav links */
  /* Dark enough to clear 4.5:1 against the warmest part of the hero backdrop
     (rendered luminance ~231), not just against the flat page white. */
  --muted:         #61616B;   /* body copy */
  --page:          #F7F7F5;   /* page background */
  --surface:       #FFFFFF;   /* cards, nav bar */
  --line:          rgba(22, 22, 27, 0.09);
  --line-strong:   rgba(22, 22, 27, 0.16);

  /* --- Elevation --------------------------------------------------------- */
  --shadow-sm:     0 0.25rem 0.75rem -0.25rem rgba(22, 22, 27, 0.08);
  --shadow-md:     0 0.75rem 2rem -0.5rem rgba(22, 22, 27, 0.10);
  --shadow-lg:     0 1.75rem 3.5rem -1rem rgba(22, 22, 27, 0.14);
  --shadow-yellow: 0 0.75rem 1.5rem -0.5rem rgba(240, 176, 0, 0.40);

  /* --- Radii ------------------------------------------------------------- */
  --r-sm:  0.5rem;
  --r-md:  0.7rem;
  --r-lg:  1.35rem;
  --r-xl:  1.9rem;
  --r-pill: 62.5rem;

  /* --- Layout ------------------------------------------------------------ */
  --maxw:   90rem;   /* content ceiling; grows with the root scale */
  --gutter: 4rem;    /* page edge padding */

  /* --- Type ------------------------------------------------------------- */
  --font-display: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* --- Motion ------------------------------------------------------------ */
  --ease:     cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);   /* confident arrivals */
}


/* ============================================================================
   3. FLUID ROOT SCALE
   The single value the whole page derives from.

   The mockup was drawn on a 1600px canvas where 1rem = 17.5px.

     viewport   root      container width
     ────────   ──────    ───────────────
      1280px    16.0px    1152px
      1440px    16.8px    1306px
      1600px    17.5px    1460px   ← reference design
      1920px    19.0px    1712px   (hits the 90rem ceiling)
      2560px    22.0px    1980px   (root capped)
      3840px    22.0px    1980px

   Growth is damped — 0.47vw, not 1vw — so bigger monitors get a comfortably
   larger page instead of a magnified one. The clamp bounds are in rem so the
   visitor's own browser font-size setting still scales everything.
   ============================================================================ */

html {
  font-size: clamp(0.9375rem, 0.625rem + 0.47vw, 1.375rem);
}

/* Below 1150px the three-column hero stacks, so tie the scale to a phone /
   tablet reading size instead of the desktop curve. */
@media (max-width: 1149px) {
  html { font-size: clamp(0.9375rem, 0.875rem + 0.35vw, 1.0625rem); }
}


/* ============================================================================
   4. BASE TYPOGRAPHY
   ============================================================================ */

body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--muted);
  background: var(--page);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--font-display);
  color: var(--ink);
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

strong { color: var(--ink); font-weight: 600; }

.accent { color: var(--yellow); }

::selection { background: var(--yellow); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -4rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: #fff;
  border-radius: var(--r-sm);
  font-size: 0.85rem;
  transition: top 0.2s var(--ease-out);
}
.skip-link:focus { top: 0.5rem; }


/* ============================================================================
   5. LAYOUT PRIMITIVES
   ============================================================================ */

.container {
  width: min(var(--maxw), 100% - var(--gutter) * 2);
  margin-inline: auto;
}

.section { padding: 6.5rem 0; }

.section--tint { background: var(--surface); }

.section--dark {
  background: var(--ink);
  color: rgba(255, 255, 255, 0.68);
}
.section--dark h2,
.section--dark h3 { color: #fff; }

.section__head {
  max-width: 42rem;
  margin-bottom: 3.5rem;
}

.section__title {
  font-size: 2.9rem;
  font-weight: 800;
  text-transform: uppercase;
  line-height: 1.0;
}

.section__lede {
  margin-top: 1.25rem;
  font-size: 1.05rem;
  max-width: 34rem;
}

.eyebrow {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--yellow-deep);
  margin-bottom: 1rem;
}
.eyebrow--light { color: var(--yellow); }

.placeholder-note {
  margin-top: 2rem;
  font-size: 0.85rem;
  color: var(--muted);
}


/* ============================================================================
   6. COMPONENTS — buttons, badges, chips
   ============================================================================ */

.btn {
  --btn-py: 0.95rem;
  --btn-px: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
  padding: var(--btn-py) var(--btn-px);
  font-family: var(--font-display);
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1;
  border-radius: var(--r-md);
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.2s var(--ease-out),
              box-shadow 0.2s var(--ease-out),
              background-color 0.2s var(--ease-out);
}

/* Hover lives on the icon, not the button. A whole-button lift moves the
   target out from under the cursor mid-press, and with a row of them it
   reads as the page twitching; the arrow doing the travelling says
   "forward" without shifting anything you are aiming at. Every variant
   already changes colour on hover, so no button loses its feedback. */
.btn:active { transform: scale(0.985); }

.btn--sm { --btn-py: 0.8rem; --btn-px: 1.25rem; font-size: 0.85rem; }
.btn--lg { --btn-py: 1.1rem; --btn-px: 2rem; font-size: 1rem; }
.btn--block { width: 100%; }

.btn--primary {
  background: var(--yellow);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.btn--primary:hover { background: var(--yellow-deep); box-shadow: var(--shadow-yellow); }

.btn--ghost {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.btn--ghost:hover { box-shadow: var(--shadow-md); }

.btn--dark {
  background: var(--ink);
  color: #fff;
}
.btn--dark:hover { background: #26262E; }

.btn--on-dark {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  box-shadow: none;
  border: 1px solid rgba(255, 255, 255, 0.18);
}
.btn--on-dark:hover { background: rgba(255, 255, 255, 0.14); }

/* Circular arrow / play affordance inside a button */
.btn__icon {
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--ink);
  color: var(--yellow);
  flex: none;
  overflow: hidden;
}
.btn__icon svg { width: 0.9rem; height: 0.9rem; }

.btn__icon--outline {
  background: transparent;
  color: var(--ink);
  border: 1.5px solid var(--ink);
}
.btn--on-dark .btn__icon { background: #fff; color: var(--ink); }

/* The arrow leaves to the right and returns from the left, so the loop
   closes instead of stranding the glyph off-centre. The badge clips it,
   which is why the fade only has to cover the turnaround. */
@keyframes btn-arrow-send {
  0%   { transform: translateX(0);        opacity: 1; }
  45%  { transform: translateX(0.85rem);  opacity: 0; }
  46%  { transform: translateX(-0.85rem); opacity: 0; }
  100% { transform: translateX(0);        opacity: 1; }
}
.btn:hover .btn__icon svg { animation: btn-arrow-send 0.55s var(--ease-out); }

/* A phone should ring, not travel. Declared after the arrow rule and one
   class heavier so it wins on both counts. */
@keyframes btn-phone-ring {
  0%, 60%, 100% { transform: rotate(0); }
  10% { transform: rotate(-16deg); }
  22% { transform: rotate(13deg); }
  34% { transform: rotate(-9deg); }
  46% { transform: rotate(5deg); }
}
.btn:hover .btn__icon.btn__icon--phone svg {
  animation: btn-phone-ring 0.9s var(--ease-out);
}

/* Play is a transport control, not a "go forward" one, so it does not
   travel either. It presses: the triangle dips and springs back while a
   single ring pushes out past the badge, the way a player acknowledges a
   hit. The badge has to un-clip itself for the ring to leave it. */
@keyframes btn-play-press {
  0%   { transform: scale(1); }
  30%  { transform: scale(0.82); }
  62%  { transform: scale(1.14); }
  100% { transform: scale(1); }
}
@keyframes btn-play-ripple {
  0%   { transform: scale(1);    opacity: 0.55; }
  100% { transform: scale(1.75); opacity: 0; }
}
.btn__icon--play { overflow: visible; position: relative; }
.btn__icon--play::after {
  content: "";
  position: absolute;
  inset: -1.5px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  opacity: 0;
  pointer-events: none;
}
.btn:hover .btn__icon.btn__icon--play svg {
  animation: btn-play-press 0.5s var(--ease-out);
}
.btn:hover .btn__icon--play::after {
  animation: btn-play-ripple 0.7s var(--ease-out);
}
.btn__icon--phone svg { width: 0.86rem; height: 0.86rem; }

/* Pill badge — "Video ads for DTC brands" */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 1.1rem;
  background: var(--surface);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}
.badge__star { color: var(--yellow); font-size: 0.85rem; }

/* Small labelled facts under the sample ad */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}
.chip svg { width: 0.95rem; height: 0.95rem; color: var(--yellow-deep); flex: none; }

.stars { color: var(--yellow); font-size: 0.9rem; letter-spacing: 0.1em; }
.stars--lg { font-size: 1.4rem; }


/* ============================================================================
   7. HEADER + NAV
   Floating white bar, matching the mockup. Nav hover is an underline wipe.
   ============================================================================ */

/* Full-bleed bar, not a floating pill. Translucent with a blur so the hero's
   warm backdrop reads through it instead of being cut off by a white slab —
   which is also why .hero::before still has to reach up behind the header. */
/* The announcement bar and the header stick as ONE element. Sticking them
   separately would mean giving the header `top: <bar height>`, and that height
   changes the moment the bar wraps — so the header would either overlap the bar
   or float below it at some widths. One sticky parent has no such number. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 60;
}

.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--line);
}

/* Inside .topbar the parent does the sticking. The header keeps its own rule
   above so it still behaves if the bar is ever removed. */
.topbar > .header { position: relative; top: auto; }

/* --- Announcement bar ------------------------------------------------------
   Dark, so it separates from the translucent white header instead of blending
   into it, and so the yellow reads as the loudest thing on screen.
   -------------------------------------------------------------------------- */
.announce {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 1rem;
  padding: 0.6rem var(--gutter);
  background: var(--ink);
  color: rgba(255, 255, 255, 0.88);
  font-size: 0.85rem;
  line-height: 1.35;
  text-align: center;
}

.announce__msg {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.55rem;
}
.announce__msg strong { color: var(--yellow); font-weight: 700; }

.announce__tag {
  padding: 0.22rem 0.5rem;
  border-radius: var(--r-sm);
  background: var(--yellow);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}

.announce__spots {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.22rem 0.7rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.78);
  white-space: nowrap;
}
.announce__dot {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--yellow);
  animation: spot-pulse 2.6s ease-in-out infinite;
}
@keyframes spot-pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.8); }
}

.announce__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--r-sm);
  background: var(--yellow);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 600;
  white-space: nowrap;
  transition: background 0.2s var(--ease);
}
.announce__cta:hover { background: var(--yellow-deep); }
/* Bare glyph, not the circular badge the .btn icons use. At this size the
   ink disc would outweigh the label and turn a quiet sticky bar loud. Sized
   in em so it tracks the pill's font rather than the root. */
.announce__phone { width: 0.95em; height: 0.95em; flex: none; }
.announce__cta:hover .announce__phone { animation: btn-phone-ring 0.9s var(--ease-out); }

/* Narrow: the offer and the CTA are the message. The label and the counter are
   supporting detail and are the first things to go. */
@media (max-width: 720px) {
  .announce { gap: 0.5rem 0.7rem; font-size: 0.8rem; }
  .announce__tag { display: none; }
}
@media (max-width: 460px) {
  .announce__spots { display: none; }
}

/* Fallback for browsers without backdrop-filter: go opaque rather than let
   content show through at 72% and turn the nav unreadable. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .header { background: rgba(255, 255, 255, 0.96); }
}

.header__bar {
  width: min(var(--maxw), 100% - var(--gutter) * 2);
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 2rem;
  padding: 0.65rem 0;
}

/* --- Logo lockup ------------------------------------------------------------
   The SR monogram is a real mark (assets/img/logo-mark.png, transparent, keyed
   to --yellow exactly). MEDIA stays as type beside it, matching the mockup's
   lockup and keeping that half crisp at any size.
   The mark ships on a square canvas, so its width sets the whole footprint.
   -------------------------------------------------------------------------- */
.logo {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-display);
  flex: none;
}
.logo__mark {
  width: 2.05rem;
  height: auto;
  flex: none;
}
.logo__word {
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink);
}

.nav { margin-inline: auto; }

.nav__list {
  display: flex;
  gap: 2.1rem;
}

.nav__link {
  position: relative;
  display: inline-block;
  padding-block: 0.25rem;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--ink-soft);
  transition: color 0.2s var(--ease-out);
}
.nav__link:hover { color: var(--ink); }

/* The underline wipe. Deliberately not a sliding pill. */
.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--yellow);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.28s var(--ease);
}
.nav__link:hover::after,
.nav__link:focus-visible::after { transform: scaleX(1); }

/* --- Nav dropdowns ---------------------------------------------------------
   Opened by :hover and :focus-within on the list item — no JavaScript, so it
   survives a failed script and works from the keyboard for free. Touch has no
   hover, which is why the mobile drawer lists the sub-pages flat instead.

   The panel is rendered at all times and only made invisible, so its width is
   already resolved when it opens and it never reflows mid-animation.
   -------------------------------------------------------------------------- */
.nav__item--has-panel { position: relative; }

/* The reset sets svg { display: block }, which drops this onto its own line
   inside the link. It has to be inline to sit beside the label. */
.nav__chev {
  display: inline-block;
  width: 0.72rem;
  height: 0.72rem;
  margin-left: 0.3rem;
  vertical-align: -0.08em;
  transition: transform 0.3s var(--ease-expo);
}
.nav__item--has-panel:hover .nav__chev,
.nav__item--has-panel:focus-within .nav__chev { transform: rotate(180deg); }

.nav__panel {
  position: absolute;
  top: 100%;
  left: 50%;
  z-index: 60;
  /* Bridges the gap to the trigger so the pointer can cross without the panel
     closing under it. */
  padding-top: 0.85rem;
  translate: -50% 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.4rem) scale(0.98);
  transition: opacity 0.28s var(--ease-expo),
              transform 0.28s var(--ease-expo),
              visibility 0s linear 0.28s;
}
.nav__item--has-panel:hover .nav__panel,
.nav__item--has-panel:focus-within .nav__panel {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.28s var(--ease-expo),
              transform 0.28s var(--ease-expo),
              visibility 0s;
}

.nav__panel-inner {
  display: grid;
  gap: 0.15rem;
  width: 19rem;
  padding: 0.5rem;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .nav__panel-inner { background: var(--surface); }
}

.navcard {
  display: grid;
  gap: 0.15rem;
  padding: 0.7rem 0.75rem;
  border-radius: var(--r-md);
  transition: background-color 0.2s var(--ease-out);
}
.navcard:hover, .navcard:focus-visible { background: var(--page); }

.navcard__title {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-display);
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
}
.navcard__desc { font-size: 0.78rem; line-height: 1.4; color: var(--muted); }

.navcard__arrow {
  display: inline-block;
  width: 0.72rem;
  height: 0.72rem;
  color: var(--muted);
  transition: transform 0.25s var(--ease-expo);
}
.navcard:hover .navcard__arrow { transform: translate(0.12rem, -0.12rem); }

.header__cta { flex: none; }

/* --- Mobile ---------------------------------------------------------------- */
.nav-toggle {
  display: none;
  /* .nav carries the auto margin on desktop, but it is hidden here, so the
     toggle needs its own push to the right edge. */
  margin-left: auto;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  cursor: pointer;
  place-items: center;
  flex: none;
}
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 1.15rem;
  height: 2px;
  border-radius: 2px;
  background: var(--ink);
  transition: transform 0.25s var(--ease-out), opacity 0.2s linear;
}
.nav-toggle__bars::before,
.nav-toggle__bars::after { content: ""; position: absolute; }
.nav-toggle__bars::before { transform: translateY(-0.4rem); }
.nav-toggle__bars::after  { transform: translateY(0.4rem); }

.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after  { transform: rotate(-45deg); }

/* Full-bleed panel dropping out of the full-bleed bar. */
.mobile-nav {
  padding: 0.75rem var(--gutter) 1.25rem;
  background: var(--surface);
  border-top: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}
.mobile-nav ul { display: grid; gap: 0.25rem; margin-bottom: 1rem; }
.mobile-nav a {
  display: block;
  padding: 0.7rem 0.5rem;
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--ink);
  border-radius: var(--r-sm);
}
.mobile-nav a:hover { background: var(--page); }

/* Sub-pages are indented under the section they belong to. Touch has no hover,
   so the drawer is where those links actually live for phone visitors. */
.mobile-nav__sub {
  padding-left: 1.6rem !important;
  font-size: 0.9rem;
  color: var(--muted) !important;
}
.mobile-nav__sub::before {
  content: "";
  display: inline-block;
  width: 0.6rem;
  height: 1px;
  margin-right: 0.5rem;
  vertical-align: middle;
  background: var(--line-strong);
}


/* ============================================================================
   8. HERO
   Three columns: pitch / portrait / sample ad. Height is driven by the
   portrait in rem, never by vh, so it is proportionally identical everywhere.
   ============================================================================ */

/* Clipped sideways but NOT vertically: the glow has to spill past the bottom
   edge into the next section, or the clip draws a hard band across the page.
   `overflow-x: clip` is what makes that possible — `hidden` would force the
   other axis to `auto` and cut the glow off at the section boundary. */
/* Short bottom padding on purpose: the portrait's dissolve and the glow below it
   are the transition into the next section, so extra padding here would only
   open a dead gap between the two. */
.hero {
  position: relative;
  padding: 3.25rem 0 1rem;
  overflow-x: clip;
  isolation: isolate;
}

/* Atmospheric backdrop: a near-white plate with a warm bloom in the top right,
   which is where the ad card sits. Its lower left is deliberately clean so the
   headline keeps full contrast. Masked so it dissolves before the section ends
   rather than drawing a line across the page.
   Painting order inside .hero: this (-3), then the glow (-2), then content. */
.hero::before {
  content: "";
  position: absolute;
  /* Reaches up past the sticky header to the top of the document, so the plate
     does not draw a hard edge across the page under the nav. */
  inset: -6rem 0 0;
  z-index: -3;
  background: url("../img/hero-bg.jpg") no-repeat center top / cover;
  mask-image: linear-gradient(to bottom, #000 55%, transparent 94%);
  opacity: 0.9;
}

/* Column 1's share is load bearing: it is sized so the authored <br> breaks in
   the headline hold without re-wrapping down to 1150px. When rebalancing to give
   the portrait more room, keep 1.35 and the 3.8 total unchanged and take the
   width from column 3 — changing either re-wraps the headline. */
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1.52fr) minmax(0, 0.93fr);
  gap: 1.5rem;
  align-items: start;
}

/* --- Decoration ----------------------------------------------------------- */

/* Warm glow pooling under the portrait */
.hero__glow {
  position: absolute;
  left: 52%;          /* centre of the portrait column, not of the viewport */
  bottom: -6rem;      /* pools above the brands strip, which would cover it */
  width: min(62rem, 100%);   /* never wider than the hero, so phones don't scroll */
  height: 34rem;
  translate: -50% 0;
  /* Kept light: the backdrop plate above already carries the warmth, so this
     only needs to pool a little colour under the portrait. */
  background: radial-gradient(50% 50% at 50% 50%, rgba(255, 198, 41, 0.26), transparent 70%);
  filter: blur(0.5rem);
  z-index: -2;
  animation: breathe 9s ease-in-out infinite;
}

/* Dot field and sparkle live inside .hero__sample (see markup) so they stay
   pinned to the card rather than sliding to the viewport edge on wide screens. */
.hero__dots {
  position: absolute;
  top: 0.5rem;
  right: -2rem;   /* stays inside the page gutter at every width */
  width: 12rem;
  height: 8rem;
  background-image: radial-gradient(var(--yellow) 1.2px, transparent 1.2px);
  background-size: 1.15rem 1.15rem;
  opacity: 0.45;
  mask-image: linear-gradient(105deg, transparent, #000 55%);
  z-index: -1;
}

/* Amber bokeh, kept faint and pushed to the upper right so it reads as stray
   light near the ad card rather than as a field of dots across the hero. */
.hero__lights {
  position: absolute;
  inset: -4rem 0 auto;
  height: 44rem;
  background: url("../img/hero-lights.webp") no-repeat center top / cover;
  mask-image: radial-gradient(70% 80% at 78% 22%, #000, transparent 70%);
  opacity: 0.4;
  z-index: -2;
  pointer-events: none;
}

.hero__sparkle {
  position: absolute;
  top: -2.2rem;
  right: -2.5rem;
  width: 2.1rem;
  height: 2.1rem;
  fill: var(--yellow);
  animation: twinkle 5s ease-in-out infinite;
}

/* --- Column 1: pitch ------------------------------------------------------ */

.hero__pitch { padding-top: 1.25rem; }

/* 2.4rem is the ceiling at which the longest authored line, "THREE WEEKS AGO",
   still fits column 1 at 1150px — the tightest point in the three-column range,
   where the root scale has bottomed out on its clamp floor but the container is
   still shrinking. Raising it re-wraps the headline there. If you change this
   value or the headline copy, re-measure at 1150px, not just at 1600px. */
.hero__title {
  margin-top: 1.25rem;
  font-size: 2.4rem;
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  text-wrap: initial;   /* the line breaks are authored, keep them */
}

.hero__sub {
  margin-top: 1.4rem;
  max-width: 27rem;
  font-size: 1rem;
  line-height: 1.62;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-top: 1.9rem;
}

/* Avatar stack beside the score, so the proof leads with a face rather than a
   sentence. Sized to sit under the buttons without competing with them. */
.proofbar {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  width: fit-content;
  max-width: 27rem;
  margin-top: 2rem;
  padding: 0.7rem 1.1rem 0.7rem 0.8rem;
  background: var(--surface);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-sm);
}

/* --- Avatar stack ----------------------------------------------------------
   Overlapping circles. The ring is the card colour, so each face reads as
   sitting in front of the one behind it. Cap the list at three and add
   .avatars__more for the remainder — a long row of faces stops being scannable
   and starts being decoration.
   -------------------------------------------------------------------------- */
.avatars {
  display: flex;
  align-items: center;
  flex: none;
}
.avatars > li { display: flex; }
.avatars > li + li { margin-left: -0.6rem; }

.avatars img,
.avatars__more {
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  border: 2px solid var(--surface);
  object-fit: cover;
  flex: none;
}

.avatars__more {
  display: grid;
  place-items: center;
  background: var(--ink);
  color: var(--yellow);
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0;
}

/* --- Partial-fill rating ---------------------------------------------------
   Two stacked star rows: a muted base and a yellow overlay clipped to --fill.
   A real average is rarely a whole number, and rounding 4.925 up to five solid
   stars would be a claim the reviews do not support.
   Deliberately NOT reusing .stars, which the dark proof band styles for itself.
   -------------------------------------------------------------------------- */
.rating {
  position: relative;
  display: inline-block;
  font-size: 0.85rem;
  line-height: 1;
  letter-spacing: 0.06em;
  flex: none;
}
.rating__base { color: rgba(22, 22, 27, 0.20); }
.rating__fill {
  position: absolute;
  inset: 0;
  width: var(--fill, 100%);
  overflow: hidden;
  white-space: nowrap;
  color: var(--yellow);
}

.proofbar__body { min-width: 0; }

.proofbar__score {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.9rem;
  color: var(--ink);
}
.proofbar__score strong { font-family: var(--font-display); font-weight: 700; }

/* The denominator is context, not the number itself — lighter so "4.9" still
   carries the weight while the scale stays explicit. */
.proofbar__outof {
  font-weight: 600;
  font-size: 0.82em;
  color: var(--muted);
}

.proofbar__meta {
  margin-top: 0.1rem;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--muted);
}

/* Turns the proof from a closed statement about one client into an opening.
   Sits under the bar, not inside it, so it reads as ours rather than as part
   of the review. */
.hero__welcome {
  margin-top: 0.9rem;
  font-family: var(--font-display);
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink);
}

/* --- Column 2: portrait --------------------------------------------------- */

/* No fixed height: the portrait's own aspect ratio sets this column's height, so
   the disc and rings below can be positioned as percentages of the image itself
   rather than of an arbitrary box. That is what makes --disc-top stable when the
   cut-out is ever re-shot at a different crop. Sits on the row's baseline. */
.hero__portrait {
  /* TUNING KNOB — percentage of the portrait's own height. The disc should sit
     behind the head with the hair breaking over its top edge, as in the mockup.
     If the portrait is replaced with a differently framed cut-out, this is the
     only value that needs revisiting. */
  --disc-top: 11%;

  position: relative;
  align-self: end;
  min-height: 12rem;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Runs past the hero's bottom edge so the brands strip crops it. This is what
     makes the subject read as standing behind that strip rather than as a PNG
     resting on the page. The strip must stay taller than this overhang. */
  margin-bottom: -5rem;
}

/* Yellow disc behind the subject.
   Sized against two limits. Wide enough to read either side of the head — the
   jacket's shoulders are nearly as wide as the frame, so anything much smaller
   vanishes behind them. And its lower edge must stay above where
   .portrait__img's mask fade begins, or the yellow glows through the fading
   jacket as a muddy band. Both hold at 66% with --disc-top 11%, measured
   against this cut-out: subject top at 1.3% of its height, shoulders at ~44%. */
.portrait__disc {
  position: absolute;
  top: var(--disc-top);
  left: 50%;
  width: 66%;
  aspect-ratio: 1;
  translate: -50% 0;
  background: var(--yellow);
  border-radius: 50%;
  z-index: -1;
}

/* Two tilted rings, counter-rotating slowly.
   Given the same box as the disc and then scaled up, so the rings stay
   concentric with it whatever the column ends up measuring. */
.portrait__orbit {
  position: absolute;
  top: var(--disc-top);
  left: 50%;
  width: 66%;
  aspect-ratio: 1;
  translate: -50% 0;
  scale: 1.3;
  rotate: -14deg;
  overflow: visible;
  z-index: -1;
}
/* One stroke colour that reads on both grounds the rings cross: a shade darker
   than the yellow disc, a pale gold against the page. Avoids a second layer. */
.orbit {
  fill: none;
  stroke: rgba(240, 176, 0, 0.30);
  stroke-width: 1.5;
  transform-box: fill-box;
  transform-origin: center;
}
.orbit--a { animation: spin 34s linear infinite; }
.orbit--b { animation: spin 52s linear infinite reverse; stroke: rgba(240, 176, 0, 0.18); }

/* Sized above the column width on purpose: the portrait then fills whatever
   column 2 resolves to at every breakpoint, instead of being pinned smaller. */
/* Slightly wider than its column, bleeding 3% into the gutters on each side.
   The gap is 1.5rem, so this never reaches the ad card or the proof bar. */
.portrait__frame {
  position: relative;
  width: 106%;
  margin-inline: -3%;
  max-width: 40rem;
}

/* height:auto — the intrinsic ratio of the trimmed cut-out drives the layout.
   The drop-shadow follows the alpha silhouette, which is what makes this read as
   a cut-out resting above the page rather than a photo pasted into it. The fade
   is only the last 8%, just enough that the waist crop is not a razor line —
   fading earlier would make the black jacket translucent over the yellow disc. */
.portrait__img {
  width: 100%;
  height: auto;
  /* No mask any more. The brands strip crops the subject, and a hard edge
     disappearing behind an opaque strip reads as depth, where a fade into it
     would just look like he is dissolving. The shadow still lifts him off the
     backdrop above the crop. */
  filter: drop-shadow(0 1.25rem 1.75rem rgba(22, 22, 27, 0.18));
}

/* --- Column 3: sample ad -------------------------------------------------- */

.hero__sample { position: relative; padding-top: 3rem; }

.hero__kicker {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.18;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  text-wrap: initial;
}

/* Do NOT rename this back to .adcard, or to anything with an "ad" token.
   EasyList carries a generic cosmetic filter for .adcard and .ad-card, so
   uBlock, AdBlock and Brave shields set display:none on it. It cost us a
   silently missing hero card in production: the file served fine, no rule in
   our stylesheet touched it, and it was only invisible in browsers with a
   blocker installed -- which is most of them. Verified: .adcard and .ad-card
   are hidden, .reelcard is not. */
.reelcard {
  margin-top: 1.75rem;
  background: var(--surface);
  border-radius: var(--r-xl);
  padding: 0.6rem;
  box-shadow: var(--shadow-lg);
  animation: float 7s ease-in-out infinite;
}

.reelcard__media {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink);
  aspect-ratio: 4 / 3;
}
.reelcard__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.reelcard__badge {
  position: absolute;
  top: 0.85rem;
  left: 0.85rem;
  z-index: 2;
  padding: 0.4rem 0.8rem;
  background: var(--yellow);
  color: var(--ink);
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  box-shadow: var(--shadow-sm);
}

/* Chips are nowrap individually, so the row must be allowed to wrap — otherwise
   the three of them overflow the card just above the stacking breakpoint. */
.reelcard__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.55rem;
  padding: 0.95rem 0.5rem 0.55rem;
}


/* ============================================================================
   8b. BRANDS STRIP
   Doubles as the hero's bottom edge. Its opaque background plus z-index crop
   the portrait's overhang (.hero__portrait has margin-bottom: -5rem), which is
   what makes the subject read as standing behind it. Two rules follow from that:
   the background must stay opaque, and the strip must stay taller than the
   overhang, or the crop turns into a floating cut-off edge.
   ============================================================================ */

/* Solid brand yellow. No border needed — against the hero's pale cream above and
   the near-white work section below, the block delineates itself. Everything on
   it is tinted from --ink rather than grey, so the yellow reads through it. */
.brands {
  position: relative;
  z-index: 1;
  background: var(--yellow);
  padding: 1.75rem 0 2rem;
}

.brands__label {
  width: min(var(--maxw), 100% - var(--gutter) * 2);
  margin: 0 auto 1.5rem;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  /* Tracking eased back from 0.16em: the same openness that makes a small
     eyebrow legible reads as gappy once the type is this size. */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(22, 22, 27, 0.75);   /* measured 6.2:1 on --yellow */
}

/* --- Marquee ---------------------------------------------------------------
   Full bleed, faded at both ends so logos enter and leave rather than popping
   at a hard edge.
   -------------------------------------------------------------------------- */
.marquee {
  overflow: hidden;
  mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}

.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee 38s linear infinite;
}

/* How far the track travels: exactly one copy's width, so the loop restarts on
   an identical frame. site.js overrides both this and the duration once it knows
   how many copies it had to make. */
.marquee__track { --marquee-shift: -50%; }

/* Each copy carries half the gap as padding, so the spacing across the seam
   matches the spacing inside a copy. Keep padding-inline at exactly gap/2. */
.marquee__list {
  display: flex;
  align-items: center;
  gap: 3rem;
  padding-inline: 1.5rem;
}

/* Travels one copy's width. With N copies the shift is -100%/N, which site.js
   sets — the markup's two copies are only the no-JS baseline.

   THE RULE: a seamless loop needs `viewport <= (copies - 1) * copyWidth`. At the
   moment the track has scrolled a full copy, the visible window still has to
   land on content. Two copies of a 1212px list left a wide screen showing empty
   track, which is exactly the gap this replaced. */
@keyframes marquee {
  to { transform: translateX(var(--marquee-shift, -50%)); }
}

.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

/* Nonessential loop: stopped while off screen (site.js toggles the class). */
.marquee.is-offscreen .marquee__track { animation-play-state: paused; }

/* The dashed placeholder slots that used to fill this strip and the About panel
   were removed once every one held real artwork. If you need them back before
   the next batch of logos arrives, they are in git — the last commit that had
   them is the one that added the About photo. */

/* A real client logo, not a placeholder: no dashed box around it. The artwork is
   dark on transparent, which sits directly on the yellow. A logo that is light
   or that carries its own background needs its own treatment here.

   Width is intentionally `auto`. A fixed slot width wider than the artwork adds
   its own slack on top of the flex gap, which is what made the spacing read as a
   big gap — the visible distance was the gap plus roughly 40px of empty box on
   each side. With auto width the gap alone controls the rhythm. */
/* Each item is the model's mark on a white chip, with its name beside it. The
   chip is what makes nine logos of different shapes, grounds and colours read as
   one row: it gives every mark the same footprint and puts each brand's colours
   on the white they were designed for, rather than on saturated yellow. */
.modelname {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  height: 3.6rem;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: rgba(22, 22, 27, 0.82);   /* 7.4:1 on --yellow */
}

.modelname__chip {
  flex: none;
  display: block;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 0.72rem;
  overflow: hidden;                /* rounds Sora's square tile with everything else */
  background: #fff;
  box-shadow: 0 0.15rem 0.5rem -0.15rem rgba(22, 22, 27, 0.22);
}
/* cover, not contain: the marks are already squared with their own inset baked
   in by the build script, so there is nothing to letterbox. */
.modelname__chip img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 700px) {
  .modelname { font-size: 1.05rem; height: 3rem; gap: 0.5rem; }
  .modelname__chip { width: 2rem; height: 2rem; border-radius: 0.6rem; }
}


/* ============================================================================
   9. WORK — placeholder grid
   ============================================================================ */

/* Six across, one row: the volume of creative *is* the pitch, and 9:16 at a
   sixth of the container is roughly the size a reel is actually watched at.
   Fixed counts (not auto-fill) so six items never leave an orphan row. */
.work-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1rem;
}

.videoslot {
  position: relative;
  aspect-ratio: 9 / 16;
  display: grid;
  place-items: center;
  gap: 0.75rem;
  align-content: center;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  background:
    repeating-linear-gradient(135deg, rgba(22,22,27,0.02) 0 0.5rem, transparent 0.5rem 1rem);
  color: var(--muted);
  transition: border-color 0.25s var(--ease-out), background-color 0.25s var(--ease-out);
}
.videoslot:hover { border-color: var(--yellow); background-color: var(--yellow-tint); }

.videoslot__play {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  position: relative;
}
.videoslot__play::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 54%;
  translate: -50% -50%;
  border-style: solid;
  border-width: 0.5rem 0 0.5rem 0.8rem;
  border-color: transparent transparent transparent var(--ink);
}

.videoslot__label {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Sits under the process steps, styled and spaced like .about__actions so the
   two secondary page links on the landing page read as the same control. */
.process__cta { margin-top: 2.75rem; }

/* A slot holding real footage: no dashed placeholder chrome, video fills it. */
.videoslot--filled {
  display: block;
  padding: 0;
  border: 0;
  background: var(--ink);
  overflow: hidden;
}
.videoslot--filled:hover { background: var(--ink); }

/* Inert on purpose. There are no controls to reach, and this also takes away
   the right-click menu's "Show controls" and picture-in-picture entries — the
   only remaining ways a visitor could put a control bar over the work. */
.videoslot__video {
  pointer-events: none;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Marks the clips that are real client work, so the rest read as what they are.
   Sits above the video and stays legible over any frame.

   This is the original solid tag, restored at Sajal's request after trying a
   glass pill and a bottom caption bar. Both alternatives are in git history if
   they are ever wanted back — see the commits either side of 87e4e72. */
.videoslot__badge {
  position: absolute;
  top: 0.55rem;
  left: 0.55rem;
  z-index: 2;
  padding: 0.3rem 0.55rem;
  background: var(--yellow);
  color: var(--ink);
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  box-shadow: var(--shadow-sm);
}


/* ============================================================================
   10. SERVICES + PROCESS
   ============================================================================ */

/* Three across: six services land as a clean 3x2 with no orphan. */
.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5rem;
}

.card {
  padding: 2rem 1.75rem;
  background: var(--page);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }

.card__num {
  display: block;
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--yellow-deep);
  margin-bottom: 1.1rem;
}
.card h3 { font-size: 1.15rem; font-weight: 700; margin-bottom: 0.6rem; letter-spacing: -0.01em; }
.card p  { font-size: 0.92rem; }

.steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.5rem;
}

.step {
  position: relative;
  padding-top: 2rem;
  border-top: 2px solid var(--line);
}
.step__n {
  position: absolute;
  top: -1.1rem;
  left: 0;
  display: grid;
  place-items: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  background: var(--yellow);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.9rem;
  font-weight: 700;
}
.step h3 { font-size: 1.1rem; font-weight: 700; margin-bottom: 0.5rem; }
.step p  { font-size: 0.92rem; }


/* ============================================================================
   11. PROOF (dark band)
   ============================================================================ */

/* --- Testimonial carousel --------------------------------------------------
   Quote on the left, the client it came from on the right, so the words and
   whose they are are never separated. site.js keeps the two panels paired.
   -------------------------------------------------------------------------- */
.tcarousel {
  display: grid;
  grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr);
  gap: 1.5rem;
  align-items: stretch;
}

.tcarousel__main,
.tcarousel__aside {
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--r-xl);
}

.tcarousel__main {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding: 2rem;
}

/* Every slide occupies the same grid cell, so the stage is as tall as the
   longest quote and swapping slides never changes the section's height. That
   is also why no JS measures anything here. */
.tcarousel__stage {
  display: grid;
  flex: 1;
}

.tslide {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  opacity: 0;
  visibility: hidden;          /* also removes it from the a11y tree */
  transform: translateY(0.6rem);
  transition: opacity 0.5s var(--ease-expo),
              transform 0.5s var(--ease-expo),
              visibility 0s linear 0.5s;
}
.tslide.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.5s var(--ease-expo),
              transform 0.5s var(--ease-expo),
              visibility 0s;
}

.tslide__head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* The base row is near-black by default, which would vanish on this band. */
.section--dark .rating__base { color: rgba(255, 255, 255, 0.24); }

.tslide__score {
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 700;
  color: #fff;
}

.tslide__order {
  margin-left: auto;
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.tslide__quote {
  font-size: 1.05rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.94);
}

/* Visibly secondary to the words the client actually wrote. */
.tslide__translation {
  padding-top: 0.9rem;
  border-top: 1px solid rgba(255, 255, 255, 0.10);
  font-size: 0.88rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.62);
}
.tslide__translation span {
  display: block;
  margin-bottom: 0.35rem;
  font-family: var(--font-display);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
}

/* --- Dots: one per review by the client currently showing ------------------ */
.tcarousel__dots {
  display: flex;
  gap: 0.45rem;
  align-items: center;
}

.tdot {
  width: 0.5rem;
  height: 0.5rem;
  padding: 0;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.28);
  cursor: pointer;
  transition: width 0.35s var(--ease-expo), background-color 0.35s var(--ease-out);
}
.tdot:hover { background: rgba(255, 255, 255, 0.5); }
.tdot[aria-selected="true"] {
  width: 1.6rem;
  background: var(--yellow);
}

/* --- Client panel ---------------------------------------------------------- */
.tcarousel__aside {
  display: grid;
  place-items: center;
  padding: 2rem 1.5rem;
  text-align: center;
}

.tclient {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.4rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s var(--ease-expo), visibility 0s linear 0.5s;
}
.tclient.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.5s var(--ease-expo), visibility 0s;
}

/* Light plate rather than an inverted logo: recolouring someone's mark is not
   ours to do, and this one is dark ink on transparency. */
.tclient__logo {
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 12rem;
  padding: 0.85rem 1.1rem;
  background: #fff;
  border-radius: var(--r-md);
}
.tclient__logo img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 2rem;
}

.tclient__face {
  width: 6.5rem;
  height: 6.5rem;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid rgba(255, 255, 255, 0.16);
}

.tclient__name {
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
}
.tclient__name span {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.6);
}


/* ============================================================================
   12. PRICING
   ============================================================================ */

.plans {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.75rem;
  align-items: start;
}

.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 2.25rem 2rem;
  background: var(--page);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
}

.plan--featured {
  background: var(--ink);
  border-color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.plan--featured .plan__name,
.plan--featured .plan__price { color: #fff; }
.plan--featured .plan__term,
.plan--featured li { color: rgba(255, 255, 255, 0.68); }
.plan--featured li::before { background: var(--yellow); }

.plan__flag {
  position: absolute;
  top: -0.75rem;
  left: 2rem;
  padding: 0.35rem 0.8rem;
  background: var(--yellow);
  color: var(--ink);
  border-radius: var(--r-pill);
  font-family: var(--font-display);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.plan__name {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
}
.plan__price {
  font-family: var(--font-display);
  font-size: 2.75rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
}
.plan__price small { font-size: 0.95rem; font-weight: 500; letter-spacing: 0; }
.plan__term { font-size: 0.82rem; }

.plan ul {
  display: grid;
  gap: 0.7rem;
  margin: 1.5rem 0 2rem;
  font-size: 0.92rem;
}
.plan li { position: relative; padding-left: 1.5rem; }
.plan li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--yellow-deep);
}
.plan .btn { margin-top: auto; }


/* ============================================================================
   13. ABOUT + CTA + FOOTER
   ============================================================================ */

.about {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 4rem;
  align-items: center;
}
.about__text p { margin-top: 1.25rem; font-size: 1.02rem; max-width: 32rem; }
.about__actions { margin-top: 2rem; }

.about__slot { max-width: 22rem; margin-left: auto; }
.about__photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
}

/* The dark button's circular icon needs the inverse of the primary treatment. */
.btn--dark .btn__icon--light { background: #fff; color: var(--ink); }

.section--cta {
  background: var(--ink);
  text-align: center;
}
.cta { max-width: 44rem; margin-inline: auto; }
.cta__title {
  font-size: 3.1rem;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
  color: #fff;
}
.cta__sub {
  margin: 1.5rem auto 0;
  max-width: 34rem;
  font-size: 1.02rem;
  color: rgba(255, 255, 255, 0.68);
}
.cta__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  justify-content: center;
  margin-top: 2.5rem;
}
.cta__fine {
  margin-top: 1.75rem;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.38);
}

.footer { padding: 3rem 0; background: var(--ink); border-top: 1px solid rgba(255,255,255,0.08); }
.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 2rem;
}
.logo--footer .logo__word { color: #fff; }
.footer__line { font-size: 0.85rem; color: rgba(255, 255, 255, 0.5); }
.footer__copy { margin-left: auto; font-size: 0.85rem; color: rgba(255, 255, 255, 0.38); }

/* The social list takes over the push to the right, so the copyright sits with
   it as a pair rather than both fighting for the same auto margin — two
   `margin-left: auto` siblings split the free space and leave a gap between. */
.footer__social {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  margin-left: auto;
  list-style: none;
  padding: 0;
}
.footer__social + .footer__copy { margin-left: 0; }

.footer__social a {
  display: grid;
  place-items: center;
  width: 1.25rem;
  height: 1.25rem;
  color: rgba(255, 255, 255, 0.55);
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}
.footer__social a::after { content: ""; position: absolute; inset: -0.45rem; }
.footer__social li { position: relative; display: grid; }
.footer__social a:hover,
.footer__social a:focus-visible { color: var(--yellow); transform: translateY(-0.1rem); }
.footer__social svg { width: 100%; height: 100%; fill: currentColor; }

/* Below this the row wraps badly — the socials hold the right edge while the
   copyright drops alone to the left. Stacking is tidier than half a row. */
@media (max-width: 820px) {
  .footer__inner { flex-direction: column; align-items: flex-start; gap: 1rem; }
  .footer__social,
  .footer__social + .footer__copy,
  .footer__copy { margin-left: 0; }
}


/* ============================================================================
   13b. 404
   Only used by 404.html. Sized against the viewport rather than the root scale,
   because the artwork is the page — it should fill whatever screen it lands on
   instead of holding the body-copy proportions the rest of the site uses.
   ============================================================================ */

.body--404 {
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: linear-gradient(180deg, #FDFDFC 0%, #FBF5E7 100%);
}

.e404 {
  width: min(var(--maxw), 100% - var(--gutter) * 2);
  /* Generous top padding: the blob rises above the robot and the ticks sit
     above that again, so both get clipped by the viewport edge without it. */
  padding: 7rem 0 4rem;
  text-align: center;

  /* One unit drives the whole composition: it is the blob's width, and the
     digits are sized from it. The 42vh term is what keeps "Back to home" above
     the fold — on a wide-but-short window (1920x900 laptops) a purely vw-based
     size grows the art until the button falls off the bottom. */
  --u: clamp(5.5rem, min(22vw, 38vh), 24rem);
}

/* --- Artwork ----------------------------------------------------------------
   Three glyphs on one ground line: 4, the blob, 4. The blob IS the zero, so it
   is sized and centred like a digit and the robot stands inside it. Getting
   that backwards — robot first, blob tucked behind — reads as a halo, not a
   character, and the figure spills out of one side.

   Every proportion below is tied to the blob's width, so the trio scales as a
   single piece of lettering. The ratios are lifted off the reference:
     robot width  = 0.69x blob width  -> blob comes out at 0.80 wide-to-tall
     robot height = 0.83x blob height -> fills the zero, ~17% clear above the head
     digit height = 0.91x blob height -> the 4s sit just inside the zero
   Poppins renders a digit at ~0.76 of its font-size, measured off the render
   rather than assumed, which is where the 1.5x on --u comes from.
   -------------------------------------------------------------------------- */
.e404__art {
  position: relative;
  display: flex;
  align-items: end;      /* digits and feet share one ground line */
  justify-content: center;
  gap: calc(var(--u) * 0.16);
}

.e404__digit {
  font-family: var(--font-display);
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  line-height: 0.78;
  letter-spacing: -0.05em;
  color: #24242B;        /* a touch off pure ink, so the yellow stays loudest */
  filter: drop-shadow(0 1.4rem 1.1rem rgba(22, 22, 27, 0.13));
}

/* Block flow, not grid. The robot inside is sized as a percentage of this box,
   and a percentage width on a grid item in an auto-sized track has nothing
   definite to resolve against — it collapses and the figure disappears. */
.e404__bot {
  position: relative;
  flex: none;
  width: var(--u);
}

/* The zero. Centred on the layout, not on the robot: it has to sit squarely
   between the two 4s to be read as a digit. The robot is what shifts. */
.e404__blob {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100%;
  height: 120%;
  translate: -50% 0;
  background: var(--yellow);
  border-radius: 50%;
  z-index: 0;
}

/* Nudged left of the box centre. The cut-out's bounding box centres at 50%, but
   the mass does not — the raised arm is thin and reaches far, while the body and
   legs sit right of centre. Shifting by a few percent evens the yellow margin. */
.e404__figure {
  position: relative;
  z-index: 1;
  width: 69%;
  margin: 0 auto;
  translate: -3% 0;
  filter: drop-shadow(0 1.1rem 0.9rem rgba(22, 22, 27, 0.12));
}
.e404__robot  { width: 100%; height: auto; display: block; }

/* Positioned as a share of the robot, so it tracks at every size. */
.e404__chest {
  position: absolute;
  top: 47%;
  left: 51%;
  width: 17%;
  height: auto;
  translate: -50% 0;
  opacity: 0.9;
  mix-blend-mode: multiply;   /* sits into the plastic instead of on top of it */
}

.e404__orbit,
.e404__ticks,
.e404__spark { position: absolute; pointer-events: none; }

.e404__orbit {
  inset: -6% -4% auto;
  width: 108%;
  height: 100%;
  z-index: 0;
  fill: none;
  stroke: rgba(240, 176, 0, 0.45);
  stroke-width: 1.25;
  stroke-linecap: round;
}

/* Clear of the blob entirely, up and left — reading as a thought above the hand
   that is scratching, not as antennae growing out of the head. */
.e404__ticks {
  bottom: 116%;
  left: 27%;
  width: 22%;
  height: auto;
  translate: -50% 0;
  z-index: 2;
  fill: none;
  stroke: var(--yellow);
  stroke-width: 5;
  stroke-linecap: round;
}

.e404__spark { width: clamp(1rem, 2vw, 1.9rem); height: auto; fill: var(--yellow); }
.e404__spark--l { top: 22%; left: 2%; }
.e404__spark--r { top: 30%; right: 3%; }

/* --- Copy ------------------------------------------------------------------ */
.e404__title {
  margin-top: clamp(1.5rem, 4vw, 3rem);
  font-size: clamp(1.5rem, 3.4vw, 2.6rem);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: initial;
}

.e404__sub {
  margin: 1rem auto 0;
  max-width: 34rem;
  font-size: 1rem;
  color: var(--muted);
}

.e404__cta { margin-top: 2rem; }

.e404__hint { margin-top: 1.5rem; font-size: 0.85rem; color: var(--muted); }
.e404__hint a {
  color: var(--ink);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-color: var(--line-strong);
}
.e404__hint a:hover { text-decoration-color: var(--yellow); }

/* --- Motion ----------------------------------------------------------------
   The robot idles: a slow bob with a slight lean, so it reads as a character
   waiting rather than a pasted-in render. Everything else is a quiet
   counterpoint at a different period, so the loops never march in step.
   -------------------------------------------------------------------------- */
@keyframes bot-idle {
  0%, 100% { transform: translateY(0) rotate(-1.2deg); }
  50%      { transform: translateY(-2.6%) rotate(1.2deg); }
}
/* Centring lives in the `translate` property on each element; these keyframes
   must not repeat it. Setting translate(-50%) here too shifted both a full width
   off their mark — which is how the ticks ended up over the arm. */
@keyframes ticks-pulse {
  0%, 100% { opacity: 0.4; transform: translateY(0.15rem) scale(0.92); }
  50%      { opacity: 1;   transform: translateY(0) scale(1); }
}
@keyframes blob-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.025); }
}

.e404__figure { animation: bot-idle 5.5s ease-in-out infinite; }
.e404__ticks  { animation: ticks-pulse 2.2s ease-in-out infinite; }
.e404__blob   { animation: blob-breathe 7s ease-in-out infinite; }
.e404__spark--l { animation: twinkle 4.5s ease-in-out infinite; }
.e404__spark--r { animation: twinkle 4.5s ease-in-out infinite 1.4s; }

@media (max-width: 700px) {
  /* The gap scales with --u now, so it needs no override here. */
  .e404__hint { line-height: 1.8; }
}


/* ============================================================================
   13c2. FORM PAGES  (/free-ad, /call, /thanks)
   Three pages whose whole job is one embedded thing. The chrome is the site's,
   the copy is short, and the page gets out of the way: no decoration competing
   with a form the visitor is trying to fill in.
   ============================================================================ */

.formpage {
  position: relative;
  overflow: hidden;          /* the backdrop runs off every edge on purpose */
  padding-top: 4.5rem;
}
.formpage__inner { position: relative; z-index: 1; max-width: 48rem; }

/* --- Page backdrop ----------------------------------------------------------
   The same primitives the team and FAQ pages use, generalised so the three form
   pages share one set instead of each growing its own. All decorative, all
   pointer-events: none so none of it can intercept a click meant for the form.

   Held deliberately faint. These pages are a heading and one card on a wide
   field; the job is to give that card somewhere to sit, not to be looked at.
   -------------------------------------------------------------------------- */
.pagedeco {
  position: absolute;
  pointer-events: none;
  z-index: 0;
}

.pagedeco--dots-tl,
.pagedeco--dots-br {
  width: 14rem;
  height: 12rem;
  background-image: radial-gradient(currentColor 1.6px, transparent 1.7px);
  background-size: 1.15rem 1.15rem;
  color: rgba(240, 176, 0, 0.34);
}
.pagedeco--dots-tl { top: 2.5rem; left: -2.5rem; }
.pagedeco--dots-br { bottom: 3rem; right: -3rem; color: rgba(240, 176, 0, 0.26); }

.pagedeco--ring {
  bottom: -14rem;
  left: -10rem;
  width: 30rem;
  height: 30rem;
  border: 1.5px solid rgba(240, 176, 0, 0.3);
  border-radius: 50%;
}

/* Blurred rather than flat: a hard disc reads as a graphic element competing
   with the card, a wash reads as light behind it. */
.pagedeco--disc,
.pagedeco--disc-2 {
  border-radius: 50%;
  background: var(--yellow);
  /* Heavy blur and pushed well off-canvas. At a smaller blur the disc keeps a
     readable edge, and a visible arc reads as a shape sitting on the page rather
     than light falling across it. */
  filter: blur(4.5rem);
}
.pagedeco--disc   { top: -12rem;  right: -11rem; width: 30rem; height: 26rem; opacity: 0.22; }
.pagedeco--disc-2 { bottom: 4rem; left: -12rem; width: 24rem; height: 20rem; opacity: 0.14; }

.pagedeco--spark,
.pagedeco--spark-2 { fill: var(--yellow); height: auto; }
.pagedeco--spark   { top: 9rem;  left: 4.5rem;  width: 1.9rem; }
.pagedeco--spark-2 { top: 22rem; right: 5.5rem; width: 1.4rem; }

/* No margin left to decorate at this width: these start crowding the card
   rather than framing it. The two washes stay, since they sit behind. */
@media (max-width: 900px) {
  .pagedeco--dots-tl,
  .pagedeco--dots-br,
  .pagedeco--spark,
  .pagedeco--spark-2,
  .pagedeco--ring { display: none; }
}

.formpage__head { text-align: center; margin-bottom: 2.5rem; }
.formpage__title {
  font-size: clamp(2rem, 4.4vw, 3.1rem);
  text-transform: none;
  line-height: 1.08;
}
.formpage__lede {
  margin: 1.1rem auto 0;
  max-width: 34rem;
  font-size: 1.02rem;
  color: var(--muted);
}

/* A card around the embed. The form used to sit straight on the page and read as
   floating in the middle of it; the card gives it edges and a ground, which is
   what makes it look like the thing you are meant to fill in. */
.formcard {
  padding: clamp(1.25rem, 2.6vw, 2.25rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
}

/* Sits directly above the card, where "what do I need before I start" is the
   question actually being asked. Kept small so it reads as a practical aside and
   does not compete with the lede above it. */
.formpage__note {
  max-width: 34rem;
  margin: 0 auto 1rem;
  font-size: 0.88rem;
  color: var(--muted);
  text-align: center;
}

/* Tally lays its fields and choice buttons out at their own narrow width and
   left-aligns them, so a wide card leaves every option stranded in dead space.
   Pulling the card in to roughly the form's own measure is the part of "the
   options look odd" that is actually fixable from this side: what is inside the
   iframe is cross-origin and cannot be styled from here at all. */
.formcard--tight {
  max-width: 34rem;
  margin-inline: auto;
}

.embed {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
}
.embed iframe {
  display: block;
  width: 100%;
  border: 0;
  /* A floor only. Tally's script grows the frame to fit, so a fixed height here
     would cap it and reintroduce the inner scrollbar. */
  min-height: 26rem;
}

/* Cal reports its own height and the embed grows to match, so this is only a
   floor for the moment before the script answers. It was 34rem, which was taller
   than the widget actually needs and left a band of empty card below it. */
.embed--cal { min-height: 20rem; }

/* --- What happens next ------------------------------------------------------
   Sits under the form, not above it: it answers "is this worth my time" for
   anyone who hesitates, without standing between them and the first field.
   -------------------------------------------------------------------------- */
.nextsteps {
  display: grid;
  gap: 1rem;
  margin: 2.5rem auto 0;
  max-width: 34rem;
  list-style: none;
  padding: 0;
  counter-reset: none;
}
.nextsteps li {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
}
.nextsteps__n {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  margin-top: 0.05rem;
  border-radius: 50%;
  background: var(--yellow);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 700;
}
.nextsteps__t {
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--muted);
}

.formpage__fallback {
  margin-top: 1.5rem;
  font-size: 0.85rem;
  color: var(--muted);
  text-align: center;
}
.formpage__fallback a {
  color: var(--ink);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-color: var(--line-strong);
}
.formpage__fallback a:hover { text-decoration-color: var(--yellow); }

/* --- /thanks ---------------------------------------------------------------- */
.formpage--thanks { padding-bottom: 6rem; }
.thanks__next {
  margin-top: 2.75rem;
  padding-top: 2.25rem;
  border-top: 1px solid var(--line);
  text-align: center;
}
.thanks__nextline {
  margin-bottom: 1.15rem;
  font-size: 0.95rem;
  color: var(--muted);
}


/* ============================================================================
   13d. FAQ PAGE  (faq.html)
   Rows are native <details>. No JavaScript, so the disclosure, keyboard
   behaviour and screen-reader announcement all come for free and survive a
   failed script. Height is deliberately not animated: that needs JS or
   ::details-content, which is not safe across browsers yet, so the answer
   fades and lifts instead — it degrades to "just appears", never to broken.
   ============================================================================ */

.faqhero {
  position: relative;
  overflow: hidden;
  padding: 4.5rem 0 2.5rem;
  text-align: center;
  background: linear-gradient(180deg, #FDFCF8 0%, var(--page) 100%);
}
/* Soft, and asymmetric rather than a plain circle — a hard disc reads as a
   graphic element competing with the heading instead of a wash behind it. */
.faqhero__blob {
  position: absolute;
  top: -11rem;
  right: -8rem;
  width: 30rem;
  height: 24rem;
  border-radius: 52% 48% 44% 56% / 55% 50% 50% 45%;
  background: var(--yellow);
  opacity: 0.38;
  filter: blur(1.5rem);
  pointer-events: none;
}
.faqhero .container { position: relative; z-index: 1; }

.faqhero__title {
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 5vw, 3.6rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--ink);
}
.faqhero__lede {
  margin: 1.1rem auto 0;
  max-width: 32rem;
  font-size: 1.02rem;
  color: var(--muted);
}
.faqhero__cta { margin-top: 1.9rem; }

.faqwrap { padding: 0 0 5.5rem; }

.faqcard {
  max-width: 84rem;
  margin: 0 auto;
  padding: clamp(1.6rem, 3.2vw, 4rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
}

.faqcard__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 2.25rem;
  border-bottom: 1px solid var(--line);
}
.faqcard__mark {
  font-family: var(--font-display);
  font-size: clamp(3rem, 9vw, 5.5rem);
  font-weight: 800;
  line-height: 0.85;
  letter-spacing: -0.045em;
  color: var(--ink);
}
.faqcard__note {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: right;
}

/* One column per group, side by side, each under its own label. Rows flowing
   across shared columns put unrelated questions next to each other and made the
   labels read as interruptions; a column per group means everything beside a
   question belongs to the same subject.

   align-items: start is what makes it behave. Grid items stretch by default, so
   the three columns would match the tallest and an opened answer would push the
   others' backgrounds around. Starting them lets each column size itself. */
.faqgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(2rem, 3.4vw, 4.5rem);
  margin-top: 2.5rem;
  align-items: start;
}

/* Section label between runs of rows. Not a heading level, because these sit
   between sibling <details> and would break the outline for no gain. */
.faqgroup {
  margin: 0 0 0.9rem;
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--yellow-deep);
}

/* --- Rows ------------------------------------------------------------------ */
.qa { border-bottom: 1px solid var(--line); }

.qa > summary {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 1.3rem 0;
  cursor: pointer;
  list-style: none;                 /* Firefox */
  -webkit-tap-highlight-color: transparent;
}
.qa > summary::-webkit-details-marker { display: none; }   /* Safari */
.qa > summary:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* The +/- drawn in CSS: two bars, and the vertical one collapses when open. */
.qa__sign {
  position: relative;
  flex: none;
  width: 0.85rem;
  height: 0.85rem;
}
.qa__sign::before,
.qa__sign::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: var(--yellow-deep);
  border-radius: 1px;
  transition: transform 0.25s var(--ease), opacity 0.2s var(--ease);
}
.qa__sign::before { width: 100%; height: 2px; }
.qa__sign::after  { width: 2px; height: 100%; }
.qa[open] .qa__sign::after { transform: scaleY(0); opacity: 0; }

.qa__text {
  flex: 1;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink);
}
.qa > summary:hover .qa__text { color: var(--yellow-deep); }

.qa__arrow {
  flex: none;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--yellow);
  color: var(--ink);
  transition: transform 0.3s var(--ease), background 0.2s var(--ease);
}
.qa__arrow svg { width: 1rem; height: 1rem; display: block; }
.qa[open] .qa__arrow { transform: rotate(-90deg); }   /* points up when open */
.qa > summary:hover .qa__arrow { background: var(--yellow-deep); }

.qa__a {
  padding: 0.2rem 0.5rem 1.5rem 1.75rem;
  animation: qa-reveal 0.32s var(--ease) both;
}
.qa__a p { font-size: 0.95rem; line-height: 1.65; color: var(--muted); }
.qa__a strong { color: var(--ink); font-weight: 600; }
.qa__a a {
  color: var(--ink);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-color: var(--line-strong);
}
.qa__a a:hover { text-decoration-color: var(--yellow); }

@keyframes qa-reveal {
  from { opacity: 0; transform: translateY(-0.35rem); }
  to   { opacity: 1; transform: none; }
}

/* --- Still have questions --------------------------------------------------- */
.faqhelp {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  max-width: 84rem;
  margin: 1.75rem auto 0;
  padding: 1.5rem clamp(1.5rem, 3.2vw, 4rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.faqhelp__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--yellow-tint);
  color: var(--yellow-deep);
}
.faqhelp__icon svg { width: 1.4rem; height: 1.4rem; }
.faqhelp__body { flex: 1; }
.faqhelp__title {
  font-family: var(--font-display);
  font-size: 1.02rem;
  font-weight: 700;
  color: var(--ink);
}
.faqhelp__sub { font-size: 0.9rem; color: var(--muted); }
.faqhelp__cta { flex: none; }

@media (max-width: 1180px) {
  .faqgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* One column before the questions start wrapping to three lines each. */
@media (max-width: 760px) {
  .faqgrid { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
}

@media (max-width: 620px) {
  .faqcard__head { flex-direction: column; align-items: flex-start; gap: 0.35rem; }
  .faqcard__note { text-align: left; }
  .qa > summary { gap: 0.75rem; }
  .qa__text { font-size: 0.95rem; }
  .qa__arrow { width: 1.8rem; height: 1.8rem; }
  .qa__a { padding: 0 0 1.3rem 1.6rem; }
  .faqhelp { flex-wrap: wrap; }
  .faqhelp__cta { width: 100%; justify-content: center; }
}


/* ============================================================================
   13c. TEAM PAGE  (team.html)
   Portrait cards on a gradient that runs yellow at the top into black at the
   bottom, so a greyscale cut-out reads against the brand colour up top and the
   copy reads against black underneath. The photo is masked out before it
   reaches the text rather than being cropped, which is what keeps the join
   invisible whatever the subject's framing.
   ============================================================================ */

.team {
  position: relative;
  overflow: hidden;          /* the decoration runs off every edge on purpose */
  padding-top: 5rem;
}

/* Centred head, and NOT uppercase. Section titles are uppercase everywhere else,
   but this heading is a sentence rather than a two-word label, and setting it in
   caps at that length shouts. */
.team .section__head {
  max-width: 40rem;
  margin: 0 auto;
  text-align: center;
}
.team .section__title {
  font-size: clamp(2.1rem, 4.6vw, 3.5rem);
  text-transform: none;
  line-height: 1.08;
}
.team .section__lede { margin: 1.15rem auto 0; }

/* --- Backdrop -------------------------------------------------------------
   Two dot fields, two outlined rings and two soft discs. All decorative, all
   pointer-events: none so none of it can swallow a click on the cards.
   -------------------------------------------------------------------------- */
.team__dots,
.team__ring,
.team__blob,
.team__spark { position: absolute; pointer-events: none; z-index: 0; }

.team__dots {
  width: 13rem;
  height: 11rem;
  background-image: radial-gradient(currentColor 1.6px, transparent 1.7px);
  background-size: 1.15rem 1.15rem;
  color: rgba(240, 176, 0, 0.42);
}
.team__dots--tl { top: 1.5rem; left: -2rem; }
.team__dots--br { bottom: 2rem; right: -2.5rem; color: rgba(240, 176, 0, 0.34); }

.team__ring {
  border: 1.5px solid rgba(240, 176, 0, 0.35);
  border-radius: 50%;
}
.team__ring--tr { top: -7rem; right: -4rem; width: 20rem; height: 20rem; }
.team__ring--r  { top: 34%;  right: -13rem; width: 26rem; height: 26rem; }

.team__blob { border-radius: 50%; background: var(--yellow); opacity: 0.16; }
.team__blob--tl { top: 2.5rem; left: 5rem;    width: 5.5rem; height: 5.5rem; }
.team__blob--r  { top: 12rem;  right: -6rem;  width: 13rem;  height: 13rem; }

.team__spark { fill: var(--yellow); }
.team__spark--tr { top: 9rem;  right: 6rem; width: 2.1rem; }
.team__spark--l  { top: 24rem; left: 3rem;  width: 1.6rem; }

.team .container { position: relative; z-index: 1; }

/* --- Cards ---------------------------------------------------------------- */
.teamgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5rem;
  max-width: 58rem;
  margin: 3.25rem auto 0;
  list-style: none;
  padding: 0;
}

.tcard {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  aspect-ratio: 62 / 100;
  border-radius: 1.15rem;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(
    180deg,
    #FFCE45 0%,
    #FFC629 24%,
    #DFA71F 42%,
    #6A5217 53%,
    #1B1811 63%,
    #0C0C0C 76%,
    #0A0A0A 100%
  );
  box-shadow: 0 1.4rem 2.4rem -0.9rem rgba(22, 22, 27, 0.3);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.tcard:hover {
  transform: translateY(-0.35rem);
  box-shadow: 0 2rem 3rem -0.9rem rgba(22, 22, 27, 0.36);
}

.tcard__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  margin: 0;
}
.tcard__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 12%;
  /* Greyscale so every portrait sits on the yellow the same way, whatever was
     worn on the day. The mask fades the photo out above the copy, so the card
     needs no hard crop line and no per-photo tuning.

     Desaturating alone leaves the subject flat and grey against a saturated
     yellow, so the contrast lift is not decoration — it puts back the tonal
     range greyscale removed, and lets the darks meet the card's black bottom
     instead of hovering above it. */
  filter: grayscale(1) contrast(1.28) brightness(1.03);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 46%, rgba(0,0,0,0.72) 60%, transparent 78%);
          mask-image: linear-gradient(180deg, #000 0%, #000 46%, rgba(0,0,0,0.72) 60%, transparent 78%);
}

.tcard__spark {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 2;
  width: 1.05rem;
  height: auto;
  fill: #fff;
  opacity: 0.9;
}

.tcard__body {
  position: relative;
  z-index: 1;
  padding: 0 1.35rem 1.35rem;
}

.tcard__name {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1.2;
  color: #fff;
}
.tcard__role {
  margin-top: 0.3rem;
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--yellow);
}
/* Three lines' worth of floor. The card bottom-anchors its copy, so without this
   a shorter bio pushes its name down and the three names stop lining up. */
.tcard__bio {
  margin-top: 0.7rem;
  min-height: calc(0.85rem * 1.55 * 3);
  font-size: 0.85rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.68);
}

.tcard__social {
  display: flex;
  gap: 0.9rem;
  margin-top: 1.1rem;
  list-style: none;
  padding: 0;
}
/* Real links out to each profile. The hit area is padded past the glyph so it
   clears the 24px minimum on touch without the icons drifting apart. */
.tcard__soc {
  display: grid;
  place-items: center;
  width: 1.35rem;
  height: 1.35rem;
  color: rgba(255, 255, 255, 0.82);
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}
.tcard__soc::after {
  content: "";
  position: absolute;
  inset: -0.4rem;
}
.tcard__social li { position: relative; display: grid; }
.tcard__soc:hover,
.tcard__soc:focus-visible { color: var(--yellow); transform: translateY(-0.1rem); }
.tcard__soc svg { width: 100%; height: 100%; fill: currentColor; }

/* The dashed slot, scoped down from the global one. Full-bleed there, but here
   it must sit inside the photo area only — covering the card would hide the
   gradient the design is built on.

   The selector repeats [data-asset].is-missing deliberately. The global rule is
   `[data-asset].is-missing .asset-missing` (0,3,0) and it is declared LATER in
   this file, so a plain `.tcard .asset-missing` (0,2,0) loses twice over. This
   file has been bitten by that exact pairing before — see the .logoslot note. */
.tcard [data-asset].is-missing .asset-missing {
  position: absolute;
  inset: 0.75rem 0.75rem 42%;
  /* Both of these are undoing the global rule. It sets height:100% and a 12rem
     min-height for a full-bleed slot; left in place they beat the bottom inset
     and the box runs down into the black, taking its dark label with it. */
  height: auto;
  min-height: 0;
  padding: 0.75rem;
  border-color: rgba(22, 22, 27, 0.3);
  border-radius: 0.8rem;
  background-color: transparent;
  background-image: none;
  font-size: 0.66rem;
  line-height: 1.45;
  color: rgba(22, 22, 27, 0.62);
}
.tcard [data-asset].is-missing .asset-missing code { color: rgba(22, 22, 27, 0.82); }

/* The page ends on the cards. There is no CTA row: the header carries both the
   nav and "Get a free ad", so a second set of buttons underneath was repeating
   what is already one scroll away. */

@media (max-width: 860px) {
  .teamgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 32rem; }
  .team__ring--r, .team__blob--r { display: none; }
}
@media (max-width: 560px) {
  .teamgrid { grid-template-columns: minmax(0, 1fr); max-width: 19rem; }
  /* There is no margin left to decorate at this width — these start crossing
     the heading instead of framing it. */
  .team__spark--l,
  .team__dots--tl,
  .team__blob--tl,
  .team__ring--tr { display: none; }
}


/* ============================================================================
   14. MISSING-ASSET FALLBACK
   Personal and client media is deliberately not committed (see .gitignore), so
   a fresh clone shows a labelled slot instead of a broken image icon.
   site.js adds .is-missing when an <img> inside [data-asset] fails to load.
   ============================================================================ */

.asset-missing { display: none; }

[data-asset].is-missing img { display: none; }

[data-asset].is-missing .asset-missing {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 0.5rem;
  height: 100%;
  min-height: 12rem;
  padding: 1.5rem;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  /* Opaque and above the hero decoration, or the instruction sits unreadable
     behind the yellow disc. */
  position: relative;
  z-index: 1;
  background-color: var(--page);
  background-image: repeating-linear-gradient(135deg, rgba(22,22,27,0.02) 0 0.5rem, transparent 0.5rem 1rem);
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 500;
  line-height: 1.5;
  text-align: center;
  color: var(--muted);
}
[data-asset].is-missing .asset-missing code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  color: var(--ink);
}
.reelcard__media [data-asset] { height: 100%; }


/* ============================================================================
   15. MOTION
   Only transform / opacity animate, so nothing triggers layout or paint.
   ============================================================================ */

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes float {
  0%, 100% { transform: translateY(-0.4rem); }
  50%      { transform: translateY(0.4rem); }
}

/* Animates the `scale` property, not `transform`. The glow is centred with the
   `translate` property, and the two compose — a `transform: translate(-50%…)`
   here would stack on top of that and shift the glow a full width off-centre. */
@keyframes breathe {
  0%, 100% { opacity: 0.75; scale: 1; }
  50%      { opacity: 1;    scale: 1.06; }
}

@keyframes twinkle {
  0%, 100% { opacity: 0.35; transform: rotate(0deg) scale(0.85); }
  50%      { opacity: 1;    transform: rotate(45deg) scale(1); }
}


/* --- Lenis ------------------------------------------------------------------
   From the library's own stylesheet, trimmed to the rules this site can reach.
   `height: auto` is the load-bearing one: Lenis measures the document, and a
   height set on html or body would give it the viewport instead of the page.
   -------------------------------------------------------------------------- */
html.lenis,
html.lenis body { height: auto; }

.lenis.lenis-stopped { overflow: clip; }

.lenis.lenis-smooth iframe { pointer-events: none; }

/* --- Hero parallax ---------------------------------------------------------
   site.js writes one value, --py, onto .hero: the scroll distance in px, capped
   at the hero's own height. Every depth factor lives here so the whole effect is
   tuned in one place.

   Read the factors as distance from the viewer. Page content scrolls at 1.0.
   Anything below 1.0 lags behind and reads as further away; the portrait is
   NEGATIVE, so it drifts up faster than the page and reads as nearest — that is
   what sells it as a cut-out floating above the composition.

     backdrop plate  0.16   furthest
     bokeh lights    0.30
     warm glow       0.10
     disc + rings    0.12
     portrait       -0.07   nearest

   Transforms compose with the `translate` / `scale` / `rotate` properties these
   elements already use, so those are left untouched.
   -------------------------------------------------------------------------- */

.hero { --py: 0px; }

.hero::before      { transform: translate3d(0, calc(var(--py) *  0.16), 0); }
.hero__lights      { transform: translate3d(0, calc(var(--py) *  0.30), 0); }
.hero__glow        { transform: translate3d(0, calc(var(--py) *  0.10), 0); }
.portrait__disc,
.portrait__orbit   { transform: translate3d(0, calc(var(--py) *  0.12), 0); }
.portrait__img     { transform: translate3d(0, calc(var(--py) * -0.07), 0); }

/* Promote only while the hero is actually on screen — site.js adds this. Keeping
   will-change on permanently would hold five extra compositor layers for the
   whole page, including the drop-shadowed portrait. */
.hero.is-parallax .hero__lights,
.hero.is-parallax .hero__glow,
.hero.is-parallax .portrait__disc,
.hero.is-parallax .portrait__orbit,
.hero.is-parallax .portrait__img { will-change: transform; }

/* --- Motion system ---------------------------------------------------------
   Three named entrances, each with a job. Not one generic reveal reused on
   every section — that reads as a page that animates because it can.

     deal   the focal moment. Six ad slots arrive in sequence, wiping up from
            their own bottom edge like creative being dealt out. The pitch is
            volume and cadence, so the work grid is the thing worth authoring.
     wipe   the typographic signature on section titles. One consistent gesture,
            used in exactly one role.
     rise   quiet support. Short travel, short duration, no ceremony.

   All three start from the element's resting state and are applied by adding
   .is-in, so nothing is hidden if the script fails. Delays come from --d.
   -------------------------------------------------------------------------- */

.js-anim [data-anim] { opacity: 0; }
.js-anim [data-anim].is-in { opacity: 1; }

/* NOTE ON MATERIAL. An earlier version wiped these in with clip-path. It was
   dropped deliberately: clip-path's animated value did not resolve in either
   verification environment, and a stalled clip leaves the element *permanently
   invisible* — the worst failure mode on a page whose job is conversion. Blur
   and transform degrade benignly (blurry-but-readable, or simply in place), so
   the character is carried by those instead. Do not reintroduce a property that
   can hide content if its transition never completes. */

/* deal — the focal moment. Slots lift and settle in sequence, each landing from
   a slightly different tilt, like creative being dealt onto a table. */
.js-anim [data-anim="deal"] {
  transform: translateY(2.25rem) scale(0.94) rotate(-1.5deg);
}
.js-anim [data-anim="deal"]:nth-child(even) { transform: translateY(2.25rem) scale(0.94) rotate(1.5deg); }
.js-anim [data-anim="deal"].is-in,
.js-anim [data-anim="deal"]:nth-child(even).is-in {
  transform: none;
  transition: transform 0.66s var(--ease-expo) var(--d, 0ms),
              opacity   0.36s linear           var(--d, 0ms);
}

/* wipe — the signature on section titles: resolves out of a soft blur, which
   reads as the headline coming into focus rather than sliding around. */
.js-anim [data-anim="wipe"] {
  transform: translateY(0.9rem);
  filter: blur(7px);
}
.js-anim [data-anim="wipe"].is-in {
  transform: none;
  filter: blur(0);
  transition: transform 0.7s var(--ease-expo) var(--d, 0ms),
              filter    0.7s var(--ease-expo) var(--d, 0ms),
              opacity   0.45s linear          var(--d, 0ms);
}

/* lines — the first thing a visitor sees resolve. Each authored line of the
   headline hides its own text and lets it rise back into place, one after the
   next. It is the one place on the site with a text-level entrance: doing this
   to every heading would turn a considered opening into a tic.

   The line hides the text, so the h1 itself must NOT also fade. Overriding the
   shared opacity rule keeps the reveal to one gesture instead of a fade and a
   rise fighting each other. */
.js-anim [data-anim="lines"] { opacity: 1; }
.hero__title .titleline {
  display: block;
  overflow: hidden;
  /* Uppercase has no descenders, but the face still overshoots its baseline
     slightly; the padding keeps that from being clipped and the negative margin
     gives the space back so line-height is unchanged. */
  padding-bottom: 0.06em;
  margin-bottom: -0.06em;
}
.js-anim [data-anim="lines"] .titleline > span {
  display: block;
  transform: translateY(105%);
}
.js-anim [data-anim="lines"].is-in .titleline > span {
  transform: none;
  transition: transform 0.72s var(--ease-expo) var(--ld, 0ms);
}
.js-anim [data-anim="lines"].is-in .titleline:nth-child(1) > span { --ld: calc(var(--d, 0ms) + 0ms); }
.js-anim [data-anim="lines"].is-in .titleline:nth-child(2) > span { --ld: calc(var(--d, 0ms) + 70ms); }
.js-anim [data-anim="lines"].is-in .titleline:nth-child(3) > span { --ld: calc(var(--d, 0ms) + 140ms); }

/* rise — supporting copy and cards. */
.js-anim [data-anim="rise"] {
  transform: translateY(0.85rem);
}
.js-anim [data-anim="rise"].is-in {
  transform: none;
  transition: transform 0.55s var(--ease-expo) var(--d, 0ms),
              opacity   0.4s  linear          var(--d, 0ms);
}

/* step — the team page's focal moment. The card arrives first and the portrait
   inside settles a beat later and from further down, so the person reads as
   stepping forward out of the yellow rather than the whole card sliding. That
   two-part offset is the entire idea; flattening it into one move loses it.

   The photo is the only thing that moves inside, so the gradient, the label and
   the sparkle stay put and the card never looks like it is assembling itself. */
.js-anim [data-anim="step"] {
  transform: translateY(2rem) scale(0.97);
}
.js-anim [data-anim="step"] .tcard__photo {
  transform: translateY(1.6rem);
  opacity: 0;
}
.js-anim [data-anim="step"].is-in {
  transform: none;
  transition: transform 0.7s var(--ease-expo) var(--d, 0ms),
              opacity   0.4s linear           var(--d, 0ms);
}
.js-anim [data-anim="step"].is-in .tcard__photo {
  transform: none;
  opacity: 1;
  transition: transform 0.8s var(--ease-expo) calc(var(--d, 0ms) + 120ms),
              opacity   0.5s linear           calc(var(--d, 0ms) + 120ms);
}

/* column — the FAQ page. The three groups are columns, so they arrive as
   columns: one gesture per group, not twenty-two rows each announcing itself.
   Short travel, because the rows carry no ceremony of their own. */
.js-anim [data-anim="column"] {
  transform: translateY(1.1rem);
}
.js-anim [data-anim="column"].is-in {
  transform: none;
  transition: transform 0.6s var(--ease-expo) var(--d, 0ms),
              opacity   0.4s linear           var(--d, 0ms);
}

/* land — the 404. The digits and the robot drop onto the line together and the
   robot keeps its idle loop afterwards, so the page arrives already alive. */
.js-anim [data-anim="land"] {
  transform: translateY(-1.4rem) scale(0.96);
}
.js-anim [data-anim="land"].is-in {
  transform: none;
  transition: transform 0.75s var(--ease-expo) var(--d, 0ms),
              opacity   0.45s linear           var(--d, 0ms);
}

/* Group stagger. Capped at six steps so a total sequence never exceeds ~360ms —
   past that a stagger stops reading as rhythm and starts reading as waiting. */
[data-stagger] > :nth-child(1) { --d: 0ms; }
[data-stagger] > :nth-child(2) { --d: 60ms; }
[data-stagger] > :nth-child(3) { --d: 120ms; }
[data-stagger] > :nth-child(4) { --d: 180ms; }
[data-stagger] > :nth-child(5) { --d: 240ms; }
[data-stagger] > :nth-child(n+6) { --d: 300ms; }

/* Looping decoration is paused whenever the hero is off screen. site.js toggles
   .is-parallax from the hero's observer, so this rides along with it. */
.hero:not(.is-parallax) .hero__glow,
.hero:not(.is-parallax) .hero__sparkle,
.hero:not(.is-parallax) .reelcard,
.hero:not(.is-parallax) .orbit { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .js-anim [data-anim] { opacity: 1; transform: none; filter: none; }
  /* The "step" entrance also hides a CHILD, the portrait. The rule above only
     resets the [data-anim] element itself, so without this the cards render
     with no photo in them — content lost outright, not merely un-animated.
     Any future entrance that hides a descendant has to be added here too. */
  .js-anim [data-anim="step"] .tcard__photo { opacity: 1; transform: none; }
  .js-anim [data-anim="lines"] .titleline > span { transform: none; }
  .btn:hover, .card:hover { transform: none; }
  .btn:hover .btn__icon svg,
  .btn:hover .btn__icon.btn__icon--phone svg,
  .btn:hover .btn__icon.btn__icon--play svg,
  .btn:hover .btn__icon--play::after,
  .announce__cta:hover .announce__phone { animation: none; }
  /* Not merely sped up: the global rule above would snap the track to its end
     frame. Stop it where it stands instead. */
  .marquee__track { animation: none; }
  /* site.js already skips the scroll listener here; this guarantees the layers
     sit at their resting position even if --py were set some other way. */
  .hero { --py: 0px !important; }
}


/* ============================================================================
   16. RESPONSIVE
   Only two real breakpoints, because the root scale already handles size:
     <= 1320px  tighten the gutters and nav spacing
     <= 1149px  stack the hero, switch to the drawer nav
   1149px is set by the headline, not by a device — see .hero__title.
   ============================================================================ */

/* Laptop: tighten spacing before the nav starts to crowd */
@media (max-width: 1320px) {
  :root { --gutter: 2.5rem; }
  .nav__list { gap: 1.5rem; }
}

/* Tablet and below: single column hero, portrait leads */
@media (max-width: 1149px) {
  :root { --gutter: 1.5rem; }

  .nav, .header__cta { display: none; }
  .nav-toggle { display: grid; }

  .section { padding: 4.5rem 0; }
  .section__title { font-size: 2.4rem; }

  .hero { padding-top: 2rem; }
  .hero__grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .hero__pitch { padding-top: 0.5rem; order: 1; }
  .hero__portrait { order: 2; align-self: auto; max-width: 26rem; margin-inline: auto; }
  .hero__sample { order: 3; padding-top: 0; max-width: 26rem; }
  .hero__title { font-size: 2.85rem; }
  .hero__dots, .hero__sparkle { display: none; }
  .portrait__disc { width: 62%; }

  .work-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cards     { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .steps     { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.25rem 1.5rem; }
  .plans     { grid-template-columns: 1fr; }

  /* Client panel moves above the quote so the face is seen before the words. */
  .tcarousel { grid-template-columns: 1fr; }
  .tcarousel__aside { order: -1; padding: 1.75rem 1.5rem; }
  .tclient { flex-direction: row; gap: 1rem; text-align: left; }
  .tclient__logo { max-width: 9rem; }
  .tclient__face { width: 4rem; height: 4rem; }
  .about { grid-template-columns: 1fr; gap: 2.5rem; }
  .about__slot { margin-left: 0; }
  .cta__title { font-size: 2.4rem; }
  .footer__copy { margin-left: 0; }
}

/* Phone */
@media (max-width: 560px) {
  /* Single column here, so tie the headline to the viewport: the authored line
     breaks then hold on a 320px phone as well as a 560px one, without a
     separate breakpoint per device. */
  .hero__title { font-size: clamp(1.6rem, 8.2vw, 2.3rem); }
  .section__title, .cta__title { font-size: clamp(1.5rem, 7.2vw, 2rem); }
  .hero__actions .btn, .cta__actions .btn { flex: 1 1 100%; }
  .work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cards, .steps { grid-template-columns: 1fr; }
  .plan { padding: 1.75rem 1.5rem; }
}
