/* Becoming on the web, second pass.

   One stage, pinned to the viewport; six chapters turn on it as the page
   scrolls. System values come from the app, named the same: Theme.swift's
   colours and springs, Design/Tokens.swift's insets, sizes, radii and press
   scales. The beam is a copy this site owns (beam.js). */

@font-face {
  font-family: "Inter";
  src: url("fonts/inter.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Theme.swift — Color */
  --ink: #000;
  --bone: #fff;
  --mute: #9e9e9e;          /* white 0.62 */
  --dim: #616161;           /* white 0.38 */
  --surface: #1c1c1c;       /* white 0.11 */
  --unlock: #1f1f1f;        /* Color.unlockPill */
  --pink: #faa8d1;          /* CornerTag.pink */
  --red: #f57887;           /* CornerTag.red */
  --tag-ink: #141414;       /* CornerTag's type, white 0.08 */

  /* Tokens.swift */
  --screen: 30px;           /* Inset.screen */
  --tap: 44px;              /* Size.tap */
  --control: 52px;          /* Size.control */
  --r-card: 14px;
  --r-panel: 18px;
  --r-sheet: 24px;

  /* motion: app.js replaces these with the real springs as linear() */
  --snap: cubic-bezier(0.25, 1, 0.5, 1);   --snap-d: 0.2s;
  --glide: cubic-bezier(0.22, 1, 0.36, 1); --glide-d: 0.5s;
  --track: cubic-bezier(0.3, 1.2, 0.5, 1); --track-d: 0.35s;
  --sliver: cubic-bezier(0.34, 1.7, 0.64, 1);   /* the paper stack's own 0.45 · 0.42 */

  --vh: 100svh;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html { background: var(--ink); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overflow-x: hidden;
  /* a pinned stage whose content changes must never move the scroll
     position on the reader's behalf */
  overflow-anchor: none;
}
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
a { color: inherit; }
p, h1, h2 { margin: 0; }
:focus-visible { outline: 2px solid var(--pink); outline-offset: 3px; border-radius: 12px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.eyebrow {
  font-size: 12px;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
}

/* ── Pressable (Tokens.swift): a surface barely acknowledges, a control gives a little, chrome pops ── */
.press-control, .press-icon, .press-ring, .press-surface {
  transition: transform var(--snap-d) var(--snap), opacity 0.25s ease-out;
}
.press-surface:active { transform: scale(0.97); }
.press-control:active { transform: scale(0.95); }
.press-icon:active { transform: scale(0.88); }
.press-ring:active { transform: scale(0.92); }

/* ── Buttons ─────────────────────────────────────────────────────────── */
.btn {
  display: inline-grid;
  place-items: center;
  height: var(--control);
  padding: 0 30px;
  min-width: 187px;
  border-radius: 999px;
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  position: relative;
}
.btn-small { height: var(--tap); min-width: 0; padding: 0 20px; font-size: 14px; }
.btn-outline { background: var(--unlock); color: var(--bone); }
/* the unlock pill: near-black, a faint resting edge; libraries.dev's border
   beam wraps it (border-beam.js), so the wrapper carries the pill's radius */
.btn-metal { background: var(--unlock); color: var(--bone); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); }
[data-beam] .btn { display: grid; }

/* ── Header: the mark, and one quiet way in ──────────────────────────── */
.top {
  position: fixed;
  inset: 0 0 auto;
  z-index: 5;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: max(18px, env(safe-area-inset-top)) var(--screen) 0;
  pointer-events: none;
}
.top > * { pointer-events: auto; }
/* the wordmark is the SVG itself, never a mask: a masked element loses its
   mask the moment it composites for a fade, and the mark vanishes */
.wordmark { display: block; width: 104px; }
.wordmark img { display: block; width: 100%; height: auto; }

/* ── The scroller and the pinned stage ───────────────────────────────── */
.scroller { position: relative; }
.spacers > div { height: calc(var(--len) * var(--vh)); }
.stage-wrap {
  position: sticky;
  top: 0;
  height: var(--vh);
  overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) auto minmax(0, 0.75fr);   /* the words get the room; the index needs little */
  align-items: center;
  column-gap: clamp(32px, 5vw, 96px);
  padding-inline: var(--screen);
}
.spill {
  position: absolute;
  inset: -30% -25%;
  width: 150%;
  height: 160%;
  /* the canvas is drawn tiny and scaled up (beam.js): the blur only has
     to hide the bilinear steps, not make the light soft */
  filter: blur(28px);
  opacity: 0.55;
  pointer-events: none;
  will-change: filter;
  /* the pool of light has no edge */
  -webkit-mask: radial-gradient(closest-side, #000 35%, transparent 100%);
  mask: radial-gradient(closest-side, #000 35%, transparent 100%);
}

/* the room's two people: a soft light at each edge of the page, lit from
   the side the phone's beam is on, breathing with it */
.room {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 46vw;
  opacity: 0;
  pointer-events: none;
  filter: blur(60px);
  /* its own layer: the opacity moves every frame, the blur must not re-run */
  will-change: opacity;
  background: radial-gradient(60% 55% at var(--x) 55%, rgb(var(--room-c) / 0.55), rgb(var(--room-c) / 0.18) 40%, transparent 72%);
}
.room-l { left: -12vw; --x: 20%; }
.room-r { right: -12vw; --x: 80%; }

/* the phone on the table */
.stage {
  grid-column: 2;
  position: relative;
  width: min(390px, calc((var(--vh) - 96px) * 0.462));
  height: min(844px, calc(var(--vh) - 96px));
  border-radius: 52px;
  background: var(--ink);
  overflow: hidden;
  isolation: isolate;
  box-shadow: 0 0 0 1px #141414;
  transition: opacity 1.2s ease-in-out, transform 1.4s var(--glide), rotate 1.4s var(--glide), scale 1.4s var(--glide), border-radius 1.4s var(--glide);
}
.beam { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
.beam-layer { position: absolute; inset: 0; width: 100%; height: 100%; }
.beam-bloom { filter: blur(26px); }
.beam-far { filter: blur(48px); }
.beam-near { filter: blur(14px); }
.beam-line { filter: blur(1.4px); }

.stage-ui {
  position: relative;
  z-index: 1;
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 26px 22px;
}
.end { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; }
.end-top { transform: rotate(180deg); transition: opacity 0.8s ease-in-out; }
.ring {
  display: block;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--bone);
  transition: transform var(--snap-d) var(--snap), opacity 0.6s ease-in-out;
}
.ring-quiet { opacity: 0.45; }
.ring:hover { background: rgba(255, 255, 255, 0.04); }
.mic {
  justify-self: start;
  width: var(--tap);
  height: var(--tap);
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.1);
  transition: opacity 0.6s ease-in-out, transform var(--snap-d) var(--snap);
}
.mic svg { width: 19px; height: 19px; fill: none; stroke: rgba(255, 255, 255, 0.75); stroke-width: 1.6; stroke-linecap: round; }
.mic[aria-pressed="true"] { background: var(--bone); }
.mic[aria-pressed="true"] svg { stroke: var(--ink); }
/* chapters that have no turn to take: the rings go, the question stays */
/* the rings arrive the way the words do: a beat after the question, up
   out of nothing on the glide curve; they leave quicker than they come */
.slot { display: block; transition: opacity 0.9s ease-in-out 0.45s, transform 1.3s var(--glide) 0.45s; }
.stage-wrap[data-ch="open"] .slot, .stage-wrap[data-ch="last"] .slot, .stage-wrap[data-ch="solo"] .slot,
.stage-wrap[data-ch="decks"] .slot, .stage-wrap[data-ch="end"] .slot {
  opacity: 0; transform: scale(0.8); pointer-events: none;
  transition: opacity 0.5s ease-in, transform 0.6s ease-in;
}
.stage-wrap[data-ch="open"] .mic { opacity: 0; pointer-events: none; }
/* the opening: the mark on the stage, so the header's steps aside */
.top .wordmark { transition: opacity 0.8s ease-in-out; }
.stage-wrap[data-ch="open"] ~ .top .wordmark, body:has(.stage-wrap[data-ch="open"]) .top .wordmark { opacity: 0; }
.mark { display: block; width: min(220px, 62%); height: auto; }
.stage-wrap[data-ch="pair"] .ring-quiet { opacity: 0.45; }

/* one baseline for everything on the stage: the label of every page, and
   the mark, sit at the same height, so nothing jumps between turns */
.middle { display: grid; grid-template-rows: 1fr auto auto 1fr; align-items: start; min-height: 0; }
/* a box of one height, centred on the stage: every page's label sits at
   its top, so a two-line question and a four-line one share a baseline */
.turn { grid-row: 2; height: 180px; }
/* pages centre in the box; a question keeps a three-line height with its
   text centred inside it, so the label holds still for two lines or three */
.turn .page { align-content: start; align-self: stretch; }
.q { min-height: calc(1.22em * 3); display: grid; align-content: center; }
.last-wrap {
  grid-row: 3;
  height: 0;              /* takes no room, so the box above stays centred */
  overflow: visible;
  margin-top: -24px;
  justify-self: center;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.6s ease-in, transform 0.6s ease-in;
}
/* the chip on the transcript says it now; the card stays out */
.turn { display: grid; position: relative; }
/* a transcript is taller than the box: the exchange centres on the stage,
   not its label row. Keyed on the page, not the chapter, so the rule only
   changes once the new page is in and the old one is already frozen */
.turn:has(> .page:not(.leaving) .bub) { align-content: center; }
/* BlurTurn */
.page {
  grid-area: 1 / 1;
  display: grid;
  gap: 14px;
  justify-items: center;
  text-align: center;
  padding-inline: 6px;
  transition-property: opacity, filter;
}
/* a page on its way out is lifted out of the flow and held where it was
   (app.js sets its top), so the arriving page lays out alone */
.page.leaving { position: absolute; grid-area: auto; left: 0; right: 0; }
.qlabel { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--mute); }
.q { font-size: 26px; line-height: 1.22; letter-spacing: -0.012em; max-width: 12.5em; }  /* TypeScale.displayLarge */
.last {
  margin-top: 16px;
  display: grid;
  gap: 8px;
  justify-items: center;
  max-width: 18em;
  padding: 14px 18px 16px;
  border-radius: var(--r-panel);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.72);
  font-size: 15px;
  line-height: 1.35;
}
.last .qlabel { font-size: 11px; color: var(--pink); }

/* the chapter's words */
.copy {
  grid-column: 1;
  justify-self: center;   /* halfway into its column: half the gap from the left edge it had at the end */
  width: min(100%, 470px);   /* one width for every chapter's words */
  display: grid;
  position: relative;
  height: 22em;
  align-content: start;
  padding-top: 1.5em;
}
.copy .page { justify-items: start; text-align: left; padding: 0; gap: 6px; grid-template-rows: 12px auto auto; }
/* verse: the lines are the lines, so no balancing and no reflow */
.copy h2 {
  font-size: clamp(22px, 1rem + 0.65vw, 24px);   /* a spoken line, not a headline; ~42 characters fit the 470px column */
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
  text-wrap: pretty;
  /* three rows' height whether it takes two or three, so the lines under
     it never move between chapters: the same fix as the question's box */
  min-height: calc(1.2em * 2);
  display: grid;
  align-content: start;
}
.copy p { font-size: 17px; line-height: 1.5; color: var(--mute); max-width: 100%; }
/* a line that wraps carries on as prose, no hanging indent; a headline
   line that wraps breaks in its middle, never stranding its last word */
.copy .l { display: block; }
.copy h2 .l { text-wrap: balance; }

/* the index: where you are, and how much is left */
.index {
  grid-column: 3;
  justify-self: end;
  display: grid;
  gap: 4px;
  text-align: right;
}
/* the names are the story's contents page */
.index button {
  display: grid;
  transition: color 0.6s ease-in-out, border-color 0.6s ease-in-out;
  grid-template-columns: 8.5em auto;
  justify-items: end;
  gap: 14px;
  align-items: center;
  min-height: 36px;
  padding: 0 0 0 12px;
  font-size: 15px;
  color: var(--dim);
  border-left: 1.5px solid transparent;
  transition: color 0.4s ease-out, border-color 0.4s ease-out;
}
.index button span:last-child { font-size: 13px; letter-spacing: 0.5px; font-variant-numeric: tabular-nums; }
.index button[aria-current="true"] { color: var(--bone); }
.index button:hover { color: var(--mute); }

/* two of you: the phone turns round to face the person across the table */
/* the individual `rotate` property, so it interpolates as a number: 0 to
   180 and back, never the long way round through a full turn */
.stage { rotate: 0deg; }
/* two of you: the phone lies sideways between the two people, the way it
   does on the table in the app, and turns to whoever is talking */
@media (min-width: 881px) {
  /* it lies down once and stays: nobody turns the phone, the light moves */
  /* it lies down once and stays: nobody turns the phone, the light moves */
  .stage-wrap[data-ch="pair"] .stage { rotate: -90deg; scale: 0.92; }
  .stage-wrap[data-ch="pair"] .turn { rotate: 90deg; }
  /* the words go to the corner, so the phone can have the middle; they
     glide there on the phone's own curve and clock, never jump */
  .stage-wrap[data-ch="pair"] .copy { transform: translateY(calc(50vh - 43px)); }   /* alignment never changes: only the box moves, after the fade */
}
.turn { transition: rotate 1.4s var(--glide); }
/* the index stays on top of the closing page, so its buttons still take a click */
.index { position: relative; z-index: 4; }

/* from last time: the night as the app keeps it (QuestionBlock, MessageBubble) */
.chip { display: inline-block; margin-left: 8px; padding: 4px 9px; border-radius: 999px; background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.6); letter-spacing: 0.08em; }
.tr-q { font-size: 18px; line-height: 1.35; color: var(--bone); max-width: 15em; }
.turn .page:has(.bub) { justify-items: start; text-align: left; gap: 8px; }
.turn .page:has(.bub) > .qlabel { margin-bottom: 4px; }
.turn .page:has(.bub) > .tr-q { margin-bottom: 6px; }
.turn .page { width: 100%; max-width: 100%; min-width: 0; }
.bub {
  font-size: 14.5px;
  line-height: 1.45;
  padding: 11px 15px;
  border-radius: 18px;
  max-width: calc(100% - 56px);
  text-align: left;
}
.bub.me { justify-self: end; background: #f5f0e6; color: #171410; }
.bub.them { justify-self: start; display: grid; grid-template-columns: 24px minmax(0, 1fr); justify-items: start; gap: 8px; align-items: end; padding: 0; width: 100%; max-width: 100%; color: rgba(255, 255, 255, 0.92); }
.bub.them img { width: 24px; height: 24px; border-radius: 50%; }
.them-text { display: inline-block; width: auto; overflow-wrap: anywhere; padding: 11px 15px; border-radius: 18px; background: var(--surface); max-width: calc(100% - 32px); }

/* ── Chapter five: the rail ──────────────────────────────────────────── */
.stage-wrap[data-ch="decks"] .stage, .stage-wrap[data-ch="end"] .stage { opacity: 0; pointer-events: none; transform: scale(0.96); }
/* the words rise to the top of the screen while the rail has the floor;
   same element, same column, only a transform, so it glides there */
/* the words never travel: the old page blurs out where it is, the box
   snaps while nothing is visible, the new page blurs in where it now sits */
.copy { transition: transform 0s linear 0.78s; }
.stage-wrap[data-ch="decks"] .copy,
.stage-wrap[data-ch="end"] .copy { transform: translateY(calc(120px - 1.5em - 50vh + 11em)); }   /* leaves from where it was, no slide back */
.stage-wrap[data-ch="decks"] .index { opacity: 0; pointer-events: none; }
.index { transition: opacity 0.6s ease-in-out; }
.rail-wrap {
  position: absolute;
  inset: 0;
  display: grid;
  align-items: end;
  padding-bottom: max(7vh, 56px);
  opacity: 0;
  transform: translateY(28px);
  pointer-events: none;
  transition: opacity 0.6s ease-in, transform 0.7s ease-in;   /* out: quick, and down */
}
.stage-wrap[data-ch="decks"] .rail-wrap { opacity: 1; transform: none; pointer-events: auto; transition: opacity 1.2s ease-in-out, transform 1.6s var(--glide); }
.rail {
  display: flex;
  gap: 28px;
  padding: 60px var(--screen) 10px;
  width: max-content;
  will-change: transform;
}
.card-slot { --w: clamp(220px, 31vw, 300px); position: relative; flex: 0 0 var(--w); height: calc(var(--w) * 1.5); }
/* CoverGlow: the cover's own colours, light leaking from the card's edges */
.glow {
  position: absolute;
  inset: -1.5% -2%;
  border-radius: 16px;
  overflow: hidden;
  filter: blur(26px) saturate(1.6) brightness(1.14);
  opacity: 0;
  transition: opacity 0.5s ease-out;
  pointer-events: none;
}
/* the drift only runs on the card under the pointer: twelve blurred images
   animating hue and scale behind a hidden rail cost every frame on the page */
.glow img { width: 100%; height: 100%; object-fit: cover; display: block; animation: glow 23s ease-in-out infinite alternate; animation-play-state: paused; }
.card-slot:hover .glow img, .card-slot:focus-within .glow img { animation-play-state: running; }
@keyframes glow {
  0% { transform: scale(1); filter: hue-rotate(-14deg); }
  50% { transform: scale(1.02) translate(2%, -1.2%); filter: hue-rotate(10deg); }
  100% { transform: scale(0.99) translate(-2%, 1.2%); filter: hue-rotate(14deg); }
}
/* the paper slivers springing up out of the deck, bottom-up (TonightCard) */
.slivers { position: absolute; inset: 0; pointer-events: none; }
.slivers i {
  position: absolute;
  top: 0;
  left: 10px;
  right: 10px;
  height: 56.8px;
  border-radius: 14px;
  background: hsl(0 0% calc(14% + var(--i) * 4%));
  box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.45);
  transform-origin: bottom;
  transform: translateY(8px) scale(0.92);
  opacity: 0;
  transition: transform 0.2s ease-out, opacity 0.2s ease-out;
}
.card-slot:hover .glow, .card-slot:focus-within .glow { opacity: 0.22; }
.card-slot:hover .slivers i, .card-slot:focus-within .slivers i {
  transform: translateY(calc(-4 * 10.34px - 0.3px + var(--i) * 10.34px));
  opacity: 1;
  transition: transform 0.45s var(--sliver) calc((3 - var(--i)) * 0.05s), opacity 0.2s ease-out calc((3 - var(--i)) * 0.05s);
}
.card-slot:hover .card, .card-slot:focus-within .card { transform: translateY(-4px); }
.card {
  width: 100%;
  height: 100%;
  position: relative;
  display: block;
  transition: transform 0.45s var(--glide);
  border-radius: var(--r-card);
  overflow: hidden;
  background: #111;
  text-align: center;
  color: var(--bone);
}
.card img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* DeckFace's scrim */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow:
    inset 0 -45px 30px -9px rgba(0, 0, 0, 0.18),
    inset 0 -27px 85.5px -12px rgba(92, 92, 92, 0.32),
    inset 0 -150px 90px -45px #0e0e0e;
  pointer-events: none;
}
.card-meta { position: absolute; inset: auto 12px 18px; z-index: 1; display: grid; gap: 3px; }
.card-title { font-size: 21px; line-height: 1.15; }
.card-count { font-size: 15px; color: rgba(255, 255, 255, 0.5); }
.tag {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 1;
  display: inline-grid;
  place-items: center;
  height: 24px;
  padding: 0 9px;
  border-radius: 999px;
  background: var(--pink);
  color: var(--tag-ink);
  font-size: 12px;
  font-weight: 600;
}
.tag-red { background: var(--red); }
.copy .decks-count { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--mute); }

/* ── Chapter six ─────────────────────────────────────────────────────── */
.close {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* the column is the page, never the cast's width */
  align-content: center;

  justify-items: center;
  gap: 22px;
  padding: var(--screen);
  text-align: center;
  opacity: 0;
  transform: translateY(18px);
  pointer-events: none;
  transition: opacity 0.5s ease-in, transform 0.5s ease-in;
}
/* the open card is 274px taller than its pill: keep that room below the
   stack, so the card always fits inside the window (after the shorthand) */
.close { padding-bottom: calc(var(--screen) + 274px); }
/* in: after the rail has gone, up onto the page on the glide curve */
.stage-wrap[data-ch="end"] .close { opacity: 1; transform: none; pointer-events: auto; transition: opacity 1.1s ease-out 0.55s, transform 1.5s var(--glide) 0.55s; }
.close-line {
  font-size: clamp(26px, 1rem + 2vw, 40px);
  line-height: 1.1;
  letter-spacing: -0.026em;
}
.close-line .l { display: block; }
.close-line-m { display: none; }
.close .btn { margin-top: 10px; }
.close-note { font-size: 13px; color: var(--mute); }
/* ── DetailsDisclosureView, ported (ComponentLibrary: details-disclosure) ──
   Sizes, radii and the two-stage timing are the component's. Only the
   colours and the type are the site's. */
/* the slot holds the pill's room in the page; the card grows out of it
   over whatever is below, so nothing else on the page moves */
.dd-slot { display: block; position: relative; width: 236px; height: 44px; margin-top: 10px; z-index: 3; }
/* the corner: same component, opening down from the right edge */
.dd-slot-top { width: 176px; margin-top: 0; z-index: 6; transition: opacity 0.8s ease-in-out; }
/* the last page has its own; the corner's steps aside */
body:has(.stage-wrap[data-ch="end"]) .dd-slot-top { opacity: 0; pointer-events: none; }
.dd-slot-top > [data-beam] { left: auto; right: 0; translate: 0 0; }
/* the beam's wrapper is the positioned box; the pill sits inside it and
   the wrapper takes its size, so the clip always fits */
.dd-slot > [data-beam] { position: absolute; top: 0; left: 50%; translate: -50% 0; }
.dd {
  --dd-w: 176px; --dd-h: 44px; --dd-r: 22px;
  display: block;
  position: relative;
  width: var(--dd-w);
  height: var(--dd-h);
  padding: 14px 20px;
  border-radius: var(--dd-r);
  background: var(--unlock);
  color: var(--bone);
  text-align: center;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0), 0 2px 6px rgba(0, 0, 0, 0);
  transition: width var(--dd-w-d) var(--dd-w-e), height var(--dd-h-d) var(--dd-h-e) var(--dd-h-delay),
              border-radius var(--dd-h-d) var(--dd-h-e) var(--dd-h-delay), background-color 0.3s, box-shadow 0.4s;
}
.dd[aria-expanded="true"] { --dd-w: 236px; --dd-h: 318px; --dd-r: 28px; background: var(--unlock); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.3); }
.dd-head { display: flex; align-items: center; justify-content: center; gap: 8px; height: 16px; font-size: 16px; font-weight: 600; white-space: nowrap; }
/* the app's chevron (SF chevron.right): after the words, turning down when open */
.dd-chev { order: 2; display: block; width: 14px; height: 14px; flex: 0 0 14px; fill: none; stroke: rgba(255, 255, 255, 0.75); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--dd-h-d) var(--dd-h-e) var(--dd-h-delay); }
.dd[aria-expanded="true"] .dd-chev { transform: rotate(90deg); }
.dd-body {
  display: grid;
  gap: 14px;
  justify-items: center;
  margin-top: 18px;
  opacity: 0;
  filter: blur(8px);
  transform: translateY(-6px);
  transition: opacity var(--dd-c-d) var(--dd-c-e), filter var(--dd-c-d) var(--dd-c-e), transform var(--dd-c-d) var(--dd-c-e);
}
.dd[aria-expanded="true"] .dd-body { opacity: 1; filter: blur(0); transform: none; transition-delay: 0.16s; }
.dd-qr { width: 100%; height: auto; display: block; padding: 12px; background: #fff; border-radius: 14px; }
.dd-cell { display: grid; gap: 3px; text-align: center; }
.dd-label { font-size: 13px; color: var(--mute); }
.dd-value { font-size: 15px; font-weight: 500; }

/* the cast walk in along the bottom of the last page, each drawing
   themselves in as they come, the way the opening story does it */
.cast {
  margin-bottom: 6px;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  height: 296px;
  max-width: 100%;
  overflow: visible;
  opacity: 0;
  transition: opacity 1.2s ease-out 0.3s;
}
.cast.in { opacity: 1; }
/* a family photo: shoulder to shoulder, a couple of them a step back */
.cast canvas { height: 266px; width: auto; flex: none; margin-inline: -22px; transform-origin: bottom center; position: relative; }
/* the small print sits on the floor of the page, 30px up, whatever the
   page above it is doing */
.legal { position: absolute; left: 0; right: 0; bottom: max(30px, env(safe-area-inset-bottom)); display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 0 22px; font-size: 13px; color: var(--dim); }
.legal span { min-height: var(--tap); display: inline-grid; place-items: center; }
.legal a { color: var(--dim); text-decoration: none; min-height: var(--tap); display: inline-grid; place-items: center; }
.legal a:hover { color: var(--mute); }

/* ── The deck sheet ──────────────────────────────────────────────────── */
.sheet {
  width: min(520px, 100%);
  max-width: 100%;
  max-height: min(94svh, 940px);
  margin: auto auto 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  background: var(--ink);
  color: var(--bone);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.sheet[open] { animation: sheet-in var(--glide-d) var(--glide); }
.sheet::backdrop { background: rgba(0, 0, 0, 0.62); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
@keyframes sheet-in { from { transform: translateY(48px); opacity: 0; } }
@media (min-width: 700px) { .sheet { margin: auto; border-radius: var(--r-sheet); } }
.sheet-x {
  position: absolute; top: 18px; left: 18px; z-index: 2;
  width: var(--tap); height: var(--tap);
  display: grid; place-items: center;
  border-radius: 50%; background: rgba(0, 0, 0, 0.35);
}
.sheet-x svg { width: 18px; height: 18px; stroke: #fff; stroke-width: 1.8; stroke-linecap: round; }
.sheet-art { position: relative; aspect-ratio: 4 / 4.4; overflow: hidden; }
.sheet-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sheet-art::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, 0.72) 78%, #000 100%); }
.sheet-body { position: relative; margin-top: -120px; padding: 0 var(--screen) 40px; display: grid; justify-items: center; text-align: center; gap: 6px; }
.sheet-title { font-size: 26px; font-weight: 400; line-height: 1.15; }
.sheet-mini { font-size: 14px; color: rgba(255, 255, 255, 0.6); order: -1; }
.sheet-count { font-size: 18px; color: rgba(255, 255, 255, 0.7); }
.sheet-who { margin-top: 6px; font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; color: rgba(255, 255, 255, 0.55); }
.sheet-line { margin-top: 16px; font-size: 16px; color: rgba(255, 255, 255, 0.72); max-width: 24em; }
.taste { list-style: none; margin: 26px 0 0; padding: 0; width: 100%; display: grid; gap: 8px; text-align: left; }
.taste li { padding: 16px 18px; border-radius: var(--r-card); background: var(--surface); font-size: 16px; line-height: 1.35; }
.taste-head { margin-top: 28px; }
.sheet-cta { margin-top: 30px; display: grid; gap: 10px; justify-items: center; }
.sheet-note { font-size: 13px; color: var(--mute); display: flex; align-items: center; gap: 2px; min-height: 40px; }
/* the key turning beside the note: 96px frames drawn at 40px, on black */
.sheet-key { width: 40px; height: 40px; display: block; }

/* ── Phone: the screen is the stage ──────────────────────────────────── */
@media (max-width: 880px) {
  .stage-wrap {
    display: block;
    padding: 0;
  }
  .spill { display: none; }
  .stage {
    position: absolute;
    inset: 0;
    width: auto;
    height: auto;
    /* the screen keeps the phone's curve, so the light is clipped to it
       and the corners outside the curve stay black */
    border-radius: 44px;
    box-shadow: none;
  }
  /* the same room top and bottom, so the middle of the stage is the middle of the screen */
  .stage-ui { padding: calc(max(18px, env(safe-area-inset-top)) + 52px) 30px calc(max(18px, env(safe-area-inset-bottom)) + 52px); }
  /* the question owns its screen now, so it sits dead centre: the box in
     the middle of the stage and the words in the middle of the box */
  .middle { grid-template-rows: 1fr auto auto 1fr; }
  .turn { height: 230px; }
  /* the label row is fixed and every question fills a four-line block,
     text centred inside it, so nothing moves from one card to the next */
  .q { min-height: calc(1.22em * 4); }
  /* a fixed box: the page fading out is lifted out of the flow, and a
     box that collapsed would drop its top (and the fading page) by its
     old height, since it hangs from the bottom of the screen */
  .copy { height: 220px; padding-top: 0; align-content: end; }
  .stage-wrap[data-half="words"] .copy { align-content: center; }
  .q { font-size: 28px; }
  .copy {
    position: absolute;
    left: var(--screen);
    right: var(--screen);
    bottom: calc(max(22px, env(safe-area-inset-bottom)) + 132px);
    z-index: 2;
    width: auto;
    /* the desk's justify-self: end would shrink an absolute box to its
       words and push it to the right edge; here it fills its insets */
    justify-self: auto;
    min-height: 0;
    pointer-events: none;
  }
  /* the question is the thing to look at; the headline is the caption
     under it: smaller, quieter, one step down, and the eyebrow a step
     below that */
  .copy h2 { font-size: 19px; line-height: 1.3; color: var(--bone); letter-spacing: -0.01em; min-height: 0; }
  .copy .eyebrow { display: none; }
  /* centred, like the question above it: one axis for the whole screen */
  .copy .page { grid-template-rows: auto auto; gap: 8px; justify-items: center; text-align: center; }
  .copy .l { padding-left: 0; text-indent: 0; }
  /* the header steps off the middle chapters: the mark is on the first
     page's stage, the door is on the last page */
  body:has(.stage-wrap:is([data-ch="play"], [data-ch="tonight"], [data-ch="pair"], [data-ch="last"], [data-ch="solo"], [data-ch="decks"])) .top { opacity: 0; pointer-events: none; }
  .top { transition: opacity 0.8s ease-in-out; }
  /* Start Becoming is a link here (app.js): a phone can't scan itself */
  .dd-chev { display: none; }
  .dd-head { justify-content: center; }
  .close-line { font-size: 28px; }
  .cast { height: 182px; }
  .cast canvas { height: 174px; margin-inline: -14px; }
  /* subtractive: the phone is the phone. No index (you scroll), no lines
     under the headline (the headline is the copy), no phone drawn on a
     phone — in Two of You the light crossing the screen's two ends is
     already the two people. What is left gets the room. */
  .index { display: none; }
  /* the phone is a game that fits the screen: nothing scrolls, one ring,
     no microphone, no second person's ring */
  html, body { overflow: hidden; height: 100%; }
  .mic { visibility: hidden; }   /* keeps its cell, so the ring stays centred */
  .stage-wrap[data-ch="play"] .end-top { opacity: 0; }
  .copy #play, .copy [data-beam] { pointer-events: auto; }
  /* the beam wrapper carries the button's own inline margin, so the room goes on the line above it */
  .copy p:has(#play) { padding-top: 32px; }
  /* the header's mark must not flash in while the header itself fades out for the game */
  body:has(.stage-wrap[data-ch="play"]) .top .wordmark { opacity: 0; transition: none; }
  .close-line { display: none; }
  .close-line-m { display: block; }
  /* the narration needs its second half on a phone too: small and quiet */
  .copy p:not(.eyebrow) { font-size: 13.5px; line-height: 1.4; color: var(--mute); }
  .copy .l { padding-left: 0; text-indent: 0; }
  .tr-q { font-size: 16px; }
  .bub { font-size: 13.5px; padding: 9px 13px; }
  .turn .page:has(.bub) { gap: 6px; }
  .rail { gap: 16px; }
  .card-slot { --w: 208px; }
  .rail-wrap { align-items: center; padding-bottom: 0; padding-top: 100px; }
  /* two screens per chapter. Words: the copy centred on the light, the
     phone's chrome and the rail out. Screen: the copy out, the rest in.
     Both (the opening, the close): the copy at the foot, as it lays out. */
  /* the words never slide: the container only moves once its page has faded */
  .copy { transition: opacity 0.7s ease-in-out, transform 0s linear 0.75s; }
  .stage-wrap[data-half="words"] .copy { transform: translateY(calc(154px + 50% - 50svh)); }
  .stage-wrap[data-half="screen"] .copy { opacity: 0; transform: translateY(calc(154px + 50% - 50svh)); }
  .stage-ui { transition: opacity 0.7s ease-in-out; }
  .stage-wrap[data-half="words"] .stage-ui { opacity: 0; pointer-events: none; }
  .stage-wrap[data-ch="decks"][data-half="words"] .rail-wrap { opacity: 0; pointer-events: none; }
  .stage-wrap[data-ch="end"] .copy { transform: translateY(calc(-100svh + 132px + 22px + 100% + 120px)); }
  /* the line breaks where the width says, not where the desk's <br> does */
  .close-line { font-size: 25px; text-wrap: balance; max-width: 13em; }
  .close-line br { display: none; }
  /* the pill is a link here, nothing opens under it: the page centres true */
  .close { padding: var(--screen); }
  .cast { margin-bottom: 0; }
}
@media (min-width: 881px) and (max-height: 860px) {
  .close { gap: 14px; }
  .cast { height: 190px; margin-bottom: 0; }
  .cast canvas { height: 176px; margin-inline: -14px; }
  .close-line { font-size: clamp(22px, 1rem + 1.2vw, 30px); }
}
@media (max-width: 360px) { :root { --screen: 20px; } .q { font-size: 24px; } }

@media (prefers-reduced-motion: reduce) {
  .glow img { animation: none; }
  .sheet[open] { animation: none; }
  .stage, .rail-wrap, .close { transition-duration: 0.01s; }
}
