/* ==========================================================================
   hero.css — 16:9 stills hero with Ken Burns, slide carousel, auto-advance
   --------------------------------------------------------------------------
   Reference: Figma 7539:164376 ("Hero — 16:1"), rebuilt at a true 16:9 media
   plate per the brief.

   GEOMETRY. Three numbers drive everything, all a share of the viewport width
   so the hero stays full bleed and proportional at any size:

     plate    56.250vw   the 16:9 media itself          (810px at 1440)
     visible  39.444vw   the hero's own box, 568/1440   (568px at 1440)
     overlap  16.806vw   plate minus visible            (242px at 1440)

   The plate is absolutely positioned inside a shorter .hero box, so it bleeds
   `overlap` past the bottom and the first rail sits over it. A bottom
   gradient dissolves the media into the page behind the rail.

   THREE TRANSFORM LAYERS, deliberately kept separate so they never fight:

     .hero__slide   translateX   the slide travel
     .hero__media   translateX   the parallax counter-move (the "fill")
     .hero__poster  scale/translate   the Ken Burns drift

   Every one of them is a uniform transform on a fixed aspect-ratio box, so
   nothing can ever distort and nothing reflows.

   STILLS ONLY, for now. The video path is intact — see js/hero.js and the
   MEDIA note in index.html. A slide with no `data-src` falls through to its
   poster permanently, which is the same code path as a failed video.
   ========================================================================== */

.hero {
  --hero-plate:   56.25vw;
  --hero-visible: 39.444vw;
  --hero-overlap: 16.806vw;

  position: relative;
  z-index: 0;
  height: var(--hero-visible);

  /* Driven by js/hero.js on scroll: the hero recedes and dims as it leaves,
     rather than simply scrolling away. */
  opacity: var(--hero-opacity, 1);
  /* The plate overflows downward on purpose — do not clip it here. */
}

/* The 16:9 media plate ---------------------------------------------------- */

.hero__stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--color-background);
}

/* The reel holds the travelling slides and is the ONLY thing that
   parallaxes. Scrims and the action panel are siblings of it inside the
   stage, so they stay anchored — otherwise the metadata drifts down on
   scroll and collides with the first rail. */
.hero__reel {
  position: absolute;
  inset: 0;
  transform: translate3d(0, var(--hero-parallax, 0px), 0);
}

/* The reveal. A slide's container grows from the edge of the page rather
   than sliding in from outside it — so nothing ever travels through
   off-screen space and then lands, which is what read as a jump. The two
   slides tile: at the halfway point the incoming occupies the right half and
   the outgoing the left, with no overlap and no gap. The artwork inside is
   always exactly stage-sized and stationary, so it cannot distort. */
.hero__slide {
  position: absolute;
  inset: 0;
  visibility: hidden;
  clip-path: inset(0 0 0 0);
  transition: clip-path var(--dur-slide) var(--ease-slide) var(--delay-slide);
}

.hero__slide.is-active,
.hero__slide.is-moving {
  visibility: visible;
}

/* The fill layer. It scales rather than only sliding: the incoming image
   settles down from an over-scale into place, and the outgoing one scales up
   as its container is pushed away — so each always fills its box. The shift
   stays inside the scale's overflow (14% scale = 7% spare per edge, against
   a 5% shift), which is why no empty edge can appear mid-transition. The
   scale is uniform and the box is a fixed ratio, so nothing can distort. */
/* A whisper of scale so the artwork settles into the space being opened for
   it. Uniform, and never below 1, so it can neither distort nor uncover an
   edge. */
.hero__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  transform: scale(1);
  transition: transform var(--dur-slide) var(--ease-slide) var(--delay-slide);
}

.hero__poster,
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;          /* never `fill` — that would distort */
  object-position: center;
  display: block;
  max-width: none;
}

.hero__video {
  opacity: 0;
  /* The hero resolves back to its still far more slowly than a hover
     preview does — it is a 16:9 stage, and a quick dissolve there reads as
     a cut. The fade in is brisker than the fade out. */
  transition: opacity var(--dur-hero-video-out) ease;
}

.hero__slide.video-ready .hero__video {
  opacity: 1;
  transition: opacity var(--dur-hero-video-in) ease;
}

/* Ken Burns ---------------------------------------------------------------
   A very slow uniform drift on the active still: enough to feel alive, far
   too little to read as movement on its own. It starts at scale 1.03 so the
   small pan can never expose an edge, and tops out at 1.085 — well inside
   the resolution headroom of the served asset, so it cannot soften.
   Alternate slides drift the other way, so repeats don't feel mechanical. */
@keyframes hero-kenburns-a {
  from { transform: scale(1.03)  translate3d(0, 0, 0); }
  to   { transform: scale(1.085) translate3d(-0.7%, -0.5%, 0); }
}

@keyframes hero-kenburns-b {
  from { transform: scale(1.085) translate3d(0.7%, 0.4%, 0); }
  to   { transform: scale(1.03)  translate3d(0, 0, 0); }
}

/* Starts as the slide begins opening, not when it lands. The keyframes
   begin at scale 1.03, so binding this to `is-active` meant the artwork
   jumped 3% the instant the reveal finished — the snap. Starting it while
   the slide is still clipped to nothing means the scale is already in place
   by the time any of it is visible. */
.hero__slide.is-active .hero__poster,
.hero__slide.is-moving .hero__poster {
  animation: hero-kenburns-a var(--dur-kenburns) linear both;
}

.hero__slide:nth-child(even).is-active .hero__poster,
.hero__slide:nth-child(even).is-moving .hero__poster {
  animation-name: hero-kenburns-b;
}

/* Hovering holds the whole hero still — drift, progress and timer together */
.hero.is-paused .hero__slide.is-active .hero__poster { animation-play-state: paused; }

/* Scrims ------------------------------------------------------------------ */

/* One of each, on the stage — never inside a slide. Two slides on screen
   during a transition used to mean two overlapping left-scrims, which is
   what turned the stage near-black mid-move. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.hero__scrim--bottom {
  background: linear-gradient(
    to top,
    var(--color-background) 0%,
    rgba(18, 18, 18, 0.72) 18%,
    rgba(18, 18, 18, 0.15) 42%,
    rgba(18, 18, 18, 0) 58%
  );
}

.hero__scrim--left {
  background: linear-gradient(
    to right,
    rgba(18, 18, 18, 0.88) 0%,
    rgba(18, 18, 18, 0.55) 26%,
    rgba(18, 18, 18, 0.12) 48%,
    rgba(18, 18, 18, 0) 66%
  );
}

/* Action panel ------------------------------------------------------------
   Animated on its own rhythm, deliberately offset from the image motion:
   it leaves quickly and early, then settles back in after the artwork has
   already begun travelling. Figma node 7539:164382. */
.hero__action {
  position: absolute;
  left: 0;
  bottom: calc(var(--hero-overlap) + var(--space-3xl));
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-m);
  width: calc(535px + var(--frame-gutter));
  padding-left: var(--frame-gutter);
  /* No `visibility` here on purpose. Toggling it hid the panel the instant
     `is-active` came off, so the exit fade was never seen — and holding it
     with a transition delay just makes that fragile. The children carry the
     whole state in opacity, which animates honestly; `pointer-events` stops
     an inactive panel catching clicks, and js/hero.js sets aria-hidden so it
     is not announced either. */
  pointer-events: none;
}

.hero__action.is-active {
  pointer-events: auto;
}

/* Each line resolves independently — out of focus and slightly low, into
   place — on a long controlled curve. The panel itself does not move with
   the slide; only these properties animate, all compositor-friendly. */
.hero__action > * {
  opacity: 0;
  transform: scale(0.94);
  transform-origin: left center;   /* grows from its own left edge, so the
                                      panel never drifts sideways */
  filter: blur(var(--meta-blur));
  /* The collapse properties ride along in the SAME declaration as the
     entrance ones. Declaring them separately further down the file used to
     win on equal specificity and wipe out the per-line stagger, so the meta
     and tagline arrived before the logo. */
  transition: opacity var(--dur-meta-out) var(--ease-meta-out),
              transform var(--dur-meta-out) var(--ease-meta-out),
              filter var(--dur-meta-out) var(--ease-meta-out),
              max-height var(--dur-minimal) var(--ease-meta-in),
              margin-bottom var(--dur-minimal) var(--ease-meta-in);
}

.hero__action.is-active > * {
  opacity: 1;
  transform: scale(1);
  filter: blur(0);
  transition: opacity var(--dur-meta-in) var(--ease-meta-in) var(--meta-delay),
              transform var(--dur-meta-in) var(--ease-meta-in) var(--meta-delay),
              filter var(--dur-meta-in) var(--ease-meta-in) var(--meta-delay),
              max-height var(--dur-minimal) var(--ease-meta-in),
              margin-bottom var(--dur-minimal) var(--ease-meta-in);
}

/* Minimal state — while a trailer is actually playing.
   The panel gives the picture room: the meta line and the tagline collapse
   away and the title lockup steps down, leaving just the lockup and the
   buttons. Negative margins absorb the flex gap so the column closes up
   instead of leaving holes where the collapsed rows were. */
/* No `transition` here — see the note on .hero__action > *. These two only
   declare the collapsible box; the timing is owned by the state rules. */
.hero__action .hero__meta,
.hero__action .hero__tagline {
  overflow: hidden;
  max-height: 8rem;
}

.hero__action.is-minimal .hero__meta,
.hero__action.is-minimal .hero__tagline {
  opacity: 0;
  max-height: 0;
  margin-bottom: calc(var(--space-m) * -1);   /* cancel the column gap */
  transform: scale(0.96);
  pointer-events: none;
}

.hero__action.is-minimal .hero__logo,
.hero__action.is-minimal .hero__logo--lockup {
  transform: scale(0.74);
  transform-origin: left bottom;
  transition: transform var(--dur-minimal) var(--ease-meta-in);
}

.hero__action > *:nth-child(1) { --meta-delay: calc(var(--delay-meta-in) + var(--meta-stagger) * 0); }
.hero__action > *:nth-child(2) { --meta-delay: calc(var(--delay-meta-in) + var(--meta-stagger) * 1); }
.hero__action > *:nth-child(3) { --meta-delay: calc(var(--delay-meta-in) + var(--meta-stagger) * 2); }
.hero__action > *:nth-child(4) { --meta-delay: calc(var(--delay-meta-in) + var(--meta-stagger) * 3); }

.hero__logo {
  width: 326px;
  height: 108px;
}

.hero__logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: left center;
}

.hero__meta {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--color-white-80);
  font-size: var(--type-body-m-size);
  white-space: nowrap;
}

.hero__tagline {
  width: 471px;
  max-width: 100%;
  color: var(--color-on-surface);
  font-size: var(--type-body-l-size);
}

/* Buttons — Figma 7539:164397: 202x44 primary + 44x44 secondary */
.hero__buttons {
  display: flex;
  align-items: center;
  gap: var(--space-l);
  margin-top: var(--space-xs);
}

.hero .button-primary { width: 202px; height: 44px; }
.hero .button-icon    { width: 44px;  height: 44px; padding: 12px; }

/* Figma 7539:164404 puts a 20px glyph in this 44px button. Pin both axes and
   opt out of the global img{max-width:100%}, which would otherwise squeeze
   the width against the content box while the height stayed at 24. */
.hero .button-icon img,
.hero .button-primary img {
  width: 20px;
  height: 20px;
  max-width: none;
  flex: 0 0 auto;
}

/* Arrows ------------------------------------------------------------------
   Freestanding: no disc, no border, no block — just the chevron, pinned to
   the left and right margins. Legibility over any artwork comes from a drop
   shadow on the glyph plus a soft radial darkening behind it, both of which
   fade up with the arrow rather than sitting there permanently. */
.hero__arrow {
  position: absolute;
  top: calc(var(--hero-visible) / 2);
  transform: translateY(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 84px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur-nav-fade) ease,
              transform var(--dur-nav-fade) var(--ease-zoom);
}

.hero__arrow--next { right: calc(var(--frame-gutter) - 16px); }

.hero:hover .hero__arrow,
.hero:focus-within .hero__arrow { opacity: 0.82; }

.hero__arrow:hover,
.hero__arrow:focus-visible {
  opacity: 1;
  outline: none;
}

.hero__arrow--next:hover { transform: translateY(-50%) translateX(3px); }

/* The soft gradient that keeps the glyph readable on a bright frame */
.hero__arrow::before {
  content: '';
  position: absolute;
  inset: -20px -30px;
  z-index: -1;
  border-radius: 50%;
  /* Felt, not seen — just enough to hold the glyph off a bright frame. */
  background: radial-gradient(closest-side,
              rgba(0, 0, 0, 0.20) 0%,
              rgba(0, 0, 0, 0.09) 55%,
              rgba(0, 0, 0, 0) 100%);
  opacity: 0;
  transition: opacity var(--dur-nav-fade) ease;
}

.hero:hover .hero__arrow::before { opacity: 1; }

.hero__arrow img {
  width: 34px;
  height: 34px;
  display: block;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.7))
          drop-shadow(0 0 10px rgba(0, 0, 0, 0.45));
}


/* Tray: mute + pagination -------------------------------------------------- */

.hero__tray {
  position: absolute;
  right: var(--frame-gutter);
  bottom: var(--space-3xl);      /* relative to .hero, the visible box */
  z-index: 3;
  display: flex;
  align-items: center;
  gap: var(--space-l);
}

/* Kept for when a trailer is supplied; hidden while the hero is stills-only.
   Top right, in the corner the app bar leaves free — down beside the
   pagination it was competing with the metadata for the same eyeline. */
.hero__control--mute {
  position: absolute;
  top: calc(var(--appbar-height) + var(--space-l));
  right: var(--frame-gutter);
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  /* Absent until the item actually has a clip, and then it ARRIVES rather
     than appearing: `display:none` -> `flex` popped it into place the
     instant the slide landed, out of step with everything else on screen.
     It now resolves in on the metadata's own curve, a beat behind the
     buttons, so the whole panel reads as one arrival. */
  opacity: 0;
  visibility: hidden;
  transform: scale(0.88);
  transition: opacity var(--dur-meta-out) var(--ease-meta-out),
              transform var(--dur-meta-out) var(--ease-meta-out),
              visibility 0s linear var(--dur-meta-out);
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.07);
  backdrop-filter: blur(12px);
  cursor: pointer;
  transition: background-color var(--dur-nav-fade) ease;
}

.hero.has-video .hero__control--mute {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity var(--dur-meta-in) var(--ease-meta-in) var(--delay-mute-in),
              transform var(--dur-meta-in) var(--ease-meta-in) var(--delay-mute-in),
              visibility 0s linear var(--delay-mute-in);
}

.hero__control--mute:hover { background: rgba(255, 255, 255, 0.16); }
.hero__control--mute img { width: 24px; height: 24px; display: block; opacity: 0.85; }

/* Pagination --------------------------------------------------------------
   The active item is a pill rather than a dot, and it drains a progress fill
   across the dwell — so the indicator shows both which item is up and how
   much of its time is left. The width animates, so the active state slides
   between positions instead of blinking from one dot to the next. */
.hero__dots {
  display: flex;
  align-items: center;
  gap: 0;              /* the slots carry the spacing; see .hero__dot */
}

/* The slot. Fixed width, transparent, and it is also the hit area — this
   is the part that stops the row jumping. When the active state was the
   button's own width, growing one dot from 8 to 44 reflowed the flex row
   and shoved every other dot sideways mid-transition. Now the geometry of
   the row is constant and only the bar inside a slot changes. */
.hero__dot {
  position: relative;
  width: var(--dot-slot);        /* 44px */
  height: 20px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.hero__dot-bar {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--dot-size);        /* 10px */
  height: var(--dot-size);
  transform: translate(-50%, -50%);
  border-radius: var(--radius-full);
  /* No drop shadow: it read as a hard black smudge under every dot. The
     legibility comes from opacity instead — these sit inside the hero's
     own bottom scrim, which is already darkening this band, so an opaque
     white carries perfectly well on its own. */
  background: rgba(255, 255, 255, 0.72);
  /* Same duration, curve and delay as the slide, so the indicator travels
     with the carousel rather than snapping after it. */
  transition: width var(--dur-slide) var(--ease-slide) var(--delay-slide),
              background-color var(--dur-slide) var(--ease-slide) var(--delay-slide);
}

/* The active item is simply the brand yellow, solid, at full slot width —
   always, from the moment it becomes active. It used to be a 35% bed with
   a progress fill draining across it, which meant that for most of an
   item's turn the indicator was a pale wash rather than a yellow pill. */
.hero__dot[aria-current="true"] .hero__dot-bar {
  width: var(--dot-slot);
  background: var(--color-primary);
}

.hero__dot:hover .hero__dot-bar,
.hero__dot:focus-visible .hero__dot-bar { background: rgba(255, 255, 255, 0.85); }
.hero__dot:focus-visible { outline: none; }
.hero__dot[aria-current="true"]:hover .hero__dot-bar { background: var(--color-primary); }

/* The draining progress fill is gone — see the note above. */

/* The first rail rides over the hero's bleed ------------------------------ */
.rail--over-hero {
  position: relative;
  z-index: 1;
}

/* Cinema ------------------------------------------------------------------
   While a trailer is actually playing AND the pointer has gone quiet, the
   page steps out of the way: the metadata has already collapsed to its
   lockup and buttons (.is-minimal), and everything below the hero drops by
   --cinema-drop so more of the plate shows through.

   EVERYTHING below, not just the first rail — moving one rail alone would
   walk it into the next one. The drop is exactly the rail's own 64px
   bottom padding, so nothing can ever collide, and the page simply gains
   64px of slack at the foot.

   Any pointer movement puts it all back (js/hero.js). The clip keeps
   playing regardless: it stops only when it ends, when the hero is
   scrolled out of view, or when the item changes. */
.hero__action,
.hero__tray,
.hero ~ * {
  transition: transform var(--dur-cinema) var(--ease-morph-in);
}

/* The pagination travels with the metadata and the rails — it sits inside
   .hero, so the sibling selector below never reached it and it was the one
   thing left behind while everything around it stepped down. */
.hero.is-cinema ~ *,
.hero.is-cinema .hero__action,
.hero.is-cinema .hero__tray {
  transform: translateY(var(--cinema-drop));
}

@media (prefers-reduced-motion: reduce) {
  .hero__action,
  .hero__tray,
  .hero ~ * { transition: none; }
  .hero.is-cinema ~ *,
  .hero.is-cinema .hero__action,
  .hero.is-cinema .hero__tray { transform: none; }
}

/* Reduced motion ----------------------------------------------------------
   No travel, no drift, no auto-advance (that is enforced in hero.js). The
   indicator still marks the active item; it just doesn't animate. */
@media (prefers-reduced-motion: reduce) {
  .hero__slide,
  .hero__media,
  .hero__action,
  .hero__video,
  .hero__dot-bar,
  .hero__arrow,
  .hero__nav {
    transition: none;
  }

  .hero__slide.is-active .hero__poster { animation: none; }

  .hero__action > *,
  .hero__action.is-active > * {
    transition: none;
    transform: none;
    filter: none;
  }
}

/* Title lockup with a subtitle ---------------------------------------------
   "Avatar: The Way of Water" is not available as a single exported asset —
   only the AVATAR wordmark is. The subtitle is typeset beneath it in the
   film's manner (wide-tracked caps) so the slide reads as the right title.
   Replace the whole block with a real lockup image if one turns up. */
.hero__logo--lockup {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  height: 108px;
}

.hero__logo--lockup img {
  width: auto;
  height: 62px;
  object-fit: contain;
  object-position: left center;
}

.hero__logo-sub {
  padding-left: 3px;
  color: var(--color-on-surface);
  font-size: 15px;
  font-weight: var(--type-weight-regular);
  letter-spacing: 0.42em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0.92;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
}
