/* ==========================================================================
   hero-flythrough — iteration block
   --------------------------------------------------------------------------
   Pure-CSS layout + decorative scene gradients. ALL motion lives in
   ./hero-flythrough.js via transform + opacity, driven by one rAF loop and
   one [0,1] progress value. Block contract: everything attaches to the
   single <section data-teako-hero> root, so it ports cleanly into ACF
   later. Spec: teako-hero-build-prompt.md (vendored alongside in chat).
   ========================================================================== */

.thero {
  /* Off-black, tinted cool toward the mineral palette (not pure #000). */
  --thero-bg:    #07090D;
  --thero-ink:   #F4F5F7;
  --thero-mute:  #72788C;
  --thero-tileW: 20vw;
  /* Entry fade — JS writes 0 → 1 across the first ~75vh of the track
     entering viewport. The fade is applied to .thero__stage (not .thero
     itself) so the solid black background stays constant while the
     videos, headings, and chrome materialise. Fallback 1 means visible
     if JS hasn't run yet. */
  --thero-enter: 1;

  /* Full-bleed escape from any parent max-width — works inside the playground. */
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  background: var(--thero-bg);
  color: var(--thero-ink);
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}
.thero,
.thero * {
  box-sizing: border-box;
}

/* Tall scroll track — its height controls the duration (spec §7.1: 820vh). */
.thero__track {
  position: relative;
  height: 820vh;
}

/* Right-side diagonal topo pattern — sits behind the hero video. The
   45° hairlines are the same as hero-scrollytelling's left-side topo;
   the mask is mirrored (225deg gradient: dense at top-right, transparent
   at bottom-left) so the pattern reads as "coming from the right".
   Opacity binds to --thero-hero-take so it fades up with the hero.
   z-index 1 keeps it above the black bg but below tiles + hero. */
.thero__topo {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: calc(var(--thero-hero-take, 0) * 0.085);
  z-index: 1;
  background-image: repeating-linear-gradient(
    45deg,
    #ffffff 0,
    #ffffff 1px,
    transparent 1px,
    transparent 16px
  );
  -webkit-mask-image: linear-gradient(225deg, #000 0%, transparent 65%);
  mask-image: linear-gradient(225deg, #000 0%, transparent 65%);
}

/* Depth field — gives the black void a 3D read behind the floating scenes:
   atmospheric haze brightening toward the vanishing point (50% 45%, where the
   scenes converge and the headline sits) + faint perspective lines converging
   on that point, masked to a mid-ring so they fade in from the haze and out
   before the edges. STATIC by design — the fly-through already carries the
   motion (design-motion-principles: depth should be felt, not noticed). Sits
   at z-index 0, behind every tile; inherits the stage's entry fade. */
.thero__depth {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(58% 52% at 50% 45%,
      rgba(104, 122, 150, 0.16) 0%,
      rgba(48, 58, 76, 0.05) 44%,
      rgba(7, 9, 13, 0) 72%);
}
.thero__depth::before {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-conic-gradient(
    from 0deg at 50% 45%,
    rgba(214, 224, 238, 0.10) 0deg 0.13deg,
    transparent 0.13deg 5deg
  );
  -webkit-mask-image: radial-gradient(circle at 50% 45%, transparent 13%, #000 46%, transparent 90%);
  mask-image: radial-gradient(circle at 50% 45%, transparent 13%, #000 46%, transparent 90%);
}
/* Concentric depth rings — perpendicular to the spokes, completing the 1-point
   perspective tunnel. Faintest of all, masked to the same mid-ring. */
.thero__depth::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-radial-gradient(
    circle at 50% 45%,
    rgba(214, 224, 238, 0.06) 0 1px,
    transparent 1px 92px
  );
  -webkit-mask-image: radial-gradient(circle at 50% 45%, transparent 18%, #000 55%, transparent 92%);
  mask-image: radial-gradient(circle at 50% 45%, transparent 18%, #000 55%, transparent 92%);
}

/* Sticky stage pinned at viewport top while the track scrolls through.
   opacity binds to --thero-enter so the inner content (videos, headings,
   hero, chrome) fades up out of the solid black .thero background — the
   black never goes through the fade itself, so there's no "wash" effect. */
.thero__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  overflow: hidden;
  opacity: var(--thero-enter, 1);
}

/* HUD bar. Spec says position:fixed; using absolute inside the stage so the
   block stays self-contained — the bar appears/disappears with the sticky. */
.thero__bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  padding: 10px 14px;
  background: linear-gradient(#000, rgba(0,0,0,0));
  font: 11px/1 ui-monospace, 'SF Mono', Menlo, monospace;
  letter-spacing: 0.08em;
  pointer-events: none;
}
.thero__bar-lbl  { color: var(--thero-mute); text-transform: uppercase; }
.thero__bar-prog { margin-left: auto; color: var(--thero-mute); }

/* Headings sit in front of flying tiles, behind the hero (z-index: 6). */
.thero__headings {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  z-index: 6;
  pointer-events: none;
  text-align: center;
  padding: 0 6vw;
}
.thero__h {
  position: absolute;
  margin: 0;
  font-weight: 300; /* D1 */
  font-size: clamp(28px, 4.2vw, 64px);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.thero__h .ln { display: block; }
.thero__h .ln i {
  display: block;
  font-style: normal;
  opacity: 0;
  will-change: transform, opacity;
}

/* Flying tiles. JS sets `left`/`top` from the TILES config + transforms
   each frame. Tiles use z-index 3..5 (depth-based, set in JS). */
.thero__tile {
  position: absolute;
  width: var(--thero-tileW);
  aspect-ratio: 16 / 9;
  transform: translate(-50%, -50%);
  will-change: transform, opacity, filter;
  z-index: 3;
}

.thero__frame {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background-color: #0a0d12; /* fallback when video is loading or missing */
}
.thero__frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.thero__frame::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 120% at 50% 40%, transparent 50%, rgba(0,0,0,0.55));
  pointer-events: none;
}

/* Scene fallback gradients — show through while the video loads or before
   the file exists. Maps 1:1 with the prototype's s-* scene classes. */
.thero__tile--scene-river  .thero__frame { background-image: linear-gradient(160deg, #2a3340, #4a5560 35%, #cfd6dc 60%, #1d242c); }
.thero__tile--scene-aerial .thero__frame { background-image: linear-gradient(140deg, #1c2a1e, #3c5436 45%, #7d8a5c 70%, #202a20); }
.thero__tile--scene-truckA .thero__frame { background-image: linear-gradient(120deg, #10161b, #27435e 50%, #3f6f96 65%, #0d1318); }
.thero__tile--scene-truckB .thero__frame { background-image: linear-gradient(120deg, #0e1419, #22384f 55%, #356088 70%, #0c1116); }
.thero__tile--scene-roadA  .thero__frame { background-image: linear-gradient(150deg, #1a2128, #445063 50%, #c9d2da 72%, #1a222b); }
.thero__tile--scene-roadB  .thero__frame { background-image: linear-gradient(150deg, #161d24, #3a4658 50%, #b7c2cc 74%, #161e26); }
.thero__tile--scene-ridge  .thero__frame { background-image: linear-gradient(135deg, #1b232c, #33414f 50%, #8d9aa6 72%, #141a20); }

/* Constant-size coordinate labels (counter-scaled per frame in JS).
   N: top-left above the tile. E: bottom-right below. */
.thero__coord {
  position: absolute;
  font: 6px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0.12em;
  color: var(--thero-mute);
  white-space: nowrap;
}
.thero__coord--n {
  left: 0;
  bottom: 100%;
  margin-bottom: 7px;
  transform-origin: 0 100%;
}
.thero__coord--e {
  right: 0;
  top: 100%;
  margin-top: 7px;
  text-align: right;
  transform-origin: 100% 0;
}

/* Hero — separate element, hidden behind the headings (z-index 4), emerges
   to z-index 9 once the third heading is reached. Initial scale 0.45,
   final 2.13 (spec §7.6). */
/* Hero — full-bleed by default. JS scales from 0.4 → 1.0 as `take`
   ramps 0 → 1 during the scroll, so the emerge ends with the video
   filling the entire 100 vw × 100 vh sticky stage. Contains only the
   ambient muted loop now — the feature video lives inside .thero__pip
   and physically expands from the corner on click. */
.thero__hero {
  position: absolute;
  inset: 0;
  z-index: 4;
  opacity: 0;
  transform: scale(0.4);
  transform-origin: center;
  will-change: transform, opacity, filter;
  background: #0b141c;
}
.thero__hero[data-state="ambient"],
.thero__hero[data-state="playing"] {
  cursor: none;
}
.thero__hero-ambient {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: #0b141c;
}

/* Bottom-right PIP — is the feature video. Paused with poster in
   ambient state; on click the element itself physically expands to
   fill the stage (width / height / bottom / right transitions) AND
   the video starts playing. Click again to shrink back. */
.thero__pip {
  position: absolute;
  bottom: 28px;
  right: 28px;
  width: clamp(180px, 14vw, 240px);
  height: calc(clamp(180px, 14vw, 240px) * 9 / 16);
  z-index: 12;
  padding: 0;
  appearance: none;
  background: #0a0a0a;
  border: 1px solid rgba(255, 255, 255, 0.18);
  overflow: hidden;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  box-shadow: 0 22px 48px rgba(0, 0, 0, 0.5);
  /* The size / position transitions are what create the "PIP grows
     into a full-screen player" feel. Keep them long enough to read
     as deliberate (≈ 680 ms) and ease-in-out so the motion settles. */
  transition:
    width 680ms cubic-bezier(0.76, 0, 0.24, 1),
    height 680ms cubic-bezier(0.76, 0, 0.24, 1),
    bottom 680ms cubic-bezier(0.76, 0, 0.24, 1),
    right 680ms cubic-bezier(0.76, 0, 0.24, 1),
    border-color 400ms ease,
    box-shadow 400ms ease,
    opacity 360ms ease;
}
.thero__pip.is-visible {
  opacity: 1;
  pointer-events: auto;
}
.thero__pip:hover {
  border-color: rgba(255, 255, 255, 0.45);
}

/* Expanded — fills the entire sticky stage. The same transitions
   drive the inverse shrink-back when state flips to ambient. */
.thero__hero[data-state="playing"] ~ .thero__pip {
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
  border-color: transparent;
  box-shadow: none;
}
.thero__pip-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.thero__pip-play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.20);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  backdrop-filter: blur(10px) saturate(1.4);
  border: 1px solid rgba(255, 255, 255, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  pointer-events: none;
  transition: opacity 240ms ease;
}
.thero__hero[data-state="playing"] ~ .thero__pip .thero__pip-play {
  opacity: 0;
}
.thero__pip-play svg {
  width: 14px;
  height: 14px;
  margin-left: 2px;
  fill: currentColor;
}

/* Close control for the expanded player. Hidden by default; phones show it
   while the hero is in the playing state (root carries .is-playing, set in
   JS). Sits above the HUD bar (z 50) and the expanded PIP (z 12). */
.thero__close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 56;
  width: 40px;
  height: 40px;
  padding: 0;
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(20, 22, 28, 0.6);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  backdrop-filter: blur(10px) saturate(1.4);
  color: #fff;
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.thero__close svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

/* Custom mouse-following cursor tag. position:fixed so it escapes the
   sticky stage; JS writes --cx / --cy from mousemove and the offset
   translate keeps the tag just below+right of the actual pointer. */
.thero__cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 8px 8px;
  background: rgba(20, 22, 28, 0.78);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px;
  font-family: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #fff;
  pointer-events: none;
  white-space: nowrap;
  opacity: 0;
  transform: translate(var(--cx, -200px), var(--cy, -200px)) translate(18px, 18px);
  transition: opacity 200ms ease;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
.thero__cursor.is-visible { opacity: 1; }
.thero__cursor-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  flex-shrink: 0;
}
.thero__cursor-icon svg {
  width: 10px;
  height: 10px;
  fill: currentColor;
}
.thero__cursor-icon[data-icon="close"] svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.thero__cursor-meta {
  color: rgba(255, 255, 255, 0.55);
}
.thero__hero[data-state="playing"] ~ .thero__cursor .thero__cursor-meta {
  display: none;
}

/* Touch / no-pointer environments — show a static pill in the centre
   so the play affordance is still discoverable. */
@media (hover: none), (pointer: coarse) {
  .thero__cursor {
    position: absolute;
    left: 50%;
    top: 56%;
    transform: translate(-50%, -50%) !important;
  }
  .thero__hero[data-state="ambient"],
  .thero__hero[data-state="playing"] {
    cursor: pointer;
  }
}
/* Final title + meta line + vignette + scroll hint. */
.thero__final {
  position: absolute;
  left: 0;
  right: 0;
  top: 4vh;
  z-index: 12;
  margin: 0;
  text-align: center;
  font-weight: 500;
  font-size: clamp(24px, 2.8vw, 44px);
  letter-spacing: -0.01em;
  opacity: 0;
  pointer-events: none;
  will-change: opacity, transform;
}
/* Meta sits tight under the video edges. Left/right insets match the
   final hero width (75vw at heroFinalScale = 2.5): (100-75)/2 = 12.5vw. */
.thero__meta {
  position: absolute;
  z-index: 13;
  left: 12.5vw;
  right: 12.5vw;
  bottom: 5vh;
  display: flex;
  justify-content: space-between;
  font: 12px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0.14em;
  color: var(--thero-mute);
  opacity: 0;
  pointer-events: none;
}
.thero__meta b {
  color: var(--thero-ink);
  font-weight: 400;
}
.thero__vignette {
  position: absolute;
  inset: 0;
  z-index: 14;
  pointer-events: none;
  background: radial-gradient(130% 130% at 50% 50%, transparent 58%, rgba(0,0,0,0.42));
}
.thero__hint {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 40;
  font: 11px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0.18em;
  color: var(--thero-mute);
  text-transform: uppercase;
  pointer-events: none;
  transition: opacity 0.4s;
}

/* Reduced-motion fallback (spec §9). JS detects the same media query and
   skips per-frame transforms; this CSS just smooths the static cross-fade. */

@media (max-width: 760px) {
  /* Floating gallery tiles read as specks at 20vw on a phone — scale the
     constellation up so each shot is legible while scrolling. Bigger and
     square-masked on phones (client, 28 Aug 2026): landscape 16:9 crops
     were slivers at this width; 1:1 keeps each shot readable. The JS
     positions are per-tile percentages, so the constellation holds. */
  .thero { --thero-tileW: 42vw; }
  .thero__tile { aspect-ratio: 1 / 1; }
  /* The atmospheric haze at the vanishing point read as a harsh light-grey
     blob behind the headings on a phone (client, 28 Aug 2026) — soften it
     to roughly 40% of the desktop strength. Spokes/rings untouched. */
  .thero__depth {
    background:
      radial-gradient(58% 52% at 50% 45%,
        rgba(104, 122, 150, 0.065) 0%,
        rgba(48, 58, 76, 0.02) 44%,
        rgba(7, 9, 13, 0) 72%);
  }
  /* Narrower text container so the three beats no longer run edge to edge
     on a phone (client, 28 Aug 2026). The headings are absolutely positioned,
     so the container's padding cannot constrain them — cap their own width
     (76vw = 12vw clear each side). */
  .thero__h { max-width: 76vw; }
  /* The two lines of each beat flow as ONE sentence on phones (client,
     28 Aug 2026) — inline, so the wrap is natural and there is no block
     gap. Inline boxes ignore the JS translateY, so the reveal is a plain
     fade on phones (the slide stays on desktop). */
  .thero__h .ln,
  .thero__h .ln i { display: inline; }
  /* PIP feature player on phones (client, 28 Aug 2026): a small PORTRAIT
     screen with slightly rounded corners, taking a little more of the
     viewport than the old 180px landscape tile. Expanded state keeps the
     full-stage fill (radius drops to 0) and gains the close control. */
  .thero__pip {
    width: 42vw;
    height: calc(42vw * 16 / 9);
    bottom: 16px;
    right: 16px;
    border-radius: 10px;
    transition:
      width 680ms cubic-bezier(0.76, 0, 0.24, 1),
      height 680ms cubic-bezier(0.76, 0, 0.24, 1),
      bottom 680ms cubic-bezier(0.76, 0, 0.24, 1),
      right 680ms cubic-bezier(0.76, 0, 0.24, 1),
      border-radius 400ms ease,
      border-color 400ms ease,
      box-shadow 400ms ease,
      opacity 360ms ease;
  }
  .thero__hero[data-state="playing"] ~ .thero__pip { border-radius: 0; }
  .thero.is-playing .thero__close { display: flex; }
  /* The progress readout sits where the close control lands — hide it while
     the film plays. */
  .thero.is-playing .thero__bar { opacity: 0; }
}


/* Brand font unification (2026-08-02): headings were falling back to
   Helvetica Neue — display type is Geologica everywhere on the page. */
.thero__h { font-family: 'Geologica', system-ui, sans-serif; }

/* ---------- Rail — the phone fly-through (client, 10 Sep 2026) ----------
   Phones only (<=760px). Replaces the Stories clock (5 Sep). Black ground; two
   vertical columns of 4:5 frames under the nav clearance; the left column
   carries each sentence as its frame's caption and rests one block per beat,
   the right column counter-glides; from 78% the crag arrives full-bleed
   through the live ending's take; the bar is pinned at the bottom.
   Geometry on an iPhone 13 (390 × 664): rail 0–634 masked soft at the top
   (96px) and bottom (28px); left column 62% = 217px, a 4:5 frame 271px, the
   index on a 10px line, the sentence 28px/1.2; each block a fixed 490px so
   the pitch never depends on the line count; right column 128px, 4:5
   frames with a 16px gap. Track 200vh: three beats to 65%, the crag's take
   78% → 98%.
   Prototype: design/hero-mobile-3/rail-3.html (branch design/hero-mobile-03).
   Everything here overrides the older phone rules above; desktop unaffected. */
.thero__bar-segs,
.thero__rail { display: none; }
@media (max-width: 760px) {
  .thero__track { height: 200vh; }                       /* live desktop: 820vh */
  .thero__stage { height: 100vh; height: 100svh; }
  .thero__depth,
  .thero__topo,
  .thero__hint,
  .thero__bar-prog,
  .thero__coord,
  .thero__headings,
  .thero__tile,
  .thero__frame::after { display: none; }
  /* Segmented bar, pinned at the bottom of the stage above the hand-off. */
  .thero__bar {
    top: auto;
    bottom: 14px;
    left: 16px;
    right: 16px;
    padding: 0;
    background: none;
    z-index: 8;
    opacity: calc(1 - var(--thero-hero-take, 0) * 1.4);
  }
  .thero__bar-segs { display: flex; flex: 1; gap: 4px; }
  .thero__bar-segs i {
    position: relative;
    flex: 1;
    height: 2px;
    border-radius: 1px;
    overflow: hidden;
    background: rgba(244, 245, 247, 0.28);
  }
  .thero__bar-segs i::after {
    content: '';
    position: absolute;
    inset: 0;
    background: #F4F5F7;
    transform-origin: 0 50%;
    transform: scaleX(var(--fill, 0));
  }
  /* The rail: two columns under a soft mask; fades under the expanding crag. */
  .thero__rail {
    position: absolute;
    left: 20px;
    right: 20px;
    top: 0;
    bottom: 30px;
    z-index: 3;
    display: flex;
    gap: 12px;
    align-items: flex-start;
    overflow: hidden;
    pointer-events: none;
    opacity: calc(1 - var(--thero-hero-take, 0) * 1.4);
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 96px, #000 calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 96px, #000 calc(100% - 28px), transparent 100%);
  }
  .thero__rail-col { display: flex; flex-direction: column; will-change: transform; }
  .thero__rail-col--a { flex: 0 0 62%; }
  .thero__rail-col--b { flex: 1 1 0; gap: 16px; }
  /* Client, 11 Sep 2026: left frames shorter (4:3) and sentences at 24px so the
     last block — clip, sentence, then the crag beneath — fits on one screen. */
  .thero__rail-col--a .thero__rail-block { width: 100%; height: 348px; margin: 0; }   /* 4:3 frame 163 + caption up to five 24px lines */
  .thero__rail-col--a .thero__rail-block--last { height: auto; }
  .thero__rail-col--a .thero__rail-frame { aspect-ratio: 4 / 3; }
  .thero__rail-crag { position: relative; margin-top: 14px; aspect-ratio: 4 / 3; background: #0b141c center / cover no-repeat; }
  .thero__rail-col--b .thero__rail-block { width: 100%; margin: 0; }
  /* A clip in a 4:5 mask with its poster as the first paint; the video is
     invisible over the poster until its first painted frame (.is-live). */
  .thero__rail-frame {
    position: relative;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    background: #0a0d12 center / cover no-repeat;
  }
  .thero__rail-frame video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 320ms ease-out;
  }
  .thero__rail-frame video.is-live { opacity: 1; }
  .thero__rail-idx {
    display: block;
    margin: 8px 0 0;
    height: 10px;
    font: 10px/10px 'Space Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    letter-spacing: 0.12em;
    color: #72788C;
  }
  /* The caption: index, then the sentence (the live 28px Geologica 300). The
     sentence travels with its frame; the third leaves under the crag's take. */
  .thero__rail-cap {
    margin: 12px 0 0;
    opacity: calc(1 - var(--thero-hero-take, 0) / 0.6);
  }
  .thero__rail-cap .thero__rail-idx { margin: 0 0 8px; }
  .thero__rail-h {
    display: block;
    font: 300 24px/1.2 'Geologica', system-ui, sans-serif;
    letter-spacing: -0.01em;
    color: #F4F5F7;
  }
  /* The PIP feature player: a small PORTRAIT screen (client, 28 Aug 2026),
     full-stage when playing, with the close control. */
  .thero__pip {
    width: 42vw;
    height: calc(42vw * 16 / 9);
    bottom: 16px;
    right: 16px;
    border-radius: 10px;
    transition:
      width 680ms cubic-bezier(0.76, 0, 0.24, 1),
      height 680ms cubic-bezier(0.76, 0, 0.24, 1),
      bottom 680ms cubic-bezier(0.76, 0, 0.24, 1),
      right 680ms cubic-bezier(0.76, 0, 0.24, 1),
      border-radius 400ms ease,
      border-color 400ms ease,
      box-shadow 400ms ease,
      opacity 360ms ease;
  }
  .thero__hero[data-state="playing"] ~ .thero__pip { border-radius: 0; }
  .thero.is-playing .thero__close { display: flex; }
  .thero.is-playing .thero__bar,
  .thero.is-playing .thero__rail { opacity: 0; }
  /* .thero__hero on phones: placed by the JS over the crag box (origin top-left,
     clipped to the rail's band) and grown to the stage. No blur, no centre scale. */
  .thero__hero { opacity: 1; transform-origin: 0 0; transform: none; filter: none; will-change: transform, clip-path, opacity; }
}
@media (max-width: 760px) and (prefers-reduced-motion: reduce) {
  .thero__rail-frame video { transition: none; }
  .thero__rail-col { will-change: auto; }
}
