/* reh·cord — the livelier site's stylesheet.
 *
 * The tokens are site/style.css's, which are `Shared/NoNotesTokens.swift`
 * translated one to one; the dark values are the same derived palette, with
 * the same reasoning (see the comment block in site/style.css). If a value
 * here disagrees with the Swift file, the Swift file is right.
 *
 * Motion is held to one rule: it behaves like paper, ink and light. No
 * gradients as decoration, no glow, no glass. Every animation has a still end
 * state, and under prefers-reduced-motion that end state is all there is.
 *
 * There are no screenshots. Every picture of the app — the transcript page,
 * the waveform above it, the record screen, the covers, a notebook's row — is
 * drawn here from the same tokens as the page, so it is sharp at any size and
 * follows the page into dark mode.
 */

/* ------------------------------------------------------------------------ */
/* Tokens                                                                    */
/* ------------------------------------------------------------------------ */

:root {
  color-scheme: light dark;

  --paper: #FBF7F2;
  --card: #FFFCF8;
  --sunken: #F4EFE8;
  --rule: #E9E0D5;
  --ink: #2B2620;
  --inkSecondary: #6F675C;
  --inkTertiary: #A79E8F;

  --accent: #C9463A;
  --accentDeep: #9E372C;
  --accentWash: #F7E6E1;
  --liveDot: #D94A3D;

  --musicInk: #3E5E77;
  --musicWash: #D7E3EE;

  --sheetPaper: #FFFDFA;
  --paperRule: #C9D6E4;
  --paperMargin: #E0A29B;

  --wavePlayed: #54483C;
  --waveIdle: #CFC3AF;

  --hairline: rgba(43, 38, 32, 0.18);
  --hairlineLight: rgba(43, 38, 32, 0.09);
  --coverShadow: rgba(43, 38, 32, 0.12);
  --grainOpacity: 0.4;

  /* A board is a physical object: its label, its fore-edge and the ink
     printed on it are the same in both schemes. */
  --plate: #FFFDFA;
  --plateInk: #2B2620;
  --plateInkSecondary: #6F675C;
  --boardInk: rgba(43, 38, 32, 0.15);
  --boardSpine: rgba(43, 38, 32, 0.13);
  --coverLight: none;

  /* Paper objects: the app's own surfaces, laid on the page — the recording's
     card (DSCard) and the sheet of writing paper the iCloud panel is written
     on. The app is light-only, so like the boards these keep their light
     values in both schemes and are only seen under the dark page's lower
     light (--coverLight). NNPalette.card, .sheetPaper, .rule, .paperMargin,
     .ink, .inkSecondary, and DS.cardShadow. */
  --objCard: #FFFCF8;
  --objSheet: #FFFDFA;
  --objRule: #E9E0D5;
  --objMargin: #E0A29B;
  --objInk: #2B2620;
  --objInkSecondary: #6F675C;
  --objEdge: rgba(43, 38, 32, 0.18);
  --objShadow: rgba(107, 91, 74, 0.10);
  --radius-card: 18px;

  --space-xxs: 4px;
  --space-xs: 8px;
  --space-s: 12px;
  --space-m: 16px;
  --space-l: 20px;
  --space-xl: 28px;
  --space-xxl: 40px;
  --gutter: 20px;
  --radius-object: 3px;

  --serif: ui-serif, "New York", Georgia, serif;
  --sans: system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;

  --type-reading: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  --type-heading: clamp(1.1875rem, 1.1rem + 0.35vw, 1.3125rem);
  --type-title: clamp(1.875rem, 1.35rem + 2.2vw, 3rem);
  --type-subtitle: clamp(1.25rem, 1.1rem + 0.8vw, 1.625rem);
  --type-footnote: 0.9375rem;
  --type-label: 0.75rem;
  --type-display: clamp(3.75rem, 2rem + 8vw, 7.5rem);

  --measure: 34rem;
  --wrap: 72rem;

  /* The transcript page's own metrics (PaperMetrics): a 17-point body, a rule
     every 1.7 bodies, the margin rule at 34 and the writing at 48. The pitch
     is an absolute length, so every line on the page — heading, summary,
     sentence, tag — is exactly one rule tall whatever its type size. */
  --paper-size: clamp(1.0625rem, 1rem + 0.2vw, 1.125rem);
  --pp: calc(var(--paper-size) * 1.7);
  --paper-margin-x: 34px;
  --paper-text-x: 48px;

  /* One easing for everything that settles: quick out, long soft landing. */
  --settle: cubic-bezier(0.2, 0.7, 0.2, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #2B2723;
    --card: #332E29;
    --sunken: #262220;
    --rule: #463F36;
    --ink: #EDE7DB;
    --inkSecondary: #B5AB9C;
    --inkTertiary: #837A6C;

    --accent: #D94A3D;
    --accentDeep: #E47E6B;
    --accentWash: #452C27;
    --liveDot: #D94A3D;

    --musicInk: #87A3BA;
    --musicWash: #2B3641;

    --sheetPaper: #221F1B;
    --paperRule: #2F3338;
    --paperMargin: #6A3F3A;

    --wavePlayed: #CFC3AF;
    --waveIdle: #5A5245;

    --hairline: rgba(237, 231, 219, 0.18);
    --hairlineLight: rgba(237, 231, 219, 0.09);
    --coverShadow: rgba(0, 0, 0, 0.45);
    --grainOpacity: 0.22;

    /* The boards keep their colours — they are objects, not chrome — but are
       seen under a lower light, as site/ sees them, so they are not the
       brightest thing on a dark page. */
    --coverLight: brightness(0.86);
    --objShadow: rgba(0, 0, 0, 0.45);
  }

  /* The transcript paper is the app's paper, whatever the page is doing —
     the owner's call (2026-09-28): the sheet had gone dark with the page,
     and he wanted the app's own colour back. So the paper re-pins the light
     values for itself and everything written on it, and stands under the
     same lowered light as the covers and the card. */
  .paper {
    --sheetPaper: #FFFDFA;
    --paperRule: #C9D6E4;
    --paperMargin: #E0A29B;
    --ink: #2B2620;
    --inkSecondary: #6F675C;
    --inkTertiary: #A79E8F;
    --accent: #C9463A;
    --accentDeep: #9E372C;
    --musicInk: #3E5E77;
    --hairline: rgba(43, 38, 32, 0.18);
    filter: var(--coverLight);
  }
}

/* ------------------------------------------------------------------------ */
/* The page                                                                  */
/* ------------------------------------------------------------------------ */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--type-reading);
  line-height: 1.55;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

body::after {
  content: "";
  position: fixed;
  inset: 0;
  background-image: url("paper-grain.png");
  background-size: 96px 96px;
  mix-blend-mode: overlay;
  opacity: var(--grainOpacity);
  pointer-events: none;
  z-index: -2;
}

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.wrap {
  max-width: calc(var(--wrap) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
}

p { margin: 0 0 1em; }
figure { margin: 0; }


.label {
  font-family: var(--sans);
  font-size: var(--type-label);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--inkSecondary);
}

.dot { color: var(--accent); }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

a {
  color: var(--accentDeep);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-object);
}

/* What is shown depends on what the page can do. Without scripting, and
   under reduced motion, the demonstration is a still: the still's caption
   shows and the scrolling invitation does not. */
.only-js,
.only-motion { display: none; }
.js .only-js { display: block; }

@media (prefers-reduced-motion: no-preference) {
  .js .only-motion { display: block; }
  .js .only-still { display: none; }
}

/* The live dot: the record screen's own breath, 0.35 → 1 → 0.35 every 1.7 s. */
.live-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

@media (prefers-reduced-motion: no-preference) {
  .live-dot { animation: breathe 1.7s ease-in-out infinite; }
}

@keyframes breathe {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

/* ------------------------------------------------------------------------ */
/* Running head                                                              */
/* ------------------------------------------------------------------------ */

.top {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-m);
  padding-top: var(--space-l);
  padding-bottom: var(--space-s);
}

.top-name {
  font-weight: 600;
  font-size: 1.0625rem;
}

.top-state {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}

/* The rule under the running head is drawn in, once, on load. */
.top::before {
  content: "";
  position: absolute;
  left: max(var(--gutter), env(safe-area-inset-left));
  right: max(var(--gutter), env(safe-area-inset-right));
  bottom: 0;
  height: 1px;
  background: var(--hairline);
  transform-origin: left center;
}

@media (prefers-reduced-motion: no-preference) {
  .top::before { animation: rule-in 1.1s var(--settle) 0.1s both; }
}

@keyframes rule-in {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* ------------------------------------------------------------------------ */
/* 1. Hero                                                                   */
/* ------------------------------------------------------------------------ */

.hero {
  padding-top: clamp(var(--space-xl), 6vw, 5rem);
}

.wordmark {
  margin: 0;
  font-size: var(--type-display);
  font-weight: 600;
  line-height: 0.95;
  letter-spacing: -0.02em;
}

.tagline {
  margin: var(--space-s) 0 0;
  font-size: var(--type-subtitle);
  line-height: 1.3;
  color: var(--inkSecondary);
}

.lede {
  margin: var(--space-l) 0 0;
  max-width: var(--measure);
}

/* The page settles: once, on load, a few pixels and no more. */
@media (prefers-reduced-motion: no-preference) {
  .hero > * { animation: settle 0.9s var(--settle) both; }
  .hero > :nth-child(2) { animation-delay: 0.08s; }
  .hero > :nth-child(3) { animation-delay: 0.16s; }
  /* The demonstration only fades: a transform here would sit over the
     waveform's sticky band. */
  .demo { animation: arrive 1.1s var(--settle) 0.3s both; }
}

@keyframes settle {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

@keyframes arrive {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ------------------------------------------------------------------------ */
/* 1. The demonstration: a lesson on the page                                */
/* ------------------------------------------------------------------------ */

.demo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-l);
  padding-top: clamp(var(--space-xxl), 7vw, 5rem);
}

.demo-aside h2 { margin-bottom: var(--space-s); }

.demo-hint {
  margin: 0;
  font-size: var(--type-footnote);
  line-height: 1.45;
  color: var(--inkSecondary);
}

/* On a phone the sheet runs to the edges of the screen, as the app's own
   page does; from a small tablet up it is a sheet lying on the page. */
.lesson { margin-inline: calc(-1 * var(--gutter)); }

@media (min-width: 40rem) {
  .lesson { margin-inline: 0; }
}

@media (min-width: 60rem) {
  .demo {
    grid-template-columns: minmax(0, 16rem) minmax(0, 38rem);
    gap: clamp(3rem, 6vw, 6rem);
    align-items: start;
  }
  .demo-aside { position: sticky; top: 7rem; }
}

/* The top of a recording. It stays at the top of the screen while its page
   scrolls under it, as it does in the app, and goes when the page does. */
.lesson-band {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: 10px var(--gutter) 12px;
  background: var(--paper);
  border-bottom: 1px solid var(--hairlineLight);
}

@media (min-width: 40rem) {
  .lesson-band { padding-inline: 0; }
}

.band-status {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-s);
  margin: 0 0 8px;
  font-family: var(--sans);
  font-size: 0.75rem;
  line-height: 1.35;
  color: var(--inkTertiary);
  font-variant-numeric: tabular-nums;
}

.band-where { display: inline-flex; align-items: center; gap: 6px; }

.band-note {
  display: none;
  width: 0.7rem;
  height: 0.9rem;
  fill: var(--musicInk);
}

.lesson-band.is-playing .band-note { display: block; }

/* The whole recording in miniature (MiniOverviewWaveform). */
.ov {
  position: relative;
  height: 40px;
  overflow: hidden;
}

.ov-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.wash-speech { fill: var(--accentWash); }
.wash-music { fill: var(--musicWash); }

.ov-mid {
  stroke: var(--rule);
  stroke-width: 0.75;
  vector-effect: non-scaling-stroke;
}

.ov-bars {
  fill: none;
  stroke: var(--wavePlayed);
  stroke-width: 1.5;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* Everything right of the playhead is unplayed, and the app draws it paler.
   Here the paper itself lies over it, and moves with the playhead. */
.ov-veil,
.ov-track {
  position: absolute;
  inset: 0;
  transform: translateX(calc(var(--at, 0) * 100%));
  pointer-events: none;
}

.ov-veil {
  background: var(--paper);
  opacity: 0.62;
}

.ov-head {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -1px;
  width: 2px;
  border-radius: 1px;
  background: var(--accentDeep);
}

/* A marker hangs off the top edge: the Marker button's bookmark on a short
   stem, twelve points in all. */
.ov-mark {
  position: absolute;
  top: 0;
  width: 0;
  height: 12px;
}

.ov-mark svg {
  position: absolute;
  top: 0;
  left: -3.5px;
  width: 7px;
  height: 8px;
  fill: var(--accentDeep);
}

.ov-mark::after {
  content: "";
  position: absolute;
  top: 8px;
  left: -0.75px;
  width: 1.5px;
  height: 4px;
  background: var(--accentDeep);
  opacity: 0.9;
}

/* ------------------------------------------------------------------------ */
/* The page (TranscriptPaper)                                                */
/* ------------------------------------------------------------------------ */

.paper {
  --ruleInk: var(--paperRule);
  --lineInk: var(--ink);
  position: relative;
  padding: var(--pp) var(--space-l) calc(2 * var(--pp)) var(--paper-text-x);
  font-size: var(--paper-size);
  line-height: var(--pp);
  background-color: var(--sheetPaper);
  /* A rule under every line, lifted to sit just below the writing. */
  background-image: repeating-linear-gradient(to bottom, transparent 0 calc(var(--pp) - 1px), var(--ruleInk) calc(var(--pp) - 1px) var(--pp));
  background-position: 0 calc(var(--pp) * -0.2);
  box-shadow: 0 0 0 0.5px var(--hairline), 0 1px 2px var(--coverShadow);
}

@supports (color: color-mix(in srgb, red, blue)) {
  .paper {
    --ruleInk: color-mix(in srgb, var(--paperRule) 70%, transparent);
    /* Every line but the one being followed is ink stepped back a little,
       so the page has a focus at all. */
    --lineInk: color-mix(in srgb, var(--ink) 80%, transparent);
  }
}

@media (min-width: 40rem) {
  .paper { border-radius: 0 0 var(--radius-object) var(--radius-object); }
}

/* The margin rule. */
.paper::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--paper-margin-x);
  width: 1px;
  background: var(--paperMargin);
}

.paper p { margin: 0; }

/* The section's name, in the serif's small capitals, quiet. */
.ln-head,
.ln-tag {
  font-size: 0.64em;
  font-weight: 600;
  letter-spacing: 0.07em;
}

.ln-head {
  text-transform: uppercase;
  color: var(--inkTertiary);
}

/* The section's summary: a note about the page, smaller and grey. */
.ln-summary {
  font-size: 0.8em;
  color: var(--inkSecondary);
}

.ln { color: var(--lineInk); }

/* The sentence being said now is written in the red; the one the page is
   merely parked on (in a pause, or while the playing goes on) is plain ink. */
.ln.is-live { color: var(--accentDeep); }
.ln.is-parked { color: var(--ink); }

/* The still: one line, marked in the markup, for when nothing follows. */
html:not(.js) .ln.is-preset { color: var(--accentDeep); }
@media (prefers-reduced-motion: reduce) {
  .ln.is-preset { color: var(--accentDeep); }
}

/* The word being said: the same ink, emboldened by two copies a hair apart —
   SpokenLine's own trick, so no word ever reflows. */
.w.is-word { text-shadow: -0.35px 0 currentColor, 0.35px 0 currentColor; }

/* A stretch of playing: a note and one word, where the words stop. */
.ln-music {
  font-family: var(--sans);
  font-size: 0.72em;
  letter-spacing: 0.02em;
}

.ln-music,
.ln-music.is-parked { color: var(--inkTertiary); }
.ln-music.is-playing { color: var(--musicInk); }

.ln-note {
  display: inline-block;
  width: 0.8em;
  height: 1.05em;
  margin-right: 0.45em;
  vertical-align: -0.2em;
  fill: var(--musicInk);
}

/* A spoken marker's tag: the bookmark in the red, MARKER in the heading's
   capitals, and what followed it in quotation marks. */
.ln-tag .tag-name { text-transform: uppercase; color: var(--inkTertiary); }
.ln-tag .tag-label { color: var(--inkSecondary); letter-spacing: 0.04em; }
.ln-tag.is-live .tag-name,
.ln-tag.is-live .tag-label { color: var(--ink); }

.ln-bookmark {
  display: inline-block;
  width: 0.95em;
  height: 1.1em;
  margin-right: 5px;
  vertical-align: -0.2em;
  fill: var(--accentDeep);
  transform-origin: 50% 0;
}

/* With scripting, each line is a button: tap it and the page goes there.
   Nothing about it changes the line's box, so the rules stay where they are. */
.ln-btn {
  all: unset;
  display: block;
  margin-inline: -6px;
  padding-inline: 6px;
  border-radius: 6px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.ln-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

@media (hover: hover) {
  .ln-btn:hover { background: var(--hairlineLight); }
}

/* ------------------------------------------------------------------------ */
/* Sections                                                                  */
/* ------------------------------------------------------------------------ */

.block {
  padding-top: clamp(4.5rem, 10vw, 8rem);
}

.intro { max-width: 40rem; }

.eyebrow {
  margin: 0 0 var(--space-s);
  color: var(--accentDeep);
}

h2 {
  margin: 0 0 var(--space-l);
  font-size: var(--type-title);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

/* One word leaning, as the setup flow's display headings lean one. */
h2 em { font-style: italic; font-weight: 600; }

.intro p:not(.eyebrow) {
  color: var(--inkSecondary);
  max-width: var(--measure);
}

/* Scroll-triggered reveals. Only with scripting, only with motion allowed:
   without either, everything is simply there. */
@media (prefers-reduced-motion: no-preference) {
  .js [data-reveal] {
    transition: opacity 0.9s var(--settle), transform 0.9s var(--settle);
  }
  .js [data-reveal]:not(.in) {
    opacity: 0;
    transform: translateY(16px);
  }
}

/* ------------------------------------------------------------------------ */
/* 2. Markers: during, and afterwards                                        */
/* ------------------------------------------------------------------------ */

.marking {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xxl);
  margin-top: var(--space-xl);
}

@media (min-width: 56rem) {
  .marking {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(3rem, 6vw, 6rem);
    align-items: center;
  }
}

.step {
  margin: 0;
  font-size: var(--type-footnote);
  line-height: 1.45;
  color: var(--inkSecondary);
  text-align: center;
}

.rec {
  display: grid;
  justify-items: center;
  padding: var(--space-l) 0 0;
}

.rec-head {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}

.rec-head .label {
  color: var(--accentDeep);
  letter-spacing: 0.14em;
}

.rec-clock {
  margin: var(--space-xs) 0 var(--space-l);
  font-size: clamp(2.75rem, 2rem + 3vw, 4rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* Written between two rules, like the record screen's band. The drawing
   hangs 15 px above the top rule so a marker's cap has somewhere to fall
   from. */
.rec-band {
  position: relative;
  width: 100%;
  height: 72px;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairlineLight);
}

.rec-band canvas,
.rec-still {
  position: absolute;
  left: 0;
  right: 0;
  top: -15px;
  width: 100%;
  height: calc(100% + 15px);
  /* The left edge is history leaving the window: a fade, not a cut. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 12%);
  mask-image: linear-gradient(to right, transparent 0, #000 12%);
}

html:not(.js) .rec-band canvas,
.js .rec-still { display: none; }

.rec-still-mid { stroke: var(--rule); stroke-width: 0.75; }
.rec-still-bars { fill: none; stroke: var(--wavePlayed); stroke-width: 3; stroke-linecap: round; }
.rec-still-stem { stroke: var(--accentDeep); stroke-width: 1.5; opacity: 0.7; }
.rec-still-cap { fill: var(--accentDeep); }
.rec-still-live { fill: var(--liveDot); }

.rec-landed { margin-top: var(--space-s); }

@media (prefers-reduced-motion: no-preference) {
  .js .rec-landed { transition: opacity 0.6s var(--settle); }
  .js .rec-landed:not(.in) { opacity: 0; }
}

/* The Marker button as the record screen draws it: the bookmark and its
   name, in the red, on the paper, with nothing round them. */
.rec-marker {
  display: grid;
  justify-items: center;
  gap: 10px;
  margin-top: var(--space-l);
  min-width: 140px;
  min-height: 120px;
  padding: var(--space-m);
  border: 0;
  background: none;
  color: var(--accentDeep);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.rec-marker:disabled { cursor: default; }

.rec-marker .glyph {
  width: 48px;
  height: 56px;
  overflow: visible;
  transition: transform 0.28s cubic-bezier(0.3, 1.6, 0.5, 1);
}

.rec-marker .mark-shape { fill: currentColor; transition: opacity 0.15s; }
.rec-marker .tick-shape {
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  transition: opacity 0.15s;
}

.rec-marker.done .mark-shape { opacity: 0; }
.rec-marker.done .tick-shape { opacity: 1; }
.rec-marker.done .glyph,
.rec-marker:not(:disabled):active .glyph { transform: scale(1.06); }

.rec-word {
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.after-step { margin-bottom: var(--space-m); }

.paper-snippet {
  padding-top: var(--pp);
  padding-bottom: var(--pp);
  border-radius: var(--radius-object);
}

/* The spoken marker: the pressed one's counterpart, given its own beat. No
   box — it stands on the page, carried by its size and the room round it. */
.voice {
  max-width: 38rem;
  margin: clamp(4.5rem, 10vw, 7.5rem) auto 0;
  text-align: center;
}

.voice-mark {
  display: block;
  width: 20px;
  height: 24px;
  margin: 0 auto var(--space-l);
  fill: var(--accentDeep);
}

.voice-head {
  margin: 0 0 var(--space-m);
  font-size: clamp(1.625rem, 1.2rem + 1.8vw, 2.5rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.voice-say {
  margin: 0;
  font-size: var(--type-subtitle);
  line-height: 1.45;
  color: var(--inkSecondary);
  text-wrap: pretty;
}

/* What you say, in the ink; what the app does about it, a step back. */
.voice-say .said { color: var(--ink); }

/* ------------------------------------------------------------------------ */
/* 3. Notebooks                                                              */
/* ------------------------------------------------------------------------ */

.s3 {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xxl);
}

@media (min-width: 56rem) {
  .s3 {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(3rem, 6vw, 6rem);
    align-items: center;
  }
}

/* The shelf: three boards standing on one rule. */
.shelf {
  --cw: clamp(5.75rem, 26vw, 8.75rem);
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: clamp(10px, 3vw, 18px);
  border-bottom: 1px solid var(--hairline);
}

/* NotebookCover: 3:4, square-cut with 3 points of wear, a rolled spine down
   the bound edge, the block of pages showing down the other, and a label
   pasted on. Rulings at height × 0.085, as the app prints them. */
.cover {
  --step: calc(var(--cw) * 4 / 3 * 0.085);
  position: relative;
  flex: none;
  width: var(--cw);
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-object);
  background-color: var(--board);
  overflow: hidden;
  filter: var(--coverLight);
  box-shadow:
    inset 0 0 0 0.75px rgba(43, 38, 32, 0.15),
    0 1px 2px var(--coverShadow),
    0 4px 10px -4px var(--coverShadow);
}

.cover::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: calc(var(--cw) * 4 / 3 * 0.082);
  background: var(--boardSpine);
}

.cover::after {
  content: "";
  position: absolute;
  top: 5%;
  bottom: 5%;
  right: 0;
  width: max(2px, calc(var(--cw) * 4 / 3 * 0.03));
  background: var(--plate);
}

.cover.ruled {
  background-image: repeating-linear-gradient(to bottom, transparent 0 calc(var(--step) - 1px), var(--boardInk) calc(var(--step) - 1px) var(--step));
}

.cover.graph {
  background-image:
    repeating-linear-gradient(to bottom, transparent 0 calc(var(--step) - 1px), var(--boardInk) calc(var(--step) - 1px) var(--step)),
    repeating-linear-gradient(to right, transparent 0 calc(var(--step) - 1px), var(--boardInk) calc(var(--step) - 1px) var(--step));
}

/* NNPalette.notebookCoverHexes, and Unsorted's own warm grey. */
.terracotta { --board: #E8CFC2; }
.sage { --board: #D9E0CE; }
.warmgrey { --board: #DCD6CB; }

.plate {
  position: absolute;
  z-index: 1;
  top: calc(var(--cw) * 0.12);
  left: calc(var(--cw) * 0.2);
  right: calc(var(--cw) * 0.12);
  margin: 0;
  padding: calc(var(--cw) * 0.05) calc(var(--cw) * 0.055);
  background: var(--plate);
  box-shadow: inset 0 0 0 0.75px rgba(43, 38, 32, 0.16);
  color: var(--plateInk);
}

.plate-name {
  display: block;
  font-size: max(0.6875rem, calc(var(--cw) * 0.12));
  font-weight: 600;
  line-height: 1.15;
}

.plate-line {
  display: block;
  margin-top: 4px;
  padding-top: 3px;
  border-top: 0.75px solid rgba(43, 38, 32, 0.18);
  font-family: var(--sans);
  font-size: max(0.5rem, calc(var(--cw) * 0.068));
  line-height: 1.3;
  color: var(--plateInkSecondary);
}

/* One recording in a notebook's list: the title you read, the filing line
   you use, and the summary under them — on the app's card, which is cream
   whatever the page is doing. */
.entry {
  margin-top: var(--space-xl);
  padding: var(--space-m) var(--space-l) calc(var(--space-m) + 2px);
  border-radius: var(--radius-card);
  background: var(--objCard);
  color: var(--objInk);
  box-shadow: inset 0 0 0 0.75px var(--objRule), 0 4px 16px var(--objShadow);
  filter: var(--coverLight);
}

.entry p { margin: 0; }

.entry-title {
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
}

.entry-meta {
  margin-top: var(--space-xxs) !important;
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--objInkSecondary);
  font-variant-numeric: tabular-nums;
}

.entry-meta b { font-weight: 600; }

.entry-summary {
  margin-top: 7px !important;
  font-size: 1rem;
  line-height: 1.45;
  color: var(--objInkSecondary);
}

/* The one highlighted panel: a sheet of the transcript's writing paper, red
   margin rule and all, laid on the page — cream in both schemes, like the
   card above. */
.sheet {
  position: relative;
  padding: var(--space-l) var(--space-l) calc(var(--space-l) + 2px) var(--paper-text-x);
  border-radius: var(--radius-object);
  background: var(--objSheet);
  color: var(--objInk);
  box-shadow: 0 0 0 0.5px var(--objEdge), 0 1px 2px var(--coverShadow), 0 6px 18px -8px var(--objShadow);
  filter: var(--coverLight);
}

.sheet::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--paper-margin-x);
  width: 1px;
  background: var(--objMargin);
}

.offload {
  margin-top: var(--space-xl);
  max-width: var(--measure);
}

.offload h3 {
  margin: 0 0 var(--space-xs);
  font-size: var(--type-heading);
  font-weight: 600;
  line-height: 1.25;
}

.intro .offload p {
  margin: 0;
  color: var(--objInkSecondary);
}

/* A block of points: the same quiet prose, but each point stands on its own
   line with a breath between — the owner's break-up (2026-09-28). */
.points p { margin: 0; }
.points p + p { margin-top: var(--space-s); }

/* ------------------------------------------------------------------------ */
/* 4. Availability, and the foot                                             */
/* ------------------------------------------------------------------------ */

.finale {
  text-align: center;
  display: grid;
  justify-items: center;
  padding-bottom: var(--space-xl);
}

.finale-mark {
  margin: 0 0 var(--space-l);
  font-size: clamp(2.5rem, 1.75rem + 3.5vw, 4.25rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
}

.finale p:not(.finale-mark) { max-width: var(--measure); color: var(--inkSecondary); }

.foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-xs) var(--space-l);
  margin-top: clamp(4rem, 8vw, 6rem);
  padding-top: var(--space-l);
  padding-bottom: var(--space-xxl);
  position: relative;
}

.foot::before {
  content: "";
  position: absolute;
  top: 0;
  left: max(var(--gutter), env(safe-area-inset-left));
  right: max(var(--gutter), env(safe-area-inset-right));
  height: 1px;
  background: var(--hairline);
}

.foot .name { font-weight: 600; }
.foot .name .dot { color: var(--accentDeep); }

.foot-links {
  display: flex;
  gap: var(--space-l);
  font-size: var(--type-footnote);
}

.foot-links a[aria-current="page"] {
  color: var(--inkSecondary);
  text-decoration: none;
}

/* ------------------------------------------------------------------------ */
/* The two prose pages: privacy and support                                  */
/* ------------------------------------------------------------------------ */

a.top-name {
  color: inherit;
  text-decoration: none;
}

/* A column of prose under the running head, set to the page's measure. */
.doc {
  max-width: 38rem;
  padding-top: clamp(var(--space-xxl), 7vw, 5rem);
}

.doc h1 {
  margin: 0 0 var(--space-l);
  font-size: var(--type-title);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.01em;
}

.doc h2 {
  margin: var(--space-xxl) 0 var(--space-xs);
  font-size: var(--type-heading);
  line-height: 1.3;
  letter-spacing: 0;
}

.doc p { max-width: var(--measure); }

.doc .doc-lede {
  font-size: var(--type-subtitle);
  line-height: 1.4;
  color: var(--inkSecondary);
}

.doc .doc-date {
  font-size: var(--type-footnote);
  color: var(--inkSecondary);
}

/* ------------------------------------------------------------------------ */
/* The download (ready before it exists) and the notebooks' shared board     */
/* ------------------------------------------------------------------------ */

/* The store badge: drawn in the page's own inks, inert and greyed until
   main.js finds a URL in data-store-url. At release, consider Apple's
   official badge artwork instead. */
.get { margin: var(--space-xl) 0 0; }

.store-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px 10px 16px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--card);
  text-decoration: none;
  color: var(--ink);
}

.store-badge[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}

.store-mark { width: 17px; height: 20px; fill: currentColor; }

.store-words { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.15; }
.store-pre { font-family: var(--sans); font-size: 0.6875rem; color: var(--inkSecondary); }
.store-name { font-family: var(--sans); font-size: 1.125rem; font-weight: 600; letter-spacing: 0.01em; }

/* One board under the shelf and the recording's card, so the notebook and
   the row it holds read as one thing (owner's ask, 2026-09-28; second cut
   same day: "closer to the cream, not the background brown"). It is a paper
   object like the covers and the card — NNPalette.sunken, cream in both
   schemes, dimmed as one piece in the dark. The covers and the card drop
   their own dimming inside it so the light falls once, not twice. */
.notebooks {
  background: #F4EFE8;
  border-radius: var(--radius-card);
  padding: var(--space-l) var(--space-l) var(--space-xl);
  box-shadow: inset 0 0 0 0.75px rgba(43, 38, 32, 0.12);
}

@media (prefers-color-scheme: dark) {
  /* On a cream board the shelf's rule must be ink, not the dark page's
     light hairline. */
  .notebooks { filter: var(--coverLight); --hairline: rgba(43, 38, 32, 0.18); }
  .notebooks .cover, .notebooks .entry { filter: none; }
}

/* The price, one quiet line under the badge. */
.price {
  margin: var(--space-m) 0 0;
  font-size: var(--type-footnote);
  color: var(--inkSecondary);
}

/* ------------------------------------------------------------------------ */
/* The gutters: the home screen's pile, either side of the column            */
/* ------------------------------------------------------------------------ */

/* Wide screens only — the strips live in the space outside the 72rem wrap
   and are clipped to it, so a board can run off the outer edge like the
   app's own collage but never slides under the words. Behind the grain
   (z -2), so the paper texture unifies them with the page. */
.gutter-pile {
  position: fixed;
  top: 0;
  bottom: 0;
  /* The strip stops 64px short of the wrap: the owner wanted clear air
     between the writing and the boards (2026-09-29). */
  width: calc((100vw - 72rem) / 2 - 64px);
  min-width: 84px;
  max-width: 320px;
  overflow: hidden;
  /* Above the grain (which moved to -2): the owner disliked the grain
     texturing the boards, so the boards now sit clean on top of it. */
  z-index: -1;
  pointer-events: none;
  display: none;
}
.gutter-pile.left { left: 0; }
.gutter-pile.right { right: 0; }

/* From the first width at which a strip of boards fits beside the wrap —
   a 14-inch MacBook's full screen (1512 logical px) must qualify. */
@media (min-width: 87rem) {
  .gutter-pile { display: block; }
}

.gutter-pile .cover {
  position: absolute;
  left: var(--gx);
  top: var(--gy);
  transform: rotate(var(--ga));
}

/* On the dark page the boards keep their object dimming (the .cover base
   rule), and step back a little further still — wallpaper, not content. */
@media (prefers-color-scheme: dark) {
  .gutter-pile { opacity: 0.82; }
}

/* The one outside link: the Instagram glyph, in the footer's quiet ink. */
.foot-insta {
  display: inline-flex;
  align-items: center;
  color: var(--inkSecondary);
}
.foot-insta svg { width: 18px; height: 18px; }
.foot-insta:hover { color: var(--accentDeep); }
