/* Reading themes. Paper is the light default; auto (no data-theme) follows
   the OS. Night is warm off-white on off-black, never pure white on black. */
:root{
  --bg:#f8f7f3; --ink:#1c2320; --ink-2:#4b544e; --muted:#5f6962;
  --line:#e4e2da; --line-strong:#d6d3c9; --hover:#efede6;
  --accent:#1f4f42; --accent-hover:#2a6a58; --on-accent:#fff; --visited:#64506e;
  --track:#e4e2da; --surface:#fff; --scrim:rgba(28,35,32,.45);
  --pill-bg:#e3ece6; --cover-ink:#f1efe8; --danger:#b3261e; --danger-bg:#f6e3de; --danger-line:#e8c2b8;
  --serif:ui-serif,'Iowan Old Style',Charter,'Bitstream Charter',Georgia,serif;
  --sans:system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:ui-monospace,'SF Mono',Menlo,monospace;
  --read-size:19px; --read-lh:1.7; --read-width:640px;
  color-scheme:light;
}
html[data-theme="sepia"]{
  --bg:#f4ecdc; --ink:#33291b; --ink-2:#33291b; --muted:#6f5f47;
  --line:#e3d6bd; --line-strong:#d4c4a6; --hover:#ece2cc;
  --accent:#1f4f42; --on-accent:#fff; --track:#e3d6bd; --surface:#f4ecdc; --visited:#644a5f;
  --scrim:rgba(51,41,27,.45); --pill-bg:#e9ddc4; --cover-ink:#f1efe8; --danger:#b3261e; --danger-bg:#f3dccf; --danger-line:#e0bda6;
}
html[data-theme="night"]{
  --bg:#121513; --ink:#d6dcd7; --ink-2:#aab3ad; --muted:#8b958e;
  --line:#262d29; --line-strong:#38413c; --hover:#1f2522;
  --accent:#8fc9b0; --accent-hover:#8fc9b0; --on-accent:#121513; --visited:#c3aecd;
  --track:#262d29; --surface:#1b201d; --scrim:rgba(0,0,0,.55);
  --pill-bg:#1e2b25; --cover-ink:#f1efe8; --danger:#f0856d; --danger-bg:#2e1d19; --danger-line:#5a3027;
  color-scheme:dark;
}
@media (prefers-color-scheme: dark){
  html:not([data-theme="paper"]):not([data-theme="sepia"]){
    /* auto + night: same token set as html[data-theme="night"] */
    --bg:#121513; --ink:#d6dcd7; --ink-2:#aab3ad; --muted:#8b958e;
    --line:#262d29; --line-strong:#38413c; --hover:#1f2522;
    --accent:#8fc9b0; --accent-hover:#8fc9b0; --on-accent:#121513; --track:#262d29; --surface:#1b201d; --visited:#c3aecd;
    --scrim:rgba(0,0,0,.55); --pill-bg:#1e2b25; --cover-ink:#f1efe8; --danger:#f0856d; --danger-bg:#2e1d19; --danger-line:#5a3027; color-scheme:dark;
  }
}

/* Component layer (C6). Every rule reads the token blocks above; class
   names are the pre-redesign vocabulary so screens not yet redesigned
   inherit the new look unchanged. Square corners, 1px hairlines, 44px
   tap-target floor, logical properties throughout (dir=rtl mirrors free). */

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.6 var(--sans);
  /* header, main, footer: the footer rests at the viewport bottom on short pages */
  min-height: 100vh; display: flex; flex-direction: column;
}
.site-main { flex: 1 0 auto; width: 100%; }
a { color: var(--accent); }
/* Plain text links show where the reader has been; component links (titles,
   rows, chips, controls) carry their own classes and keep their colors. */
.site-main a:not([class]):visited { color: var(--visited); }
a:hover { color: var(--accent-hover); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
::selection { background: var(--pill-bg); }
html { scrollbar-color: var(--line-strong) var(--bg); }
input, select, textarea { caret-color: var(--accent); }

/* Site header: one row, hairline bottom, nav links between the brand and
   the Menu control (mobile) or the search form (desktop). */
.site-head {
  display: flex; align-items: center; gap: 0;
  min-height: 56px; padding-inline: 20px 8px;
  background: var(--bg);
  border-block-end: 1px solid var(--line);
}
.brand {
  font-family: var(--serif); font-variant: small-caps; letter-spacing: .08em;
  font-size: 20px; color: var(--ink); text-decoration: none; white-space: nowrap;
}
.site-nav { display: flex; align-items: center; gap: 2px; min-height: 44px; }
.site-nav a, .nav-account {
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: 12px; white-space: nowrap; text-decoration: none;
  font: 500 15px/1 var(--sans); color: var(--ink);
}
.site-nav a:hover, .nav-account:hover, .nav-search-link:hover, .nav-menu-link:hover { color: var(--accent); }
/* Authors/Series are D3-only; the account link lives in the Menu sheet
   below 768px (M1 shows only Search and Menu). */
.site-nav .nav-wide { display: none; }
.nav-account { display: none; }
.nav-search { display: none; }
.nav-search input {
  width: 300px; min-height: 40px; padding: 4px 10px;
  border: 1px solid var(--line-strong); border-radius: 0;
  background: var(--surface); color: var(--ink); font: 15px var(--sans);
}
.nav-menu-link {
  margin-inline-start: auto;
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: 12px; text-decoration: none;
  font: 500 14px/1 var(--sans); color: var(--ink);
}
/* The plain /search link sits between the nav and the Menu control; it is
   the search affordance wherever the input form is hidden (below 1024px). */
.nav-search-link {
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: 12px; white-space: nowrap; text-decoration: none;
  font: 500 14px/1 var(--sans); color: var(--ink);
}

/* The header theme quick toggle: markup on every themed page, but dead
   weight without scripting, so the base rule hides it and html.js reveals
   a 44px square icon button. The glyph is a half-filled circle drawn here
   (no icon font, no image): ink on the header's own background, so the
   same two colors read in paper, sepia, and night. */
.theme-toggle { display: none; }
.js .theme-toggle { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; flex: none; padding: 0; border: 0; background: transparent; color: var(--ink); }
.js .theme-toggle:hover { background: var(--hover); color: var(--ink); }
.theme-toggle::before {
  content: ""; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid currentColor;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}

/* Main column: mobile gutters by default, the 1200px shell from 1024px. */
.site-main { padding: 32px 24px 64px; }

/* The site footer: secondary destinations and the site credit. */
.site-foot {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px 32px;
  margin-block-start: 0; padding: 28px 20px 36px;
  border-block-start: 1px solid var(--line);
  font: 13px/1.6 var(--sans); color: var(--muted);
}
.foot-brand { margin: 0; }
.foot-brand > a { font: 15px var(--serif); font-variant: small-caps; letter-spacing: .08em; color: var(--ink); text-decoration: none; margin-inline-end: 6px; }
.site-foot a { color: var(--ink-2); }
.site-foot a:hover { color: var(--accent); }
.foot-nav { display: flex; flex-wrap: wrap; gap: 4px 20px; }
.foot-nav a { display: inline-flex; align-items: center; min-height: 44px; text-decoration: none; }
@media (min-width:1024px) { .foot-nav a { min-height: 32px; } }
/* Reading surfaces keep their own chrome: no footer under the reader. */
body:has(.reader) .site-foot { display: none; }
@media (min-width:768px) { .site-foot { padding-inline: 40px; } }
@media (min-width:1024px) { .site-foot { padding-inline: max(40px, calc((100% - 1200px) / 2 + 40px)); } }

/* Sheets: the zero-JS dialog pattern. Hidden until :target, then a fixed
   panel anchored to the bottom edge. The scrim dims the page behind an open
   sheet where body:has() is available; where it is not, the sheet's own
   opaque surface and max-height keep it fully usable on its own. */
.sheet { display: none; }
.sheet:target {
  display: flex; flex-direction: column;
  position: fixed; inset-inline: 0; bottom: 0; z-index: 40;
  max-height: 85vh; overflow-y: auto;
  background: var(--surface);
  border-block-start: 1px solid var(--line-strong);
  padding: 8px 24px 24px;
  box-shadow: 0 -12px 40px -12px var(--scrim);
}
.sheet-handle { display: block; width: 36px; height: 4px; margin: 4px auto 8px; background: var(--line-strong); }
.sheet-done {
  margin-inline-start: auto;
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: 12px; text-decoration: none;
  font: 600 15px/1 var(--sans); color: var(--accent);
}
.sheet:target nav { display: flex; flex-direction: column; padding-block: 4px; }
.sheet:target nav a {
  display: flex; align-items: center; min-height: 48px;
  padding-inline: 4px; text-decoration: none; color: var(--ink);
  font: 15px/1.3 var(--sans);
  border-block-end: 1px solid var(--line);
}
.sheet:target nav a:last-child, .sheet:target nav a:has(+ .sheet-group) { border-block-end: none; }
.sheet nav .sheet-group:first-child { margin-block-start: 4px; }
.sheet-group { display: block; margin: 20px 0 2px; font: 12px/1.5 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.sheet-logout { margin-block-start: 12px; padding-block-start: 12px; border-block-start: 1px solid var(--line); }
.sheet-logout .link-btn { min-height: 44px; color: var(--muted); font-size: 15px; }
.page-head .page-actions .link-btn { color: var(--muted); }
.scrim { display: none; }
body:has(.sheet:target) .scrim {
  display: block; position: fixed; inset: 0; z-index: 30;
  background: var(--scrim);
}
/* An empty hash-target for the Done links to land on; never visible. */
.skip-close { position: fixed; inset-block-start: 0; inset-inline-start: 0; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* Typography: serif headings at weight 400, balanced wrapping, tabular
   numerals wherever counts render. */
h1, h2, h3, h4 {
  font-family: var(--serif); font-weight: 400;
  line-height: 1.15; text-wrap: balance; margin: 0 0 .75rem;
}
h1 { font-size: 38px; line-height: 1.05; }
h2 { font-size: 22px; }
h3, h4 { font-size: 18px; }
.meta, .chapter-meta {
  color: var(--muted); font-family: var(--sans);
  font-size: 13px; line-height: 1.5;
}
.meta { font-size: 12.5px; font-variant-numeric: tabular-nums; }
kbd {
  font-family: var(--mono); font-size: .85em;
  border: 1px solid var(--line-strong); padding: 1px 5px;
}

/* Reading column: the core of the product. Token-driven so C8's data-attr
   overrides only ever rebind --read-size/-lh/-width. Book paragraphs: the
   first sits flush, every later one indents (the spaced mode opts out). */
.prose {
  font-family: var(--serif);
  font-size: var(--read-size); line-height: var(--read-lh);
  max-width: var(--read-width); margin-inline: auto;
  text-wrap: pretty; hyphens: auto;
}
.prose p { margin: 0; }
html:not([data-paragraphs="spaced"]) .prose p + p { text-indent: 1.4em; }
html[data-paragraphs="spaced"] .prose p { margin-block-end: 1em; }
/* Chapter prose is the reader's own: .e-content on the chapter page and
   section.prose on the whole work. Every other markdown body (a review, a
   reply, a news comment, a message, a bio, a challenge prompt) is body copy
   inside its card: flush, 17px, spaced paragraphs, no opening small caps,
   no book indent. The design pass caught reviews rendering as chapter
   openings (centered 640px column, small-caps first line). */
.prose:not(.e-content, section) { font-size: 17px; line-height: 1.6; max-width: none; margin-inline: 0; }
html .prose:not(.e-content, section) p + p { text-indent: 0; margin-block-start: .6em; }
.prose ul, .prose ol { margin: 0 0 1em; padding-inline-start: 1.5em; }
.prose blockquote { margin: 0 0 1em; padding-inline-start: 1em; border-inline-start: 2px solid var(--line-strong); }
.prose img { max-width: 100%; height: auto; }
.chapter-meta { margin-block: .25rem; }
/* The Text panel's plain link into focus mode (the F key's no-script twin). */
.focus-entry-row { margin: 1rem 0 0; }
.focus-entry { display: inline-flex; align-items: center; min-height: 44px; font: 14px/1.4 var(--sans); color: var(--accent); }
/* Once the infinite module stacks chapters, the opening chapter's static
   prev/next block would point at the wrong chapters: each unit's own
   next-chapter link and the contents list take over. */
.reader.is-stacked .chapter-nav { display: none; }
.chapter-nav {
  display: flex; justify-content: space-between; gap: 1rem;
  max-width: var(--read-width); margin-inline: auto; margin-block: 2.5rem;
}

/* Listings and cards. */
.story-list { list-style: none; margin: 0; padding: 0; }
.story-list li { border-block-start: 1px solid var(--line); padding: 20px 0; }
.story-list li:last-child { border-block-end: 1px solid var(--line); }
.story-list > li > a:first-child { font-family: var(--serif); font-size: 22px; line-height: 1.25; }
.badge {
  display: inline-block; border: 1px solid var(--line-strong); border-radius: 0;
  padding: 2px 8px; font: 500 12px/1.5 var(--sans);
  letter-spacing: .04em; color: var(--ink-2);
}
.card {
  max-width: 480px; margin: 4rem auto; text-align: center;
  border: 1px solid var(--line-strong); background: var(--surface);
  padding: 2.5rem 2rem;
}
/* The age gate card: the story's identity leads (the gate page is the
   crawler's view of the work), the warning reads as the label it is. */
.gate-kicker {
  display: block; margin: 0 0 .25rem;
  font: 500 12px/1.5 var(--sans); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.gate-by { margin: 0 0 1.5rem; color: var(--muted); }

.review { border-block-start: 1px solid var(--line); padding-block: 1.5rem; max-width: 720px; }
.review-reply {
  margin: 1rem 0; padding-inline-start: 1rem;
  border-inline-start: 2px solid var(--line-strong);
}
.whole-toc { margin-block: 1.5rem 2.5rem; }
.print-hint { display: block; margin-block-start: .5rem; font: 12px var(--sans); color: var(--muted); }

/* Forms and controls (Kip blog S4/S5, admin 03): bold 13px labels stacked
   over full-width fields, square 1px boxes, a 44px floor, and one solid
   brand-green primary action per form. Inline forms (one field plus a
   button, or a lone toggle) stay on one row with outline buttons. */
label { display: block; margin-block-end: .5rem; font: 13px/1.5 var(--sans); color: var(--ink-2); }
input, select, textarea {
  min-height: 44px; padding: 6px 12px;
  border: 1px solid var(--line-strong); border-radius: 0;
  background: var(--surface); color: var(--ink); font: 16px var(--sans);
}
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
input[type="checkbox"], input[type="radio"] { min-height: 0; width: 18px; height: 18px; accent-color: var(--accent); }
input[type="search"] { min-height: 40px; }
textarea { min-height: 96px; line-height: 1.6; }
button {
  min-height: 44px; padding: 8px 16px;
  border: 1px solid var(--line-strong); border-radius: 0;
  background: transparent; color: var(--ink);
  font: 500 15px var(--sans); cursor: pointer;
}
button:hover { background: var(--hover); color: var(--ink); }
button:disabled { opacity: .5; cursor: not-allowed; }
.inline { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.site-main form:where(:not(.inline):not(.text-settings)) label:where(:not(.inline)) {
  display: flex; flex-direction: column; gap: 6px; margin-block-end: 18px;
  font: 600 13.5px/1.4 var(--sans); color: var(--ink);
}
.site-main form:where(:not(.inline):not(.text-settings)) label.inline { display: flex; margin-block-end: 18px; font: 15px/1.4 var(--sans); color: var(--ink); }
.site-main form:where(:not(.inline):not(.text-settings)) :where(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="range"]):not([type="file"]), select) { width: 100%; max-width: 560px; font-weight: 400; }
.site-main form:where(:not(.inline):not(.text-settings)) textarea { width: 100%; font: 400 17px/1.6 var(--serif); }
.site-main fieldset:not(.text-settings fieldset) { border: 1px solid var(--line); padding: 16px 18px 4px; margin: 0 0 18px; }
.site-main fieldset legend { padding-inline: 6px; font: 600 12px/1.5 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
/* A checkbox or radio label reads as one row: control, then its text. */
.site-main form:not(.text-settings) label:has(> input:is([type="checkbox"], [type="radio"])) {
  display: flex; flex-direction: row; align-items: center; gap: 10px;
  margin-block-end: 12px; font: 400 15px/1.4 var(--sans); color: var(--ink);
}
/* Account settings: each form is its own block under the Settings rule. */
.settings-group > form { padding-block: 16px 20px; }
.settings-group > form + form:not(:has(> .section-label:first-of-type)) { padding-block-start: 0; }
.settings-group .section-label { margin-block: 28px 12px; }
.settings-group > .section-label:first-child { margin-block-start: 8px; }
.settings-group .avatar { display: block; margin-block: 16px 0; border: 1px solid var(--line-strong); }
.field-hint { display: block; font: 400 13px/1.5 var(--sans); color: var(--muted); }
/* The primary action: the last direct-child submit of a stacked form. */
.btn-primary,
.site-main form:where(:not(.inline):not(.text-settings)):has(:is(input:not([type="hidden"]), select, textarea)) > button:last-of-type:where(:not(.link-btn):not(.reset-link):not(.btn-secondary)) {
  min-height: 48px; padding-inline: 24px;
  background: #1f4f42; border-color: #1f4f42; color: #fff; font-weight: 500;
}
.btn-primary:hover,
.site-main form:where(:not(.inline):not(.text-settings)):has(:is(input:not([type="hidden"]), select, textarea)) > button:last-of-type:where(:not(.link-btn):not(.reset-link):not(.btn-secondary)):hover { background: #1f4f42; color: #fff; opacity: .92; }
.link-btn { min-height: 0; padding: 0; border: 0; background: none; color: var(--accent); font: inherit; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.link-btn:hover { background: none; color: var(--accent-hover); }
/* Form card (Kip blog S3 "Leave a comment"): a white surface holding a
   short title, the fields, and the primary action. */
.form-card { max-width: 640px; margin-block: 8px 0; padding: 24px; background: var(--surface); border: 1px solid var(--line-strong); }
.form-card-title { margin: 0 0 16px; font: 600 15px/1.4 var(--sans); color: var(--ink); }
.site-main .form-card select { max-width: 240px; }

/* Alerts (S5): a tinted box with the message and its fix; notices are the
   quiet green twin. */
.error, [role="alert"] {
  display: block; margin: 0 0 18px; padding: 12px 14px;
  background: var(--danger-bg); border: 1px solid var(--danger-line);
  color: var(--danger); font: 500 14px/1.5 var(--sans);
}
.notice { display: block; margin: 0 0 18px; padding: 12px 14px; background: var(--pill-bg); color: var(--accent); font: 500 14px/1.5 var(--sans); }

/* Page system for the screens the comps did not draw, from the Kip blog
   (S1/S2) and admin (02) frames: a page head (serif title, one-line lede,
   strong ink rule), small uppercase section labels, a readable centered
   column for text pages, admin-style tables, and plain empty states. */
.page { max-width: 760px; margin-inline: auto; }
.page-head { display: flex; flex-direction: column; gap: 8px; padding-block-end: 24px; margin-block-end: 8px; border-block-end: 1px solid var(--ink); }
.page-head > * { margin: 0; }
.page-head h1 { font-size: 38px; line-height: 1.05; }
.page-head .eyebrow { margin: 0; }
.lede { font: 16px/1.5 var(--sans); color: var(--ink-2); max-width: 60ch; }
.page-head .page-actions { display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: center; font: 14px var(--sans); }
.section-label {
  margin: 32px 0 4px; font: 12px/1.5 var(--sans); letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.page-head + .section-label, .page-head + section > .section-label:first-child { margin-block-start: 24px; }
.page h2:not(.section-label) { margin-block: 32px 12px; }
.section-more { margin: 16px 0 0; font: 14px var(--sans); }
.section-more a::after { content: "\00a0\2192"; }
.section-label + .story-list > li:first-child { border-block-start: 0; }
.empty-state { margin: 20px 0; padding: 24px 0; color: var(--muted); font: 15px/1.6 var(--sans); }
.site-main table {
  width: 100%; border-collapse: collapse; margin-block: 16px 24px;
  background: var(--surface); border: 1px solid var(--line-strong);
  font: 14px/1.45 var(--sans); font-variant-numeric: tabular-nums;
}
.site-main th {
  text-align: start; padding: 12px 16px; border-block-end: 1px solid var(--line-strong);
  background: var(--bg); font: 500 12px/1.4 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}
.site-main td { padding: 12px 16px; border-block-start: 1px solid var(--line); vertical-align: middle; }
.site-main td form.inline { margin: 0; }
.site-main td button, .site-main td input, .site-main td select { min-height: 36px; font-size: 14px; }
.site-main td button { padding: 4px 12px; }
/* Plain (unclassed) lists only: every component list owns its own box. */
.site-main :where(ol, ul):not([class]) { padding-inline-start: 1.4em; }
.site-main :where(ol, ul):not([class]) > li { margin-block: 4px; }
/* Auth (S5): one centered card holding the heading, a one-line lede, the
   form and its full-width primary button. */
.auth-card {
  max-width: 420px; margin: 24px auto; padding: 32px 28px;
  background: var(--surface); border: 1px solid var(--line-strong);
}
.auth-card h1 { font-size: 32px; margin: 0 0 6px; }
.auth-card .lede { font-size: 14px; color: var(--muted); margin: 0 0 20px; }
.auth-card form :where(input:not([type="checkbox"]):not([type="hidden"]), select) { max-width: none; }
.auth-card form:not(.inline) > button:last-of-type { width: 100%; }
.auth-card .auth-links { margin: 18px 0 0; font: 14px var(--sans); color: var(--muted); display: flex; flex-wrap: wrap; gap: 6px 18px; }
/* Safety net for screens still written as a bare h1 plus content: the
   leading h1 reads as a page head and the screen keeps the readable column,
   so no view falls back to an unstyled document. (Recently updated is a
   drawn screen, M6: its h1 sits on the chip row with no rule.) */
.site-main > h1:first-child:not(:has(+ .filter-chips)), .site-main > :is(section, article):first-child > h1:first-child {
  font-size: 38px; line-height: 1.05;
  padding-block-end: 24px; margin-block-end: 24px; border-block-end: 1px solid var(--ink);
}
.site-main:has(> h1:first-child) > h2, .site-main > section > h2, .site-main > article > h2 { margin-block: 32px 12px; }
@media (min-width:768px) { :is(.site-main > h1:first-child:not(:has(+ .filter-chips)), .site-main > :is(section, article):first-child > h1:first-child) { font-size: 48px; } }
@media (min-width:1024px) {
  :is(.site-main > h1:first-child:not(:has(+ .filter-chips)), .site-main > :is(section, article):first-child > h1:first-child) { font-size: 56px; }
  /* text screens keep a readable column; table screens (admin, stats) keep the shell width */
  .site-main:is(:has(> h1:first-child), :has(> section:first-child > h1), :has(> article:first-child > h1)):not(:has(table)) { max-width: 920px; }
}

/* Row lists (browse categories): serif name left, count right, hairlines
   between, the chapter-list row vocabulary without numerals. */
.row-list { list-style: none; margin: 0; padding: 0; }
.site-main .row-list { padding: 0; }
.row-list li { margin: 0; border-block-start: 1px solid var(--line); }
.row-list li:last-child { border-block-end: 1px solid var(--line); }
.row-list a { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; min-height: 56px; padding: 14px 4px; color: var(--ink); text-decoration: none; }
.row-list a:hover { background: var(--hover); }
.row-title { font: 20px/1.3 var(--serif); }
.row-meta { font: 13px var(--sans); color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.section-label + .row-list > li:first-child { border-block-start: 0; }
.empty-state a { white-space: nowrap; }
/* Follow rows carry their own controls, so the row itself is not a link. */
.follow-rows li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 16px; padding: 14px 4px; }
.follow-rows .row-meta { flex: 1; }
.row-actions { display: inline-flex; gap: 16px; }
/* Feed addresses: monospace, selectable, never wrapping mid-address on wide screens. */
.feed-rows code.row-meta { font: 13px var(--mono); color: var(--ink-2); white-space: normal; overflow-wrap: anywhere; text-align: end; }
.feed-note { margin-block-start: 20px; }
/* A-Z letter row (authors): square 36px cells, the current one filled. */
.letter-nav { display: flex; flex-wrap: wrap; gap: 4px; margin-block: 20px 4px; }
.letter-nav a {
  display: inline-flex; align-items: center; justify-content: center; min-width: 36px; min-height: 36px; padding-inline: 8px;
  border: 1px solid var(--line-strong); color: var(--ink); text-decoration: none; font: 500 13px var(--sans);
}
.letter-nav a:hover { background: var(--hover); }
.letter-nav a[aria-current] { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.site-main td.num, .site-main th.num { text-align: end; }
.site-main td.mono { font: 13px var(--mono); color: var(--ink-2); white-space: nowrap; }
.cell-strong { font-weight: 600; color: var(--ink); }
.link-btn.quiet { color: var(--muted); font-size: 13px; margin-inline-start: 8px; }
/* Series reading order: numeral column + serif title, meta, owner tools. */
.site-main .series-items { list-style: none; padding: 0; margin: 16px 0; }
.series-items > li { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 10px; margin: 0; padding: 16px 0; border-block-start: 1px solid var(--line); }
.series-items .ch-num { padding-block-start: 4px; }
.series-item { display: block; }
.series-item .story-title { display: block; margin-block-end: 4px; font: 20px/1.25 var(--serif); color: var(--ink); text-decoration: none; }
.series-item .meta { display: block; margin-block-end: 6px; }
.series-item form.inline { margin-inline-end: 4px; }
.series-item .story-title:hover { color: var(--accent); }
.series-item form.inline button { min-height: 32px; padding: 2px 10px; font-size: 13px; }
.page-head .byline { font-size: 15px; }
.page-head .summary { font-size: 18px; margin: 4px 0 0; }

/* Notifications: hairline rows, the unread ones marked by a small accent
   square and full-strength text, the date right-aligned and quiet. */
.site-main .notif-list { list-style: none; padding: 0; margin: 8px 0 0; }
.notif-list li { display: flex; align-items: baseline; gap: 16px; margin: 0; padding: 14px 4px 14px 20px; border-block-end: 1px solid var(--line); color: var(--ink-2); position: relative; }
.notif-list li > span { flex: 1; }
.notif-list li.unread { color: var(--ink); }
.notif-list li.unread::before { content: ""; position: absolute; inset-inline-start: 4px; top: 22px; width: 6px; height: 6px; background: var(--accent); }
.notif-time { font: 13px var(--sans); color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Search: one large query row, then a quiet Refine disclosure. */
.search-form { margin-block: 24px 8px; }
.search-row { display: flex; gap: 8px; align-items: stretch; }
.search-form .search-q { flex: 1; margin: 0; }
.search-form .search-q input { width: 100%; max-width: none; min-height: 52px; font-size: 18px; }
.search-row .btn-primary { min-height: 52px; }
.search-refine { margin-block-start: 14px; }
.search-refine summary { cursor: pointer; font: 500 14px var(--sans); color: var(--ink-2); min-height: 32px; display: inline-flex; align-items: center; }
.search-refine summary:hover { color: var(--ink); }
.search-refine summary { list-style: none; }
.search-refine summary::-webkit-details-marker { display: none; }
.search-refine summary::before { content: "+"; display: inline-block; width: 1.1em; font-weight: 400; }
.search-refine[open] summary::before { content: "\2212"; }
.refine-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0 20px; margin-block-start: 14px; align-items: end; }
.profile-card { border: 1px solid var(--line); background: var(--surface); padding: 1.5rem; margin-block-end: 2rem; }
@media (max-width:767px) {
  .site-main table { display: block; overflow-x: auto; }
  .auth-card { margin: 0; padding: 24px 20px; border-inline: 0; }
}
@media (min-width:768px) {
  .page-head h1 { font-size: 48px; }
}
@media (min-width:1024px) {
  .page-head h1 { font-size: 56px; }
}

/* Story page (C7, frames M1/T2/D3), values from the comp source. One
   markup, three arrangements: mobile stacks info, actions, chapters (the
   cover hides); tablet pairs the cover with the info column and puts the
   actions under it (T2); desktop is two columns, cover + Continue + action
   cells on the left, info + chapters + reviews on the right (D3). The
   .story-side/.story-main wrappers dissolve (display:contents) below 1024px
   so their children can join one grid. */
.story-hero { display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; }
.story-side, .story-main { display: contents; }
.story-info { order: 1; } .story-actions { order: 2; } .chapters { order: 3; } .story-reviews { order: 4; }
.story-info { display: flex; flex-direction: column; gap: 12px; }
.story-info > * { margin: 0; }
.story-cover { max-width: 300px; }
.story-cover .cover {
  display: block; width: 100%; height: auto;
  aspect-ratio: 2 / 3; object-fit: cover;
  border: 1px solid var(--line-strong);
}
.page-head .cover { max-width: 300px; height: auto; border-radius: 4px; }
.cover-card {
  display: flex; flex-direction: column; justify-content: space-between;
  aspect-ratio: 2 / 3; padding: 22px 20px;
  /* fixed brand green (A.1): the cover card does not re-theme */
  background: #1f4f42; color: var(--cover-ink);
}
.cover-kicker { font: 11px/1.4 var(--sans); letter-spacing: .16em; text-transform: uppercase; opacity: .8; }
.cover-title { font-family: var(--serif); font-size: 28px; line-height: 1.1; }
.cover-author { font-family: var(--serif); font-style: italic; font-size: 15px; opacity: .85; }
.story-actions { display: flex; flex-direction: column; gap: 14px; }
/* Continue reading: the solid brand-green block in M1/T2/D3 (the light
   pill is M6's .continue-pill, a different component). */
.continue-cta {
  display: flex; flex-direction: column; gap: 3px; justify-content: center;
  min-height: 60px; padding: 10px 18px;
  background: #1f4f42; color: #fff; text-decoration: none;
}
.continue-cta:hover { opacity: .92; color: #fff; }
.continue-label { font: 600 16px/1.3 var(--sans); }
.continue-sub { font: 13px/1.4 var(--sans); opacity: .85; font-variant-numeric: tabular-nums; }
.eyebrow {
  font: 12px/1.5 var(--sans); letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
/* D3 appends "Updated {date}" to the eyebrow on desktop only; the span
   rides every render so the bytes stay one shape, CSS picks the widths. */
.story-info .eyebrow-updated { display: none; }
.story-info h1 { font-size: 36px; line-height: 1.08; letter-spacing: -.015em; }
.byline { color: var(--ink-2); font-size: 15px; }
.byline a { color: var(--ink); font-weight: 600; }
.byline a:hover { color: var(--accent); }
/* The byline Follow toggle reads as text, not as a control. */
.story-info .byline .follow-btn {
  min-height: 0; padding: 0; background: none; border: 0; cursor: pointer;
  font: 15px/1.5 var(--sans); color: var(--ink-2);
}
.story-info .byline .follow-btn:hover { background: none; color: var(--accent); text-decoration: underline; }
.story-info .byline .follow-state { color: var(--muted); }
.story-info .meta-line { font-size: 13px; }
.story-stats { display: none; }
.summary {
  font-family: var(--serif); font-size: 17px; line-height: 1.6;
  max-width: 640px; text-wrap: pretty;
}
/* Tag chips (D3/T2): outlined, square, the warnings line closes the row. */
.story-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tag-chips { display: contents; }
.tag-chip, .story-tags .story-warnings {
  display: inline-flex; align-items: center; margin: 0;
  padding: 5px 10px; border: 1px solid var(--line-strong);
  font: 13px/1.4 var(--sans); color: var(--ink-2);
}
.story-notes { border-inline-start: 2px solid var(--line-strong); padding-inline-start: 14px; color: var(--ink-2); font-size: 15px; }
.story-notes p { margin: 0 0 .5em; }
.story-notes .notes-label { font: 12px/1.5 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin: 0 0 4px; }
/* Engagement: the three action cells share one 1px box (M1/D3). */
.engagement-bar { display: flex; flex-direction: column; gap: 10px; }
.action-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--line-strong); }
.action-cell { display: flex; flex-direction: column; justify-content: center; min-height: 46px; }
.action-cell + .action-cell { border-inline-start: 1px solid var(--line-strong); }
.action-cell form { display: flex; align-items: stretch; flex: 1; }
.action-cell .action-btn, .action-cell .action-link {
  flex: 1; display: flex; align-items: center; justify-content: center;
  min-height: 46px; padding: 4px 8px;
  background: none; border: 0; cursor: pointer;
  font: 500 14px/1.2 var(--sans); font-variant-numeric: tabular-nums;
  color: var(--ink); text-decoration: none; text-align: center;
}
.action-cell .action-btn:hover, .action-cell .action-link:hover { background: var(--hover); color: var(--ink); }
.action-cell .is-on { color: var(--accent); font-weight: 600; }
/* The already-kudos'd member reads a label + state pair instead of the form. */
.action-label { display: block; padding: 6px 8px 0; text-align: center; font: 500 14px/1.3 var(--sans); font-variant-numeric: tabular-nums; }
.action-state { display: block; padding: 0 8px 6px; text-align: center; font: 12px/1.4 var(--sans); color: var(--muted); }
.action-aux { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; font: 13px/1.6 var(--sans); }
.action-aux a, .action-aux summary { color: var(--muted); }
.action-aux a:hover, .action-aux summary:hover { color: var(--ink); }
.action-aux button { min-height: 36px; padding: 4px 12px; font-size: 13px; }
.report-disclosure summary { cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.report-disclosure[open] { flex-basis: 100%; }
.report-disclosure form { margin-block-start: 8px; flex-wrap: wrap; }
.report-disclosure input { min-height: 36px; padding: 4px 10px; font-size: 13px; flex: 1; min-width: 180px; }
/* Chapters (M1 rows; T2/D3 widen the numeral column and the title). */
.chapters { display: flex; flex-direction: column; gap: 8px; }
.section-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 24px; }
.section-head h2 { margin: 0; font-size: 24px; }
.section-links { display: flex; flex-wrap: wrap; gap: 6px 20px; font: 13px/1.6 var(--sans); }
.chapter-list { list-style: none; margin: 0; padding: 0; }
.chapter-list li { border-block-start: 1px solid var(--line); }
.chapter-list a {
  display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; align-items: center;
  gap: 8px; min-height: 54px; padding-block: 8px;
  text-decoration: none; color: var(--ink);
}
.chapter-list a:hover { background: var(--hover); }
.ch-num { font-family: var(--serif); font-size: 14px; font-variant-numeric: tabular-nums; color: var(--muted); padding-inline-start: 4px; }
.chapter-list .ch-title { font-family: var(--serif); font-size: 16.5px; min-width: 0; }
.chapter-list li.is-read .ch-title { color: var(--ink-2); }
.chapter-list li.is-current a, .chapter-list li.is-current .ch-num { color: var(--accent); }
.chapter-list li.is-current .ch-title { font-weight: 600; }
.ch-here { display: block; color: var(--accent); font: 12px/1.5 var(--sans); }
.ch-meta { font: 12px/1.6 var(--sans); color: var(--muted); font-variant-numeric: tabular-nums; padding-inline-end: 4px; }
/* Reviews: a quiet section under the chapters; the form is the Kip blog's
   white comment card (S3). */
.story-reviews { display: flex; flex-direction: column; gap: 12px; margin-block-start: 24px; }
.story-reviews > h2 { margin: 0; font-size: 24px; }
.story-reviews .review { max-width: none; padding-block: 16px; }
.story-reviews .review form.inline { margin-block-start: 8px; flex-wrap: wrap; }
/* Reply and Report under a review: a quiet row of disclosures; an open one
   takes the full row so its field has room. */
.review-tools { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-block-start: 8px; font: 13px/1.6 var(--sans); color: var(--ink-2); }
.review-tools details[open] { flex-basis: 100%; }
.review-tools summary { display: inline-flex; align-items: center; min-height: 32px; }
.story-reviews .review form.inline input { flex: 1; min-width: 180px; min-height: 36px; font-size: 14px; }
.story-reviews .review form.inline button { min-height: 36px; font-size: 13px; }
@media (min-width:768px) {
  /* T2: cover beside the info column, the actions under the info. */
  .story-hero {
    grid-template-columns: 220px minmax(0, 1fr); column-gap: 40px; row-gap: 20px;
    grid-template-areas: "cover info" "cover actions" "chapters chapters" "reviews reviews";
    align-items: start;
  }
  .story-cover { grid-area: cover; }
  .story-info { grid-area: info; gap: 14px; }
  .story-actions { grid-area: actions; flex-direction: row; flex-wrap: wrap; align-items: stretch; gap: 10px; }
  .chapters { grid-area: chapters; margin-block-start: 12px; }
  .story-reviews { grid-area: reviews; }
  .story-info h1 { font-size: 46px; line-height: 1.05; }
  .summary { font-size: 18px; }
  .byline { font-size: 16px; }
  /* T2 merges byline and meta into one line: "by Name · Teen · 600 words ...". */
  .story-info .byline { display: inline; }
  .story-info .meta-line { display: inline; font-size: 16px; color: var(--ink-2); }
  .story-info .byline:has(+ .meta-line) { display: inline; }
  .continue-cta { min-height: 58px; padding: 0 22px; }
  .story-actions .engagement-bar { flex: 1 1 320px; }
  .action-row { min-height: 58px; }
  .section-head h2, .story-reviews > h2 { font-size: 28px; }
  .section-links { font-size: 14px; }
  .chapter-list a { grid-template-columns: 44px minmax(0, 1fr) auto; gap: 10px; min-height: 56px; padding-block: 0; }
  .ch-num { font-size: 15px; padding-inline-start: 0; }
  .chapter-list .ch-title { font-size: 18px; }
  .ch-here { display: inline; margin-inline-start: 10px; font-size: 12.5px; font-weight: 500; }
  .ch-meta { font-size: 13px; }
  .chapter-list li:not(.is-read) .ch-meta::after { content: var(--words-unit, ""); }
}
@media (min-width:1024px) {
  /* D3: two real columns again; the wrappers come back as boxes. */
  .story-page { padding-block-start: 8px; }
  .story-hero { display: grid; grid-template-columns: 300px minmax(0, 1fr); grid-template-areas: none; gap: 64px; }
  .story-side { display: flex; flex-direction: column; gap: 14px; }
  .story-main { display: flex; flex-direction: column; gap: 28px; min-width: 0; }
  .story-cover, .story-info, .story-actions, .chapters, .story-reviews { grid-area: auto; }
  .story-actions { flex-direction: column; gap: 14px; }
  .story-actions .engagement-bar { flex: none; }
  .continue-cta { min-height: 58px; padding: 0 20px; gap: 2px; }
  .action-row { min-height: 0; }
  .action-cell, .action-cell .action-btn, .action-cell .action-link { min-height: 44px; }
  .cover-card { padding: 26px 24px; }
  .cover-title { font-size: 34px; line-height: 1.08; }
  .cover-author { font-size: 16px; }
  .story-info { gap: 14px; }
  .story-info h1 { font-size: 58px; line-height: 1.02; letter-spacing: -.02em; }
  .story-info > .meta-line { display: none; }
  .story-info .byline { display: block; }
  .story-info .eyebrow-updated { display: inline; }
  .story-stats {
    display: grid; grid-template-columns: repeat(6, auto);
    justify-content: start; gap: 4px 40px;
    border-block-start: 1px solid var(--ink); border-block-end: 1px solid var(--line);
    padding-block: 18px; margin-block: 14px;
  }
  /* Each pair rides inside a wrapper div (view.php), so a dt and its dd
     never land on different grid rows when the member-only time_left
     changes the item count (review; the comp wraps pairs too). */
  .story-stats > div { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
  .story-stats dt { font: 12px/1.5 var(--sans); text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
  .story-stats dd { margin: 0; font-family: var(--serif); font-size: 20px; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .summary { font-size: 19px; }
  .story-tags { margin-block-start: 0; }
  .chapters { margin-block-start: 0; gap: 6px; }
  .chapter-list a { grid-template-columns: 48px minmax(0, 1fr) 120px; min-height: 52px; }
  .ch-num { padding-inline-start: 4px; }
  .ch-meta { text-align: end; }
  .ch-here { margin-inline-start: 12px; }
}

/* Chapter reader (C8, frames M2/T1/D1 + focus D2): sticky header with the
   story-span progressbar, end-of-chapter block, bottom control bar, sheet
   tabs, and the text-settings segmented controls. The reading column itself
   is the .prose block above; the data-attr overrides below rebind its
   tokens only when a cookie set a non-default value (Prefs::dataAttrs). */
.reader { padding-block-end: 88px; }
.reader-head {
  position: sticky; top: 0; z-index: 20;
  display: grid; grid-template-columns: 44px 1fr 44px; grid-template-rows: auto 2px;
  align-items: center; column-gap: 12px;
  min-height: 52px; padding-inline: 8px;
  background: var(--bg); border-block-end: 1px solid var(--line);
}
.reader-back {
  grid-column: 1; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; text-decoration: none;
  color: var(--ink); font-size: 22px; line-height: 1;
}
.reader-titles { grid-column: 2; min-width: 0; display: flex; flex-direction: column; gap: 1px; text-align: center; }
.rt-story, .rt-chapter {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rt-story { font: 400 15px/1.3 var(--serif); color: var(--ink); }
.rt-chapter { font: 12px/1.4 var(--sans); color: var(--muted); }
.reader-pct {
  grid-column: 3; text-align: center;
  font: 12px var(--sans); font-variant-numeric: tabular-nums; color: var(--muted);
}
/* Progressbar: the track spans the header's second row; the fill paints the
   chapter's span of the whole story. The static fallback is the --p-end
   gradient; where scroll() timelines exist the fill animates from the
   chapter's start to its end as the page scrolls (A.3). */
.reader-progress {
  grid-column: 1 / -1; grid-row: 2;
  height: 2px; background: var(--track);
  margin-inline: -8px; /* edge to edge: cancels the head's inline padding */
}
.reader-progress::after {
  content: ""; display: block; height: 100%;
  background: linear-gradient(var(--accent), var(--accent)) left center / var(--p-end, 0%) 100% no-repeat;
}
/* CSS has no logical background-position, so the sized fill anchors
   physically; the dir=rtl override re-anchors it at the inline-start edge
   (right) so a mirrored document fills its progressbar from its reading
   edge. Pinned in PerUserTest with the other directional rules. */
html[dir="rtl"] .reader-progress::after {
  background: linear-gradient(var(--accent), var(--accent)) right center / var(--p-end, 0%) 100% no-repeat;
}
@supports (animation-timeline: scroll()) {
  .reader-progress::after {
    animation: reader-progress-fill linear both;
    animation-timeline: scroll(root);
  }
  /* Once the position module paints the already-interpolated --p-end, the
     scroll timeline would interpolate it a second time and lag the fill
     behind the readout: the module's bar drops the animation. */
  .reader-progress.is-live::after { animation: none; }
}
@keyframes reader-progress-fill {
  from { background-size: var(--p-start, 0%) 100%; }
  to { background-size: var(--p-end, 0%) 100%; }
}
.reader-main { padding-block: 2rem 0.5rem; }

/* Chapter opening anatomy (M2/M3): a letterspaced uppercase kicker over the
   serif title, a short centered hairline rule under it, and a small-caps
   first line on the opening paragraph. The end-of-chapter next-chapter
   block repeats the kicker+title+rule anatomy. */
.reader-main .ch-kicker {
  margin: 0 0 12px; text-align: center;
  font: 12px/1.5 var(--sans);
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.reader-main .p-name { text-align: center; font-size: 30px; line-height: 1.12; letter-spacing: -.01em; margin: 0 0 32px; }
.reader-main .p-name::after {
  content: ""; display: block; width: 40px; height: 1px;
  margin: 18px auto 0; background: var(--ink);
}
.prose.e-content > p:first-of-type::first-line, section.prose > p:first-of-type::first-line { font-variant: small-caps; letter-spacing: .02em; }

/* Utility: keeps markup in the document for parsers and screen readers
   while the comp drops it visually (the read page's mf2 byline row). */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* Typography preference overrides (html attrs from Prefs::dataAttrs). */
html[data-size="16"] { --read-size: 16px; }
html[data-size="17"] { --read-size: 17px; }
html[data-size="18"] { --read-size: 18px; }
html[data-size="20"] { --read-size: 20px; }
html[data-size="21"] { --read-size: 21px; }
html[data-size="22"] { --read-size: 22px; }
html[data-size="23"] { --read-size: 23px; }
html[data-size="24"] { --read-size: 24px; }
html[data-spacing="snug"] { --read-lh: 1.6; }
html[data-spacing="airy"] { --read-lh: 1.85; }
html[data-typeface="sans"] .prose { font-family: var(--sans); }
html[data-width="narrow"] { --read-width: 560px; }
html[data-width="wide"] { --read-width: 720px; }
/* Paged mode (scoped to the reader's own prose: .prose is shared by
   reviews, news, and messages, which must never reflow into a deck).
   The columns themselves scroll freely inside .reader-main; the snap
   rule from the first cut is gone because multicol columns are not
   snap targets, so mandatory snapping never engaged (review). */
html[data-mode="pages"] .reader-main { overflow-x: auto; }
html[data-mode="pages"] .reader-main .prose {
  max-width: none; column-width: var(--read-width); column-gap: 48px;
  height: 70vh;
}

/* End-of-chapter block (M3/D2): dot ornament, kudos + review actions, and
   the next-chapter link. */
/* The chapter end is a labelled group, not a separator: a separator's
   children are presentational, which hid the kudos, review and next-chapter
   controls inside it from screen readers (qa-full /a11y, WCAG 4.1.2). */
.chapter-end {
  max-width: var(--read-width); margin: 3rem auto 0; padding-block: 24px;
  border-block: 1px solid var(--line-strong); text-align: center;
}
.chapter-end .dots { display: block; margin-block-end: 12px; }
.dots::before {
  content: ""; display: inline-block; width: 4px; height: 4px;
  background: var(--muted); box-shadow: 12px 0 0 var(--muted), -12px 0 0 var(--muted);
}
.chapter-end p {
  margin: 0 0 16px; font: 14px/1.5 var(--sans); color: var(--muted);
}
.chapter-end-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.chapter-end-actions a {
  display: inline-flex; align-items: center; min-height: 44px; padding-inline: 16px;
  border: 1px solid var(--line-strong); text-decoration: none;
  font: 500 15px var(--sans); color: var(--ink);
}
.chapter-end-actions a:hover { background: var(--hover); }
/* The comp's next-chapter block (M3): the kicker + serif title + rule link
   that replaces the old filled button; centered by .chapter-end. */
.next-chapter { margin-block-start: 24px; }
.next-chapter a { display: block; text-decoration: none; color: var(--ink); text-align: center; }
.next-chapter .ch-kicker {
  display: block;
  margin: 0 0 .5rem;
  font: 12px/1.5 var(--sans);
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.next-chapter .next-title { display: block; font-family: var(--serif); font-size: 24px; line-height: 1.2; }
.next-chapter .next-title::after {
  content: ""; display: block; width: 40px; height: 1px;
  margin: 16px auto 0; background: var(--line-strong);
}
.next-chapter a:hover .next-title { color: var(--accent-hover); }

/* Reader fragment units (infinite module): every chapter on the page is
   one .chapter-unit block. The divider between units reuses the existing
   hairline - the previous unit's chapter-end rule closes it - so appended
   units only bring the read page's breathing room. The sentinel is the
   module's observe target and must keep a box (a display:none element
   never intersects): one silent pixel, nothing painted. */
.chapter-unit + .chapter-unit { margin-block-start: 3rem; }
.reader-sentinel { display: block; height: 1px; }

/* Whole-work boundaries (C9, frame M3): each chapter closes with the same
   .chapter-end separator the reader uses, and every chapter after the first
   opens with the comp's next-chapter block: kicker, serif heading, 40x1
   rule. Sections breathe between separators; the first needs no gap. */
/* Whole-work head: the story page's eyebrow / serif title / meta line. */
.whole-head { display: flex; flex-direction: column; gap: 10px; max-width: var(--read-width); margin-inline: auto; }
.whole-head > * { margin: 0; }
.whole-head h1 a { color: var(--ink); text-decoration: none; }
.whole-head h1 a:hover { color: var(--accent); }
.whole-head .meta { font-size: 13px; }
.whole-toc { max-width: var(--read-width); margin: 32px auto 48px; }
.whole-toc h2 { font-size: 24px; margin: 0 0 8px; }
.whole-work section.prose { margin-block: 3rem 0; }
.whole-work section.prose:first-of-type { margin-block-start: 0; }
.whole-work .ch-kicker {
  margin: 0 0 .5rem;
  font: 600 12px/1.5 var(--sans);
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.whole-work .p-name { font-size: 30px; line-height: 1.2; margin-block-end: 1rem; }
.whole-work .p-name::after {
  content: ""; display: block; width: 40px; height: 1px;
  margin-block-start: 16px; background: var(--line-strong);
}

/* Recently updated (C10, frame M6): filter chips and M6 story cards. The
   chip row scrolls horizontally and bleeds to the viewport edge on mobile;
   the active chip is the ink/bg inversion (the comp's filled state), every
   chip keeps the 38px comp height inside the 44px tap-target floor via
   padding. Cards: serif title, strong byline, meta line, two-line clamp. */
.filter-chips {
  display: flex; gap: 8px; margin: 0 0 18px;
  overflow-x: auto; padding-block: 3px;
}
.chip {
  flex: none; display: inline-flex; align-items: center;
  min-height: 38px; padding-inline: 14px;
  white-space: nowrap; text-decoration: none;
  border: 1px solid var(--line-strong);
  font: 500 13.5px/1 var(--sans); color: var(--ink);
}
.chip:hover { background: var(--hover); color: var(--ink); }
.chip.is-active { background: var(--ink); border-color: var(--ink); color: var(--bg); }
/* M6 cards: ink serif title, byline with a strong name, a plain meta line
   (the status badge reads as text here), ink-2 summary clamped to two. */
.story-list li.story-card { display: flex; flex-direction: column; gap: 8px; padding: 20px 0; }
.story-list li.story-card:last-child { border-block-end: 0; }
.story-card > * { margin: 0; }
.story-card .story-title {
  display: block; font-family: var(--serif); color: var(--ink);
  font-size: 22px; line-height: 1.2; text-decoration: none; text-wrap: balance;
}
.story-card .story-title:hover { color: var(--accent); }
.story-card .byline { font-size: 14px; }
.story-card .byline strong { font-weight: 600; color: var(--ink); }
.story-card .meta .badge { border: 0; padding: 0; font: inherit; letter-spacing: 0; color: inherit; }
.story-card .card-updated { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.story-card .summary {
  font-family: var(--serif); color: var(--ink-2);
  font-size: 16px; line-height: 1.55;
}
.clamp-2 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.continue-pill {
  align-self: flex-start; display: inline-flex; align-items: center;
  min-height: 40px; margin-block-start: 2px; padding-inline: 12px;
  background: var(--pill-bg); color: var(--accent); text-decoration: none;
  font: 600 13.5px/1 var(--sans); font-variant-numeric: tabular-nums;
}
.continue-pill:hover { opacity: .92; color: var(--accent); }

/* Pager (Kip blog S2, admin 02): outline buttons, Older pinned to the end. */
.pager { display: flex; justify-content: space-between; gap: 12px; margin-block-start: 20px; }
.pager a {
  display: inline-flex; align-items: center; min-height: 44px; padding-inline: 18px;
  border: 1px solid var(--line-strong); color: var(--ink); text-decoration: none;
  font: 500 15px var(--sans);
}
.pager a:hover { background: var(--hover); color: var(--ink); }
.pager a[rel="prev"]::before { content: "\2190\00a0"; }
.pager a[rel="next"]::after { content: "\00a0\2192"; }
.pager .pager-next { margin-inline-start: auto; }
html[dir="rtl"] .pager a[rel="prev"]::before { content: "\2192\00a0"; }
html[dir="rtl"] .pager a[rel="next"]::after { content: "\00a0\2190"; }

/* Bottom control bar: fixed with safe-area padding on mobile, a floating
   centered pill from 768px, in normal flow under the column from 1024px. */
.reader-bar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 30;
  display: flex; align-items: stretch; justify-content: space-around;
  background: var(--bg); border-block-start: 1px solid var(--line-strong);
  padding-block-end: max(18px, env(safe-area-inset-bottom, 0px));
}
/* Icon-over-caption items (M2): a 20px glyph slot above a 12px muted
   caption; the count ("n / m") and the Aa glyph fill the icon slot as
   tabular text. Prev/next live in the chapter-nav block, not here. */
.reader-bar a, .reader-bar button, .bar-chapter {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-height: 52px; min-width: 56px; padding-inline: 12px;
  background: none; border: 0; cursor: pointer; text-decoration: none;
  color: var(--ink);
}
.reader-bar a:hover, .reader-bar button:hover { color: var(--accent-hover); background: none; }
.bar-top { display: flex; align-items: center; justify-content: center; height: 20px; }
.bar-icon { display: block; width: 20px; height: 20px; }
.bar-count { font: 600 15px/1 var(--sans); font-variant-numeric: tabular-nums; }
.bar-glyph { font: 400 17px/1 var(--serif); }
.bar-caption { font: 12px/1 var(--sans); color: var(--muted); }
.bar-bookmark button.is-saved { color: var(--accent); }
.bar-bookmark button.is-saved .bar-icon { fill: currentColor; }

/* Focus variant (D2): the layout hides .site-head under body.focus; the
   reader adds a right-edge vertical dock of three 48px controls. */
body.focus .site-head { display: none; }
/* M2/T1: below the desktop breakpoint the reading surfaces drop the site
   header too - the reader header, back arrow, contents sheet, and bottom
   bar carry navigation. :has() rides the same progressive allowance as the
   scrim: engines without it keep the site header, which stays usable. */
@media (max-width:1023px) {
  body:has(.reader) .site-head { display: none; }
}
/* The regular reader head keeps brand/byline/controls desktop-only; the
   focus breadcrumb (D2) shows brand + separators at every width and never
   shows the byline or controls. */
.rt-brand, .rt-by, .rt-ctls { display: none; }
.reader-breadcrumb { display: flex; align-items: center; column-gap: 12px; }
.rt-left { display: inline-flex; align-items: baseline; gap: 12px; min-width: 0; }
.reader-breadcrumb .rt-sep { color: var(--muted); }
.reader-breadcrumb { min-height: 44px; }
.reader-breadcrumb .rt-brand { display: inline; font: 13px var(--serif); font-variant: small-caps; letter-spacing: .08em; color: var(--ink-2); text-decoration: none; }
.reader-breadcrumb .rt-story, .reader-breadcrumb .rt-chapter { font: 13px var(--sans); color: var(--muted); }
.reader-breadcrumb .reader-progress { height: 1px; }
.reader-breadcrumb .reader-pct { display: inline; margin-inline-start: auto; font-weight: 400; font-size: 13px; white-space: nowrap; }
.reader-breadcrumb .reader-progress { position: absolute; inset-inline: 0; bottom: 0; }
.focus-hint {
  position: fixed; inset-inline-start: 24px; bottom: 24px; z-index: 30;
  font: 13px var(--sans); color: var(--muted);
}
.focus-hint a { color: var(--ink); }
/* Keyboard hint bar (keys module): always in the markup, hidden until the
   enhancement layer runs - the html.js rule reveals it, so noscript bytes
   carry nothing. The reveal is gated on :not([hidden]) as well as .js: an
   author display rule outranks the UA's [hidden] rule, so a bare .js
   reveal would show the bar for the window before keys.js clears the
   attribute, and forever if keys.js fails to load. Fixed bottom-left like
   the focus hint, muted, under the sheets' z-order; focus mode lifts it
   above the focus-hint line. */
.hint-keys { display: none; }
.js .hint-keys:not([hidden]) {
  display: flex; flex-wrap: wrap; gap: 2px 14px; align-items: baseline;
  position: fixed; inset-inline-start: 24px; bottom: 24px; z-index: 25;
  font: 13px/1.6 var(--sans); color: var(--muted);
}
.js .hint-keys:not([hidden]) kbd { color: var(--ink); }
.js body.focus .hint-keys:not([hidden]) { bottom: 56px; }
/* Below the desktop floor the reader bar owns the bottom edge, and the
   hint row collided with it on tablets (design review, run 3). An earlier
   copy of this rule sat above the .js reveal and lost the cascade; the rule
   has to follow the reveal and carry its :not([hidden]) specificity. */
@media (max-width:1023px) { .js .hint-keys:not([hidden]) { display: none; } }
/* Focus mode is the dock plus the exit hint at every width; below the
   desktop floor the reader bar stayed up underneath them (qa-full /a11y). */
.reader.reader-focus .reader-bar { display: none; }
/* The exit hint has no backing, and on narrow screens it printed over the
   chapter text; the dock's close link is the exit there. */
@media (max-width:1023px) { .focus-hint { display: none; } }
.reader-dock {
  position: fixed; inset-inline-end: 28px; bottom: 28px; z-index: 30;
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line-strong);
}
.reader-dock a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; text-decoration: none;
  color: var(--ink); font-size: 18px; line-height: 1;
  border-block-end: 1px solid var(--line);
}
.reader-dock a:hover { background: var(--hover); }
.reader-dock a:last-child { border-block-end: 0; }

/* Reader sheets beyond the C6 shell pattern: radio-tabbed panes in
   #contents, and the segmented settings groups in #text. */
.ctab-radio {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
}
.sheet-tabs { display: flex; gap: 24px; border-block-end: 1px solid var(--line-strong); }
.sheet-tabs label {
  display: inline-flex; align-items: center; min-height: 44px;
  font: 600 15px/1 var(--sans); color: var(--muted); cursor: pointer;
  border-block-end: 2px solid transparent; margin-block-end: -1px;
}
#ctab-contents:checked ~ .sheet-tabs label[for="ctab-contents"],
#ctab-bookmarks:checked ~ .sheet-tabs label[for="ctab-bookmarks"] {
  color: var(--ink); border-block-end-color: var(--accent);
}
/* The radios are visually clipped, so the UA focus ring dies with them;
   paint it on the label instead (the .segmented rule's own pattern). */
#ctab-contents:focus-visible ~ .sheet-tabs label[for="ctab-contents"],
#ctab-bookmarks:focus-visible ~ .sheet-tabs label[for="ctab-bookmarks"] {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.pane-bookmarks { display: none; }
#ctab-bookmarks:checked ~ .pane-bookmarks { display: block; }
#ctab-bookmarks:checked ~ .pane-contents { display: none; }
.sheet-title { font-size: 18px; margin-block: 1rem .25rem; }
/* With the member tabs present, the tab row names each pane already. */
.sheet-tabs ~ .pane .sheet-title { display: none; }
/* M5 bookmark rows: kind label, chapter line, italic note, text actions. */
.bookmark-list { list-style: none; margin: 0; padding: 0; }
.bookmark-list li { border-block-end: 1px solid var(--line); padding-block: 16px; }
.bm-kind { margin: 0 0 4px; font: 500 11.5px/1.5 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.bm-resume .bm-kind { color: var(--accent); font-weight: 600; }
.bm-kind { display: flex; justify-content: space-between; gap: 12px; }
.bm-date { text-transform: none; letter-spacing: 0; font: 12px var(--sans); color: var(--muted); }
.bm-chapter { font: 600 14px/1.6 var(--sans); color: var(--ink); text-decoration: none; }
.bm-chapter:hover { color: var(--accent); }
.bm-pct { font: 14px/1.6 var(--sans); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.bm-actions { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0 20px; margin-block-start: 4px; }
.bm-note-edit summary, .link-btn {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0;
  background: none; border: 0; cursor: pointer; list-style: none;
  font: 13px var(--sans); color: var(--muted);
}
.bm-note-edit summary::-webkit-details-marker { display: none; }
.bm-note-edit summary:hover, .link-btn:hover { background: none; color: var(--ink); }
.bm-note-edit[open] { flex-basis: 100%; }
.bm-note-edit form { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.bm-note-edit label { width: 100%; margin: 0; }
.bm-note-edit textarea { width: 100%; min-height: 64px; font: italic 16px/1.5 var(--serif); }
.bm-note {
  margin: 4px 0; font-family: var(--serif); font-style: italic;
  font-size: 16px; line-height: 1.5; color: var(--ink-2);
}
.text-settings { display: flex; flex-direction: column; gap: 20px; }
.text-settings fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
/* The legend floats so it lays out like a block row: label left, value right. */
.text-settings legend {
  float: inline-start; width: 100%; padding: 0; margin: 0 0 10px;
  display: flex; justify-content: space-between; align-items: baseline;
  font: 12px/1.5 var(--sans); text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
}
.text-settings legend + * { clear: both; }
.text-settings legend .val { color: var(--ink); text-transform: none; letter-spacing: 0; }
/* Text size slider (M4): a native range between the small/large A marks,
   the px readout floated to the legend's far edge. Square 16px thumb on a
   4px hairline track: the system's square-corner vocabulary. */
/* M4/D1: one boxed row, small A | slider | large A. The Small/Large words
   stay in the markup for screen readers; font-size 0 drops them visually. */
.size-row { display: grid; grid-template-columns: 52px minmax(0, 1fr) 52px; align-items: center; border: 1px solid var(--line-strong); }
.size-end {
  display: flex; align-items: center; justify-content: center; height: 48px;
  font-size: 0; color: var(--ink);
}
.size-end:first-child { border-inline-end: 1px solid var(--line-strong); }
.size-end:last-child { border-inline-start: 1px solid var(--line-strong); }
.size-a { font-family: var(--serif); font-size: 15px; line-height: 1; color: var(--ink); }
.size-a-lg { font-size: 24px; }
.size-row input[type="range"] {
  margin-inline: 14px; min-width: 0; min-height: 0; height: 24px; padding: 0;
  appearance: none; -webkit-appearance: none;
  background: none; border: 0;
}
.size-row input[type="range"]::-webkit-slider-runnable-track { height: 2px; background: var(--line); }
.size-row input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 14px; height: 14px; margin-block-start: -6px;
  background: var(--accent); border: 0; border-radius: 0; cursor: pointer;
}
.size-row input[type="range"]::-moz-range-track { height: 2px; background: var(--line); }
.size-row input[type="range"]::-moz-range-progress { height: 2px; background: var(--accent); }
.size-row input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px; background: var(--accent); border: 0; border-radius: 0; cursor: pointer;
}
.size-readout {
  font: 13px var(--sans); color: var(--ink-2);
  font-variant-numeric: tabular-nums; text-transform: none; letter-spacing: 0;
}
.segmented { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); border: 1px solid var(--line-strong); }
.segmented label {
  flex: 1; display: flex; margin: 0; cursor: pointer;
  border-inline-start: 1px solid var(--line-strong);
}
.segmented label:first-child { border-inline-start: 0; }
.segmented input {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
}
.segmented input + span {
  flex: 1; display: flex; align-items: center; justify-content: center;
  min-height: 44px; padding-inline: 6px; font: 500 14px var(--sans); color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.segmented input[value="serif"] + span { font-family: var(--serif); font-size: 16px; }
.segmented input:checked + span { background: var(--ink); color: var(--bg); font-weight: 600; }
.segmented input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Theme swatches (M4): a chip previewing each palette, ringed when chosen. */
/* Theme swatches (M4/D1): four free-standing chips, no group box; the
   chosen one carries the 2px accent ring and a bold caption. */
.segmented.swatches { grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; border: 0; }
.segmented.swatches label { border: 0; }
.swatch { flex-direction: column; align-items: center; gap: 7px; padding: 0; }
.swatch span:last-of-type { text-transform: capitalize; font: 12.5px var(--sans); color: var(--muted); }
.swatch input:checked ~ span:last-of-type { color: var(--ink); font-weight: 600; }
.swatch .swatch-aa {
  min-height: 0; height: 46px; width: 100%; flex: none;
  border: 1px solid var(--line-strong);
  font-family: var(--serif); font-size: 17px;
}
/* .segmented prefix: outranks the generic checked-cell inversion. */
.segmented .swatch-paper .swatch-aa { background: #f8f7f3; color: #1c2320; }
.segmented .swatch-sepia .swatch-aa { background: #f4ecdc; color: #33291b; }
.segmented .swatch-night .swatch-aa { background: #121513; color: #d6dcd7; }
.segmented .swatch-auto .swatch-aa { background: linear-gradient(90deg, #f8f7f3 50%, #121513 50%); color: transparent; }
.swatch input:checked ~ .swatch-aa { border: 2px solid var(--accent); font-weight: 400; }
/* No-JS durability: Save writes the cookie (and the member row). The
   enhancement layer applies every change instantly, so it stays a quiet
   full-width control at the end of the panel. */
.settings-save { width: 100%; }
@media (min-width:768px) {
  .reader-head { min-height: 56px; padding-inline: 16px; }
  .reader-progress { margin-inline: -16px; }
  .reader-bar {
    inset-inline: auto; bottom: 28px; left: 50%; transform: translateX(-50%);
    border: 1px solid var(--line-strong); background: var(--surface);
    border-radius: 12px; /* the comp's one rounded element: the floating pill */
    box-shadow: 0 12px 30px -16px var(--scrim);
    padding-block-end: 0;
  }
  .reader-bar a, .reader-bar button { min-width: 48px; }
  .reader { padding-block-end: 48px; }
}
@media (min-width:1024px) {
  /* D1: the desktop reader is a three-pane workstation. The reader header
     becomes the top bar (brand | titles | byline | the three dark controls);
     the two sheets become permanent side panels; the bottom bar retires (the
     controls live in the top bar). No site header on reading surfaces at any
     width - the reader head IS the chrome (comp M2/T1/D1 all ship none). */
  body:has(.reader) .site-head { display: none; }
  /* Full bleed: the workstation spans the viewport (comp D1 is edge to
     edge); the 1200px shell stays for every other surface. */
  body:has(.reader) .site-main { max-width: none; margin-inline: 0; padding: 0; }
  .reader-head .rt-brand { display: inline-flex; }
  .reader-head .rt-by { display: inline; }
  .reader-head .rt-ctls { display: inline-flex; }
  .reader {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr) 320px;
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "head head head"
      "contents main text";
    min-height: 100vh;
    padding-block-end: 0;
  }
  .reader-head {
    grid-area: head;
    /* brand | divider | titles | byline(1fr) | controls (D1); the back
       arrow and percent are display:none here */
    grid-template-columns: auto 1px auto 1fr auto;
    grid-template-rows: 60px 2px;
    min-height: 0; padding-inline: 28px 24px; column-gap: 20px;
  }
  .reader-head:not(.reader-breadcrumb) .reader-progress { margin-inline: -28px -24px; }
  .rt-divider { display: block; width: 1px; height: 20px; background: var(--line); }
  .reader-head:not(.reader-breadcrumb) .rt-chapter { display: none; }
  .reader-head:not(.reader-breadcrumb) .reader-titles { text-align: start; }
  .reader-head:not(.reader-breadcrumb) > .rt-brand { grid-area: 1 / 1; }
  .reader-head:not(.reader-breadcrumb) > .rt-divider { grid-area: 1 / 2; }
  .reader-head:not(.reader-breadcrumb) > .reader-titles { grid-area: 1 / 3; }
  .reader-head:not(.reader-breadcrumb) > .rt-by { grid-area: 1 / 4; }
  .reader-head:not(.reader-breadcrumb) > .rt-ctls { grid-area: 1 / 5; }
  .reader-head:not(.reader-breadcrumb) .rt-story { font-size: 16px; }
  .reader-back, .reader-pct { display: none; }
  .rt-brand {
    display: inline-flex; align-items: center;
    font: 400 21px var(--serif); font-variant: small-caps; letter-spacing: .08em;
    color: var(--ink); text-decoration: none;
  }
  .rt-by { display: inline; font: 14px/1.4 var(--sans); color: var(--muted); white-space: nowrap; }
  .rt-ctls { display: inline-flex; align-items: center; gap: 4px; justify-self: end; }
  /* D1 controls: Contents and Text read pressed (their panels are open),
     Bookmark is a ghost control with the outline ribbon. */
  .rt-ctl {
    display: inline-flex; align-items: center; gap: 9px; min-height: 40px; padding: 0 12px;
    background: transparent; color: var(--ink);
    font: 500 14px/1 var(--sans); text-decoration: none; border: 0; cursor: pointer;
  }
  .rt-ctl:hover { background: var(--hover); color: var(--ink); }
  .rt-ctl.is-open { background: var(--ink); color: var(--bg); }
  .rt-ctl.is-open:hover { background: var(--ink); color: var(--bg); opacity: .88; }
  .rt-ctl.is-saved { color: var(--accent); }
  .ctl-bars { display: flex; flex-direction: column; gap: 3.5px; }
  .ctl-bars span { display: block; width: 16px; height: 1.6px; background: currentColor; }
  .ctl-bars span:last-child { width: 10px; }
  .ctl-aa { font: 16px/1 var(--serif); }
  .ctl-aa span { font-size: .72em; }
  .ctl-ribbon {
    position: relative; display: block; width: 12px; height: 16px; background: currentColor;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 72%, 0 100%);
  }
  .ctl-ribbon::after {
    content: ""; position: absolute; inset: 1.6px 1.6px 0;
    background: var(--bg); clip-path: polygon(0 0, 100% 0, 100% 84%, 50% 62%, 0 84%);
  }
  .rt-ctl.is-saved .ctl-ribbon::after { display: none; }
  .reader-progress { grid-column: 1 / -1; }
  /* The side panels: the sheets, always on, static, each its own scroll. */
  .reader .sheet {
    display: block; position: static; max-height: none; overflow: visible;
    background: transparent; border: 0; box-shadow: none; padding: 28px 24px;
  }
  #contents.sheet { padding: 28px 16px; }
  #contents {
    grid-area: contents;
    position: sticky; top: 0; align-self: start;
    max-height: 100vh; overflow-y: auto;
    border-inline-end: 1px solid var(--line);
  }
  #text {
    grid-area: text;
    position: sticky; top: 0; align-self: start;
    max-height: 100vh; overflow-y: auto;
    border-inline-start: 1px solid var(--line);
  }
  .reader .sheet-handle, .reader .sheet-done { display: none; }
  /* Targeting a pane that is already on screen must not raise the scrim:
     the pane has no Done link here, so nothing could dismiss it. */
  body:has(.reader:not(.reader-focus) :is(#contents, #text):target) .scrim { display: none; }
  .panel-head {
    display: flex; align-items: baseline; justify-content: space-between;
    margin-block-end: 1rem;
  }
  .reset-link {
    background: none; border: 0; padding: 0; min-height: 0; cursor: pointer;
    font: 13px var(--sans); color: var(--accent); text-decoration: underline;
  }
  #text .sheet-title { font-size: 22px; margin: 0; }
  /* D1 contents: a small uppercase label over borderless rows; the current
     chapter sits on the surface with the 2px accent rule. Member
     annotations (minutes left, bookmark counts) ride under the title. */
  #contents .sheet-title {
    margin: 0 0 14px; padding-inline: 14px;
    font: 12px/1.5 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
  }
  .ch-note { display: block; grid-column: 2; font: 12px/1.6 var(--sans); color: var(--muted); font-variant-numeric: tabular-nums; }
  .ch-note:empty { display: none; }
  .reader .chapter-list { display: flex; flex-direction: column; gap: 2px; }
  .reader .chapter-list li { border: 0; }
  .reader .chapter-list .ch-meta { display: none; }
  .reader .chapter-list a {
    grid-template-columns: 32px minmax(0, 1fr); gap: 2px 6px; align-items: baseline;
    min-height: 0; padding: 9px 12px; border-inline-start: 2px solid transparent;
    color: var(--ink-2);
  }
  .reader .chapter-list a:hover { background: none; color: var(--ink); }
  .reader .chapter-list .ch-num { font-size: 14.5px; padding: 0; color: var(--muted); }
  .reader .chapter-list .ch-title { font-size: 15.5px; }
  .reader .chapter-list li.is-current a { background: var(--surface); border-inline-start-color: var(--accent); color: var(--ink); }
  .reader .chapter-list li.is-current .ch-num { color: var(--accent); }
  /* D1 chapter opening: left-aligned kicker, 44px title, short ink rule. */
  .reader-main { grid-area: main; padding: 64px 48px 3rem; }
  .reader:not(.reader-focus) .reader-main .prose > .ch-kicker { text-align: start; }
  #contents .sheet-tabs { margin: 0 14px 14px; gap: 20px; }
  #contents .sheet-tabs label { font: 12px/1.5 var(--sans); letter-spacing: .12em; text-transform: uppercase; min-height: 32px; }
  .reader-main .p-name { font-size: 44px; margin-block-end: 36px; }
  .reader:not(.reader-focus) .reader-main .p-name { text-align: start; }
  .reader:not(.reader-focus) .reader-main .p-name::after { margin-inline: 0; }
  .reader-bar { display: none; }
  /* D2 focus (desktop): the distraction-free variant. One centered column;
     the panes yield (the dock's Contents/Text still open the sheets as the
     fixed overlays the mobile width uses); the breadcrumb keeps its six
     tracks against the four-track regular head. */
  .reader.reader-focus { display: block; min-height: 100vh; }
  .reader.reader-focus .sheet { display: none; }
  .reader.reader-focus .sheet:target {
    display: flex; flex-direction: column;
    position: fixed; inset-inline: 0; bottom: 0; z-index: 40;
    max-height: 85vh; overflow-y: auto;
    background: var(--surface);
    border-block-start: 1px solid var(--line-strong);
    padding: 8px 24px 24px;
    box-shadow: 0 -12px 40px -12px var(--scrim);
  }
  .reader.reader-focus .sheet:target .panel-head { display: none; }
  .reader.reader-focus .sheet:target .sheet-handle, .reader.reader-focus .sheet:target .sheet-done { display: inline-flex; }
  .reader-focus .reader-main { max-width: none; padding-block: 3rem; }
}
@media (max-width:1023px) {
  /* Below the desktop pane: annotations hide, word counts return, the
     desktop-only chrome never renders, and the sheets keep :target. The
     inline Search hides too (the search link beside Menu is the
     sub-desktop affordance; the desktop swaps that link for the form). */
  .ch-note, .rt-brand, .rt-by, .rt-ctls, .rt-divider { display: none; }
  /* M4: the sheet's title row is "Text ... Done"; Done pins to the row's
     end and Reset sits beside the title. */
  .reader .sheet:target { position: fixed; }
  .reader #contents.sheet:target { top: 92px; max-height: none; }
  .reader .sheet-done { position: absolute; inset-block-start: 20px; inset-inline-end: 16px; }
  .reader .panel-head { display: flex; align-items: baseline; gap: 16px; margin: 8px 0 4px; padding-inline-end: 72px; }
  .reader .panel-head .sheet-title { margin: 0; font-size: 22px; }
  .reset-link { background: none; border: 0; padding: 0; min-height: 0; cursor: pointer; font: 13px var(--sans); color: var(--accent); text-decoration: underline; }
  /* M2/T1: the reader chrome is full bleed; the column keeps 24px gutters. */
  body:has(.reader) .site-main { padding: 0; }
  .reader-main { padding: 26px 24px 0; }
}

/* Breakpoints per the comp: <=767 mobile, 768-1023 tablet, >=1024 desktop. */
@media (min-width:768px) {
  :root { --read-lh:1.72; --read-width:600px; }
  .site-head { min-height: 64px; padding-inline: 40px 28px; }
  .brand { font-size: 22px; }
  .nav-account { display: inline-flex; }
  .nav-menu-link { font-size: 15px; }
  h1 { font-size: 40px; }
  h2 { font-size: 24px; }
  /* T2: the nav cluster right-aligns so it sits beside the Menu link, and
     its own Search serves that range (the separate search link hides). */
  .site-nav { margin-inline-start: auto; }
  .nav-menu-link { margin-inline-start: 0; }
  .nav-search-link { display: none; }
  .site-main { padding: 40px 64px 80px; }
}
@media (min-width:1024px) {
  :root { --read-lh:1.72; --read-width:640px; }
  /* D3: the header row sits in the 1200px shell (40px gutters inside it). */
  .site-head { min-height: 68px; padding-inline: max(40px, calc((100% - 1200px) / 2 + 40px)); gap: 6px; }
  .brand { font-size: 24px; margin-inline-end: 18px; }
  .site-nav { gap: 6px; margin-inline-start: 0; }
  .site-nav .nav-wide { display: inline-flex; }
  .site-nav .nav-inline-search { display: none; }
  .nav-search { display: block; margin-inline-start: auto; margin-inline-end: 6px; }
  .nav-search input { padding: 0 14px; font-size: 14px; }
  .nav-search-link { display: none; }
  .nav-menu-link:not(.is-member) { display: none; }
  /* Desktop menu (members): a right-hand panel instead of a bottom sheet. */
  #menu.sheet:target {
    inset: 0 0 0 auto; width: 360px; max-height: none;
    border-block-start: 0; border-inline-start: 1px solid var(--line-strong);
    padding: 20px 28px; box-shadow: -16px 0 40px -20px var(--scrim);
  }
  #menu .sheet-handle { display: none; }
  h1 { font-size: 44px; }
  .site-main { max-width: 1200px; margin-inline: auto; padding: 48px 40px 96px; }
}
@media (max-width:767px) {
  /* Mobile chrome (M1): the header is brand + Menu; the sheet owns the nav
     links. Hiding the inline row is what keeps the header from pushing the
     document past the viewport (nowrap links have a min-content width no
     flex child shrinks below). Gutters tighten to the comp's 20px and the
     chip row bleeds to the viewport edge the way the comp draws it. M1 is
     content-first: the cover column (and the Continue CTA riding it) hides,
     leaving eyebrow, title, byline, meta, summary. */
  .site-nav { display: none; }
  .nav-search-link { margin-inline-start: auto; }
  .nav-menu-link { margin-inline-start: 0; }
  .story-cover { display: none; }
  .site-main { padding: 28px 20px 48px; }
  .sheet:target { padding-inline: 20px; }
  .filter-chips { margin-inline: -20px; padding-inline: 20px; }
}

/* Touch widths: every secondary link and inline control keeps a 44px tap
   target (the visible text stays its size; the box grows around it). */
@media (max-width:1023px) {
  .action-aux a, .action-aux summary, .review-tools summary, .section-links a, .page-actions a, .page-actions .link-btn,
  .story-info .byline .follow-btn, .section-more a, .auth-links a, .bm-chapter {
    display: inline-flex; align-items: center; min-height: 44px;
  }
  .site-main form:not(.text-settings) label:has(> input:is([type="checkbox"], [type="radio"])) { min-height: 44px; margin-block-end: 0; }
  .series-item form.inline button, .letter-nav a { min-height: 44px; min-width: 44px; }
  .report-disclosure input, .report-disclosure button, .story-reviews .review form.inline :is(input, button) { min-height: 44px; }
  .chip { min-height: 44px; }
}

/* Motion kill switch: nothing animates for reduced-motion visitors. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* The post-password card's form (the age gate twin): the house stacked
   one-field form, full-width field, actions row with the outline back
   link beside the solid primary. */
.gate-pass { margin-block-start: 1.5rem; text-align: start; }
.gate-pass label { font-weight: 500; }
.gate-pass input[type="password"] { width: 100%; margin-block-end: .75rem; }
.gate-pass .gate-actions { display: flex; align-items: center; gap: 1rem; margin-block-start: .25rem; }
.gate-warning { margin: 0 0 1rem; font: 500 14px/1.5 var(--sans); }
