/* ============================================================
   PREVOW — the secondary routes
   programme · yours · download · contact · privacy · terms · 404

   Loaded after tokens.css and nav.css, INSTEAD of base.css and
   prevow.css. It replaces both: those two carried the previous
   generation's page furniture — the pill rows, the bordered cards,
   the component-library presentation — and nothing here inherits
   from them.

   The primitives below are deliberately the same ones the homepage
   uses (display type, the authored line mask, the metadata label,
   the seam) so that arriving on an interior page is arriving on the
   same website. What is NOT shared is composition: every route here
   has its own arrangement and its own single signature moment.
   ============================================================ */

*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; }
body{
  margin:0;
  font-family:var(--font);
  font-weight:var(--w-body);
  font-size:var(--t-body);
  line-height:var(--lh-body);
  color:var(--ink);
  background:var(--white);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img{ max-width:100%; display:block; }
a{ color:inherit; }
h1,h2,h3,h4,p,figure,blockquote,dl,dd{ margin:0; }
ol,ul{ margin:0; padding:0; list-style:none; }
button{ font:inherit; }

::selection{ background:var(--teal); color:var(--on-teal); }
/* The TRACK is transparent, not cloud. A cloud track is a light strip
   running the full height of the window, which is invisible against the white
   page and then very visible against the ink footer — a pale line down the
   edge exactly where the page turns dark. Transparent lets it take whatever
   is behind it. */
html{ scrollbar-color:var(--chevron) transparent; }
:root{ accent-color:var(--ink); caret-color:var(--ink); }

.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.skip-link{
  position:absolute; left:var(--s-2); top:-999px; z-index:300;
  background:var(--ink); color:var(--white); padding:14px 20px; border-radius:var(--r-pill);
  font-weight:var(--w-bold); font-size:var(--t-row); text-decoration:none;
}
.skip-link:focus{ top:var(--s-2); }
:where(a,button,input,textarea,summary,[tabindex]):focus-visible{
  outline:3px solid var(--ink); outline-offset:3px; border-radius:var(--r-chip);
}

.wrap{ width:100%; max-width:var(--page); margin-inline:auto; padding-inline:var(--gutter); }

/* THE READING MEASURE, APPLIED.
   --page-narrow and .wrap--narrow have existed since the first build and were
   used by exactly zero pages, so every paragraph on the site sat in the 1200px
   container instead. Measured: 109 characters per line on /yours at 768px, 101
   on /contact at 1440, 92 on /programme at 768, against a readable band of
   45-75. Rather than hand-tagging every section, the measure is enforced on the
   prose itself — headings, figures and full-bleed compositions are untouched
   because they are supposed to cross the full column. 68ch is the target;
   100% keeps it honest inside already-narrow parents. */
.wrap > p,
.wrap > ul:not([class]),
.wrap > ol:not([class]),
.doc-body > p,
.doc-body > ul,
.doc-body > ol{ max-width:min(46ch, 100%); }

/* 46ch, not 68. `ch` is the advance of "0", which in Plus Jakarta Sans is
   about 1.5x the average lowercase advance — so 46ch renders as roughly 70
   characters, and 68ch renders as 94. The .lede rule already in home.css was
   set to 46ch by someone who had measured it properly; an earlier pass here
   overrode it with 62ch and made the one correctly-set measure on the site
   worse. It is left alone now.

   These four are the ones that genuinely had no cap, measured by glyph
   advance rather than by a guessed ratio:
     /privacy   94 chars, 17 of 17 paragraphs over the band
     /terms     81 chars, 13 of 13
     /yours     105 chars at 768, inside the pinned panel
     programme   88 chars at 768 */
.crisis{ max-width:min(46ch, 100%); }
.pv__say{ max-width:min(40ch, 100%); }
.beat p{ max-width:min(44ch, 100%); }
.wrap--wide{ max-width:var(--page-wide); }
.wrap--narrow{ max-width:var(--page-narrow); }
.wrap--tight{ max-width:var(--page-tight); }

/* Bar clearance lives in nav.css, which does it CONDITIONALLY:
   body:not(.has-hero) main. This file used to repeat it unconditionally
   and, loading after nav.css, won — so a route whose masthead is meant to
   run under the bar got 76px of white above the photograph anyway, and the
   nav never saw the photo zone reach its probe line, so it stayed dark on a
   dark picture. One rule, in the file that owns the bar. */

/* ---- type primitives, shared with the homepage ---- */
.display{
  font-family:var(--font-display);
  font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial);
  letter-spacing:var(--tr-display);
  line-height:var(--lh-editorial);
  font-size:var(--t-display);
  text-wrap:balance;
}
.display--hero{ font-size:var(--t-hero); }
.display--title{ font-size:var(--t-title); }
.quiet{ color:var(--chevron); }
.ind-1{ padding-left:1.1ch; }
.ind-2{ padding-left:2.2ch; }

.meta{
  font-family:var(--font);
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--muted);
  display:flex; align-items:center; gap:var(--s-2);
  margin:0 0 var(--s-4);
}
.meta::after{ content:""; flex:1; height:var(--seam); background:var(--seam-ink); }
.meta--bare::after{ display:none; }

.lede{ color:var(--muted); font-size:var(--t-body); max-width:46ch; margin-top:var(--s-4); }

/* the authored line mask */
/* The mask box has to be TALLER than the line it hides, or it crops the
   glyphs it is supposed to reveal. Fraunces at 0.95-1.04 leading puts
   ascenders and the odd descender outside the line box, and overflow:hidden
   duly cut the tops off "The subjects" and the tails off anything with a
   descender. Padding opens the box; the matching negative margin means the
   layout does not move, so the mask is bigger without the type shifting. */
.split .ln{ display:block; overflow:hidden; padding-block:.18em; margin-block:-.18em; }
.split .ln > span{ display:block; }
.js .split .ln > span{ transform:translateY(108%); transition:transform var(--dur-reveal) var(--ease); }
.js .split.is-in .ln > span{ transform:translateY(0); }
.js .split .ln:nth-child(2) > span{ transition-delay:120ms; }
.js .split .ln:nth-child(3) > span{ transition-delay:240ms; }

/* ---- controls ---- */
.btn{
  --bg:var(--ink); --fg:var(--white); --sweep:var(--teal); --fg-hover:var(--ink);
  position:relative; isolation:isolate; overflow:hidden;
  display:inline-flex; align-items:center; gap:10px;
  min-height:56px; padding:0 30px;
  background:var(--bg); color:var(--fg);
  border:0; border-radius:var(--r-pill);
  font-size:var(--t-row); font-weight:var(--w-bold);
  letter-spacing:var(--tr-row); line-height:1; text-decoration:none; cursor:pointer;
}
.btn::before{
  content:""; position:absolute; inset:0; z-index:-1;
  background:var(--sweep); border-radius:var(--r-pill);
  transform:scaleX(0); transform-origin:left center;
  transition:transform var(--dur-base) var(--ease);
}
.btn:hover::before{ transform:scaleX(1); }
.btn:hover{ color:var(--fg-hover); }
.btn .ph{ font-size:1.05em; transition:transform var(--dur-quick) var(--ease); }
.btn:hover .ph{ transform:translateX(4px); }
.btn--onink{ --bg:var(--white); --fg:var(--ink); --sweep:var(--cloud); --fg-hover:var(--ink); }

.quietlink{
  position:relative; text-decoration:none; font-weight:var(--w-bold);
  font-size:var(--t-row); display:inline-flex; align-items:center; gap:9px;
  padding-block:10px;
}
.quietlink::after{
  content:""; position:absolute; left:0; right:100%; bottom:6px; height:var(--seam);
  background:currentColor; transition:right var(--dur-base) var(--ease);
}
.quietlink:hover::after{ right:0; }
.quietlink .ph{ transition:transform var(--dur-quick) var(--ease); }
.quietlink:hover .ph{ transform:translateX(5px); }

/* ---- section rhythm ---- */
.section{ padding-block:var(--sec); }
.section--loose{ padding-block:var(--sec-loose); }
.section--tight{ padding-block:var(--sec-tight); }
.section--cloud{ background:var(--cloud); }

/* ============================================================
   PAGE OPENING
   Interior pages do not get a photographic hero — the homepage
   owns that. They open on type against white, with the seam
   drawing down beside the title. Flush left, per brand rule.
   ============================================================ */
.open{ padding-block:var(--sec-loose) var(--sec); }
.open__title{ max-width:16ch; }
.open__lede{ margin-top:var(--s-5); }
.open__rule{
  height:var(--seam); background:var(--seam-ink);
  margin-top:var(--sec-tight); transform-origin:left center;
}
.js .open__rule{ transform:scaleX(0); transition:transform var(--dur-reveal) var(--ease-seam); }
.js .open.is-in .open__rule{ transform:scaleX(1); }

/* ---- the ten kept lines ----
   The Vowbook as it actually is early on: two lines written, eight
   still empty. Showing the empty rows is the honest version and it
   is also the more persuasive one — a finished artefact asks
   nothing of you, an unfinished one does. */
.lines{ border-top:var(--seam) solid var(--seam-ink); max-width:var(--page-narrow); }
.lines li{
  display:grid; grid-template-columns:3rem minmax(0,1fr); gap:var(--s-4);
  padding-block:var(--s-4); border-bottom:var(--seam) solid var(--seam-ink); align-items:baseline;
}
.lines span{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); color:var(--chevron); font-size:var(--t-row);
}
.lines p{ font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-card); line-height:1.3; letter-spacing:var(--tr-display); }
.lines li[data-empty] p{ color:var(--cloud); }
.lines__note{ margin-top:var(--s-4); color:var(--muted); font-size:var(--t-meta); }

/* ---- cost ---- */
.cost{ display:flex; flex-wrap:wrap; gap:var(--s-2); margin-top:var(--s-5); }
.cost span{
  font-size:var(--t-label); font-weight:var(--w-bold); letter-spacing:var(--tr-label);
  text-transform:uppercase; color:var(--ink);
  border:var(--seam) solid var(--ink); border-radius:var(--r-pill); padding:9px 16px;
}

/* ---- questions ----
   Hairlines, not pill rows. The previous generation set these as
   100px-radius capsules stacked down the page, which is the
   component-library look this redesign is removing. */
.qa{ border-top:var(--seam) solid var(--seam-ink); max-width:var(--page-narrow); }
.qa details{ border-bottom:var(--seam) solid var(--seam-ink); }
.qa summary{
  list-style:none; cursor:pointer; display:flex; align-items:center; justify-content:space-between;
  gap:var(--s-4); padding-block:var(--s-5);
  font-size:var(--t-section); font-weight:var(--w-bold); letter-spacing:var(--tr-section);
}
.qa summary::-webkit-details-marker{ display:none; }
.qa .sign{ position:relative; flex:0 0 auto; width:20px; height:20px; transition:transform var(--dur-base) var(--ease); }
.qa .sign::before,.qa .sign::after{
  content:""; position:absolute; top:50%; left:50%; width:14px; height:var(--seam);
  background:var(--ink); transform:translate(-50%,-50%);
}
.qa .sign::after{ transform:translate(-50%,-50%) rotate(90deg); }
.qa details[open] .sign{ transform:rotate(135deg); }
.qa__a{ padding-bottom:var(--s-5); color:var(--muted); font-size:var(--t-small); line-height:1.75; max-width:62ch; }

/* ============================================================
   WHAT STAYS YOURS — the demonstration
   SIGNATURE: one answer, shown three times, progressively taken
   away. Share is legible. Sealed keeps the shape of the writing
   but not the writing. Private keeps nothing — the panel is empty
   and stays empty, because absence is the feature.

   The concealment is a SOLID ink block over the words, never a
   blur and never a gradient: rule 3, and a blur is also a lie —
   blurred text can be recovered, a covered block cannot.
   ============================================================ */
.three{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--s-3); }
.state{
  border-radius:var(--r-block); padding:var(--s-5);
  background:var(--cloud); display:flex; flex-direction:column; min-height:340px;
}
.state--share{ background:var(--blush); }
.state--sealed{ background:var(--teal); }
.state__k{
  font-size:var(--t-label); font-weight:var(--w-bold); letter-spacing:var(--tr-label);
  text-transform:uppercase; color:var(--on-teal);
}
.state--private .state__k{ color:var(--muted); }
.state__what{ margin-top:10px; font-size:var(--t-small); line-height:1.55; color:var(--on-teal); }
.state--private .state__what{ color:var(--muted); }

/* the answer itself */
.answer{
  margin-top:var(--s-5); padding-top:var(--s-4);
  border-top:var(--seam) solid rgba(11,31,58,.22);
  font-size:var(--t-small); line-height:1.7; color:var(--ink);
  position:relative; flex:1;
}
/* SEALED — the words are covered by solid bars that keep the line
   rhythm of the writing underneath. You can see that something was
   written, and how much. You cannot see what. */
.answer--sealed{ color:transparent; user-select:none; }
.answer--sealed span{ position:relative; }
.answer--sealed span::before{
  content:""; position:absolute; inset:0.12em 0 0.16em 0;
  background:var(--on-teal); opacity:.55; border-radius:2px;
}
/* PRIVATE — nothing. Not a covered answer: no answer. */
.answer--private{ color:var(--muted); font-style:normal; }
.answer--private i{ font-style:normal; opacity:.75; }

.state__icon{ margin-top:var(--s-4); }
.state__icon .ph{ font-size:26px; }

@media (max-width:820px){ .three{ grid-template-columns:1fr; } .state{ min-height:0; } }

/* the promise list — hairlines, not cards */
.promise{ border-top:var(--seam) solid var(--seam-ink); }
.promise li{
  display:grid; grid-template-columns:minmax(0,20rem) minmax(0,1fr); gap:var(--s-4);
  padding-block:var(--s-5); border-bottom:var(--seam) solid var(--seam-ink);
}
.promise b{ font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-card); letter-spacing:var(--tr-display); }
.promise p{ color:var(--muted); font-size:var(--t-small); line-height:1.65; max-width:52ch; }
@media (max-width:760px){ .promise li{ grid-template-columns:1fr; gap:var(--s-2); } }

/* ============================================================
   DOWNLOAD — the threshold
   SIGNATURE: the page stops describing and starts. It shows the
   actual first question of chapter one, full size, as the last
   thing before the action — so the step you are taking is legible
   rather than promised.
   ============================================================ */
.threshold{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:clamp(var(--s-6),7vw,var(--s-16)); align-items:center; }
.qcard{
  border-radius:var(--r-block); background:var(--cloud);
  padding:clamp(var(--s-5),4vw,var(--s-8));
}
.qcard__k{
  font-size:var(--t-label); font-weight:var(--w-bold); letter-spacing:var(--tr-label);
  text-transform:uppercase; color:var(--muted); margin-bottom:var(--s-4);
  display:flex; align-items:center; gap:var(--s-2);
}
.qcard__k::after{ content:""; flex:1; height:var(--seam); background:var(--seam-ink); }
.qcard__q{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-title); line-height:1.18;
  letter-spacing:var(--tr-display); text-wrap:balance;
}
/* the empty field: a real writing line, left blank on purpose */
.qcard__field{
  margin-top:var(--s-6); display:flex; flex-direction:column; gap:14px;
}
.qcard__field i{ display:block; height:var(--seam); background:var(--seam-ink); }
.qcard__field i:nth-child(2){ width:82%; }
.qcard__field i:nth-child(3){ width:64%; }
.qcard__note{ margin-top:var(--s-4); color:var(--muted); font-size:var(--t-meta); }

.steps-in{ margin-top:var(--s-6); }
.steps-in li{
  display:grid; grid-template-columns:2rem 1fr; gap:var(--s-3);
  padding-block:var(--s-4); border-top:var(--seam) solid var(--seam-ink);
  font-size:var(--t-small); color:var(--muted); line-height:1.6;
}
.steps-in b{ color:var(--ink); font-weight:var(--w-bold); }
.steps-in span{ font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); color:var(--chevron); }
@media (max-width:900px){ .threshold{ grid-template-columns:1fr; } }

/* ============================================================
   CONTACT — quiet
   SIGNATURE: none, deliberately. Four routes as a ruled table.
   The only motion is the underline on a link. A contact page that
   performs is a contact page getting in the way.
   ============================================================ */
.routes{ border-top:var(--seam) solid var(--seam-ink); }
.routes li{
  display:grid; grid-template-columns:minmax(0,16rem) minmax(0,1fr) minmax(0,16rem);
  gap:var(--s-4); align-items:baseline;
  padding-block:var(--s-6); border-bottom:var(--seam) solid var(--seam-ink);
}
.routes h2{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-card); letter-spacing:var(--tr-display);
}
.routes p{ color:var(--muted); font-size:var(--t-small); line-height:1.65; max-width:46ch; }
.routes a{ font-weight:var(--w-bold); font-size:var(--t-body); text-decoration:none;
  border-bottom:var(--seam) solid var(--ink); padding-bottom:2px; }
.routes small{ display:block; margin-top:8px; color:var(--muted); font-size:var(--t-meta); }
/* Two columns inside a narrow column, not three. .routes was built as a wide
   table — heading, description, link — and reserving 16rem for a third column
   that a FAQ never uses left the answer about 44px wide inside a 720px
   .wrap--narrow, one word per line. /questions and /download both use it that
   way. */
.wrap--narrow .routes li{ grid-template-columns:minmax(0,15rem) minmax(0,1fr); }
/* the 46ch cap from .routes p stays: in two columns the column is narrower
   than the cap so it never binds, and once stacked at 900 it is the only thing
   stopping the answer running to 92 characters. */
@media (max-width:900px){
  .routes li,
  .wrap--narrow .routes li{ grid-template-columns:1fr; gap:var(--s-2); }
  .routes a{ margin-top:var(--s-2); display:inline-block; }
}

/* the crisis note is set apart, because it must not read as one of
   the four ordinary routes */
.crisis{
  margin-top:var(--sec-tight); padding:var(--s-5);
  border-radius:var(--r-block); background:var(--cloud);
  color:var(--ink); font-size:var(--t-small); line-height:1.7; max-width:70ch;
}
.crisis b{ display:block; margin-bottom:6px; }

/* ============================================================
   LEGAL — privacy and terms
   A document, composed as a document.

   These two pages are the ones a reader arrives at already braced
   for something exhausting, so the design's whole job is to make
   the shape of the thing visible: how many sections there are,
   which one you are in, and how far is left. That is what the
   index and the hanging numbers do. Nothing here animates beyond
   the mark moving down the index — legal prose that performs is
   legal prose nobody finishes.

   Held LEFT throughout: centring a privacy policy is a costume.
   ============================================================ */
.doc-layout{
  display:grid;
  grid-template-columns:minmax(0,15rem) minmax(0,var(--page-narrow));
  gap:clamp(var(--s-6),6vw,var(--s-12));
  align-items:start;
}

/* the contents, built by js/route.js from the document's own headings */
.doc-index{ position:sticky; top:calc(var(--nav-h) + var(--s-6)); }
.doc-index__k{
  font-size:var(--t-label); font-weight:var(--w-bold); letter-spacing:var(--tr-label);
  text-transform:uppercase; color:var(--muted);
  padding-bottom:var(--s-3); border-bottom:var(--seam) solid var(--seam-ink);
}
.doc-index ol{ margin-top:var(--s-3); }
.doc-index a{
  display:grid; grid-template-columns:2.2rem 1fr; gap:var(--s-2);
  padding-block:7px; text-decoration:none;
  font-size:var(--t-meta); line-height:1.35; color:var(--muted);
  transition:color var(--dur-quick) var(--ease);
}
.doc-index a span{ font-variant-numeric:tabular-nums; color:var(--chevron); }
.doc-index a:hover{ color:var(--ink); }
.doc-index a[data-on]{ color:var(--ink); font-weight:var(--w-bold); }
.doc-index a[data-on] span{ color:var(--ink); }

.legal{ max-width:var(--page-narrow); counter-reset:sec; }
/* the section number hangs in the margin beside the heading rather
   than sitting inside the measure, so the prose column stays a clean
   rectangle and the numbers read as an edge you can scan down */
.legal h2{
  position:relative;
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-title); line-height:1.15;
  letter-spacing:var(--tr-display); margin-top:var(--sec); padding-top:var(--s-5);
  border-top:var(--seam) solid var(--seam-ink);
  counter-increment:sec;
}
.legal h2::before{
  content:counter(sec,decimal-leading-zero);
  position:absolute; left:-4.25rem; top:calc(var(--s-5) + .12em);
  font-size:var(--t-row); font-variant-numeric:tabular-nums;
  letter-spacing:0; color:var(--chevron);
}
/* the closing call is not a numbered clause */
.legal h2.is-close{ counter-increment:none; }
.legal h2.is-close::before{ content:none; }

@media (max-width:1080px){
  .doc-layout{ grid-template-columns:1fr; }
  .doc-index{ position:static; margin-bottom:var(--sec-tight); }
  .doc-index ol{ columns:2; column-gap:var(--s-5); }
  .legal h2::before{ position:static; display:block; margin-bottom:var(--s-2); }
}
@media (max-width:560px){
  .doc-index ol{ columns:1; }
}
.legal h3{ font-size:var(--t-section); font-weight:var(--w-bold); margin-top:var(--s-5); }
.legal p, .legal li{ color:var(--muted); font-size:var(--t-body); line-height:1.75; margin-top:var(--s-3);
  /* 46ch, not 68. `ch` is the advance of "0", roughly 1.5x the average
     lowercase advance, so 68ch rendered 81 characters — every paragraph of
     both legal pages sat outside the readable band. */
  max-width:46ch; }
.legal li{ padding-left:var(--s-3); position:relative; }
.legal li::before{ content:""; position:absolute; left:0; top:.85em; width:10px; height:var(--seam); background:var(--chevron); }
.legal a{ font-weight:var(--w-bold); }
.legal dt{ font-weight:var(--w-bold); margin-top:var(--s-4); }
.legal dd{ color:var(--muted); margin-top:6px; }

/* the summary that opens a policy — a block, not a bordered card */
.doc-short{
  background:var(--cloud); border-radius:var(--r-block);
  padding:clamp(var(--s-5),4vw,var(--s-8)); margin-bottom:var(--sec-tight);
}
.doc-short-label{
  font-size:var(--t-label); font-weight:var(--w-bold); letter-spacing:var(--tr-label);
  text-transform:uppercase; color:var(--muted); margin-bottom:var(--s-4);
}
.doc-short ul{ display:flex; flex-direction:column; gap:var(--s-3); }
.doc-short li{
  position:relative; padding-left:var(--s-4);
  font-size:var(--t-small); line-height:1.7; color:var(--ink); max-width:64ch;
}
.doc-short li::before{
  content:""; position:absolute; left:0; top:.72em; width:11px; height:var(--seam); background:var(--ink);
}
.doc-short em{ font-style:normal; font-weight:var(--w-bold); }
.doc-date{ color:var(--muted); font-size:var(--t-meta); margin-top:var(--s-4); }

/* ============================================================
   404
   ============================================================ */
.lost{ padding-block:var(--sec-air) var(--sec-loose); }
.lost__links{ display:flex; flex-wrap:wrap; gap:var(--s-4); margin-top:var(--s-6); }

/* ============================================================
   CLOSING CALL — the last band before the footer, shared by the
   routes that end on an action. Cloud, so the ink footer beneath
   it still lands as a change of ground.
   ============================================================ */
.close{ background:var(--cloud); padding-block:var(--sec-loose); }
.close__title{ max-width:18ch; }
.close .btn{ margin-top:var(--s-6); }

/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.01ms !important; transition-duration:.01ms !important; }
  .split .ln > span{ transform:none; }
  .open__rule{ transform:scaleX(1); }
  .js .spine[data-active] .chap{ opacity:1; }
}

/* ============================================================
   PROGRAMME — the reading head
   THE SIGNATURE, AND IT EXISTS ONLY HERE.

   The previous attempt was ten identical rows down 3200px with an
   empty third column. It was a numbered list with better type, which
   is the one thing the brief ruled out, and spreading ten items over
   three screens meant you could never see the shape of the programme
   at all.

   This is the opposite arrangement. The ten conversations are a dense
   index you can take in almost at once, and beside it a large panel
   holds ONE chapter at a time: its number at display scale, its name,
   what you come away with, and a sentence that exists nowhere else on
   the site. Scrolling the index changes what the panel is holding.

   So the page reads as a book's contents with a thumb held in it,
   rather than as a list of ten equal things.
   ============================================================ */
/* A scroll track, so the eleven chapters are not walked through in 160px.
   The section was 865px tall and the whole index visible inside it, which gave
   each chapter about a sixth of a screen before the panel turned again. 500vh
   leaves roughly 330px of scroll per chapter — enough to read one before the
   next arrives. Same construction as .vb__scroll.

   This is the number to turn if the pacing wants changing again: 420vh gave
   262px and read as slightly hurried, 500vh gives 327px. */
/* NO TRACK. The panel advances on a timer now, so the section is as tall
   as its own content and a reader who does not care about it scrolls past
   an ordinary section. It used to be five screens of track whose only
   purpose was to meter out the chapters as you ground through it — which
   made watching the panel and getting past it the same gesture.

   .pg keeps its two columns and stops being a sticky stage; .pg__head is
   still sticky within it, so the big number follows you down the index
   rather than scrolling away at the top. */
.pg__scroll{ height:auto; }
.pg{
  display:grid;
  grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:clamp(var(--s-6),5vw,var(--s-12));
  align-items:start;
}

/* ---- the panel ---- */
.pg__head{
  position:sticky; top:calc(var(--nav-h) + var(--s-6));
  display:flex; flex-direction:column;
}
.pg__n{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial);
  font-size:clamp(6rem,15vw,13.5rem); line-height:.8; letter-spacing:-.05em;
  color:var(--ink);
  display:block; overflow:hidden;
}
/* the number rolls; the words cross-fade. Two different treatments so
   the change reads as one object turning rather than four things
   blinking at once. */
/* The exit was --dur-base (420ms) while the text swap fired at 200ms, so the
   outgoing number was replaced less than halfway out of frame — the new one
   appeared from nowhere. The exit is quick and the swap now waits for it.

   And it is a true roll: out through the top, then the incoming number is
   placed BELOW with no transition and released upward into place. Before, the
   same element slid up and came back down, which reads as a bounce rather
   than a counter turning. */
.pg__n i{ display:block; font-style:normal; transition:transform var(--dur-quick) var(--ease); }
.pg[data-turning] .pg__n i{ transform:translateY(-108%); }
.pg[data-entering] .pg__n i{ transform:translateY(108%); transition:none; }
.pg[data-entering] .pg__body{ opacity:0; transition:none; }
.pg:not([data-turning]):not([data-entering]) .pg__n i{
  transform:translateY(0); transition:transform var(--dur-base) var(--ease);
}

.pg__body{ margin-top:var(--s-5); transition:opacity var(--dur-quick) var(--ease); }
.pg[data-turning] .pg__body{ opacity:0; }
.pg__title{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-title); line-height:1.1;
  letter-spacing:var(--tr-display); text-wrap:balance; max-width:14ch;
}
.pg__note{ margin-top:var(--s-4); color:var(--muted); font-size:var(--t-small); line-height:1.7; max-width:40ch; }
.pg__out{
  margin-top:var(--s-5); padding-top:var(--s-3);
  border-top:var(--seam) solid var(--ink);
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase; color:var(--ink);
  display:inline-flex; align-items:center; gap:var(--s-2);
}
.pg__free{
  background:var(--teal); color:var(--ink); border-radius:var(--r-pill);
  padding:5px 11px; font-size:var(--t-label); letter-spacing:var(--tr-label);
}

/* ---- the index ---- */
.pg__list{ border-top:var(--seam) solid var(--ink); }
.pg__list li{ border-bottom:var(--seam) solid var(--seam-ink); }
/* The ten chapters are LINKS now — each opens its own page — and the
   pre-chapter, which has no page, stays a button. Both are the same row,
   so every rule here names both rather than assuming one. */
.pg__list a,
.pg__list button{
  width:100%; text-decoration:none; text-align:left; background:none; border:0; cursor:pointer;
  display:grid; grid-template-columns:2.6rem minmax(0,1fr) auto; gap:var(--s-3);
  align-items:baseline; padding:15px 0;
  /* the nine inactive chapter names inherit this; at --chevron they measured
     3.18:1 against a 4.5 floor. --muted is the same "quiet" register and
     passes, and hover/active still resolve to full ink. */
  color:var(--muted);
  transition:color var(--dur-quick) var(--ease), padding-left var(--dur-base) var(--ease);
}
.pg__list b{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-section);
  letter-spacing:var(--tr-display); color:inherit;
}
.pg__list span{ font-variant-numeric:tabular-nums; font-size:var(--t-meta); color:inherit; }
.pg__list em{ font-style:normal; font-size:var(--t-meta); color:var(--muted); opacity:0; transition:opacity var(--dur-quick) var(--ease); }
.pg__list a:hover,
.pg__list button:hover{ color:var(--ink); }
/* the one being held in the panel */
.pg__list [data-on] a,
.pg__list [data-on] button{ color:var(--ink); padding-left:var(--s-2); }
.pg__list [data-on] em{ opacity:1; color:var(--muted); }
.pg__list a:focus-visible{ outline:2px solid var(--ink); outline-offset:-2px; }
.pg__list [data-pre] button b{ font-size:var(--t-row); }

@media (max-width:1000px){
  /* The panel becomes a compact held header above the list. It is driven
     by the same timer as everywhere else; touch has no hover, so tapping an
     entry is what takes it. */
  .pg{ grid-template-columns:1fr; gap:var(--s-6); }
  /* the panel becomes a compact held header above the list, still sticky */
  .pg__head{
    position:sticky; top:var(--nav-h); z-index:5; min-height:0;
    background:var(--white); padding-block:var(--s-4);
    border-bottom:var(--seam) solid var(--ink);
    display:grid; grid-template-columns:auto minmax(0,1fr); gap:var(--s-4); align-items:center;
  }
  .pg__n{ font-size:clamp(3.25rem,17vw,5rem); }
  .pg__body{ margin-top:0; }
  .pg__title{ font-size:var(--t-card); max-width:none; }
  .pg__note{ display:none; }   /* the panel must stay one line tall on a phone */
  .pg__out{ margin-top:var(--s-2); padding-top:var(--s-2); }
}

/* ---- the full-width statements between groups ---- */
.arc{
  padding-block:var(--sec-loose);
  border-top:var(--seam) solid var(--seam-ink);
  border-bottom:var(--seam) solid var(--seam-ink);
  margin-block:var(--sec);
}
/* :not() so the label is not caught by the statement's own type —
   `.arc p` beat `.arc__k` on specificity and set the 11px kicker at
   display size. */
.arc p:not(.arc__k){
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-display);
  line-height:1.06; letter-spacing:var(--tr-display); text-wrap:balance;
  max-width:22ch;
}
.arc span{ color:var(--chevron); }
.arc__k{
  font-size:var(--t-label); font-weight:var(--w-bold); letter-spacing:var(--tr-label);
  text-transform:uppercase; color:var(--muted); margin-bottom:var(--s-4);
}

/* The index is the control surface, so it has to read as one: the row
   under the pointer takes the ink, shifts, and shows its outcome. */
.pg__list a,
.pg__list button{ position:relative; }
.pg__list a::before,
.pg__list button::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:2px;
  background:var(--ink); transform:scaleY(0); transform-origin:center;
  transition:transform var(--dur-quick) var(--ease);
}
.pg__list [data-on] a::before,
.pg__list [data-on] button::before{ transform:scaleY(1); }

/* ============================================================
   WHAT STAYS YOURS — one answer, three steps

   This was a pinned frame that changed as you scrolled: a 340vh track, a
   sticky stage, a scroll-driven state machine, and three separate fallbacks
   for the cases where the scroll could not carry it — reduced motion, phones
   too short to hold the stage without clipping content that then could not be
   scrolled to, and no JS. Every one of those existed to show three things one
   at a time in the same place. Shown as three steps they are simply three
   steps, and all of it goes with them: no track, no pinning, no state
   machine, no fallbacks, and nothing that behaves differently at one viewport
   height than at another.

   The reason it was ever one frame is that three cards read as three
   OBJECTS, when privacy is one answer in three conditions. That is answered
   by what sits above the steps rather than by pinning them: the answer
   appears once, marked as the part that none of the three touch, and the
   steps are conditions of it.
   ============================================================ */
.pv{ position:relative; }

/* ---- the constant ---- */
.pv__you{ margin-top:var(--s-8); max-width:62ch; }
.pv__who{
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--muted); margin:0 0 var(--s-3);
}
.pv__sheet{
  position:relative;
  padding:clamp(var(--s-4),2.4vw,var(--s-6));
  background:var(--cloud);
  border:var(--seam) solid var(--seam-ink); border-radius:var(--r-block);
}
.pv__q{ font-size:var(--t-meta); color:var(--muted); margin:0 0 var(--s-4); }
.pv__answer{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:clamp(1.15rem,1.9vw,1.6rem);
  line-height:1.5; letter-spacing:var(--tr-display); color:var(--ink);
  margin:0;
}
.pv__foot{
  margin:var(--s-3) 0 0; color:var(--muted);
  font-size:var(--t-label); line-height:1.6;
}

/* ---- the three steps ---- */
.pv__steps{
  list-style:none; margin:var(--s-8) 0 0; padding:0;
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(var(--s-4),2.6vw,var(--s-6));
  align-items:stretch;
}
.pv__step{ min-width:0; display:flex; flex-direction:column; }
.pv__n{
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); color:var(--chevron);
  margin:0; font-variant-numeric:tabular-nums;
}
.pv__word{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:clamp(1.5rem,2.4vw,2.1rem);
  line-height:1.1; letter-spacing:var(--tr-display); color:var(--ink);
  margin:var(--s-2) 0 0;
}
.pv__say{
  margin:var(--s-3) 0 var(--s-5);
  color:var(--muted); font-size:var(--t-small); line-height:1.7;
}
/* Their page is what each step acts on, so it reads as a screen rather than
   as the paper your own answer sits on. flex:1 keeps the three level when one
   description runs a line longer than another. */
.pv__sheet--them{ background:var(--white); flex:1; }
.pv__sheet--them .pv__who{ color:var(--chevron); }
.pv__theirs{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:clamp(1rem,1.4vw,1.2rem);
  line-height:1.5; letter-spacing:var(--tr-display); color:var(--ink);
  margin:0;
}
.pv__mine,
.pv__next{
  margin-top:var(--s-4); padding-top:var(--s-4);
  border-top:var(--seam) solid var(--seam-ink);
}
.pv__mine-k{
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--chevron); margin:0 0 var(--s-2);
}
.pv__mirror{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:clamp(1rem,1.4vw,1.2rem);
  line-height:1.5; letter-spacing:var(--tr-display); color:var(--ink);
  margin:0;
}
.pv__next .pv__q{ margin-bottom:var(--s-3); }
.pv__rule{ display:flex; flex-direction:column; gap:var(--s-3); margin:0; }
.pv__rule i{ display:block; height:var(--seam); background:var(--seam-ink); }
.pv__rule i:last-child{ width:62%; }

/* ---- AWAITING THE APP SCREENSHOT ----
   Each panel is a hand-built stand-in for a frame of the real thing in that
   state, so it is marked as one: a dashed edge instead of the hairline, a tag
   above it and the brief below. It keeps the section working in the meantime
   — an empty box in these three slots would put the section straight back to
   the fault it was rebuilt out of — while making it plain that nothing here
   is a photograph of the product yet.

   Delete .pv__sheet--todo, .pv__shot-k and .pv__shot-brief when the frames
   land; the panel underneath is already the right size, so nothing moves. */
.pv__shot-k{
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--chevron); margin:0 0 var(--s-2);
}
.pv__sheet--todo{ border-style:dashed; }
.pv__shot-brief{
  margin:var(--s-3) 0 0; padding-left:var(--s-3);
  border-left:var(--seam) solid var(--seam-ink);
  color:var(--muted); font-size:var(--t-label); line-height:1.6;
  /* the briefs run 3, 4 and 4 lines, which left the three panels above them
     ending at three different heights. Four lines' worth for all of them, so
     the panels stay level while the scaffolding is still here. */
  min-height:calc(4 * 1.6em);
}
/* the state line is the section's own copy, so it stays below the brief and
   keeps the weight — the brief is scaffolding, that is not */
.pv__shot-brief + .pv__foot{ margin-top:var(--s-3); }

/* ---- STEP 02, SEALED: the words are covered where they arrive ----
   On .pv__mirror — your answer as it reaches THEM — and never on .pv__answer
   above, which is your own page. Covering your own writing would say the app
   hides your words from you, which is not what any of the three states do.
   A solid block, not a blur: a blur implies the words are still recoverable,
   a cover does not. */
.pv__mirror span{ position:relative; }
.pv__mirror span i{ font-style:normal; }
.pv__step[data-step="2"] .pv__mirror span i{ opacity:0; }
.pv__step[data-step="2"] .pv__mirror span::after{
  content:""; position:absolute; left:-.06em; right:-.06em; top:.12em; bottom:.18em;
  background:var(--ink); border-radius:2px;
}

@media (max-width:1080px){
  /* Three columns of ~250px is not three steps, it is three slivers — at
     901px each one was 247px wide, which puts your answer on seven lines.
     Measured: the columns only stay comfortable (288px and up) above about
     1080, so that is where they stack rather than at the usual 900. Stacked
     they lose nothing — a numbered heading and a rule between them read as
     steps at any width. */
  .pv__steps{ grid-template-columns:1fr; gap:var(--s-6); }
  .pv__step + .pv__step{ padding-top:var(--s-6); border-top:var(--seam) solid var(--seam-ink); }
  .pv__say{ margin-bottom:var(--s-4); max-width:min(52ch,100%); }
  .pv__you{ margin-top:var(--s-6); }
}

/* Restored when the privacy demonstration lost its pinned stage: these two
   rules were sharing that section's reduced-motion block but belong to the
   chapter panel, which is still pinned. */
@media (prefers-reduced-motion:reduce){
  /* No pinning for choreography under reduced motion — the reader gets the
     panel and the list as an ordinary section, at ordinary scroll length. */
  .pg__scroll{ height:auto; }
  .pg{ position:static; height:auto; align-content:start; }
}

/* ============================================================
   THE BLEED — the image interruption
   Mate Libre's rhythm principle, in Prevow's register: the page
   must stop being a column of type at intervals. This breaks the
   grid entirely — full width, no rounded card around it, and it
   OPENS as it arrives rather than sitting there.

   The frame is clipped and the image inside is oversized, so what
   moves is the crop, not the element. Nothing here changes layout.
   ============================================================ */
.bleed{ margin-block:var(--sec-loose); }
.bleed__frame{
  position:relative; overflow:hidden;
  /* NOT 100vw. This component had never been placed in the markup, and the
     first time it was it put 8px of horizontal scroll on every chapter page:
     100vw counts the scrollbar, so a 1425px viewport got a 1440px frame and
     calc(50% - 50vw) hung 7.5px off each side.

     The breakout is not needed at all. .bleed is a direct child of <main>
     and is therefore already the full width of the page — 1425 of 1425 —
     so the frame simply fills its parent. Place a .bleed inside a .wrap and
     it will be constrained by it, which is the correct behaviour: the way
     to make something full-bleed on this site is to take it out of the
     wrap, not to have it measure the viewport behind its parent's back. */
  width:100%;
  height:clamp(320px,42vw,620px);
}
.bleed--tall .bleed__frame{ height:clamp(380px,52vw,760px); }
.bleed__img{
  position:absolute; inset:0;
  width:100%; height:118%;      /* oversized so the crop can travel */
  object-fit:cover; object-position:50% 46%;
  will-change:transform;
}
/* the crop opens: the frame is masked to a band and widens to full.
   clip-path only — no height animation, so nothing reflows. */
.js .bleed__frame{
  clip-path:inset(22% 0 22% 0);
  transition:clip-path 1.2s var(--ease-seam);
}
.js .bleed.is-in .bleed__frame{ clip-path:inset(0 0 0 0); }

.bleed__cap{
  position:absolute; left:var(--gutter); bottom:var(--s-5);
  color:var(--white); font-size:var(--t-meta); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  text-shadow:none;
}
/* the caption needs a ground, and rule 3 forbids a gradient scrim, so it
   sits on a solid ink bar sized to itself */
.bleed__cap{ background:var(--ink); padding:8px 14px; border-radius:var(--r-pill); }

@media (max-width:700px){
  .bleed{ margin-block:var(--sec); }
  .bleed__frame{ height:clamp(300px,72vw,420px); }
  .bleed--tall .bleed__frame{ height:clamp(340px,86vw,480px); }
}
@media (prefers-reduced-motion:reduce){
  .js .bleed__frame{ clip-path:none; }
}

/* ============================================================
   THE VOWBOOK — a notebook you turn
   One spread per chapter: the left page nearly empty with the
   numeral at its foot, the right page carrying the note, the
   title, its outcome and the line the two of you kept.

   A book is normally drawn with drop shadows and this kit forbids
   them, which is the useful constraint. What makes a bound object
   read as bound is not a shadow — it is the SPINE, the gutter
   margins being wider than the outer ones, ruled paper, and the
   sheet being a different white from the ground it rests on.

   ON THE COLOUR: the reference this follows sets its numeral in
   teal. That is not available here and the kit says why in its own
   words — "the new palette has no light accent that clears
   contrast". #81D8D0 on white measures 1.66:1, which fails even
   the relaxed bar for large text. The numeral is ink. Teal appears
   in the one place the kit sanctions it, "NOW, the live thing":
   the pill that says chapter one is free.
   ============================================================ */
.vb{ position:relative; }
.vbk__count{
  margin-top:var(--s-4);
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase; color:var(--muted);
}
.vbk__count b{ color:var(--ink); font-variant-numeric:tabular-nums; }

.vbk{ position:relative; margin-top:var(--s-6); }
/* THE FRAME CLIPS, AND THE LEAF IS INSIDE IT.
   The corner used to live on the turning page, and could not: an element
   under a 3D transform is rasterised as a rectangle and its own clip —
   border-radius or clip-path — is discarded for the length of the turn. So
   the page was round at rest, square in flight, round again at the end.

   The clip belongs to something that is NOT being transformed. The frame
   holds the border, the corner and the perspective, and the leaf turns
   inside it, so the rounded box is applied in the frame's own flat space to
   whatever the leaf has become. Nothing about the leaf has to survive
   anything. */
.vbk__frame{
  position:relative;
  border:var(--seam) solid var(--seam-ink);
  border-radius:var(--r-block);
  background:var(--white);
  overflow:hidden;
  /* the depth the turn is seen through. Too little and the leaf folds flat
     like a page being closed; this reads as one lifting. */
  perspective:2400px;
}
.vbk__book{
  position:relative;
  list-style:none; margin:0; padding:0;
  display:grid;
}
/* Every spread occupies the same cell, so the book is as tall as its tallest
   page and nothing reflows on a turn. */
.vbk__spread{
  grid-area:1/1;
  display:grid; grid-template-columns:1fr 1fr;
  min-height:clamp(420px,52vw,600px);
  /* A grid item is min-width:auto, so it refuses to shrink below the
     min-content width of what is inside it. With a nowrap pill beside a
     fixed-width polaroid, that floor came out at 380px inside a 327px book
     on a phone: the spread overflowed its own container and .vbk__book's
     overflow:hidden quietly cropped it — while the turning leaf, sized to
     the container, was the correct 325. The two disagreed by 55px. */
  min-width:0;
  opacity:0; visibility:hidden;
}
.vbk__spread[data-on]{ opacity:1; visibility:visible; }
html:not(.js) .vbk__spread{ opacity:1; visibility:visible; grid-area:auto; }
html:not(.js) .vbk__spread + .vbk__spread{ border-top:var(--seam) solid var(--seam-ink); }

/* ---- the paper ----
   Ruled, because that is what a notebook is. One hue at two alphas, which is
   the single thing rule 3 still allows — a colour ramp would be a gradient
   and the gate is right to refuse it. The rhythm is 34px, close enough to a
   real feint ruling to read as paper and far enough from the type's own
   leading not to fight it. */
.vbk__page{
  position:relative; min-width:0;
  padding:clamp(var(--s-5),3.2vw,var(--s-8));
  display:flex; flex-direction:column;
  background-image:repeating-linear-gradient(
    to bottom,
    rgba(11,31,58,0) 0, rgba(11,31,58,0) 33px,
    rgba(11,31,58,.05) 33px, rgba(11,31,58,.05) 34px);
  background-position:0 var(--s-6);
}
/* THE SPINE — one hairline, and a gutter wider than the outer margin on
   both pages, which is what a gutter actually is and what makes the halves
   read as one folded sheet rather than two panels. */
.vbk__page--left{
  padding-right:clamp(var(--s-6),4.6vw,var(--s-12));
  border-right:var(--seam) solid var(--seam-ink);
  /* NOT space-between: that spaces all three apart and leaves the numeral
     stranded in the middle of the page. The numeral belongs immediately
     above the label it names, and the pair belong at the foot — so the
     numeral takes the slack and the two travel down together. */
  justify-content:flex-start;
}
.vbk__page--right{
  padding-left:clamp(var(--s-6),4.6vw,var(--s-12));
  justify-content:space-between;
}
/* the paper curves into the fold */
.vbk__page--left::after,
.vbk__page--right::after{
  content:""; position:absolute; top:0; bottom:0; width:7%;
  pointer-events:none;
}
.vbk__page--left::after{
  right:0; background:linear-gradient(to right, rgba(11,31,58,0), rgba(11,31,58,.05));
}
.vbk__page--right::after{
  left:0; background:linear-gradient(to left, rgba(11,31,58,0), rgba(11,31,58,.05));
}

/* ---- left page ---- */
.vbk__eyebrow,
.vbk__chapter-of{
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--chevron); margin:0;
}
.vbk__numeral{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial);
  font-size:clamp(4rem,9vw,7.5rem); line-height:.82;
  letter-spacing:-.02em; color:var(--ink);
  /* auto on top: the numeral takes the page's free space above it, so it
     and the label beneath travel to the foot together. Set here rather
     than as a separate margin-top, which the shorthand below would
     silently undo — it did, and put the numeral back at the head. */
  margin:auto 0 var(--s-3);
  font-variant-numeric:tabular-nums;
}

/* ---- right page ---- */
.vbk__top{ display:flex; align-items:flex-start; justify-content:space-between; gap:var(--s-4); }
/* NOW, the live thing — the one use of teal the kit sanctions. Ink on teal,
   never the reverse: white on teal is 1.66:1. */
.vbk__pill{
  /* nowrap: the polaroid beside it took enough width to break "chapter one
     is free" across two lines, and a two-line pill reads as a paragraph
     that has been given a background by mistake */
  margin:0; flex:0 0 auto; white-space:nowrap;
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--on-teal); background:var(--teal);
  border-radius:100px; padding:7px 14px;
}
.vbk__pill--quiet{
  background:none; color:var(--chevron); padding:7px 0;
}
/* THE PHOTOGRAPH IS A POLAROID.
   Not a styling flourish: a print laid on a page is what this section is
   describing, and a bare square inset in the margin read as a UI thumbnail.
   The frame is the print — even margins on three sides and a deep one at
   the foot, which is the whole of what makes the shape recognisable.

   Tilted a little, because a print set perfectly square to the page reads
   as placed by software. Two degrees is enough to read as laid down by
   hand; more starts performing. No shadow, so the frame carries a hairline
   instead — on this ground a white card with no edge would simply vanish. */
.vbk__polaroid{
  flex:0 0 clamp(96px,14vw,148px);
  /* A tilted box is wider than its layout box: 2.1 degrees on a print about
     130px tall adds roughly 2.4px each side, which is exactly how far it was
     hanging past the page's own padding on a phone. The margin is that
     overhang, given back. */
  margin:0 3px; padding:8px 8px 0;
  background:var(--white);
  border:var(--seam) solid var(--seam-ink);
  border-radius:2px;
  transform:rotate(-2.1deg);
  transform-origin:center;
}
.vbk__shot{ margin:0; border-radius:0; border-style:dashed; }
.vbk__polaroid figcaption{
  /* the deep foot of a polaroid, and the only place a caption belongs on
     one: written on the frame, not over the picture */
  padding:9px 2px 11px;
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-style:italic; font-size:var(--t-meta); line-height:1.2;
  color:var(--muted); text-align:center;
}

.vbk__body{ margin-top:var(--s-6); }
.vbk__title{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial-mid);
  font-size:clamp(1.5rem,1.1rem + 1.5vw,2.5rem);
  line-height:1.12; letter-spacing:var(--tr-display);
  color:var(--ink); margin:0; max-width:15ch;
}
.vbk__out{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-style:italic; font-size:var(--t-body);
  color:var(--muted); margin:var(--s-2) 0 0;
}
/* the kept line, set as the quotation it is */
.vbk__quote{ margin:var(--s-5) 0 0; padding-left:var(--s-4); border-left:2px solid var(--ink); }
.vbk__quote blockquote{
  margin:0;
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-card);
  line-height:1.42; letter-spacing:var(--tr-display); color:var(--ink);
}
.vbk__quote figcaption{
  margin-top:var(--s-2);
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase; color:var(--chevron);
}
/* A line not yet written is ruled space waiting for it. An empty box reads
   as content that failed to load; two rules read as a page still to fill. */
.vbk__quote--blank{ border-left-color:var(--seam-ink); }
.vbk__quote--blank blockquote{ display:flex; flex-direction:column; gap:var(--s-4); padding-block:var(--s-2); }
.vbk__rule{ display:block; height:var(--seam); background:var(--seam-ink); }
.vbk__rule:last-child{ width:58%; }

/* NO SETTLING ANIMATION ON THE ARRIVING PAGE.

   There was one: the words rose and resolved once the leaf landed. It was
   wrong, and wrong in a specific way — fading a whole page of text up from
   zero is the same gesture a page makes when it is LOADING, so a turn that
   had already completed looked like it was fetching something. The content
   is already painted on the back of the leaf and arrives with it; anything
   further is the page telling you again what it has just shown you. */

/* ---- the turning leaf ----
   Hinged on the spine, carrying the page being left on its front face and
   the page being arrived at on its back — so there is real content on both
   sides of the fold rather than a blank sheet wiping across. */
.vbk__leaf{
  /* INSET BY THE BOOK'S OWN BORDER.
     The leaf is positioned against .vbk, but the pages it stands in for live
     inside .vbk__book, whose 1px border insets its content box. Aligned to
     the border box the leaf sat one pixel out — 160.5/200/552x602 against the
     real 161.5/201/551x600 — so every word on the page, the numeral
     included, moved a pixel the instant the leaf was removed. That single
     pixel is what reads as the page re-rendering when the turn ends. */
  /* No inset any more. These used to sit outside .vbk__book and had to be
     pulled in by its 1px border to line up with the pages; inside the frame
     they are already in its padding box, so the same inset counted the
     border twice and put the leaf a pixel off again. */
  position:absolute;
  top:0; bottom:0; left:50%; right:0;
  transform-origin:left center;
  transform-style:preserve-3d;
  pointer-events:none;
  visibility:hidden;
}
.vbk[data-turn] .vbk__leaf{
  visibility:visible;
  transition:transform var(--dur-cinematic) var(--ease-paper);
}
.vbk[data-turn="next"] .vbk__leaf{ transform:rotateY(-180deg); }
.vbk[data-turn="prev"] .vbk__leaf{
  left:0; right:50%; transform-origin:right center; transform:rotateY(180deg);
}
/* armed: placed for the turn, in the frame before it starts */
.vbk[data-arm="prev"] .vbk__leaf{ left:0; right:50%; transform-origin:right center; }
.vbk[data-arm] .vbk__leaf{ visibility:visible; transition:none; transform:none; }
.vbk__face{
  position:absolute; inset:0;
  backface-visibility:hidden; -webkit-backface-visibility:hidden;
  /* no background and no corner of its own — see .vbk__sheet below */
}
.vbk__face--back{ transform:rotateY(180deg); }
/* THE UNDER PANEL — the half the leaf is lifting out of, carrying the page
   revealed beneath it. Same box as the leaf and the same corner, one layer
   down, and only while a turn is running. Without it the spread had to be
   swapped at the START of the turn, which changed the OTHER half of the
   book in plain sight the moment you clicked. */
.vbk__under{
  position:absolute;
  top:0; bottom:0; left:50%; right:0;
  visibility:hidden; pointer-events:none;
}
.vbk[data-turn] .vbk__under,
.vbk[data-arm] .vbk__under{ visibility:visible; }
.vbk[data-turn="prev"] .vbk__under,
.vbk[data-arm="prev"] .vbk__under{ left:0; right:50%; }
/* THE SHEET is the paper. It is a plain element with no transform of its
   own, so it is painted into whichever face or panel contains it rather
   than being composited separately — which means its corner survives the
   turn. The face above it is now only a hinge and a backface test. */
.vbk__sheet{
  position:absolute; inset:0;
  background:var(--white);
  overflow:hidden;
  /* CLIP-PATH, NOT BORDER-RADIUS.
     border-radius here is a paint-time clip on the element's own box, and
     when this subtree is rasterised for the leaf's 3D transform that clip is
     discarded: the corner is round while the page lies flat and square the
     moment it starts turning. Measured — flat, the corner cuts in at 6px,
     which is exactly a 20px radius; rotated 34 degrees, the corner point is
     inside the sheet again.

     clip-path is applied in the element's own coordinate space BEFORE the
     transform, so the clipped shape is what gets rasterised and it survives
     the rotation. Same corner, same value, kept for the whole turn.

     border-radius stays alongside it so the element still reports its corner
     to anything that reads computed style. */
  display:grid; grid-template-columns:1fr;
}
.vbk__sheet .vbk__page{ position:relative; inset:auto; border-radius:0; }

/* THE PAGE INSIDE A FACE CARRIES THE CORNER TOO.
   The face has the radius and overflow:hidden, which ought to be enough —
   and is not. It sits inside a transform-style:preserve-3d leaf, where
   clipping a 3D-transformed subtree to a rounded box is not reliable, and
   the cloned page inside paints its own ruled background across the whole
   of its own square box. So the turning page had square corners while the
   book it came out of had round ones, and only matched again once the leaf
   went away — which is what read as the page re-rendering at the end.

   The child is rounded itself now, so nothing depends on the parent
   clipping it. Same value, same side, and the same swap for `prev`. */
.vbk__face .vbk__page,
.vbk__under .vbk__page{ position:absolute; inset:0; }
/* THE PAGE FLYING AWAY CARRIES NO RULING.
   A leaf at 40 degrees is foreshortened, so its rules sit at a different
   pitch from the rules on the page it is uncovering — two sets of lines
   disagreeing along the leaf's edge for the length of the turn. It is
   correct perspective and it reads as a mistake. The face that LANDS keeps
   its ruling, because it becomes a page that has it; the one that leaves
   does not need it, because it is leaving. */
.vbk__face--front .vbk__page{ background-image:none; }

/* ---- turning it ---- */
.vbk__controls{
  display:flex; align-items:center; justify-content:center; gap:var(--s-4);
  margin-top:var(--s-5);
}
.vbk__turn{
  width:48px; height:48px; display:grid; place-items:center;
  padding:0; border:var(--seam) solid var(--seam-ink); background:none;
  border-radius:100px; color:var(--ink); cursor:pointer;
}
.vbk__turn:hover:not(:disabled){ border-color:var(--ink); }
.vbk__turn:disabled{ opacity:.32; cursor:default; }
.vbk__turn i{ font-size:20px; }
.vbk__turn:focus-visible{ outline:2px solid var(--ink); outline-offset:3px; }
.vbk__where{
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--muted); margin:0; min-width:14ch; text-align:center;
  font-variant-numeric:tabular-nums;
}
/* the pages are the control: the right half turns forward, the left back */
.js .vbk__book[data-live]{ cursor:pointer; }

/* ---- ON A PHONE IT IS A PAD, NOT A BOOK ----
   A spread needs two facing pages and a spine, and a phone has room for
   neither — so below 820px the same ten become a BUNDLE of sheets with the
   top one taken off at a time.

   This also retires the leaf here. The 3D turn was the source of every
   phone bug in this section: a rotated subtree is rasterised as a rectangle,
   which cost the corners, and the whole apparatus of faces, under panel and
   cloned pages existed only to make one sheet look like two. Nothing rotates
   now. A sheet slides off the top of the pad and the next one is already
   underneath, which is what the gesture actually is.

   Depth is carried by offset and by each sheet having its own edge — the
   book's border and clip come off here, because a pad that clips its own
   stack has nothing to show for being a stack. */
@media (max-width:820px){
  .vbk{ perspective:none; }
  .vbk__book{
    border:0; background:none; overflow:visible;
    /* room beneath for the two sheets showing under the top one */
    padding-bottom:22px;
  }
  /* every sheet is its own piece of paper now */
  .vbk__spread{
    grid-template-columns:1fr;
    min-height:0;
    background:var(--white);
    border:var(--seam) solid var(--seam-ink);
    border-radius:var(--r-block);
    overflow:hidden;
    transform-origin:50% 0;
    transition:transform var(--dur-base) var(--ease), opacity var(--dur-base) var(--ease);
  }
  /* the top sheet, and the two showing under it */
  .vbk__spread[data-depth]{ opacity:1; visibility:visible; }
  .vbk__spread[data-depth="0"]{ z-index:3; transform:none; }
  /* scaleX, not scale. Scaling both axes from a top origin pulls the sheet's
     BOTTOM edge upward — 2.8% of a 565px sheet is 16px, against an 11px
     offset — so the sheets underneath ended up shorter than the one on top
     and the pad showed no stack at all. Narrowing them horizontally is what
     reads as "underneath"; the vertical offset then has nothing fighting it. */
  .vbk__spread[data-depth="1"]{ z-index:2; transform:translateY(10px) scaleX(.955); }
  .vbk__spread[data-depth="2"]{ z-index:1; transform:translateY(20px) scaleX(.91); }
  /* anything deeper stays out of the way entirely */
  .vbk__spread:not([data-depth]){ opacity:0; visibility:hidden; }

  /* TAKEN OFF THE TOP. Up and away, tipping as it goes, the way a sheet
     lifts off a pad rather than sliding out of a wallet. */
  .vbk__spread[data-off]{
    z-index:4;
    transform:translate(-14%,-9%) rotate(-5.5deg) scale(1.01);
    opacity:0;
    pointer-events:none;
  }
  /* and coming back: the same move, run backwards */
  .vbk__spread[data-back]{
    transition:none;
    transform:translate(-14%,-9%) rotate(-5.5deg) scale(1.01);
    opacity:0;
  }

  /* the leaf and its under panel are desktop machinery */
  .vbk__leaf, .vbk__under{ display:none; }

  /* the pages inside a sheet */
  .vbk__page{ padding:var(--s-3); }
  .vbk__page--left{
    padding-bottom:0; border-right:0;
    flex-direction:row; align-items:baseline; gap:var(--s-3);
  }
  .vbk__page--left::after,
  .vbk__page--right::after{ display:none; }
  .vbk__numeral{ font-size:clamp(2.5rem,13vw,3.5rem); margin:0; }
  .vbk__eyebrow{ display:none; }
  .vbk__page--right{ padding-left:var(--s-3); padding-top:var(--s-4); }
  .vbk__body{ margin-top:var(--s-5); }
  .vbk__title{ max-width:none; }
  .vbk__top{ gap:var(--s-3); flex-wrap:wrap; }
  .vbk__pill{ white-space:normal; flex:0 1 auto; min-width:0; }
  .vbk__polaroid{ flex:0 0 clamp(84px,24vw,110px); }

  /* "take the top one off" is the whole interaction, so it gets a word */
  .vbk__hint{
    display:block; margin-top:var(--s-5); text-align:center;
    font-size:var(--t-label); font-weight:var(--w-bold);
    letter-spacing:var(--tr-label); text-transform:uppercase; color:var(--chevron);
  }
}
@media (min-width:821px){
  .vbk__hint{ display:none; }
}
@media (max-width:820px) and (prefers-reduced-motion:reduce){
  .vbk__spread{ transition:none; }
  .vbk__spread[data-off]{ transform:none; }
}
@media (prefers-reduced-motion:reduce){
  .vbk[data-turn] .vbk__leaf,
  .vbk[data-arm] .vbk__leaf{ transition:none; visibility:hidden; }
}


/* ============================================================
   POSTER — typography as the composition
   The recording comparison found Prevow's display type sitting at
   roughly 15% of the frame against the reference's ~33%, which is
   most of why the pages read as a document rather than a website.

   This is the corrective, applied to a handful of phrases only.
   Tighter leading than the display step, because at this size the
   default leading opens the block up and loses it.
   ============================================================ */
.poster{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-poster);
  line-height:.95; letter-spacing:-.035em; text-wrap:balance;
}
.poster .ln{ display:block; overflow:hidden; padding-block:.16em; margin-block:-.16em; }
.poster .ln > span{ display:block; }
.js .poster .ln > span{ transform:translateY(108%); transition:transform var(--dur-reveal) var(--ease); }
.js .poster.is-in .ln > span{ transform:translateY(0); }
.js .poster .ln:nth-child(2) > span{ transition-delay:110ms; }
.js .poster .ln:nth-child(3) > span{ transition-delay:220ms; }
.js .poster .ln:nth-child(4) > span{ transition-delay:330ms; }

/* a poster band gets its own air and its own ground */
.stage{ padding-block:var(--sec-air); }
.stage--cloud{ background:var(--cloud); }
.stage--ink{ background:var(--ink); color:var(--white); }
.stage--ink .quiet{ color:var(--on-navy); }
.stage__after{ margin-top:var(--s-8); max-width:44ch; color:var(--muted); font-size:var(--t-body); }
.stage--ink .stage__after{ color:var(--on-navy); }

@media (max-width:700px){
  .stage{ padding-block:var(--sec-loose); }
  .poster{ line-height:1; letter-spacing:-.03em; }
}

/* ============================================================
   THE OPENING — two crops of one photograph meeting
   The reference's strongest move, rebuilt on Prevow's material.

   Measured off the recording at 3fps: the two panels are separate
   small shapes at 21.0s, still apart at 21.7s, nearly touching at
   22.3s, joined at 22.7s, and full bleed at 23.3s — about 4.3
   seconds of scrolling for one image to open, with the corner
   radius shrinking to zero on the way. It is slow on purpose; that
   is what makes it read as expensive rather than as a reveal.

   Here the two halves are the SAME photograph, so when they meet
   they become one continuous picture rather than two pictures
   side by side. Nothing animates width or height — the panels are
   full-size throughout and clip-path does all the work, so the
   whole thing is composited and never reflows.
   ============================================================ */
.grow{ position:relative; }
.grow__scroll{ height:360vh; }
.grow__stage{
  position:sticky; top:0; height:100svh; overflow:hidden;
  background:var(--white);
  display:grid; place-items:center;
}
.grow__panes{ position:absolute; inset:0; }
.grow__pane{ position:absolute; inset:0; overflow:hidden; }
.grow__pane img{ width:100%; height:100%; object-fit:cover; }

/* The two crops start as small panels inset from opposite corners and
   grow toward each other. `--p` is written by js/route.js, 0 -> 1. */
.grow__pane--a{
  clip-path:inset(
    calc((1 - var(--p,0)) * 42%) calc(50% + (1 - var(--p,0)) * 8%) calc((1 - var(--p,0)) * 42%) calc((1 - var(--p,0)) * 8%)
    round calc((1 - var(--p,0)) * var(--r-block)));
}
.grow__pane--b{
  clip-path:inset(
    calc((1 - var(--p,0)) * 42%) calc((1 - var(--p,0)) * 8%) calc((1 - var(--p,0)) * 42%) calc(50% + (1 - var(--p,0)) * 8%)
    round calc((1 - var(--p,0)) * var(--r-block)));
}

/* the phrase lands only once the picture is whole */
.grow__say{
  position:relative; z-index:2; width:100%;
  max-width:var(--page-wide); margin-inline:auto; padding-inline:var(--gutter);
  color:var(--white);
  opacity:0; transform:translateY(14px);
  transition:opacity var(--dur-reveal) var(--ease), transform var(--dur-reveal) var(--ease);
}
.grow[data-landed] .grow__say{ opacity:1; transform:none; }
.grow__say .poster{ max-width:15ch; }
.grow__veil{
  position:absolute; inset:0; background:var(--photo-scrim);
  opacity:0; transition:opacity var(--dur-reveal) var(--ease);
}
.grow[data-landed] .grow__veil{ opacity:1; }

@media (max-width:760px){
  /* a phone gets the simplified vertical version: one crop opening
     from the middle outward, no two-panel meeting */
  .grow__scroll{ height:280vh; }
  .grow__pane--b{ display:none; }
  .grow__pane--a{
    clip-path:inset(calc((1 - var(--p,0)) * 34%) 0 calc((1 - var(--p,0)) * 34%) 0
      round calc((1 - var(--p,0)) * var(--r-block)));
  }
}

@media (prefers-reduced-motion:reduce){
  .grow__scroll{ height:auto; }
  .grow__stage{ position:static; height:auto; aspect-ratio:16/9; }
  .grow__pane--a,.grow__pane--b{ clip-path:none; }
  .grow__pane--b{ display:none; }
  .grow__say{ opacity:1; transform:none; }
  .grow__veil{ opacity:1; }
}


/* ---- cost, tightened ----
   Three pills wrapping 2-then-1 read as clutter on a phone, so they stack.
   They were stacked as a RULED list, which was worse: four hairlines to
   separate three short phrases that are already on their own lines. A rule
   earns its place when it divides things that would otherwise run together,
   and stacked labels do not. The lines are gone and the spacing does the
   work they were doing. */
@media (max-width:620px){
  .cost{ display:block; margin-top:var(--s-4); }
  .cost span{
    display:block; border:0; border-radius:0; padding:0;
    color:var(--muted);
  }
  .cost span + span{ margin-top:var(--s-2); }
}
.section--loose:has(.cost){ padding-bottom:var(--sec); }






@media (max-width:560px){
  
  
  
  
}


/* ---- why the ruled paper went ----
   The rules were absolutely positioned from the top of the sheet, which
   includes the question line above the answer, so they landed ACROSS the
   words rather than under them — visible as strikethroughs on a sentence
   that is supposed to be perfectly readable in SHARE. Aligning them to a
   variable-wrap answer is not worth the complexity: the redaction bars
   already carry SEALED on their own, and in PRIVATE the point is that
   nothing remains, which rules would actively contradict. */

/* ============================================================
   CHAPTER ONE, UP CLOSE — restored
   These rules were collateral damage when the old chapter-spine block
   was cut out of this file: the markup on /programme kept using
   .close-up, .beat and .kept-line while their styles went with the
   spine, so the section rendered completely unstyled — the three beats
   ran together with no spacing and the caption sat on top of the kept
   line. That is the clutter.
   ============================================================ */
.close-up{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(var(--s-6),6vw,var(--s-12)); align-items:start;
}
.beat{
  display:grid; grid-template-columns:2.5rem minmax(0,1fr); gap:var(--s-3);
  padding-block:var(--s-4); border-top:var(--seam) solid var(--seam-ink);
}
.beat__i{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); color:var(--muted); font-size:var(--t-section);
}
.beat p{ color:var(--muted); font-size:var(--t-small); line-height:1.65; margin:0; }
.beat b{
  display:block; color:var(--ink); font-size:var(--t-section);
  font-weight:var(--w-bold); letter-spacing:var(--tr-section); margin-bottom:5px;
}
.kept-line{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-title); line-height:1.3;
  letter-spacing:var(--tr-display); text-wrap:balance;
  padding-top:var(--s-5); border-top:var(--seam) solid var(--ink); margin:0;
}
.kept-line + p{ margin-top:var(--s-4); color:var(--muted); font-size:var(--t-meta); }
/* the poster above the beats needs room of its own; it has no bottom margin
   by default because most posters sit alone in a band */
.close-up .poster{ margin-bottom:var(--s-6); }
@media (max-width:900px){
  .close-up{ grid-template-columns:1fr; gap:var(--s-6); }
  .close-up .poster{ margin-bottom:var(--s-5); }
}


/* ============================================================
   THE QUESTIONS HUB  (/questions)
   The ten chapters as ten question sets. Built from the same ruled
   material as .lines and .steps — a numbered gutter, a hairline between
   entries, no cards and no boxes.
   ============================================================ */
.qch-list{ margin-top:var(--s-8); border-top:var(--seam) solid var(--seam-ink); }
.qch{
  display:grid; grid-template-columns:3.5rem minmax(0,1fr); gap:var(--s-4);
  padding-block:var(--s-6);
  border-bottom:var(--seam) solid var(--seam-ink);
  align-items:start;
}
.qch__n{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-row);
  color:var(--chevron); font-variant-numeric:tabular-nums; margin:0;
}
.qch__name{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-title);
  letter-spacing:var(--tr-display); line-height:1.2; margin:0 0 var(--s-4);
}
.qch__name em{ font-style:normal; color:var(--muted); }
/* Each chapter is a page now, and the heading is the way in. The whole
   heading is the target rather than a "read more" bolted underneath it:
   the name is already the thing being pointed at, so it should be the
   thing you click. The em keeps its muted colour through `inherit`, and
   the arrow is the affordance that says this row goes somewhere. */
.qch__go{ color:inherit; text-decoration:none; }
.qch__go:hover{
  text-decoration:underline; text-decoration-thickness:1.5px; text-underline-offset:6px;
}
.qch__go:focus-visible{ outline:2px solid var(--ink); outline-offset:4px; }
/* No whitespace between the name and this arrow in the markup, so there is
   no break opportunity and it cannot wrap onto a line of its own — at 360px
   four of the ten did exactly that, leaving a stray glyph under the heading.
   The gap is margin, not a space character, for that reason. */
.qch__go i{
  font-size:.62em; color:var(--chevron); margin-left:.34em;
  transition:transform var(--dur-quick) var(--ease);
  display:inline-block; vertical-align:baseline;
}
.qch__go:hover i{ transform:translateX(4px); }
@media (prefers-reduced-motion:reduce){
  .qch__go i{ transition:none; }
  .qch__go:hover i{ transform:none; }
}
.qch__list{ list-style:none; margin:0; padding:0; }
.qch__list li{
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial); font-size:var(--t-card); line-height:1.45;
  letter-spacing:var(--tr-display);
  padding-left:var(--s-4); position:relative;
}
.qch__list li + li{ margin-top:var(--s-3); }
/* a hanging rule rather than a bullet — the same hairline vocabulary */
.qch__list li::before{
  content:""; position:absolute; left:0; top:.72em;
  width:var(--s-3); height:var(--seam); background:var(--chevron);
}
@media (max-width:760px){
  .qch{ grid-template-columns:2.4rem minmax(0,1fr); gap:var(--s-3); padding-block:var(--s-5); }
  .qch__name{ font-size:var(--t-card); }
  .qch__list li{ font-size:var(--t-body); padding-left:var(--s-3); }
}


/* ---- two surface-mismatch contrast fixes (Aug 2026 audit) ----
   --muted is defined in tokens.css as "on white / cloud / teal-pale ONLY".
   Both of these put it on a dark ground, where it measured 3.03:1 against a
   4.5 floor. On ink the palette's answer is --on-navy. */
.stage--ink .lede,
.stage--ink p{ color:var(--on-navy); }
.steps-in span{ color:var(--muted); }


/* ============================================================
   PHOTO PLACEHOLDER  —  development only
   A slot that is deliberately, legibly unfinished. It holds the exact
   aspect ratio the final photograph will occupy at each width, so the
   layout below it is already production-accurate and swapping the image
   in causes no reflow.

   It is not a grey box and not decoration: it states the role, the
   subject and the crop, so the brief travels with the slot. Remove the
   whole element when the photograph lands — see CONTENT-ASSET-TODO.md.
   ============================================================ */
.ph-slot{
  position:relative;
  aspect-ratio:var(--ph-desktop, 16/10);
  background:var(--cloud);
  border:1px dashed var(--chevron);
  border-radius:var(--r-block);
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:clamp(var(--s-3),2.4vw,var(--s-5));
  overflow:hidden;
}
/* Two hairlines mark the focal point. Solid backgrounds on pseudo-elements,
   not a gradient — rule 3 forbids gradients and the gate caught the first
   attempt at exactly this. */
.ph-slot::before,
.ph-slot::after{ content:""; position:absolute; background:var(--chevron); opacity:.3; pointer-events:none; }
.ph-slot::before{ top:0; bottom:0; width:1px; left:var(--ph-focal-x,50%); }
.ph-slot::after{ left:0; right:0; height:1px; top:var(--ph-focal-y,50%); }
.ph-slot__k{
  position:relative; z-index:1;
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--muted); margin:0 0 6px;
}
.ph-slot__body{
  position:relative; z-index:1;
  font-size:var(--t-meta); color:var(--muted); margin:0; max-width:46ch;
}
.ph-slot__meta{
  position:relative; z-index:1;
  /* --muted, not --chevron: chevron is 3.18:1 and this is label-size text.
     The placeholder is temporary but it still has to pass AA while it ships. */
  font-size:var(--t-label); color:var(--muted); margin:8px 0 0;
  font-variant-numeric:tabular-nums;
}
/* A brief, not a grey box. A placeholder that says only "photo goes here"
   invites whatever photograph is nearest to hand, which is how a page ends
   up with pictures that decorate it rather than argue for it. So each slot
   carries the JOB the frame has to do at that point in the page, and the
   list of things that must stay out of it — on this page especially, since
   every stock privacy image (padlock, keyhole, blurred screen) contradicts
   the one promise the copy actually makes. */
.ph-slot__why{
  position:relative; z-index:1;
  font-size:var(--t-meta); color:var(--ink); margin:0 0 8px; max-width:52ch;
}
.ph-slot__no{
  position:relative; z-index:1;
  font-size:var(--t-meta); color:var(--muted); margin:8px 0 0; max-width:52ch;
  padding-top:8px; border-top:var(--seam) solid var(--seam-ink);
}
.ph-slot__no b{ color:var(--ink); font-weight:var(--w-bold); }
/* The slot is sized by the ratio the final photograph will occupy, but a
   brief is longer than "photo goes here" — so the ratio has to be a FLOOR,
   not a fixed height.

   height:auto does not do it. aspect-ratio against a definite width gives a
   definite height, and this box is justify-content:flex-end, so content that
   does not fit overflows UPWARD and overflow:hidden eats it. That failure is
   silent in both directions a check would normally look: scrollHeight equals
   clientHeight because top overflow is not counted, and the last line still
   sits comfortably inside the bottom edge. Measured at 375px, the brief was
   551px of content in a 409px box with its first line 197px above the top —
   the kicker and half the reasoning were simply gone.

   min-height:fit-content does not fix it either — measured, all three of
   fit-content/max-content/min-content returned the same 409px, because for
   a flex container the intrinsic block keywords resolve against the
   ratio-derived size rather than growing past it. Dropping the ratio gave
   the true 631px.

   So: the content sits at the TOP, and the ratio is dropped on a phone.
   Top-aligned means any future overflow clips at the bottom edge, where it
   is obvious, instead of disappearing off the top where nothing reports it.
   On desktop the empty space below the brief is the photograph's footprint,
   which is the thing the ratio was there to show. On a phone the box is
   content-height and the ratio is stated in the meta line instead — a
   placeholder that cannot be read is worth less than one that previews a
   crop. */
.ph-slot{ justify-content:flex-start; }
@media (max-width:760px){
  .ph-slot{ aspect-ratio:auto; }
}
@media (prefers-reduced-motion:reduce){
  .ph-slot{ transition:none; }
}

/* Eleven screens of legal text on a phone, and the contents list is at the
   very top where you can no longer reach it. One static link at the end —
   no scroll-spy, no floating button, nothing animated over legal copy. */
.backtotop{ margin-top:var(--sec-tight); padding-top:var(--s-4);
  border-top:var(--seam) solid var(--seam-ink); }

/* ============================================================
   THE CHAPTER PAGER
   Two links. It should look like two links.

   The first attempt was the .routes component — the 404 page's
   three-column route table — which given two rows of two words
   became three tall blocks of mostly air. The second attempt
   over-corrected: it borrowed the rail card's grammar wholesale,
   number over hairline over name, and ended up 261px tall with
   five horizontal rules and a vertical seam for two words. On the
   card that hairline divides a composition with a photograph in
   it. With no photograph it divides nothing, and a line that
   separates nothing is decoration.

   So: one rule, at the top, where the pager parts from the page.
   The number joins the direction on the label line instead of
   claiming a row of its own, and left-against-right does the work
   the centre seam was doing. Two lines of type a side, ~105px.
   ============================================================ */
.chnav{
  display:grid; grid-template-columns:1fr 1fr; gap:var(--s-4);
  margin-top:var(--sec); padding-top:var(--s-5);
  border-top:var(--seam) solid var(--seam-ink);
}
.chnav__side{
  min-width:0; display:block;
  color:inherit; text-decoration:none;
}
.chnav__side--prev{ grid-column:1; }
.chnav__side--next{ grid-column:2; text-align:right; }
.chnav__dir{
  display:flex; align-items:center; gap:8px;
  font-size:var(--t-label); font-weight:var(--w-bold);
  letter-spacing:var(--tr-label); text-transform:uppercase;
  color:var(--muted);
}
.chnav__side--next .chnav__dir{ justify-content:flex-end; }
.chnav__dir i{ font-size:15px; transition:transform var(--dur-quick) var(--ease); }
.chnav__side--prev:hover .chnav__dir i{ transform:translateX(-4px); }
.chnav__side--next:hover .chnav__dir i{ transform:translateX(4px); }
.chnav__name{
  display:block; margin-top:var(--s-2);
  font-family:var(--font-display); font-variation-settings:var(--fv-display);
  font-weight:var(--w-editorial-mid);
  font-size:clamp(1.5rem,1.35rem + 0.6vw,2rem);
  letter-spacing:var(--tr-display); line-height:1.1;
}
.chnav__side:hover .chnav__name{
  text-decoration:underline; text-decoration-thickness:1.5px; text-underline-offset:5px;
}
.chnav__side:focus-visible{ outline:2px solid var(--ink); outline-offset:4px; }

/* `.wrap > p` caps every paragraph at 46ch, which is right for prose and
   wrong for this: a centred link inside a 566px box sits 269px left of the
   middle of the page, which reads as a stray alignment rather than a centre.
   Exempted by specificity — .wrap > .chnav__all (0,2,0) beats .wrap > p
   (0,1,1) — rather than by loosening the measure rule for everything. */
.wrap > .chnav__all{
  max-width:none; margin-top:var(--s-5); text-align:center;
}

/* THE TWO SIDES STAY SIDE BY SIDE.
   They used to stack on a phone, which cost the one thing the pager is for:
   back and forward reading as opposite directions. Stacked, "previous" sat
   above "next" and both pointed left, so the only thing telling them apart
   was the word.

   They keep their columns at every width. What gives instead is the type —
   two names across 375px is about 150px each, and the display size set for
   a 550px column would break "The first year" across three lines there. */
@media (max-width:700px){
  .chnav{ gap:var(--s-3); }
  .chnav__side{ padding:var(--s-4) 0 var(--s-5); }
  .chnav__side--prev{ padding-right:var(--s-2); }
  .chnav__side--next{ padding-left:var(--s-2); }
  .chnav__name{ font-size:clamp(1.05rem,4.6vw,1.35rem); line-height:1.15; }
  .chnav__dir{ font-size:10px; letter-spacing:.08em; gap:5px; }
  .chnav__dir i{ font-size:13px; }
  /* the seam between them is what makes two columns read as a pair */
  .chnav__side + .chnav__side::before{ top:var(--s-4); bottom:var(--s-5); }
}
/* Narrower still, the chapter number is what goes: "Previous" and "Next"
   carry the direction on their own, and the name underneath says which. */
@media (max-width:400px){
  .chnav__dir .chnav__of{ display:none; }
}
@media (prefers-reduced-motion:reduce){
  .chnav__dir i{ transition:none; }
  .chnav__side--prev:hover .chnav__dir i,
  .chnav__side--next:hover .chnav__dir i{ transform:none; }
}

/* ============================================================
   THE CHAPTER MASTHEAD
   The chapter opened as a white page of type with the photograph
   sitting underneath it as a separate band — two things about the
   same subject, introduced one after the other. The photograph is
   not an illustration of the chapter, it IS the chapter's register,
   so the words belong on it.

   Same construction as the homepage hero, which cannot simply be
   reused because it lives in home.css and these pages load route.css:
   a picture, a scrim, and the type on top of both. It runs under the
   navigation — hence `has-hero` on the body and data-under="photo" on
   the section, which is what turns the bar white while it is under it.

   The type sits at the BOTTOM. The crop of these ten frames puts its
   subject in the middle, and a headline over the middle of the frame
   covers the thing being photographed.
   ============================================================ */
.chhead{ position:relative; }
.chhead__frame{
  position:relative; overflow:hidden;
  display:grid; align-content:end;
  min-height:clamp(440px, 64vh, 660px);
}
.chhead__img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; object-position:50% 46%;
}
/* The scrim is heavier here than the hero's. The hero photographs are
   architectural and dark; these ten are kitchen tables and daylight, and
   the lede is small text that has to hold 4.5:1 against the brightest
   pixel behind it, not just look legible on the average one. */
.chhead__veil{
  position:absolute; inset:0;
  background:rgba(11,31,58,.74);
}
.chhead__inner{
  position:relative; z-index:2;
  padding-top:calc(var(--nav-h) + var(--s-6));
  padding-bottom:var(--s-7);
  color:var(--white);
}
.chhead .meta{ color:var(--white); opacity:.78; }
.chhead h1{ color:var(--white); max-width:16ch; }
.chhead h1 em{ font-style:normal; color:rgba(255,255,255,.74); }
.chhead .lede{ color:var(--white); opacity:.94; max-width:48ch; }
.chhead :focus-visible{ outline-color:var(--white); }

/* The reset zeroes paragraph margins and every component sets its own
   rhythm — .legal p takes s-3, .lines__note takes s-4. The chapter body
   was written with unclassed <p>, so it took nothing: the heading butted
   straight against the first paragraph and the two paragraphs ran together
   as one undifferentiated block. */
.chbody h2{ margin-bottom:var(--s-4); }
.chbody p + p{ margin-top:var(--s-4); }

@media (max-width:700px){
  .chhead__frame{ min-height:clamp(420px, 78vh, 560px); }
  .chhead__inner{
    padding-top:calc(var(--nav-h) + var(--s-5));
    padding-bottom:var(--s-6);
  }
  .chhead h1{ max-width:none; }
}
