/* =========================================================
   Docs — site.css
   Design tokens originally extracted from "Jaunty Docs App.dc.html"

   Three layers of colour scheme, in this order and for this reason:
     1. html.jt      — dark, the default, so a page with no signal at all is dark;
     2. @media (prefers-color-scheme: light) — the OS preference, honoured
        automatically, which is what a reader who never touches the toggle gets;
     3. html.jt[data-theme=...] — the explicit choice, which must beat both.

   Every token block is scoped to `html`, and that is load-bearing rather than
   tidy. Both <html> and <body> carry class="jt", so a bare `.jt { --bg: ... }`
   declares the tokens TWICE, once on each. The toggle writes data-theme on
   <html> only — and a property declared on an element beats one inherited from
   an ancestor, whatever the selectors' specificity — so <body>'s own copy of
   the dark values won over the explicit light override for everything on the
   page. Layer 3 was a no-op: toggling to light on a dark machine changed the
   button label and nothing else. Scoped to html, <body> inherits instead of
   re-declaring, and the three layers behave as written.
   The light values below were already written before any of this existed and
   were unreachable: nothing ever set data-theme and there was no media query.
========================================================= */

/* ---------- fonts, served from this directory ---------- */
/* Never Google. A generated site has to work from a USB stick, from behind a
   corporate proxy, and in five years; a webfont CDN fails all three. */
@font-face {
  font-family: 'IBM Plex Sans';
  font-weight: 400; font-style: normal; font-display: swap;
  src: url('fonts/plex-sans-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-weight: 600; font-style: normal; font-display: swap;
  src: url('fonts/plex-sans-600.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-weight: 400; font-style: normal; font-display: swap;
  src: url('fonts/jetbrains-mono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-weight: 500; font-style: normal; font-display: swap;
  src: url('fonts/jetbrains-mono-500.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-weight: 600; font-style: normal; font-display: swap;
  src: url('fonts/jetbrains-mono-600.woff2') format('woff2');
}

/* ---------- design tokens ---------- */
html.jt {
  /* Tells the UA to draw its own furniture -- scrollbars, form controls, the
     canvas behind a short page -- to match. Nothing in this sheet reaches those. */
  color-scheme: dark;

  /* type: two families, because they do different jobs. Prose wants a
     humanist sans; code wants fixed advance widths and the programming
     ligatures JetBrains Mono draws through the `calt` feature. */
  --font-prose: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-code:  'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* A modular scale at 1.125 (a major second), not the more usual 1.2. The
     chrome's sizes all sit between 10px and 25px, and at 1.2 that range holds
     only four steps -- snapping to them redraws the header, sidebar and status
     bar rather than re-expressing them. 1.125 keeps the design and makes it
     scalable, which was the point. Root is 0.875rem = 14px at a default
     browser setting, and --fs-scale is what the reader's A-/A+ control moves. */
  --fs--3: 0.702rem;
  --fs--2: 0.790rem;
  --fs--1: 0.889rem;
  --fs-0:  1rem;
  --fs-1:  1.125rem;
  --fs-2:  1.266rem;
  --fs-3:  1.424rem;
  --fs-4:  1.602rem;
  --fs-5:  1.802rem;

  --bg:       #0e0e10;
  --bg2:      #0a0a0c;
  --panel:    #141419;
  --border:   #1e1e23;
  --border2:  #26262c;
  --tx:       #e6e6e2;
  --tx2:      #b9b9bd;
  --mut:      #8d8d95;
  --dim:      #63636b;
  --faint:    #4a4a52;
  --hi:       #ffffff;
  --hov:      #15151a;
  --code-bg:  #101013;
  --code-hd:  #121215;
  --code-bd:  #232329;
  --code-tx:  #d6d6d2;

  /* Diagram palette. Every colour a pre-rendered diagram carries is rewritten
     to var(--dg-*, #originalhex) at build time (DiagramTheme.cs), so these are
     what actually decide how a diagram looks. The dark values are the ones
     mermaid rendered against, restated here so the two schemes read as one
     table -- change one, look at the other. */
  --dg-node-bg:     #161b24;
  --dg-node-bg-2:   #1b2230;
  --dg-cluster-bg:  #141922;
  --dg-canvas:      #0f1319;
  --dg-border:      #2b323d;
  --dg-line:        #8b97a8;
  --dg-text:        #e6edf3;
  --dg-edge-label:  #ebe6dd;
  --dg-title:       #f0ece6;
  --dg-label-bg:    rgba(27, 34, 48, 0.5);
  --dg-ok-bg:       #1f6f4a;
  --dg-ok-border:   #2ea36a;
  --dg-ok-text:     #eaf6ef;
  --dg-warn-bg:     #7a4a1f;
  --dg-warn-border: #c07c34;
  --dg-warn-text:   #fdf1e3;
  --dg-info-bg:     #1f4f7a;
  --dg-info-border: #3a86c8;
  --dg-info-text:   #e8f2fb;
  --dg-bad-bg:      #7a1f2e;
  --dg-bad-border:  #c2405a;
  --dg-bad-text:    #fdeaee;
}

/* Layer 2: the OS preference, for a reader who never touches the toggle. */
@media (prefers-color-scheme: light) {
  html.jt {
    color-scheme: light;
    --bg:       #f6f6f4;
    --bg2:      #efefec;
    --panel:    #e8e8e3;
    --border:   #e1e1da;
    --border2:  #d5d5cd;
    --tx:       #1a1a1d;
    --tx2:      #3c3c42;
    --mut:      #5e5e66;
    --dim:      #8b8b91;
    --faint:    #b0b0b6;
    --hi:       #000000;
    --hov:      #eaeae5;
    /* Code blocks stay dark in the light theme. Deliberate, and inherited from
       the palette this was extracted from: a code block is a quotation from a
       terminal, and every syntax colour here was picked against a dark ground. */
    --code-bg:  #15151a;
    --code-hd:  #1b1b21;
    --code-bd:  #28282f;
    --code-tx:  #d6d6d2;

    /* Diagrams inverted. Backgrounds lighten, text darkens, and the classDef
       families keep their hue so a green node stays the "good" one -- only the
       lightness is exchanged between fill and text. */
    --dg-node-bg:     #ffffff;
    --dg-node-bg-2:   #f2f4f7;
    --dg-cluster-bg:  #f7f8fa;
    --dg-canvas:      #eef1f5;
    --dg-border:      #c9d1da;
    --dg-line:        #5b6673;
    --dg-text:        #1a1f26;
    --dg-edge-label:  #2b2620;
    --dg-title:       #14100c;
    --dg-label-bg:    rgba(255, 255, 255, 0.72);
    --dg-ok-bg:       #d9f2e4;
    --dg-ok-border:   #1f7d50;
    --dg-ok-text:     #10381f;
    --dg-warn-bg:     #fbebd6;
    --dg-warn-border: #a8672a;
    --dg-warn-text:   #452710;
    --dg-info-bg:     #dceaf8;
    --dg-info-border: #2f6ea6;
    --dg-info-text:   #10283d;
    --dg-bad-bg:      #fadfe4;
    --dg-bad-border:  #a83249;
    --dg-bad-text:    #40121b;
  }
}

/* Layer 3: the explicit choice. Must beat both of the above, so every token
   either scheme defines is restated here rather than inherited. */
html.jt[data-theme="light"] {
  color-scheme: light;
  --bg:       #f6f6f4;
  --bg2:      #efefec;
  --panel:    #e8e8e3;
  --border:   #e1e1da;
  --border2:  #d5d5cd;
  --tx:       #1a1a1d;
  --tx2:      #3c3c42;
  --mut:      #5e5e66;
  --dim:      #8b8b91;
  --faint:    #b0b0b6;
  --hi:       #000000;
  --hov:      #eaeae5;
  --code-bg:  #15151a;
  --code-hd:  #1b1b21;
  --code-bd:  #28282f;
  --code-tx:  #d6d6d2;

  --dg-node-bg:     #ffffff;
  --dg-node-bg-2:   #f2f4f7;
  --dg-cluster-bg:  #f7f8fa;
  --dg-canvas:      #eef1f5;
  --dg-border:      #c9d1da;
  --dg-line:        #5b6673;
  --dg-text:        #1a1f26;
  --dg-edge-label:  #2b2620;
  --dg-title:       #14100c;
  --dg-label-bg:    rgba(255, 255, 255, 0.72);
  --dg-ok-bg:       #d9f2e4;
  --dg-ok-border:   #1f7d50;
  --dg-ok-text:     #10381f;
  --dg-warn-bg:     #fbebd6;
  --dg-warn-border: #a8672a;
  --dg-warn-text:   #452710;
  --dg-info-bg:     #dceaf8;
  --dg-info-border: #2f6ea6;
  --dg-info-text:   #10283d;
  --dg-bad-bg:      #fadfe4;
  --dg-bad-border:  #a83249;
  --dg-bad-text:    #40121b;
}

html.jt[data-theme="dark"] {
  color-scheme: dark;
  --bg:       #0e0e10;
  --bg2:      #0a0a0c;
  --panel:    #141419;
  --border:   #1e1e23;
  --border2:  #26262c;
  --tx:       #e6e6e2;
  --tx2:      #b9b9bd;
  --mut:      #8d8d95;
  --dim:      #63636b;
  --faint:    #4a4a52;
  --hi:       #ffffff;
  --hov:      #15151a;
  --code-bg:  #101013;
  --code-hd:  #121215;
  --code-bd:  #232329;
  --code-tx:  #d6d6d2;

  --dg-node-bg:     #161b24;
  --dg-node-bg-2:   #1b2230;
  --dg-cluster-bg:  #141922;
  --dg-canvas:      #0f1319;
  --dg-border:      #2b323d;
  --dg-line:        #8b97a8;
  --dg-text:        #e6edf3;
  --dg-edge-label:  #ebe6dd;
  --dg-title:       #f0ece6;
  --dg-label-bg:    rgba(27, 34, 48, 0.5);
  --dg-ok-bg:       #1f6f4a;
  --dg-ok-border:   #2ea36a;
  --dg-ok-text:     #eaf6ef;
  --dg-warn-bg:     #7a4a1f;
  --dg-warn-border: #c07c34;
  --dg-warn-text:   #fdf1e3;
  --dg-info-bg:     #1f4f7a;
  --dg-info-border: #3a86c8;
  --dg-info-text:   #e8f2fb;
  --dg-bad-bg:      #7a1f2e;
  --dg-bad-border:  #c2405a;
  --dg-bad-text:    #fdeaee;
}

/* ---------- diagrams ---------- */
figure.diagram {
  margin: 24px 0;
  text-align: center;
  background: transparent;
}
figure.diagram svg {
  max-width: 100%;
  height: auto;
}
/* A diagram that would not parse. Deliberately conspicuous: it is a defect in the
   source document, and the reader of the page is usually the one who can fix it. */
.diagram-error {
  text-align: left;
  border: 1px solid var(--dg-bad-border);
  background: var(--dg-bad-bg);
  color: var(--dg-bad-text);
  border-radius: 4px;
  padding: 12px 14px;
  font-size: var(--fs--1);
}
.diagram-error p { margin: 6px 0; }
.diagram-error pre {
  margin: 8px 0 0;
  overflow-x: auto;
  font-size: var(--fs--2);
  opacity: .85;
}

@media (max-width: 760px) {
  /* Below this width, scaling a diagram down makes its labels unreadable, so
     scroll it instead. --dw is the diagram's own width, written into the
     figure at build time -- an SVG with only a viewBox has no intrinsic width,
     and `width:auto` would resolve back to the container. */
  figure.diagram { overflow-x: auto; }
  figure.diagram svg { width: var(--dw, auto); max-width: none; }
}

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

html.jt {
  /* 0.875rem of the browser's own default is the 14px this design was drawn
     at, and respects a reader who has already raised that default -- which a
     hardcoded `14px` silently overrode. --fs-scale is the A-/A+ control. */
  font-size: calc(0.875rem * var(--fs-scale, 1));
  height: 100%;
}

body.jt {
  font-family: var(--font-prose);
  background: var(--bg);
  color: var(--tx);
  height: 100%;
  overflow: hidden;
}

/* The chrome stays monospaced. Prose changed family; the shell did not, and
   that is the point of having two: the header, nav, breadcrumb and status bar
   read as the terminal frame this design was drawn as, and the article reads
   as a document sitting inside it. */
.jt-header, .jt-sidebar, .jt-statusbar, .breadcrumb, .page-nav {
  font-family: var(--font-code);
}

/* Ligatures are the reason JetBrains Mono is here rather than any mono: `calt`
   is the feature that draws => != >= as single glyphs. On by default in most
   browsers, asked for explicitly because it is the point. */
code, pre, kbd, samp, .code-block, .mono {
  font-family: var(--font-code);
  font-feature-settings: "calt" 1;
  font-variant-ligatures: contextual;
}

/* ---------- shell grid ---------- */
.jt-shell {
  display: grid;
  grid-template-rows: 46px 1fr 26px;
  height: 100vh;
  overflow: hidden;
}

/* ---------- header ---------- */
.jt-header {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  background: var(--bg2);
  border-bottom: 1px solid var(--border);
  z-index: 30;
  position: relative;
}

.hamburger {
  display: none;
  background: none;
  border: none;
  color: var(--tx);
  font-size: var(--fs-1);
  cursor: pointer;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  flex: none;
}
.hamburger:hover { color: var(--hi); background: var(--hov); }

.header-brand {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.brand-name {
  font-size: var(--fs-0);
  font-weight: 600;
  color: var(--hi);
}

.brand-crumb {
  font-size: var(--fs--2);
  color: var(--dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 320px;
}

.header-spacer { flex: 1; }

/* ---------- header tools: text size, colour scheme ---------- */
.header-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

.fs-group { display: flex; gap: 2px; }

.tool-btn {
  background: none;
  border: 1px solid transparent;
  color: var(--mut);
  font: inherit;
  font-size: var(--fs--2);
  line-height: 1;
  cursor: pointer;
  padding: 5px 8px;
  border-radius: 4px;
  min-width: 28px;
}
.tool-btn:hover { color: var(--hi); background: var(--hov); border-color: var(--border2); }
/* Keyboard focus must stay visible: these are the only controls on the page
   that change what the page looks like, so losing track of them is worse here
   than for an ordinary link. */
.tool-btn:focus-visible { outline: 2px solid var(--border2); outline-offset: 1px; }

.theme-btn { min-width: 46px; }

.search-btn { display: inline-flex; align-items: center; gap: 8px; }

kbd {
  font: 400 var(--fs--3) var(--font-code);
  color: var(--mut);
  background: var(--panel);
  border: 1px solid var(--border2);
  border-bottom-width: 2px;
  border-radius: 3px;
  padding: 1px 5px;
  line-height: 1.2;
}

/* ---------- search ---------- */
.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(0,0,0,.55);
  padding: 10vh 16px 0;
}
.search-overlay[hidden] { display: none; }

.search-box {
  max-width: 640px;
  margin: 0 auto;
  background: var(--bg2);
  border: 1px solid var(--border2);
  border-radius: 6px;
  box-shadow: 0 12px 40px rgba(0,0,0,.5);
  display: flex;
  flex-direction: column;
  max-height: 70vh;
  font-family: var(--font-code);
}

.search-box input {
  font: 400 var(--fs-0)/1.4 var(--font-code);
  color: var(--tx);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  outline: none;
  padding: 14px 16px;
}
.search-box input::placeholder { color: var(--faint); }

.search-results { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--border2) transparent; }

.search-hit {
  display: block;
  padding: 9px 16px;
  text-decoration: none;
  border-left: 2px solid transparent;
}
.search-hit:hover, .search-hit.selected { background: var(--hov); border-left-color: var(--tx); }

.search-hit-title {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: var(--fs--1);
  color: var(--tx);
}
.search-hit-where { color: var(--mut); }
.search-hit-where::before { content: "\203A "; color: var(--dim); }
.search-hit-section { margin-left: auto; font-size: var(--fs--3); color: var(--dim); text-transform: uppercase; letter-spacing: .08em; white-space: nowrap; }

.search-hit-snippet {
  margin-top: 3px;
  font: 400 var(--fs--2)/1.5 var(--font-prose);
  color: var(--mut);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.search-hit-snippet mark { background: transparent; color: var(--hi); font-weight: 600; }

.search-empty { padding: 14px 16px; color: var(--dim); font-size: var(--fs--2); }

.search-foot {
  display: flex;
  gap: 6px;
  align-items: center;
  padding: 8px 16px;
  border-top: 1px solid var(--border);
  font-size: var(--fs--3);
  color: var(--dim);
}
.search-foot kbd { margin-right: 2px; }

/* ---------- keyboard help ---------- */
.kbd-help {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(0,0,0,.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.kbd-help[hidden] { display: none; }

.kbd-box {
  background: var(--bg2);
  border: 1px solid var(--border2);
  border-radius: 6px;
  box-shadow: 0 12px 40px rgba(0,0,0,.5);
  padding: 18px 22px;
  min-width: 320px;
  font-family: var(--font-code);
}
.kbd-title { font-size: var(--fs--2); color: var(--dim); text-transform: uppercase; letter-spacing: .08em; margin-bottom: 12px; }
.kbd-box table { border-collapse: collapse; }
.kbd-box td { padding: 4px 14px 4px 0; font-size: var(--fs--1); color: var(--tx2); vertical-align: baseline; }
.kbd-box td:first-child { white-space: nowrap; }
.kbd-box kbd { margin-right: 3px; }

/* ---------- body grid ---------- */
.jt-body {
  display: grid;
  /* --nav-w is the reader's drag width, restored by the head script before first
     paint; the default is the 240px the design was drawn at. */
  grid-template-columns: var(--nav-w, 240px) 1fr;
  overflow: hidden;
  min-height: 0;
}
html[data-nav="hidden"] .jt-body { grid-template-columns: 0 1fr; }
html[data-nav="hidden"] .jt-sidebar { display: none; }
html.nav-resizing { cursor: col-resize; user-select: none; }

/* ---------- sidebar ---------- */
.nav-backdrop {
  display: none;
  position: fixed;
  inset: 46px 0 26px 0;
  background: rgba(0,0,0,.45);
  z-index: 35;
}

.jt-sidebar {
  position: relative;
  background: var(--bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 40;
}

/* The drag handle: a strip over the sidebar's right edge, invisible until hovered. */
.nav-resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 6px;
  height: 100%;
  cursor: col-resize;
  z-index: 41;
  touch-action: none;
}
.nav-resizer:hover, html.nav-resizing .nav-resizer { background: var(--border2); }

.sidebar-filter {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 10px 10px 4px;
  padding: 5px 9px;
  background: var(--panel);
  border: 1px solid var(--border2);
  border-radius: 4px;
}

.filter-icon {
  font-size: var(--fs--2);
  color: var(--faint);
  flex: none;
}

.sidebar-filter input {
  flex: 1;
  min-width: 0;
  font: 400 var(--fs--2)/1 var(--font-code);
  color: var(--tx);
  background: transparent;
  border: none;
  outline: none;
}
.sidebar-filter input::placeholder { color: var(--faint); }

.sidebar-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 4px 8px 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--border2) transparent;
}

/* nav groups */
.nav-group { margin-bottom: 2px; }

.nav-group-header {
  display: flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  padding: 5px 7px;
  border-radius: 3px;
}
.nav-group-header:hover { background: var(--hov); }

.nav-chev {
  font-size: var(--fs--3);
  color: var(--dim);
  transition: transform .15s ease;
  display: inline-block;
}
.nav-group[data-open="true"] .nav-chev { transform: rotate(90deg); }

.nav-group-label {
  font-size: var(--fs--3);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--mut);
}

.nav-group-items {
  display: none;
  flex-direction: column;
  padding: 1px 0 4px;
}
.nav-group[data-open="true"] .nav-group-items { display: flex; }

.nav-group-items a {
  display: block;
  padding: 5px 9px 5px 18px;
  font-size: var(--fs--1);
  color: var(--tx2);
  text-decoration: none;
  border-left: 2px solid transparent;
  border-radius: 0 3px 3px 0;
}
.nav-group-items a:hover {
  background: var(--hov);
  color: var(--tx);
}
.nav-group-items a.active {
  color: var(--hi);
  font-weight: 500;
  border-left-color: var(--tx);
  background: var(--hov);
}

/* filter hidden */
.nav-hidden { display: none !important; }

/* ---------- content ---------- */
.jt-content {
  overflow-y: auto;
  min-height: 0;
  background: var(--bg);
  scrollbar-width: thin;
  scrollbar-color: var(--border2) transparent;
}

.content-inner {
  max-width: 820px;
  padding: 24px 36px 60px;
  margin: 0 auto;
}

/* ---------- on-this-page rail ---------- */
/* The rail is a grid column beside the content rather than a floated aside, so
   the content keeps its own centring when there is no rail at all -- a page
   with one heading gets no rail, and must not then sit off-centre. */
/* The rail is written before the article in the source, and placed to its right
   here. That order is what makes the narrow layout work without a second rule:
   block flow puts the rail above the article, where a list of section links is
   the most useful thing on a phone -- below it, it would be a footer nobody
   scrolls to. */
.jt-content.has-toc {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  align-items: start;
}
.jt-content.has-toc > .content-inner { grid-area: 1 / 1; }
.jt-content.has-toc > .toc           { grid-area: 1 / 2; }

.toc {
  position: sticky;
  top: 24px;
  padding: 24px 20px 60px 0;
  font-size: var(--fs--2);
  line-height: 1.5;
  border-left: 1px solid var(--border);
  padding-left: 14px;
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border2) transparent;
}

.toc-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  color: var(--dim);
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: var(--fs--3);
  margin-bottom: 10px;
}

.toc-toggle {
  font: 400 var(--fs--3) var(--font-code);
  color: var(--dim);
  background: none;
  border: 1px solid transparent;
  border-radius: 3px;
  padding: 1px 6px;
  cursor: pointer;
  text-transform: none;
  letter-spacing: 0;
}
.toc-toggle:hover { color: var(--tx); border-color: var(--border2); }
/* The label is the stylesheet's, because the stylesheet is what knows whether the rail
   is beside the article and hidden, or above it and folded. */
.toc-toggle::after { content: "hide"; }
html[data-toc="hidden"] .toc-toggle::after { content: "show"; }

/* The rail is a column of block links, and a block link is a hand cursor across its
   whole row. fit-content keeps the hand over the words. */
.toc a {
  display: block;
  width: fit-content;
  max-width: 100%;
  color: var(--mut);
  text-decoration: none;
  padding: 3px 0;
  border-left: 2px solid transparent;
  margin-left: -14px;
  padding-left: 12px;
}

/* Hidden: the rail collapses to a tab on the right edge, and the content takes the
   column back. Set on <html> by the head script, so there is no flash of rail. */
.toc-tab { display: none; }
html[data-toc="hidden"] .jt-content.has-toc { grid-template-columns: minmax(0, 1fr) 28px; }
html[data-toc="hidden"] .toc {
  padding: 0;
  border-left: none;
  overflow: visible;
}
html[data-toc="hidden"] .toc > :not(.toc-tab) { display: none; }
html[data-toc="hidden"] .toc-tab {
  display: block;
  position: sticky;
  top: 24px;
  writing-mode: vertical-rl;
  font: 400 var(--fs--3) var(--font-code);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--dim);
  background: none;
  border: none;
  border-left: 1px solid var(--border);
  padding: 10px 6px;
  cursor: pointer;
  white-space: nowrap;
}
html[data-toc="hidden"] .toc-tab:hover { color: var(--tx); }
.toc a:hover { color: var(--tx); }
.toc a.toc-l3 { padding-left: 26px; }
.toc a.toc-active {
  color: var(--hi);
  border-left-color: var(--border2);
}

@media (max-width: 1100px) {
  /* Below this the rail costs the content more width than it is worth. */
  .jt-content.has-toc { display: block; }
  .toc {
    position: static;
    max-height: none;
    border-left: none;
    border-bottom: 1px solid var(--border);
    max-width: 820px;
    margin: 0 auto;
    padding: 16px 36px;
  }
  .toc a { margin-left: 0; padding-left: 0; border-left: none; }
  .toc a.toc-l3 { padding-left: 14px; }
  /* Above the article here, so it starts folded to its title row: a long page's rail
     was 450px of links before the first paragraph. The toggle opens it for this page. */
  .toc a { display: none; }
  .toc-title { margin-bottom: 0; }
  html[data-toc-narrow="open"] .toc a { display: block; }
  html[data-toc-narrow="open"] .toc-title { margin-bottom: 10px; }
  html[data-toc="hidden"] .jt-content.has-toc { display: block; }
  html[data-toc="hidden"] .toc > :not(.toc-tab) { display: block; }
  html[data-toc="hidden"] .toc { padding: 16px 36px; border-bottom: 1px solid var(--border); }
  html[data-toc="hidden"] .toc-tab, .toc-tab { display: none; }
  html[data-toc="hidden"] .toc a { display: none; }
  html[data-toc="hidden"][data-toc-narrow="open"] .toc a { display: block; }
  .toc-toggle::after, html[data-toc="hidden"] .toc-toggle::after { content: "show"; }
  html[data-toc-narrow="open"] .toc-toggle::after { content: "hide"; }
}

/* breadcrumb */
.breadcrumb {
  font-size: var(--fs--3);
  color: var(--dim);
  margin-bottom: 16px;
}

/* ---------- article typography ---------- */
article h1 {
  font: 600 var(--fs-5)/1.15 var(--font-prose);
  letter-spacing: -.02em;
  color: var(--hi);
  margin: 0 0 6px;
}

article h2 {
  font-size: var(--fs-1);
  font-weight: 600;
  color: var(--tx);
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
  margin: 32px 0 14px;
}

article h3 {
  font-size: var(--fs--1);
  font-weight: 600;
  color: var(--tx2);
  margin: 22px 0 10px;
}

/* Not uppercased: jaunty's API pages put method signatures in h4, and
   `WITHMAPPER(FUNC<IDATAREADER, T> MAPPER)` is not a signature anyone can read. */
article h4 {
  font-size: var(--fs--1);
  font-weight: 600;
  color: var(--mut);
  margin: 18px 0 8px;
}

article p {
  font: 400 var(--fs-0)/1.7 var(--font-prose);
  color: var(--tx2);
  margin: 0 0 18px;
  max-width: 74ch;
}

article ul, article ol {
  margin: 0 0 18px 1.2em;
  padding: 0;
}

article li {
  font: 400 var(--fs-0)/1.65 var(--font-prose);
  color: var(--tx2);
  margin-bottom: 4px;
}

article strong { color: var(--tx); font-weight: 600; }

article a {
  color: var(--tx);
  text-decoration: underline;
  text-decoration-color: var(--border2);
}
article a:hover { text-decoration-color: var(--mut); }

article hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 24px 0;
}

/* ---------- inline code ---------- */
article code {
  font: 400 var(--fs--1)/1 var(--font-code);
  color: var(--tx);
  background: var(--panel);
  border: 1px solid var(--border2);
  border-radius: 3px;
  padding: 1px 5px;
}

/* ---------- code blocks ---------- */
.code-block {
  border: 1px solid var(--code-bd);
  border-radius: 6px;
  margin: 0 0 22px;
  overflow: hidden;
}

.code-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 7px 12px;
  background: var(--code-hd);
  border-bottom: 1px solid var(--code-bd);
}

.code-lang {
  font-size: var(--fs--3);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--mut);
}

/* Code blocks are dark in both schemes, so these are fixed rather than tokens: the
   tokens go light with the page and the button vanished into the header. */
.copy-btn {
  font: 400 var(--fs--2) var(--font-code);
  color: #c9c9c4;
  background: rgba(255,255,255,.04);
  border: 1px solid #45454d;
  border-radius: 3px;
  padding: 3px 10px;
  cursor: pointer;
}
.copy-btn:hover { color: #ffffff; border-color: #8d8d95; background: rgba(255,255,255,.08); }
.copy-btn.copied { color: #87b47a; border-color: #87b47a; }

article pre {
  margin: 0;
  padding: 14px 16px;
  background: var(--code-bg);
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border2) transparent;
}

article pre code {
  font: 400 var(--fs--1)/1.75 var(--font-code);
  color: var(--code-tx);
  background: none;
  border: none;
  padding: 0;
}

/* syntax tokens: VS Code Dark+, since every code block is a dark panel in both schemes.
   One class per thing an editor colours; Highlight.cs is the only writer. */
.tok-kw   { color: #569cd6; }
.tok-ctl  { color: #c586c0; }
.tok-type { color: #4ec9b0; }
.tok-fn   { color: #dcdcaa; }
.tok-str  { color: #ce9178; }
.tok-num  { color: #b5cea8; }
.tok-com  { color: #6a9955; font-style: italic; }
.tok-attr { color: #d7ba7d; }
.tok-var  { color: #9cdcfe; }
.tok-tag  { color: #569cd6; }
.tok-key  { color: #9cdcfe; }
.tok-lit  { color: #569cd6; }
.tok-pre  { color: #c586c0; }
.tok-punc { color: #808080; }

/* ---------- tables ---------- */
article table {
  border-collapse: collapse;
  width: 100%;
  margin: 0 0 22px;
  font-size: var(--fs--1);
}

article th, article td {
  border: 1px solid var(--border2);
  padding: 7px 10px;
  text-align: left;
  color: var(--tx2);
}

article th {
  background: var(--panel);
  color: var(--tx);
  font-weight: 600;
}

article tr:nth-child(even) td { background: rgba(255,255,255,.015); }

/* ---------- callouts ---------- */
.callout {
  margin: 0 0 22px;
  padding: 13px 16px;
  background: var(--panel);
  border: 1px solid var(--border2);
  border-left: 3px solid var(--mut);
  border-radius: 0 6px 6px 0;
  font-size: var(--fs--1);
  line-height: 1.75;
  color: var(--tx2);
}

.callout ul, .callout ol { margin: 0; padding-left: 1.2em; color: var(--tx2); }

.callout-warn { border-left-color: #c19a6b; }
.callout-tip  { border-left-color: #7b9eaf; }

/* ---------- prev/next ---------- */
.page-nav { margin-top: 44px; padding-top: 18px; border-top: 1px solid var(--border); }

.prev-next {
  display: flex;
  justify-content: space-between;
  gap: 20px;
}

.pn-prev, .pn-next {
  display: inline-flex;
  flex-direction: column;
  gap: 3px;
  text-decoration: none;
  opacity: .85;
}
.pn-next { align-items: flex-end; text-align: right; }
.pn-prev:hover, .pn-next:hover { opacity: 1; }

.pn-label { font-size: var(--fs--3); color: var(--dim); }
.pn-title { font-size: var(--fs--1); font-weight: 600; color: var(--tx); }

/* ---------- status bar ---------- */
.jt-statusbar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 14px;
  background: var(--bg2);
  border-top: 1px solid var(--border);
  font-size: var(--fs--3);
  color: var(--dim);
}

.status-dot { color: var(--mut); }
.status-spacer { flex: 1; }
.status-kbd {
  font: inherit;
  color: var(--dim);
  background: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.status-kbd:hover { color: var(--tx); }
.status-kbd kbd { font-size: inherit; padding: 0 4px; }

/* ---------- responsive ---------- */
@media (max-width: 760px) {
  .hamburger { display: flex; }
  .brand-crumb { display: none; }

  .jt-body { grid-template-columns: 1fr; }

  .jt-sidebar {
    position: fixed;
    inset: 46px auto 26px 0;
    width: 260px;
    transform: translateX(-100%);
    transition: transform .2s ease;
    border-right: 1px solid var(--border2);
    box-shadow: 4px 0 24px rgba(0,0,0,.4);
  }
  .jt-sidebar.open { transform: translateX(0); }
  .nav-backdrop.open { display: block; }
}