/* Skimmaxxer: the sheet every shell loads.

   The palette, the face and the head of the page live here, declared once, so
   a reader who crosses from the landing page to the shelf to a paper never
   arrives somewhere that looks like somewhere else. home.css and landing.css
   lay the library pages out on top of this and redeclare nothing in it.

   One hue, blue on white. The page is white and so is every card, panel and
   field on it: a hairline and a shadow tell a surface from the page, never a
   wash across it. The accent says one thing - "this is the way forward" - and
   appears on the button a reader acts on, the underline of a term, the
   numerals down the rail. The four depth stops (--d0..--d3) carry the one other
   meaning colour has: how far into the recursive narrative a page sits, navy ->
   slate -> stone -> brass, so a reader can tell before reading a word.

   One face. DM Sans sets the titles, the prose and the controls alike, on every
   page. Small labels are set in it as capitals, tracked open; a real monospace
   is kept for code and for nothing else.

   One ladder of sizes under it (--t-micro .. --t-display), one ratio apart,
   which the reading pages take whole. Nothing on them sets a size of its own:
   a heading is a rung above the paragraph under it, and the small type stands
   on three or four rungs rather than drifting through every half pixel between
   ten and seventeen.

   Three-state theming: bare :root = light, prefers-color-scheme dark (guarded),
   explicit data-theme wins both ways. */

:root {
  /* ---- ground and ink ---- */
  --bg: #ffffff;
  --bg-raise: #ffffff;
  --bg-sunken: #eaf1fb;
  --ink: #0b0e14;
  --ink-soft: #232a32;
  --ink-faint: #48515a;
  --line: #dbe6f5;
  --line-soft: #e9f0fb;

  /* depth: the one thing colour is allowed to say */
  --d0: #123570;
  --d1: #3b6b8f;
  --d2: #8a8678;
  --d3: #c9a227;
  --d0-ink: #123570;
  --d1-ink: #2f5a78;
  --d2-ink: #6b6858;
  --d3-ink: #8a6a12;
  --d0-soft: rgba(18, 53, 112, 0.10);
  --d1-soft: rgba(59, 107, 143, 0.12);
  --d2-soft: rgba(138, 134, 120, 0.14);
  --d3-soft: rgba(201, 162, 39, 0.16);

  /* Deep blue: the same colour as the ground, further down. */
  --accent: #1d4ed8;
  --accent-text: #1e40af;
  --accent-soft: rgba(29, 78, 216, 0.07);
  --accent-ring: rgba(29, 78, 216, 0.18);
  --on-accent: #ffffff;

  /* Two stops past the accent, the same blue lightening twice. Neither is ever
     painted flat: they exist so that a gradient has somewhere to travel. */
  --accent-2: #3b82f6;
  --accent-3: #60a5fa;

  /* the four kinds of edge */
  --blue: #3b6b8f;
  --green: #3f7d5e;
  --violet: #6b5ea8;
  --red: #a8523f;

  --code-bg: #eaf1fb;

  /* Two steps only: resting and raised. Tinted with the ink rather than with
     black, so a card on the white ground does not go grey. */
  --shadow-sm: 0 1px 2px rgba(11, 14, 20, 0.05);
  --shadow: 0 1px 2px rgba(11, 14, 20, 0.04), 0 10px 28px -14px rgba(11, 14, 20, 0.16);
  --shadow-lift: 0 1px 2px rgba(11, 14, 20, 0.05), 0 18px 40px -18px rgba(11, 14, 20, 0.22);

  --r-sm: 8px;
  --r: 12px;
  --r-lg: 16px;
  --r-xl: 22px;

  /* The page column and the height of the rail, so the rail can line its
     contents up with the page below it and everything sticky can clear it. */
  --page: 1160px;
  --gutter: 32px;
  --rail-h: 62px;

  /* One face. --display and --mark are kept as names because the sheets that
     lay the library out reach the face through them; they all resolve to the
     same thing. */
  --sans: "DM Sans", system-ui, sans-serif;
  --display: var(--sans);
  --mark: var(--sans);
  --mono: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;

  /* One ladder. Every size a reading page sets is a rung of it, and nothing
     sets a number of its own. The rungs are one ratio apart - 1.2, from the
     reading size outward in both directions - with a half step (1.095) put in
     wherever a whole one left a gap too wide to fill. That is what makes a
     subhead read as a size above the paragraph rather than as the same size in
     bold, and what stops the small type collecting in a drift of half pixels.

     The face is variable and carries an optical size axis, so a rung is not
     only larger than the one below it: it is drawn for the size it is set at,
     the caps opening and the strokes evening out as the type comes down. */
  --t-micro: 11px;      /* the smallest thing still read: sub-labels, counts */
  --t-mini: 12px;       /* tracked capitals, chips, numerals in a rail */
  --t-fine: 13.2px;     /* captions, citation lines, the rail's rows */
  --t-small: 14.5px;    /* controls, notes, a line under a name */
  --t-plain: 15.8px;    /* the second prose size: cards, drawers, columns */
  --t-mid: 17.3px;      /* prose in a column, and the smallest heading in one */
  --t-read: 19px;       /* the reading size */
  --t-minor: 20.8px;    /* the subheads the prose sets for itself */
  --t-sub: 22.8px;      /* a heading inside a chapter, and the lede */
  --t-head: 27.4px;     /* the head of a chapter, and the mark */
  --t-title-sm: 32.8px; /* the title of a page opened in the column */
  --t-title: 39.4px;    /* the title of a page, where the window is narrow */
  --t-display: 47.3px;  /* the title of a page: a concept, a figure, a theme,
                           named at a size nothing under it can be mistaken
                           for */

  /* Leading comes down as the type goes up: a title is one block of words and
     a paragraph is many lines a reader has to find their way back along. */
  --lh-title: 1.1;
  --lh-head: 1.25;
  --lh-read: 1.6;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #080d18;
    --bg-raise: #0f1626;
    --bg-sunken: #060a12;
    --ink: #e8edf5;
    --ink-soft: #a1abbd;
    --ink-faint: #6d7789;
    --line: #1d2739;
    --line-soft: #151d2b;

    --d0: #7aa5e0;
    --d1: #63b0c9;
    --d2: #b9b39c;
    --d3: #ecc75a;
    --d0-ink: #7aa5e0;
    --d1-ink: #63b0c9;
    --d2-ink: #b9b39c;
    --d3-ink: #ecc75a;
    --d0-soft: rgba(122, 165, 224, 0.14);
    --d1-soft: rgba(99, 176, 201, 0.14);
    --d2-soft: rgba(185, 179, 156, 0.14);
    --d3-soft: rgba(236, 199, 90, 0.15);

    --accent: #2563eb;
    --accent-text: #7fb0f9;
    --accent-soft: rgba(59, 130, 246, 0.12);
    --accent-ring: rgba(59, 130, 246, 0.26);
    --accent-2: #3b82f6;
    --accent-3: #60a5fa;

    --blue: #7fb2d8;
    --green: #7fbf9a;
    --violet: #a99bd3;
    --red: #dd8f7c;

    --code-bg: #121a29;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 28px -14px rgba(0, 0, 0, 0.8);
    --shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.5), 0 18px 40px -18px rgba(0, 0, 0, 0.9);
  }
}

:root[data-theme="dark"] {
  --bg: #080d18;
  --bg-raise: #0f1626;
  --bg-sunken: #060a12;
  --ink: #e8edf5;
  --ink-soft: #a1abbd;
  --ink-faint: #6d7789;
  --line: #1d2739;
  --line-soft: #151d2b;

  --d0: #7aa5e0;
  --d1: #63b0c9;
  --d2: #b9b39c;
  --d3: #ecc75a;
  --d0-ink: #7aa5e0;
  --d1-ink: #63b0c9;
  --d2-ink: #b9b39c;
  --d3-ink: #ecc75a;
  --d0-soft: rgba(122, 165, 224, 0.14);
  --d1-soft: rgba(99, 176, 201, 0.14);
  --d2-soft: rgba(185, 179, 156, 0.14);
  --d3-soft: rgba(236, 199, 90, 0.15);

  --accent: #2563eb;
  --accent-text: #7fb0f9;
  --accent-soft: rgba(59, 130, 246, 0.12);
  --accent-ring: rgba(59, 130, 246, 0.26);
  --accent-2: #3b82f6;
  --accent-3: #60a5fa;

  --blue: #7fb2d8;
  --green: #7fbf9a;
  --violet: #a99bd3;
  --red: #dd8f7c;

  --code-bg: #121a29;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 28px -14px rgba(0, 0, 0, 0.8);
  --shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.5), 0 18px 40px -18px rgba(0, 0, 0, 0.9);
}

/* ---------- gradients ---------- */
/* The one material past flat colour, and the only place any of it is defined.

   Declared on the body rather than on :root, and built out of the palette
   tokens rather than out of hex. A custom property resolves its var()s against
   the element it is declared on, so this single block yields the light values
   on a light page and the dark ones on a dark page. Nothing here needs
   restating per theme.

   Surfaces are flat - the page and every card and panel on it - so nothing
   that was neutral becomes a hue a reader has to interpret. What carries a
   gradient is the button a reader acts on, the thin marks that point at
   something, and the wordmark. */
body {
  --grad-brand: linear-gradient(118deg, var(--accent) 0%, var(--accent-2) 54%, var(--accent-3) 100%);
  /* The wordmark, and nothing else on the site. Every other heading is ink:
     gradient type is a signature, and a page of signatures signs nothing. */
  --grad-title: linear-gradient(112deg, var(--ink) 0%, color-mix(in srgb, var(--ink) 32%, var(--accent)) 58%, var(--accent-3) 100%);

  /* A raised surface is flat. A card is told apart from the page by its
     hairline and its shadow, never by a wash laid across it. They stay as
     tokens rather than being chased out of the sheet rule by rule, because
     every card, panel, drawer, field and badge on the site reads its ground
     from one of these three. */
  --surface: var(--bg-raise);
  --surface-end: var(--bg-raise);
  --surface-soft: var(--bg-sunken);

  /* a hairline that fades in from nothing and back out to it */
  --hairline: linear-gradient(90deg,
      transparent 0%,
      color-mix(in srgb, var(--accent) 34%, transparent) 24%,
      color-mix(in srgb, var(--accent-3) 32%, transparent) 74%,
      transparent 100%);

  /* the accent cast rather than drawn */
  --glow: 0 14px 34px -18px color-mix(in srgb, var(--accent) 62%, transparent);
  --glow-lift: 0 20px 46px -20px color-mix(in srgb, var(--accent-3) 55%, transparent);
}

/* depth stops, addressable by level */
[data-depth="0"] { --depth: var(--d0); --depth-ink: var(--d0-ink); --depth-soft: var(--d0-soft); }
[data-depth="1"] { --depth: var(--d1); --depth-ink: var(--d1-ink); --depth-soft: var(--d1-soft); }
[data-depth="2"] { --depth: var(--d2); --depth-ink: var(--d2-ink); --depth-soft: var(--d2-soft); }
[data-depth="3"] { --depth: var(--d3); --depth-ink: var(--d3-ink); --depth-soft: var(--d3-soft); }
[data-depth="4"] { --depth: var(--d3); --depth-ink: var(--d3-ink); --depth-soft: var(--d3-soft); }

* { box-sizing: border-box; }
html { height: 100%; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 18px;
  line-height: 1.65;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--accent-soft); }

/* ---------- the rail ---------- */
/* One head on every page: the mark at the left, the theme control at the
   right and, while a paper is open as printed, the reader's controls between
   them. Sticky and solid rather than frosted, so the page never shows faintly
   through the mark; ruled underneath, with the accent carried across the page
   once in the hairline. Lined up with the page column, so on the library pages
   the mark sits over the headline rather than out at the window edge. */
.rail {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 20px;
  height: var(--rail-h);
  padding: 0 max(var(--gutter), calc((100% - var(--page)) / 2 + var(--gutter)));
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.rail::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--hairline);
  pointer-events: none;
}
/* The mark is the only place a page sets the name, so it is given the size of
   a name rather than of a nav item - and the same size on every page, which is
   what stops one page reading as a different site from the one you came from.
   It is also the way back. */
.rail-mark {
  font: 700 var(--t-head) var(--mark);
  letter-spacing: -0.03em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
@supports (-webkit-background-clip: text) or (background-clip: text) {
  .rail-mark {
    background-image: var(--grad-title);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
/* The wiki or the paper: the two readings of the same work, and the only thing
   in the rail that says what else exists rather than acting on what is open. So
   both names stay on screen and the one you are in is the raised chip, rather
   than a button naming a destination you have to read to know there are two.

   The accent stays off the chip on purpose. In this palette it means the way
   forward, and the way forward from here is always the other half - so it is
   the half you can press that takes the colour, under the pointer.

   It sits in the middle of the rail rather than beside the mark, because it
   belongs to neither end: the mark is the way out, the controls act on what is
   open, and this one names the other reading of the whole thing. Centred on the
   window rather than on the space left over, which means lifting it out of the
   row - the mark on the left and the controls on the right are nowhere near the
   same width, so a flowed centring would sit visibly off to one side. Where the
   row is too narrow to keep it clear of both, it drops back into the row and
   takes a line of its own; those rules are with the responsive ones. */
.rail-switch {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.rail-switch:empty { display: none; }

/* A rounded rectangle rather than the pill every other small control wears.
   The pills act on the page you are on; this one names a place to go, and the
   corner is what tells them apart at a glance. */
.switcher {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.sw-half {
  display: inline-block;
  padding: 5px 15px;
  font: 600 var(--t-fine) var(--sans);
  line-height: 1.25;
  color: var(--ink-faint);
  text-decoration: none;
  white-space: nowrap;
  border-radius: 5px;
  transition: color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.sw-half.is-on {
  color: var(--ink);
  background: var(--bg-raise);
  box-shadow: var(--shadow-sm);
}
a.sw-half { cursor: pointer; }
a.sw-half:hover { color: var(--accent-text); background: var(--accent-soft); }
a.sw-half:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The reader's controls, when a paper is open as printed. Empty on every other
   page, and takes no room then. */
.rail-tools {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: 1 1 auto;
  min-width: 0;
}
.rail-tools:empty { display: none; }

/* A mark, not a word: the state is worth showing and not worth a line of the
   rail. The name lives in aria-label and the tooltip. */
/* The rail's ? is the way in to the card that says which of the four readings
   to open, so it sits with the theme toggle at the end of the rail: neither of
   them acts on the page in front of you. It carries a hairline where the toggle
   carries none - a question mark on its own is a glyph, and this has to read as
   something you can press. */
#help-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  margin: 0 0 0 auto;
  width: 32px;
  height: 32px;
  padding: 0;
  background: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 600 var(--t-small)/1 var(--sans);
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
#help-btn:hover {
  color: var(--accent-text);
  background: var(--accent-soft);
  border-color: var(--accent-ring);
}
#help-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the two chips end the rail together, so the margin that pushes them there
   belongs to the first of them and the second only keeps its distance */
#help-btn + #theme-toggle { margin-left: 4px; }

#theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  margin: 0 0 0 auto;
  width: 32px;
  height: 32px;
  color: var(--ink-faint);
  background: none;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 0;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
}
#theme-toggle:hover { color: var(--ink); background: var(--surface-soft); }
#theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* On a paper the page is the full window, sidebar and all, so the rail lines
   its mark up with the rail below it rather than with a centred column. */
body.reading .rail { padding: 0 20px 0 18px; }

/* ---------- shell ---------- */

#app { display: flex; min-height: calc(100vh - var(--rail-h)); }

#sidebar {
  width: 290px;
  flex: 0 0 290px;
  border-right: 1px solid var(--line);
  /* the same hairline, holding the accent where the rail starts and letting
     go of it a third of the way down */
  border-image: linear-gradient(180deg, color-mix(in srgb, var(--accent-2) 42%, var(--line)) 0%, var(--line) 46%) 1;
  background: var(--bg);
  padding: 22px 18px 36px;
  position: sticky;
  top: var(--rail-h);
  height: calc(100vh - var(--rail-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  /* the stock scrollbar is a wall between rail and sheet; keep it a hairline */
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

#main { flex: 1 1 auto; min-width: 0; }

.content {
  max-width: 42rem;
  margin: 0 auto;
  padding: 56px 32px 140px;
}
/* the rail floats over the page, so anything a link can jump to clears it */
.content [id] { scroll-margin-top: calc(var(--rail-h) + 22px); }

/* ---------- labels ---------- */
/* The one small-type style on the site: capitals, tracked open, in the quiet
   ink. Eyebrows, section captions on the rail, the heads of the reader's
   column - anything that names what follows rather than being read. */
.eyebrow,
.nav-label,
.site-link,
.zoom-label,
.chart-link-label,
.lead-in-label,
.beside-label,
.col-back,
.find-count,
.pop-kind,
#search-results .kind {
  font: 600 var(--t-mini) var(--sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

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

.site-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--t-micro);
  text-decoration: none;
  padding: 3px 0;
}
.site-link:hover { color: var(--accent-text); }
.site-link::before { content: "\2190"; font-size: var(--t-mini); }

.brand {
  margin: 12px 0 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
  font: 700 var(--t-plain) var(--sans);
  line-height: 1.3;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.brand a { color: var(--ink); text-decoration: none; }
.brand a:hover { color: var(--accent-text); }

.nav-label {
  font-size: var(--t-micro);
  margin: 20px 0 6px;
  padding: 0 9px;
}
/* The label is a plain caption ("In this chapter"); section doors live in the
   fold headings below. */

.nav-list { list-style: none; margin: 0; padding: 0; font-size: var(--t-fine); }
.nav-list li { margin: 0; }
.nav-list a {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 5px 9px;
  border-radius: 7px;
  color: var(--ink-soft);
  text-decoration: none;
  line-height: 1.45;
  transition: background 0.12s ease, color 0.12s ease;
}
/* The numerals wear the accent: on this site the accent is the colour of the
   things you operate, so a blue column down the rail says the whole list is
   doors before anything is hovered. */
.nav-list .n {
  flex: 0 0 auto;
  min-width: 11px;
  font: 500 var(--t-micro) var(--sans);
  color: var(--accent-text);
  opacity: 0.72;
}
/* one line each: a rail of wrapped titles is a wall */
.nav-list .t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-list a.lead .t { font-weight: 600; color: var(--ink); }
.nav-list a.up .n { color: var(--accent-text); }
/* Every row carries a standing chevron at the rail's edge. Hover used to be
   the only tell that these go somewhere; a mark that is already there says it
   to a reader who never hovers. */
.nav-list a::after {
  content: "\203A";
  margin-left: auto;
  align-self: center;
  padding-left: 8px;
  font: 600 var(--t-mini) var(--sans);
  line-height: 1;
  color: var(--accent-text);
  opacity: 0.35;
  transition: opacity 0.12s ease, transform 0.12s ease;
}
.nav-list a:hover { background: var(--accent-soft); color: var(--ink); }
.nav-list a:hover::after { opacity: 0.9; transform: translateX(2px); }
/* Where you are is a filled pill, not a white card: on the white rail a raised
   white row is invisible, a wash of the accent is not. At the rail's edge the
   go-mark becomes a here-mark: the row's chevron turns into a dot. */
.nav-list a.active {
  background: var(--accent-soft);
  color: var(--ink);
  font-weight: 600;
}
.nav-list a strong { font-weight: 600; }
.nav-list a.sub { font-size: var(--t-mini); }
.nav-list a.active .n { color: var(--accent-text); opacity: 1; }
.nav-list a.active::after { content: "\2022"; font-size: var(--t-small); opacity: 1; transform: none; }

/* everything that is not the chapter in front of you folds away */
.nav-fold { margin: 16px 0 0; padding-top: 12px; border-top: 1px solid var(--line-soft); }
/* The heading of a fold is a control, so it is built like a chapter row and not
   like a caption: the same 9px inset, the same rounded hover box, the darker
   ink, and a triangle that turns a quarter turn when the fold opens. */
.nav-fold > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  list-style: none;
  margin-bottom: 2px;
  padding: 6px 9px;
  border-radius: 7px;
  font: 600 var(--t-micro) var(--sans);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
  transition: background 0.12s ease, color 0.12s ease;
}
.nav-fold > summary::-webkit-details-marker { display: none; }
/* Pointed at, a section says what kind of read it holds: a small card under
   the heading, held back for a beat so it does not flash on pass-through.
   The heading is capitals, so the card resets to the plain reading face.

   It hangs off the name rather than the row, and the name takes the left of
   the row up to the count - so the card answers the half of the heading that
   asks the question, and the count and the chevron are quiet. Positioned
   against the summary all the same, which is what left and top read from. */
.nav-fold > summary { position: relative; }
.nav-fold > summary .fold-name { flex: 1 1 auto; min-width: 0; }
.nav-fold > summary .fold-name[data-tip]::before {
  content: attr(data-tip);
  position: absolute;
  left: 9px;
  top: calc(100% + 4px);
  z-index: 5;
  width: max-content;
  max-width: 220px;
  padding: 7px 11px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow);
  font: 400 var(--t-mini)/1.45 var(--sans);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.nav-fold > summary .fold-name[data-tip]:hover::before { opacity: 1; transition-delay: 0.4s; }
/* a closed fold says how much it is holding, so it reads as a full drawer
   rather than a dead caption - the same count chip the shelf's section heads
   carry */
.nav-fold > summary .count {
  margin-left: auto;
  padding: 1px 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 500 var(--t-micro) var(--sans);
  letter-spacing: 0;
  color: var(--ink-faint);
}
/* The chevron is the only thing that opens the fold, so it is drawn as a
   button and not as a mark: a chip the size of the count beside it, on the
   surface colour so it stays raised when the row fills in under the pointer.
   The name is the door, and it is much the larger target - which is the way
   round it should be, since the reading is what a reader wants and the list
   of its parts is the smaller errand. */
.nav-fold > summary .fold-toggle {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  margin-left: 8px;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.nav-fold > summary .fold-toggle::before {
  content: "";
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform 0.15s ease;
}
.nav-fold[open] > summary .fold-toggle::before { transform: rotate(90deg); }
.nav-fold > summary .fold-toggle:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-text);
}
.nav-fold > summary .fold-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* a fold with a door has no count sitting against its edge, so the chip on its
   own holds the rail's edge */
.nav-fold > summary:not(:has(.count)) .fold-toggle { margin-left: auto; }
.nav-fold > summary:hover { background: var(--accent-soft); color: var(--ink); }
.nav-fold > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* The heading holds the door: the name is a link and navigates, and so does
   the rest of the row, which is only ever standing in for the name. The dot is
   the here-mark. */
.nav-fold > summary a {
  color: inherit;
  text-decoration: none;
  transition: color 0.12s ease;
}
.nav-fold > summary a:hover { color: var(--accent-text); }
.nav-fold > summary a.active { color: var(--accent-text); }
.nav-fold > summary a.active::after { content: "\2022"; margin-left: 6px; font-size: var(--t-mini); line-height: 1; }
/* the rail's first fold sits directly under the search field, where a
   starting rule would double the field's own border */
#search-results + details.nav-fold { margin-top: 14px; padding-top: 0; border-top: 0; }

.nav-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin: 20px 0 0;
  padding: 14px 9px 0;
  border-top: 1px solid var(--line-soft);
  font: var(--t-fine) var(--sans);
}
/* ink-faint here read as disabled text; these are pages, so they keep the
   working ink and show where you are like every other row on the rail */
.nav-foot a { color: var(--ink-soft); text-decoration: none; }
.nav-foot a:hover { color: var(--accent-text); }
.nav-foot a.active { color: var(--accent-text); font-weight: 600; }

/* the shelf's field: a hairline, a soft corner, and a ring when it has focus */
#search {
  width: 100%;
  padding: 8px 12px;
  font: var(--t-fine) var(--sans);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
#search::placeholder { color: var(--ink-faint); }
#search:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
#search-results { margin: 7px 0 0; padding: 0; list-style: none; font-size: var(--t-fine); }
#search-results a { display: block; padding: 5px 9px; border-radius: 6px; color: var(--ink-soft); text-decoration: none; }
#search-results a:hover { background: var(--accent-soft); color: var(--ink); }
#search-results .kind { font-size: var(--t-micro); margin-left: 6px; }

/* ---------- typography ---------- */

h1, h2, h3, h4 {
  font-family: var(--sans);
  line-height: 1.2;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
h1 {
  font-size: clamp(30px, 3.6vw, 42px);
  font-weight: 700;
  line-height: 1.08;
  margin: 10px 0 18px;
}
h2 { font-size: 24px; font-weight: 700; margin: 56px 0 14px; }
h3 { font-size: 18px; font-weight: 600; margin: 34px 0 8px; }
h4 { font-size: 16px; font-weight: 600; margin: 26px 0 6px; }
p { margin: 0 0 1.15em; }

.eyebrow { margin: 0 0 10px; }
.lede { font-size: var(--t-sub); color: var(--ink-soft); margin: 0 0 30px; line-height: 1.45; }

/* ---------- the reading scale ---------- */
/* The paper and the story are read; the library is scanned. So the two pages a
   reader stays on take the ladder, and only they: prose a rung above where it
   was, and every heading a rung above the one below it, so the hierarchy is
   carried by size and weight together instead of by weight alone. Before this,
   an h3 was 18px over 18px prose - a subhead the same size as its paragraph.

   The measure is unchanged at 42rem, which at the new size is a little under
   sixty-five characters a line: the point where a reader's eye still finds the
   next line without hunting for it. */
body.reading {
  font-size: var(--t-read);
  line-height: var(--lh-read);
  /* Proportional figures in running prose, so "28.4 BLEU" sits in the sentence
     instead of standing in a column of its own width. The places where numbers
     are meant to line up ask for tabular back, by name, below. */
  font-variant-numeric: normal;
}
body.reading :is(.chapter-num, .c-n, .nav-list .n, .nav-fold > summary .count,
  .level-badge, .source-pg, .reader-count, .zoom-ctl span, .find-count,
  table.kv, .pdf-page) {
  font-variant-numeric: tabular-nums;
}
/* One class and one element apiece, and no more. The column beside the paper
   sets the same headings a scale smaller further down this sheet; at equal
   weight the later rule wins, which is how it stays able to. */
.reading h1 {
  font-size: clamp(var(--t-title), 3.84vw, var(--t-display));
  line-height: var(--lh-title);
  letter-spacing: -0.026em;
  margin: 10px 0 18px;
}
.reading h2 {
  font-size: var(--t-head);
  line-height: var(--lh-head);
  letter-spacing: -0.018em;
  margin: 58px 0 16px;
}
.reading h3 {
  font-size: var(--t-sub);
  line-height: 1.3;
  letter-spacing: -0.012em;
  margin: 38px 0 10px;
}
.reading h4 {
  font-size: var(--t-minor);
  line-height: 1.35;
  letter-spacing: -0.006em;
  margin: 28px 0 7px;
}
/* ---------- name, description, page ---------- */
/* A concept, a figure, a theme all open the same way: what it is, then one
   line saying what it is about, then the writing. Those three were set too
   close together to read as three things - a 39px name over a 23px summary
   over 19px prose, the summary set larger than the page it was introducing.
   So the ends move and the middle stays put. The name takes a whole rung it
   did not have before. The summary drops six, all the way to the rung the
   captions are set on, which is what turns it into a standfirst: a line under
   the name rather than the first paragraph of the page, read on the way past
   rather than stopped at. And the writing itself is left exactly where it was,
   because it is the one of the three a reader is here for.

   Where the labels follow - a concept's chips, the sections it was read out of
   - the summary closes up against them, because the name and the line under it
   are one thing and the gap belongs after the pair, not inside it.

   The column beside the paper opens these same pages and takes the same shape
   a scale down, further along this sheet. */
.reading .lede {
  font-size: var(--t-fine);
  line-height: 1.6;
  margin: 0 0 30px;
}
.reading .lede:has(+ .chips),
.reading .lede:has(+ .source-cite) { margin-bottom: 13px; }

/* A paragraph is allowed to steal from its own last-but-one line rather than
   leave a single word stranded on the last one. Wrapping only: the margins
   stay where every p on the site gets them, so the ones that carry their own
   (a summary in the column, a citation line) keep it. */
.reading p { text-wrap: pretty; }

/* On the connections page a section is named by the kind of edge under it, and
   the name arrives as a chip rather than as words. That left a heading's whole
   box - its size, its leading, fifty-eight pixels of air above it - wrapped
   around a pill that carries none of it. Shrink the box back onto the pill,
   and let the pill stand up to the job the h2 was doing: it is the one place
   on the site where a chip is a heading, and the colour it carries is the
   whole point of it being one. */
.reading h2:has(> .chip:only-child) {
  margin: 52px 0 4px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  line-height: 1;
}
/* Not a pill. Every row under this heading joins its two names with a pill, so
   a heading built out of one more pill is the section and the rows saying the
   same thing in the same voice. It becomes the site's label instead - capitals,
   tracked open - and keeps the colour, which is the part that was carrying the
   meaning all along. */
.reading h2 > .chip:only-child {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font: 600 var(--t-mini) var(--sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

a { color: var(--accent-text); text-underline-offset: 2px; }

a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* internal term links: underlined rather than coloured, so prose stays readable */
a.term {
  color: inherit;
  text-decoration: none;
  background-image: var(--grad-brand);
  background-size: 100% 1px;
  background-position: 0 calc(100% - 1px);
  background-repeat: no-repeat;
  cursor: pointer;
  transition: background-size 0.12s ease, color 0.12s ease;
}
a.term:hover { color: var(--accent-text); background-size: 100% 2px; }
h1 a.term, h2 a.term, h3 a.term { background-image: none; color: var(--ink); }
h1 a.term:hover, h2 a.term:hover, h3 a.term:hover { color: var(--accent-text); }
a.term-missing {
  color: var(--red);
  background-image: linear-gradient(var(--red) 0 0);
  background-size: 100% 1px;
}

code {
  font-family: var(--mono);
  font-size: 0.85em;
  background: var(--code-bg);
  padding: 1.5px 5px;
  border-radius: 4px;
}
pre { background: var(--code-bg); padding: 14px 16px; border-radius: var(--r-sm); overflow-x: auto; }
pre code { background: none; padding: 0; }

blockquote {
  margin: 0 0 1.15em;
  padding: 3px 0 3px 18px;
  border-left: 2px solid var(--line);
  color: var(--ink-soft);
}

ul, ol { margin: 0 0 1.15em; padding-left: 26px; }
li { margin-bottom: 7px; }
li::marker { color: var(--ink-faint); }

/* the same 1px, drawn as a rule that fades in and out rather than a line */
hr { border: none; height: 1px; background: var(--hairline); margin: 32px 0; }

.math-raw { font-family: var(--mono); font-size: 0.85em; color: var(--accent-text); }
.katex { font-size: 1.04em; }
.math-block { overflow-x: auto; padding: 8px 0; margin: 0 0 15px; }

/* ---------- chips & cards ---------- */

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 20px; }
/* the shelf's chip: a pill on a hairline */
.chip {
  font: 500 var(--t-fine) var(--sans);
  letter-spacing: 0;
  padding: 3px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  background: var(--surface);
  text-decoration: none;
  white-space: nowrap;
  line-height: 1.5;
}
a.chip { transition: border-color 0.12s ease, color 0.12s ease; }
a.chip:hover { border-color: var(--accent); color: var(--accent-text); }
.chip.major { background: var(--d0-soft); border-color: transparent; color: var(--d0); }
.chip.floor { color: var(--ink-faint); }
.chip.t-depends-on { color: var(--blue); }
.chip.t-supported-by { color: var(--green); }
.chip.t-instance-of { color: var(--violet); }
.chip.t-contrasts-with { color: var(--red); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 17px 19px;
  margin: 0 0 12px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.card:hover { box-shadow: var(--shadow), var(--glow); }
.card h3, .card h4 { margin-top: 0; }
.card-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 0 0 18px; }
/* a thumbnail sits above its title, not inside the line of it */
.card-grid .card { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; }
.card-grid .card > a { display: block; width: 100%; }
.card-grid .card img { display: block; margin: 0 auto; }
.card-grid .card .sub { margin: 0; }
@media (max-width: 720px) { .card-grid { grid-template-columns: 1fr; } }
.card .sub { font-size: var(--t-plain); color: var(--ink-soft); margin: 6px 0 0; line-height: 1.55; }
.card a.title { font: 600 var(--t-mid) var(--sans); color: var(--ink); text-decoration: none; letter-spacing: -0.008em; }
.card a.title:hover { color: var(--accent-text); }

/* On the white sheet a boxed list reads as furniture, so a run of cards is
   ruled instead; the grid of figures keeps its cards, being a grid. */
body.reading .card {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  border-radius: 0;
  box-shadow: none;
  padding: 15px 2px;
  margin: 0;
}
body.reading .card:hover { background: none; }
body.reading .card-grid .card {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 16px 18px;
  box-shadow: var(--shadow-sm);
}

.callout {
  /* The stripe is painted into the border box instead of being the border's
     colour, so the 3px inset and the corner radius are exactly what they were
     and the mark can run down the accent. The ground under it is flat. */
  background-image: linear-gradient(170deg, var(--accent), var(--accent-3));
  background-repeat: no-repeat;
  background-origin: border-box;
  background-clip: border-box;
  background-size: 3px 100%;
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid transparent;
  border-radius: var(--r);
  padding: 15px 19px;
  margin: 0 0 18px;
}
.callout .eyebrow { font-size: var(--t-micro); margin-bottom: 6px; color: var(--accent-text); }
.callout p:last-child { margin-bottom: 0; }

details.sub-concept {
  border: 1px solid var(--line);
  border-radius: var(--r);
  margin: 0 0 8px;
  background: var(--surface);
}
details.sub-concept > summary {
  cursor: pointer;
  padding: 11px 15px;
  font: 600 var(--t-mid) var(--sans);
  color: var(--ink);
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: 9px;
}
details.sub-concept > summary::-webkit-details-marker { display: none; }
details.sub-concept > summary::before {
  content: "+";
  font: 600 var(--t-mid) var(--sans);
  color: var(--accent-text);
}
details.sub-concept[open] > summary::before { content: "\2212"; }
details.sub-concept[open] > summary { border-bottom: 1px solid var(--line-soft); }
/* The name takes the width it needs and the gloss takes what is left, on one
   line, ending in the browser's own ellipsis. Left to share the row evenly they
   fought over it, and a three-word name came out stacked three lines deep. */
details.sub-concept > summary .hint {
  /* Nothing of its own to start from, so every pixel the name does not want
     goes to the gloss and the name is never the one that gives way. */
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 400;
  color: var(--ink-faint);
  font-size: var(--t-small);
}
details.sub-concept > .body { padding: 12px 15px 4px; font-size: var(--t-mid); }

/* ---------- figure pages ---------- */

.figure-wrap {
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 18px;
  margin: 0 0 8px;
  overflow-x: auto;
  box-shadow: var(--shadow-sm);
}
:root[data-theme="dark"] .figure-wrap { background: #f4f5f7; border-color: transparent; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .figure-wrap { background: #f4f5f7; border-color: transparent; }
}
.figure-wrap img { max-width: 100%; height: auto; display: block; margin: 0 auto; }
.fig-note { font: var(--t-small) var(--sans); color: var(--ink-faint); margin: 0 0 26px; line-height: 1.6; }

/* The way out of a figure to the shape it is drawn in. Built like the zoom
   link, quieter: it is an offer of help, not the next step of the story. */
.chart-link {
  display: block;
  margin: 22px 0 10px;
  padding: 13px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  text-decoration: none;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.chart-link:hover { border-color: var(--accent); transform: translateY(-1px); }
.chart-link-label { display: block; font-size: var(--t-micro); }
.chart-link-name {
  display: block;
  font: 600 var(--t-plain) var(--sans);
  color: var(--accent-text);
  margin-top: 5px;
  letter-spacing: -0.01em;
}

/* Not the authors' caption - the sentence their article leads into the figure
   with. Said plainly, because a quote mark would claim otherwise. */
.lead-in-label { font-size: var(--t-micro); line-height: 1; margin: 0 0 8px; }

table.kv {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-plain);
  margin: 0 0 22px;
}
table.kv th {
  font: 600 var(--t-micro) var(--sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-align: left;
  padding: 7px 14px 7px 0;
  border-bottom: 1px solid var(--line);
}
table.kv td { padding: 9px 14px 9px 0; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
table.kv tr:last-child td { border-bottom: 1px solid var(--line); }
table.kv td.k { font-weight: 600; font-size: var(--t-small); white-space: nowrap; color: var(--ink); }
.table-scroll { overflow-x: auto; }

/* ---------- edges ---------- */

.edge-row {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 13px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--t-mid);
}
.edge-row .rel { flex: 0 0 auto; }
/* In prose a term is a quiet offer to go deeper. In a row it is the content,
   and the row is two of them joined by a connective, so they take the weight
   that tells a reader where one ends and the next begins. */
.edge-row a.term { font-weight: 500; }
.edge-exp { color: var(--ink-soft); font-size: var(--t-plain); margin: 4px 0 0; line-height: 1.55; }

/* ---------- narrative ---------- */

.chapter { margin: 0 0 60px; }
.chapter h2 { position: relative; }
.chapter-num {
  font: 500 var(--t-fine) var(--sans);
  letter-spacing: 0;
  color: var(--ink-faint);
  margin-right: 10px;
}
@media (min-width: 1180px) {
  .chapter-num { position: absolute; right: calc(100% + 16px); top: 0.45em; margin: 0; }
}

/* the chapter index of whichever level you are on */
.contents {
  list-style: none;
  margin: 4px 0 48px;
  padding: 0;
  columns: 2;
  column-gap: 36px;
}
.contents li { margin: 0; break-inside: avoid; }
.contents a {
  display: flex;
  gap: 11px;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink-soft);
  text-decoration: none;
  font: var(--t-plain) var(--sans);
  line-height: 1.35;
}
.contents a:hover { color: var(--accent-text); border-bottom-color: var(--accent); }
.c-n {
  flex: 0 0 auto;
  font: 500 var(--t-mini) var(--sans);
  color: var(--ink-faint);
}
@media (max-width: 760px) { .contents { columns: 1; } }

.level-note { font: var(--t-small) var(--sans); color: var(--ink-faint); margin: 0 0 22px; line-height: 1.55; }
.level-note a { color: var(--accent-text); }

/* ---------- popover ---------- */

#popover {
  position: absolute;
  z-index: 50;
  max-width: 340px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-lift);
  padding: 13px 15px;
  font-size: var(--t-small);
  line-height: 1.55;
  display: none;
}
#popover .pop-name { font: 600 var(--t-small) var(--sans); margin: 0 0 5px; color: var(--ink); }
#popover .pop-kind { font-size: var(--t-micro); margin-left: 7px; }
#popover p { margin: 0; color: var(--ink-soft); }

/* ---------- responsive ---------- */

/* On a narrow screen the rail carries the way to the contents. A pill, like
   every small control on the site. */
#menu-btn { display: none; }

@media (max-width: 900px) {
  body { --rail-h: 56px; }
  #app { display: block; }
  #sidebar {
    position: fixed;
    top: var(--rail-h);
    left: 0;
    z-index: 40;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: var(--shadow-lift);
  }
  #sidebar.open { transform: none; }
  #menu-btn {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    height: 34px;
    padding: 0 14px;
    font: 500 var(--t-fine) var(--sans);
    background: var(--surface);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 999px;
    cursor: pointer;
  }
  .rail { gap: 12px; }
  body.reading .rail { padding: 0 14px 0 16px; }
  .rail-mark { font-size: var(--t-sub); }
  .content { padding: 36px 22px 96px; }
  h2, .reading h2 { margin-top: 40px; }
  /* A phone gives the prose about 350px, and at the desktop size that is
     thirty-six characters to a line - short enough that a reader spends the
     paragraph starting new lines. The column cannot widen, so the type comes
     down a rung and the line fills out to forty. The headings stay where they
     are: they were sized against the window, not against the measure. */
  body.reading { font-size: var(--t-mid); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

.muted { color: var(--ink-faint); }
.small { font-size: var(--t-plain); }
.placeholder {
  border: 1px dashed var(--line);
  border-radius: var(--r);
  padding: 22px;
  color: var(--ink-faint);
  font-size: var(--t-small);
}

/* ---------- recursive narrative ---------- */

.crumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  font: var(--t-fine) var(--sans);
  color: var(--ink-faint);
  margin: 0 0 18px;
}
.crumb a { color: var(--ink-soft); text-decoration: none; }
.crumb a:hover { color: var(--accent-text); text-decoration: underline; }
.crumb-here { color: var(--ink); font-weight: 600; }
.crumb-sep { color: var(--ink-faint); }
.crumb-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: linear-gradient(150deg,
    var(--depth, var(--d0)) 0%,
    color-mix(in srgb, var(--depth, var(--d0)) 45%, var(--accent-3)) 100%);
  display: inline-block;
  flex: 0 0 auto;
}

/* how far in this page sits */
.level-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: 600 var(--t-mini) var(--sans);
  color: var(--depth-ink, var(--d0-ink));
  background: var(--depth-soft, var(--d0-soft));
  border-radius: 999px;
  padding: 4px 12px;
  margin: 0 0 12px;
}

a.zoom {
  display: block;
  position: relative;
  margin: 20px 0 8px;
  padding: 15px 18px 15px 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
a.zoom::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: linear-gradient(180deg,
    var(--depth, var(--d1)) 0%,
    color-mix(in srgb, var(--depth, var(--d1)) 34%, var(--accent-3)) 100%);
}
a.zoom:hover {
  border-color: var(--depth, var(--d1));
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}
.zoom-label { display: block; font-size: var(--t-micro); color: var(--depth-ink, var(--d1-ink)); }
.zoom-title { display: block; font: 600 var(--t-mid) var(--sans); color: var(--ink); margin-top: 5px; letter-spacing: -0.01em; }
.zoom-sub { display: block; font: var(--t-fine) var(--sans); color: var(--ink-faint); margin-top: 5px; }

.up-link {
  display: inline-block;
  margin: 32px 0 0;
  font: var(--t-small) var(--sans);
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
}
.up-link:hover { color: var(--accent-text); border-bottom-color: var(--accent); }

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

.source-cite {
  margin: 0 0 26px;
  font: var(--t-fine) var(--sans);
  color: var(--ink-faint);
  line-height: 1.9;
}
.source-label { color: var(--ink-faint); margin-right: 9px; white-space: nowrap; }
a.source-link {
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}
a.source-link:hover { color: var(--accent-text); border-bottom-color: var(--accent); }
.source-pg { margin-left: 5px; white-space: nowrap; font: 500 var(--t-mini) var(--sans); color: var(--ink-faint); }
a.source-link:hover .source-pg { color: var(--accent-text); }
.src-sep { color: var(--line); margin: 0 8px; }
.source-more { margin-left: 8px; color: var(--ink-faint); }
.source-note { color: var(--ink-faint); font-style: italic; margin-left: 8px; }

/* The per-chapter line inside a narrative is quieter than a page-level one -
   quieter by sitting up tight under its heading rather than by being set a
   size smaller, which would put a rung on the ladder to no purpose. */
.source-cite.small-cite { margin: -12px 0 24px; }

/* ---------- insights: relationships under a chapter ---------- */

details.edge-drawer {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  margin: 8px 0 10px;
}
details.edge-drawer > summary {
  cursor: pointer;
  padding: 10px 15px;
  font: 500 var(--t-fine) var(--sans);
  color: var(--ink-soft);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 9px;
}
details.edge-drawer > summary::-webkit-details-marker { display: none; }
details.edge-drawer > summary::before { content: "\21c4"; color: var(--blue); font-weight: 700; }
details.edge-drawer[open] > summary { border-bottom: 1px solid var(--line-soft); }
details.edge-drawer > .body { padding: 6px 15px 10px; }
details.edge-drawer .edge-row:last-child { border-bottom: none; }

/* a hairline rather than a wash, like every other surface on the site */
.related-insight {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 14px 0 4px;
  padding: 11px 15px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  font-size: var(--t-fine);
}
.ri-label { font: 600 var(--t-mini) var(--sans); color: var(--ink-faint); }
.related-insight a { color: var(--ink-soft); text-decoration: none; border-bottom: 1px solid var(--line); }
.related-insight a:hover { color: var(--accent-text); border-bottom-color: var(--accent); }

.coverage-note {
  margin: 48px 0 0;
  padding: 20px 24px;
  border: 1px dashed var(--line);
  border-radius: var(--r);
  background: var(--surface);
  font-size: var(--t-plain);
  color: var(--ink-soft);
}
.coverage-note p:last-child { margin-bottom: 0; }

/* ---------- the reader ---------- */
/* The PDF as printed, with the concepts of the block you are on beside it.
   On this route the site rail stays and the sidebar steps aside: the page
   needs the width, and the rail takes the reader's few controls - the way
   back, find, where you are, zoom - between the mark and the theme toggle.

   Nothing is drawn over the paper while you read. The column names the block
   it is describing by quoting it; the page marks only under the pointer and
   when pinned, where a mark is an affordance rather than a label. */

body.reader-mode { --top-h: var(--rail-h); }
body.reader-mode #sidebar,
body.reader-mode #menu-btn { display: none; }
body.reader-mode .content { max-width: none; margin: 0; padding: 0; }

.reader-count { flex: 0 0 auto; font: 500 var(--t-mini) var(--sans); color: var(--ink-faint); white-space: nowrap; }

.zoom-ctl { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.zoom-ctl button {
  width: 28px;
  height: 28px;
  font: 500 var(--t-plain) var(--sans);
  line-height: 1;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.zoom-ctl button:hover:not(:disabled) { color: var(--accent-text); border-color: var(--accent); }
.zoom-ctl button:disabled { opacity: 0.35; cursor: default; }
.zoom-ctl span { min-width: 40px; text-align: center; font: 500 var(--t-mini) var(--sans); color: var(--ink-faint); }

/* The column takes its width from the paper when a page is open in it. */
.reader {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 336px;
  align-items: start;
  transition: grid-template-columns 0.24s ease;
}
.reader.wide { grid-template-columns: minmax(0, 1fr) min(52vw, 620px); }

/* A paper shown as its own framed page, rather than as rendered PDF pages.

   Two things follow. Changing the width of a canvas scales a picture; changing
   the width of an article re-flows every line of it, so animating the column
   open re-flowed the whole paper once per frame for a quarter of a second.
   It snaps instead: one re-flow, not fifteen.

   And the width belongs to the article. Its own layout decides how wide the
   text runs from how much room it is given, in steps - below 1040px it uses a
   472px column, then 512, then 704 at 1200 - so the pane's own padding is
   worth about one of those steps. The article brings its own margins; ours
   only cost it a breakpoint. */
.reader.framed { transition: none; }
.reader.framed .pdf-pane { padding-left: 4px; padding-right: 4px; }

.pdf-pane { overflow-x: auto; padding: 24px clamp(10px, 2.5vw, 36px) 120px; }
.pdf-wait { padding: 60px 24px; font-size: var(--t-small); color: var(--ink-faint); }
.pdf-page {
  position: relative;
  width: var(--pdf-w, 100%);
  margin: 0 auto 18px;
  scroll-margin-top: calc(var(--top-h) + 10px);
  background: #fff;
  border-radius: 2px;
  box-shadow: var(--shadow);
}
.pdf-page canvas { display: block; width: 100%; height: auto; border-radius: 2px; }
.pdf-page { user-select: none; }

/* Paper is white. At night it is still paper, just not a floodlight - dimmed
   rather than inverted, so figures and colour plots stay truthful. */
:root[data-theme="dark"] .pdf-page { filter: brightness(0.84); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pdf-page { filter: brightness(0.84); }
}

/* Blocks are drawn from fractions of the page, so they hold at any zoom. They
   are hit targets and nothing else: no fill, no rule, nothing over the paper in
   any state. The cursor says a block can be clicked, and the column says which
   block it is on and whether it is pinned. */
.rgn { position: absolute; cursor: pointer; }
.rgn.r-heading { cursor: default; }

/* A paper published as a web page is shown as its authors published it, from
   our own copy of it. Same rule as the PDF: nothing of ours over their page.
   The marks under the pointer and on the pinned block are injected into the
   frame itself, since that is the only document that can carry them. */
.paper-frame {
  display: block;
  width: 100%;
  border: 0;
  margin: 0 auto;
  background: #fff;
  border-radius: 2px;
  box-shadow: var(--shadow);
}
:root[data-theme="dark"] .paper-frame { filter: brightness(0.84); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .paper-frame { filter: brightness(0.84); }
}

.beside {
  position: sticky;
  top: var(--top-h);
  height: calc(100vh - var(--top-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 28px 48px;
  border-left: 1px solid var(--line);
  background: var(--bg);
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.beside-bar { display: none; }
.beside-label { margin: 24px 0 8px; font-size: var(--t-micro); }
/* A second heading in the same column: the evidence sitting where you are
   reading, under the concepts it is evidence for. Ruled off, because it
   answers a different question from the list above it. */
.beside-label-more {
  margin-top: 26px;
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
}
/* "Figure 8" beside its name: the number is how the prose refers to it, so it
   leads, quietly. */
.beside-fig {
  display: block;
  font: 600 var(--t-micro) var(--sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 2px;
}
/* Which block the column is about, said rather than drawn. */
.beside-quote {
  margin: 0 0 18px;
  padding-left: 11px;
  border-left: 2px solid var(--line);
  font: italic var(--t-fine)/1.5 var(--sans);
  color: var(--ink-faint);
}
.beside-c {
  padding: 12px 0 14px;
  border-top: 1px solid var(--line-soft);
  cursor: pointer;
}
.beside-c:first-of-type { border-top: none; padding-top: 2px; }
.beside-name {
  display: block;
  font: 600 var(--t-small) var(--sans);
  letter-spacing: -0.005em;
  color: var(--ink);
  text-decoration: none;
}
.beside-c:hover .beside-name { color: var(--accent-text); }
.beside-sum { margin: 5px 0 0; font: var(--t-fine)/1.6 var(--sans); color: var(--ink-soft); }
.beside-c.small { padding: 7px 0; border-top: none; }
.beside-empty { font: var(--t-fine)/1.6 var(--sans); color: var(--ink-faint); }
.beside-fold { margin-top: 16px; border-top: 1px solid var(--line-soft); }
.beside-fold summary {
  padding: 11px 0;
  font: 500 var(--t-mini) var(--sans);
  color: var(--ink-faint);
  cursor: pointer;
}
.beside-fold summary:hover { color: var(--accent-text); }
/* the shelf's small button: a pill on a hairline */
.beside-unpin {
  margin-top: 20px;
  padding: 6px 13px;
  font: 500 var(--t-mini) var(--sans);
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.beside-unpin:hover { color: var(--accent-text); border-color: var(--accent); }

/* A concept opened in the column. Links inside it stay inside it, so the
   column grows a way back rather than the reader losing the paper. */
.col-head {
  position: sticky;
  top: 0;
  z-index: 2;
  margin: 0 -28px;
  padding: 14px 28px 12px;
  background: var(--bg);
  border-bottom: 1px solid var(--line-soft);
}
.col-back {
  font-size: var(--t-micro);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.col-back:hover { color: var(--accent-text); }
body.reader-mode .beside .content { max-width: none; padding: 22px 0 40px; }
.col-out { margin-top: 34px; padding-top: 18px; border-top: 1px solid var(--line-soft); }
.col-out-link { font: 500 var(--t-fine) var(--sans); color: var(--accent-text); text-decoration: none; }

/* Narrow: the paper takes the width and the concepts become a sheet. */
@media (max-width: 900px) {
  .reader, .reader.wide { grid-template-columns: 1fr; }
  .pdf-pane { padding-bottom: 92px; }
  .beside {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 30;
    display: flex;
    flex-direction: column;
    height: auto;
    max-height: 68vh;
    padding: 0;
    border-left: none;
    border-top: 1px solid var(--line);
    box-shadow: var(--shadow-lift);
    transform: translateY(calc(100% - 46px));
    transition: transform 0.2s ease;
  }
  .beside.open { transform: none; }
  .beside-bar {
    display: block;
    width: 100%;
    padding: 14px 20px;
    font: 600 var(--t-fine) var(--sans);
    text-align: left;
    color: var(--ink);
    background: none;
    border: none;
    cursor: pointer;
  }
  .beside-bar::after { content: "\25B4"; float: right; color: var(--ink-faint); }
  .beside.open .beside-bar::after { content: "\25BE"; }
  .beside-body { overflow-y: auto; padding: 0 20px 24px; }
  .beside-label { margin-top: 4px; }
  .col-head { margin: 0 -20px; padding: 12px 20px 10px; }
  .beside-unpin { margin: 0 20px 20px; }
}

/* ---------- find in the paper ---------- */
/* The paper cannot be selected, so the browser's find has nothing to catch.
   This searches the same block text the column is keyed to, which means a hit
   lands somewhere that can explain itself. */

.find-wrap { position: relative; margin-left: auto; flex: 0 0 auto; }
#find {
  width: 190px;
  padding: 6px 12px;
  font: var(--t-fine) var(--sans);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  outline: none;
  transition: width 0.18s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
#find::placeholder { color: var(--ink-faint); }
#find:focus { width: 260px; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }

.find-results {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  width: min(430px, 82vw);
  max-height: min(60vh, 460px);
  overflow-y: auto;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-lift);
  /* the rail sets the page's own leading; a list wants a tighter one */
  line-height: 1.5;
}
.find-count,
.find-none { margin: 6px 8px 8px; font-size: var(--t-micro); }
.find-none { text-transform: none; letter-spacing: 0; font: var(--t-fine) var(--sans); color: var(--ink-faint); }
.find-row {
  display: block;
  width: 100%;
  padding: 9px 10px;
  text-align: left;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  cursor: pointer;
}
.find-row:hover { background: var(--accent-soft); }
.find-sec {
  display: block;
  margin-bottom: 3px;
  font: 500 var(--t-micro) var(--sans);
  color: var(--ink-faint);
}
.find-snip { display: block; font: var(--t-fine)/1.5 var(--sans); color: var(--ink-soft); }
.find-snip mark { background: var(--accent-soft); color: var(--ink); border-radius: 2px; padding: 0 1px; }

/* ---------- a page opened in the column ---------- */
/* The same renderer the standalone page uses, at a scale that belongs in a
   column: the title labels what you opened rather than heading a magazine. */

body.reader-mode .beside .content { max-width: none; padding: 0; }
.col-body {
  max-width: 33rem;
  margin: 0 auto;
  padding: 26px 0 56px;
  font-size: var(--t-plain);
  line-height: 1.65;
}
.col-body .eyebrow { margin: 0 0 9px; font-size: var(--t-micro); }
.col-body h1 { font-size: var(--t-head); font-weight: 700; letter-spacing: -0.018em; line-height: 1.15; margin: 0 0 13px; }
.col-body h2 { font-size: var(--t-minor); margin: 36px 0 10px; letter-spacing: -0.008em; }
.col-body h3 { font-size: var(--t-read); margin: 28px 0 8px; letter-spacing: 0; }
.col-body h4 { font-size: var(--t-mid); margin: 24px 0 6px; }
.col-body .lede { font-size: var(--t-mini); line-height: 1.6; margin: 0 0 22px; }
.col-body .lede:has(+ .chips),
.col-body .lede:has(+ .source-cite) { margin-bottom: 11px; }

/* Opened, the column takes half the window, and the size that was right in a
   336px rail leaves seventy characters to a line out there. So the column
   climbs a rung rather than the measure being pinched back down - the same
   ladder, read one step higher, headings and all. Move them together or the
   heading lands on the paragraph's own size, which is where this started. */
.reader.wide .col-body { font-size: var(--t-mid); line-height: 1.6; }
.reader.wide .col-body h1 { font-size: var(--t-title-sm); }
.reader.wide .col-body h2 { font-size: var(--t-sub); }
.reader.wide .col-body h3 { font-size: var(--t-minor); }
.reader.wide .col-body h4 { font-size: var(--t-read); }
.reader.wide .col-body .lede { font-size: var(--t-fine); }
.col-body p { margin: 0 0 1.05em; }
.col-body ul, .col-body ol { padding-left: 21px; margin-bottom: 1.05em; }
.col-body li { margin-bottom: 5px; }
.col-body blockquote { font-size: var(--t-fine); padding: 1px 0 1px 14px; margin: 0 0 20px; }
.col-body .chips { gap: 5px; margin: 0 0 20px; }
.col-body .chip { font-size: var(--t-micro); padding: 2px 8px; }
.col-body .callout { padding: 12px 15px; border-radius: var(--r-sm); margin: 0 0 20px; font-size: var(--t-small); }
.col-body .callout .eyebrow { font-size: var(--t-micro); margin-bottom: 4px; }
.col-body .figure-wrap { padding: 12px; border-radius: var(--r); margin-bottom: 8px; }
.col-body .fig-note { font-size: var(--t-fine); margin-bottom: 24px; }
.col-body details.sub-concept { border-radius: var(--r-sm); }
.col-body details.sub-concept > summary { font-size: var(--t-small); padding: 9px 13px; }
.col-body details.sub-concept > .body { font-size: var(--t-plain); padding: 10px 13px 2px; }
.col-body .source-cite { font-size: var(--t-mini); }
.col-body .edge-row { font-size: var(--t-plain); padding: 11px 0; }
.col-body .edge-exp { font-size: var(--t-fine); }
/* A card in the column is an index entry in a rail, not a row on a page. */
.col-body .card a.title { font-size: var(--t-plain); }
.col-body .card .sub { font-size: var(--t-fine); }
.col-body .small { font-size: var(--t-fine); }
.col-body h2:has(> .chip:only-child) { margin: 30px 0 8px; }
.col-body h2 > .chip:only-child { font-size: var(--t-fine); padding: 4px 12px; }
.col-body table.kv { font-size: var(--t-fine); }
.col-body hr { margin: 26px 0; }
.col-body .katex-display > .katex { font-size: 1em; }

/* Narrow, on the paper: the rail cannot hold the mark, the switch, the
   controls and the toggle on one line, so the controls take a line of their own
   under the mark. The rail grows to fit; the paper's scroll margin follows it
   by hand. */
@media (max-width: 900px) {
  body.reader-mode { --top-h: 112px; }
  body.reader-mode .rail {
    flex-wrap: wrap;
    height: auto;
    min-height: var(--rail-h);
    padding-top: 10px;
    padding-bottom: 10px;
    row-gap: 8px;
  }
  body.reader-mode .rail-tools { order: 3; flex-basis: 100%; gap: 10px; }
  /* The switch stays lifted out of the row and centred, but the row it is
     centred on is now the first of two. Half the rail is between the lines,
     so it hangs from the top padding instead. */
  body.reader-mode .rail-switch { top: 10px; transform: translateX(-50%); }
  .find-wrap { margin-left: auto; }
  #find { width: 130px; }
  #find:focus { width: 170px; }
  .find-results { width: min(430px, calc(100vw - 32px)); }
  .col-body { padding: 20px 0 40px; }
}

/* Between the two: the controls still share the mark's line, and there is no
   longer room to hold a centred switch clear of them. It rejoins the row, which
   is where it used to live, and the row still fits. */
@media (min-width: 901px) and (max-width: 1120px) {
  body.reader-mode .rail-switch { position: static; transform: none; }
}

/* Narrower still, on the paper: the mark and the toggle alone fill the first
   line, so the switch takes the second and the controls the third. 112 plus a
   34px line and the 8px between them. */
@media (max-width: 620px) {
  body.reader-mode { --top-h: 154px; }
  body.reader-mode .rail-switch {
    position: static;
    transform: none;
    order: 2;
    flex-basis: 100%;
  }
}

/* Off the paper, at the width where the rail also picks up the contents
   button: the menu, the mark, the switch and the toggle no longer fit on one
   line, so the switch takes a line of its own - the same answer the reader
   gives its controls. The rail grows, and the sidebar hanging below it is told
   the new height rather than left to overlap. */
@media (max-width: 900px) {
  /* 10 + 34 + 8 + 34 + 10, and a pixel over rather than under: the sidebar
     hangs from this number, and starting a hair low shows a hairline where
     starting a hair high hides a row of it behind the rail. */
  body.reading:not(.reader-mode) { --rail-h: 98px; }
  body.reading:not(.reader-mode) .rail {
    flex-wrap: wrap;
    height: auto;
    min-height: var(--rail-h);
    padding-top: 10px;
    padding-bottom: 10px;
    row-gap: 8px;
  }
  body.reading:not(.reader-mode) #theme-toggle { order: 3; }
  body.reading:not(.reader-mode) .rail-switch {
    position: static;
    transform: none;
    order: 4;
    flex-basis: 100%;
  }
}

/* The summary's door in the rail is a section label like THE STORY, built in
   buildNav; nothing extra to draw here. */

/* Beats run longer than chapters and carry no zoom link at the end, so they
   need their own breathing room rather than a chapter's. */
.chapter.beat { margin-bottom: 44px; }
.chapter.beat > p:first-of-type { margin-top: 0.6em; }

/* ---------- a figure sitting in the prose ---------- */
/* The paragraph reads through as written and the crop follows underneath. What
   keeps this prose with pictures in it rather than a slide deck is the cap: a
   paper prints figures from a 200px table to a full-page architecture diagram,
   and an uncapped crop pushes the next paragraph off the screen. Anything
   taller is scaled down and says so, and the click opens it at full size. */
.fig-inline {
  margin: 26px 0 30px;
  padding: 0;
  cursor: pointer;
  border-radius: var(--r-lg);
  outline-offset: 3px;
}
/* The crop is fetched lazily - a chapter can carry sixteen of them - so the
   box holds a band of space before the image arrives. Without it an unloaded
   figure is nothing at all and the paragraph under it jumps as you read. */
.fig-inline-media {
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 16px;
  min-height: 190px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
:root[data-theme="dark"] .fig-inline-media { background: #f4f5f7; border-color: transparent; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .fig-inline-media { background: #f4f5f7; border-color: transparent; }
}
.fig-inline:hover .fig-inline-media,
.fig-inline:focus-visible .fig-inline-media {
  box-shadow: var(--shadow), var(--glow);
  border-color: var(--accent-ring);
}
.fig-inline img {
  display: block;
  margin: 0 auto;
  max-width: 100%;
  max-height: 420px;
  height: auto;
  object-fit: contain;
}
/* An equation has no crop to cap; it is set on the page's own ground rather
   than on the white a scanned figure needs. */
.fig-inline.is-eq .fig-inline-media {
  background: var(--accent-soft);
  border-color: var(--accent-ring);
  box-shadow: none;
  padding: 20px 16px;
  /* Nothing is fetched here, so there is no space to hold open: a one-line
     formula sits in a box the height of a formula. */
  min-height: 0;
  text-align: center;
}
:root[data-theme="dark"] .fig-inline.is-eq .fig-inline-media { background: var(--accent-soft); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .fig-inline.is-eq .fig-inline-media { background: var(--accent-soft); }
}
.fig-inline figcaption { margin: 10px 2px 0; }
.fig-inline-label {
  display: inline-block;
  font: 600 var(--t-micro) var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.fig-inline-title {
  display: inline;
  font: 600 var(--t-small) var(--sans);
  color: var(--ink);
  margin-left: 9px;
}
.fig-inline:hover .fig-inline-title { color: var(--accent-text); }
.fig-inline-take {
  display: block;
  margin-top: 5px;
  font: var(--t-small)/1.6 var(--sans);
  color: var(--ink-soft);
}
/* In the reading column the prose is already at the column's scale, so the cap
   comes down with it. */
.col-body .fig-inline { margin: 18px 0 20px; }
.col-body .fig-inline-media { padding: 10px; }
.col-body .fig-inline img { max-height: 240px; }
.col-body .fig-inline-take { font-size: var(--t-fine); }

/* ---------- a figure opened over the article ---------- */
.figpop { position: fixed; inset: 0; z-index: 60; }
/* A flat scrim, deliberately. Blurring it means compositing the whole article
   behind it, and an article here runs to seventeen thousand pixels - it cost
   enough to stall a screenshot outright, which is a fair proxy for what it
   costs a reader's machine. The dimming does the whole job. */
.figpop-scrim {
  position: absolute;
  inset: 0;
  background: rgba(11, 14, 20, 0.55);
}
.figpop-panel {
  position: absolute;
  inset: 3vh 0 0;
  width: min(760px, 94vw);
  margin: 0 auto;
  background: var(--bg);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.figpop-body { overflow-y: auto; padding: 30px 34px 40px; flex: 1; }
.figpop-close {
  position: absolute;
  top: 10px;
  right: 12px;
  z-index: 1;
  width: 32px;
  height: 32px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--bg);
  color: var(--ink-faint);
  font: var(--t-read)/1 var(--sans);
  cursor: pointer;
}
.figpop-close:hover { color: var(--ink); border-color: var(--accent-ring); }
/* The page behind it does not scroll while it is open. */
body.figpop-open { overflow: hidden; }
@media (max-width: 720px) {
  .figpop-panel { inset: 8vh 0 0; width: 100%; }
  .figpop-body { padding: 24px 18px 36px; }
}

/* ---------- which read to open ---------- */
/* A card in the middle of the window rather than the sheet a figure opens in:
   this is a page of prose that ends, and it is read once and dismissed, so it
   is sized to itself. The scrim is the figure's, unchanged - one dimming for
   everything that opens over the page. */
.helppop {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
/* the display above would otherwise beat the hidden attribute */
.helppop[hidden] { display: none; }
.helppop-panel {
  position: relative;
  z-index: 1;
  width: min(620px, 100%);
  max-height: min(84vh, 760px);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lift);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.helppop-body { overflow-y: auto; padding: 30px 34px 34px; }
/* clear of the body's scrollbar, which runs under it whenever the card is
   taller than the window */
.helppop-panel .figpop-close { right: 20px; }
.helppop-body h2 {
  margin: 0 0 8px;
  font: 700 var(--t-head) var(--sans);
  letter-spacing: -0.02em;
  color: var(--ink);
}
.help-lede { margin: 0 0 4px; font: 400 var(--t-plain)/1.55 var(--sans); color: var(--ink-faint); }
/* One reading to a block, each block headed by the name it carries in the rail
   so the answer can be matched to the thing it is about without reading down. */
.help-read { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line-soft); }
.help-read h3 {
  margin: 0 0 10px;
  font: 600 var(--t-mid) var(--sans);
  color: var(--ink);
}
/* The two lines are the same sentence twice, so they are set as one grid: the
   labels line up down the card and the cases read as a column of their own. */
.help-yes,
.help-no {
  display: grid;
  grid-template-columns: 66px 1fr;
  gap: 12px;
  margin: 0 0 6px;
  font: 400 var(--t-plain)/1.55 var(--sans);
  color: var(--ink-soft);
}
.help-tag {
  font: 600 var(--t-micro) var(--sans);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding-top: 2px;
}
.help-yes .help-tag { color: var(--green); }
.help-no .help-tag { color: var(--red); }
/* The one thing here that is not a case for or against: where the ground under
   this reading runs out, and what to do when it does. */
.help-note {
  margin: 12px 0 0 78px;
  padding-left: 12px;
  border-left: 2px solid var(--line);
  font: 400 var(--t-plain)/1.55 var(--sans);
  color: var(--ink-faint);
}
body.helppop-open { overflow: hidden; }
@media (max-width: 620px) {
  .helppop { padding: 12px; }
  .helppop-body { padding: 26px 20px 28px; }
  .help-yes,
  .help-no { grid-template-columns: 1fr; gap: 2px; }
  .help-note { margin-left: 0; }
}

/* ---------- a figure held up close ---------- */
/* The panel on a figure page is the button that opens it, so it keeps every
   line of the panel it already was and adds only what says it can be pressed:
   the cursor, a ring on focus, and a corner mark that is always there. Always,
   because a mark that appears on hover is a mark a touch screen never shows. */
.figure-wrap.figure-closeup {
  position: relative;
  display: block;
  width: 100%;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: zoom-in;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.figure-closeup:hover { border-color: var(--accent-ring); box-shadow: var(--shadow); }
.figure-closeup:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.figure-closeup-mark {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  /* The plate under it is white in either theme, so the mark is coloured for
     white rather than off the palette. */
  border: 1px solid rgba(11, 14, 20, 0.16);
  border-radius: 50%;
  background: #ffffff;
  color: #48515a;
  font: var(--t-fine)/1 var(--sans);
  transition: color 0.15s ease, border-color 0.15s ease;
}
.figure-closeup:hover .figure-closeup-mark { color: #1e40af; border-color: #1d4ed8; }
.col-body .figure-closeup-mark { top: 6px; right: 6px; }

/* On its own page the figure is the subject rather than an illustration inside
   a column of prose, so the plate steps out of the column and takes the width
   the window gives it - the same width for every figure, instead of each one
   arriving at whatever size it happened to be cropped at. A crop off a PDF runs
   from 640 pixels to 1,800, and drawn at its own size that is what the reader
   saw: two figures on the same paper, one twice the other, for a reason that
   has nothing to do with either.

   Height is a page measure too. A portrait figure stops at four fifths of the
   window and gives back the width it does not need, so the plate is always
   the size of the picture and the picture is always the size of the page. */
body:not(.reader-mode) #content .figure-closeup {
  /* The sidebar's 290 and a gutter either side of the plate. */
  --fig-w: min(1000px, calc(100vw - 371px));
  --fig-h: 82vh;
  width: fit-content;
  max-width: none;
  margin-left: 50%;
  transform: translateX(-50%);
}
/* Whichever limit binds first. --fig-ar is the picture's own width over its
   height, written on the plate by figRatio() once the file has arrived; until
   then the fallback is large enough that only the width counts. */
body:not(.reader-mode) #content .figure-closeup img {
  width: min(var(--fig-w), calc(var(--fig-h) * var(--fig-ar, 99)));
  max-width: none;
  max-height: var(--fig-h);
}
@media (max-width: 900px) {
  /* The sidebar is off the page here and there is no room to step out of the
     column, so the plate lands on the prose's own gutter: the window, less
     that gutter both sides, the plate's padding and hairline, and room for a
     scrollbar on the machines that keep one. Off the window rather than the
     column, because a plate that shrinks to its picture cannot be measured as
     a percentage of itself. */
  body:not(.reader-mode) #content .figure-closeup { --fig-w: calc(100vw - 96px); }
}

/* A solid ground rather than the figure popup's dimmed one, and no panel on it:
   the picture is the whole content here, and anything drawn around it is another
   edge competing with the one the crop already has. Solid also because a wash
   this large, laid over an article of seventeen thousand pixels, is a
   composite the browser does not always draw - and a backdrop that sometimes
   arrives is worse than one that is simply opaque. */
.closeup { position: fixed; inset: 0; z-index: 80; background: #0b0e14; }
.closeup-stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  display: grid;
  place-items: center;
  /* The browser's own pan and pinch would fight the picture's. */
  touch-action: none;
}
.closeup-stage.is-movable { cursor: grab; }
.closeup-stage.is-movable:active { cursor: grabbing; }
#closeup-img {
  max-width: 92vw;
  max-height: 84vh;
  /* Crops are drawn for white paper, and a few carry transparency. */
  background: #f4f5f7;
  border-radius: var(--r-sm);
  transform-origin: center center;
  will-change: transform;
  user-select: none;
  -webkit-user-drag: none;
}
/* The ground is dark in either theme, so the controls on it are lit off the
   picture rather than off the page's palette. */
.closeup-tools {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  gap: 6px;
  padding: 6px;
  /* Solid, because at any zoom past the fit the picture is under it, and a
     white plate on a white figure is a control the reader cannot find. */
  background: #141922;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
}
.closeup-tools button { background: transparent; border-color: rgba(255, 255, 255, 0.3); color: #e9edf3; }
.closeup-close { background: #141922; border-color: rgba(255, 255, 255, 0.3); color: #e9edf3; }
.closeup-tools button:hover:not(:disabled),
.closeup-close:hover { color: #ffffff; border-color: #ffffff; }
.closeup-tools #closeup-reset { width: auto; min-width: 54px; padding: 0 10px; font: 500 var(--t-mini)/1 var(--sans); font-variant-numeric: tabular-nums; color: #b9c2ce; }
.closeup-close { position: absolute; top: 14px; right: 16px; }
body.closeup-open { overflow: hidden; }
@media (max-width: 720px) {
  #closeup-img { max-width: 96vw; max-height: 78vh; }
  .closeup-tools { bottom: 16px; }
}

/* ---------- thumbnails where a figure is named ---------- */
/* The figures index and "Where you can see it" both named a figure and showed
   no picture. Both lead with the crop now. */
.card-shot img { max-width: 100%; max-height: 130px; object-fit: contain; }
.card-fig { display: flex; gap: 14px; align-items: flex-start; }
.card-fig-shot {
  flex: 0 0 132px;
  display: block;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 7px;
}
:root[data-theme="dark"] .card-fig-shot { background: #f4f5f7; border-color: transparent; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card-fig-shot { background: #f4f5f7; border-color: transparent; }
}
.card-fig-shot img { display: block; width: 100%; max-height: 96px; object-fit: contain; }
/* An equation is its own thumbnail, set small enough to sit in the same slot. */
.card-fig-shot.is-eq {
  background: var(--accent-soft);
  border-color: var(--accent-ring);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-size: var(--t-mini);
  padding: 9px 6px;
}
:root[data-theme="dark"] .card-fig-shot.is-eq { background: var(--accent-soft); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card-fig-shot.is-eq { background: var(--accent-soft); }
}
.card-fig-shot.is-eq .katex-display { margin: 0; }
.card-fig-shot.is-eq .katex { font-size: 0.86em; }
.card-fig-text { flex: 1 1 auto; min-width: 0; }
@media (max-width: 560px) {
  .card-fig { display: block; }
  .card-fig-shot { margin-bottom: 10px; }
}

/* A figure named in the reading column, with the crop the column was missing.
   Only the rows pointing elsewhere in the section carry one. */
.beside-figrow { display: flex; gap: 10px; align-items: flex-start; }
.beside-thumb {
  flex: 0 0 54px;
  display: block;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 3px;
}
:root[data-theme="dark"] .beside-thumb { background: #f4f5f7; border-color: transparent; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .beside-thumb { background: #f4f5f7; border-color: transparent; }
}
.beside-thumb img { display: block; width: 100%; max-height: 42px; object-fit: contain; }
.beside-figtext { flex: 1 1 auto; min-width: 0; }

/* Which paper a search hit came from. */
#search-results .from {
  display: block;
  font: var(--t-micro) var(--sans);
  color: var(--ink-faint);
  margin-top: 1px;
}

/* ---------- rights notice ---------- */
/* The reading shell carries the same footer as the shelf, but style.css is the
   only sheet it loads, so the rule lives here too. Scoped to .reading so the
   shelf's own .site-foot in home.css is left alone. Aligned to the article
   column - 42rem plus the same 32px gutter - so it reads as the end of the
   page rather than a band across it. */
.reading .site-foot {
  max-width: 42rem;
  margin: 0 auto;
  padding: 24px 32px 72px;
  border-top: 1px solid transparent;
  background-image: var(--hairline);
  background-repeat: no-repeat;
  background-size: calc(100% - 64px) 1px;
  background-position: 32px top;
  font-size: var(--t-small);
  line-height: 1.65;
  color: var(--ink-faint);
}
.reading .site-foot p { margin: 0 0 10px; }
.reading .site-foot p:last-child { margin-bottom: 0; }
.reading .site-foot .foot-label {
  font: 600 var(--t-mini) var(--sans);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
.reading .site-foot a { color: var(--ink-soft); }
/* The paper as printed is the one page where the notice matters most, so it
   stays. The pane runs the width of the window rather than the article column,
   and the notice follows it - centred on the same 42rem so it stays readable,
   but with the pane's own gutter rather than the article's. */
body.reader-mode .site-foot {
  /* left-aligned, not centred: the paper sits against the pane's left gutter,
     and a notice centred in the window would read as unrelated to it */
  max-width: calc(42rem + 2 * clamp(10px, 2.5vw, 36px));
  margin: 0;
  padding: 22px clamp(10px, 2.5vw, 36px) 64px;
  background-size: calc(100% - 2 * clamp(10px, 2.5vw, 36px)) 1px;
  background-position: clamp(10px, 2.5vw, 36px) top;
}

/* ---------- waiting on a paper this shell has not got ---------- */
/* A link out of this paper fetches it before the page can be drawn. That is
   usually a few hundred milliseconds and the page you are leaving is still on
   screen, so this says something is happening without throwing the reading
   away: the article fades a little and the pointer says wait. Only the first
   visit to a paper waits - after that it is in PAPERS and in the cache. */
body.loading-paper { cursor: progress; }
body.loading-paper #content {
  opacity: 0.55;
  transition: opacity 140ms ease-in 90ms;
}
@media (prefers-reduced-motion: reduce) {
  body.loading-paper #content { transition: none; }
}
