/* ============================================================
   A READER — four editions, one canonical DOM.

   STRUCTURE
     1. reset
     2. neutral shell  (colophon mark, panel, sheet, selection
                        popover, done control, drawer, modes)
     3. edition: letterpress
     4. edition: periodical
     5. edition: onionskin
     6. edition: quietpage
     7. responsive

   All chrome collapses into ONE in-flow colophon mark after the
   article. Reading mode shows no fixed chrome. Formatting is a
   selection popover. To add an edition: copy one edition section,
   retune, and register it in reader.js (EDITIONS).
   ============================================================ */

/* ---------- 1. reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

/* Chrome font: a clean, legible system sans used for ALL functional UI
   (action bar, colophon menu, sheet, drawer, quick dock) regardless of
   edition. The per-edition --font-ui faces (e.g. Letterpress's small-caps
   IM Fell) are beautiful but unreadable at control sizes — chrome should
   disappear into legibility, leaving the prose to carry the edition's voice. */
:root {
  --font-chrome: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --reading-scale: 1;
  --dock-gutter-offset: 9.5rem;
}
@media (max-width: 680px) {
  :root { --reading-scale: 1.1; }
}
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
ul { list-style: none; }
/* visible keyboard focus across all chrome (the editor keeps its caret-only focus
   via its own outline:none). Zero-specificity :where() so per-component looks win. */
:where(button, a, input, textarea, [role="button"], [tabindex]):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px;
}

/* Text-selection wash (the drag-select color), per edition × theme.
   Works on Chrome / Firefox / desktop Safari.
   KNOWN PLATFORM LIMITATION — verified on a real iPhone (iOS 26.5, WebKit
   605.1.15) with a side-by-side test: iOS Safari ignores ::selection background
   ENTIRELY — global or scoped, `background` or `background-color`, opaque or
   translucent — so on iPhone the selection stays the system default and there
   is NO css override. (The CSS Custom Highlight API does work there, which is
   why annotation highlights render; the native selection just can't be
   restyled.) Do not "fix" this again. Literal colors, since iOS also ignored
   var() here. ::-moz-selection covers Firefox. */
::selection      { background-color: rgba(122, 46, 46, 0.32); }   /* default (letterpress light) */
::-moz-selection { background-color: rgba(122, 46, 46, 0.32); }
html[data-edition="letterpress"] ::selection      { background-color: rgba(122, 46, 46, 0.32); }
html[data-edition="letterpress"] ::-moz-selection  { background-color: rgba(122, 46, 46, 0.32); }
html[data-edition="letterpress"][data-theme="dark"] ::selection      { background-color: rgba(199, 136, 79, 0.38); }
html[data-edition="letterpress"][data-theme="dark"] ::-moz-selection  { background-color: rgba(199, 136, 79, 0.38); }
html[data-edition="periodical"] ::selection      { background-color: rgba(160, 44, 32, 0.30); }
html[data-edition="periodical"] ::-moz-selection  { background-color: rgba(160, 44, 32, 0.30); }
html[data-edition="periodical"][data-theme="dark"] ::selection      { background-color: rgba(224, 122, 95, 0.34); }
html[data-edition="periodical"][data-theme="dark"] ::-moz-selection  { background-color: rgba(224, 122, 95, 0.34); }
html[data-edition="onionskin"] ::selection      { background-color: rgba(177, 49, 26, 0.30); }
html[data-edition="onionskin"] ::-moz-selection  { background-color: rgba(177, 49, 26, 0.30); }
html[data-edition="onionskin"][data-theme="dark"] ::selection      { background-color: rgba(212, 74, 49, 0.34); }
html[data-edition="onionskin"][data-theme="dark"] ::-moz-selection  { background-color: rgba(212, 74, 49, 0.34); }
html[data-edition="quietpage"] ::selection      { background-color: rgba(28, 28, 26, 0.18); }
html[data-edition="quietpage"] ::-moz-selection  { background-color: rgba(28, 28, 26, 0.18); }
html[data-edition="quietpage"][data-theme="dark"] ::selection      { background-color: rgba(217, 214, 203, 0.26); }
html[data-edition="quietpage"][data-theme="dark"] ::-moz-selection  { background-color: rgba(217, 214, 203, 0.26); }

/* highlight wash (shared; editions inherit unless they override) — 40% lighter */
html { --highlight: rgba(244, 212, 116, 0.33); }
html[data-theme="dark"] { --highlight: rgba(214, 182, 112, 0.16); }

/* themed scrollbar — thin, paper-toned (the persistent "how far am I" cue). */
html { scrollbar-width: thin; scrollbar-color: var(--ink-faint) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: var(--ink-faint); border-radius: 999px;
  border: 3px solid var(--bg);            /* inset look: thumb floats in the gutter */
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--ink-soft); }

/* ============================================================
   2. NEUTRAL SHELL
   ============================================================ */
html, body {
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background-color 0.5s ease, color 0.5s ease;
}
/* ONLY <html> carries the background (color + paper texture); <body> is
   transparent. This gives one continuous, seamless background across the
   whole scroll area — the previous seam came from <body> painting a solid
   color over the texture inside its box, then the textured <html> showing
   below the body's bottom edge. Scroll (not fixed) so the grain doesn't
   band or shift relative to the content. */
html {
  background-color: var(--bg);
  background-image: var(--body-texture, none);
  background-size: 320px 320px;
}
/* optional dot-grid "mesh" — a configurable paper texture over the reading column
   (Appearance ▸ Mesh). Distinct from each edition's organic --body-texture grain;
   layers on the .prose surface only, so it never fights the editions' .book paint.
   The dot tone adapts to light/dim for free. */
html { --mesh-dot: rgba(64, 48, 28, 0.05); }
html[data-theme="dark"] { --mesh-dot: rgba(224, 210, 184, 0.045); }
html[data-mesh="on"] .prose {
  background-image: radial-gradient(var(--mesh-dot) 1px, transparent 1px);
  background-size: 5px 5px;
}
body {
  background: transparent;
  padding: 3.5rem 1.25rem 6rem;
  min-height: 100vh;
  min-height: 100dvh;            /* dynamic viewport: no gap under a retracting mobile URL bar */
  overscroll-behavior: none;      /* blocks Android horizontal overscroll-nav + iOS pull-to-refresh mid-read */
}

/* visually hidden, still announced by screen readers */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* stage */
.stage { max-width: var(--measure); margin: 0 auto; position: relative; transition: max-width 0.4s ease; }

/* invitation (empty state) — slots filled by JS, styled per edition */
.invitation { padding: 7rem 1rem; animation: fade 0.8s ease both; }
.inv-head { font-weight: 400; }
.inv-head em, .inv-key span, .inv-key kbd { font: inherit; }

/* editor — neutral base; width/surface tuned per edition */
.editor {
  display: block; width: 100%; max-width: var(--editor-measure, 40rem); margin-inline: auto;
  min-height: 60vh; background: transparent; border: none; outline: none; cursor: text;
  color: var(--ink); font-family: var(--font-body);
  font-size: calc(var(--reading-base) * var(--reading-scale)); line-height: 1.72;
  resize: none; caret-color: var(--accent); word-wrap: break-word;
}
/* clear the fixed formatting bar while editing so it never covers text */
body[data-mode="edit"] .editor { padding-top: 3.4rem; }
/* live formatting inside the editor */
.editor :where(h1.t-title) { font-family: var(--font-display); font-size: 1.7rem; line-height: 1.2; margin: 0.2rem 0 0.6rem; }
.editor :where(h2.t-subtitle) { font-family: var(--font-display); font-size: 1.2rem; color: var(--ink-soft); margin: 0.2rem 0 0.8rem; }
.editor :where(p) { margin: 0 0 1em; }
.editor :where(blockquote) { margin: 1rem 0; padding-left: 1rem; border-left: 2px solid var(--rule); color: var(--ink-soft); font-style: italic; }
.editor :where(ul, ol) { margin: 0.8rem 0 0.8rem 1.4rem; }
.editor :where(hr) { border: none; border-top: 1px solid var(--rule); margin: 1.2rem 0; }
.editor :where(strong, b) { font-weight: 600; }
.editor :where(em, i) { font-style: italic; }
.editor :where(mark) { background: var(--highlight); color: inherit; }

/* rich content in the reading view */
.prose :where(strong, b) { font-weight: 600; }
.prose :where(em, i) { font-style: italic; }
.prose :where(u) { text-underline-offset: 2px; }
.prose :where(mark) { background: var(--highlight); color: inherit; padding: 0 0.06em; border-radius: 1px; }
.prose :where(blockquote) { margin: 1.7rem 0; padding-left: 1.3rem; border-left: 2px solid var(--rule); color: var(--ink-soft); font-style: italic; }
.prose :where(ul, ol) { margin: 1.1rem 0 1.1rem 1.5rem; }
.prose :where(li) { margin: 0.3rem 0; }
.prose :where(li)::marker { color: var(--ink-faint); }
/* Gap below a title block is a function of having a TITLE, not a byline.
   With a byline, the byline carries the gap; a title with NO byline (masthead
   or mid-page) carries it itself so body text never butts the title. */
.masthead .title:last-child,
.prose .t-title:not(:has(+ .t-subtitle)) { margin-bottom: var(--title-gap, 3.2rem); }

/* a soft stanza break (a single blank line the author typed): one empty line,
   then the next paragraph sits FLUSH (no indent, no drop cap). render() adds
   .spacer to the blank line and .loose to the paragraph after it. */
.prose p.spacer { margin: 0 !important; text-indent: 0 !important; }
.prose p.loose { text-indent: 0 !important; }

/* in-prose titles/subtitles inherit per-edition .title/.byline styling
   (render() adds those classes). They're h1/h2 elements, which default to
   bold — reset to normal weight so a mid-page heading matches the masthead
   (which uses div/normal); explicit per-edition weights still win (higher
   specificity). The margin gives a mid-page heading breathing room. */
.prose :where(.t-title) { margin-top: 2.2rem; font-weight: 400; }
.prose :where(.t-subtitle) { margin-top: 0.2rem; font-weight: 400; }

/* canonical-DOM defaults: optional slots hidden; editions opt in.
   eyebrow → quietpage only; meta → periodical + onionskin; colophon
   → letterpress (neutral style below), hidden by periodical/onionskin,
   restyled by quietpage. */
.eyebrow { display: none; }
.meta { display: none; }
.colophon {
  display: flex; justify-content: center; gap: 1rem; margin-top: 4rem;
  padding-top: 1.4rem; border-top: 1px solid var(--rule);
  /* a system mono for the word/time counters — its even, fixed-width digits
     read cleanly as metadata; display serifs (esp. Letterpress's IM Fell)
     render numerals poorly. Zero extra font load. */
  font-family: ui-monospace, SFMono-Regular, Menlo, "Cascadia Mono", Consolas, "Liberation Mono", monospace;
  font-size: 0.64rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--ink-faint);
}
.col-sep { opacity: 0.4; }

/* callouts (boxed aside) vs plain quote */
:where(.prose, .editor) blockquote.callout {
  font-style: normal; border-left: 3px solid var(--accent); background: var(--rule-soft);
  padding: 0.9rem 1.15rem; border-radius: 2px; margin: 1.7rem 0; color: var(--ink);
}

/* selectable separator styles (override the edition default) */
:where(.prose, .editor) :is(hr.rule-asterism, hr.rule-dots, hr.rule-fleuron, hr.rule-stars, hr.rule-diamond) {
  border: none; height: auto; text-align: center; line-height: 1; color: var(--accent); margin: 2.1rem 0 1.7rem;
}
:where(.prose, .editor) hr.rule-asterism::after { content: '⁂'; font-size: 1.4rem; }
:where(.prose, .editor) hr.rule-dots::after     { content: '· · ·'; font-size: 1rem; letter-spacing: 0.5em; }
:where(.prose, .editor) hr.rule-fleuron::after  { content: '❦'; font-size: 1.5rem; }
:where(.prose, .editor) hr.rule-stars::after    { content: '✦  ✦  ✦'; font-size: 0.85rem; letter-spacing: 0.1em; }
:where(.prose, .editor) hr.rule-diamond::after  { content: '◆ ◆ ◆'; font-size: 0.6rem; letter-spacing: 0.5em; }
:where(.prose, .editor) hr.rule-line { border: none; border-top: 1px solid var(--rule); width: 5rem; height: 0; margin: 2.4rem auto; }

/* ---------- the colophon mark: single in-flow trigger ---------- */
.colophon-foot { display: flex; flex-direction: column; align-items: center; position: relative; margin-top: 3.2rem; }
/* hide the mark in the empty state until there's something to read */
body[data-mode="read"][data-empty="true"] .colophon-foot { display: none; }
.mark {
  position: relative; width: 3.4rem; height: 3.4rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-faint); opacity: 0.5;
  transition: opacity 0.45s ease, color 0.25s ease, background-color 0.4s ease, transform 0.3s ease;
}
.mark:hover { opacity: 1; color: var(--accent); }
.mark-glyph { font-family: var(--font-display); font-size: 1.6rem; line-height: 1; }
.mark-done { display: none; }
.mark-done svg { width: 1.4rem; height: 1.4rem; stroke: currentColor; fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
/* idle: fade the mark further while reading */
html[data-idle="true"][data-mode="read"] .mark { opacity: 0.16; }
html[data-idle="true"][data-mode="read"] .mark:hover { opacity: 1; }

/* ---------- desktop inline panel (blooms upward from the mark) ---------- */
.panel {
  position: absolute; bottom: calc(100% + 0.8rem); left: 50%;
  transform: translateX(-50%) translateY(6px) scale(0.98); transform-origin: bottom center;
  width: min(27rem, calc(100vw - 2rem)); z-index: 22;
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  border-radius: 9px; padding: 0.7rem; font-family: var(--font-chrome);
  opacity: 0; visibility: hidden;
  transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.2,0.7,0.2,1), visibility 0.22s ease;
}
.colophon-foot.open .panel { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0) scale(1); }
.panel-row { display: flex; align-items: center; gap: 0.4rem; }
.panel-actions { gap: 0.3rem; }
.panel-div { height: 1px; background: var(--rule); margin: 0.55rem 0.2rem; }
.panel-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 0.42rem;
  padding: 0.62rem 0.5rem; border-radius: 6px; color: var(--ink-soft);
  font-size: 0.84rem; letter-spacing: 0.01em;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.panel-btn:hover { background: var(--rule-soft); color: var(--ink); }
.panel-btn .pi { font-size: 1em; opacity: 0.8; }
.panel-wide { justify-content: flex-start; padding-left: 0.7rem; }
.panel-field { padding: 0.25rem 0.3rem; gap: 0.6rem; flex-wrap: wrap; }
.panel-label { font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }
.panel-label-2 { margin-left: auto; }
.panel-editions { display: flex; flex-wrap: wrap; gap: 0.25rem; }
.panel-editions button {
  font-family: var(--font-chrome); font-size: 0.8rem; letter-spacing: 0; color: var(--ink-soft);
  padding: 0.36rem 0.55rem; border-radius: 5px; transition: background-color 0.15s ease, color 0.15s ease;
}
.panel-editions button:hover { background: var(--rule-soft); color: var(--ink); }
.panel-editions button[aria-current="true"] { background: var(--rule-soft); color: var(--accent); }
.seg { display: inline-flex; align-items: center; gap: 0.1rem; border: 1px solid var(--rule); border-radius: 6px; padding: 0.1rem; }
.seg button { padding: 0.3rem 0.55rem; border-radius: 4px; color: var(--ink-soft); font-size: 0.82rem; transition: background-color 0.15s ease, color 0.15s ease; }
.seg button:hover { background: var(--rule-soft); color: var(--ink); }
.seg-mid { font-size: 0.8rem; color: var(--ink-faint); padding: 0 0.3rem; }
.panel-theme { padding: 0.36rem 0.75rem; border: 1px solid var(--rule); border-radius: 6px; color: var(--ink-soft); font-size: 0.8rem; transition: color 0.15s ease, border-color 0.15s ease; }
.panel-theme:hover { color: var(--accent); border-color: var(--accent); }

/* ---------- floating quick-dock (Library / Share / Theme / Text size) --------
   Desktop: a VERTICAL cluster floating in the left gutter (JS sets its `left`
   to the midpoint between the screen edge and the page card), with its TOP
   aligned to the top of the page content card, receding while the reader is idle.
   Mobile: hidden until a right-edge swipe reveals it from the right; it then
   auto-hides after 3s (see reader.js). */
.quick-dock {
  position: fixed; top: 3.5rem; left: max(8px, calc((100vw - var(--measure, 38rem)) / 2 - var(--dock-gutter-offset))); z-index: 27;   /* JS refines this once the page column is measured */
  display: flex; flex-direction: column; align-items: center; gap: 0.08rem;
  padding: 0.3rem 0.24rem; border-radius: 12px;
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  font-family: var(--font-chrome);
  opacity: 0.72;
  transition: opacity 0.3s ease, transform 0.34s cubic-bezier(0.2,0.8,0.2,1), visibility 0.34s ease;
}
.quick-dock:hover { opacity: 1; }
.quick-dock button {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.95rem; height: 1.95rem; padding: 0 0.45rem; border-radius: 7px;
  color: var(--ink-soft); font-size: 0.82rem; line-height: 1;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.quick-dock button:hover { background: var(--rule-soft); color: var(--ink); }
.quick-dock button[hidden] { display: none; }   /* the dock's display:inline-flex would otherwise override the UA hidden rule */
.quick-dock button.qd-text { letter-spacing: 0.02em; }
.quick-dock svg { width: 1.05rem; height: 1.05rem; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.qd-div { width: 1.15rem; height: 1px; background: var(--rule); margin: 0.16rem 0; }
.quick-dock .qd-bookmarks.active { color: var(--accent); }
.quick-dock .qd-bookmarks.active svg { fill: color-mix(in srgb, var(--accent) 24%, transparent); }

/* Page controls. Bookmarks store a reading location and the page sheets expose
   their own visual markers without changing prose text. */
.page-hud {
  position: fixed; right: max(1.15rem, calc((100vw - var(--measure, 38rem)) / 2 - 10.25rem)); bottom: calc(3.5rem + env(safe-area-inset-bottom)); z-index: 18;
  display: inline-flex; flex-direction: column; align-items: center; gap: 0.12rem;
  padding: 0.22rem 0.18rem; border-radius: 999px; background: var(--page);
  border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  color: var(--ink-soft); font-family: var(--font-chrome);
  opacity: 0.72; transition: opacity 0.2s ease, transform 0.2s ease;
}
.page-hud[hidden] { display: none; }
.page-hud:hover, .page-hud:focus-within { opacity: 1; }
.page-hud button {
  width: 1.85rem; height: 1.85rem; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-faint); transition: color 0.15s ease, background-color 0.15s ease;
}
.page-hud button:hover { color: var(--accent); background: var(--rule-soft); }
.page-hud svg { width: 1rem; height: 1rem; stroke: currentColor; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.page-hud button:first-of-type svg,
.page-hud button:last-of-type svg { transform: rotate(90deg); }
.page-hud [data-page-label] {
  min-width: 0; min-height: 3.4rem; padding: 0.12rem 0;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.04rem;
  text-align: center; font-size: 0.64rem;
  letter-spacing: 0.08em; color: var(--ink-faint);
}
.page-hud [data-page-label] span { min-width: 0; line-height: 1; }
.page-label-sep { font-size: 0.62rem; color: var(--ink-faint); }
.page-label-current,
.page-label-total { font-size: 0.72rem; color: var(--ink-soft); }
html[data-idle="true"] .page-hud:not(:hover):not(:focus-within) { opacity: 0.2; }
body[data-mode="edit"] .page-hud,
html[data-welcome="true"] .page-hud,
html[data-feedback] .page-hud { display: none !important; }
@media (max-width: 680px) {
  .page-hud { display: none !important; }
}
/* dock labels — name each control to the LEFT of the vertical dock. An icon
   alone is ambiguous (what does the eye do?), so the label spells it out.
   Desktop: reveal on hover / keyboard focus. Mobile: shown whenever the dock is
   swiped in (no hover on touch), each over a soft page-colored pill so the text
   never blends into the prose underneath. */
.quick-dock button { position: relative; }
.quick-dock button[data-label]::after {
  content: attr(data-label);
  position: absolute; right: calc(100% + 0.5rem); top: 50%; transform: translateY(-50%);
  white-space: nowrap; pointer-events: none;
  font-family: var(--font-chrome); font-size: 0.72rem; letter-spacing: 0.01em; color: var(--ink);
  background: var(--page); padding: 0.32rem 0.6rem; border-radius: 7px;
  border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  opacity: 0; transition: opacity 0.14s ease;
}
@media (min-width: 681px) {
  .quick-dock button[data-label]:hover::after,
  .quick-dock button[data-label]:focus-visible::after { opacity: 1; }
}
/* tight left gutter (narrow desktop / narrow edition): JS flips labels to the
   RIGHT of the dock so they don't clip off the screen edge (M9). */
.quick-dock.labels-right button[data-label]::after { right: auto; left: calc(100% + 0.5rem); }
@media (max-width: 680px) {
  .quick-dock.docked button[data-label]::after { opacity: 1; }
  /* Keep each label on ONE readable line (the base rule's white-space: nowrap),
     just cap its width so a long one can't run off a small phone's left edge —
     clipping with an ellipsis rather than wrapping into a tall, broken pill. */
  .quick-dock button[data-label]::after { max-width: calc(100vw - 4.5rem); overflow: hidden; text-overflow: ellipsis; }
}
/* while editing, keep a SLIM dock (Index / New / Edition / Theme / Text) so a
   blank or new page is always escapable — tap Index to bail to the library.
   Hide the redundant Edit + Share (the Done FAB handles exit) and the eye. */
body[data-mode="edit"] .quick-dock .qd-edit,
body[data-mode="edit"] .quick-dock .qd-share,
body[data-mode="edit"] .quick-dock .qd-toc,
body[data-mode="edit"] .quick-dock .qd-toc-div,
body[data-mode="edit"] .quick-dock .qd-bookmarks,
body[data-mode="edit"] .quick-dock .qd-bookmarks-div,
body[data-mode="edit"] .quick-dock .qd-attn,
body[data-mode="edit"] .quick-dock .qd-anno,
body[data-mode="edit"] .quick-dock .qd-anno-div { display: none; }
/* on the public share view the dock stays (Theme / Text / annotations toggle),
   but the author-only actions (Library / Edit / Share) are hidden — and the
   author sign-in affordance appears in their place. */
html[data-public] .quick-dock .qd-owner { display: none; }
.quick-dock .qd-signin { display: none; }
html[data-public] .quick-dock button.qd-signin { display: inline-flex; }
html[data-public] .quick-dock span.qd-signin { display: block; }
/* edition picker popover, floated beside the dock's edition button */
.edition-pop {
  position: fixed; z-index: 28; left: 0; top: 0;
  display: none; flex-direction: column; gap: 0.1rem;
  padding: 0.3rem; border-radius: 10px;
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  font-family: var(--font-chrome);
}
.edition-pop.open { display: flex; animation: fade 0.16s ease both; }
.edition-pop button {
  display: block; width: 100%; text-align: left; white-space: nowrap;
  font-size: 0.82rem; color: var(--ink-soft);
  padding: 0.46rem 0.7rem; border-radius: 6px;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.edition-pop button:hover { background: var(--rule-soft); color: var(--ink); }
.edition-pop button[aria-current="true"] { background: var(--rule-soft); color: var(--accent); }
/* appearance popover — edition chips (built by JS) sit above the Theme/Mesh toggle rows */
.appear-pop .appear-toggles { margin-top: 0.3rem; padding-top: 0.34rem; border-top: 1px solid var(--rule-soft); }
.appear-pop .appear-toggle { display: flex; align-items: center; justify-content: space-between; gap: 1.4rem; }
.appear-pop .appear-toggle .at-v { color: var(--ink-faint); font-size: 0.76rem; }
.appear-pop .appear-toggle:hover .at-v { color: var(--accent); }
/* desktop only: recede while idle */
@media (min-width: 681px) {
  html[data-idle="true"] .quick-dock:not(:hover):not(:focus-within) { opacity: 0.12; }
  html[data-public] .quick-dock button.qd-signin[data-label]::after { opacity: 0; }
  html[data-public] .quick-dock button.qd-signin[data-label]:hover::after,
  html[data-public] .quick-dock button.qd-signin[data-label]:focus-visible::after {
    opacity: 1;
  }
}
/* === Mobile dock — feathered labelled cluster ================================
   On mobile the dock sheds its pill: it's a vertical icon column with each control's
   label floating to its LEFT (glowing over the prose, no chips), the whole cluster
   sitting in a soft page-coloured pool that emerges from the right and slides in WITH
   it. The pool is the dock's own ::before (NOT a fixed overlay → the old iOS band can't
   recur) and it's pulled out far enough that even the longest label sits inside its
   feather. Thin separators fan out from each icon and fade toward the text, so it reads
   as a menu without hard chrome. var(--page)/var(--ink) ⇒ adapts to every edition + dim
   mode. Scoped to ≤680px — the desktop pill + hover tooltips are untouched. */
@media (max-width: 680px) {
  .quick-dock {
    top: 50%; left: auto; right: 0; margin-right: 0.55rem;
    transform: translateY(-50%) translateX(calc(100% + 1rem));
    opacity: 0; visibility: hidden; pointer-events: none;
    background: none; border-color: transparent; box-shadow: none;   /* no pill — the pool is the backdrop */
    gap: 0.34rem;
  }
  .quick-dock.docked { transform: translateY(-50%) translateX(0); opacity: 1; visibility: visible; pointer-events: auto; }

  /* labels float to the LEFT of each icon (the base rule's absolute ::after), shown on
     mobile with a soft page-colour halo so they stay legible over the prose; opacity:1
     (not .docked-gated) so they slide in WITH the cluster instead of popping in at the end. */
  .quick-dock button[data-label]::after {
    opacity: 1; pointer-events: auto;                       /* tappable — a tap on the LABEL fires the button, not just the icon */
    right: calc(100% + 0.2rem);                             /* sit the label close to its icon so the pair reads as one menu item */
    max-width: none; overflow: visible; line-height: 1.5;   /* no clip → descenders (g, y, p) render in full */
    background: none; border: none; box-shadow: none; padding: 0.3rem 0.05rem 0.3rem 0.55rem;   /* tiny right pad so text hugs the icon; left pad keeps the tap target */
    font-size: 0.85rem; letter-spacing: 0.005em;            /* up from 0.74rem — was too tiny */
    text-shadow: 0 0 5px var(--page), 0 0 5px var(--page), 0 0 10px var(--page);
  }
  .quick-dock svg { width: 1.16rem; height: 1.16rem; }      /* up from the base 1.05rem to match the larger labels */
  /* subtle separators — a thin rule that starts at each icon and fades toward the text,
     giving the cluster the structure of a menu with no hard chrome. color-mix keeps it
     ink-toned in every edition + dim mode; falls back to var(--rule) on older engines. */
  .quick-dock button[data-label]:not(:last-child)::before {
    content: ''; position: absolute; right: 0.2rem; bottom: -0.2rem; height: 1px; width: 12rem;
    pointer-events: none;
    background: linear-gradient(to left, var(--rule), transparent 74%);
    background: linear-gradient(to left, color-mix(in srgb, var(--ink) 22%, transparent), transparent 74%);
  }
  .qd-div { display: none; }   /* the per-item separators replace the group dividers on mobile */
  /* …including the sign-in divider, which the public-view rule (html[data-public] span.qd-signin
     { display:block }) otherwise re-shows on mobile — stacking a 2nd hairline next to the sign-in
     button's separator. That double line was the reader-only "two thin lines above Appearance". */
  html[data-public] .quick-dock span.qd-signin { display: none; }

  /* the feathered pool — a soft page-colour cloud emerging from the right, pulled out so
     even the longest label sits in its feather. The radial is DENSE vertically (130% — no
     vertical fade) so every item top-to-bottom is covered, and feathers only horizontally
     (left); a separate vertical mask softens the top + bottom edges. Decoupling the two
     axes is what lets the cloud reach the FIRST and LAST items while still dissolving
     softly on every side. To roll back the pool: delete this ::before rule. */
  .quick-dock::before {
    content: ''; position: absolute; z-index: -1; pointer-events: none;
    top: 50%; right: -0.9rem; transform: translateY(-50%);
    width: 24rem; height: calc(100% + 5rem);
    background: radial-gradient(80% 130% at 100% 50%, var(--page) 56%, transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent);
            mask-image: linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent);
  }
}
/* ============================================================================ */


/* ---------- formatting bar (sticky at the top during edit mode) ----------
   A persistent bar — not a selection popover — so block actions (Title,
   Subtitle, Quote, Callout, separator) work on the current line even when
   it's blank with nothing to select. Inline marks still apply to a
   selection. Centered, scrollable on narrow screens. */
.sel-pop {
  /* centered WITHOUT a transform: a transformed ancestor becomes the containing
     block for position:fixed children and would clip the separator dropdown
     against this bar's own overflow box. Auto-margins center it instead. */
  position: fixed; top: 0; left: 0; right: 0; margin-inline: auto; width: max-content;
  z-index: 28; display: none; align-items: center; gap: 0.15rem;
  margin-top: 0.7rem; background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  border-radius: 8px; padding: 0.32rem 0.42rem; font-family: var(--font-chrome);
  opacity: 0; transition: opacity 0.18s ease;
  max-width: calc(100vw - 1rem); overflow-x: auto;
}
.sel-pop.show { display: flex; opacity: 1; }
@media (max-width: 640px) { .sel-pop { left: 0.5rem; right: 0.5rem; width: auto; margin-inline: 0; max-width: none; } }
.sel-pop button {
  font: inherit; font-size: 0.82rem; letter-spacing: 0; color: var(--ink-soft);
  padding: 0.44rem 0.6rem; border-radius: 4px; line-height: 1; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 0.25rem;
  transition: background-color 0.15s ease, color 0.15s ease;
}
@media (max-width: 680px) {
  .sel-pop button { min-height: 44px; padding-inline: 0.7rem; }
  .fb-caret { padding-inline: 0.6rem !important; }
  .fb-rules button { min-height: 44px; }
}
.sel-pop button:hover { background: var(--rule-soft); color: var(--ink); }
.sel-pop button.active { background: var(--rule-soft); color: var(--accent); }
.sel-pop [data-cmd="bold"] b { font-weight: 700; }
.sel-pop [data-cmd="italic"] i { font-style: italic; font-family: var(--font-body); }
.sel-pop [data-cmd="break"] { font-size: 0.95rem; line-height: 0.7; }
.fb-hl { background: var(--highlight); border-radius: 2px; padding: 0 0.22em; }
.fb-sep { width: 1px; align-self: stretch; background: var(--rule); margin: 0.25rem 0.2rem; }

/* separator-style picker (used inside the popover).
   position:fixed + JS-set top/left so it escapes the action bar's overflow
   clip (the bar scrolls horizontally on narrow screens). */
.fb-group { position: relative; display: inline-flex; align-items: center; }
.fb-caret { font-size: 0.62rem !important; padding: 0.45rem 0.34rem !important; }
.fb-rules {
  position: fixed; top: 0; left: 0; z-index: 30;
  transform: translateY(-4px);
  display: flex; flex-direction: column; min-width: 12rem; padding: 0.3rem;
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow); border-radius: 6px;
  opacity: 0; visibility: hidden; transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease;
}
.fb-group.open .fb-rules { opacity: 1; visibility: visible; transform: translateY(0); }
.fb-rules button { justify-content: flex-start; gap: 0.5rem; width: 100%; font-size: 0.82rem; padding: 0.5rem 0.6rem; }

/* ---------- single Done control while editing ---------- */
.done-fab {
  position: fixed; bottom: calc(1.6rem + env(safe-area-inset-bottom)); left: 50%; transform: translateX(-50%) translateY(8px);
  z-index: 19; display: none; align-items: center; gap: 0.5rem;
  background: var(--page); border: 1px solid var(--rule); box-shadow: var(--shadow);
  color: var(--ink-soft); padding: 0.6rem 1.1rem; min-height: 44px; border-radius: 999px;
  font-family: var(--font-ui); font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase;
  opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease, color 0.2s ease, border-color 0.2s ease;
}
.done-fab svg { width: 0.95rem; height: 0.95rem; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.done-fab:hover { color: var(--accent); border-color: var(--accent); }
body[data-mode="edit"] .done-fab { display: inline-flex; opacity: 0.92; transform: translateX(-50%) translateY(0); }

/* ---------- mobile bottom sheet ---------- */
.sheet-scrim {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 32;
  opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease;
}
html[data-sheet="open"] .sheet-scrim { opacity: 1; visibility: visible; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 33;
  background: var(--page); box-shadow: var(--shadow);
  border-radius: 16px 16px 0 0; padding: 0.7rem 1.2rem calc(1.4rem + env(safe-area-inset-bottom));
  transform: translateY(102%); transition: transform 0.4s cubic-bezier(0.2,0.7,0.2,1);
}
html[data-sheet="open"] .sheet { transform: none; }
.sheet-grip { width: 2.4rem; height: 0.28rem; border-radius: 999px; background: var(--rule); margin: 0.3rem auto 1.1rem; }
.sheet-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(4.2rem, 1fr)); gap: 0.5rem; margin-bottom: 1.1rem; }
.sheet-act {
  display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
  padding: 0.85rem 0.3rem; border-radius: 10px; background: var(--rule-soft);
  color: var(--ink); font-family: var(--font-chrome); font-size: 0.78rem; letter-spacing: 0.01em;
}
.sheet-act .pi { font-size: 1.2rem; opacity: 0.85; }
.sheet-act:active { background: var(--rule); }
.sheet-field { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.7rem 0; border-top: 1px solid var(--rule-soft); }
.sheet-label { font-family: var(--font-chrome); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }
.sheet-editions { display: flex; flex-wrap: wrap; gap: 0.4rem; justify-content: flex-end; }
.sheet-editions button { font-family: var(--font-chrome); font-size: 0.82rem; color: var(--ink-soft); padding: 0.48rem 0.75rem; border-radius: 7px; background: var(--rule-soft); }
.sheet-editions button[aria-current="true"] { color: var(--accent); background: var(--rule); }
.seg-lg button { padding: 0.52rem 0.85rem; font-size: 0.9rem; }
.sheet-theme { padding: 0.52rem 1rem; border: 1px solid var(--rule); border-radius: 8px; color: var(--ink-soft); font-family: var(--font-chrome); font-size: 0.85rem; }

/* ---------- table of contents — bottom sheet (mobile), floating card (desktop) ---------- */
.toc-scrim {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 34;
  opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease;
}
html[data-toc="open"] .toc-scrim { opacity: 1; visibility: visible; }
.toc-sheet {
  position: fixed; left: 50%; bottom: 0; z-index: 35;
  width: min(34rem, 100%); transform: translate(-50%, 102%);
  display: flex; flex-direction: column; max-height: min(72vh, 72dvh);
  background: var(--page); box-shadow: var(--shadow);
  border-radius: 16px 16px 0 0;
  padding: 0 1.3rem calc(1rem + env(safe-area-inset-bottom));
  transition: transform 0.4s cubic-bezier(0.2,0.7,0.2,1);
}
html[data-toc="open"] .toc-sheet { transform: translate(-50%, 0); }
.toc-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 0 0.7rem; border-bottom: 1px solid var(--rule-soft);
}
.toc-title { font-family: var(--font-chrome); font-size: 0.7rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-faint); }
.toc-close { font-size: 1.5rem; line-height: 1; color: var(--ink-faint); padding: 0.1rem 0.5rem; transition: color 0.2s ease; }
.toc-close:hover { color: var(--ink); }
.toc-list { overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 0.3rem 0 0.2rem; }
.toc-item {
  display: flex; align-items: baseline; gap: 0.7rem; width: 100%; text-align: left;
  font-family: var(--font-body); font-size: 1.02rem; color: var(--ink-soft);
  padding: 0.78rem 0.4rem; border-bottom: 1px solid var(--rule-soft); border-radius: 6px;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.toc-item:last-child { border-bottom: none; }
.toc-item:hover { background: var(--rule-soft); color: var(--ink); }
.toc-item .toc-n { font-family: var(--font-ui); font-size: 0.72rem; color: var(--ink-faint); min-width: 1.2rem; flex: 0 0 auto; }

/* ---------- bookmarks — bottom sheet (mobile), floating card (desktop) ---------- */
.bookmark-scrim {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 34;
  opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease;
}
html[data-bookmarks="open"] .bookmark-scrim { opacity: 1; visibility: visible; }
.bookmark-panel {
  position: fixed; left: 50%; bottom: 0; z-index: 35;
  width: min(34rem, 100%); transform: translate(-50%, 102%);
  display: flex; flex-direction: column; max-height: min(76vh, 76dvh);
  background: var(--page); box-shadow: var(--shadow);
  border-radius: 16px 16px 0 0;
  padding: 0 1.3rem calc(1rem + env(safe-area-inset-bottom));
  transition: transform 0.4s cubic-bezier(0.2,0.7,0.2,1);
}
html[data-bookmarks="open"] .bookmark-panel { transform: translate(-50%, 0); }
.bookmark-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 0 0.7rem; border-bottom: 1px solid var(--rule-soft);
}
.bookmark-title { font-family: var(--font-chrome); font-size: 0.7rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-faint); }
.bookmark-close { font-size: 1.5rem; line-height: 1; color: var(--ink-faint); padding: 0.1rem 0.5rem; transition: color 0.2s ease; }
.bookmark-close:hover { color: var(--ink); }
.bookmark-tools {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.8rem 0; border-bottom: 1px solid var(--rule-soft);
}
.bookmark-add {
  display: inline-flex; align-items: center; gap: 0.45rem; min-height: 44px;
  color: var(--accent); font-family: var(--font-chrome); font-size: 0.76rem;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.bookmark-add svg { width: 1rem; height: 1rem; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linejoin: round; }
.bookmark-page { font-family: var(--font-chrome); font-size: 0.7rem; color: var(--ink-faint); white-space: nowrap; }
.bookmark-list { overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 0.35rem 0 0.2rem; }
.bookmark-empty { padding: 1.2rem 0.4rem; font-family: var(--font-body); font-style: italic; color: var(--ink-faint); }
.bookmark-item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.25rem;
  border-bottom: 1px solid var(--rule-soft);
}
.bookmark-item:last-child { border-bottom: none; }
.bm-jump {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: baseline; gap: 0.7rem;
  width: 100%; text-align: left; padding: 0.78rem 0.4rem; border-radius: 6px;
  transition: background-color 0.15s ease;
}
.bm-jump:hover { background: var(--rule-soft); }
.bm-page { font-family: var(--font-chrome); font-size: 0.68rem; color: var(--accent); white-space: nowrap; }
.bm-label {
  min-width: 0; font-family: var(--font-body); font-size: 0.98rem; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bm-del {
  width: 2.2rem; height: 2.2rem; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-faint); font-size: 1.2rem; opacity: 0.65;
}
.bm-del:hover { color: var(--accent); background: var(--rule-soft); opacity: 1; }

/* desktop (≥681px): a compact floating index card in the upper-right — no page dimming.
   The scrim stays in place but goes transparent, so an outside click still closes it
   (no JS change needed). The card itself sits above the scrim and fades up on open. */
@media (min-width: 681px) {
  .toc-scrim { background: transparent; }
  .toc-sheet {
    left: auto; right: 2.5rem; bottom: auto; top: 4.5rem;
    width: 17rem; max-height: min(70vh, 70dvh);
    border-radius: 14px; border: 1px solid var(--rule-soft);
    box-shadow: 0 12px 36px rgba(0,0,0,0.18);
    padding: 0 1.1rem 0.7rem;
    transform: translateY(-8px); opacity: 0; visibility: hidden;
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  }
  html[data-toc="open"] .toc-sheet { transform: translateY(0); opacity: 1; visibility: visible; }
  .bookmark-scrim { background: transparent; }
  .bookmark-panel {
    left: auto; right: 2.5rem; bottom: auto; top: 4.5rem;
    width: 20rem; max-height: min(72vh, 72dvh);
    border-radius: 14px; border: 1px solid var(--rule-soft);
    box-shadow: 0 12px 36px rgba(0,0,0,0.18);
    padding: 0 1.1rem 0.7rem;
    transform: translateY(-8px); opacity: 0; visibility: hidden;
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  }
  html[data-bookmarks="open"] .bookmark-panel { transform: translateY(0); opacity: 1; visibility: visible; }
}

/* in-reader attention overlay: paragraphs tinted by reader dwell (author toggle) */
.quick-dock .qd-attn.on { color: #b5532e; }
.quick-dock .qd-attn.on svg { stroke: #b5532e; }
.prose > .att { border-radius: 5px; transition: background-color 0.35s ease; }


/* reader swipe coachmark (mobile, public view) — train new readers to swipe LEFT
   for the menu. Prominent pill with an exaggerated demo: a touch dot sweeps left
   past left-pointing chevrons, mimicking the gesture. */
.swipe-hint { position: fixed; left: 50%; bottom: calc(2.4rem + env(safe-area-inset-bottom)); transform: translateX(-50%);
  z-index: 33; display: none; align-items: center; gap: 0.55rem; padding: 0.6rem 1.1rem 0.6rem 0.8rem;
  background: var(--page); color: var(--ink); border: 1.5px solid var(--accent); border-radius: 999px;
  box-shadow: 0 6px 22px rgba(0,0,0,0.24); font-family: var(--font-chrome); font-size: 0.92rem; font-weight: 600;
  letter-spacing: 0.01em; cursor: pointer; opacity: 0; pointer-events: none; transition: opacity 0.4s ease; }
@media (max-width: 680px) { .swipe-hint { display: flex; } }   /* mobile only; JS toggles .on */
/* stays pointer-events:none even when shown — a swipe that STARTS on the hint must fall
   through to the page so it registers as the reveal gesture (people aim at the hint). */
.swipe-hint.on { opacity: 1; animation: sh-bob 2.4s ease-in-out infinite; }
@keyframes sh-bob { 0%, 100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(-3px); } }
.swipe-hint .sh-text { white-space: nowrap; }
/* the gesture demo */
.swipe-hint .sh-demo { position: relative; width: 2.9rem; height: 1.3rem; flex: none; }
.swipe-hint .sh-chevrons { position: absolute; inset: 0; width: 100%; height: 100%;
  stroke: var(--accent); fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; opacity: 0.4; }
.swipe-hint .sh-finger { position: absolute; top: 50%; left: 50%; width: 0.95rem; height: 0.95rem; border-radius: 50%;
  background: var(--accent); box-shadow: 0 1px 4px rgba(0,0,0,0.3); transform: translate(-50%, -50%);
  animation: sh-swipe 1.8s cubic-bezier(.5,0,.2,1) infinite; }
@keyframes sh-swipe {
  0%   { left: 92%; opacity: 0; transform: translate(-50%,-50%) scale(0.6); }
  16%  { opacity: 1; transform: translate(-50%,-50%) scale(1); }
  62%  { left: 8%;  opacity: 1; transform: translate(-50%,-50%) scale(1); }
  80%  { left: 8%;  opacity: 0; transform: translate(-50%,-50%) scale(0.7); }
  100% { left: 8%;  opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .swipe-hint.on { animation: none; }
  .swipe-hint .sh-finger { animation: none; left: 8%; opacity: 1; transform: translate(-50%,-50%); }
}

/* name wall (public readers) — a Medium-style soft gate: the page fades + blurs out
   below, and a card asks the reader for a name. Self-ID is the single identity.
   Fades in; clears instantly on submit. */
.namewall { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  height: min(56vh, 32rem); display: flex; align-items: flex-end; justify-content: center;
  opacity: 0; transition: opacity 0.45s ease; }
.namewall.on { opacity: 1; }
.namewall[hidden] { display: none; }
/* the fade: content behind dissolves into the page colour, with the blur masked to
   ramp up toward the bottom so the transition reads as "fading out", not a hard line */
.namewall-veil { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 0%, transparent) 0%, var(--bg) 52%);
  -webkit-backdrop-filter: blur(2.5px); backdrop-filter: blur(2.5px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 38%); mask-image: linear-gradient(to bottom, transparent 0%, #000 38%); }
.namewall-card { position: relative; z-index: 1; width: min(30rem, 92vw); margin: 0 auto 2.4rem;
  padding: 0 1.2rem; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0.7rem; }
.namewall-mark { font-family: var(--font-display, var(--font-body)); font-size: 1.5rem; color: var(--accent); line-height: 1; }
.namewall-card h2 { font-family: var(--font-display, var(--font-body)); font-weight: 400; font-size: 1.55rem;
  margin: 0; color: var(--ink); letter-spacing: 0.01em; }
.namewall-card p { font-family: var(--font-body); font-size: 0.98rem; line-height: 1.5; color: var(--ink-soft); margin: 0; max-width: 24rem; }
.namewall-card input { width: 100%; box-sizing: border-box; padding: 0.72rem 0.95rem; font-size: 1rem; font-family: var(--font-body);
  border: 1px solid var(--rule); border-radius: 9px; background: var(--page); color: var(--ink); margin-top: 0.25rem; }
.namewall-card input:focus { outline: none; border-color: var(--ink-faint); }
.namewall-card input.shake { animation: nw-shake 0.35s ease; }
@keyframes nw-shake { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-6px); } 50% { transform: translateX(5px); } 75% { transform: translateX(-3px); } }
@media (prefers-reduced-motion: reduce) { .namewall-card input.shake { animation: none; border-color: var(--accent); } }
.namewall-card button[data-namewall-go] { width: 100%; font-family: var(--font-chrome); font-size: 0.9rem; letter-spacing: 0.04em;
  padding: 0.65rem 1.4rem; border: none; border-radius: 9px; background: var(--accent); color: var(--page); cursor: pointer; }
.namewall-card button[data-namewall-go]:hover { opacity: 0.92; }
@media (prefers-reduced-motion: reduce) { .namewall { transition: none; } }

/* library drawer */
.drawer-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.38);
  opacity: 0; visibility: hidden; transition: opacity 0.35s ease, visibility 0.35s ease; z-index: 30;
}
html[data-drawer="open"] .drawer-overlay { opacity: 1; visibility: visible; }
.drawer {
  position: fixed; top: 0; left: 0; bottom: 0; width: min(23rem, 88vw);
  background: var(--page); box-shadow: var(--shadow); z-index: 31;
  transform: translateX(-100%); transition: transform 0.42s cubic-bezier(0.2, 0.7, 0.2, 1);
  display: flex; flex-direction: column;
}
html[data-drawer="open"] .drawer { transform: none; }
.drawer-head {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 2rem 1.6rem 1.2rem; border-bottom: 1px solid var(--rule);
}
.drawer-head .t { font-family: var(--font-display); font-size: 1.15rem; letter-spacing: 0.1em; color: var(--ink); }
.drawer-head button {
  font-family: var(--font-ui); font-size: 0.68rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--accent); transition: opacity 0.2s ease;
}
.drawer-head button:hover { opacity: 0.65; }
.passage-list { flex: 1; overflow-y: auto; padding: 0.6rem 0.8rem 2rem; }
.passage-item {
  position: relative; padding: 0.95rem 2.2rem 1rem 1rem; cursor: pointer;
  border-left: 2px solid transparent; border-radius: 2px;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.passage-item:hover { background: var(--rule-soft); }
.passage-item.active { border-left-color: var(--accent); background: var(--rule-soft); }
.passage-item .pi-title {
  font-family: var(--font-body); font-size: 1.05rem; color: var(--ink);
  margin-bottom: 0.2rem; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
.passage-item .pi-snip {
  font-family: var(--font-body); font-style: italic; font-size: 0.86rem;
  color: var(--ink-soft); line-height: 1.4; margin-bottom: 0.45rem;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.passage-item .pi-meta { font-family: var(--font-ui); font-size: 0.6rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-faint); }
.passage-item .pi-del {
  position: absolute; top: 0.55rem; right: 0.4rem; width: 2rem; height: 2rem;
  border-radius: 50%; display: flex; align-items: center; justify-content: center;
  color: var(--ink-faint); opacity: 0.4; font-size: 1.25rem; line-height: 1;
  transition: opacity 0.2s ease, color 0.2s ease, background-color 0.2s ease;
}
.passage-item:hover .pi-del { opacity: 0.7; }
.passage-item .pi-del:hover, .passage-item .pi-del:focus-visible { opacity: 1; color: var(--accent); background: var(--rule-soft); }
/* touch devices have no hover — keep the delete control clearly visible */
@media (hover: none) { .passage-item .pi-del { opacity: 0.65; } }
.passage-empty { padding: 3rem 1.4rem; text-align: center; color: var(--ink-faint); font-style: italic; font-size: 0.95rem; }

/* toast */
.toast {
  position: fixed; bottom: calc(1.8rem + env(safe-area-inset-bottom)); left: 50%; z-index: 40;
  transform: translateX(-50%) translateY(1.2rem);
  background: var(--ink); color: var(--page);
  padding: 0.65rem 1.1rem; border-radius: 2px;
  /* system sans (not the per-edition display serif) so messages stay legible on
     every edition — the toast is UI chrome, not part of the typeset page. */
  font-family: var(--font-chrome); font-size: 0.66rem; letter-spacing: 0.24em;
  text-transform: uppercase; opacity: 0; pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- auth gate (served mode) ---------- */
.auth-gate {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: var(--bg); background-image: var(--body-texture, none); background-size: 320px 320px;
  padding: 1.5rem; animation: fade 0.5s ease both;
}
.auth-gate[hidden] { display: none; }
.auth-card[hidden] { display: none; }   /* .auth-card's display:flex would otherwise override the UA hidden rule (two-card reader gate) */

/* reader library — a signed-in reader's home (everything shared with them) */
.reader-home {
  position: fixed; inset: 0; z-index: 58; overflow-y: auto;
  background: var(--bg); background-image: var(--body-texture, none); background-size: 320px 320px;
  animation: fade 0.5s ease both;
}
.reader-home[hidden] { display: none; }
.rh-inner { max-width: 40rem; margin: 0 auto; padding: clamp(2.5rem, 8vh, 6rem) 1.5rem 4rem; }
.rh-head { text-align: center; margin-bottom: 2.5rem; }
.rh-mark { font-family: var(--font-display); font-size: 1.4rem; color: var(--accent); margin-bottom: 0.8rem; }
.rh-head h1 { font-family: var(--font-display); font-weight: 400; font-size: 1.9rem; letter-spacing: 0.1em; color: var(--ink); margin-bottom: 0.4rem; }
.rh-sub { font-family: var(--font-body); font-style: italic; color: var(--ink-soft); font-size: 1rem; }
.rh-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.7rem; }
.rh-item { margin: 0; }
.rh-link {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: 1.1rem 1.4rem; background: var(--page); border: 1px solid var(--rule-soft);
  border-radius: 4px; text-decoration: none; box-shadow: var(--shadow);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.rh-link:hover { border-color: var(--accent); transform: translateY(-1px); }
.rh-link.is-new { border-left: 3px solid var(--accent); }
.rh-title { font-family: var(--font-display); font-size: 1.15rem; color: var(--ink); letter-spacing: 0.02em; }
.rh-meta { font-family: var(--font-body); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint, var(--ink-soft)); white-space: nowrap; }
.rh-link.is-new .rh-meta { color: var(--accent); font-weight: 600; }
.rh-empty { text-align: center; font-family: var(--font-body); font-style: italic; color: var(--ink-soft); margin-top: 2rem; }
.rh-signout {
  display: block; margin: 2.5rem auto 0; padding: 0.5rem 1.2rem; background: none;
  border: 1px solid var(--rule-soft); border-radius: 4px; color: var(--ink-soft);
  font-family: var(--font-body); font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase;
  cursor: pointer; transition: border-color 0.15s ease, color 0.15s ease;
}
.rh-signout:hover { border-color: var(--accent); color: var(--accent); }
html[data-auth-pending="true"] [data-reader],
html[data-auth-pending="true"] [data-editor],
html[data-auth-pending="true"] [data-invitation],
html[data-auth-pending="true"] [data-foot],
html[data-auth-pending="true"] .quick-dock,
html[data-auth-pending="true"] .page-hud,
html[data-auth-required="true"] [data-reader],
html[data-auth-required="true"] [data-editor],
html[data-auth-required="true"] [data-invitation],
html[data-auth-required="true"] [data-foot],
html[data-auth-required="true"] .quick-dock,
html[data-auth-required="true"] .page-hud {
  display: none !important;
}
html[data-auth-required="true"] .auth-gate[hidden] { display: flex !important; }
.auth-card {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  width: min(22rem, 100%); padding: 2.6rem 2rem; background: var(--page);
  border: 1px solid var(--rule-soft); border-radius: 4px; box-shadow: var(--shadow);
}
.auth-mark { font-family: var(--font-display); font-size: 1.4rem; color: var(--accent); margin-bottom: 1rem; }
.auth-card h1 { font-family: var(--font-display); font-weight: 400; font-size: 1.5rem; letter-spacing: 0.12em; color: var(--ink); margin-bottom: 0.5rem; }
.auth-card p { font-family: var(--font-body); font-style: italic; color: var(--ink-soft); margin-bottom: 1.8rem; font-size: 0.98rem; }
.auth-card input {
  width: 100%; padding: 0.7rem 0.9rem; margin-bottom: 0.9rem; background: var(--bg);
  border: 1px solid var(--rule); border-radius: 3px; color: var(--ink);
  font-family: var(--font-body); font-size: 1rem; outline: none; transition: border-color 0.2s ease;
}
.auth-card input:focus { border-color: var(--accent); }
.auth-card button {
  width: 100%; padding: 0.7rem; background: var(--accent); color: var(--page);
  border-radius: 3px; font-family: var(--font-ui); font-size: 0.72rem; letter-spacing: 0.22em;
  text-transform: uppercase; transition: opacity 0.2s ease;
}
.auth-card button:hover { opacity: 0.88; }
.auth-err { min-height: 1.2rem; margin-top: 0.7rem; font-family: var(--font-body); font-style: italic; font-size: 0.86rem; color: var(--accent); }
.auth-link { margin-top: 0.9rem; background: none; border: none; color: var(--ink-faint); font-family: var(--font-ui); font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase; cursor: pointer; transition: color 0.2s ease; }
.auth-link:hover { color: var(--ink); }

/* ---------- confirm dialog (destructive actions) ----------
   Centered modal over a scrim; sits above the library drawer (z-31) and
   everything else management-related. Matches the auth-card aesthetic. */
.confirm {
  position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.42); padding: 1.5rem; animation: fade 0.25s ease both;
}
.confirm[hidden] { display: none; }
.confirm-card {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  width: min(22rem, 100%); padding: 2.2rem 1.8rem 1.6rem; background: var(--page);
  border: 1px solid var(--rule-soft); border-radius: 4px; box-shadow: var(--shadow);
  animation: confirm-rise 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
@keyframes confirm-rise { from { opacity: 0; transform: translateY(0.6rem) scale(0.98); } to { opacity: 1; transform: none; } }
.confirm-mark { font-family: var(--font-display); font-size: 1.3rem; color: var(--accent); margin-bottom: 0.8rem; }
.confirm-card h2 { font-family: var(--font-display); font-weight: 400; font-size: 1.3rem; letter-spacing: 0.06em; color: var(--ink); margin-bottom: 0.5rem; }
.confirm-card p { font-family: var(--font-body); font-style: italic; color: var(--ink-soft); margin-bottom: 1.6rem; font-size: 0.95rem; line-height: 1.5; }
.confirm-actions { display: flex; gap: 0.7rem; width: 100%; }
.confirm-actions button {
  flex: 1; padding: 0.65rem 0.8rem; border-radius: 3px;
  font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase;
  transition: opacity 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
.confirm-actions button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.confirm-cancel { background: var(--bg); border: 1px solid var(--rule); color: var(--ink); }
.confirm-cancel:hover { border-color: var(--ink-faint); }
.confirm-ok { background: var(--accent); border: 1px solid var(--accent); color: var(--page); }
.confirm-ok:hover { opacity: 0.88; }
.confirm-ok.danger { background: #a3342b; border-color: #a3342b; }
html[data-theme="dark"] .confirm-ok.danger { background: #c0473c; border-color: #c0473c; }

/* ---------- public share view (/p/:token): read-only ----------
   The colophon mark stays (reading prefs: edition / text / theme),
   but all management actions are hidden. */
html[data-public] .done-fab,
html[data-public] .panel-actions,
html[data-public] .panel-div,
html[data-public] .panel-manage,
html[data-public] .sheet-actions { display: none !important; }

/* ---------- annotations: highlights, selection menu, tooltip thread ----------
   Painted via the CSS Custom Highlight API (no <mark> in the DOM), so the
   drop cap, justified text, and word boundaries are never disturbed. */
/* Literal colors — iOS/WebKit ignores var() INSIDE ::highlight() pseudos (the
   same limitation documented for ::selection above; the multi-reviewer buckets
   below already use literals). var() here painted the owner/solo highlight
   transparent on iPhone — the reported "highlights don't work". Background
   tracks light/dark; the anno-note underline tracks edition × theme. */
::highlight(anno)      { background-color: rgba(244, 212, 116, 0.33); }
::highlight(anno-note) { background-color: rgba(244, 212, 116, 0.33); text-decoration: underline dotted #7a2e2e; text-decoration-thickness: 1px; text-underline-offset: 3px; }
html[data-theme="dark"] ::highlight(anno)      { background-color: rgba(214, 182, 112, 0.16); }
html[data-theme="dark"] ::highlight(anno-note) { background-color: rgba(214, 182, 112, 0.16); text-decoration-color: #c7884f; }
html[data-edition="periodical"] ::highlight(anno-note){text-decoration-color:#a02c20;} html[data-edition="periodical"][data-theme="dark"] ::highlight(anno-note){text-decoration-color:#e07a5f;}
html[data-edition="onionskin"] ::highlight(anno-note){text-decoration-color:#b1311a;} html[data-edition="onionskin"][data-theme="dark"] ::highlight(anno-note){text-decoration-color:#d44a31;}
html[data-edition="quietpage"] ::highlight(anno-note){text-decoration-color:#1c1c1a;} html[data-edition="quietpage"][data-theme="dark"] ::highlight(anno-note){text-decoration-color:#d9d6cb;}
/* combined (multi-reviewer) overlay — 10 per-reviewer hues; *-cn* = commented (dotted underline) */
::highlight(anno-c0){background-color:hsl(4 75% 50% / .26);}   ::highlight(anno-cn0){background-color:hsl(4 75% 50% / .26);text-decoration:underline dotted hsl(4 70% 45%);text-underline-offset:3px;}
::highlight(anno-c1){background-color:hsl(28 75% 50% / .26);}  ::highlight(anno-cn1){background-color:hsl(28 75% 50% / .26);text-decoration:underline dotted hsl(28 70% 45%);text-underline-offset:3px;}
::highlight(anno-c2){background-color:hsl(150 60% 45% / .26);} ::highlight(anno-cn2){background-color:hsl(150 60% 45% / .26);text-decoration:underline dotted hsl(150 60% 40%);text-underline-offset:3px;}
::highlight(anno-c3){background-color:hsl(200 70% 50% / .26);} ::highlight(anno-cn3){background-color:hsl(200 70% 50% / .26);text-decoration:underline dotted hsl(200 70% 45%);text-underline-offset:3px;}
::highlight(anno-c4){background-color:hsl(260 60% 55% / .26);} ::highlight(anno-cn4){background-color:hsl(260 60% 55% / .26);text-decoration:underline dotted hsl(260 60% 50%);text-underline-offset:3px;}
::highlight(anno-c5){background-color:hsl(320 65% 55% / .26);} ::highlight(anno-cn5){background-color:hsl(320 65% 55% / .26);text-decoration:underline dotted hsl(320 65% 50%);text-underline-offset:3px;}
::highlight(anno-c6){background-color:hsl(50 80% 50% / .28);}  ::highlight(anno-cn6){background-color:hsl(50 80% 50% / .28);text-decoration:underline dotted hsl(50 70% 42%);text-underline-offset:3px;}
::highlight(anno-c7){background-color:hsl(100 55% 45% / .26);} ::highlight(anno-cn7){background-color:hsl(100 55% 45% / .26);text-decoration:underline dotted hsl(100 55% 40%);text-underline-offset:3px;}
::highlight(anno-c8){background-color:hsl(180 60% 45% / .26);} ::highlight(anno-cn8){background-color:hsl(180 60% 45% / .26);text-decoration:underline dotted hsl(180 60% 40%);text-underline-offset:3px;}
::highlight(anno-c9){background-color:hsl(290 55% 55% / .26);} ::highlight(anno-cn9){background-color:hsl(290 55% 55% / .26);text-decoration:underline dotted hsl(290 55% 50%);text-underline-offset:3px;}

.anno-menu, .anno-tip {
  position: fixed; z-index: 45; font-family: var(--font-ui);
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  border-radius: 8px; opacity: 0; visibility: hidden; transform: translate(-50%, 0);
  transition: opacity 0.14s ease;
}
.anno-menu { display: flex; padding: 0.3rem; gap: 0.15rem; transform: translate(-50%, -100%); }
.anno-menu.show, .anno-tip.show { opacity: 1; visibility: visible; }
.anno-menu button {
  font: inherit; font-size: 0.72rem; letter-spacing: 0.04em; color: var(--ink-soft);
  padding: 0.45rem 0.7rem; border-radius: 5px; display: inline-flex; align-items: center; gap: 0.4rem; white-space: nowrap;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.anno-menu button:hover { background: var(--rule-soft); color: var(--ink); }
.anno-menu .a-hl { background: var(--highlight); border-radius: 2px; padding: 0 0.22em; }
/* touch: bigger tap targets (JS floats it just below the selection) */
@media (hover: none) and (pointer: coarse) {
  .anno-menu { padding: 0.4rem; gap: 0.3rem; }
  .anno-menu button { padding: 0.6rem 0.95rem; font-size: 0.8rem; min-height: 44px; }
  /* 44px-tall rows for vertical touch, but the button is only as WIDE as its icon so the
     label sits right beside it (a wide min-width floated the icon far from the label). The
     label is tappable (pointer-events:auto) so the whole row — not just the icon box — is
     the hit target. */
  .quick-dock button { min-width: 0; height: 2.6rem; padding: 0 0.22rem; }
  .quick-dock { gap: 0.34rem; }   /* room for the fading separators between rows */
}

.anno-tip {
  width: min(20rem, calc(100vw - 1.5rem)); padding: 0.9rem; transform: translate(-50%, 0);
  text-align: left; max-height: 60vh; overflow-y: auto;
}
.anno-tip .tip-quote { font-family: var(--font-body); font-style: italic; font-size: 0.86rem; color: var(--ink-soft); border-left: 2px solid var(--rule); padding-left: 0.6rem; margin-bottom: 0.7rem; }
.anno-tip .tip-note { font-family: var(--font-body); font-size: 0.95rem; color: var(--ink); line-height: 1.5; margin-bottom: 0.6rem; }
.anno-tip .tip-note-bare { font-style: italic; color: var(--ink-faint); }
.anno-tip .tip-thread { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.7rem; }
.anno-tip .tip-msg { font-family: var(--font-body); font-size: 0.9rem; line-height: 1.45; color: var(--ink); background: var(--rule-soft); border-radius: 6px; padding: 0.5rem 0.65rem; }
.anno-tip .tip-msg b { display: block; font-size: 0.66rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 0.2rem; font-weight: 600; }
.anno-tip .tip-msg.owner { border-left: 2px solid var(--accent); }
.anno-tip .tip-msg.owner b { color: var(--accent); }
.anno-tip .tip-bar { display: flex; gap: 0.8rem; }
.anno-tip .tip-bar button { font-family: var(--font-ui); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); transition: color 0.15s ease; }
.anno-tip .tip-bar button:hover { color: var(--accent); }
.anno-tip .tip-reply { display: none; margin-top: 0.7rem; gap: 0.5rem; flex-direction: column; }
.anno-tip .tip-reply.show { display: flex; }
.anno-tip textarea, .anno-tip .tip-input {
  width: 100%; min-height: 4rem; resize: vertical; border: 1px solid var(--rule); border-radius: 6px;
  /* font-size MUST stay >=16px: iOS Safari auto-zooms into any smaller input on
     focus, which shifts the visual viewport and makes swipe gestures pan the
     page sideways instead of pulling the dock. */
  background: var(--bg); color: var(--ink); font-family: var(--font-body); font-size: 16px; padding: 0.55rem 0.65rem; outline: none;
}
.anno-tip textarea:focus, .anno-tip .tip-input:focus { border-color: var(--accent); }
.anno-tip .tip-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.6rem; }
.anno-tip button.primary, .anno-tip [data-reply-send] {
  background: var(--accent); color: var(--page); border-radius: 5px; padding: 0.4rem 0.8rem;
  font-family: var(--font-ui); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; align-self: flex-end;
}
.anno-tip [data-cancel] { font-family: var(--font-ui); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); padding: 0.4rem 0.6rem; }

/* feedback chips in the library drawer */
.pi-feedback { margin-top: 0.55rem; }
.pi-feedback:empty { display: none; }
.pi-feedback .fb-open {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-family: var(--font-ui); font-size: 0.64rem; letter-spacing: 0.08em; color: var(--accent);
  border: 1px solid var(--rule); border-radius: 999px; padding: 0.3rem 0.7rem; transition: background-color 0.15s ease, border-color 0.15s ease;
}
.pi-feedback .fb-open:hover { background: var(--rule-soft); border-color: var(--accent); }
.pi-feedback .fb-open.has-unread { border-color: var(--accent); }
.pi-feedback .fb-new { background: var(--accent); color: var(--page); border-radius: 999px; padding: 0.02rem 0.38rem; font-size: 0.92em; }

/* ---------- contributors panel (author: all reviewers for a passage) ---------- */
.contrib-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 34; opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease; }
html[data-contrib="open"] .contrib-overlay { opacity: 1; visibility: visible; }
.contrib {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(24rem, 92vw); z-index: 35;
  background: var(--page); box-shadow: var(--shadow); display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform 0.42s cubic-bezier(0.2,0.7,0.2,1);
}
html[data-contrib="open"] .contrib { transform: none; }
.contrib-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; padding: 1.8rem 1.5rem 1.2rem; border-bottom: 1px solid var(--rule); }
.contrib-kicker { font-family: var(--font-ui); font-size: 0.6rem; letter-spacing: 0.22em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 0.35rem; }
.contrib-title { font-family: var(--font-display); font-size: 1.2rem; color: var(--ink); line-height: 1.2; }
.contrib-close { font-size: 1.4rem; line-height: 1; color: var(--ink-faint); padding: 0.2rem 0.4rem; transition: color 0.2s ease; }
.contrib-close:hover { color: var(--accent); }
.contrib-list { flex: 1; overflow-y: auto; padding: 0.6rem; }
.contrib-all, .contrib-item {
  display: flex; align-items: center; gap: 0.7rem; width: 100%; text-align: left;
  padding: 0.85rem 0.8rem; border-radius: 7px; transition: background-color 0.15s ease;
}
.contrib-all:hover, .contrib-item:hover { background: var(--rule-soft); }
.contrib-all { font-family: var(--font-ui); }
.contrib-all .ci-name { font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.contrib-div { height: 1px; background: var(--rule); margin: 0.5rem 0.6rem; }
.contrib-item .ci-swatch { width: 0.7rem; height: 0.7rem; border-radius: 50%; flex: 0 0 auto; }
.ci-name { font-family: var(--font-body); font-size: 1.02rem; color: var(--ink); }
.ci-meta { font-family: var(--font-ui); font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); margin-left: auto; }
.ci-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--accent); flex: 0 0 auto; margin-left: 0.5rem; }
.contrib-item.unread .ci-name { font-weight: 500; }

/* combined-mode margin/tooltip: show whose note */
.m-note .m-who, .tip-who { display: flex; align-items: center; gap: 0.4rem; font-family: var(--font-ui); font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); margin-bottom: 0.35rem; }
.m-note .m-sw, .tip-sw { width: 0.55rem; height: 0.55rem; border-radius: 50%; flex: 0 0 auto; }

/* feedback fab (reviewer hint / author with-clean toggle) */
.feedback-fab {
  position: fixed; bottom: calc(1.6rem + env(safe-area-inset-bottom)); right: 1.4rem;
  z-index: 19; background: var(--page); border: 1px solid var(--rule); box-shadow: var(--shadow);
  color: var(--ink-soft); padding: 0.55rem 1.1rem; border-radius: 999px;
  font-family: var(--font-ui); font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase;
  max-width: calc(100vw - 2rem); transition: color 0.2s ease, border-color 0.2s ease;
}
.feedback-fab[hidden] { display: none; }
.feedback-fab:hover { color: var(--accent); border-color: var(--accent); }
.feedback-fab.hint { pointer-events: none; opacity: 0.85; }
/* in any feedback/annotation view the in-flow colophon menu is irrelevant — hide it */
html[data-feedback] .colophon-foot { display: none; }

/* ---------- margin layer: side-note cards (desktop) / dots (mobile) ---------- */
.anno-margin { position: absolute; top: 0; left: 0; width: 100%; height: 0; z-index: 14; pointer-events: none; }
.anno-margin.show { pointer-events: none; }
.anno-margin > * { pointer-events: auto; }

/* side-note cards (wide screens) */
.m-note {
  position: absolute; width: 13rem; padding: 0.6rem 0.75rem; border-radius: 7px;
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow);
  cursor: pointer; transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
  border-left: 2px solid var(--accent);
}
.m-note:hover { transform: translateX(-3px); }
.m-note.active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), var(--shadow); }
.m-note.unread { border-left-width: 3px; }
.m-note .m-badge {
  position: absolute; top: -5px; left: -5px; width: 0.7rem; height: 0.7rem; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--page); box-shadow: 0 0 0 1px var(--accent);
}
.m-note .m-quote { font-family: var(--font-body); font-style: italic; font-size: 0.72rem; color: var(--ink-faint); margin-bottom: 0.3rem; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.m-note .m-note-body { font-family: var(--font-body); font-size: 0.85rem; color: var(--ink); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* gutter dots (narrow screens) */
.m-dot {
  position: absolute; width: 1.35rem; height: 1.35rem; border-radius: 50%;
  background: var(--page); border: 1.5px solid var(--accent); color: var(--accent);
  font-family: var(--font-ui); font-size: 0.6rem; line-height: 1; display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow); cursor: pointer; transition: transform 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
.m-dot:hover, .m-dot.active { background: var(--accent); color: var(--page); transform: scale(1.1); }
.m-dot.unread { background: var(--accent); color: var(--page); }
.m-dot.unread::after {
  content: ''; position: absolute; top: -3px; right: -3px; width: 0.55rem; height: 0.55rem; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--page); animation: anno-pulse 1.8s ease-in-out infinite;
}
@keyframes anno-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.45; } }

/* ---------- jump list: "N notes" toggle + popup ---------- */
.anno-jump {
  position: fixed; bottom: 1.6rem; left: 1.4rem; z-index: 18; display: none;
  opacity: 0.82; transition: opacity 0.2s ease, transform 0.2s ease;
}
.anno-jump.show { display: block; }
.anno-jump:hover,
.anno-jump:focus-within { opacity: 1; }
html[data-idle="true"] .anno-jump.show:not(:hover):not(:focus-within) { opacity: 0.2; }
.jump-btn {
  background: var(--page); border: 1px solid var(--rule); box-shadow: var(--shadow);
  color: var(--ink-soft); padding: 0.55rem 1rem; border-radius: 999px;
  font-family: var(--font-ui); font-size: 0.64rem; letter-spacing: 0.14em; text-transform: uppercase;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.jump-btn:hover { color: var(--accent); border-color: var(--accent); }
.anno-jump.has-unread .jump-btn { color: var(--accent); border-color: var(--accent); }
.jump-btn .jump-new {
  display: inline-block; margin-left: 0.4rem; padding: 0.08rem 0.4rem; border-radius: 999px;
  background: var(--accent); color: var(--page); font-size: 0.92em; letter-spacing: 0.06em;
}
.jump-item.unread .ji-q { color: var(--ink); font-weight: 500; }
.jump-item .ji-dot { width: 0.45rem; height: 0.45rem; border-radius: 50%; background: var(--accent); flex: 0 0 auto; margin-left: auto; }
.jump-list {
  position: absolute; bottom: calc(100% + 0.5rem); left: 0; width: 16rem; max-height: 50vh; overflow-y: auto;
  background: var(--page); border: 1px solid var(--rule-soft); box-shadow: var(--shadow); border-radius: 8px; padding: 0.3rem;
  opacity: 0; visibility: hidden; transform: translateY(6px); transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease;
}
.anno-jump.open .jump-list { opacity: 1; visibility: visible; transform: none; }
.jump-item { display: flex; align-items: baseline; gap: 0.6rem; width: 100%; padding: 0.55rem 0.6rem; border-radius: 5px; text-align: left; transition: background-color 0.15s ease; }
.jump-item:hover { background: var(--rule-soft); }
.jump-item .ji-n { font-family: var(--font-ui); font-size: 0.66rem; color: var(--accent); min-width: 1.1rem; }
.jump-item .ji-q { font-family: var(--font-body); font-style: italic; font-size: 0.86rem; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
/* bare highlights (no comment) listed for navigation — quieter than comments */
.jump-item.bare .ji-n { color: var(--ink-faint); }
.jump-item.bare .ji-q { font-style: normal; color: var(--ink-soft); }
/* small hint line in the notes popover (hidden / no-comments states) */
.jump-hint { padding: 0.5rem 0.6rem; font-family: var(--font-chrome); font-size: 0.78rem; color: var(--ink-faint); font-style: italic; }
/* pill state when annotations are hidden — the count chip reads "hidden" */
.jump-btn .jump-off { display: inline-block; margin-left: 0.4rem; padding: 0.08rem 0.45rem; border-radius: 999px; background: var(--rule); color: var(--ink-soft); font-size: 0.92em; letter-spacing: 0.06em; }
.anno-jump.is-hidden .jump-btn { border-style: dashed; }
/* dock annotations toggle: accent-tinted while annotations are hidden */
.quick-dock .qd-anno.off { color: var(--accent); }

/* mode visibility */
body[data-mode="read"] .editor,
body[data-mode="read"] .invitation { display: none; }
body[data-mode="edit"] .book { display: none; }
body[data-mode="edit"] .colophon-foot { display: none; }

/* First paint shell: index.html ships a real book surface so the reader never
   paints an empty article while deferred JS, IndexedDB, or the network settle. */
.boot-reader[aria-busy="true"] { min-height: min(62vh, 42rem); }
.boot-reader .boot-page { min-height: 22rem; }
.boot-reader .boot-masthead { opacity: 0.72; }
.boot-reader .boot-masthead .byline { min-height: 1rem; }
.boot-reader .boot-prose p { text-indent: 0 !important; }
.boot-reader .boot-prose p::first-letter { float: none !important; font: inherit !important; color: inherit !important; }
.boot-line {
  display: block; height: 0.72em; margin: 0.56em 0; max-width: 100%;
  border-radius: 999px; background: var(--rule); opacity: 0.62;
}
.boot-line-lg { width: 88%; }
.boot-line-md { width: 72%; }
.boot-line-sm { width: 56%; }
.boot-line-xs { width: 38%; }
@media (max-width: 640px) {
  .boot-reader[aria-busy="true"] { min-height: min(68vh, 36rem); }
  .boot-reader .boot-page { min-height: 18rem; }
}
/* Empty state: the editor stays a REAL, tappable, focusable surface so
   mobile long-press → Paste has a target. The invitation floats over it
   as a non-interactive prompt and fades once the field has focus. */
body[data-mode="edit"][data-empty="true"] .invitation {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  display: flex; flex-direction: column; justify-content: center;
  transition: opacity 0.3s ease;
}
body[data-mode="edit"][data-empty="true"] .stage { position: relative; }
body[data-mode="edit"][data-empty="true"] .editor:focus ~ .invitation { opacity: 0.32; }
/* a touch-only Paste affordance under the invitation */
.paste-hint {
  display: none; margin-top: 2rem; align-self: center; pointer-events: auto;
  font-family: var(--font-ui); font-size: 0.72rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-soft);
  border: 1px solid var(--rule); border-radius: 999px; padding: 0.7rem 1.4rem;
  background: var(--page); box-shadow: var(--shadow);
}
body[data-mode="edit"][data-empty="true"] .paste-hint { display: inline-block; }

/* WELCOME landing (read mode + html[data-welcome]) — the calm entry shown on
   boot with an empty library or after abandoning a blank page: the edition's
   invitation as a prompt + a primary Start-writing action, with the dock
   available. No editor focus, no trap. */
html[data-welcome="true"] .invitation { display: block; }
html[data-welcome="true"] .book { display: none; }   /* no empty page card behind the prompt */
.share-unavailable {
  padding: 4.5rem 1rem; text-align: center; color: var(--ink-soft);
}
.share-unavailable .inv-head {
  font-family: var(--font-body); font-style: italic; font-weight: 400;
  font-size: clamp(1.7rem, 4.5vw, 2.4rem); color: var(--ink); margin-bottom: 0.8rem;
}
.share-unavailable .inv-sub { font-size: 1.02rem; font-style: italic; color: var(--ink-soft); }
.welcome-cta {
  display: none; margin-top: 2.2rem;
  font-family: var(--font-ui); font-size: 0.74rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--page);
  background: var(--accent); border-radius: 999px; padding: 0.8rem 1.7rem;
  box-shadow: var(--shadow); transition: opacity 0.15s ease, transform 0.15s ease;
}
.welcome-cta:hover { opacity: 0.92; transform: translateY(-1px); }
html[data-welcome="true"] .welcome-cta { display: inline-block; }

/* ===== calm first-paint loader (shared link opened cold) =====
   Non-blank by design: it sits above the already-painted book shell instead of
   covering the page with a solid backdrop. */
.loading { position: fixed; inset: 0; z-index: 30; display: none; align-items: flex-start; justify-content: center; pointer-events: none; background: transparent; padding-top: calc(2rem + env(safe-area-inset-top)); }
html[data-loading] .loading { display: flex; }
.loading-mark { font-family: var(--font-display); color: var(--accent); font-size: 2.3rem; line-height: 1; animation: loadpulse 1.5s ease-in-out infinite; text-shadow: 0 0 8px var(--page), 0 0 18px var(--page); }
@keyframes loadpulse { 0%, 100% { opacity: 0.28; transform: scale(0.97); } 50% { opacity: 1; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .loading-mark { animation: none; opacity: 0.7; } }

/* ===== first-run walkthrough ===== */
.tour { position: fixed; inset: 0; z-index: 50; }
.tour[hidden] { display: none; }
.tour-catch { position: fixed; inset: 0; }   /* blocks app interaction during the tour */
.tour-veil { position: fixed; inset: 0; background: rgba(18,13,8,0.62); opacity: 0; pointer-events: none; transition: opacity 0.3s ease; }
.tour-veil.on { opacity: 1; }
.tour-spot { position: fixed; border-radius: 12px; pointer-events: none; opacity: 0;
  box-shadow: 0 0 0 9999px rgba(18,13,8,0.62), 0 0 0 2px rgba(246,242,231,0.85) inset;
  transition: left 0.38s cubic-bezier(0.2,0.8,0.2,1), top 0.38s cubic-bezier(0.2,0.8,0.2,1), width 0.38s, height 0.38s, opacity 0.25s ease; }
.tour-spot.on { opacity: 1; }
/* swipe-gesture hint (mobile): a fingertip with a motion trail that performs
   the swipe ONE WAY in the gesture's direction (it fades out and restarts from
   the start, so it never reads as a back-and-forth bounce). */
.tour-gesture { position: fixed; left: 0; right: 0; top: 41%; display: flex; justify-content: center; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; }
.tour-gesture.on { opacity: 1; }
.tg-swipe { position: relative; width: 150px; height: 40px; }
.tg-tip { position: absolute; top: 50%; margin-top: -18px; width: 36px; height: 36px; border-radius: 50%;
  background: rgba(246,242,231,0.97); box-shadow: 0 0 0 10px rgba(122,46,46,0.16), 0 8px 22px rgba(0,0,0,0.38); }
.tg-tail { position: absolute; top: 50%; margin-top: -8px; height: 16px; width: 86px; border-radius: 8px; }
/* LEFT: tip leads on the left, trail behind on the right, glides left */
.tour-gesture.left .tg-tip  { left: 0; }
.tour-gesture.left .tg-tail { left: 34px; background: linear-gradient(to right, rgba(122,46,46,0.5), rgba(122,46,46,0)); }
.tour-gesture.left .tg-swipe { animation: tg-glide-left 1.7s cubic-bezier(0.45,0,0.15,1) infinite; }
/* RIGHT: mirror — tip on the right, trail on the left, glides right */
.tour-gesture.right .tg-tip  { right: 0; }
.tour-gesture.right .tg-tail { right: 34px; background: linear-gradient(to left, rgba(122,46,46,0.5), rgba(122,46,46,0)); }
.tour-gesture.right .tg-swipe { animation: tg-glide-right 1.7s cubic-bezier(0.45,0,0.15,1) infinite; }
@keyframes tg-glide-left  { 0% { transform: translateX(58px);  opacity: 0; } 16% { opacity: 1; } 70% { transform: translateX(-46px); opacity: 1; } 100% { transform: translateX(-46px); opacity: 0; } }
@keyframes tg-glide-right { 0% { transform: translateX(-58px); opacity: 0; } 16% { opacity: 1; } 70% { transform: translateX(46px);  opacity: 1; } 100% { transform: translateX(46px);  opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .tour-gesture .tg-swipe { animation: none !important; } }

.tour-coach { position: fixed; left: 50%; transform: translateX(-50%); width: min(22rem, calc(100vw - 2rem));
  background: var(--page); border: 1px solid var(--rule-soft); border-radius: 16px; box-shadow: var(--shadow);
  padding: 1.3rem 1.3rem 1rem; opacity: 0; transition: opacity 0.28s ease, top 0.38s cubic-bezier(0.2,0.8,0.2,1);
  text-align: left; }
.tour-coach.on { opacity: 1; }
.tour-coach.center { top: 50% !important; transform: translate(-50%,-50%); text-align: center; padding: 2.2rem 1.7rem 1.6rem; }
.tc-mark { font-family: var(--font-display); color: var(--accent); font-size: 2rem; line-height: 1; margin-bottom: 0.9rem; }
.tc-title { font-family: var(--font-body); font-size: 1.35rem; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 0.5rem; color: var(--ink); }
.tour-coach.center .tc-title { font-style: italic; font-weight: 400; font-size: 1.7rem; }
.tc-body { font-family: var(--font-body); font-size: 1.04rem; line-height: 1.5; color: var(--ink-soft); margin: 0 0 1.2rem; }
.tc-row { display: flex; align-items: center; gap: 0.8rem; font-family: var(--font-chrome); }
.tc-dots { display: flex; gap: 0.32rem; flex: 1; }
.tc-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--rule); transition: background 0.2s, transform 0.2s; }
.tc-dots i.on { background: var(--accent); transform: scale(1.25); }
.tc-row button { font-family: var(--font-chrome); font-size: 0.82rem; border-radius: 9px; padding: 0.55rem 0.95rem; border: 1px solid var(--rule); }
.tc-back { background: transparent; color: var(--ink-soft); }
.tc-next { background: var(--accent); color: var(--page); border-color: var(--accent); }
.tour-coach.center .tc-row { flex-direction: column; gap: 0.7rem; }
.tour-coach.center .tc-dots { display: none; }
.tour-coach.center .tc-next { width: 100%; padding: 0.85rem; font-size: 0.92rem; letter-spacing: 0.02em; order: -1; }
.tour-coach.center .tc-back { font-size: 0.78rem; }
/* Skip must be legible + tappable at ALL times — above the coach/veil (which are
   z-index:auto and later in the DOM), prominent (solid pill), clear of the notch. */
.tour-skip { position: fixed; top: calc(0.8rem + env(safe-area-inset-top)); right: 1rem; z-index: 5;
  font-family: var(--font-chrome); font-size: 0.8rem; font-weight: 600; color: var(--ink);
  background: var(--page); border: 1px solid var(--rule); border-radius: 999px;
  padding: 0.5rem 0.95rem; box-shadow: 0 2px 12px rgba(0,0,0,0.22); }
.tour-skip:hover { background: var(--rule-soft); }

/* desktop vs mobile menu surface */
@media (min-width: 681px) { .sheet, .sheet-scrim { display: none !important; } }
@media (max-width: 680px) { .panel { display: none !important; } }

/* animations */
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.book { animation: rise 0.7s cubic-bezier(0.2,0.7,0.2,1) both; }

/* ============================================================
   3. EDITION — LETTERPRESS  (classic clothbound novel)
   ============================================================ */
html[data-edition="letterpress"] {
  --font-body: 'EB Garamond', Georgia, serif;
  --font-display: 'IM Fell English SC', serif;
  --font-ui: 'IM Fell English SC', serif;
  --font-byline: 'IM Fell DW Pica', serif;
  --dropcap-font: 'IM Fell English SC', serif;
  --ornament: '⁂';
  --reading-base: calc(1.3rem + 1px); --measure: 38rem; --editor-measure: 38rem;

  --bg: #ece7d7; --page: #f6f2e7; --page-edge: #e0d9c6;
  --ink: #1f1a12; --ink-soft: #5b4d3a; --ink-faint: #74664e;
  --accent: #7a2e2e; --rule: rgba(31,26,18,0.14); --rule-soft: rgba(31,26,18,0.07);
  --selection: rgba(122,46,46,0.18);
  --shadow: 0 18px 50px -22px rgba(31,26,18,0.45), 0 2px 6px -2px rgba(31,26,18,0.18);
  --body-texture: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.045 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
html[data-edition="letterpress"][data-theme="dark"] {
  --bg: #110d08; --page: #1a140d; --page-edge: #271e13;
  --ink: #ead9b3; --ink-soft: #ad9670; --ink-faint: #8e7d60;
  --accent: #c7884f; --rule: rgba(234,217,179,0.10); --rule-soft: rgba(234,217,179,0.05);
  --selection: rgba(199,136,79,0.22);
  --shadow: 0 28px 70px -30px rgba(0,0,0,0.95), 0 2px 6px -2px rgba(0,0,0,0.6);
}
html[data-edition="letterpress"] .book {
  background: var(--page); padding: 5rem clamp(1.75rem,5.5vw,4.75rem) 5.5rem;
  box-shadow: var(--shadow); border-radius: 2px;
  background-image:
    linear-gradient(to right, rgba(0,0,0,0.025), transparent 4%, transparent 96%, rgba(0,0,0,0.025)),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 100% 100%, 280px 280px;
}
html[data-edition="letterpress"] .book::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  box-shadow: inset 0 0 60px 0 rgba(0,0,0,0.03);
}
html[data-edition="letterpress"] .title { font-family: var(--font-display); font-weight: 400; font-size: 1.45rem; text-align: center; letter-spacing: 0.18em; margin-bottom: 0.5rem; color: var(--ink); }
html[data-edition="letterpress"] .byline { text-align: center; font-family: var(--font-byline); font-style: italic; color: var(--ink-soft); margin: 0.5rem auto 3.2rem; font-size: 1rem; }
html[data-edition="letterpress"] .byline::before, html[data-edition="letterpress"] .byline::after {
  content: ''; display: inline-block; width: 1.4rem; height: 1px; background: var(--ink-soft); opacity: 0.5; vertical-align: middle; margin: 0 0.9rem;
}
html[data-edition="letterpress"] .prose p { font-size: calc(var(--reading-base)*var(--reading-scale)); line-height: 1.72; text-align: justify; hyphens: auto; text-indent: 1.5em; orphans: 3; widows: 3; }
html[data-edition="letterpress"] .prose p.opener, html[data-edition="letterpress"] .prose hr + p { text-indent: 0; }
html[data-edition="letterpress"] .prose p.opener::first-letter { font-family: var(--dropcap-font); font-size: 4.8em; float: left; line-height: 0.82; padding: 0.05em 0.1em 0 0; color: var(--accent); }
html[data-edition="letterpress"] .brk { border: none; text-align: center; margin: 2.2rem 0 1.6rem; height: 1.2rem; color: var(--accent); font-size: 1.4rem; line-height: 1; }
html[data-edition="letterpress"] .brk::after { content: var(--ornament); }
html[data-edition="letterpress"] .col-words::after { content: ' words'; }
html[data-edition="letterpress"] .invitation { text-align: center; color: var(--ink-soft); }
html[data-edition="letterpress"] .inv-label { font-family: var(--font-ui); font-size: 0.85rem; letter-spacing: 0.4em; color: var(--ink-faint); margin-bottom: 2.5rem; }
html[data-edition="letterpress"] .inv-label::before, html[data-edition="letterpress"] .inv-label::after {
  content: ''; display: inline-block; width: 2rem; height: 1px; background: var(--rule); vertical-align: middle; margin: 0 1rem;
}
html[data-edition="letterpress"] .inv-head { font-family: var(--font-body); font-style: italic; font-size: clamp(1.8rem, 4.5vw, 2.6rem); color: var(--ink); margin-bottom: 0.8rem; letter-spacing: -0.005em; }
html[data-edition="letterpress"] .inv-sub { font-size: 1.05rem; font-style: italic; color: var(--ink-soft); }
html[data-edition="letterpress"] .inv-key { margin-top: 3.5rem; font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.42em; color: var(--ink-faint); }
/* mark = printer's ornament */
html[data-edition="letterpress"] .mark-glyph { content: '⁂'; }

/* ============================================================
   4. EDITION — PERIODICAL  (literary magazine, marginalia grid)
   ============================================================ */
html[data-edition="periodical"] {
  --font-body: 'Newsreader', Georgia, serif;
  --font-display: 'Fraunces', serif;
  --font-ui: 'JetBrains Mono', monospace;
  --font-byline: 'JetBrains Mono', monospace;
  --reading-base: 1.3rem; --measure: 62rem; --editor-measure: 38rem;

  --bg: #f3f0e8; --page: #f3f0e8; --page-edge: #e6e1d4;
  --ink: #181513; --ink-soft: #5f574e; --ink-faint: #746c64;
  --accent: #a02c20; --rule: rgba(24,21,19,0.18); --rule-soft: rgba(24,21,19,0.07);
  --selection: rgba(160,44,32,0.16);
  --shadow: 0 24px 60px -32px rgba(24,21,19,0.4), 0 4px 14px -10px rgba(24,21,19,0.15);
  --body-texture: none;
}
html[data-edition="periodical"][data-theme="dark"] {
  --bg: #0f1418; --page: #131a1f; --page-edge: #1d262c;
  --ink: #e8ddc8; --ink-soft: #a39a8a; --ink-faint: #888074;
  --accent: #e07a5f; --rule: rgba(232,221,200,0.20); --rule-soft: rgba(232,221,200,0.07);
  --selection: rgba(224,122,95,0.18);
  --shadow: 0 28px 70px -32px rgba(0,0,0,0.85), 0 4px 14px -10px rgba(0,0,0,0.5);
}
html[data-edition="periodical"] .book { display: grid; grid-template-columns: 13rem minmax(0, 1fr); column-gap: 3.5rem; background: none; box-shadow: none; padding: 0; }
html[data-edition="periodical"] .book::before { display: none; }
html[data-edition="periodical"] .meta {
  display: block; grid-column: 1; grid-row: 1 / 99; align-self: start; position: sticky; top: 5rem;
  font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); line-height: 1.6;
}
html[data-edition="periodical"] .meta::before { content: 'A Passage'; display: block; color: var(--accent); margin-bottom: 1rem; }
html[data-edition="periodical"] .meta-field { display: block; margin-bottom: 1.1rem; }
html[data-edition="periodical"] .meta-pages { display: none; }
html[data-edition="periodical"] .meta.no-byline .meta-by { display: none; }
html[data-edition="periodical"] .meta-by::before   { content: 'By'; }
html[data-edition="periodical"] .meta-words::before { content: 'Length'; }
html[data-edition="periodical"] .meta-time::before  { content: 'Reading'; }
html[data-edition="periodical"] .meta-field::before { display: block; }
html[data-edition="periodical"] .meta-val { display: block; font-family: var(--font-body); text-transform: none; letter-spacing: 0; color: var(--ink); font-size: 0.95rem; margin-top: 0.2rem; }
html[data-edition="periodical"] .meta-words .meta-val::after { content: ' words'; }
html[data-edition="periodical"] .masthead { grid-column: 2; }
html[data-edition="periodical"] .prose { grid-column: 2; max-width: 36rem; }
html[data-edition="periodical"] .title { font-family: var(--font-display); font-weight: 300; font-style: italic; font-size: clamp(2.4rem, 5.5vw, 3.8rem); line-height: 1.04; letter-spacing: -0.022em; color: var(--ink); margin-bottom: 0.6rem; }
html[data-edition="periodical"] .byline { font-family: var(--font-ui); font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); padding-bottom: 1.5rem; border-bottom: 2px solid var(--ink); margin-bottom: 2.4rem; }
html[data-edition="periodical"] .prose p { font-size: calc(var(--reading-base)*var(--reading-scale)); line-height: 1.65; color: var(--ink); margin-bottom: 1.15em; }
html[data-edition="periodical"] .prose p.opener::first-letter { font-family: var(--font-display); font-weight: 300; font-style: italic; font-size: 3.6em; float: left; line-height: 0.85; padding: 0.06em 0.12em 0 0; color: var(--accent); }
html[data-edition="periodical"] .brk { border: none; text-align: center; margin: 1.8rem 0; font-family: var(--font-ui); color: var(--ink-faint); letter-spacing: 1em; font-size: 0.7rem; }
html[data-edition="periodical"] .brk::after { content: '· · ·'; }
html[data-edition="periodical"] .colophon { display: none; }
html[data-edition="periodical"] .invitation { text-align: left; padding: 4rem 0 6rem; }
html[data-edition="periodical"] .inv-label { font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent); margin-bottom: 1.5rem; }
html[data-edition="periodical"] .inv-head { font-family: var(--font-display); font-style: italic; font-weight: 300; font-size: clamp(2.4rem, 6.5vw, 4.6rem); line-height: 1.02; color: var(--ink); letter-spacing: -0.025em; margin-bottom: 1.4rem; }
html[data-edition="periodical"] .inv-head em { font-style: normal; color: var(--accent); }
html[data-edition="periodical"] .inv-sub { font-family: var(--font-body); font-style: italic; font-size: 1.15rem; color: var(--ink-soft); max-width: 32rem; line-height: 1.55; }
html[data-edition="periodical"] .inv-key { margin-top: 4rem; font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--ink-faint); }
html[data-edition="periodical"] .inv-key span { color: var(--ink); border-bottom: 1px solid var(--rule); padding-bottom: 1px; }
html[data-edition="periodical"] .mark-glyph { font-style: italic; }

/* ============================================================
   5. EDITION — ONION SKIN  (typewriter draft on ruled paper)
   ============================================================ */
html[data-edition="onionskin"] {
  --font-body: 'Courier Prime', 'Courier New', monospace;
  --font-display: 'Special Elite', monospace;
  --font-ui: 'Special Elite', monospace;
  --reading-base: 1.12rem; --measure: 44rem; --editor-measure: 44rem;
  --rule-blue: #6b88b0; --line: rgba(42,31,18,0.07); --line-firm: rgba(42,31,18,0.18);

  --bg: #d8c79e; --page: #efe2bf; --page-edge: #e4d4ad;
  --ink: #2a1f12; --ink-soft: #6a583c; --ink-faint: #60523d;
  --accent: #b1311a; --rule: rgba(42,31,18,0.14); --rule-soft: rgba(42,31,18,0.07);
  --selection: rgba(177,49,26,0.16);
  --shadow: 0 22px 50px -28px rgba(42,31,18,0.55), 0 6px 14px -10px rgba(42,31,18,0.25);
  --body-texture: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.78' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.07 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
html[data-edition="onionskin"][data-theme="dark"] {
  --rule-blue: #4b6b94; --line: rgba(221,201,155,0.06); --line-firm: rgba(221,201,155,0.16);
  --bg: #14100a; --page: #1d160e; --page-edge: #271d12;
  --ink: #ddc99b; --ink-soft: #9c8a65; --ink-faint: #8e7e5e;
  --accent: #d44a31; --rule: rgba(221,201,155,0.12); --rule-soft: rgba(221,201,155,0.06);
  --selection: rgba(212,74,49,0.18);
  --shadow: 0 28px 70px -30px rgba(0,0,0,0.95), 0 6px 14px -10px rgba(0,0,0,0.5);
}
html[data-edition="onionskin"] .book {
  background: var(--page); padding: 4rem 3rem 5rem 5.5rem; box-shadow: var(--shadow); border-radius: 1px;
  background-image:
    linear-gradient(to right, transparent 4.2rem, var(--rule-blue) 4.2rem, var(--rule-blue) calc(4.2rem + 1px), transparent calc(4.2rem + 1px)),
    repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px));
}
html[data-edition="onionskin"] .book::before { content: ''; position: absolute; top: 4rem; left: 2.2rem; width: 1.4rem; height: 1.4rem; border-radius: 50%; border: 1.5px solid var(--accent); opacity: 0.35; transform: rotate(-12deg); }
html[data-edition="onionskin"] .book::after { content: '✓'; position: absolute; top: 4.15rem; left: 2.4rem; color: var(--accent); font-family: var(--font-display); font-size: 1rem; opacity: 0.55; transform: rotate(-12deg); }
html[data-edition="onionskin"] .meta { display: flex; align-items: baseline; gap: 0.4rem; font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--ink-soft); border-bottom: 1px dashed var(--line-firm); padding-bottom: 0.7rem; margin-bottom: 2.6rem; }
html[data-edition="onionskin"] .meta::before { content: '— DRAFT —'; color: var(--accent); }
html[data-edition="onionskin"] .meta-by, html[data-edition="onionskin"] .meta-time { display: none; }
html[data-edition="onionskin"] .meta-words { margin-left: auto; }
html[data-edition="onionskin"] .meta-words .meta-val::after { content: ' words'; }
html[data-edition="onionskin"] .meta-pages::before { content: ' · '; }
html[data-edition="onionskin"] .meta-pages .meta-val::after { content: ' pp.'; }
html[data-edition="onionskin"] .title { font-family: var(--font-display); font-weight: 400; font-size: clamp(1.15rem, 3.6vw, 1.5rem); text-align: center; text-transform: uppercase; letter-spacing: 0.1em; line-height: 1.3; color: var(--ink); margin: 2.5rem 0 0.7rem; }
html[data-edition="onionskin"] .byline { text-align: center; font-family: var(--font-body); font-size: 0.95rem; color: var(--ink-soft); margin-bottom: 3.2rem; }
html[data-edition="onionskin"] .prose p { font-family: var(--font-body); font-size: calc(var(--reading-base)*var(--reading-scale)); line-height: 1.65rem; color: var(--ink); text-indent: 2.5em; }
html[data-edition="onionskin"] .prose p.opener { text-indent: 0; }
html[data-edition="onionskin"] .prose p.opener::first-letter { font: inherit; float: none; color: inherit; }
html[data-edition="onionskin"] .brk { border: none; text-align: center; margin: 1.65rem 0; font-family: var(--font-body); color: var(--ink-faint); letter-spacing: 0.4em; line-height: 1.65rem; font-size: 1rem; }
html[data-edition="onionskin"] .brk::after { content: '# # #'; }
html[data-edition="onionskin"] .colophon { display: none; }
html[data-edition="onionskin"] .invitation { text-align: center; background: var(--page); box-shadow: var(--shadow); border-radius: 1px; padding: 5rem 3rem; background-image: repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px)); }
html[data-edition="onionskin"] .inv-label { display: inline-block; font-family: var(--font-display); font-size: 0.7rem; letter-spacing: 0.4em; color: var(--accent); border: 1.5px solid var(--accent); padding: 0.4rem 0.9rem 0.35rem; transform: rotate(-3deg); margin-bottom: 3rem; }
html[data-edition="onionskin"] .inv-head { font-family: var(--font-display); font-size: clamp(1.6rem, 4.6vw, 2.3rem); color: var(--ink); line-height: 1.3; margin-bottom: 0.9rem; }
html[data-edition="onionskin"] .inv-sub { font-family: var(--font-body); font-size: 1rem; color: var(--ink-soft); line-height: 1.6; }
html[data-edition="onionskin"] .inv-key { margin-top: 3rem; font-family: var(--font-display); font-size: 0.68rem; letter-spacing: 0.35em; color: var(--ink-faint); }
html[data-edition="onionskin"] .editor {
  background: var(--page); box-shadow: var(--shadow); border-radius: 1px; padding: 3.5rem 3rem 4rem 5.5rem; line-height: 1.65rem;
  background-image:
    linear-gradient(to right, transparent 4.2rem, var(--rule-blue) 4.2rem, var(--rule-blue) calc(4.2rem + 1px), transparent calc(4.2rem + 1px)),
    repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px));
}
html[data-edition="onionskin"] .mark-glyph { font-size: 0.85rem; letter-spacing: 0.3em; }

/* ============================================================
   6. EDITION — QUIET PAGE  (minimal editorial, vast whitespace)
   ============================================================ */
html[data-edition="quietpage"] {
  --font-body: 'Source Serif 4', Georgia, serif;
  --font-display: 'Fraunces', serif;
  --font-ui: 'Source Serif 4', serif;
  --reading-base: 1.3rem; --measure: 34rem; --editor-measure: 34rem;

  --bg: #fafaf6; --page: #fafaf6; --page-edge: #eeede6;
  --ink: #1c1c1a; --ink-soft: #6a6a64; --ink-faint: #75746c;
  --accent: #1c1c1a; --rule: rgba(28,28,26,0.10); --rule-soft: rgba(28,28,26,0.05);
  --selection: rgba(28,28,26,0.10);
  --shadow: 0 24px 60px -34px rgba(28,28,26,0.32), 0 4px 14px -12px rgba(28,28,26,0.18);
  --body-texture: none;
}
html[data-edition="quietpage"][data-theme="dark"] {
  --bg: #16161a; --page: #1c1c20; --page-edge: #26262b;
  --ink: #d9d6cb; --ink-soft: #8a877e; --ink-faint: #86837c;
  --accent: #d9d6cb; --rule: rgba(217,214,203,0.12); --rule-soft: rgba(217,214,203,0.06);
  --selection: rgba(217,214,203,0.12);
  --shadow: 0 28px 70px -34px rgba(0,0,0,0.8), 0 4px 14px -12px rgba(0,0,0,0.5);
}
html[data-edition="quietpage"] body { padding-top: clamp(5rem, 14vh, 10rem); padding-bottom: clamp(6rem, 18vh, 12rem); }
html[data-edition="quietpage"] .book { background: none; box-shadow: none; padding: 0; }
html[data-edition="quietpage"] .book::before { display: none; }
html[data-edition="quietpage"] .eyebrow { display: block; font-family: var(--font-body); font-style: italic; font-weight: 300; font-size: 0.85rem; color: var(--ink-faint); letter-spacing: 0.02em; margin-bottom: 1.4rem; }
html[data-edition="quietpage"] .eyebrow::before { content: ''; display: inline-block; width: 1.4rem; height: 1px; background: var(--ink-faint); vertical-align: middle; margin-right: 0.7rem; }
html[data-edition="quietpage"] .title { font-family: var(--font-display); font-weight: 300; font-variation-settings: "opsz" 144; font-size: clamp(2.6rem, 6.5vw, 4.2rem); line-height: 1.02; letter-spacing: -0.035em; color: var(--ink); margin-bottom: 0.4rem; }
html[data-edition="quietpage"] .byline { font-family: var(--font-body); font-style: italic; font-weight: 400; font-size: 1rem; color: var(--ink-soft); margin-bottom: 3.2rem; }
html[data-edition="quietpage"] .prose p { font-family: var(--font-body); font-size: calc(var(--reading-base)*var(--reading-scale)); line-height: 1.72; color: var(--ink); margin-bottom: 1.3em; font-weight: 400; }
html[data-edition="quietpage"] .prose p.opener::first-letter { font-family: var(--font-display); font-style: italic; font-weight: 300; font-size: 1.15em; color: var(--ink); }
html[data-edition="quietpage"] .brk { border: none; height: 1px; width: 4rem; background: var(--rule); margin: 2.6rem 0; }
html[data-edition="quietpage"] .brk::after { content: none; }
html[data-edition="quietpage"] .colophon { justify-content: space-between; text-transform: none; letter-spacing: 0.01em; font-family: var(--font-body); font-style: italic; font-weight: 300; font-size: 0.8rem; margin-top: 5rem; }
html[data-edition="quietpage"] .col-sep { display: none; }
html[data-edition="quietpage"] .col-words::after { content: ' words'; }
html[data-edition="quietpage"] .invitation { text-align: left; padding: 4rem 0 6rem; }
html[data-edition="quietpage"] .inv-label { font-family: var(--font-body); font-style: italic; font-weight: 300; font-size: 0.85rem; color: var(--ink-faint); letter-spacing: 0.02em; margin-bottom: 2.5rem; }
html[data-edition="quietpage"] .inv-label::before { content: ''; display: inline-block; width: 1.4rem; height: 1px; background: var(--ink-faint); vertical-align: middle; margin-right: 0.7rem; }
html[data-edition="quietpage"] .inv-head { font-family: var(--font-display); font-weight: 200; font-variation-settings: "opsz" 144; font-size: clamp(2.8rem, 8vw, 5rem); line-height: 1.0; color: var(--ink); margin-bottom: 1.4rem; letter-spacing: -0.04em; }
html[data-edition="quietpage"] .inv-head em { font-style: italic; font-weight: 200; color: var(--ink-soft); }
html[data-edition="quietpage"] .inv-sub { font-family: var(--font-body); font-size: 1.15rem; line-height: 1.55; color: var(--ink-soft); max-width: 26rem; font-weight: 300; }
html[data-edition="quietpage"] .inv-key { margin-top: 4rem; font-family: var(--font-body); font-style: italic; font-weight: 300; font-size: 0.82rem; color: var(--ink-faint); letter-spacing: 0.01em; }
html[data-edition="quietpage"] .inv-key kbd { font: inherit; color: var(--ink); border-bottom: 1px solid var(--rule); padding: 0 1px 2px; margin: 0 0.15rem; }
/* mark = a bare graphite dot that swells on hover */
html[data-edition="quietpage"] .mark { width: 0.6rem; height: 0.6rem; background: var(--ink-faint); opacity: 0.7; }
html[data-edition="quietpage"] .mark-glyph { display: none; }
html[data-edition="quietpage"] .mark:hover { width: 3.4rem; height: 3.4rem; background: transparent; border: 1px solid var(--rule); }
html[data-edition="quietpage"] .mark:hover .mark-glyph { display: block; }
/* touch: the dot can't be hovered — give it a real tap target */
@media (hover: none) { html[data-edition="quietpage"] .mark { width: 3.4rem; height: 3.4rem; background: transparent; border: 1px solid var(--rule); }
  html[data-edition="quietpage"] .mark .mark-glyph { display: block; } }

/* ============================================================
   PAGINATED READING FLOW
   ============================================================ */
body[data-mode="read"] .book.is-paginated {
  display: block;
  width: min(100%, var(--measure));
  max-width: none;
  padding: 0;
  background: none;
  background-image: none;
  box-shadow: none;
  border-radius: 0;
}
body[data-mode="read"] .book.is-paginated::before,
body[data-mode="read"] .book.is-paginated::after { display: none; }
body[data-mode="read"] .book.is-paginated > .masthead,
body[data-mode="read"] .book.is-paginated > .eyebrow,
body[data-mode="read"] .book.is-paginated > .meta {
  display: none;
}
/* Paged mode has no trailing colophon: the stats already live in page 1's
   frontmatter, and a lone stats strip dressed as a page reads as a broken sheet. */
body[data-mode="read"] .book.is-paginated > .colophon { display: none; }
body[data-mode="read"] .book.is-paginated .prose.paginated {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 5.5vh, 3.6rem);
  max-width: none;
}
body[data-mode="read"] .reader-page {
  position: relative;
  width: 100%;
  height: var(--reader-page-height, 46rem);
  /* bottom padding is the JS-measured folio band (--reader-page-footer-padding);
     the clamp is only a floor for the rare no-JS case — kept low so the measured
     band, not the clamp, decides where prose stops (was flooring ~4 lines of waste). */
  padding: clamp(3.4rem, 7vh, 5.2rem) clamp(1.75rem,5.5vw,4.75rem) max(clamp(2.4rem, 4.5vh, 3.4rem), var(--reader-page-footer-padding, 3.4rem));
  background: var(--page);
  color: var(--ink);
  box-shadow: var(--shadow);
  border-radius: 2px;
  overflow: hidden;
  contain: layout;   /* isolates the per-page layout reads the measured paginator makes */
}
body[data-mode="read"] .reader-page.bookmarked::before {
  content: none;
  display: none !important;
}
body[data-mode="read"] .reader-page .page-bookmark {
  position: absolute;
  top: 0;
  right: clamp(0.85rem, 2.8vw, 1.45rem);
  z-index: 6;
  width: 2.15rem;
  height: 3.35rem;
  display: inline-flex;
  align-items: flex-start;
  justify-content: center;
  padding: 0.58rem 0 0;
  color: color-mix(in srgb, var(--page) 35%, var(--accent));
  background: color-mix(in srgb, var(--page) 80%, var(--accent));
  border: 1px solid color-mix(in srgb, var(--page) 74%, var(--accent));
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
  box-shadow: 0 8px 18px rgba(0,0,0,0.08);
  opacity: 0.72;
  /* color-only transition: transform/opacity transitions promote the ribbon to a
     compositing layer, and iOS Safari fails to clip composited children to the
     page's overflow:hidden — the ribbon paints past the sheet's top edge. */
  transition: background-color 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
body[data-mode="read"] .reader-page .page-bookmark svg {
  display: block;
  width: 1rem;
  height: 1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linejoin: round;
}
body[data-mode="read"] .reader-page .page-bookmark:hover,
body[data-mode="read"] .reader-page .page-bookmark:focus-visible {
  opacity: 0.9;
}
body[data-mode="read"] .reader-page .page-bookmark.active {
  color: var(--page);
  background: color-mix(in srgb, var(--page) 44%, var(--accent));
  border-color: color-mix(in srgb, var(--page) 38%, var(--accent));
  opacity: 0.9;
}
body[data-mode="read"] .reader-page .page-bookmark.active svg {
  fill: currentColor;
}
body[data-mode="read"] .reader-page::after {
  content: attr(data-page-number);
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--reader-page-number-offset, 2.8rem);
  text-align: center;
  font-family: var(--font-chrome);
  font-size: max(0.72rem, 11px);   /* legibility floor — 0.62rem rendered ~9px on mobile */
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  opacity: 0.66;
  pointer-events: none;
}
body[data-mode="read"] .reader-page-body {
  min-height: 0;
}
body[data-mode="read"] .reader-page-probe {
  position: static !important;
  width: 100% !important;
  visibility: hidden !important;
  pointer-events: none !important;
  overflow: visible !important;
}
body[data-mode="read"] .reader-page [data-page-frontmatter] {
  max-width: none;
}
body[data-mode="read"] .reader-page .masthead[data-page-frontmatter] {
  margin-top: 0;
  margin-bottom: clamp(2rem, 6vh, 3.6rem);
}
body[data-mode="read"] .reader-page .meta[data-page-frontmatter] {
  margin-bottom: clamp(1.2rem, 3vh, 2rem);
}
/* Reading time's home (owner's pick): a quiet "68,970 words · 5 hr" line on the
   first sheet for the editions whose base design hides the meta block entirely.
   Periodical/Onion Skin keep their own richer meta treatments (edition-scoped
   rules win on specificity). */
html[data-edition="letterpress"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter],
html[data-edition="quietpage"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] {
  display: flex;
  justify-content: center;
  gap: 0.55rem;
  font-family: var(--font-chrome);
  font-size: max(0.66rem, 11px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
html[data-edition="letterpress"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] .meta-by,
html[data-edition="quietpage"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] .meta-by,
html[data-edition="letterpress"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] .meta-pages,
html[data-edition="quietpage"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] .meta-pages {
  display: none;   /* just words · time — the byline lives in the masthead, pages in the HUD */
}
html[data-edition="letterpress"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] .meta-words .meta-val::after,
html[data-edition="quietpage"] body[data-mode="read"] .reader-page .meta[data-page-frontmatter] .meta-words .meta-val::after {
  content: ' words · ';
}
body[data-mode="read"] .reader-page-body > :first-child { margin-top: 0; }
body[data-mode="read"] .reader-page-body > :last-child { margin-bottom: 0; }
body[data-mode="read"] .reader-page-body p.continued {
  text-indent: 0 !important;
}
body[data-mode="read"] .reader-page-body :is(blockquote, ul, ol).continued {
  margin-top: 0;
}
body[data-mode="read"] .reader-page-body li.continued {
  list-style: none;
}
body[data-mode="read"] .reader-page-body p.continued::first-letter {
  font: inherit !important;
  float: none !important;
  color: inherit !important;
}
html[data-edition="letterpress"] body[data-mode="read"] .reader-page {
  background: var(--page);
  background-image:
    linear-gradient(to right, rgba(0,0,0,0.025), transparent 4%, transparent 96%, rgba(0,0,0,0.025)),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 100% 100%, 280px 280px;
  box-shadow:
    var(--shadow),
    inset 0 0 60px 0 rgba(0,0,0,0.03);
}
html[data-edition="onionskin"] body[data-mode="read"] .reader-page {
  padding-left: clamp(3rem, 7vw, 5.5rem);
  background-image:
    linear-gradient(to right, transparent 4.2rem, var(--rule-blue) 4.2rem, var(--rule-blue) calc(4.2rem + 1px), transparent calc(4.2rem + 1px)),
    repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px));
}
html[data-edition="periodical"] body[data-mode="read"] .book.is-paginated .masthead,
html[data-edition="periodical"] body[data-mode="read"] .book.is-paginated .meta,
html[data-edition="periodical"] body[data-mode="read"] .book.is-paginated .prose,
html[data-edition="periodical"] body[data-mode="read"] .book.is-paginated .colophon {
  grid-column: auto;
}
html[data-edition="quietpage"] body[data-mode="read"] .reader-page {
  background: var(--page);
  box-shadow: var(--shadow);
}

/* ============================================================
   7. RESPONSIVE
   ============================================================ */
@media (max-width: 820px) {
  html[data-edition="periodical"] .book { grid-template-columns: 1fr; row-gap: 1.4rem; }
  html[data-edition="periodical"] .meta { position: static; grid-row: auto; display: flex; flex-wrap: wrap; gap: 1.2rem; padding-bottom: 1rem; border-bottom: 1px solid var(--rule-soft); }
  html[data-edition="periodical"] .meta::before { width: 100%; margin-bottom: 0; }
  html[data-edition="periodical"] .meta-field { margin-bottom: 0; }
  html[data-edition="periodical"] .masthead, html[data-edition="periodical"] .prose { grid-column: 1; }
  html[data-edition="periodical"] .prose { max-width: none; }
}
@media (max-width: 640px) {
  /* real side gutters on phones: the bleed editions (periodical, quietpage)
     have no card, so they inherit this; ~1.25rem keeps text off the glass. */
  body { padding: 2.5rem 1.25rem 4rem; }

  html[data-edition="letterpress"] .book { padding: 2.6rem 1.9rem 3.2rem; }
  body[data-mode="read"] .book.is-paginated { padding: 0; }
  body[data-mode="read"] .reader-page {
    padding: 2.6rem 1.9rem max(3rem, var(--reader-page-footer-padding, 3rem));
    height: var(--reader-page-height, 35rem);
  }
  body[data-mode="read"] .reader-page::after { bottom: var(--reader-page-number-offset, 2.25rem); font-size: max(0.64rem, 11px); }
  body[data-mode="read"] .reader-page-body { min-height: 0; }
  html[data-edition="onionskin"] body[data-mode="read"] .reader-page {
    padding-left: 3rem;
    background-image:
      linear-gradient(to right, transparent 2.2rem, var(--rule-blue) 2.2rem, var(--rule-blue) calc(2.2rem + 1px), transparent calc(2.2rem + 1px)),
      repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px));
  }
  html[data-edition="letterpress"] .prose p { font-size: calc(1.18rem * var(--reading-scale)); text-align: left; hyphens: none; text-indent: 1.2em; }
  html[data-edition="letterpress"] .prose p.opener::first-letter { font-size: 3.6em; }

  html[data-edition="onionskin"] .book {
    padding: 3rem 1.5rem 3rem 3rem;
    background-image:
      linear-gradient(to right, transparent 2.2rem, var(--rule-blue) 2.2rem, var(--rule-blue) calc(2.2rem + 1px), transparent calc(2.2rem + 1px)),
      repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px));
  }
  html[data-edition="onionskin"] .book::before, html[data-edition="onionskin"] .book::after { left: 1rem; }
  html[data-edition="onionskin"] .editor { padding: 3rem 1.5rem 3rem 3rem;
    background-image:
      linear-gradient(to right, transparent 2.2rem, var(--rule-blue) 2.2rem, var(--rule-blue) calc(2.2rem + 1px), transparent calc(2.2rem + 1px)),
      repeating-linear-gradient(to bottom, transparent 0, transparent 1.65rem, var(--line) 1.65rem, var(--line) calc(1.65rem + 1px));
  }

  html[data-edition="periodical"] .prose p { font-size: calc(1.2rem * var(--reading-scale)); }
  html[data-edition="quietpage"] .prose p { font-size: calc(1.19rem * var(--reading-scale)); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
