/* ==========================================================
   ORBITAL — Hero scroll experience
   ========================================================== */

:root {
  --bg: #000000;
  --fg: #ffffff;
  --fg-soft: rgba(255, 255, 255, 0.72);
  --fg-faint: rgba(255, 255, 255, 0.45);

  /* Brand gradient — orange → yellow, tuned for legibility on dark sky */
  --grad-start: #ff7a18;
  --grad-mid:   #ffae3b;
  --grad-end:   #ffd86b;

  /* Apple-style system font stack with Inter as fallback for non-Apple OSes */
  --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro", "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-body:    -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --ease-out:    cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

html {
  /* Smooth physical scroll on touch devices; we don't use scroll-behavior:smooth
     because that fights our scrub. */
  background: var(--bg);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--fg);
  /* Prevent horizontal jitter from any subpixel transforms */
  overflow-x: hidden;
}

/* ----------------------------------------------------------
   NAV
   ---------------------------------------------------------- */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  padding: 18px 0;
  /* Glass blur — only kicks in once content is behind it */
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  background: linear-gradient(to bottom, rgba(0,0,0,0.45), rgba(0,0,0,0));
}

.nav__inner {
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.nav__brand {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.01em;
  color: var(--fg);
  text-decoration: none;
}

.nav__links {
  display: flex;
  gap: 28px;
}
.nav__links a {
  font-size: 14px;
  font-weight: 400;
  color: var(--fg-soft);
  text-decoration: none;
  transition: color 220ms var(--ease-out);
}
.nav__links a:hover { color: var(--fg); }

@media (max-width: 640px) {
  .nav__links { display: none; }
}

/* ----------------------------------------------------------
   HERO — sticky, scroll-driven scrub
   ---------------------------------------------------------- */
.hero {
  /* Scroll runway. 440vh gives us four distinct beats:
     primary headline → caption → finale letter-reveal → bento stats.
     Tweak this to slow / speed up the whole sequence. */
  position: relative;
  height: 440vh;
  background: #000;
}

.hero__stage {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  /* iOS Safari needs the dynamic viewport unit so the address bar
     hide/show doesn't cause layout shifts. */
  height: 100dvh;
  overflow: hidden;
  background: #000;
}

/* Poster image: visible IMMEDIATELY on load (no flash, no fade-in).
   Once the video has decoded its first frame, JS sets
   `data-video-ready` on .hero__stage and we crossfade the poster out. */
.hero__poster,
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* Promote to its own layer so paints don't trigger reflows. */
  will-change: opacity;
  transform: translateZ(0);
}

.hero__poster {
  z-index: 1;
  opacity: 1;
  transition: opacity 280ms var(--ease-out);
}

.hero__video {
  z-index: 2;
  opacity: 0; /* hidden until decoded */
  transition: opacity 280ms var(--ease-out);
  pointer-events: none; /* never let it accept clicks */
}

/* Once the video is ready, swap them. Both layers stay mounted so
   there is never a single frame of black between them. */
.hero__stage[data-video-ready="true"] .hero__video  { opacity: 1; }
.hero__stage[data-video-ready="true"] .hero__poster { opacity: 0; }

/* Cinematic vignette */
.hero__vignette {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.55) 100%),
    linear-gradient(to bottom, rgba(0,0,0,0.25), rgba(0,0,0,0) 25%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.55));
}

/* ----------------------------------------------------------
   HERO COPY — centered, clean, gradient
   ---------------------------------------------------------- */
.hero__copy {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 24px;
  /* Move the lockup up a touch so it sits visually centered with
     the scroll hint at the bottom. */
  padding-bottom: 6vh;
  /* Animated by JS — not by CSS scroll listeners. */
  will-change: opacity, transform;
  transform: translate3d(0, 0, 0);
}

.hero__eyebrow {
  /* Rounded pill chip — matches the case-study category chips for
     visual consistency across "chapter" markers throughout the site. */
  display: inline-block;
  font-family: var(--font-display);
  margin: 0 0 22px;
  padding: 7px 16px;
  font-size: 11px;
  letter-spacing: 0.28em;
  font-weight: 600;
  color: #ffb27a;
  text-transform: uppercase;
  background: rgba(255, 122, 24, 0.10);
  border: 1px solid rgba(255, 165, 75, 0.30);
  border-radius: 999px;
  line-height: 1.2;
  /* Subtle warm glow ties it to the brand gradient palette. */
  box-shadow: 0 0 24px rgba(255, 122, 24, 0.15);
}

.hero__title {
  font-family: var(--font-display);
  margin: 0;
  /* Responsive type — clamp keeps it readable from 320px to 4K. */
  font-size: clamp(44px, 8.4vw, 132px);
  line-height: 0.98;
  letter-spacing: -0.035em;
  font-weight: 700;
  color: var(--fg);
  /* Never break words across lines. The line breaks here are
     anyway controlled manually via .hero__line, but these rules
     ensure no auto-hyphenation or mid-word wrap can sneak in. */
  hyphens: none;
  -webkit-hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
  text-wrap: balance;
}

.hero__line {
  display: block;
}

/* The gradient highlight: orange → yellow.
   We give it a fallback color (orange) so even in browsers that
   somehow miss background-clip, the word is still visible. */
.hero__gradient {
  background: linear-gradient(
    100deg,
    var(--grad-start) 0%,
    var(--grad-mid) 45%,
    var(--grad-end) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: var(--grad-start); /* fallback */
  /* Subtle inner glow via filter for a luminous feel */
  filter: drop-shadow(0 0 22px rgba(255, 150, 50, 0.18));
}

.hero__sub {
  font-family: var(--font-body);
  margin: 28px 0 0;
  font-size: clamp(14px, 1.35vw, 18px);
  line-height: 1.55;
  font-weight: 400;
  color: var(--fg-soft);
  max-width: 560px;
  letter-spacing: -0.005em;
}

/* Scroll hint at the bottom of the hero */
.hero__scrollhint {
  position: absolute;
  bottom: max(28px, env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.hero__scrollline {
  width: 1px;
  height: 36px;
  background: linear-gradient(to bottom, var(--fg-faint), transparent);
  animation: scrollLineDrop 2.4s var(--ease-in-out) infinite;
  transform-origin: top center;
}
@keyframes scrollLineDrop {
  0%   { transform: scaleY(0);   opacity: 0; }
  30%  { transform: scaleY(1);   opacity: 1; }
  70%  { transform: scaleY(1);   opacity: 1; }
  100% { transform: scaleY(0) translateY(36px); opacity: 0; }
}

@media (max-width: 640px) {
  .hero__eyebrow { font-size: 10px; letter-spacing: 0.28em; margin-bottom: 16px; }
  .hero__sub     { margin-top: 20px; padding: 0 8px; }
  .hero__copy    { padding-bottom: 12vh; }
}

/* ----------------------------------------------------------
   HERO CAPTION — bottom-left, fades in partway through scrub
   ---------------------------------------------------------- */
.hero__caption {
  position: absolute;
  z-index: 4;
  /* Bottom-left, generous gutter. Use safe-area for notched devices. */
  left: max(40px, env(safe-area-inset-left));
  bottom: max(56px, calc(env(safe-area-inset-bottom) + 56px));
  max-width: min(520px, 44vw);
  text-align: left;
  /* Hidden by default — JS will reveal it across the scroll window. */
  opacity: 0;
  transform: translate3d(0, 16px, 0);
  will-change: opacity, transform;
  pointer-events: none;
}

.hero__caption-eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  margin: 0 0 14px;
  padding: 6px 14px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: #ffb27a;
  background: rgba(255, 122, 24, 0.10);
  border: 1px solid rgba(255, 165, 75, 0.30);
  border-radius: 999px;
  line-height: 1.2;
  box-shadow: 0 0 24px rgba(255, 122, 24, 0.15);
}

.hero__caption-title {
  font-family: var(--font-display);
  margin: 0 0 14px;
  /* Smaller than the primary headline so it functions as a caption,
     not a competing title. Still sized for impact at desktop scale. */
  font-size: clamp(28px, 3.6vw, 56px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  font-weight: 600;
  color: var(--fg);
  hyphens: none;
  -webkit-hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
  text-wrap: balance;
}

.hero__caption-sub {
  font-family: var(--font-body);
  margin: 0;
  font-size: clamp(13px, 1.05vw, 16px);
  line-height: 1.55;
  font-weight: 400;
  color: var(--fg-soft);
  letter-spacing: -0.005em;
  max-width: 420px;
}

@media (max-width: 768px) {
  .hero__caption {
    left: 24px;
    right: 24px;
    bottom: max(80px, calc(env(safe-area-inset-bottom) + 80px));
    max-width: none;
  }
  .hero__caption-eyebrow { font-size: 10px; letter-spacing: 0.28em; margin-bottom: 10px; }
  .hero__caption-title   { font-size: clamp(24px, 7vw, 36px); }
  .hero__caption-sub     { font-size: 13px; }
}

/* ----------------------------------------------------------
   HERO FINALE — centered title + bento stats
   ----------------------------------------------------------
   Each character of the title is wrapped in a .hero__char span by
   JS at init. The rAF loop sets a CSS custom property on each one
   to control its individual reveal state. The bento grid below
   fades in after the title finishes revealing.
   ---------------------------------------------------------- */
.hero__finale {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(28px, 4vw, 56px);
  padding: 0 32px;
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
}

.hero__finale-title {
  font-family: var(--font-display);
  margin: 0;
  text-align: center;
  /* Slightly smaller than the original single-line treatment so a
     longer phrase fits cleanly on 1–2 lines without dominating. */
  font-size: clamp(34px, 6.4vw, 96px);
  line-height: 1.04;
  letter-spacing: -0.035em;
  font-weight: 700;
  color: var(--fg);
  max-width: 18ch;
  text-wrap: balance;
  /* Never split a word across lines, never auto-hyphenate. */
  hyphens: none;
  -webkit-hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
}

/* Per-word wrapper for the finale: keeps all .hero__char inline-blocks
   inside one word from breaking across lines. The whole word either
   fits on the current line or moves to the next, never splits. */
.hero__word {
  display: inline-block;
  white-space: nowrap;
}

/* Each letter is a span; we control its opacity directly via a
   custom property so we never trigger a style recalc cascade. */
.hero__char {
  display: inline-block;
  opacity: var(--char-opacity, 0);
  /* Warm glow on the leading edge — peaks mid-reveal, fades to 0
     once the letter is fully resolved. */
  text-shadow:
    0 0 calc(var(--char-glow, 0) * 24px)
    rgba(255, 170, 70, calc(var(--char-glow, 0) * 0.55));
  transform: translateY(calc((1 - var(--char-opacity, 0)) * 6px));
  will-change: opacity, transform;
}

.hero__space {
  display: inline-block;
  width: 0.28em;
}

/* ----------------------------------------------------------
   BENTO STATS — marketing agency metrics
   ----------------------------------------------------------
   Subtle dark cards with a single-edge orange→yellow gradient
   border on either the top OR left edge (alternating per card)
   for an asymmetric, premium accent. Fade in en masse after the
   letter reveal completes; the value numbers count up at the
   same time.
   ---------------------------------------------------------- */
.hero__bento {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  width: 100%;
  max-width: 1080px;
  /* Group fade controlled by JS via opacity. Cards stagger via
     a shared --bento-progress variable. */
  opacity: 0;
  will-change: opacity;
}

.bento {
  position: relative;
  /* Glassy translucent fill to sit nicely over video without
     blocking it. backdrop-filter adds the actual blur where supported. */
  background: linear-gradient(
    180deg,
    rgba(20, 18, 24, 0.55),
    rgba(12, 10, 14, 0.65)
  );
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-radius: 14px;
  padding: 26px 28px 28px;
  text-align: left;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    0 18px 40px rgba(0, 0, 0, 0.35);
  /* Per-card local progress (0..1) is computed and clamped in JS,
     then set as --bento-local. Reveal uses opacity + translateY. */
  --bento-local: 0;
  opacity: var(--bento-local);
  transform: translate3d(0, calc((1 - var(--bento-local)) * 12px), 0);
  will-change: opacity, transform;
}

/* Single-edge gradient accent — TOP edge variant.
   We use a ::before instead of border-image because gradient
   border-image gets pixelated on rounded corners in Safari. A
   precisely-placed slab is sharper and renders the same everywhere. */
.bento--edge-top::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1.5px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--grad-start) 18%,
    var(--grad-mid) 50%,
    var(--grad-end) 82%,
    transparent 100%
  );
  border-radius: 14px 14px 0 0;
  /* Soft glow tying the accent to the warm palette without
     overpowering the text. */
  box-shadow: 0 0 18px rgba(255, 150, 50, 0.35);
}

.bento--edge-left::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 1.5px;
  background: linear-gradient(
    180deg,
    transparent 0%,
    var(--grad-start) 18%,
    var(--grad-mid) 50%,
    var(--grad-end) 82%,
    transparent 100%
  );
  border-radius: 14px 0 0 14px;
  box-shadow: 0 0 18px rgba(255, 150, 50, 0.35);
}

.bento__value {
  font-family: var(--font-display);
  margin: 0 0 14px;
  font-size: clamp(36px, 4vw, 56px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--fg);
  display: flex;
  align-items: baseline;
  gap: 2px;
}
.bento__num {
  /* Tabular numbers prevent layout jitter while counting up. */
  font-variant-numeric: tabular-nums;
}
.bento__unit {
  font-size: 0.7em;
  font-weight: 600;
  /* Subtle gradient on the unit symbol to echo the edge accent. */
  background: linear-gradient(100deg, var(--grad-start), var(--grad-end));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: var(--grad-start);
  margin-left: 2px;
}

.bento__label {
  font-family: var(--font-display);
  margin: 0 0 10px;
  font-size: clamp(20px, 1.85vw, 26px);
  font-weight: 600;
  color: var(--fg);
  letter-spacing: -0.018em;
  line-height: 1.22;
}

.bento__sub {
  margin: 0;
  font-size: 17px;
  font-weight: 400;
  color: var(--fg-soft);
  letter-spacing: -0.005em;
  line-height: 1.55;
}

@media (max-width: 900px) {
  .hero__bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 768px) {
  .hero__finale-title {
    font-size: clamp(28px, 7.6vw, 48px);
    letter-spacing: -0.025em;
    max-width: 18ch;
  }
  .hero__bento { gap: 12px; }
  .bento { padding: 22px 20px 24px; border-radius: 12px; }
  .bento__value { font-size: clamp(32px, 8.5vw, 44px); margin-bottom: 12px; }
  .bento__label { font-size: 18px; margin-bottom: 8px; }
  .bento__sub { font-size: 15px; line-height: 1.5; }
}

@media (max-width: 480px) {
  .hero__bento { grid-template-columns: 1fr 1fr; }
}

/* ==========================================================
   SCENE 2 — pitch-black fade-in, then scrubbing video
   ==========================================================
   Architecture mirrors .hero: a tall .scene2 (scroll runway)
   contains a sticky .scene2__stage. The stage's opacity is
   driven from 0 → 1 across the first slice of its scroll, then
   the video begins scrubbing for the remainder. A centered
   heading reveals letter-by-letter, with horizontal translation
   keeping the active letter at the viewport center.
   ========================================================== */
.scene2 {
  position: relative;
  /* Scroll runway. 360vh gives us:
     - 100vh of approach (above sticky pin) where the stage fades in
     - 260vh of sticky scrub for the video + letter reveal
     The fade-in happens during approach so the entire sticky range
     is available for scrubbing — no opacity work eating into motion. */
  height: 360vh;
  background: #000;
}

.scene2__stage {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: #000;
  /* JS drives this from 0 → 1 across the fade-in window. */
  opacity: 0;
  will-change: opacity;
}

.scene2__poster,
.scene2__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  will-change: opacity;
  transform: translateZ(0);
}

.scene2__poster { z-index: 1; opacity: 1; transition: opacity 220ms var(--ease-out); }
.scene2__video  { z-index: 2; opacity: 0; transition: opacity 220ms var(--ease-out); pointer-events: none; }

.scene2__stage[data-video-ready="true"] .scene2__video  { opacity: 1; }
.scene2__stage[data-video-ready="true"] .scene2__poster { opacity: 0; }

.scene2__vignette {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% 50%, rgba(0,0,0,0) 35%, rgba(0,0,0,0.55) 100%);
}

/* Edge-fade overlay: pure black at the very top and bottom of the
   stage, fading to transparent through the middle. Hides the seam
   where the video meets the surrounding page-black. The transparent
   band covers the middle ~76% so the headline and planet are never
   dimmed; only the empty top/bottom bands get the wash. */
.scene2__edgefade {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    #000 0%,
    rgba(0,0,0,0.92) 3%,
    rgba(0,0,0,0) 12%,
    rgba(0,0,0,0) 88%,
    rgba(0,0,0,0.92) 97%,
    #000 100%
  );
}

/* ----- Heading layout -----
   The mask is a 100vw-wide container at the viewport center. The
   track inside it is a single nowrap line we translate horizontally.
   When the active letter is "letter N", JS translates the track so
   that letter N's center sits at the mask's center — which is the
   viewport's center. The first letter (N=0) is therefore dead-
   center on its own, and as more letters reveal, the track slides
   leftward to keep the head centered.

   The mask has no clipping so letters off to the right just sit
   off-screen until they reveal. We let them be invisible via the
   per-letter --char-opacity. */
.scene2__copy {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  pointer-events: none;
  padding: 0 24px;
}

/* ==========================================================
   CAPABILITIES — vertical-reveal bento section
   ==========================================================
   Sits AFTER scene 2 in normal flow. The scene 2 title is no
   longer sticky once the user scrolls into here. Cards still
   reveal with a head-sweep tied to scroll, but driven by this
   section's own progress (computed in JS).
   ========================================================== */
.capabilities {
  background: #000;
  /* The scene 2 stage is 100vh tall with the title vertically
     centered, leaving ~50vh of empty stage below the title. When
     sticky releases, that empty space would normally scroll past
     before anything else could appear — reading as a giant gap.
     We solve this in two parts:
       1. negative margin-top pulls the section UP geometrically
          so its content appears below the title with breathing
          room (NOT directly under it — overshooting upward makes
          the bento crowd or overlap the headline).
       2. translateY(--caps-lift) cancels the negative margin while
          scene 2 is still sticky, hiding the bento off-screen so
          it never enters the viewport during the scrub. JS animates
          --caps-lift back to 0 in the final stretch of scene 2's
          sticky range, just before unpin.
     The page background is solid black so the eventual overlap
     is purely a visual offset; nothing covers anything important. */
  margin-top: -28vh;
  --caps-lift: 28vh; /* default = fully hidden; JS animates to 0 */
  transform: translateY(var(--caps-lift));
  position: relative;
  z-index: 5; /* above scene 2's stage so the bento isn't hidden */
  padding: clamp(24px, 5vh, 56px) 24px clamp(80px, 14vh, 160px);
  will-change: transform;
}

.capabilities__inner {
  max-width: 760px;
  margin: 0 auto;
}

.scene2__bento {
  /* Stacked vertically so the reveal sweep is top-down (the vertical
     analog of the scene 2 headline's left-to-right letter reveal). */
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.capbox {
  position: relative;
  background: linear-gradient(
    180deg,
    rgba(20, 18, 24, 0.45),
    rgba(10, 8, 12, 0.65)
  );
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 14px;
  /* Horizontal layout inside each card: kicker on the left (small
     fixed-width column), title + body stacked on the right. Gives
     a tight, scannable rhythm when stacked. */
  display: grid;
  grid-template-columns: minmax(180px, 22%) 1fr;
  gap: 22px;
  align-items: start;
  padding: 18px 22px;
  text-align: left;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);
  /* Per-card reveal driven by JS — head-sweep math. */
  --capbox-opacity: 0;
  --capbox-glow: 0;
  opacity: var(--capbox-opacity);
  transform: translate3d(0, calc((1 - var(--capbox-opacity)) * 18px), 0);
  will-change: opacity, transform;
}

/* Warm glow ring on the leading-edge card while it reveals — the
   same trick the letter reveal uses, just at card scale. We draw
   it as a 1px gradient ring using a mask-composite trick so it
   only paints as an outline, not a fill. */
.capbox::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 17px;
  pointer-events: none;
  padding: 1px;
  background: linear-gradient(
    135deg,
    rgba(255, 122, 24, 0.7),
    rgba(255, 216, 107, 0.35)
  );
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: var(--capbox-glow, 0);
  transition: none;
}

.capbox__kicker {
  margin: 0;
  padding-top: 6px; /* nudge to align with title baseline */
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  background: linear-gradient(100deg, var(--grad-start), var(--grad-end));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: var(--grad-start);
  /* Allow wrapping for longer kicker labels like "Paid Media · Propulsion".
     White-space: normal + word-break: break-word handles all locales. */
  white-space: normal;
  word-break: break-word;
  line-height: 1.4;
}

.capbox__content { /* nothing structural — purely a grouping wrapper */ }

.capbox__title {
  font-family: var(--font-display);
  margin: 0 0 12px;
  font-size: clamp(20px, 1.85vw, 26px);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.018em;
  color: var(--fg);
  hyphens: none;
  -webkit-hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
  text-wrap: balance;
}

.capbox__body {
  margin: 0;
  font-size: clamp(16px, 1.3vw, 19px);
  line-height: 1.5;
  font-weight: 400;
  color: var(--fg-soft);
  letter-spacing: -0.005em;
}

.scene2__eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  margin: 0;
  padding: 7px 16px;
  font-size: 11px;
  letter-spacing: 0.28em;
  font-weight: 600;
  color: #ffb27a;
  text-transform: uppercase;
  background: rgba(255, 122, 24, 0.10);
  border: 1px solid rgba(255, 165, 75, 0.30);
  border-radius: 999px;
  line-height: 1.2;
  box-shadow: 0 0 24px rgba(255, 122, 24, 0.15);
  /* Eyebrow fades in alongside the stage but holds steady. */
}

.scene2__title-mask {
  width: 100%;
  /* Centerline of the mask = centerline of the viewport.
     The track inside is positioned absolutely so we can translate
     it freely without the parent flexbox re-centering it. */
  position: relative;
  height: clamp(56px, 11vw, 160px);
  overflow: visible;
}

.scene2__title-track {
  font-family: var(--font-display);
  margin: 0;
  /* CRITICAL: nowrap keeps the headline as a single horizontal line
     so we can translate it as one rigid unit. Without this, letters
     would wrap and the slide-left effect would break. */
  white-space: nowrap;
  font-size: clamp(40px, 7.6vw, 112px);
  line-height: 1;
  letter-spacing: -0.035em;
  font-weight: 700;
  color: var(--fg);
  /* Position the track so its translation origin is the horizontal
     center of the mask. We start with translateX(0) which means the
     element's own center sits at the parent center; JS then offsets
     it so the *active letter* is what's centered. */
  position: absolute;
  top: 50%;
  left: 50%;
  /* JS sets --track-offset (in pixels). The base translate centers
     the element by -50% horizontally; the variable adds the letter-
     specific offset on top. */
  --track-offset: 0px;
  transform: translate3d(calc(-50% + var(--track-offset)), -50%, 0);
  /* Hyphens / word-break protection per the previous fix. */
  hyphens: none;
  -webkit-hyphens: none;
  overflow-wrap: normal;
  word-break: normal;
  will-change: transform;
}

/* Per-letter spans inside the track. Same opacity / glow technique
   as the hero finale. */
.scene2__char {
  display: inline-block;
  opacity: var(--char-opacity, 0);
  text-shadow:
    0 0 calc(var(--char-glow, 0) * 26px)
    rgba(255, 170, 70, calc(var(--char-glow, 0) * 0.6));
  transform: translateY(calc((1 - var(--char-opacity, 0)) * 6px));
  will-change: opacity, transform;
}

/* Gradient-highlighted characters: orange→yellow text fill. We apply
   it per-character (rather than per-word) so the gradient still works
   while individual letters animate their opacity. The opacity is
   handled via the parent span's color/fill, NOT background-clip,
   because background-clip + opacity don't compose well. Instead we
   layer: the actual character is invisible (color: transparent), and
   a ::before draws the gradient version sized 1:1 with it. The simpler
   approach below uses background-clip and just relies on opacity on
   the *element* — which works fine because the element opacity scales
   the visible gradient text. */
.scene2__char--gradient {
  background: linear-gradient(
    100deg,
    var(--grad-start) 0%,
    var(--grad-mid) 45%,
    var(--grad-end) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: var(--grad-start); /* fallback */
  filter: drop-shadow(0 0 22px rgba(255, 150, 50, 0.18));
}

.scene2__space {
  display: inline-block;
  width: 0.28em;
}

@media (max-width: 768px) {
  .scene2__title-mask {
    /* On mobile we abandon the per-letter horizontal slide reveal
       (which requires nowrap) and let the headline wrap naturally
       across multiple lines. The mask becomes a content-sized
       container instead of a fixed-height single-line window.
       The per-line left→right reveal animation still runs — JS
       recomputes each letter's _pos within its visual line. */
    height: auto;
    width: auto;
    max-width: 100%;
    overflow: visible;
    text-align: center;
  }
  .scene2__title-track {
    /* Allow wrapping. Drop the absolute positioning + transform
       chain so the text just lays out as a normal centered block.
       JS still sets --track-offset on this element, but we override
       the transform here so the slide doesn't happen on mobile. */
    position: static;
    transform: none !important;
    white-space: normal;
    word-break: normal;
    overflow-wrap: break-word;
    text-align: center;
    font-size: clamp(28px, 7vw, 40px);
    line-height: 1.15;
    letter-spacing: -0.02em;
    /* Comfortable measure so each line breaks at a natural point. */
    max-width: 14ch;
    margin: 0 auto;
  }
  /* Per-letter spans: KEEP the JS-driven --char-opacity / --char-glow
     animation. We don't override opacity/transform here — that would
     kill the reveal entirely. The mobile-specific change happens in
     JS (measureScene2 recomputes _pos per visual line so each line
     reveals left→right in parallel). */
  .scene2__space {
    display: inline-block;
  }
  .scene2__eyebrow { font-size: 11px; letter-spacing: 0.28em; }

  /* Mobile spacing tuning — keep video full-width / full-bleed,
     just tighten the gap between eyebrow chip and headline. */
  .scene2__copy { gap: 18px; padding: 0 24px; }
}

@media (max-width: 480px) {
  .scene2__title-track {
    font-size: clamp(24px, 7.4vw, 32px);
    max-width: 12ch;
  }
  .scene2__eyebrow {
    font-size: 10px;
    padding: 6px 12px;
    letter-spacing: 0.24em;
  }
  .scene2__copy { gap: 14px; padding: 0 20px; }
}

@media (max-width: 720px) {
  .scene2__bento { gap: 10px; max-width: 480px; }
  .capbox {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 18px 18px 20px;
  }
  .capbox__kicker { padding-top: 0; font-size: 12px; }
  .capbox__title { font-size: 18px; margin-bottom: 8px; }
  .capbox__body  { font-size: 15px; line-height: 1.5; }
}

/* ==========================================================
   BRANDS — three rows of client logo wordmarks
   ==========================================================
   Sits as a separate section below scene 2. Fades in via
   IntersectionObserver once scrolled into view. Inline SVG
   wordmarks let us mix typographic styles across the rows
   while keeping the visual weight even.
   ========================================================== */
.brands {
  position: relative;
  background: #000;
  padding: clamp(80px, 12vh, 140px) 24px clamp(80px, 12vh, 140px);
  /* Subtle warm haze bleeding up from the previous scene */
  background:
    radial-gradient(70% 50% at 50% 0%, rgba(255, 122, 24, 0.05), rgba(0,0,0,0) 65%),
    #000;
}

.brands__inner {
  max-width: 1320px;
  margin: 0 auto;
  text-align: center;
}

.brands__kicker {
  margin: 0 0 56px;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--fg-faint);
}

.brands__grid {
  display: flex;
  flex-direction: column;
  gap: clamp(28px, 5vh, 56px);
}

.brands__row {
  display: flex;
  align-items: center;
  justify-content: space-around;
  flex-wrap: wrap;
  gap: clamp(16px, 2.5vw, 36px);
}

.brand {
  /* Each logo starts dimmed and de-saturated; coming in via group
     fade (set on .brands.is-visible). Hovering brings it to full. */
  color: rgba(255, 255, 255, 0.55);
  display: inline-flex;
  align-items: center;
  height: 36px;
  /* Per-logo stagger via inline custom property set in JS. */
  --brand-delay: 0ms;
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition:
    opacity 700ms var(--ease-out) var(--brand-delay),
    transform 700ms var(--ease-out) var(--brand-delay),
    color 220ms var(--ease-out);
}

.brand svg {
  height: 100%;
  width: auto;
  display: block;
}

.brand:hover {
  color: var(--fg);
}

/* Group reveal: when the section enters the viewport, the JS adds
   .is-visible to .brands; each .brand transitions in with its own
   stagger delay. */
.brands.is-visible .brand {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

@media (max-width: 720px) {
  .brands__row {
    gap: 28px;
  }
  .brand { height: 28px; }
}

@media (prefers-reduced-motion: reduce) {
  .brand {
    transition: opacity 200ms linear, color 220ms var(--ease-out);
    transform: none;
  }
}

/* ==========================================================
   CASE STUDIES — "From wave to outcome"
   ----------------------------------------------------------
   Plain, defensive CSS using a fresh `cs-` class prefix so
   nothing else on the page can possibly cascade in. Every
   important rule includes its own positioning + sizing
   without depending on inherited values.
   ========================================================== */
.cs-section {
  position: relative;
  display: block;
  width: 100%;
  background: #000;
  padding: 120px 24px;
  overflow: hidden;
  z-index: 1;
}

/* Top + bottom fade-to-black overlays so the section blends
   seamlessly into the brand strip above and scene 3 below — no
   visible seam where the orange glow meets neighbouring black. */
.cs-section::before,
.cs-section::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 220px;
  pointer-events: none;
  z-index: 3;
}
.cs-section::before {
  top: 0;
  background: linear-gradient(to bottom,
    #000 0%,
    rgba(0, 0, 0, 0.85) 35%,
    rgba(0, 0, 0, 0) 100%);
}
.cs-section::after {
  bottom: 0;
  background: linear-gradient(to top,
    #000 0%,
    rgba(0, 0, 0, 0.85) 35%,
    rgba(0, 0, 0, 0) 100%);
}

/* ---- Animated graph backdrop ---- */
.cs-bg {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  pointer-events: none;
  z-index: 0;
}
.cs-graph {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
  display: block;
  animation: cs-drift 22s ease-in-out infinite alternate;
}
@keyframes cs-drift {
  0%   { transform: translate3d(-1.5%, 0, 0); opacity: 0.85; }
  50%  { transform: translate3d( 1.5%, -0.6%, 0); opacity: 1; }
  100% { transform: translate3d(-1.5%, 0, 0); opacity: 0.85; }
}
.cs-curve {
  filter: drop-shadow(0 0 6px rgba(255, 150, 50, 0.45));
}
.cs-curve-soft {
  opacity: 0.5;
}

/* ---- Corner glows ---- */
.cs-glow {
  position: absolute;
  width: 600px;
  height: 600px;
  border-radius: 50%;
  filter: blur(80px);
  pointer-events: none;
}
.cs-glow-tl {
  top: -150px;
  left: -100px;
  background: radial-gradient(closest-side, rgba(255, 122, 24, 0.55), rgba(255, 122, 24, 0) 70%);
  opacity: 0.45;
  animation: cs-glow-a 14s ease-in-out infinite alternate;
}
.cs-glow-br {
  bottom: -180px;
  right: -120px;
  background: radial-gradient(closest-side, rgba(255, 184, 74, 0.40), rgba(255, 184, 74, 0) 70%);
  opacity: 0.4;
  animation: cs-glow-b 18s ease-in-out infinite alternate;
}
@keyframes cs-glow-a {
  0%   { transform: translate3d(0, 0, 0)  scale(1);    opacity: 0.35; }
  100% { transform: translate3d(40px, 30px, 0) scale(1.1); opacity: 0.55; }
}
@keyframes cs-glow-b {
  0%   { transform: translate3d(0, 0, 0)   scale(1);   opacity: 0.30; }
  100% { transform: translate3d(-30px, -40px, 0) scale(1.12); opacity: 0.50; }
}

/* ---- Section content (above graph) ---- */
.cs-inner {
  position: relative;
  z-index: 2;
  max-width: 1240px;
  margin: 0 auto;
  width: 100%;
}
.cs-head {
  display: block;
  text-align: center;
  margin: 0 0 72px 0;
}
.cs-title {
  font-family: var(--font-display);
  margin: 0 0 14px 0;
  font-size: 56px;
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-weight: 700;
  color: #ffffff;
}
.cs-sub {
  margin: 0;
  font-size: 18px;
  color: rgba(255, 255, 255, 0.72);
  letter-spacing: -0.005em;
  line-height: 1.5;
}

/* ---- Grid + cards ---- */
.cs-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
  width: 100%;
}
.cs-card {
  display: block;
  background: linear-gradient(180deg, rgba(20, 18, 24, 0.62), rgba(10, 8, 12, 0.78));
  -webkit-backdrop-filter: blur(16px) saturate(140%);
          backdrop-filter: blur(16px) saturate(140%);
  border-radius: 18px;
  padding: 40px;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    0 24px 60px rgba(0, 0, 0, 0.45);
  transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
.cs-card:hover {
  transform: translateY(-3px);
  box-shadow:
    inset 0 0 0 1px rgba(255, 165, 75, 0.20),
    0 30px 70px rgba(0, 0, 0, 0.5),
    0 0 60px rgba(255, 122, 24, 0.10);
}

.cs-chip {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(255, 122, 24, 0.10);
  border: 1px solid rgba(255, 165, 75, 0.30);
  color: #ffb27a;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  margin: 0 0 28px 0;
}
.cs-h {
  font-family: var(--font-display);
  margin: 0 0 16px 0;
  font-size: 28px;
  line-height: 1.18;
  letter-spacing: -0.022em;
  font-weight: 700;
  color: #ffffff;
}
.cs-body {
  margin: 0 0 32px 0;
  font-size: 17px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.72);
  letter-spacing: -0.005em;
  max-width: 56ch;
}
.cs-rule {
  display: block;
  width: 100%;
  height: 1px;
  margin: 0 0 24px 0;
  background: linear-gradient(to right,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.16) 22%,
    rgba(255, 255, 255, 0.16) 78%,
    rgba(255, 255, 255, 0) 100%);
  border: none;
}
.cs-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  width: 100%;
}
.cs-stat {
  display: block;
}
.cs-num {
  font-family: var(--font-display);
  margin: 0 0 6px 0;
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1;
  color: #ffffff;
  font-variant-numeric: tabular-nums;
}
.cs-unit {
  margin: 0;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  color: rgba(255, 255, 255, 0.45);
  text-transform: uppercase;
}

/* ---- Responsive ---- */
@media (max-width: 860px) {
  .cs-grid { grid-template-columns: 1fr; }
  .cs-title { font-size: 40px; }
}
@media (max-width: 560px) {
  .cs-section { padding: 64px 18px; }
  .cs-card { padding: 24px 22px; border-radius: 16px; }
  .cs-h { font-size: 22px; }
  .cs-body { font-size: 15px; }
  .cs-num { font-size: 24px; }
  .cs-unit { font-size: 10px; letter-spacing: 0.18em; }
  .cs-stats { gap: 14px; }
  .cs-head { margin-bottom: 48px; }
}

@media (prefers-reduced-motion: reduce) {
  .cs-graph, .cs-glow-tl, .cs-glow-br { animation: none; }
}

/* ==========================================================
   SCENE 3 — galaxy → moon zoom with CTA / form swap
   ==========================================================
   Same architecture as .scene2: tall scroll runway with a sticky
   inner stage. JS drives stage opacity 0 → 1 across the approach,
   then scrubs the video for the bulk of the sticky range, and
   swaps the centered CTA headline for the application form once
   the moon ground rises into the bottom half of the frame.
   ========================================================== */
.scene3 {
  position: relative;
  /* Scroll runway. Beats inside the sticky range:
     - 0.00 → 0.05  settle
     - 0.05 → 0.55  video scrubs galaxy → moon (CTA visible)
     - 0.45 → 0.70  CTA fades out, form fades in
     - 0.70 → 0.85  hold (form fully visible, video on last frame)
     - 0.85 → 1.00  form lifts up + fades out, footer rises in
     520vh gives the user enough scroll to feel each beat as a
     distinct moment without rushing. */
  height: 520vh;
  background: #000;
}

.scene3__stage {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: #000;
  /* JS drives this from 0 → 1 across the fade-in window. */
  opacity: 0;
  will-change: opacity;
}

.scene3__poster,
.scene3__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  will-change: opacity;
  transform: translateZ(0);
}

.scene3__poster { z-index: 1; opacity: 1; transition: opacity 220ms var(--ease-out); }
.scene3__video  { z-index: 2; opacity: 0; transition: opacity 220ms var(--ease-out); pointer-events: none; }

.scene3__stage[data-video-ready="true"] .scene3__video  { opacity: 1; }
.scene3__stage[data-video-ready="true"] .scene3__poster { opacity: 0; }

.scene3__vignette {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% 50%, rgba(0,0,0,0) 35%, rgba(0,0,0,0.55) 100%);
}

.scene3__edgefade {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    #000 0%,
    rgba(0,0,0,0.92) 3%,
    rgba(0,0,0,0) 12%,
    rgba(0,0,0,0) 88%,
    rgba(0,0,0,0.92) 97%,
    #000 100%
  );
}

/* ----- State A: centered CTA headline ----- */
.scene3__cta {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate3d(-50%, -50%, 0);
  z-index: 5;
  text-align: center;
  width: min(88vw, 720px);
  /* JS drives --cta-opacity from 1 → 0 as the form takes over. */
  opacity: var(--cta-opacity, 1);
  transition: opacity 280ms var(--ease-out);
  pointer-events: none;
  will-change: opacity, transform;
}

.scene3__eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  padding: 7px 16px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: #ffb27a;
  background: rgba(255, 122, 24, 0.10);
  border: 1px solid rgba(255, 165, 75, 0.30);
  border-radius: 999px;
  line-height: 1.2;
  margin: 0 0 20px;
  box-shadow: 0 0 24px rgba(255, 122, 24, 0.15);
}

.scene3__title {
  font-family: var(--font-display);
  font-size: clamp(40px, 7.6vw, 96px);
  line-height: 1.04;
  letter-spacing: -0.035em;
  font-weight: 700;
  color: var(--fg);
  margin: 0 0 18px;
  text-wrap: balance;
}

.scene3__gradient {
  background: linear-gradient(100deg, var(--grad-start), var(--grad-end));
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
          color: transparent;
}

.scene3__sub {
  font-size: clamp(15px, 1.3vw, 19px);
  line-height: 1.55;
  color: var(--fg-soft);
  max-width: 560px;
  margin: 0 auto;
}

/* ----- State B: application form ----- */
.scene3__form {
  position: absolute;
  top: 50%;
  left: 50%;
  /* Three transforms composed:
     1) center via -50% offsets
     2) small entry slide: form drops by 24px when --form-opacity is 0
        and lands at 0 when fully visible (handled implicitly via the
        --form-opacity term).
     3) --form-lift (JS-driven): pushes the form upward as the footer
        rises into frame, so the two slide past each other smoothly. */
  transform: translate3d(
    -50%,
    calc(-50% + (1 - var(--form-opacity, 0)) * 24px - var(--form-lift, 0px)),
    0
  );
  z-index: 6;
  width: min(92vw, 640px);
  /* Glass panel so the moon shows through subtly */
  padding: clamp(24px, 4vh, 36px) clamp(20px, 4vw, 36px);
  background: rgba(8, 10, 14, 0.55);
  backdrop-filter: blur(18px) saturate(1.2);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
  /* JS drives --form-opacity from 0 → 1 once the moon rises. */
  opacity: var(--form-opacity, 0);
  /* Don't intercept clicks until the form is mostly visible. */
  pointer-events: var(--form-pe, none);
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-out);
  will-change: opacity, transform;
}

.scene3__form-eyebrow {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0 0 8px;
}

.scene3__form-title {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.6vw, 30px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-weight: 700;
  color: var(--fg);
  margin: 0 0 22px;
}

.scene3__form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 14px;
}
@media (max-width: 560px) {
  .scene3__form-row { grid-template-columns: 1fr; }
}

.scene3__field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.scene3__field--full { margin-bottom: 18px; }

.scene3__field-label {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--fg-faint);
}

.scene3__field input,
.scene3__field select,
.scene3__field textarea {
  width: 100%;
  padding: 11px 14px;
  font-family: inherit;
  font-size: 14px;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  outline: none;
  transition: border-color 180ms var(--ease-out), background 180ms var(--ease-out);
  appearance: none;
  -webkit-appearance: none;
}
.scene3__field textarea {
  resize: vertical;
  min-height: 76px;
  font-family: inherit;
}
.scene3__field select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path fill='rgba(255,255,255,0.55)' d='M0 0l6 8 6-8z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  padding-right: 36px;
}
.scene3__field option {
  background: #0c0e12;
  color: var(--fg);
}
.scene3__field input::placeholder,
.scene3__field textarea::placeholder {
  color: rgba(255, 255, 255, 0.32);
}
.scene3__field input:focus,
.scene3__field select:focus,
.scene3__field textarea:focus {
  border-color: rgba(255, 165, 75, 0.55);
  background: rgba(255, 255, 255, 0.06);
}

.scene3__submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 26px;
  border: none;
  border-radius: 999px;
  background: linear-gradient(100deg, var(--grad-start), var(--grad-end));
  color: #1a0a00;
  font-family: inherit;
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: transform 220ms var(--ease-out), box-shadow 220ms var(--ease-out);
  box-shadow: 0 10px 40px rgba(255, 150, 50, 0.22);
  margin-top: 4px;
}
.scene3__submit:hover {
  transform: translateY(-2px);
  box-shadow: 0 16px 50px rgba(255, 150, 50, 0.34);
}

.scene3__form-fineprint {
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--fg-faint);
  letter-spacing: 0.01em;
}

@media (max-width: 720px) {
  .scene3__title { font-size: clamp(34px, 11vw, 56px); }
  .scene3__form { width: 92vw; padding: 20px 18px 22px; }
  .scene3__form-title { font-size: 22px; margin-bottom: 16px; }
}

/* ==========================================================
   SCENE 3 FOOTER — transparent overlay inside the moon stage
   ==========================================================
   The footer lives INSIDE .scene3__stage, positioned absolutely
   along the bottom edge. The video underneath is frozen on the
   moon end-frame at this point, so the footer's transparent
   background lets the actual moon surface and Earth glow show
   through — no separate moon image is involved.

   JS drives --footer-rise from 0 (parked just below the bottom
   of the viewport) to 1 (fully revealed) as the user scrolls
   past the form-shown state. The form itself is also lifted
   upward and faded out during the same window so the two move
   in sync — form goes up and out, footer comes up and in.
   ========================================================== */
.scene3__footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 7;
  pointer-events: var(--footer-pe, none);
  /* Translate down by (1 - rise) * 100% so we sit just out of
     view at rise=0, and at our natural bottom position at rise=1. */
  transform: translate3d(0, calc((1 - var(--footer-rise, 0)) * 100%), 0);
  opacity: var(--footer-rise, 0);
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-out);
  will-change: transform, opacity;
  /* Subtle dark wash at the very bottom so the copyright row
     stays legible against bright moon highlights, while keeping
     the menu area fully transparent. */
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 0.30) 55%,
    rgba(0, 0, 0, 0.78) 100%
  );
  padding: clamp(28px, 5vh, 64px) 24px 0;
  color: var(--fg);
}

.scene3__footer-inner {
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.3fr 2fr;
  gap: clamp(28px, 5vw, 80px);
  padding-bottom: clamp(20px, 3.5vh, 36px);
}

.scene3__footer-brandmark {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.4vw, 26px);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
  color: var(--fg);
}
.scene3__footer-tagline {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg-soft);
  max-width: 260px;
}

.scene3__footer-nav {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 3vw, 40px);
}

.scene3__footer-col {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.scene3__footer-col-title {
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0 0 4px;
}
.scene3__footer-col a {
  font-size: 13px;
  color: var(--fg-soft);
  text-decoration: none;
  letter-spacing: -0.005em;
  transition: color 200ms var(--ease-out);
  /* Slight text shadow to keep contrast against bright moon */
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55);
}
.scene3__footer-col a:hover { color: var(--fg); }
.scene3__footer-brandmark,
.scene3__footer-tagline,
.scene3__footer-col-title,
.scene3__footer-copyright {
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.65);
}

.scene3__footer-base {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding: 14px 0 18px;
  text-align: center;
}
.scene3__footer-copyright {
  margin: 0;
  font-size: 11px;
  color: var(--fg-faint);
  letter-spacing: 0.04em;
}

@media (max-width: 720px) {
  .scene3__footer { padding-top: 28px; }
  .scene3__footer-inner {
    grid-template-columns: 1fr;
    gap: 22px;
    padding-bottom: 14px;
  }
  .scene3__footer-nav {
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
  }
  .scene3__footer-col a { font-size: 12px; }
  .scene3__footer-tagline { display: none; }
}
@media (max-width: 480px) {
  .scene3__footer-nav { grid-template-columns: 1fr 1fr; }
}

/* ----------------------------------------------------------
   Reduced motion: respect users' OS settings
   ---------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .hero__scrollline { animation: none; }
  /* Scrub still works (it's user-initiated motion), but the looping
     scroll-hint animation is killed. */
}
