/* =============================================================================
   WILDROOT / HNS.ONE — DESIGN LIBRARY
   One system, two skins (SITES.md D11). Hand-authored plain CSS, no build step.

   POINT OF VIEW — "the specimen sheet"
   -----------------------------------------------------------------------------
   Every block of content opens on a full-width hairline rule whose first 40px
   is a 2px accent tick, and is introduced by a monospaced index label. That
   rule-and-index discipline is the whole structural idea: the page reads as a
   technical specimen sheet rather than a stack of floating cards. Depth comes
   from a three-step background ramp and hairlines — not from drop shadows, of
   which there is exactly one token, reserved for things that genuinely float.
   Two voices: Archivo (sans) speaks to the reader; IBM Plex Mono is the machine
   voice and is used for anything checkable — indices, versions, sizes, hashes,
   status words, table headers, field labels. Colour is almost entirely
   greyscale so the one brand purple stays structural (a rule, a marker, one
   filled button per view) and never becomes wallpaper.

   HARD RULES (see DESIGN.md §"Rules a future editor must not break")
     * --accent is #6e2de5 / #a98ef8. It is the Wildroot browser chrome's
       --ag-color-purple, exactly. Never redefine it, including in a skin.
     * Zero external requests. Fonts are self-hosted from /fonts/.
     * Every token is redefined in all three theme blocks (§2). Nothing in the
       dark theme may inherit a light value.
     * Status is never colour alone: every status carries a shape marker AND
       a word.

   SECTIONS
     §0   Fonts (self-hosted)
     §1   Tokens — colour ramps, light
     §2   Tokens — colour ramps, dark (media + explicit)
     §3   Tokens — type, space, radius, depth, motion, layout
     §4   Reset and base elements
     §5   Layout primitives
     §6   Typography
     §7   Header and navigation
     §8   Hero variants
     §9   Buttons
     §10  Tags, badges, status markers
     §11  Cards, panels, stats
     §12  Feature lists
     §13  Steps
     §14  Tables
     §15  Code, address chips, keys
     §16  Callouts, the honesty block, banners
     §17  Disclosure and FAQ
     §18  Downloads
     §19  Form controls
     §20  Docs shell — sidebar, article prose, table of contents
     §21  Figures and screenshots
     §22  Footer
     §23  Utilities
     §24  Motion, print, forced colours
   ========================================================================== */


/* =============================================================================
   §0  FONTS — self-hosted, zero external requests
   -----------------------------------------------------------------------------
   Latin subsets only (U+0000–00FF plus the usual punctuation), taken from the
   upstream OFL releases. See fonts/README.md for provenance and licences.

   Paths are ROOT-ABSOLUTE (/fonts/…) on purpose: this stylesheet is inlined
   into pages at many depths (/, /download/, /docs/dane/), so a relative URL
   would resolve differently on every page. Deploy copies _lib/fonts/*.woff2 to
   <docroot>/fonts/ on each site.

   The fallback stacks are real, not decorative. If /fonts/ is ever missing the
   pages still read correctly — a little wider, never broken.
   ========================================================================== */
@font-face{
  font-family:"Archivo";
  src:url(/fonts/archivo-latin-var.woff2) format("woff2");
  font-weight:400 700; font-style:normal; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}
/* Real italics — only fetched when a page actually sets italic text. */
@font-face{
  font-family:"Archivo";
  src:url(/fonts/archivo-latin-var-italic.woff2) format("woff2");
  font-weight:400 700; font-style:italic; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}
@font-face{
  font-family:"Plex Mono";
  src:url(/fonts/plexmono-latin-400.woff2) format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Plex Mono";
  src:url(/fonts/plexmono-latin-600.woff2) format("woff2");
  font-weight:600; font-style:normal; font-display:swap;
}


/* =============================================================================
   §1  TOKENS — COLOUR, LIGHT
   -----------------------------------------------------------------------------
   Two ramps and four status hues. The ramps are stops, not semantics: the
   semantic names below them are what components use, so a component never
   reaches into a ramp directly and a re-theme touches one block.

   NEUTRAL RAMP is violet-tinted, anchored on the values the brand already
   shipped (--n-1 = the old --bg, --n-4 = --line, --n-9 = --muted,
   --n-12 = --ink) so nothing in the running panel or browser chrome shifts.
   ACCENT RAMP is built around #6e2de5 at --a-6. That stop is immovable.
   ========================================================================== */
:root{
  color-scheme:light dark;

  /* neutral ramp — 0 is the lightest surface, 12 is text */
  --n-0:#ffffff;
  --n-1:#faf9fc;
  --n-2:#f4f1f9;
  --n-3:#f0edf6;
  --n-4:#e7e3ef;
  --n-5:#d8d3e4;
  --n-6:#bab3ca;
  --n-7:#948ca6;
  --n-8:#6b6380;
  --n-9:#5b5468;
  --n-10:#423c4f;
  --n-11:#2b2636;
  --n-12:#18141f;

  /* accent ramp — --a-6 IS the brand purple; do not move it */
  --a-1:#f8f5fe;
  --a-2:#f3eefd;
  --a-3:#dfd2f8;
  --a-4:#c3a7f5;
  --a-5:#9668ef;
  --a-6:#6e2de5;
  --a-7:#5a1fc4;
  --a-8:#46189a;
  --a-9:#2b0f60;

  /* ---- semantic: ground and surfaces ------------------------------------ */
  --bg:var(--n-1);            /* the page */
  --surface:var(--n-0);       /* cards, tables, inputs — one step up from bg */
  --surface-2:var(--n-2);     /* nested fills, hovers, table heads */
  --sunken:#f7f5fb;           /* code blocks, wells — one step DOWN from bg */
  --panel:var(--surface);     /* legacy alias, kept so app.css markup works */
  --hover:var(--n-2);

  /* ---- semantic: ink ---------------------------------------------------- */
  --ink:var(--n-12);
  --ink-2:var(--n-10);        /* headings inside quieter contexts */
  --muted:var(--n-9);         /* body-weight secondary text — AA on --bg */
  --dim:var(--n-8);           /* metadata, captions — AA at >=14px */
  --faint:var(--n-7);         /* NON-TEXT ONLY — decorative glyphs and rules.
                                 On a near-white ground, AA at 4.5:1 needs a
                                 grey this dark, so there is no third readable
                                 tier below --dim. Quiet text is --dim. */

  /* ---- semantic: rules -------------------------------------------------- */
  --line:var(--n-4);
  --line-soft:var(--n-3);
  --line-strong:var(--n-5);
  --field-line:var(--n-7);  /* form control edges — 3:1 non-text */
  --grid-line:#efecf6;        /* the drafting-grid overlay, deliberately faint */

  /* ---- semantic: accent ------------------------------------------------- */
  --accent:var(--a-6);
  --accent-hover:var(--a-7);
  --accent-active:var(--a-8);
  --accent-ink:#ffffff;       /* text ON accent */
  --accent-soft:var(--a-2);   /* tinted chips, selected nav */
  --accent-line:var(--a-3);
  --accent-text:var(--a-7);   /* accent used AS text on --bg: darker for AA */

  /* ---- semantic: status. Each has ink / tint / rule. -------------------- */
  --ok:#12703a;      --ok-bg:#ebf6ef;   --ok-line:#b9dcc6;
  --info:#1f5590;    --info-bg:#eaf1f9; --info-line:#b6cee6;
  --warn:#8a5300;    --warn-bg:#fdf6e9; --warn-line:#e6d3a8;
  --bad:#9c1830;     --bad-bg:#fdeef0;  --bad-line:#eec2ca; --bad-ink:#ffffff;

  /* the honesty block. Ochre, but the block is a SURFACE with an ochre rule,
     not a yellow box — see §16. */
  --note-bg:#fdfbf5;  --note-line:#eadfc4; --note-rule:#b4741c; --note-ink:#7a4e12;

  /* ---- semantic: depth -------------------------------------------------- */
  --shadow-1:0 1px 2px rgb(24 20 31/.06);
  --shadow-2:0 1px 2px rgb(24 20 31/.05),0 8px 24px -8px rgb(24 20 31/.14);
  --shadow-3:0 2px 6px rgb(24 20 31/.07),0 24px 48px -16px rgb(24 20 31/.22);
  --shadow:var(--shadow-2);   /* legacy alias */
  --btn-gloss:inset 0 1px 0 rgb(255 255 255/.18);  /* 1px top light on fills */
  --selection:var(--a-2);
  --scroll-shade:rgb(24 20 31/.14);  /* the shadow at a scroller's edge */
}


/* =============================================================================
   §2  TOKENS — COLOUR, DARK
   -----------------------------------------------------------------------------
   Defined twice, on purpose:
     (a) under prefers-color-scheme, guarded by :not([data-theme="light"]) so an
         explicit light choice beats the OS;
     (b) under [data-theme="dark"] so an explicit dark choice beats a light OS.
   The two blocks are byte-identical below their selectors. If you edit one,
   edit the other — there is no shortcut that keeps both an OS preference and an
   explicit override working.

   EVERY token from §1 is restated. Nothing inherits a light value.
   ========================================================================== */
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  color-scheme:dark;
  --n-0:#0c0a10; --n-1:#131017; --n-2:#1b1723; --n-3:#221d2d; --n-4:#2d2839;
  --n-5:#3b3549; --n-6:#574f6b; --n-7:#6f6784; --n-8:#8b8399; --n-9:#a49cb6;
  --n-10:#c4bcd6; --n-11:#dad4e8; --n-12:#eeeaf6;
  --a-1:#181130; --a-2:#2a2144; --a-3:#3f3363; --a-4:#5c4a90; --a-5:#8067c9;
  --a-6:#a98ef8; --a-7:#bba4fa; --a-8:#d3c5fc; --a-9:#ece5fe;
  --bg:var(--n-1); --surface:var(--n-2); --surface-2:var(--n-3);
  --sunken:var(--n-0); --panel:var(--surface); --hover:var(--n-3);
  --ink:var(--n-12); --ink-2:var(--n-11); --muted:var(--n-9); --dim:var(--n-8);
  --faint:var(--n-7);
  --line:var(--n-4); --line-soft:var(--n-3); --line-strong:var(--n-5);
  --field-line:var(--n-7);
  --grid-line:#1d1926;
  --accent:var(--a-6); --accent-hover:var(--a-7); --accent-active:var(--a-8);
  --accent-ink:#160b2e; --accent-soft:var(--a-2); --accent-line:var(--a-3);
  --accent-text:var(--a-6);
  --ok:#63d894;   --ok-bg:#123023;   --ok-line:#28553d;
  --info:#82b6ec; --info-bg:#12243a; --info-line:#2a4a6b;
  --warn:#e0b45c; --warn-bg:#2a2010; --warn-line:#4c3d1c;
  --bad:#f792a6;  --bad-bg:#331520;  --bad-line:#5c2634; --bad-ink:#2b0710;
  --note-bg:#1a1610; --note-line:#3a3020; --note-rule:#dfae3c; --note-ink:#e6bf74;
  --shadow-1:0 1px 2px rgb(0 0 0/.5);
  --shadow-2:0 1px 2px rgb(0 0 0/.5),0 8px 24px -8px rgb(0 0 0/.6);
  --shadow-3:0 2px 6px rgb(0 0 0/.5),0 24px 48px -16px rgb(0 0 0/.7);
  --shadow:var(--shadow-2);
  --btn-gloss:inset 0 1px 0 rgb(255 255 255/.10);
  --selection:var(--a-3);
  --scroll-shade:rgb(0 0 0/.55);
}}
:root[data-theme="dark"]{
  color-scheme:dark;
  --n-0:#0c0a10; --n-1:#131017; --n-2:#1b1723; --n-3:#221d2d; --n-4:#2d2839;
  --n-5:#3b3549; --n-6:#574f6b; --n-7:#6f6784; --n-8:#8b8399; --n-9:#a49cb6;
  --n-10:#c4bcd6; --n-11:#dad4e8; --n-12:#eeeaf6;
  --a-1:#181130; --a-2:#2a2144; --a-3:#3f3363; --a-4:#5c4a90; --a-5:#8067c9;
  --a-6:#a98ef8; --a-7:#bba4fa; --a-8:#d3c5fc; --a-9:#ece5fe;
  --bg:var(--n-1); --surface:var(--n-2); --surface-2:var(--n-3);
  --sunken:var(--n-0); --panel:var(--surface); --hover:var(--n-3);
  --ink:var(--n-12); --ink-2:var(--n-11); --muted:var(--n-9); --dim:var(--n-8);
  --faint:var(--n-7);
  --line:var(--n-4); --line-soft:var(--n-3); --line-strong:var(--n-5);
  --field-line:var(--n-7);
  --grid-line:#1d1926;
  --accent:var(--a-6); --accent-hover:var(--a-7); --accent-active:var(--a-8);
  --accent-ink:#160b2e; --accent-soft:var(--a-2); --accent-line:var(--a-3);
  --accent-text:var(--a-6);
  --ok:#63d894;   --ok-bg:#123023;   --ok-line:#28553d;
  --info:#82b6ec; --info-bg:#12243a; --info-line:#2a4a6b;
  --warn:#e0b45c; --warn-bg:#2a2010; --warn-line:#4c3d1c;
  --bad:#f792a6;  --bad-bg:#331520;  --bad-line:#5c2634; --bad-ink:#2b0710;
  --note-bg:#1a1610; --note-line:#3a3020; --note-rule:#dfae3c; --note-ink:#e6bf74;
  --shadow-1:0 1px 2px rgb(0 0 0/.5);
  --shadow-2:0 1px 2px rgb(0 0 0/.5),0 8px 24px -8px rgb(0 0 0/.6);
  --shadow-3:0 2px 6px rgb(0 0 0/.5),0 24px 48px -16px rgb(0 0 0/.7);
  --shadow:var(--shadow-2);
  --btn-gloss:inset 0 1px 0 rgb(255 255 255/.10);
  --selection:var(--a-3);
  --scroll-shade:rgb(0 0 0/.55);
}
:root[data-theme="light"]{color-scheme:light}


/* =============================================================================
   §3  TOKENS — TYPE, SPACE, RADIUS, DEPTH, MOTION, LAYOUT
   -----------------------------------------------------------------------------
   These are the knobs a SKIN turns. Colour is not.
   ========================================================================== */
:root{
  /* ---- families --------------------------------------------------------- */
  --font-sans:"Archivo",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,
    "Helvetica Neue",Arial,sans-serif;
  --font-mono:"Plex Mono",ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,
    "Liberation Mono",monospace;
  --font-display:var(--font-sans);

  /* ---- type scale ------------------------------------------------------
     A considered scale, not a formula: tight steps in the reading range where
     hierarchy is subtle, wide jumps at display sizes where it must be obvious.
     px equivalents at a 16px root are in the comments. */
  --fs-2xs:.6875rem;   /* 11 — mono micro labels, tags */
  --fs-xs:.75rem;      /* 12 — table heads, field labels */
  --fs-sm:.8125rem;    /* 13 — code, metadata */
  --fs-md:.875rem;     /* 14 — UI text, nav, buttons, captions */
  --fs-base:1rem;      /* 16 — body */
  --fs-lg:1.125rem;    /* 18 — lede, large body */
  --fs-xl:1.3125rem;   /* 21 — h3 large / card titles on wildroot */
  --fs-2xl:1.5rem;     /* 24 — h2 */
  --fs-3xl:1.875rem;   /* 30 — h2 display / small hero */
  --fs-4xl:2.375rem;   /* 38 */
  --fs-5xl:3rem;       /* 48 */
  --fs-6xl:3.75rem;    /* 60 */
  /* the one fluid step; skins re-clamp it */
  --fs-display:clamp(2.125rem,1.45rem + 2.9vw,3.25rem);

  /* ---- line heights ----------------------------------------------------- */
  --lh-display:1.06;
  --lh-head:1.2;
  --lh-body:1.6;
  --lh-tight:1.4;
  --lh-mono:1.55;

  /* ---- tracking. Big type gets negative, small caps get positive. ------- */
  --track-display:-.032em;
  --track-head:-.02em;
  --track-body:0em;
  --track-label:.08em;   /* sans micro-labels */
  --track-mono:.06em;    /* mono uppercase labels — mono is already wide */

  /* ---- weights ---------------------------------------------------------- */
  --w-body:400; --w-med:500; --w-semi:600; --w-bold:700;

  /* ---- spacing scale — 4px base, every value a multiple ----------------- */
  --s1:.25rem; --s2:.5rem;  --s3:.75rem; --s4:1rem;  --s5:1.5rem;
  --s6:2rem;   --s7:3rem;   --s8:4rem;   --s9:6rem;  --s10:8rem;

  /* ---- rhythm knobs the skins turn ------------------------------------- */
  --wrap:70rem;          /* the outer measure */
  --gutter:1.25rem;      /* page side padding */
  --measure:68ch;        /* prose measure */
  --measure-tight:52ch;  /* ledes, sub-heads */
  --section-y:var(--s8); /* vertical air between sections */
  --hero-y:var(--s8);
  --stack:var(--s4);     /* default gap inside .stack */
  --row-y:.7rem;         /* table cell padding-block */
  --field-h:2.5rem;      /* one height for every form control */
  --tap:1.5rem;          /* 24px minimum tap target */

  /* ---- radii. Small and consistent — precision, not pillows. ------------ */
  --r-none:0; --r-sm:4px; --r:8px; --r-lg:12px; --r-pill:999px;

  /* ---- motion ----------------------------------------------------------- */
  --dur-1:110ms; --dur-2:190ms; --dur-3:320ms;
  --ease:cubic-bezier(.2,.6,.25,1);
  --ease-out:cubic-bezier(.16,1,.3,1);

  /* ---- the signature: section rule + accent tick ------------------------ */
  --tick-w:2.5rem;   /* length of the accent segment that opens a rule */
  --tick-h:2px;
}


/* =============================================================================
   §4  RESET AND BASE ELEMENTS
   -----------------------------------------------------------------------------
   Deliberately small. Anything that is really a component lives below.
   ========================================================================== */
*,*::before,*::after{box-sizing:border-box}
*{margin:0;padding:0}
html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  scroll-padding-top:5rem;      /* sticky header must not eat anchor targets */
  text-size-adjust:100%;
}
body{
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-sans);
  font-size:var(--fs-base);
  line-height:var(--lh-body);
  font-weight:var(--w-body);
  letter-spacing:var(--track-body);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  font-synthesis-weight:none;   /* never fake a weight the variable font has */
  overflow-wrap:break-word;
  /* RESPONSIVE FLOOR: nothing may push the body sideways. Wide content
     scrolls inside its own container (.scroll, .tw, pre). */
  overflow-x:hidden;
}
img,svg,video,canvas{display:block;max-width:100%}
img,video{height:auto}
svg{fill:none}
a{color:var(--accent-text);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:.15em;
  text-decoration-thickness:1px}
strong,b{font-weight:var(--w-semi)}
em,i{font-style:italic}
small{font-size:var(--fs-md)}
hr{border:0;border-top:1px solid var(--line);margin:var(--s6) 0}
ul,ol{padding-left:1.15rem}
li{margin:.35rem 0}
::selection{background:var(--selection);color:var(--ink)}

/* Focus. One visible treatment everywhere, on top of everything, never removed.
   The 2px offset ring plus a 1px contrast halo keeps it visible on both the
   page ground and on filled buttons. */
:focus{outline:none}
:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
  border-radius:var(--r-sm);
}
.btn:focus-visible,.tag:focus-visible,summary:focus-visible{
  box-shadow:0 0 0 2px var(--bg);
}

/* Skip link — visible on focus, or it is a trap that announces itself. */
.skip{position:absolute;left:-9999px;top:0;z-index:60}
.skip:focus{
  left:var(--s3);top:var(--s3);
  background:var(--accent);color:var(--accent-ink);
  padding:.6rem 1rem;border-radius:var(--r);
  font-weight:var(--w-semi);font-size:var(--fs-md);
  box-shadow:var(--shadow-2);
}
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;
}


/* =============================================================================
   §5  LAYOUT PRIMITIVES
   -----------------------------------------------------------------------------
   .wrap      the page measure
   .sect      a ruled section — THE structural unit (rule + accent tick)
   .stack     vertical rhythm without margin collapse surprises
   .cluster   horizontal wrap group
   .split     asymmetric two-column (never 50/50 — see DESIGN.md)
   .rail      narrow mono metadata column beside a measure
   .scroll    the escape hatch for anything wider than the viewport
   ========================================================================== */
.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gutter)}
.wrap.narrow{max-width:56rem}
.wrap.wide{max-width:84rem}

/* --- the ruled section. The accent tick is drawn ON the rule, flush with the
   content edge, so the rule always starts with the brand. ------------------ */
.sect{position:relative;padding-block:var(--section-y);counter-increment:sect}
.sect + .sect,.sect.ruled{border-top:1px solid var(--line)}
.sect.ruled::before,.sect + .sect::before{
  content:"";position:absolute;top:-1px;left:0;right:0;height:var(--tick-h);
  pointer-events:none;
  background:linear-gradient(var(--accent),var(--accent)) no-repeat;
  background-size:var(--tick-w) var(--tick-h);
  /* Park the tick on the CONTENT edge at every width, with no media query.
     A percentage in background-position resolves against (box - image), so
     `50% + tick/2` is exactly the box's midpoint; subtract half the wrap and
     add the gutter and you land on the text edge. Once the viewport is
     narrower than the wrap that expression goes below the gutter, and max()
     pins it back to the gutter — which is then the text edge anyway. */
  background-position:max(var(--gutter),
    calc(50% + var(--tick-w)/2 - var(--wrap)/2 + var(--gutter))) 0;
}
.sect.tight{padding-block:var(--s6)}
.sect.flush-top{padding-top:0}

/* A standalone rule with the same signature, for use inside a section. */
.rule{position:relative;height:1px;background:var(--line);margin-block:var(--s6);
  border:0}
.rule.accent::before{content:"";position:absolute;top:0;left:0;
  width:var(--tick-w);height:var(--tick-h);background:var(--accent)}

/* --- stack: the owl. One gap token, no collapsing margins. --------------- */
.stack > * + *{margin-top:var(--stack)}
.stack.gap-sm{--stack:var(--s2)}
.stack.gap-md{--stack:var(--s4)}
.stack.gap-lg{--stack:var(--s6)}

/* --- cluster: a wrapping row of things. --------------------------------- */
.cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3)}
.cluster.gap-sm{gap:var(--s2)}
.cluster.gap-lg{gap:var(--s5)}
.cluster.between{justify-content:space-between}
.cluster.end{justify-content:flex-end}
.cluster.baseline{align-items:baseline}

/* --- split: asymmetric two-column. 7:5 by default. ---------------------- */
.split{display:grid;gap:var(--s7);grid-template-columns:7fr 5fr;align-items:start}
.split.reverse{grid-template-columns:5fr 7fr}
.split.even{grid-template-columns:1fr 1fr}
.split.wide-left{grid-template-columns:8fr 4fr}
/* legacy alias used by the current pages */
.band{display:grid;gap:var(--s6);grid-template-columns:1.1fr .9fr;align-items:start}
@media (max-width:56rem){
  .split,.split.reverse,.split.even,.split.wide-left,.band{grid-template-columns:1fr;gap:var(--s5)}
}

/* --- rail: the mono metadata column. The vertical hairline is the point. -- */
.rail-grid{display:grid;grid-template-columns:minmax(0,1fr) 15rem;gap:var(--s7);
  align-items:start}
.rail-grid.left{grid-template-columns:11rem minmax(0,1fr)}
.rail{font-family:var(--font-mono);font-size:var(--fs-sm);line-height:var(--lh-mono);
  color:var(--dim);font-variant-numeric:tabular-nums}
.rail-grid > .rail{border-left:1px solid var(--line);padding-left:var(--s5)}
.rail-grid.left > .rail{border-left:0;border-right:1px solid var(--line);
  padding-left:0;padding-right:var(--s5);text-align:right}
.rail dt,.rail .k{color:var(--dim);text-transform:uppercase;
  letter-spacing:var(--track-mono);font-size:var(--fs-2xs)}
.rail dd,.rail .v{color:var(--ink);margin:0 0 var(--s3)}
@media (max-width:56rem){
  .rail-grid,.rail-grid.left{grid-template-columns:1fr;gap:var(--s5)}
  .rail-grid > .rail,.rail-grid.left > .rail{
    border:0;border-top:1px solid var(--line);padding:var(--s4) 0 0;text-align:left}
}

/* --- scroll: wide content scrolls inside itself, never the body. --------- */
.scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}

/* --- the drafting-grid overlay. Structural, faint, opt-in. --------------- */
.gridded{position:relative;isolation:isolate}
.gridded::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:repeating-linear-gradient(90deg,
    var(--grid-line) 0 1px,transparent 1px calc(100%/12));
  background-size:calc(min(var(--wrap),100%) - var(--gutter)*2) 100%;
  background-position:center top;background-repeat:no-repeat;
  mask-image:linear-gradient(180deg,#000,transparent 85%);
}
@media (max-width:56rem){.gridded::before{display:none}}

/* --- corner ticks. Registration marks instead of a drop shadow. Use on at
   most one element per screen — see DESIGN.md. --------------------------- */
.ticks{position:relative}
/* Drawn INSIDE the box, not around it: a framed figure clips its overflow, and
   registration marks that get clipped are worse than none. */
.ticks::after{
  content:"";position:absolute;inset:7px;pointer-events:none;z-index:1;
  --tick:var(--accent);--tl:10px;
  background:
    linear-gradient(var(--tick),var(--tick)) 0 0/var(--tl) 1px no-repeat,
    linear-gradient(var(--tick),var(--tick)) 0 0/1px var(--tl) no-repeat,
    linear-gradient(var(--tick),var(--tick)) 100% 0/var(--tl) 1px no-repeat,
    linear-gradient(var(--tick),var(--tick)) 100% 0/1px var(--tl) no-repeat,
    linear-gradient(var(--tick),var(--tick)) 0 100%/var(--tl) 1px no-repeat,
    linear-gradient(var(--tick),var(--tick)) 0 100%/1px var(--tl) no-repeat,
    linear-gradient(var(--tick),var(--tick)) 100% 100%/var(--tl) 1px no-repeat,
    linear-gradient(var(--tick),var(--tick)) 100% 100%/1px var(--tl) no-repeat;
}


/* =============================================================================
   §6  TYPOGRAPHY
   -----------------------------------------------------------------------------
   Two voices.
     SANS  (Archivo)   — the human voice. Headings, prose, buttons, nav.
     MONO  (Plex Mono) — the machine voice. Anything a reader could check:
                         indices, versions, sizes, hashes, hostnames, status
                         words, table heads, field labels, keyboard keys.
   The rule for editors: if a person wrote it, it is sans. If a machine
   produced it or a machine consumes it, it is mono.
   ========================================================================== */
h1,h2,h3,h4,h5,h6{
  font-family:var(--font-display);
  font-weight:var(--w-semi);
  line-height:var(--lh-head);
  letter-spacing:var(--track-head);
  color:var(--ink);
  text-wrap:balance;
}
h1{font-size:var(--fs-3xl);font-weight:var(--w-bold);letter-spacing:var(--track-display)}
h2{font-size:var(--fs-2xl);font-weight:var(--w-semi)}
h3{font-size:var(--fs-lg);font-weight:var(--w-semi);letter-spacing:-.012em}
h4{font-size:var(--fs-base);font-weight:var(--w-semi);letter-spacing:-.008em}
h5,h6{font-size:var(--fs-md);font-weight:var(--w-semi)}

/* --- the display size. Only one per page. -------------------------------- */
.display{
  font-size:var(--fs-display);
  line-height:var(--lh-display);
  letter-spacing:var(--track-display);
  font-weight:var(--w-bold);
  max-width:18ch;
  text-wrap:balance;
}
.display.long{max-width:26ch}
/* One phrase in the headline may carry the accent. One. */
.display em,.display .hl,h1 .hl{font-style:normal;color:var(--accent-text)}

/* --- eyebrow: the mono index label that opens every block. --------------- */
.eyebrow{
  display:flex;align-items:center;gap:var(--s3);
  font-family:var(--font-mono);
  font-size:var(--fs-2xs);
  font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);
  text-transform:uppercase;
  color:var(--dim);
  margin-bottom:var(--s3);
}
.eyebrow .idx{color:var(--accent-text);font-variant-numeric:tabular-nums}
/* CSS supplies the number when the markup does not: <span class="idx auto"></span> */
.eyebrow .idx.auto::before{content:counter(sect,decimal-leading-zero)}
.eyebrow::after{content:"";flex:1 1 auto;height:1px;background:var(--line);
  min-width:var(--s5)}
.eyebrow.bare::after{display:none}

/* --- kicker: a standalone pill-free flag above a hero headline. ---------- */
.kicker{
  display:inline-flex;align-items:center;gap:var(--s2);
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;
  color:var(--accent-text);
  padding:.3rem 0 .3rem .7rem;
  border-left:var(--tick-h) solid var(--accent);
  margin-bottom:var(--s4);
}

/* --- lede and section sub. ---------------------------------------------- */
.lede{font-size:var(--fs-lg);line-height:1.55;color:var(--muted);
  max-width:var(--measure-tight);letter-spacing:-.006em}
.sect-sub{color:var(--muted);max-width:var(--measure);margin-top:var(--s3)}

/* --- section head block -------------------------------------------------- */
.sect-head{margin-bottom:var(--s6);max-width:var(--measure)}
.sect-head h2{max-width:22ch;text-wrap:balance}

/* --- micro copy ---------------------------------------------------------- */
.micro{font-size:var(--fs-xs);color:var(--dim);line-height:var(--lh-tight)}
.meta{font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--dim);
  font-variant-numeric:tabular-nums;letter-spacing:0}
.mono{font-family:var(--font-mono);font-size:.92em;letter-spacing:0}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.muted{color:var(--muted)}
.dim{color:var(--dim)}
.label{font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim)}

/* Paragraph rhythm inside free-flowing content. */
p{max-width:var(--measure)}
p + p{margin-top:var(--s4)}

/* --- heading rhythm in free-flowing content ------------------------------
   ADDED 2026-08-24. Headings carried NO margin at all: the library assumed
   every heading arrives inside a `.sect-head` (which has its own spacing) or
   opens its own `<section>`. Real prose pages run several h2 sections inside
   one section, and every one of them butted straight onto the paragraph above
   — the whole page read as one squashed block. Components that set their own
   heading margins (`.card h3`, `.steps h3`) are more specific and still win. */
h2{margin-top:var(--s7)}
h3{margin-top:var(--s6)}
h4{margin-top:var(--s5)}
:is(h2,h3,h4) + p,
:is(h2,h3,h4) + .scroll,
:is(h2,h3,h4) + ul,
:is(h2,h3,h4) + ol,
:is(h2,h3,h4) + pre{margin-top:var(--s3)}
/* never open a block with a gap above its first line */
:is(h1,h2,h3,h4):first-child{margin-top:0}
.sect-head :is(h2,h3,h4),
.hero :is(h1,h2),
.note :is(h3,h4),
.qa :is(h2,h3,h4){margin-top:0}


/* =============================================================================
   §7  HEADER AND NAVIGATION
   -----------------------------------------------------------------------------
   Opaque sticky bar on a hairline. No blur, no translucency — the page ground
   is a designed colour and we do not want it smeared. The current page is
   marked by a 2px accent segment that sits ON the header's bottom rule: the
   active indicator is literally part of the rule system.

   Mobile: the nav wraps onto a second ruled row. No hamburger, no JS.
   ========================================================================== */
.site-head{
  position:sticky;top:0;z-index:40;
  background:var(--bg);
  border-bottom:1px solid var(--line);
}
.site-head > .wrap{
  display:flex;align-items:center;gap:var(--s5);
  min-height:3.75rem;
}
.brand{
  display:inline-flex;align-items:center;gap:.55rem;
  color:var(--ink);font-weight:var(--w-bold);
  font-size:1.0625rem;letter-spacing:-.022em;
  flex:none;
}
.brand:hover{color:var(--ink);text-decoration:none}
.brand .mark{
  width:1.5rem;height:1.5rem;flex:none;
  border-radius:var(--r-sm);
  background:var(--accent);color:var(--accent-ink);
  display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--font-mono);font-size:.75rem;font-weight:var(--w-semi);
  line-height:1;box-shadow:var(--btn-gloss);
}
.brand .word{white-space:nowrap}
/* the quiet half of a two-part wordmark, e.g. HNS<i>.ONE</i> */
.brand i{font-style:normal;color:var(--dim);font-weight:var(--w-med)}

.site-nav{display:flex;align-items:center;gap:var(--s1);flex-wrap:wrap;
  margin-left:auto}
.site-nav a{
  position:relative;
  color:var(--muted);font-size:var(--fs-md);font-weight:var(--w-med);
  padding:.5rem .7rem;border-radius:var(--r-sm);
  min-height:var(--tap);display:inline-flex;align-items:center;
  transition:color var(--dur-1) var(--ease),background var(--dur-1) var(--ease);
}
.site-nav a:hover{color:var(--ink);background:var(--hover);text-decoration:none}
.site-nav a[aria-current]{color:var(--ink);font-weight:var(--w-semi)}
/* the accent segment lands exactly on the header rule */
.site-nav a[aria-current]::after{
  content:"";position:absolute;left:.7rem;right:.7rem;
  bottom:calc(-1 * (3.75rem - 100%) / 2 - 1px);
  height:var(--tick-h);background:var(--accent);
}
.site-nav .btn{margin-left:var(--s2)}
.site-nav a.btn{color:var(--accent-ink);font-weight:var(--w-semi)}
.site-nav a.btn:hover{color:var(--accent-ink)}
.site-nav a.btn.ghost{color:var(--ink)}
.site-nav a.btn::after{display:none}

@media (max-width:52rem){
  .site-head > .wrap{flex-wrap:wrap;gap:var(--s3);padding-block:.55rem}
  .site-nav{margin-left:auto}
  .site-nav a[aria-current]::after{bottom:.15rem;left:.7rem;right:.7rem}
}
/* Below 34rem the nav needs a second row. A sticky header that tall eats a
   sixth of a phone screen, and a horizontally scrolling nav hides the download
   button off the right edge — so here the header stops being sticky and the
   nav wraps. Everything stays visible; nothing scrolls sideways. */
@media (max-width:34rem){
  .site-head{position:static}
  .site-head > .wrap{padding-bottom:0}
  .site-nav{
    width:100%;margin-left:0;order:3;flex-wrap:wrap;
    border-top:1px solid var(--line-soft);
    padding:.45rem 0 .6rem;
    gap:var(--s1) 0;
  }
  .site-nav a{white-space:nowrap}
  .site-nav .btn{margin-left:auto}
}


/* =============================================================================
   §8  HERO VARIANTS
   -----------------------------------------------------------------------------
   .hero            editorial default — measure on the left, mono spec rail on
                    the right, hairline top and bottom. No gradient band.
   .hero.center     short pages: one centred measure, still ruled.
   .hero.compact    docs/interior page header.
   .hero.figure     product shot on the right (wildroot.io).
   ========================================================================== */
.hero{
  position:relative;
  padding-block:var(--hero-y) calc(var(--hero-y) * .8);
  border-bottom:1px solid var(--line);
  background:var(--bg);
}
.hero > .wrap{display:grid;grid-template-columns:minmax(0,1fr) 14rem;
  gap:var(--s7);align-items:stretch}
.hero.no-rail > .wrap{grid-template-columns:minmax(0,1fr)}
.hero h1{
  font-size:var(--fs-display);line-height:var(--lh-display);
  letter-spacing:var(--track-display);font-weight:var(--w-bold);
  max-width:19ch;text-wrap:balance;margin-bottom:var(--s4);
}
.hero h1 span,.hero h1 em{font-style:normal;color:var(--accent-text)}
.hero .lede{max-width:46ch}
.hero .cta{margin-top:var(--s5)}

/* the spec rail: version, platforms, licence — mono, right-hand, hairlined */
/* The rail's hairline runs the full height of the hero; its content sits at
   the bottom, level with the call to action. */
.hero-spec{
  display:flex;flex-direction:column;justify-content:flex-end;
  border-left:1px solid var(--line);padding-left:var(--s5);
  font-family:var(--font-mono);font-size:var(--fs-sm);
  color:var(--dim);font-variant-numeric:tabular-nums;
}
.hero-spec dl{display:grid;gap:var(--s3)}
.hero-spec dt{font-size:var(--fs-2xs);text-transform:uppercase;
  letter-spacing:var(--track-mono);color:var(--dim)}
.hero-spec dd{color:var(--ink);margin:0}

.hero.center > .wrap{grid-template-columns:minmax(0,1fr);justify-items:center;
  text-align:center}
.hero.center h1,.hero.center .lede{max-width:24ch;margin-inline:auto}
.hero.center .lede{max-width:52ch}
.hero.center .kicker{border-left:0;border-top:var(--tick-h) solid var(--accent);
  padding:.55rem 0 0}
.hero.center .cta{justify-content:center}

.hero.compact{padding-block:var(--s7) var(--s6)}
.hero.compact > .wrap{grid-template-columns:minmax(0,1fr);gap:var(--s4)}
.hero.compact h1{font-size:var(--fs-3xl);max-width:24ch;margin-bottom:var(--s3)}
.hero.compact .lede{font-size:var(--fs-base);max-width:var(--measure)}

.hero.figure > .wrap{grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
  align-items:center}

/* the call-to-action cluster */
.cta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3)}
.cta .also{font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--dim);
  margin-left:var(--s2)}

@media (max-width:56rem){
  .hero > .wrap,.hero.figure > .wrap{grid-template-columns:minmax(0,1fr);
    gap:var(--s5);align-items:start}
  .hero-spec{border-left:0;border-top:1px solid var(--line);padding:var(--s4) 0 0}
  .hero-spec dl{grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));
    display:grid}
}


/* =============================================================================
   §9  BUTTONS
   -----------------------------------------------------------------------------
   One shape, four intents, three sizes.
     .btn            primary — the accent fill. AT MOST ONE per screen region.
     .btn.ghost      the ordinary choice — outlined, ink text.
     .btn.quiet      tertiary — text with a hover ground, no border.
     .btn.danger     destructive — outlined in --bad, NEVER shaped like primary,
                     so a destructive action can never be mistaken for the safe
                     one sitting next to it. .danger.solid only for the final
                     confirm inside a dialog that is already about deleting.
   Every size clears the 24px minimum target; the default clears 40px.
   ========================================================================== */
.btn{
  --btn-h:2.5rem;
  display:inline-flex;align-items:center;justify-content:center;gap:.45rem;
  min-height:var(--btn-h);
  padding:0 1rem;
  border:1px solid var(--accent);
  border-radius:var(--r);
  background:var(--accent);
  color:var(--accent-ink);
  box-shadow:var(--btn-gloss);
  font-family:var(--font-sans);
  font-size:var(--fs-md);font-weight:var(--w-semi);letter-spacing:-.006em;
  line-height:1;
  text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:background var(--dur-1) var(--ease),
             border-color var(--dur-1) var(--ease),
             color var(--dur-1) var(--ease);
}
.btn:hover{background:var(--accent-hover);border-color:var(--accent-hover);
  color:var(--accent-ink);text-decoration:none}
.btn:active{background:var(--accent-active);border-color:var(--accent-active)}
.btn svg{width:1.05em;height:1.05em;flex:none}
/* a trailing arrow that nudges — the only motion a button is allowed */
.btn .arrow{transition:transform var(--dur-2) var(--ease-out)}
.btn:hover .arrow{transform:translateX(2px)}

.btn.ghost,.btn.secondary{
  background:var(--surface);color:var(--ink);border-color:var(--line);
  box-shadow:none;
}
.btn.ghost:hover,.btn.secondary:hover{background:var(--hover);
  border-color:var(--line-strong);color:var(--ink)}

.btn.quiet{background:transparent;color:var(--muted);border-color:transparent;
  box-shadow:none;font-weight:var(--w-med)}
.btn.quiet:hover{background:var(--hover);color:var(--ink);border-color:transparent}

.btn.danger{background:transparent;color:var(--bad);border-color:var(--bad-line);
  box-shadow:none}
.btn.danger:hover{background:var(--bad-bg);border-color:var(--bad);color:var(--bad)}
/* the filled destructive button. Only for the final confirm inside a dialog
   that is already about deleting — never as the primary action on a page. */
.btn.danger.solid{background:var(--bad);border-color:var(--bad);
  color:var(--bad-ink);box-shadow:var(--btn-gloss)}
.btn.danger.solid:hover{background:var(--bad);border-color:var(--bad);
  color:var(--bad-ink);filter:brightness(1.08)}

.btn.sm{--btn-h:2rem;padding:0 .7rem;font-size:var(--fs-sm);border-radius:var(--r-sm)}
.btn.lg{--btn-h:3rem;padding:0 1.35rem;font-size:var(--fs-base)}
.btn.block{display:flex;width:100%}
.btn.icon{padding:0;width:var(--btn-h);aspect-ratio:1}

.btn[disabled],.btn[aria-disabled="true"],.btn.is-disabled{
  opacity:.45;cursor:not-allowed;pointer-events:none;
}

/* A text link that behaves like an action. Keeps the 24px target. */
.link-action{
  display:inline-flex;align-items:center;gap:.35rem;min-height:var(--tap);
  font-weight:var(--w-med);font-size:var(--fs-md);color:var(--accent-text);
}
.link-action .arrow{transition:transform var(--dur-2) var(--ease-out)}
.link-action:hover .arrow{transform:translateX(2px)}


/* =============================================================================
   §10  TAGS, BADGES, STATUS MARKERS
   -----------------------------------------------------------------------------
   STATUS IS NEVER COLOUR ALONE. Every tag carries a shape marker and the word.
   The shape is pseudo-content with an empty alt (`content:"●" / ""`) so screen
   readers hear the word, not the glyph.

     .tag.live / .ok        ●  shipped, working
     .tag.beta / .info      ◆  experimental, caveated
     .tag.soon / .planned   ○  not built yet
     .tag.warn              ▲  needs attention
     .tag.bad               ✕  failed, off
   ========================================================================== */
.tag{
  display:inline-flex;align-items:center;gap:.35rem;
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;line-height:1;
  padding:.28rem .5rem;
  border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--surface);color:var(--dim);
  vertical-align:.1em;white-space:nowrap;
}
.tag::before{content:"○" / "";font-size:.9em;line-height:1}
h3 .tag,h2 .tag,h4 .tag{margin-left:.5rem}

.tag.live,.tag.ok,.tag.o{color:var(--ok);border-color:var(--ok-line);background:var(--ok-bg)}
.tag.live::before,.tag.ok::before,.tag.o::before{content:"●" / ""}

.tag.beta,.tag.info,.tag.experimental,.tag.u{
  color:var(--info);border-color:var(--info-line);background:var(--info-bg)}
.tag.beta::before,.tag.info::before,.tag.experimental::before,.tag.u::before{content:"◆" / ""}

.tag.soon,.tag.planned,.tag.off,.tag.s{color:var(--dim);border-color:var(--line);
  background:transparent}
.tag.soon::before,.tag.planned::before,.tag.off::before,.tag.s::before{content:"○" / ""}

.tag.warn,.tag.c{color:var(--warn);border-color:var(--warn-line);background:var(--warn-bg)}
.tag.warn::before,.tag.c::before{content:"▲" / ""}

.tag.bad,.tag.critical,.tag.x{color:var(--bad);border-color:var(--bad-line);
  background:var(--bad-bg)}
.tag.bad::before,.tag.critical::before,.tag.x::before{content:"✕" / ""}

.tag.accent{color:var(--accent-text);border-color:var(--accent-line);
  background:var(--accent-soft)}
.tag.accent::before{content:"◆" / ""}
.tag.plain::before{display:none}
.tag.pill{border-radius:var(--r-pill);padding-inline:.6rem}

/* An inline status word in running text — same rule, no box. */
.status{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--font-mono);
  font-size:.9em;font-weight:var(--w-semi)}
.status::before{content:"●" / "";font-size:.8em}
.status.ok{color:var(--ok)} .status.info{color:var(--info)}
.status.warn{color:var(--warn)} .status.warn::before{content:"▲" / ""}
.status.bad{color:var(--bad)}  .status.bad::before{content:"✕" / ""}
.status.off{color:var(--dim)}  .status.off::before{content:"○" / ""}


/* =============================================================================
   §11  CARDS, PANELS, STATS
   -----------------------------------------------------------------------------
   .grid            auto-fit card grid
   .grid.ruled      THE PREFERRED FORM — cards divided by hairlines inside one
                    frame, so a feature set reads as a specimen table rather
                    than a row of floating tiles.
   .card            a bordered surface
   .card.flat       no border, opens on a rule (for stacked lists)
   .panel           a titled container with rows
   .stat            a number with a mono label
   Icons live in a SQUARE with a hairline, never a filled circle, and are SVG —
   never emoji.
   ========================================================================== */
.grid{display:grid;gap:var(--s4);
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.grid.two{grid-template-columns:repeat(auto-fit,minmax(20rem,1fr))}
.grid.three{grid-template-columns:repeat(auto-fit,minmax(13rem,1fr))}

.grid.ruled{
  gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
}
.grid.ruled > .card{border:0;border-radius:0;background:var(--surface)}
.grid.ruled > .card:hover{background:var(--surface-2)}

.card{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  padding:var(--s5);
  transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease);
}
.card > * + *{margin-top:var(--s3)}
.card h3{font-size:var(--fs-base);margin:0;letter-spacing:-.012em}
.card p{color:var(--muted);font-size:var(--fs-md);margin:0;max-width:none}
.card p + p{margin-top:var(--s3)}
.card.flat{background:transparent;border:0;border-top:1px solid var(--line);
  border-radius:0;padding:var(--s5) 0}
.card.link:hover{border-color:var(--line-strong)}
a.card{color:inherit;display:block}
a.card:hover{text-decoration:none;border-color:var(--accent-line)}

/* icon: a square with a hairline, accent glyph. Never a filled circle. */
.card .ic,.ic{
  width:1.9rem;height:1.9rem;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--accent-line);border-radius:var(--r-sm);
  background:var(--accent-soft);color:var(--accent-text);
}
.ic svg{width:1rem;height:1rem;stroke-width:1.75}
.ic.plain{border-color:var(--line);background:var(--surface-2);color:var(--dim)}

/* --- panel: a titled container of rows ---------------------------------- */
.panel{background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-lg);overflow:hidden}
.panel-head{display:flex;align-items:center;gap:var(--s3);
  padding:var(--s3) var(--s4);border-bottom:1px solid var(--line);
  background:var(--surface-2);
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim)}
.panel-head .btn{margin-left:auto}
.panel-row{padding:var(--s4);border-bottom:1px solid var(--line-soft)}
.panel-row:last-child{border-bottom:0}
.panel-foot{padding:var(--s3) var(--s4);border-top:1px solid var(--line);
  background:var(--surface-2)}

/* --- stat: number first, mono label above -------------------------------- */
.stats{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:var(--r-lg);overflow:hidden;
  grid-template-columns:repeat(auto-fit,minmax(9rem,1fr))}
.stat{background:var(--surface);padding:var(--s4)}
.stat .k{display:block;font-family:var(--font-mono);font-size:var(--fs-2xs);
  font-weight:var(--w-semi);letter-spacing:var(--track-mono);
  text-transform:uppercase;color:var(--dim);margin-bottom:var(--s2)}
.stat .v{display:block;font-size:var(--fs-2xl);font-weight:var(--w-semi);
  letter-spacing:var(--track-head);font-variant-numeric:tabular-nums;
  line-height:1.1;color:var(--ink)}
.stat .n{display:block;font-size:var(--fs-xs);color:var(--dim);margin-top:var(--s1)}

/* --- empty state: say what to do next, not just that there is nothing. --- */
.empty{border:1px dashed var(--line-strong);border-radius:var(--r-lg);
  padding:var(--s6) var(--s5);text-align:center;background:var(--surface)}
.empty b{display:block;font-size:var(--fs-base);margin-bottom:var(--s2)}
.empty p{color:var(--muted);font-size:var(--fs-md);margin:0 auto var(--s4);
  max-width:38ch}


/* =============================================================================
   §12  FEATURE LISTS
   -----------------------------------------------------------------------------
   .plain      a ruled definition list — the anti-deck. Use this instead of a
               card grid whenever the items are sentences rather than products.
   .plain.indexed  adds the mono index rail.
   .kv         label/value pairs
   .live-list  a grid of links with a mono address and a plain gloss
   .checks     a list whose markers are ticks/crosses, for capability matrices
   ========================================================================== */
/* Capped to the prose measure: the rules are part of the text block, and a
   hairline running 400px past the last word reads as a layout mistake. */
.plain{list-style:none;padding:0;margin:0;max-width:var(--measure)}
.plain > li{
  margin:0;padding:var(--s5) 0;border-top:1px solid var(--line-soft);
  display:grid;gap:var(--s1);
}
.plain > li:last-child{border-bottom:1px solid var(--line-soft)}
.plain b{font-size:var(--fs-base);font-weight:var(--w-semi);letter-spacing:-.012em;
  color:var(--ink)}
.plain span{color:var(--muted);font-size:var(--fs-md);max-width:var(--measure)}

.plain.indexed{counter-reset:pl}
.plain.indexed > li{counter-increment:pl;grid-template-columns:2.5rem minmax(0,1fr);
  column-gap:var(--s4);align-items:baseline}
.plain.indexed > li::before{
  content:counter(pl,decimal-leading-zero);
  grid-row:1 / span 2;
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);color:var(--dim);
  font-variant-numeric:tabular-nums;
}
@media (max-width:34rem){
  .plain.indexed > li{grid-template-columns:minmax(0,1fr)}
  .plain.indexed > li::before{grid-row:auto}
}

/* --- kv: definition pairs on hairlines ---------------------------------- */
.kv{display:grid;grid-template-columns:11rem minmax(0,1fr);gap:0;margin:0}
.kv > dt{
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
  padding:var(--s3) var(--s4) var(--s3) 0;border-top:1px solid var(--line-soft);
  line-height:1.7;
}
.kv > dd{margin:0;padding:var(--s3) 0;border-top:1px solid var(--line-soft);
  color:var(--ink);font-size:var(--fs-md)}
@media (max-width:38rem){
  .kv{grid-template-columns:minmax(0,1fr)}
  .kv > dd{border-top:0;padding-top:0;padding-bottom:var(--s4)}
}

/* --- live-list: link cards with a mono address -------------------------- */
.live-list{display:grid;gap:1px;list-style:none;padding:0;margin:0;
  background:var(--line);border:1px solid var(--line);border-radius:var(--r-lg);
  overflow:hidden;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr))}
.live-list li{margin:0;background:var(--surface);padding:var(--s4)}
.live-list li:hover{background:var(--surface-2)}
.live-list a{font-family:var(--font-mono);font-size:var(--fs-sm);
  font-weight:var(--w-semi);color:var(--accent-text);
  display:inline-flex;align-items:center;min-height:var(--tap)}
.live-list .what{display:block;color:var(--muted);font-size:var(--fs-md);
  margin-top:var(--s1)}

/* --- checks: capability list. Marker AND word, never marker alone. ------ */
.checks{list-style:none;padding:0;margin:0}
.checks > li{display:grid;grid-template-columns:1.4rem minmax(0,1fr);
  gap:var(--s3);align-items:start;padding:var(--s3) 0;
  border-top:1px solid var(--line-soft)}
.checks > li:last-child{border-bottom:1px solid var(--line-soft)}
.checks > li::before{content:"●" / "";font-family:var(--font-mono);
  font-size:var(--fs-sm);color:var(--ok);line-height:1.7}
.checks > li.no::before{content:"✕" / "";color:var(--bad)}
.checks > li.partial::before{content:"◆" / "";color:var(--info)}
.checks > li.soon::before{content:"○" / "";color:var(--dim)}


/* =============================================================================
   §13  STEPS
   -----------------------------------------------------------------------------
   Not badge-and-card. A ruled sequence with the number in a mono rail and a
   hairline running down the sequence — a procedure, printed.
     .steps       vertical (default). Best for 3+ steps or long text.
     .steps.row   horizontal, ruled at the top. Best for exactly 3 short steps.
   ========================================================================== */
.steps{counter-reset:step;display:grid;gap:0;margin:0;list-style:none;padding:0}
/* FIXED 2026-08-24: this was `display:grid` with `3rem minmax(0,1fr)`, which
   only works when a step has EXACTLY ONE child. The ::before counter takes
   cell 1, so a step containing both an <h3> and a <p> put the heading in
   cell 2 and the paragraph back in cell 1 -- a 3rem-wide column, one word per
   line. Absolutely positioning the counter and padding the step instead makes
   the component independent of how many children a step has. */
.steps > *{
  counter-increment:step;position:relative;
  display:block;padding:var(--s5) 0 var(--s5) 3rem;
  border-top:1px solid var(--line-soft);
}
.steps > *:last-child{border-bottom:1px solid var(--line-soft)}
.steps > *::before{
  content:counter(step,decimal-leading-zero);
  position:absolute;left:0;top:var(--s5);
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);color:var(--accent-text);
  font-variant-numeric:tabular-nums;line-height:1.9;
}
/* the connector: a hairline down the number rail */
.steps > *::after{
  content:"";position:absolute;left:.6rem;top:2.2rem;bottom:0;width:1px;
  background:var(--line);
}
.steps > *:last-child::after{display:none}
.steps h3{font-size:var(--fs-base);margin:0 0 var(--s2);letter-spacing:-.012em}
.steps p{margin:0;color:var(--muted);font-size:var(--fs-md)}

.steps.row{grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));
  column-gap:var(--s5);border-top:1px solid var(--line)}
.steps.row > *{gap:var(--s2);
  border-top:0;padding:var(--s4) 0 0}
.steps.row > *::before{position:static}
.steps.row > *:last-child{border-bottom:0}
.steps.row > *::before{line-height:1.4}
.steps.row > *::after{display:none}
/* each column gets its own accent tick on the shared top rule */
.steps.row > *{position:relative}
.steps.row > *::after{content:"";display:block;position:absolute;
  top:-1px;left:0;width:var(--tick-w);height:var(--tick-h);
  background:var(--accent);opacity:.35}
.steps.row > *:first-child::after{opacity:1}
@media (max-width:34rem){
  .steps > *{grid-template-columns:2.2rem minmax(0,1fr);gap:var(--s3)}
  .steps > *::after{left:.35rem}
}


/* =============================================================================
   §14  TABLES
   -----------------------------------------------------------------------------
   Wrap every table in <div class="tw"> (or .scroll). The wrapper carries pure
   CSS scroll shadows — background-attachment:local — so a phone reader can SEE
   that the table continues sideways. Head cells are the machine voice.
   ========================================================================== */
.tw{
  overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;
  border:1px solid var(--line);border-radius:var(--r-lg);
  background:
    linear-gradient(to right,var(--surface) 30%,transparent),
    linear-gradient(to right,transparent,var(--surface) 70%) 100% 0,
    radial-gradient(farthest-side at 0 50%,var(--scroll-shade),transparent),
    radial-gradient(farthest-side at 100% 50%,var(--scroll-shade),transparent) 100% 0;
  background-repeat:no-repeat;
  background-size:2.5rem 100%,2.5rem 100%,.75rem 100%,.75rem 100%;
  background-attachment:local,local,scroll,scroll;
  background-color:var(--surface);
}
table{width:100%;border-collapse:collapse;font-size:var(--fs-md);
  background:var(--surface)}
thead th{
  text-align:left;
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
  padding:var(--s3) var(--s4);
  border-bottom:1px solid var(--line-strong);
  background:var(--surface-2);white-space:nowrap;
}
tbody td,tbody th{padding:var(--row-y) var(--s4);
  border-bottom:1px solid var(--line-soft);vertical-align:top}
tbody th{text-align:left;font-weight:var(--w-semi)}
tbody tr:last-child td,tbody tr:last-child th{border-bottom:0}
tbody tr:hover{background:var(--surface-2)}
td .num,th .num,td.num,th.num{font-variant-numeric:tabular-nums;
  font-family:var(--font-mono);text-align:right}
table code{background:transparent;border:0;padding:0;
  overflow-wrap:anywhere;font-size:var(--fs-sm)}
table caption{caption-side:bottom;text-align:left;color:var(--dim);
  font-size:var(--fs-xs);padding:var(--s3) var(--s4)}
table.compact{--row-y:.4rem;font-size:var(--fs-sm)}
table.zebra tbody tr:nth-child(even){background:var(--surface-2)}
table.fixed{table-layout:fixed}


/* =============================================================================
   §15  CODE, ADDRESS CHIPS, KEYS
   -----------------------------------------------------------------------------
   Code sits in a SUNKEN surface — one step below the page ground — because a
   thing you copy out of is a well, not a card. The optional head bar carries
   the filename in the machine voice.
   ========================================================================== */
code,kbd,samp,pre{font-family:var(--font-mono);font-variant-ligatures:none}
code{
  font-size:.875em;
  background:var(--surface-2);
  border:1px solid var(--line-soft);
  border-radius:var(--r-sm);
  padding:.1em .35em;
  overflow-wrap:anywhere;
  color:var(--ink);
}
a code{color:inherit}

pre{
  background:var(--sunken);
  border:1px solid var(--line);
  border-radius:var(--r);
  padding:var(--s4) var(--s5);
  overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;
  font-size:var(--fs-sm);line-height:var(--lh-mono);
  color:var(--ink);
  tab-size:2;
}
pre code{background:none;border:0;padding:0;font-size:inherit;
  overflow-wrap:normal;white-space:pre}

.codeblock{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  background:var(--sunken)}
.codeblock .code-head{
  display:flex;align-items:center;gap:var(--s3);
  padding:.45rem var(--s4);
  border-bottom:1px solid var(--line);
  background:var(--surface-2);
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
}
.codeblock .code-head .btn{margin-left:auto}
.codeblock pre{border:0;border-radius:0;background:transparent}

/* a long opaque string — a hash, a CID, a public key — that must wrap */
.hashline{
  display:block;font-family:var(--font-mono);font-size:var(--fs-sm);
  color:var(--muted);overflow-wrap:anywhere;line-height:var(--lh-mono);
  background:var(--sunken);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:var(--s3);user-select:all;
}

/* --- .addr: the address-bar chip. A rounded RECT, like a real one. ------- */
.addr-demo{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3)}
.addr{
  display:inline-flex;align-items:center;gap:.5rem;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r);
  padding:.5rem .8rem;
  font-family:var(--font-mono);font-size:var(--fs-sm);
  color:var(--muted);white-space:nowrap;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;
}
.addr .lock{color:var(--ok);flex:none;display:inline-flex;align-items:center}
.addr .lock svg{width:.9rem;height:.9rem;stroke-width:2}
.addr b{font-weight:var(--w-semi);color:var(--ink)}
.addr .scheme{color:var(--accent-text);font-weight:var(--w-semi)}
.addr-demo .eq{color:var(--faint);font-family:var(--font-mono)}
.addr-demo .why{flex-basis:100%;font-family:var(--font-sans);
  font-size:var(--fs-md);color:var(--dim);max-width:var(--measure)}

/* --- kbd: a key. Heavier bottom border reads as physical. --------------- */
kbd{
  display:inline-block;font-size:var(--fs-2xs);font-weight:var(--w-semi);
  line-height:1;padding:.28rem .4rem;
  color:var(--ink);background:var(--surface);
  border:1px solid var(--line-strong);border-bottom-width:2px;
  border-radius:var(--r-sm);white-space:nowrap;
}


/* =============================================================================
   §16  CALLOUTS, THE HONESTY BLOCK, BANNERS
   -----------------------------------------------------------------------------
   THE HONESTY BLOCK is load-bearing in this project's voice: it is where we
   write down what is not finished. It must look considered, not like a browser
   warning. So it is a SURFACE with a 3px ochre rule down its leading edge and
   an ochre mono eyebrow — not a yellow box. The tint is 2–3%, present but
   never shouting.

   Markup, both supported:
       <div class="note"><strong>Heading</strong><p>…</p></div>
       <div class="callout note"><strong>Heading</strong><p>…</p></div>
   Kinds: .note (ochre, the honesty block) .info .ok .warn .bad .accent
   ========================================================================== */
.note,.callout{
  --c-rule:var(--note-rule);
  --c-ink:var(--note-ink);
  --c-bg:var(--note-bg);
  --c-line:var(--note-line);
  --c-mark:"▲";
  position:relative;
  background:var(--c-bg);
  border:1px solid var(--c-line);
  border-left:3px solid var(--c-rule);
  border-radius:var(--r-sm) var(--r-lg) var(--r-lg) var(--r-sm);
  padding:var(--s5);
  font-size:var(--fs-md);
  color:var(--ink);
  max-width:var(--measure);
}
.note > strong:first-child,.callout > strong:first-child,.callout-title{
  display:flex;align-items:center;gap:.5rem;
  font-family:var(--font-mono);font-size:var(--fs-xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;
  color:var(--c-ink);
  margin-bottom:var(--s3);
}
.note > strong:first-child::before,.callout > strong:first-child::before,
.callout-title::before{content:var(--c-mark) / "";font-size:.85em}
.note > strong:first-child::after,.callout > strong:first-child::after,
.callout-title::after{content:"";flex:1 1 auto;height:1px;
  background:var(--c-line);min-width:var(--s4)}
.note p,.callout p{margin:0;color:var(--muted);max-width:none}
.note p + p,.callout p + p{margin-top:var(--s3)}
.note p b,.callout p b{color:var(--ink);font-weight:var(--w-semi)}
.note ul,.callout ul{margin:var(--s3) 0 0;color:var(--muted)}
.note.wide,.callout.wide{max-width:none}

.callout.info{--c-rule:var(--info);--c-ink:var(--info);--c-bg:var(--info-bg);
  --c-line:var(--info-line);--c-mark:"◆"}
.callout.ok{--c-rule:var(--ok);--c-ink:var(--ok);--c-bg:var(--ok-bg);
  --c-line:var(--ok-line);--c-mark:"●"}
.callout.warn{--c-rule:var(--warn);--c-ink:var(--warn);--c-bg:var(--warn-bg);
  --c-line:var(--warn-line);--c-mark:"▲"}
.callout.bad{--c-rule:var(--bad);--c-ink:var(--bad);--c-bg:var(--bad-bg);
  --c-line:var(--bad-line);--c-mark:"✕"}
.callout.accent{--c-rule:var(--accent);--c-ink:var(--accent-text);
  --c-bg:var(--accent-soft);--c-line:var(--accent-line);--c-mark:"◆"}
/* quiet: no tint at all, just the rule. For long honest passages. */
.callout.quiet,.note.quiet{--c-bg:var(--surface)}

/* --- banners: transient messages. Tags land verbatim from Django. ------- */
.banner{
  display:flex;gap:var(--s3);align-items:flex-start;
  border:1px solid var(--line);border-left:3px solid var(--dim);
  border-radius:var(--r-sm) var(--r) var(--r) var(--r-sm);
  background:var(--surface);padding:var(--s3) var(--s4);
  font-size:var(--fs-md);color:var(--ink);
}
.banner::before{content:"◆" / "";font-family:var(--font-mono);color:var(--dim);
  line-height:1.6;flex:none}
.banner.success{border-left-color:var(--ok);background:var(--ok-bg);
  border-color:var(--ok-line)}
.banner.success::before{content:"●" / "";color:var(--ok)}
.banner.info{border-left-color:var(--info);background:var(--info-bg);
  border-color:var(--info-line)}
.banner.info::before{content:"◆" / "";color:var(--info)}
.banner.warn,.banner.warning{border-left-color:var(--warn);background:var(--warn-bg);
  border-color:var(--warn-line)}
.banner.warn::before,.banner.warning::before{content:"▲" / "";color:var(--warn)}
.banner.err,.banner.error{border-left-color:var(--bad);background:var(--bad-bg);
  border-color:var(--bad-line)}
.banner.err::before,.banner.error::before{content:"✕" / "";color:var(--bad)}


/* =============================================================================
   §17  DISCLOSURE AND FAQ
   -----------------------------------------------------------------------------
   Ruled rows, mono index, a chevron drawn in CSS. The open row gains an accent
   tick on its own rule so the open state is structural, not just a rotation.
   ========================================================================== */
.qa{margin:0}
.qa details{position:relative;border-top:1px solid var(--line-soft);
  counter-increment:qa}
.qa{counter-reset:qa}
.qa details:last-of-type{border-bottom:1px solid var(--line-soft)}
.qa summary{
  display:grid;grid-template-columns:2.5rem minmax(0,1fr) 1.5rem;
  align-items:baseline;gap:var(--s3);
  padding:var(--s4) 0;min-height:var(--tap);
  font-weight:var(--w-semi);font-size:var(--fs-base);letter-spacing:-.012em;
  cursor:pointer;list-style:none;
}
.qa summary::-webkit-details-marker{display:none}
.qa summary::marker{content:""}
.qa summary::before{
  content:counter(qa,decimal-leading-zero);
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);color:var(--dim);
  font-variant-numeric:tabular-nums;
}
/* the chevron: a rotated corner, not a glyph */
.qa summary .chev,.qa summary::after{
  content:"";justify-self:end;align-self:center;
  width:.5rem;height:.5rem;
  border-right:1.5px solid var(--dim);border-bottom:1.5px solid var(--dim);
  transform:rotate(45deg);transform-origin:center;
  transition:transform var(--dur-2) var(--ease);
}
.qa details[open] > summary::after{transform:rotate(-135deg);
  border-color:var(--accent)}
.qa details[open]{border-top-color:var(--line)}
.qa details[open]::before{content:"";position:absolute;top:-1px;left:0;
  width:var(--tick-w);height:var(--tick-h);background:var(--accent)}
.qa summary:hover{color:var(--accent-text)}
.qa .answer,.qa details > p,.qa details > div{
  padding:0 var(--s5) var(--s5) 2.5rem;
  color:var(--muted);font-size:var(--fs-md);max-width:none;margin:0;
}
.qa .answer > * + *{margin-top:var(--s3)}
@media (max-width:34rem){
  .qa summary{grid-template-columns:1.9rem minmax(0,1fr) 1.2rem;gap:var(--s2)}
  .qa .answer,.qa details > p,.qa details > div{padding-left:1.9rem;padding-right:0}
}
/* Progressive enhancement: animate the open height where supported. */
@supports (interpolate-size:allow-keywords){
  :root{interpolate-size:allow-keywords}
  .qa details::details-content{
    block-size:0;overflow:clip;
    transition:block-size var(--dur-3) var(--ease),content-visibility var(--dur-3) allow-discrete;
  }
  .qa details[open]::details-content{block-size:auto}
}


/* =============================================================================
   §18  DOWNLOADS
   -----------------------------------------------------------------------------
   .dl-list   THE PREFERRED FORM — one ruled row per platform, so the file
              facts (name, size, arch) read as a manifest.
   .dl-grid   the card form, when the picker is the whole page.
   .checksum  verification, present but secondary (SITES.md D9).
   ========================================================================== */
.dl-list{display:grid;gap:0;list-style:none;padding:0;margin:0;
  border-top:1px solid var(--line)}
.dl,.dl-list > li{
  display:grid;grid-template-columns:1.9rem minmax(0,1fr) auto;
  gap:var(--s4);align-items:center;
  padding:var(--s4) 0;border-bottom:1px solid var(--line-soft);margin:0;
}
.dl .os{display:flex;flex-direction:column;gap:.1rem;min-width:0}
.dl .os > b,.dl .os-name{font-size:var(--fs-base);font-weight:var(--w-semi);
  letter-spacing:-.012em;color:var(--ink)}
.dl .file{font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--dim);
  overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
.dl .links{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap}
.dl .meta{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--dim)}
.dl .ic svg{width:1rem;height:1rem}
@media (max-width:38rem){
  .dl,.dl-list > li{grid-template-columns:1.9rem minmax(0,1fr);gap:var(--s3)}
  .dl .links{grid-column:1 / -1}
}

/* card form */
.dl-grid{display:grid;gap:var(--s4);
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.dl-grid > .dl{
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--s2);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--s5);
}
.dl-grid > .dl .links{margin-top:auto;padding-top:var(--s2)}
.dl-grid.stacked{grid-template-columns:minmax(0,1fr)}

.checksum{margin-top:var(--s5)}
.checksum > summary{
  font-family:var(--font-mono);font-size:var(--fs-xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
  cursor:pointer;min-height:var(--tap);display:flex;align-items:center;gap:.4rem;
}
.checksum > summary::marker{content:""}
.checksum > summary::-webkit-details-marker{display:none}
.checksum > summary::before{content:"+";font-weight:400;color:var(--dim)}
.checksum[open] > summary::before{content:"\2212"}
.checksum[open] > summary{color:var(--ink)}
.verify-note{font-size:var(--fs-md);color:var(--muted);max-width:var(--measure)}


/* =============================================================================
   §19  FORM CONTROLS
   -----------------------------------------------------------------------------
   ONE shape for every control, matched by exclusion so a type-less <input> is
   covered too. Labels are the machine voice. Errors carry a marker AND a
   sentence — never a red border alone.

   (wildroot.io has no forms at all, by construction — SITES.md D3. These are
   for hns.one and the account panel, and for the review harness.)
   ========================================================================== */
.field{display:grid;gap:var(--s2);max-width:26rem}
.field.wide{max-width:none}
label,.field > .label{
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
}
label .req{color:var(--bad)}

/* The base shape is matched WITHOUT :not() chains — those inflate specificity
   and then a modifier class like .mono cannot win. The controls that need a
   different shape (checkbox, radio, file, range) override it below, by type. */
input,select,textarea{
  width:100%;min-height:var(--field-h);
  padding:.5rem .7rem;
  font-family:var(--font-sans);font-size:var(--fs-md);color:var(--ink);
  background:var(--surface);
  border:1px solid var(--field-line);
  border-radius:var(--r);
  transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);
}
input.mono,textarea.mono,select.mono{font-family:var(--font-mono);
  font-size:var(--fs-sm)}
input[type=range]{width:auto;min-height:0;padding:0;border:0;background:none;
  accent-color:var(--accent)}
textarea{min-height:7rem;line-height:var(--lh-body);resize:vertical}
input::placeholder,textarea::placeholder{color:var(--dim)}
input:hover:not([disabled]),select:hover:not([disabled]),textarea:hover:not([disabled]){
  border-color:var(--n-8)}
input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft);
}
input[disabled],select[disabled],textarea[disabled]{
  opacity:.55;cursor:not-allowed;background:var(--surface-2)}
input[aria-invalid="true"],textarea[aria-invalid="true"]{border-color:var(--bad)}

select{
  appearance:none;padding-right:2rem;
  background-image:
    linear-gradient(45deg,transparent 50%,currentColor 50%),
    linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 1.05rem) 55%,calc(100% - .75rem) 55%;
  background-size:.3rem .3rem,.3rem .3rem;
  background-repeat:no-repeat;
  color:var(--ink);
}

.field-hint{font-size:var(--fs-xs);color:var(--dim);max-width:38ch}
.field-error{
  display:flex;align-items:flex-start;gap:.4rem;
  font-size:var(--fs-xs);color:var(--bad);font-weight:var(--w-med);
}
.field-error::before{content:"✕" / "";font-family:var(--font-mono);flex:none}

/* input + button on one line */
.row{display:flex;gap:var(--s2);align-items:stretch;flex-wrap:wrap}
.row > input,.row > select{flex:1 1 12rem;min-width:0}
.row > .btn{flex:none}
form.inline{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}

/* checkbox and radio: accent-tinted natives with a real target area */
input[type=checkbox],input[type=radio]{
  appearance:none;width:1.05rem;height:1.05rem;min-height:0;flex:none;
  margin:0;padding:0;
  border:1px solid var(--field-line);background:var(--surface);
  border-radius:var(--r-sm);cursor:pointer;position:relative;
  transition:background var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease);
}
input[type=radio]{border-radius:50%}
input[type=checkbox]:checked,input[type=radio]:checked{
  background:var(--accent);border-color:var(--accent)}
input[type=checkbox]:checked::after{
  content:"";position:absolute;left:.3rem;top:.11rem;
  width:.28rem;height:.55rem;border:solid var(--accent-ink);
  border-width:0 2px 2px 0;transform:rotate(42deg)}
input[type=radio]:checked::after{
  content:"";position:absolute;inset:.25rem;border-radius:50%;
  background:var(--accent-ink)}
.check{display:flex;align-items:center;gap:.55rem;min-height:var(--tap);
  cursor:pointer}
.check > span{font-family:var(--font-sans);font-size:var(--fs-md);color:var(--ink);
  text-transform:none;letter-spacing:0;font-weight:var(--w-body)}

/* file input as a drop zone */
input[type=file]{
  width:100%;padding:var(--s5);font-size:var(--fs-md);color:var(--muted);
  background:var(--surface);border:1px dashed var(--field-line);
  border-radius:var(--r);cursor:pointer;
}
input[type=file]::file-selector-button{
  appearance:none;-webkit-appearance:none;
  margin-right:var(--s3);padding:.4rem .7rem;
  font-family:var(--font-sans);font-size:var(--fs-sm);font-weight:var(--w-semi);
  color:var(--ink);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-sm);cursor:pointer;
}
input[type=file]:hover{border-color:var(--accent-line);background:var(--accent-soft)}

/* segmented control — used for the theme/skin switch in the review harness */
.toggle{display:inline-flex;background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--r);padding:2px;gap:2px}
.toggle > button,.toggle > label{
  appearance:none;border:0;background:transparent;cursor:pointer;
  min-height:calc(var(--field-h) - 8px);padding:0 .65rem;
  border-radius:var(--r-sm);
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;
  color:var(--dim);
  display:inline-flex;align-items:center;gap:.35rem;
}
.toggle > button:hover{color:var(--ink)}
.toggle > button[aria-pressed="true"],.toggle > button.is-on{
  background:var(--surface);color:var(--ink);box-shadow:var(--shadow-1)}


/* =============================================================================
   §20  DOCS SHELL — SIDEBAR, ARTICLE PROSE, TABLE OF CONTENTS
   -----------------------------------------------------------------------------
   The rail motif again: nav items hang off a vertical hairline, and the
   current item replaces its segment of that hairline with the accent.
   Prose is where links are underlined; UI is where they are not.
   ========================================================================== */
.docs{
  display:grid;
  grid-template-columns:14rem minmax(0,1fr) 12rem;
  gap:var(--s7);
  align-items:start;
  padding-block:var(--s6);
}
.docs.no-toc{grid-template-columns:14rem minmax(0,1fr)}
@media (max-width:72rem){.docs{grid-template-columns:14rem minmax(0,1fr)}
  .docs-toc{display:none}}
@media (max-width:56rem){.docs{grid-template-columns:minmax(0,1fr);gap:var(--s5)}}

.docs-nav{position:sticky;top:5rem;max-height:calc(100dvh - 6rem);overflow-y:auto;
  font-size:var(--fs-md)}
.docs-nav h4{
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
  margin:var(--s5) 0 var(--s2);
}
.docs-nav h4:first-child{margin-top:0}
.docs-nav ul{list-style:none;padding:0;margin:0;border-left:1px solid var(--line)}
.docs-nav li{margin:0}
.docs-nav a{
  display:flex;align-items:center;min-height:var(--tap);
  padding:.3rem 0 .3rem var(--s4);margin-left:-1px;
  border-left:var(--tick-h) solid transparent;
  color:var(--muted);font-weight:var(--w-med);
}
.docs-nav a:hover{color:var(--ink);text-decoration:none;border-left-color:var(--line-strong)}
.docs-nav a[aria-current]{color:var(--accent-text);font-weight:var(--w-semi);
  border-left-color:var(--accent)}
@media (max-width:56rem){
  .docs-nav{position:static;max-height:none;border-bottom:1px solid var(--line);
    padding-bottom:var(--s4)}
  .docs-nav ul{display:flex;flex-wrap:wrap;gap:var(--s1);border-left:0}
  .docs-nav a{border-left:0;border-bottom:var(--tick-h) solid transparent;
    padding:.3rem .5rem}
  .docs-nav a[aria-current]{border-left:0;border-bottom-color:var(--accent)}
}

.docs-toc{position:sticky;top:5rem;font-size:var(--fs-sm)}
.docs-toc .label{display:block;margin-bottom:var(--s3)}
.docs-toc ul{list-style:none;padding:0;margin:0;border-left:1px solid var(--line)}
.docs-toc a{display:block;padding:.3rem 0 .3rem var(--s3);margin-left:-1px;
  border-left:var(--tick-h) solid transparent;color:var(--dim)}
.docs-toc a:hover{color:var(--ink);text-decoration:none}
.docs-toc a[aria-current]{color:var(--ink);border-left-color:var(--accent)}
.docs-toc li li a{padding-left:var(--s5);font-size:var(--fs-xs)}

/* --- prose: the article voice ------------------------------------------- */
.prose{max-width:var(--measure);font-size:var(--fs-base);line-height:var(--lh-body)}
.prose > * + *{margin-top:var(--s4)}
.prose h2{
  position:relative;font-size:var(--fs-xl);margin-top:var(--s7);
  padding-top:var(--s5);border-top:1px solid var(--line);
}
.prose h2::before{content:"";position:absolute;top:-1px;left:0;
  width:var(--tick-w);height:var(--tick-h);background:var(--accent)}
.prose h3{font-size:var(--fs-lg);margin-top:var(--s6)}
.prose h4{margin-top:var(--s5)}
.prose h2 + *,.prose h3 + *,.prose h4 + *{margin-top:var(--s3)}
.prose p{color:var(--ink)}
.prose a{color:var(--accent-text);text-decoration:underline;
  text-decoration-color:var(--accent-line);text-decoration-thickness:1px;
  text-underline-offset:.18em}
.prose a:hover{text-decoration-color:var(--accent)}
.prose ul,.prose ol{padding-left:1.35rem;max-width:var(--measure)}
.prose ul{list-style:none;padding-left:1.1rem}
.prose ul > li{position:relative}
.prose ul > li::before{content:"";position:absolute;left:-1.1rem;top:.62em;
  width:.3rem;height:.3rem;background:var(--accent);opacity:.5}
.prose ol{list-style:none;counter-reset:pr;padding-left:1.9rem}
.prose ol > li{counter-increment:pr;position:relative}
.prose ol > li::before{content:counter(pr) ".";position:absolute;left:-1.9rem;
  font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--dim);
  font-variant-numeric:tabular-nums}
.prose li + li{margin-top:var(--s2)}
.prose blockquote{border-left:var(--tick-h) solid var(--accent);
  padding-left:var(--s4);color:var(--muted);font-size:var(--fs-lg);
  line-height:1.5;letter-spacing:-.008em}
.prose blockquote p{color:inherit;max-width:none}
.prose figure figcaption{font-family:var(--font-mono);font-size:var(--fs-xs);
  color:var(--dim);margin-top:var(--s2)}
.prose hr{margin-block:var(--s6)}
.prose > .tw,.prose > pre,.prose > .codeblock{max-width:none}


/* =============================================================================
   §21  FIGURES AND SCREENSHOTS
   -----------------------------------------------------------------------------
   A framed shot with a mono caption bar. No fake browser chrome, no tilt, no
   floating shadow — the frame IS the hairline. Add .ticks for the registration
   marks on the one figure per page that should carry them.
   ========================================================================== */
.shot{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  overflow:hidden;
  margin:0;
}
.shot img,.shot video{display:block;width:100%;height:auto}
.shot .cap,.shot figcaption{
  display:flex;align-items:center;gap:var(--s3);
  padding:var(--s3) var(--s4);
  border-top:1px solid var(--line);
  background:var(--surface-2);
  font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--dim);
}
.shot .cap .n{margin-left:auto;color:var(--dim)}
.shot.bleed{border-radius:0;border-inline:0}
/* a placeholder for a shot that has not been taken yet */
.shot .placeholder{
  display:grid;place-items:center;min-height:14rem;
  background:
    repeating-linear-gradient(45deg,var(--surface-2) 0 8px,transparent 8px 16px);
  color:var(--dim);font-family:var(--font-mono);font-size:var(--fs-xs);
  letter-spacing:var(--track-mono);text-transform:uppercase;
}


/* =============================================================================
   §22  FOOTER
   -----------------------------------------------------------------------------
   Not four equal columns. A wide identity block, then link columns that only
   take the width they need, then a mono baseline bar carrying the facts —
   version, licence, year. The footer opens on the same rule + accent tick as
   every other block.
   ========================================================================== */
.site-foot{
  position:relative;
  margin-top:var(--s8);
  border-top:1px solid var(--line);
  background:var(--bg);
}
.site-foot::before{content:"";position:absolute;top:-1px;left:0;right:0;
  height:var(--tick-h);pointer-events:none;
  background:linear-gradient(var(--accent),var(--accent)) no-repeat;
  background-size:var(--tick-w) var(--tick-h);
  background-position:max(var(--gutter),
    calc(50% + var(--tick-w)/2 - var(--wrap)/2 + var(--gutter))) 0}
.site-foot > .wrap{
  display:grid;gap:var(--s6);
  grid-template-columns:minmax(16rem,2fr) repeat(3,minmax(8rem,1fr));
  padding-block:var(--s7) var(--s5);
}
.site-foot .about h4{font-family:var(--font-sans);font-size:1.0625rem;
  font-weight:var(--w-bold);letter-spacing:-.022em;color:var(--ink);
  text-transform:none;margin-bottom:var(--s3)}
.site-foot h4{
  font-family:var(--font-mono);font-size:var(--fs-2xs);font-weight:var(--w-semi);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--dim);
  margin-bottom:var(--s3);
}
.site-foot ul{list-style:none;padding:0;margin:0}
.site-foot li{margin:0}
.site-foot a{color:var(--muted);font-size:var(--fs-md);
  display:inline-flex;align-items:center;min-height:var(--tap)}
.site-foot a:hover{color:var(--ink)}
.site-foot .about p{color:var(--muted);font-size:var(--fs-md);max-width:34ch}
.foot-bar{
  border-top:1px solid var(--line-soft);
}
.foot-bar > .wrap{
  display:flex;flex-wrap:wrap;gap:var(--s3) var(--s5);align-items:center;
  padding-block:var(--s4);
  font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--dim);
  font-variant-numeric:tabular-nums;
}
.foot-bar a{color:var(--dim)}
.foot-bar .right{margin-left:auto}
@media (max-width:56rem){
  .site-foot > .wrap{grid-template-columns:1fr 1fr;gap:var(--s5)}
  .site-foot .about{grid-column:1 / -1}
}
@media (max-width:26rem){
  .site-foot > .wrap{grid-template-columns:1fr}
}


/* =============================================================================
   §23  UTILITIES
   -----------------------------------------------------------------------------
   Deliberately few. If you find yourself wanting a tenth spacing utility, the
   component is missing a variant.
   ========================================================================== */
.measure{max-width:var(--measure)}
.measure-tight{max-width:var(--measure-tight)}
.measure-none{max-width:none}
.center{text-align:center}
.nowrap{white-space:nowrap}
.mb0{margin-bottom:0}
.mt-4{margin-top:var(--s4)}
.mt-5{margin-top:var(--s5)}
.mt-6{margin-top:var(--s6)}
.full{width:100%}
.hide{display:none}
@media (max-width:52rem){.hide-sm{display:none}}
@media (min-width:52.01rem){.only-sm{display:none}}


/* =============================================================================
   §24  MOTION, PRINT, FORCED COLOURS
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
}

/* High-contrast / forced-colours: keep the structure, drop our palette. */
@media (forced-colors:active){
  .btn{border:1px solid ButtonText}
  .tag,.card,.panel,.note,.callout,.shot,.tw{border:1px solid CanvasText}
  .sect.ruled::before,.sect + .sect::before,.site-foot::before,
  .prose h2::before,.rule.accent::before{background:Highlight;forced-color-adjust:none}
  .site-nav a[aria-current]::after{background:Highlight;forced-color-adjust:none}
}

@media print{
  .site-head,.site-foot,.docs-nav,.docs-toc,.cta,.skip{display:none !important}
  body{background:#fff;color:#000;font-size:11pt}
  .sect{padding-block:1rem;break-inside:avoid}
  .card,.note,.callout,.tw,.shot{break-inside:avoid}
  a[href^="/"]::after,a[href^="http"]::after{
    content:" (" attr(href) ")";font-family:var(--font-mono);font-size:9pt}
  .docs{grid-template-columns:1fr}
}

/* =============================================================================
   §21  FLOW — vertical rhythm for stacked block components
   -----------------------------------------------------------------------------
   ADDED 2026-08-24, after building real pages with this library.

   Every block component above sets `margin:0` or no margin at all, because the
   library assumed each one opens its own <section> and takes its spacing from
   the section padding. That holds for a landing page. It does NOT hold for a
   prose or documentation page, which stacks a paragraph, a table, a callout
   and a list inside ONE section — there, every component collided with the one
   above it and the page read as a single squashed block.

   This block comes last on purpose: it has to win over the `margin:0` in the
   component definitions, and it does so by source order at equal specificity.
   The :first-child reset keeps a component from opening a section with a gap.
   ========================================================================== */
.grid,.steps,.plain,.qa,.note,.dl-grid,.verify-note,.scroll,.addr-demo,
pre,figure,blockquote{margin-top:var(--s5)}

:is(.grid,.steps,.plain,.qa,.note,.dl-grid,.verify-note,.scroll,.addr-demo,
    pre,figure,blockquote):first-child{margin-top:0}

/* A callout is a change of voice — it earns a little more room than a list. */
.note{margin-bottom:var(--s5)}
.note:last-child{margin-bottom:0}

/* Two callouts in a row are a stack, not two separate interruptions. */
.note + .note{margin-top:var(--s4)}

/* The section rhythm lives on `.sect`, but content that writes plain semantic
   HTML uses a bare <section> and got NO padding at all — adjacent sections
   collided and only the h2's own margin separated them. Top padding only, so
   two stacked sections produce one gap rather than two. */
section:not(.sect):not(.hero){padding-block:var(--section-y) 0}
section:not(.sect):last-of-type{padding-bottom:var(--section-y)}
