/* ==========================================================================
   DINKOMART — Documentation shell

   Shared by two documentation sets, split by WHO IS ALLOWED TO READ THEM:

     docs/    PUBLIC help centre, for customers. Ships with the site.
     dev/     INTERNAL owner and developer guides. Loads this file as
              ../docs/guide.css, and must be password-protected in production.

   One stylesheet on purpose. Two copies would drift, and the split is about
   audience, not about looking different.

   THE LINE THAT MATTERS
   ---------------------
   docs/ must never mention placeholder prices, sample figures, unconfirmed
   stock, internal defects or anything else a customer should not read. All of
   that lives in dev/, which needs its own server-side protection — there is
   none yet.

   THE LAYOUT
   ----------
   A real manual shell, four regions plus the body:

       ┌──────────────────────────────────────────────────────┐
       │  top bar — brand, guide switcher, search, theme      │  sticky
       ├──────────┬─────────────────────────────┬─────────────┤
       │ sidebar  │  main                       │  aside      │
       │ every    │  the chapters               │  on this    │
       │ chapter  │                             │  page       │
       │ sticky   │                             │  sticky     │
       ├──────────┴─────────────────────────────┴─────────────┤
       │  footer — every surface in the project, in columns   │
       └──────────────────────────────────────────────────────┘

   Below 1180px the aside drops. Below 960px the sidebar becomes a drawer and
   the body is one column.

   NAVIGATION IS BUILT FROM THE DOCUMENT, NOT TYPED
   ------------------------------------------------
   guide.js reads every `<section class="sec" id>` and its `<h2>`, plus the
   `<h3>`s inside it, and builds the sidebar, the contents grid, the aside and
   the prev/next pager from that. So adding a chapter needs no edit here and no
   edit in four navigations that could disagree with each other.

   The consequence: those four are empty without JavaScript. That is acceptable
   because they are NAVIGATION. Every word of actual content is in the markup
   and stays readable — nothing is hidden waiting for a script to reveal it.
   That rule has cost this project six blank-section bugs; it is not broken
   here.

   COLOUR
   ------
   Everything comes from ../req/css/tokens.css. Nothing below declares a colour
   literal, and no wash, tint or gradient is painted from a raw palette token
   (--bone-*, --loam-*, --forest-*) — those do not flip with the theme. Only
   semantic tokens are used: --surface, --rhythm, --glass*, --band-*.

   Bootstrap 5.3.3 is vendored and rebound onto the tokens below; it is here
   for .table and the swatch grid, nothing else.
   ========================================================================== */

/* ==========================================================================
   1. Bootstrap, rebound onto the project tokens
   ========================================================================== */
:root {
  --bs-body-bg: var(--bg);
  --bs-body-color: var(--fg);
  --bs-body-font-family: var(--font-body);
  --bs-body-font-size: var(--t-md);
  --bs-body-line-height: var(--lh-body);
  --bs-emphasis-color: var(--fg);
  --bs-secondary-color: var(--fg-subtle);
  --bs-border-color: var(--border);
  --bs-border-radius: var(--r-ctl);
  --bs-border-radius-lg: var(--r-card);
  --bs-link-color: var(--brand-ink);
  --bs-link-hover-color: var(--brand-hover);
  --bs-font-monospace: var(--font-mono);
  --bs-heading-color: var(--fg);

  /* The shell's own measurements, in one place. */
  --doc-top: 60px;
  --doc-rail: 286px;
  --doc-aside: 232px;
  --doc-gutter: clamp(1.25rem, 3vw, 3rem);
}
[data-theme='dark'] { --bs-link-color: var(--band-sprout); }

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* ==========================================================================
   NO PAGE HERE MAY SCROLL SIDEWAYS

   The storefront carries this rule in signature.css and the guides never got
   it, which left every documentation page without the one guard that catches
   the whole class of bug.

   THE SIGNATURE IS AN OVERFLOW WITH NO OFFENDER. `scrollWidth` exceeds the
   viewport, a horizontal scrollbar appears, and walking every element in the
   document finds nothing out of place — because the thing that did it is
   `position: fixed` and follows the pointer. These pages carry two such
   elements that only exist in a real browser: the custom cursor from
   `cursor.js`, which mounts only under `(hover: hover) and (pointer: fine)`,
   and the assistant's panel. Neither can be reproduced in a headless or
   pointerless renderer, which is exactly why an audit run here comes back
   clean while a person watching the page sees a scrollbar.

   IT ALSO EXPLAINS THE FLICKER. A scrollbar that appears and disappears as
   the pointer moves takes ~15px off the viewport each time it does, and the
   whole layout reflows on every toggle. One cause, both symptoms.

   `clip` rather than `hidden`, and this is the part that bites: `hidden`
   would make the root a scroll container and break every `position: sticky`
   on these pages — the topbar, the chapter rail, the "on this page" aside.
   `clip` clips without creating one. Guarded because Safari only took `clip`
   in 16; older engines keep the scrollbar rather than lose their sticky rail.

   Unlike the storefront this needs no companion `body` rule, because
   guide.css never sets `body { overflow-x: hidden }` — measured: both compute
   to `visible` here. Do not add one; on the storefront that combination is
   what silently moved the scrolling box onto body and sent the sticky header
   to -563px.
   ========================================================================== */
@supports (overflow-x: clip) {
  html { overflow-x: clip; }
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--t-md);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: var(--lh-snug);
  color: var(--fg);
  margin: 0;
}
p { margin: 0; }
a { color: inherit; text-decoration: none; }
.prose a, a.link, .note a, .task a, td a {
  color: var(--bs-link-color);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.prose a:hover, a.link:hover, .note a:hover, .task a:hover, td a:hover { color: var(--brand-hover); }

code, kbd, samp { font-family: var(--font-mono); font-size: .88em; }
code {
  background: var(--brand-soft);
  color: var(--brand-ink);
  padding: .1em .4em;
  border-radius: 5px;
  overflow-wrap: anywhere;
}
[data-theme='dark'] code {
  background: color-mix(in srgb, var(--brand) 20%, transparent);
  color: var(--band-sprout);
}
pre code { background: none; padding: 0; color: inherit; }

kbd {
  display: inline-block; padding: .12em .5em;
  border: 1px solid var(--border-strong); border-bottom-width: 2px;
  border-radius: 6px; background: var(--surface-2); color: var(--fg-muted);
  font-size: .8em; line-height: 1.5;
}

.muted { color: var(--fg-subtle); }
.mono { font-family: var(--font-mono); }
.ico {
  width: 1em; height: 1em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.ico-sm { width: .85em; height: .85em; }

::selection { background: color-mix(in srgb, var(--accent) 34%, transparent); }
:where(a, button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 3px;
  border-radius: var(--r-chip);
}

.skip {
  position: fixed; left: 50%; top: -100px; transform: translateX(-50%);
  z-index: 400; padding: .8rem 1.4rem;
  background: var(--brand); color: var(--brand-fg);
  border-radius: 0 0 var(--r-ctl) var(--r-ctl);
  font-size: var(--t-sm); font-weight: 600;
}
.skip:focus { top: 0; }

/* ==========================================================================
   2. Top bar
   ========================================================================== */
.topbar {
  position: sticky; top: 0; z-index: var(--z-nav);
  height: var(--doc-top);
  display: flex; align-items: center; gap: var(--s-4);
  padding: 0 var(--doc-gutter);
  background: var(--glass-2);
  backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  border-bottom: 1px solid var(--border);
}

.topbar-brand { display: inline-flex; align-items: center; gap: .6rem; flex: none; }
.topbar-brand img { display: block; object-fit: cover; }
.topbar-brand b {
  display: block; font-family: var(--font-display);
  font-size: var(--t-base); font-weight: 700; letter-spacing: -.02em; line-height: 1.15;
}
.topbar-brand small {
  display: block; font-family: var(--font-mono); font-size: var(--t-2xs);
  color: var(--fg-faint); letter-spacing: .06em;
}

/* Which of the two documentation sets you are in. */
.setswitch {
  display: inline-flex; align-items: center; gap: 2px; flex: none;
  padding: 3px; background: var(--surface-sunk);
  border: 1px solid var(--border); border-radius: var(--r-pill);
}
.setswitch a {
  padding: .3rem .8rem; border-radius: var(--r-pill);
  font-family: var(--font-mono); font-size: var(--t-2xs);
  letter-spacing: .05em; color: var(--fg-subtle); white-space: nowrap;
  transition: background var(--dur-1), color var(--dur-1);
}
.setswitch a:hover { color: var(--fg); }
.setswitch a.is-on { background: var(--surface); color: var(--fg); box-shadow: var(--shadow-xs); }

.topbar-spacer { flex: 1 1 auto; }

.topbar-links { display: flex; align-items: center; gap: .15rem; }
.topbar-links a {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .45rem .8rem; border-radius: var(--r-ctl);
  font-size: var(--t-sm); color: var(--fg-muted);
  transition: background var(--dur-1), color var(--dur-1);
}
.topbar-links a:hover { background: var(--surface-2); color: var(--fg); }

.topbar-progress {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  pointer-events: none;
}
.topbar-progress i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--brand), var(--accent));
  transition: width 90ms linear;
}

.icon-btn {
  display: inline-grid; place-items: center; width: 40px; height: 40px;
  flex: none; font-size: 1.05rem;
  color: var(--fg-muted); background: transparent;
  border: 1px solid transparent; border-radius: var(--r-ctl); cursor: pointer;
  transition: background var(--dur-1), color var(--dur-1), border-color var(--dur-1);
}
.icon-btn:hover { background: var(--surface-2); color: var(--fg); border-color: var(--border); }
[data-theme='light'] .i-sun, [data-theme='dark'] .i-moon { display: none; }

.only-narrow { display: none; }

/* ==========================================================================
   3. The three-column body
   ========================================================================== */
.layout {
  display: grid;
  grid-template-columns: var(--doc-rail) minmax(0, 1fr) var(--doc-aside);
  gap: var(--doc-gutter);
  align-items: start;
  max-width: 1680px;
  margin-inline: auto;
  padding: 0 var(--doc-gutter);
}

/* -------------------------------------------------------------- sidebar */
.sidebar {
  position: sticky; top: var(--doc-top);
  max-height: calc(100vh - var(--doc-top));
  overflow-y: auto; overscroll-behavior: contain;
  padding: var(--s-7) var(--s-4) var(--s-8) 0;
  scrollbar-width: thin;
}
.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 99px; }

.rail-search { position: relative; margin-bottom: var(--s-5); }
.rail-search .ico {
  position: absolute; left: .7rem; top: 50%; transform: translateY(-50%);
  font-size: .95rem; color: var(--fg-faint); pointer-events: none;
}
.rail-search input {
  width: 100%; height: 38px; padding: 0 2.2rem 0 2.2rem;
  font-family: var(--font-body); font-size: var(--t-sm); color: var(--fg);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-ctl);
}
.rail-search input::placeholder { color: var(--fg-faint); }
.rail-search input:focus { border-color: var(--border-focus); outline: none; }
.rail-search kbd { position: absolute; right: .5rem; top: 50%; transform: translateY(-50%); }
.rail-search input:not(:placeholder-shown) + kbd { display: none; }

/* -------------------------------------------------------------- accordion
   ONE PART OPEN AT A TIME. Flat, this rail was every chapter of every part at
   once — twenty-three links and eight headings in the longest guide, a column
   you scrolled past to reach the thing you actually wanted. Grouped, it is
   eight rows, and opening one part closes the last (guide.js `openGroup`).

   The body is `display:none` when closed rather than height-animated: a rail
   that has to measure itself is a rail that can measure wrong, and the one
   thing this project has learned the hard way is not to hide content behind a
   measurement. Closed here means "the reader closed it", never "the script
   has not run yet" — with JS off there is no accordion and no rail at all,
   and every #anchor in the page still works. */
.rail-nav { display: block; }

.rail-group + .rail-group { border-top: 1px solid var(--hairline); }
.rail-group.is-bare { padding-bottom: .3rem; }

.rail-group-head {
  display: grid; grid-template-columns: 1rem 1fr auto; align-items: center;
  gap: .5rem; width: 100%; padding: .62rem .55rem;
  background: none; border: 0; border-radius: var(--r-ctl);
  text-align: left; cursor: pointer; color: var(--fg-muted);
  transition: background var(--dur-1), color var(--dur-1);
}
.rail-group-head:hover { background: var(--surface-2); color: var(--fg); }
.rail-group-head .chev {
  font-size: .9rem; color: var(--fg-faint);
  transition: transform var(--dur-1);
}
.rail-group-name {
  display: block; min-width: 0;
  font-family: var(--font-display); font-size: var(--t-sm); font-weight: 650;
  line-height: 1.25; letter-spacing: -.005em;
}
.rail-group-name small {
  display: block;
  font-family: var(--font-mono); font-size: var(--t-3xs, .625rem); font-weight: 400;
  text-transform: uppercase; letter-spacing: .13em; color: var(--fg-faint);
}
/* --fg-faint measured 4.42:1 here against a 4.5 requirement, once per part —
   eight failures on the console guide. It is documented as the 4.7:1 floor on
   bone, and this pill's own --surface-2 ground takes it under. A tint eats
   about half a point, which is exactly enough to fail; one step up clears it
   without changing the hierarchy. */
.rail-group-n {
  font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--fg-subtle);
  background: var(--surface-2); border-radius: 99px; padding: .1rem .42rem;
}

.rail-group-body { display: none; padding: 0 0 .45rem; }
.rail-group.is-open > .rail-group-body { display: grid; gap: 1px; }
.rail-group.is-open > .rail-group-head { color: var(--fg); }
.rail-group.is-open > .rail-group-head .chev { transform: rotate(90deg); }

/* The part you are reading, so the rail says where you are even when the
   chapter link itself has scrolled out of the rail's own view. */
.rail-group.is-open > .rail-group-head .rail-group-name { color: var(--fg); }
.rail-group.is-found > .rail-group-head .rail-group-n {
  background: var(--brand-soft); color: var(--brand-ink);
}

.rail-link {
  display: grid; grid-template-columns: 1.9rem 1fr; align-items: baseline;
  gap: .2rem; padding: .42rem .7rem;
  border-radius: var(--r-ctl); border-left: 2px solid transparent;
  font-size: var(--t-base); line-height: var(--lh-copy); color: var(--fg-muted);
  transition: background var(--dur-1), color var(--dur-1), border-color var(--dur-1);
}
.rail-link .n {
  font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--fg-faint);
}
.rail-link:hover { background: var(--surface-2); color: var(--fg); }
.rail-link.is-on {
  background: var(--brand-soft); color: var(--brand-ink);
  border-left-color: var(--brand); font-weight: 600;
}
.rail-link.is-on .n { color: var(--brand-ink); }
[data-theme='dark'] .rail-link.is-on {
  background: color-mix(in srgb, var(--brand) 22%, transparent);
  color: var(--band-fg);
}
[data-theme='dark'] .rail-link.is-on .n { color: var(--band-sprout); }

/* The h3s under the open chapter. Shown only for the chapter you are in —
   the whole tree expanded is a wall you have to read past every time. */
.rail-sub { display: none; margin: .1rem 0 .35rem 1.9rem; padding-left: .75rem;
            border-left: 1px solid var(--hairline); }
.rail-link.is-on + .rail-sub { display: grid; gap: 1px; }
.rail-sub a {
  padding: .28rem .55rem; border-radius: var(--r-chip);
  font-size: var(--t-sm); line-height: var(--lh-copy); color: var(--fg-subtle);
}
.rail-sub a:hover { background: var(--surface-2); color: var(--fg); }
.rail-sub a.is-on { color: var(--brand-ink); font-weight: 600; }
[data-theme='dark'] .rail-sub a.is-on { color: var(--band-sprout); }

.rail-none {
  padding: .6rem .7rem; font-size: var(--t-sm); color: var(--fg-faint);
}

/* ------------------------------------------------- one chapter at a time

   `is-off` is added ONLY by guide.js, never by the document, so a guide whose
   script does not run shows every chapter exactly as it always did. That is
   the inverse of the rule that has cost this project six blank sections, and
   it is inverted on purpose: the failure mode here is "too long", not "empty".

   Printing un-hides everything — a PDF of one chapter out of twenty-three is
   not what anybody meant by File → Print. */
.is-off { display: none !important; }
@media print {
  .is-off { display: revert !important; }
}

.rail-mode {
  display: flex; align-items: flex-start; gap: .6rem;
  width: 100%; margin-top: var(--s-5); padding: .7rem .75rem;
  text-align: left; cursor: pointer;
  background: var(--surface); color: var(--fg-muted);
  border: 1px solid var(--border); border-radius: var(--r-ctl);
  transition: background var(--dur-1), border-color var(--dur-1);
}
.rail-mode:hover { background: var(--surface-2); border-color: var(--border-strong); }
.rail-mode .ico { font-size: 1.05rem; color: var(--brand); margin-top: .1rem; }
.rail-mode span { display: block; min-width: 0; font-size: var(--t-2xs); color: var(--fg-faint); line-height: 1.45; }
.rail-mode b {
  display: block; margin-bottom: .1rem;
  font-family: var(--font-display); font-size: var(--t-sm); color: var(--fg);
}

.rail-foot {
  margin-top: var(--s-7); padding-top: var(--s-5);
  border-top: 1px solid var(--hairline); display: grid; gap: 1px;
}
.rail-foot a {
  display: flex; align-items: center; gap: .55rem;
  padding: .4rem .7rem; border-radius: var(--r-ctl);
  font-size: var(--t-sm); color: var(--fg-subtle);
}
.rail-foot a:hover { background: var(--surface-2); color: var(--fg); }
.rail-foot .ico { font-size: .95rem; color: var(--fg-faint); }
.rail-foot .out { margin-left: auto; font-size: .8rem; }

.rail-x { display: none; }
.sidebar-scrim { display: none; }

/* ----------------------------------------------------------------- main */
.doc-main { min-width: 0; padding: var(--s-7) 0 var(--s-10); }

/* ---------------------------------------------------------------- aside */
.onthis {
  position: sticky; top: var(--doc-top);
  max-height: calc(100vh - var(--doc-top));
  overflow-y: auto; overscroll-behavior: contain;
  padding: var(--s-7) 0 var(--s-8);
  font-size: var(--t-sm);
}
.onthis:empty { display: none; }
.onthis h2 {
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: .14em;
  color: var(--fg-faint); margin-bottom: var(--s-3);
}
.onthis nav { display: grid; gap: 1px; border-left: 1px solid var(--hairline); }
.onthis a {
  padding: .32rem .75rem; margin-left: -1px;
  border-left: 2px solid transparent;
  color: var(--fg-subtle); line-height: var(--lh-copy);
}
.onthis a:hover { color: var(--fg); }
.onthis a.is-on { border-left-color: var(--brand); color: var(--brand-ink); font-weight: 600; }
[data-theme='dark'] .onthis a.is-on { color: var(--band-sprout); }
.onthis .top {
  display: inline-flex; align-items: center; gap: .4rem;
  margin-top: var(--s-5); padding: .35rem .75rem;
  font-family: var(--font-mono); font-size: var(--t-2xs);
  color: var(--fg-faint);
}
.onthis .top:hover { color: var(--brand-ink); }

/* ==========================================================================
   4. Page head
   ========================================================================== */
/* overflow:hidden matters. The wash below is absolutely positioned and bleeds
   sideways; without clipping it counted toward the document's scroll width and
   put a phantom horizontal scrollbar on every page. */
.doc-hero { position: relative; overflow: hidden; padding-bottom: var(--s-7); }
.doc-hero::before {
  content: ''; position: absolute; inset: -30% -25% 30% -25%;
  pointer-events: none; z-index: 0;
  background:
    radial-gradient(52% 62% at 12% 22%, color-mix(in srgb, var(--brand) 15%, transparent), transparent 64%),
    radial-gradient(46% 56% at 88% 8%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 62%);
}
.doc-hero > * { position: relative; z-index: 1; }

.crumbs {
  display: flex; align-items: center; flex-wrap: wrap; gap: .45rem;
  font-family: var(--font-mono); font-size: var(--t-2xs);
  letter-spacing: .06em; color: var(--fg-faint); margin-bottom: var(--s-5);
}
.crumbs a:hover { color: var(--brand-ink); }
.crumbs .ico { font-size: .85rem; }

.eyebrow {
  font-family: var(--font-mono); font-size: var(--t-xs);
  text-transform: uppercase; letter-spacing: .14em; color: var(--accent-ink);
}

.doc-hero h1 {
  margin-top: var(--s-3);
  font-size: clamp(2.1rem, 4.6vw, 3.4rem);
  letter-spacing: -.035em; max-width: 17ch;
}
.lead { margin-top: 1.1rem; font-size: var(--t-lg); color: var(--fg-muted); max-width: 62ch; }

.meta-row {
  display: flex; flex-wrap: wrap; gap: var(--s-7);
  margin: var(--s-7) 0 0; padding: var(--s-5) 0;
  border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline);
}
.meta-row div { display: grid; gap: .15rem; }
.meta-row dt {
  font-family: var(--font-mono); font-size: var(--t-2xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--fg-faint);
}
.meta-row dd { margin: 0; font-family: var(--font-display); font-size: var(--t-base); font-weight: 700; }

/* ==========================================================================
   5. Contents grid — the shape of the document, before you start
   ========================================================================== */
.contents { margin: var(--s-8) 0 var(--s-6); }
.contents-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); margin-bottom: var(--s-4);
}
.contents-head h2 { font-size: var(--t-lg); }
.contents-head span { font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--fg-faint); }

.chapters { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(230px, 100%), 1fr)); gap: .7rem; }
.chapter-card {
  display: grid; gap: .3rem; align-content: start;
  padding: 1rem 1.15rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card);
  transition: transform var(--dur-1) var(--ease-out), border-color var(--dur-1), box-shadow var(--dur-1);
}
.chapter-card:hover { transform: translateY(-3px); border-color: var(--brand); box-shadow: var(--shadow-md); }
.chapter-card .n { font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--accent-ink); letter-spacing: .1em; }
.chapter-card b { font-family: var(--font-display); font-size: var(--t-base); }
.chapter-card span { font-size: var(--t-sm); color: var(--fg-subtle); line-height: var(--lh-copy); }

/* ==========================================================================
   6. Sections
   ========================================================================== */
.sec {
  scroll-margin-top: calc(var(--doc-top) + 1.25rem);
  padding: clamp(2.25rem, 4.5vw, 3.5rem) 0;
  border-top: 1px solid var(--border);
}
.part-rule {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: var(--s-6);
  border-top: 2px solid var(--border-strong);
}
.part-rule .k {
  font-family: var(--font-mono); font-size: var(--t-2xs);
  text-transform: uppercase; letter-spacing: .16em; color: var(--accent-ink);
}
.part-rule h2 { font-size: var(--t-xl); margin-top: .35rem; }
.part-rule p { margin-top: .5rem; font-size: var(--t-base); color: var(--fg-subtle); max-width: 64ch; }

.sec-num {
  font-family: var(--font-mono); font-size: var(--t-2xs);
  text-transform: uppercase; letter-spacing: .16em; color: var(--accent-ink);
  margin-bottom: .7rem;
}
.sec h2 { font-size: clamp(1.55rem, 3.2vw, 2.2rem); max-width: 22ch; }
.sec h2 + .prose { margin-top: 1rem; }
.sec h3 {
  font-size: var(--t-xl); margin: 2.4rem 0 .8rem;
  scroll-margin-top: calc(var(--doc-top) + 1.25rem);
}
.sec h4 { font-size: var(--t-md); margin: 1.7rem 0 .5rem; }

/* A quiet anchor beside every h3, so a heading is a link you can send. */
.anchor {
  margin-left: .45rem; font-family: var(--font-mono); font-weight: 400;
  font-size: .6em; color: var(--fg-faint); opacity: 0;
  transition: opacity var(--dur-1);
}
h3:hover .anchor, .anchor:focus-visible { opacity: 1; }

.prose { max-width: 70ch; }
.prose p + p { margin-top: .9rem; }
.prose ul, .prose ol { margin: .9rem 0; padding-left: 1.3rem; }
.prose li + li { margin-top: .45rem; }
.prose li::marker { color: var(--fg-faint); }
.lead-sm { font-size: var(--t-lg); color: var(--fg-muted); line-height: var(--lh-copy); }

/* ==========================================================================
   7. Steps and task cards
   ========================================================================== */
.steps { counter-reset: step; display: grid; gap: 0; margin: 1.5rem 0; max-width: 76ch; }
.step {
  counter-increment: step; position: relative;
  padding: 1.1rem 0 1.1rem 3.4rem;
  border-bottom: 1px solid var(--hairline);
}
.step:last-child { border-bottom: 0; }
.step::before {
  content: counter(step);
  position: absolute; left: 0; top: 1rem;
  width: 2.2rem; height: 2.2rem;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: var(--t-sm); font-weight: 600;
  color: var(--brand-fg); background: var(--brand); border-radius: 50%;
}
.step b { display: block; font-family: var(--font-display); font-size: var(--t-md); margin-bottom: .2rem; }
.step p { color: var(--fg-muted); font-size: var(--t-base); line-height: var(--lh-copy); }
.step p + p { margin-top: .5rem; }
.step .after { margin-top: .6rem; }

.tasks { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr)); gap: 1rem; margin: 1.5rem 0; }
.task {
  padding: 1.25rem 1.35rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card);
}
.task h4 { margin: 0 0 .5rem; font-size: var(--t-md); }
.task p, .task li { font-size: var(--t-sm); color: var(--fg-muted); line-height: var(--lh-copy); }
.task p + p { margin-top: .5rem; }
.task ol, .task ul { margin: .5rem 0 0; padding-left: 1.15rem; }
.task .where {
  display: inline-flex; align-items: center; gap: .35rem;
  margin-bottom: .6rem; padding: .2rem .6rem;
  font-family: var(--font-mono); font-size: var(--t-2xs);
  color: var(--brand-ink); background: var(--brand-soft); border-radius: var(--r-pill);
}
[data-theme='dark'] .task .where {
  background: color-mix(in srgb, var(--brand) 22%, transparent); color: var(--band-fg);
}

/* ==========================================================================
   8. Callouts
   ========================================================================== */
.note {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: 1rem 1.25rem; margin: 1.4rem 0; max-width: 76ch;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--tone, var(--brand)); border-radius: var(--r-card);
}
.note .ico { font-size: 1.2rem; color: var(--tone, var(--brand)); margin-top: .15rem; }
.note b { font-size: var(--t-base); }
.note p { margin-top: .2rem; font-size: var(--t-sm); color: var(--fg-subtle); line-height: var(--lh-copy); }
.note p + p { margin-top: .5rem; }
.note ul { margin: .5rem 0 0; padding-left: 1.15rem; font-size: var(--t-sm); color: var(--fg-subtle); }
.note.warn { --tone: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.note.bad  { --tone: var(--danger); background: color-mix(in srgb, var(--danger) 7%, var(--surface)); }
.note.good { --tone: var(--success); background: color-mix(in srgb, var(--success) 6%, var(--surface)); }
.note.info { --tone: var(--chill); background: color-mix(in srgb, var(--chill) 6%, var(--surface)); }

/* ==========================================================================
   9. Code
   ========================================================================== */
.code { position: relative; margin: 1.2rem 0; max-width: 78ch; }
.code pre {
  margin: 0; padding: 1.05rem 1.2rem;
  background: var(--band-bg); color: var(--band-fg);
  border-radius: var(--r-card); overflow-x: auto;
  font-family: var(--font-mono); font-size: var(--t-xs); line-height: 1.8;
}
.code.is-wide { max-width: none; }
.code .copy {
  position: absolute; top: .5rem; right: .5rem;
  padding: .3rem .65rem; font-family: var(--font-mono); font-size: var(--t-2xs);
  color: var(--band-fg-muted); background: color-mix(in srgb, var(--band-fg) 10%, transparent);
  border: 0; border-radius: 7px; cursor: pointer; opacity: 0;
  transition: opacity var(--dur-1), background var(--dur-1);
}
.code:hover .copy, .copy:focus-visible { opacity: 1; }
.code .copy:hover { background: color-mix(in srgb, var(--band-fg) 22%, transparent); color: var(--band-fg); }
.tree b { color: var(--band-sprout); font-weight: 600; }
.tree i { color: var(--band-accent); font-style: normal; }
.tree u { color: var(--band-chill); text-decoration: none; }

/* ==========================================================================
   10. Tables
   ========================================================================== */
.table-responsive { margin: 1.3rem 0; }
.table {
  --bs-table-bg: transparent; --bs-table-color: var(--fg);
  --bs-table-border-color: var(--hairline);
  --bs-table-hover-bg: var(--surface-2); --bs-table-hover-color: var(--fg);
  font-size: var(--t-sm); margin-bottom: 0;
}
.table > thead th {
  font-family: var(--font-mono); font-size: var(--t-2xs); font-weight: 500;
  text-transform: uppercase; letter-spacing: .09em;
  /* --fg-subtle, not --fg-faint. Faint is the floor on --bg (4.7:1); on the
     slightly darker --surface-2 it measures 4.42:1 and fails AA. */
  color: var(--fg-subtle); background: var(--surface-2);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table td, .table th { padding: .7rem .9rem; vertical-align: top; line-height: var(--lh-copy); }
.table td b { font-weight: 700; }

/* Bootstrap's .row uses negative margins that assume a padded container. The
   prose column has none, so a row pokes half a gutter past its parent and
   inflates the document's scroll width. Used only by the token swatches. */
.doc-main .row { margin-inline: 0; }

/* ==========================================================================
   11. Pills, buttons
   ========================================================================== */
.pill {
  display: inline-block; padding: .18rem .58rem; border-radius: var(--r-pill);
  font-family: var(--font-mono); font-size: var(--t-2xs); font-weight: 600; white-space: nowrap;
}
.p-good { color: var(--success); background: var(--success-soft); }
.p-warn { color: var(--accent-ink); background: var(--accent-soft); }
.p-bad  { color: var(--danger); background: var(--danger-soft); }
.p-info { color: var(--chill); background: var(--chill-soft); }
.p-brand{ color: var(--brand-ink); background: var(--brand-soft); }
.p-iron { color: var(--iron-ink); background: var(--iron-soft); }
.p-mute { color: var(--fg-subtle); background: var(--surface-sunk); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 44px; padding: .6rem 1.2rem;
  font-family: var(--font-body); font-size: var(--t-sm); font-weight: 600;
  border: 1px solid transparent; border-radius: var(--r-ctl); cursor: pointer;
  transition: background var(--dur-1), border-color var(--dur-1), color var(--dur-1);
}
.btn-brand { background: var(--brand); color: var(--brand-fg); }
.btn-brand:hover { background: var(--brand-hover); color: var(--brand-fg); }
.btn-line { background: transparent; border-color: var(--border); color: var(--fg-muted); }
.btn-line:hover { background: var(--surface-2); color: var(--fg); border-color: var(--border-strong); }

/* ==========================================================================
   12. Prev / next pager
   ========================================================================== */
.pager {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: .8rem;
  margin-top: clamp(2.25rem, 4.5vw, 3.5rem); padding-top: var(--s-7);
  border-top: 1px solid var(--border);
}
.pager a {
  display: grid; gap: .2rem; padding: 1rem 1.2rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card);
  transition: border-color var(--dur-1), transform var(--dur-1) var(--ease-out);
}
.pager a:hover { border-color: var(--brand); transform: translateY(-2px); }
.pager .k {
  font-family: var(--font-mono); font-size: var(--t-2xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--fg-faint);
}
.pager b { font-family: var(--font-display); font-size: var(--t-md); }
.pager .is-next { text-align: right; }

/* ==========================================================================
   13. What-next cards
   ========================================================================== */
.next { margin-top: clamp(2.25rem, 4.5vw, 3.5rem); padding-top: var(--s-7); border-top: 1px solid var(--border); }
.next-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: 1rem; margin-top: var(--s-5); }
.next-card {
  display: grid; gap: .4rem; align-content: start;
  padding: 1.3rem 1.4rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card);
  transition: transform var(--dur-1) var(--ease-out), border-color var(--dur-1);
}
.next-card:hover { transform: translateY(-3px); border-color: var(--brand); }
.next-card .k { font-family: var(--font-mono); font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: .1em; color: var(--fg-faint); }
.next-card b { font-family: var(--font-display); font-size: var(--t-md); }
.next-card span { font-size: var(--t-sm); color: var(--fg-subtle); line-height: var(--lh-copy); }

/* ==========================================================================
   14. Site footer — the deep band
   ========================================================================== */
.sitefoot {
  margin-top: var(--s-9);
  padding: var(--s-9) var(--doc-gutter) var(--s-7);
  background: var(--band-bg); color: var(--band-fg-muted);
  font-size: var(--t-sm);
}
.sitefoot-in { max-width: 1680px; margin-inline: auto; }
.sitefoot-grid {
  display: grid;
  /* min() inside minmax() is what stops this overflowing. A bare
     minmax(240px, …) makes the track AT LEAST 240px even when the container
     is narrower, so at a 390px viewport the first column plus one auto-fit
     150px column plus the gap came to 432px and pushed a horizontal
     scrollbar onto every docs page. min(240px, 100%) lets the track shrink
     with the container instead. Same fix on the auto-fit track. */
  grid-template-columns: minmax(min(240px, 100%), 1.4fr) repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: var(--s-7);
}
.sitefoot-mark { display: flex; align-items: center; gap: .65rem; }
.sitefoot-mark img { object-fit: cover; }
.sitefoot-mark b { font-family: var(--font-display); font-size: var(--t-lg); color: var(--band-fg); }
.sitefoot-mark small { display: block; font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--band-fg-faint); }
.sitefoot-blurb { margin-top: var(--s-4); max-width: 40ch; line-height: var(--lh-copy); }

.sitefoot h3 {
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: .14em;
  color: var(--band-fg-faint); margin-bottom: var(--s-4);
}
.sitefoot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.sitefoot a { color: var(--band-fg-muted); }
.sitefoot a:hover { color: var(--band-sprout); }
.sitefoot .out { font-size: .8em; margin-left: .3rem; opacity: .7; }

.sitefoot-base {
  display: flex; flex-wrap: wrap; gap: var(--s-4) var(--s-7);
  align-items: baseline; justify-content: space-between;
  margin-top: var(--s-8); padding-top: var(--s-5);
  border-top: 1px solid var(--band-hairline);
  font-family: var(--font-mono); font-size: var(--t-2xs);
  color: var(--band-fg-faint); line-height: 1.9;
}
.sitefoot-base code { background: color-mix(in srgb, var(--band-fg) 10%, transparent); color: var(--band-fg-muted); }

.sign { margin-top: var(--s-7); font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--fg-faint); line-height: 1.9; }

/* ==========================================================================
   15. The hub page — docs/index.php and dev/index.php
   ========================================================================== */
.hub { padding: clamp(2.5rem, 6vw, 5rem) var(--doc-gutter) clamp(2rem, 5vw, 4rem); }
.hub-in { max-width: 1180px; margin-inline: auto; }
.hub h1 { font-size: clamp(2.3rem, 5.6vw, 3.9rem); letter-spacing: -.035em; max-width: 18ch; }

.fork-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: 1.1rem; margin-top: var(--s-8); }
.fork-card {
  position: relative; overflow: hidden;
  display: grid; gap: .75rem; align-content: start;
  padding: clamp(1.5rem, 3vw, 2.2rem);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-panel);
  transition: transform var(--dur-2) var(--ease-out), border-color var(--dur-1), box-shadow var(--dur-2);
}
.fork-card:hover { transform: translateY(-5px); border-color: var(--brand); box-shadow: var(--shadow-lg); }
.fork-card::after {
  content: ''; position: absolute; inset: auto -30% -60% auto; width: 70%; aspect-ratio: 1;
  background: radial-gradient(circle, color-mix(in srgb, var(--tone, var(--brand)) 16%, transparent), transparent 70%);
  pointer-events: none;
}
.fork-card > * { position: relative; z-index: 1; }
.fork-ico {
  display: grid; place-items: center; width: 52px; height: 52px;
  border-radius: var(--r-card); font-size: 1.45rem;
  color: var(--tone, var(--brand));
  background: color-mix(in srgb, var(--tone, var(--brand)) 13%, transparent);
}
.fork-card h2 { font-size: var(--t-2xl); }
.fork-card > p { font-size: var(--t-base); color: var(--fg-muted); line-height: var(--lh-copy); }
.fork-list { list-style: none; margin: .3rem 0 0; padding: 0; display: grid; gap: .45rem; }
.fork-list li { display: flex; gap: .6rem; align-items: flex-start; font-size: var(--t-sm); color: var(--fg-subtle); }
.fork-list .ico { color: var(--tone, var(--brand)); margin-top: .28em; font-size: .85em; }
.fork-go {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: .7rem;
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  /* --tone-ink, not --tone. The tone is a fill colour for the icon tile; used
     as 12px text on --surface, raw --accent measures 3.07:1 and fails AA. Every
     card sets both, and the ink variants exist for exactly this. */
  color: var(--tone-ink, var(--tone, var(--brand)));
  text-transform: uppercase; letter-spacing: .08em;
}
.fork-go .ico { transition: transform var(--dur-1) var(--ease-out); }
.fork-card:hover .fork-go .ico { transform: translateX(3px); }

.quick { display: flex; flex-wrap: wrap; gap: .55rem; margin-top: var(--s-8); }
.quick a {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .55rem 1rem; font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--fg-muted); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  transition: border-color var(--dur-1), color var(--dur-1);
}
.quick a:hover { border-color: var(--brand); color: var(--brand-ink); }

/* A row of plain figures — used on both hub pages. */
.figs {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
  gap: var(--s-6); margin-top: var(--s-8);
  padding: var(--s-6) 0; border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline);
}
.figs div { display: grid; gap: .2rem; }
.figs dt { font-family: var(--font-mono); font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: .1em; color: var(--fg-faint); }
.figs dd { margin: 0; font-family: var(--font-display); font-size: var(--t-xl); font-weight: 700; letter-spacing: -.02em; }

/* ==========================================================================
   16. Responsive
   ========================================================================== */
@media (max-width: 1180px) {
  .layout { grid-template-columns: var(--doc-rail) minmax(0, 1fr); }
  .onthis { display: none; }
}

@media (max-width: 960px) {
  .only-narrow { display: inline-grid; }
  .layout { grid-template-columns: minmax(0, 1fr); }

  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: var(--z-overlay);
    width: min(320px, 86vw); max-height: none;
    padding: var(--s-5) var(--s-5) var(--s-8);
    background: var(--bg); border-right: 1px solid var(--border);
    box-shadow: var(--shadow-xl);
    transform: translateX(-102%);
    /* visibility, not just transform. A translated-off drawer still takes
       keyboard focus and still counts toward the document's scroll width —
       both were real: 24 links tabbable off-screen, and a phantom horizontal
       scrollbar. visibility:hidden removes it from both, and delaying it to
       the end of the slide keeps the close animation visible. */
    visibility: hidden;
    transition: transform var(--dur-2) var(--ease-out),
                visibility 0s linear var(--dur-2);
  }
  .rail-open .sidebar {
    transform: none;
    visibility: visible;
    transition: transform var(--dur-2) var(--ease-out), visibility 0s;
  }
  .rail-x { display: inline-grid; position: absolute; top: var(--s-4); right: var(--s-4); }
  .sidebar-scrim {
    display: block; position: fixed; inset: 0; z-index: calc(var(--z-overlay) - 1);
    background: color-mix(in srgb, var(--band-bg) 55%, transparent);
    backdrop-filter: blur(3px);
  }
  .setswitch { display: none; }
  .topbar-links a span { display: none; }
  .topbar-links a { padding: .45rem .6rem; }
}

@media (max-width: 700px) {
  :root { --doc-gutter: 1.15rem; }
  .step { padding-left: 2.9rem; }
  .step::before { width: 1.9rem; height: 1.9rem; font-size: var(--t-xs); }
  .meta-row { gap: var(--s-5); }
  .topbar-brand small { display: none; }
  .sitefoot-grid { gap: var(--s-6); }
}

/* THE TOPBAR IS A FLEX ROW WITH NOTHING ALLOWED TO SHRINK.

   `.topbar-brand` carries `flex: none`, so at 320px the row came to 394px —
   menu button, brand, links and the theme toggle, plus four 16px gaps — and
   the toggle sat 56px past the edge on all five guides.

   The brand is the only item with slack in it, so it is the one that gives:
   `min-width: 0` lets the flex item shrink and the wordmark truncates. The
   gaps tighten at the same time, which covers the rest. Nothing is hidden —
   every control in this bar is still reachable at 320px. */
@media (max-width: 560px) {
  .topbar { gap: var(--s-2); }
  .topbar-brand { flex: 0 1 auto; min-width: 0; }
  .topbar-brand b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .topbar-links a { padding: .4rem .45rem; }
}

/* The footer grid, below the width where its two narrowest tracks still fit.

   min() inside minmax() (see the base rule) rescues a SINGLE track that is
   wider than its container, but it cannot help when two tracks' minimums add
   up to more than the container: 240px + 150px + a 32px gap needs 422px, and
   a 390px phone gives the grid about 350px. auto-fit always places at least
   one repetition, so the row overflowed and put a horizontal scrollbar on
   every docs page at phone width. Measured at 432px against a 390px viewport.

   Two columns down to 560px, then one. */
@media (max-width: 720px) {
  .sitefoot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-6); }
}
@media (max-width: 560px) {
  .sitefoot-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }
  .chapter-card:hover, .fork-card:hover, .next-card:hover, .pager a:hover { transform: none; }
}

@media print {
  .topbar, .sidebar, .onthis, .sidebar-scrim, .copy, .pager, .skip { display: none !important; }
  .layout { display: block; padding: 0; }
  .sec { break-inside: avoid; }
  .sitefoot { background: none; color: inherit; }
}
