/* Copyright (c) 2026 Moiz Saeed (Bubble Laboratories). All rights reserved.
   SPDX-License-Identifier: LicenseRef-Folio-1.0 (Folio License 1.0, see LICENSE) */
/* Folio — reader stylesheet */

/* One palette, both themes, each value written once. `light-dark()` chooses from
   the element's `color-scheme`, which replaces a second `prefers-color-scheme`
   block that was a hand-maintained copy of these colours — and which only ever
   matched `:root`, so inside a shadow root (where `:root` matches nothing) the
   embed had no dark mode at all. It also makes the theme *declarable*: an
   attribute can set `color-scheme` and win over the media query without the
   palette existing twice. */
:root, :host, .folio {
  color-scheme: light dark;   /* follow the OS unless something below overrides */

  --paper: var(--folio-paper, light-dark(#FAF9F6, #161513));
  --ink: var(--folio-ink, light-dark(#1C1B19, #E8E5DF));
  --ink-2: var(--folio-ink-secondary, light-dark(#6E6A63, #98938A));
  --ink-3: var(--folio-ink-tertiary, light-dark(#76716A, #85807A));   /* ≥4.5:1 on paper in both themes (WCAG AA) */
  --hairline: var(--folio-rule, light-dark(rgba(28, 27, 25, 0.12), rgba(232, 229, 223, 0.15)));
  --hairline-soft: light-dark(rgba(28, 27, 25, 0.07), rgba(232, 229, 223, 0.08));
  --code-bg: var(--folio-code-background, light-dark(rgba(28, 27, 25, 0.045), rgba(232, 229, 223, 0.055)));
  --accent: var(--folio-accent, light-dark(#3D5AC8, #93A8F4));
  --mark: var(--folio-find-highlight, light-dark(rgba(255, 200, 60, 0.45), rgba(255, 190, 60, 0.30)));
  --mark-active: light-dark(rgba(255, 160, 20, 0.75), rgba(255, 170, 40, 0.55));
  --thumb: light-dark(rgba(28, 27, 25, 0.28), rgba(232, 229, 223, 0.30));
  --hud-bg: light-dark(rgba(250, 249, 246, 0.86), rgba(22, 21, 19, 0.82));

  /* A reader's own mark, and deliberately not `--mark`: find's yellow is a
     transient the app painted and will take away again, so it is allowed to
     shout. A highlight is the reader's and stays on the page for years, so it
     is the warm ochre of a soft pencil on cream rather than a signal colour —
     it has to sit under running text without making that text a warning. The
     pool is the same ink where a wet mark settles at the foot of the stroke. */
  --annot: light-dark(rgba(206, 158, 62, 0.26), rgba(214, 168, 82, 0.19));
  --annot-pool: light-dark(rgba(168, 118, 26, 0.46), rgba(220, 176, 96, 0.40));
  --annot-ink: light-dark(#8A5F14, #D3A960);

  /* the scrubber reads as one continuous ribbon: unread ink, read blue */
  --scrub-blue: light-dark(#0089D0, #2CB2F0);
  --scrub-rest: light-dark(rgba(28, 27, 25, 0.22), rgba(232, 229, 223, 0.24));
  /* How visible the ribbon is when nothing is happening — not scrolling, not
     hovered, not being dragged. Zero here is a reading decision, not a default
     nobody chose: in the app the scrubber is something you reach for, and a
     permanent rail down the right margin is one more thing on screen while you
     read. A site embedding the reader is often making the opposite trade, using
     it as a visible table of contents, so set `--folio-scrub-idle: 1` above the
     page and it stays up. Fractions work and are usually the better answer: at
     0.35 the ribbon is quietly always there and still brightens on scroll or
     hover. Named apart from the internal for the same reason as
     `--folio-measure`, below — and so keeping the scrubber up stops being an
     override of `#scrub-track`, which is ours to rename. */
  --scrub-idle: var(--folio-scrub-idle, 0);

  --fs: var(--folio-font-size, 1.1875rem);          /* body size, adjustable */
  /* A host can hand Folio its own column: set `--folio-measure` anywhere above
     the element and it inherits through the shadow boundary. Named separately
     from `--measure` so a host cannot collide with an internal by accident, and
     so "use my column" stays a declaration rather than a fork of this file —
     rather than an edit to this file. */
  --measure: var(--folio-measure, 42rem);

  /* figures and charts: every series colour is at least 3:1 against the paper
     and every label 4.5:1, in both themes (package/build.sh checks it) */
  --chart-1: var(--folio-chart-1, light-dark(#2F5FB3, #7FA6F0));
  --chart-2: var(--folio-chart-2, light-dark(#B35900, #F0A050));
  --chart-3: var(--folio-chart-3, light-dark(#2E7D4F, #6CC08C));
  --chart-4: var(--folio-chart-4, light-dark(#B33A5E, #F08AA8));
  --chart-5: var(--folio-chart-5, light-dark(#6B4FA0, #B49CEB));
  --chart-6: var(--folio-chart-6, light-dark(#1D7680, #5CC8CF));
  --chart-gain: var(--folio-chart-gain, light-dark(#2E7D4F, #6CC08C));
  --chart-loss: var(--folio-chart-loss, light-dark(#B3261E, #F28B82));
  --chart-axis: var(--folio-chart-axis, light-dark(#6E6A63, #98938A));
  --chart-label: var(--folio-chart-label, light-dark(#5E5A54, #A8A39A));
  --chart-grid: var(--folio-chart-grid, light-dark(rgba(28, 27, 25, 0.10), rgba(232, 229, 223, 0.12)));
  --figure-surface: var(--folio-figure-surface, transparent);

  --serif: var(--folio-serif, ui-serif, "New York", Charter, Georgia, serif);
  --sans: var(--folio-sans, -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif);
  --mono: var(--folio-mono, ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace);

  /* code palette */
  --tok-comment: light-dark(#79726A, #8C867D);   /* AA on code background */
  --tok-keyword: light-dark(#B04A2F, #E0937A);
  --tok-string: light-dark(#3D6B36, #A3C495);
  --tok-number: light-dark(#8A5A00, #D9B36A);
  --tok-title: light-dark(#34548A, #92B0E8);
  --tok-type: light-dark(#6E4FA3, #B79FE0);
}

/* An explicit theme beats the OS. `color-scheme` inherits, so setting it on the
   root of the tree — the host element of a shadow tree, or a `.folio` wrapper in
   the light DOM — reaches every `light-dark()` underneath it. `theme="auto"`
   needs no rule: it is the declaration above. */
:host([theme="light"]), .folio[data-folio-theme="light"] { color-scheme: light; }
:host([theme="dark"]),  .folio[data-folio-theme="dark"]  { color-scheme: dark; }

/* on the wide-gamut displays every Mac ships with, sRGB #0089D0 is a duller
   blue than the panel can actually make. Ask for the real one. */
@supports (color: color(display-p3 0 0.59 0.9)) {
  :root, :host, .folio {
    --scrub-blue: light-dark(color(display-p3 0 0.535 0.827),
                             color(display-p3 0.213 0.7 0.945));
  }
}

* { box-sizing: border-box; }

html, body, :host, .folio {
  margin: 0;
  padding: 0;
  background: var(--paper);
}

html { scrollbar-width: none; }

/* Embedding: the app owns a page, an embed owns a box. `body` and `:root` match
   nothing inside a shadow root, so without these the typography and the paper
   simply don't apply and the document inherits the host site's font — legible
   proof of which is that it renders dark ink on whatever colour the host is. */
:host { display: block; }
::-webkit-scrollbar { display: none; }

body, :host, .folio {
  font-family: var(--serif);
  font-size: var(--fs);
  line-height: 1.65;
  color: var(--ink);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

::selection { background: rgba(150, 160, 220, 0.30); }

#stage {
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
body.scrubbing #stage {
  opacity: 0.55;
}

.content {
  overflow-wrap: break-word;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 4.5rem 2.5rem 7rem;
}

/* ---------- prose ---------- */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.22;
  color: var(--ink);
  position: relative;
  text-wrap: balance;
}

h1 { font-size: 2.1em;  margin: 2.6em 0 0.7em; letter-spacing: -0.015em; }
h2 { font-size: 1.5em;  margin: 2.2em 0 0.6em; letter-spacing: -0.01em; }
h3 { font-size: 1.18em; margin: 1.8em 0 0.5em; }
h4 { font-size: 1em;    margin: 1.6em 0 0.4em; }
h5, h6 {
  font-family: var(--sans);
  font-size: 0.78em;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
  margin: 1.6em 0 0.4em;
}

.content > h1:first-child {
  margin-top: 0;
  font-size: 2.5em;
}
.content > h1:first-child::after {
  content: "";
  display: block;
  width: 2.2rem;
  border-bottom: 1px solid var(--hairline);
  margin-top: 0.55em;
}

.heading-anchor {
  position: absolute;
  inset-inline-start: -1.1em;
  width: 1.1em;
  font-size: 0.8em;
  font-family: var(--sans);
  font-weight: 400;
  color: var(--ink-3);
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.18s ease;
  line-height: inherit;
  /* a site with its own section links turns these off: --folio-permalinks: none */
  display: var(--folio-permalinks, inline);
}
h1:hover .heading-anchor, h2:hover .heading-anchor, h3:hover .heading-anchor,
h4:hover .heading-anchor, h5:hover .heading-anchor, h6:hover .heading-anchor,
.heading-anchor:focus-visible { opacity: 1; }

/* Present to a screen reader, absent from the page. `clip-path: inset(50%)`
   rather than `display: none` or `visibility: hidden`, either of which would
   take the name back out of the accessibility tree and undo the point of
   having it. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

p { margin: 0 0 1.1em; }

a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s ease;
}
a:hover { text-decoration-color: var(--accent); }

strong { font-weight: 650; }

blockquote {
  margin: 1.6em 0;
  padding-inline: 1.4em 0;
  border-inline-start: 2px solid var(--hairline);
  color: var(--ink-2);
  font-style: italic;
}
blockquote strong { color: var(--ink); }
blockquote blockquote { margin: 0.8em 0; }

ul, ol { padding-inline-start: 1.6em; margin: 0 0 1.1em; }
li { margin: 0.3em 0; }
li > p { margin-bottom: 0.5em; }
ul { list-style: none; }
ul > li::before {
  content: "–";
  position: absolute;
  margin-inline-start: -1.4em;
  color: var(--ink-3);
}
ul.contains-task-list > li::before { content: none; }

/* task lists */
.task-list-item { position: relative; }
.task-list-item input[type="checkbox"] {
  appearance: none;
  width: 0.95em;
  height: 0.95em;
  border: 1.5px solid var(--ink-3);
  border-radius: 4px;
  margin-inline-end: 0.55em;
  vertical-align: -0.12em;
  position: relative;
}
.task-list-item input[type="checkbox"]:checked {
  background: var(--ink-2);
  border-color: var(--ink-2);
}
.task-list-item input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 0.24em; top: 0.06em;
  width: 0.28em; height: 0.5em;
  border: solid var(--paper);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
.task-list-item input[type="checkbox"]:checked + label,
.task-list-item input[type="checkbox"]:checked ~ * {
  color: var(--ink-3);
}

/* A live box says so by behaving like a control — it takes the pointer and it
   takes focus. A box Folio will not write stays exactly the box it has always
   been, which is the honest way for the difference to read: one is a control,
   the other is a picture of one. */
.task-list-item input[type="checkbox"]:enabled { cursor: pointer; }
.task-list-item input[type="checkbox"]:enabled:hover { border-color: var(--ink-2); }
.task-list-item input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* the write landed: the box is briefly ringed in the reader's blue, so the
   change is visible where the reader was already looking */
@keyframes task-written {
  from { box-shadow: 0 0 0 3px color-mix(in srgb, var(--scrub-blue) 45%, transparent); }
  to   { box-shadow: 0 0 0 3px transparent; }
}
.task-list-item input[type="checkbox"].task-written {
  animation: task-written 1.5s ease-out;
}
.task-list-item input[type="checkbox"].task-writing { opacity: 0.55; }

hr {
  border: none;
  margin: 3em 0;
  text-align: center;
}
hr::after {
  content: "···";
  display: block;
  font-size: 1.1em;
  letter-spacing: 0.8em;
  margin-left: 0.8em; /* optical centering vs letter-spacing */
  color: var(--ink-3);
}

/* ---------- code ---------- */

code {
  font-family: var(--mono);
  font-size: 0.82em;
  background: var(--code-bg);
  border-radius: 5px;
  padding: 0.15em 0.4em;
}

.code-block {
  position: relative;
  margin: 1.5em 0;
}
.code-block pre {
  margin: 0;
  background: var(--code-bg);
  border-radius: 10px;
  padding: 1.05em 1.25em;
  overflow-x: auto;
  line-height: 1.55;
}
/* a fenced block is a left-to-right artifact even when the prose around it
   runs the other way — indentation is meaningless mirrored */
.content pre { direction: ltr; }
.code-block pre code {
  background: none;
  padding: 0;
  border-radius: 0;
  font-size: 0.8em;
}
.code-block::before {
  content: attr(data-lang);
  position: absolute;
  top: 0.65em;
  right: 1em;
  font-family: var(--sans);
  font-size: 0.65rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-3);
  pointer-events: none;
}
.code-block[data-lang=""]::before { content: none; }

.hljs-comment, .hljs-quote { color: var(--tok-comment); font-style: italic; }
.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-tag { color: var(--tok-keyword); }
.hljs-string, .hljs-regexp, .hljs-addition { color: var(--tok-string); }
.hljs-number, .hljs-symbol, .hljs-bullet, .hljs-meta, .hljs-link { color: var(--tok-number); }
.hljs-title, .hljs-section, .hljs-name, .hljs-attribute, .hljs-attr, .hljs-selector-id, .hljs-selector-class { color: var(--tok-title); }
.hljs-type, .hljs-class .hljs-title, .hljs-built_in, .hljs-template-variable, .hljs-variable { color: var(--tok-type); }
.hljs-deletion { color: var(--tok-keyword); }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: 600; }

/* A block the highlighter declined to colour otherwise reads as Folio not
   knowing the language. The note sits under the block, in the caption voice
   the figures already use, and only that block ever mentions it. */
.code-note {
  font-family: var(--sans);
  font-size: 0.66rem;
  letter-spacing: 0.05em;
  color: var(--ink-3);
  text-align: right;
  margin-top: 0.55em;
}

/* ---------- bidirectional text ---------- */

/* Bidi controls are invisible by definition, which is what makes them useful
   for making link text disagree with its target. Folio drops them from prose,
   where dir="auto" already does everything they legitimately did, and shows
   them inside code, where a hidden override *is* the thing worth seeing. */
.bidi-ctl {
  font-family: var(--sans);
  font-size: 0.62em;
  font-weight: 650;
  letter-spacing: 0.04em;
  vertical-align: 0.1em;
  padding: 0.1em 0.32em;
  margin: 0 0.15em;
  border-radius: 4px;
  background: color-mix(in srgb, var(--tok-keyword) 16%, transparent);
  color: var(--tok-keyword);
  direction: ltr;
  unicode-bidi: isolate;
  cursor: help;
}

/* ---------- tables ---------- */

table {
  border-collapse: collapse;
  margin: 1.6em 0;
  width: 100%;
  font-size: 0.88em;
  font-family: var(--sans);
  line-height: 1.5;
  display: block;
  overflow-x: auto;
}
th, td {
  text-align: start;
  padding-block: 0.55em;
  padding-inline: 0 1em;
  border-bottom: 1px solid var(--hairline-soft);
  vertical-align: top;
}
th {
  font-weight: 600;
  font-size: 0.92em;
  border-bottom: 1px solid var(--hairline);
}
tr:last-child td { border-bottom: none; }

/* ---------- figures & media ---------- */

img, video {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
}
figure {
  margin: 2em 0;
  text-align: center;
}
figcaption {
  font-family: var(--sans);
  font-size: 0.72em;
  color: var(--ink-2);
  margin-top: 0.9em;
  line-height: 1.5;
}

/* wide content escapes the 42rem measure, stays centered */
.breakout {
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: min(90vw, 68rem);
}
table.breakout { display: block; overflow-x: auto; }

/* ---------- mermaid ---------- */

.mermaid-figure {
  margin: 2.2em auto;
  text-align: center;
}
.mermaid-figure svg {
  max-width: 100%;
  height: auto;
}

/* ---------- callouts ---------- */

.callout {
  margin: 1.6em 0;
  padding: 0.9em 1.25em;
  border-radius: 10px;
  background: var(--code-bg);
  border-inline-start: 3px solid var(--ink-3);
  font-size: 0.94em;
}
.callout p:last-child { margin-bottom: 0; }
.callout-title {
  font-family: var(--sans);
  font-size: 0.68rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  margin-bottom: 0.5em;
  color: var(--ink-2);
}
.callout-note      { border-inline-start-color: #5B7BD5; }
.callout-tip       { border-inline-start-color: #4F9153; }
.callout-important { border-inline-start-color: #8A63C9; }
.callout-warning   { border-inline-start-color: #C08A2D; }
.callout-caution   { border-inline-start-color: #C05B4D; }
.callout-note      .callout-title { color: #5B7BD5; }
.callout-tip       .callout-title { color: #4F9153; }
.callout-important .callout-title { color: #8A63C9; }
.callout-warning   .callout-title { color: #C08A2D; }
.callout-caution   .callout-title { color: #C05B4D; }

/* ---------- math ---------- */

.math[data-tex], .math-block[data-tex] {
  font-family: var(--mono);
  font-size: 0.85em;
  color: var(--ink-2);
}
.math .katex, .math-block .katex { color: var(--ink); font-size: 1.06em; }
.math-block {
  margin: 1.6em 0;
  text-align: center;
  overflow-x: auto;
}

/* ---------- wikilinks ---------- */

a.wikilink {
  text-decoration-style: dotted;
}

/* ---------- outline sidebar ---------- */

/* ---- figures: ::: figure, numbered and captioned ------------------------ */
.folio-figure {
  margin: 2em 0;
  background: var(--figure-surface);
}
.folio-figure > p:only-of-type { margin: 0; }
.folio-figure img, .folio-figure svg, .folio-figure video {
  display: block;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
}
.folio-figure figcaption {
  margin-top: 0.7em;
  font-family: var(--sans);
  font-size: 0.82em;
  line-height: 1.45;
  color: var(--ink-2);
}
.folio-figure .fig-label { color: var(--ink); font-weight: 600; }
/* wide and full figures leave the measure, centred on it */
.folio-figure[data-width="wide"] {
  width: min(calc(100vw - 4rem), 64rem);
  margin-inline: calc(50% - min(calc(100vw - 4rem), 64rem) / 2);
}
.folio-figure[data-width="full"] {
  width: calc(100vw - 2rem);
  margin-inline: calc(50% - (100vw - 2rem) / 2);
}
.fig-ref { white-space: nowrap; }
.fig-ref.is-missing { color: var(--ink-3); border-bottom: 1px dotted var(--ink-3); }

/* ---- charts: ```chart, drawn by the renderer ---------------------------- */
.folio-chart-block { margin: 1.8em 0; background: var(--figure-surface); }
.folio-chart { display: block; width: 100%; height: auto; font-family: var(--sans); overflow: visible; }
.folio-chart .chart-title { fill: var(--ink); font-size: 14px; font-weight: 600; }
.folio-chart .chart-label { fill: var(--chart-label); font-size: 12px; font-variant-numeric: tabular-nums; }
.folio-chart .chart-grid { stroke: var(--chart-grid); stroke-width: 1; }
.folio-chart .chart-axis { stroke: var(--chart-axis); stroke-width: 1; }
.folio-chart path.chart-series { fill: none; stroke-width: 2.25; stroke-linejoin: round; stroke-linecap: round; }
.folio-chart path.chart-1 { stroke: var(--chart-1); } .folio-chart rect.chart-1 { fill: var(--chart-1); }
.folio-chart path.chart-2 { stroke: var(--chart-2); } .folio-chart rect.chart-2 { fill: var(--chart-2); }
.folio-chart path.chart-3 { stroke: var(--chart-3); } .folio-chart rect.chart-3 { fill: var(--chart-3); }
.folio-chart path.chart-4 { stroke: var(--chart-4); } .folio-chart rect.chart-4 { fill: var(--chart-4); }
.folio-chart path.chart-5 { stroke: var(--chart-5); } .folio-chart rect.chart-5 { fill: var(--chart-5); }
.folio-chart path.chart-6 { stroke: var(--chart-6); } .folio-chart rect.chart-6 { fill: var(--chart-6); }
.chart-data { margin-top: 0.4em; font-family: var(--sans); font-size: 0.8em; color: var(--ink-2); }
.chart-data summary { cursor: pointer; }
.chart-data table { margin-top: 0.5em; }

#outline {
  position: fixed;
  top: var(--folio-chrome-top, 0px); left: 0; bottom: 0;
  width: 264px;
  transform: translateX(-100%);
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  background: var(--hud-bg);
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  border-right: 1px solid var(--hairline-soft);
  z-index: 55;
  overflow-y: auto;
  padding: 3.4rem 0.6rem 2rem;
}
body.outline-open #outline { transform: translateX(0); }
body.outline-open .content { padding-left: calc(2.5rem + 132px); }
@media (min-width: 1100px) {
  body.outline-open .content { padding-left: 2.5rem; }
}
.outline-item {
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--ink-2);
  padding: 5px 10px;
  border-radius: 6px;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.outline-item:hover { background: var(--code-bg); color: var(--ink); }
.outline-item.active { color: var(--ink); font-weight: 600; box-shadow: inset 2px 0 0 var(--scrub-blue); }
.outline-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.outline-item.lvl-1 { font-weight: 600; color: var(--ink); margin-top: 8px; }
.outline-item.lvl-2 { padding-inline-start: 22px; }
.outline-item.lvl-3 { padding-inline-start: 34px; font-size: 12px; }

/* ---------- lightbox ---------- */

#lightbox {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  z-index: 70;
  cursor: zoom-out;
}
body.lightbox-open #lightbox { display: flex; }
#lightbox img {
  max-width: 92vw;
  max-height: 92vh;
  border-radius: 8px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.25);
  animation: lightbox-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes lightbox-in {
  from { transform: scale(0.94); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
.content img { cursor: zoom-in; }

/* ---------- frontmatter ---------- */

.frontmatter {
  font-family: var(--sans);
  font-size: 0.72rem;
  color: var(--ink-2);
  border: 1px solid var(--hairline-soft);
  border-radius: 10px;
  padding: 0.9em 1.2em;
  margin: 0 0 2.5em;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35em 1.8em;
}
.frontmatter .fm-item { display: flex; gap: 0.5em; }
.frontmatter .fm-key {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--ink-3);
}

/* ---------- footnotes ---------- */

/* The marker itself — `sup.footnote-ref` — is set with `sup.cite` under
   citations below. They are the same typographic object, and letting them drift
   apart is how one apparatus ends up with two conventions in it. */
a.footnote-backref {
  text-decoration: none;
  color: var(--ink-3);
}
a.footnote-backref:hover { color: var(--accent); }
.footnotes {
  margin-top: 4em;
  font-size: 0.82em;
  color: var(--ink-2);
}
.footnotes-sep { margin: 3em 0 1.5em; }
.footnotes-sep::after { content: ""; }
.footnotes-sep {
  border-bottom: 1px solid var(--hairline-soft);
  width: 6rem;
  text-align: start;
}
.footnotes ol { padding-inline-start: 1.2em; }

/* ---------- version lens: changed blocks flash ---------- */

.block-new {
  animation: block-flash 2.2s ease-out;
  border-radius: 6px;
}
@keyframes block-flash {
  0%   { background: color-mix(in srgb, var(--accent) 14%, transparent); }
  100% { background: transparent; }
}

/* ---------- citations ---------- */

/* The marker is a superior numeral, not a badge. Two things make it one.
   It is set in the document's own face at the size a superior is cut at — a
   marker in a different family is the seam you see first, and it is the whole
   complaint about apparatus bolted on afterwards. And it is raised by
   `position: relative`, which paints the glyph above the baseline without
   layout ever hearing about it.
   `line-height: 0` is the other half, and the load-bearing one: an inline box
   with no leading contributes nothing to the line box, so a paragraph carrying
   markers sets to exactly the rhythm of one without. The UA default —
   `vertical-align: super` at `font-size: smaller` — does the opposite: it opens
   the line box by a couple of px, once, on whichever lines happen to carry a
   marker, and that uneven leading down a page is the tell. */
sup.cite, sup.footnote-ref {
  font-size: 0.64em;
  line-height: 0;
  vertical-align: baseline;      /* beats the UA's `super` */
  position: relative;
  top: -0.42em;                  /* ≈0.27em of body — the figure's cap meets the text's */
  font-variant-numeric: lining-nums tabular-nums;
  margin-inline-start: 0.08em;   /* clear of the word before it, still tight to it */
  white-space: nowrap;
}
sup.cite a, sup.footnote-ref a {
  font-family: inherit;          /* a superior belongs to the text, not to the UI */
  font-weight: 550;              /* figures this small need a hair more colour to hold */
  color: var(--accent);
  text-decoration: none;
  /* the hit target is bought in the block direction, where there is room: inline
     padding also has to sit between the figures of a run, and 0.16em there was
     enough to turn "3,4,5" into "3 , 4 , 5". Neither axis touches the line box. */
  padding: 0.35em 0.08em;
  border-radius: 3px;
}
sup.cite a:hover, sup.footnote-ref a:hover,
sup.cite a:focus-visible, sup.footnote-ref a:focus-visible {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
sup.cite a:focus-visible, sup.footnote-ref a:focus-visible {
  outline: 1.5px solid var(--accent);
  outline-offset: 0;
}
/* followed a back-link here: say which marker you came back to, then stop */
sup.cite a:target, sup.footnote-ref a:target { background: var(--mark); }

/* A sentence carrying three sources must read as three numbers, not as one long
   one. The separation is space — about four fifths of a figure's width, which
   is more than sits between a word and the marker after it, so a run reads as a
   run and its members read as separate.
   Print would set them "3,4,5", and a comma is the stronger separator. It is
   not here because CSS cannot ask for it correctly: `sup.cite + sup.cite` is
   the only hook the markup offers, and the sibling combinator skips text, so it
   also matches two markers with a whole sentence between them — which puts a
   comma in front of a marker that opens a clause. A gap that misfires the same
   way is invisible; a comma that misfires is a wrong glyph in the prose. The
   run needs a hook of its own before the comma can come back.
   No wrap handling is needed: two inline boxes with no whitespace between them
   offer no break opportunity, so a run cannot split across lines. */
sup.cite + sup.cite { margin-inline-start: 0.3em; }

/* ---------- the reference list ---------- */

.references {
  margin-top: 4em;
  font-size: 0.82em;             /* the apparatus sets a size down, as the footnotes do */
  color: var(--ink-2);
}
/* the same short rule the footnotes open with, so the two apparatus blocks read
   as one register rather than as two conventions that met in a document */
.references::before {
  content: "";
  display: block;
  width: 6rem;
  border-top: 1px solid var(--hairline-soft);
  margin-bottom: 1.5em;
}
.references h5 { margin-top: 0; }

.reference-list {
  list-style: none;              /* the figure is drawn below, where it can be aligned */
  padding-inline-start: 0;
  margin: 0;
}

/* A reference list, set as one. The entry starts at a fixed rail and every
   wrapped line returns to it; the figure lives in the indent, right-aligned so
   9 and 10 agree on the period, in tabular figures so the column is a column.
   `counter(list-item)` rather than a counter of our own: that one belongs to
   the <ol>, so `start` and `value` still mean what they say if a host ever
   renumbers. The indent is padding on the entry rather than on the list so the
   figure sits *inside* the entry's box — which is what lets `:target` below
   highlight an entry with its number instead of beside it. */
.reference {
  position: relative;
  padding-inline-start: 2.6em;
  /* enough that an entry which wraps onto a second line still reads as one
     entry rather than as two; run-on entries need the space between them to be
     larger than the space inside them */
  margin: 0.7em 0;
  overflow-wrap: anywhere;       /* a bare URL does not get to widen the page */
}
.reference::before {
  content: counter(list-item) ".";
  position: absolute;
  inset-inline-start: 0;
  width: 2.1em;
  text-align: end;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--ink-3);
}

/* The label is the entry; that it is also a link is not the point of it. A
   reference list in accent blue with a rule under every line is a list of links
   — which is the thing this is trying not to be. Ink, and a hairline that only
   becomes a link when you go looking for one. */
.ref-target {
  color: var(--ink);
  text-decoration-color: var(--hairline-soft);
  text-underline-offset: 2px;    /* a rule under a whole block of entries reads as
                                    texture; keeping it close keeps it a hairline */
}
.ref-target:hover { color: var(--accent); text-decoration-color: var(--accent); }

/* Domain and status are the quieter register — sans, a size down, ink-3: the
   voice figcaptions and the colophon are already set in. */
.ref-domain, .ref-status {
  font-family: var(--sans);
  font-size: 0.84em;
  color: var(--ink-3);
}
.ref-domain {
  margin-inline-start: 0.55em;
  white-space: nowrap;           /* a hostname broken across lines is unreadable */
}
.ref-status { margin-inline-start: 0.55em; }

/* `data-status` is the host's vocabulary and we will not have seen all of it,
   so what gets drawn is the *presence* of a status: one small mark before the
   word, coloured by a custom property. A value we have never met takes the
   default and sets correctly — quiet ink, hollow mark — which is the only
   behaviour that survives a word we did not anticipate.
   Two shifts are worth making, and both move only the mark. `ok` and `self` are
   the expected outcomes, so they stay hollow and a clean list is a column of
   empty rings. The ones that mean "this is not quite the source you asked for"
   fill in, and the eye finds them without reading a line. */
.ref-status {
  --ref-mark: var(--ink-3);
  --ref-fill: var(--ref-mark);
}
.ref-status[data-status="ok"],
.ref-status[data-status="self"] { --ref-fill: transparent; }
.ref-status[data-status="paywall"],
.ref-status[data-status="archived"] { --ref-mark: var(--tok-number); }
.ref-status::before {
  content: "";
  display: inline-block;
  width: 0.45em;
  height: 0.45em;
  border: 1px solid var(--ref-mark);
  border-radius: 50%;
  background: var(--ref-fill);
  vertical-align: 0.03em;
  margin-inline-end: 0.4em;
}

/* The back-link is furniture: findable, never the first thing seen. */
.ref-back {
  margin-inline-start: 0.5em;
  color: var(--ink-3);
  text-decoration: none;
}
.ref-back:hover { color: var(--accent); }
.ref-back + .ref-back { margin-inline-start: 0.3em; }

/* Arriving from a marker: the entry says so, in the yellow the find bar already
   uses, and says nothing else. `outline` rather than padding, because the
   highlight wants air around it and the entry must not move to get it. */
.reference:target {
  background: color-mix(in srgb, var(--mark) 55%, transparent);
  outline: 0.35em solid color-mix(in srgb, var(--mark) 55%, transparent);
  border-radius: 4px;
}

/* ---------- sidenotes ---------- */

/* Folio's measure is 42rem inside whatever the window is. Past a point there is
   a margin either side of it doing nothing, and that margin is where a
   scholarly edition has always put its notes.
   The mechanism is a float with a negative inline-end margin: width + gap comes
   back off the margin, so the float's margin box lands entirely outside the
   column and no line of text is shortened by it. A float — not absolute
   positioning — because `clear` makes two notes from adjacent lines stack
   instead of overlap, and overlapping is the failure mode that actually shows
   up in a document with a dense apparatus. A float takes the top of the line
   box it appears in, so a note emitted beside its marker lands beside its
   marker; one emitted after the paragraph lands at the paragraph's foot, which
   is the best that can be had without measuring text.
   Below the width where the margin exists there is nowhere to put it, so it is
   not put anywhere and the end list carries the document. `screen and` is doing
   that job for print too — paper has one apparatus, never two. */
.sidenote { display: none; }

@media screen and (min-width: 1140px) {
  .sidenote {
    --sidenote-w: 12rem;
    --sidenote-gap: 1.6rem;
    display: block;
    float: inline-end;
    clear: inline-end;
    width: var(--sidenote-w);
    margin-inline-end: calc(-1 * (var(--sidenote-w) + var(--sidenote-gap)));
    margin-block: 0.3em 1.1em;
    font-size: 0.75em;
    line-height: 1.5;
    color: var(--ink-2);
    text-align: start;
    hyphens: auto;               /* 12rem is a narrow measure; let words break */
  }
  /* the note carries its own number, in the marker's treatment at the note's
     size — a margin note that does not say which marker it answers is decoration */
  .sidenote::before {
    content: attr(data-ref);
    font-size: 0.8em;
    font-weight: 550;
    font-variant-numeric: lining-nums;
    color: var(--accent);
    line-height: 0;
    position: relative;
    top: -0.4em;
    margin-inline-end: 0.35em;
  }
  .sidenote p { margin: 0 0 0.5em; }
  .sidenote p:last-child { margin-bottom: 0; }
}

/* ---------- annotations ---------- */

/* A highlight has to read as a mark made *on* the page, not as a rectangle the
   browser filled in behind it. Three things do that and none of them is colour.
   The wash starts a little below the cap line and stops a little above the
   descender, so the stroke has the height of a pen nib rather than of a line
   box. It settles at the foot — a second, denser band where a wet mark pools
   against the baseline — which is the part the eye actually reads as ink. And
   it bleeds a hair past the glyphs on either side, because a hand-drawn stroke
   overshoots the word and a selection rectangle never does.
   `box-decoration-break: clone` is what makes a highlight over three lines three
   strokes instead of one long box with two open ends. */
mark.annot {
  color: inherit;
  background-color: transparent;
  background-image: linear-gradient(to bottom,
    transparent 7%,
    var(--annot) 15%,
    var(--annot) 84%,
    var(--annot-pool) 84%,
    var(--annot-pool) 93%,
    transparent 93%);
  padding: 0.06em 0.14em;
  margin: 0 -0.14em;
  border-radius: 2px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* A highlight carrying a note says so in the mark: the ink settles twice.
   Below the sidenote breakpoint the margin is gone and the note sets as a block
   further down, so this is the only thing tying the two together at the point
   the eye passes the sentence — it has to be legible without the margin. */
mark.annot[data-noted] {
  background-image: linear-gradient(to bottom,
    transparent 7%,
    var(--annot) 15%,
    var(--annot) 78%,
    var(--annot-pool) 78%,
    var(--annot-pool) 85%,
    transparent 85%,
    transparent 90%,
    var(--annot-pool) 90%,
    var(--annot-pool) 97%,
    transparent 97%);
}

mark.annot:hover { background-color: color-mix(in srgb, var(--annot) 45%, transparent); }
/* arrived from the notes list: say which one, then stop saying it */
mark.annot.lit { background-color: color-mix(in srgb, var(--annot) 90%, transparent); }

/* The second tenant of the sidenote apparatus. It inherits the float, the
   width, the gap and the clearing from `.sidenote` and changes only what makes
   it a reader's note rather than a source: the marker takes the annotation's
   ochre instead of the citation blue, and the note is a control, so it does not
   join a selection of the prose it sits beside. */
/* A note is seated next to its mark, and a mark can be inside anything — an
   emphasis, a heading, a table cell. Inherited typography would then make the
   note italic, or bold, or set at a heading's size, so the note states its own:
   upright, at a size struck from the body measure rather than from whatever
   element it happens to be standing in. It stays in the document's serif,
   because the apparatus it is a tenant of is set in the document's serif and
   the ochre marker is enough to say whose voice it is. */
.sidenote.annot-note {
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  white-space: pre-wrap;         /* a note is typed, so its own line breaks are text */
  font-style: normal;
  font-weight: 400;
  font-variant: normal;
  letter-spacing: normal;
  text-transform: none;
}
@media screen and (min-width: 1140px) {
  .sidenote.annot-note {
    font-size: calc(var(--fs) * 0.63);
  }
  .sidenote.annot-note::before { color: var(--annot-ink); }
  .sidenote.annot-note:hover { color: var(--ink); }
}

/* Below the breakpoint there is no margin to put a note in, and on paper there
   is one apparatus and it is not this one — but a note the reader wrote is not
   a citation, and hiding it is losing it. So it sets as a block where it
   already stands: immediately after the sentence it is about, indented off a
   rule in the note's own register. It interrupts the paragraph, which is
   exactly what a marginal hand does when the margin runs out, and it is the
   only placement that keeps a note next to the words it answers without
   measuring text or inventing a second panel to hide it in. */
@media print, screen and (max-width: 1139.98px) {
  .sidenote.annot-note {
    display: block;
    float: none;
    clear: both;
    width: auto;
    margin: 0.9em 0 1.1em;
    padding-inline-start: 0.95em;
    border-inline-start: 2px solid var(--annot-pool);
    font-size: calc(var(--fs) * 0.72);
    line-height: 1.5;
    color: var(--ink-2);
    text-align: start;
  }
  .sidenote.annot-note::before {
    content: attr(data-ref);
    font-size: 0.82em;
    font-weight: 650;
    font-variant-numeric: lining-nums;
    color: var(--annot-ink);
    margin-inline-end: 0.5em;
  }
}

/* ---------- the toast ---------- */

/* Folio writing to a reader's document is a small thing that should never be a
   silent one, so it says which file it wrote to, once, and takes it away again.
   The find bar's material, because it is the same kind of object: something the
   app put in front of the page for exactly as long as it is needed. It does not
   exist at rest — the element is not built until there is something to say. */
#folio-toast {
  position: fixed;
  bottom: 20px;
  right: 48px;
  transform: translateY(6px);
  z-index: 64;
  font-family: var(--sans);
  font-size: 12.5px;
  color: var(--ink-2);
  background: var(--hud-bg);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--hairline-soft);
  border-radius: 9px;
  padding: 7px 13px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
#folio-toast.open { opacity: 1; transform: translateY(0); }
/* a refusal is not a confirmation: it stays longer and it is not quiet */
#folio-toast.is-bad {
  color: var(--ink);
  max-width: min(34rem, calc(100vw - 40px));
  border-color: var(--annot-ink);
}

/* ---------- the selection affordance ---------- */

/* No mode, no toolbar, no chrome at rest: this exists while a selection does.
   It is the find bar's material — the same blurred panel, hairline and radius —
   because it is the same kind of object, a control the app put in front of the
   page for as long as it is needed. */
#annot-pop {
  position: fixed;
  z-index: 62;
  display: none;
  flex-direction: column;
  gap: 6px;
  /* nearly solid: it sits over the line above the selection, and at the HUD's
     translucency that line read through the buttons */
  background: light-dark(rgba(250, 249, 246, 0.97), rgba(30, 29, 27, 0.97));
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--hairline-soft);
  border-radius: 10px;
  padding: 5px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
}
#annot-pop.open { display: flex; }
.annot-row { display: flex; gap: 2px; }
.annot-btn {
  font-family: var(--sans);
  font-size: 12px;
  border: none;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  padding: 4px 9px;
  border-radius: 6px;
  white-space: nowrap;
}
.annot-btn:hover { background: var(--code-bg); color: var(--ink); }
/* a new selection has nothing to remove; an existing highlight is already one */
#annot-pop[data-mode="new"] .annot-btn[data-act="del"] { display: none; }
#annot-pop[data-mode="edit"] .annot-btn[data-act="hl"] { display: none; }
#annot-pop .annot-field { display: none; }
#annot-pop.noting .annot-field { display: block; }
.annot-field {
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.45;
  width: 230px;
  border: 1px solid var(--hairline-soft);
  border-radius: 7px;
  background: var(--paper);
  color: var(--ink);
  padding: 6px 8px;
  outline: none;
  resize: none;
}
.annot-field:focus { border-color: var(--hairline); }

/* ---------- the notes list ---------- */

/* Under the outline, in the same panel: one list of things at positions in the
   document, then another. Built only when the document has annotations, so a
   reader who has none opens exactly the sidebar they opened yesterday. */
#outline-notes { margin-top: 1.4rem; }
.outline-head {
  font-family: var(--sans);
  font-size: 0.64rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  padding: 6px 10px;
  border-top: 1px solid var(--hairline-soft);
  margin-bottom: 4px;
}
.note-row {
  font-family: var(--sans);
  padding: 6px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.note-row:hover { background: var(--code-bg); }
/* the quote is what the note is about, so it is set as a quotation — one line
   of it, in the reader's ochre, with the note itself in ink underneath */
.note-quote {
  display: block;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border-inline-start: 2px solid var(--annot-pool);
  padding-inline-start: 6px;
}
.note-text {
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--ink-2);
  margin-top: 3px;
  overflow: hidden;
  display: -webkit-box;          /* three lines of a note, then an ellipsis */
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
.note-text::before {
  content: attr(data-ref);
  font-size: 0.8em;
  font-weight: 650;
  color: var(--annot-ink);
  margin-inline-end: 0.4em;
}
.note-row:hover .note-text { color: var(--ink); }

/* Orphaned: the text this note was about is not in the document any more. It
   stays visible and stays in the sidecar — it re-attaches by itself if the
   sentence comes back — so the only thing it offers is a way to let it go. */
.note-row.is-orphan { cursor: default; }
.note-row.is-orphan:hover { background: transparent; }
.note-row.is-orphan .note-quote {
  border-inline-start-color: var(--hairline);
  text-decoration: line-through;
  text-decoration-color: var(--hairline);
}
.note-orphan {
  display: block;
  font-size: 10.5px;
  color: var(--ink-3);
  font-style: italic;
  margin-top: 2px;
}
.note-drop {
  font-family: var(--sans);
  font-size: 10.5px;
  border: none;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  padding: 2px 6px;
  margin: 3px 0 0 -6px;
  border-radius: 5px;
}
.note-drop:hover { background: var(--code-bg); color: var(--ink); }

/* ---------- shelf ---------- */

.shelf-title { margin-top: 0; font-size: 2.5em; }
.shelf-sub {
  font-family: var(--sans);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  margin: -1.4em 0 2.2em;
}
.shelf-search {
  width: 100%;
  font-family: var(--sans);
  font-size: 0.85rem;
  color: var(--ink);
  background: var(--code-bg);
  border: 1px solid var(--hairline-soft);
  border-radius: 10px;
  padding: 0.65em 1em;
  outline: none;
  margin-bottom: 0.8rem;
}
.shelf-search:focus { border-color: var(--hairline); }
.shelf-list { margin-top: 1.4rem; }
.shelf-row {
  display: flex;
  align-items: baseline;
  gap: 1.1em;
  padding: 0.7em 0.4em;
  border-bottom: 1px solid var(--hairline-soft);
  cursor: pointer;
  transition: background 0.15s ease;
  border-radius: 6px;
}
.shelf-row:hover { background: var(--code-bg); }
.shelf-num {
  font-family: var(--sans);
  font-size: 0.72rem;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.shelf-chapter { flex: 1; }
.shelf-meta {
  font-family: var(--sans);
  font-size: 0.7rem;
  color: var(--ink-3);
}
.shelf-dir {
  font-family: var(--sans);
  font-size: 0.78em;
  color: var(--ink-3);
  margin-inline-end: 0.35em;
}
.shelf-results { margin-top: 0.2rem; }
.shelf-result-none {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--ink-3);
  padding: 0.4em;
}
.shelf-count {
  font-family: var(--sans);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ink-3);
  padding: 0.2em 0.4em 0.6em;
}
.shelf-doc { margin-bottom: 1.1rem; }
.shelf-doc-head {
  display: flex;
  gap: 0.7em;
  align-items: baseline;
  padding: 0.3em 0.4em;
  cursor: pointer;
  border-radius: 6px;
}
.shelf-doc-head:hover { background: var(--code-bg); }
.shelf-doc-title {
  font-family: var(--sans);
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--ink);
}
.shelf-doc-path {
  font-family: var(--sans);
  font-size: 0.7rem;
  color: var(--ink-3);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}
.shelf-doc-hits {
  font-family: var(--sans);
  font-size: 0.7rem;
  color: var(--ink-3);
  white-space: nowrap;
}
.shelf-hit {
  display: flex;
  gap: 0.9em;
  align-items: baseline;
  padding: 0.35em 0.4em 0.35em 1.4em;
  cursor: pointer;
  border-radius: 6px;
  font-size: 0.85em;
  border-inline-start: 1px solid var(--hairline-soft);
  margin-inline-start: 0.5em;
}
.shelf-hit:hover { background: var(--code-bg); }
.shelf-hit-heading {
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--ink-3);
  white-space: nowrap;
  max-width: 30%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.shelf-hit-text {
  flex: 1;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shelf-mark {
  background: var(--mark);
  color: inherit;
  border-radius: 2px;
  padding: 0 0.05em;
}
.shelf-hit-more {
  padding-inline-start: 1.9em;
  cursor: pointer;
}
.shelf-more {
  font-family: var(--sans);
  font-size: 0.72rem;
  color: var(--ink-3);
  padding: 0.5em 0.4em;
}
.shelf-more.is-button {
  color: var(--ink-2);
  cursor: pointer;
  border-top: 1px solid var(--hairline-soft);
}
.shelf-more.is-button:hover { color: var(--ink); }

/* ---------- chapter navigation ---------- */

.chapter-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5em;
  margin-top: 5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--hairline-soft);
  font-family: var(--sans);
  font-size: 0.8rem;
}
.chapter-link {
  color: var(--ink-2);
  cursor: pointer;
  max-width: 38%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color 0.15s ease;
}
.chapter-link:hover { color: var(--ink); }
.chapter-link:empty { cursor: default; }
.chapter-link.contents { color: var(--ink-3); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; }

/* ---------- colophon ---------- */

.colophon {
  margin-top: 6rem;
  text-align: center;
  font-family: var(--sans);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.colophon::before {
  content: "";
  display: block;
  width: 2.2rem;
  border-top: 1px solid var(--hairline);
  margin: 0 auto 1.6rem;
}

/* ---------- the scrubber (the Map) ---------- */

#scrub-zone {
  position: fixed;
  top: var(--folio-chrome-top, 0px); right: 0; bottom: 0;
  width: 28px;
  z-index: 50;
  cursor: default;
}

/* The track is the table of contents, drawn edge-on: one segment per section,
   its height the section's true share of the document. Two identical stacks of
   segments sit on top of each other — the lower one unread ink, the upper one
   blue and clipped to the read fraction — so the fill can cut a segment in
   half mid-chapter instead of snapping between them. */
#scrub-track {
  position: fixed;
  top: var(--folio-chrome-top, 0px); right: 0; bottom: 0;
  width: 28px;
  z-index: 51;
  pointer-events: none;
  opacity: var(--scrub-idle);
  transition: opacity 0.45s ease;
}
body.scroll-active #scrub-track,
body.scrub-hover #scrub-track,
body.scrubbing #scrub-track { opacity: 1; }
body.is-empty #scrub-track { opacity: 0 !important; }

.scrub-layer {
  position: absolute;
  inset: 0;
}
#scrub-rest .scrub-seg { background: var(--scrub-rest); }
#scrub-fill {
  /* set from JS: inset(0 0 <unread px> 0) */
  clip-path: inset(0 0 100% 0);
}
#scrub-fill .scrub-seg { background: var(--scrub-blue); }

.scrub-seg {
  position: absolute;
  right: 6px;
  width: 2.5px;
  border-radius: 99px;
  transition: width 0.22s cubic-bezier(0.22, 1, 0.36, 1),
              right 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
body.scrub-hover .scrub-seg,
body.scrubbing .scrub-seg { width: 5px; right: 5px; }

/* The subsection rail: inboard of the section column, shorter and quieter, so
   the modules still read as modules and their parts are legible beside them
   rather than inside them. */
.scrub-tick {
  position: absolute;
  right: 13px;
  width: 4px;
  height: 1.5px;
  border-radius: 99px;
  opacity: 0.5;
}
#scrub-rest .scrub-tick { background: var(--scrub-rest); }
#scrub-fill .scrub-tick { background: var(--scrub-blue); }
body.scrub-hover .scrub-tick,
body.scrubbing .scrub-tick { right: 14px; width: 6px; opacity: 0.75; }


/* the read/unread boundary doubles as the grab handle */
#scrub-thumb {
  position: fixed;
  right: 5px;
  height: 2px;
  width: 5px;
  margin-top: -1px;
  border-radius: 99px;
  background: var(--scrub-blue);
  opacity: 0;
  transition: opacity 0.25s ease, height 0.2s ease, width 0.2s ease, right 0.2s ease;
  z-index: 52;
  pointer-events: none;
}
body.scrub-hover #scrub-thumb {
  opacity: 1;
  height: 3px;
  width: 11px;
  right: 4px;
}
body.scrubbing #scrub-thumb {
  opacity: 1;
  height: 3px;
  width: 13px;
  right: 3px;
}
body.scrub-grab #scrub-zone { cursor: grab; }
body.scrubbing #scrub-zone { cursor: grabbing; }

.map-label {
  position: fixed;
  right: 26px;
  transform: translateY(-50%) translateX(14px) scale(0.96);
  transform-origin: 100% 50%;
  opacity: 0;
  clip-path: inset(0 0 0 100%);
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 450;
  letter-spacing: 0.01em;
  color: var(--ink-2);
  white-space: nowrap;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 52;
  cursor: pointer;
  padding: 3px 8px;
  border-radius: 6px;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.35s ease,
              clip-path 0.45s cubic-bezier(0.22, 1, 0.36, 1),
              color 0.2s ease;
}
.map-label.lvl-1 { font-weight: 600; color: var(--ink); }
/* sections you've already passed take the fill's colour, so the labels read as
   part of the same ribbon rather than a separate list floating beside it */
.map-label.read { color: var(--scrub-blue); }
body.scrub-hover .map-label {
  opacity: 0.62;
  transform: translateY(-50%) translateX(0) scale(1);
  clip-path: inset(0 0 0 0);
}
body.scrubbing .map-label {
  opacity: 1;
  transform: translateY(-50%) translateX(0) scale(1);
  clip-path: inset(0 0 0 0);
}
.map-label.near {
  color: var(--ink);
  transform: translateY(-50%) translateX(-6px) scale(1.05) !important;
}
body.scrubbing .map-label.near { opacity: 1; }

#scrub-hud {
  position: fixed;
  right: 306px;
  transform: translateY(-50%);
  background: var(--hud-bg);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--hairline-soft);
  border-radius: 8px;
  padding: 6px 12px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--ink);
  z-index: 53;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  white-space: nowrap;
  display: flex;
  gap: 10px;
  align-items: baseline;
}
body.scrubbing #scrub-hud { opacity: 1; }
#scrub-hud .hud-pct {
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  font-size: 11px;
}

/* ---------- blocked remote content ---------- */

/* A blocked image keeps its element — restoring is then a matter of putting the
   reference back — but stands in as a quiet ruled rectangle instead of the
   broken-image glyph an empty src would otherwise draw. The alt text stays on
   the element for assistive tech; painting it transparent keeps it off the page,
   where a figure already repeats it as a caption and 500 of them would shout. */
.content img.remote-blocked {
  display: inline-block;
  width: 3.4em;
  aspect-ratio: 16 / 10;
  vertical-align: -0.35em;
  background: var(--code-bg);
  border: 1px solid var(--hairline-soft);
  border-radius: 5px;
  color: transparent;
  overflow: hidden;
  cursor: default;
}
.content figure > img.remote-blocked {
  display: block;
  width: 100%;
  max-width: 20rem;
  margin: 0 auto;
  border-radius: 6px;
  vertical-align: baseline;
}

#remote-bar {
  position: fixed;
  top: calc(14px + var(--folio-chrome-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 58;
  display: none;
  align-items: center;
  gap: 10px;
  background: var(--hud-bg);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--hairline-soft);
  border-radius: 10px;
  padding: 6px 8px 6px 13px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--ink-2);
  white-space: nowrap;
}
body.has-blocked-remote #remote-bar { display: flex; }
/* the find bar owns the top strip while it is open */
body.finding #remote-bar { display: none; }

.remote-btn {
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 11.5px;
  cursor: pointer;
  padding: 2px 9px;
  border-radius: 6px;
  transition: background 0.15s ease;
}
.remote-btn:hover { background: var(--code-bg); }

/* ---------- agent reading sessions ---------- */

/* The same quiet pill as the remote-content banner, deliberately: a reader has
   already learned in this app that a small bar at the top of the page is Folio
   telling them what it did or did not let through. This one says something has
   just read the document — no dismiss control, because the state is the point. */

#agent-bar {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 59;
  display: none;
  align-items: center;
  gap: 9px;
  background: var(--hud-bg);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--hairline-soft);
  border-radius: 10px;
  padding: 6px 8px 6px 12px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--ink-2);
  white-space: nowrap;
}
body.agent-attached #agent-bar { display: flex; }
body.finding #agent-bar { display: none; }

.agent-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
  animation: agent-pulse 2.4s ease-in-out infinite;
}
@keyframes agent-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .agent-dot { animation: none; } }

/* both can be true at once, and neither may hide the other */
body.agent-attached.has-blocked-remote #remote-bar { top: 52px; }

/* ---------- find bar ---------- */

#find-bar {
  position: fixed;
  top: calc(14px + var(--folio-chrome-top, 0px));
  right: 48px;
  z-index: 60;
  display: none;
  align-items: center;
  gap: 8px;
  background: var(--hud-bg);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--hairline-soft);
  border-radius: 10px;
  padding: 7px 12px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08);
}
body.finding #find-bar { display: flex; }
#find-input {
  font-family: var(--sans);
  font-size: 13px;
  border: none;
  outline: none;
  background: transparent;
  color: var(--ink);
  width: 180px;
}
#find-count {
  font-family: var(--sans);
  font-size: 11.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  min-width: 46px;
  text-align: right;
}
.find-btn {
  border: none;
  background: transparent;
  color: var(--ink-2);
  font-size: 12px;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: 5px;
  font-family: var(--sans);
}
.find-btn:hover { background: var(--code-bg); }

mark.find { background: var(--mark); color: inherit; border-radius: 2px; }
mark.find.active { background: var(--mark-active); }

/* ---------- empty state ---------- */

#empty {
  position: fixed;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  color: var(--ink-2);
}
body.is-empty #empty { display: flex; }
body.is-empty #stage { display: none; }
#empty .empty-mark {
  font-family: var(--serif);
  font-size: 2rem;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.02em;
}
#empty .empty-hint {
  font-family: var(--sans);
  font-size: 0.9rem;
  color: var(--ink-2);
  text-align: center;
  max-width: 32rem;
  padding: 0 1rem;
  overflow-wrap: anywhere;
}
#empty .empty-actions { display: flex; gap: 0.6rem; margin-top: 0.6rem; }
body.is-error #empty-guide { display: none; }
#empty .empty-btn {
  font: 500 0.85rem/1 var(--sans); color: var(--ink);
  background: var(--code-bg); border: 1px solid var(--hairline);
  border-radius: 7px; padding: 0.55em 1.1em; cursor: pointer;
}
#empty .empty-btn.primary { background: var(--accent); border-color: transparent; color: var(--paper); }
#empty .empty-btn:hover { filter: brightness(1.06); }
#empty .empty-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.content .doc-empty { color: var(--ink-2); font-style: italic; text-align: center; margin-top: 30vh; }
#empty kbd {
  font-family: var(--sans);
  font-size: 0.72rem;
  border: 1px solid var(--hairline);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 0.1em 0.45em;
  color: var(--ink-2);
}
body.drag-over #empty .empty-hint,
body.drag-over #empty .empty-mark { color: var(--accent); }

/* ---------- print ---------- */

@media print {
  #scrub-zone, #scrub-track, #scrub-thumb, #scrub-hud, #find-bar, #remote-bar, .map-label,
  #agent-bar, #annot-pop, #folio-toast { display: none !important; }
  body { font-size: 11pt; }
  .content { max-width: none; padding: 0; }
  .code-block pre { overflow-x: visible; white-space: pre-wrap; }

  /* Paper gets the list, never both — sidenotes are already off, because the
     query that turns them on is `screen and`. What is left is the apparatus
     behaving like print: an entry does not straddle a page, a back-link is a
     dead control on paper, and blue ink is a claim a laser printer cannot keep. */
  .reference { break-inside: avoid; }
  /* on screen ink-3 is a legible quiet; on paper, at 8pt, it is a grey the
     printer half-keeps — and the figure is the one part of an entry a reader
     has to match against a marker */
  .reference::before { color: var(--ink-2); }
  .ref-back { display: none; }
  sup.cite a, sup.footnote-ref a, .ref-target { color: inherit; }
}


/* Subsection labels, revealed only for the division under the pointer. Indented
   under their parent and a size down, so the hierarchy is legible in the fan
   rather than asserted by a rule. */
.map-label.minor {
  font-size: 11px;
  color: var(--ink-3);
  right: 34px;          /* indented under its parent, so the fan reads as a tree */
}

/* Save failures stay visible until resolved; controls wrap with enlarged text. */
#annotation-save-status {
  position: sticky; top: 0; z-index: 30; padding: 1rem;
  background: var(--paper); color: var(--ink); border-bottom: 1px solid var(--hairline);
  font: 0.9rem/1.5 var(--sans); overflow-wrap: anywhere;
}
#annotation-save-status button, #shelf-exclusions button, #recent-documents button {
  font: inherit; color: inherit; background: var(--code-bg);
  border: 1px solid var(--hairline); border-radius: 5px;
  padding: 0.4em 0.65em; margin: 0.2em; cursor: pointer;
}
#recent-documents { width: min(90vw, 26rem); max-height: 45vh; overflow: auto; margin-top: 1.6rem; }
#recent-documents .recent-label {
  font: 600 0.7rem/1 var(--sans); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-2); margin: 0 0 0.5rem 0.65em;
}
#recent-documents button {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.15em;
  width: 100%; margin: 0; text-align: left; background: transparent; border-color: transparent;
}
#recent-documents button:hover { background: var(--code-bg); }
#recent-documents .recent-name { font: 500 0.92rem/1.3 var(--serif); color: var(--ink); overflow-wrap: anywhere; }
#recent-documents .recent-where { font: 0.75rem/1.3 var(--sans); color: var(--ink-2); overflow-wrap: anywhere; }
#shelf-exclusions { margin: 1rem 0; font: 0.85rem/1.5 var(--sans); overflow-wrap: anywhere; }
#shelf-exclusions summary { cursor: pointer; }
#annotation-save-status button:focus-visible, #recent-documents button:focus-visible, #shelf-exclusions button:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 2px;
}
@media print { #annotation-save-status { display: none; } }


/* The native window draws its title over the top of the page
   (fullSizeContentView), so text scrolling up would print through the title.
   A paper-coloured band fades it out. App only: index.html marks its root. */
html[data-folio-app] body::before {
  content: ''; position: fixed; inset: 0 0 auto 0; height: 40px;
  background: linear-gradient(var(--paper) 55%, transparent);
  z-index: 45; pointer-events: none;
}
@media print { html[data-folio-app] body::before { display: none; } }

/* <mark> written by the document (not find's, not a highlight) */
.content mark:not(.find):not(.annot) { background: var(--annot); color: inherit; padding: 0 .1em; border-radius: 2px; }

/* Reduced motion: no recede, no fans, no flashes — state changes, instantly. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* While the spine is fanned out its labels sit over the right of the page.
   A paper wash behind them keeps the labels legible and the body text from
   reading through them; it arrives with the labels and leaves with them. */
html[data-folio-app] body::after {
  content: ''; position: fixed; top: 0; right: 0; bottom: 0; width: 360px;
  background: linear-gradient(to left, var(--paper) 62%, transparent);
  opacity: 0; pointer-events: none; z-index: 50;   /* under the track (51) and labels (52) */
  transition: opacity .18s ease;
}
html[data-folio-app] body.scrubbing::after { opacity: .94; }
html[data-folio-app] body.scrub-hover::after { opacity: .7; }
@media print { html[data-folio-app] body::after { display: none; } }

/* MathML — what exports, Quick Look and MCP renders carry (KaTeX's MathML
   output: no fonts or script to ship). STIX Two Math ships with macOS. */
math { font-family: "STIX Two Math", "Latin Modern Math", math; }
.math-block math { font-size: 1.25em; }
.math-block[data-typeset] { overflow-x: auto; text-align: center; margin: 1.2em 0; }

/* ---------- code: copy, overflow ---------- */

/* The copy button takes the language label's corner on hover or focus, so the
   resting block keeps its one quiet label and gains no chrome. */
.code-copy {
  position: absolute; top: 0.45em; right: 0.6em;
  font: 500 0.68rem/1 var(--sans); letter-spacing: 0.02em;
  color: var(--ink-2); background: var(--paper);
  border: 1px solid var(--hairline); border-radius: 6px;
  padding: 0.35em 0.7em; cursor: pointer;
  opacity: 0; transition: opacity .12s ease;
}
.code-block:hover .code-copy, .code-copy:focus-visible { opacity: 1; }
.code-block:hover::before, .code-block:focus-within::before { opacity: 0; }
.code-copy::after { content: 'Copy'; }
.code-copy.done::after { content: 'Copied'; }
.code-copy { user-select: none; -webkit-user-select: none; }
.code-copy.done { color: var(--scrub-blue); border-color: currentColor; opacity: 1; }
.code-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* more to the right: a fade into the block's own colour, gone at the end */
.code-block.overflows::after, .math-block.overflows::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; width: 2.75em;
  pointer-events: none; border-radius: 0 10px 10px 0;
  background: linear-gradient(to right, transparent, color-mix(in srgb, var(--ink) 4.5%, var(--paper)));
}
.math-block.overflows { position: relative; }
.math-block.overflows::after { background: linear-gradient(to right, transparent, var(--paper)); }
.code-block.at-end::after, .math-block.at-end::after { content: none; }

/* ---------- tables: numbers stay whole ---------- */

table { font-variant-numeric: tabular-nums; }
th[style*="right"], td[style*="right"] { white-space: nowrap; }
.content table.measuring { width: max-content; max-width: none; }

/* ---------- a local image that is not there ---------- */

.img-missing {
  display: inline-block; padding: 0.7em 1em; border: 1px dashed var(--hairline);
  border-radius: 6px; color: var(--ink-2); font: 0.8rem/1.4 var(--sans);
  overflow-wrap: anywhere;
}
@media print { .code-copy { display: none; } .code-block.overflows::after, .math-block.overflows::after { content: none; } }

/* ---------- Word documents (FolioEngine/Docx.swift) ---------- */

/* A Word document's colours, exactly as written in light mode; in dark mode
   blended toward the reader's ink and paper so they stay legible rather than
   dark-on-dark. The colour travels as a custom property, so the document's
   value is data and these rules decide how it is shown. */
.content .docx-color { color: light-dark(var(--docx-fg), color-mix(in srgb, var(--docx-fg) 55%, var(--ink))); }
.content .docx-shade { background: light-dark(var(--docx-bg), color-mix(in srgb, var(--docx-bg) 32%, var(--paper))); }
.content table.docx-table { border-collapse: collapse; }
.content table.docx-table th, .content table.docx-table td {
  border: 1px solid var(--hairline); padding: 0.4em 0.6em; vertical-align: top;
}
.content table.docx-table th { font-weight: 600; }
.content figure.docx-chart { margin: 2em 0; text-align: left; }
.content .docx-chart-svg { display: block; width: 100%; height: auto; color: var(--ink); }
.content .docx-chart-data { margin-top: 0.6em; font: 0.8em/1.4 var(--sans); color: var(--ink-2); }
.content .docx-chart-data summary { cursor: pointer; }
.content .docx-chart-data table { font-size: 1em; }
.content .docx-chart-open { margin: 0.5em 0 0; font: 0.8em/1.4 var(--sans); }
/* a drawn Windows metafile was made for a white page: keep it on one */
.content img.docx-metafile { background: #fff; border-radius: 4px; }
@media print { .content .docx-chart-data, .content .docx-chart-open { display: none; } }
