/* Scarlet Citadel -- Finished HTML. Layout, palette and panel mechanics
   adapted from the Analects prototype (C:\Users\adam\Documents\AI\Project\_Shared\AL\_Prototype\Analects\analects.css).
   The publication has no right-side page rail: there is no Source PDF for
   this work, so no page geometry exists to mark (Captain's ruling). The
   prototype's --source-rail / --source-label reservation and its
   .source-page-origin markers are simply not part of this stylesheet -- the
   reading column takes the full measure instead of a rail being zeroed out. */

:root {
  --parchment: #f6f1e7;
  --parchment-mid: #eee7d6;
  --parchment-dark: #ddd3bd;
  --ink: #211c15;
  --ink-mid: #44392d;
  --ink-light: #665746;
  --rust: #842727;
  --rust-light: #a13a32;
  --gold: #7b6326;
  --rule: #c5b48f;
  --shadow: rgba(30, 25, 18, 0.16);
  /* Title-plate size lives here as one named number so it can be tried live
     without touching a rule:
       document.documentElement.style.setProperty('--plate-width','560px')
     This caps the FRAMED box.  box-sizing is border-box, so the 5px frame on
     each side is spent from it -- the picture itself lands 10px narrower. */
  --plate-width: 610px;
  --contents-panel-width: 16rem;
  --header-height: 3.55rem;
  --section-bar-height: 2.15rem;
  --body: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif;
  --display: "Palatino Linotype", "Book Antiqua", Georgia, serif;
  /* Formerly hard-coded outside the token set (16 values, Captain-ordered
     dark-mode audit, post-production edit 2026-09-03): each is used at
     least once below and now lives here so a theme switch can retarget it.
     Names describe role, not the light value, since dark mode gives each a
     different value. */
  --paper-highlight: rgba(255, 255, 255, 0.82);
  --paper-texture: rgba(83, 64, 32, 0.018);
  --on-accent: white;
  --header-text: #f8f1df;
  --header-bg: rgba(32, 27, 20, 0.97);
  --header-shadow: rgba(0, 0, 0, 0.2);
  --toggle-hover-color: #e3c46b;
  --toggle-hover-bg: rgba(255, 255, 255, 0.08);
  --nav-separator: #d7b85b;
  --nav-meta: rgba(248, 241, 223, 0.82);
  --link-hover-bg-strong: rgba(132, 39, 39, 0.07);
  --backdrop-bg: rgba(22, 18, 14, 0.42);
  --footer-text: #eee3ca;
  --footer-bg: #241f18;
  --title-ink: #1e1913;
  --panel-link-bg: rgba(255, 255, 255, 0.3);
  /* Palette-parity tokens (post-production edit, Captain's ruling
     2026-09-03): Sunzi-war's design tokens, copied verbatim so the two
     builds' contents-panel component is byte-for-byte the same palette.
     --note-bg/--note-border/--link-hover-bg/--panel-highlight did not
     previously exist in this stylesheet -- the carded Dark Mode control
     and the .display-toggle-* family adopted below need them. */
  --note-bg: #eee5cf;
  --note-border: #c0a070;
  --link-hover-bg: rgba(132, 39, 39, 0.06);
  --panel-highlight: rgba(255, 255, 255, 0.28);
  color-scheme: light;
}

/* ---- Dark mode (Captain-ordered, post-production edit 2026-09-03) --------
   Two paths reach the same palette: the System path follows the OS via
   prefers-color-scheme, suppressed when the reader has explicitly chosen
   Off (:root[data-theme="light"]); the explicit On path is
   :root[data-theme="dark"] and always wins regardless of the OS setting.
   This is a pulp-adventure text, not a generic inverted website, so hue is
   kept close to the light values -- warm ink on a dark citadel-stone paper --
   only lightness/direction flips. Rust and gold are brightened (not merely
   lightened) to clear 4.5:1 against the dark paper while still reading as
   the same two accent colours; --on-accent flips to a dark ink so button
   text stays legible against the now-bright rust. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --parchment: #1b1712;
    --parchment-mid: #241f18;
    --parchment-dark: #2c251c;
    --ink: #e8dfc9;
    --ink-mid: #c9bc9c;
    --ink-light: #a89877;
    --rust: #e0785f;
    --rust-light: #ef9478;
    --gold: #d4af5a;
    --rule: #4a4030;
    --shadow: rgba(0, 0, 0, 0.5);
    --paper-highlight: rgba(255, 240, 210, 0.045);
    --paper-texture: rgba(0, 0, 0, 0.32);
    --on-accent: #1b1712;
    --header-text: #f3e8d0;
    --header-bg: rgba(20, 16, 12, 0.97);
    --header-shadow: rgba(0, 0, 0, 0.5);
    --toggle-hover-color: #f0c979;
    --toggle-hover-bg: rgba(255, 255, 255, 0.12);
    --nav-separator: #d8ae55;
    --nav-meta: rgba(243, 232, 208, 0.82);
    --link-hover-bg-strong: rgba(226, 118, 90, 0.16);
    --backdrop-bg: rgba(0, 0, 0, 0.6);
    --footer-text: #ece0c8;
    --footer-bg: #14100c;
    --title-ink: #f2e6cd;
    --panel-link-bg: rgba(255, 255, 255, 0.06);
    --note-bg: #2a2318;
    --note-border: #6b5636;
    --link-hover-bg: rgba(224, 120, 95, 0.14);
    --panel-highlight: rgba(255, 255, 255, 0.06);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --parchment: #1b1712;
  --parchment-mid: #241f18;
  --parchment-dark: #2c251c;
  --ink: #e8dfc9;
  --ink-mid: #c9bc9c;
  --ink-light: #a89877;
  --rust: #e0785f;
  --rust-light: #ef9478;
  --gold: #d4af5a;
  --rule: #4a4030;
  --shadow: rgba(0, 0, 0, 0.5);
  --paper-highlight: rgba(255, 240, 210, 0.045);
  --paper-texture: rgba(0, 0, 0, 0.32);
  --on-accent: #1b1712;
  --header-text: #f3e8d0;
  --header-bg: rgba(20, 16, 12, 0.97);
  --header-shadow: rgba(0, 0, 0, 0.5);
  --toggle-hover-color: #f0c979;
  --toggle-hover-bg: rgba(255, 255, 255, 0.12);
  --nav-separator: #d8ae55;
  --nav-meta: rgba(243, 232, 208, 0.82);
  --link-hover-bg-strong: rgba(226, 118, 90, 0.16);
  --backdrop-bg: rgba(0, 0, 0, 0.6);
  --footer-text: #ece0c8;
  --footer-bg: #14100c;
  --title-ink: #f2e6cd;
  --panel-link-bg: rgba(255, 255, 255, 0.06);
  --note-bg: #2a2318;
  --note-border: #6b5636;
  --link-hover-bg: rgba(224, 120, 95, 0.14);
  --panel-highlight: rgba(255, 255, 255, 0.06);
}

:root[data-theme="light"] {
  color-scheme: light;
}

/* Preserved artefacts: image files themselves are never touched. Dark mode
   only dims them slightly so a bright scan does not glare on a dark page.
   Both of this edition's two <img> elements are .cover-figure img (the
   title-page plate and the mid-document Weird Tales plate); the bare `img`
   rule below never actually paints an element, since .cover-figure img
   (same (0,1,1) specificity, later in the cascade) always overrides it, so
   the dark override targets .cover-figure img directly and out-specifies
   it with the extra attribute/class selector rather than relying on
   source order. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cover-figure img {
    filter: brightness(0.85);
  }
}

:root[data-theme="dark"] .cover-figure img {
  filter: brightness(0.85);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: auto;
  scroll-padding-top: calc(var(--header-height) + var(--section-bar-height) + 0.75rem);
}

body {
  margin: 0;
  color: var(--ink);
  background:
    radial-gradient(circle at 18% 10%, var(--paper-highlight), transparent 34rem),
    repeating-linear-gradient(0deg, var(--paper-texture) 0, var(--paper-texture) 1px, transparent 1px, transparent 4px),
    var(--parchment);
  font-family: var(--body);
  font-size: clamp(1.06rem, 0.98rem + 0.24vw, 1.24rem);
  line-height: 1.58;
  text-rendering: optimizeLegibility;
}

a { color: var(--rust); text-decoration-thickness: 0.08em; text-underline-offset: 0.16em; }
a:hover { color: var(--rust-light); }

.skip-link {
  position: fixed;
  z-index: 100;
  top: 0.5rem;
  left: 0.5rem;
  padding: 0.65rem 1rem;
  color: var(--on-accent);
  background: var(--rust);
  transform: translateY(-150%);
}
.skip-link:focus { transform: none; }

.site-header {
  position: sticky;
  z-index: 30;
  top: 0;
  color: var(--header-text);
  background: var(--header-bg);
  border-bottom: 2px solid var(--gold);
  box-shadow: 0 0.25rem 1rem var(--header-shadow);
}

/* Floating section-title bar (post-production edit, 2026-09-03; ported from
   the Sunzi-war build's CAP-011): a second, slimmer sticky strip directly
   beneath .site-header, showing the current chapter's title as the reader
   scrolls. Reserves its height at all times so the reading column never
   jumps when it fills in; only its own opacity/visibility toggle when a
   section is known. No Part concept in this work, so no part span/
   separator -- just the title. */
.section-bar {
  position: sticky;
  z-index: 25;
  top: var(--header-height);
  display: flex;
  align-items: center;
  min-height: var(--section-bar-height);
  padding: 0;
  color: var(--ink-light);
  background: var(--parchment-mid);
  border-bottom: 1px solid var(--rule);
  box-shadow: 0 0.15rem 0.4rem var(--shadow);
  font-family: var(--display);
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.35rem);
  transition: opacity 160ms ease, transform 160ms ease, visibility 0s linear 160ms;
}

.section-bar.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 160ms ease, transform 160ms ease;
}

/* Inner wrapper mirrors main's own max-width/margin-inline/padding rule
   (below) so the title's left edge tracks the running text column's left
   edge at every viewport. No Contents-open override is needed here: per
   the 2026-08-24 centring-defect fix (see the comment above the
   .contents-open block near the end of this stylesheet), the panel inset
   is applied as `padding-left` on body itself, not as a margin on main --
   so .section-bar, an ordinary sticky flow child of body exactly like
   main, has its own content box narrowed by body's padding in lockstep
   with main's. This wrapper's "100%" is already main's own content-box
   width in both states; no escape/re-offset trick required, and none is
   applied, matching .section-bar's existing (pre-edit) inset behaviour. */
.section-bar-inner {
  max-width: 52rem;
  width: 100%;
  height: 100%;
  margin-inline: auto;
  padding: 0 1.5rem;
  box-sizing: border-box;
  display: flex;
  align-items: center;
}

.site-nav {
  width: min(100% - 2rem, 76rem);
  min-height: var(--header-height);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  font-family: var(--display);
  font-size: 0.72rem;
  letter-spacing: 0.055em;
  text-transform: uppercase;
}

.nav-leading { min-width: 0; flex: 1; display: flex; align-items: center; gap: 0.75rem; }
.site-nav a { color: inherit; text-decoration: none; }

.contents-toggle, .contents-close, .contents-backdrop { border: 0; font: inherit; cursor: pointer; }

.contents-toggle {
  width: 2.25rem; height: 2.25rem; padding: 0;
  display: grid; place-items: center;
  color: var(--header-text); background: transparent; border-radius: 0.25rem;
  font-family: var(--body); font-size: 1.2rem; line-height: 1;
}
.contents-toggle:hover, .contents-toggle[aria-expanded="true"] {
  color: var(--toggle-hover-color); background: var(--toggle-hover-bg);
}

.nav-brand { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.55rem; row-gap: 0.08rem; font-size: 0.86rem; line-height: 1.3; }
.nav-title { white-space: nowrap; }
.nav-meta-group { display: inline-flex; align-items: baseline; gap: 0.55rem; white-space: nowrap; }
.nav-separator { color: var(--nav-separator); font-size: 0.68rem; }
.nav-meta { color: var(--nav-meta); font-size: 0.54rem; letter-spacing: 0.045em; }
.top-link { white-space: nowrap; }

main {
  min-height: 100vh;
  transition: margin-left 180ms ease;
  overflow-x: clip;
  max-width: 52rem;
  margin-inline: auto;
  padding: clamp(2rem, 6vw, 4rem) 1.5rem clamp(4rem, 8vw, 6rem);
}

/* --- publication content: carried over unchanged from BasicHTML, styled
   in place. No wrapper divs were introduced around it. --- */

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 400;
  text-align: center;
  color: var(--ink);
  margin: 1.4em 0 0.6em;
}
h1 { font-size: clamp(2.4rem, 5vw, 3.6rem); letter-spacing: 0.01em; }
h2 { font-size: clamp(1.6rem, 3.4vw, 2.2rem); margin-top: 2.2em; }
h3 { font-size: 1.05rem; letter-spacing: 0.04em; }
h4 { font-size: 1rem; font-style: italic; color: var(--ink-light); }
h2 a { color: inherit; text-decoration: none; }

hr { border: none; border-top: 1px solid var(--rule); margin: 2.5em auto; width: 50%; }

img { max-width: 100%; height: auto; display: block; margin: 1.25em auto; filter: sepia(0.08) contrast(1.02); }

/* --- title-page hero: h1/byline/cover-plate/first-publication-line, taken
   out of the plain reading column and given the prototype's distinct
   treatment (analects.css .title-page / .cover-figure / .title-rule /
   .scroll-cue), scaled down from the prototype's 20-book front matter to
   this five-chapter novelette's much shorter title matter. --- */
.title-page {
  min-height: calc(100vh - var(--header-height));
  padding: clamp(2.5rem, 6vw, 4.5rem) 1.5rem clamp(2.5rem, 5vw, 3.5rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  align-content: start;
  text-align: center;
}
/* Display face for the title, distinct from --display, matching
   analects.css:236-245 exactly except for font-size, which stays at our
   scaled-down clamp() (sanctioned; a five-chapter novelette does not need
   the prototype's 6.75rem ceiling). Nothing else in section.title-page
   gets a distinct face: the prototype only special-cases h1 and .kicker
   (analects.css:247-252), and this build has no .kicker element -- the
   byline (h4/h2) and the first-publication line (h3) are not given the
   Bodoni treatment by the prototype, so they keep the generic heading
   rule here too. */
.title-page h1 {
  margin: 0;
  color: var(--title-ink);
  font-family: "Bodoni MT", Didot, "Times New Roman", serif;
  font-size: clamp(2.4rem, 5vw, 3.6rem);
  font-weight: 400;
  letter-spacing: 0.015em;
  line-height: 0.82;
  text-transform: uppercase;
}
.title-page .kicker {
  margin: clamp(1.1rem, 2.2vw, 1.6rem) 0 0;
  color: var(--rust);
  font-family: "Bodoni MT", Didot, "Times New Roman", serif;
  font-size: clamp(0.74rem, 1.2vw, 1rem);
  font-weight: 400;
  letter-spacing: 0.34em;
  line-height: 1.3;
  text-transform: uppercase;
}
.title-rule { width: 6rem; margin: 1.5rem 0; border-top: 1px solid var(--rule); }
.title-credits { margin: 0 0 1.75rem; }
.title-credits h4, .title-credits h2 { margin: 0.15em 0; }
/* The frame hugs the plate.  Both cover images are smaller than the old fixed
   figure width (400x560 and 424x620 against a 28rem/448px box), so a fixed width
   left the border enclosing a blank strip to the right of the picture -- and
   `img { margin: 0 }` had overridden the generic `margin: auto`, so the image sat
   flush left and the whole gap fell on one side.  fit-content sizes the figure to
   the rendered image; max-width still caps it on narrow screens, where the image
   scales down inside it.  The plates are never upscaled past their natural size --
   enlarging an archival scan to fill a box only softens it. */
/* The border sits on the IMAGE, not on the figure.  A border on the figure
   enclosed the caption as well, so the plate's title read as part of the framed
   picture; and because the figure is a block, the frame could also be wider than
   the plate inside it.  Bordering the image makes the box the picture's own edge
   by definition -- it cannot be wider or narrower than what it frames -- and
   leaves the caption below it, outside the box.  The figure shrink-wraps with
   fit-content so the caption still centres under the plate.  The plates are never
   upscaled to fill a box; enlarging an archival scan only softens it. */
.cover-figure {
  width: fit-content;
  /* Presentation size set by the Captain: 125% of the original plate's
     presented width.  The source cover presented at 400px, so the target is
     500px -- 31.25rem -- which is 60% of main's 52rem/832px reading measure.
     The height cap below is deliberately loose (85vh) so it does not undercut
     that width on an ordinary desktop; it still catches a short viewport,
     where a 1024x1536 plate would otherwise fill the screen. */
  max-width: min(var(--plate-width), 80vw);
  margin: 0 auto 1.5rem;
  padding: 0;
  background: transparent;
  border: 0;
}
.cover-figure img {
  display: block;
  margin: 0;
  filter: none;
  width: auto;
  max-width: 100%;
  height: auto;
  /* Loose enough not to undercut --plate-width on an ordinary desktop: a
     610px framed box on this 2:3 artwork stands 910px tall, so an 85vh cap
     would have held it to ~513px on a 900px-tall viewport and quietly
     delivered something narrower than the width that was asked for.  It
     still catches a genuinely short window. */
  max-height: 110vh;
  border: 5px solid var(--ink);
}
.title-page h3 { margin-top: 0.5rem; }
/* Imprint line and closing block, from the prototype (analects.css:214-223
   .library-edition, :1160-1175 .site-footer).  The footer sits outside <main>,
   so it is outside the invariant span and adds no chrome to it. */
.library-edition {
  margin: 0.35rem 0 0;
  color: var(--ink-light);
  font-family: var(--display);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1.2;
  text-transform: uppercase;
}
.site-footer {
  padding: 2.5rem 1rem;
  color: var(--footer-text);
  background: var(--footer-bg);
  border-top: 3px solid var(--gold, #c9a227);
  font-size: 0.86rem;
  text-align: center;
}
.site-footer p { margin: 0.2rem; }
.site-footer a { color: var(--toggle-hover-color); }
.scroll-cue {
  margin-top: 1.5rem;
  display: inline-block;
  font-family: var(--display);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
}

/* Weird Tales plate, mid-document -- same framed idiom, in the normal
   reading column rather than the hero. */
main > figure.cover-figure { width: fit-content; max-width: min(30rem, 80vw); margin: 1.5em auto; }
main > figure.cover-figure p.caption { margin: 0.6em 0 0; border: none; }

/* analects.css:1755-1758: loosen the tight display line-height at narrow
   widths so the uppercased, tracked title does not collide with itself. */
@media (max-width: 700px) {
  .title-page h1 { line-height: 0.94; }
}

/* The in-document table of contents runs in two columns, matching the chapter
   grid in the left panel (.chapter-links above).  Five entries fill it 1-2 /
   3-4 / 5.  It is centred under its own centred heading rather than carrying
   the source's left indent: that indent came from the capture's
   `margin-left:40%`, which belongs to the plain BasicHTML edition and is
   preserved there.  Width is fit-content so the pair of columns centres as a
   block instead of stretching across the reading measure. */
ul.toc {
  margin: 1em auto;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, auto));
  gap: 0.35em 3em;
  justify-content: center;
  width: fit-content;
  font-family: var(--display);
  font-size: 0.95em;
}
ul.toc li { margin: 0.15em 0; }
ul.toc a { color: var(--ink); }

/* Prose narrative paragraphs -- the two-space sentence rule depends on
   pre-wrap actually being applied here; unchanged from BasicHTML. */
p.prose { white-space: pre-wrap; margin: 1.1em 0; text-align: left; }
p.first { text-indent: 0; }

/* Chapter 1's opening words, set in capitals to match chapters 2-5.  Only the
   rendering changes: the underlying text is untouched, so selecting or
   copying the line still yields "THE roar of battle". */
.opening-words { text-transform: uppercase; }

p.verse, p.quote { margin: 1.3em 0; font-style: italic; color: var(--ink-mid); text-align: left; }
p.verse, p.quote { margin-left: 3em; }

/* The captured markup puts a bare <br> between each ballad and the paragraph
   that follows it.  That <br> contributes a full line box AND blocks margin
   collapse, so the ballad sat 70px above the prose but only 22px below the
   chapter title.  Suppressing just that <br> lets the margins collapse
   normally and leaves the ballad the same 1.3em from the title above and the
   prose below.  The <br> itself is untouched in the markup. */
p.verse + br { display: none; }

/* The closing attribution sits one indent level in from its ballad. */
.verse-attribution { display: block; margin-left: 3em; }
p.caption { text-align: center; font-style: italic; color: var(--ink-light); margin: 0.25em 0 1em; }

/* --- collapsible left contents panel: structure and behaviour from the
   Analects prototype. --- */

.contents { font-size: 1rem; }

.contents-panel {
  position: fixed;
  z-index: 40;
  top: var(--header-height);
  bottom: 0;
  left: 0;
  width: min(var(--contents-panel-width), calc(100vw - 3rem));
  padding: 1.25rem 1rem 2rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  color: var(--ink);
  background:
    repeating-linear-gradient(0deg, var(--paper-texture) 0, var(--paper-texture) 1px, transparent 1px, transparent 4px),
    var(--parchment);
  border-right: 1px solid var(--rule);
  box-shadow: 0.5rem 0 1.4rem var(--shadow);
  transform: translateX(-105%);
  visibility: hidden;
  transition: transform 180ms ease, visibility 0s linear 180ms;
}

.contents-open .contents-panel { transform: translateX(0); visibility: visible; transition-delay: 0s; }

.contents-panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.contents-panel-head .eyebrow { margin: 0 0 0.25rem; color: var(--rust); font-family: var(--display); font-size: 0.68rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; }
/* The panel headings take their face and weight from the prototype, which
   has no base h1-h4 rule at all: its .contents-panel-head h2 and .toc-group
   h3 fall through to the UA default of bold, and the h2 inherits the body
   face from <body>.  This build does have a base heading rule
   (font-family: var(--display); font-weight: 400), which would otherwise
   capture both and render them light and in the display face.  These two
   rules restore the prototype's rendering; do not fold them back into the
   base rule. */
.contents-panel-head h2 { margin: 0; font-family: var(--body); font-size: 1.65rem; font-weight: 700; text-align: left; }

.contents-close { flex: 0 0 auto; width: 2rem; height: 2rem; padding: 0; color: var(--ink-light); background: transparent; border-radius: 0.25rem; font-size: 1.6rem; line-height: 1; }
.contents-close:hover { color: var(--rust); background: var(--link-hover-bg-strong); }

.contents-backdrop { position: fixed; z-index: 35; inset: var(--header-height) 0 0; display: none; padding: 0; background: var(--backdrop-bg); }

/* Dark Mode control (post-production edit, Captain's order 2026-09-03;
   re-carded to match Sunzi-war's component exactly, further
   post-production edit, Captain's order, 2026-09-03) -- ported from the
   Sunzi-war build (_Build\Sunzi-war\_Build-Scripts\build_finished_html.py,
   CSS_CONTENT: .display-controls / .display-toggle / .display-toggle-master
   / .display-toggle-label, and .theme-switch / .theme-switch-option),
   verbatim. This build has no note-box toggles of its own (no
   .display-toggle-child/-switch/-track/-state), so only the master-row
   shape and the bordered card are adopted -- a three-way segmented group
   (role="radiogroup"), not a track-and-thumb switch: that shape only ever
   honestly shows two states. */
.display-controls {
  margin: 1rem 0 1.25rem;
  padding: 0.55rem 0.7rem 0.6rem;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--parchment-dark);
  box-shadow: 0 2px 6px var(--shadow), inset 0 1px 0 var(--panel-highlight);
}
.display-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.28rem 0;
}
.display-toggle-master { padding-top: 0.15rem; }
.display-toggle-label {
  color: var(--ink-mid);
  font-family: var(--display);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1.25;
  text-transform: uppercase;
}
.theme-switch {
  display: inline-flex;
  flex: none;
  border: 1px solid var(--note-border);
  border-radius: 0.85rem;
  overflow: hidden;
}
.theme-switch-option {
  border: 0;
  border-left: 1px solid var(--note-border);
  padding: 0.2rem 0.5rem;
  background: transparent;
  color: var(--ink-light);
  cursor: pointer;
  font: inherit;
  font-family: var(--display);
  font-size: 0.58rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.4;
}
.theme-switch-option:first-child { border-left: 0; }
.theme-switch-option[aria-checked="true"] { color: var(--parchment); background: var(--rust); }
.theme-switch-option:focus-visible { outline: 2px solid var(--rust); outline-offset: 2px; }

/* Group-header treatment (Captain's order, 2026-09-13: "Update the TOC panel
   and boxes to the same style as the Analects build"), superseding the
   2026-09-03 boxed `.toc-group h3` above -- vendored instead from Analects'
   CURRENT `.toc-group h3` (analects.css, the rule immediately above its own
   `.toc-end h3, .toc-title h3 { margin: 0; }`), which is unboxed: rust
   small-caps text, no background, no border, no padding. Analects has no
   base h1-h4 rule at all, so its plain `.toc-group h3` (Front Matter /
   Chapters-equivalent headings) falls through to the UA defaults of
   font-weight 700 and a symmetric "1em 0" margin block; this build's own
   base `h1, h2, h3, h4` rule (above) sets font-weight 400 and an asymmetric
   "1.4em 0 0.6em", so both are restored explicitly here -- the same
   precedent already used for `.contents-panel-head h2` -- rather than left
   to fall through to the wrong values. Measured equal to Analects live in
   both themes: color var(--rust), font-size 0.86rem (13.76px), font-weight
   700, letter-spacing 0.09em (1.2384px), margin 13.76px top and bottom. */
.toc-columns { display: grid; grid-template-columns: 1fr; gap: 1.75rem; }
.toc-group h3 {
  margin: 1em 0;
  color: var(--rust);
  font-family: var(--display);
  font-size: 0.86rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-align: left;
  text-transform: uppercase;
}
/* End of Document (Captain's order, 2026-09-13: renamed from "The End") and
   Title (Captain's order, 2026-09-13: moved out of the boxed
   `.major-links-simple` list into this same heading-style entry, placed
   first in the panel) -- vendored from Analects' `.toc-end h3, .toc-title
   h3 { margin: 0; }` and `.toc-end a, .toc-title a { color: inherit;
   text-decoration: none; }`. Both share the base `.toc-group h3` rust/caps
   look above; this is only the zero-margin, plain-link addition each single-
   line entry needs on top of it, exactly as in Analects. */
.toc-end h3,
.toc-title h3 {
  margin: 0;
}
.toc-end a,
.toc-title a {
  color: inherit;
  text-decoration: none;
}
.major-links-simple { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.5rem; }
.major-links-simple a {
  display: block;
  padding: 0.65rem 0.75rem;
  color: var(--ink);
  background: var(--parchment-mid);
  border: 1px solid var(--rule);
  border-radius: 4px;
  font-family: var(--display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
}
.major-links-simple a:hover { border-color: var(--gold); color: var(--rust); }

.chapter-links { margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.4rem; list-style: none; }
.chapter-links a { display: block; padding: 0.4rem 0.3rem; color: var(--ink-mid); border-bottom: 1px dotted var(--rule); text-align: center; text-decoration: none; }
.chapter-links a:hover { color: var(--rust); }
.chapter-links span { display: inline; }

/* Intentional divergence from the prototype (analects.css:820-824), which
   uses this same margin-left-on-main rule and inherits the same bug: it
   replaces main's auto left margin while leaving the right margin auto, so
   at wide viewports the reading column sits pinned beside the panel and
   every remaining pixel piles up on the right -- reported by the Captain at
   ~1920px. Fixed here by moving the offset onto body's padding instead of
   main's margin: body keeps box-sizing: border-box, so padding-left simply
   shrinks its content box, and main's own margin-inline: auto (untouched)
   re-centres inside that shrunk box -- equal gaps on both sides of the
   remaining space, not one auto margin absorbing everything. .site-header
   is position: sticky, not fixed, so it is itself a padded child of body
   and would shrink and reveal a gap on the right of the coloured bar; it is
   pulled back out to full viewport width with a matching negative margin.
   .contents-panel and .contents-backdrop are position: fixed and .skip-link
   likewise, so body padding does not move any of them -- verified in a real
   render, not assumed. This build has no .site-footer to carry the same
   treatment. Do not revert this toward the prototype's version; the
   prototype's behaviour is the defect being fixed. */
@media (min-width: 901px) {
  .contents-open { padding-left: var(--contents-panel-width); }
  .contents-open .site-header {
    margin-left: calc(-1 * var(--contents-panel-width));
    width: calc(100% + var(--contents-panel-width));
  }
}
@media (max-width: 900px) {
  body.contents-open { overflow: hidden; }
  .contents-open .contents-backdrop { display: block; }
}

@media (max-width: 600px) {
  main { padding-left: 1rem; padding-right: 1rem; }
  /* .section-bar-inner mirrors main's own padding above -- must be kept
     in step at this breakpoint too, or the title drifts 0.5rem off the
     text column's now-narrower left inset. */
  .section-bar-inner { padding-left: 1rem; padding-right: 1rem; }
  ul.toc { gap: 0.35em 1.5em; }
  p.verse, p.quote { margin-left: 1.5em; }
  .verse-attribution { margin-left: 1.5em; }
}

/* ---- Reduced motion ------------------------------------------------------
   Added alongside the section-bar (post-production edit, 2026-09-03). Must
   be the universal *, *::before, *::after form -- a guard naming individual
   selectors gets out-specified by their own more specific transition rules
   (e.g. .contents-panel, .section-bar.is-visible) and silently does
   nothing, a lesson carried over from the Sunzi-war build. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
