/* ============================================================================
   SOARCERY INDEX HERO: THE TRAILER (Spec 05, docs/specs/05-pivot-restory.md)
   A 4-scene cinematic "trailer" of plain-English security automation.
   ASK (the Familiar) > PLAN (the Spell) > APPROVE (the Seal) > PROVE (receipt).
   The Familiar and the Seal scenes inject their own styles; the Spell scene's
   styles live below. Site deltas:
   tokens come from site.css, height respects the sticky header, and every
   scene's visual stage is clipped above the copy block (--stage-clear is set
   by trailer.js from the measured copy height) so NOTHING can overlap the
   words, in any scene or animation. Three-light: purple=Soarcery/AI,
   teal=resolved/human, orange=attention, red=confirmed-bad.
   ============================================================================ */

.trailer{position:relative;width:100%;height:calc(100vh - var(--nav-h,69px));min-height:640px;max-height:980px;overflow:hidden;
  background:radial-gradient(120% 90% at 50% -10%,rgba(124,58,237,.06),transparent 60%),#050508}

/* ---- progress bar (top) ---- */
.t-progress{position:absolute;top:0;left:0;right:0;height:2px;z-index:30;background:rgba(255,255,255,.05)}
.t-progress-fill{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--purple-400),var(--purple-300));box-shadow:0 0 12px var(--purple-glow)}

/* ---- ambient field ---- */
.t-field{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.t-field .halo{position:absolute;border-radius:9999px;filter:blur(110px);transition:background 1.2s ease,opacity 1.2s ease,transform 1.2s ease}
.halo-a{top:-22%;left:-4%;width:60vw;height:60vw;max-width:880px;max-height:880px;opacity:.46;background:radial-gradient(circle,var(--purple-glow),transparent 60%)}
.halo-b{top:12%;right:4%;width:42vw;height:42vw;opacity:.22;background:radial-gradient(circle,var(--teal-glow),transparent 60%)}
.halo-c{bottom:-34%;left:34%;width:42vw;height:42vw;opacity:.14;background:radial-gradient(circle,var(--orange-glow),transparent 60%)}
.t-grid{position:absolute;inset:auto 0 0 0;height:52%;
  background-image:linear-gradient(rgba(124,58,237,.07) 1px,transparent 1px),linear-gradient(90deg,rgba(124,58,237,.07) 1px,transparent 1px);
  background-size:52px 52px;-webkit-mask-image:linear-gradient(to top,#000,transparent);mask-image:linear-gradient(to top,#000,transparent);
  transform:perspective(680px) rotateX(60deg);transform-origin:bottom;opacity:.4}
.t-dust{position:absolute;inset:0}
.t-dust i{position:absolute;width:2px;height:2px;border-radius:9999px;background:#fff;animation:t-tw 6s ease-in-out infinite}
@keyframes t-tw{0%,100%{opacity:.05}50%{opacity:.3}}

/* field tints per scene (set on .trailer[data-scene]) */
.trailer[data-scene="1"] .halo-b{opacity:.26}
.trailer[data-scene="2"] .halo-a{opacity:.6} .trailer[data-scene="2"] .halo-b{opacity:.1}
.trailer[data-scene="3"] .halo-b{opacity:.3} .trailer[data-scene="3"] .halo-c{opacity:.2}
.trailer[data-scene="4"] .halo-a{opacity:.32} .trailer[data-scene="4"] .halo-b{opacity:.36;background:radial-gradient(circle,var(--teal-glow),transparent 60%)}

/* ---- scenes ---- */
.t-scenes{position:absolute;inset:0;z-index:2}
.scene{position:absolute;inset:0;opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .8s ease,visibility .8s ease}
.scene.is-active{opacity:1;visibility:visible;pointer-events:auto}

/* the staged area where each scene's visual lives. The bottom boundary is the
   no-overlap guarantee: trailer.js measures the tallest copy block and sets
   --stage-clear so the stage (overflow:hidden) ends above the words. */
/* contain:paint hardens the clip cross-engine: it forces the stage to crop its
   descendants to its own box on every engine (belt and braces over overflow:
   hidden), so a scene visual can never paint outside the stage on the animated
   desktop/iPad path either (KAN-227 4e). */
.scene-stage{position:absolute;left:0;right:0;top:0;bottom:var(--stage-clear,44%);z-index:2;overflow:hidden;contain:paint}
/* top-center scene title (the "shot" label) */
.scene-kicker{position:absolute;top:34px;left:0;right:0;z-index:4;text-align:center;pointer-events:none}
.scene-kicker .k1{display:block;font-family:var(--font-mono);font-size:14px;font-weight:600;letter-spacing:.28em;text-transform:uppercase;color:var(--fg)}
.scene-kicker .k2{display:block;font-family:var(--font-mono);font-size:12.5px;letter-spacing:.24em;text-transform:uppercase;color:var(--purple-300);margin-top:9px}

/* ---- headline block (lower-left, per scene) ---- */
.scene-copy{position:absolute;left:clamp(28px,5vw,72px);bottom:6vh;z-index:5;max-width:min(640px,52vw)}
.scene-copy .eyebrow{display:inline-flex;align-items:center;gap:9px;font-family:var(--font-mono);font-size:12px;font-weight:500;
  text-transform:uppercase;letter-spacing:.18em;color:var(--purple-300)}
.scene-copy .eyebrow .tick{width:8px;height:8px;border-radius:9999px;background:var(--purple-400);box-shadow:0 0 12px var(--purple-glow)}
.scene-copy h1,.scene-copy .t-h1{font-size:clamp(30px,3.6vw,46px);line-height:1.04;letter-spacing:-.034em;margin:14px 0 0;text-wrap:balance;font-weight:600}
.scene-copy .grad{background:linear-gradient(108deg,#fff 6%,var(--purple-300) 54%,var(--purple-400) 92%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.scene-copy .grad-teal{background:linear-gradient(108deg,#fff 6%,var(--teal-300) 60%,var(--teal-400) 95%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.scene-copy .sub{font-size:clamp(14.5px,1.5vw,17px);line-height:1.5;color:var(--fg-muted);margin:14px 0 0;max-width:560px}
.scene-copy .sub b{color:var(--fg-secondary);font-weight:600}
.scene-copy .cta-row{display:flex;gap:13px;margin-top:20px;flex-wrap:wrap}
/* buttons come from site.css (.btn/.btn-lg/.btn-cast/.btn-ghost) */
/* server-rendered SEO copy block: visible without JS, adopted into scene 1 by
   trailer.js on start (it gains .rv reveals there) */
.trailer > .scene-copy.t-static{z-index:6}

/* staged reveal helper: elements animate in when scene becomes active */
.rv{opacity:0;transform:translateY(14px)}
.scene.is-active .rv{animation:rv-in .8s cubic-bezier(.2,.7,.2,1) forwards}
.scene.is-active .rv.d1{animation-delay:.15s}.scene.is-active .rv.d2{animation-delay:.32s}
.scene.is-active .rv.d3{animation-delay:.5s}.scene.is-active .rv.d4{animation-delay:.68s}
@keyframes rv-in{to{opacity:1;transform:none}}

/* ---- scene dots ---- */
.t-dots{position:absolute;right:26px;top:38%;transform:translateY(-50%);z-index:20;display:flex;flex-direction:column;gap:14px}
.t-dot{width:9px;height:9px;border-radius:9999px;border:0;background:rgba(255,255,255,.2);cursor:pointer;padding:0;position:relative;transition:background .3s ease,transform .3s ease}
.t-dot:hover{background:rgba(255,255,255,.4)}
.t-dot.on{background:var(--purple-300);transform:scale(1.35);box-shadow:0 0 12px var(--purple-glow)}

/* ---- control ---- */
.t-control{position:absolute;right:22px;bottom:22px;z-index:25;display:flex;align-items:center;gap:13px;
  padding:8px 14px 8px 9px;border-radius:9999px;background:rgba(12,12,18,.78);border:1px solid var(--border-strong);
  backdrop-filter:blur(8px);opacity:.5;transition:opacity .2s ease}
.t-control:hover{opacity:1}
.t-play{width:30px;height:30px;border-radius:9999px;border:1px solid var(--border-strong);background:rgba(255,255,255,.04);color:var(--fg-secondary);cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
.t-play:hover{color:#fff;border-color:var(--purple-400)}
.t-play svg{width:15px;height:15px;fill:currentColor}
.t-play .ic-play{display:none}
.trailer.paused .t-play .ic-pause{display:none}
.trailer.paused .t-play .ic-play{display:block;margin-left:1px}
.t-count{font-family:var(--font-mono);font-size:12.5px;font-weight:600;color:var(--fg);letter-spacing:.06em;font-variant-numeric:tabular-nums}
.t-label{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--fg-faint);padding-left:12px;border-left:1px solid var(--border)}

/* ===========================================================================
   SHARED constellation kit (scene 0: the Familiar's beams into your tools)
   =========================================================================== */
.cn-wires{position:absolute;inset:0;z-index:1;pointer-events:none;overflow:visible}
.cn-base{fill:none;stroke:rgba(176,168,210,.2);stroke-width:1.3}
.cn-live{fill:none;stroke-width:2.4;stroke-linecap:round;opacity:0;filter:drop-shadow(0 0 6px currentColor);transition:opacity .4s ease}
.cn-live.on{opacity:.8}
.cn-core{fill:#fff;opacity:0}
.cn-halo{opacity:0}
/* t-beat is reused by scene styles for pulsing dots */
@keyframes t-beat{0%,100%{opacity:1}50%{opacity:.35}}

/* ===========================================================================
   SCENE 1: THE SPELL (plain English > plan)
   Site delta: the spell column is a centered flex stack (card + plan) so it
   always fits inside the clipped stage instead of using fixed px offsets.
   =========================================================================== */
.spell{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:min(940px,92vw);z-index:3;
  display:flex;flex-direction:column;align-items:center;gap:clamp(14px,3vh,26px)}
.spell-card{position:relative;width:min(760px,100%);border:1px solid var(--border-strong);border-radius:20px;padding:clamp(16px,2.6vh,26px) 30px;
  background:linear-gradient(180deg,rgba(22,20,34,.8),rgba(12,12,20,.85));box-shadow:0 30px 90px rgba(0,0,0,.5),0 0 60px rgba(124,58,237,.12);backdrop-filter:blur(8px)}
.spell-card .lab{font-family:var(--font-mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--fg-faint);display:flex;align-items:center;gap:10px}
.spell-card .lab .glyph{color:var(--purple-300)}
.spell-text{font-size:clamp(22px,2.6vw,32px);font-weight:600;letter-spacing:-.02em;line-height:1.2;margin-top:12px;color:var(--fg);min-height:1.2em}
.spell-text .cap{color:var(--purple-300);font-weight:700}
.spell-caret{display:inline-block;width:3px;height:1.05em;background:var(--purple-300);margin-left:3px;vertical-align:-.15em;animation:t-blink 1s step-end infinite}
@keyframes t-blink{50%{opacity:.2}}
.spell-cast{margin-top:14px;display:flex;align-items:center;gap:10px;font-family:var(--font-mono);font-size:12.5px;color:var(--purple-300);opacity:0;transition:opacity .4s ease}
.spell-cast.show{opacity:1}
.spell-cast .dot{width:7px;height:7px;border-radius:9999px;background:var(--purple-400);box-shadow:0 0 10px var(--purple-glow);animation:t-beat 1.3s ease-in-out infinite}
/* the compiled plan steps */
.spell-plan{width:100%;z-index:3;display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
.plan-step{display:flex;align-items:center;gap:11px;padding:12px 15px;border-radius:13px;border:1px solid var(--border);
  background:rgba(14,14,22,.7);min-width:156px;opacity:0;transform:translateY(10px) scale(.96)}
.plan-step.in{animation:plan-in .55s cubic-bezier(.3,1.2,.5,1) forwards}
@keyframes plan-in{to{opacity:1;transform:none}}
.plan-step .pn{width:30px;height:30px;border-radius:9px;flex:none;display:flex;align-items:center;justify-content:center;border:1px solid var(--border-strong);background:rgba(124,58,237,.1);color:var(--purple-300)}
.plan-step .pn svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.plan-step .pt{font-size:13.5px;font-weight:600;color:var(--fg-secondary)}
.plan-step .ps{display:block;font-family:var(--font-mono);font-size:10px;color:var(--fg-faint);margin-top:3px;letter-spacing:.04em}
.plan-step.tone-teal .pn{color:var(--teal-300);border-color:rgba(20,184,166,.4);background:rgba(20,184,166,.1)}
.plan-link{align-self:center;color:var(--fg-faint);opacity:0;transition:opacity .4s}
.plan-link.in{opacity:1}

/* SCENE 2 (the Seal) and SCENE 3 (the receipt) inject their own styles from
   assets/hero/scene2-seal.js and scene3-receipt.js. */

@media(max-width:900px){
  /* bottom offset is max(4.5vh, 44px): the trailer height calc undershoots the
     real header by ~40px (--nav-h fallback 68 vs actual ~108), so its bottom
     falls ~40px past the fold. A >=44px offset keeps the bottom-pinned copy and
     CTA above the fold at these widths where 4.5vh alone (36-38px) does not. */
  .scene-copy{left:24px;right:24px;bottom:max(4.5vh,44px);max-width:none}
  .t-dots{right:14px;top:26%}
  .scene-kicker{top:22px}
  .scene-kicker .k1{font-size:12px}.scene-kicker .k2{font-size:10.5px;margin-top:6px}
}
/* hide the play/pause control wherever the copy goes full-width (left:24;
   right:24 at max-width:900): a bottom-pinned full-width copy block reaches the
   bottom-right corner the control sits in, so they collide. Above 900px the
   copy is max-width-capped on the left, clearing the control. */
@media(max-width:900px){
  .t-control{display:none}
}
/* while the docked consent bar is showing, shrink the hero so its bottom-pinned
   CTA clears the bar. The bar is dismissible; the full-height cinematic returns
   once a choice is made. :has-scoped so the hero-overlap gate (which removes
   .cookie before measuring) still sees the full-height geometry. Held above the
   narrow-phone clamp so it never overrides it. */
@media(min-width:521px){
  body:has(.cookie.show) .trailer{height:calc(100dvh - var(--nav-h,69px) - 72px)}
}
/* narrow phones: cap the trailer so the h1 + CTA row land above the fold
   (dvh, not vh, per repo rule). Verified at 390x844 with hero-overlap-check. */
@media(max-width:520px){
  /* min-height:0 (unbounded shrink) plus 62dvh worked for tall narrow phones
     (844px+) but produced unusably short trailers on short-height phones
     like the 667px iPhone SE class (414px) or 568px class (352px), where
     even fully-compacted copy no longer fits inside the 38% stage floor
     without the floor forcing an overlap. Floor the trailer itself instead
     of chasing it with ever-smaller text. */
  .trailer{height:62dvh; min-height:480px; max-height:none}
  /* kicker compaction for narrow phones lives in the LATER max-width:520 block
     (below the max-height:760 block) so it wins the source-order tie at
     viewports that match both (e.g. 375x667). See that block. */
}
/* short viewports: compact the shot chrome so the stage keeps room to act */
@media(max-height:760px){
  .scene-kicker{top:16px}
  .scene-kicker .k1{font-size:11.5px}.scene-kicker .k2{font-size:10px;margin-top:5px}
  .scene-copy h1,.scene-copy .t-h1{font-size:clamp(26px,3vw,38px)}
  .scene-copy .sub{font-size:14px;margin-top:10px}
  .scene-copy .cta-row{margin-top:14px}
  .spell-text{font-size:clamp(19px,2.2vw,26px)}
}
/* 2026-07-19 regression: tall-narrow phones (390x844 etc) never trigger the
   max-height:760px compaction above, so the copy block landed at 417px and
   ate the entire stage down to 9.6% of the trailer. Mirror that compaction
   here, keyed to WIDTH, so it fires on narrow phones regardless of height.
   Placed AFTER the max-height:760px block on purpose: at narrow-AND-short
   viewports (e.g. 375x667, 320x568) both blocks match with equal
   specificity, and source order decides the winner. These values are the
   more aggressive of the two, so they must win that tie or the shorter
   trailers on those viewports fall back to the taller max-height:760
   numbers and the stage floor (trailer.js) ends up forced to intrude on
   the copy to compensate. */
@media(max-width:520px){
  .scene-copy h1,.scene-copy .t-h1{font-size:clamp(22px,6.4vw,30px);margin-top:10px}
  .scene-copy .sub{font-size:13px;line-height:1.38;margin-top:8px}
  .scene-copy .cta-row{margin-top:10px;gap:6px}
  .scene-copy .cta-row .btn{padding:9px 10px;font-size:12px;min-height:40px}
  /* kicker: narrow-phone values, moved here (after the max-height:760 block)
     so they win the equal-specificity source-order tie at narrow-AND-short
     viewports (e.g. 375x667), where both this block and max-height:760 match
     and the more-compact narrow values must win. */
  .scene-kicker{top:14px}
  .scene-kicker .k1{font-size:11px}.scene-kicker .k2{font-size:9.5px;margin-top:4px}
}
/* short viewports (landscape phones: 667x375, 812x375, 896x414 etc). The base
   .trailer floor is min-height:640px and the narrow compaction only fires at
   max-width:520, so a wide-but-short landscape phone kept the 640px trailer and
   dropped the whole copy block and CTA below a ~375px fold. Release the floor,
   pin the trailer to the fold (trailer.js fitToFold() sets the exact height,
   accounting for the real header height, which is taller than --nav-h), and
   compact the copy hard. Keyed to height only so it fires regardless of width.
   Placed after the max-width:520 and max-height:760 blocks so it wins the
   source-order tie at any viewport matching several of them. NOTE: the stage
   floor here is 25% (not the 38% used elsewhere); a 38% floor cannot fit the
   full h1 + sub + CTA above it in the height left on a 375px-tall viewport.
   This 25% is encoded in trailer.js (measureClear cap) and the gate too. */
@media(max-height:580px){
  .trailer{min-height:0; height:calc(100dvh - var(--nav-h,69px)); max-height:none}
  .scene-copy{bottom:10px}
  .scene-copy .eyebrow{font-size:11px}
  .scene-copy h1,.scene-copy .t-h1{font-size:clamp(20px,4.4vw,26px);margin-top:6px;line-height:1.04}
  .scene-copy .sub{font-size:12px;line-height:1.32;margin-top:6px;max-width:none}
  .scene-copy .cta-row{margin-top:8px;gap:8px}
  .scene-copy .cta-row .btn{padding:8px 12px;font-size:12px;min-height:38px}
  .scene-kicker{top:8px}
  .scene-kicker .k1{font-size:10.5px}.scene-kicker .k2{font-size:9px;margin-top:3px}
  .spell-text{font-size:clamp(17px,2vw,22px)}
  /* the short-viewport stage is a thin strip (25% floor), too short to hold
     scene 0's Familiar constellation: the orb glow lands behind the kicker and
     the name/role labels clip at the stage boundary. Hide the whole core and
     its satellites; the strip carries only the ambient starfield. */
  .fam-node,.cn-wires,.cn-comet,.fam-ask,.fam-plan,.fam-core{display:none!important}
}
@media(prefers-reduced-motion:reduce){
  .scene{transition:none}
  .rv,.plan-step,.plan-link,.spell-cast{animation:none!important;opacity:1!important;transform:none!important}
  .t-dust i,.spell-caret,.spell-cast .dot{animation:none!important}
  .cn-core,.cn-halo{display:none!important}
}

/* ===========================================================================
   STATIC PHONE HERO (KAN-227). The predicate below is verbatim shared with
   trailer.js (staticMode) and scripts/hero-overlap-check.cjs (STATIC
   classifier):  (max-width:767px) or (max-height:580px)
   At these sizes the animated stage is OFF. On a short phone stage the old
   center-anchored absolute scene art was taller than the stage, so its top edge
   rose above the trailer top under the sticky header and the kicker printed
   across the card (worst on real iPhones). Here each scene is a centered
   normal-flow column: kicker, then ONE clipped fixed-aspect visual holding the
   motif's composed end-state (de-absolutized), then the rotating copy + CTA.
   Nothing can escape the trailer: the column is centered inside the hero and the
   only absolute descendants are decorative, living inside the overflow-clipped
   visual box. Desktop and iPad (>=768 wide AND >580 tall) never match this and
   keep the animated trailer unchanged.
   =========================================================================== */
@media (max-width:767px) or (max-height:580px){
  /* Fit the trailer to the visible region below the header, then center the
     column. --nav-h (68px) is the nav ROW height, but the real sticky header
     renders ~40px taller; fitToFold (which corrected this on the animated path)
     is off in static mode, so subtract the extra here to keep the trailer bottom
     at the fold and the centered CTA on screen. */
  .trailer{height:calc(100dvh - var(--nav-h,69px) - 44px);min-height:0;max-height:none}

  /* each scene becomes a centered normal-flow column. It stays absolutely
     stacked (inset:0) for the cross-dissolve, but its own children are in flow */
  .trailer .scene{display:flex;flex-direction:column;align-items:stretch;justify-content:center;
    gap:clamp(8px,1.6vh,14px);padding:10px clamp(16px,5vw,28px)}

  /* kicker back into flow at the top of the column */
  .trailer .scene-kicker{position:static;top:auto;left:auto;right:auto;flex:none}

  /* the one visual: a clipped fixed-aspect box holding the de-absolutized motif
     end-state. overflow:hidden + contain:paint + the fade mask crop any card
     taller than the box so nothing spills out, on any engine */
  .trailer .scene-stage{position:relative;inset:auto;top:auto;right:auto;bottom:auto;left:auto;
    width:100%;max-width:460px;margin:0 auto;aspect-ratio:16/10;height:auto;
    max-height:min(200px,24dvh);flex:none;overflow:hidden;contain:paint;
    -webkit-mask-image:linear-gradient(180deg,#000 74%,transparent);mask-image:linear-gradient(180deg,#000 74%,transparent)}

  /* copy rotates as before, now in normal flow below the visual */
  .trailer .scene-copy{position:static;inset:auto;top:auto;left:auto;right:auto;bottom:auto;
    max-width:none;width:100%;flex:none}

  /* de-absolutize the motif roots: pin them to fill the clipped visual box
     (absolute inset:0 inside an overflow:hidden fixed box cannot escape it) */
  .trailer .spell,.trailer .seal,.trailer .receipt{position:absolute;inset:0;left:0;top:0;right:0;bottom:0;
    transform:none;width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
    gap:0;padding:clamp(10px,3vw,16px)}
  .trailer .fam-core{position:absolute;inset:0;left:0;top:0;transform:none;width:auto;
    display:flex;flex-direction:column;align-items:center;justify-content:center}

  /* the cards fill the box width and read from the top */
  .trailer .spell-card,.trailer .seal-card,.trailer .receipt-card{width:100%;margin:0}

  /* keep it to ONE motif per scene: hide the secondary choreography pieces */
  .trailer .spell-plan,.trailer .seal-foot,
  .trailer .fam-node,.trailer .cn-wires,.trailer .cn-comet,.trailer .fam-ask,
  .trailer .fam-plan,.trailer .fam-core .ring{display:none!important}

  /* the play/pause control overlaps a full-width bottom copy block. It is
     hidden at max-width:900, but short landscape (>900 wide, <=580 tall) also
     goes static, so hide it across the whole static predicate */
  .trailer .t-control{display:none}
  /* dots stay usable, centered on the right edge, clear of the content */
  .trailer .t-dots{right:12px;top:50%}
}
/* short static viewports (landscape phones, tiny portraits). Every viewport
   with height <= 580 is a STATIC viewport (and no animated viewport is that
   short), so this refinement never touches the animated stage. The visible band
   below the header is only ~230-270px here, so shrink the visual hard and
   tighten the column so the compacted copy + CTA still clear the fold. Placed
   after the static block so it wins the source-order tie. */
@media (max-height:580px){
  .trailer .scene{gap:6px;padding:8px clamp(14px,4vw,24px)}
  .trailer .scene-stage{max-height:min(112px,20dvh);aspect-ratio:2/1;border-radius:12px}
}

/* ===========================================================================
   KAN-255: cookie banner space reservation on narrow static-mode phones.
   The >=521px rule above (body:has(.cookie.show) .trailer, near the top of
   this file) already shrinks the trailer by a flat 72px while the banner is
   showing, but that rule stops at 521px wide, so it never reaches the exact
   phones this bug was filed against (iPhone SE class and similar: 375x667,
   360x640). At those widths the STATIC PHONE HERO block above already fits
   the whole trailer to the fold with nothing held back for the banner, so the
   banner's fixed footprint lands directly over the bottom-pinned CTA row.
   Mirror the >=521px reservation here, but subtract the EXACT rendered banner
   height (--cookie-h, published by site.js from the banner's offsetHeight,
   0px when hidden or dismissed) instead of a flat guess: narrow phones wrap
   the banner copy onto more lines, so its height varies more than on wider
   viewports and a flat number would under- or over-reserve.
   :has(.cookie.show) is one selector more specific than the plain .trailer
   rules above (both here and in the STATIC PHONE HERO block), so this wins
   whenever the banner is visible regardless of source order, and steps out of
   the way (falling back to those rules) the instant it is dismissed.
   Only .trailer's own height (and the column's own alignment, next) change;
   .scene-stage keeps its own aspect-ratio/max-height clamp untouched
   (KAN-227), so the visual is simply repositioned, never resized or clipped.

   The column is also switched from centered to bottom-aligned here. The
   static column is taller than the shrunk trailer even before the banner
   (that slack is normally centered top/bottom with room to spare), so
   centering it would only buy the CTA row HALF of the height just reserved:
   the other half goes to widening the (harmless, off-screen-behind-the-header)
   overflow at the top. Bottom-aligning (flex-end) puts the full reservation
   where the bug is, pinning the CTA row's bottom to the trailer's own bottom
   edge, above the banner, with any leftover overflow pushed to the top where
   there is no banner to clear. */
@media(max-width:520px){
  body:has(.cookie.show) .trailer{height:calc(100dvh - var(--nav-h,69px) - 44px - var(--cookie-h,0px));min-height:0}
  body:has(.cookie.show) .trailer .scene{justify-content:flex-end}
}
