/* penname — structural web theme. Warm paper in the DuJardin Consulting
   palette: coffee-brown text and structure on invoice off-white, copper
   and slate as the two accent voices, moss/rust for verdicts — a
   playground-for-ideas register, not a terminal. Projects append a theme
   that defines their figure vocabulary and may re-point the tokens; the
   base only ever speaks semantic ones. Three accent roles cover the
   vocabulary-independent chrome: --accent (warm, labels/controls),
   --link (cool, links/kicker), --accent-2 (third voice, code titles).
   The PDF base defines the SAME structure with print values; renderers
   only ever speak tokens. */

:root {
  --bg: #f6f1e6;
  --panel: #efe9da;
  --panel-deep: #e8dfca;
  --border: #d5c9af;
  --border-soft: #e3dac5;
  --text: #453425;
  --text-dim: #6b5a45;
  --text-faint: #8d7c64;
  --text-ghost: #ab9c85;
  --good: #5d7d46;
  --bad: #a8402f;
  --accent: #9c6119;
  --link: #45788c;
  --accent-2: #7c5f88;
  --powder: #a9c6cf;
  --sans: "IBM Plex Sans", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --wrap-w: 1120px;
}

* { box-sizing: border-box; }
html { background: var(--bg); }
body {
  margin: 0;
  color: var(--text);
  font: 400 19px/1.7 var(--sans);
}
.wrap { max-width: var(--wrap-w); margin: 0 auto; padding: 56px 28px 108px; }

/* ── masthead ── */
.kicker {
  font: 500 13px/1 var(--mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--link);
}
.doc-title { font-size: 44px; line-height: 1.15; margin: 14px 0 10px; letter-spacing: -0.01em; }
.byline { color: var(--text-dim); font-size: 16px; }
.byline .author + .author::before { content: " · "; color: var(--text-ghost); }
.affil { color: var(--text-faint); font-size: 14px; }
.byline a { color: var(--text-faint); text-decoration: none; }
.dateline { margin-top: 6px; font: 400 14px var(--mono); color: var(--text-faint); }
.dateline a { color: var(--link); text-decoration: none; }
.doi.pending { color: var(--text-ghost); }
.credit { margin-top: 4px; font-size: 15px; color: var(--text-faint); font-style: italic; }
.abstract {
  margin: 28px 0 8px;
  padding: 22px 26px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  color: var(--text-dim);
  font-size: 17px;
}
.abs-label {
  font: 500 12px var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-right: 8px;
}

/* ── contents (opt-in on the web) ── */
.toc { margin: 28px 0 8px; padding: 20px 24px; background: var(--panel); border: 1px solid var(--border); border-radius: 14px; }
.toc-title { font: 500 12px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); margin-bottom: 10px; }
.toc ol { list-style: none; margin: 0; padding: 0; font-size: 16px; }
.toc li { margin: 4px 0; }
.toc li.toc-2 { margin-left: 18px; }
.toc li.toc-3 { margin-left: 36px; }
.toc a { color: var(--text-dim); text-decoration: none; }
.toc a:hover { color: var(--link); }

/* ── floating contents (toc.web: "float") ──
   One <details> in three geometries, picked by viewport width. Wide: it
   docks in a gutter beside the article; the gutter is reserved whether
   the panel is open or closed, so toggling never moves the text, and the
   closed tab sits where the card's head is, so it opens in place.
   Between: a corner tab that opens a card over the page. Phone: the tab
   sits in the bottom corner and opens a sheet behind a scrim. --toc-mode
   names the geometry so the runtime reads the decision the CSS made
   instead of repeating the breakpoints. Closed, only the tab is there;
   the box itself never takes clicks. The card's background sits on the
   tab and the list rather than the box, so the sheet's scrim (a
   negative-z pseudo-element) can slip between the box and its contents. */
:root { --toc-w: 312px; --toc-gap: 24px; --toc-edge: 20px; }
.toc-float { --toc-mode: overlay; position: fixed; z-index: 40; top: 16px; right: 16px; width: var(--toc-w); max-width: calc(100% - 32px); pointer-events: none; font-size: 15px; }
.toc-float > * { pointer-events: auto; }
.toc-tab {
  display: flex; align-items: center; gap: 8px; margin-left: auto; width: max-content; max-width: 100%;
  list-style: none; cursor: pointer; user-select: none; padding: 8px 14px 8px 16px;
  background: #faf6ec; border: 1px solid var(--border); border-radius: 999px; box-shadow: 0 6px 20px rgba(69, 52, 37, 0.14);
  font: 500 12.5px/1.4 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent);
}
.toc-tab::-webkit-details-marker { display: none; }
.toc-tab:hover { border-color: var(--accent); }
.toc-tab:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.toc-tab-here { color: var(--link); letter-spacing: 0.04em; text-transform: none; max-width: 14ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.toc-tab-here:empty { display: none; }
.toc-tab-here::before { content: "· "; color: var(--text-ghost); }
.toc-tab-mark::before { content: "⌄"; font: 500 14px var(--mono); color: var(--accent); }
.toc-float[open] .toc-tab-mark::before { content: "⌃"; }
/* open: the tab is the card's head */
.toc-float[open] { pointer-events: auto; border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 16px 48px rgba(69, 52, 37, 0.2); overflow: hidden; }
.toc-float[open] .toc-tab { margin: 0; width: auto; border: 0; border-radius: 0; box-shadow: none; background: var(--panel); padding: 13px 18px 11px; }
.toc-float[open] .toc-tab-mark { margin-left: auto; }
.toc-float[open] .toc-tab-here { display: none; }
.toc-progress { height: 2px; background: var(--border-soft); }
.toc-progress-bar { height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 120ms linear; }
.toc-panel { background: var(--panel); }
/* the list scrolls and fades at its edges; the fade is on the scroller,
   not the card, so nothing behind the card shows through the bands */
.toc-list { max-height: calc(100vh - 32px - 48px); overflow-y: auto; overscroll-behavior: contain; padding: 12px 12px 16px; mask-image: linear-gradient(#0000, #000 12px, #000 calc(100% - 14px), #0000); }
.toc-list ol { list-style: none; margin: 0; padding: 0; }
.toc-list ol ol { padding-left: 16px; }
.toc-list a { position: relative; display: flex; gap: 10px; align-items: baseline; padding: 4px 10px 4px 12px; border-radius: 7px; color: var(--text-dim); text-decoration: none; line-height: 1.45; transition: color 120ms; }
.toc-list a::before { content: ""; position: absolute; left: 0; top: 8px; bottom: 8px; width: 2px; border-radius: 2px; background: var(--accent); opacity: 0; transition: opacity 120ms; }
.toc-list a:hover { color: var(--text); background: var(--bg); }
.toc-list li.within > a { color: var(--text); }
/* the current row keeps its weight: bold would rewrap a long title and
   jog every row beneath it */
.toc-list li.current > a { color: var(--text); background: var(--bg); }
.toc-list li.current > a::before { opacity: 1; }
/* the first row is the document itself, and returns to the top */
.toc-list .toc-top > a { color: var(--text); font-weight: 500; margin-bottom: 6px; }
.toc-list .toc-2 > a { font-size: 14.5px; }
.toc-list .toc-3 > a { font-size: 14px; }
.toc-num { flex: 0 0 auto; font: 500 13px var(--mono); color: var(--link); min-width: 18px; }
.toc-2 > a > .toc-num { min-width: 28px; }
.toc-3 > a > .toc-num { min-width: 42px; }
@media (prefers-reduced-motion: no-preference) {
  .toc-float[open] .toc-panel { animation: toc-in 160ms ease-out; }
  @keyframes toc-in { from { opacity: 0; transform: translateY(-6px); } }
  @keyframes toc-up { from { opacity: 0; transform: translateY(8px); } }
}
/* wide: docked in a gutter the page always keeps. The box hugs the
   column's right edge (the page is centered in what the gutter leaves
   it); the closed tab keeps the card's right edge, so the chevron stays
   put across a toggle. */
@media (min-width: 1280px) {
  .toc-float { --toc-mode: dock; top: var(--toc-edge); right: max(var(--toc-edge), calc(50% - var(--wrap-w) / 2 - var(--toc-w) / 2 - var(--toc-gap) / 2 + var(--toc-edge) / 2)); }
  .toc-float[open] { box-shadow: 0 4px 16px rgba(69, 52, 37, 0.08); }
  .toc-float[open] .toc-list { max-height: calc(100vh - 2 * var(--toc-edge) - 48px); }
  body:has(> .toc-float) { padding-right: calc(var(--toc-w) + var(--toc-gap) + var(--toc-edge)); }
}
/* phone: the tab in the bottom corner, the list as a sheet */
@media (max-width: 700px) {
  .toc-float { --toc-mode: sheet; top: auto; left: 12px; right: 12px; bottom: max(12px, env(safe-area-inset-bottom)); width: auto; max-width: none; }
  .toc-tab-mark::before { content: "⌃"; }
  .toc-float[open] .toc-tab-mark::before { content: "⌄"; }
  .toc-float[open] { border-radius: 16px; box-shadow: 0 24px 64px rgba(69, 52, 37, 0.3); }
  .toc-float[open]::before { content: ""; position: fixed; inset: 0; z-index: -1; background: rgba(69, 52, 37, 0.32); }
  .toc-float[open] .toc-list { max-height: min(60vh, calc(100vh - 120px)); }
  .toc-float[open] .toc-panel { animation-name: toc-up; }
}
@media print {
  .toc-float { display: none; }
  body:has(> .toc-float) { padding-right: 0; }
}
/* a jump lands a little below the top edge */
article :is(h1, h2, h3)[id] { scroll-margin-top: 24px; }

/* ── section links: a # after every heading, shown on hover ──
   A click puts the section's address in the URL bar (and, with
   enableHeadingLinks, on the clipboard). Touch screens have no hover, so
   there the mark is faintly always on. */
.h-anchor { margin-left: 0.45em; font: 500 0.72em var(--mono); color: var(--text-ghost); text-decoration: none; opacity: 0; transition: opacity 120ms, color 120ms; vertical-align: 0.08em; }
:is(h1, h2, h3):hover > .h-anchor, .h-anchor:focus-visible { opacity: 1; }
.h-anchor:hover { color: var(--link); }
.h-anchor[data-copied]::after { content: " copied"; font-size: 0.85em; letter-spacing: 0.04em; color: var(--good); }
@media (hover: none) { .h-anchor { opacity: 0.6; } }

/* ── prose ── */
article h1 { font-size: 30px; margin: 56px 0 14px; letter-spacing: -0.01em; }
article h2 { font-size: 23px; margin: 40px 0 12px; letter-spacing: -0.005em; }
article p { margin: 15px 0; }
article strong { color: var(--text); }
article em { color: var(--text-dim); }
article a { color: var(--link); }
a.cite { color: var(--link); text-decoration: none; font-size: 0.85em; vertical-align: super; line-height: 0; }
a.cite.narrative { font-size: 1em; vertical-align: baseline; }
code { font: 400 0.88em var(--mono); background: var(--panel); border: 1px solid var(--border-soft); border-radius: 5px; padding: 1px 5px; }
pre { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 18px 20px; overflow-x: auto; }
pre code { background: none; border: none; padding: 0; font-size: 14.5px; line-height: 1.6; }
article img { max-width: 100%; height: auto; display: block; margin: 24px auto; border-radius: 10px; }
.table-wrap { overflow-x: auto; margin: 22px 0; }
article table { border-collapse: collapse; font-size: 16px; width: 100%; line-height: 1.55; }
article th, article td { border: 1px solid var(--border); padding: 9px 14px; text-align: left; font-variant-numeric: tabular-nums; white-space: nowrap; }
article th { background: var(--panel); color: var(--text-dim); font-weight: 500; }
article tbody tr:nth-child(even) { background: rgba(69, 52, 37, 0.03); }
article blockquote { margin: 15px 0; padding: 2px 18px; border-left: 3px solid var(--border); color: var(--text-dim); }
.katex-display { margin: 20px 0; overflow-x: auto; overflow-y: hidden; padding: 4px 0; }
.katex { font-size: 1.04em; }

/* ── figure chrome ── */
figure.fig {
  margin: 30px 0;
  padding: 24px 24px 18px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow-x: auto;
}
.fig-title { font: 500 14px var(--mono); color: var(--text-dim); margin-bottom: 14px; letter-spacing: 0.02em; }
.fig-note { font-size: 15px; color: var(--text-faint); margin-top: 12px; line-height: 1.6; }
figcaption { font-size: 15px; color: var(--text-faint); margin-top: 10px; }
.chart { width: 100%; height: auto; display: block; }
.panel-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; }
.panel-row > svg { flex: 1 1 46%; min-width: 240px; }

/* svg text labels (shared across vocabularies) */
.ax-label { fill: var(--text-faint); font: 500 11px var(--mono); }
.ax-label.ghost { fill: var(--text-ghost); }
.pt-label { fill: var(--text-dim); font: 500 11px var(--mono); }
.pt-label.small { font-size: 9.5px; }
.pt-label.ghost { fill: var(--text-ghost); }

/* legends */
.leg-row { display: flex; gap: 18px; margin-top: 10px; flex-wrap: wrap; }
.leg { font: 500 13px var(--mono); color: var(--text-dim); display: inline-flex; align-items: center; gap: 6px; }
.leg-swatch { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }
.good { color: var(--good); }
.bad { color: var(--bad); }

/* controls (hydrated figures) */
.ctl-row { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.ctl-label { font: 500 12.5px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); }
.ctl-value { font: 500 13.5px var(--mono); color: var(--accent); min-width: 76px; }
.ctl-text { background: #faf6ec; border: 1px solid var(--border); border-radius: 8px; color: var(--text); font: 400 15px var(--mono); padding: 6px 10px; width: 140px; }
input[type="range"] { accent-color: var(--accent); flex: 1 1 160px; max-width: 320px; }
.btn {
  background: #faf6ec; border: 1px solid var(--border); border-radius: 8px;
  color: var(--accent); font: 500 13.5px var(--mono); padding: 6px 14px; cursor: pointer;
}
.btn:hover { border-color: var(--accent); }
.btn-row { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.btn.active { background: var(--accent); border-color: var(--accent); color: #fbf7ee; }
figure.fig.live { border-color: #cbb98f; }
figure.fig.live .fig-title::after { content: " · live"; color: var(--good); }

/* clock faces (the `clockFace` primitive in svg.ts): layout only — ink is the project's */
.clock-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; justify-content: center; }
.clock-cell { text-align: center; }
.clock-cap { font: 400 11px var(--mono); color: var(--text-ghost); margin-top: 2px; }

/* code folding (hydration wraps long listings). The fade anchors to the
   pre's own clipped box so no half-cut line can peek out beneath it. */
.code-fold { margin: 14px 0; }
.code-fold pre { margin: 0; position: relative; }
.code-fold:not(.open) pre { max-height: 320px; overflow: hidden; }
.code-fold:not(.open) pre::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 84px; background: linear-gradient(rgba(239, 233, 218, 0), var(--panel)); pointer-events: none; border-radius: 0 0 14px 14px; }
.code-fold-btn { display: block; margin: 8px auto 0; }

/* A listing with a marked region: the region shows, the details holds the
   whole file, and once it is open the region hides so nothing prints twice.
   Pure HTML + CSS — the no-JS page folds the same way. */
.listing { margin: 14px 0; }
.listing pre { margin: 0; }
.listing-more > summary { display: block; width: max-content; margin: 8px auto 0; list-style: none; cursor: pointer; }
.listing-more > summary::-webkit-details-marker { display: none; }
.listing-more[open] > summary { margin-bottom: 8px; }
.listing-when-open, .listing-more[open] .listing-when-closed { display: none; }
.listing-more[open] .listing-when-open { display: inline; }
.listing:has(.listing-more[open]) > .listing-region { display: none; }

/* syntax highlighting (highlight.js classes, token colors) */
.hljs-keyword { color: var(--link); }
.hljs-string { color: var(--good); }
.hljs-number { color: var(--accent); }
.hljs-comment { color: var(--text-ghost); font-style: italic; }
.hljs-title, .hljs-title.function_ { color: var(--accent-2); }
.hljs-built_in { color: var(--link); }
.hljs-params { color: var(--text-dim); }
.hljs-literal { color: var(--accent); }
.hljs-operator { color: var(--text-dim); }
.hljs-meta { color: var(--text-faint); }

/* references, footer */
.refs { margin-top: 56px; }
.refs ol { padding-left: 22px; color: var(--text-dim); font-size: 15.5px; }
.refs li { margin: 8px 0; }
.refs a { color: var(--link); word-break: break-all; }
/* a note's glossary follows the references as back matter and takes their
   size; a book's glossary page (the same list) keeps reading size */
.glossary-section dl.glossary { font-size: 15.5px; }
.glossary-section dl.glossary dt { margin-top: 10px; }
.glossary-section dl.glossary dd { font-size: inherit; }
.colophon { margin-top: 72px; padding-top: 18px; border-top: 1px solid var(--border); color: var(--text-ghost); font: 400 13.5px var(--mono); }

/* ── book chrome (landing + chapter pages) ── */
.crumbs { display: flex; gap: 12px; align-items: baseline; font: 500 13.5px var(--mono); color: var(--text-ghost); padding-bottom: 26px; }
.crumbs a { color: var(--link); text-decoration: none; }
.chapter-head { margin-bottom: 8px; }
.chapter-lede { color: var(--text-dim); font-size: 17.5px; max-width: 720px; }
.book-intro { color: var(--text-dim); }
.act { margin-top: 36px; }
.act-label { font: 500 13px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); margin-bottom: 10px; }
.chapter-list { list-style: none; margin: 0; padding: 0; }
.chapter-list li + li { margin-top: 8px; }
.chapter-list a { display: flex; gap: 16px; align-items: baseline; padding: 14px 18px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; text-decoration: none; color: var(--text); }
.chapter-list a:hover { border-color: var(--link); }
.ch-num { font: 500 14px var(--mono); color: var(--link); min-width: 28px; }
.ch-entry { display: flex; flex-direction: column; gap: 3px; }
.ch-title { font-weight: 500; }
.ch-blurb { color: var(--text-faint); font-size: 14.5px; line-height: 1.55; }
.chapter-nav { display: flex; justify-content: space-between; gap: 14px; margin-top: 56px; padding-top: 18px; border-top: 1px solid var(--border); }
.chapter-nav a { display: flex; flex-direction: column; gap: 3px; text-decoration: none; padding: 10px 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel); max-width: 46%; }
.chapter-nav a:hover { border-color: var(--link); }
.chapter-nav .next { text-align: right; margin-left: auto; }
.chapter-nav .dir { font: 500 12px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); }
.chapter-nav .ttl { color: var(--text); font-size: 15.5px; }

@media (max-width: 700px) {
  body { font-size: 17px; }
  .doc-title { font-size: 30px; }
}

/* ── course: unpack folds (:::unpack) ──
   One step down the explanation mipmap. Ships open (print/no-JS get the
   full ladder); enableCourse closes every fold so the dense prose reads
   clean, and the chevron is the one consistent "there is more beneath
   this" mark. The left padding is constant so opening never reflows the
   summary line. */
details.unpack { margin: 0.9em 0; border-left: 3px solid transparent; padding-left: 1.05em; }
details.unpack[open] { border-left-color: var(--border); }
details.unpack details.unpack[open] { border-left-color: var(--border-soft); }
details.unpack > summary { cursor: pointer; padding: 0.1em 0; list-style: none; color: var(--text-dim); font-size: 0.96em; }
details.unpack > summary::-webkit-details-marker { display: none; }
details.unpack > summary:hover { color: var(--text); }
.unpack-mark::before { content: "⌄"; font: 500 13px var(--mono); color: var(--accent); margin-right: 9px; display: inline-block; }
details.unpack[open] > summary .unpack-mark::before { content: "⌃"; }
.unpack-body { font-size: 0.97em; }
.unpack-body > p:first-child { margin-top: 6px; }

/* ── course: concept units (:::concept) ── */
section.concept { margin: 30px 0; }
details.concept-fold { background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 14px; padding: 6px 22px; }
summary.concept-head, div.concept-head { cursor: pointer; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 9px 0; list-style: none; }
.concept-head::-webkit-details-marker { display: none; }
.concept-kicker { font: 500 11px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.concept-head .concept-title { font-weight: 600; }
.concept-gist { color: var(--text-faint); font-size: 15px; flex: 1 1 auto; }
details.concept-fold[open] > .concept-head { border-bottom: 1px solid var(--border-soft); margin-bottom: 0.6em; }
.concept-body { font-size: 0.97em; }
.concept-requires { font-size: 14.5px; color: var(--text-faint); margin-top: 4px; }
.concept-requires .req { color: var(--text-dim); }
.concept-stub { padding: 10px 16px; background: var(--panel); border: 1px solid var(--border-soft); border-radius: 10px; font-size: 15.5px; color: var(--text-dim); }
.concept-stub .concept-kicker { margin-right: 4px; }
a.concept-back { color: var(--link); text-decoration: none; }

/* ── course, callout mode: concepts as a knowledge base ──
   Every mention is the same collapsed card; a run of them is a strip of
   chips, and an open chip takes the row. A practiced concept carries its
   best round on the summary. */
.concepts { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; margin: 22px 0; }
details.concept.callout { background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 12px; padding: 0 16px; flex: 0 1 auto; max-width: 100%; }
details.concept.callout:hover { border-color: var(--accent); border-left-color: var(--accent); }
details.concept.callout[open], .concepts > details.concept.callout:only-child { flex-basis: 100%; }
.concepts > details.concept.callout:not([open]):not(:only-child) > summary .concept-gist { display: none; }
details.concept.callout > summary.concept-head { padding: 8px 0; }
details.concept.callout > summary.concept-head::after { content: "⌄"; font: 500 13px var(--mono); color: var(--accent); margin-left: auto; }
details.concept.callout[open] > summary.concept-head::after { content: "⌃"; }
details.concept.callout[open] > .concept-head { border-bottom: 1px solid var(--border-soft); margin-bottom: 0.6em; }
details.concept.callout > .concept-body { padding-bottom: 8px; }
/* nesting alternates the background instead of adding depth: a card inside a
   card sits on the page color, and one inside that is back on the panel */
.concept-body details.concept.callout { background: var(--bg); border-left-color: var(--link); }
.concept-body .concept-body details.concept.callout { background: var(--panel); border-left-color: var(--accent); }
.concept-body .concept-body .concept-body details.concept.callout { background: var(--bg); border-left-color: var(--link); }
.concept-body .concepts { margin: 16px 0; }
.concept-body details.unpack { padding-left: 0.8em; }
.concept-mark { font: 500 12px var(--mono); color: var(--good); }
details.concept.callout.practiced { border-left-color: var(--good); }
.concept-page-link { font-size: 14px; }
.concept-page-link a, a.concept-link { color: var(--link); text-decoration: none; }
.concept-ref { display: none; }
.concept-entry-head .concept-kicker { display: block; margin-bottom: 4px; }
.concept-entry-title { margin: 0 0 6px; }
.concept-entry-head .concept-gist { font-size: 18px; color: var(--text-dim); margin: 0 0 8px; }
.concept-used { font-size: 14.5px; color: var(--text-faint); margin-top: 4px; }
.concept-used a { color: var(--link); text-decoration: none; }
.concept-page .concept-body { font-size: 1em; }

/* ── course: worksheets + the practice takeover ── */
section.worksheet { margin: 18px 0 6px; padding: 12px 16px; background: var(--bg); border: 1px dashed var(--border); border-radius: 10px; }
section.worksheet.practiced { border-style: solid; border-color: var(--good); }
.ws-head { font: 500 11.5px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); }
.ws-key-note { display: none; }
.ws-list { font-size: 16px; color: var(--text-dim); padding-left: 22px; }
.ws-choices { list-style: lower-alpha; font-size: 15px; padding-left: 20px; }
.ws-space { display: none; }
.ws-entry { display: flex; gap: 14px; align-items: center; margin-top: 10px; flex-wrap: wrap; }
.ws-mastery { font: 500 13px var(--mono); color: var(--good); }
/* The session is a dialog over the dimmed page, not a page of its own:
   the reading context stays visible behind a soft scrim, so entering and
   leaving practice reads as a focus shift, not a scene change. */
.study-mode { position: fixed; inset: 0; background: rgba(69, 52, 37, 0.32); backdrop-filter: blur(2.5px); -webkit-backdrop-filter: blur(2.5px); z-index: 50; overflow-y: auto; padding: 7vh 20px 48px; }
.study-panel { max-width: 660px; margin: 0 auto; background: var(--bg); border: 1px solid var(--border); border-radius: 16px; box-shadow: 0 24px 64px rgba(69, 52, 37, 0.3); padding: 24px 28px 28px; }
@media (prefers-reduced-motion: no-preference) {
  .study-panel { animation: study-in 150ms ease-out; }
  @keyframes study-in { from { opacity: 0; transform: translateY(8px); } }
}
.study-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; border-bottom: 1px solid var(--border); padding-bottom: 16px; }
.study-kicker { font: 500 12px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.study-title { font-size: 27px; font-weight: 600; letter-spacing: -0.01em; }
.study-dots { display: flex; gap: 8px; margin: 20px 0; }
.study-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--panel-deep); border: 1px solid var(--border); }
.study-dot.now { border-color: var(--accent); background: var(--panel); }
.study-dot.right { background: var(--good); border-color: var(--good); }
.study-dot.helped { background: var(--accent); border-color: var(--accent); }
.study-dot.shown { background: var(--bad); border-color: var(--bad); }
.study-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 24px 26px; }
.study-prompt { font-size: 19px; }
.study-answer { margin: 18px 0 6px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.study-input { width: 190px; font-size: 17px; }
.study-unit { color: var(--text-faint); font: 400 15px var(--mono); }
.study-feedback { min-height: 24px; margin: 10px 0 4px; font: 500 15px var(--mono); }
.study-feedback.ok { color: var(--good); }
.study-feedback.bad { color: var(--bad); }
.study-feedback.warn { color: var(--accent); }
.study-hint { color: var(--text-dim); font-weight: 400; font-family: var(--sans); }
.study-explain { color: var(--text-dim); font: 400 15.5px var(--sans); margin-top: 10px; line-height: 1.6; }
.study-actions { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
.study-summary { font-size: 22px; font-weight: 600; margin-bottom: 16px; }

/* ── course: landing-page concept index ── */
.concept-index .concept-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 8px; }
.concept-index a { display: flex; flex-direction: column; gap: 2px; padding: 12px 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; text-decoration: none; color: var(--text); }
.concept-index a:hover { border-color: var(--link); }
.concept-index .concept-title { font-weight: 500; }
.concept-index .concept-gist { font-size: 14px; line-height: 1.5; }
.concept-index .concept-where { font: 500 12px var(--mono); color: var(--text-ghost); margin-top: 4px; }

/* ── background folds (:::background) ── */
details.bg { margin: 1.4em 0; border: 1px solid var(--border); border-radius: 8px; padding: 0.15em 1.1em; }
details.bg > summary { cursor: pointer; font-weight: 600; padding: 0.55em 0; }
details.bg > summary::marker { content: "▸ "; }
details.bg[open] > summary::marker { content: "▾ "; }
details.bg[open] > summary { border-bottom: 1px solid var(--border-soft); margin-bottom: 0.7em; }
.sec-ref { text-decoration: none; border-bottom: 1px dotted currentColor; }

/* ── panel layout: a left nav on every page (layout: "panel") ── */
body.panel { display: grid; grid-template-columns: 272px minmax(0, 1fr); min-height: 100vh; }
nav.side { position: sticky; top: 0; height: 100vh; overflow-y: auto; padding: 26px 20px 40px; border-right: 1px solid var(--border); background: var(--panel); font-size: 14.5px; }
body.panel .content { min-width: 0; }
body.panel .wrap { max-width: 980px; padding: 44px 40px 108px; }
.side-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; }
.side-brand { font: 600 20px var(--sans); color: var(--text); text-decoration: none; }
.side-kicker { flex-basis: 100%; font: 500 10.5px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--link); margin: -2px 0 14px; }
.side-toggle { display: none; margin-left: auto; }
.side-search { position: relative; margin-bottom: 10px; }
.side-search-input { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; color: var(--text); font: 400 14px var(--sans); padding: 7px 10px; }
.side-search-input:focus { outline: none; border-color: var(--link); }
.side-results { position: absolute; z-index: 20; left: 0; right: 0; top: calc(100% + 4px); background: var(--bg); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 12px 32px rgba(69, 52, 37, 0.18); max-height: 60vh; overflow-y: auto; }
.side-results a { display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; text-decoration: none; color: var(--text); border-bottom: 1px solid var(--border-soft); }
.side-results a:last-child { border-bottom: 0; }
.side-results a:hover { background: var(--panel); }
.sr-kind { font: 500 10.5px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.sr-title { font-weight: 500; }
.sr-snip { font-size: 12.5px; color: var(--text-faint); line-height: 1.45; }
.sr-none { padding: 10px 12px; color: var(--text-faint); font-size: 13px; }
.side-group { margin-top: 16px; }
.side-label { font: 500 11px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
details.side-details > summary.side-label { cursor: pointer; list-style: none; }
details.side-details > summary.side-label::-webkit-details-marker { display: none; }
details.side-details > summary.side-label::after { content: " ⌄"; }
details.side-details[open] > summary.side-label::after { content: " ⌃"; }
nav.side ol, nav.side ul { list-style: none; margin: 6px 0 0; padding: 0; }
nav.side li a { display: flex; gap: 8px; align-items: baseline; padding: 4px 8px; border-radius: 6px; color: var(--text-dim); text-decoration: none; line-height: 1.4; }
nav.side li a:hover { background: var(--panel-deep); color: var(--text); }
nav.side li a[aria-current="page"] { background: var(--bg); color: var(--text); font-weight: 500; }
nav.side .num { font: 500 12px var(--mono); color: var(--link); min-width: 22px; }
@media (max-width: 900px) {
  body.panel { display: block; }
  nav.side { position: static; height: auto; border-right: 0; border-bottom: 1px solid var(--border); padding: 16px 20px; }
  .side-toggle { display: inline-block; }
  .side-lists { display: none; }
  body.nav-open .side-lists { display: block; }
  body.panel .wrap { padding: 28px 22px 80px; }
}

/* ── glossary: marked terms, the popover, a book's optional swap ──
   A known term gets a faint tint and the help cursor, nothing louder:
   the reader who knows the word reads past it. */
.term { background: color-mix(in srgb, var(--link) 5%, transparent); border-radius: 3px; padding: 0 2px; margin: 0 -2px; cursor: help; transition: background 120ms; }
.term:hover { background: color-mix(in srgb, var(--link) 13%, transparent); }
body.nicknames .term { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.term-pop { position: absolute; z-index: 60; background: var(--bg); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 14px 40px rgba(69, 52, 37, 0.22); padding: 12px 14px 12px; font-size: 14.5px; line-height: 1.5; color: var(--text); }
.tp-term { font-weight: 600; }
.tp-plain { font: 500 12.5px var(--mono); color: var(--accent); margin: 2px 0 6px; }
.tp-explain { margin: 0 0 10px; color: var(--text-dim); }
.tp-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.tp-actions a { color: var(--link); text-decoration: none; font-size: 13.5px; }
.tp-swap { font-size: 12px; }
.side-plain { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; margin: 22px 0 0; font-size: 13.5px; color: var(--text-dim); cursor: pointer; }
.side-plain-note { flex-basis: 100%; font-size: 12px; color: var(--text-ghost); }
dl.glossary { margin: 8px 0; }
dl.glossary dt { font-weight: 600; margin-top: 18px; }
dl.glossary dt .nick { font: 500 12.5px var(--mono); color: var(--accent); margin-left: 10px; }
dl.glossary dd { margin: 4px 0 0; color: var(--text-dim); font-size: 16.5px; }

a.chapter-ref { color: var(--link); text-decoration: none; border-bottom: 1px dotted currentColor; }

/* ── project theme ── */

/* Hill Space — web theme over the penname base. The base carries the
   DJC paper palette and scale; this file is the hill vocabulary:
   copper = tanh (sign), slate = sigmoid (magnitude gate), plum = the
   composed weight W. The PDF theme defines the SAME token names with
   print values; renderers only ever speak tokens. */

:root {
  --tanh: var(--accent);
  --sigmoid: var(--link);
  --weight: var(--accent-2);
}

/* section headers: top-level sections announce themselves — larger type,
   a hairline rule, and asymmetric spacing (big above, small below) so they
   read as chapter breaks instead of blending into the subsections. */
article h1 { font-size: 30px; margin: 72px 0 14px; padding-top: 28px; border-top: 1px solid var(--border); }
article h1:first-child { margin-top: 40px; }

/* svg vocabulary */
.line-tanh { stroke: var(--tanh); stroke-width: 2; }
.line-sigmoid { stroke: var(--sigmoid); stroke-width: 2; }
.line-weight { stroke: var(--weight); stroke-width: 2; }
.line-good { stroke: var(--good); stroke-width: 2; }
.line-bad { stroke: var(--bad); stroke-width: 2; }
.line-ghost { stroke: var(--text-ghost); stroke-width: 1.4; stroke-dasharray: 5 5; }
.line-axis { stroke: var(--text-ghost); stroke-width: 1; }
.dot-tanh { fill: var(--tanh); }
.dot-sigmoid { fill: var(--sigmoid); }
.dot-weight { fill: var(--weight); }
.dot-bad { fill: var(--bad); }
.ring-target { fill: none; stroke: var(--text-ghost); stroke-width: 1.4; }
.bar-tanh { fill: var(--tanh); }
.bar-sigmoid { fill: var(--sigmoid); }
.bar-weight { fill: var(--weight); }
.bar-ghost { fill: var(--text-ghost); }
.bar-bad { fill: var(--bad); }

/* legend swatches for this vocabulary */
.leg-swatch.bar-tanh { background: var(--tanh); }
.leg-swatch.bar-sigmoid { background: var(--sigmoid); }
.leg-swatch.bar-weight { background: var(--weight); }
.leg-swatch.bar-ghost { background: var(--text-ghost); }
.leg-swatch.bar-bad { background: var(--bad); }
.leg-swatch.bar-good { background: var(--good); }

/* ── the chip/flow layout language (primitive figures) ── */
.flow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0; font-family: var(--mono); }
.flow-op { color: var(--text-faint); font-size: 14px; }
.flow-sub { color: var(--text-ghost); font-size: 12px; }
.flow-cols { display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap; }
.flow-cols > div { flex: 1 1 300px; }
.circle-chart { flex: 0 0 auto; width: 210px; height: 210px; }
.chip { display: inline-flex; align-items: baseline; gap: 6px; padding: 3px 9px; border-radius: 7px; font: 500 13px var(--mono); border: 1px solid var(--border); background: var(--panel-deep); color: var(--text); }
.chip-label { font-size: 10.5px; color: var(--text-faint); text-transform: none; }
.chip-in { border-color: rgba(69, 120, 140, 0.45); color: var(--sigmoid); }
.chip-w { border-color: rgba(156, 97, 25, 0.4); color: var(--tanh); }
.chip-out { border-color: rgba(124, 95, 136, 0.5); color: var(--weight); }
.chip-ok { border-color: rgba(93, 125, 70, 0.45); color: var(--good); }
.chip-err { border-color: rgba(168, 64, 47, 0.45); color: var(--bad); }
.chip-dim { color: var(--text-dim); }

/* the hero equation row: large labeled chips, few of them */
.flow-hero { gap: 12px; margin: 16px 0; }
.flow-hero .flow-op { font-size: 20px; }
.chip-col { display: inline-block; text-align: center; padding: 8px 16px; border-radius: 10px; }
.chip-col .chip-label { display: block; font-size: 10.5px; margin-bottom: 2px; }
.chip-col .chip-value { display: block; font: 600 17px var(--mono); }

/* verdict cards: model vs calculator vs error */
.verdict { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin: 14px 0 4px; }
.vcard { border: 1px solid var(--border); background: var(--panel-deep); border-radius: 10px; padding: 8px 16px; min-width: 130px; }
.v-label { font: 500 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-faint); }
.v-value { font: 600 15.5px var(--mono); margin-top: 3px; color: var(--text); }
.vcard.v-model .v-value { color: var(--weight); }
.vcard.v-model { border-color: rgba(124, 95, 136, 0.5); }
.vcard.v-truth .v-value { color: var(--text-dim); }
.vcard.v-ok { border-color: rgba(93, 125, 70, 0.45); }
.vcard.v-ok .v-value { color: var(--good); }
.vcard.v-bad { border-color: rgba(168, 64, 47, 0.45); }
.vcard.v-bad .v-value { color: var(--bad); }
.v-route { font: 400 12px var(--mono); color: var(--text-ghost); flex-basis: 100%; }

/* step-by-step walkthroughs: expanded by default (no-JS, PDF); with JS the
   label becomes a toggle and they start collapsed. */
.steps { margin: 12px 0 2px; border-top: 1px dashed var(--border); padding-top: 8px; }
.steps-label { font: 500 11.5px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); }
.steps ol { margin: 10px 0 0; padding-left: 4px; font-size: 13.5px; color: var(--text-dim); list-style: none; counter-reset: step; }
.steps li { margin: 8px 0; line-height: 2; counter-increment: step; position: relative; padding-left: 32px; }
.steps li::before { content: counter(step); position: absolute; left: 0; top: 5px; width: 21px; height: 21px; border-radius: 50%; background: var(--sigmoid); color: #fbf7ee; font: 600 11.5px var(--mono); display: flex; align-items: center; justify-content: center; }
.js .steps-label { cursor: pointer; }
.js .steps-label::after { content: " ▸"; color: var(--text-ghost); }
.js .steps.open .steps-label::after { content: " ▾"; }
.js .steps ol { display: none; }
.js .steps.open ol { display: block; }

/* trig product grid */
.tp-grid { display: grid; grid-template-columns: repeat(2, minmax(150px, 220px)); gap: 10px; margin: 12px 0; }
.tp-cell { border: 1px solid var(--border); border-radius: 10px; padding: 8px 12px; background: var(--panel-deep); }
.tp-cell.tp-selected { border-color: var(--weight); box-shadow: 0 0 10px rgba(124, 95, 136, 0.2); }
.tp-name { font: 500 12px var(--mono); color: var(--text-dim); }
.tp-val { font: 500 15px var(--mono); color: var(--text); margin-top: 2px; }
.tp-selected .tp-val { color: var(--weight); }
.tp-coeff { font: 400 11px var(--mono); color: var(--text-ghost); margin-top: 2px; }

/* optimizer matrix (embedded measured results; cell colors are data) */
.om-row { display: flex; gap: 20px; flex-wrap: wrap; flex-direction: column; }
.om-panel { min-width: 0; overflow-x: auto; }
.om-label { font: 500 12px var(--mono); color: var(--text-dim); margin-bottom: 8px; }
.om-table { border-collapse: collapse; font: 500 13.5px var(--mono); width: 100%; }
.om-table th { color: var(--text-faint); font-weight: 500; padding: 6px 10px; text-align: right; border: none; background: none; }
.om-table tr:first-child th { text-align: center; vertical-align: bottom; padding: 6px 5px; font-size: 11px; overflow-wrap: break-word; }
.om-table td { text-align: center; padding: 10px 12px; border: 1px solid var(--bg); min-width: 40px; }

/* hill-surface readout */
.hs-map { max-width: 720px; margin: 0 auto; display: block; }
.hs-readout { margin-top: 10px; justify-content: center; }
