/* Preset: Notebook */
:root {
    --doc-font: "Arial", "Helvetica", sans-serif;
    --doc-font-size: 16px;
    --doc-line-height: 1.6;
    --doc-text: #000;
    --doc-link: #1976d2;
    --doc-code-font: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
    --doc-rule: rgba(128,128,128,0.45);
    --doc-cell-head-bg: rgba(128,128,128,0.1);
}
body {
    font-family: var(--doc-font);
    font-size: var(--doc-font-size);
    line-height: var(--doc-line-height);
    color: var(--doc-text);
}
/* Headings are deliberately unstyled: they are the browser's defaults in the
   editor as well, so setting sizes here would be a difference, not a match. */
p { margin: 1em 0; }
code, pre { font-family: var(--doc-code-font); }
table { border-collapse: collapse; width: 100%; table-layout: fixed; }
th, td { border: 1px solid var(--doc-rule); padding: 4px 8px; vertical-align: top; }
th { background: var(--doc-cell-head-bg); font-weight: 600; }
a { color: var(--doc-link); }


:root {
    /* Brand. Both blue by default; a theme may set them equal. */
    --site-link: #2a6496;          /* links in navigation and content */
    --site-accent: #2d6cdf;        /* the brand: links, focus ring, active pill */
    --site-accent-fg: #fff;        /* writing on an accent-filled shape */

    /* The functional color code of the topic model, the same one the app
       uses: a family always reads in its own hue, so a section is recognized
       before it is read. Carried as a dot beside a neutral label — never as
       colored heading text. Names blue, topics amber, connections purple,
       references green. */
    --site-family-names: #1976d2;
    --site-family-topics: #f9a825;
    --site-family-connections: #7b1fa2;
    --site-family-references: #2e7d32;

    /* The bar at the top of every page. */
    --site-banner-bg: #1f2a44;
    --site-banner-fg: #fff;
    --site-banner-hover-bg: rgba(255,255,255,0.14);
    --site-banner-scrim: rgba(15,20,32,0.45);
    --site-banner-scrim-pale: rgba(255,255,255,0.55);

    /* Writing on a picture — a page's backdrop block. */
    --site-hero-fg: #fff;
    /* What holds white writing against a photograph. A shadow, not a panel and
       not a wash: both of those were tried and both spend the picture to buy
       legibility for the words. Its own token because a template that lightens
       a site will want to soften this too. */
    --site-backdrop-shadow: 0 1px 3px rgba(0,0,0,0.75), 0 0 12px rgba(0,0,0,0.45);
    /* Amber, not the white it was. A white button on a blue band is what a
       band looks like before anyone has styled it, and most sites here will
       never be styled at all — the default IS the design for someone publishing
       in a hurry. One warm note against the blue is a choice; white is the
       absence of one. The text is warm-dark rather than the band's navy, so the
       button reads as its own object instead of a hole cut in the gradient.

       It is a bet, and worth naming: recolor the band to something warm and
       this argues with it. Both are tokens — the panel changes them per site,
       under the list of buttons they belong to. */
    --site-btn-primary-bg: #f2b13c;
    --site-btn-primary-fg: #23180a;
    /* Quieter than the solid button, on purpose: two buttons of equal weight
       ask the reader to choose rather than telling them where to start. It was
       0.8 opaque, which put the outlined ones almost level with the one that
       matters. */
    --site-btn-secondary-border: rgba(255,255,255,0.45);
    --site-btn-secondary-fg: #fff;
    /* What lifts the solid button off the band instead of pasting it on. Cast
       in the band's own dark rather than in gray, so it reads as shadow rather
       than as a smudge. */
    --site-btn-shadow: 0 10px 22px -10px rgba(6,14,34,0.65);
    --site-btn-shadow-hover: 0 16px 30px -12px rgba(6,14,34,0.78);
    /* Hovered. Derived from the button's own color rather than fixed, so a
       site that recolors its buttons gets a hover that still belongs to them
       — the alternative is one hardcoded gray that is wrong on every palette
       but the default one. Both are ordinary tokens, so either can be set
       outright. `color-mix` is not universal; every use below carries a
       fallback to the unhovered color, which is a hover that does nothing
       rather than a button that goes transparent. */
    --site-btn-primary-hover-bg: color-mix(in srgb, var(--site-btn-primary-bg) 90%, #000);
    --site-btn-secondary-hover-bg: rgba(255,255,255,0.14);

    /* Writing. See the module docstring on the grays. */
    --site-text: #333;             /* the introduction, a topic's description */
    --site-text-muted: #6b7280;    /* the workhorse: chrome links and labels */
    --site-text-dim: #666;         /* footer, Contents heading, tile blurbs */
    --site-text-soft: #868e9a;     /* breadcrumbs, nested nav, current page */
    --site-text-faint: #9aa0aa;    /* occurrence links, disclosure marker */
    --site-text-quiet: #888;       /* concat-layout nav, relation roles */
    --site-text-hint: #999;        /* "no matches" */
    --site-rail-head: #8a9099;     /* the uppercase heads atop both rails */
    --site-heading: #4a5a6a;       /* section headings in indexes and topics */
    --site-label-strong: #2a3540;  /* current page, notebook names */
    --site-menu-fg: var(--site-text-muted);  /* menu items at rest */
    --site-nav-active: #374151;    /* the page you are on */
    --site-nav-hover: #2b2f36;     /* pointer over a nav item */
    --site-nav-link: #5a6c7d;      /* concat-layout prev/next */
    --site-nav-link-hover: #1a2733;

    /* Surfaces. */
    --site-page-bg: #fff;          /* the paper every page is printed on */
    --site-surface: #fff;          /* inputs, dropdowns, popovers */
    --site-input-fg: #1f2a44;
    /* The rails are a shade OF the page, not a fixed gray: set the page to
       cream and a hardcoded #f6f7f9 rail stops looking like the same site.
       Declared twice on purpose — an engine without color-mix keeps the first
       and gets today's appearance, which is what the second computes anyway
       against a white page. Setting Side panel > Background overrides both,
       since the site's own token block is emitted last. */
    /* Lighter than it was (#f6f7f9 / 96%). The rail is a column of quiet type;
       a tint heavy enough to read as a PANEL made it the first thing the eye
       landed on and the reading column the second. Barely-there is enough to
       say "this is not the page", and the divider does the rest. */
    --site-rail-bg: #fbfbfc;       /* sidebar and top menu */
    /* The mix runs toward `--site-rail-shade`, not toward black, because the
       direction is only right on a light page: a rail is a shade OF the page,
       and on a DARK page "a shade of the page" is lighter, not darker. A dark
       template flips this one token and the rail follows.
       The literal above remains the fallback for an engine without color-mix —
       which is why a dark template must also set `--site-rail-bg` outright, or
       that engine renders a near-white sidebar on a dark page. */
    --site-rail-shade: #000;
    --site-rail-bg: color-mix(in srgb, var(--site-page-bg) 98%, var(--site-rail-shade));
    --site-hover-bg: #eceef1;      /* the hover wash, used everywhere */
    --site-nav-bg: #fafafa;        /* concat-layout nav strip */
    --site-docnav-top-bg: #eef1f6;
    --site-docnav-bottom-bg: #fafbfc;
    /* THE DROP-DOWN IS PART OF THE MENU, so it starts as the menu's own
       color rather than as a second near-white that has to be matched by hand.
       mb, having set a dark menu and found the drop-down still pale: "by
       default, can you apply the same color on the menu and submenus?"
       It stays a token of its own — a drop-down deliberately lighter than its
       bar is a real design — but the DEFAULT no longer costs anybody a copy
       and a paste to get the obvious answer. */
    --site-submenu-bg: var(--site-rail-bg);

    /* Lines and shadow. */
    --site-border: #e4e6ea;        /* the standard hairline */
    --site-border-soft: #e9ebee;
    --site-border-strong: #d6dbe2;
    --site-border-plain: #e4e4e4;
    --site-rule: #d0d0d0;          /* the dashed page divider */
    /* The bar marking the active section. Reads the brand rather than being
       one more gray: "you are here" is the one thing in a rail of quiet type
       that should be allowed to carry color, and a gray bar against gray text
       on a gray ground was invisible until you looked for it. Still its own
       token, so a theme that wants it neutral can say so. */
    --site-active-bar: var(--site-accent);
    --site-crumb-sep: #b0b6bf;     /* the breadcrumb separator */
    --site-marker: #c2c7cf;        /* the bullet before an occurrence */
    --site-shadow: rgba(0,0,0,0.12);

    /* Chrome type. The reading face is the export CSS's business, not ours. */
    --site-font-chrome: Helvetica, Arial, sans-serif;

    /* ── Geometry ───────────────────────────────────────────────────────
       Color was tokenised first and nothing else was, so a preset, a font
       and every color token together could not change a single DIMENSION on
       a published page — templates built on that vocabulary would have been
       the same site recolored. These are the scales that make a template
       more than a palette.

       Units are deliberately NOT normalized. An `em` step is a proportion of
       its container and some of them nest — a topic's cross-reference sits
       inside a rail row that is itself scaled — so rewriting those as `rem`
       would resize them. Each step carries the unit its role needs.

       BREAKPOINTS ARE NOT HERE and cannot be: `@media` does not read custom
       properties. They stay literal, at 560 / 720 / 820px. */

    /* Type, chrome only — the reading column's face and size come from the
       content preset (--doc-*), which is a separate axis on purpose. */
    --site-type-micro: 0.72em;      /* uppercase rail and section labels */
    --site-type-xs: 0.8em;
    --site-type-sm: 0.85em;
    --site-type-md: 0.9em;
    --site-type-lg: 0.95em;
    --site-type-base: 1em;
    --site-type-up: 1.15em;
    --site-type-title: 1.25em;

    /* Display sizes are absolute: they answer to the page, not to a parent. */
    --site-display-sm: 1.08rem;
    --site-display-lg: 1.9rem;

    /* Spacing. The chrome measures in em, so it moves with its own type; the
       landing bands measure in rem, so they keep their proportions. */
    --site-space-1: 0.15em;
    --site-space-2: 0.25em;
    --site-space-3: 0.4em;
    --site-space-4: 0.6em;
    --site-space-5: 0.9em;
    --site-space-6: 1.25em;
    --site-space-7: 1.5em;
    --site-space-8: 2.5em;
    /* The reading column's gutter, in `rem` and not `em` ON PURPOSE. Each block
       now carries the measure itself, as the measure LESS this gutter — and an
       `em` in that subtraction would resolve against the block's own font size,
       so a heading came out 40px narrower than the paragraph under it and sat
       centered inside its own line. A gutter is a property of the page, not of
       whatever is written in it. */
    --site-gutter: 2.5rem;
    /* What a block of writing is actually as wide as: the measure less the
       gutter on each side. Written once, because four rules need it and one of
       them is arithmetic nobody should have to redo in their head. */
    --site-measure-inner: calc(var(--site-measure) - 2 * var(--site-gutter));
    --site-band-1: 1rem;
    --site-band-2: 1.5rem;
    --site-band-3: 2rem;

    /* Corners. */
    --site-radius-sm: 4px;
    --site-radius-md: 6px;
    --site-radius-lg: 10px;
    --site-radius-pill: 999px;

    /* Widths: the reading measure, the standard page, the wide
       (three-column) page, and a rail. */
    --site-measure: 760px;
    --site-width: 1100px;
    --site-width-wide: 1240px;
    /* Wider than it was (220px), and the extra goes to the gutter rather than
       to the text: a list of titles set hard against the edge of its own tint
       reads as cramped however much room is outside it. */
    --site-rail: 240px;

    /* ── What a TEMPLATE moves ──────────────────────────────────────────
       Bands and columns. These exist because a template has to be able to
       change what a visitor notices first, and none of it was reachable: the
       banner's height was whatever its contents happened to be, and the
       contents column could only ever sit on the left.

       Declaring a token HERE is what makes it settable at all — the allow-list
       is scraped from this block — so each is declared and read by exactly one
       rule below. */

    /* The banner's floor. `auto` is today's behavior exactly: the height is
       the padding plus whichever is taller, the logo or the title line. A
       template wanting a photographic bar sets a real height — the background
       is `object-fit: cover` on `inset: 0`, so it contributes no height of its
       own and simply fills whatever it is given. */
    /* What the browser should paint the things WE do not: form controls, the
       scrollbar, the canvas behind a short page. A dark palette that forgets
       this gets a light scrollbar down a dark page. `light dark` means "either,
       follow the reader" and belongs to the template that switches. */
    --site-color-scheme: light;

    --site-banner-min-height: auto;
    /* THE MENU'S OWN SIZE. Declared as the chrome size rather than left to a
       var() fallback: an undeclared token renders as NOTHING, not as its
       fallback, in the places that read it bare — and a theme that sets this
       expects it to exist. Unset still means unset, because what it is unset
       TO is what every site had before the token. */
    --site-menu-size: var(--site-type-md);
    --site-logo-height: 40px;
    /* A template's own ornament for the bar — inline, never a fetched file, so
       it behaves identically in the editor's preview (which inlines the
       stylesheet), in a zip opened from a disk, and on a live host. It sits
       UNDER an author's photograph, not instead of it: the photograph is an
       <img> at `inset: 0`, so a site with one covers this entirely. */
    --site-banner-pattern: none;

}

/* ─── Responsive base (always included) ─── */
html { color-scheme: var(--site-color-scheme); }
*, *::before, *::after { box-sizing: border-box; }
img, svg, video, canvas, iframe { max-width: 100%; height: auto; }
/* Wide tables scroll within their column instead of widening the page */
.site-content table { display: block; overflow-x: auto; max-width: 100%; }

/* Task lists. The editor's markup carries the checkbox but no styling of its
   own, so without these a published checklist reads as a bullet, a checkbox,
   and its text on the next line. Same rules as the editor (index.css), so a
   page looks the same published as it did while it was written. The boxes are
   disabled: a published page is read, not filled in. */
.site-content ul[data-type="taskList"] { list-style: none; padding-left: var(--site-space-2); }
.site-content ul[data-type="taskList"] li { display: flex; align-items: flex-start; gap: var(--site-space-3); }
.site-content ul[data-type="taskList"] li > label { flex: 0 0 auto; margin-top: var(--site-space-1); }
.site-content ul[data-type="taskList"] li > div { flex: 1 1 auto; min-width: 0; }
.site-content ul[data-type="taskList"] li > div > p { margin: 0; }
.site-content ul[data-type="taskList"] input[type="checkbox"] { pointer-events: none; }

/* ─── Publish-pipeline chrome (always included) ─── */

.site-nav, .page-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-space-7);
    padding: var(--site-space-5) var(--site-space-6);
    margin: 0 0 var(--site-space-7) 0;
    background: var(--site-nav-bg);
    border-bottom: 1px solid var(--site-border-plain);
    font-size: var(--site-type-sm);
    color: var(--site-text-quiet);
}

/* Two-level document nav, below the banner: notebook row + page row. */
/* Prev / current / next row. Typography matches the breadcrumbs (sans-serif,
   small, muted), with the same ‹ › chevrons. */
.doc-nav { max-width: var(--site-width); margin: 0 auto; font-family: var(--site-font-chrome); }
.docnav-row {
    display: flex;
    align-items: center;
    gap: var(--site-space-6);
    padding: var(--site-space-3) var(--site-space-7);
    font-size: var(--site-type-xs);
    border-bottom: 1px solid var(--site-border-soft);
}
.docnav-notebooks { background: var(--site-docnav-top-bg); font-weight: 600; }
.docnav-pages { background: var(--site-docnav-bottom-bg); }
.docnav-prev, .docnav-next {
    flex: 1 1 0; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.docnav-next { text-align: right; }
.docnav-cur {
    flex: 0 1 auto; text-align: center; max-width: 50%;
    color: var(--site-text-soft);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.doc-nav a { color: var(--site-text-muted); text-decoration: none; }
.doc-nav a:hover { color: var(--site-link); text-decoration: underline; }

.site-nav a, .page-nav a {
    color: var(--site-nav-link);
    text-decoration: none;
}
.site-nav a:hover, .page-nav a:hover {
    color: var(--site-nav-link-hover);
    text-decoration: underline;
}

.site-nav-prev, .page-nav-prev,
.site-nav-next, .page-nav-next {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.site-nav-next, .page-nav-next { text-align: right; }

.site-nav-current, .page-nav-up {
    flex: 0 1 auto;
    text-align: center;
    color: var(--site-label-strong);
    font-weight: 600;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Top-level publication index */
.publish-section { margin: 0 0 var(--site-space-7) 0; }
.publish-section h2 {
    margin: var(--site-space-4) 0 var(--site-space-3) 0;
    font-size: var(--site-type-up);
    color: var(--site-heading);
    letter-spacing: 0.02em;
}
.publish-toc {
    list-style: none;
    padding-left: var(--site-space-4);
    margin: 0;
}
.publish-toc li { padding: var(--site-space-2) 0; }
.publish-toc li a { color: var(--site-link); text-decoration: none; }
.publish-toc li a:hover { text-decoration: underline; }

/* Collapsible per-notebook entries in the folder index (native <details>). */
.publish-notebook { margin: var(--site-space-2) 0; }
.publish-notebook > summary {
    cursor: pointer;
    padding: var(--site-space-3) 0;
    font-weight: 600;
    color: var(--site-label-strong);
    list-style-position: inside;
}
.publish-notebook > summary:hover { color: var(--site-accent); }
.publish-notebook[open] > summary { color: var(--site-accent); }
.publish-notebook > .publish-toc { padding-left: var(--site-space-7); margin: 0 0 var(--site-space-4); }

/* Concat-with-divider boundary between pages */
.page-divider {
    border: 0;
    border-top: 1px dashed var(--site-rule);
    margin: var(--site-space-8) 0;
}

/* ─── Notebook site theme (page-per-file layout only) ─── */
/* Scoped to `body.site` (set by the orchestrator for page-per-file) so the
   full-bleed banner/sidebar layout never touches the concat layouts. */

/* The page's own background. Stated rather than left to the browser default,
   because a site that wants cream or charcoal has to have something to change —
   and "whatever the browser does" is not a value anyone can override. */
body.site { margin: 0; background: var(--site-page-bg); }

.site-banner {
    /* Positioning context for the background image below. Deliberately no
       `overflow: hidden` and no `z-index`: the image is inset:0 and cropped by
       `object-fit`, so it cannot overflow anyway, and either property would
       clip or re-layer the topic-search results that drop out of this bar. */
    position: relative;
    background-color: var(--site-banner-bg);
    background-image: var(--site-banner-pattern);
    color: var(--site-banner-fg);
    padding: var(--site-space-6) var(--site-space-7);
    min-height: var(--site-banner-min-height);
    /* So a bar given a real height centers what it holds instead of stacking
       it against the top edge. `.banner-inner` must then be told to fill the
       bar: as a flex ITEM it shrinks to its contents, and its `margin: 0 auto`
       — which used to center a full-width box inside the bar — started
       centring the words themselves. */
    display: flex;
    align-items: center;
}
.site-banner > .banner-inner { flex: 1 1 auto; }
/* The banner's optional background image, behind its own content. A real
   <img> rather than a CSS background, exactly like the banner: the asset
   rewriter finds images by `src`, so a background-image URL would survive
   bundling as a broken /media/ link — and the focus point rides on
   `object-position` for free. */
.banner-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
/* Optional wash between the image and the writing on it. Dark by default (the
   banner's text is light); `.pale` is the version for dark banner text. */
.banner-scrim { position: absolute; inset: 0; z-index: 0; background: var(--site-banner-scrim); }
.banner-scrim.pale { background: var(--site-banner-scrim-pale); }
/* Above the background image by document order, NOT by z-index: a z-index here
   would make this a stacking context and trap the search dropdown's z-index
   inside the bar, behind the top menu's. */
.banner-inner {
    position: relative;
    max-width: var(--site-width); margin: 0 auto; display: flex; align-items: center; gap: var(--site-space-5);
}
/* ─── A banner written as a PAGE ─── */
/* The bar's content comes from a designated page, so it is a column of blocks
   rather than a logo beside a title — headings, pictures, a band, columns. It
   takes the width, and the pieces that are GENERATED from the site sit beside
   it: the contents toggle, the topic search, the links up and out. Those cannot
   be written by hand, which is why designating a page cannot cost a site any of
   them. */
/* NO CAP when the bar is a page. The configured bar holds a logo and a title
   and wants the reading width; a page holds blocks and decides its own — a band
   asked to be full width has to reach both edges of the bar, which it cannot do
   inside a centred column. The band's own inner box still holds the WORDS to a
   readable measure, which is the same inversion the reading column uses. */
.site-banner:has(.banner-from-page) { padding: 0; }
.banner-inner.banner-from-page {
    align-items: flex-start;
    max-width: none;
    gap: 0;
}
.banner-page [data-band] { margin-block: 0; }
/* A picture with writing on it IS the bar when it is the bar — no gap under it
   and no reading column holding it in, the same inversion the band above gets.
   The block's own rules still place the writing on the picture; this is only
   about where the block's edges are.

   THE HOST IS NAMED TWICE ON PURPOSE. The general rule for the block sets a
   margin under it, and `:is(.site-content, .banner-page, …) [data-backdrop]`
   scores a class plus an attribute — the same 0,2,0 as `.banner-page
   [data-backdrop]`, and it comes later in this sheet, so a tie went to it.
   What showed was 20px of the bar's own dark ground under the picture, which
   is exactly what mb saw and called a bottom border. Adding the ancestor makes
   it 0,3,0 and settles it by specificity rather than by which line is lower. */
.site-banner .banner-page [data-backdrop],
.site-footer.site-footer-page [data-backdrop] {
    margin-block: 0;
    max-width: none;
}
.banner-page [data-band][data-full-width] > [data-band-inner] {
    max-width: var(--site-width);
    margin-inline: auto;
    padding: var(--site-space-6) var(--site-space-7);
}
/* The tools sit over the bar rather than beside it once the page takes the
   width: search and the contents toggle belong at its edge, not in a column of
   their own that the writing has to make room for. */
.banner-inner.banner-from-page > .banner-tools {
    position: absolute;
    top: var(--site-space-4);
    right: var(--site-space-5);
    z-index: 1;
}
.banner-page { flex: 1 1 auto; min-width: 0; }
.banner-page > :first-child { margin-top: 0; }
.banner-page > :last-child { margin-bottom: 0; }
/* A COLOR ON A CONTAINER NEVER REACHES THE WORDS — the bar sets its own, and a
   rule that MATCHES a heading beats one inherited from its parent. The same
   list a band has to name, and for the same reason. */
.banner-page :where(p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th, a) {
    color: inherit;
}
.banner-tools {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--site-space-4);
}

.site-logo { height: var(--site-logo-height); width: auto; display: block; flex: 0 0 auto; }
.banner-text { display: flex; flex-direction: column; gap: var(--site-space-1); }
.site-tagline { font-size: var(--site-type-xs); font-weight: 400; opacity: 0.8; }
/* Everything written in the banner inherits the banner's color, so setting
   that one color re-inks the whole bar — the point of the control, since a
   background image can be any shade. The values these replaced (#fff here,
   #dbe3f0 on the topbar links) are what the default banner still resolves to. */
.site-banner .site-title {
    color: inherit;
    font-size: var(--site-type-title);
    font-weight: 600;
    text-decoration: none;
}

/* The way up to the publication's own front page, at the left of the banner —
   a folder site only. The banner title beside it goes to THIS notebook's front
   page, which is a different place and a different question. */
.site-banner .site-up { flex: 0 0 auto; margin-right: var(--site-space-3); opacity: 0.85; }
.site-banner .site-up:hover { opacity: 1; }

/* The way OUT of a named sub-site, back to the app's front site (a link to
   '/'). A small pill, distinct from the site-up house icon (which stays inside
   this site). Self-contained via currentColor, so the same rule reads on the
   dark banner AND on the bare folder table-of-contents page (which has no
   banner): its own landing must not be the one page with no way back. */
.front-site {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--site-space-2);
    font-size: var(--site-type-xs);
    padding: var(--site-space-2) var(--site-space-4);
    border: 1px solid currentColor;
    border-radius: var(--site-radius-pill);
    opacity: 0.75;
    white-space: nowrap;
    text-decoration: none;
    color: inherit;
}
.front-site:hover { opacity: 1; }
/* The bar that carries the back-link above a bare folder table of contents. */
.toc-front-bar { margin: 0 0 var(--site-space-6); }

/* `stretch`, so a rail is as tall as the page beside it and its tint runs the
   full height. It used to be flex-start, which shrink-wrapped each rail to its
   own contents: two gray blocks ending at two different heights, which reads
   as unfinished rather than as a column. What actually needs to stay put while
   the page scrolls is the rail's CONTENTS — see `.rail-inner`. */
.site-layout {
    display: flex;
    max-width: var(--site-width);
    margin: 0 auto;
    align-items: stretch;
}
/* Which side the contents column sits on. A body class, not a token: the
   divider has to move WITH the column — a rail on the right is bounded on its
   left — and one custom property cannot say both things. Structure already
   travels this way (`topmenu`, `topics`, `nojs`), so this is the existing seam
   rather than a new one.

   Scoped above the stacking breakpoint, because the mobile block below orders
   these deliberately — content first, rails after — and an unscoped `order`
   would argue with it. */
@media (min-width: 721px) {
    body.rail-right .notebook-nav:not(.topics-rail) {
        order: 1;
        border-right: none;
        border-left: 1px solid var(--site-border);
    }
}

.notebook-nav {
    flex: 0 0 var(--site-rail);
    background: var(--site-rail-bg);
    border-right: 1px solid var(--site-border);
}
.rail-inner {
    padding: var(--site-space-7) 0;
    position: sticky;
    top: 0;
    /* The rail scrolls on its own; a full-width scrollbar down a 240px column
       is furniture. Ignored where it is not supported, which costs nothing. */
    scrollbar-width: thin;
    /* A sticky box taller than the viewport does not scroll internally and
       does not scroll away — its lower part is simply unreachable. Give it its
       own scroll: it holds the page tree AND (when on) this page's sections. */
    max-height: 100vh;
    overflow-y: auto;
}

/* "On this page" — the current page's own headings, nested inside the sidebar
   nav rather than beside it (a second .notebook-nav would be a second column).
   Indented per level so the shape of the page reads at a glance. */
.section-menu { margin-top: var(--site-space-6); border-top: 1px solid var(--site-border); padding-top: var(--site-space-5); }
/* A sub-head inside the Contents rail, not a third rail head: same face and
   tracking as `.rail-head` so the column reads as one thing, but no dot and no
   bold — it is subordinate to the head above it, and looking identical would
   claim otherwise. */
.section-menu-head {
    padding: 0 var(--site-space-7) var(--site-space-3);
    font-size: var(--site-type-micro);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--site-rail-head);
}
.section-menu ul { list-style: none; margin: 0; padding: 0; }
.section-menu li a { display: block; padding: var(--site-space-2) var(--site-space-7); font-size: var(--site-type-sm); }
/* A real tree now, indented by nesting rather than by a padding class per
   heading tag — so the depth follows the document instead of being asserted
   five times in CSS. Matches the page list's step above it. */
.section-menu ul ul { padding-left: var(--site-space-5); }
/* The page list's chevron rules (.notebook-nav summary…) already reach these:
   the section menu nests INSIDE that nav. Only the sizing differs — these rows
   are smaller than a page's, and a summary must not stand taller than the
   links either side of it. */
.section-menu summary {
    padding: var(--site-space-2) var(--site-space-7) var(--site-space-2) var(--site-space-3);
    font-size: var(--site-type-sm);
}
.section-menu summary a { font-size: inherit; padding: 0; }
/* The topic side is 3-column: alphabet (left) · content · Related Topics
   (right). Give it a little more width, and put the right rail's divider on
   its left edge since it sits on the right. Keyed on the LAYOUT, not on
   `body.topics`: a notebook page in topics mode is two columns, and the wide
   box would leave it sitting left of center with a dead band beside it. */
.site-layout-wide { max-width: var(--site-width-wide); }
.notebook-nav.topics-rail {
    border-right: none;
    border-left: 1px solid var(--site-border);
}
/* Both rails use the sans-serif heading face (body copy is serif), so the
   navigation reads as chrome, distinct from the reading column. */
.notebook-nav { font-family: var(--site-font-chrome); }
/* Both rails are headed the same way — see `.rail-head` below. The head used
   to be hidden outside topics mode, on the grounds that a lone rail needs no
   label to tell it from the one opposite. It is kept in both modes now,
   because it no longer labels the whole rail: Home sits above it, so what it
   names is the page list under it. */
.notebook-nav ul { list-style: none; margin: 0; padding: 0; }
/* Home sits ABOVE the Contents head — it is where the site starts, not the
   first of its pages — so it is a link in its own right rather than a row of
   the list. Inset to the gutter like the head below it, and ruled off, so the
   rail reads as three bands: where you start · the label · the pages. */
.notebook-nav .rail-home {
    display: block;
    margin: 0 var(--site-space-7) var(--site-space-6);
    padding-bottom: var(--site-space-4);
    border-bottom: 1px solid var(--site-border);
    color: var(--site-text-muted);
    text-decoration: none;
    font-size: var(--site-type-lg);
}
.notebook-nav .rail-home:hover { color: var(--site-nav-hover); }
.notebook-nav .rail-home.active { color: var(--site-nav-active); font-weight: 600; }
.notebook-nav li a {
    display: block;
    padding: var(--site-space-4) var(--site-space-7);
    color: var(--site-text-muted);
    text-decoration: none;
    font-size: var(--site-type-lg);
    /* Titles in this list are often long enough to wrap — several of them at
       once, in a column 240px wide. Tight leading INSIDE a row and air BETWEEN
       rows is what keeps a wrapped title reading as one entry instead of the
       whole list reading as ragged prose. */
    line-height: 1.35;
}
.notebook-nav li a:hover { background: var(--site-hover-bg); color: var(--site-nav-hover); }
.notebook-nav li.active a {
    color: var(--site-nav-active);
    font-weight: 600;
}
/* One continuous bar down the active section (its whole subtree), drawn as an
   inset shadow so it neither shifts the text nor fragments into a per-item,
   per-indent staircase the way a border on each link did. The faint wash under
   it is what makes "you are here" legible at a glance: weight alone is a
   difference you have to compare rows to notice. */
.notebook-nav li.active {
    box-shadow: inset 3px 0 0 var(--site-active-bar);
    background: var(--site-hover-bg);
}
/* Outline tree: each nesting level indents one step further, with a hairline
   spine down the group. The same idiom a topic page uses for a page's
   sections, so a branch means the same thing in both places. */
.notebook-nav ul ul {
    margin-left: var(--site-space-7);
    padding-left: 0;
    border-left: 1px solid var(--site-border);
}
.notebook-nav ul ul li a {
    padding-left: var(--site-space-5);
    font-size: var(--site-type-md);
    color: var(--site-text-soft);
}
/* Collapsible sections (parents with children) — JS-free <details>.
   A parent's title stays a link to its own page, so the TRIANGLE is the only
   thing that can expand it — and it has to be drawn here, because
   `list-style-type` inherits: the `list-style: none` on the list above reaches
   the <summary> (a display:list-item) and takes its native marker with it.
   Same reason .page-topics draws its own; same chevron, so the two disclosures
   on a page look like one idea. Sized and padded to be a real target rather
   than a decoration beside the link. */
.notebook-nav summary {
    cursor: pointer;
    padding: var(--site-space-4) var(--site-space-7) var(--site-space-4) var(--site-space-3);
    font-size: var(--site-type-lg);
    color: var(--site-text-muted);
    /* NOT display:flex. Changing a <summary>'s display can stop some engines
       treating it as the disclosure widget at all — the branch then never
       opens, whatever the markup says. `.page-topics` below has drawn its
       chevron this way for as long as it has worked; copy the thing that
       works. The cost is that a wrapped title runs back under the chevron
       instead of hanging indented, which is what `.page-topics` does too. */
    list-style: none;
}
.notebook-nav summary::-webkit-details-marker { display: none; }
.notebook-nav summary::before {
    content: "▸";
    display: inline-block;
    width: 0.9em;
    margin-right: var(--site-space-2);
    color: var(--site-text-faint);
    font-size: var(--site-type-xs);
    transition: transform 0.15s ease;
}
.notebook-nav details[open] > summary::before { transform: rotate(90deg); }
.notebook-nav summary:hover { background: var(--site-hover-bg); }
.notebook-nav summary:hover::before { color: var(--site-link); }
.notebook-nav summary a {
    display: inline;
    padding: 0;
    font-size: inherit;
}
.notebook-nav ul ul summary { font-size: var(--site-type-md); }
.notebook-nav li.active > details > summary a { color: var(--site-nav-active); font-weight: 600; }

/* Contents-page table of contents, rendered as the same outline tree. */
.notebook-toc, .notebook-toc ul { list-style: none; }
.notebook-toc { padding-left: 0; margin: var(--site-space-4) 0; }
.notebook-toc ul { padding-left: var(--site-space-6); }
.notebook-toc li { padding: var(--site-space-2) 0; }
.notebook-toc a { text-decoration: none; color: var(--site-link); }
.notebook-toc a:hover { text-decoration: underline; }

/* A placed list of pages FOLDS, the way the side panel's outline does — the
   same <details> from the same function. The chevron has to be drawn here
   though: the sidebar's rules are scoped to `.notebook-nav`, and this list
   lives in the reading column. NOT display:flex on the summary — changing a
   summary's display can stop an engine treating it as the disclosure widget at
   all, and the branch then never opens whatever the markup says. Same note as
   the sidebar's, and the same reason. */
.page-list summary { cursor: pointer; list-style: none; }
.page-list summary::-webkit-details-marker { display: none; }
.page-list summary::before {
    content: "▸";
    display: inline-block;
    width: 0.9em;
    margin-right: var(--site-space-2);
    color: var(--site-text-faint);
    font-size: var(--site-type-xs);
    transition: transform 0.15s ease;
}
.page-list details[open] > summary::before { transform: rotate(90deg); }
.page-list summary:hover::before { color: var(--site-link); }
/* Inside a CARD the branch is a second thing in the tile, so it says what it
   holds rather than repeating the page's own name. */
.page-list .toc-branch > summary {
    font-size: var(--site-type-md);
    color: var(--site-text-dim);
    margin-top: var(--site-space-2);
}
.page-list .toc-branch ul, .page-list .toc-branch ul ul {
    list-style: none;
    margin: var(--site-space-1) 0 0;
    padding-left: var(--site-space-4);
}

/* THE READING MEASURE IS ON THE BLOCKS, NOT ON THE COLUMN.
   The column used to be capped and padded, and everything inside it followed.
   That reads the same and cannot be escaped: a picture meant to span the page
   would have to break out of its own container with a negative margin measured
   in `vw`, which counts the scrollbar, is wrong wherever the column is not
   centered in the window (any page with a rail), and has to out-shout an inline
   width the editor wrote as somebody dragged.
   Inverted, a block that spans the page is simply a block with no cap — and the
   measure, the padding and the centering are each block's own. It is the idiom
   the chrome has always used: `.site-banner` is full width with
   `.banner-inner` holding the reading measure inside it.
   The numbers are unchanged. `box-sizing: border-box` is global, so a block
   capped at the measure with the old padding inside it holds exactly the text
   width it held before. */
.site-content {
    flex: 1 1 auto;
    /* The side padding stays here, as the GUTTER — what keeps writing off the
       edge of a narrow window. It is the one thing that is still the column's. */
    padding: var(--site-space-7) var(--site-gutter);
    max-width: none;
}
/* Each block holds the reading measure itself, and centers itself in whatever
   room there is. The number is the measure LESS the gutter, because the gutter
   is now outside the block rather than inside the cap — so a paragraph, a
   table and a picture all come out exactly as wide as they were. */
.site-content > * {
    max-width: var(--site-measure-inner);
    margin-inline: auto;
}
/* A picture and a table each carry a `max-width` of their own further down, and
   an element selector beats `> *`, so they say the measure for themselves. */
.site-content > img, .site-content > table { max-width: var(--site-measure-inner); }
/* A picture is an INLINE thing, and an auto margin does not center one: it
   computes to zero, so a picture narrower than the measure sat against the
   gutter rather than where the writing starts. This is the distance from the
   edge of the column to the edge of the writing, which it had for nothing while
   the column itself was the measure. An author's own centering is written
   inline by the editor and still wins. */
.site-content > img {
    margin-left: max(0px, calc((100% - var(--site-measure-inner)) / 2));
}
/* And the whole point: the gutter given back, so the block reaches both edges of
   whatever it stands in. The negative margin is not the `100vw` breakout this
   design exists to avoid — it cancels a padding of known size on its own
   parent, so it is right beside a rail and needs no scrollbar tricks.
   The width is stated rather than merely uncapped: `max-width: none` on a
   PICTURE means "as wide as the file", and a 2266-pixel photograph then pushed
   the whole page out to 2266 pixels and took the reading column with it.
   Only a direct child is reached, which is what keeps a marked picture inside a
   column or a table cell exactly where it is — there is no whole width to take
   in a third of the page. */
.site-content > [data-full-width] {
    display: block;
    max-width: none;
    width: calc(100% + 2 * var(--site-gutter));
    margin-inline: calc(-1 * var(--site-gutter));
}
.site-content img { max-width: 100%; height: auto; }
.site-content h1:first-child, .site-content h2:first-child { margin-top: 0; }

/* ─── Writing side by side ─── */
/* Flex rather than grid, because a column's width belongs to the COLUMN. Flex
   distributes per child, so each one states its share relative to its siblings
   and the block holds nothing — where grid would need a track list on the
   block, a second copy of how many columns there are and what each is worth.
   Two earlier versions stored that kind of number and both drifted: empty a
   column and it is removed (a column may not be empty), while the stored count
   went on drawing a track that held nothing.
   Shares are RATIOS, never widths. A ratio means the same in a wide editing
   pane and a narrow published column; a width means two different things, which
   is why there is no dragging.
   The one automatic behavior is the collapse below, which is what makes a
   column layout survive a phone without the author thinking about it. */
/* COLUMNS ARE NOT ONLY A READING-COLUMN BLOCK any more: a footer is columns
   of links, which is what mb asked the footer to become. Scoped to
   `.site-content` alone they simply stacked there — the same trap the
   picture-with-writing block was in, found the same way, by measuring a built
   page and seeing two columns at the same left edge. */
:is(.site-content, .banner-page, .site-footer-page) [data-columns] {
    display: flex;
    gap: var(--site-space-6);
    /* `margin-block`, not the shorthand: the inline margins are what center a
       block in the reading column now (see `.site-content > *`). */
    margin-block: 0 var(--site-space-6);
}
/* `flex-basis: 0`, not `auto`: the shares divide the ROW, not whatever happens
   to be written in each column. `min-width: 0` is the same guard from the other
   side, so a long word or a wide picture cannot push a column past its share. */
:is(.site-content, .banner-page, .site-footer-page) [data-column] { flex: 1 1 0; min-width: 0; }
:is(.site-content, .banner-page, .site-footer-page) [data-column][data-column-share="2"] { flex: 2 1 0; }
:is(.site-content, .banner-page, .site-footer-page) [data-column] > :first-child { margin-top: 0; }
/* PADDING ARRIVES WITH A BACKGROUND, and only then. A column has never had any
   here, so giving every column padding would move the writing on every
   two-column layout already published — to serve the one column that has just
   been tinted. Keyed on the attribute, the tinted column gets room to breathe
   and its plain neighbor does not move at all.
   The color itself is written inline on the column by the editor, as the share
   is written as an attribute: nothing in this stylesheet needs to know which
   color, only that there is one. */
:is(.site-content, .banner-page, .site-footer-page) [data-column][data-column-bg] {
    padding: var(--site-space-6);
    border-radius: var(--site-radius-sm);
}

/* ─── A band: writing on a ground of its own ─── */
/* The one thing the chrome has always been made of and a page never could be: a
   banner is a band, a footer is a band. Two elements, and the separation is
   the whole trick — the band carries the ground and may span the page, the
   inner box holds the reading measure inside it. `.site-banner`/`.banner-inner`
   is that shape; this is the same shape made available to a page. */
.site-content [data-band] { margin-block: 0 var(--site-space-6); }
/* Padding only where there is a ground to keep the writing off the edge of. */
.site-content [data-band][data-band-bg] > [data-band-inner] {
    padding: var(--site-space-7) var(--site-gutter);
}
/* Spanning the page is the band's; the reading measure is the inner box's.
   Without this a band across the window would drag its writing across the
   window with it. */
.site-content [data-band][data-full-width] > [data-band-inner] {
    max-width: var(--site-measure-inner);
    margin-inline: auto;
}
.site-content [data-band] > [data-band-inner] > :first-child { margin-top: 0; }
.site-content [data-band] > [data-band-inner] > :last-child { margin-bottom: 0; }
/* A color on a container never reaches the words: the rule that MATCHES a
   paragraph wins over one inherited from its parent. Twin of the column rule
   below, and the reason a band's color has to name the elements it dresses.
   `a` IS ON THAT LIST: left off it, a link kept the site's link color, so a
   white-on-dark band published blue links nobody could read. Nothing is added
   to mark the link in exchange — mb, 2026-08-31: the pointer turning to a hand
   is enough, and underlining every link on a band is too much to impose. */
.site-content [data-band][data-band-fg] :where(p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th, a) {
    color: inherit;
}

/* ─── A picture with writing on it ─── */
/* THREE PLACES, not one. The block is written in a page, and it is also what
   the site's banner and footer are written as — mb's words for that dialog:
   "the same interface as for image with text, except that the image format is
   wide". So every rule below names all three hosts, spelt out rather than
   shortened: this sheet is one plain string, `{` in an f-string would have to
   be doubled everywhere, and a prefix that cost that is a prefix that would go
   wrong. What the rules DO is put the writing on the picture; scoped to
   `.site-content` alone, a banner's words fall below its photograph.
   `.banner-page` and `.site-footer-page` are `layouts.py`'s own class names. */

/* Everything stacks in one grid cell, so the block is as tall as the tallest
   thing in it — normally the picture at its own proportions. The picture is an
   <img> rather than a CSS background, so the asset pass bundles and rewrites it
   like any other; a URL in a style string is one that pass never reads, and it
   would be missing from every download.
   The writing is a property of the picture, typed in a dialog rather than over
   the photograph, which is why nothing here dims the picture or boxes the
   words: both of those existed to make typing possible against an image. A
   shadow holds white words against anything. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] {
    display: grid;
    overflow: hidden;
    /* `margin-block`: the inline margins center it — see `.site-content > *`. */
    margin-block: 0 var(--site-space-6);
    /* The writing is placed against this block by percentage, dragged there in
       the editor's dialog, so the block is what the percentage measures. */
    position: relative;
    /* The writing is sized in `cqw` — a share of THIS block's width — so a size
       chosen on a desktop is not four words to a line on a phone. Without this
       the unit falls back to the viewport and every line comes out huge. */
    container-type: inline-size;
}
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > * { grid-column: 1; grid-row: 1; }
/* A LOGO ON THE PICTURE. Everything it needs is carried inline by the node —
   where it sits, how wide it is — because that is the author's answer and not
   a rule. What belongs here is only what is true of every logo: it keeps its
   own proportions, and it never stretches to the box it is given. A logo
   squashed to fit is a logo nobody recognizes. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > img[data-backdrop-logo] {
    height: auto;
    object-fit: contain;
    max-width: 100%;
}
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > img[data-backdrop-image] {
    width: 100%;
    object-fit: cover;
    /* A grid item will not shrink below its own intrinsic size unless it is
       told it may: without this a picture taller than the shape chosen for it
       pushes the block past that shape. */
    min-height: 0;
}
/* A shape means the block has a height of its own, so the picture takes it and
   object-fit crops to it. With no shape the block is as tall as the picture,
   and the picture has to be left to say so. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop][data-backdrop-shape] > img[data-backdrop-image] {
    height: 100%;
}
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop]:has(> img[data-backdrop-image]) {
    color: var(--site-hero-fg);
}
/* Buttons on a picture inside a page. They are the SAME object as the front
   page's opening buttons — same `.btn` classes, defined once above — because
   they are authored with the same control and mean the same thing. All that is
   needed here is the row they sit in; how they line up is written inline by the
   editor, from the same choice that lines up the writing over them. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop-button],
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop-buttons] .btn {
    /* The writing's shadow does not carry onto a button: it holds white words
       against a photograph, and a button has a ground of its own. Asked for, it
       is written back inline by the editor. */
    text-shadow: none;
}
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop-buttons] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--site-band-1);
    margin-top: var(--site-space-6);
}

/* The wash that dims the picture: a layer in the same grid cell, after the
   picture and before the words, so it dims the one and not the other. */
/* Laid OVER the picture rather than placed in the grid beside it: an empty
   element in a grid has nothing of its own to be as big as, and depends on the
   row to stretch it. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > [data-backdrop-wash] {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
/* Width that does not depend on position: these are placed with a `left` and no
   `right`, and such a box takes whatever room is left between it and the far
   edge — so a button pushed to the right had its label broken onto two lines by
   nothing but its position. As wide as what is in it, wherever it is. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > [data-backdrop-body],
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > [data-backdrop-line],
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > [data-backdrop-button] {
    width: max-content;
    box-sizing: border-box;
}
/* The block is held inside the picture; a line or a button standing on its own
   is not — held to the picture's width, a big title wraps, fills it, and can
   then only be moved up and down. */
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > [data-backdrop-body] { max-width: 100%; }
:is(.site-content, .banner-page, .site-footer-page) [data-backdrop] > [data-backdrop-body] {
    position: absolute;
    padding: var(--site-space-6);
    line-height: 1.25;
    text-shadow: var(--site-backdrop-shadow);
}

/* ─── A captioned image ─── */
/* The editor's Figure node renders <figure><img><div data-figcaption>, the div
   holding the caption. Both selectors are named because the same page can also
   carry a hand-written <figure><figcaption> from HTML source mode, and a
   caption that reads on one and not the other would be a trap.
   No preset styles figcaption at all, so this is the only rule it gets; it
   sits here, with .pdf-page, because both dress a figure the pipeline knows
   about rather than the reading column a preset owns. */
.site-content figure { margin-block: 0 var(--site-space-6); }
.site-content figure img { display: block; }
.site-content figcaption {
    font-size: var(--site-type-md);
    line-height: 1.45;
    padding-top: 0.4em;
    color: var(--site-text-muted);
}

/* ─── A rendered PDF page, above the text extracted from it ─── */
/* The sheet carries a light border rather than a drop shadow: the shadow is a
   reading-app affordance for a document floating over a workspace, and a
   published page is not floating over anything. The text of the page follows
   it in the flow, which is why the spacing below is larger than above. */
.site-content .pdf-page { margin-block: 0 var(--site-space-8); }
.site-content .pdf-page img {
    display: block;
    width: 100%;
    border: 1px solid var(--site-border-strong);
    border-radius: var(--site-radius-sm);
    background: var(--site-surface);
}

/* ─── Collapsible table of contents (pure-CSS hamburger toggle) ─── */
/* The #toc-toggle checkbox is the FIRST thing in the body; its
   <label class="toc-toggle-btn"> lives in the banner after it. Default state
   (unchecked) shows the sidebar on desktop; checking it collapses the
   sidebar so the content spans full width. The mobile breakpoint below
   flips the default (collapsed) and the checked state (expanded). */

/* Hidden to the eye, NOT to the keyboard. It carried the `hidden` attribute,
   which takes an element out of the tab order — and a <label> is not tabbable
   either, so there was no way to open or close the drawer without a pointer.
   Clipped instead of removed, so it still takes focus. */
.toc-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
/* …and the focus has to be VISIBLE somewhere. It lands on a clipped control,
   so the ring is drawn on the label instead — which is why the checkbox now
   precedes the banner rather than following it: a sibling selector only
   reaches forwards. */
.toc-toggle:focus-visible ~ .site-banner .toc-toggle-btn {
    outline: 2px solid var(--site-banner-fg);
    outline-offset: 2px;
}
.toc-toggle-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9em;
    height: 1.9em;
    margin-right: var(--site-space-1);
    font-size: var(--site-type-up);
    line-height: 1;
    color: inherit;
    cursor: pointer;
    border-radius: var(--site-radius-sm);
    user-select: none;
}
.toc-toggle-btn:hover { background: var(--site-banner-hover-bg); }
.toc-toggle:checked ~ .site-layout .notebook-nav:not(.topics-rail) { display: none; }
/* With the rail closed the reading column should take the space it freed.
   The `:only-child` rule that centers a lone column cannot do this: the rail
   is display:none but still a CHILD, so it never matched, and closing the
   drawer left the text against the left edge with a dead band beside it. */
.toc-toggle:checked ~ .site-layout > .site-content { margin: 0 auto; }

.site-footer {
    border-top: 1px solid var(--site-border);
    color: var(--site-text-dim);
    font-size: var(--site-type-sm);
    text-align: center;
    padding: var(--site-space-7);
}
.site-footer a { color: var(--site-accent); }
/* A foot written as a PAGE holds blocks, not one small line, so it is given the
   reading width and left aligned as writing is. It keeps the rule above it and
   the quiet color: it is still the foot of the page, whoever wrote it. */
.site-footer-page {
    text-align: left;
    font-size: inherit;
}
.site-footer-page > * { max-width: var(--site-width); margin-inline: auto; }
.site-footer-page > :first-child { margin-top: 0; }
.site-footer-page > :last-child { margin-bottom: 0; }

@media (max-width: 720px) {
    /* Side by side stops being side by side. This is the whole responsive
       story for columns: no author sets it, and it is the same breakpoint the
       chrome already stacks at, so a page does not reorganise itself twice on
       the way down. */
    :is(.site-content, .banner-page, .site-footer-page) [data-columns] { flex-direction: column; }

    /* Topbar wraps: logo + title on the first line, the nav (search / Topics /
       Contents / Home) on a full-width second line, with the search box
       flexing to fill the row instead of overflowing the page. */
    .site-banner { padding: var(--site-space-5) var(--site-space-6); }
    .banner-inner { flex-wrap: wrap; }
    .topbar-nav { margin-left: 0; width: 100%; margin-top: var(--site-space-4); gap: var(--site-space-5); }
    .topic-search { flex: 1 1 auto; }
    .topic-search input { width: 100%; max-width: none; }

    .site-layout { flex-direction: column; }
    .notebook-nav {
        flex-basis: auto;
        width: 100%;
        border-right: none;
        border-bottom: 1px solid var(--site-border);
    }
    /* Stacked, a rail is above or below the content rather than beside it, so
       there is nothing for it to stay level with — and a sticky box with a
       100vh cap would eat the screen. */
    .rail-inner { position: static; max-height: none; overflow-y: visible; }
    /* Mode 1 (no topics): the page-list sidebar collapses behind the ☰ toggle
       on mobile — hidden by default, shown when toggled. */
    body:not(.topics) .notebook-nav { display: none; }
    body:not(.topics) .toc-toggle:checked ~ .site-layout .notebook-nav { display: block; }
    /* Mode 2: content first, then the Related-Topics rail, then the ToC — all
       stacked full-width and visible below the content (the ☰ toggle can still
       collapse the ToC via the global checked rule). */
    .notebook-nav.topics-rail { border-left: none; }
    body.topics .site-content { order: -2; }
    body.topics .notebook-nav.topics-rail { order: -1; }
    /* Neutralizes the no-rail `margin: 0 auto` centering, and pins the main
       column full-width in the stacked layout. */
    .site-content { width: 100%; max-width: none; }
    /* The desktop rule reserves the missing right rail's width; stacked, there
       is no rail beside anything and the reserve would just overflow. */
    .site-layout > .topic-page-content:last-child { margin-right: 0; }
    .topic-index-list { column-width: auto; }

    .doc-nav .docnav-row { padding: var(--site-space-3) var(--site-space-6); }
    /* The gutter narrows on a phone, and the TOKEN is what narrows — a
       full-width block gives back exactly this much, so a hard-coded padding
       here would have it escape by the difference and put a sideways scrollbar
       on every page. */
    .site-content { --site-gutter: 1.25rem; padding: var(--site-gutter); }
}

/* ─── Buttons on a picture, and the cards of a Featured Links block ─── */

/* The border is on `.btn`, transparent, rather than on `.btn-secondary` alone.
   These are inline-blocks with no width, so `box-sizing` settles nothing: a
   border on one look and not the other made the outlined buttons 3px taller
   and wider than the button beside them. Two buttons in a row that do not
   agree on their own size is most of what "unstyled" looks like. */
.btn {
    display: inline-block; padding: var(--site-band-1) var(--site-band-3); border-radius: var(--site-radius-lg);
    font-size: var(--site-type-base); font-weight: 600; letter-spacing: 0.01em;
    text-decoration: none; border: 1.5px solid transparent;
    transition: background-color 0.15s ease, border-color 0.15s ease,
                box-shadow 0.15s ease, transform 0.15s ease;
}
.btn-primary {
    background: var(--site-btn-primary-bg); color: var(--site-btn-primary-fg);
    box-shadow: var(--site-btn-shadow);
}
.btn-secondary {
    border-color: var(--site-btn-secondary-border);
    color: var(--site-btn-secondary-fg);
}
/* A button that does not answer the pointer reads as a picture of a button.
   The fallbacks matter: an unsupported color-mix leaves the custom property
   invalid, and a background reading an invalid property with nothing behind it
   computes to transparent — a button that vanishes under the cursor. */
.btn:hover { transform: translateY(-1px); }
.btn-primary:hover {
    background: var(--site-btn-primary-hover-bg, var(--site-btn-primary-bg));
    box-shadow: var(--site-btn-shadow-hover);
}
.btn-secondary:hover {
    background: var(--site-btn-secondary-hover-bg, transparent);
}
/* The lift is the only thing here that MOVES, so it is the only thing that has
   to be withdrawn. The color changes stay: they are what says "this answers
   the pointer", and nobody asked for a page that stops responding. */
@media (prefers-reduced-motion: reduce) {
    .btn { transition: background-color 0.15s ease, border-color 0.15s ease; }
    .btn:hover { transform: none; }
}

.contents-grid { display: grid; grid-template-columns: repeat(3, 1fr); column-gap: var(--site-band-3); row-gap: var(--site-band-2); }
.toc-item { border-top: 1px solid var(--site-border); padding-top: var(--site-band-1); }
.toc-title {
    display: inline-block; font-size: var(--site-display-sm); font-weight: 600;
    color: var(--site-accent); text-decoration: none; margin-bottom: var(--site-band-1);
}
.toc-title:hover { text-decoration: underline; }
.toc-desc { display: block; font-size: var(--site-type-md); color: var(--site-text-dim); }

@media (max-width: 820px) {
    .contents-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
    .contents-grid { grid-template-columns: 1fr; }
}

/* ─── Topics (publish mode 2: "pages + topics") ─── */

/* ── The two rails ────────────────────────────────────────────────────────
   A topics page has a column either side of the reading column: Contents on
   the left, Topics on the right. They are two lists of links doing the same
   job at the same size, and they were built differently — one head was
   generated text on a list, the other an element in a panel; one row was a
   full-width link with a hover wash, the other a bare line with none. Read
   together, which is the only way they are ever read, that looked like two
   components that happened to be adjacent.

   One head treatment, one row rhythm, one hover. What still differs between
   them is what they SAY, which is the difference worth seeing. */

.rail-head {
    display: flex;
    align-items: center;
    gap: var(--site-space-3);
    /* The rail's gutter, one step wider than the old 1.25em. It is a MARGIN
       rather than padding so the hairline below stops at the same inset as
       the words — a rule running edge to edge under an indented label reads as
       a divider between two things rather than as the label's own underline. */
    margin: 0 var(--site-space-7) var(--site-space-6);
    padding-bottom: var(--site-space-4);
    border-bottom: 1px solid var(--site-border);
    font-size: var(--site-type-micro);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--site-rail-head);
}
/* The same functional dot the topic page's section headings carry, reading in
   the app's own color code: Contents is pages, so it keeps the neutral
   marker; a list of topics is amber; and the related list on a topic page is
   purple, because those are connections rather than the page's own topics.
   Three rails, three answers to "what am I looking at". */
.rail-head::before {
    content: "";
    flex: 0 0 auto;
    width: 0.55em;
    height: 0.55em;
    border-radius: var(--site-radius-pill);
    background: var(--site-marker);
}
.topics-rail .rail-head::before,
.topics-nav .rail-head::before { background: var(--site-family-topics); }
.topics-panel-related .rail-head::before { background: var(--site-family-connections); }

/* The panel no longer holds the rows' horizontal padding: the rows do, so a
   hover reaches the full width of the rail the way the page list's does. The
   head keeps its own padding, above. */
.topics-panel { padding: 0; }
/* ─── Topbar nav (banner right side): Search · Contents · Home ─── */
.topbar-nav {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--site-space-5);
}
/* Dimmed banner color rather than a fixed near-white, so these follow a
   custom banner text color instead of staying pale blue on top of it. */
.topbar-link {
    color: inherit;
    opacity: 0.82;
    text-decoration: none;
    font-size: var(--site-type-lg);
    white-space: nowrap;
    /* Padded so the hover tint below has something to fill: a background on
       bare text hugs the letters and reads as a highlighter pen. */
    padding: var(--site-space-2) var(--site-space-3);
    border-radius: var(--site-radius-sm);
}
/* A tint rather than an underline. The bar is a set of destinations, and the
   thing under the pointer should look pressable — which is also what the
   contents toggle beside it does, through the same token. */
.topbar-link:hover { opacity: 1; background: var(--site-banner-hover-bg); }
.topbar-home {
    display: inline-flex;
    align-items: center;
    color: inherit;
    opacity: 0.82;
}
.topbar-home:hover { opacity: 1; }

/* Topic-name search box on the topbar; results drop down over the page. */
.topic-search { position: relative; }
.topic-search input {
    width: 200px;
    max-width: 46vw;
    box-sizing: border-box;
    padding: var(--site-space-3) var(--site-space-4);
    font-size: var(--site-type-md);
    border: 1px solid transparent;
    border-radius: var(--site-radius-sm);
    background: var(--site-surface);
    color: var(--site-input-fg);
}
.topic-search input:focus { outline: none; border-color: var(--site-accent); }
.topic-search-results {
    list-style: none;
    margin: 0;
    padding: 0;
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    /* Out of the bar, so it is the bar's drop-down like the other one — same
       token, same reason, and found at the same time. */
    background: var(--site-submenu-bg);
    border: 1px solid var(--site-border-strong);
    border-radius: var(--site-radius-sm);
    box-shadow: 0 6px 18px var(--site-shadow);
    max-height: 60vh;
    overflow-y: auto;
    z-index: 20;
}
.topic-search-results:empty { display: none; }
.topic-search-results li a {
    display: block;
    padding: var(--site-space-3) var(--site-space-4);
    color: var(--site-link);
    text-decoration: none;
    font-size: var(--site-type-md);
}
.topic-search-results li a:hover { background: var(--site-hover-bg); }
.topic-search-results .topic-search-empty {
    padding: var(--site-space-3) var(--site-space-4);
    color: var(--site-text-hint);
    font-size: var(--site-type-sm);
    font-style: italic;
}

/* A–Z bar at the top of each index page's content (NOT the sidebar): only the
   letters that have topics, the current one highlighted. */
.topic-alpha-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--site-space-2) var(--site-space-3);
    margin: 0 0 var(--site-space-7);
    padding-bottom: var(--site-space-5);
    border-bottom: 1px solid var(--site-border);
}
.topic-alpha-bar a {
    display: inline-block;
    min-width: 1.7em;
    text-align: center;
    padding: var(--site-space-2) var(--site-space-3);
    font-weight: 600;
    color: var(--site-link);
    text-decoration: none;
    border-radius: var(--site-radius-sm);
}
.topic-alpha-bar a:hover { background: var(--site-hover-bg); }
.topic-alpha-bar a.active { background: var(--site-accent); color: var(--site-accent-fg); }

/* In the left rail the alphabet sets as a block of letters rather than a bar
   across the page: 220px fits five or six per row, and the rule under it is
   the rail's own divider, not a page rule. */
.topics-nav .topic-alpha-bar {
    gap: var(--site-space-2) var(--site-space-2);
    /* The panel's own inset moved onto the rows, so the pieces that are NOT
       rows carry it themselves. */
    margin: 0 var(--site-space-6) var(--site-space-5);
    padding-bottom: var(--site-space-5);
}
.topics-nav .topic-index-link { padding: 0 var(--site-space-6); }
.topics-nav .topic-alpha-bar a { min-width: 1.5em; font-size: var(--site-type-md); }
.topic-index-link {
    display: block;
    font-size: var(--site-type-sm);
    color: var(--site-link);
    text-decoration: none;
}
.topic-index-link:hover { text-decoration: underline; }

/* A letter page is a list of names, not reading matter: it takes the whole
   layout rather than the 760px reading measure, sets in columns so 400 terms
   are scanned rather than scrolled, and says how many there are. */
.topic-index-page { max-width: none; }
.topic-index-count {
    margin: -0.2em 0 var(--site-space-7);
    font-family: var(--site-font-chrome);
    font-size: var(--site-type-xs);
    color: var(--site-text-dim);
}
.topic-index-list {
    column-width: 12rem;
    column-gap: var(--site-band-3);
    padding-left: 0;
}
.topic-index-list li { break-inside: avoid; padding: var(--site-space-2) 0; }

/* When a page has no rail, every block centers itself (`.site-content > *`),
   so the column can span the whole window — which is what lets a full-width
   block reach both edges. With a rail the layout stays capped: the rail has to
   stay where it is, and a full-width block spans the region beside it. */
.site-layout:has(> .site-content:only-child) { max-width: none; }

/* Topic pages + topic index reuse the banner/footer chrome. */

/* The topic title. No bare h1 rule exists (content headings belong to the
   export CSS, which users override), so this is scoped to the generated topic
   column — a topic title is chrome we author, not content someone wrote. */
/* A topic with no related topics has no right rail. Reserve its width anyway,
   so the layout box stays balanced and the reading column sits where it does
   on a topic that has one — the whole point of the left rail is that the title
   never moves. */
.site-layout > .topic-page-content:last-child { margin-right: var(--site-rail); }

.topic-page-content > h1 {
    font-size: var(--site-display-lg);
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--site-heading);
    margin: 0 0 var(--site-space-4);
}

/* About, Synonyms, References and Weblinks used to be the same object four
   times — same ground, same indent, same disc. The heading is now a quiet
   uppercase label carrying its family's dot, and each section sets its
   contents in its own rhythm below. */
.topic-section { margin: var(--site-space-8) 0 0; }
.topic-section h2 {
    display: flex;
    align-items: center;
    gap: var(--site-space-4);
    margin: 0 0 var(--site-space-5);
    padding-bottom: var(--site-space-3);
    font-family: var(--site-font-chrome);
    font-size: var(--site-type-micro);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--site-rail-head);
    border-bottom: 1px solid var(--site-border);
}
.topic-section h2::before {
    content: "";
    flex: 0 0 auto;
    width: 0.62em;
    height: 0.62em;
    border-radius: var(--site-radius-pill);
    background: var(--site-marker);
}
.topic-about h2::before { background: var(--site-family-topics); }
.topic-synonyms h2::before { background: var(--site-family-names); }
.topic-refs h2::before { background: var(--site-family-references); }
.topic-links h2::before { background: var(--site-family-references); }

/* About is prose: it reads at body rhythm, with nothing decorating it. */
.topic-about { color: var(--site-text); }
.topic-about > :first-child { margin-top: 0; }

/* Synonyms are labels, not a list of things to go to — inline chips, so a
   dozen of them take one band rather than a dozen lines. */
.topic-synonyms-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--site-space-3);
    list-style: none;
    margin: 0;
    padding: 0;
}
.topic-synonyms-list li {
    padding: var(--site-space-1) var(--site-space-4);
    font-size: var(--site-type-md);
    color: var(--site-text-muted);
    background: var(--site-rail-bg);
    border: 1px solid var(--site-border);
    border-radius: var(--site-radius-pill);
}

/* References and Weblinks are ruled lists: one hairline per placement, so the
   eye can count them. A page's sections hang under it as a lighter branch. */
.topic-references, .topic-weblinks { list-style: none; margin: 0; padding: 0; }
.topic-references > li, .topic-weblinks > li {
    padding: var(--site-space-4) 0;
    border-top: 1px solid var(--site-border-soft);
}
.topic-references > li:first-child, .topic-weblinks > li:first-child { border-top: none; }
.topic-references a, .topic-weblinks a { color: var(--site-link); text-decoration: none; }
.topic-references a:hover, .topic-weblinks a:hover { text-decoration: underline; }
.topic-reference-page > a { font-weight: 600; }
.topic-reference-sections {
    list-style: none;
    margin: var(--site-space-3) 0 0;
    padding: 0 0 0 var(--site-space-5);
    border-left: 2px solid var(--site-border);
}
.topic-reference-sections li { padding: var(--site-space-1) 0; }
.topic-reference-sections a { font-size: var(--site-type-md); color: var(--site-text-muted); }
.topic-reference-sections a:hover { color: var(--site-link); }
.topic-weblink-url {
    display: block;
    margin-top: var(--site-space-1);
    font-family: var(--site-font-chrome);
    font-size: var(--site-type-xs);
    color: var(--site-text-faint);
    overflow-wrap: anywhere;
}

.topic-related .rel-role { color: var(--site-text-quiet); font-size: var(--site-type-sm); }

/* A pointer to a Networker Table, standing where the page mentions it. Reads
   as a deliberate signpost rather than as a stray link in the prose — the
   table itself lives on its own page. */
.ntable-link {
    display: block;
    margin: var(--site-space-6) 0;
    padding: var(--site-space-5) var(--site-space-5);
    border: 1px solid var(--site-border);
    border-left: 3px solid var(--site-link);
    border-radius: var(--site-radius-sm);
}
.ntable-link-title {
    display: block;
    font-weight: 600;
    color: var(--site-link);
    text-decoration: none;
}
.ntable-link-title:hover { text-decoration: underline; }
.ntable-link-size { font-size: var(--site-type-sm); color: var(--site-text-quiet); }

/* A published table's own page. */
.ntable-size { color: var(--site-text-quiet); font-size: var(--site-type-md); }
.ntable-referrers a { color: var(--site-link); text-decoration: none; }
.ntable-referrers a:hover { text-decoration: underline; }
/* The row a reference points at, once followed — and, coming the other way,
   the mention a table's back-link lands on. */
.ntable tr:target { background: var(--site-border); }
.ntable-link:target { background: var(--site-border); }

/* Related Topics rail on a topic page. Literally the same rows as the topics
   rail on a notebook page — same padding, same step, same hover — because it
   is the same kind of list in the same place on the screen. */
.notebook-nav .topic-related { list-style: none; margin: 0; padding: 0; }
.notebook-nav .topic-related li {
    padding: var(--site-space-3) var(--site-space-6);
    font-size: var(--site-type-md);
}
.notebook-nav .topic-related li:hover { background: var(--site-hover-bg); }
.notebook-nav .topic-related a { color: var(--site-text-muted); text-decoration: none; }
.notebook-nav .topic-related a:hover { color: var(--site-nav-hover); }

/* ─── Top-menu layout ("Top navigation menu" option): a horizontal level-1
   menu with a JS '⋯' overflow replaces the left sidebar; readers drill down
   via breadcrumbs + each section page's child list. ─── */
body.topmenu .site-layout { max-width: var(--site-width-wide); }
/* Every horizontal band on a top-menu page is the wide one — including the bar
   ABOVE the menu, which kept the standard width and so began some 70px inside
   the menu running directly under it. Four bands each starting somewhere
   slightly different reads as a mistake rather than as a design.
   Keyed on the menu being PRESENT, not on the mode: the front page carries no
   menu bars, and there the banner belongs with the Featured grid beneath it,
   which is the standard width. A browser without `:has()` simply keeps
   today's behavior. */
body.topmenu:has(.top-menu) .banner-inner,
body.topmenu:has(.top-menu) .doc-nav { max-width: var(--site-width-wide); }
/* EXCEPT A BAR THAT IS WRITTEN. The rule above holds every band on a top-menu
   page to one width so they start at the same place — right for a logo and a
   title, wrong for a picture, which is a picture OF the bar and has to reach
   both edges of it. Said again here because the rule above out-specifies the
   `max-width: none` up in the written-banner section: a bare class lost to
   `body.topmenu:has(.top-menu) .banner-inner`, and what showed was the bar's
   own dark ground down the left and right of the picture. */
body.topmenu:has(.top-menu) .banner-inner.banner-from-page { max-width: none; }

.top-menu {
    display: flex;
    align-items: stretch;
    /* EDGE TO EDGE, like the bar above it. mb: "The menu should occupy the
       whole width, like the banner. Currently it occupies the text width, and
       there is a gap between the banner and the menu."

       Measured before changing anything: the vertical gap was ZERO. What reads
       as a gap is horizontal — a full-width banner over a menu held to 1240px
       left 80px of page showing down each side of the colored strip, and two
       stacked bands that do not start at the same place read as a seam.

       The strip takes the width and the ITEMS keep the column, which is the
       same inversion a full-width band uses inside the reading area. The
       padding is the greater of the ordinary inset and whatever centers the
       column, so a narrow screen keeps its margin instead of going to zero. */
    max-width: none;
    margin: 0;
    padding: 0 max(var(--site-space-6),
                   calc((100% - var(--site-width-wide)) / 2));
    background: var(--site-rail-bg);
    border-bottom: 1px solid var(--site-border);
    font-family: var(--site-font-chrome);
    /* Its OWN size. A menu is often wanted bigger or smaller than the rest
       of the furniture, and --site-type-md is shared with things that should
       not move with it. */
    font-size: var(--site-menu-size);
}
.top-menu > a {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;          /* don't shrink — nav.js measures true widths to overflow */
    padding: var(--site-space-5) var(--site-space-5);
    color: var(--site-menu-fg);
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 3px solid transparent;
}
.top-menu > a:hover { color: var(--site-nav-hover); background: var(--site-hover-bg); }
.top-menu > a.active { color: var(--site-nav-active); font-weight: 600; border-bottom-color: var(--site-active-bar); }

/* Secondary bar: the current section's level-2 pages. Lighter and a touch
   smaller than the level-1 menu, so the hierarchy reads at a glance. */
.sub-menu {
    background: var(--site-submenu-bg);
    font-size: var(--site-type-sm);
}
.sub-menu > a { padding: var(--site-space-4) var(--site-space-5); }

/* Left "‹" control: appears when the menu has slid to reveal the active item;
   click jumps back to the start. */
.top-menu-back {
    flex: 0 0 auto;
    border: none;
    background: none;
    cursor: pointer;
    padding: var(--site-space-4) var(--site-space-5);
    color: var(--site-menu-fg);
    font-size: var(--site-type-up);
    line-height: 1;
    font-family: inherit;
}
.top-menu-back:hover { color: var(--site-nav-hover); background: var(--site-hover-bg); }

.top-menu-more { position: relative; margin-left: auto; flex: 0 0 auto; }
.top-menu-more > summary {
    list-style: none;
    cursor: pointer;
    padding: var(--site-space-5) var(--site-space-5);
    color: var(--site-menu-fg);
}
.top-menu-more > summary::-webkit-details-marker { display: none; }
.top-menu-more[open] > summary { color: var(--site-nav-hover); background: var(--site-hover-bg); }
.top-menu-more-items {
    position: absolute;
    right: 0;
    top: 100%;
    z-index: 20;
    min-width: 180px;
    /* Cap the width to the viewport so a long title can't push the panel off
       the left edge; items wrap instead of overflowing. */
    max-width: min(280px, 90vw);
    /* THE MENU'S OWN COLOR, not the site's generic surface. This is what a
       reader means by the drop-down: the panel that hangs off More ▾ when the
       bar runs out of room, filled by the nav script. It was painted
       `--site-surface` — a token NO region offers — so "Drop-down background"
       colored the level-2 and level-3 bars and left this white, with nothing
       anywhere that could reach it. mb: "only applies to the first submenu
       line. If there others, they stay white."
       The built-in dark template gives the bug away: it sets --site-surface
       and --site-submenu-bg to the same value by hand, which is somebody
       hitting this and working around it in silence. */
    background: var(--site-submenu-bg);
    border: 1px solid var(--site-border);
    border-radius: 0 0 var(--site-radius-md) var(--site-radius-md);
    box-shadow: 0 6px 16px var(--site-shadow);
    display: flex;
    flex-direction: column;
    padding: var(--site-space-2) 0;
}
.top-menu-more-items > a {
    padding: var(--site-space-4) var(--site-space-6);
    color: var(--site-menu-fg);
    text-decoration: none;
    white-space: normal;      /* long titles wrap within the panel */
}
.top-menu-more-items > a:hover { background: var(--site-hover-bg); color: var(--site-nav-hover); }
.top-menu-more-items > a.active { color: var(--site-nav-active); font-weight: 600; }

/* PART OF THE MENU'S BAND, not a line floating under it. mb: "The breadcrumbs
   should get the exact same treatment as the menu."

   The width treatment is the menu's exactly — the strip takes the page, the
   words keep the column — and on its own that would have been invisible,
   because breadcrumbs had no background to reach the edges with. They take the
   menu's, which is what makes "the same treatment" something you can see: the
   navigation is one band from the bar down to the last crumb.

   It also settles a coupling that was quietly wrong. `--site-text-soft` is
   governed by the MENU's background (it is chrome), and breadcrumbs were
   sitting on the PAGE — so a dark menu over a light page gave them pale grey
   words on white. Now the ground under them is the one their color answers
   to. */
.breadcrumbs {
    max-width: none;
    margin: 0;
    padding: var(--site-space-3) max(var(--site-space-6),
                                     calc((100% - var(--site-width-wide)) / 2));
    background: var(--site-rail-bg);
    border-bottom: 1px solid var(--site-border);
    font-family: var(--site-font-chrome);
    font-size: var(--site-type-xs);
    color: var(--site-text-soft);
}
.breadcrumbs a { color: var(--site-text-muted); text-decoration: none; }
.breadcrumbs a:hover { color: var(--site-link); text-decoration: underline; }
.breadcrumbs .crumb-sep { color: var(--site-crumb-sep); margin: 0 var(--site-space-1); }


/* This site's appearance */
:root {
    --site-banner-bg: #1b2d55;
    --site-banner-fg: #2e2e2e;
    --site-banner-hover-bg: #d25b5b;
    --site-btn-primary-bg: #f03d3d;
    --site-btn-primary-fg: #de7c7c;
    --site-docnav-bottom-bg: #151a20;
    --site-docnav-top-bg: #1a2028;
    --site-hover-bg: #232a33;
    --site-menu-fg: #a3adba;
    --site-nav-active: #e9eef4;
    --site-nav-bg: #1b2027;
    --site-nav-hover: #ffffff;
    --site-nav-link: #9fb0c2;
    --site-nav-link-hover: #d8e3ee;
    --site-rail-bg: #060506;
    --site-rail-head: #818b97;
    --site-rail-shade: #ffffff;
    --site-text-soft: #8d97a4;
}
