/*  base.css — page shell, paper aesthetic, masthead, side panel, footer.
    View-specific styles live in plate.css and graph.css.                    */

/*  Pansophia theme tokens (@generated by l30-theme-codegen from
 *  decisions/design/themes/pansophia.md). Imported here so the ontology
 *  landing — the de-facto reference web rendering of the pansophia
 *  register — consumes the same `--color-*` variables emitted for the
 *  document viewer and any future HTML-rendered L30 doc. The short
 *  aliases below (--paper, --ink, --accent, etc.) preserve the existing
 *  authoring vocabulary used throughout this stylesheet and its
 *  siblings; updating the canonical token in pansophia.md propagates
 *  here automatically. See .claude/plans/themed-html-content-plan.md
 *  Phase 4. */
@import url("../../brand/themes/pansophia.css");

@font-face {
  font-family: 'et-book';
  src: url('https://cdn.jsdelivr.net/gh/edwardtufte/et-book@gh-pages/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff') format('woff');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'et-book';
  src: url('https://cdn.jsdelivr.net/gh/edwardtufte/et-book@gh-pages/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff') format('woff');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'et-book';
  src: url('https://cdn.jsdelivr.net/gh/edwardtufte/et-book@gh-pages/et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff') format('woff');
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  /*  Short aliases over the pansophia.css tokens. Keeping the existing
   *  short authoring vocabulary (--paper, --ink, --accent, --reg-*) so
   *  the rest of this file (and its siblings) need no further rewrite;
   *  the canonical values live in brand/themes/pansophia.css. */
  --paper:       var(--color-paper);
  --paper-warm:  var(--color-paper-warm);
  --rule:        var(--color-rule);
  --rule-faint:  var(--color-rule-faint);
  --ink:         var(--color-ink);
  --ink-2:       var(--color-ink-2);
  --ink-3:       var(--color-ink-3);
  --ink-quiet:   var(--color-ink-quiet);
  --accent:      var(--color-accent);
  --accent-soft: var(--color-accent-soft);
  --reg-structural: var(--color-reg-structural);
  --reg-decision:   var(--color-reg-decision);
  --reg-lifecycle:  var(--color-reg-lifecycle);
  --reg-actor:      var(--color-reg-actor);
  --serif: var(--type-serif-family);
  --mono:  var(--type-mono-family);

  /*  Poeticism envelopes — written by applyPoeticismLight in index.html.
   *  Four-stage map (compressed plateaus, layered fresco):
   *    embodied     [0.00, 0.05]   stable; type graph at full
   *    transition   [0.05, 0.12]   embodied → editorialized (--morph-t ramps)
   *    editorialized[0.12, 0.18]   stable bare plate (Tufte)
   *    transition   [0.18, 0.24]   editorialized → aestheticized (painterly ramps in)
   *    aestheticized[0.24, 0.40]   stable painterly vectors
   *    transition   [0.40, 0.50]   aestheticized → poeticized (painterly fades; sigils stay)
   *    poeticized   [0.50, 0.95]   fresco frames layer additively; sigils migrate
   *    transition   [0.95, 1.00]   schema overlay + sigils fade out; AV register kicks in
   *
   *  Defaults stay 0/1 so before the slider runs nothing is composited
   *  except the schema (which is fully visible by default).             */
  --sigil-migration:        0;
  --sigil-opacity:          0;
  --gold-tint:              0;
  --atmosphere-opacity:     0;
  --schema-graph-opacity:   1;
  --frame-rect-fade:        0;
  --schema-overlay-opacity: 1;
  --transcend-intensity:    0;
  --substrate-intensity:    1;  /* high at t=0; cybersigilist atmosphere */
}

/*  Virtual scroll length for the desktop register-walk. THREE stops
 *  — Chapter I (t=0.14), Chapter II (t=0.26), Chapter III (t=1.0).
 *  The appendix is OUTSIDE this scroll axis: visitors reach it via
 *  the slider's "How it works / embodied" station only, never via
 *  scroll. See index.html's CHAPTER_STOPS / chapterStopForScroll /
 *  tweenScrollToVirtualStop for the JS side.                         */
:root {
  --chapter-walk-stop-len: 360px;
  --chapter-walk-scroll: calc(var(--chapter-walk-stop-len) * 3);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/*  Page-level scrolling: html anchors 100vh math (the ontology
 *  section's grid uses min-height: 100vh), and gives us
 *  scroll-behavior: smooth so the escape-hatch's anchor link
 *  glides back to the top. body owns horizontal-overflow clamping
 *  and overscroll-behavior so iOS rubber-band doesn't reveal void
 *  outside the painted page. Vertical scrolling is enabled — the
 *  page now spans landing → transition → ontology. */
html { height: 100%; scroll-behavior: smooth; }
body {
  min-height: 100%;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  overscroll-behavior-y: none;
}

/*  Paper grain — barely-there. Scoped to the ontology section so it
 *  doesn't paint over the cybersigilist landing above. position:
 *  fixed is intentional: as the visitor scrolls inside the ontology
 *  section the noise tracks the viewport, giving paper its texture
 *  consistently. The .ontology-section establishes a new
 *  containing block for fixed children only inside transform/
 *  filter/will-change contexts; we have none of those, so the
 *  pseudo simply paints over the viewport while the section is on
 *  screen. (When the landing scrolls in, the noise is hidden behind
 *  the landing's own opaque background and pseudo-elements.) */
.ontology-section::before {
  content: "";
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 1;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence baseFrequency='0.9' numOctaves='2' seed='4'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.06 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  mix-blend-mode: multiply;
  opacity: 0.5;
}

#app {
  position: relative;
  z-index: 2;
  min-height: 100vh;
}

/*  Register-walk — virtual-length scroll container that pins the
 *  ontology section across THREE chapter stops. The container's
 *  height is one viewport plus the virtual-scroll length; the
 *  inner .ontology-section is `position: sticky` so it stays put
 *  while the visitor scrolls past the virtual length, and the JS
 *  chapter-trigger maps scrollY → chapter index → tweenPoeticismTo.
 *  Mobile overrides this to a normal flow (see mobile.css).          */
.register-walk {
  position: relative;
  height: calc(100vh + var(--chapter-walk-scroll));
}
@supports (height: 100dvh) {
  .register-walk {
    height: calc(100dvh + var(--chapter-walk-scroll));
  }
}

/*  The ontology section — masthead, slider rail, stage+panel, footer
 *  — uses a 4-row grid sized to the viewport. position: sticky pins
 *  it inside .register-walk; height: 100vh anchors the grid math.
 *  Mobile overrides position to static (see mobile.css). */
.ontology-section {
  position: sticky;
  top: 0;
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  height: 100vh;
}
@supports (height: 100dvh) {
  .ontology-section {
    height: 100dvh;
  }
}

/* — Masthead ——————————————————————————————————————— */
/*
 *  Frontispiece composition: an engraved double-rule above the title,
 *  the title in serif roman (ET Book), a brand-voiced italic subtitle
 *  in IM Fell English, then a second engraved double-rule below.
 *  Each rule is broken at its midpoint by a small four-pointed
 *  compass-rose star (✦) — the cardinal ornament from the L30 brand
 *  medallion (see /brand/icon.png). The whole block is sized to
 *  match the slider rail's central column (~720px max) so masthead,
 *  rail, and panel all share a single editorial spine.
 *
 *  At higher poeticism the title and ornaments warm with a faint
 *  bioluminescent halo, tying the frontispiece register to the
 *  lunarpunk register the slider drives toward.                      */

header.masthead {
  padding: 1.4rem 2.2rem 1.0rem;
  text-align: center;
}

/*  Engraved double-rule. Two thin lines via ::before/::after with
 *  symmetric horizontal fades so the rule reads as printed-edition
 *  ruling rather than a hard div border. The ornament inside masks
 *  out the central section so the rule appears to "break" around
 *  the star — same visual logic as the painted-plate cartouche
 *  rule + corner fleurons.                                            */
.masthead-rule {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 7px;
  margin: 0 auto;
  width: min(720px, 80%);
}
.masthead-rule::before,
.masthead-rule::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(to right,
    transparent 0%,
    var(--rule) 8%,
    var(--rule) 92%,
    transparent 100%);
}
.masthead-rule::before { top: 1px; }
.masthead-rule::after  { bottom: 1px; opacity: 0.55; height: 0.6px; }

/*  Compass-rose ornament (✦) — gold-tinted, gently phosphorescent at
 *  higher poeticism. Background matches paper to mask the rules so
 *  the star reads as drawn ON the printed page, breaking the rule
 *  rather than overlaying it. */
.masthead-ornament {
  position: relative;
  z-index: 2;
  display: inline-block;
  background: var(--paper);
  padding: 0 14px;
  font-family: 'IM Fell English', var(--serif);
  font-size: 13px;
  line-height: 1;
  color: var(--color-gold);
  text-shadow: 0 0 4px rgba(240, 196, 104, calc(var(--painted-opacity, 0) * 0.5 + 0.18));
  transition: color 320ms ease, text-shadow 320ms ease;
}

/*  Title — engraved wordmark image (brand/ontology-of-creation-title.png).
 *  Replaces the previous text-set title so the lockup reads as a
 *  printed plate-title, with the slashed-Ø ligature into "0ntology of
 *  Creation" and the surrounding constellation glyphs in one piece.
 *  Sized with max-height so it scales with the page's typography
 *  rhythm rather than forcing a fixed pixel width. The :root margin
 *  matches what a 38px text title used to occupy. */
/*  Title — ET Book roman, the page's primary serif voice. Letter-
 *  spacing the title slightly opens it for the engraved-page register
 *  (printed titles almost always use looser tracking). */
.masthead-title {
  font-family: var(--serif);
  font-weight: 400;
  font-style: normal;
  font-size: 38px;
  letter-spacing: 0.012em;
  color: var(--ink);
  line-height: 1.1;
  margin: 0.45rem 0 0.15rem;
  /*  Faint bioluminescent halo at higher poeticism — the title takes
   *  on the lunarpunk register as the slider drives toward it. */
  text-shadow: 0 0 14px rgba(240, 196, 104, calc(var(--painted-opacity, 0) * 0.20));
  transition: text-shadow 420ms ease;
}

/*  Subtitle retired: the active chapter label was redundant with
 *  the slider rail's active station label and the prose-title h2
 *  inside the chapter prose. */

/* — Slider rail (horizontal, between masthead and main) — see slider.css. */

/* — Main split ————————————————————————————————————————
 *
 *  The canvas area — the stage (plate) on the left and the prose
 *  panel on the right — is bounded by two engraved hairlines (top
 *  and bottom) that match the masthead's frontispiece rules. The
 *  hairlines fade at their horizontal edges so the canvas reads as
 *  a *plate* — drawn ON the page rather than partitioned off it —
 *  and the existing border-right between stage and panel finishes
 *  the cartouche on the inside.                                       */

main {
  position: relative;
  display: grid;
  grid-template-columns: 1fr minmax(540px, 680px);
  min-height: 0;
}

/*  Top + bottom engraved hairlines bracketing the canvas. Same
 *  fading-gradient pattern as the masthead rules so the page reads
 *  in one register. ::before is the upper rule (full strength);
 *  ::after is the lower rule (slightly faded — frontispiece pages
 *  conventionally weight the rule above more than the rule below).
 *  z-index: 5 keeps them above the stage's SVG content while
 *  pointer-events: none lets clicks pass through to the plate.       */
main::before,
main::after {
  content: "";
  position: absolute;
  left: 3%;
  right: 3%;
  height: 1px;
  pointer-events: none;
  z-index: 5;
  background: linear-gradient(to right,
    transparent 0%,
    var(--rule)  6%,
    var(--rule) 94%,
    transparent 100%);
}
main::before { top: 0; }
main::after  { bottom: 0; opacity: 0.55; height: 0.6px; }
article#stage {
  position: relative;
  min-height: 0;
  border-right: 1px solid var(--rule);
  overflow: hidden;
}

/*  Cybersigilist substrate atmosphere — visible at t=0 (embodied),
 *  fades by t=0.14 (editorialized). Two layers: a deep-ocean radial
 *  vignette darkening the stage corners, and a sparse constellation
 *  of phosphorescent gold dots scattered across the canvas. Together
 *  they read as "the schema sitting on the cosmic substrate" — the
 *  type-graph at low poeticism is not floating on paper, but on a
 *  faintly visible night-ocean.
 *
 *  Both layers gate on --substrate-intensity, so they're only on
 *  during the embodied plateau and dissolve as the bare plate emerges. */
article#stage::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: var(--substrate-intensity, 0);
  transition: opacity 280ms ease;
  background:
    /* Sparse constellation of phosphorescent dots. Inline SVG with
     * fixed-position circles — the dots are small enough that a 1500-
     * unit viewBox stretched to the stage gives roughly 1-2px stars. */
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1500 1000' preserveAspectRatio='none'><g fill='%23f0c468'><circle cx='180' cy='150' r='1.6' opacity='0.85'/><circle cx='420' cy='80' r='1.1' opacity='0.6'/><circle cx='720' cy='220' r='1.4' opacity='0.75'/><circle cx='1020' cy='110' r='1.2' opacity='0.7'/><circle cx='1280' cy='280' r='1.6' opacity='0.85'/><circle cx='90' cy='420' r='1.0' opacity='0.55'/><circle cx='320' cy='360' r='1.3' opacity='0.7'/><circle cx='600' cy='480' r='1.0' opacity='0.6'/><circle cx='880' cy='400' r='1.4' opacity='0.8'/><circle cx='1180' cy='540' r='1.2' opacity='0.7'/><circle cx='1380' cy='460' r='1.0' opacity='0.55'/><circle cx='200' cy='680' r='1.5' opacity='0.85'/><circle cx='480' cy='720' r='1.1' opacity='0.65'/><circle cx='760' cy='800' r='1.3' opacity='0.75'/><circle cx='1080' cy='720' r='1.0' opacity='0.6'/><circle cx='1320' cy='820' r='1.4' opacity='0.8'/><circle cx='40' cy='880' r='1.1' opacity='0.65'/><circle cx='550' cy='930' r='1.3' opacity='0.75'/><circle cx='980' cy='950' r='1.0' opacity='0.55'/></g></svg>"),
    /* Deep-ocean vignette — stage corners drift toward the lunarpunk
     * deep-ocean color, while the centre stays paper-light so the
     * schema content remains legible. */
    radial-gradient(
      ellipse at 50% 55%,
      transparent 0%,
      transparent 35%,
      rgba(42, 68, 88, 0.045) 75%,
      rgba(42, 68, 88, 0.085) 100%
    );
  /* Both layers fill the same area */
  background-size: 100% 100%, 100% 100%;
  background-repeat: no-repeat;
}
aside#panel {
  position: relative;
  overflow-y: auto;
  padding: 1.8rem 2.4rem 3rem;
  background: var(--paper);
}
aside#panel::-webkit-scrollbar { width: 8px; }
aside#panel::-webkit-scrollbar-track { background: transparent; }
aside#panel::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 0; }

/* — Intro panel ——————————————————————————————————————— */

/*  The intro section dropped its static <h2> + reg-line head — its
 *  only heading is now the per-register .prose-title, which sits at
 *  the top of each .prose div. Restore the engraved top rule that
 *  the head used to carry so the section still has its frontispiece
 *  upper boundary. */
.intro .body {
  border-top: 2px solid var(--ink);
  padding-top: 0.9rem;
}
.intro h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 22px;
  letter-spacing: 0.005em;
  color: var(--ink);
  margin-bottom: 0.6rem;
}
.intro p {
  color: var(--ink-2);
  margin-bottom: 0.7rem;
  line-height: 1.6;
}
/*  Drop-cap on the FIRST paragraph of EACH chapter prose block. Limited
 *  to .prose-holistic / -aesthetic / -transcendental so appendix
 *  paragraphs (.appendix-subheading, .appendix-prose) don't accidentally
 *  inherit a drop-cap from the :first-of-type rule. */
.intro .prose-holistic > p:first-of-type::first-letter,
.intro .prose-aesthetic > p:first-of-type::first-letter,
.intro .prose-transcendental > p:first-of-type::first-letter {
  font-size: 2.6em;
  font-weight: 400;
  line-height: 0.85;
  float: left;
  padding: 6px 8px 0 0;
  color: var(--accent);
  font-family: var(--serif);
}
.intro .mono { font-family: var(--mono); font-size: 12.5px; }
.intro .legend {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.9rem;
  row-gap: 0.4rem;
  margin-top: 1rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--rule);
  font-size: 14px;
}
.intro .legend dt {
  font-variant: small-caps;
  letter-spacing: 0.08em;
  font-style: italic;
  font-size: 11px;
  padding-top: 0.18rem;
}
.intro .legend dt[data-reg="structural"] { color: var(--reg-structural); }
.intro .legend dt[data-reg="decision"]   { color: var(--reg-decision); }
.intro .legend dt[data-reg="lifecycle"]  { color: var(--reg-lifecycle); }
.intro .legend dt[data-reg="actor"]      { color: var(--reg-actor); }
.intro .legend dd {
  color: var(--ink-2);
  line-height: 1.5;
  border-bottom: 1px dotted var(--rule);
  padding-bottom: 0.4rem;
}
.intro .legend dd:last-of-type { border-bottom: 0; }

/* — Class panel ——————————————————————————————————————— */

.class-panel { animation: panel-in 280ms ease-out; }
@keyframes panel-in {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}
.class-panel .head {
  border-top: 2px solid var(--ink);
  padding-top: 0.7rem;
  margin-bottom: 1.1rem;
}
.class-panel h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 30px;
  letter-spacing: 0.005em;
  line-height: 1.05;
  color: var(--ink);
}
.class-panel .reg-line {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  margin-top: 0.25rem;
  letter-spacing: 0.02em;
}
.class-panel .reg-line[data-reg="structural"] { color: var(--reg-structural); }
.class-panel .reg-line[data-reg="decision"]   { color: var(--reg-decision); }
.class-panel .reg-line[data-reg="lifecycle"]  { color: var(--reg-lifecycle); }
.class-panel .reg-line[data-reg="actor"]      { color: var(--reg-actor); }
.class-panel .uri {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 0.15rem;
  letter-spacing: 0.01em;
}
.class-panel .body {
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.62;
  color: var(--ink);
  max-width: 60ch;
}
/*  Prose-stack: technical and holistic registers occupy the same grid
 *  cell so only the visible register takes vertical space.  CSS toggles
 *  opacity based on `aside#panel[data-register=...]`; the slider sets
 *  that attribute on threshold cross. The 300ms ease-in-out gives the
 *  threshold a gentle crossfade rather than an instant cut.            */
.class-panel .prose-stack {
  display: grid;
  grid-template-columns: 1fr;
}
.class-panel .prose-stack > .prose {
  grid-column: 1;
  grid-row: 1;
  /*  Default: hidden. JS picks the active prose-* div for the current
   *  register (with fallback through the chain — see PROSE_FALLBACK in
   *  index.html) and sets data-active="true" on it. The active prose
   *  reveals; the others stay hidden. Crossfades on register changes
   *  via the opacity transition. */
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms ease-in-out;
}
.class-panel .prose-stack > .prose[data-active="true"] {
  opacity: 1;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .class-panel .prose-stack > .prose { transition: none; }
}

/* — Active-scrub guard ——————————————————————————————————
 *
 * While the slider is actively being moved (pointer drag, wheel, or
 * keyboard nudge), the plate's per-element CSS transitions fight the
 * continuous input — every ~16ms tick fires a fresh 220-300 ms ease,
 * so the rendered state lags the cursor by hundreds of milliseconds.
 *
 * `body[data-scrubbing="true"]` is set by the slider input handlers
 * for the duration of an interaction (cleared 150 ms after the last
 * input event). During that window we kill transitions and animations
 * on plate elements so the painted state tracks the slider value
 * frame-for-frame. Discrete clicks/dblclick still see the cinematic
 * crossfade because the scrub flag clears between events.            */
body[data-scrubbing="true"] .plate-svg,
body[data-scrubbing="true"] .plate-svg *,
body[data-scrubbing="true"] .plate-wrap,
body[data-scrubbing="true"] .plate-wrap *,
body[data-scrubbing="true"] .slider-rail,
body[data-scrubbing="true"] .slider-rail *,
body[data-scrubbing="true"] .slider-rail::before,
body[data-scrubbing="true"] .slider-rail::after,
body[data-scrubbing="true"] .station-name,
body[data-scrubbing="true"] .masthead-title,
body[data-scrubbing="true"] .masthead-ornament,
body[data-scrubbing="true"] article#stage::before {
  transition: none !important;
  animation-duration: 0s !important;
}

/*  Per-register prose title — the intro section's primary heading,
 *  one per register. Mirrors the original `.class-panel h2`
 *  treatment that "0k.computer" used (ET Book serif, 30px, regular
 *  weight) so each register reads as a section title rather than a
 *  styled tagline. Selector is intro-scoped so other class panels
 *  keep their own heading shape if they ever grow prose-titles. */
.intro .body .prose-title {
  font-family: var(--serif);
  font-weight: 400;
  font-style: normal;
  font-size: 30px;
  letter-spacing: 0.005em;
  line-height: 1.05;
  color: var(--ink);
  margin-bottom: 1.1rem;
}

/*  Holistic-register feature list — gold ✦ bullets, paragraph-spacing
 *  on items so the list reads as a small printed manifesto. Brand-
 *  consistent with the masthead's ✦ ornament and the Decision-stratum
 *  examples list elsewhere on the page. */
.intro .body .intro-features {
  list-style: none;
  margin: 1.1rem 0 1.2rem;
  padding-left: 0.25rem;
}
.intro .body .intro-features li {
  position: relative;
  padding: 0.18rem 0 0.18rem 1.4rem;
  color: var(--ink-2);
  line-height: 1.55;
}
.intro .body .intro-features li::before {
  content: '✦';
  position: absolute;
  left: 0;
  top: 0.42rem;
  font-size: 0.7rem;
  line-height: 1;
  color: var(--color-gold);
  text-shadow: 0 0 4px rgba(240, 196, 104, 0.30);
}

/*  Transcendental-register epigraph — IM Fell English italic, slightly
 *  larger and more spacious than ordinary body prose so the Chardin
 *  quote reads as set-apart. Attribution beneath in roman small caps
 *  feel via letter-spacing. */
.intro .body .intro-epigraph {
  font-family: 'IM Fell English', var(--serif);
  font-style: italic;
  font-size: 1.18rem;
  line-height: 1.65;
  color: var(--ink);
  margin: 1.4rem 0 0.6rem;
  max-width: 50ch;
}
.intro .body .intro-epigraph-attribution {
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.95rem;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  margin-top: 0.2rem;
}

.class-panel .body p { margin-bottom: 0.8rem; }
.class-panel .body p + p { text-indent: 1.2em; }
.class-panel .body p:first-child { text-indent: 0; }
.class-panel .body strong { font-weight: 700; color: var(--ink); }
.class-panel .body em { font-style: italic; }
.class-panel .body code {
  font-family: var(--mono);
  font-size: 0.85em;
  background: var(--paper-warm);
  padding: 0 4px;
  color: var(--ink-2);
}
/*  Embodiment block — the "where this lives in code" anchor surfaced
 *  at the top of the technical prose. Visible at low poeticism where
 *  the embodiment is load-bearing. Density-rich: each ontology
 *  concept's matched code symbols, grouped by crate, with the primary
 *  anchor flagged. Visually a tight monospace block, scrollable when
 *  long so it doesn't push prose past the fold.                       */
.class-panel .body .embodiment-block {
  margin: 0 0 1rem;
  padding: 0.5rem 0.7rem;
  border-left: 2px solid var(--ink-quiet);
  background: var(--paper-warm);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-2);
  max-height: 540px;
  overflow-y: auto;
}
/*  Type-graph subgraph — small SVG above the crate-grouped symbol
 *  list. Tufte-clean: thin lines, sparse labels, no fills beyond
 *  paper-warm. Each node kind gets a different glyph (square /
 *  hexagon / circle / dashed-circle). Cross-concept gateway nodes
 *  are stroked in their target concept's register colour, so the
 *  reader can spot which types bridge to other parts of the
 *  ontology at a glance.                                            */
.class-panel .body .embodiment-typegraph {
  margin: 0 0 0.7rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px dotted var(--rule);
}
.class-panel .body .embodiment-typegraph .tg-svg {
  display: block;
  width: 100%;
  max-height: 220px;
  overflow: visible;
}
.class-panel .body .embodiment-typegraph .tg-glyph {
  fill: var(--paper-warm);
  stroke: var(--ink-2);
  stroke-width: 1.1;
}
.class-panel .body .embodiment-typegraph .tg-glyph-extern {
  fill: var(--paper);
  stroke: var(--ink-quiet);
  stroke-dasharray: 2 2;
  stroke-width: 1;
}
.class-panel .body .embodiment-typegraph .tg-node-cross .tg-glyph {
  stroke: var(--cross-stroke);
  stroke-width: 1.6;
}
.class-panel .body .embodiment-typegraph .tg-node-label {
  font-family: var(--mono);
  font-size: 10px;
  fill: var(--ink-2);
  letter-spacing: 0.01em;
  pointer-events: none;
}
.class-panel .body .embodiment-typegraph .tg-node-cross .tg-node-label {
  fill: var(--cross-stroke);
}
.class-panel .body .embodiment-typegraph .tg-edge {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 0.9;
}
.class-panel .body .embodiment-typegraph .tg-edge-implements_trait,
.class-panel .body .embodiment-typegraph .tg-edge-type_alias_resolves_to {
  stroke: var(--ink-3);
}
.class-panel .body .embodiment-typegraph .tg-edge-implements_for_type {
  stroke: var(--ink-2);
  stroke-width: 1.1;
}
.class-panel .body .embodiment-typegraph .tg-edge-label {
  font-family: var(--mono);
  font-size: 8.5px;
  font-style: italic;
  /* WCAG AA: text labels use --ink-3 (~5.5:1) not --ink-quiet (~2.4:1). */
  fill: var(--ink-3);
  pointer-events: none;
}
.class-panel .body .embodiment-typegraph .tg-node {
  cursor: default;
}

.class-panel .body .embodiment-summary {
  font-family: var(--serif);
  font-size: 13px;
  color: var(--ink-3);
  margin-bottom: 0.5rem;
  font-style: italic;
}
.class-panel .body .embodiment-summary .embodiment-count {
  font-family: var(--mono);
  font-style: normal;
  color: var(--ink-2);
  font-weight: 500;
}
.class-panel .body .embodiment-crate-group {
  margin-bottom: 0.45rem;
}
.class-panel .body .embodiment-crate-group:last-child {
  margin-bottom: 0;
}
.class-panel .body .embodiment-crate-head {
  font-size: 11px;
  color: var(--ink-2);
  font-weight: 500;
  letter-spacing: 0.02em;
  margin-bottom: 0.15rem;
}
.class-panel .body .embodiment-crate-count {
  /* WCAG AA: count text bumped --ink-quiet → --ink-3. */
  color: var(--ink-3);
  font-weight: 400;
  margin-left: 0.4em;
}
.class-panel .body .embodiment-symbol-list {
  list-style: none;
  padding: 0;
  margin: 0 0 0 0.5rem;
}
.class-panel .body .embodiment-symbol {
  padding: 0.05rem 0;
  display: grid;
  grid-template-columns: max-content max-content 1fr;
  gap: 0.4em;
  align-items: baseline;
  white-space: nowrap;
  overflow: hidden;
}
.class-panel .body .embodiment-symbol.primary {
  color: var(--ink);
}
.class-panel .body .embodiment-primary-mark {
  color: var(--accent);
  margin-right: 0.2em;
  font-size: 0.85em;
  display: inline-block;
  width: 0.7em;
}
.class-panel .body .embodiment-kind {
  /* WCAG AA: kind label is meaningful text, bump --ink-quiet → --ink-3. */
  color: var(--ink-3);
  font-style: italic;
  font-size: 0.85em;
  min-width: 3.5em;
}
.class-panel .body .embodiment-name {
  color: var(--ink-2);
  font-weight: 500;
}
.class-panel .body .embodiment-symbol.primary .embodiment-name {
  color: var(--ink);
}
.class-panel .body .embodiment-loc {
  /* WCAG AA: file-path text bumped --ink-quiet → --ink-3. */
  color: var(--ink-3);
  font-size: 0.85em;
  text-overflow: ellipsis;
  overflow: hidden;
  min-width: 0;
}

.class-panel .body blockquote {
  margin: 0.8rem 0;
  padding: 0.1rem 0 0.1rem 1rem;
  border-left: 2px solid var(--accent);
  color: var(--ink-2);
  font-style: italic;
}
.class-panel .body blockquote p { margin-bottom: 0.4rem; }
.class-panel .body a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--accent-soft);
}
.class-panel .body a:hover { border-bottom-color: var(--accent); }

.class-panel dl.meta {
  margin-top: 1.4rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--rule);
  font-size: 14px;
}
.class-panel dl.meta dt {
  font-variant: small-caps;
  letter-spacing: 0.1em;
  font-size: 10.5px;
  color: var(--ink-3);
  margin-top: 0.85rem;
}
.class-panel dl.meta dt:first-child { margin-top: 0; }
.class-panel dl.meta dd {
  color: var(--ink-2);
  line-height: 1.55;
  margin-top: 0.15rem;
}
.class-panel dl.meta ul { list-style: none; padding: 0; }
.class-panel dl.meta ul li {
  padding: 0.18rem 0;
  border-bottom: 1px dotted var(--rule);
}
.class-panel dl.meta ul li:last-child { border-bottom: 0; }
.class-panel dl.meta li code,
.class-panel dl.meta li .pred {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  letter-spacing: 0.01em;
}
.class-panel a.class-link {
  font-family: var(--serif);
  font-style: italic;
  color: var(--accent);
  cursor: pointer;
  border-bottom: 1px solid var(--accent-soft);
  text-decoration: none;
}
.class-panel a.class-link:hover { border-bottom-color: var(--accent); }
.class-panel .arrow {
  /* WCAG AA: arrow glyph carries meaning ("relates to"); bump for legibility. */
  color: var(--ink-3);
  font-style: italic;
  margin: 0 0.35em;
}

/*  Per-class Architecture decisions block (Phase 2). Sits below the
 *  meta dl, surfacing the ADRs that ground this class. Section is
 *  only rendered when the manifest has an `adrs` entry; absence is
 *  silent. Heading styled in IM Fell English italic to echo the
 *  frontispiece register; list items in serif with .adr-link reusing
 *  the .class-link visual idiom (italic accent, soft underline).      */
.class-panel .class-architecture-decisions {
  margin-top: 1.4rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--rule);
}
.class-panel .class-architecture-decisions .adr-heading {
  font-family: var(--display, "IM Fell English", var(--serif));
  font-style: italic;
  font-weight: normal;
  font-size: 16px;
  color: var(--ink-2);
  margin: 0 0 0.5rem 0;
  letter-spacing: 0.01em;
}
.class-panel .class-architecture-decisions .adr-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.class-panel .class-architecture-decisions .adr-list li {
  font-family: var(--serif);
  font-size: 14px;
  padding: 0.18rem 0;
  border-bottom: 1px dotted var(--rule);
}
.class-panel .class-architecture-decisions .adr-list li:last-child {
  border-bottom: 0;
}
.class-panel .class-architecture-decisions a.adr-link {
  font-family: var(--serif);
  font-style: italic;
  color: var(--accent);
  border-bottom: 1px solid var(--accent-soft);
  text-decoration: none;
}
.class-panel .class-architecture-decisions a.adr-link:hover {
  border-bottom-color: var(--accent);
}

/* — Edge popover ———————————————————————————————————— */

#edge-popover {
  position: fixed;
  background: var(--paper);
  border: 1px solid var(--ink);
  box-shadow: 4px 4px 0 var(--rule-faint);
  color: var(--ink);
  padding: 0.55rem 0.8rem;
  font-family: var(--serif);
  font-size: 13px;
  line-height: 1.5;
  max-width: 32ch;
  pointer-events: none;
  display: none;
  z-index: 10;
}
#edge-popover .pred-name {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent);
  display: block;
  margin-bottom: 0.2rem;
  letter-spacing: 0.02em;
}

/* — Appendix block — state-driven, NOT inline ————————————————
 * The appendix is a sibling of `.prose-stack` inside the panel's
 * `.body`. It's hidden by default; visible only when the slider is
 * in substrate territory (t < 0.12), via body[data-substrate="true"].
 * In that state, the chapter prose-stack is hidden and the appendix
 * takes its place. The visitor reaches the appendix by scrubbing the
 * slider to its leftmost position — clicking the "How it works /
 * embodied" station, dragging the thumb left, or pressing arrow keys
 * past Chapter I. */

.appendix-block {
  display: none;
  padding-top: 1rem;
  position: relative;
}
body[data-substrate="true"] .appendix-block {
  display: block;
}
body[data-substrate="true"] .class-panel.intro .prose-stack {
  display: none;
}
/* Smooth fade-in when entering appendix; instant hide on leave */
.appendix-block {
  animation: appendix-reveal 320ms ease-out 60ms backwards;
}
@keyframes appendix-reveal {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .appendix-block { animation: none; }
}

.appendix-rule {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 7px;
  margin: 0 auto 1rem;
  width: min(720px, 80%);
}
.appendix-rule::before,
.appendix-rule::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 1px;
  background: linear-gradient(to right,
    transparent 0%,
    var(--rule) 8%,
    var(--rule) 92%,
    transparent 100%);
}
.appendix-rule::before { top: 1px; }
.appendix-rule::after  { bottom: 1px; opacity: 0.55; height: 0.6px; }

.appendix-ornament {
  position: relative;
  z-index: 2;
  display: inline-block;
  background: var(--paper);
  padding: 0 14px;
  font-family: 'IM Fell English', var(--serif);
  font-size: 13px;
  line-height: 1;
  color: var(--color-gold);
  text-shadow: 0 0 4px rgba(240, 196, 104, calc(var(--painted-opacity, 0) * 0.5 + 0.18));
}

.appendix-heading {
  font-family: 'IM Fell English', var(--serif);
  font-style: italic;
  font-size: 24px;
  color: var(--ink);
  text-align: center;
  margin: 0 0 0.25rem;
  font-weight: 400;
}

.appendix-subheading {
  font-family: var(--serif);
  font-style: normal;
  font-size: 16px;
  color: var(--ink-2);
  text-align: center;
  margin: 0 0 1.5rem;
  letter-spacing: 0.01em;
  font-weight: 400;
}

/* — Appendix two-register toggle ——————————————————————————————— */

.appendix-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  margin: 0 auto 1.5rem;
}

.appendix-toggle-button {
  font-family: 'IM Fell English', var(--serif);
  font-style: italic;
  font-size: 14px;
  line-height: 1;
  color: var(--ink-3);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 0.4rem 1rem;
  cursor: pointer;
  letter-spacing: 0.01em;
  transition:
    color 240ms ease,
    background 240ms ease,
    border-color 240ms ease,
    text-shadow 280ms ease;
}
.appendix-toggle-button:hover {
  color: var(--ink-2);
  border-color: var(--ink-3);
}
.appendix-toggle-button[aria-selected="true"] {
  color: var(--ink);
  font-style: normal;
  font-weight: 400;
  background: rgba(255, 247, 200, 0.35);
  border-color: var(--color-gold);
  text-shadow:
    0 0 4px rgba(240, 196, 104, 0.55),
    0 0 8px rgba(240, 196, 104, 0.25);
}
.appendix-toggle-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.appendix-toggle-fleuron {
  font-family: 'IM Fell English', var(--serif);
  font-size: 14px;
  color: var(--ink-quiet);
  padding: 0 12px;
  user-select: none;
  text-shadow: 0 0 4px rgba(240, 196, 104, calc(var(--painted-opacity, 0) * 0.4 + 0.15));
}

/* — Appendix prose blocks (two registers) —————————————————————— */

.appendix-prose {
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.7;
  color: var(--ink-2);
  max-width: 640px;
  margin: 0 auto;
  transition: opacity 280ms ease;
}
.appendix-prose p {
  margin: 0 0 1rem;
}
.appendix-prose p:last-child {
  margin-bottom: 0;
}
.appendix-prose code {
  font-family: var(--mono);
  font-size: 0.85em;
  color: var(--ink);
  background: rgba(184, 142, 68, 0.08);
  padding: 0.05em 0.3em;
  border-radius: 2px;
  letter-spacing: 0.01em;
}
.appendix-prose a {
  color: var(--accent);
  border-bottom: 1px solid var(--accent-soft);
  text-decoration: none;
}
.appendix-prose a:hover {
  border-bottom-color: var(--accent);
}

/*  Toggle visibility — only one register visible at a time. Default
 *  is overview; technical is hidden via the `hidden` attribute and
 *  shown via body[data-appendix-register="technical"].               */
.appendix-prose-technical[hidden] {
  display: none;
}
body[data-appendix-register="technical"] .appendix-prose-overview {
  display: none;
}
body[data-appendix-register="technical"] .appendix-prose-technical {
  display: block;
}

/*  The technical register is denser and benefits from slightly tighter
 *  leading.                                                            */
.appendix-prose-technical {
  font-size: 15px;
  line-height: 1.6;
}

/* — Phase-3 Wave B: appendix browseable catalogs ——————————————————
 *
 * Two browseable lists at the bottom of the appendix:
 *   .appendix-affordances → what the system offers (with spec status)
 *   .appendix-modules     → what implements the system (crates)
 * Both render as a column of cards inside the existing appendix-block,
 * carrying the same engraved/serif register as the rest of the
 * appendix. Status badges in the affordance section are color-coded
 * by spec health (passing/failing/unknown).                           */

.appendix-affordances,
.appendix-modules {
  max-width: 640px;
  margin: 1.8rem auto 0;
}

.appendix-section-heading {
  font-family: 'IM Fell English', var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 19px;
  color: var(--ink);
  text-align: center;
  margin: 0 0 0.25rem;
  letter-spacing: 0.01em;
}

.appendix-section-lede {
  font-family: var(--serif);
  font-size: 14px;
  font-style: italic;
  color: var(--ink-3);
  text-align: center;
  margin: 0 0 1rem;
  line-height: 1.5;
}

.appendix-placeholder {
  font-family: var(--serif);
  font-style: italic;
  font-size: 14px;
  color: var(--ink-3);
  text-align: center;
  padding: 0.8rem 1rem;
  border: 1px dotted var(--rule);
}

.affordance-list,
.module-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.65rem;
}

.affordance-card,
.module-card {
  position: relative;
  padding: 0.7rem 0.9rem;
  background: var(--paper);
  border: 1px solid rgba(184, 142, 68, 0.45);
  box-shadow: inset 0 0 0 1px rgba(255, 247, 200, 0.35);
  font-family: var(--serif);
  color: var(--ink-2);
}

.affordance-card h4,
.module-card h4 {
  font-family: 'IM Fell English', var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 16px;
  color: var(--ink);
  margin: 0 0 0.25rem;
  letter-spacing: 0.01em;
}

.affordance-card p,
.module-card p {
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0 0 0.35rem;
}
.affordance-card p:last-of-type,
.module-card p:last-of-type {
  margin-bottom: 0.35rem;
}

.affordance-card .affordance-title {
  font-style: italic;
  color: var(--ink);
}
.affordance-card .affordance-description {
  color: var(--ink-2);
}

.affordance-status {
  display: inline-block;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  padding: 0.12rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: var(--paper-warm);
  color: var(--ink-3);
  text-transform: lowercase;
}
.affordance-status[data-status="passing"] {
  color: #2f6b3a;
  border-color: rgba(74, 110, 58, 0.55);
  background: rgba(74, 110, 58, 0.08);
}
.affordance-status[data-status="failing"] {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: rgba(178, 34, 34, 0.06);
}
.affordance-status[data-status="unknown"] {
  color: var(--ink-quiet);
  border-color: var(--rule);
}

.module-classes {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.01em;
  margin-top: 0.2rem;
}

.appendix-affordances code,
.appendix-modules code {
  font-family: var(--mono);
  font-size: 0.85em;
  color: var(--ink);
  background: rgba(184, 142, 68, 0.08);
  padding: 0.05em 0.3em;
  border-radius: 2px;
  letter-spacing: 0.01em;
}

/* — Footer ————————————————————————————————————————— */

/*  Footer — small brand mark + centered "Get in touch" line. The
 *  mark sits to the left of the contact text, scaled to roughly
 *  match cap-height so the line reads as one composed unit. */
footer.colophon-foot {
  padding: 0.85rem 2.2rem;
  border-top: 1px solid var(--rule);
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink-2);
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
}
footer.colophon-foot .colophon-mark {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  /*  Invert: the brand icon is white-on-black; flipped here to
   *  black-on-white so it reads on the paper-cream footer.
   *  multiply blend then drops the icon's now-white background to
   *  paper, leaving just the dark slashed-Ø linework. */
  filter: invert(1);
  mix-blend-mode: multiply;
  opacity: 0.85;
}
footer.colophon-foot .contact {
  font-size: 16px;
}
footer.colophon-foot .contact a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 0.5px solid var(--rule);
  transition: color 200ms ease, border-color 200ms ease;
}
footer.colophon-foot .contact a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* — Chapter-nav chevrons (desktop only) ————————————————————
 *
 * Two circular gold-ring chevron buttons positioned at the bottom
 * corners of aside#panel, sequencing the visitor through Chapters
 * I, II, III. Same visual vocabulary as .landing-scroll-cue but
 * smaller. Hidden in substrate (no chapter nav for appendix) and
 * on mobile (mobile uses chip strip + scroll).                      */
.chapter-nav {
  position: absolute;
  bottom: 1.5rem;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1;
  color: #8b6e3a;
  text-decoration: none;
  border-radius: 50%;
  border: 1px solid rgba(184, 142, 68, 0.55);
  box-shadow:
    inset 0 0 0 3px rgba(255, 247, 200, 0.2),
    0 0 14px rgba(240, 196, 104, 0.18);
  background: rgba(255, 247, 220, 0.35);
  text-shadow: 0 0 6px rgba(240, 196, 104, 0.5);
  cursor: pointer;
  z-index: 5;
  transition:
    color 220ms ease,
    border-color 220ms ease,
    background 220ms ease,
    box-shadow 240ms ease,
    opacity 220ms ease;
}
.chapter-nav-prev {
  left: 1.25rem;
}
.chapter-nav-next {
  right: 1.25rem;
}
.chapter-nav:hover {
  color: #1a1611;
  border-color: rgba(240, 196, 104, 0.9);
  background: rgba(255, 247, 200, 0.6);
  box-shadow:
    inset 0 0 0 3px rgba(255, 247, 200, 0.32),
    0 0 22px rgba(240, 196, 104, 0.4);
}
.chapter-nav:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.chapter-nav[hidden] {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .chapter-nav { transition: opacity 0s, color 0s, background 0s; }
}

/* Hide on mobile via the existing breakpoint. */
@media (max-width: 720px) {
  .chapter-nav { display: none !important; }
}

