/* film-world-skin — layout for the single-film hero.

   scroll-world-skin.css already styles the TYPE (.sw-copy__eyebrow/__title/__body/
   __tags, .sw-btn) and owns the brand tokens. It does NOT position the stage: those
   rules live inside scrub-engine.js, which the film hero does not load. So everything
   structural is declared here, and nothing here restates a type or colour decision. */

.fw-root { position: relative; }
.fw-track { position: relative; z-index: 1; pointer-events: none; }

/* The stage paints the ROBOT-FREE master plate (m00-beeby-lake, no baked mascot) while
   the hero is at rest. The film's own frame 0 already contains the flying robot, so
   showing it under the waving mascot put two robots on screen at once. The film is
   therefore held back until launch — the mascot waves alone, lifts off, and the film
   fades in with him already airborne. */
.fw-stage {
  position: fixed; inset: 0; z-index: 10;
  /* ?v=2 — the first poster was the film's own frame 0, which has the flying robot
     baked in. Bumping the query is what actually evicts it from the CSS image cache. */
  background: var(--sw-bg) url("scroll/hero-film-poster.jpg?v=2") center / cover no-repeat;
  pointer-events: none;
  overflow: hidden;
}

/* The film sits under a left-weighted scrim so copy holds contrast over bright
   campus footage. Opacity waits for the first painted frame (.has-film) — on iOS a
   seeked-but-never-played muted video is blank, and revealing on metadata flashes. */
.fw-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  /* A cut, not a dissolve. Measured at .45s and .22s: the film's baked flying robot
     double-exposes against the robot-free poster plate for the whole fade, and the two
     plates are different camera positions, so it reads as several ghost robots. 90ms is
     short enough that no frame shows both and long enough to avoid a decode flash. */
  transition: opacity .09s linear;
}
/* Needs BOTH: decoded (has-film) and FLOWN. `is-launched` fired the moment the takeoff
   started, so the film's baked robot faded up while the mascot was still on screen at
   partial opacity — two translucent robots in the same frame, the "ghost robots" bug.
   `is-flown` lands after the mascot is display:none, so only one robot ever paints.
   The fade also drops to .22s: even one robot arriving at 50% alpha reads as a ghost. */
.fw-root.has-film.is-flown .fw-video { opacity: 1; }

.fw-stage::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  width: min(58vw, 820px);
  background: linear-gradient(90deg,
    var(--sw-bg) 0%,
    color-mix(in srgb, var(--sw-bg) 80%, transparent) 34%,
    color-mix(in srgb, var(--sw-bg) 38%, transparent) 62%,
    transparent 100%);
}

/* ── MASCOT INTRO ────────────────────────────────────────────────────────────────
   Waving on frame 0, then one takeoff the instant the user scrolls. Both clips are
   VP9 with alpha, so no matte or blend mode is needed. */
.fw-mascot {
  position: absolute; z-index: 4;
  right: clamp(24px, 11vw, 190px); bottom: 0;
  height: min(56vh, 460px);
  pointer-events: none;
  transition: transform .85s cubic-bezier(.3, 0, .2, 1), opacity .5s ease .35s;
}
.fw-mascot__clip { height: 100%; width: auto; display: block; }
.fw-mascot__lift { display: none; }

.fw-root.is-launched .fw-mascot { transform: translate3d(6vw, -78vh, 0) scale(.62); opacity: 0; }
.fw-root.is-launched .fw-mascot__wave { display: none; }
.fw-root.is-launched .fw-mascot__lift { display: block; }
.fw-root.is-flown .fw-mascot { display: none; }

/* ── COPY ────────────────────────────────────────────────────────────────────────
   Cards stack in one fixed layer and are driven entirely by the engine (opacity +
   translate per frame), so every scroll pass raises them in and lets them fall back
   out. No scroll-linked CSS animation, so there is one source of truth. */
.fw-copylayer { position: fixed; inset: 0; z-index: 20; pointer-events: none; }

.fw-copy {
  position: absolute;
  left: clamp(18px, 5vw, 74px);
  top: 50%;
  width: min(46vw, 620px);
  /* Vertical centring uses the `translate` property, NOT transform, because the engine
     overwrites transform every frame. The two compose, so centring survives. */
  translate: 0 -50%;
  transform: translate3d(0, 34px, 0);
  opacity: 0;
  will-change: opacity, transform;
  transition: opacity .18s linear;
}

/* Ezra stop (segment index 3): copy reads from the TOP of the frame so it clears the
   robot below. `translate`, never transform — the engine owns transform per frame. */
.fw-copy[data-seg="3"] { top: clamp(64px, 10vh, 130px); translate: 0 0; }

.fw-copy__cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.fw-copy__cta .sw-btn {
  display: inline-flex; align-items: center;
  padding: 12px 20px; font-size: .92rem; text-decoration: none;
}
.sw-btn--ghost { border: var(--cain-rule) solid rgba(255,255,255,.5); color: #fff; background: none; }

/* ── ROUTE DOTS ──────────────────────────────────────────────────────────────── */
/* Right rail, vertically centred and inset far enough that it never collides with the
   site's own top nav or the Get-matched CTA. */
.fw-route {
  position: fixed; right: clamp(14px, 2.4vw, 30px); top: 50%;
  z-index: 40; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 20px; padding: 18px 0;
}
/* Grows leftward off the right rail. scaleX, not width, so the active dot does not
   relayout the rail on every section change. */
.fw-route__dot {
  position: relative;
  width: 34px; height: var(--cain-rule);
  background: rgba(255,255,255,.34);
  border: 0; padding: 0; cursor: pointer;
  transform: scaleX(.647); transform-origin: 100% 50%;
  transition: background .25s, transform .25s;
}
.fw-route__dot.is-on { background: var(--sw-accent); transform: scaleX(1); }

/* The section name rides the active bar. This is where the old "01 / 05" counter went —
   it used to sit above the eyebrow and is now hidden (scroll-world-skin.css). Text comes
   from the aria-label the engine already sets, so no engine change and no duplicate copy.
   Only the active bar shows one, and the active bar is scaleX(1), so no text distortion. */
.fw-route__dot::after {
  content: attr(aria-label);
  position: absolute; right: calc(100% + 14px); top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  font-family: var(--sw-font-body); font-size: .84rem; font-weight: 500;
  letter-spacing: .09em; color: rgba(255,255,255,.92);
  text-shadow: 0 1px 14px rgba(20,16,16,.9);
  opacity: 0; transition: opacity .25s;
}
.fw-route__dot.is-on::after { opacity: 1; }

.fw-hint {
  position: fixed; left: 50%; bottom: 26px; z-index: 30;
  transform: translateX(-50%);
  font-family: var(--sw-font-body);
  font-size: .76rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--sw-ink-soft);
  transition: opacity .3s;
}

/* Same contract as scroll-world: once the hero track leaves the viewport, every fixed
   child must stop painting or it floats over the rest of the page. */
.fw-root.is-offscreen > .fw-stage,
.fw-root.is-offscreen > .fw-copylayer,
.fw-root.is-offscreen > .fw-route,
.fw-root.is-offscreen > .fw-hint { display: none; }

@media (max-width: 860px) {
  .fw-copy { width: min(88vw, 560px); top: auto; bottom: 13vh; translate: none; transform: translate3d(0, 34px, 0); }
  .fw-copylayer .fw-copy { translate: none; }
  /* Ezra stays top-anchored on mobile too (base rule above is bottom-anchored). */
  .fw-copy[data-seg="3"] { top: 9vh; bottom: auto; }
  .fw-stage::after {
    width: 100%;
    background: linear-gradient(0deg,
      var(--sw-bg) 6%,
      color-mix(in srgb, var(--sw-bg) 74%, transparent) 42%,
      transparent 78%);
  }
  .fw-mascot { right: 6vw; height: min(40vh, 330px); }
  /* The rail used to be hidden here. It now carries the section name that replaced the
     "01 / 05" counter, so hiding it would delete that label on phones. Bars shrink and
     the copy is bottom-anchored, so the rail sits in empty space. */
  .fw-route { gap: 14px; }
  .fw-route__dot { width: 22px; }
  .fw-route__dot::after { font-size: .76rem; right: calc(100% + 10px); }
}

@media (prefers-reduced-motion: reduce) {
  .fw-mascot, .fw-copy { transition: none; }
}
