/* =========================================================================
   PULP — scroll-driven 3D site.
   Zero dependencies. The scroll bar is the transport; every 3D move is
   driven off panel progress, never off time.

   Comments without a project name are load-bearing — each one is a trap
   that has cost a session.
   ========================================================================= */

:root {
  /* sampled off the frame grid: the clip is entirely warm brown-amber, and
     the sweatshirt is the only cool thing in it — so teal is the accent and
     juice orange is the one hot token. */
  --ink:    #0d0906;   /* darkest value in the clip */
  --paper:  #f7efe1;   /* brightest — this is the type colour */
  --slate:  #9d8a72;   /* mid tone for secondary text */
  --accent: #1d6f63;   /* the subject's colour: the sweatshirt */
  --hot:    #ff9d0a;   /* juice. Used sparingly */

  --gut: clamp(20px, 4.2vw, 76px);
  --display: 'Anton', 'Haettenschweiler', 'Arial Narrow', sans-serif;
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* pointer parallax, smoothed in JS */
  --mx: 0deg;
  --my: 0deg;

  /* With every layer over the film removed, this is the ONLY thing keeping
     type readable on the footage. A tight near-black shadow gives each glyph
     its own edge against bright juice; the mid one thickens that edge; the
     wide one lifts the whole word off busy detail. Every piece of text that
     sits directly on the clip uses it. */
  --ink-shadow:
    0 1px 2px rgba(0, 0, 0, .95),
    0 2px 6px rgba(0, 0, 0, .85),
    0 8px 40px rgba(0, 0, 0, .75);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  background: var(--ink);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--sans);
  color: var(--paper);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }
::selection { background: rgba(255, 157, 10, .45); color: #14100a; }

/* ------------------------------------------------------------- background */

.bg { position: fixed; inset: 0; z-index: 0; background: var(--ink); }

.scrub { position: absolute; inset: 0; overflow: hidden; }

.scrub__poster,
.scrub__video,
.scrub__canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: opacity .6s ease;
}
.scrub__video,
.scrub__canvas { opacity: 0; }

/* poster -> video -> canvas handoff */
.scrub.is-video  .scrub__video  { opacity: 1; }
.scrub.is-video  .scrub__poster { opacity: 0; }
.scrub.is-canvas .scrub__canvas { opacity: 1; }
.scrub.is-canvas .scrub__video  { opacity: 0; }

/* the extraction source: kept in-document (detached elements don't reliably
   produce drawable frames) but parked far out of the way */
.scrub__extractor {
  position: fixed; left: -10000px; top: 0;
  width: 2px; height: 2px;
  opacity: .01; pointer-events: none;
}

/* Nothing is layered over the film. The global grade stack (tint, cut bloom,
   vignette, grain) and every per-panel scrim have both been removed by
   request, so the clip plays straight from edge to edge. The only surfaces
   left that sit on it are the content components themselves — the annotation
   chips, the three cards on panel IV, the aperture disc and the credits
   table — each of which carries its own backdrop-blur. */

/* -------------------------------------------------------------------- HUD */

.hud {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: clamp(15px, 2.2vw, 28px) var(--gut);
  font-family: var(--mono);
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--paper);
  /* With the vignette gone, the HUD sits directly on frames that are almost
     pure bright juice. A tight dark shadow plus a wide soft one holds it
     without putting another layer over the film. */
  text-shadow: var(--ink-shadow);
}
.hud__mark {
  display: inline-flex; align-items: center; gap: 10px;
  color: inherit; text-decoration: none; font-weight: 500; letter-spacing: .3em;
}
.hud__dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
}
.hud__nav [data-chapter] { opacity: .88; transition: opacity .3s ease; }
.hud__meta { opacity: .78; }
.hud__meta b { font-weight: 500; font-variant-numeric: tabular-nums; color: var(--hot); }

@media (max-width: 900px) { .hud__meta { display: none; } }

.rail {
  position: fixed; top: 0; left: 0; right: 0; z-index: 41;
  height: 2px; background: rgba(255, 255, 255, .10);
}
.rail i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent), var(--hot));
}

/* ------------------------------------------------------------- the panels */

.panel { position: relative; z-index: 10; }

/* The most important numbers on the page, and they do not stand alone: each
   height is paired with a breakpoint in TIME_MAP in js/main.js. The heights
   decide how much SCROLL a panel gets; the map decides which stretch of FILM
   is playing under it. Change one without the other and the panel slides off
   its act.

   Totals 1700vh = 1600vh of scroll (page 1800vh). The map's breakpoints sit at
   the midpoint of each handoff, so all six of the film's hard cuts land on a
   screen with no type on it:

     hero    pinned film 0.000–0.027   fruit I    wide, batter loaded
     -- cut 0.037 --
     slam    pinned film 0.051–0.079   fruit II   macro burst on the bat
     -- cut 0.093 --
     lens    pinned film 0.107–0.140   fruit III  hands on the grip
     -- cut 0.154 --
     flats   pinned film 0.181–0.256   fruit IV   the long final wide
     ghost   pinned film 0.311–0.386   fruit IV
     -- cut 0.413 — the junction between the two clips --
     product pinned film 0.484–0.765   can A      the 6s push-in
     -- cut 0.765 --   the 2s macro rim plays out entirely in this handoff
     -- cut 0.880 --
     outro   pinned film 0.880–0.955   can C      the closing wide ring

   The can clip's own frame 0 carries a burnt-in lockup. It sits at the 0.413
   junction, inside a handoff, and at 120 cached frames over 409 it is not even
   sampled — it only ever shows during the brief <video> fallback. */
.panel--hero    { height: 247vh; }
.panel--slam    { height: 195vh; }
.panel--lens    { height: 212vh; }
.panel--flats   { height: 238vh; }
.panel--ghost   { height: 238vh; }
.panel--product { height: 300vh; }
.panel--outro   { height: 270vh; }

.stage {
  position: sticky; top: 0;
  height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(88px, 12vh, 132px) var(--gut) clamp(56px, 9vh, 96px);
  perspective: 1150px;
  perspective-origin: 50% 46%;
}
@supports (height: 100svh) { .stage { height: 100svh; } }

.stage__inner {
  position: relative;
  width: 100%; max-width: 1320px;
  transform-style: preserve-3d;
  transform: rotateX(var(--my)) rotateY(var(--mx));
}

/* the block that flies through Z as a whole */
.deep {
  transform-style: preserve-3d;
  transform: translateZ(var(--depth, 0px));
}

/* No scrims. Every layer over the film has been removed by request — the global
   grade stack first, then these per-panel washes. Nothing darkens the clip
   anywhere on the page now; legibility lives entirely in --ink-shadow, applied
   on each type rule below. */

/* -------------------------------------------------------- shared typography */

/* Secondary text is carried a few points brighter than it would be over a
   scrim — with the washes gone, .72 grey on lit concrete disappears. */
.eyebrow, .label {
  font-family: var(--mono);
  font-size: clamp(10px, 1vw, 11.5px);
  letter-spacing: .26em; text-transform: uppercase;
  color: rgba(247, 239, 225, .86);
  text-shadow: var(--ink-shadow);
}
.label--mid { text-align: center; }

/* Anton is a display-only face: it wants no negative tracking and a little
   more line-height than a serif at the same size. */
.h2 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.4rem, 6.2vw, 5.4rem);
  line-height: 1.0; letter-spacing: 0;
  text-shadow: var(--ink-shadow);
}
.h2--big { font-size: min(clamp(2.6rem, 7.4vw, 6.4rem), 14vh); }

.body {
  max-width: 46ch;
  font-size: clamp(.95rem, 1.25vw, 1.08rem);
  font-weight: 300; line-height: 1.72;
  color: rgba(247, 239, 225, .94);
  text-shadow: var(--ink-shadow);
}

/* ------------------------------------------------------------ I — the hero */

/* The batter holds centre-right of frame with the orange at far right, so the
   title takes the low-left quarter and lets the image breathe. */
.panel--hero .stage {
  align-items: flex-end;
  /* pull the vanishing point down-left so the receding title converges into
     the corner it started in, instead of drifting to the middle of the frame.
     28% not 34%: forward Z pushes content radially AWAY from this origin, so
     moving it left over the block reduces how hard the title is shoved off
     the left edge on its way out. */
  perspective-origin: 28% 64%;
}
.panel--hero .stage__inner { text-align: left; }
.panel--hero .deep { max-width: min(760px, 76%); }

.title {
  font-family: var(--display);
  font-weight: 400;
  font-size: min(clamp(3.6rem, 15vw, 13rem), 27vh);
  line-height: .88; letter-spacing: -.005em;
  text-transform: uppercase;
  margin: clamp(14px, 2vh, 26px) 0 clamp(24px, 4vh, 48px);
  transform-style: preserve-3d;
}
.title__line {
  display: block;
  transform: translateZ(var(--tz, 0px));
  text-shadow: var(--ink-shadow);
}
/* The outlined line cannot use --ink-shadow. text-shadow paints the shadow of
   the GLYPH SHAPE, so on a transparent fill it floods every counter with black
   and the word reads as a solid slab. drop-shadow follows the rendered pixels
   — here just the stroke — which is the only way to give an outlined word an
   edge now that there is no scrim under it. */
.title__line--b {
  color: transparent;
  -webkit-text-stroke: 1.7px rgba(247, 239, 225, .95);
  text-shadow: none;
  filter:
    drop-shadow(0 1px 2px rgba(0, 0, 0, .95))
    drop-shadow(0 4px 18px rgba(0, 0, 0, .8));
  padding-left: .04em;
}

.lede {
  max-width: 34ch;
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  font-weight: 300; line-height: 1.6;
  color: rgba(247, 239, 225, .9);
  text-shadow: var(--ink-shadow);
}

/* floating annotations, each pinned at its own depth */
.note {
  position: absolute;
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 14px;
  border-left: 2px solid var(--accent);
  background: rgba(12, 10, 8, .34);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
  white-space: nowrap;
  transform: translateZ(var(--nz, 0px));
  transition: opacity .5s ease;
}
.note b { color: var(--hot); font-weight: 500; }
.note span { color: rgba(247, 239, 225, .66); }
/* held well clear of the right edge: perspective magnifies anything pushed
   toward the viewer *outward* from the vanishing point, and a note flush to
   the gutter slides off screen as soon as it comes forward */
.note--a { top: 5%;    right: 9%; }
.note--b { top: 46%;   right: 16%; }
.note--c { bottom: 8%; right: 12%; border-left-color: var(--hot); }

@media (max-width: 900px) { .note { display: none; } }

.cue {
  position: absolute; left: 50%; bottom: clamp(20px, 4vh, 44px);
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  font-family: var(--mono);
  font-size: 10px; letter-spacing: .3em; text-transform: uppercase;
  color: rgba(247, 239, 225, .82);
  text-shadow: var(--ink-shadow);
}
.cue i {
  width: 1px; height: 42px;
  background: linear-gradient(180deg, rgba(247, 239, 225, .7), transparent);
  animation: fall 2.4s ease-in-out infinite;
}
@keyframes fall {
  0%, 100% { transform: scaleY(.35); transform-origin: top; opacity: .3; }
  50%      { transform: scaleY(1);   transform-origin: top; opacity: 1; }
}

/* --------------------------------------------------------- II — the tunnel */

.panel--slam .stage__inner {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(34px, 7vh, 72px);
}

.slam {
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(2px, .6vh, 8px);
  transform-style: preserve-3d;
}
.slam__line {
  display: block;
  font-family: var(--display); font-weight: 400;
  font-size: min(clamp(2.6rem, 8.6vw, 7.4rem), 16vh);
  line-height: 1.02; letter-spacing: 0; text-transform: lowercase;
  /* both driven per-word by the tunnel sweep in main.js */
  transform: translateZ(var(--sz, 0px));
  /* NOTE: opacity here is on the element itself, inside the preserve-3d chain.
     Putting it on an ancestor would flatten the whole scene. */
  opacity: var(--so, 1);
  text-shadow: var(--ink-shadow);
  white-space: nowrap;
}
.slam__line--hot {
  color: var(--hot);
  text-shadow: var(--ink-shadow), 0 0 70px rgba(255, 157, 10, .55);
}
.slam__foot {
  font-family: var(--mono);
  font-size: clamp(10px, 1.1vw, 12px); letter-spacing: .2em; text-transform: uppercase;
  color: rgba(247, 239, 225, .82); text-align: center;
  text-shadow: var(--ink-shadow);
}
.slam__foot b { color: var(--hot); font-weight: 500; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------- III — the lens */

.lens-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(28px, 6vw, 90px);
  transform-style: preserve-3d;
}

.say { flex: 1 1 46%; max-width: 560px; }
.say .h2 { margin: 14px 0 22px; }

.lens {
  position: relative; flex: 0 0 auto;
  width: clamp(190px, 27vw, 380px);
  /* inset from the gutter — see the note on .note--a */
  margin-right: clamp(0px, 5vw, 96px);
  aspect-ratio: 1;
  transform-style: preserve-3d;
  transform: translateZ(var(--lz, 0px)) rotateY(var(--lry, 0deg));
}
.ring {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(247, 239, 225, .22);
  transform: translateZ(calc(var(--rz, 0px) * var(--lens-open, 0)));
  opacity: calc(.25 + .75 * var(--lens-open, 0));
}
.ring--gold {
  border-color: rgba(255, 157, 10, .75);
  box-shadow: 0 0 50px rgba(255, 157, 10, .22), inset 0 0 40px rgba(255, 157, 10, .10);
}
.lens__core {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 46%, rgba(255, 157, 10, .16), rgba(10, 8, 6, .34) 62%);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  transform: translateZ(calc(120px * var(--lens-open, 0)));
}
.lens__word {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(2rem, 4.4vw, 3.6rem); letter-spacing: .01em;
  color: var(--hot);
  filter: blur(calc(10px * (1 - var(--lens-open, 0))));
  text-shadow: var(--ink-shadow), 0 0 60px rgba(255, 157, 10, .45);
}
.lens__cap {
  font-family: var(--mono);
  font-size: 10px; letter-spacing: .22em; text-transform: uppercase;
  color: rgba(247, 239, 225, .82);
  text-shadow: var(--ink-shadow);
  opacity: var(--lens-open, 0);
}

@media (max-width: 900px) {
  .lens-row { gap: 20px; }
  .say { flex: 1 1 58%; }
  .lens { width: min(34vw, 230px); }
  .say .body { font-size: .9rem; line-height: 1.62; }
}
@media (max-width: 620px) {
  .lens-row { flex-direction: column; align-items: flex-start; }
  .lens { width: min(56vw, 260px); align-self: center; }
}

/* ------------------------------------------------------- IV — the triptych */

.flats {
  display: flex; align-items: stretch; justify-content: center;
  gap: clamp(14px, 2.4vw, 34px);
  transform-style: preserve-3d;
}

.flat {
  flex: 1 1 0;
  min-height: clamp(240px, 42vh, 400px);
  display: flex; flex-direction: column; justify-content: space-between;
  padding: clamp(18px, 2.4vw, 32px);
  border: 1px solid rgba(247, 239, 225, .18);
  background: linear-gradient(155deg, rgba(20, 16, 12, .58), rgba(10, 8, 6, .40));
  backdrop-filter: blur(11px); -webkit-backdrop-filter: blur(11px);
  /* centre origin: a left origin swings the far edge past the viewport and the
     flat reads as clipped rather than as depth */
  transform-origin: 50% 50%;
  transform: translateZ(var(--fz, 0px)) rotateY(var(--fry, 0deg));
  box-shadow: 0 30px 90px rgba(0, 0, 0, .45);
}
.flat__no { font-family: var(--mono); font-size: 11px; letter-spacing: .24em; color: var(--hot); }
.flat p {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(1.05rem, 1.9vw, 1.6rem);
  line-height: 1.34; letter-spacing: -.01em;
  text-shadow: var(--ink-shadow);
}

@media (max-width: 760px) {
  .flats { flex-direction: column; gap: 12px; }
  /* stacked, they must size to their own copy — `flex: 1 1 0` would slice the
     column into three equal boxes and clip every line */
  .flat { flex: 0 0 auto; min-height: 0; gap: 10px; padding: 16px 18px; }
  .flat p { font-size: clamp(.98rem, 4vw, 1.3rem); }
}

/* ---------------------------------------------- V — the receding ghost stack */

/* Off-centre vanishing point. With the origin at 50% the receding copies are
   concentric with the front word and it occludes every one of them exactly —
   the stack renders as a single word with a faint halo. Pushing the origin up
   and left fans them diagonally so each copy peeks out past the one in front,
   which is what makes the recession read at all. */
.panel--ghost .stage { perspective-origin: 24% 34%; }

.panel--ghost .stage__inner {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(16px, 3vh, 34px);
  text-align: center;
}

.ghost {
  position: relative;
  width: 100%;
  min-height: clamp(110px, 20vh, 220px);
  display: flex; align-items: center; justify-content: center;
  transform-style: preserve-3d;
}
.ghost__word {
  font-family: var(--display); font-weight: 400;
  font-size: min(clamp(2.4rem, 10.5vw, 8.4rem), 18vh);
  line-height: 1; letter-spacing: 0; text-transform: lowercase;
  white-space: nowrap;
  transform: translateZ(var(--gz, 0px));
  /* per-element, inside the preserve-3d chain — an ancestor opacity would
     flatten the whole stack into one plane */
  opacity: var(--go, 1);
  text-shadow: var(--ink-shadow);
}
/* every copy but the last is a ghost stacked behind the front word. They carry
   the hot colour and the front word is cream: the footage is wall-to-wall
   orange, so cream is the contrast and orange is the smear. */
.ghost__word:not(:last-child) {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: rgba(255, 157, 10, .78);
}
.ghost__word:last-child {
  color: var(--paper);
  text-shadow: var(--ink-shadow);
}

.ghost__foot {
  font-family: var(--mono);
  font-size: clamp(10px, 1.1vw, 12px); letter-spacing: .2em; text-transform: uppercase;
  color: rgba(247, 239, 225, .82); text-align: center;
  text-shadow: var(--ink-shadow);
}

/* -------------------------------------------------------- VI — the product */

/* The can owns the centre of frame for this whole act and grows as it pushes
   in, so the copy takes the two margins and the gutter between them is sized
   to leave the product completely clear. */
.yield {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(150px, 30vw, 520px);
  transform-style: preserve-3d;
}
.yield__side {
  flex: 0 1 clamp(190px, 23vw, 330px);
  /* --yx / --yz / --yo are driven per-side from panel progress in main.js */
  transform: translate3d(var(--yx, 0px), 0, var(--yz, 0px));
  opacity: var(--yo, 1);
}
.yield__side--r { text-align: right; }
.yield__side .h2 { margin: 12px 0 18px; }
.yield__side .body { font-size: clamp(.9rem, 1.15vw, 1rem); }

/* hairline spec table — no card, since nothing may sit over the film */
.spec { display: grid; gap: clamp(8px, 1.4vh, 14px); }
.spec > div {
  display: flex; justify-content: flex-end; align-items: baseline; gap: 14px;
  padding-top: 8px;
  border-top: 1px solid rgba(247, 239, 225, .3);
}
.spec dt {
  font-family: var(--mono);
  font-size: 9.5px; letter-spacing: .22em; text-transform: uppercase;
  color: rgba(247, 239, 225, .78);
  text-shadow: var(--ink-shadow);
}
.spec dd {
  font-size: clamp(.86rem, 1.05vw, .96rem); font-weight: 300;
  text-shadow: var(--ink-shadow);
}

@media (max-width: 900px) {
  .yield { gap: clamp(70px, 14vw, 150px); }
  .yield__side { flex: 0 1 40%; }
  .yield__side .h2 { font-size: clamp(1.9rem, 5.4vw, 3.4rem); }
  .yield__side .body { display: none; }
}
@media (max-width: 620px) {
  /* the can fills too much of a phone frame for two columns — keep the claim,
     drop to a single left block and let the spec sit under it */
  .yield { flex-direction: column; align-items: flex-start; gap: clamp(18px, 4vh, 40px); }
  .yield__side { flex: 0 0 auto; }
  .yield__side--r { text-align: left; align-self: stretch; }
  .spec > div { justify-content: space-between; }
}

/* --------------------------------------------------------- VII — the outro */

.outro {
  display: flex; align-items: center;
  gap: clamp(28px, 6vw, 84px);
  transform-style: preserve-3d;
}

.plate {
  flex: 0 0 auto;
  width: clamp(230px, 30vw, 420px);
  transform-style: preserve-3d;
  transform: translateZ(var(--pz, 0px)) rotateY(var(--ry, 0deg)) rotateX(var(--rx, 0deg));
  box-shadow: 0 50px 120px rgba(0, 0, 0, .6);
}
.plate img {
  width: 100%;
  border: 1px solid rgba(247, 239, 225, .16);
  filter: saturate(.92) contrast(1.04);
}
.plate figcaption {
  margin-top: 10px;
  font-family: var(--mono);
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(247, 239, 225, .78);
  text-shadow: var(--ink-shadow);
}

.outro__text { flex: 1 1 auto; transform-style: preserve-3d; }
.outro__text .body { margin-top: clamp(14px, 2.2vh, 24px); }
.outro__text .h2 { margin-top: 12px; }

.credits {
  margin-top: clamp(18px, 3vh, 34px);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px;
  background: rgba(247, 239, 225, .14);
  border: 1px solid rgba(247, 239, 225, .14);
}
.credits > div {
  padding: 12px 15px;
  background: rgba(10, 8, 6, .58);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.credits dt {
  font-family: var(--mono);
  font-size: 9.5px; letter-spacing: .22em; text-transform: uppercase;
  color: rgba(247, 239, 225, .5);
}
.credits dd { margin-top: 5px; font-size: .92rem; font-weight: 300; }

.acts { margin-top: clamp(18px, 2.6vh, 30px); display: flex; flex-wrap: wrap; gap: 12px; }
.btn {
  display: inline-flex; align-items: center;
  padding: 11px 22px;
  border: 1px solid rgba(247, 239, 225, .3);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--paper); text-decoration: none;
  text-shadow: var(--ink-shadow);
  background: rgba(247, 239, 225, .22);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.btn:hover { background: rgba(247, 239, 225, .18); }
.btn--solid { background: var(--hot); color: #1a1206; border-color: var(--hot); }
.btn--solid:hover { background: #ffb23e; border-color: #ffb23e; }

/* A sticky stage cannot grow past the viewport, and `space-between` will not
   shrink content — it just overflows. The busiest panel steps down together. */
@media (max-width: 900px) {
  .outro { flex-direction: column; align-items: flex-start; gap: 14px; }
  .plate { width: 200px; }
  .plate figcaption { display: none; }
  .outro .h2--big { font-size: min(clamp(2.1rem, 6.4vw, 4.4rem), 11vh); }
  .outro__text .body { margin-top: 12px; font-size: .88rem; line-height: 1.6; }
  .credits { margin-top: 16px; }
  .credits > div { padding: 10px 12px; }
  .credits dd { font-size: .84rem; }
  .acts { margin-top: 14px; }
  .btn { padding: 9px 18px; }
}

/* Short-and-wide windows run out of height long before they run out of width;
   drop the least load-bearing lines rather than shrinking everything to mush. */
@media (max-height: 660px) {
  .outro__text .body { display: none; }
  .panel--ghost .ghost__foot { display: none; }
  .slam__foot { display: none; }
  /* the hero is the tallest stack on the page — measured, it overflows a
     1280x520 window by 16px on the default clamps */
  .stage { padding-top: clamp(70px, 11vh, 132px); }
  .title {
    font-size: min(clamp(3.2rem, 13vw, 11rem), 24vh);
    margin: clamp(8px, 1.2vh, 16px) 0 clamp(12px, 2vh, 24px);
  }
  .lede { font-size: 1rem; line-height: 1.5; }
}

/* On a phone the busiest panel gives up on pinning and simply flows. */
@media (max-width: 620px) {
  .panel--hero .stage { padding-bottom: clamp(78px, 13vh, 112px); }
  .plate { display: none; }
  /* The outro must KEEP its vh height and stay pinned. Letting it collapse to
     `height: auto` here silently broke the time map: the map's last anchors
     are measured off panel offsets, so a short outro left the whole closing
     act with 0.8% of the page to play in. Trim its contents on small screens
     instead of shortening the panel. */
  .credits { grid-template-columns: 1fr; }
  .credits > div { padding: 8px 12px; }
  .credits dt { font-size: 9px; }
  .credits dd { font-size: .8rem; }
}

/* -------------------------------------------------------------- the footer */

.foot {
  position: relative; z-index: 10;
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px;
  padding: 22px var(--gut) 30px;
  border-top: 1px solid rgba(247, 239, 225, .12);
  background: rgba(8, 7, 5, .84);
  font-family: var(--mono);
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(247, 239, 225, .48);
}

/* ------------------------------------------------------------- the reveals */

[data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .9s ease, transform .9s cubic-bezier(.2, .7, .2, 1);
}
[data-reveal].in { opacity: 1; transform: none; }

/* Dev mode: kill ambient motion so a frozen capture shows the real end state.
   Toggling the same class an animated hide uses is NOT enough — the transition
   has not finished when the screenshot tool freezes the page. */
html.is-dev .cue i { animation: none !important; }
html.is-dev [data-reveal] { transition: none !important; opacity: 1 !important; transform: none !important; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .cue i { animation: none; }
  [data-reveal] { transition: none; opacity: 1; transform: none; }
}
