/* ============================================================================
   TOKENS — the coffee system.
   Matte black with a warm roast undertone; crema for ink; brass for emphasis.
   Dark is the primary design. Light is a considered second cut, not an
   inversion — the paper warms rather than bleaching to white.
   ========================================================================= */

:root {
  /* — surface, darkest to lightest — */
  --void:        #0A0807;  /* the matte black. warm, never blue. */
  --bed:         #100C0A;  /* page ground */
  --raise:       #171210;  /* cards, callouts, code */
  --raise-2:     #1F1815;  /* nested surfaces */
  --edge:        #251D19;  /* hairlines */
  --edge-strong: #362B24;

  /* — ink — */
  --crema:       #EDE4D8;  /* body text: warm bone, not white */
  --crema-dim:   #A2907E;  /* secondary, captions */
  --crema-faint: #6E6055;  /* tertiary, numerals, furniture */

  /* — accent: brass, used sparingly and never decoratively — */
  --brass:        #C08A4E;
  --brass-bright: #DDA968;
  --brass-sunk:   #8A6236;
  --brass-wash:   rgba(192, 138, 78, 0.10);

  /* — signal — */
  --oxblood:  #8A4038;  /* gated / restricted */
  --verdigris:#4E7C6B;  /* verified / resolved */

  --selection: rgba(192, 138, 78, 0.24);

  /* — type — */
  --serif: "Source Serif 4", "Source Serif 4 Subset", Charter, "Bitstream Charter",
           "Sitka Text", Cambria, Georgia, serif;
  --mono:  "JetBrains Mono", "JetBrains Mono Subset", "Cascadia Code",
           ui-monospace, SFMono-Regular, Menlo, monospace;
  /* Modular scale, 1.200 (minor third) — restrained. Luxury is not loud. */
  --t--2: 0.694rem;
  --t--1: 0.833rem;
  --t-0:  1rem;
  --t-1:  1.200rem;
  --t-2:  1.440rem;
  --t-3:  1.728rem;
  --t-4:  2.074rem;
  --t-5:  2.488rem;

  /* Vertical rhythm. Every vertical metric is a multiple of --lead. */
  --lead: 1.62;
  --rhythm: calc(var(--t-0) * var(--lead));

  /* Measure: 66 characters. The single most consequential number here. */
  --measure: 66ch;
  --margin-col: 16rem;   /* sidenote column */
  --gutter: 2.5rem;

  --rule: 1px;
  --radius: 2px;         /* almost none. matte, machined, not soft. */

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Light: warm paper. Roles swap consistently; nothing becomes pure #FFF. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --void:        #EDE6DA;
    --bed:         #F5F0E8;
    --raise:       #FBF8F2;
    --raise-2:     #FFFDF9;
    --edge:        #DED3C2;
    --edge-strong: #C4B49E;

    --crema:       #1A1310;
    --crema-dim:   #574A40;
    --crema-faint: #857463;

    --brass:        #8A5A20;
    --brass-bright: #6E4718;
    --brass-sunk:   #B08A55;
    --brass-wash:   rgba(138, 90, 32, 0.08);

    --oxblood:   #8A3028;
    --verdigris: #2F5A4A;

    --selection: rgba(138, 90, 32, 0.18);
  }
}

:root[data-theme="light"] {
  --void:        #EDE6DA;
  --bed:         #F5F0E8;
  --raise:       #FBF8F2;
  --raise-2:     #FFFDF9;
  --edge:        #DED3C2;
  --edge-strong: #C4B49E;

  --crema:       #1A1310;
  --crema-dim:   #574A40;
  --crema-faint: #857463;

  --brass:        #8A5A20;
  --brass-bright: #6E4718;
  --brass-sunk:   #B08A55;
  --brass-wash:   rgba(138, 90, 32, 0.08);

  --oxblood:   #8A3028;
  --verdigris: #2F5A4A;

  --selection: rgba(138, 90, 32, 0.18);
}

:root[data-theme="dark"] {
  --void: #0A0807; --bed: #100C0A; --raise: #171210; --raise-2: #1F1815;
  --edge: #251D19; --edge-strong: #362B24;
  --crema: #EDE4D8; --crema-dim: #A2907E; --crema-faint: #6E6055;
  --brass: #C08A4E; --brass-bright: #DDA968; --brass-sunk: #8A6236;
  --brass-wash: rgba(192, 138, 78, 0.10);
  --oxblood: #8A4038; --verdigris: #4E7C6B;
  --selection: rgba(192, 138, 78, 0.24);
}

/* ============================================================================
   THE TYPOGRAPHY ENGINE
   Everything here exists to make justified text on a screen approach what
   Typst or TeX gets on a page. CSS provides the floor; Justif (30-justif.js)
   provides the Knuth–Plass ceiling as progressive enhancement.
   ========================================================================= */

/* — faces. Variable, so one file per style covers the whole weight range. — */

@font-face {
  font-family: "Source Serif 4";
  src: url("/assets/fonts/SourceSerif4-Roman.subset.80818c5642.woff2") format("woff2-variations");
  font-weight: 200 900;
  font-stretch: normal;
  font-style: normal;
  font-display: swap;
  /* opsz is exposed to the browser, which drives it from the computed size. */
}

@font-face {
  font-family: "Source Serif 4";
  src: url("/assets/fonts/SourceSerif4-Italic.subset.5a0a9a49ec.woff2") format("woff2-variations");
  font-weight: 200 900;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/assets/fonts/JetBrainsMono.subset.91ee592466.woff2") format("woff2-variations");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/assets/fonts/JetBrainsMono-Italic.subset.9c29d5b0ce.woff2") format("woff2-variations");
  font-weight: 100 800;
  font-style: italic;
  font-display: swap;
}

/* — the base — */

html {
  font-size: clamp(16.5px, 0.94rem + 0.28vw, 20px);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  background: var(--bed);
  color: var(--crema);
  font-family: var(--serif);
  font-size: var(--t-0);
  line-height: var(--lead);
  font-weight: 400;

  /* Let the browser drive the opsz axis from the computed size. This is the
     whole point of a variable text face: 9pt captions get a sturdier, more
     open cut than 36pt display, automatically. */
  font-optical-sizing: auto;

  /* Old-style figures in running prose — numerals should sit in the text,
     not stand above it shouting. Tabular lining figures are switched back on
     locally wherever numbers need to align (tables, metrics). */
  font-variant-numeric: oldstyle-nums proportional-nums;
  font-variant-ligatures: common-ligatures contextual;

  /* Kerning on, always. */
  font-kerning: normal;

  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection { background: var(--selection); color: var(--crema); }

/* — prose — */

.prose {
  max-width: var(--measure);
  /* Hanging punctuation is real optical margin alignment where supported
     (Safari). Justif does protrusion for everyone else. */
  hanging-punctuation: first allow-end last;
}

.prose p {
  margin: 0 0 var(--rhythm);
  text-align: justify;
  text-justify: inter-word;
  hyphens: auto;
  -webkit-hyphens: auto;
  hyphenate-limit-chars: 6 3 3;   /* don't hyphenate short words or leave stubs */
  hyphenate-limit-lines: 2;       /* at most 2 consecutive hyphenated lines */
  /* Browser's own paragraph-aware breaker. Justif supersedes it when it runs,
     but this is a genuinely good fallback on its own. */
  text-wrap: pretty;
  orphans: 2;
  widows: 2;
}

/* The opening paragraph of a main page: no indent, and small caps for the
   first few words — a considered entrance rather than a drop cap, which at
   screen sizes usually just looks like a mistake. */
.prose > p.lede {
  text-indent: 0;
  font-size: var(--t-1);
  line-height: 1.5;
  color: var(--crema);
}

.prose > p.lede::first-line {
  font-variant-caps: small-caps;
  font-variant-numeric: oldstyle-nums;
  letter-spacing: 0.02em;
}

/* Continental paragraph indentation: indent every paragraph *except* the one
   that starts a section. Indentation and vertical space are redundant, so
   pages set in `.prose--indented` drop the space and use the indent. */
.prose--indented p { margin-bottom: 0; text-indent: 1.4em; }
.prose--indented p.lede,
.prose--indented :is(h1,h2,h3,h4,figure,blockquote,pre,.callout) + p { text-indent: 0; }
.prose--indented :is(h1,h2,h3,h4,figure,blockquote,pre,.callout) + p::first-letter { }

/* — headings. Tight, brass-free, weight and tracking do the work. — */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--serif);
  font-optical-sizing: auto;
  line-height: 1.12;
  text-wrap: balance;      /* headings get balanced rags, not pretty ones */
  hyphens: none;
  margin: 0;
  color: var(--crema);
}

h1 {
  font-size: var(--t-5);
  font-weight: 600;
  letter-spacing: -0.021em;   /* optical tightening at display size */
  margin-block: 0 calc(var(--rhythm) * 0.75);
}

h2 {
  font-size: var(--t-3);
  font-weight: 600;
  letter-spacing: -0.012em;
  margin-block: calc(var(--rhythm) * 2) calc(var(--rhythm) * 0.5);
}

h3 {
  font-size: var(--t-1);
  font-weight: 600;
  letter-spacing: -0.004em;
  margin-block: calc(var(--rhythm) * 1.5) calc(var(--rhythm) * 0.25);
}

/* h4 as a run-in sidehead, small caps — the LaTeX \paragraph move. */
h4 {
  font-size: var(--t-0);
  font-weight: 600;
  font-variant-caps: small-caps;
  letter-spacing: 0.045em;
  color: var(--crema-dim);
  margin-block: var(--rhythm) 0;
}

/* — inline — */

em { font-style: italic; }
strong { font-weight: 650; }        /* variable axis: not a jump to 700 */

/* Nested emphasis flips, as it should. */
em em, i i { font-style: normal; }

/* True small caps, never faked by scaling. */
.sc, .smallcaps {
  font-variant-caps: small-caps;
  font-variant-numeric: oldstyle-nums;
  letter-spacing: 0.045em;
}

/* Abbreviations and acronyms get small caps automatically — an all-caps run
   in justified serif text is a hole in the page otherwise. */
abbr, .caps {
  font-variant-caps: all-small-caps;
  letter-spacing: 0.05em;
  text-decoration: none;
}

/* Numerals that must align: tables, metrics, line numbers. */
.tnum, table td.num, .metric-value {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "zero" 1;   /* slashed zero where the face has it */
}

/* Proper fractions via the frac feature rather than sup/sub hacks. */
.frac { font-variant-numeric: diagonal-fractions; }

a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--brass-sunk);
  text-decoration-thickness: 0.055em;
  text-underline-offset: 0.16em;
  /* Skip descenders — the single cheapest way to make links look considered. */
  text-decoration-skip-ink: auto;
  transition: text-decoration-color 120ms var(--ease), color 120ms var(--ease);
}

a:hover {
  color: var(--brass-bright);
  text-decoration-color: var(--brass);
}

a:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
  border-radius: var(--radius);
}

blockquote {
  margin: var(--rhythm) 0;
  padding-left: var(--gutter);
  border-left: var(--rule) solid var(--edge-strong);
  color: var(--crema-dim);
  font-style: italic;
}

blockquote p { text-align: justify; }

hr {
  border: 0;
  height: var(--rule);
  background: var(--edge);
  margin: calc(var(--rhythm) * 2) 0;
}

/* A typographic break rather than a rule: three brass asterisks. */
hr.asterism {
  background: none;
  height: auto;
  text-align: center;
  overflow: visible;
}
hr.asterism::after {
  content: "❊";
  color: var(--brass-sunk);
  font-size: var(--t-1);
}

/* — reduced motion — */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   LAYOUT — measure plus a margin column.
   Sidenotes float into the margin from inside the paragraph they belong to,
   which is the only way to keep them vertically anchored to their reference.
   ========================================================================= */

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

body { margin: 0; }

.page {
  max-width: calc(var(--measure) + var(--gutter) + var(--margin-col));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block: calc(var(--rhythm) * 2);
}

.prose,
.masthead,
.article__header,
.page > p,
.page > h1, .page > h2, .page > h3, .page > h4,
.page > ul, .page > ol, .page > pre, .page > blockquote {
  max-width: var(--measure);
}

/* Deliberate escapes from the measure. */
.wide { max-width: calc(var(--measure) + var(--gutter) + var(--margin-col)); }
.full { max-width: none; }

/* — masthead — */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gutter);
  padding-bottom: var(--rhythm);
  margin-bottom: calc(var(--rhythm) * 2);
  border-bottom: var(--rule) solid var(--edge);
  max-width: none;
}

.masthead__mark {
  font-weight: 600;
  font-size: var(--t-0);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.14em;
  text-decoration: none;
  color: var(--crema);
  white-space: nowrap;
}

.masthead__mark::before {
  content: "";
  display: inline-block;
  width: 0.44em; height: 0.44em;
  margin-right: 0.62em;
  background: var(--brass);
  transform: rotate(45deg) translateY(-0.06em);
}

.masthead nav {
  display: flex;
  gap: 1.5rem;
  font-size: var(--t--1);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.09em;
  color: var(--crema-dim);
}

.masthead nav a { text-decoration: none; }
.masthead nav a:hover { color: var(--brass-bright); }

/* — article furniture — */

.article__header { margin-bottom: calc(var(--rhythm) * 2); }

.article__subtitle {
  font-size: var(--t-1);
  font-style: italic;
  color: var(--crema-dim);
  line-height: 1.35;
  margin: calc(var(--rhythm) * -0.35) 0 var(--rhythm);
  text-wrap: balance;
}

.article__meta {
  font-size: var(--t--1);
  color: var(--crema-faint);
  font-variant-caps: all-small-caps;
  font-variant-numeric: oldstyle-nums;
  letter-spacing: 0.08em;
  display: flex;
  gap: 1.1rem;
  flex-wrap: wrap;
  align-items: baseline;
}

.article__meta .sep { color: var(--edge-strong); }

/* — SIDENOTES ————————————————————————————————————————————————————————— */

.sidenote {
  float: right;
  clear: right;
  width: var(--margin-col);
  /* Pull it out of the measure and into the margin column. */
  margin-right: calc(-1 * (var(--margin-col) + var(--gutter)));
  margin-bottom: calc(var(--rhythm) * 0.6);
  margin-left: var(--gutter);

  font-size: var(--t--1);
  line-height: 1.5;
  color: var(--crema-dim);

  /* Never justify a 16rem column — it is all river. */
  text-align: left;
  hyphens: auto;
  text-indent: 0;
  position: relative;
}

.sidenote__no {
  font-variant-numeric: lining-nums;
  color: var(--brass);
  margin-right: 0.4em;
  font-size: 0.8em;
  vertical-align: 0.35em;
}

.sidenote p { margin: 0 0 0.5em; text-align: left; text-indent: 0; }
.sidenote p:last-child { margin-bottom: 0; }

/* In-text marker. */
.noteref {
  font-variant-numeric: lining-nums;
  font-size: 0.72em;
  vertical-align: 0.42em;
  color: var(--brass);
  text-decoration: none;
  cursor: pointer;
  padding-inline: 0.08em;
}
.noteref:hover { color: var(--brass-bright); }

.sidenote-toggle { display: none; }

/* — the coffee note — */

.coffee-note {
  margin: calc(var(--rhythm) * 1.25) 0;
  padding: calc(var(--rhythm) * 0.7) calc(var(--gutter) * 0.9);
  padding-right: calc(var(--gutter) * 1.8);
  background: var(--raise);
  border-left: 2px solid var(--brass-sunk);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--crema-dim);
  font-size: var(--t--1);
  line-height: 1.55;
  position: relative;
  text-indent: 0;
}

/* The ring — a cup set down on the page, once, deliberately. */
.coffee-note::before {
  content: "";
  position: absolute;
  top: calc(var(--rhythm) * 0.7);
  right: calc(var(--gutter) * 0.7);
  width: 1.15rem; height: 1.15rem;
  border: 1.5px solid var(--brass-sunk);
  border-radius: 50%;
  opacity: 0.45;
}

.coffee-note__label {
  display: block;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.11em;
  font-size: 0.85em;
  color: var(--brass);
  margin-bottom: 0.25em;
}

.coffee-note p { margin-bottom: 0.5em; text-align: left; text-indent: 0; }
.coffee-note p:last-child { margin-bottom: 0; }

/* — NARROW: fold the margin column away ——————————————————————————————— */

@media (max-width: 62rem) {
  :root { --measure: 100%; --gutter: 1.35rem; }

  .page { max-width: 40rem; padding-inline: var(--gutter); }

  .sidenote {
    float: none;
    width: auto;
    margin: var(--rhythm) 0;
    padding: 0.8rem 1rem;
    background: var(--raise);
    border-left: 2px solid var(--brass-sunk);
    border-radius: 0 var(--radius) var(--radius) 0;

    /* Collapsed until its marker is tapped. */
    display: none;
  }

  .sidenote-toggle:checked + .sidenote { display: block; }

  /* A ~40-character measure cannot be justified without rivers, whatever the
     line-breaker. Below this width the text rags right. */
  .prose p, blockquote p { text-align: left; }
  .prose--indented p { text-indent: 0; margin-bottom: var(--rhythm); }
}

@media (max-width: 34rem) {
  .masthead { flex-direction: column; gap: 0.6rem; align-items: flex-start; }
  .masthead nav { gap: 1.1rem; flex-wrap: wrap; }
}

/* — PRINT ————————————————————————————————————————————————————————————— */

@media print {
  :root {
    --bed: #fff; --raise: #fff; --crema: #000;
    --crema-dim: #333; --brass: #6b4a1c; --edge: #ccc;
  }
  .masthead nav, .noteref, .equation__anchor { display: none; }
  .page { max-width: none; }
  .sidenote { display: block; float: right; clear: right; width: 38%; }
  a { text-decoration: none; color: #000; }
  .prose p { text-align: justify; }
  pre, figure, .equation, blockquote { break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; }
}

/* — THE SETTING STATE ——————————————————————————————————————————————————
   Justif re-breaks every paragraph before the text is fit to show, so the
   prose is held back rather than painted once badly and again well.

   The grid goes up only when the faces are still arriving, which setting.js
   determines by asking. There is no threshold and no minimum display time:
   the fade is what keeps a short wait from reading as a flash, since a grid
   that is only up for a moment never reaches full strength in the first
   place. Proportional, rather than timed. */

.prose-wrap { position: relative; }

.prose { transition: opacity 240ms var(--ease); }

:root[data-setting] .prose { opacity: 0; }

.setting-grid {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms var(--ease);
  background: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent calc(var(--rhythm) - 1px),
    var(--edge) calc(var(--rhythm) - 1px),
    var(--edge) var(--rhythm)
  );
  /* Fade the grid out at the foot so it reads as a hint, not a cage. */
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
}

:root[data-setting="slow"] .setting-grid { opacity: 1; }

.setting-grid__label {
  position: absolute;
  top: calc(var(--rhythm) * -1.4);
  right: 0;
  font-size: var(--t--2);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.16em;
  color: var(--crema-faint);
}

.setting-grid__label::after {
  content: "";
  display: inline-block;
  width: 0.36em;
  height: 0.36em;
  margin-left: 0.6em;
  background: var(--brass);
  transform: rotate(45deg) translateY(-0.08em);
  animation: setting-pulse 1.4s var(--ease) infinite;
}

@keyframes setting-pulse { 50% { opacity: 0.25; } }

@media (prefers-reduced-motion: reduce) {
  .setting-grid { transition: none; }
  .setting-grid__label::after { animation: none; }
}

/* No script, no held-back prose. */
.no-js .setting-grid { display: none; }

/* ============================================================================
   CONTENT — maths, code, figures, references, tables.
   ========================================================================= */

/* — MATHEMATICS ————————————————————————————————————————————————————————
   Every equation on this site, display or inline, is a picture drawn by
   Typst's own typesetter, with the MathML kept beside it as the hidden
   machine-readable layer. So there are no rules here for painting <math>:
   nothing on the page ever paints one, and the maths webfont is not loaded.

   Should MathML ever be made visible again, note that it must not be given a
   `display`. MathML Core's UA stylesheet uses the two-value forms `inline
   math` and `block math`, and the second keyword is what selects the maths
   layout algorithm. Overriding it with a plain `block` or `inline` silently
   drops that, and every <mrow>, <msup> and <mfrac> falls back to generic CSS
   box layout, which stacks the expression vertically. Chromium does exactly
   this; Firefox's engine is more forgiving, which is how the bug ships unseen.
   ————————————————————————————————————————————————————————————————————— */

/* — THE THREE LAYERS OF A DISPLAY EQUATION ————————————————————————————
   Stacked in one box: the picture, the selectable description, the structure.
   See lib/theme.typ for why each one is there. */

/* Also the scroll container: a long derivation scrolls inside its own box and
   the page never scrolls sideways. */
.equation__body {
  position: relative;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  padding-block: 0.15rem;
  scrollbar-width: thin;
}

/* The picture. currentColor is substituted for Typst's baked-in black by the
   build, so the maths inverts with the theme like everything else. */
.eq-svg { color: var(--crema); }
/* max-width belongs here, not on the element: a cap on the inline maths would
   shrink its width without its height and skew the glyphs. A wide display
   equation is scrolled by .equation__body instead of pushing the page. */
.eq-svg svg {
  display: block;
  margin-inline: auto;
  max-width: 100%;
}

/* The description, rendered but transparent, lying over the picture. This is
   what a sighted reader selects; copying an equation yields the sentence the
   author wrote rather than a string of flattened Unicode. */
.eq-sel {
  position: absolute;
  inset: 0;
  margin: 0;
  /* Centred, so a drag through the middle of a tall equation crosses the text
     line. Pinned to the top it is unselectable for anything taller than one
     line, which is most display maths. */
  display: flex;
  align-items: center;
  color: transparent;
  cursor: text;
  overflow: hidden;
  white-space: nowrap;
  font-size: var(--t--1);
  line-height: 1.2;
  user-select: text;
  -webkit-user-select: text;
}

.eq-sel::selection { background: var(--selection); }

/* The structure. Visually hidden but still rendered, so it stays in the
   accessibility tree: a screen reader can walk the expression and a braille
   display can set it as maths. `display: none` would remove it from both.
   The serif stack keeps it from pulling in the maths webfont it never shows. */
.eq-a11y {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  font-family: serif;
}

/* — INLINE MATHS ——————————————————————————————————————————————————————
   The same three layers as a display equation: the picture, the transcript a
   reader selects, and the structure assistive technology walks.

   The SVG needs no vertical-align. Typst's frame bottom is the text baseline
   and an inline <svg> aligns its bottom edge to the baseline, so they already
   agree; anything that hangs lower spills, which is why the frame is drawn
   with overflow visible. Nothing here may give the SVG a `display` or a
   `height`: either one would replace that agreement with a guess. */
.imath {
  white-space: nowrap;
}

.imath__vis {
  color: var(--crema);
}

/* The transcript. In the flow, and therefore in the selection, but occupying
   no space and painting nothing: this is what a reader gets when they drag
   through a sentence and copy it. */
.imath__txt {
  display: inline-block;
  width: 0;
  height: 0;
  overflow: hidden;
  color: transparent;
  white-space: nowrap;
  user-select: text;
  -webkit-user-select: text;
}

/* The structure. Taken out of the flow, which drops it from the selection so
   it is not copied on top of the transcript, while leaving it rendered and so
   still in the accessibility tree — a screen reader can walk the expression
   and a braille display can set it as maths. `display: none` would remove it
   from both. Never the maths face: this layer is never painted, and naming it
   here would pull a webfont down for glyphs nobody sees. */
.imath__src {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  font-family: serif;
}


/* The numbered-equation frame. The number is emitted by the Typst template
   (see lib/theme.typ) so that it always agrees with what @refs resolve to. */
.equation {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: var(--gutter);
  margin-block: var(--rhythm);
  scroll-margin-top: 3rem;
}

.equation__body > math { margin-block: 0; }

.equation__no {
  font-variant-numeric: lining-nums;
  font-size: var(--t--1);
  color: var(--crema-faint);
  user-select: none;
  white-space: nowrap;
}

/* The permalink affordance on an equation: appears on hover, brass, quiet. */
.equation__anchor {
  opacity: 0;
  color: var(--brass);
  text-decoration: none;
  margin-left: 0.4em;
  transition: opacity 120ms var(--ease);
}
.equation:hover .equation__anchor,
.equation__anchor:focus-visible { opacity: 1; }

/* Deep-link highlight, for both #anchors and ::target-text fragments. */
:target, .is-flash { animation: settle 900ms var(--ease); }
::target-text { background: var(--selection); color: var(--crema); }

@keyframes settle {
  from { background: var(--brass-wash); }
  to   { background: transparent; }
}

/* — CODE ——————————————————————————————————————————————————————————————— */

code, kbd, samp, pre {
  font-family: var(--mono);
  font-variant-ligatures: contextual;   /* JetBrains Mono's arrows and !=  */
  font-feature-settings: "zero" 1;
  font-optical-sizing: auto;
}

/* Inline code: sized down, because mono x-heights run large next to serif. */
:not(pre) > code {
  font-size: 0.875em;
  background: var(--raise);
  border: var(--rule) solid var(--edge);
  border-radius: var(--radius);
  padding: 0.08em 0.34em;
  color: var(--crema);
  /* Never let a long identifier blow out the measure. */
  overflow-wrap: break-word;
}

pre {
  margin: var(--rhythm) 0;
  padding: calc(var(--rhythm) * 0.75) 1.15rem;
  background: var(--raise);
  border: var(--rule) solid var(--edge);
  border-radius: var(--radius);
  overflow-x: auto;
  font-size: var(--t--1);
  line-height: 1.55;
  tab-size: 2;
  scrollbar-width: thin;
  /* code is never justified, never hyphenated */
  text-align: left;
  hyphens: none;
}

pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: inherit;
}

/* Syntax colours: drawn from the coffee palette, not a rainbow. Hue does
   semantic work only where it must; the rest is weight and value. */
.tok-kw      { color: var(--brass);        font-weight: 600; }
.tok-fn      { color: var(--brass-bright); }
.tok-str     { color: var(--verdigris);    }
.tok-num     { color: var(--verdigris);    font-variant-numeric: lining-nums; }
.tok-com     { color: var(--crema-faint);  font-style: italic; }
.tok-type    { color: var(--crema);        font-weight: 600; }
.tok-punct   { color: var(--crema-faint);  }

/* — FIGURES ———————————————————————————————————————————————————————————— */

figure {
  margin: calc(var(--rhythm) * 1.5) 0;
  scroll-margin-top: 3rem;
}

figure svg,
figure img {
  display: block;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
}

/* CeTZ figures are emitted as inline SVG with currentColor strokes by the
   build step, so they invert correctly between themes. */
figure svg { color: var(--crema); }

figcaption {
  margin-top: calc(var(--rhythm) * 0.5);
  font-size: var(--t--1);
  line-height: 1.5;
  color: var(--crema-dim);
  text-align: left;
  hyphens: auto;
}

/* Typst emits "Figure 1: caption" — style the label run distinctly. */
figcaption::first-line { }
.fig-label {
  font-variant-caps: all-small-caps;
  letter-spacing: 0.08em;
  color: var(--brass);
  font-variant-numeric: lining-nums;
}

/* A figure allowed to use the sidenote column too. */
figure.wide { max-width: none; }

/* — REFERENCES & HOVER PREVIEWS ——————————————————————————————————————— */

/* Internal cross-references read as part of the sentence, not as links. */
a.ref {
  text-decoration: none;
  color: var(--brass);
  font-variant-numeric: lining-nums;
  border-bottom: 1px dotted var(--brass-sunk);
}
a.ref:hover { color: var(--brass-bright); border-bottom-style: solid; }

/* The preview card, positioned by 40-refs.js. */
.refcard {
  /* Fixed, not absolute: an absolutely positioned card placed low on the page
     extends the document, which on a phone scrolls the reader into empty
     space below the content. */
  position: fixed;
  overflow-y: auto;
  z-index: 40;
  max-width: min(30rem, 88vw);
  padding: 0.85rem 1.1rem;
  background: var(--raise-2);
  border: var(--rule) solid var(--edge-strong);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px -12px rgba(0,0,0,0.75), 0 0 0 1px rgba(0,0,0,0.2);
  font-size: var(--t--1);
  line-height: 1.5;
  color: var(--crema);
  opacity: 0;
  transform: translateY(3px);
  transition: opacity 130ms var(--ease), transform 130ms var(--ease);
  pointer-events: none;
}
.refcard[data-open="true"] { opacity: 1; transform: none; }
.refcard__kind {
  display: block;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.1em;
  font-size: 0.82em;
  color: var(--brass);
  margin-bottom: 0.25em;
}
.refcard math { font-size: 1em; }

/* Citations. */
a.cite {
  text-decoration: none;
  color: var(--brass);
  font-variant-numeric: lining-nums;
}
a.cite::before { content: "["; color: var(--crema-faint); }
a.cite::after  { content: "]"; color: var(--crema-faint); }

.bibliography {
  font-size: var(--t--1);
  line-height: 1.5;
  color: var(--crema-dim);
}
.bibliography li { margin-bottom: 0.6em; scroll-margin-top: 3rem; }

/* — FOOTNOTES (Typst's doc-endnotes, when not promoted to sidenotes) —— */

[role="doc-endnotes"] {
  margin-top: calc(var(--rhythm) * 2.5);
  padding-top: var(--rhythm);
  border-top: var(--rule) solid var(--edge);
  font-size: var(--t--1);
  color: var(--crema-dim);
}
[role="doc-endnotes"] ol { padding-left: 0; }
[role="doc-endnotes"] li { margin-bottom: 0.5em; }
[role="doc-noteref"] a { color: var(--brass); text-decoration: none; }

/* — TABLES ————————————————————————————————————————————————————————————
   Set the way a statistics table in a journal is set: rules only where they
   carry meaning, never a full grid. A vertical rule is almost always the
   typesetter admitting the columns are too close together. */

.table-wrap,
figure:has(table) {
  overflow-x: auto;
  scrollbar-width: thin;
  margin: calc(var(--rhythm) * 1.5) 0;
}

table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--t--1);
  line-height: 1.45;
  /* Digits in a column must align, always. */
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "zero" 1;
}

/* Booktabs: a heavier rule above and below the table, a lighter one under
   the header, and nothing else. */
thead { border-top: 1.5px solid var(--edge-strong); }
tbody { border-bottom: 1.5px solid var(--edge-strong); }

th {
  text-align: left;
  font-weight: 600;
  font-variant-caps: all-small-caps;
  font-variant-numeric: normal;
  letter-spacing: 0.07em;
  color: var(--crema-dim);
  border-bottom: var(--rule) solid var(--edge-strong);
  padding: 0.55em 1.1em 0.5em 0;
  white-space: nowrap;
}

td {
  padding: 0.42em 1.1em 0.42em 0;
  border-bottom: var(--rule) solid var(--edge);
  vertical-align: baseline;
}

tbody tr:last-child td { border-bottom: 0; }

/* Last column carries no trailing padding, so the table optically aligns to
   the measure rather than sitting short of it. */
th:last-child, td:last-child { padding-right: 0; }

/* Numeric columns right-align so the decimal points stack. Mark them with
   `align: right` in the Typst source and this follows automatically. */
th[align="right"], td[align="right"] { text-align: right; }

/* A table inside a figure loses the figure's own top margin: the caption
   already provides the separation. */
figure > table { margin: 0; }

/* — QUOTATION ————————————————————————————————————————————————————————
   Two registers. A blockquote is evidence: someone else's words, set apart
   and attributed. A pull quote is emphasis: the page's own words, enlarged.
   Conflating them is how a design ends up quoting itself for decoration. */

blockquote {
  margin: calc(var(--rhythm) * 1.25) 0;
  padding-left: var(--gutter);
  border-left: var(--rule) solid var(--edge-strong);
  color: var(--crema-dim);
  font-style: italic;
}

blockquote p { text-align: justify; }
blockquote p:last-child { margin-bottom: 0; }

/* Attribution sits below the quotation, ranged right, in the small-caps
   register the rest of the furniture uses. */
.attribution {
  display: block;
  margin-top: 0.5em;
  text-align: right;
  font-style: normal;
  font-size: var(--t--1);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.07em;
  color: var(--crema-faint);
}
.attribution::before { content: "— "; }
.attribution cite { font-style: italic; font-variant-caps: normal; }

/* The pull quote carries no quotation marks, so it gets no hanging indent
   either - a negative text-indent with nothing to hang just pushes the first
   line out past the measure. It is indented to the same edge as a blockquote
   and set one step up, which is enough of a change of voice without turning
   into a headline. */
.pull-quote {
  margin: calc(var(--rhythm) * 1.6) 0;
  padding-left: var(--gutter);
  font-size: var(--t-1);
  line-height: 1.36;
  font-weight: 380;
  letter-spacing: -0.004em;
  color: var(--crema);
  text-align: left;
  text-wrap: balance;
  hyphens: none;
  font-style: normal;
  border: 0;
}

/* — CITATIONS & BIBLIOGRAPHY ——————————————————————————————————————————— */

/* Typst emits author-date citations as doc-biblioref links. They should read
   as part of the sentence, not interrupt it. */
a[role="doc-biblioref"] {
  color: var(--brass);
  text-decoration: none;
  border-bottom: 1px dotted var(--brass-sunk);
  font-variant-numeric: oldstyle-nums;
}
a[role="doc-biblioref"]:hover {
  color: var(--brass-bright);
  border-bottom-style: solid;
}

[role="doc-bibliography"] {
  margin-top: calc(var(--rhythm) * 2.5);
  padding-top: var(--rhythm);
  border-top: var(--rule) solid var(--edge);
  font-size: var(--t--1);
  line-height: 1.5;
  color: var(--crema-dim);
}

[role="doc-bibliography"] h2 {
  font-size: var(--t-0);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.11em;
  font-weight: 600;
  color: var(--crema-dim);
  margin-block: 0 var(--rhythm);
}

[role="doc-bibliography"] ul { padding-left: 0; margin: 0; }

/* Hanging indent: the author's name is what you scan for, so it is the only
   thing on the left edge. */
[role="doc-bibliography"] li {
  margin-bottom: 0.7em;
  padding-left: 1.6em;
  text-indent: -1.6em;
  scroll-margin-top: 3rem;
}

[role="doc-bibliography"] li em { color: var(--crema); }

/* — LISTS —————————————————————————————————————————————————————————————— */

ul, ol { padding-left: 1.4em; margin: 0 0 var(--rhythm); }
li { margin-bottom: 0.3em; }
li::marker { color: var(--brass-sunk); }
ol { font-variant-numeric: oldstyle-nums; }

/* — GATED CONTENT MARKER ——————————————————————————————————————————————— */

.gated {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.09em;
  font-size: var(--t--2);
  color: var(--oxblood);
  border: var(--rule) solid currentColor;
  border-radius: var(--radius);
  padding: 0.1em 0.5em;
}

/* Macros get their own value so `println!` reads as invocation, not function. */
.tok-macro { color: var(--brass-bright); font-weight: 500; }

/* — CONTROLS ——————————————————————————————————————————————————————————— */

.theme-toggle {
  font: inherit;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.09em;
  background: none;
  border: 0;
  padding: 0;
  color: var(--crema-faint);
  cursor: pointer;
  min-width: 3.2em;         /* stop the nav reflowing as the label changes */
  text-align: left;
}
.theme-toggle:hover { color: var(--brass-bright); }
.theme-toggle:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }

.quote-link {
  position: fixed;
  z-index: 50;
  font: inherit;
  font-size: var(--t--2);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.08em;
  background: var(--raise-2);
  color: var(--brass);
  border: var(--rule) solid var(--edge-strong);
  border-radius: var(--radius);
  padding: 0.3em 0.7em;
  cursor: pointer;
  box-shadow: 0 8px 22px -10px rgba(0,0,0,0.8);
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms var(--ease);
}
.quote-link[data-open="true"] { opacity: 1; pointer-events: auto; }
.quote-link:hover { color: var(--brass-bright); border-color: var(--brass-sunk); }

/* — INDEX ——————————————————————————————————————————————————————————————— */

.index-entry {
  padding-block: calc(var(--rhythm) * 0.9);
  border-bottom: var(--rule) solid var(--edge);
}
.index-entry:last-of-type { border-bottom: 0; }

.index-entry__title {
  display: block;
  font-size: var(--t-2);
  font-weight: 600;
  letter-spacing: -0.011em;
  line-height: 1.15;
  text-decoration: none;
  text-wrap: balance;
}
.index-entry__title:hover { color: var(--brass-bright); }

.index-entry__sub {
  margin: 0.3em 0 0.55em;
  color: var(--crema-dim);
  font-size: var(--t-0);
  line-height: 1.4;
  text-wrap: pretty;
}

.index-entry .article__meta { margin: 0; }

/* — JUSTIF ————————————————————————————————————————————————————————————— */
/* Justif reads these at layout time. Tuned rather than left at defaults:
   this face has no `wdth` axis, so width adjustment is unavailable and the
   work has to be done by spacing, tracking and protrusion. */

.prose {
  --justif-hyphenate: auto;
  --justif-hang-punctuation: auto;   /* optical margin alignment */
  --justif-tracking-limit: 0.006em;  /* barely-there, never visible as tracking */
  --justif-max-adjustment-ratio: 1.6;
}

/* The section permalink: present, but only visible when looked for. */
.heading-anchor {
  margin-left: 0.4em;
  color: var(--brass-sunk);
  text-decoration: none;
  font-weight: 400;
  opacity: 0;
  transition: opacity 120ms var(--ease);
}
:is(h2, h3, h4):hover > .heading-anchor,
.heading-anchor:focus-visible { opacity: 1; }

/* Keep the anchor out of copied text and out of the heading's own balance. */
@media print { .heading-anchor { display: none; } }

/* — SPECIMEN ————————————————————————————————————————————————————————————
   Only used by the specimen page, which exists so the type scale can be
   judged at the sizes it is actually set in. */

.specimen-scale {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin: var(--rhythm) 0;
  padding: calc(var(--rhythm) * 0.8) 0;
  border-block: var(--rule) solid var(--edge);
}

.specimen-scale__row {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  align-items: baseline;
  gap: var(--gutter);
}

.specimen-scale__label {
  font-family: var(--mono);
  font-size: var(--t--2);
  color: var(--crema-faint);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0.02em;
}

.specimen-scale__x { line-height: 1.1; color: var(--crema); }
.specimen-scale__x.s5  { font-size: var(--t-5); font-weight: 600; letter-spacing: -0.021em; }
.specimen-scale__x.s3  { font-size: var(--t-3); font-weight: 600; letter-spacing: -0.012em; }
.specimen-scale__x.s1  { font-size: var(--t-1); font-weight: 600; }
.specimen-scale__x.s0  { font-size: var(--t-0); }
.specimen-scale__x.sm1 { font-size: var(--t--1); color: var(--crema-dim); }

/* Preview cards for the kinds that are not equations need a little room to
   breathe: a table preview is wide, a cited work is a paragraph. */
.refcard table { font-size: 0.92em; }
.refcard figcaption { margin-top: 0.4em; font-size: 0.92em; }
.refcard li { margin: 0; padding-left: 1.4em; text-indent: -1.4em; list-style: none; }
.refcard ul { padding: 0; margin: 0; }

