/* ==========================================================================
   trailer-card.css — hover preview, three variants for review
   --------------------------------------------------------------------------
   A1 "panel"       Figma 7539:166281 — 398 x ~362. Video on top, then a
                    progress bar, then an info panel: title, description,
                    meta line and three actions on a dark surface.
   A2 "panel-logo"  Same box and same growth, stripped back: the title
                    lockup sits on the artwork instead of being typeset,
                    the synopsis is gone, and the panel carries only three
                    mini actions (play, watchlist, rate) over one meta line.
   B  "overlay"     Figma 7539:166355 — 538 x 303. Full-bleed video with
                    everything floated on it: title lockup, meta, mute +
                    progress bottom-left, actions bottom-right, big play.

   A1 and A2 float above the rail in a fixed-position layer, so opening one
   never moves a card or reflows a rail. B grows inside the row instead.

   Which rail uses which is set in js/trailer-card.js; `?hover=a1`, `a2` or
   `b` forces one everywhere for side-by-side comparison.
   ========================================================================== */

.trailer-layer {
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;   /* only the card itself is interactive */
}

.trailer-card {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  border: 1.5px solid var(--card-outline-hover);   /* white @80 */
  border-radius: 10.182px;
  overflow: hidden;
  background: var(--color-surface);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.6),
              0 4px 14px rgba(0, 0, 0, 0.45);
  /* Morphs out of the card it came from: js/trailer-card.js seeds left/top/
     width/height with the source card's own rect, then animates the box to
     the preview's size. The content is never scaled, so nothing distorts.
     Geometry is animated via the Web Animations API, which states both
     keyframes explicitly — see the note there.

     NO opacity transition on the way in. It used to fade up over 180ms
     while sitting exactly on the card, so for those frames you saw the
     card's own lockup and progress bar THROUGH the preview's — two sets
     of everything at once. It is opaque from the first frame now; the
     fade out is in retract()'s keyframes. */
}

.trailer-card.is-open {
  opacity: 1;
  pointer-events: auto;
}

/* ---- Chrome -------------------------------------------------------------
   The chrome does not travel with the box. It waits out most of the growth
   (--delay-chrome) and then resolves in a short stagger, each line settling
   a few pixels up into place. That pause in the middle is what stops the
   open reading as one flat move: the card grows, holds, then furnishes.

   Every element below carries a --chrome-i, its place in the stagger. The
   two state rules own the timing outright — no other rule may set
   `transition` on these, or its shorthand would silently drop the delay. */
.trailer-card__mute,
.trailer-card__bigplay,
.trailer-card__progress,
.trailer-card__logo,
.trailer-card__title,
.trailer-card__desc,
.trailer-card__meta,
.trailer-card__actions,
.trailer-card__sound {
  --chrome-i: 0;
  opacity: 0;
  transform: translateY(var(--chrome-lift));
  /* The last two are only meaningful for the mute button, which is also a
     .trailer-btn: that rule's own `transition` shorthand ties on specificity
     with this one, so its colour feedback has to be restated here or the
     later declaration would drop it. */
  transition: opacity var(--dur-chrome-out) var(--ease-morph-out),
              transform var(--dur-chrome-out) var(--ease-morph-out),
              background-color var(--dur-ring) ease,
              border-color var(--dur-ring) ease;
}

.trailer-card.is-settled .trailer-card__mute,
.trailer-card.is-settled .trailer-card__bigplay,
.trailer-card.is-settled .trailer-card__progress,
.trailer-card.is-settled .trailer-card__logo,
.trailer-card.is-settled .trailer-card__title,
.trailer-card.is-settled .trailer-card__desc,
.trailer-card.is-settled .trailer-card__meta,
.trailer-card.is-settled .trailer-card__actions,
.trailer-card.is-settled .trailer-card__sound {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-chrome) var(--ease-meta-in)
                calc(var(--delay-chrome) + var(--chrome-stagger) * var(--chrome-i)),
              transform var(--dur-chrome) var(--ease-meta-in)
                calc(var(--delay-chrome) + var(--chrome-stagger) * var(--chrome-i)),
              background-color var(--dur-ring) ease,
              border-color var(--dur-ring) ease;
}

/* Reading order of the stagger, top of the card downwards. */
.trailer-card__logo     { --chrome-i: 0; }
.trailer-card__title    { --chrome-i: 0; }
.trailer-card__progress { --chrome-i: 1; }
.trailer-card__desc     { --chrome-i: 1; }
.trailer-card__actions  { --chrome-i: 2; }
.trailer-card__meta     { --chrome-i: 3; }
.trailer-card__sound    { --chrome-i: 3; }
/* A1 reads title, synopsis, facts, actions; A2 reads lockup, actions,
   facts. The stagger follows the eye, so the two flavours differ here. */
.trailer-card--panel .trailer-card__meta    { --chrome-i: 2; }
.trailer-card--panel .trailer-card__actions { --chrome-i: 3; }
.trailer-card__mute     { --chrome-i: 4; }
.trailer-card__bigplay  { --chrome-i: 4; }

/* The card underneath hands over rather than lingering: its own chrome
   goes as the preview's arrives, so there is never a moment with two
   lockups, two progress bars and two titles stacked on the same pixels. */
.card-cw.is-previewing .card-cw__logo,
.card-cw.is-previewing .card-cw__info,
.card-cw.is-previewing .card-cw__scrim,
.card-poster.is-previewing .card-badge {
  opacity: 0;
  transition: opacity 0.16s var(--ease-morph-out);
}

.card-cw__logo,
.card-cw__info,
.card-cw__scrim,
.card-badge {
  transition: opacity var(--dur-chrome) var(--ease-meta-in) 0.12s;
}

/* Travelling between cards: the new content resolves up while the box
   glides, instead of being cut in on a single frame. Short, and offset a
   touch so the move starts before the content changes. */
.trailer-card.is-reflowing .trailer-card__poster,
.trailer-card.is-reflowing .trailer-card__text,
.trailer-card.is-reflowing .trailer-card__logo,
.trailer-card.is-reflowing .trailer-card__meta {
  animation: tc-reflow 0.34s var(--ease-meta-in) both;
}

.trailer-card.is-reflowing .trailer-card__text { animation-delay: 0.05s; }
.trailer-card.is-reflowing .trailer-card__meta { animation-delay: 0.08s; }

@keyframes tc-reflow {
  from { opacity: 0; transform: translateY(6px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .trailer-card.is-reflowing .trailer-card__poster,
  .trailer-card.is-reflowing .trailer-card__text,
  .trailer-card.is-reflowing .trailer-card__logo,
  .trailer-card.is-reflowing .trailer-card__meta { animation: none; }
}

/* Retracting gets the same care as arriving, run backwards: the chrome
   leaves last-line-first on a tighter interval, clearing the box before it
   starts shrinking, instead of every line blinking out together. */
.trailer-card.is-closing { pointer-events: none; }

.trailer-card.is-closing .trailer-card__mute,
.trailer-card.is-closing .trailer-card__bigplay,
.trailer-card.is-closing .trailer-card__progress,
.trailer-card.is-closing .trailer-card__logo,
.trailer-card.is-closing .trailer-card__title,
.trailer-card.is-closing .trailer-card__desc,
.trailer-card.is-closing .trailer-card__meta,
.trailer-card.is-closing .trailer-card__actions,
.trailer-card.is-closing .trailer-card__sound {
  transition: opacity var(--dur-chrome-out) var(--ease-morph-out)
                calc(var(--chrome-stagger-out) * (var(--chrome-depth) - var(--chrome-i))),
              transform var(--dur-chrome-out) var(--ease-morph-out)
                calc(var(--chrome-stagger-out) * (var(--chrome-depth) - var(--chrome-i)));
}

/* Media ------------------------------------------------------------------- */

.trailer-card__media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #000;
  /* Not negotiable as a flex item: the card is a fixed-height column, so a
     shrinkable media would be squeezed to fit and the height js/trailer-
     card.js animates during the morph would be silently ignored. */
  flex: 0 0 auto;
}

/* The still is not a fresh image — it is the source card's own artwork,
   cloned node for node by js/trailer-card.js, so the morph carries the very
   picture you were pointing at instead of cutting to a different one.

   Because a card's art may be a stack of layers positioned by percentages
   of its own box, the clone is given a box with the CARD's aspect ratio and
   then centred inside the 16:9 window. Every inline percentage in the clone
   therefore still resolves against the geometry it was authored for; the
   16:9 frame simply crops it. --poster-bias nudges the crop band for tall
   posters, where the centre of a 2:3 image is not the interesting part. */
.trailer-card__poster {
  position: absolute;
  inset: 0;
  overflow: hidden;
  display: grid;
  align-content: center;
}

/* REVERTED (see source.md §24). This was briefly a letterbox treatment —
   the subject kept the card's shape and sat on a blurred bed of its own
   artwork, with a landscape still cross-fading in where one existed. It
   was not liked, so the preview is back to filling the window: the clone
   is the full width of the media and cropped by it.

   The blurred bed and the landscape layer are gone from the markup. The
   `land:` entries stay in the CATALOGUE in js/trailer-card.js — five
   titles have landscape artwork — so re-enabling that on its own is a
   small change if the crop ever needs addressing another way. */
.trailer-card__poster-inner {
  position: relative;
  width: 100%;
  aspect-ratio: var(--poster-ratio, 16 / 9);
  transform: translateY(var(--poster-bias, 0%));
}

/* Variant B widens the real card, so its own artwork is cover-cropped to
   the wider box. The clone has to do exactly that too, or the two would
   show different crops of the same picture as they cross-fade. */
.trailer-card__poster--fill .trailer-card__poster-inner {
  position: absolute;
  inset: 0;
  width: auto;
  aspect-ratio: auto;
  transform: none;
}

.trailer-card__poster-inner > * { position: absolute; inset: 0; }

.trailer-card__poster-inner img {
  width: 100%;
  height: 100%;
  object-fit: cover;        /* never `fill` — that would distort */
  display: block;
  max-width: none;
}

/* A cloned .card-poster__layer keeps its own inline crop box, so it must
   not be re-fitted — same rule as on the card itself. */
.trailer-card__poster-inner .card-poster__layer img {
  position: absolute;
  object-fit: fill;   /* its inline width/height ARE the crop */
}

.trailer-card__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  max-width: none;
}

.trailer-card__video {
  opacity: 0;
  transition: opacity var(--dur-video-fade) ease;
}

.trailer-card.video-ready .trailer-card__video { opacity: 1; }

/* The close affordance is gone from both variants. A hover preview closes
   when you stop hovering it — an X was a control for a state the user
   cannot get stuck in. Its top-bar gradient went with it, since that
   existed only to hold the glyph off the artwork. */

/* ---- Secondary audio control ---------------------------------------------
   ONE treatment for all three previews. They had drifted apart: A1 and A2
   used the yellow-tinted action circle (brand yellow on brand yellow, over
   whatever the artwork was doing), while B used a bare 18px glyph with no
   container at all and nothing behind it. Neither read reliably on video.

   Container, everywhere — a dark blurred disc with the near-white glyph
   the hero already uses. Deliberately NOT the yellow action style: this
   is a utility, not one of the three things you came here to do. The
   hero's own control is a different, larger component and is untouched. */
.trailer-mute {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: var(--radius-full);
  background: rgba(12, 12, 12, 0.55);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  cursor: pointer;
}

.trailer-mute:hover,
.trailer-mute:focus-visible {
  background: rgba(12, 12, 12, 0.78);
  border-color: rgba(255, 255, 255, 0.55);
  outline: none;
}

.trailer-mute img {
  display: block;
  width: 16px;
  height: 16px;
  max-width: none;
  flex: 0 0 auto;
}

/* The yellow-tinted circular action, shared by both variants */
.trailer-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10.909px;
  border: 1.2px solid var(--color-primary-20);
  border-radius: var(--radius-full);
  background: var(--color-primary-20);
  cursor: pointer;
  flex: 0 0 auto;
  transition: background-color var(--dur-ring) ease,
              border-color var(--dur-ring) ease;
}

.trailer-btn:hover,
.trailer-btn:focus-visible {
  background: var(--color-primary-30);
  border-color: var(--accent-ring-hover);
  outline: none;
}

.trailer-btn img { display: block; width: 18px; height: 18px;
                   max-width: none; flex: 0 0 auto; }

.trailer-card__progress {
  position: relative;
  height: 5.091px;
  width: 100%;
  background: var(--color-surface-variant);
  flex: 0 0 auto;
}

.trailer-card__progress span {
  position: absolute;
  inset: 0 auto 0 0;
  width: 31.25%;
  background: var(--color-primary);
}


/* ==========================================================================
   Variant A — "panel"  (Figma 7539:166281)
   --------------------------------------------------------------------------
   Two flavours share this box and this growth:
     A1 .trailer-card--panel       typeset title + synopsis + meta + actions
     A2 .trailer-card--panel-logo  lockup on the art, actions + one meta line
   ========================================================================== */

.trailer-card--panel,
.trailer-card--panel-logo {
  display: flex;
  flex-direction: column;
}

/* A2 is the picture and nothing else — its panel floats on it, so the box
   is exactly 16:9 with no second block underneath. */
.trailer-card--panel-logo { background: #000; }

.trailer-card--panel-logo .trailer-card__progress {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 4;
  height: 4px;
  background: rgba(255, 255, 255, 0.22);
}

/* Mute sits inside the video, bottom-right */
.trailer-card--panel .trailer-card__mute {
  position: absolute;
  right: 14px;
  bottom: 14px;
  z-index: 3;
}

/* A2's foot is occupied by the panel, so audio sits top right instead. */
.trailer-card--panel-logo .trailer-card__mute {
  position: absolute;
  right: 14px;
  top: 14px;
  z-index: 4;
}

.trailer-card--panel .trailer-card__info {
  display: flex;
  align-items: center;
  padding: 10.182px;
}

.trailer-card--panel .trailer-card__text {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1 0 0;
  min-width: 0;
}

.trailer-card--panel .trailer-card__title {
  color: var(--color-on-surface);
  font-size: 20.36px;
  font-weight: var(--type-weight-semi-bold);
  line-height: 1.5;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.trailer-card--panel .trailer-card__desc {
  color: var(--color-on-surface-variant);
  font-size: 15.27px;
  font-weight: var(--type-weight-regular);
  line-height: 1.5;
  /* Figma sets this nowrap against a fixed width; clamping instead keeps a
     real sentence readable at the demo's card width. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.trailer-card--panel .trailer-card__meta {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--color-white-80);
  font-size: 12px;
  white-space: nowrap;
}

.trailer-card--panel .trailer-card__actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.trailer-card--panel .trailer-card__logo,
.trailer-card--panel .trailer-card__bigplay { display: none; }


/* ==========================================================================
   Variant A2 — "panel-logo"
   --------------------------------------------------------------------------
   The same 398-wide box and the same growth as A1, argued the other way:
   the title is the show's own lockup sitting on the artwork (where a viewer
   already expects to read it), the synopsis is dropped entirely, and the
   panel underneath carries only what you act on — play, watchlist, rate —
   above a single line of facts.
   ========================================================================== */

.trailer-card--panel-logo .trailer-card__bigplay { display: none; }

/* A shallow foot. It was reaching two thirds of the way up the frame and
   the clip was barely visible behind it; it now stops at about a third. */
.trailer-card--panel-logo .trailer-card__scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: linear-gradient(to top,
    rgba(10, 10, 10, 0.88) 0%,
    rgba(10, 10, 10, 0.55) 14%,
    rgba(10, 10, 10, 0.16) 26%,
    rgba(10, 10, 10, 0) 38%);
}

.trailer-card--panel-logo .trailer-card__logo {
  width: 38%;
  max-width: 190px;
  height: 34px;
  display: block;
}

.trailer-card--panel-logo .trailer-card__logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;                 /* wordmarks keep their own ratio */
  object-position: left bottom;
  max-width: none;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.85));
}

/* Fallback when a title has no lockup: set the name instead of inventing
   artwork for it. Same slot, same weight in the layout. */
.trailer-card--panel-logo .trailer-card__logo--text {
  display: flex;
  align-items: flex-end;
  width: 70%;
  color: var(--color-on-surface);
  font-size: 20.36px;
  font-weight: var(--type-weight-semi-bold);
  line-height: 1.25;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.85);
}

/* The panel is a blurred, tinted plate sitting ON the picture — no grey
   block under it. The blur keeps a meta line readable over a busy frame
   without blacking the artwork out, and the plate is kept shallow so the
   clip behind it is still the thing you are looking at. */
.trailer-card--panel-logo .trailer-card__info {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 18px 16px;
  background-image: linear-gradient(to top,
    rgba(10, 10, 10, 0.55) 0%,
    rgba(10, 10, 10, 0.22) 60%,
    rgba(10, 10, 10, 0) 100%);
  -webkit-backdrop-filter: blur(12px) saturate(120%);
          backdrop-filter: blur(12px) saturate(120%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 58%, transparent 100%);
          mask-image: linear-gradient(to top, #000 0%, #000 58%, transparent 100%);
}

/* Actions and facts on one line. */
.trailer-card--panel-logo .trailer-card__foot {
  display: flex;
  align-items: center;
  gap: var(--space-l);
  width: 100%;
  min-width: 0;
}

.trailer-card--panel-logo .trailer-card__meta {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.trailer-card--panel-logo .trailer-card__actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.trailer-card--panel-logo .trailer-card__meta {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--color-white-80);
  font-size: var(--type-body-s-size);   /* 14px */
  line-height: 1.5;
  white-space: nowrap;
  overflow: hidden;
}

/* A2's actions are the same size as every other preview's — they were
   30px against 40 everywhere else, which read as a different component. */

/* The primary of the three reads solid, the other two as outlines, so the
   row has a clear first action instead of three equal circles. */
.trailer-btn--primary {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.trailer-btn--primary:hover,
.trailer-btn--primary:focus-visible {
  background: var(--color-primary);
  border-color: var(--color-on-surface);
}

/* The outline glyphs are authored in brand yellow; on the solid button the
   glyph has to be the ground colour instead. This was done by masking the
   yellow asset, which meant the button rendered as a blank yellow disc
   anywhere the mask did not resolve, with nothing in the markup to show
   for it. icon-play-20 is already filled #121212 — the hero's primary Play
   button uses it — so js/trailer-card.js now sets that as a plain <img>
   and there is no recolouring left to fail. */


/* ==========================================================================
   Variant B — "in-rail"  (Figma 7539:166355 content, 7539:165485 in situ)
   --------------------------------------------------------------------------
   This one does not grow *in* size over its neighbours — it grows *to* size
   inside the row. The card's own width animates 202 -> 538 while its height
   stays at 303, so the flex rail pushes everything after it to the right,
   exactly as the Figma frame shows. Nothing floats and nothing overlaps.
   ========================================================================== */

/* Retracting is quicker than growing and uses the mirrored curve, so the
   row closing up reads as the same gesture run backwards. Both ends of both
   moves are eased: the rail never starts or stops at speed. */
.card-poster {
  transition: width var(--dur-morph-out) var(--ease-morph-out);
}

.card-poster.is-expanded {
  width: var(--card-expanded-width);        /* 538px */
  z-index: 2;
  transition: width var(--dur-trailer-grow) var(--ease-morph-in);
}

/* The landscape treatment that resolves in over the poster as it widens */
.card-trailer {
  position: absolute;
  inset: 0;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-morph-out) var(--ease-morph-out);
}

.card-poster.is-expanded .card-trailer {
  opacity: 1;
  pointer-events: auto;
  transition: opacity var(--dur-chrome) var(--ease-meta-in) 0.14s;
}

/* Same staggered furnishing as variant A, so the two read as one family. */
.card-trailer__logo,
.card-trailer__meta,
.card-trailer__sound,
.card-trailer__actions {
  --chrome-i: 0;
  opacity: 0;
  transform: translateY(var(--chrome-lift));
  transition: opacity var(--dur-chrome-out) var(--ease-morph-out),
              transform var(--dur-chrome-out) var(--ease-morph-out);
}

/* The logo's selector was written twice — `.card-poster.is-expanded
   .card-poster.is-expanded` needs one card nested inside another, which
   never exists — so the lockup never left the opacity: 0 it starts at
   above. Every Most Popular preview has been showing genre and year with
   no title on it. */
.card-poster.is-expanded .card-trailer__logo,
.card-poster.is-expanded .card-trailer__meta,
.card-poster.is-expanded .card-trailer__sound,
.card-poster.is-expanded .card-trailer__actions {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-chrome) var(--ease-meta-in)
                calc(var(--delay-chrome) + var(--chrome-stagger) * var(--chrome-i)),
              transform var(--dur-chrome) var(--ease-meta-in)
                calc(var(--delay-chrome) + var(--chrome-stagger) * var(--chrome-i));
}

.card-trailer__logo    { --chrome-i: 0; }
.card-trailer__meta    { --chrome-i: 1; }
.card-trailer__sound   { --chrome-i: 2; }
.card-trailer__actions { --chrome-i: 2; }

/* Same backwards exit as variant A. js/trailer-card.js holds .is-collapsing
   on the card for the length of the retract. */
.card-poster.is-collapsing .card-trailer__logo,
.card-poster.is-collapsing .card-trailer__meta,
.card-poster.is-collapsing .card-trailer__sound,
.card-poster.is-collapsing .card-trailer__actions {
  transition: opacity var(--dur-chrome-out) var(--ease-morph-out)
                calc(var(--chrome-stagger-out) * (var(--chrome-depth) - var(--chrome-i))),
              transform var(--dur-chrome-out) var(--ease-morph-out)
                calc(var(--chrome-stagger-out) * (var(--chrome-depth) - var(--chrome-i)));
}

/* The panel itself only starts fading once its contents have gone. */
.card-poster.is-collapsing .card-trailer {
  transition: opacity var(--dur-chrome-out) var(--ease-morph-out) 0.16s;
}

/* The big play is centred with a translate of its own, so it can only
   stagger on opacity — a translateY here would knock it off centre. */
.card-trailer__bigplay {
  opacity: 0;
  transition: opacity var(--dur-morph-out) var(--ease-morph-out),
              transform var(--dur-ring) var(--ease-zoom);
}

.card-poster.is-expanded .card-trailer__bigplay {
  opacity: 1;
  transition: opacity var(--dur-chrome) var(--ease-meta-in)
                calc(var(--delay-chrome) + var(--chrome-stagger) * 3),
              transform var(--dur-ring) var(--ease-zoom);
}

/* B's still is the same cloned-artwork slot as A's — see
   .trailer-card__poster above; the class is shared deliberately. */
.card-trailer__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  max-width: none;
}

.card-trailer__video { opacity: 0; transition: opacity var(--dur-video-fade) ease; }
.card-poster.video-ready .card-trailer__video { opacity: 1; }

/* The foot carries the metadata on the left and the action row on the
   right, both over whatever the artwork happens to be doing there.

   The previous bottom wash was a 176deg gradient running from transparent
   at 67.5% to 0.8 at 98.4%: on a 303px card that is only ~0.30 alpha where
   the metadata actually sits, which disappears over a bright frame — the
   Interstellar still is near-white exactly there, and the yellow glyphs on
   the action discs went with it.

   So the bottom wash is measured from the bottom up instead, and is at
   full strength across the whole band the chrome occupies rather than
   only in the last few pixels. The top wash and the left corner are
   unchanged. */
.card-trailer__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* top — for the badge and the card's own edge */
    linear-gradient(180deg, rgba(18, 18, 18, 0.8) 0%, rgba(18, 18, 18, 0) 23.1%),
    /* bottom — the band holding the lockup, the metadata and the actions.
       It has to reach the LOCKUP, not just the text: the info column is
       about 104px of a 303px card, so the wash has to still be doing work
       at ~34%. It was 0.5 there, and these lockups are white wordmarks —
       on the Interstellar still, which is near-white behind them, they
       were invisible and the card read as having no logo at all. */
    linear-gradient(0deg,
      rgba(18, 18, 18, 0.94) 0%,
      rgba(18, 18, 18, 0.90) 18%,
      rgba(18, 18, 18, 0.78) 34%,
      rgba(18, 18, 18, 0.44) 46%,
      rgba(18, 18, 18, 0.12) 58%,
      rgba(18, 18, 18, 0) 68%),
    /* bottom-left corner — deepens behind the longest metadata line */
    linear-gradient(234deg, rgba(18, 18, 18, 0) 48.9%, rgba(18, 18, 18, 0.8) 100%);
}

.card-trailer__info {
  position: absolute;
  left: 14.5px;
  bottom: 14px;
  width: 170px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.card-trailer__logo { width: 100%; height: 56.319px; }
/* Two tight shadows, and deliberately no wide glow. The Continue Watching
   lockup carries three including a 22px one, but that card is a 16:9 still
   where the wordmark sits in the middle of open space. These wordmarks run
   the full width of a 170px column, so a 22px blur from every glyph merges
   with its neighbours into a solid rectangle behind the lockup — the same
   smudge-belonging-to-nothing that was removed from the CW card. The scrim
   holds ~0.78 at this height, so the shadows only have to separate the
   glyph edges, not light the whole band. */
.card-trailer__logo img {
  width: 100%; height: 100%;
  object-fit: contain; object-position: left center;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.85))
          drop-shadow(0 2px 8px rgba(0, 0, 0, 0.5));
}

.card-trailer__meta {
  display: flex; flex-direction: column;
  color: var(--color-on-surface);
  font-size: 14px; line-height: 1.5;
}
.card-trailer__meta-row { display: flex; align-items: center; gap: var(--space-xs); }

/* The mute control alone. It no longer stretches: with the progress bar
   gone there is nothing to share the row with, and `width: 100%` would
   leave the disc floating at the end of 170px of nothing. (The progress
   bar rules that lived here are gone with it — variant A keeps its own,
   .trailer-card__progress, which is a different element.) */
.card-trailer__sound { display: flex; align-items: center; gap: var(--space-m); }

.card-trailer__actions {
  position: absolute; right: 16px; bottom: 14px;
  display: flex; align-items: center; gap: 12px;
}

.card-trailer__bigplay {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 38.333px; height: 43.333px;
  padding: 0; border: 0; background: none; cursor: pointer;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.7));
  /* No `transition` here — it is owned by the stagger rules above, whose
     specificity this ties with. A shorthand at this point would replace
     theirs outright and take the opacity delay with it. */
}
.card-trailer__bigplay:hover { transform: translate(-50%, -50%) scale(1.1); }
.card-trailer__bigplay img { width: 100%; height: 100%; }


/* Reduced motion: no growth, no autoplay (enforced in js/trailer-card.js).
   The staggered furnishing goes too — everything simply is there, at once,
   with only a short cross-fade so nothing snaps. --chrome-lift is zeroed
   rather than the rules being unpicked, so the travel disappears while the
   fade and the ordering logic stay intact. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --chrome-lift: 0px;
    --delay-chrome: 0s;
    --chrome-stagger: 0s;
    --dur-chrome: 0.2s;
    --dur-chrome-out: 0.15s;
    --dur-trailer-grow: 0.2s;
    --dur-morph-out: 0.15s;
  }

  .trailer-card,
  .card-poster,
  .card-trailer { transition: opacity 0.2s ease; }

  .trailer-card__video,
  .card-trailer__video { transition: none; }
}
