/* Legal Station — a pitch deck that happens to be a web page.
 *
 * MOBILE FIRST, LITERALLY: every rule here is written for a phone, and the
 * only media queries widen. Nothing is designed at desktop and then squeezed.
 *
 * CREAM AND WARM, FORMAL AND LEGAL. The surfaces are warm off-white; gold is
 * the accent and stays jewellery — rules, figures, keylines, the play glyph.
 * Two golds, deliberately: `--gold` is a FILL (it has no contrast against
 * cream as text, 2.2:1), `--gold-deep` is the readable one for small type at
 * 5.2:1. Never swap them.
 *
 * THE PRIMARY ACTION IS INK, NOT GOLD. On a cream page a gold button reads
 * washed out at button sizes; espresso on cream measures 12:1 and is
 * unmistakable. Gold still signs it — a gold hairline and a gold arrow — so
 * the accent system is unbroken.
 *
 * THE FIRST SCREEN IS THE FILM, held in a GLASS SLAB. Not a frame and not the
 * dark mat this page carried an hour ago: a translucent, floating object that
 * refracts the warm light behind it. `backdrop-filter` renders as flat tint
 * over flat colour, so `.stage-hero::before` puts real structure underneath —
 * that is what makes the rim read as glass instead of as a pale border.
 *
 * THE DECK. Stages are full-height and snap. `proximity`, NEVER `mandatory`:
 * a stage taller than the viewport (the spec cards on a small phone) must not
 * become a trap, and proximity is the guarantee. Reveals are
 * IntersectionObserver-driven rather than `animation-timeline: view()`, which
 * is still Chromium-only and this page will be judged in Safari.
 *
 * Tokens first, and ONLY tokens: a second shade has to be added here, on
 * purpose, by someone who can see the first one.
 */
:root {
  /* ── surfaces, warm off-white ── */
  --paper: #f1ebdf; /* muted a notch from #f6f1e6 — same cream, less glare */
  --paper-lit: #fffcf5;
  --paper-sunk: #efe7d6;

  /* ── ink, warm near-black rather than grey ── */
  --ink: #221e17;
  --ink-soft: #4a4238;
  --dim: #6d6455;

  /* ── gold, in two jobs ── */
  --gold: #c9a227; /* FILLS and keylines only */
  --gold-deep: #7d6212; /* small type on cream — 5.2:1 */

  --edge: #ded4bf;
  --edge-soft: #e8e0cd;

  /* Derived, so a change above propagates instead of drifting. */
  --gold-hair: color-mix(in oklab, var(--gold) 55%, transparent);
  --veil: color-mix(in oklab, var(--paper) 82%, transparent);
  --ink-lit: color-mix(in oklab, var(--ink) 88%, white);

  --measure: 34rem;
  --gutter: clamp(1.15rem, 5vw, 2.5rem);
  --round: 12px;
  --round-slab: clamp(18px, 3.2vw, 28px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --bar-h: 3.5rem;

  /* A serif for display type and a sans for reading. Both are system faces:
     the CSP forbids a webfont CDN on purpose, and formality should not cost a
     network request. Georgia is on macOS, Windows and iOS; Android falls
     through to its own serif, which is the same intent. */
  --display:
    ui-serif, Georgia, "Iowan Old Style", "Times New Roman", Times, serif;
  --text:
    ui-sans-serif, -apple-system, "Segoe UI", Roboto, Helvetica, Arial,
    sans-serif;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* PROXIMITY. See the header note — `mandatory` turns any over-tall stage
     into a scroll trap, which is the one failure a deck must not have. */
  scroll-snap-type: y proximity;
}
/* Set by main.js when the visitor has asked for reduced motion or Save-Data.
   Everything choreographed switches off together, and what is left is an
   ordinary, complete, readable page. */
html.is-plain {
  scroll-snap-type: none;
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 clamp(1rem, 0.95rem + 0.3vw, 1.125rem) / 1.6 var(--text);
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* THE WANDERING LIGHT. Three soft pools of colour — honey, apricot-rose and a
   cool pale sage — each drifting on its own path at its own pace (47 s, 59 s,
   71 s: no two periods share a factor, so the three never fall back into
   step and the composition never visibly repeats). Their paths cross the
   middle of the page, so they meet, merge into one warm cloud and drift
   apart again.

   SMOOTHNESS is in two places. Each pool falls off along an eased curve
   (seven stops approximating ease-out) instead of the two-stop linear ramp
   that leaves a visible ring; and the colours are mixed `in oklab`, which
   keeps a honey-to-cream fade from dipping through grey on the way.

   The positions are registered @property percentages, so they interpolate
   inside the gradient — no transform on a fixed element (see body::after
   for why that matters on this page). */
@property --ax { syntax: "<percentage>"; inherits: false; initial-value: 18%; }
@property --ay { syntax: "<percentage>"; inherits: false; initial-value: 22%; }
@property --bx { syntax: "<percentage>"; inherits: false; initial-value: 82%; }
@property --by { syntax: "<percentage>"; inherits: false; initial-value: 30%; }
@property --cx { syntax: "<percentage>"; inherits: false; initial-value: 50%; }
@property --cy { syntax: "<percentage>"; inherits: false; initial-value: 86%; }

body::before {
  --honey: #e8c170;
  --apricot: #e9ad93;
  --sage: #c9d2b0;
  content: "";
  position: fixed;
  inset: 0;
  z-index: -3;
  pointer-events: none;
  background:
    radial-gradient(
      62vmax 52vmax at var(--ax) var(--ay) in oklab,
      color-mix(in oklab, var(--honey) 46%, transparent) 0%,
      color-mix(in oklab, var(--honey) 38%, transparent) 14%,
      color-mix(in oklab, var(--honey) 27%, transparent) 30%,
      color-mix(in oklab, var(--honey) 16%, transparent) 46%,
      color-mix(in oklab, var(--honey) 7%, transparent) 63%,
      color-mix(in oklab, var(--honey) 2%, transparent) 80%,
      transparent 100%
    ),
    radial-gradient(
      54vmax 60vmax at var(--bx) var(--by) in oklab,
      color-mix(in oklab, var(--apricot) 40%, transparent) 0%,
      color-mix(in oklab, var(--apricot) 33%, transparent) 14%,
      color-mix(in oklab, var(--apricot) 23%, transparent) 30%,
      color-mix(in oklab, var(--apricot) 13%, transparent) 46%,
      color-mix(in oklab, var(--apricot) 6%, transparent) 63%,
      color-mix(in oklab, var(--apricot) 2%, transparent) 80%,
      transparent 100%
    ),
    radial-gradient(
      58vmax 46vmax at var(--cx) var(--cy) in oklab,
      color-mix(in oklab, var(--sage) 44%, transparent) 0%,
      color-mix(in oklab, var(--sage) 36%, transparent) 14%,
      color-mix(in oklab, var(--sage) 25%, transparent) 30%,
      color-mix(in oklab, var(--sage) 14%, transparent) 46%,
      color-mix(in oklab, var(--sage) 6%, transparent) 63%,
      color-mix(in oklab, var(--sage) 2%, transparent) 80%,
      transparent 100%
    );
  animation:
    wander-a 47s ease-in-out infinite,
    wander-b 59s ease-in-out infinite,
    wander-c 71s ease-in-out infinite;
}
/* Each path is a loose closed loop that passes near the centre at least once,
   and at a different moment from the others — that is where they merge. */
@keyframes wander-a {
  0%, 100% { --ax: 18%; --ay: 22%; }
  22% { --ax: 44%; --ay: 48%; }
  41% { --ax: 72%; --ay: 18%; }
  63% { --ax: 58%; --ay: 70%; }
  82% { --ax: 26%; --ay: 62%; }
}
@keyframes wander-b {
  0%, 100% { --bx: 82%; --by: 30%; }
  19% { --bx: 64%; --by: 78%; }
  38% { --bx: 40%; --by: 52%; }
  57% { --bx: 14%; --by: 26%; }
  78% { --bx: 52%; --by: 14%; }
}
@keyframes wander-c {
  0%, 100% { --cx: 50%; --cy: 86%; }
  24% { --cx: 20%; --cy: 58%; }
  46% { --cx: 48%; --cy: 36%; }
  67% { --cx: 84%; --cy: 64%; }
  86% { --cx: 70%; --cy: 92%; }
}

/* ── the ambient layers ─────────────────────────────────────────────────
   Three fixed layers behind everything, stacked by z-index in the ROOT
   stacking context (body has none of its own), so every photograph, the film
   and every card paints OVER them:
     -3  body::before  the three wandering pools of colour
     -2  body::after   the sheen (an occasional glint of light)
     -1  html::after   the dots (invisible until the cursor asks for them)

   Registered custom properties (@property) are what make this smooth: an
   UNregistered custom property is a string and snaps between values, a
   registered one is typed, so it interpolates — in a transition, in a
   keyframe, inside a gradient stop or a mask position. That is the whole
   trick behind the sheen, the wave, and the dots fading in and out. */
@property --sheen {
  syntax: "<percentage>";
  inherits: false;
  initial-value: -40%;
}
@property --wave {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
@property --spot {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

/* The sheen: one soft band of warm light that crosses
   the page every so often, like light moving across paper. `background-
   position` and a registered stop position, NOT a transform — a transformed
   fixed element contributes to the document's scroll width, which is how the
   hero glow once put a horizontal scrollbar on this page. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  opacity: 0.62;
  background:
    linear-gradient(
      108deg,
      transparent calc(var(--sheen) - 16%),
      #fffaf0a6 calc(var(--sheen) - 3%),
      #fffdf7d9 var(--sheen),
      #fffaf0a6 calc(var(--sheen) + 3%),
      transparent calc(var(--sheen) + 16%)
    );
  animation: sheen 17s cubic-bezier(0.45, 0, 0.25, 1) infinite;
}
/* Crosses in the first ~60% of the cycle and rests off-screen for the rest,
   so it reads as an occasional glint rather than a scanner. */
@keyframes sheen {
  0% {
    --sheen: -40%;
  }
  60%,
  100% {
    --sheen: 140%;
  }
}

/* THE DOTS. A fine, even grid of tiny warm points — the textured "bump"
   field of generated imagery — that is never visible on its own. Two masks,
   intersected:
     1. a soft spotlight at the cursor (--mx, --my), faded by --spot
     2. soft diagonal bands that drift back and forth (--wave)
   so what shows is only the part of the field under the cursor, and inside
   that the density swells and ebbs in waves as the bands pass through.
   main.js moves the spotlight and sets --spot; everything else is CSS. */
html {
  --mx: -400px;
  --my: -400px;
  --spot: 0;
  transition: --spot 0.9s var(--ease);
}
html::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--spot);
  background-image: radial-gradient(
    circle,
    color-mix(in oklab, var(--gold-deep) 42%, transparent) 0.7px,
    transparent 1.2px
  );
  background-size: 8px 8px;
  -webkit-mask-image:
    radial-gradient(
      170px 170px at var(--mx) var(--my),
      #000 0%,
      #000000b3 38%,
      transparent 100%
    ),
    repeating-linear-gradient(
      118deg,
      #000 0px,
      #0000008c 18px,
      #0000001f 34px,
      #0000008c 50px,
      #000 68px
    );
  mask-image:
    radial-gradient(
      170px 170px at var(--mx) var(--my),
      #000 0%,
      #000000b3 38%,
      transparent 100%
    ),
    repeating-linear-gradient(
      118deg,
      #000 0px,
      #0000008c 18px,
      #0000001f 34px,
      #0000008c 50px,
      #000 68px
    );
  -webkit-mask-position:
    0 0,
    var(--wave) 0;
  mask-position:
    0 0,
    var(--wave) 0;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  animation: wave 5.5s ease-in-out infinite alternate;
}
@keyframes wave {
  from {
    --wave: -34px;
  }
  to {
    --wave: 34px;
  }
}

/* Still for anyone who asked for less motion, and no dots at all where there
   is no cursor to put them under. */
@media (prefers-reduced-motion: reduce) {
  body::before,
  body::after {
    animation: none;
  }
  html::after {
    display: none;
  }
}
@media not ((hover: hover) and (pointer: fine)) {
  html::after {
    display: none;
  }
}
html.is-plain::after {
  display: none;
}

/* ── the deck ────────────────────────────────────────────────────────────── */
.stage {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  scroll-snap-align: start;
  padding: calc(var(--bar-h) + 1rem) var(--gutter) calc(1.5rem + var(--safe-b));
}

.mid {
  width: 100%;
  max-width: 62rem;
  margin-inline: auto;
}

/* ── the reveal ──────────────────────────────────────────────────────────── */
[data-rise] {
  opacity: 0;
  transform: translateY(1.5rem);
  transition:
    opacity 0.75s var(--ease),
    transform 0.75s var(--ease);
  transition-delay: calc(var(--i, 0) * 95ms);
}
.stage.is-live [data-rise] {
  opacity: 1;
  transform: none;
}
html.is-plain [data-rise] {
  opacity: 1;
  transform: none;
  transition: none;
}

/* ── STAGE 0 — the film in glass ─────────────────────────────────────────── */
.stage-hero {
  /* A CENTRED COLUMN, not `auto 1fr auto` with the cue pinned to the bottom
     edge. That version put every pixel of slack in ONE place: on a 393x852
     phone the slab sat 278px down with 331px of empty cream above it and the
     cue stranded 240px below, which reads as a broken layout rather than as
     space. Centring the group splits the slack evenly above and below, so the
     film reads as a framed object hung on the wall — which is the whole
     conceit — instead of a small video adrift. */
  grid-template-rows: none;
  align-content: center;
  justify-items: center;
  gap: clamp(1rem, 3vh, 1.8rem);
  padding-inline: clamp(0.6rem, 3vw, 2.5rem);
  padding-top: calc(1.25rem + env(safe-area-inset-top, 0px));
}

/* What the glass refracts. Without real structure behind it `backdrop-filter`
   is an expensive way to draw a flat tint. */
.stage-hero::before {
  content: "";
  position: absolute;
  /* Vertical bleed only. `inset: -10%` bled 144px past each side at 1440px and
     put a horizontal scrollbar on the whole document — a pseudo-element does
     not appear in a querySelectorAll sweep, so it is invisible to the usual
     overflow hunt and was found by subtracting scrollWidth from clientWidth.
     `overflow-x: hidden` on <body> does not help: <html> is the scroller. */
  inset: -12% 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(26rem 20rem at 20% 26%, #e8c76b5c, transparent 70%),
    radial-gradient(24rem 19rem at 82% 74%, #d9b8985e, transparent 70%),
    radial-gradient(34rem 26rem at 62% 8%, #f2e6c47a, transparent 72%);
}

.wordmark {
  margin: 0;
  font-family: var(--text);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold-deep);
  transition:
    opacity 0.45s var(--ease),
    transform 0.45s var(--ease);
}

/* THE SLAB. Layered shadows do the floating: a tight contact shadow so it sits
   on something, then two wide soft ones so it sits ABOVE it. All warm brown —
   a neutral grey shadow on cream reads dirty. */
.slab {
  margin: 0;
  /* Near edge-to-edge on a phone: every point of width is a point of film. */
  width: min(97vw, 76rem);
  padding: clamp(0.5rem, 1.5vw, 0.8rem);
  border-radius: var(--round-slab);
  background: linear-gradient(148deg, #fffdf8bf, #fdf8ec8c 42%, #f7efdd7a);
  backdrop-filter: blur(20px) saturate(165%);
  -webkit-backdrop-filter: blur(20px) saturate(165%);
  box-shadow:
    inset 0 1px 0 #fffffff2,
    inset 0 0 0 1px #ffffff6b,
    0 0 0 1px #4a380f14,
    0 2px 5px -1px #4a380f1f,
    0 26px 50px -18px #4a380f3d,
    0 54px 110px -40px #4a380f2e;
  transition:
    transform 0.62s var(--ease-io),
    opacity 0.62s var(--ease-io),
    filter 0.62s var(--ease-io);
  /* The object breathes. ONLY the shadow is animated — `.slab` already has two
     writers on `transform` (the reveal, and the departing recede), and a third
     would silently win over both. Shifting the spread and offset alone reads
     as the slab rising and settling, which is the effect, without touching a
     property something else owns. */
  animation: slab-breathe 7.5s var(--ease-io) infinite alternate;
}

@keyframes slab-breathe {
  from {
    box-shadow:
      inset 0 1px 0 #fffffff2,
      inset 0 0 0 1px #ffffff6b,
      0 0 0 1px #4a380f14,
      0 2px 5px -1px #4a380f1f,
      0 20px 40px -16px #4a380f38,
      0 44px 92px -38px #4a380f26;
  }
  to {
    box-shadow:
      inset 0 1px 0 #fffffff2,
      inset 0 0 0 1px #ffffff6b,
      0 0 0 1px #4a380f14,
      0 2px 5px -1px #4a380f1a,
      0 34px 64px -20px #4a380f42,
      0 72px 132px -44px #4a380f33;
  }
}

.film {
  position: relative;
  overflow: hidden;
  border-radius: calc(var(--round-slab) - 7px);
  background: #17130d;
  aspect-ratio: 16 / 9;
  /* A hairline between glass and picture, drawn INSIDE so it reads as part of
     the object rather than as a border on the video. */
  box-shadow:
    inset 0 0 0 1px #00000026,
    0 1px 2px #4a380f1a;
}

.hero-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fallback {
  padding: 2rem;
  color: #cfc7b5;
  text-align: center;
}

/* ── the film's own chrome ───────────────────────────────────────────────── */
.film-chrome {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: clamp(1.6rem, 5vw, 2.4rem) clamp(0.6rem, 2vw, 1rem)
    clamp(0.5rem, 1.6vw, 0.75rem);
  /* The scrim exists only where the controls are, and it comes and goes with
     them. */
  background: linear-gradient(180deg, #0000, #0f0c0794);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.28s var(--ease);
}

/* HIDDEN UNTIL ASKED FOR. Three ways in and nothing else:
     .is-awake        — set by main.js on a mouse moving over the film or a
                        tap, cleared on a timer; held while seeking
     :hover on the bar — the cursor resting ON the controls keeps them, but
                        only where hover is real (a fine pointer). On a touch
                        screen `:hover` sticks after a tap and would pin them.
     :focus-visible   — keyboard focus inside the bar. NOT `:focus-within`:
                        that stays true after you TAP a button, because the
                        button keeps focus, and one press pinned the controls
                        on screen for good. That was the "always visible".
   There is no reveal on arrival. */
.film.is-awake .film-chrome,
.film-chrome:has(:focus-visible) {
  opacity: 1;
  pointer-events: auto;
}
@media (hover: hover) and (pointer: fine) {
  .film-chrome:hover {
    opacity: 1;
    pointer-events: auto;
  }
}

/* Fullscreen: the film fills the screen and the picture keeps its shape. */
.film:fullscreen,
.film:-webkit-full-screen {
  width: 100vw;
  height: 100vh;
  border-radius: 0;
}
.film:fullscreen .hero-video,
.film:-webkit-full-screen .hero-video {
  object-fit: contain;
  background: #000;
}

#fullscreen .ico-shrink,
#fullscreen[data-full="true"] .ico-expand {
  display: none;
}
#fullscreen[data-full="true"] .ico-shrink {
  display: block;
}

/* ── the two controls ────────────────────────────────────────────────────────
   NO WORDS ON THE FILM. Both controls are the same 44px circle carrying one
   glyph, and their accessible names are set from main.js — an <svg>-only
   button has none of its own, so a name that exists only in the markup would
   be no name at all.

   The muted state is signalled by WEIGHT, not by text: the button fills gold
   and reads as the one thing on the picture asking to be pressed. That is the
   state that needs an answer — no browser will start a video aloud on a first
   visit — and a filled circle answers it without putting a caption on a film
   that is supposed to carry itself. */
.ctl {
  flex: none;
  display: grid;
  place-items: center;
  /* A full 44px touch target. Nothing is presented smaller than it is. */
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #0f0c07a3;
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: inset 0 0 0 1px #ffffff2e;
  color: #f3ecda;
  cursor: pointer;
  transition:
    background-color 0.2s var(--ease),
    box-shadow 0.2s var(--ease),
    transform 0.2s var(--ease);
}
.ctl:active {
  transform: scale(0.94);
}
@media (hover: hover) and (pointer: fine) {
  .ctl:hover {
    background: #0f0c07cc;
  }
}
.ctl:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
.ctl .ico {
  grid-area: 1 / 1;
  color: var(--gold);
}

/* Both controls stack their two glyphs in one cell, so neither button resizes
   or shifts as it toggles. */
.sound .ico-on,
#playpause .ico-pause {
  display: none;
}
.sound[aria-pressed="true"] .ico-on,
#playpause[data-playing="true"] .ico-pause {
  display: block;
}
.sound[aria-pressed="true"] .ico-off,
#playpause[data-playing="true"] .ico-play {
  display: none;
}

/* Silent: filled, and the glyph goes dark against it. */
.sound[aria-pressed="false"] {
  background: var(--gold);
  box-shadow:
    inset 0 0 0 1px #ffffff40,
    0 0 0 0.35rem color-mix(in oklab, var(--gold) 22%, transparent);
}
.sound[aria-pressed="false"] .ico {
  color: #17130a;
}
@media (hover: hover) and (pointer: fine) {
  .sound[aria-pressed="false"]:hover {
    background: color-mix(in oklab, var(--gold) 88%, white);
  }
}

/* The timeline. The ELEMENT is a 44px hit area — the same size as the
   buttons beside it — and the 3px rule you see is a child inside it, so a
   finger does not have to land on three pixels. `touch-action: none` stops
   the browser claiming a drag on it as a page scroll. */
.elapsed {
  flex: 1 1 auto;
  position: relative;
  display: flex;
  align-items: center;
  height: 44px;
  cursor: pointer;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}
.elapsed:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  border-radius: 6px;
}
.elapsed-track {
  position: relative;
  flex: 1;
  height: 3px;
  border-radius: 999px;
  background: #ffffff33;
  transition: height 0.15s var(--ease);
}
.elapsed-fill {
  position: relative;
  display: block;
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: var(--gold);
  transition: width 0.25s linear;
}
/* The knob is what says "this can be dragged". It rides the end of the fill. */
.elapsed-fill::after {
  content: "";
  position: absolute;
  right: -6px;
  top: 50%;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 0 2px #0f0c0766;
  transform: translateY(-50%);
}
.film.is-seeking .elapsed-track {
  height: 5px;
}
/* While dragging, the fill follows the finger exactly — an eased width lags
   the touch point and reads as the seek not working. */
.film.is-seeking .elapsed-fill {
  transition: none;
}
@media (hover: hover) and (pointer: fine) {
  .elapsed:hover .elapsed-track {
    height: 5px;
  }
}

/* ── the scroll cues. Controls, not decoration. ──────────────────────────
   Two, side by side, both leading DOWN: the rail, the falling dot and the
   chevron at its foot all say "below", so neither reads as "start here". */
.cues {
  display: flex;
  justify-content: center;
  gap: clamp(1.5rem, 5vw, 3.5rem);
}
.cue {
  text-decoration: none;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.9rem;
  border: 0;
  background: none;
  color: var(--dim);
  font: 600 0.66rem/1 var(--text);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    opacity 0.45s var(--ease),
    transform 0.45s var(--ease),
    color 0.2s var(--ease);
}
.cue:hover {
  color: var(--ink-soft);
}
.cue:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 3px;
  border-radius: 8px;
}
.cue-rail {
  position: relative;
  display: block;
  width: 1px;
  height: 2rem;
  background: linear-gradient(180deg, var(--edge), transparent);
}
/* The chevron at the foot of the rail — the "down" in one glyph. */
.cue-rail::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -2px;
  width: 7px;
  height: 7px;
  margin-left: -3.5px;
  border-right: 1.5px solid var(--gold-deep);
  border-bottom: 1.5px solid var(--gold-deep);
  transform: rotate(45deg);
  opacity: 0.7;
}
.cue:hover .cue-rail::after {
  opacity: 1;
}
.cue-dot {
  position: absolute;
  left: 50%;
  top: 0;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--gold);
  animation: cue-fall 2s var(--ease-io) infinite;
}
@keyframes cue-fall {
  0% {
    transform: translateY(0);
    opacity: 0;
  }
  22% {
    opacity: 1;
  }
  78% {
    opacity: 1;
  }
  100% {
    transform: translateY(1.85rem);
    opacity: 0;
  }
}

/* THE CHOREOGRAPHED EXIT. The first downward scroll while the film plays is
   intercepted, and this is what it buys: the slab recedes and softens as the
   page is carried to the next stage, so the move reads as one action instead
   of a drag. main.js adds and removes `.is-departing`; it releases itself
   after 900ms whatever happens, so a failure here can never strand anyone. */
.stage-hero.is-departing .slab {
  animation: none;
  transform: translateY(-2.5vh) scale(0.945);
  opacity: 0.32;
  filter: blur(3px);
}
.stage-hero.is-departing .wordmark,
.stage-hero.is-departing .cues {
  opacity: 0;
  transform: translateY(-0.75rem);
}

/* ── the persistent bar ──────────────────────────────────────────────────── */
.topbar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: var(--bar-h);
  padding-inline: var(--gutter);
  background: var(--veil);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border-bottom: 1px solid var(--edge-soft);
  transform: translateY(-101%);
  transition: transform 0.42s var(--ease);
}
.topbar.is-shown {
  transform: none;
}
.topbar-mark {
  font-family: var(--display);
  font-size: 1rem;
  letter-spacing: 0.02em;
  color: var(--ink);
  text-decoration: none;
}

/* ── the action ──────────────────────────────────────────────────────────── */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-width: min(22rem, 100%);
  /* 1.05rem of block padding measures 59px — clears 44px at every clamp step. */
  padding: 1.05rem 2rem;
  border-radius: 999px;
  background: var(--ink);
  color: #f8f4e9;
  font: 600 1rem/1 var(--text);
  letter-spacing: 0.005em;
  text-decoration: none;
  box-shadow:
    inset 0 0 0 1px var(--gold-hair),
    0 0.7rem 1.6rem -0.6rem #3d2f0f59;
  transition:
    transform 0.2s var(--ease),
    background-color 0.2s var(--ease),
    box-shadow 0.2s var(--ease);
}
.cta-arrow {
  flex: none;
  color: var(--gold);
  transition: transform 0.2s var(--ease);
}
.cta:hover {
  background: var(--ink-lit);
  transform: translateY(-1px);
  box-shadow:
    inset 0 0 0 1px var(--gold),
    0 0.85rem 1.9rem -0.6rem #3d2f0f6b;
}
.cta:hover .cta-arrow {
  transform: translateX(3px);
}
.cta:active {
  transform: translateY(0);
}
.cta:focus-visible {
  outline: 3px solid var(--gold-deep);
  outline-offset: 3px;
}
/* The bar's copy of the action. Smaller, but still a 44px target. */
.cta-sm {
  min-width: 0;
  padding: 0.7rem 1.1rem;
  font-size: 0.85rem;
  box-shadow: inset 0 0 0 1px var(--gold-hair);
}

.reassure {
  margin: 0.85rem 0 0;
  font-size: 0.82rem;
  letter-spacing: 0.01em;
  color: var(--dim);
}

/* ── type ────────────────────────────────────────────────────────────────── */
.eyebrow {
  margin: 0 0 0.75rem;
  font-family: var(--text);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.eyebrow::after {
  content: "";
  display: block;
  width: 2.25rem;
  height: 1px;
  margin: 0.6rem auto 0;
  background: var(--gold);
}

.headline,
.band-title,
.section-head,
.close-line {
  font-family: var(--display);
  font-weight: 500;
  letter-spacing: -0.014em;
  color: var(--ink);
  text-wrap: balance;
}

.headline {
  margin: 0 0 0.75rem;
  font-size: clamp(2rem, 1.2rem + 3.6vw, 3.6rem);
  line-height: 1.1;
}

.sub {
  margin: 0 auto;
  max-width: var(--measure);
  color: var(--ink-soft);
  text-wrap: pretty;
}

.band-title {
  margin-block: 0 clamp(1.6rem, 5vw, 2.5rem);
  margin-inline: auto;
  max-width: 32rem;
  font-size: clamp(1.45rem, 1.1rem + 1.5vw, 2.1rem);
  line-height: 1.2;
  text-align: center;
}

.section-head {
  margin: 0 0 0.75rem;
  font-size: clamp(1.45rem, 1.1rem + 1.5vw, 2.1rem);
  line-height: 1.2;
}

.prose {
  margin: 0;
  max-width: var(--measure);
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* Stages 1, 2, 5 and 6 are centred compositions. */
.stage[data-stage="1"] .mid,
.stage-close .mid {
  text-align: center;
}

/* ── the enquiry placeholder ─────────────────────────────────────────────────
   INERT, and INVISIBLE UNTIL ASKED FOR. It does nothing at all: no form
   element, no request, no storage. It is not on the page at rest — a standing
   block explaining that the enquiry route is not built yet is a note to
   ourselves on a page other people look at, and it reads as unfinished. As the
   ANSWER to a button press it reads as deliberate. */
/* ── the enquiry dialog ──────────────────────────────────────────────────
   Top layer, so nothing here can affect the height of the stage the button
   sits in. The four stages are exactly one viewport each and a panel opening
   inside one would push it past that. */
.enquiry {
  width: min(30rem, calc(100vw - 2 * var(--gutter)));
  max-height: calc(100dvh - 2rem);
  padding: clamp(1.4rem, 5vw, 2rem);
  border: 0;
  border-radius: var(--round-slab);
  background: var(--paper-lit);
  box-shadow:
    inset 0 0 0 1px var(--edge-soft),
    0 24px 60px #4a380f2e;
  color: var(--ink);
  overflow: auto;
  overscroll-behavior: contain;
}
.enquiry::backdrop {
  background: #221e1785;
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
/* NO-JS FALLBACK. Without script the dialog never opens, so the anchor on the
   call to action — href="#enquire" — brings it up as an ordinary block
   instead. `:modal` is what tells the two cases apart: it matches only a
   dialog opened by showModal(), so the normal path keeps the real dialog
   behaviour and this rule applies to nothing. */
.enquiry:target:not(:modal) {
  display: block;
  margin: var(--gutter) auto;
}

.enquiry-form,
.enquiry-done {
  display: grid;
  gap: 0.85rem;
}
.enquiry-done[hidden],
.enquiry-form[hidden] {
  display: none;
}
.enquiry-done {
  justify-items: center;
  text-align: center;
  gap: 0.6rem;
}
.enquiry-title {
  margin: 0;
  font: 400 clamp(1.3rem, 3.4vw, 1.7rem) / 1.2 var(--display);
  letter-spacing: -0.01em;
}
.enquiry-title:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 4px;
  border-radius: 4px;
}
.enquiry-sub {
  margin: 0 0 0.3rem;
  font-size: 0.93rem;
  line-height: 1.5;
  color: var(--ink-soft);
}
.enquiry-sub:empty {
  display: none;
}

.field {
  display: grid;
  gap: 0.3rem;
}
.field-label {
  font: 600 0.78rem/1.2 var(--text);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.field-opt {
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--dim);
}
.field-input {
  width: 100%;
  /* 16px or larger, or iOS Safari zooms the whole page on focus. */
  min-height: 44px;
  padding: 0.55rem 0.7rem;
  border: 0;
  border-radius: 9px;
  background: var(--paper);
  box-shadow: inset 0 0 0 1px var(--edge);
  font: 400 1rem/1.4 var(--text);
  color: var(--ink);
}
.field-input:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}
.field-input[aria-invalid="true"] {
  box-shadow: inset 0 0 0 2px #a3341f;
}
.field-err,
.enquiry-err {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: #8c2c1a; /* 5.6:1 on the cream */
}
.field-err[hidden],
.enquiry-err[hidden] {
  display: none;
}

/* The honeypot. Off-canvas rather than `display: none`, because the simplest
   bots skip what is display:none and fill what they can see in the markup. */
.field-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* `.cta-sm` trims the call to action down for the top bar, where it sits
   beside text rather than under a finger. In the dialog it is the primary
   target on a phone, so the 44px floor every other control here meets is put
   back — measured at 36px before this. */
.enquiry-actions .cta-sm {
  min-height: 44px;
  min-width: 0;
}
.enquiry-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  justify-content: flex-end;
  margin-top: 0.3rem;
}
.btn-quiet {
  min-height: 44px;
  padding: 0 1rem;
  border: 0;
  border-radius: 999px;
  background: none;
  box-shadow: inset 0 0 0 1px var(--edge);
  font: 500 0.92rem/1 var(--text);
  color: var(--ink-soft);
  cursor: pointer;
}
.btn-quiet:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
@media (hover: hover) and (pointer: fine) {
  .btn-quiet:hover {
    background: var(--paper-sunk);
  }
}
/* `.cta` was written for an <a>. On a <button> the UA supplies a border, its
   own font and a default cursor, so those three are answered here rather than
   by loosening the shared rule. */
button.cta {
  border: 0;
  cursor: pointer;
  font-family: var(--text);
}
.cta-sm[aria-busy="true"] {
  opacity: 0.7;
  pointer-events: none;
}

.demo {
  display: grid;
  gap: 0.4rem;
  justify-items: center;
  max-width: 30rem;
  margin-inline: auto;
  margin-top: clamp(1.2rem, 4vw, 1.8rem);
  padding: clamp(0.85rem, 3.5vw, 1.15rem) clamp(1.1rem, 5vw, 1.6rem);
  border-radius: var(--round);
  background: color-mix(in oklab, var(--paper-lit) 72%, transparent);
  box-shadow: inset 0 0 0 1px var(--edge-soft);
  text-align: center;
}
/* `[hidden]` is the whole mechanism — there is no state to keep, nothing to
   undo, and nothing remembered between visits. It needs the explicit rule
   because `display: grid` above would otherwise beat the UA default. */
.demo[hidden] {
  display: none;
}

.demo-tag {
  margin: 0;
  font: 700 0.62rem/1 var(--text);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.demo-line {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* A merged stage holds two blocks that used to own a viewport each. This is
   the only thing keeping them apart. */
.mid-stack {
  display: grid;
  gap: clamp(1.9rem, 5.5vh, 3.25rem);
}

/* ── the specification band ──────────────────────────────────────────────── */
.spec-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(0.7rem, 2.5vw, 1rem);
  /* Explicit steps, not `auto-fit, minmax(13rem, 1fr)`. Auto-fit fitted THREE
     columns at 768px and orphaned the fourth card — measured. Four facts want
     1, 2 or 4 across; three-and-one is the one arrangement that looks like a
     mistake. */
  grid-template-columns: minmax(0, 1fr);
  text-align: left;
}

.spec {
  padding: clamp(1.1rem, 4vw, 1.5rem);
  border-radius: var(--round);
  background: var(--paper-lit);
  box-shadow:
    0 0 0 1px var(--edge),
    0 0.5rem 1.4rem -0.9rem #4a380f26;
}

.spec-figure {
  margin: 0 0 0.5rem;
  font-family: var(--display);
  font-size: clamp(1.45rem, 1.25rem + 1vw, 1.9rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--gold-deep);
  font-variant-numeric: tabular-nums;
}

/* The card heading is an <h2> now that the stage's <h1> is the claim above it
   — heading LEVEL is document structure and has nothing to do with size. The
   selector has to follow the markup or the element falls back to the UA
   stylesheet, which is what happened: 1rem became 1.5rem bold and every card
   grew a second line. */
.spec h2,
.spec h3 {
  margin: 0 0 0.4rem;
  font: 650 1rem/1.3 var(--text);
  letter-spacing: -0.005em;
  color: var(--ink);
}

.spec-sub {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--dim);
  text-wrap: pretty;
}

/* ── the split stage ─────────────────────────────────────────────────────── */
.split {
  display: grid;
  gap: clamp(1.5rem, 5vw, 3rem);
  align-items: center;
}
.split-copy .eyebrow::after {
  margin-inline: 0;
}

/* ── the three steps ─────────────────────────────────────────────────────── */
.step-list {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  display: grid;
  gap: clamp(1.5rem, 5vw, 2.25rem);
  max-width: var(--measure);
  text-align: left;
}

.step {
  padding-left: 1.4rem;
  border-left: 2px solid var(--gold-hair);
}

.step-n {
  margin: 0 0 0.35rem;
  font: 600 0.7rem/1 var(--text);
  letter-spacing: 0.22em;
  color: var(--gold-deep);
  font-variant-numeric: tabular-nums;
}

.step h3 {
  margin: 0 0 0.45rem;
  font-family: var(--display);
  font-size: clamp(1.2rem, 1rem + 0.9vw, 1.5rem);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
}

.step p {
  margin: 0;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* ── image + content placeholders ────────────────────────────────────────────
   Deliberately VISIBLE. The operator asked for slots that name the shot he has
   to generate, so these are legible at a glance and obviously not final. They
   are swapped for an <img> and deleted; nothing else should inherit them. */
/* ── the photographs ─────────────────────────────────────────────────────────
   Three operator-supplied frames, re-encoded and resized and otherwise
   untouched. Every one is BOUNDED IN HEIGHT, which is the whole trick: a
   photograph sized only by its own width grows the stage it sits in, and this
   page's contract is that a stage is one viewport.

   THE HEIGHT IS ON THE FIGURE, NOT ON THE IMAGE, and that is not a style
   preference. `max-height` on a replaced element does not crop it — it
   re-derives the WIDTH from the intrinsic ratio and shrinks the whole box, so
   a 768px band came back 313px wide, centred in a field of cream, with
   `object-fit: cover` never getting a chance to fire. `min-width: 100%` does
   not rescue it either; the constraint table resolves the pair the other way.
   A figure with a DEFINITE height and an `inset: 0` image is the shape where
   `cover` actually crops.

   The `width`/`height` attributes in the markup still matter: they reserve the
   aspect box before the bytes arrive, so a stage does not jump as it decodes. */
.shot {
  /* `margin: 0` because <figure> carries `1em 40px` from the UA stylesheet,
     which quietly ate 80px off the product column. */
  margin: 0;
  position: relative;
  overflow: hidden;
  border-radius: var(--round);
  /* The same hairline the spec cards carry, so a photograph sits IN the page
     rather than on top of it, and a shadow soft enough to lift it off cream. */
  box-shadow:
    0 0 0 1px var(--edge),
    0 22px 38px -28px color-mix(in oklab, var(--ink) 58%, transparent);
}

.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.shot-tall {
  height: min(40svh, 20rem, 52vw);
}
/* `width: 100%` IS REQUIRED beside `margin-inline: auto`. An auto inline
   margin cancels a grid or flex item's stretch, so the figure falls back to
   shrink-to-fit — and a shrink-to-fit box around an image with an intrinsic
   ratio and a definite height sizes itself from the RATIO. Both of these came
   back at 16:9 of their own height, 356px and 512px wide, centred in cream. */
.shot-wide {
  width: 100%;
  height: min(30svh, 16rem, 34vw);
}
/* A strip, deliberately. It takes the slack stage 1 already carried at desktop
   and stays modest on a phone, where that stage is the tightest on the deck.

   THE `vw` TERM IS THE PHONE TERM. Without it a 20rem box on a 393px screen is
   very nearly square, and the two stages that were already taller than a phone
   viewport — 936px and 947px before any image landed — grew by another 230px.
   Capping against the WIDTH keeps every crop at roughly the ratio it has on a
   desktop instead of turning into a portrait. */
.shot-band {
  width: 100%;
  height: min(23svh, 11.5rem, 26vw);
  max-width: 48rem;
  margin-inline: auto;
}

/* The reveal stagger, for the same reason. Enumerated rather than inline so a
   list that grows keeps cascading without touching the markup. */
.spec-grid > *:nth-child(1),
.step-list > *:nth-child(1) {
  --i: 1;
}
.spec-grid > *:nth-child(2),
.step-list > *:nth-child(2) {
  --i: 2;
}
.spec-grid > *:nth-child(3),
.step-list > *:nth-child(3) {
  --i: 3;
}
.spec-grid > *:nth-child(4),
.step-list > *:nth-child(4) {
  --i: 4;
}
.spec-grid > *:nth-child(5),
.step-list > *:nth-child(5) {
  --i: 5;
}
.spec-grid > *:nth-child(6),
.step-list > *:nth-child(6) {
  --i: 6;
}

/* ── the close ───────────────────────────────────────────────────────────── */
.close-line {
  margin: 0 auto 1.9rem;
  max-width: var(--measure);
  font-size: clamp(1.7rem, 1.15rem + 2.4vw, 2.8rem);
  line-height: 1.14;
  letter-spacing: -0.016em;
}

/* ── the footer ──────────────────────────────────────────────────────────── */
.foot {
  padding: clamp(2rem, 7vh, 3rem) var(--gutter)
    calc(clamp(2.5rem, 9vh, 3.5rem) + var(--safe-b));
  border-top: 1px solid var(--edge-soft);
  background: var(--paper-sunk);
  text-align: center;
  scroll-snap-align: start;
}
.foot-mark {
  margin: 0 0 0.4rem;
  font-family: var(--display);
  font-size: 1.15rem;
  letter-spacing: 0.02em;
  color: var(--ink);
}
.foot-line {
  margin: 0;
  font-size: 0.84rem;
  color: var(--dim);
}

/* ── the stage rail ──────────────────────────────────────────────────────────
   Desktop only: on a phone it lands exactly where the thumb rests. Real
   buttons with real labels, built by main.js from the stages present. */
.rail {
  display: none;
}

@media (min-width: 62rem) and (pointer: fine) {
  .rail {
    position: fixed;
    top: 50%;
    right: clamp(0.9rem, 1.6vw, 1.6rem);
    z-index: 15;
    display: grid;
    gap: 0.7rem;
    transform: translateY(-50%);
    opacity: 0;
    visibility: hidden;
    transition:
      opacity 0.4s var(--ease),
      visibility 0.4s;
  }
  .rail.is-shown {
    opacity: 1;
    visibility: visible;
  }
  .rail-dot {
    width: 24px;
    height: 24px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }
  .rail-dot::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: color-mix(in oklab, var(--ink) 22%, transparent);
    transition:
      background-color 0.3s var(--ease),
      transform 0.3s var(--ease);
  }
  .rail-dot:hover::before {
    background: color-mix(in oklab, var(--ink) 45%, transparent);
  }
  .rail-dot[aria-current="true"]::before {
    background: var(--gold-deep);
    transform: scale(1.5);
  }
  .rail-dot:focus-visible {
    outline: 2px solid var(--gold-deep);
    outline-offset: 1px;
    border-radius: 50%;
  }
}

/* ── widen ───────────────────────────────────────────────────────────────── */
@media (min-width: 34rem) {
  .spec-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 48rem) {
  /* THE SLAB MUST FIT THE VIEWPORT, HEIGHT FIRST. A 16:9 object sized only by
     width overflows a short laptop window: at 1440x900 an unconstrained slab
     is 1354px wide and therefore 762px tall, and the caption and cue fall off
     the bottom. The third term caps the WIDTH by the height available, so the
     composition stays inside the viewport at any aspect ratio. */
  .slab {
    max-width: min(94vw, 76rem, calc((78svh - 5rem) * 16 / 9));
  }

  .split {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    text-align: left;
  }

  .step-list {
    max-width: 40rem;
  }

  .shot-wide {
    max-width: 48rem;
    margin-inline: auto;
  }
}

@media (min-width: 64rem) {
  .spec-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ── respect the visitor's settings ──────────────────────────────────────────
   `is-plain` on <html> (set by main.js) already turns off snap, reveals,
   autoplay and the choreographed exit. This is the belt to that braces: any
   animation that slipped through stops here. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
    scroll-snap-type: none;
  }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  [data-rise] {
    opacity: 1;
    transform: none;
  }
}

/* A visitor who has asked for a dark UI is NOT asking for a different brand.
   The cream direction is the design; forcing a dark repaint would invert the
   art direction the operator chose. What `prefers-color-scheme: dark` gets is
   the same page with its contrast nudged, and nothing else. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #f2ece0;
    --paper-sunk: #e9e0cc;
    --ink: #1c1913;
  }
}
