/* PANIM — site.css
   ============================================================================
   DIRECTION B — "The Plate" (2026-08-27, author-directed rebuild)

   The previous design was built as a premium landing page: centred hero, stacked
   full-width sections over full-bleed photography, gold-on-black, one display
   serif at eight sizes. That is the reference class for a product launch, not
   for a book, and it read as generic because it was.

   This rebuild uses the reference class the work actually belongs to — literary
   and art-book publishing. Three rules govern everything below:

     1. NOTHING IS CENTRED except things that are genuinely symmetrical objects.
        Text sits in a named column range on a 12-column grid, with the outer
        column left open for the apparatus (chapter number, verse reference,
        thread notes, plate captions). Asymmetry is the structure, not a flourish.

     2. A PHOTOGRAPH IS NEVER A BACKDROP. Type never sits on top of an image.
        Plates get the full measure of the page to themselves and the words land
        on paper underneath. This is what makes the photography look expensive:
        nothing competes with it.

     3. NO DECORATION THAT PRETENDS TO BE MATERIAL. No gradient text, no gold, no
        glow, no glass, no bevel. Hierarchy comes from size, weight, position and
        air. If a rule can do the job, a rule does the job.

   The dawn arc survives, but inverted: it is now carried by PAPER TEMPERATURE
   and accent rather than by black turning to cream. The book opens on a cool,
   almost grey stock and warms, page by page, until chapter X is a bright warm
   white. The Listening Room stays dark — it is a phone on a nightstand, and that
   is a different object with a different job (see room.css).
   ============================================================================ */

:root {
  /* ---- type -------------------------------------------------------------
     Literata for everything read: a face drawn for long-form reading on screens,
     with an italic that is a genuine text italic. Archivo for apparatus only:
     labels, captions, numbers, chrome. Frank Ruhl Libre for Hebrew, which is the
     classic Hebrew book face and the only one here that can carry פָּנִים at
     display size without looking like a fallback.

     LITERATA REPLACED FRAUNCES, 2026-08-27 — the italic. Fraunces' italic at text
     optical sizes is much darker in colour than its own roman, so every <em> in
     running prose read as bold italic. Measured, not assumed: the same line
     rendered with the weight stated explicitly, and with no font-variation-settings
     at all, came out identical. The weight was never the problem. See the note at
     the top of fonts/fonts.css, and the old build in fonts/archive/. */
  --serif: 'Literata', Georgia, 'Times New Roman', serif;
  --ui: 'Archivo', system-ui, -apple-system, 'Helvetica Neue', sans-serif;
  --heb: 'Frank Ruhl Libre', 'Literata', Georgia, serif;

  /* Setting font-variation-settings disables font-optical-sizing:auto, so opsz has
     to be stated by hand everywhere it matters, or every size renders in one cut.
     Literata's axis runs 7–72 (Fraunces' ran to 144, which is why these numbers
     changed with the face — 144 is off the end of this axis and would be clamped).
       text 12 · mid 28 · display 60
     There is no SOFT and no WONK here. Those two tags were in the old Fraunces
     declarations and did nothing at all: that download was cut with `opsz,wght`
     only, so both axes had been instanced out of the files. Check a font's fvar
     before writing an axis name into this file. */
  --lit-normal:  'opsz' 12;
  --lit-mid:     'opsz' 28;
  --lit-display: 'opsz' 60;

  /* 🛑 THE --fr-* ALIASES ARE GONE, 2026-09-07. They existed so that anything still
     written against the Fraunces names kept its optical size through the type swap.
     Nothing says --fr-* any more — the whole sheet is on --lit-*. Do not re-add a
     compatibility layer for a name no rule uses. */

  /* ---- paper + ink ------------------------------------------------------
     Default is chapter I's stock. Per-chapter values are set further down and
     mirrored in js/motion.js, which interpolates between them on scroll. */
  --paper: #F1EDE4;
  --ink: #191510;
  /* Three tiers, all AA against the DARKEST stock and therefore against all ten.
     WCAG AUDIT, 2026-08-28 — #F1EDE4 above is the :root FALLBACK, not the darkest
     stock: js/motion.js overwrites --paper on <html> before first paint, so no
     reader ever actually sees it, and the real darkest rendered stock is chapter
     VIII's #EBE6E1 (measured 0.79692 relative luminance — a hair under even
     chapter II/III). --ink-faint was checked against the fallback (4.51:1 there)
     and shipped believing it cleared AA everywhere; against #EBE6E1 it is 4.25:1,
     a real fail, and it carries real text in the same eleven places the note below
     still describes — verse translations, plate labels, contents meta, apparatus
     captions, most of it 10–11px caps. Darkened three RGB steps to clear 4.5:1
     against #EBE6E1 with margin (4.72:1) without changing its hue. Tiers now run
     15.5 : 6.4 : 4.7 against the fallback, 14.6 : 6.0 : 4.7 against the true
     darkest stock. Anything added to this scale gets checked against #EBE6E1
     (chapter VIII), not #F1EDE4 and not the warm stocks where everything passes. */
  --ink-soft: #5C5449;
  --ink-faint: #6B6459;
  --rule: rgba(25, 21, 16, .14);
  --rule-strong: rgba(25, 21, 16, .28);
  /* --control-edge: THE LINE THAT DRAWS A CONTROL, and it is a different job from
     --rule-strong even though it used to be the same value.
     WCAG 2.2 SC 1.4.11 wants 3:1 for the visual boundary of a control. --rule-strong
     measures 1.84:1 against the darkest paper stock (#EBE6E1) — a real fail on every
     button on the site, and the buttons have no fill, so that hairline is the only
     thing drawing them.
     The author asked whether it could be solved stylistically instead of by darkening.
     It cannot: at 1px there is no arrangement of a .28 line that reaches 3:1, the
     alpha has to go up. What CAN be done stylistically is change what the darker line
     READS as — .btn now carries a 3% ink wash, so the control is a soft filled chip
     with an edge rather than an empty box drawn in a harder outline. Measured at
     alpha .50: 3.25:1 against the darkest paper and 3.08:1 against the button's own
     wash, so both edges of the line clear the floor.
     CONTAINERS KEEP --rule-strong. A card, a sheet and a dialog are not controls;
     1.4.11 does not apply to them and darkening their frames would coarsen the page
     for nothing. Only things you can press use this token. */
  --control-edge: rgba(25, 21, 16, .50);
  --control-wash: rgba(25, 21, 16, .03);
  --accent: #32638F;          /* night — the default before any section claims the page */

  /* ---- the apparatus scale -----------------------------------------------
     THREE SIZES, 2026-08-28. There were twenty-one distinct sub-1rem sizes in this
     stylesheet and eleven of them rendered at 10px or under on a phone — measured,
     not estimated, at a 402px viewport. Small type is right for apparatus; twenty-one
     sizes of it is not a system, it is an accident. Everything that is a label, a
     caption, a numeral or a reference now takes one of these three and nothing else.
     The floor is deliberate and it is a real floor: --ap-sm is 10.24px at a 16px
     root, so nothing on the site renders under 10px any more — it was eleven
     declarations before. --ap-sm is only ever used for tracked-out uppercase, which
     reads larger than its size. Anything carrying a sentence takes --ap-md or --ap-lg.

     ⚠️ Literata has NO smcp table — checked with fontTools against fonts/l04.woff2,
     which lists only ccmp/dnum/frac/liga/locl/numr/pnum/rvrn/tnum. So
     `font-variant-caps: small-caps` would be SYNTHESISED: scaled-down capitals with
     the wrong stem weight. Everywhere this file wants small caps it uses uppercase
     with tracking instead, which is honest and is what a printed apparatus does. */
  /* 🔴 THE WHOLE SCALE WENT UP ONE STEP, 2026-09-07. The author: "look at the text
     and find the smallest ... do we need to make any text bigger."
     🛑 AND THE ANSWER WAS IN THE COUNT, NOT IN ANY ONE LABEL. Measured on the live
     page: 10.24px was the computed size of FOURTEEN different components and just
     over three hundred elements — 114 verse-note book names, 51 lexicon chips, 26
     roman-numeral index links, 20 back-matter links, 13 block references, 13 thread
     reference rows, the ten plate credits, the eleven chapter numerals. That is not
     an apparatus floor any more. That is a third of the type on the page.
     ⚠️ AND IT HAD ALREADY BEEN WALKED BACK THREE TIMES ONE COMPONENT AT A TIME —
     the Names index letter ("the abc ... could be bigger its hard to see"), the
     Sources group heading, the player's chapter rail. Three patches to a token that
     was simply too small. This raises the token instead.
     🛑 THE THREE STEPS KEEP THEIR RATIOS so nothing inverts: 1 : 1.11 : 1.25 before,
     1 : 1.11 : 1.25 after. --ap-xl is untouched at 15.2px; it was already right.
     ⚠️ VERIFIED BY MEASUREMENT, not by looking: zero horizontal document overflow at
     320 / 402 / 900 / 1440 / 1920, and the lexicon chip wall, the contents rows, the
     player bar and the back-matter indexes were each re-measured for reflow. */
  --ap-sm: .72rem;   /* tracked uppercase only: numerals, references, labels */
  --ap-md: .80rem;   /* captions, running times, anything with a few words */
  --ap-lg: .90rem;   /* apparatus that carries a sentence */
  /* ⭐ ADDED 2026-09-05, and it is a real addition to the scale rather than a
     number written inline. The author, of .hero-sample-note: "tap any line that
     text is super small too."
     He is right and the scale is what made it small. The three sizes above are
     sized for apparatus that sits BESIDE something — a running time, a plate
     caption, a reference. .hero-sample-note is not that: it is a full sentence on
     the jacket, in the reading column, whose whole job is to tell a stranger the
     book is a play button. At --ap-md that is 11.5px of body copy, which nobody
     reads. This is the size apparatus takes when it is the only thing in its own
     line of the page and is meant to be read rather than consulted. */
  --ap-xl: .95rem;   /* apparatus that IS the line: a full sentence, read not consulted */

  /* ---- measure + rhythm -------------------------------------------------
     62ch is the reading measure. It is NOT the page width: the page is a
     12-column grid and the measure occupies columns 3–9, which is what puts
     the text off-centre and leaves the margin column free. */
  --measure: 62ch;
  --step: clamp(14px, 1.7vw, 26px);   /* grid gutter */
  --edge: clamp(20px, 4vw, 64px);     /* page margin */
  --shell: 1440px;

  /* Raised 2026-08-28 at the author's ask: was clamp(1.06rem, .55vw + .94rem, 1.22rem),
     i.e. 17.0–19.5px. Now 18.2–21.1px. The measure is in `ch`, so it scales with the
     type and the line still breaks at 62 characters — the column does not get longer,
     the letters get bigger, which is the difference between setting a book larger and
     just widening it. 21.1px is the ceiling because 62ch of Literata at that size is
     ~702px and columns 3–9 are 755px at the 1440px shell; past it the measure would
     start wrapping short of its own limit. */
  --body-size: clamp(1.14rem, .5vw + 1.03rem, 1.32rem);
  --body-leading: 1.68;

  --ease: cubic-bezier(.22, .61, .36, 1);
  --dur-fast: 140ms;
  --dur-med: 320ms;
  --dur-slow: 620ms;
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* ⚠️ THIS SMOOTH IS FOR HOPS ONLY, and it is not the whole rule any more.
   It governs anchor navigation AND every programmatic scroll on the page, and the
   book is ~312,000px tall on a phone — so on its own it turned a tap in the
   Contents into a 1.5s flight that rendered every content-visibility section on
   the way past. js/ui.js (wireLongAnchors / PanimScroll) intercepts anything
   longer than three screens and lands it in one frame instead. Deleting this line
   would make the short hops instant too; changing it to `auto` is not the fix. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
/* WCAG 2.4.11 Focus Not Obscured (Minimum) — the running head and the player bar
   are both `position: fixed`, and neither reserved any room in the browser's own
   scroll-into-view math. .section already carries scroll-margin-top for anchor
   jumps, but a Tab press lands on things that are not a .section — a link in
   running prose, a .gloss-term, a .chapter-mark — and without this the browser is
   free to park a freshly focused element flush against the viewport edge, which
   is exactly where the nav (--nav-h, components.css) or the player bar
   (--player-h, player.css) sit on top of it. Reusing both tokens rather than a
   new number so this tracks the bar hiding on idle and the nav's mobile height. */
html { scroll-padding-top: var(--nav-h, 59px); scroll-padding-bottom: var(--player-h, 134px); }
body, h1, h2, h3, p, figure, blockquote, dl, dd { margin: 0; }
img, svg { display: block; max-width: 100%; }
/* <picture> wraps every plate (AVIF srcset, 2026-08-29). It is an inline box by
   default, which would sit between .plate-frame and its image and eat the
   height/object-fit rules; display:contents takes it back out of the layout. */
picture { display: contents; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }
ul { list-style: none; margin: 0; padding: 0; }

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

/* ---------- base ---------- */
html, body { min-height: 100%; }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-variation-settings: var(--lit-normal);
  font-weight: 400;
  font-size: var(--body-size);
  line-height: var(--body-leading);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* background-color is driven per frame by js/motion.js; no transition here */
  transition: color var(--dur-med) var(--ease);
}

.skip-link {
  position: fixed; top: -100px; left: var(--edge); z-index: 1000;
  background: var(--ink); color: var(--paper);
  padding: .7em 1.1em;
  display: inline-flex; align-items: center; min-height: 44px;   /* was 145x35 */
  font-family: var(--ui); font-size: var(--ap-md); font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  transition: top var(--dur-fast) var(--ease);
}
.skip-link:focus { top: 1rem; }

/* ============================================================================
   THE GRID
   Every band of the page is a .row: a 12-column grid inside the page margin.
   Children claim a column range. There is no auto-centring anywhere.

   NOTE ON NAMING: the obvious name for this was .sheet, but index.html already
   uses <div class="sheet" role="dialog"> for the slide-over panels. Two unrelated meanings
   on one class name means a `position: fixed` panel rule silently applies to
   every band of the page. Hence .row.
   ============================================================================ */
.row, .section {
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--edge);
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--step);
}
/* 🛑 THE COLUMN RANGES ARE A VOCABULARY, NOT CLASSES — the utilities were deleted
   2026-09-07 having never once appeared in markup. Every component states its own
   `grid-column` directly, which is why comments across components.css cite these
   ranges by name. Those names still mean this, and nothing more:
       .col-margin  1 / 3     chapter numbers, plate numbers, labels
       .col-text    3 / 9     the reading measure
       .col-aside  10 / 13    thread notes, captions, references
       .col-wide    3 / 12    titles that need more room than text
       .col-full    1 / -1
   Under 900px the grid is six columns and each of those collapses to 1 / 7.
   🛑 .rule-line went the same day, same reason: a 1px grid-wide rule with no markup.
   If a component wants one, it is one declaration in that component. */

@media (max-width: 900px) {
  .row, .section { grid-template-columns: repeat(6, 1fr); }
}

/* ---------- sections ----------
   .section IS the grid container (above), so render.js's <div class="section-inner">
   wrapper is dissolved with display:contents and its children land on the page
   grid directly. That keeps the existing DOM contract intact. */
main { position: relative; }
.section { position: relative; padding-block: clamp(3rem, 7vh, 6rem); scroll-margin-top: 84px; }

/* ============================================================================
   CONTENT-VISIBILITY — 2026-09-04. The one change that makes this book scroll.
   The document is 254,000px of prose in 7,500 nodes, and the browser was laying
   out and style-resolving ALL of it on every global invalidation. The dawn arc is
   a global invalidation: js/motion.js writes --paper on <html> as the paper stock
   lerps, and --paper is inherited, so every one of those writes re-resolved the
   whole book.
   ⭐ MEASURED, not assumed — headless Chrome against this page, 900x800:
        full relayout      0.65ms  ->  0.04ms   (16x)
        one --paper write 35.41ms  ->  3.69ms   (10x)
   35ms is two and a half dropped frames, and the arc changes stock roughly every
   3,000px of scroll, so that was a visible hitch a few times per chapter forever.
   ⚠️ THE HERO IS DELIBERATELY EXCLUDED. It is the LCP element and it is on screen
   at zero scroll; skipping it would cost paint, not save it.
   🛑 contain-intrinsic-size IS MEASURED PER SECTION, AND THAT IS THE WHOLE TRICK.
   A wrong estimate is not a rendering bug, it is a SCROLL bug: the scrollbar lies,
   #ch07 lands in the wrong paragraph, and js/motion.js measures its section table
   against fiction. The two sets below are the real offsetHeight of every section
   at 1440px and at 402px, read off the live page. The `auto` keyword means the
   browser replaces the estimate with the true height the moment a section has
   rendered once, so the fallback only has to be right for the FIRST jump.
   ⚠️ RE-MEASURE THESE WHENEVER THE TEXT CHANGES LENGTH. tools/ has no generator
   for them yet; they were read with document.querySelectorAll('.section[data-ch]')
   and .offsetHeight in each of the two widths. Stale numbers here are silent.
   ============================================================================ */
/* ⚠️ TWO SECTIONS ARE EXCLUDED ON PURPOSE. [data-ch="0"] is the hero — the LCP
   element, on screen at zero scroll, so skipping it costs paint instead of saving
   it. [data-ch="fw"] is the five-words ending, 500px whose whole point is a
   word-by-word reveal driven by an IntersectionObserver in js/motion.js; it is too
   small to be worth skipping and too choreographed to risk. */
.section[data-ch]:not([data-ch="0"]):not([data-ch="fw"]),
#lexicon, #thread, #scripture, #names, #sources {
  content-visibility: auto;
}
.section[data-ch="1"] { contain-intrinsic-size: auto 16100px; }
.section[data-ch="2"] { contain-intrinsic-size: auto 20800px; }
.section[data-ch="3"] { contain-intrinsic-size: auto 19500px; }
.section[data-ch="4"] { contain-intrinsic-size: auto 15500px; }
.section[data-ch="5"] { contain-intrinsic-size: auto 26000px; }
.section[data-ch="6"] { contain-intrinsic-size: auto 20600px; }
.section[data-ch="7"] { contain-intrinsic-size: auto 30100px; }
.section[data-ch="8"] { contain-intrinsic-size: auto 26600px; }
.section[data-ch="9"] { contain-intrinsic-size: auto 24800px; }
.section[data-ch="10"] { contain-intrinsic-size: auto 41300px; }
#lexicon { contain-intrinsic-size: auto 1300px; }
#thread { contain-intrinsic-size: auto 1400px; }
#scripture { contain-intrinsic-size: auto 1700px; }
#names { contain-intrinsic-size: auto 4100px; }
#sources { contain-intrinsic-size: auto 2500px; }
/* THE SAME BOOK IN SPANISH, 2026-09-16. js/spanish-text.js sets lang="es" on each
   chapter it swaps, and the Spanish page is SHORTER than the English — the verse
   notes are hidden in Spanish — by up to 4,000px a chapter on a phone. Measured the
   same way, at 1440px and 402px, with the Spanish on the page. Re-measure these
   with the English ones. */
.section[lang="es"][data-ch="1"] { contain-intrinsic-size: auto 16300px; }
.section[lang="es"][data-ch="2"] { contain-intrinsic-size: auto 20000px; }
.section[lang="es"][data-ch="3"] { contain-intrinsic-size: auto 19500px; }
.section[lang="es"][data-ch="4"] { contain-intrinsic-size: auto 15500px; }
.section[lang="es"][data-ch="5"] { contain-intrinsic-size: auto 25600px; }
.section[lang="es"][data-ch="6"] { contain-intrinsic-size: auto 20100px; }
.section[lang="es"][data-ch="7"] { contain-intrinsic-size: auto 29600px; }
.section[lang="es"][data-ch="8"] { contain-intrinsic-size: auto 25800px; }
.section[lang="es"][data-ch="9"] { contain-intrinsic-size: auto 25100px; }
.section[lang="es"][data-ch="10"] { contain-intrinsic-size: auto 41600px; }

@media (max-width: 900px) {
  .section[data-ch="1"] { contain-intrinsic-size: auto 18700px; }
  .section[data-ch="2"] { contain-intrinsic-size: auto 25800px; }
  .section[data-ch="3"] { contain-intrinsic-size: auto 23400px; }
  .section[data-ch="4"] { contain-intrinsic-size: auto 19200px; }
  .section[data-ch="5"] { contain-intrinsic-size: auto 32000px; }
  .section[data-ch="6"] { contain-intrinsic-size: auto 24600px; }
  .section[data-ch="7"] { contain-intrinsic-size: auto 35800px; }
  .section[data-ch="8"] { contain-intrinsic-size: auto 30800px; }
  .section[data-ch="9"] { contain-intrinsic-size: auto 30100px; }
  .section[data-ch="10"] { contain-intrinsic-size: auto 50000px; }
  #lexicon { contain-intrinsic-size: auto 2000px; }
  #thread { contain-intrinsic-size: auto 1700px; }
  #scripture { contain-intrinsic-size: auto 3600px; }
  #names { contain-intrinsic-size: auto 7400px; }
  #sources { contain-intrinsic-size: auto 2800px; }
  .section[lang="es"][data-ch="1"] { contain-intrinsic-size: auto 18800px; }
  .section[lang="es"][data-ch="2"] { contain-intrinsic-size: auto 22400px; }
  .section[lang="es"][data-ch="3"] { contain-intrinsic-size: auto 22300px; }
  .section[lang="es"][data-ch="4"] { contain-intrinsic-size: auto 18300px; }
  .section[lang="es"][data-ch="5"] { contain-intrinsic-size: auto 29600px; }
  .section[lang="es"][data-ch="6"] { contain-intrinsic-size: auto 22900px; }
  .section[lang="es"][data-ch="7"] { contain-intrinsic-size: auto 33600px; }
  .section[lang="es"][data-ch="8"] { contain-intrinsic-size: auto 28500px; }
  .section[lang="es"][data-ch="9"] { contain-intrinsic-size: auto 29200px; }
  .section[lang="es"][data-ch="10"] { contain-intrinsic-size: auto 48100px; }
}
.section-inner { display: contents; }

/* every direct child of a section that has not claimed a range defaults to the
   reading measure, so a new block type never lands full-bleed by accident */
.section > .block-p,
.section-inner > .block-p { grid-column: 3 / 9; }
@media (max-width: 900px) {
  .section > .block-p, .section-inner > .block-p { grid-column: 1 / 7; }
}

/* ============================================================================
   THE ARC — paper temperature, not black to cream
   Each chapter warms the stock a little and moves the accent along the light
   story: cold slate while the face is hidden, ember at the mountain, clay
   through the wilderness, and finally a bright warm white at face to face.
   Every accent clears 4.5:1 on its own paper (checked; figures in comments),
   because the accent paints .chapter-num and .verse-ref at ~11px.
   js/motion.js mirrors this table exactly.
   ============================================================================ */
/* THREE ACCENTS, NOT TEN — 2026-08-28.
   There were ten and only four real hues: three near-identical blues (II, IV, VII),
   four near-identical brown-golds (V, VI, IX, X), and chapter V — whose light is
   fire — painted a dull brown. Ten near-misses read as a palette generator. Three
   that mean something read as a decision, and the switch happens where the BOOK
   turns, not once per chapter:

     NIGHT   #32638F   I–IV     the face is buried, hidden, fled from, wrestled in the dark
     FIRE    #A8391B   V–VIII   the bush, the shine, the glory leaving, the flint and the tear
     MORNING #7E5A20   IX–X     the second fire at dawn, and the face in full light

   The night→morning arc is not lost: it is still carried chapter by chapter by
   PAPER TEMPERATURE, which is finer-grained than the accent ever was.
   Contrast, measured against the darkest stock in the set (#EBE6E1, chapter VIII):
   night 6.79 : 1, fire 5.19 : 1, morning 5.03 : 1 — all clear of the 4.5 AA floor,
   which matters because the accent paints .chapter-num and .verse-ref at ~10-12px.
   js/motion.js mirrors this table exactly. */
/* 🔴 THE NIGHT BLUE WENT #32506B → #32638F, 2026-09-07. The author: "the blue isnt
   visible and only talking about under the ribbon nothing else."
   ⭐ AND HE IS RIGHT FOR A REASON THAT IS NOT CONTRAST. The old blue measured 7.07:1
   on the caption's stock — the HIGHEST of the three accents, higher than the red he
   says looks good. The problem is the other end: the ribbon caption arrives in the
   chapter's accent and settles on --ink (see .plh-w in css/components.css), and the
   old blue's luminance was 0.075 against ink's 0.008, while red sits at 0.113 and
   gold at 0.119. The blue was nearly as dark as the ink it turns into, so the
   arrival had nothing to travel — the word landed already looking settled. Red and
   gold are lighter and warmer, so their arrival reads. Raising contrast would have
   made it worse; what it needed was to move AWAY from the ink.
   Same hue (208°), lightness 31% → 38%, saturation 36% → 48%. Luminance 0.116, which
   is red's and gold's own footing. Re-measured on all five of its stocks: 5.32, 5.22,
   5.11, 5.11, 5.15:1 — worst 5.11, clearing AA's 4.5 for normal text everywhere, not
   just the 3.0 the 34px caption would have needed.
   🛑 NIGHT IS UNTOUCHED AND WAS MEASURED BEFORE DECIDING: #8FB4D8 sits at 0.434
   against a near-white ink at 0.819, so all three night accents separate from ink
   already. The fault was day-only, which is exactly the half he described. */
.section[data-ch="0"]   { --paper:#EFEBE1; --ink:#191510; --accent:#32638F; } /* the jacket */
.section[data-ch="1"]   { --paper:#EDE9DF; --ink:#191510; --accent:#32638F; } /* the tomb — found in the dark */
.section[data-ch="2"]   { --paper:#E7E7E4; --ink:#16181A; --accent:#32638F; } /* the hiding */
.section[data-ch="3"]   { --paper:#EDE6DB; --ink:#1A1510; --accent:#32638F; } /* the mountain they fled */
.section[data-ch="4"]   { --paper:#E6E8EA; --ink:#15181B; --accent:#32638F; } /* the ford at night */
.section[data-ch="5"]   { --paper:#F0E9DC; --ink:#1A1510; --accent:#A8391B; } /* the bush that is not consumed */
.section[data-ch="6"]   { --paper:#F2ECE0; --ink:#1A1610; --accent:#A8391B; } /* borrowed light */
.section[data-ch="7"]   { --paper:#E9E9E7; --ink:#17191B; --accent:#A8391B; } /* the glory backs out — the fire leaves */
.section[data-ch="8"]   { --paper:#EBE6E1; --ink:#181412; --accent:#A8391B; } /* flint, and the curtain */
.section[data-ch="9"]   { --paper:#F4EEE1; --ink:#1A1610; --accent:#7E5A20; } /* the second fire, at dawn */
.section[data-ch="10"]  { --paper:#FBF7EE; --ink:#1A1712; --accent:#7E5A20; } /* full morning */
.section[data-ch="fw"] { --paper:#FDFAF3; --ink:#1A1712; --accent:#7E5A20; } /* five words */

/* ============================================================================
   TYPOGRAPHY
   ============================================================================ */
.block-p, .prose {
  margin: 0 0 1.15em;
  max-width: var(--measure);
  text-wrap: pretty;
}
.block-p em, .prose em { font-style: italic; }
.block-p:last-child { margin-bottom: 0; }

/* Literata's optical-size axis: display sizes want a tighter, higher-contrast
   cut than text does. Setting opsz by hand is the difference between a serif
   that looks typeset and one that looks scaled.
   Weight is 400, not the 300 this rule carried under Fraunces: Literata's light
   end is thinner than Fraunces' was, and 300 left a 3.7rem chapter title looking
   underinked against the warm stocks late in the book. */
.chapter-title, .hero-title, .fivewords-text {
  font-variation-settings: var(--lit-display);
  font-weight: 400;
  letter-spacing: -.018em;
  line-height: 1.03;
  text-wrap: balance;
}

.chapter-title { font-size: clamp(2.1rem, 4.6vw, 3.7rem); }

.chapter-num {
  font-family: var(--ui);
  font-size: var(--ap-sm); font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--accent);
  padding-top: .95em;   /* optical alignment with the title's cap height */
}

/* Option C, the same treatment the contents list uses: the apparatus sans, not
   the book's serif. The argument for keeping the serif here was that a chapter
   standfirst is the author's voice leading into the prose. In practice it reads
   as a slightly smaller first paragraph, and the reader starts the chapter twice.
   The sans says plainly that this line is about the chapter rather than part of
   it, and it makes the drop cap below the first real sentence in the book's face.
   Never italic: this line is apparatus, and the sans has no italic in play here. */
/* SET IN THE BOOK'S OWN FACE, 2026-08-28. This was Archivo — the interface sans —
   on the argument that a sans stops the reader starting the chapter twice. It does,
   but it also made the author's own standfirst speak in the player buttons' voice.
   Literata italic does the same separating job honestly: italic is not the body
   roman, so the eye still knows this line is about the chapter rather than in it. */
/* 🔴 ROMAN, NOT ITALIC — 2026-09-07. The author: "the beggining of chapter
   descriptions also have weird font not sure its working", and on the sheet, of the
   same setting: "im not sure about the kind of text we chose thats like italics its
   hard to read?????"
   ⚠️ THIS IS THE SECOND ITALIC HE FLAGGED THIS ROUND AND ONLY THE OTHER ONE WAS A
   BUG. The ribbon caption was italic by accident — js/ui.js was building its words
   with createElement('i') — and that is simply fixed. THIS one was chosen, twice, on
   the argument written above: a standfirst has to look like it is ABOUT the chapter
   rather than the chapter's own first paragraph, and italic separates it honestly
   where the sans made the author's voice sound like a player button.
   ⭐ THE SEPARATION IS REAL AND IT DOES NOT HAVE TO BE ITALIC. It was already being
   carried three other ways — a lighter ink, a shorter measure, and a full line of
   space — and italic was the fourth. Losing it costs nothing the reader can name and
   buys back the one thing a run of italic at body size never has, which is reading
   speed. Weight 450 against the body's 400 replaces it: heavier than the prose, in a
   softer ink than the prose, which is exactly how a printed standfirst is set.
   🛑 .toc-hook IN css/components.css IS THE SAME LINE IN THE CONTENTS AND MOVED IN
   THE SAME EDIT. They have always been one decision; the note there says so. */
.chapter-hook {
  font-family: var(--serif);
  font-variation-settings: var(--lit-normal);
  font-style: normal;
  font-weight: 450;
  color: var(--ink-soft);
  margin: 1.1em 0 0;
  /* ⭐ THE STANDFIRST TRACKS THE BODY, 2026-09-05. The author: "how is textsize and
     cohesion looking any weird text that needs to be bigger or less weird."
     It was a flat 1rem — 16px at every width, which is a fifth SMALLER than the
     body copy it introduces once the page is past 928px and --body-size has hit
     its 1.32rem ceiling. A standfirst that reads smaller than the paragraph under
     it inverts the hierarchy: the eye takes it for a caption and skips it, and it
     is the one line telling the reader what the chapter is about. Same size as the
     body, in italic and --ink-soft, is the printed convention and it costs no new
     token — this IS the body token. */
  font-size: var(--body-size);
  line-height: 1.55;
  letter-spacing: 0;
  max-width: 58ch;
}

/* 🛑 .hebrew-inline IS GONE, 2026-09-07 — it had no markup. Hebrew inside prose is
   set by .heb-word and the lexicon components, all of which name var(--heb)
   themselves. */

/* ---------- glossary term: a dotted underline, nothing more ---------- */
.gloss-term {
  border-bottom: 1px dotted var(--accent);
  cursor: help;
  text-underline-offset: 3px;
}

/* ============================================================================
   MOTION
   Reveals are small and fast. The old build had veil-lifts, ken-burns, breathing
   glows and letter-spacing settles running at once; that busyness is itself a
   tell. What is left: an 8px rise on first sight, and the plate parallax.
   ============================================================================ */
/* Scroll-triggered fade-up on running text is the single most generic web
   animation there is, and it actively fights reading — a paragraph that is still
   arriving is a paragraph you cannot start. It now applies ONLY to plates and to
   the closing line. Text is simply there. */
.reveal { opacity: 1; transform: none; }
.plate.reveal, .fivewords-text .fw-word, .fivewords-ref {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
.plate.reveal.is-visible { opacity: 1; transform: none; }

.hairline {
  grid-column: 3 / 9;
  height: 1px; width: 0;
  background: var(--rule-strong);
  margin: 2.2rem 0;
  transition: width var(--dur-slow) var(--ease);
}
.hairline.is-drawn { width: 5rem; }

/* Both dividers ARE the hairline; they differ only in how much air they take.
   These used to set height, which overrode .hairline's 1px and drew each one as
   a 1.6rem slab of --rule-strong once it was drawn. With thirteen dividers on
   the site that was easy to miss; there are ninety-seven now. */
.divider-beat  { grid-column: 3 / 9; margin: 2.2rem 0; }
.divider-swell { grid-column: 3 / 9; margin: 3.8rem 0; }
/* 🛑 THESE TWO NEEDED THE MOBILE RANGE AND DID NOT HAVE IT, AND IT COST THE WHOLE
   PHONE LAYOUT. Below 900px the grid is six columns, so `3 / 9` asks for a line 9
   that does not exist and the browser creates TWO IMPLICIT TRACKS to reach it.
   `grid-column: 1 / -1` counts back from the end of the EXPLICIT grid, so from that
   moment every full-bleed element spanned six tracks of an eight-track grid and came
   up 28px short: measured 2026-08-29, plates rendered 374px wide in a 402px viewport
   instead of 402 (so a "full-bleed" plate had a 28px gutter down one side), chapter
   headers 334 instead of 362, and every paragraph in all ten chapters was set to a
   narrower measure than the design asks for. 88 dividers, ten chapters, one missing
   media query.
   ⚠️ Any new `grid-column` that ends past line 7 needs a range here too — the failure
   is silent, and it does not look like a bug, it looks like a margin. */
@media (max-width: 900px) {
  .divider-beat, .divider-swell { grid-column: 1 / 7; }
}
.divider-swell.is-drawn { width: 9rem; }

/* 🛑 THIS BLOCK HAD NEVER ONCE APPLIED TO A PLATE. It said `.reveal` — one class,
   specificity (0,1,0) — while the rule it is trying to switch off is `.plate.reveal`
   at (0,2,0), so the plain selector lost the cascade every time and every plate went
   on sliding 10px up the screen for a reader who had asked the operating system to
   stop exactly that. Measured 2026-08-29 with --force-prefers-reduced-motion=reduce:
   ten elements still carrying `opacity, transform 0.62s`.
   ⚠️ A reduced-motion override has to be written at the specificity of the rule it
   overrides. Adding a selector above without adding it here is a silent regression:
   the page looks right to whoever is testing it, because they do not have the setting
   on. The parallax in js/motion.js was always correct — this was CSS only. */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  .plate.reveal, .plate.reveal.is-visible,
  .fivewords-text .fw-word, .fivewords-ref { opacity: 1; transform: none; transition: none; }
  .hairline { width: 5rem; transition: none; }
}

/* legacy hooks kept inert so js/motion.js and js/sync.js keep their contracts.
   🛑 #ambient-light and #grain came off this line 2026-09-07 — neither id exists in
   any markup or script, so the rule was hiding nothing. .veil-lift and .veil-boundary
   stay: js/motion.js still reads both. */
.veil-lift::after, .veil-boundary { display: none !important; }


/* ============================================================================
   THE SECOND DOOR — the five minutes, offered under the ribbon
   It shipped 2026-09-04 as .hero-second-door: one ghost line of --ink-faint at
   opacity .72 with an arrow that drifted 0.18em on hover. Everything about that
   was correct for a footnote and wrong for the single highest-yield action on the
   page — a stranger will not spend five hours on a book they have not heard, and
   they will spend five minutes.
   ⚠️ IT NO LONGER LIVES IN THE HERO. Markup in js/render.js (THE_SECOND_DOOR),
   position under the ten plates, full history in the rules below.
   ============================================================================ */
/* 🔴 REBUILT AND MOVED, 2026-09-05 (round three). Two author notes landed at once:
   "move this down below photos and add what chapter 7 holds and the quote there so
   its still super sweet and doesnt miss", and — of the passage it opened on — "it
   should be emotional, deeper than the brother thing."
   So this is no longer a 68px control tucked under two buttons in the hero. It sits
   below the ribbon of ten plates, it is the last thing before the contents, and it
   is the only element on the page that prints the book's own voice at display size.
   🛑 THE MARKUP IS IN js/render.js NOW (THE_SECOND_DOOR, above renderPlateIndex).
   The names stayed .hero-sample / .hs-* on purpose; see the note there.

   ⚠️ IT STILL MUST NOT OUTRANK "Begin listening", and the reason is unchanged and
   is FILL: .btn-solid is a solid slab of --ink and this is a wash inside a hairline.
   The two are also no longer on the same screen, which settles it further.
   🛑 NO NEW TOKENS. Edge --control-edge, wash --control-wash, accent rule --accent,
   display voice --lit-mid, apparatus --ui/--ap-lg/--ap-xl, timing --dur-fast/--ease.
   ⚠️ --control-edge, NOT --rule-strong, and the distinction still holds: the whole
   rectangle is one link, so WCAG 2.2 SC 1.4.11 wants 3:1 for its boundary.
   #plates carries no [data-ch] of its own, and MEASURED — not assumed — its paper
   composites to the same rgb(239,235,225) the jacket sits on, so the edge measures
   3.30:1 here exactly as it did in the hero and --rule-strong would still fail at
   1.84:1. Re-measure if #plates ever gains a [data-ch] palette. */
.hero-sample {
  /* ⚠️ COLUMN 1, WITH THE CAPTION, NOT THE READING MEASURE. .pl-hook above it
     starts where the first plate starts and so does this; the two of them are one
     left-ranged block hanging under the strip. Putting the door on the prose
     columns (3/9) would leave it floating two tracks in from the caption it
     follows, which is the same fault the caption's own note argues against. */
  grid-column: 1 / 8;
  display: block;
  /* 🔴 SMALLER, 2026-09-05 (round seven). The author: "i said the box ws ugly and
     all you did was make it bigger it looks ok but now its too big… keep that
     shrter."
     He is right, and the previous round's open note in docs/FRONT-DOOR.md §4.3 had
     already spotted half of it: "the card is 42rem wide and the quote only fills
     about half of it at 1440." A card whose display-size quote runs two short lines
     inside a 672px box is not a wide card, it is a box with a hole in it. 35rem is
     the width the quote actually wants — it sets to three fuller lines — and the
     card stops reading as a panel and starts reading as a note pinned under the
     caption. The type came down with it (.hs-quote, .hs-holds below); shrinking the
     box alone would have made a cramped panel out of a loose one. */
  max-width: 35rem;
  margin: clamp(1.4rem, 2.6vw, 2.1rem) 0 0;
  /* 🔴 THE BOX WENT, 2026-09-07. The author, for the fourth time about this object:
     "the if you only have 5 minutes seems pretty bloated and the coding is uggluy on
     it such a gross looking box. its not terrible but i feel like it ccould be
     substantially better."
     ⭐ THE ANSWER IS THE ONE .btn-begin ALREADY REACHED, ONE DAY EARLIER AND FOR THE
     SAME COMPLAINT. That button was a washed rectangle, the author said "i meant loud
     as in ugly lol", and the note there is exact: "This page is hairlines and paper —
     a bordered box is the one shape it never uses anywhere else, which is exactly why
     a control drawn as one looks like something pasted on from a different website."
     Every word of that is true of this card, and this card is the more boxed of the
     two — it had a full 1px edge AND a tinted fill AND a second hairline cutting it
     in half. Three chrome elements around four content ones is the definition of the
     word he used.
     🛑 SO WHAT IS LEFT IS THE BOOK'S OWN MARK: one accent rule down the left edge, the
     way the text marks a change of voice everywhere, and nothing else. No border, no
     fill, no internal rule. The card is now four pieces of type and one drawn play
     mark hanging off a coloured rule — which is what it always was underneath.
     ⚠️ THE WASH WAS THE EYE-MAGNET AND SOMETHING HAS TO REPLACE IT. It does: the play
     mark was redrawn this round (css/components.css .transport-play) and it is now a
     46px accent ring with a body in it rather than 40px of hairline. The magnet moved
     from the rectangle to the thing you actually press, which is where it belongs.
     ⚠️ AND THE HOVER HAS TO DO REAL WORK NOW, exactly as .btn-begin's does — with no
     resting surface there is nothing to deepen, so hover paints one in.
     ⚠️ RE-MEASURED ON BARE PAPER, which is simpler than the composite the wash needed
     — day rgb(239,235,225), night rgb(18,17,15):
       --ink (the quote)        13.14:1 day · 16.02:1 night
       --ink-soft (.hs-holds)    5.39:1 day ·  8.74:1 night   (needs 4.5)
       --accent (rule, eyebrow)  5.68:1 day ·  8.71:1 night   (needs 4.5 as text) */
  padding: clamp(.9rem, 1.5vw, 1.15rem) clamp(1rem, 1.7vw, 1.35rem)
           clamp(.9rem, 1.5vw, 1.15rem) clamp(1.15rem, 2vw, 1.6rem);
  border: 0;
  /* the accent edge is the eye-magnet, and it is a RULE, not a glow. It is doing
     double duty now: the book marks a change of voice with a rule everywhere, and
     the thing directly inside it is a quotation.
     ⚠️ 2px → 3px WITH THE BOX GONE. It is the card's only remaining edge, so it is
     the whole of SC 1.4.11's boundary as well as the whole of the design. */
  border-left: 3px solid var(--accent);
  /* 🔴 THE CARD IS LIT NOW, NOT GREY, 2026-09-06. The author: "thsi box is really
     ugly", and separately: "could be flashing or have color."
     🛑 IT IS NOT FLASHING AND IT WILL NOT BE. A blinking element is a WCAG 2.3
     failure above three flashes a second and a migraine and a vestibular trigger
     well below that, and prefers-reduced-motion would switch it off for exactly the
     reader most likely to be on a phone at night, who is who this card is for.
     ⭐ COLOUR IS THE VERSION OF THAT ASK THAT WORKS, AND THE COLOUR IS ALREADY HIS.
     7% of the CURRENT CHAPTER'S accent, mixed into the same control wash every other
     control uses — so the card sits on the dawn arc with everything else instead of
     being decorated. No new token, and the card is now the only tinted rectangle
     above the fold, which is what makes it the eye-magnet the grey one never was.
     ⚠️ MEASURED, not assumed, by compositing the card's translucent wash over the
     paper it actually sits on — day rgb(215,212,203), night rgb(18,17,15):
       --ink (the quote)        12.26:1 day · 15.62:1 night
       --ink-soft (.hs-holds)    5.03:1 day ·  8.52:1 night   (needs 4.5)
       --accent (ring, eyebrow)  5.68:1 day ·  8.71:1 night   (needs 3 as a control,
                                                               4.5 as the eyebrow's text)
     Re-measure if --control-wash or the accent stops being 7%. */
  background: none;
  color: var(--ink);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease);
}
/* 🔴 THE CARD IS LIT BY THE CHAPTER IT OPENS — 2026-09-07. The author, of the type
   on the ribbon: "i like the red color on the text that looks good the first ones
   dont look as goood."
   ⭐ HE IS DESCRIBING THE DAWN ARC, AND THIS CARD WAS NOT ON IT. #plates carries no
   [data-ch], so everything inside it — this card's rule, its eyebrow and its play
   mark — was painted in the ROOT accent, which is the night blue of chapter I. The
   card does not go to chapter I. It goes to chapter VII, which is the fire, and the
   fire is the red he likes. So it takes its own chapter's light: the door and the
   room behind it are now the same colour, which is the arc's whole argument.
   🛑 THE ARC ITSELF IS UNTOUCHED. This is one element claiming the accent of the one
   chapter it links to — not a re-colouring of chapters I-IV, which is a separate
   question and is written up in docs/DECISIONS.md as one.
   ⚠️ THE TWO VALUES ARE COPIED FROM THE ARC TABLE ABOVE, [data-ch="7"], day and
   night. They are a hand-kept duplicate of two literals, which this file already
   does for the dawn arc in js/motion.js — if the fire ever changes, it changes in
   three places, and this is the third. */
/* 🔴 THE RED CAME OFF THIS CARD, 2026-09-07, ONE ROUND AFTER IT WENT ON. The author:
   "the red can look good but its not calming so red not for the chapter preview lol."
   ⭐ SEPARATE THE THING FROM ITS FRAME: what he approved last round was the BOX
   GOING, and the rule down the left that replaced it. The red arrived in the same
   commit and is the part he is naming now. The rule stays; only its colour goes back.
   With the override gone the card inherits the accent of the section it sits in —
   the jacket, [data-ch="0"], which is the night blue he says looks good — instead of
   reaching two arcs forward for chapter VII's fire. That also retires the hand-kept
   triplicate the note above this used to warn about: the fire now lives in
   css/site.css's arc table and nowhere else.
   ⚠️ HE ALSO ASKED, of the same object: "left of the text when its red is that
   necesssary". That is a question about the RULE, not the colour, and it is still
   open on the sheet — it is not answered by deleting it on his behalf. */
.hero-sample:hover, .hero-sample:focus-visible {
  border-left-color: var(--accent);
  /* ⚠️ THE SURFACE ARRIVES; NOTHING INVERTS AND NOTHING MOVES. Same gesture as
     .btn-begin, and for the same reason — a hover that flips a control the reader is
     already pointing at is the black-slab move in disguise.
     ⚠️ color-mix OFF --accent NOW, NOT OFF --ink. With no resting fill there is
     nothing to deepen, so the wash that arrives should be the card's own light rather
     than a grey smudge — which is what an ink mix looks like on cream. 9%, the same
     strength .btn-begin's hover uses, so the two doors on this page answer a pointer
     identically. */
  background: color-mix(in srgb, var(--accent) 9%, transparent);
}
.hero-sample:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------- 1. THE OFFER: why you would stop here ----------
   🔴 IT WAS THE LOCATOR UNTIL round four, 2026-09-05. The author: "it should say
   only have 5 minutea and then something els. its a teaser."
   He is right, and the reason is that a card which opens by naming the chapter is
   answering a question nobody asked — a stranger does not know what Chapter VII is
   and cannot want it. "If you only have five minutes" is the one sentence on this
   page that is about the READER. The locator went to the action row, where a play
   ring wants a destination beside it anyway. */
.hs-eyebrow {
  display: block;
  font-family: var(--ui); font-size: var(--ap-lg);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .7em;
}
/* the separator is an <i> so it can be dimmed without a second colour token, and
   aria-hidden keeps a middle dot out of the accessible name.
   ⚠️ IT IS ON .hs-title NOW, NOT .hs-eyebrow — the locator moved to the action row
   in round four so the eyebrow could carry the offer. Both are listed because the
   pair swap places whenever the copy is reworked, and a dot at full weight against
   a dimmed one is a difference nobody notices until it looks cheap. */
.hs-eyebrow i, .hs-title i { font-style: normal; opacity: .55; padding-inline: .25em; }
/* ⭐ ONCE YOU HAVE HEARD IT — 2026-09-09, the author's "this is a good idea".
   The whole of the built state is this one declaration plus one line of copy
   (js/ui.js, wireHeardDoor). The eyebrow comes off --accent onto --ink-soft, which
   is exactly what .seek-mark.is-complete does in css/player.css: on this site
   "you have already done this one" is said by stepping back, never by adding a tick
   or a badge. Nothing else on the card moves — the rule down the left stays at full
   accent, because it is the card's only edge and SC 1.4.11 is resting on it.
   ⚠️ CONTRAST IS ALREADY MEASURED FOR THIS EXACT PAIRING and it is in the table
   above: --ink-soft on the card reads 5.03:1 day and 8.52:1 night against the
   tinted wash, 5.39:1 and 8.74:1 on bare paper. AA needs 4.5. */
.hero-sample.is-heard .hs-eyebrow { color: var(--ink-soft); }

/* ---------- 2. the voice: the book's own words, at display size ----------
   ⭐ THIS IS THE ELEMENT THE ROUND WAS FOR. ch07-p169 + ch07-p170 verbatim. It is
   set in the display voice — Literata at --lit-mid, weight 350 — because it is not
   apparatus and not a caption: it is two sentences out of the book, and the page
   has no other place where that happens outside a chapter. The <br> is the break
   the book itself uses; the two sentences are separate paragraphs there. */
.hs-quote { margin: 0; }
.hs-quote p {
  margin: 0;
  font-variation-settings: var(--lit-mid);
  font-weight: 350;
  /* clamp(1.5rem, 2.5vw, 2.1rem) → this, with the card's own width, 2026-09-05.
     🛑 THE VOICE DOES NOT CHANGE, ONLY THE SIZE. This is still the one place on the
     page outside a chapter where the book speaks in its own display setting, and
     that is the whole reason the card works. It is now 27px at 1440 against the
     plate caption's 34 directly above it — the caption is the louder line, which is
     correct: the caption belongs to ten photographs and this belongs to one offer. */
  font-size: clamp(1.28rem, 1.95vw, 1.7rem);
  line-height: 1.24; letter-spacing: -.012em;
  color: var(--ink);
  text-wrap: balance;
}

/* ---------- 3. WHAT THE FIVE MINUTES HOLD ----------
   The author asked for "what chapter 7 holds", and this is it: three concrete
   things from inside the excerpt, none of them the quote above and none of them
   the action below. Deliberately NOT the chapter's hook — the hook describes the
   glory leaving the temple, which is the chapter; this describes the passage. */
.hs-holds {
  display: block;
  margin-top: .9em;
  /* 🛑 NO max-width HERE. The card itself caps at 42rem, and a second cap inside it
     set this line at 400px inside a 615px box — a narrow ragged column floating in
     a wide one, which reads as a mistake rather than as a measure. One cap, on the
     outside, is the rule this page follows everywhere else. */
  /* 🔴 THE SERIF, NOT THE SANS — 2026-09-07, and it is the last piece of "bloated".
     ⚠️ --ap-xl WAS THE RIGHT SIZE IN THE WRONG FAMILY. The note it replaces is
     correct that this line is the reason --ap-xl exists; what it never asked is why a
     sentence out of the book was being set in the interface face at all. With the box
     and the internal hairline gone, the card is four things stacked on a rule — and
     three of them were speaking in three different voices: tracked sans caps, then
     Literata at display size, then Archivo at 15px, then Literata again. A reader
     does not call that "four elements", he calls it bloated, which is the word the
     author used.
     ⭐ TWO VOICES NOW, NOT THREE. The eyebrow is signage and stays in the sans; every
     other word on this card is out of the book and is set in the book's face. The
     site's own rule, written at .verse-note: "the serif is the book and the sans is
     the machine, and a note about Hebrew grammar written by the author is not
     machinery." Neither is this.
     ⚠️ IT GOT ONE STEP LARGER WITH THE FAMILY. Literata at 15.2px against Archivo at
     15.2px reads smaller — the serif's x-height is lower — and this line was already
     the smallest thing on the card. 17px at 1440 puts it just under the .hs-act title
     beside the play mark, which is the right order: this describes, that locates.
     ⚠️ --ink-soft on bare paper measures 5.39:1 day / 8.74:1 night. */
  font-family: var(--serif);
  font-variation-settings: var(--lit-normal);
  font-weight: 400;
  font-size: clamp(.98rem, 1.18vw, 1.06rem);
  line-height: 1.5; letter-spacing: 0;
  color: var(--ink-soft);
}

/* ---------- 4. the action ---------- */
/* 🛑 THE HAIRLINE ABOVE THIS ROW CAME OFF 2026-09-07 WITH THE BOX AROUND IT. It was
   the third piece of chrome on a card the author called bloated, and it was drawing a
   line between the two halves of a single sentence: the quote is why you press this
   and the row is what you get. Nothing needed separating. The space does it. */
.hs-act {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: .85rem;
  margin-top: 1.15em;
}
/* the ring + triangle. 46px clears the 24px minimum for a non-text control
   (WCAG 2.2 SC 2.5.8) many times over, and the CARD is the touch target anyway:
   the whole rectangle is the link and it measures well over 200px tall.
   🔴 40px → 46px AND THE MARK ITSELF WAS REDRAWN, 2026-09-07. The author: "we need to
   find a better play button ours is not impressive it looks like chlkdrens coding."
   The five faults and the geometry are written out once, at .transport-play in
   css/components.css; this is the third of the three places that carry it. It got the
   extra six pixels because it is also now the card's only eye-magnet — the tinted
   rectangle that used to be that is gone (see .hero-sample above). */
.hs-glyph { display: block; width: 46px; height: 46px; }
.hs-glyph svg { display: block; width: 100%; height: 100%; overflow: visible; }
.hs-ring {
  /* a body, not a hole. The same 14% wash of its own accent the transport button and
     the jacket's door now carry — it is what stops a 46px circle reading as a
     wireframe, and it is a decoration under an opaque glyph, so it carries no
     contrast debt of its own. */
  fill: color-mix(in srgb, var(--accent) 14%, transparent);
  /* accent at rest, not --ink: the ring is the only mark on the card that says
     "this plays", and it was the same near-black as the type around it. */
  stroke: var(--accent);
  stroke-width: 1.5;
  /* 2πr, r=20.5 → 128.81. The dash pattern is what lets it draw itself.
     ⚠️ IT MUST TRACK THE RADIUS IN js/render.js. It was 119.38 for r=19 and 138.23
     for r=22 before that; a dasharray left behind by a radius change leaves units the
     circle never uses, so the ring finishes drawing early and then sits still for the
     rest of the animation. Silent, every time. */
  stroke-dasharray: 128.81;
  stroke-dashoffset: 0;
  transform: rotate(-90deg);
  transform-origin: 22px 22px;
  transition: fill var(--dur-fast) var(--ease);
}
.hs-tri {
  fill: var(--accent);
  /* the stroke IS the corner radius — same paint as the fill, so the triangle gains a
     radius rather than an outline, and gains back the size the radius eats. */
  stroke: var(--accent); stroke-width: 3; stroke-linejoin: round;
  transition: fill var(--dur-fast) var(--ease), stroke var(--dur-fast) var(--ease);
}

/* ⭐ ONE PULSE, ON FIRST ARRIVAL, AND NEVER AGAIN — the author's pick, 2026-09-06.
   js/ui.js adds .is-arrived the first time the card crosses into view and removes
   nothing; the animation has no iteration count, so it plays once and stops. A loop
   here would be a blinking element by another name, which is the thing refused
   above. The ring draws itself and the triangle lifts with it — the same
   gesture the transport button makes when a chapter starts, so the card is
   rehearsing what pressing it does.
   ⚠️ THE RING'S DASH LENGTH IS 2πr FOR r=20.5 AND IT MUST TRACK THE RADIUS. */
@keyframes hs-draw {
  from { stroke-dashoffset: 128.81; }
  to   { stroke-dashoffset: 0; }
}
@keyframes hs-lift {
  0%   { transform: scale(.82); opacity: .35; }
  55%  { transform: scale(1.06); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.hero-sample.is-arrived .hs-ring {
  animation: hs-draw var(--dur-slow) var(--ease) 180ms both;
}
.hero-sample.is-arrived .hs-tri {
  transform-origin: 22px 22px;
  animation: hs-lift var(--dur-med) var(--ease) 480ms both;
}
@media (prefers-reduced-motion: reduce) {
  .hero-sample.is-arrived .hs-ring,
  .hero-sample.is-arrived .hs-tri { animation: none; }
}
.hero-sample:hover .hs-ring,
.hero-sample:focus-visible .hs-ring {
  stroke: var(--accent);
  fill: color-mix(in srgb, var(--accent) 26%, transparent);
}
.hero-sample:hover .hs-tri,
.hero-sample:focus-visible .hs-tri { fill: var(--accent); }

/* 🛑 A SECOND @keyframes hs-draw STOOD HERE AND IT WON, because a later rule of the
   same name replaces the earlier one. It was left over from the superseded design and
   it carried the OLD dash length — 119.38, which is 2πr for r=19, against the r=20.5
   the circle is actually drawn at in js/render.js. The ring therefore started life
   about 7% already drawn: precisely the silent failure the comment on .hs-ring above
   was written to warn about. Its companion `.hs-ring { animation: ... }` also fired on
   load for every ring, unconditionally, which is what .is-arrived exists to control.
   Both are gone. The one true copy is the @keyframes above. */

.hs-title {
  display: block; min-width: 0;
  font-variation-settings: var(--lit-mid);
  font-weight: 400;
  font-size: clamp(1.08rem, 1.35vw, 1.22rem);
  line-height: 1.22; letter-spacing: -.005em;
  color: var(--ink);
  /* ⚠️ balance, 2026-09-07. At 402 this line wraps, and unbalanced it broke as
     "Chapter VII · The Glory Backs / Out" — one orphaned word under a 46px play mark,
     which is the shape of a layout accident. Balanced it breaks after "Glory". It is
     a headline-length string, which is the only place `balance` is correct (see
     css/polish.css). */
  text-wrap: balance;
}
/* 🛑 .hs-meta WAS DELETED WITH ITS MARKUP, 2026-09-05. It read
   "Chapter VII · about 4 minutes" under a title that already said the number of
   minutes, under an eyebrow that had said it once before that. Do not restore this
   rule without markup that says something the other four lines do not. */

/* THE LINE THAT NAMES A FEATURE THAT ALREADY EXISTED.
   Hidden by default and revealed only by .can-tap-to-listen, which js/sync.js
   sets on <html> where it actually binds the handler. A promise the page cannot
   keep is worse than no promise.
   ⚠️ THIS ONE IS STILL IN THE HERO — it is about the whole book, not about the
   excerpt, and it was never part of the card. See index.html. */
/* ⚠️ IT WAS 11.5px OF BODY COPY. The author, 2026-09-05: "tap any line that text
   is super small too." --ap-md is .72rem, and the token block's own note says
   "Anything carrying a sentence takes --ap-md or --ap-lg" — this line carries a
   sentence AND is the only thing on its row, which is a third case the scale did
   not have. It takes --ap-xl (.95rem, 15.2px), and the colour comes off
   --ink-faint (4.51:1, the floor) onto --ink-soft (measured 6.26:1 composited over
   this stock), because a sentence a stranger is meant to actually read should not
   be sitting on the contrast minimum. */
.hero-sample-note {
  display: none;
  grid-column: 3 / 9;
  max-width: 34rem;
  margin: 1.1rem 0 0;
  /* 🔴 BACK TO THE SANS, 2026-09-07, ONE ROUND AFTER IT WENT TO THE SERIF. The author:
     "The one that says click on any paragraph and it will play has weirds font and it
     could do its job better."
     🛑 THE TAG AND THE COMPUTED STYLE WERE CHECKED BEFORE THE FAMILY WAS TOUCHED,
     because the last "weird font" report on this site was a wrapper element and not a
     font at all — js/ui.js building caption words with createElement('i'). This one is
     real: Literata, font-style normal, weight 400, 15.68px, --ink-soft. Nothing
     inherited it and there is no stray <i>. The face itself is the complaint.
     ⭐ AND THE ROUND THAT SET IT IN THE SERIF ARGUED FROM THE WRONG ELEMENT. Its
     reasoning was "every other word on THIS CARD is out of the book" — but this line
     is not on the card. The note directly above says so in its own words: "THIS ONE IS
     STILL IN THE HERO — it is about the whole book, not about the excerpt, and it was
     never part of the card." It is an instruction about how the interface behaves,
     which is the definition of machinery, and this site's own rule at .verse-note is
     "the serif is the book and the sans is the machine". Set in the book's voice at a
     size just under the quote above it, it read as a runt paragraph of that quote
     rather than as something you can act on — which is both halves of what he said:
     weird, and not doing its job. .hs-holds keeps the serif; it IS on the card and it
     is describing the passage, so the same round's reasoning holds there.
     ⚠️ THE SIZE GOES BACK WITH THE FAMILY AND THAT IS NOT A RETURN TO "SUPER SMALL".
     --ap-xl is .95rem — the token added for exactly this line, in answer to exactly
     that complaint. Archivo's x-height is taller than Literata's, so 15.2px of Archivo
     reads larger than the 15.68px of Literata it replaces: the previous round raised
     the number to compensate for the family, and the compensation leaves with it.
     ⚠️ --ink-soft on bare paper measures 5.39:1 day / 8.74:1 night — unchanged. */
  font-family: var(--ui);
  font-weight: 400;
  font-size: var(--ap-xl);
  line-height: 1.5; letter-spacing: 0;
  color: var(--ink-soft);
}
.can-tap-to-listen .hero-sample-note { display: block; }
/* never tell a phone to click. Pointer-only devices get "Tap"; anything with a
   real hover gets "Click". Exactly one of the two is ever in the box. */
.hsn-verb { display: none; }
.hsn-tap { display: inline; }
@media (hover: hover) {
  .hsn-tap { display: none; }
  .hsn-click { display: inline; }
}

@media (max-width: 900px) {
  .hero-sample { grid-column: 1 / 7; max-width: none; }
  .hero-sample-note { grid-column: 1 / 7; max-width: none; }
}

/* 🛑 REDUCED MOTION IS A FULL STOP, NOT A SLOWER VERSION.
   The ring is simply already drawn. Colour still changes on hover — that is a
   state change, not motion — and the card is exactly as usable either way. */
@media (prefers-reduced-motion: reduce) {
  .hs-ring { animation: none; stroke-dashoffset: 0; }
  .hero-sample { transition: none; }
  .hs-tri { transition: none; }
}

/* ============================================================================
   🌙 NIGHT — the whole book with the lights off, 2026-09-05
   The author: "continue balck buttons are so ugly… and maybe i need a night mode
   that might ahve disappeared."

   🛑 IT IS NOT AN INVERSION AND IT IS NOT A FILTER. The arc is the point of this
   book's colour: the paper warms and lightens chapter by chapter from the tomb to
   full morning. Night keeps that arc and moves it down — chapter I is the tomb at
   1 a.m. and chapter X is the same morning seen from a dark room. A `filter:
   invert()` would have turned every photograph into a negative, and a flat
   #000/#fff pair would have thrown away the one thing the palette says.

   🛑 THE TABLE MUST STAY IDENTICAL TO TOKENS_NIGHT IN js/motion.js, exactly as the
   day table above must stay identical to TOKENS. Two files, one decision, twice.

   ⭐ EVERY VALUE IS MEASURED, against the LIGHTEST night stock (#201B15, the five
   words) rather than against a convenient one — that is the stock where a light ink
   has the least room:
       ink        #EFE9DE  14.14:1      night   #8FB4D8   7.88:1
       ink-soft   #B6ADA1   7.71:1      fire    #E58156   6.19:1
       ink-faint  #968D82   5.23:1      morning #DCAA51   8.06:1
   and the control boundary (WCAG 2.2 SC 1.4.11 wants 3:1): white at .36 alpha
   composites to 3.55:1. --rule / --rule-strong carry containers, which 1.4.11 does
   not cover, and are set by eye at the same weights the day palette uses.

   ⚠️ THE ACCENTS ARE LIFTED, NOT REUSED. #32638F on #121110 is 2.98:1 — it paints
   .chapter-num and .verse-ref at ~11px, so the day accents are a real failure here
   rather than a taste question. Same three hues, same three moments in the book.
   ============================================================================ */
html[data-theme="night"] {
  --paper: #121110;
  --ink: #EFE9DE;
  --ink-soft: #B6ADA1;
  --ink-faint: #968D82;
  --rule: rgba(239, 233, 222, .14);
  --rule-strong: rgba(239, 233, 222, .26);
  --control-edge: rgba(239, 233, 222, .36);
  --control-wash: rgba(239, 233, 222, .05);
  --accent: #8FB4D8;
  color-scheme: dark;
}
html[data-theme="night"] .section[data-ch="0"]  { --paper:#141311; --ink:#EFE9DE; --accent:#8FB4D8; }
html[data-theme="night"] .section[data-ch="1"]  { --paper:#121110; --ink:#EFE9DE; --accent:#8FB4D8; }
html[data-theme="night"] .section[data-ch="2"]  { --paper:#111315; --ink:#EAEBEE; --accent:#8FB4D8; }
html[data-theme="night"] .section[data-ch="3"]  { --paper:#151211; --ink:#F0E9DD; --accent:#8FB4D8; }
html[data-theme="night"] .section[data-ch="4"]  { --paper:#101215; --ink:#E9ECEF; --accent:#8FB4D8; }
html[data-theme="night"] .section[data-ch="5"]  { --paper:#17130F; --ink:#F2EADC; --accent:#E58156; }
html[data-theme="night"] .section[data-ch="6"]  { --paper:#191410; --ink:#F3EBDD; --accent:#E58156; }
html[data-theme="night"] .section[data-ch="7"]  { --paper:#131415; --ink:#ECEDEE; --accent:#E58156; }
html[data-theme="night"] .section[data-ch="8"]  { --paper:#151312; --ink:#EFEAE4; --accent:#E58156; }
html[data-theme="night"] .section[data-ch="9"]  { --paper:#1A1510; --ink:#F4EDDF; --accent:#DCAA51; }
html[data-theme="night"] .section[data-ch="10"] { --paper:#1E1913; --ink:#F7F1E5; --accent:#DCAA51; }
html[data-theme="night"] .section[data-ch="fw"] { --paper:#201B15; --ink:#F8F2E7; --accent:#DCAA51; }

/* ⚠️ THE PHOTOGRAPHS COME DOWN A STOP, AND ONLY IN NIGHT. A full-brightness plate
   on a near-black page is a lightbulb in a dark room: the eye stops on the picture
   and cannot read the paragraph beside it. This is the same call css/room.css makes
   for the Listening Room, at a fraction of the depth — the page is still a book,
   not a nightstand. Transform-free, so it costs nothing on scroll. */
html[data-theme="night"] .plate-frame img,
html[data-theme="night"] .pl-frame img,
html[data-theme="night"] .img-slot img { filter: brightness(.86) contrast(1.03); }
/* 🛑 AND THE RIBBON'S OWN DIM STILL HAS TO WIN. .pl-plate:not(.is-lit) sets its own
   filter; without this the rule above would replace it and every plate in the strip
   would look lit. Composed by hand rather than by !important. */
html[data-theme="night"] .pl-plate:not(.is-lit) .pl-frame img {
  filter: brightness(.86) saturate(.62) contrast(1.05);
}

/* The one control that has to be told twice: a theme toggle whose icon is a moon
   in the day and a sun at night. Both glyphs are in the button; one shows. */
.theme-sun { display: none; }
html[data-theme="night"] .theme-moon { display: none; }
html[data-theme="night"] .theme-sun { display: block; }
