/* ==========================================================================
   Novelyze — Reading & library surface

   Split out of components.css: these are the classes for the reader and the
   library, not for the app shell. They are ~40% of the design system's CSS and
   no shell page uses one of them, so they no longer ship on the marketing page.

   This file is plain CSS on the same tokens — it needs no Tailwind pass — so it
   is served straight from static/ and pulled in only by the templates that
   read. Add it to a reading template with:

     {% block head %}
       <link rel="stylesheet" href="{% static 'css/reading.css' %}" />
     {% endblock %}

   It declares @layer components so Tailwind utilities keep beating it, exactly
   as they do for components.css.
   ========================================================================== */

@layer components {
  /* ---- Choice (the signature component) --------------------------------- */
  .choices { list-style: none; padding: 0; margin: 0; counter-reset: choice; border-top: 1px solid var(--line); }
  .choice {
    --marker: var(--ink-2);
    --nudge: 0;
    position: relative; display: grid; grid-template-columns: 2.25rem 1fr auto; align-items: baseline; gap: 0 var(--space-3);
    width: 100%; padding: var(--space-4) var(--space-3) var(--space-4) 0; text-align: left;
    border-bottom: 1px solid var(--line); border-radius: 0;
    font-family: var(--font-read); font-size: var(--text-read); line-height: 1.4; color: var(--ink-0);
    transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
  }
  /* The hover nudge is a transform, not padding. Animating padding reflowed the
     choice text sideways under the cursor the reader was aiming with. */
  .choice::before,
  .choice__text,
  .choice__hint {
    translate: var(--nudge) 0;
    transition: translate var(--dur-base) var(--ease-out), color var(--dur-fast) var(--ease-out);
  }
  .choice::before {
    counter-increment: choice; content: counter(choice, lower-roman) ".";
    font-family: var(--font-display); font-style: italic; font-size: 0.85em; color: var(--marker); text-align: right; padding-right: 0.2em;
  }
  /* Plain wrapping: 'pretty' evens out a two- or three-line choice into short lines that
     leave half a phone's width empty. */
  .choice__text { text-wrap: wrap; }
  .choice__hint { grid-column: 2; font-family: var(--font-ui); font-size: var(--text-xs); letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-2); margin-top: 0.35em; }
  .choice__meta { grid-column: 3; grid-row: 1; align-self: center; font-family: var(--font-ui); font-size: var(--text-xs); color: var(--ink-2); }
  .choice:hover, .choice.is-hover { --marker: var(--rubric); --nudge: var(--space-2); background: var(--rubric-soft); }
  .choice:active, .choice.is-active { background: color-mix(in oklch, var(--rubric-soft) 70%, var(--paper-3)); }
  .choice:focus-visible, .choice.is-focus { outline: none; --marker: var(--rubric); box-shadow: inset 3px 0 0 var(--rubric); }
  .choice:disabled, .choice.is-disabled { opacity: 0.4; cursor: not-allowed; }
  .choice.is-selected { --marker: var(--rubric); color: var(--rubric-ink); background: var(--rubric-soft); }
  .choice.is-selected::before { content: "¶"; font-style: normal; }

  .choice-custom { display: grid; grid-template-columns: 2.25rem minmax(0, 1fr); gap: var(--space-2) var(--space-3); align-items: center; padding: var(--space-3) var(--space-3) var(--space-3) 0; border-bottom: 1px solid var(--line); transition: background-color var(--dur-base) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); }
  .choice-custom::before { content: "✎"; font-family: var(--font-display); color: var(--ink-2); text-align: right; padding-right: 0.2em; }
  .choice-custom > .form__actions { grid-column: 2; padding-top: 0; }
  .choice-custom__field { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
  /* The line the reader writes on is a control, so it carries a --line-control rule
     (WCAG 1.4.11) even though it is otherwise a bare, italic line on the page. */
  .choice-custom__field .input { flex: 1 1 14rem; min-width: 0; font-family: var(--font-read); font-size: var(--text-md); font-style: italic; background: transparent; padding-inline: 0; border: 0; border-bottom: 1px solid var(--line-control); border-radius: 0; }
  .choice-custom__field .input:hover { border-bottom-color: var(--ink-2); }
  /* Focus reads like a hovered choice: the pen turns rubric, the row takes the wash and
     the rubric bar a focused .choice carries; the rule under the words turns rubric. */
  .choice-custom__field .input:focus { border-bottom-color: var(--rubric); box-shadow: none; }
  .choice-custom:focus-within::before { color: var(--rubric); }
  .choice-custom:focus-within { background: var(--rubric-soft); box-shadow: inset 3px 0 0 var(--rubric); }
  /* ---- Passage & reading ------------------------------------------------- */
  .passage { font-family: var(--font-read); font-size: var(--text-read); line-height: var(--leading-read); color: var(--ink-0); max-width: var(--measure); }
  .passage p + p { margin-top: 1.15em; }
  .passage p { hanging-punctuation: first; }
  .passage--dropcap > p:first-of-type::first-letter {
    float: left; font-family: var(--font-display); font-weight: 500; font-style: italic; font-size: 3.55em; line-height: 0.78;
    padding: 0.12em 0.12em 0 0; color: var(--rubric);
  }
  .passage .w { display: inline; }
  .passage.is-writing .w { opacity: 0; animation: ink var(--dur-slow) var(--ease-out) forwards; animation-delay: calc(var(--i) * 22ms); }
  @keyframes ink { from { opacity: 0; filter: blur(2px); } to { opacity: 1; filter: blur(0); } }
  /* The word-by-word reveal is the one thing a reduced-motion reader must not be
     given a faster version of — the stagger IS the motion. Hand them the finished
     paragraph instead. */
  @media (prefers-reduced-motion: reduce) {
    .passage.is-writing .w { opacity: 1; animation: none; }
  }

  .chapter-head { text-align: center; margin-block: var(--space-6) var(--space-6); }
  .chapter-head__num { font-family: var(--font-ui); font-size: var(--text-xs); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--ink-2); font-weight: 600; }
  .chapter-head__title { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 400; margin-top: var(--space-2); }

  .your-move { display: flex; align-items: baseline; gap: var(--space-3); margin: var(--space-7) 0 var(--space-3); }
  .your-move__label { font-family: var(--font-display); font-style: italic; font-size: var(--text-xl); color: var(--rubric); }
  .your-move__rule { flex: 1; border-top: 1px solid var(--line); }
  .your-move__count { font-size: var(--text-xs); color: var(--ink-2); letter-spacing: 0.04em; }
  /* ---- Covers ------------------------------------------------------------
     A pen-and-ink drawing with no frame, standing on the page's own paper
     (docs/cover-art.md). The art is a transparent WebP per story. */
  .cover { aspect-ratio: 2 / 3; margin: 0; }
  .cover__art { width: 100%; height: 100%; object-fit: contain; }
  .cover--sm { width: 3.25rem; }
  /* The washes are light paper tones; at night they would glare, so they dim like a lamp-lit page. */
  [data-theme="night"] .cover__art { filter: brightness(0.82); }

  .story-card { display: grid; gap: var(--space-3); text-decoration: none; color: inherit; position: relative; border-radius: var(--radius-sm); }
  /* On a phone the card is the column; the cover stays book-sized and centred. */
  .story-card .cover { width: 100%; max-width: 15rem; justify-self: center; }
  .story-card:focus-visible, .story-card.is-focus { outline: none; box-shadow: var(--ring); }
  .story-card.is-disabled { opacity: 0.45; pointer-events: none; }
  .story-card__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 500; line-height: 1.2; }
  .story-card__meta { font-size: var(--text-xs); color: var(--ink-2); display: flex; flex-wrap: wrap; gap: 0.35em 0.75em; }
  .story-card .progress { margin-top: var(--space-1); }

  .story-row { display: grid; grid-template-columns: auto 1fr auto; gap: var(--space-4); align-items: center; padding: var(--space-3) var(--space-2); text-decoration: none; color: inherit; border-radius: var(--radius-sm); transition: background-color var(--dur-fast) var(--ease-out); }
  .story-row:hover, .story-row.is-hover { background: var(--paper-2); }
  .story-row:active, .story-row.is-active { background: var(--paper-3); }
  .story-row:focus-visible, .story-row.is-focus { outline: none; box-shadow: var(--ring); }
  .story-row.is-disabled { opacity: 0.45; pointer-events: none; }
  .story-row__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 500; line-height: 1.2; }
  .story-row__meta { font-size: var(--text-xs); color: var(--ink-2); margin-top: 0.2em; display: flex; flex-wrap: wrap; gap: 0.2em 0.7em; }
  .story-row__aside { text-align: right; font-size: var(--text-xs); color: var(--ink-2); display: grid; gap: var(--space-1); justify-items: end; }
  @media (max-width: 40rem) { .story-row__aside .btn { display: none; } }

  /* The running head: story and page, then two controls. It tucks up while the reader
     reads down (reader.js) and the rubric rail is all that stays: the thread of progress
     without the furniture. Translate only, so nothing under it reflows. */
  .readbar { position: sticky; top: var(--proto-h); z-index: var(--z-nav); height: var(--topbar-h); display: flex; align-items: center; gap: var(--space-2); padding-inline: var(--gutter); background: var(--paper-0); border-bottom: 1px solid var(--line-soft); transition: translate var(--dur-base) var(--ease-out); }
  .readbar.is-tucked { translate: 0 -100%; }
  .readbar__mark { margin-right: var(--space-3); }
  .readbar__home { display: none; margin-left: calc(-1 * var(--space-3)); }
  @media (max-width: 40rem) {
    .readbar__mark { display: none; }
    .readbar__home { display: inline-flex; }
  }
  .readbar__title { flex: 1; min-width: 0; margin: 0; display: flex; align-items: baseline; gap: 0.6em; font-family: var(--font-ui); font-size: var(--text-sm); white-space: nowrap; }
  .readbar__title b { min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--ink-0); font-weight: 500; }
  .readbar__page { flex: none; color: var(--ink-2); font-variant-numeric: tabular-nums; }

  /* "Aa": everything that changes how the page looks, in one sheet. */
  .reading-menu > summary { list-style: none; }
  .reading-menu > summary::-webkit-details-marker { display: none; }
  .reading-menu[open] > summary { background: var(--paper-2); color: var(--ink-0); }
  .reading-menu__aa { font-family: var(--font-read); font-size: 1.15rem; font-weight: 500; line-height: 1; color: var(--ink-1); }
  .reading-menu__aa small { font-size: 0.78em; }
  .reading-menu__panel { width: min(19rem, calc(100vw - 2 * var(--gutter))); min-width: 0; gap: var(--space-4); padding: var(--space-4); }
  .reading-menu__group { display: grid; gap: var(--space-2); margin: 0; }
  .reading-menu__label { font-family: var(--font-ui); font-size: var(--text-sm); font-weight: 500; color: var(--ink-1); }
  .reading-menu__seg { display: flex; width: 100%; }
  .reading-menu__seg button { flex: 1; justify-content: center; min-height: 2.75rem; }
  .reading-menu__note { font-size: var(--text-xs); line-height: 1.45; color: var(--ink-2); text-wrap: pretty; }
  .reading-menu__row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-3); min-height: 2.75rem; padding: var(--space-2) var(--space-1); margin-inline: calc(-1 * var(--space-1)); font-family: var(--font-ui); font-size: var(--text-sm); font-weight: 500; color: var(--ink-0); text-align: left; border-radius: var(--radius-sm); transition: background-color var(--dur-fast) var(--ease-out); }
  .reading-menu__row:hover { background: var(--paper-2); }
  .reading-menu__row:focus-visible { outline: none; box-shadow: var(--ring); }
  .reading-menu .reading-menu__row .icon { display: block; color: var(--ink-1); }
  /* Drawn like .switch: the track is the control's boundary, so it carries --line-control. */
  .reading-menu__switch { position: relative; width: 2.5rem; height: 1.5rem; border-radius: var(--radius-full); background: var(--paper-3); border: 1px solid var(--line-control); transition: background-color var(--dur-base) var(--ease-out); }
  .reading-menu__switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: calc(1.5rem - 6px); aspect-ratio: 1; border-radius: 50%; background: var(--paper-1); box-shadow: var(--shadow-1); transition: translate var(--dur-base) var(--ease-out); }
  .reading-menu__row[aria-pressed="true"] .reading-menu__switch { background: var(--ink-0); border-color: var(--ink-0); }
  .reading-menu__row[aria-pressed="true"] .reading-menu__switch::after { translate: 1rem 0; background: var(--on-ink); }
  /* --p is a unitless 0..1 fraction written by novelyze.js inside rAF. */
  .read-rail { position: fixed; top: var(--proto-h); left: 0; height: 2px; width: 100%; transform-origin: left center; scale: var(--p, 0) 1; background: var(--rubric); z-index: calc(var(--z-nav) + 1); }

  /* ---- Story detail: the frontispiece ------------------------------------
     The story's place drawn across the full page width, then one centred column
     read top to bottom like the opening pages of a book: the title, the name, the blurb and the way in, the facts as one quiet
     colophon line, then the opening set as page one. No rules: space separates.
     The way back is a quiet link above the page, not a second button beside the
     rubric one; labels are sentence case at a readable size, never 11px capitals. */
  .back-link { display: inline-flex; align-items: center; gap: 0.4em; min-height: 2.75rem; font-size: var(--text-sm); font-weight: 500; color: var(--ink-1); text-decoration: none; border-radius: var(--radius-xs); transition: color var(--dur-fast) var(--ease-out); }
  .back-link:hover { color: var(--ink-0); }
  .back-link:focus-visible { outline: none; box-shadow: var(--ring); }
  .back-link .icon { transition: translate var(--dur-base) var(--ease-out); }
  .back-link:hover .icon { translate: -0.2em 0; }

  .frontis { padding-block: var(--space-4) var(--space-9); }
  .frontis__head, .frontis__opening { width: min(100%, var(--container-narrow)); margin-inline: auto; }
  .frontis__head { display: grid; justify-items: center; text-align: center; margin-top: var(--space-6); }
  /* The plate is frameless like a cover: the drawing's own ragged edge meets the paper.
     Below 40rem the <picture> serves the portrait cover instead, at cover size. */
  .frontis__plate { display: block; margin-top: var(--space-4); }
  .frontis__plate img { display: block; width: 13rem; height: auto; margin-inline: auto; }
  @media (min-width: 40rem) {
    .frontis__plate img { width: 100%; }
  }
  [data-theme="night"] .frontis__plate img { filter: brightness(0.82); }
  .frontis__title { margin-top: var(--space-6); font-size: var(--text-4xl); font-weight: 400; line-height: 1.02; text-wrap: balance; }
  .frontis__author { margin-top: var(--space-4); font-family: var(--font-read); font-style: italic; font-size: var(--text-xl); color: var(--ink-1); }
  .frontis__blurb { margin-top: var(--space-6); max-width: var(--measure-narrow); font-family: var(--font-read); font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem); line-height: 1.55; color: var(--ink-1); text-wrap: pretty; }
  .frontis__head > form, .frontis__head > .btn { margin-top: var(--space-6); }
  /* No separator glyphs: a dot that wraps lands at the start of a line. Space does the work. */
  .frontis__colophon { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2) var(--space-5); margin-top: var(--space-5); max-width: 40rem; font-size: var(--text-sm); color: var(--ink-1); }
  .frontis__colophon > div { display: flex; gap: 0.35em; }
  .frontis__colophon dt { color: var(--ink-2); }
  .frontis__colophon dt::after { content: ":"; }
  .frontis__opening { margin-top: var(--section); }
  .frontis__heading { font-size: var(--text-2xl); font-weight: 400; text-align: center; }
  .frontis__mood { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-1) var(--space-5); margin: var(--space-3) auto 0; padding: 0; max-width: 36rem; font-family: var(--font-read); font-style: italic; font-size: var(--text-md); color: var(--ink-2); }
  .frontis__opening .passage { margin: var(--space-7) auto 0; }
}

/* ==========================================================================
   Live reading: the composed wait, the reader's marker, the end (NOVELYZE.md §19)
   ========================================================================== */
@layer components {
  .book__pages { padding-block: var(--space-5) var(--space-9); }
  /* Pages of one stretch read as one column: the next page starts one paragraph gap below the
     last, as if the text had never been cut. A decision between them (the marker) brings
     its own space. */
  .beat + .beat .passage > p:first-child { margin-top: 1.15em; }
  /* The page being written sits in #live, after the column: the same gap, so nothing moves
     when it is committed in place. */
  .beat--live .passage > p:first-child { margin-top: 1.15em; }
  .beat--live .passage { min-height: 1.5em; }

  /* The reader's own decision, set between passages in the rubric: canon they wrote. */
  /* "Previously": the recap hierarchy for a reader coming back after a day. Quiet, italic,
     set apart by a rule, never the whole book. */
  .previously { margin: 0 0 var(--space-6); padding: var(--space-2) 0 var(--space-4); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  .previously:not([open]) { padding-bottom: var(--space-2); }
  .previously summary { display: flex; align-items: center; gap: 0.5em; min-height: 2.75rem; cursor: pointer; list-style: none; border-radius: var(--radius-xs); }
  .previously summary::-webkit-details-marker { display: none; }
  .previously summary::after { content: ""; width: 0.45em; height: 0.45em; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; rotate: -45deg; translate: 0 -0.05em; transition: rotate var(--dur-fast) var(--ease-out); }
  .previously[open] > summary::after, .previously__earlier[open] > summary::after { rotate: 45deg; translate: 0 -0.2em; }
  .previously summary:hover { color: var(--ink-0); }
  .previously summary:focus-visible { outline: none; box-shadow: var(--ring); }
  .previously__head { font-family: var(--font-ui); font-size: var(--text-xs); font-weight: 600; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--ink-2); }
  .previously__earlier { margin-bottom: var(--space-3); }
  .previously__earlier > summary { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--ink-2); }
  .previously__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); font-family: var(--font-read); font-style: italic; font-size: var(--text-md); color: var(--ink-1); }
  .previously__list li { text-wrap: pretty; }

  .marker { display: flex; gap: 0.5em; align-items: baseline; margin: var(--space-5) 0 var(--space-6); font-family: var(--font-read); font-style: italic; font-size: var(--text-md); color: var(--ink-1); }
  .marker__mark { color: var(--rubric); font-style: normal; font-family: var(--font-display); }
  .marker--quiet { color: var(--ink-2); }
  /* The decision that turned the page, at its head: an epigraph, set off by a hairline. */
  .marker--epigraph { margin: 0 0 var(--space-5); padding-bottom: var(--space-4); border-bottom: 1px solid var(--line-soft); }

  /* The wait is a quiet, typographic, in-world moment. No bar, no counter, no "thinking". */
  .wait { display: grid; justify-items: center; gap: var(--space-3); padding: var(--space-7) 0 var(--space-6); text-align: center; color: var(--ink-2); }
  .wait__mark { width: 2.6em; height: 2.6em; color: var(--ink-1); }
  .wait__line { font-family: var(--font-read); font-style: italic; font-size: var(--text-lg); color: var(--ink-1); max-width: 30ch; text-wrap: balance; animation: wait-breathe 6s var(--ease-in-out) infinite; }
  /* The breath bottoms out at 0.82: --ink-1 stays above 4.5:1 on the page all the way through. */
  @keyframes wait-breathe { 0%, 100% { opacity: 0.82; } 50% { opacity: 1; } }
  .wait__noscript a { color: var(--ink-1); }
  /* The story running on: written while the reader reads, so usually never seen. If the
     reader catches up, a quiet line at the end of the column, not the moment after a choice. */
  .wait--running { grid-auto-flow: column; justify-content: start; align-items: center; gap: var(--space-2); padding: var(--space-5) 0; text-align: left; }
  .wait--running .wait__mark { width: 1.5em; height: 1.5em; color: var(--ink-2); }
  .wait--running .wait__line { font-size: var(--text-md); max-width: none; }
  .wait--running .wait__slow { grid-column: 1 / -1; justify-items: start; text-align: left; }
  .wait:focus { outline: none; }
  .wait__slow { display: grid; justify-items: center; gap: var(--space-3); margin-top: var(--space-4); max-width: 34ch; text-wrap: balance; }
  @media (prefers-reduced-motion: reduce) { .wait__line { animation: none; opacity: 1; } }

  .decision { margin-top: var(--space-3); }
  .decision--continue { display: flex; justify-content: center; padding-block: var(--space-5); }
  /* With reader.js the story runs on by itself and "Read on" is only the no-script path. */
  .decision--continue.is-running { display: none; }
  /* Several ways at once: the checkbox stands where the numeral would, and a ticked
     row holds the wash the way a taken choice does. */
  .choices label.choice { cursor: pointer; }
  .choices label.choice::before { content: none; }
  .choices label.choice .check { grid-column: 1; grid-row: 1; justify-self: end; align-self: center; }
  .choices label.choice .choice__text { grid-column: 2; grid-row: 1; }
  .choices label.choice:has(:checked) { --marker: var(--rubric); background: var(--rubric-soft); }
  .choices label.choice:has(:focus-visible) { box-shadow: inset 3px 0 0 var(--rubric); }
  .choices .check input:checked { background: var(--rubric); border-color: var(--rubric); }

  .stalled { display: grid; gap: var(--space-3); padding: var(--space-6) 0; text-align: center; justify-items: center; }
  .stalled__line { font-family: var(--font-display); font-style: italic; font-size: var(--text-xl); color: var(--ink-1); }
  .stalled form { display: flex; gap: var(--space-2); flex-wrap: wrap; justify-content: center; }

  .passage__resting { font-family: var(--font-read); font-size: var(--text-md); color: var(--ink-1); max-width: 60ch; text-wrap: pretty; }

  /* The care screen (docs/distress-policy.md): outside the fiction, plain type, no ornament. */
  .care { display: grid; gap: var(--space-3); padding: var(--space-5) var(--space-4); margin: var(--space-5) 0; font-family: var(--font-ui); font-size: var(--text-md); color: var(--ink-1); background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--radius-md); max-width: 60ch; }
  .care__lead { font-family: var(--font-ui); font-weight: 600; font-size: var(--text-lg); line-height: 1.4; letter-spacing: 0; }
  .care__lead:focus { outline: none; }
  .care__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
  .care__item { display: grid; gap: 0.15em; padding: var(--space-2) 0; border-top: 1px solid var(--line); }
  .care__name { font-weight: 600; }
  .care__name a { color: inherit; }
  .care__contact { font-variant-numeric: tabular-nums; }

  .the-end__question { font-family: var(--font-read); font-style: italic; font-size: var(--text-lg); color: var(--ink-1); max-width: 34ch; text-wrap: balance; }

  /* "Something felt off?" (§25.7): quiet, under the page, never in the way. */
  .flag { margin: var(--space-4) 0 var(--space-2); font-family: var(--font-ui); }
  .flag__summary { display: inline-flex; align-items: center; min-height: 2.75rem; cursor: pointer; font-size: var(--text-sm); }
  .flag__summary:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-xs); }
  .flag__summary:hover { color: var(--ink-1); }
  .flag__form { display: flex; gap: var(--space-2); align-items: center; margin-top: var(--space-2); flex-wrap: wrap; }
  .flag__form .input { flex: 1; min-width: 14rem; }
  .flag__done { font-size: var(--text-sm); }
  .check-row { display: flex; gap: var(--space-2); align-items: flex-start; }

  .the-end { display: grid; justify-items: center; gap: var(--space-2); padding: var(--space-7) 0; text-align: center; }
  .the-end__mark { font-family: var(--font-display); font-style: italic; font-size: var(--text-3xl); color: var(--ink-0); }

  /* A page that receives focus after it is written is a landmark, not a control. */
  .beat:focus { outline: none; }

  /* Text size, in the "Aa" sheet. */
  .type-size__a { font-family: var(--font-read); line-height: 1; }
  .type-size__a--s { font-size: 0.85em; }
  .type-size__a--l { font-size: 1.2em; }
  .type-size__a--xl { font-size: 1.45em; }

  /* ---- The page turn (one beat per page) ---------------------------------- */
  .pager { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--space-3); margin-top: var(--space-7); padding-top: var(--space-4); border-top: 1px solid var(--line); font-family: var(--font-ui); font-size: var(--text-sm); }
  .pager__link { display: inline-flex; align-items: center; justify-self: start; gap: 0.4em; min-height: 2.75rem; min-width: 2.75rem; color: var(--ink-1); text-decoration: none; padding: var(--space-2) var(--space-2); border-radius: var(--radius-sm); transition: color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out); }
  .pager__link:hover { color: var(--ink-0); background: var(--paper-2); }
  .pager__link:focus-visible { outline: none; box-shadow: var(--ring); }
  .pager__link--next { justify-self: end; }
  .pager__link.is-disabled { color: var(--ink-3); pointer-events: none; }
  .pager__where { text-align: center; color: var(--ink-2); font-variant-numeric: tabular-nums; }
  .pager__where a { display: inline-flex; align-items: center; min-height: 2.75rem; color: inherit; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 0.3em; }
  .pager__where a:hover { color: var(--ink-0); text-decoration-color: currentColor; }
  .pager__where a:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-xs); }
  @media (max-width: 40rem) { .pager__link span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); } }

  /* ---- Contents (the table of pages) ------------------------------------- */
  .contents { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
  .contents__item { border-bottom: 1px solid var(--line); }
  .contents__link { display: grid; gap: 0.25em; padding: var(--space-3) var(--space-2); text-decoration: none; color: inherit; border-radius: var(--radius-sm); transition: background-color var(--dur-fast) var(--ease-out); }
  .contents__link:hover { background: var(--paper-2); }
  .contents__link:focus-visible { outline: none; box-shadow: var(--ring); }
  .contents__num { font-family: var(--font-ui); font-size: var(--text-2xs); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--ink-2); font-weight: 600; }
  .contents__opening { font-family: var(--font-read); font-size: var(--text-md); color: var(--ink-1); }
  .contents__marker { font-family: var(--font-read); font-style: italic; font-size: var(--text-sm); color: var(--ink-2); }
  .contents__marker .marker__mark { margin-right: 0.4em; }

  /* Metrics page tables (staff only). */
  .table-wrap { overflow-x: auto; }
  .data-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
  .data-table th, .data-table td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; }
  .data-table th { font-size: var(--text-2xs); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--ink-2); }
  .data-table .num { text-align: right; font-variant-numeric: tabular-nums; }
  .data-table tr.is-flagged td { background: var(--rubric-soft); }
}
