/* RAWDAWG home page: the landing's scroll story (site/index.html, src/site/home.ts).
   Today's home page with 001's scroll story (site/designs/object.html) as its landing: today's
   type, colours and CSS box, told in 001's six beats. Every rule here is scoped to the landing
   (.story) or to a page that has one (body:has(.story)); everything else is styles.css.

   Without the script, or with reduced motion, the landing is six still frames, each with its own
   box posed for its line. With motion allowed and scripts on, the first frame is today's hero
   (the BEAT 01 block below), and home.ts adds .is-story: one pinned stage that opens with
   today's drop, the box landing on the headline and the letters flying off the page; then one
   box plays every pose as the lines crossfade in place. */

.story {
  --nav-h: 64px;
  --soft: #64625c;                         /* small print: AA on the paper (5.4:1) */
  --tick: #bdbab3;
  /* wide screens: the words keep to a column on the left, the box stands to its right */
  --col: min(46vw, 860px);
  --gap-x: clamp(32px, 4.5vw, 96px);
  --pad-t: clamp(20px, 7svh, 88px);
  --pad-b: clamp(20px, 5svh, 56px);
  /* the headline as big as the column and the screen's height both allow, leaving room for the
     counter (31px), the gap (36px) and the lede and buttons under it */
  --act-h: calc(clamp(16px, 1.4vw, 19px) * 1.5 * 3 + 28px + 52px);
  --t: clamp(56px, min(var(--col) / 3.9, (100svh - var(--nav-h) - var(--pad-t) - var(--pad-b) - 67px - var(--act-h)) / 2.76), 240px);
  --title: clamp(40px, min(5.4vw, 9svh, var(--col) / 6.6), 104px);
  position: relative;
}
@media (max-width: 640px) { .story { --nav-h: 58px; } }

/* phones and tablets held upright: the words on top, the box under them, the buttons at the
   foot. Today's phone headline, at today's size and on today's three lines ("Nothing / in the /
   way."); a short screen (under 740px tall, e.g. 375x667) sets it on two ("in the way." fits at
   that size), so the box keeps the room a third line would take. */
@media (orientation: portrait) {
  .story {
    --t: min(17.5vw, 9.5svh, (100vw - 2 * var(--gut)) / 4.95);
    --title: min(12.4vw, 6.2svh, 76px);
  }
}

/* ---------- the lines ---------- */

/* 01 ——— 06: where you are in the story; the hairline fills as you scroll */
.story__n {
  display: flex; align-items: center; gap: 12px;
  margin: 0 0 14px;
  font-family: var(--mono); font-size: 11px; line-height: 17px; letter-spacing: .14em;
  font-variant-numeric: tabular-nums;
  color: var(--soft);
}
.story__bar { position: relative; display: block; width: 44px; height: 1px; overflow: hidden; background: var(--line); }
.story__bar > i {
  position: absolute; inset: 0;
  background: var(--ink);
  transform-origin: 0 50%;
  transform: scaleX(var(--done, 0));
}
.story__frame[data-beat="1"] { --done: .1667; }
.story__frame[data-beat="2"] { --done: .3333; }
.story__frame[data-beat="3"] { --done: .5; }
.story__frame[data-beat="4"] { --done: .6667; }
.story__frame[data-beat="5"] { --done: .8333; }
.story__frame[data-beat="6"] { --done: 1; }

.story__title { font-size: var(--title); line-height: .92; }
/* "Nothing in the way." in the still frames: Libron, as big as the room allows (with motion and
   the script it's today's hero instead: BEAT 01 below) */
.story__title--hero { font-size: var(--t); line-height: .9; }
.story__title--hero .row { display: block; }
.story__title--hero .row > span { display: block; }
.story .m-only { display: inline; }
@media (orientation: portrait) and (max-height: 739px) {
  .story .m-only { display: none; }
}

.story__lede { margin-top: clamp(14px, 2.2svh, 24px); text-wrap: pretty; }
.story__note { margin: 12px 0 0; max-width: 40ch; font-size: 13px; line-height: 1.5; color: var(--soft); }
/* beat 02 carries only today's latex line under its title */
.story__title + .story__note { margin-top: clamp(14px, 2.2svh, 24px); }
.story .kicker { color: var(--soft); }

/* beat 05's labels as a list, for the still frames (the pinned story labels the foils instead) */
.story__legend { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 10px; font-size: 15px; color: var(--ink-2); }
.story__legend li { display: flex; align-items: center; gap: 12px; }
.story__legend b { min-width: 5.6em; font-weight: 500; font-size: 11px; letter-spacing: .24em; text-transform: uppercase; color: var(--ink); }
.story__chip { width: 14px; height: 14px; flex: none; }
.story__chip--white { background: var(--paper); box-shadow: inset 0 0 0 1px #c9c6bf; }
.story__chip--black { background: #141414; }
.story__chip--gold { background: linear-gradient(135deg, var(--gold-1), var(--gold-2)); }

/* the buttons, and the pre-order terms beside the buy button */
.story__frame--hero .lede { max-width: 32ch; }
.story__ctas { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 28px; }
.story__terms { margin: 14px 0 0; max-width: 46ch; font-size: 13px; line-height: 1.5; color: var(--soft); text-wrap: pretty; }
.story .btn:focus-visible { outline: 1.5px solid var(--ink); outline-offset: 4px; }

/* ---------- the box: today's CSS box, posed ----------
   A pose is a handful of numbers, set per frame below (and by home.ts while it plays):
     --ry   turn on its base (deg)    --rx  camera height (deg, negative looks down)
     --lid  0 shut → 1 open           --s   how big it may stand, in box widths (the script's cap)
   and per foil, from the middle of the box's top edge: --fx, --fy (in box widths), --fz (in box
   depths), --fr (tilt, deg), --fs (scale), --face (0 stands in the box, 1 turns to face you),
   --fo (1 shows it, 0 lets it go). Today's pose, rotateX(-4deg) rotateY(-22deg), is the default. */

.story .box {
  --w: var(--box-w);
  --h: calc(var(--w) * 1.6);
  --d: calc(var(--w) * .32);
  --ry: -22; --rx: -4; --lid: 0; --s: 1;
  transition: none;
  transform: rotateX(calc(var(--rx) * 1deg)) rotateY(calc(var(--ry) * 1deg));
}
/* the dark floor inside only shows once the lid lifts, and stops a hair short of the side panel,
   so its edge can't show through a seam as a line across the side */
.story .box__well { opacity: clamp(0, var(--lid) * 5, 1); width: calc(var(--w) - 3px); }
/* turned towards you (beat 02), the side panel catches the light; the front shades as it turns away */
.story .box__side::before {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, #f6f5f1, #e8e6e0);
  opacity: clamp(0, (var(--ry) * -1 - 40) / 45, 1);
}
.story .box__front::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: #77736b;
  opacity: clamp(0, (var(--ry) * -1 - 30) / 150, .32);
}
/* the greyhound on the lid, sized with the box (you look straight down at it in beat 03). It's on
   the outside of the lid, so it goes as the lid swings past upright and you see its underside,
   which is in the box's shade. */
.story .box__top .dog { width: 30%; margin-inline: auto; opacity: calc(.3 * clamp(0, 1 - var(--lid) * 4, 1)); }
.story .box__top::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: #a7a39a;
  opacity: clamp(0, (var(--lid) - .2) * 1.2, .5);
}
/* inside, the walls fall into shadow towards the floor (only ever seen with the lid open). Each
   dark wall keeps a light band on the edge it shares with the outside of the box (the left wall's
   front edge, the back wall's right edge: its left, turned round). Without it the dark wall bled
   through the seam as a hairline down the box's front-left and back-right edges. */
.story .box__back {
  background:
    linear-gradient(90deg, #cfccc5 0 3px, transparent 3px),
    linear-gradient(180deg, #d6d3cc 0%, #b2aea5 5%, #8f8a81 12%, #77726a 22%);
}
.story .box__left {
  background:
    linear-gradient(270deg, #e9e7e1 0 3px, transparent 3px),
    linear-gradient(180deg, #cdcac3 0%, #a9a59c 5%, #8a857c 12%, #716c64 22%);
}
/* seen almost edge-on, the front's print turns to specks: it fades as the front turns away */
@supports (top: calc(1px * cos(0deg))) {
  .story .box__mark,
  .story .box__foot { opacity: clamp(0, (cos(var(--ry) * 1deg) - .22) * 5, 1); }
}
/* a soft shadow on the floor, turning with the box */
.story .box__ground {
  position: absolute;
  left: calc(var(--w) * -.3); top: calc(var(--h) / 2 - var(--d) * 1.4);
  width: calc(var(--w) * 1.6); height: calc(var(--d) * 2.8);
  transform: translateY(calc(var(--h) / 2 + 1px)) rotateX(90deg);
  background: radial-gradient(closest-side, rgba(40, 33, 24, .3), rgba(40, 33, 24, .11) 52%, rgba(40, 33, 24, 0));
  pointer-events: none;
}
/* the foils: centred on the middle of the top edge, then placed by the pose. They only show once
   the lid is well up, so none can glint through a seam. */
.story .box__foil {
  --fx: 0; --fy: .68; --fz: 0; --fr: 0; --fs: 1; --face: 0; --fo: 1;
  left: calc(var(--w) * .21); top: calc(var(--w) * -.29);
  width: calc(var(--w) * .58);
  transform:
    translate3d(calc(var(--fx) * var(--w)), calc(var(--fy) * var(--w)), calc(var(--fz) * var(--d)))
    rotateY(calc(var(--ry) * var(--face) * -1deg))
    rotateX(calc(var(--rx) * var(--face) * -1deg))
    rotate(calc(var(--fr) * 1deg))
    scale(var(--fs));
  opacity: calc(var(--fo) * clamp(0, (var(--lid) - .15) * 8, 1));
}
/* white stands at the back, so it rises highest and leads */
.story .box__foil--white { --fz: -.26; }
.story .box__foil--gold { --fz: .26; }

/* ---------- the six poses ---------- */

/* 01: today's pose, a little bigger */
.story__frame[data-beat="1"] .box { --s: 1.2; }
/* 02: turned edge-on */
.story__frame[data-beat="2"] .box { --ry: -86; --rx: -4; --s: 1.15; }
/* 03: from above, the lid open; the tips of the foils show inside */
.story__frame[data-beat="3"] .box { --ry: -30; --rx: -30; --lid: 1; --s: 1.05; }
.story__frame[data-beat="3"] .box__foil--white { --fy: .28; --fr: 2; }
.story__frame[data-beat="3"] .box__foil--black { --fy: .35; --fr: -3; }
.story__frame[data-beat="3"] .box__foil--gold { --fy: .46; }
/* 04: the foils rise, white highest */
.story__frame[data-beat="4"] .box { --ry: -24; --rx: -14; --lid: 1; }
.story__frame[data-beat="4"] .box__foil--white { --fx: .05; --fy: -.24; --fr: 3; }
.story__frame[data-beat="4"] .box__foil--black { --fx: -.1; --fy: -.1; --fr: -7; }
.story__frame[data-beat="4"] .box__foil--gold { --fx: .1; --fy: .04; --fr: 6; }
/* 05: fanned out over the box, turned to face you. White keeps its place behind the other two,
   so no foil passes through another on the way. */
.story__frame[data-beat="5"] .box { --ry: -12; --rx: -8; --lid: 1; --s: .9; }
.story__frame[data-beat="5"] .box__foil { --face: 1; }
.story__frame[data-beat="5"] .box__foil--white { --fx: 0; --fy: -.66; --fz: -.12; }
.story__frame[data-beat="5"] .box__foil--black { --fx: -.62; --fy: -.5; --fz: .1; --fr: -10; }
.story__frame[data-beat="5"] .box__foil--gold { --fx: .62; --fy: -.5; --fz: .1; --fr: 10; }
/* 06: the box you buy. White settles back in; black and gold drift off and let go. */
.story__frame[data-beat="6"] .box { --ry: -27; --rx: -12; --lid: 1; --s: 1.05; }
.story__frame[data-beat="6"] .box__foil--white { --fx: -.02; --fy: .1; --fr: -3; }
.story__frame[data-beat="6"] .box__foil--black { --fx: -.8; --fy: -.56; --fz: .1; --fr: -12; --face: 1; --fo: 0; }
.story__frame[data-beat="6"] .box__foil--gold { --fx: .8; --fy: -.56; --fz: .1; --fr: 12; --face: 1; --fo: 0; }

/* =========================================================================================
   STILL FRAMES (no script, or reduced motion): six frames down the page, each with its box
   ========================================================================================= */

.story__object, .story__tags, .story__blast, .story__impact { display: none; }

/* the scroll reveals further down: today they're shown unless the hero's script is there to play
   them (body:has(.hero--side:not(.is-armed)) in styles.css). This page has no hero, so the story
   takes its place: no story script (no JS, or reduced motion), no hidden reveals. */
body:has(.story:not(.is-story)) .reveal { opacity: 1; transform: none; }

.story__frame { position: relative; display: flex; flex-direction: column; padding: clamp(48px, 8vw, 96px) var(--gut); }
.story__frame + .story__frame { border-top: 1px solid var(--line); }
/* the first frame fills the first screen (with motion and the script, BEAT 01 below sets it as
   today's hero instead) */
.story__frame--hero { min-height: calc(100svh - var(--nav-h)); padding-top: 14px; padding-bottom: calc(16px + env(safe-area-inset-bottom)); }

/* the box's own space: tall enough for the foils over it, the box standing at its foot */
.story__art {
  --box-w: clamp(140px, 42vw, 230px);
  --room: 2;
  position: relative;
  display: grid; place-items: end center;
  height: calc(var(--box-w) * var(--room));
  margin: clamp(24px, 5vw, 40px) 0 0;
  padding-bottom: calc(var(--box-w) * .22);
  perspective: calc(var(--box-w) * 5);
  perspective-origin: 50% calc(100% - var(--box-w) * 1.02);
}
.story__frame[data-beat="3"] .story__art { --room: 2.15; }
.story__frame[data-beat="4"] .story__art { --room: 2.5; }
.story__frame[data-beat="5"] .story__art { --room: 2.8; }
.story__frame[data-beat="6"] .story__art { --room: 2.25; }
/* the box takes the room the words and buttons leave, so a short phone still sees both buttons */
.story__frame--hero .story__art { --box-w: clamp(120px, min(50vw, (100svh - 400px) / 1.8), 300px); flex: 1; min-height: calc(var(--box-w) * 1.8); margin: 12px 0; place-items: center; padding-bottom: 0; perspective-origin: 50% 50%; }
.story__frame--hero .story__act { margin-top: auto; }
.story__frame--hero .lede { font-size: 16px; }
.story__frame--offer .story__act { margin-top: 28px; }

@media (orientation: portrait) {
  .story__ctas { margin-top: 18px; }
}
/* phones: the two buttons share the row and Pre-order spans it. Tablets keep today's buttons. */
@media (orientation: portrait) and (max-width: 640px) {
  .story__ctas .btn { flex: 1; padding: 0 14px; }
  .story__frame--offer .btn { width: 100%; }
}

@media (orientation: landscape) {
  .story__frame {
    display: grid;
    grid-template-columns: minmax(0, var(--col)) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    column-gap: var(--gap-x);
    align-content: start;
    min-height: min(820px, 86svh);
    padding: var(--pad-t) var(--gut) var(--pad-b);
  }
  .story__copy { grid-area: 1 / 1; }
  .story__act, .story__frame--hero .story__act, .story__frame--offer .story__act { grid-area: 2 / 1; align-self: start; margin-top: 36px; }
  .story__art,
  .story__frame--hero .story__art { --box-w: min(22vw, 30svh); grid-area: 1 / 2 / 3 / 3; align-self: center; margin: 0; }
  .story__frame--hero { min-height: calc(100svh - var(--nav-h)); }
  .story__frame--hero .lede { font-size: clamp(16px, 1.4vw, 19px); }
}

/* =========================================================================================
   THE PINNED STORY (.is-story, from home.ts)
   ========================================================================================= */

/* while the script swaps the still frames for the stage, nothing animates */
.story.is-booting, .story.is-booting * { transition: none !important; }

/* how far the story scrolls: under two screens upright, two sideways. home.ts puts a snap
   point on each beat's resting place. On touch screens they're on, so a swipe moves the story on
   one beat and lands it there; with a mouse they'd pull every wheel notch back to the beat it
   left, so there the story scrolls freely and the page keys step through it (home.ts).
   While the reader goes on down past the story's end (.is-below) they're off: a gentle swipe on
   to the shop mustn't be pulled back up to beat 06 */
.story.is-story { --len: 175svh; height: calc(100svh - var(--nav-h) + var(--len)); }
@media (orientation: landscape) { .story.is-story { --len: 200svh; } }
@media (pointer: coarse) { html:has(.story.is-story:not(.is-below)) { scroll-snap-type: y proximity; } }
.story__snap {
  position: absolute; left: 0; width: 1px; height: 1px;
  scroll-snap-align: start; scroll-snap-stop: always;
  visibility: hidden; pointer-events: none;
}

.story.is-story .story__stage {
  position: sticky; top: var(--nav-h);
  height: calc(100svh - var(--nav-h));
  overflow: hidden; overflow: clip;
}
.story.is-story .story__art { display: none; }

/* the layers over the lines: the flying letters, then the fall's shadow and dust, then the box,
   which comes down in front of the headline, and the foils' labels on top */
.story.is-story .story__blast,
.story.is-story .story__impact { display: block; position: absolute; pointer-events: none; }
.story.is-story .story__blast { inset: 0; z-index: 1; }
.story.is-story .story__impact { left: 0; top: 0; width: 0; height: 0; z-index: 2; }
.story__blast {
  font-family: var(--display); font-weight: 400; font-synthesis: none;
  letter-spacing: -.025em; color: var(--ink);
}
.story__bit { position: absolute; display: block; white-space: pre; will-change: translate, rotate, scale; }

/* every line sits in the same place; the script fits the box into the room each one leaves */
.story.is-story .story__frame {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: stretch;
  min-height: 0;
  padding: 14px var(--gut) calc(16px + env(safe-area-inset-bottom));
  border: 0;
  pointer-events: none;
}
.story.is-story .story__act { margin-top: auto; }
@media (orientation: landscape) {
  .story.is-story .story__frame { align-items: flex-start; padding: var(--pad-t) var(--gut) var(--pad-b); }
  .story.is-story .story__copy,
  .story.is-story .story__act { width: var(--col); max-width: 100%; }
  .story.is-story .story__act { margin-top: 36px; }
}
/* phones held sideways (short and wide): the headline on two lines, as upright phones set it,
   and less air above and under the words, so the lede and both buttons stay on the stage */
@media (orientation: landscape) and (max-height: 520px) {
  .story {
    --col: min(52vw, 860px);
    --pad-t: 12px; --pad-b: 10px;
    --t: clamp(36px, min(var(--col) / 4.95, (100svh - var(--nav-h) - var(--pad-t) - var(--pad-b) - 43px - var(--act-h)) / 1.86), 240px);
  }
  .story .m-only { display: none; }
  .story__n { margin-bottom: 8px; }
  .story__lede { margin-top: 10px; }
  .story .story__act, .story.is-story .story__act { margin-top: 18px; }   /* still and pinned alike */
  .story__ctas { margin-top: 16px; }
  .story__ctas .btn { padding: 0 18px; }   /* both buttons on one row */
  .story__terms { margin-top: 8px; }
}

/* lines enter from below and leave upwards (the other way when scrolling back); the old line is
   gone before the new one arrives, so the two never overlap. Upright, the words sit right above
   and below the box, so they travel only 10px: less than the gap home.ts leaves between
   words and box (16px or more), so a line coming or going never dips into the box. */
.story.is-story { --in: 20px; --out: -14px; }
@media (orientation: portrait) { .story.is-story { --in: 10px; --out: -10px; } }
.story.is-story .story__copy,
.story.is-story .story__act {
  opacity: 0;
  transform: translate3d(0, var(--in), 0);
  transition: opacity .2s var(--ease), transform .4s var(--ease);
}
.story.is-story .story__frame.is-past .story__copy,
.story.is-story .story__frame.is-past .story__act { transform: translate3d(0, var(--out), 0); }
.story.is-story .story__frame.is-active .story__copy,
.story.is-story .story__frame.is-active .story__act {
  opacity: 1; transform: none;
  pointer-events: auto;
  transition: opacity .5s .16s var(--ease), transform .75s .16s var(--ease);
}
/* the list's job goes to the labels on the foils (it stays for screen readers) */
.story.is-story .story__legend {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; margin: 0;
}

/* the box's stage: the script moves and scales .story__pos (transform only); the drop moves
   .story__fall, and on a phone clips the layer under the headline while the box comes down */
.story.is-story .story__object {
  --box-w: min(56vw, 30svh, 420px);
  display: block;
  position: absolute; inset: 0; z-index: 3;
  pointer-events: none;
}
@media (orientation: landscape) { .story.is-story .story__object { --box-w: min(24vw, 36svh); } }
.story__fall { position: absolute; inset: 0; }
.story__pos {
  position: absolute; left: 0; top: 0;
  width: var(--box-w); height: calc(var(--box-w) * 1.6);
  perspective: calc(var(--box-w) * 5);
  transform-origin: 50% 50%;
  will-change: transform;
}

/* the foils' labels, which follow them while they're fanned out (beat 05) */
.story.is-story .story__tags { display: block; position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.story__tag {
  position: absolute; left: 0; top: 0;
  display: grid; justify-items: center; gap: 3px;
  translate: -50% -100%;
  font-family: var(--mono); font-size: 10px; line-height: 1.3; letter-spacing: .12em; text-transform: uppercase;
  color: var(--soft); white-space: nowrap; text-align: center;
  opacity: 0;
  transition: opacity .35s var(--ease);
  will-change: transform;
}
.story__tag b { font-family: var(--sans); font-weight: 500; font-size: 11px; letter-spacing: .28em; margin-right: -.28em; color: var(--ink); }
.story__tag::after { content: ''; width: 1px; height: 16px; margin-top: 5px; background: var(--tick); }
.story__tags.is-on .story__tag { opacity: 1; transition: opacity .7s var(--ease); }
.story__tags.is-on .story__tag:nth-child(2) { transition-delay: .08s; }
.story__tags.is-on .story__tag:nth-child(3) { transition-delay: .16s; }
/* short phone screens, upright or sideways: the labels keep only their colour, so they never touch */
@media (orientation: portrait) and (max-height: 700px), (orientation: landscape) and (max-height: 520px) {
  .story__tag small { display: none; }
}

/* =========================================================================================
   BEAT 01: TODAY'S HERO (motion allowed, scripts on)
   The first frame is today's hero (.hero in styles.css), set from the first paint, so pinning
   moves nothing. Wide (over 640px, as today): the headline huge and centred over the room above
   the lede and buttons, which share the foot of the screen. Phones: the headline on top, centred,
   on three rows; the lede and both buttons at the foot. No counter, and no foils around the words:
   the box drops onto the headline and the letters fly off (home.ts). Reduced motion, no
   scripts (or a browser that can't tell) keep the still frame above.
   ========================================================================================= */
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) {
  .story {
    --hero-pb: clamp(24px, 4vw, 48px);
    --hero-lede: clamp(16px, 1.4vw, 19px);
    /* today's size (16vw, at most 280px), as long as both rows fit over the lede (3 lines) */
    --hero-t: clamp(60px, min(16vw, (100svh - var(--nav-h) - var(--hero-pb) - var(--hero-lede) * 4.5 - 24px) / 1.84), 280px);
  }
  .story .story__frame.story__frame--hero {
    display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto;
    align-items: stretch; align-content: stretch;
    min-height: calc(100svh - var(--nav-h));
    padding: 0 var(--gut) calc(var(--hero-pb) + env(safe-area-inset-bottom));
  }
  .story .story__frame--hero .story__copy { position: relative; grid-area: 1 / 1; width: auto; min-height: 0; }
  .story .story__frame--hero .story__title--hero {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; justify-content: center; align-items: center;
    font-size: var(--hero-fit, var(--hero-t)); line-height: .92;
    white-space: nowrap; text-align: center;
  }
  .story .story__frame--hero .story__title--hero .m-only { display: none; }
  .story .story__frame--hero .story__art { display: none; }
  .story .story__frame--hero .story__act {
    grid-area: 2 / 1; width: auto; margin: 0;
    display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; flex-wrap: wrap;
  }
  .story .story__frame--hero .lede { font-size: var(--hero-lede); max-width: 32ch; }
  .story .story__frame--hero .story__ctas { margin: 0; flex-wrap: wrap; }
  .story .story__frame--hero .story__ctas .btn { flex: none; padding: 0 28px; }
}
/* phones held sideways: the stage is a short strip, so the lede and buttons keep to one row along
   its foot (narrower lede, slimmer buttons, less air under them) and leave the box what they can */
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) and (orientation: landscape) and (max-height: 520px) {
  .story { --hero-pb: 12px; }
  .story .story__frame--hero .story__act { gap: 16px; }
  .story .story__frame--hero .story__ctas .btn { padding: 0 18px; }
}
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) and (orientation: landscape) and (max-height: 520px) and (max-width: 740px) {
  .story { --hero-lede: 15px; }
  .story .story__frame--hero .lede { max-width: 28ch; }
}
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) and (max-width: 640px) {
  .story .story__frame.story__frame--hero {
    display: flex; flex-direction: column;
    padding-bottom: calc(20px + env(safe-area-inset-bottom));
  }
  .story .story__frame--hero .story__copy { position: relative; }
  .story .story__frame--hero .story__title--hero {
    position: relative; inset: auto; display: block;
    padding-top: 18px; font-size: min(17.5vw, 9.5svh); line-height: .9;
  }
  .story .story__frame--hero .story__title--hero .m-only { display: inline; }
  .story .story__frame--hero .story__act { margin-top: auto; gap: 18px; }
  .story .story__frame--hero .lede { font-size: 15px; }
  .story .story__frame--hero .story__ctas { width: 100%; }
  .story .story__frame--hero .story__ctas .btn { flex: 1; padding: 0 14px; }
}

/* =========================================================================================
   THE ENTRANCE (motion allowed, scripts on)
   Nothing that has painted is hidden again. The lede and the buttons are there from the first
   paint, exactly where the pinned story keeps them. The headline is held back, here in CSS: it
   waits, paused, for home.ts to say the type is in (.is-ready), then rises out of a soft
   blur as today's does. If the script never arrives it simply shows after 3s; if it comes after
   that (.is-late) nothing replays. The box isn't in this frame until it drops (.is-falling) and
   has landed (.is-landed); once the letters are flying (.is-blasted), the headline itself stays
   hidden but keeps its place and its name for screen readers.
   ========================================================================================= */
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) {
  .story__frame--hero .row > span {
    animation: storyRise 1.1s .1s var(--ease) both, storyShow 1ms 3s forwards;
    animation-play-state: paused, running;
  }
  .story__frame--hero .row:nth-child(2) > span { animation-delay: .22s, 3s; }
  .story.is-ready .story__frame--hero .row > span { animation: storyRise 1.1s .1s var(--ease) both; }
  .story.is-ready .story__frame--hero .row:nth-child(2) > span { animation-delay: .22s; }
  /* the script came after the 3s fallback had shown the headline: it stays as it is */
  .story.is-late .story__frame--hero .row > span { animation: none; }
  .story.is-blasted .story__title--hero { opacity: 0; }

  .story.is-story:not(.is-falling):not(.is-landed) .story__object { opacity: 0; }
}
@keyframes storyRise { from { opacity: 0; transform: translateY(.18em); filter: blur(14px); } }
@keyframes storyShow { from, to { opacity: 1; transform: none; filter: none; } }

/* =========================================================================================
   PAGE-WIDE TOUCHES (on this page only)
   ========================================================================================= */

/* the closed bag drawer's shadow smeared a grey band down the right edge, over the story */
body:has(.story) .drawer__panel { transition: transform .6s cubic-bezier(.32, .72, 0, 1), box-shadow .6s var(--ease); }
body:has(.story) .drawer:not(.is-open) .drawer__panel { box-shadow: none; }
/* 44px tap targets in the nav: an invisible hit area grows around each control, so nothing moves */
body:has(.story) .nav__btn,
body:has(.story) .nav__wordmark { position: relative; }
body:has(.story) .nav__btn::before,
body:has(.story) .nav__wordmark::before,
body:has(.story) .nav__tonight::before,
body:has(.story) .bag::before {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: max(100%, 44px); height: max(100%, 44px);
  translate: -50% -50%;
}
