/* ==== base.css ==== */
/* base.css : structure + typography. NO literal theme colors here; everything
   references tokens defined in the theme files (dark.css / light.css / print.css). */

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

:root {
  --sidebar-w:   260px;
  --content-max: 780px;
  --radius:      6px;
  --transition:  160ms ease;
  /* Font stacks. The SHIPPED family comes first in every stack: naming a font
     that is not vendored but might be installed on some readers' machines would
     make those readers see a different page, which is the opposite of what
     shipping fonts is for. The two symbol faces sit immediately behind the
     primary, because no text face carries arrows, dingbats or box drawing --
     without them the browser silently substitutes a system font mid-sentence,
     in a different style from the text around it. The generic entries trail as
     a last resort for a --fonts=system build. */
  --font-sans:   "Inter", "Notes Symbols Math", "Notes Symbols Misc",
                 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
                 "Segoe UI", Helvetica, Arial, sans-serif;
  --font-serif:  "Source Serif 4", "Notes Symbols Math", "Notes Symbols Misc",
                 ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
  --font-body:   var(--font-serif);
  --font-mono:   "JetBrains Mono", "Notes Symbols Math", "Notes Symbols Misc",
                 ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas,
                 "Liberation Mono", monospace;
  /* derived diagram tokens (hues come from the theme) */
  --diag-fill-mix:  22%;
  --diag-fill-base: var(--code-bg);
}

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.72;
  display: flex;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

/* ---- Sidebar / TOC ---- */
#sidebar {
  width: var(--sidebar-w); flex-shrink: 0;
  background: var(--surface); border-right: 1px solid var(--border);
  position: fixed; top: 0; left: 0; bottom: 0; overflow-y: auto;
  padding: 28px 0 40px;
  scrollbar-width: thin; scrollbar-color: var(--border) transparent;
  z-index: 20;
}
#sidebar::-webkit-scrollbar { width: 4px; }
#sidebar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.sidebar-header { padding: 0 20px 20px; border-bottom: 1px solid var(--border-light); margin-bottom: 12px; }
.sidebar-label { font-family: var(--font-sans); font-size: 10px; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-faint); margin-bottom: 6px; }
.sidebar-title { font-family: var(--font-sans); font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.4; }
.sidebar-home { display: inline-block; margin-top: 8px; font-family: var(--font-sans); font-size: 11px;
  color: var(--text-muted); text-decoration: none; }
.sidebar-home:hover { color: var(--accent); }
/* Home dropdown: hovering (or keyboard-focusing) the Home control reveals every
   chapter, so any chapter is reachable from any other without visiting Home. */
.sidebar-home-wrap { position: relative; }
.sidebar-chapters { display: flex; flex-direction: column; gap: 1px;
  max-height: 0; margin-top: 0; opacity: 0; overflow: hidden;
  transition: max-height var(--transition), opacity var(--transition), margin-top var(--transition); }
.sidebar-home-wrap:hover .sidebar-chapters,
.sidebar-home-wrap:focus-within .sidebar-chapters {
  max-height: 60vh; margin-top: 10px; opacity: 1; overflow-y: auto; }
.sidebar-chapter { display: flex; align-items: baseline; gap: 8px; padding: 4px 8px; border-radius: 5px;
  font-family: var(--font-sans); font-size: 11.5px; line-height: 1.35; color: var(--text-muted);
  text-decoration: none; transition: color var(--transition), background var(--transition); }
.sidebar-chapter:hover { color: var(--text); background: var(--surface); }
.sidebar-chapter .ch-num { flex: none; min-width: 1.3em; text-align: right;
  font-size: 10px; font-weight: 600; color: var(--text-faint); }
.sidebar-chapter.current { color: var(--accent); background: var(--surface); }
.sidebar-chapter.current .ch-num { color: var(--accent); }
.toc-section { margin-bottom: 4px; }
.toc-h2 { display: block; padding: 6px 20px; font-family: var(--font-sans); font-size: 12px; font-weight: 600;
  color: var(--text-muted); text-decoration: none; transition: color var(--transition); cursor: pointer; }
.toc-h2:hover { color: var(--text); }
.toc-h2.active { color: var(--accent); }
.toc-sub { display: none; padding-left: 12px; }
.toc-section.open .toc-sub { display: block; }
.toc-h3 { display: block; padding: 3px 20px 3px 8px; font-family: var(--font-sans); font-size: 11.5px;
  color: var(--text-faint); text-decoration: none; border-left: 2px solid transparent;
  transition: color var(--transition), border-color var(--transition); line-height: 1.5; }
.toc-h3:hover { color: var(--text-muted); border-left-color: var(--border); }
.toc-h3.active { color: var(--accent); border-left-color: var(--accent); }

/* ---- Main ---- */
#main { flex: 1; margin-left: var(--sidebar-w); padding: 48px clamp(24px, 5vw, 80px) 120px; }
.content { max-width: var(--content-max); margin: 0 auto; position: relative; }

/* ---- Theme toggle ---- */
#theme-toggle {
  position: fixed; top: 14px; right: 16px; z-index: 40;
  font-family: var(--font-sans); font-size: 12px; font-weight: 600; cursor: pointer;
  color: var(--text-muted); background: var(--surface);
  border: 1px solid var(--border); border-radius: 20px; padding: 5px 12px;
  transition: color var(--transition), border-color var(--transition);
}
#theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
/* ---- Sidebar show/hide toggle ---- */
#sidebar-toggle {
  position: fixed; top: 14px; left: calc(var(--sidebar-w) - 42px); z-index: 40;
  font-family: var(--font-sans); font-size: 15px; line-height: 1;
  padding: 6px 10px; cursor: pointer; color: var(--text-muted);
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
}
#sidebar-toggle:hover { color: var(--accent); border-color: var(--accent); }
html[data-sidebar="hidden"] #sidebar-toggle { left: 16px; }
#sidebar { transition: transform .2s ease; }
/* padding-right animates the annotations rail opening/closing (see below), so
   the column glides aside exactly as it does for the sidebar */
#main { transition: margin-left .2s ease, padding-right .2s ease; }
html[data-sidebar="hidden"] #sidebar { transform: translateX(-100%); }
html[data-sidebar="hidden"] #main { margin-left: 0; }

/* ---- Header / badge ---- */
.doc-header { margin-bottom: 40px; padding-bottom: 24px; border-bottom: 1px solid var(--border-light); }
.doc-badge { display: inline-block; font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  border-radius: 4px; padding: 2px 8px; margin-bottom: 14px; }
.doc-subtitle { font-size: 14px; color: var(--text-muted); margin-top: 6px; }
.doc-readtime { font-family: var(--font-sans); font-size: 12px; color: var(--text-faint); margin-top: 4px; }

/* ---- In-page index ---- */
.doc-index { margin: 8px 0 32px; padding: 24px 28px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); }
.doc-index .index-label { font-family: var(--font-sans); font-size: 10px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 16px; }
.doc-index ol { list-style: none; padding: 0; margin: 0; }
.doc-index > ol { column-width: 250px; column-gap: 30px; }
.doc-index > ol > li { break-inside: avoid; margin: 0 0 7px; }
.doc-index > ol > li:last-child { margin-bottom: 0; }
.doc-index > ol > li > a { font-size: 13.5px; font-weight: 500; color: var(--text-muted); line-height: 1.45; }
.doc-index > ol > li > a:hover { color: var(--accent); }
.doc-index ol ol { margin: 6px 0 0; padding-left: 24px; display: flex; flex-wrap: wrap; gap: 4px 18px; }
.doc-index ol ol li { margin: 0; }
.doc-index ol ol a { font-size: 13px; color: var(--text-muted); }
.doc-index a:hover { color: var(--accent); text-decoration: none; }
.doc-index .hnum { font-weight: 700; margin-right: 4px; }

/* ---- Typography ---- */
h1 { font-size: 34px; font-weight: 700; line-height: 1.2; color: var(--text); margin: 0 0 8px; letter-spacing: -.015em; }
h1 + hr { display: none; }
h2 { font-size: 27px; font-weight: 700; color: var(--text); margin: 56px 0 20px; padding-top: 16px;
  border-top: 1px solid var(--border-light); letter-spacing: -.01em; line-height: 1.3; scroll-margin-top: 24px; }
h2:first-of-type { margin-top: 32px; }
h3 { font-size: 21px; font-weight: 600; color: var(--text); margin: 34px 0 12px; line-height: 1.35; scroll-margin-top: 24px; }
h4 { font-size: 18px; font-weight: 600; color: var(--text); margin: 26px 0 8px; scroll-margin-top: 24px; }
h5 { font-size: 16px; font-weight: 700; color: var(--text); margin: 22px 0 7px; line-height: 1.4; scroll-margin-top: 24px; }
h6 { font-size: 13px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); margin: 20px 0 6px; }
.hnum { color: var(--accent); font-weight: 700; margin-right: .14em; }
p { margin: 0 0 14px; }
p:last-child { margin-bottom: 0; }
strong { font-weight: 600; color: var(--text); }
em { font-style: italic; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
hr { border: none; border-top: 1px solid var(--border-light); margin: 36px 0; }

/* heading permalinks */
.hlink { font-family: var(--font-sans); font-weight: 400; font-size: .72em; margin-left: .35em;
  color: var(--text-faint); opacity: 0; text-decoration: none; transition: opacity var(--transition); }
h2:hover .hlink, h3:hover .hlink, h4:hover .hlink { opacity: 1; }
.hlink:hover { color: var(--accent); text-decoration: none; }

/* ---- Lists ---- */
ul, ol { padding-left: 24px; margin: 0 0 14px; }
li { margin-bottom: 5px; line-height: 1.7; }
li > ul, li > ol { margin-top: 5px; margin-bottom: 0; }
ul { list-style: disc; } ul ul { list-style: circle; } ol { list-style: decimal; }

/* ---- Blockquotes ---- */
blockquote { border-left: 3px solid var(--quote-bar); margin: 16px 0; padding: 10px 16px;
  background: var(--surface); border-radius: 0 var(--radius) var(--radius) 0; color: var(--text-muted);
  display: flow-root; }   /* contain a floated figure placed inside the box */
blockquote p { margin: 0; }
blockquote p + p { margin-top: 8px; }
blockquote strong { color: var(--text); }
blockquote p > strong.bqt { display: block; margin-bottom: 6px; }

/* ---- Abbreviations (acronym hover popup) ---- */
/* A mention the prose already spells out stays plain; every other mention uses
   the pandoc span .abbr with a data-tip attribute (rendered to an abbr element).
   Pure CSS, no JS: the popup text is the data-tip value. There is deliberately
   no visible marker on the acronym. Print/PDF ignores it (no hover). */
abbr[data-tip] {
  text-decoration: none;      /* no underline; popup still appears on hover */
  cursor: help;
  position: relative;
}
abbr[data-tip]:hover::after,
abbr[data-tip]:focus::after {
  content: attr(data-tip);
  position: absolute;
  left: 0; top: calc(100% + 6px);
  z-index: 20;
  min-width: max-content; max-width: 18rem;
  white-space: normal; line-height: 1.4;
  font-size: 0.82em; font-weight: 400; font-style: normal;
  color: var(--text);
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 10px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
  pointer-events: none;
}
@media print {
  abbr[data-tip]::after { display: none; }
  /* runnable blocks print as plain listings; animation + network chrome (both
     JS-built, never in markup) have no meaning on paper */
  .runnable .run-src, .runnable .run-bar, .runnable pre.run-out[hidden],
  .anim-controls, .net-panel { display: none !important; }
}

/* ---- Cross-references (linkable figures / tables / equations / callouts) ---- */
/* Objects carry a semantic id (#fig-05-cloud, #tbl-05-..., #eq-05-...) and are
   referenced by ordinary links [testo](#fig-05-cloud). Two aids for the reader,
   since there is no visible number: keep the target clear of the viewport top,
   and flash it on arrival so the eye lands on the right object. */
figure[id], table[id], div[id], .callout[id] { scroll-margin-top: 24px; }

@keyframes xref-flash {
  0%   { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 55%, transparent); }
  100% { box-shadow: 0 0 0 4px transparent; }
}
figure:target, div[id]:target, .callout:target {
  animation: xref-flash 1.8s ease-out;
  border-radius: var(--radius);
}
@media (prefers-reduced-motion: reduce) {
  /* animation is globally disabled below; give these users a static marker */
  figure:target, div[id]:target, .callout:target {
    outline: 2px solid var(--accent); outline-offset: 3px;
  }
}

/* Hover preview: a floating clone of the referenced object (JS-driven, template).
   Shows the graphic/formula/table itself; the caption is dropped to stay compact.
   Clickable: a figure/diagram opens full-screen, other targets jump to the anchor.
   No-hover devices and print get nothing — the link still jumps. */
.xref-popup {
  position: absolute; z-index: 60;
  width: min(380px, 90vw); max-height: 360px; overflow: hidden;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
  padding: 12px 14px;
  opacity: 0; transform: translateY(4px);
  transition: opacity .12s ease, transform .12s ease;
  pointer-events: none;   /* click-through while hidden so it never blocks the page */
  cursor: pointer;
}
.xref-popup.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
.xref-popup.zoomable { cursor: zoom-in; }
.xref-popup .xref-inner { width: 100%; }
/* neutralize the cloned object's own margins/floats so it fills the popup */
.xref-popup figure, .xref-popup .callout, .xref-popup table,
.xref-popup .table-wrap, .xref-popup p, .xref-popup div[id] {
  margin: 0 !important; float: none !important; }
.xref-popup figure { width: 100% !important; }
.xref-popup .table-wrap { overflow: visible; }
.xref-popup figcaption { display: none; }
/* Inlined diagram SVGs carry only a viewBox (no width/height attr), so their
   size comes entirely from CSS: give them a definite width to resolve against,
   or they collapse to zero once the figure's own width is removed. */
.xref-popup svg { width: 100%; height: auto; display: block; }
.xref-popup img { max-width: 100%; height: auto; display: block; margin: 0 auto; }
.xref-popup .math.display, .xref-popup .katex-display { display: block; margin: 0; }
.xref-popup::after {  /* fade the bottom edge when the clone is clipped */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 26px;
  background: linear-gradient(transparent, var(--bg)); pointer-events: none;
}
@media print { .xref-popup { display: none !important; } }

/* ---- Code ---- */
code { font-family: var(--font-mono); font-size: 13px; background: var(--code-bg);
  border: 1px solid var(--code-border); border-radius: 4px; padding: 1px 5px; color: var(--code-accent); }
pre { position: relative; background: var(--code-bg); border: 1px solid var(--code-border);
  border-radius: var(--radius); padding: 16px 20px; overflow-x: auto; margin: 16px 0;
  font-family: var(--font-mono); font-size: 13px; line-height: 1.6; color: var(--code-text); }
pre code { background: none; border: none; padding: 0; color: inherit; font-size: inherit; }
.sourceCode .kw, .sourceCode .cf { color: var(--syn-kw); }
.sourceCode .co { color: var(--syn-co); font-style: italic; }
.sourceCode .st { color: var(--syn-st); }
.sourceCode .dv, .sourceCode .fl, .sourceCode .bn { color: var(--syn-dv); }
.sourceCode .op { color: var(--syn-op); }
.sourceCode .bu, .sourceCode .fu { color: var(--syn-fu); }
.sourceCode .va { color: var(--syn-va); }
.sourceCode .pp, .sourceCode .im { color: var(--syn-kw); }
pre a { color: inherit; text-decoration: none; pointer-events: none; }
.copy-btn { position: absolute; top: 8px; right: 8px; font-family: var(--font-sans); font-size: 10.5px;
  font-weight: 600; color: var(--text-faint); background: var(--surface); border: 1px solid var(--border);
  border-radius: 4px; padding: 2px 8px; cursor: pointer; opacity: 0; transition: opacity var(--transition); }
pre:hover .copy-btn { opacity: 1; }
.copy-btn:hover { color: var(--accent); border-color: var(--accent); }

/* ---- Runnable code blocks (```{.python .run} / ```{.c .run}) ----
   A transparent <textarea> sits exactly over the highlighted <pre> layer, so
   the caret edits what the layer paints: the two MUST share every text metric
   (font, size, line-height, padding, border width, tab-size). */
.runnable { margin: 16px 0; }
.runnable .run-editor { position: relative; }
.runnable pre.run-hl { margin: 0; overflow: hidden; min-height: 54px; }
.runnable .run-src {
  position: absolute; inset: 0; width: 100%; height: 100%; box-sizing: border-box;
  font-family: var(--font-mono); font-size: 13px; line-height: 1.6; tab-size: 8;
  padding: 16px 20px; border: 1px solid transparent; border-radius: var(--radius);
  margin: 0; background: transparent; color: transparent;
  caret-color: var(--code-text); resize: none; overflow: auto; white-space: pre;
  outline: none;
}
.runnable .run-src::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }
.runnable .run-src:focus { border-color: var(--accent); }
/* read-only "provided" cells (//@fixed .. //@end): shown & highlighted like the
   editor, but not editable; an accent bar (inset shadow, no layout shift) and a
   faint tint mark them as locked. */
.runnable pre.run-fixed { min-height: 0; overflow-x: auto; cursor: default;
  box-shadow: inset 2px 0 0 color-mix(in srgb, var(--accent) 60%, transparent);
  background: color-mix(in srgb, var(--code-text) 4%, var(--code-bg)); }
/* hidden cells (//@hidden .. //@end): concatenated into the program, never shown. */
.runnable .run-hidden { display: none; }
.runnable .run-bar { display: flex; gap: 8px; align-items: center; margin-top: 6px; flex-wrap: wrap; }
.run-btn, .run-reset, .run-stop, .run-save, .run-load {
  font-family: var(--font-sans); font-size: 11.5px; font-weight: 600;
  color: var(--text-muted); background: var(--surface); border: 1px solid var(--border);
  border-radius: 4px; padding: 3px 10px; cursor: pointer; }
.run-btn:hover, .run-reset:hover, .run-save:hover, .run-load:hover { color: var(--accent); border-color: var(--accent); }
.run-stop:hover { color: var(--hue-red); border-color: var(--hue-red); }
.run-btn:disabled, .run-load:disabled { opacity: .55; cursor: default; color: var(--text-faint); border-color: var(--border); }
/* filename chip: which virtual file this editor stands for in a unit */
.run-file { font-family: var(--font-mono); font-size: 11px; color: var(--code-accent);
  background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 4px;
  padding: 1px 7px; margin-right: 2px; }
/* "edited (unsaved)" indicator: a small accent dot */
.run-mod { color: var(--accent); font-size: 10px; line-height: 1; margin-left: 2px; }
.run-status { font-family: var(--font-sans); font-size: 11.5px; color: var(--text-faint); }
.run-status.err { color: var(--hue-red); }
.runnable pre.run-out { margin: 8px 0 0; white-space: pre-wrap; }
.run-out .err { color: var(--hue-red); }
.run-out .none { color: var(--text-faint); font-style: italic; }
.run-out .trunc { color: var(--text-faint); font-style: italic; }

/* ---- Virtual-network control panel (```{... .run net=... node=...}```) ----
   One panel per network, built by JS and inserted before the first node block
   (never emitted in markup, so lint/PDF/no-JS readers are unaffected). Uses
   existing theme tokens only. */
.net-panel { margin: 16px 0; padding: 10px 12px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
  font-family: var(--font-sans); font-size: 12px; }
.net-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.net-title { color: var(--text-muted); margin-right: auto; }
.net-title b { color: var(--code-accent); font-family: var(--font-mono); }
.net-run-all, .net-stop-all, .net-node-run, .net-node-stop, .net-log-clear {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600; color: var(--text-muted);
  background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
  padding: 3px 9px; cursor: pointer; }
.net-run-all:hover, .net-node-run:hover, .net-log-clear:hover { color: var(--accent); border-color: var(--accent); }
.net-stop-all:hover, .net-node-stop:hover { color: var(--hue-red); border-color: var(--hue-red); }
.net-nodes { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-bottom: 8px; }
.net-node { display: flex; align-items: center; gap: 6px; }
.net-node-id { font-family: var(--font-mono); font-size: 12px; color: var(--code-text); }
.net-node-lang { font-size: 9.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .05em; }
.net-node-run, .net-node-stop { padding: 1px 7px; }
/* per-node status light */
.net-light { width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: var(--text-faint); box-shadow: inset 0 0 0 1px var(--border); }
.net-light[data-state="idle"]    { background: var(--text-faint); }
.net-light[data-state="booting"] { background: var(--hue-yellow); animation: net-pulse 1s ease-in-out infinite; }
.net-light[data-state="running"] { background: var(--hue-blue); animation: net-pulse 1.2s ease-in-out infinite; }
.net-light[data-state="done"]    { background: var(--hue-green); }
.net-light[data-state="crashed"] { background: var(--hue-red); }
@keyframes net-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .net-light { animation: none !important; } }
/* fault controls */
.net-faults { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px;
  margin-bottom: 6px; padding-top: 8px; border-top: 1px solid var(--border); }
.net-slider { display: flex; align-items: center; gap: 6px; }
.net-slider-label { color: var(--text-faint); min-width: 34px; }
.net-slider input[type="range"] { accent-color: var(--accent); width: 88px; cursor: pointer; }
.net-slider-val { font-variant-numeric: tabular-nums; color: var(--text-muted); min-width: 42px; }
.net-seed { display: flex; align-items: center; gap: 6px; color: var(--text-faint); }
.net-seed-in { width: 52px; font-family: var(--font-mono); font-size: 11px; padding: 2px 5px;
  background: var(--bg); color: var(--code-text); border: 1px solid var(--border); border-radius: 4px; }
.net-partitions { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-bottom: 8px; }
.net-part-label { color: var(--text-faint); }
.net-part-pair, .net-part-iso { display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); }
.net-part-pair input, .net-part-iso input { accent-color: var(--hue-red); }
/* scrolling, capped, batched message log */
.net-log-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px;
  color: var(--text-faint); font-size: 11px; }
.net-log-head span { margin-right: auto; }
.net-log { margin: 0; max-height: 190px; overflow-y: auto; padding: 8px 10px;
  background: var(--code-bg); border: 1px solid var(--code-border); border-radius: var(--radius);
  font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5; white-space: pre; }
.net-log-line { white-space: pre; }
.net-log-ok   { color: var(--hue-green); }
.net-log-drop { color: var(--hue-red); }
.net-log-dup  { color: var(--hue-yellow); }

/* ---- Interactive diagram controls (svg[data-anim-dur], built by JS) ---- */
.anim-controls { display: flex; align-items: center; gap: 12px; max-width: 560px;
  margin: 12px auto 0; font-family: var(--font-sans); }
.anim-play { flex: none; font-size: 11px; line-height: 1; color: var(--text-muted);
  background: var(--surface); border: 1px solid var(--border); border-radius: 4px;
  padding: 5px 11px; cursor: pointer; }
.anim-play:hover { color: var(--accent); border-color: var(--accent); }
.anim-scrub { flex: 1; accent-color: var(--accent); cursor: pointer; min-width: 90px; }
.anim-time { flex: none; font-size: 11.5px; color: var(--text-faint); min-width: 40px;
  text-align: right; font-variant-numeric: tabular-nums; }

/* ---- Tables ---- */
.table-wrap { overflow-x: auto; margin: 16px 0; border-radius: var(--radius); border: 1px solid var(--border); }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
thead tr { background: var(--surface-alt); border-bottom: 1px solid var(--border); }
th { padding: 10px 14px; font-family: var(--font-sans); font-weight: 600; font-size: 12px;
  text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); text-align: left; white-space: nowrap; }
td { padding: 9px 14px; border-bottom: 1px solid var(--border-light); color: var(--text); vertical-align: top; }
tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface); }

/* ---- Figures: shared ---- */
figure { margin: 24px auto; text-align: center; max-width: 100%; }
figure img { max-width: 100%; height: auto; display: block; margin: 0 auto;
  border: 1px solid var(--border); border-radius: var(--radius); }
figcaption { margin-top: 10px; font-size: 12.5px; color: var(--text-muted); line-height: 1.5; text-align: center; }
figcaption strong { color: var(--text); font-weight: 600; }
figure { width: var(--figw, auto); }
figure.full { width: 100%; }
figure.center { width: var(--figw, auto); max-width: 100%; }
figure.left  { float: left;  width: var(--figw, 40%); margin: 4px 22px 12px 0; }
figure.right { float: right; width: var(--figw, 40%); margin: 4px 0 12px 22px; }
h2, h3 { clear: both; }
.figure-row { display: flex; gap: 16px; align-items: flex-start; margin: 24px 0; flex-wrap: wrap; }
.figure-row figure { flex: 1 1 0; min-width: 160px; margin: 0; width: var(--figw, auto); }
.figure-row figure[style*="--figw"] { flex: 0 1 var(--figw); }

/* ---- Diagram figures (inline SVG) ---- */
figure.diagram { padding: 22px 20px 14px; background: var(--code-bg);
  border: 1px solid var(--code-border); border-radius: var(--radius); overflow-x: auto; }
figure.diagram svg { max-width: 100%; height: auto; display: block; margin: 0 auto; }
figure.diagram img { border: none; }
figure.diagram figcaption { margin-top: 14px; }
figure.diagram figcaption svg { display: inline-block; margin: 0; vertical-align: middle; }

/* semantic diagram classes: one SVG, every theme */
.d-label     { fill: var(--diag-text); font-family: var(--font-sans); font-weight: 600; }
.d-sub       { fill: var(--diag-text-muted); font-family: var(--font-sans); }
.d-math      { fill: var(--diag-text); }   /* real LaTeX math (d.math): glyph paths, theme-coloured */
.d-math[data-tex] { cursor: pointer; }      /* click the expression to copy its LaTeX */
.d-math[data-tex]:focus { outline: none; }
.d-math-hit  { transition: fill .12s ease; }
.d-math:hover .d-math-hit,
.d-math[data-tex]:focus .d-math-hit { fill: color-mix(in srgb, var(--accent) 14%, transparent); }
.d-math-toast {
  position: absolute; transform: translate(-50%, calc(-100% - 6px)); z-index: 60;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 3px 8px;
  font-family: var(--font-sans); font-size: 12px; line-height: 1.2;
  white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity .15s; }
.d-math-toast.show { opacity: 1; }
.d-math-src { opacity: 0; }   /* LaTeX-source overlay: invisible on the page (click-to-copy handles HTML); kept ~1% in the PDF so it stays selectable there */
.d-shape     { stroke-width: 1.5; }
.d-line      { stroke-width: 1.6; fill: none; }
.d-blue   { fill: color-mix(in srgb, var(--hue-blue)   var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-blue); }
.d-orange { fill: color-mix(in srgb, var(--hue-orange) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-orange); }
.d-green  { fill: color-mix(in srgb, var(--hue-green)  var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-green); }
.d-purple { fill: color-mix(in srgb, var(--hue-purple) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-purple); }
.d-red    { fill: color-mix(in srgb, var(--hue-red)    var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-red); }
.d-yellow { fill: color-mix(in srgb, var(--hue-yellow) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-yellow); }
.d-teal   { fill: color-mix(in srgb, var(--hue-teal)   var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-teal); }
.d-grey   { fill: color-mix(in srgb, var(--hue-grey)   var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-grey); }
/* semantic aliases */
.d-primary { fill: color-mix(in srgb, var(--hue-blue) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-blue); }
.d-accent  { fill: color-mix(in srgb, var(--hue-orange) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-orange); }
.d-good    { fill: color-mix(in srgb, var(--hue-green) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-green); }
.d-danger  { fill: color-mix(in srgb, var(--hue-red) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-red); }
.d-neutral { fill: color-mix(in srgb, var(--hue-grey) var(--diag-fill-mix), var(--diag-fill-base)); stroke: var(--hue-grey); }
/* arrows + markers */
.d-arrow        { stroke: var(--diag-arrow); }
.d-arrow-blue   { stroke: var(--hue-blue); }
.d-arrow-orange { stroke: var(--hue-orange); }
.d-arrow-green  { stroke: var(--hue-green); }
.d-arrow-red    { stroke: var(--hue-red); }
.d-arrow-purple { stroke: var(--hue-purple); }
.d-arrow-teal   { stroke: var(--hue-teal); }
.d-arrow-yellow { stroke: var(--hue-yellow); }
.d-mk        { fill: var(--diag-arrow); }
.d-mk-blue   { fill: var(--hue-blue); }
.d-mk-orange { fill: var(--hue-orange); }
.d-mk-green  { fill: var(--hue-green); }
.d-mk-red    { fill: var(--hue-red); }
.d-mk-purple { fill: var(--hue-purple); }
.d-mk-teal   { fill: var(--hue-teal); }
.d-mk-yellow { fill: var(--hue-yellow); }
/* line icons (diagrams.icon): monoline glyphs that recolor per theme.
   stroke-width is set as a presentation attr on the <g> (2/scale) so the
   visible stroke stays ~2px at any size; color comes from these classes. */
.d-icon         { fill: none; stroke: var(--diag-text); stroke-linecap: round; stroke-linejoin: round; }
.d-icon-blue    { stroke: var(--hue-blue); }
.d-icon-orange  { stroke: var(--hue-orange); }
.d-icon-green   { stroke: var(--hue-green); }
.d-icon-purple  { stroke: var(--hue-purple); }
.d-icon-red     { stroke: var(--hue-red); }
.d-icon-yellow  { stroke: var(--hue-yellow); }
.d-icon-teal    { stroke: var(--hue-teal); }
.d-icon-grey    { stroke: var(--hue-grey); }
.d-icon-primary { stroke: var(--hue-blue); }
.d-icon-accent  { stroke: var(--hue-orange); }
.d-icon-good    { stroke: var(--hue-green); }
.d-icon-danger  { stroke: var(--hue-red); }
.d-icon-neutral { stroke: var(--hue-grey); }

/* ---- Callouts ---- */
.callout { position: relative; margin: 26px 0; padding: 18px 18px 15px;
  background: color-mix(in srgb, var(--co-c) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--co-c) 35%, var(--border));
  border-left: 3px solid var(--co-c); border-radius: var(--radius); }
.callout .co-title { position: absolute; top: -11px; left: 14px; padding: 2px 11px; border-radius: 20px;
  background: var(--co-c); color: var(--co-title-text); font-family: var(--font-sans);
  font-size: 11px; font-weight: 700; letter-spacing: .02em; }
.callout .co-body > :first-child { margin-top: 2px; }
.callout .co-body > :last-child { margin-bottom: 0; }
.co-definition { --co-c: var(--hue-blue); }
.co-theorem    { --co-c: var(--hue-purple); }
.co-lemma      { --co-c: var(--hue-purple); }
.co-proof      { --co-c: var(--hue-grey); }
.co-example    { --co-c: var(--accent); background: var(--surface); }  /* neutral blockquote-surface fill; accent kept in border + title pill */
.co-intuition  { --co-c: var(--hue-green); }
.co-warning    { --co-c: var(--hue-yellow); }
.co-pitfall    { --co-c: var(--hue-red); }
.co-recall     { --co-c: var(--hue-teal); }
.co-note       { --co-c: var(--hue-grey); }
/* collapsible callouts (proof) + plain details */
details.callout > summary { cursor: pointer; font-family: var(--font-sans); font-size: 13px;
  font-weight: 600; color: var(--text-muted); list-style: none; }
details.callout > summary::before { content: "▸ "; color: var(--co-c); }
details.callout[open] > summary::before { content: "▾ "; }
details.callout > summary::-webkit-details-marker { display: none; }
details.callout .co-body { margin-top: 10px; }
/* ---- Figures floated inside a callout ---- */
/* contain the float so a tall figure never spills out of the box */
.callout .co-body { display: flow-root; }
.callout .co-body > figure.left,
.callout .co-body > figure.right { margin-top: 0; }
/* blend a diagram panel into the callout (no dark box inside a coloured box) */
.callout .co-body figure.diagram { background: transparent;
  border: 1px solid var(--border); padding: 12px 12px 8px; }
details.fold { margin: 18px 0; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); padding: 12px 16px; }
details.fold > summary { cursor: pointer; font-family: var(--font-sans); font-size: 13.5px;
  font-weight: 600; color: var(--text); list-style: none; }
details.fold > summary::before { content: "▸ "; color: var(--accent); }
details.fold[open] > summary::before { content: "▾ "; }
details.fold > summary::-webkit-details-marker { display: none; }
details.fold[open] > summary { margin-bottom: 10px; }
details.fold > :last-child { margin-bottom: 0; }

/* ---- Margin notes ---- */
/* Side note: a compact box floated to the right INSIDE the text column, with the
   paragraph wrapping around it (a real "nota a margine" at normal widths). Only a
   very wide window (>=1560px) has room to push it out into the true outer margin;
   on phones it falls back to a full-width inset box. */
.margin-note {
  font-family: var(--font-sans); font-size: 12.5px; line-height: 1.55; color: var(--text-muted);
  float: right; clear: right; width: 40%; max-width: 290px;
  margin: 4px 0 12px 22px; padding: 10px 14px;
  background: var(--surface); border-left: 2px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.margin-note > :last-child { margin-bottom: 0; }
@media (min-width: 1560px) {
  .margin-note { width: 200px; max-width: 200px; margin: 2px -240px 10px 0;
    padding: 0 0 0 12px; background: none; border-left: 2px solid var(--border);
    border-radius: 0; }
}
@media (max-width: 700px) {
  .margin-note { float: none; width: auto; max-width: none; margin: 14px 0; }
}

/* ---- Reader annotations ----
   Read-time only: every mark, bubble and control below is built by the template
   JS from localStorage, so the published HTML never carries a reader's notes and
   the PDF never sees this layer. Colours come from the theme hues, so a note
   keeps its identity in every theme. */
:root { --anno-rail: 320px; --anno-card: 280px; }

/* The anchor left in the prose. Highlight and underline are INDEPENDENT (as in
   a word processor): the same range can carry both, either, or neither — a note
   with no visible mark at all is still a real annotation that flashes on click.
   Marks stay visible when the bubbles are hidden: the reader's own emphasis is
   part of the text now, only the note chrome is a layer. */
mark.anno-mark { background: transparent; color: inherit; border-radius: 2px;
  padding: 0 1px; cursor: pointer; --mk: var(--accent);
  transition: background-color var(--transition), border-color var(--transition); }
.anno-mark[data-color="yellow"] { --mk: var(--hue-yellow); }
.anno-mark[data-color="green"]  { --mk: var(--hue-green); }
.anno-mark[data-color="blue"]   { --mk: var(--hue-blue); }
.anno-mark[data-color="red"]    { --mk: var(--hue-red); }
.anno-mark[data-hl="1"] { background: color-mix(in srgb, var(--mk) 32%, transparent); }
.anno-mark[data-ul="1"] { border-bottom: 2px solid var(--mk); }
/* Hidden hides the bubbles, not the way IN: the highlights stay on the text and
   the per-block pencil still offers a note (taking one switches the layer back
   on), exactly as the "new note" button in the toolbar does. */

/* click a bubble -> its target announces itself: a mark lights up, a block pulses */
@keyframes anno-flash-mark {
  0%   { background-color: color-mix(in srgb, var(--mk) 78%, transparent);
         box-shadow: 0 0 0 3px color-mix(in srgb, var(--mk) 40%, transparent); }
  100% { box-shadow: 0 0 0 3px transparent; }
}
.anno-flash-mark { animation: anno-flash-mark 1.5s ease-out; }
.anno-flash-block { animation: xref-flash 1.8s ease-out; border-radius: var(--radius); }

/* ---- top toolbar (sits beside the theme pill) ---- */
#anno-bar { position: fixed; top: 14px; right: 112px; z-index: 40;
  display: flex; gap: 7px; align-items: center;
  background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
  padding: 5px 10px; font-family: var(--font-sans); }
html[data-anno="off"] #anno-bar { display: none; }
.anno-dot { width: 14px; height: 14px; padding: 0; border: none; border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--border); cursor: pointer;
  transition: transform var(--transition); }
.anno-dot:hover { transform: scale(1.15); }
.anno-dot[data-color="yellow"] { background: var(--hue-yellow); }
.anno-dot[data-color="green"]  { background: var(--hue-green); }
.anno-dot[data-color="blue"]   { background: var(--hue-blue); }
.anno-dot[data-color="red"]    { background: var(--hue-red); }
.anno-sep { width: 1px; align-self: stretch; background: var(--border); }
.anno-tool { display: inline-grid; place-items: center; font-family: var(--font-sans);
  font-size: 12px; font-weight: 600; line-height: 1.5; color: var(--text-muted);
  background: none; border: 1px solid var(--border); border-radius: 999px;
  padding: 1px 9px; cursor: pointer;
  transition: color var(--transition), border-color var(--transition); }
.anno-tool:hover { color: var(--accent); border-color: var(--accent); }
.anno-tool.u { text-decoration: underline; }
/* the eye is the show/hide switch; "new note" stays available while hidden */
.anno-eye { border: none; padding: 1px 2px 0; display: inline-flex; align-items: center; }
.anno-eye svg { display: block; }
html[data-anno-vis="on"] .anno-eye { color: var(--accent); }
html[data-anno-vis="on"] .eye-off, html[data-anno-vis="off"] .eye-on { display: none; }
/* tools that need a selection read as inert until there is one */
#anno-bar.idle .anno-dot, #anno-bar.idle .anno-tool.u { opacity: .45; }
/* the chosen pen colour; and, on the action buttons, what the selection already
   carries (so the same click takes it away) */
.anno-dot.on { outline: 2px solid var(--text); outline-offset: 2px; }
/* the two action buttons SHOW their action: an H wearing the pen's highlight,
   and a U underlined in it */
.anno-tool.h, .anno-tool.u { --mk: var(--accent); }
.anno-tool.h[data-color="yellow"], .anno-tool.u[data-color="yellow"] { --mk: var(--hue-yellow); }
.anno-tool.h[data-color="green"],  .anno-tool.u[data-color="green"]  { --mk: var(--hue-green); }
.anno-tool.h[data-color="blue"],   .anno-tool.u[data-color="blue"]   { --mk: var(--hue-blue); }
.anno-tool.h[data-color="red"],    .anno-tool.u[data-color="red"]    { --mk: var(--hue-red); }
.anno-tool.h { padding: 1px 7px; }
.hl-h { display: inline-block; padding: 0 3px; border-radius: 2px; font-weight: 700;
  background: color-mix(in srgb, var(--mk) 42%, transparent); }
/* the U is underlined in the pen colour by its own text-decoration — a
   pseudo-element would add a second grid row, making this button taller than
   its neighbours and leaving a bar that stayed grey while the rest lit up */
.anno-tool.u { font-weight: 700; text-decoration: underline;
  text-decoration-thickness: 2px; text-underline-offset: 3px;
  text-decoration-color: var(--mk); }
.anno-tool.u:hover { text-decoration-color: var(--accent); }
#anno-bar .anno-tool.on { color: var(--accent); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent); }
/* collapsed: everything folds away behind the pencil, which keeps its place at
   the right-hand end so the control never jumps under the pointer */
.anno-bar-toggle { border: none; padding: 1px 4px; font-size: 14px; line-height: 1; }
/* Collapsed, the strip keeps the two controls a reader wants while READING —
   show/hide, and the way back to the tools — as a pill the height of the theme
   control beside it (--anno-pill is measured from that control, so it matches
   in any language or font). The border lights up on hover the way that control
   does. */
#anno-bar[data-open="0"] > *:not(.anno-bar-toggle):not(.anno-eye) { display: none; }
#anno-bar[data-open="0"] { gap: 2px; padding: 0 5px; justify-content: center;
  height: var(--anno-pill, 30px); border-radius: 999px; color: var(--text-muted);
  transition: color var(--transition), border-color var(--transition); }
#anno-bar[data-open="0"]:hover { border-color: var(--accent); }
/* each button FILLS the pill's height: sized to its glyph it would only answer
   clicks on a few pixels while looking like a 30px target */
#anno-bar[data-open="0"] .anno-bar-toggle,
#anno-bar[data-open="0"] .anno-eye { height: 100%; min-width: 22px; padding: 0;
  border-radius: 999px; color: inherit; }
#anno-bar[data-open="0"] .anno-bar-toggle { font-size: 13px; line-height: 1; }
#anno-bar[data-open="0"] .anno-bar-toggle:hover,
#anno-bar[data-open="0"] .anno-eye:hover { color: var(--accent); }
html[data-anno-vis="on"] #anno-bar[data-open="0"] .anno-eye { color: var(--accent); }

/* ---- the rail: shown -> the column slides left, bubbles get their own column.
   Animated like the sidebar, so the text glides aside instead of jumping. ---- */
@media screen and (min-width: 1080px) {
  html[data-anno-vis="on"] #main {
    padding-right: calc(clamp(24px, 5vw, 80px) + var(--anno-rail)); }
}

/* ---- bubbles ---- */
.anno-card { position: absolute; left: 100%; margin-left: 30px; width: var(--anno-card);
  padding: 5px; font-family: var(--font-sans); font-size: 12.5px; line-height: 1.55;
  color: var(--text); background: var(--surface);
  border: 1.5px solid var(--border); border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .12); cursor: pointer;
  transition: top .18s ease, border-color var(--transition), box-shadow var(--transition); }
.anno-card:hover { border-color: var(--text-faint); }
.anno-card.active { border-color: var(--accent); box-shadow: 0 6px 22px rgba(0, 0, 0, .28); z-index: 5; }
/* the tail: an outlined notch on the left, level with the top of the target */
.anno-card::before { content: ""; position: absolute; top: 13px; left: -8px;
  width: 13px; height: 13px; background: var(--surface);
  border-left: 1.5px solid var(--border); border-bottom: 1.5px solid var(--border);
  transform: rotate(45deg); }
.anno-card:hover::before { border-color: var(--text-faint); }
.anno-card.active::before { border-color: var(--accent); }
/* body: the house blockquote look, on the ordinary surface (never hue-tinted);
   position:relative so it paints over the tail's inner corner */
.anno-body { display: block; position: relative; padding: 9px 11px 7px;
  background: var(--surface-alt); border-left: 3px solid var(--mk, var(--accent));
  border-radius: 6px; }
.anno-card[data-color="yellow"] { --mk: var(--hue-yellow); }
.anno-card[data-color="green"]  { --mk: var(--hue-green); }
.anno-card[data-color="blue"]   { --mk: var(--hue-blue); }
.anno-card[data-color="red"]    { --mk: var(--hue-red); }
.anno-card p { margin: 0 0 8px; font-size: 12.5px; line-height: 1.55; }
.anno-card p:last-child { margin-bottom: 0; }
.anno-card pre { margin: 8px 0; padding: 8px 10px; font-size: 11.5px; line-height: 1.5; }
.anno-card code { font-size: 11.5px; }
.anno-card ul, .anno-card ol { padding-left: 18px; margin: 0 0 8px; }
.anno-card li { margin-bottom: 2px; line-height: 1.5; }
.anno-card blockquote { margin: 8px 0; padding: 6px 10px; font-size: 12px; }
.anno-card .katex { font-size: 1.05em; }
.anno-math-display { text-align: center; margin: 8px 0; overflow-x: auto; }
.anno-empty { color: var(--text-faint); font-style: italic; }
/* The date and the controls are chrome, not content: they fade in when the
   reader is actually on the note. The row keeps its space so a bubble never
   changes height under the pointer (the rail lays cards out by height). */
.anno-foot { display: flex; gap: 4px; align-items: center; margin-top: 8px;
  padding-top: 6px; border-top: 1px solid transparent;
  opacity: 0; transition: opacity var(--transition), border-color var(--transition); }
.anno-card:hover .anno-foot, .anno-card.active .anno-foot,
.anno-card:focus-within .anno-foot, .anno-card.editing .anno-foot,
.lb-note .anno-foot { opacity: 1; border-top-color: var(--border); }
.anno-time { font-size: 10.5px; color: var(--text-muted); margin-right: auto;
  padding-left: 2px; }
/* generous hit area, pulled back with negative margins so the row stays thin */
.anno-act { font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  color: var(--text); background: none; border: none; cursor: pointer;
  padding: 7px 10px; margin: -6px 0; border-radius: 6px; line-height: 1;
  transition: color var(--transition), background var(--transition); }
.anno-act:hover { color: var(--accent); background: var(--surface); }
.anno-act.danger:hover { color: var(--hue-red);
  background: color-mix(in srgb, var(--hue-red) 12%, transparent); }
/* an annotation whose words the chapter lost: a dashed, unhued bubble carrying
   the quote it kept and the section it bubbled up to (or, if even that is gone,
   the name that section had) */
.anno-orphan { font-size: 11px; color: var(--hue-red); margin-bottom: 6px; }
.anno-card.orphan { --mk: var(--text-faint); }
.anno-card.orphan .anno-body { border-left-style: dashed; }
.anno-lost-quote { color: var(--text-muted); }
.anno-sec { font-size: 11px; color: var(--text-muted); margin-bottom: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- editor ---- */
.anno-tabs { display: flex; gap: 2px; margin-bottom: 7px; }
.anno-tab { font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  color: var(--text-faint); background: none; border: 1px solid transparent;
  border-radius: 999px; padding: 2px 10px; cursor: pointer; }
.anno-tab.on { color: var(--text); background: var(--surface); border-color: var(--border); }
.anno-tb { display: flex; gap: 3px; margin-bottom: 6px; flex-wrap: wrap; }
.anno-tb button { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted);
  background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 7px; cursor: pointer; }
.anno-tb button:hover { color: var(--accent); border-color: var(--accent); }
.anno-ta { width: 100%; min-height: 92px; resize: vertical; font-family: var(--font-mono);
  font-size: 12px; line-height: 1.55; color: var(--code-text); background: var(--code-bg);
  border: 1px solid var(--border); border-radius: 5px; padding: 8px 10px; outline: none; }
.anno-ta:focus { border-color: var(--accent); }
/* the same editor, opened large in the overlay for a long note */
.anno-ta-big { min-height: min(52vh, 420px); font-size: 13.5px; line-height: 1.6; }
.lb-note .anno-tabs { margin-bottom: 10px; }
.lb-note .anno-foot { margin-top: 12px; }
.anno-opts { display: flex; align-items: center; gap: 7px; margin-top: 7px; }
.anno-opts .anno-dot.sel { outline: 2px solid var(--accent); outline-offset: 1px; }
.anno-opts .anno-tool.sel { color: var(--accent); border-color: var(--accent); }
.anno-save { font-family: var(--font-sans); font-size: 11.5px; font-weight: 600;
  color: var(--accent-contrast); background: var(--accent); border: 1px solid var(--accent);
  border-radius: 999px; padding: 3px 12px; cursor: pointer; margin-left: auto; }
.anno-save:hover { filter: brightness(1.08); }

/* ---- the per-block pencil: a rounded square hugging the block, like .copy-btn.
   Hover a heading, listing, runnable block, table, figure or callout and it
   offers a note about that whole object. ---- */
[data-anno-block] { position: relative; }
.anno-pen { position: absolute; top: 4px; right: -34px; width: 26px; height: 26px;
  display: grid; place-items: center; font-family: var(--font-sans); font-size: 12.5px;
  color: var(--text-faint); background: var(--surface);
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  opacity: 0; transition: opacity var(--transition); z-index: 3; }
.anno-pen:hover, .anno-pen:focus-visible { color: var(--accent); border-color: var(--accent); }
[data-anno-block]:hover > .anno-pen, .anno-pen:focus-visible { opacity: 1; }
/* .table-wrap, figure.diagram and a bare <pre> scroll horizontally: hanging the
   pencil outside them would add phantom scroll width and clip it, so there it
   sits inside — on a listing, clear of the copy button it shares the corner
   with. */
.table-wrap > .anno-pen, figure.diagram > .anno-pen { right: 6px; top: 6px; }
pre > .anno-pen { right: 54px; top: 6px; }
pre:hover > .anno-pen { opacity: 1; }
/* a runnable block keeps its own chrome at the top-right of the editor */
.runnable > .anno-pen { top: -2px; }

/* ---- sidebar: index / annotations pills + the notes panel ---- */
.sb-tabs { display: flex; justify-content: center; gap: 5px; margin-top: 7px; }
/* the pills sit closer to Home and to the rule below them; only pages that
   actually carry the tabs are tightened, so a chapter without annotations
   keeps the header it always had */
.sidebar-header:has(.sb-tabs) { padding-bottom: 11px; }
.sb-tab { font-family: var(--font-sans); font-size: 10.5px; font-weight: 600;
  color: var(--text-muted); background: none; border: 1px solid var(--border);
  border-radius: 999px; padding: 2px 12px; cursor: pointer;
  transition: color var(--transition), border-color var(--transition); }
.sb-tab:hover { color: var(--accent); border-color: var(--accent); }
.sb-tab.on { color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
html[data-sb-tab="anno"] #sidebar .toc-section { display: none; }
html[data-sb-tab="index"] #anno-panel { display: none; }
#anno-panel { padding: 14px 20px 0; }
.anno-list { list-style: none; padding: 0; margin: 0; }
.anno-list li { margin: 0 0 3px; }
.anno-jump { display: block; width: 100%; text-align: left; font-family: var(--font-sans);
  font-size: 11.5px; line-height: 1.45; color: var(--text-muted); background: none;
  border: none; border-left: 2px solid var(--mk, var(--border)); padding: 2px 0 2px 8px;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.anno-jump:hover { color: var(--accent); }
.anno-jump[data-color="yellow"] { --mk: var(--hue-yellow); }
.anno-jump[data-color="green"]  { --mk: var(--hue-green); }
.anno-jump[data-color="blue"]   { --mk: var(--hue-blue); }
.anno-jump[data-color="red"]    { --mk: var(--hue-red); }
.anno-jump.orphan { color: var(--text-faint); font-style: italic; }
.anno-none { font-family: var(--font-sans); font-size: 11.5px; color: var(--text-faint);
  font-style: italic; }
.anno-io { display: flex; gap: 6px; margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--border-light); }
.anno-io button { font-family: var(--font-sans); font-size: 10.5px; font-weight: 600;
  color: var(--text-muted); background: none; border: 1px solid var(--border);
  border-radius: 999px; padding: 2px 10px; cursor: pointer; }
.anno-io button:hover { color: var(--accent); border-color: var(--accent); }

/* ---- expanded note: the lightbox, reused for reading a long note ---- */
#lightbox .lb-stage.lb-note { display: block; width: min(760px, 92vw);
  max-height: 86vh; overflow-y: auto; cursor: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 4px solid var(--mk, var(--accent)); border-radius: 10px;
  padding: 28px 32px; box-shadow: 0 8px 40px rgba(0, 0, 0, .5);
  font-family: var(--font-sans); font-size: 15px; line-height: 1.7; color: var(--text); }
.lb-note[data-color="yellow"] { --mk: var(--hue-yellow); }
.lb-note[data-color="green"]  { --mk: var(--hue-green); }
.lb-note[data-color="blue"]   { --mk: var(--hue-blue); }
.lb-note[data-color="red"]    { --mk: var(--hue-red); }
.lb-note p { margin: 0 0 12px; font-size: 15px; line-height: 1.7; }
.lb-note pre { margin: 14px 0; padding: 14px 18px; font-size: 13px; line-height: 1.6; }
.lb-note code { font-size: 13px; }
.lb-note ul, .lb-note ol { padding-left: 22px; margin: 0 0 12px; }
.lb-note li { margin-bottom: 4px; line-height: 1.6; }
.lb-note .katex { font-size: 1.05em; }
.lb-note .anno-math-display { margin: 14px 0; }
.lb-note-quote { font-size: 12.5px; font-style: italic; color: var(--text-faint);
  margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }

/* toast: quiet confirmation for export / import */
#anno-toast { position: fixed; bottom: 18px; right: 18px; z-index: 90;
  font-family: var(--font-sans); font-size: 12px; color: var(--text);
  background: var(--surface-alt); border: 1px solid var(--border); border-radius: 7px;
  padding: 7px 13px; box-shadow: 0 6px 18px rgba(0, 0, 0, .25);
  opacity: 0; pointer-events: none; transition: opacity .18s ease; }
#anno-toast.show { opacity: 1; }

/* ---- narrow: no rail. bubbles sit inline under their block. ---- */
@media (max-width: 1079px) {
  .anno-card { position: static; width: auto; margin: 12px 0; }
  .anno-card::before { display: none; }
  .anno-pen { display: none; }
}

/* ---- print: the reader's notes print with the prose; the chrome does not ---- */
@media print {
  #anno-bar, .anno-pen, .sb-tabs, #anno-panel, #anno-toast { display: none !important; }
  .anno-mark { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .anno-card { position: static; width: auto; margin: 10px 0; break-inside: avoid;
    box-shadow: none; }
  .anno-card::before, .anno-foot { display: none; }
}

/* ---- Math ---- */
math { font-size: 1.06em; }
math[display="block"] { display: block; margin: 14px auto 18px; text-align: center; }
.katex-display { margin: 14px 0 18px; }

/* ---- Lightbox ---- */
#lightbox { position: fixed; inset: 0; z-index: 100; display: none; background: rgba(0,0,0,.82);
  align-items: center; justify-content: center; cursor: zoom-out; padding: 4vh 4vw; }
#lightbox.open { display: flex; }
#lightbox .lb-stage { display: flex; max-width: 100%; max-height: 100%; }
/* diagram SVGs are theme-tinted for the page background, so give them their panel
   background (like figure.diagram) rather than showing them on the dark overlay */
#lightbox .lb-stage.lb-diagram { background: var(--code-bg); border-radius: var(--radius);
  padding: min(4vw, 40px); box-shadow: 0 8px 40px rgba(0,0,0,.5); }
#lightbox .lb-stage > img { max-width: 100%; max-height: 92vh;
  border-radius: var(--radius); box-shadow: 0 8px 40px rgba(0,0,0,.5); }
#lightbox .lb-stage.lb-diagram > svg { width: auto; height: auto; max-width: 100%; max-height: 84vh; }
figure:not(.nozoom) > img, figure:not(.nozoom) > svg { cursor: zoom-in; }

/* ---- Footer meta ---- */
.doc-meta { margin-top: 60px; padding-top: 20px; border-top: 1px solid var(--border-light);
  font-size: 13px; color: var(--text-faint); font-style: italic; }

/* ---- Home page cards ---- */
.home-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; margin-top: 8px; }
.home-card { display: flex; align-items: center; gap: 14px; padding: 18px 20px; border: 1px solid var(--border);
  border-radius: 12px; background: var(--surface); text-decoration: none; transition: border-color .15s; }
.home-card:hover { border-color: var(--accent); text-decoration: none; }
.home-num { font-family: var(--font-mono); font-size: 15px; font-weight: 700; color: var(--accent); }
.home-title { font-family: var(--font-sans); font-size: 15px; font-weight: 600; color: var(--text); }

/* ---- Home page: attribution / citation block (home.py --year/--code/--about) ---- */
.doc-subtitle .course-code { color: var(--text-muted); text-decoration: none;
  border-bottom: 1px dotted var(--text-faint); }
.doc-subtitle .course-code:hover { color: var(--accent); border-bottom-color: var(--accent); }
.course-about { margin-top: 18px; font-family: var(--font-sans); font-size: 13.5px;
  line-height: 1.65; color: var(--text-muted); }
.course-about p { margin: 0 0 8px; }
.course-about a { color: inherit; text-decoration: none;
  border-bottom: 1px dotted var(--text-faint); }
.course-about a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.course-disclaimer { font-size: 12.5px; color: var(--text-faint); font-style: italic; }

/* ---- Home page: back-to-the-site pill (home.py --site-root) ---- */
#all-courses { position: fixed; top: 14px; left: 16px; z-index: 40;
  font-family: var(--font-sans); font-size: 12px; line-height: 1;
  padding: 7px 12px; cursor: pointer; color: var(--text-muted); text-decoration: none;
  background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
  transition: color var(--transition), border-color var(--transition); }
#all-courses:hover { color: var(--accent); border-color: var(--accent); }

/* ---- Responsive ---- */
/* Under 1100px the sidebar cannot sit beside the text -- but it is the ONLY
   way to Home, to the other chapters and to the annotations panel, so it
   becomes a DRAWER over the page instead of disappearing. Hiding its toggle
   too (as this once did) left a phone reader with no route to any of them. */
@media (max-width: 1100px) {
  #main { margin-left: 0; }
  #sidebar { transform: translateX(-100%); z-index: 60;
    box-shadow: 4px 0 24px rgba(0, 0, 0, .28); width: min(var(--sidebar-w), 86vw); }
  html[data-drawer="open"] #sidebar { transform: none; }
  /* The handle sits BOTTOM-left, not top-left: the top row already carries the
     theme pill and the annotations toolbar (which grows leftwards from it and
     would land on a handle up there), and the bottom corner is the one a thumb
     actually reaches. It never moves -- open, it rides above the drawer and
     reads as the way out. */
  #sidebar-toggle { left: 14px; top: auto; bottom: 18px; z-index: 70;
    min-width: 44px; min-height: 44px; display: grid; place-items: center;
    font-size: 17px; padding: 0; border-radius: 999px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, .28); }
  html[data-sidebar="hidden"] #sidebar-toggle { left: 14px; }
  #sb-backdrop { position: fixed; inset: 0; z-index: 50; background: rgba(0, 0, 0, .45);
    opacity: 0; pointer-events: none; transition: opacity .2s ease; }
  html[data-drawer="open"] #sb-backdrop { opacity: 1; pointer-events: auto; }
  /* room at the foot of the drawer so the handle never covers the last entry */
  #sidebar { padding-bottom: 80px; }
}
@media (max-width: 1100px) and (prefers-reduced-motion: reduce) {
  #sidebar, #sb-backdrop { transition: none; }
}
@media (max-width: 800px) {
  #main { padding: 24px 20px 80px; }
  .doc-index { padding: 18px 20px; }
  figure.left, figure.right { float: none; width: var(--figw, auto); margin: 18px auto; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ==== dark.css ==== */
/* dark theme : the original house look, expressed as the token contract.
   To add a new theme, copy this file, rename the selector, fill every token. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:           #2d2c2a;
  --surface:      #38362f;
  --surface-alt:  #423f38;
  --border:       #4b4842;
  --border-light: #3c3a35;
  --text:         #ececec;
  --text-muted:   #a39e95;
  --text-faint:   #75716a;
  --accent:       #cc785c;
  --accent-contrast: #3a1f14;
  --link:         #8ab4f8;
  --code-bg:      #211f1d;
  --code-border:  #3a3733;
  --code-text:    #c9d1d9;
  --code-accent:  #e3a07a;
  --quote-bar:    #5a564f;
  /* syntax highlighting */
  --syn-kw: #ff7b72; --syn-co: #8b949e; --syn-st: #a5d6ff; --syn-dv: #79c0ff;
  --syn-op: #e3a07a; --syn-fu: #d2a8ff; --syn-va: #ffa657;
  /* diagram hues (stroke-strength; fills are mixed automatically) */
  --hue-blue:   #5b8fd6;
  --hue-orange: #cc785c;
  --hue-green:  #4c9a6b;
  --hue-purple: #9b7fd6;
  --hue-red:    #c5705c;
  --hue-yellow: #c9a34e;
  --hue-teal:   #4fa8a0;
  --hue-grey:   #8a867e;
  --diag-text:       #ececec;
  --diag-text-muted: #9b9b9b;
  --diag-arrow:      #8a8a8a;
  --diag-fill-mix:   22%;
  --diag-fill-base:  #211f1d;
  --co-title-text:   #26221e;
}

/* ==== light.css ==== */
/* light theme : warm-paper counterpart to the dark house look.
   Not an inversion; every token retuned for contrast on light ground. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg:           #faf7f2;
  --surface:      #f1ede5;
  --surface-alt:  #e9e4da;
  --border:       #d8d2c6;
  --border-light: #e5e0d6;
  --text:         #2b2925;
  --text-muted:   #6b665d;
  --text-faint:   #9a948a;
  --accent:       #bc5f3f;
  --accent-contrast: #fdf6f2;
  --link:         #2f6cb3;
  --code-bg:      #f3efe8;
  --code-border:  #ddd7cb;
  --code-text:    #3a3733;
  --code-accent:  #a85a34;
  --quote-bar:    #c9c2b4;
  /* syntax highlighting */
  --syn-kw: #b03a48; --syn-co: #8a8477; --syn-st: #2f6cb3; --syn-dv: #1d6fb8;
  --syn-op: #a85a34; --syn-fu: #7a4bbf; --syn-va: #b06414;
  /* diagram hues */
  --hue-blue:   #3d6fb5;
  --hue-orange: #bc5f3f;
  --hue-green:  #3d7d55;
  --hue-purple: #7a5cb8;
  --hue-red:    #b04a38;
  --hue-yellow: #a07d1e;
  --hue-teal:   #2f827a;
  --hue-grey:   #7d786e;
  --diag-text:       #2b2925;
  --diag-text-muted: #6b665d;
  --diag-arrow:      #7d786e;
  --diag-fill-mix:   13%;
  --diag-fill-base:  #ffffff;
  --co-title-text:   #fdf9f4;
}

/* ==== print.css ==== */
/* print theme : ink-friendly, high-contrast tokens, selected by the PDF step
   (data-theme="print"). Plus @media print rules that apply whenever ANY theme
   is printed: page geometry, break control, hiding screen chrome. */
:root[data-theme="print"] {
  color-scheme: light;
  --bg:           #ffffff;
  --surface:      #f5f3ef;
  --surface-alt:  #edeae4;
  --border:       #c8c3b8;
  --border-light: #dedad1;
  --text:         #1a1916;
  --text-muted:   #4e4a43;
  --text-faint:   #807a70;
  --accent:       #a34e2e;
  --accent-contrast: #ffffff;
  --link:         #1a4f8a;
  --code-bg:      #f4f2ee;
  --code-border:  #d3cec4;
  --code-text:    #24221f;
  --code-accent:  #8c4522;
  --quote-bar:    #b3ada0;
  --syn-kw: #8f2f3b; --syn-co: #6e6a60; --syn-st: #1a4f8a; --syn-dv: #144f86;
  --syn-op: #8c4522; --syn-fu: #5c3a94; --syn-va: #8a5010;
  --hue-blue:   #2d5a99;
  --hue-orange: #a34e2e;
  --hue-green:  #2e6a45;
  --hue-purple: #634a9e;
  --hue-red:    #963a2a;
  --hue-yellow: #86660f;
  --hue-teal:   #226b64;
  --hue-grey:   #6b665d;
  --diag-text:       #1a1916;
  --diag-text-muted: #4e4a43;
  --diag-arrow:      #6b665d;
  --diag-fill-mix:   10%;
  --diag-fill-base:  #ffffff;
  --co-title-text:   #ffffff;
}

@page { size: A4; margin: 0; }   /* full-bleed: margins recreated as padding below */

@media print {
  body { display: block; font-size: 11.2pt; line-height: 1.58; }
  /* Fill the whole sheet (incl. @page margins) with the theme background.
     Chromium propagates only the ROOT element's background into the margin
     band; painting <body> alone leaves the margins on the default canvas
     (black under color-scheme: dark). Setting html fixes the mismatch. */
  html, body { background: var(--bg);
    -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* Callout title pill: drop the -11px absolute overhang into normal flow so a
     page break can't slice it (absolute boxes are ignored by break-inside). */
  .callout { padding-top: 18px; }
  .callout .co-title { position: static; top: auto; left: auto;
    display: inline-block; margin: 0 0 8px; }
  #sidebar, #sidebar-toggle, #all-courses, #theme-toggle, .copy-btn, .hlink, #lightbox, .xref-popup { display: none !important; }
  #main { margin-left: 0; padding: 0; }
  /* @page margin is 0 so the background reaches the paper edge; the
     text inset lives here instead. Note: top/bottom padding only
     insets the first/last page (a browser-print limitation); left/right
     inset every page. */
  .content { max-width: none; padding: 16mm 15mm; box-sizing: border-box; }
  a { color: var(--link); }
  /* break control */
  figure, .callout, details.fold, .table-wrap, pre, blockquote { break-inside: avoid; }
  h2 { break-after: avoid; break-before: auto; }
  h3, h4 { break-after: avoid; }
  .doc-header { break-after: avoid; }
  tr { break-inside: avoid; }
  thead { display: table-header-group; }   /* repeat table headers */
  /* open all folded content so nothing is lost on paper */
  details.fold, details.callout { }
  details > summary::before { content: "" !important; }
  /* floats keep working in print; captions stay inside figures by construction */
  figure.diagram { overflow: visible; }
  .margin-note { float: right; clear: right; width: 34%; margin: 2px 0 10px 14px;
    padding: 8px 12px; background: var(--surface); border-left: 2px solid var(--accent);
    border-radius: 0; }
}