/* Scene 2 — the hero. Video underneath, PSD backdrop as the fallback, and the
   live-text name overlay from 2.psd 'slide 2'. */

#hero { z-index: 2; }
#hero .scene__backdrop { background-image: url('../assets/hero-blur.webp?v=8'); }

.hero__video,
.hero__poster,
.hero__end,
.hero__fallback {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.hero__video { z-index: 0; background: #2a1a10; }

/* Chrome drops the <video> poster the moment play() is called, ~400ms before
   the first frame is actually presented — the poster-drop blink. Hold this
   image over the video and only hide it inside requestVideoFrameCallback. */
.hero__poster { z-index: 1; transition: opacity 0.35s linear; }
.hero__poster.is-gone { opacity: 0; }

/* Held over the video once playback ends: a <video> cannot be trusted to keep
   painting its final frame (chrome-headless-shell goes black at 'ended'), so
   the hero settles onto this still of the video's own last frame. */
.hero__end {
  z-index: 2;
  opacity: 0;
  transition: opacity 0.5s linear;
}
.hero__end.is-on { opacity: 1; }

/* Shown only if the video can never play (see js/hero.js). */
.hero__fallback { z-index: 0; display: none; }
.hero.is-videoless .hero__fallback { display: block; }
.hero.is-videoless .hero__video { display: none; }

.hero__names {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  /* Never painted until the reveal decides to paint it — otherwise the
     overlay double-strikes the names already burned into the video. */
  visibility: hidden;
  opacity: 0;
}
/* When the client's video already carries the names, the overlay is kept in
   the DOM for assistive tech but never painted (config hero.video.namesBakedIn). */
.hero__names.is-baked { visibility: hidden; }

.hero__name,
.hero__amp {
  /* Client asked for white names (2026-09-08), replacing the PSD's clipped gold
     gradient. Plain colour, so this is no longer a background-clip:text node —
     one less main-thread paint path on iOS. --grad-gold still styles the
     revealed card's date. */
  color: #fff;
  -webkit-text-fill-color: #fff;
  text-shadow: 0 3px 14px rgba(0, 0, 0, 0.45);
  /* Script swashes overshoot their box; iOS WebKit clips text ink at the box
     edge, and background-clip:text clips it in every browser. Pad generously
     and pull the padding back out of the layout. */
  padding: 0.35em 0.5em;
  margin: 0 -0.5em;
  /* No `filter` here. A drop-shadow over a background-clip:text node forces
     the glyphs through a main-thread filter pass on every scroll frame on iOS
     (the names are ~250 design px tall, so the layer is large). The radial
     scrim behind them already carries the contrast. If a shadow is ever wanted
     back, duplicate the run as a solid-gold ::before layer offset behind the
     gradient text — never a filter on a bg-clip node. */
}

.hero__std {
  color: #fff;
  /* The PSD run is All Caps; the source string keeps its natural casing so the
     accessible copy and the config read normally. */
  text-transform: uppercase;
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  text-shadow: 0 3px 14px rgba(0, 0, 0, 0.45);
}

/* ------------------------------------------------------------- scroll cue
 * Reference's "Scroll To Explore" + arrow.
 *
 * BOTH of these are siblings of .stage, not children of .frame. Inside the
 * frame every length is a DESIGN px multiplied by --s (0.44 on a 390px phone),
 * so the reference's own type size came out at ~13 CSS px of light gold on a
 * bright marble last frame — invisible, which is exactly what the client
 * reported. Out here the sizes are real CSS px and the vignette gives the gold
 * a dark ground to sit on.
 *
 * They also sit ABOVE .hero__scrim (z-index 2) rather than under it.
 */

/* Fades in with the cue; opacity only, no filter, no blur. */
.hero__vignette {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 35%;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.65), transparent);
}

.hero__cue {
  position: absolute;
  left: 0;
  right: 0;
  /* Inside 100dvh even with the iOS Safari toolbar expanded, and clear of the
     home indicator. */
  bottom: calc(56px + env(safe-area-inset-bottom));
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.hero__cue-label {
  font-family: var(--font-sans);
  font-size: clamp(0.85rem, 3vw, 1.1rem);
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  text-transform: uppercase;
  color: var(--c-gold);
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.85);
  animation: hero-cue-breathe 3s infinite alternate ease-in-out;
}

.hero__cue-arrow {
  font-family: var(--font-sans);
  font-size: clamp(1.8rem, 5vw, 2.2rem);
  font-weight: 300;
  line-height: 1;
  color: var(--c-gold);
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.85);
  animation: hero-cue-pulse 2.5s infinite ease-in-out;
}

/* Namespaced: css/scratch-cue.css declares its own `cue-pulse`, and being the
   later sheet it was silently winning here — the hero arrow inherited the
   scratch cue's opacity/text-shadow pulse instead of bouncing. */
@keyframes hero-cue-breathe {
  0%   { opacity: 0.6; transform: scale(0.98); }
  100% { opacity: 1;   transform: scale(1.02); }
}
@keyframes hero-cue-pulse {
  0%   { transform: translateY(-8px); opacity: 0.6; }
  50%  { transform: translateY(8px);  opacity: 1; }
  100% { transform: translateY(-8px); opacity: 0.6; }
}
