/* ============================================================
   AI Landscape - design system (institutional / dark-first)
   Dark is the default; [data-theme="light"] overrides.
   Lens (PM/Architect) via [data-lens] on <body>.
   ============================================================ */
:root{
  color-scheme:dark;
  --page:#0a0e17; --page-2:#0c1120;
  --surface-1:#121a2b; --surface-2:#0f1626; --surface-3:#18223a;
  --text-primary:#f5f7fb; --text-secondary:#9aa6c0; --muted:#6b7793;
  --border:rgba(255,255,255,0.08); --border-strong:rgba(255,255,255,0.15);
  --accent:#5b8def; --accent-2:#8a7cf0; --gold:#d6a94e;
  /* --accent-fill is --accent USED AS A FILLED BACKGROUND, with the ink that is legible on it.
     It exists because `background:var(--accent);color:#fff` failed AA on every surface that used
     it: 3.23:1 in dark and 4.42:1 in light, against a 4.5 floor, on the theme toggle, the Signal
     tabs, the .rc-btn buttons and the nav .cta. Eleven of twelve measurements failed.
     Same shape as --give / --give-ink, and for the same reason: a bright accent cannot carry white
     text, so DARK pairs the bright accent with near-black ink, and LIGHT darkens the accent and
     keeps white ink. --accent itself is UNTOUCHED — it is the colour-as-meaning token and it is
     correct as a text/border colour on a page background. Only the filled case needed a variant.
     --accent-fill-badge is the wash used by a chip sitting INSIDE a filled surface; it must move
     AWAY from the ink (lighter in dark, darker in light) or it destroys the very contrast the
     other two tokens just bought. Verified: dark 5.54-8.12:1, light 4.95-7.23:1. */
  --accent-fill:var(--accent); --accent-fill-ink:#0b1526;
  --accent-fill-badge:rgba(255,255,255,0.28);
  --shadow:0 2px 6px rgba(0,0,0,0.35),0 18px 50px rgba(0,0,0,0.45);
  --shadow-sm:0 1px 2px rgba(0,0,0,0.3),0 6px 18px rgba(0,0,0,0.35);
  --c-blue:#5b8def; --c-violet:#9085e9; --c-aqua:#2fc99a; --c-yellow:#e0b13c;
  --c-orange:#f0824f; --c-red:#f0685f; --c-green:#54b45a; --c-magenta:#e87ba4;
  /* Use Cases. ITS OWN TOKEN, deliberately NOT an alias of --give, which holds the same value
     today: a separate token makes a future donate restyle a one-line divergence instead of a hunt
     across every nav surface. The earlier "too close to Ground aqua" rejection was withdrawn on
     measurement — 44 degrees apart in hue (210 vs 166), CIEDE2000 21.7 dark / 21.3 light, further
     apart than magenta from Operate red. Its low chroma is the feature: calm furniture beside
     seven louder tabs. */
  --c-teal:#35a8b5;
  /* Dark theme: a dark figure card so the DARK diagram render sits on dark, not a white slab.
     The light theme (below) keeps a near-white card for the light render. */
  --figure-bg:#0c1424;
  /* --maxw is the page frame. --measure is the prose line-length cap, and it is the ONE knob
     for it: every paragraph/list rule below uses var(--measure), so there is no second place
     to hunt. It was previously spread across seven selectors (820px, 760px, 720px, 74ch x4,
     78ch), which capped body text at ~50-60% of the column and left a large empty right
     gutter on a wide display.
     Set to `none` per operator direction: text runs the full column width.
     Tradeoff, recorded on purpose: at 1440px that was ~145 characters per line, past the
     ~90ch where the eye starts losing the return sweep. To pull it back, change ONLY this
     line -- e.g. `--measure:110ch` -- and every prose rule follows.
     ⚠︎ --maxw WENT 1440 -> 1680 ON 2026-08-30 (operator: the desktop width is not being used),
     SO THAT ~145 IS NOW ~170 CHARACTERS. The number above was left stale for exactly one edit
     and is corrected here rather than left to read as current -- a measured figure that quietly
     stops being true is the defect class this file's own footer comment was just fixed for.
     --measure is untouched because `none` is the operator's own call; if the longer line is
     wrong, this line is the one knob and nothing else needs finding. */
  --header-h:64px; --maxw:1680px; --measure:none; --rail-gap:14px;
  /* --nav-r is the ONE knob for the shape of every control in the top-right nav cluster.
     Before this existed the row carried THREE different radii at once: 999px on Search, Learn,
     Chip in and the avatar; 11px on Signal (and therefore on Admin, which nav.js builds as
     class="tn-signal tn-admin" and so inherits it); and 8px on the Dark/Light toggle, where
     `.tn-right .seg button` overrode the global 999px `.seg button`. Seven controls, three
     shapes, side by side.
     999px wins on the row as it stands rather than by taste: four of the seven already used it,
     and one of those four is the account avatar, which can only ever be a circle. Matching the
     odd ones out to the majority is the smaller change AND the only one that leaves the avatar
     consistent with its neighbours.
     Every nav control now points here, including the ones already at 999px, so the row cannot
     drift apart again one rule at a time. */
  --nav-r:999px;
  /* --nav-h is the same idea for SIZE, and it was needed because fixing the shape did not fix the
     row. Measured in Chrome at 1440px on 2026-07-28, the cluster carried FIVE distinct heights
     across six controls: Chip in 30.5px, Learn 31, the avatar 32, the theme toggle 35.2, and both
     Search and Signal/Admin 36.8 — a 6.3px spread. Worse, five distinct top edges spanning 3.1px,
     so the controls were not even sharing a baseline; the row read as a set of unrelated widgets.
     The cause was that every control set its own vertical padding (3+5, 7, 8, 9) or its own fixed
     box (the 32px avatar), and padding cannot produce equal heights across three different font
     sizes.
     36px wins by measurement, not taste: the search field and Signal already sat at 36.8, and the
     search field is what a reader reads as the height of the bar. Rounding the two tallest down by
     0.8px is a far smaller move than pulling them down to meet Chip in at 30.5, which would have
     left the search input cramped.
     The mechanism matters as much as the number. Height is set ONCE here and the controls centre
     their content with inline-flex, so vertical padding no longer participates — a future control
     that ships its own padding still lands at 36px. Only HORIZONTAL padding is left to vary, which
     is correct: it should follow the label. */
  --nav-h:36px;
  --font-display:"Space Grotesk",system-ui,-apple-system,"Segoe UI",sans-serif;
  --font-body:"Inter",system-ui,-apple-system,"Segoe UI",sans-serif;
}
html[data-theme="light"]{
  color-scheme:light;
  --page:#f4f4f1; --page-2:#efefec;
  --surface-1:#ffffff; --surface-2:#ffffff; --surface-3:#ffffff;
  --text-primary:#0b0b0b; --text-secondary:#52514e; --muted:#898781;
  --border:rgba(11,11,11,0.10); --border-strong:rgba(11,11,11,0.16);
  --accent:#2a78d6; --accent-2:#4a3aa7; --gold:#a9761c;
  /* Light inverts the pairing, exactly as --give does: white ink stays, so the fill darkens.
     #2a78d6 against white was 4.42:1 — a miss by 0.08, which is why it survived so long. */
  --accent-fill:#2670c9; --accent-fill-ink:#ffffff;
  --accent-fill-badge:rgba(0,0,0,0.22);
  --shadow:0 1px 2px rgba(11,11,11,0.05),0 8px 24px rgba(11,11,11,0.08);
  --shadow-sm:0 1px 2px rgba(11,11,11,0.05),0 4px 14px rgba(11,11,11,0.06);
  --c-blue:#2a78d6; --c-violet:#4a3aa7; --c-aqua:#1baf7a; --c-yellow:#c98500;
  --c-orange:#eb6834; --c-red:#e34948; --c-green:#008300; --c-magenta:#d55181;
  --c-teal:#1c7684;   /* Use Cases, light theme. 4.80:1 on the page ground. */
  --figure-bg:#fcfcfb;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;font-family:var(--font-body);background:var(--page);color:var(--text-primary);
  line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:inherit}
h1,h2,h3,h4{font-family:var(--font-display);letter-spacing:-0.02em;font-weight:700}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 24px}

/* ---------------- Top nav ---------------- */
.topnav{position:sticky;top:0;z-index:100;height:var(--header-h);
  background:color-mix(in srgb,var(--surface-2) 82%,transparent);
  backdrop-filter:saturate(1.3) blur(12px);border-bottom:1px solid var(--border)}
/* Matches --maxw so the nav lines up with the content below it */
/* The BAR goes edge to edge; page content keeps its --maxw cap. On a 1920px screen the
   capped bar left 480px of dead gutter and started the wordmark 262px in, which is what
   made it look adrift. Content is deliberately NOT freed: prose at 1900px is unreadable and
   the cap is doing real work everywhere else.
   This does NOT fix the overflow. At 1280px, where the bar actually breaks, the gutter is
   already zero — that is what slimming the controls below is for. Two problems, two fixes. */
.tn-inner{max-width:none;margin:0;height:100%;padding:0 20px;display:flex;align-items:center;gap:12px}
/* Logo mark colours — theme-aware. The mark keeps its bright two-tone on the dark header (exactly
   as signed off); on the light header it uses deeper, more saturated stops so it stays vibrant on
   near-white instead of washing out, and the centre gem tracks the mark (--lg-dot), not the page,
   so it never blends into a light background. */
/* The centre gem is the CROSSBAR of the "A". It must contrast with the header behind it: white on
   the dark header (a bright gem), but a coloured indigo on the light header — a white crossbar on
   a white page vanishes, and the mark collapses into a plain peak with no crossbar. So --lg-dot is
   white in dark and indigo in light. The legs keep the blue/violet two-tone in both. */
:root{--lg-a:#3b82f6;--lg-b:#1d4ed8;--vg-a:#8b5cf6;--vg-b:#6d28d9;--lg-dot:#4f46e5}
@media(prefers-color-scheme:dark){:root{--lg-a:#93c5fd;--lg-b:#60a5fa;--vg-a:#8b5cf6;--vg-b:#7c3aed;--lg-dot:#ffffff}}
:root[data-theme="light"]{--lg-a:#3b82f6;--lg-b:#1d4ed8;--vg-a:#8b5cf6;--vg-b:#6d28d9;--lg-dot:#4f46e5}
:root[data-theme="dark"]{--lg-a:#93c5fd;--lg-b:#60a5fa;--vg-a:#8b5cf6;--vg-b:#7c3aed;--lg-dot:#ffffff}
.brand{display:flex;align-items:center;gap:11px;text-decoration:none;font-family:var(--font-display);
  font-weight:700;font-size:19px;letter-spacing:-0.015em;color:var(--text-primary);white-space:nowrap}
/* The mark is a BARE ascent "A" — no container box, no tile, no rounded square, no glow. It sits
   directly on the header and is big, so it reads as a logo, not an app icon. Every box-producing
   property is explicitly zeroed here so no earlier rule can put a tile back behind it. */
.brand .logo{width:46px;height:46px;flex:none;display:grid;place-items:center;
  background:none;box-shadow:none;border:0;border-radius:0;
  -webkit-font-smoothing:antialiased;text-rendering:geometricPrecision}
.brand .logo svg{width:46px;height:46px;display:block;shape-rendering:geometricPrecision}
/* AI Foundry | adhana. A thin pipe divides the product name from the house brand. adhana is
   small and quiet on purpose — smaller and lighter than "AI Foundry", the parent it belongs to. */
.brand .wm-sep{width:1px;height:18px;background:var(--border-strong);flex:none;margin:0 2px}
.brand .wm-adhana{font-family:var(--font-display);font-weight:600;font-size:13px;letter-spacing:0;
  background:linear-gradient(100deg,#818cf8,#c084fc);-webkit-background-clip:text;background-clip:text;color:transparent}
@media(max-width:820px){.brand .wm-sep,.brand .wm-adhana{display:none}}
.brand .pill{font-family:var(--font-body);font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--gold);border:1px solid color-mix(in srgb,var(--gold) 45%,transparent);
  background:color-mix(in srgb,var(--gold) 12%,transparent);padding:3px 8px;border-radius:999px}
.menu{display:flex;align-items:center;gap:0;margin-left:4px}
.navitem{position:relative}
.navlink{display:inline-flex;align-items:center;gap:5px;background:transparent;border:0;cursor:pointer;text-decoration:none;
  font-family:var(--font-body);font-size:13.5px;font-weight:600;color:var(--text-secondary);white-space:nowrap;
  padding:8px 10px;border-radius:9px}
.navlink:hover,.navitem:hover .navlink,.navitem:focus-within .navlink{color:var(--text-primary);background:color-mix(in srgb,var(--text-primary) 6%,transparent)}
.navlink .car{font-size:10px;opacity:.7;transition:transform .15s ease}
.navitem:hover .navlink .car{transform:rotate(180deg)}
/* ⚑ THE BAR CARRIES SEVEN CONTROLS WHERE IT CARRIED SIX — 2026-08-24, and at 1280px that was
   11.7px too many: `.tn-right` ended at 1291.7 and every page on the site scrolled sideways.
   Measured against production, which still served the six-tab bar and fitted 1280 with 20px to
   spare, so this is a regression of the new bar and not the pre-existing 1280 tightness CLAUDE.md
   records. Padding is the right knob: it takes 7px off each control without touching the font
   size, which is what keeps the labels readable and the row on one baseline.
   ⚑ EIGHT ON 2026-08-26, WHEN Cross-domain BECAME A TAB — and the breakpoint moved 1360 -> 1600
   with it. All measured in Chrome against the built tree, never estimated:
     seven tabs   menu 641px @1280 · 693 @1366 · fits every width from 981 up
     eight tabs   menu 758px @1280 · 816 @1366 — scrollWidth 1348 @1280, 1414 @1366, 1612 @1512
   The tab costs ~117px, so the band that needs help now runs all the way to ~1600 (.tn-right is
   500px wide up there — Chip in and Learn are still in the row — where lower down it is 212).
   ⚠︎ AND THE PLATFORM GATE'S EARLIER PASS WAS AN ARTIFACT, recorded so nobody trusts it again:
   pages/platform.html carried no data-root until the same day, so nav-facts.js 404'd there, the
   industry tabs never rendered, and a bar missing its tabs cannot overflow. It went red the
   moment that page's nav actually worked. */
@media(max-width:1600px){
  .topnav .navlink,.topnav .nav-all{padding-left:7px;padding-right:7px}
  .topnav .nav-div{margin:0 4px}
  .tn-inner{gap:8px}
}
/* The tight tier, for the band between the mild one above and the hamburger below. Padding is
   spent first, then half a point of type — the same order the 2026-08-24 rules used, and for the
   same reason: nothing DISAPPEARS. The "adhana" tail of the wordmark is the one exception and it
   was already the recorded first thing to go when space is genuinely tight. */
@media(max-width:1560px){
  .topnav .navlink,.topnav .nav-all{padding-left:3px;padding-right:3px;font-size:12.5px}
  .topnav .nav-div{margin:0 2px}
  .tn-inner{gap:6px;padding:0 10px}
  .tn-right{gap:7px}
  .topnav .wm-sep,.topnav .wm-adhana{display:none}
}
/* ---- mega-menu: index on the left, preview on the right ----
   The list was a column of 34px icon tiles with a two-word subtitle under each, which on Operate
   was eight tall rows where every row shouted equally and the emoji did most of the visual work.
   Now the left column is a compact index AND the only thing you click; the right panel explains
   whatever the pointer is on. Nothing over there is interactive, so the reader never has to
   travel across the menu to act \u2014 they read right, they click left.
   Before the pointer touches anything the panel shows the GROUP, so a menu that has just opened
   still says something instead of presenting an empty half. */
.dropdown{position:absolute;top:calc(100% + 8px);left:0;width:756px;background:var(--surface-3);
  border:1px solid var(--border-strong);border-radius:16px;box-shadow:var(--shadow);padding:0;overflow:hidden;
  opacity:0;visibility:hidden;transform:translateY(6px);transition:opacity .16s ease,transform .16s ease,visibility .16s;z-index:120}
/* ⚑ OPENING IS JS-DRIVEN NOW — 2026-08-24. This was `:hover, :focus-within`, which cannot carry
   aria-expanded, cannot be closed with Escape, has no intent delay, and on a touch device made the
   first tap both open the menu and follow the link under it. nav.js sets .open; the CSS only says
   what open looks like. Keep the two apart: a second :hover rule here would re-open panels the
   controller has just closed and the two would fight on every pointer move. */
/* ⚠︎ visibility IS DELIBERATELY NOT TRANSITIONED IN THE OPEN DIRECTION. The base rule fades it
   for a clean close, but on OPEN a transitioned visibility is still `hidden` for the first frame,
   and .focus() on an element inside a hidden subtree is a silent no-op — which is exactly how
   Enter opened the panel and stranded a keyboard reader on the button. Dropping visibility from
   this rule's transition list makes it flip instantly, so the rail is focusable the moment the
   class lands. Opacity and transform still animate, so nothing looks different. */
.navitem.open .dropdown{opacity:1;visibility:visible;transform:translateY(0);
  transition:opacity .16s ease,transform .16s ease}
.navitem.open > .navlink{color:var(--text-primary);
  background:color-mix(in srgb,var(--gc,var(--accent)) 16%,transparent)}
.navitem.open > .navlink .car{transform:rotate(180deg)}
.dd-grid{display:grid;grid-template-columns:252px 1fr}
/* ⚑ THE LIST IS CAPPED AND SCROLLS — operator-reported 2026-08-18, "it keeps dragging". This rule
   had NO max-height and NO overflow, so Use Cases' 23 rows rendered ~793px tall and ran off the
   bottom of the screen; the menu could not be read without moving the pointer out of it, which
   closes it. The cap applies to every menu because a cap only bites when the content exceeds it —
   no other group is near it today, and the one that grows next is covered for free.
   overscroll-behavior stops a flick at the end of the list from scrolling the page underneath. */
.dd-list{padding:10px;border-right:1px solid var(--border);
  max-height:392px;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}
.dd-row{display:flex;gap:10px;align-items:center;text-decoration:none;padding:8px 10px;border-radius:9px;
  color:var(--text-secondary)}
.dd-row:hover,.dd-row:focus-visible{background:color-mix(in srgb,var(--gc,var(--accent)) 13%,transparent);
  color:var(--text-primary);outline:none}
.dd-n{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;color:var(--muted);width:15px;flex:none}
.dd-row:hover .dd-n,.dd-row:focus-visible .dd-n{color:var(--gc,var(--accent))}
.dd-t{font-size:13.5px;font-weight:550;line-height:1.3}
.dd-pre{padding:20px 22px;display:flex;flex-direction:column;gap:9px;min-height:250px;background:var(--surface-1)}

/* ── THE BUCKET RAIL — 2026-08-24, the industry-first bar ────────────────────────────────────
   The rail holds BUCKETS, not rows: a vertical on an industry tab, a section on Platform. Both
   render through one code path in nav.js, so these styles serve both and Platform cannot drift
   into looking like a different product.
   The eyebrow states the SORT RULE as well as the count, because the two rails are ordered by
   different rules on purpose — industries by kit count (the biggest bucket is the likeliest
   answer), Platform in build order (Models → Ground → … is a sequence, and sorting it by size
   would destroy what the order tells you). Unlabelled, one of them just looks wrong. */
.dd-eye{display:block;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted);line-height:1.5;
  padding:4px 10px 9px}
.dd-brow{display:flex;gap:9px;align-items:center;text-decoration:none;padding:7px 10px;
  border-radius:9px;color:var(--text-secondary)}
.dd-brow:hover,.dd-brow:focus-visible{background:color-mix(in srgb,var(--gc,var(--accent)) 13%,transparent);
  color:var(--text-primary);outline:none}
.dd-brow[aria-current="true"]{background:color-mix(in srgb,var(--gc,var(--accent)) 17%,transparent);
  color:var(--text-primary)}
.dd-brow:focus-visible{outline:2px solid var(--gc,var(--accent));outline-offset:-2px}
.dd-bd{width:8px;height:8px;border-radius:50%;flex:none}
.dd-bt{flex:1;min-width:0;font-size:13.5px;font-weight:550;line-height:1.3}
.dd-bn{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;font-weight:600;
  color:var(--muted);font-variant-numeric:tabular-nums;flex:none}
.dd-brow:hover .dd-bn,.dd-brow[aria-current="true"] .dd-bn{color:var(--gc,var(--accent))}
/* Preview cards. Three at most — the rail says how many there are, the panel shows what they
   look like, and "See all N" is the honest door to the rest. */
.dd-cards{display:grid;gap:8px;grid-template-columns:1fr;margin-top:2px}
.dd-card{display:flex;flex-direction:column;gap:3px;text-decoration:none;padding:9px 11px;
  border:1px solid var(--border);border-radius:10px;background:var(--surface-2)}
.dd-card:hover{border-color:var(--border-strong)}
.dd-card:focus-visible{outline:2px solid var(--gc,var(--accent));outline-offset:1px}
.dd-ct{font-size:12.5px;font-weight:600;color:var(--text-primary);line-height:1.32}
.dd-cs{font-size:11.5px;color:var(--text-secondary);line-height:1.4}
/* ⚑ THE ACCESS MARK. This bar is served to anonymous visitors on every public page and a kit
   board 302s them to the accounts host; Platform's pages do not. Saying which is which on the
   card is the difference between a wall and a broken link — the defect class four surfaces on
   this site carried for a day in August by claiming the opposite. */
.dd-cg{font-size:10px;font-weight:600;letter-spacing:.03em;color:var(--gold);margin-top:1px}
/* ⚑ AN EMPTY MARK TAKES NO ROOM — 2026-08-26. accessMark() returns "" for a walled page
   now that the sign-in lock is gone (operator: the click already forces authentication), so
   most cards emit <span class="dd-cg"></span> and its margin-top would show as a stray gap.
   ⚠︎ HIDDEN IN CSS AND DELIBERATELY NOT BY SKIPPING THE SPAN IN nav.js. The span must keep
   being built by the literal expression `dd-cg">' + accessMark(it)`, because that exact
   assignment is what build/smoke/verticals.py asserts on — the predicate exists after a
   looser one green-lit a seeded re-typing of the mark twice. Rendering is CSS's problem;
   the gate's is that the value is computed and never typed. */
.dd-cg:empty{display:none}
/* The Platform card's derived counts, the same figure a kit card carries as its measured
   dataset. Accent-coloured for the same reason: it is the fact, not the prose. */
.dd-cf{font-size:11px;font-weight:600;color:var(--gc,var(--accent))}
.dd-see{margin-top:auto;padding-top:10px;font-size:12.5px;font-weight:600;
  color:var(--gc,var(--accent));text-decoration:none}
.dd-see:hover{text-decoration:underline}
/* All Kits is a link, not a menu — it gets the accent so the bar reads "five industries, then the
   whole catalogue", and a hairline separates the industries from Platform. */
.nav-all{display:inline-flex;align-items:center;padding:8px 12px;border-radius:var(--nav-r);
  text-decoration:none;font-size:13.5px;font-weight:600;color:var(--accent);white-space:nowrap}
.nav-all:hover{background:color-mix(in srgb,var(--accent) 12%,transparent)}
.nav-div{width:1px;height:20px;background:var(--border-strong);margin:0 7px;flex:none;
  align-self:center}
.dd-pk{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--gc,var(--accent))}
.dd-pt{font-family:var(--font-display);font-size:19px;font-weight:700;line-height:1.25;color:var(--text-primary)}
.dd-ps{font-size:13px;color:var(--text-secondary);line-height:1.55}
/* What is actually inside, as counts. Sits at the foot of the panel and is derived at build
   time from the content model — never typed into nav.js — because a menu that says "9 deep
   dives" when there are 42 is the homepage's MAP_LAYERS drift with a wider audience. */
.dd-facts{margin-top:auto;padding-top:12px;border-top:1px solid var(--border);
  display:flex;flex-wrap:wrap;gap:5px 7px;min-height:1px}
.dd-facts:empty{border-top:0;padding-top:0}
/* ── FILTER-FIRST, IN THE USE CASES MENU ──────────────────────────────────────
   Operator locked Option D on 2026-08-18 and, asked which taxonomy, answered "Verb".
   The bar is the FIRST CHILD of the scrolling list and sticks to its top, so the filter and the
   chips stay put while the rows move under them. Its background must be the DROPDOWN's ground
   (--surface-3), not the panel's, or rows show through it as they pass behind.
   ⚠︎ THE LIST DROPS ITS OWN TOP PADDING WHEN IT CARRIES A BAR, AND THAT IS NOT COSMETIC. A sticky
   `top:0` pins the element's MARGIN edge to the scrollport, so the first attempt — margin-top:-10px
   to reach out over the list's 10px padding — stuck the bar 10px DOWN the scrollport and left a
   10px slot above it that rows visibly scrolled through. Measured at 10px in Chrome and seen in a
   screenshot with "Version redlining" sitting above the filter box. The fix is to take the padding
   off the list, not to cancel it with a margin; the side margins stay, so the bar still spans the
   full width and its border-bottom reaches both edges.
   ⚠︎ THE CHIPS SHIP HIDDEN. They are populated by nav.js from window.FOUNDRY_KIT_VERBS, which
   arrives with nav-facts.js — a cached older copy of that file carries no verbs, and an empty row
   of chips that filters nothing is worse than no chips. Text filtering needs no verb data and
   works either way. */
.dd-filt{padding-top:0}
.dd-fbar{position:sticky;top:0;z-index:3;background:var(--surface-3);
  margin:0 -10px 6px;padding:10px 10px 8px;border-bottom:1px solid var(--border)}
.dd-q{width:100%;height:30px;border-radius:9px;border:1px solid var(--border-strong);
  background:var(--surface-2);color:var(--text-primary);font:400 12.5px var(--font-body);padding:0 10px}
.dd-q:focus{outline:none;border-color:var(--gc,var(--accent))}
.dd-q::placeholder{color:var(--muted)}
.dd-chips{display:flex;flex-wrap:wrap;gap:4px;margin-top:7px}
.dd-chips[hidden]{display:none}
.dd-chip{font-family:var(--font-body);font-size:10.5px;font-weight:600;color:var(--text-secondary);
  background:var(--surface-2);border:1px solid var(--border);border-radius:999px;padding:3px 8px;cursor:pointer}
.dd-chip b{font-family:ui-monospace,Menlo,Consolas,monospace;color:var(--muted);font-weight:700;margin-left:3px}
.dd-chip:hover{color:var(--text-primary)}
.dd-chip.on{border-color:var(--gc,var(--accent));color:var(--text-primary)}
.dd-chip.on b{color:var(--gc,var(--accent))}
.dd-count{margin-top:6px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-variant-numeric:tabular-nums}
.dd-count b{color:var(--gc,var(--accent))}
.dd-none{padding:12px 10px;font-size:12.5px;color:var(--muted)}
.dd-none[hidden]{display:none}
.dd-row[hidden]{display:none}
.dd-f{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10px;color:var(--muted);
  background:var(--surface-2);border:1px solid var(--border);border-radius:6px;padding:3px 7px;
  white-space:nowrap;font-variant-numeric:tabular-nums}
.dd-f b{color:var(--gc,var(--accent));font-weight:700}
@media(max-width:900px){.dropdown{width:auto;min-width:300px}.dd-grid{grid-template-columns:1fr}
  .dd-list{border-right:0}.dd-pre{display:none}}
.tn-right{margin-left:auto;display:flex;align-items:center;gap:9px}
/* global search */
.tn-search{position:relative;display:flex;align-items:center;height:var(--nav-h);box-sizing:border-box}
.tn-search .tn-sicon{position:absolute;left:10px;font-size:15px;color:var(--muted);pointer-events:none}
/* Vertical padding is 0 on purpose: the height comes from --nav-h so this field lines up with the
   pills beside it. Horizontal padding still varies — the left inset clears the search glyph. */
#foundry-q{width:170px;height:100%;box-sizing:border-box;background:var(--surface-1);border:1px solid var(--border-strong);border-radius:var(--nav-r);
  color:var(--text-primary);font:inherit;font-size:13px;padding:0 12px 0 30px;outline:none;transition:width .16s,border-color .16s}
#foundry-q::placeholder{color:var(--muted)}
#foundry-q:focus{width:230px;border-color:var(--accent)}
#foundry-q::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.tn-results{position:absolute;top:calc(100% + 8px);right:0;width:360px;max-height:66vh;overflow-y:auto;z-index:200;
  background:var(--surface-1);border:1px solid var(--border-strong);border-radius:14px;box-shadow:0 18px 44px rgba(0,0,0,.4);padding:6px}
.tn-res{display:grid;grid-template-columns:1fr auto;gap:2px 10px;text-decoration:none;padding:9px 12px;border-radius:10px;align-items:baseline}
.tn-res:hover,.tn-res.on{background:color-mix(in srgb,var(--accent) 16%,var(--surface-1))}
.tn-rt{font-size:13.5px;font-weight:650;color:var(--text-primary)}
/* The ADMIN tag on a search result. Only rows from search-index-admin.js carry it, and only an
   admin's browser ever loads that file — so this marks "nobody else can see this row".
   OUTLINE, NOT A FILL, and that is the --accent-fill lesson applied rather than re-learned: a
   filled --gold carries near-black ink fine in dark (8.4:1) but the light theme's darker gold
   (#a9761c) is 4.0:1 against white, under the 4.5 floor. The outline chip is the idiom already
   used by .kit-badge above and it measures clean in both themes. */
.tn-adm{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:999px;font-size:9.5px;
  font-weight:800;letter-spacing:.07em;vertical-align:1px;color:var(--gold);
  border:1px solid color-mix(in srgb,var(--gold) 45%,transparent);
  background:color-mix(in srgb,var(--gold) 12%,transparent)}
.tn-rg{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);white-space:nowrap}
.tn-rs{grid-column:1 / -1;font-size:12px;color:var(--text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tn-empty{padding:14px 12px;font-size:13px;color:var(--muted)}
@media(max-width:1180px){#foundry-q{width:130px}#foundry-q:focus{width:180px}}
.seg{display:inline-flex;background:var(--surface-1);border:1px solid var(--border-strong);border-radius:var(--nav-r);padding:3px;
  height:var(--nav-h);box-sizing:border-box;align-items:center}
.seg button{border:0;background:transparent;cursor:pointer;font:inherit;font-size:12px;font-weight:600;
  color:var(--text-secondary);padding:0 11px;border-radius:var(--nav-r);height:100%}
.seg button[aria-pressed="true"]{background:var(--accent-fill);color:var(--accent-fill-ink)}
.cta{display:inline-flex;align-items:center;gap:7px;text-decoration:none;font-weight:650;font-size:13px;
  color:var(--accent-fill-ink);background:linear-gradient(135deg,var(--accent-fill),color-mix(in srgb,var(--accent-fill) 70%,var(--accent-2)));
  padding:0 14px;height:var(--nav-h);box-sizing:border-box;border-radius:var(--nav-r);box-shadow:0 6px 18px rgba(91,141,239,.35);white-space:nowrap}
.cta:hover{filter:brightness(1.06)}
/* Account / sign-out. An icon, not a labelled button: it is used roughly never (sign out on a
   shared machine, or switch a wrong Google account), so it should be findable without taking
   nav weight from Cheat sheet. */
/* Square by construction so --nav-r keeps it a circle: width tracks the shared height. */
.tn-account{display:inline-flex;align-items:center;justify-content:center;text-decoration:none;
  font-size:13px;line-height:1;width:var(--nav-h);height:var(--nav-h);box-sizing:border-box;border-radius:var(--nav-r);
  background:var(--surface-1);border:1px solid var(--border-strong);opacity:.75}
.tn-account:hover{opacity:1;border-color:var(--accent)}
/* Signal — the one live thing on a static site, so it gets a standalone link and a dot rather
   than a dropdown row. Sits between the account icon and the Map CTA; hides into the burger at
   the same breakpoint as the rest of tn-right. */
.tn-signal{display:inline-flex;align-items:center;gap:7px;text-decoration:none;white-space:nowrap;
  font-weight:650;font-size:13px;color:var(--text-secondary);padding:0 11px;height:var(--nav-h);box-sizing:border-box;border-radius:var(--nav-r);
  border:1px solid var(--border-strong);background:var(--surface-1)}
.tn-signal:hover{color:var(--text-primary);border-color:var(--c-aqua)}
.tn-admin:hover{border-color:var(--c-violet)}
.tn-admin-badge{display:inline-flex;align-items:center;justify-content:center;min-width:17px;height:17px;padding:0 4px;border-radius:999px;background:var(--c-red);color:#fff;font-size:10px;font-weight:800;line-height:1}
.sig-dot{width:7px;height:7px;border-radius:999px;background:var(--c-aqua);flex:none;
  box-shadow:0 0 0 0 color-mix(in srgb,var(--c-aqua) 60%,transparent);animation:sigpulse 2.6s ease-out infinite}
@keyframes sigpulse{
  0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--c-aqua) 55%,transparent)}
  70%{box-shadow:0 0 0 6px color-mix(in srgb,var(--c-aqua) 0%,transparent)}
  100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--c-aqua) 0%,transparent)}}
/* A dot that pulses is motion; respect a reader who asked the OS for none. */
@media(prefers-reduced-motion:reduce){.sig-dot{animation:none}}

/* ═══ SIGNAL — the daily brief, and the homepage news band ═══════════════════════════════════
   Layout from the approved wireframe: a ranked list of items on the brief page, and a compact
   "Today in AI" band on the homepage whose cards open the source article on its own page. No
   cost, no bill — this is news, read and ranked. */

/* Homepage band. Quiet by default: Foundry is a reading site, so this sits above the fold
   without shouting. */
.sig-band{margin:0 0 30px;padding:16px 18px;border:1px solid var(--border);border-radius:14px;
  background:radial-gradient(120% 160% at 0% 0%,color-mix(in srgb,var(--c-aqua) 9%,var(--surface-1)),var(--surface-1))}
.sig-band-hd{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:13px}
.sig-band-dot{width:7px;height:7px;border-radius:999px;background:var(--c-aqua);flex:none;
  box-shadow:0 0 0 0 color-mix(in srgb,var(--c-aqua) 55%,transparent);animation:sigpulse 2.6s ease-out infinite}
@media(prefers-reduced-motion:reduce){.sig-band-dot{animation:none}}
.sig-band-ttl{font-family:var(--font-display);font-weight:700;font-size:15px;letter-spacing:-.01em;color:var(--text-primary)}
.sig-band-when{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.sig-band-all{margin-left:auto;font-size:12px;font-weight:600;color:var(--c-aqua);text-decoration:none;flex:none}
.sig-band-all:hover{text-decoration:underline}
.sig-band-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:10px;grid-auto-rows:1fr}
.sig-bcard{display:flex;flex-direction:column;gap:6px;min-width:0;padding:12px 13px;text-decoration:none;
  background:var(--surface-2);border:1px solid var(--border);border-radius:10px;transition:border-color .15s,transform .15s}
.sig-bcard:hover{border-color:color-mix(in srgb,var(--c-aqua) 45%,transparent);transform:translateY(-1px)}
.sig-bcard-src{font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);font-weight:600}
.sig-bcard-hl{font-size:13px;font-weight:650;line-height:1.34;color:var(--text-primary)}
.sig-bcard-why{font-size:11.5px;color:var(--text-secondary);line-height:1.45}

/* Brief page — the dated header and its clocks. */
.sig-meta{display:flex;flex-direction:column;gap:7px;padding-bottom:16px;margin-bottom:8px;
  border-bottom:1px solid var(--border);font-size:12.5px;color:var(--text-secondary)}
.sig-counts,.sig-clock{display:flex;gap:8px;flex-wrap:wrap;align-items:baseline;font-variant-numeric:tabular-nums}
.sig-meta b{color:var(--text-primary);font-weight:650}
.sig-sep{opacity:.4}
.sig-next{color:var(--c-aqua)!important}
.sig-warn{color:var(--c-yellow);font-weight:600}
.sig-lead{font-size:18px;line-height:1.55;color:var(--text-primary);margin:22px 0 8px;max-width:64ch;
  font-family:var(--font-display);letter-spacing:-.01em;text-wrap:balance}

/* Listen — the read-aloud control. Hidden until signal.js confirms the browser can speak. */
.sig-listen{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:18px 0 4px}
.sig-listen-btn{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font:inherit;
  font-family:var(--font-display);font-size:13.5px;font-weight:650;color:var(--text-primary);
  background:var(--surface-1);border:1px solid var(--border-strong);border-radius:999px;padding:8px 16px 8px 13px}
.sig-listen-btn:hover{border-color:var(--c-aqua)}
.sig-listen-btn[aria-pressed="true"]{border-color:var(--c-aqua);
  background:color-mix(in srgb,var(--c-aqua) 12%,var(--surface-1))}
.sig-listen-ic{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;
  border-radius:999px;background:var(--c-aqua);color:#04140f;font-size:11px;line-height:1;flex:none}
.sig-listen-hint{font-size:11.5px;color:var(--muted)}
/* Natural-voice player (Deepgram Aura-2 MP3). Replaces the browser-TTS button when the day's audio
   was pre-rendered. Full-width audio control + a small provenance tag. */
.sig-listen-audio{flex-direction:column;align-items:stretch;gap:7px}
.sig-audio{width:100%;max-width:520px;height:40px}
.sig-audio-tag{font-family:var(--font-display);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;font-weight:600;color:var(--muted)}
.sig-opt{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:var(--muted)}
.sig-opt-lab{font-family:var(--font-display);font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:600}
.sig-opt-sel{font:inherit;font-size:12px;color:var(--text-primary);background:var(--surface-1);
  border:1px solid var(--border-strong);border-radius:8px;padding:5px 8px;cursor:pointer;max-width:210px}
.sig-opt-sel:hover{border-color:var(--c-aqua)}
.sig-opt-sel:focus-visible{outline:2px solid var(--c-aqua);outline-offset:1px}
/* Accent — a three-way segmented toggle (USA / Europe / Asian). */
.sig-acc{display:inline-flex;background:var(--surface-1);border:1px solid var(--border-strong);
  border-radius:999px;padding:3px;gap:2px}
.sig-acc-btn{font:inherit;font-size:11.5px;font-weight:600;cursor:pointer;border:0;background:transparent;
  color:var(--text-secondary);padding:5px 11px;border-radius:999px;white-space:nowrap}
.sig-acc-btn:hover:not(:disabled){color:var(--text-primary)}
.sig-acc-btn[aria-pressed="true"]{background:var(--c-aqua);color:#04140f}
.sig-acc-btn:disabled{opacity:.35;cursor:not-allowed}
.sig-acc-btn:focus-visible{outline:2px solid var(--c-aqua);outline-offset:1px}
/* The item currently being read aloud. */
.sig-reading{border-color:color-mix(in srgb,var(--c-aqua) 55%,transparent)!important;
  box-shadow:0 0 0 1px color-mix(in srgb,var(--c-aqua) 45%,transparent),
             0 8px 26px color-mix(in srgb,var(--c-aqua) 16%,transparent)}
.sig-lead.sig-reading{border-radius:10px;padding:8px 12px;margin-left:-12px}

/* Brief page — the ranked item list. */
.sig-brief{margin-top:20px}
/* News | Research split — two ranked columns off the labels the feed already emits. Stacks on
   narrow. Each column keeps its own heading and ranked list; a quiet column says so. */
.sig-cols{display:grid;grid-template-columns:1fr 1fr;gap:26px;align-items:start}
.sig-cols .sig-col>h2{margin:0 0 14px}
.sig-col-research>h2 .k{color:var(--c-violet)}
.sig-col-empty{font-size:13.5px;color:var(--muted);background:var(--surface-2);
  border:1px dashed var(--border-strong);border-radius:12px;padding:16px 18px;margin:0}
@media(max-width:860px){.sig-cols{grid-template-columns:1fr;gap:20px}}
/* "What's new" — news the daily Signal auto-linked to this page (initiative A). A dated link and
   the brief's own impact line; never a rewrite of the page. Leads the page as a freshness cue. */
.whatsnew{margin:0 0 26px;padding:15px 18px;border:1px solid var(--border);border-left:3px solid var(--c-yellow);
  border-radius:12px;background:var(--surface-2)}
.whatsnew>h2{margin:0 0 11px}
.wn-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.wn-item{font-size:14px;line-height:1.5}
.wn-hl{font-weight:650;color:var(--text-primary);text-decoration:none;border-bottom:1px solid var(--border-strong)}
.wn-hl:hover{border-color:var(--c-yellow)}
.wn-meta{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;color:var(--muted)}
.wn-impact{display:block;color:var(--text-secondary);font-size:13px;margin-top:3px}
.wn-note{font-size:11.5px;color:var(--muted);margin:13px 0 0}
/* "From Signal" — permanent, operator-approved digests promoted into a page (build/synth/placed.json). */
.sigdesk{margin:0 0 26px;padding:15px 18px;border:1px solid var(--border);border-left:3px solid var(--c-aqua);
  border-radius:12px;background:var(--surface-2)}
.sigdesk>h2{margin:0 0 11px}
.sd-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.sd-item{font-size:14px;line-height:1.55}
.sd-digest{margin:0;color:var(--text-primary)}
.sd-meta{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;color:var(--muted);margin:4px 0 0}
.sd-meta a{color:var(--muted);text-decoration:underline}
.sd-meta a:hover{color:var(--c-aqua)}
.sd-note{font-size:11.5px;color:var(--muted);margin:13px 0 0}
/* "What today means for builders" — the daily brief regrouped by build impact. Three buckets keyed
   by story category; each colour matches the type pills (cap=aqua, price=yellow, heading=blue) so
   the same taxonomy reads consistently down the page. */
.sig-builders{margin-top:26px}
.sig-builders-hd h2{font-family:var(--font-display);font-size:19px;letter-spacing:-.01em;margin:0 0 4px}
.sig-builders-hd p{font-size:13.5px;color:var(--muted);margin:0 0 16px;max-width:62ch}
.sig-builders-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;grid-auto-rows:1fr}
.sig-bkt{background:var(--surface-1);border:1px solid var(--border);border-top:2px solid var(--bkt,var(--accent));
  border-radius:12px;padding:14px 15px;display:flex;flex-direction:column;gap:11px}
.sig-bkt-cap{--bkt:var(--c-aqua)}
.sig-bkt-price{--bkt:var(--c-yellow)}
.sig-bkt-dir{--bkt:var(--c-blue)}
.sig-bkt-top{display:flex;align-items:center;gap:8px}
.sig-bkt-ic{font-size:15px;flex:none;line-height:1}
.sig-bkt-ttl{font-family:var(--font-display);font-size:12.5px;font-weight:700;letter-spacing:.01em;
  color:var(--text-primary);flex:1;min-width:0}
.sig-bkt-n{font-size:11px;font-weight:700;color:var(--bkt);background:color-mix(in srgb,var(--bkt) 14%,transparent);
  border:1px solid color-mix(in srgb,var(--bkt) 34%,transparent);border-radius:999px;min-width:20px;
  text-align:center;padding:1px 7px;font-variant-numeric:tabular-nums}
.sig-bkt-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:0}
.sig-bkt-list li{border-top:1px solid var(--border)}
.sig-bkt-list li:first-child{border-top:none}
.sig-bkt-list li a{display:flex;flex-direction:column;gap:3px;text-decoration:none;padding:9px 0}
.sig-bkt-list li:first-child a{padding-top:1px}
.sig-bkt-list li:last-child a{padding-bottom:1px}
.sig-bkt-hl{font-size:13.5px;line-height:1.35;font-weight:600;color:var(--text-primary)}
.sig-bkt-list li a:hover .sig-bkt-hl{color:var(--bkt)}
.sig-bkt-why{font-size:12px;line-height:1.45;color:var(--text-secondary)}
.sig-bkt-empty{font-size:12.5px;color:var(--muted);font-style:italic;padding:2px 0}
.sig-bkt-ago{font-size:10px;font-weight:600;color:var(--muted);border:1px solid var(--border);border-radius:4px;padding:0 5px;margin-left:6px;white-space:nowrap;vertical-align:middle}
/* Signal News / Research tabs — bold segmented control, sits right under the meta strip */
.sig-tabs{display:flex;gap:8px;margin:18px 0 8px}
.sig-tab{font-family:var(--font-display);font-size:16px;font-weight:700;color:var(--text-secondary);background:var(--surface-2);border:1.5px solid var(--border);border-radius:11px;padding:11px 22px;cursor:pointer;display:inline-flex;align-items:center;gap:9px;transition:color .14s,background .14s,border-color .14s}
.sig-tab:hover{color:var(--text-primary);border-color:var(--border-strong)}
.sig-tab-n{font-size:12px;font-weight:700;color:var(--muted);background:var(--surface-1);border-radius:999px;padding:1px 8px;font-family:var(--font-body)}
.sig-tab[aria-selected="true"]{color:var(--accent-fill-ink);background:var(--accent-fill);border-color:transparent}
.sig-tab[aria-selected="true"] .sig-tab-n{color:var(--accent-fill-ink);background:var(--accent-fill-badge)}
.sig-panel{display:none}
.sig-panel[data-on="1"]{display:block}
.sig-arch-note{margin:14px 0 0;border:1px solid var(--gold);border-radius:10px;background:rgba(214,169,78,0.08);padding:11px 15px;font-size:13px;line-height:1.5;color:var(--text-secondary)}
.sig-arch-note b{color:var(--text-primary)}
.sig-arch-note a{color:var(--accent);font-weight:600;text-decoration:none;white-space:nowrap}
/* Signal head: title on the left, the "How this stays current" card in the dead space on the
   right. It used to be a sticky rail beside the brief, which cost the body a 300px column for the
   entire scroll — the lane grid below wants every pixel and was running three narrow columns
   against an empty gutter. In the head it fills space that was empty anyway, and the brief gets
   the full width. Stacks under the title below 1000px rather than disappearing. */
.sig-head{display:grid;grid-template-columns:minmax(0,1fr) 440px;gap:30px;align-items:center}
.sig-head-t{min-width:0}
.sig-head-card{min-width:0}
@media(max-width:1000px){
  .sig-head{grid-template-columns:1fr;gap:20px}
  .sig-head-card{max-width:520px}
}
/* LANDSCAPE, not a square block. The card was authored for a 300px sticky rail, where tall was
   free; in the head its height is the header's height, so every vertical pixel it takes pushes the
   brief further down the page. Wider column plus tighter internals turns it from roughly 1:1 into a
   rectangle without dropping anything it says. Scoped to .sig-head-card so the rail proportions
   survive if the card is ever used somewhere tall again. */
.sig-head-card .sighc-in{padding:15px 17px 16px}
.sig-head-card .sighc-ttl{font-size:16px;margin:0 0 12px}
.sig-head-card .sighc-fig{margin:0 0 12px}
.sig-head-card .sighc-foot{margin:11px 0 0;padding-top:10px}
.sighc-card{position:relative;border:1px solid var(--border);border-radius:16px;
  background:var(--surface-1);box-shadow:var(--shadow);overflow:hidden}
.sighc-in{padding:18px 18px 20px}
.sighc-ttl{font-family:var(--font-display);font-size:18px;font-weight:700;letter-spacing:-.01em;color:var(--text-primary);margin:0 0 14px}
/* THE FIGURE. One brief item, two destinations — see _signal_how_card() for why this is a BRANCH
   and not the five-node sequence it replaced. Everything inks from tokens so the figure re-colours
   itself in the light theme with no second copy: --muted is a stage whose contents ROTATE, and
   --text-primary is the strongest ink the theme has, spent on the one terminal that is permanent.
   That contrast is the whole citation rule, carried by a fill colour. */
.sighc-fig{display:block;width:100%;height:auto;margin:0 0 14px}
.sighc-fig text{font-family:var(--font-body)}
.sighc-fig .sighc-l{font-size:9px;font-weight:700;letter-spacing:.8px;fill:var(--text-primary)}
.sighc-fig .sighc-lq{font-size:9px;font-weight:700;letter-spacing:.8px;fill:var(--muted)}
.sighc-fig .sighc-s{font-size:8.5px;font-weight:500;fill:var(--muted)}
.sighc-link{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:600;
  color:var(--accent);text-decoration:none;border-bottom:1px solid transparent;
  transition:border-color .14s ease}
.sighc-link:hover,.sighc-link:focus-visible{border-bottom-color:var(--accent)}
.sighc-foot{font-size:10.5px;color:var(--muted);margin:14px 0 0;padding-top:11px;
  border-top:1px solid var(--border)}
/* Signal history — every earlier brief kept, browsable inline */
.sig-hist{margin:30px 0 0;border-top:1px solid var(--border);padding-top:20px}
.sig-hist-note{font-size:12.5px;color:var(--muted);margin:0 0 14px}
.sig-hist-day{border:1px solid var(--border);border-radius:10px;background:var(--surface-2);margin:0 0 8px;overflow:hidden}
.sig-hist-day summary{cursor:pointer;padding:12px 15px;font-family:var(--font-display);font-size:14px;font-weight:600;color:var(--text-primary);list-style:none;display:flex;align-items:center;gap:9px}
.sig-hist-day summary::-webkit-details-marker{display:none}
.sig-hist-day summary::before{content:"\25B8";color:var(--muted);font-size:12px;transition:transform .15s}
.sig-hist-day[open] summary::before{transform:rotate(90deg)}
.sig-hist-n{font-size:11px;font-weight:600;color:var(--muted);background:var(--surface-1);border:1px solid var(--border);border-radius:999px;padding:1px 8px;margin-left:auto}
.sig-hist-list{padding:2px 15px 14px}
.sig-hist-row{display:flex;flex-direction:column;gap:2px;padding:9px 0;border-top:1px solid var(--border);text-decoration:none}
.sig-hist-row:first-child{border-top:0}
.sig-hist-hl{font-size:13px;font-weight:600;color:var(--text-primary);line-height:1.4}
.sig-hist-row:hover .sig-hist-hl{color:var(--accent)}
.sig-hist-src{font-size:11px;color:var(--muted)}
.sig-hist-full{display:inline-block;margin-top:11px;font-size:12.5px;font-weight:600;color:var(--accent);text-decoration:none}
/* Signal Research cards — chronological, source on the right rail */
.sig-rdate{font:700 10.5px/1 var(--font-body);letter-spacing:.6px;text-transform:uppercase;color:var(--c-violet);margin:22px 0 11px;display:flex;align-items:center;gap:10px}
.sig-rdate:first-child{margin-top:16px}
.sig-rdate::after{content:"";flex:1;height:1px;background:var(--border)}
.sig-rcard{display:flex;border:1px solid var(--border);border-radius:12px;background:var(--surface-2);overflow:hidden;margin:0 0 11px}
.sig-rmain{flex:1;min-width:0;padding:15px 17px}
.sig-rtitle{font-family:var(--font-display);font-size:15.5px;font-weight:600;line-height:1.35;margin:0 0 8px}
.sig-rtitle a{text-decoration:none;color:var(--text-primary)}
.sig-rtitle a:hover{color:var(--accent)}
.sig-rimpact{font-size:12.5px;color:var(--text-secondary);line-height:1.5;margin:0}
.sig-rimpact b{color:var(--c-aqua);font-weight:700;text-transform:uppercase;font-size:10px;letter-spacing:.4px;margin-right:6px}
.sig-rsrc{flex:0 0 172px;border-left:1px solid var(--border);background:var(--surface-1);padding:15px 15px;display:flex;flex-direction:column;gap:5px}
.sig-rsrc-l{font:700 9px/1 var(--font-body);letter-spacing:.6px;text-transform:uppercase;color:var(--muted)}
.sig-rsrc-name{font-size:13px;font-weight:700;color:var(--text-primary);line-height:1.3}
.sig-rsrc-date{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.sig-rsrc-lnk{margin-top:auto;font-size:12px;font-weight:600;color:var(--accent);text-decoration:none}
.sig-rempty{border:1px dashed var(--border);border-radius:10px;padding:16px 18px;color:var(--muted);font-size:13px;line-height:1.55;margin-top:16px}
@media(max-width:640px){.sig-rcard{flex-direction:column}.sig-rsrc{flex-basis:auto;border-left:0;border-top:1px solid var(--border);flex-direction:row;flex-wrap:wrap;align-items:center;gap:8px}.sig-rsrc-lnk{margin:0 0 0 auto}}
@media(max-width:720px){.sig-builders-grid{grid-template-columns:1fr}}
.sig-list{display:flex;flex-direction:column;gap:14px}
.sig-item{display:grid;grid-template-columns:34px 1fr;gap:10px;padding:15px 16px;
  background:var(--surface-1);border:1px solid var(--border);border-radius:12px}
.sig-rank{font-family:var(--font-display);font-size:13px;font-weight:700;color:var(--muted);
  font-variant-numeric:tabular-nums;padding-top:2px}
.sig-body{min-width:0;display:flex;flex-direction:column;gap:7px}
.sig-src{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:10.5px;color:var(--muted);
  letter-spacing:.04em;text-transform:uppercase;font-weight:600}
.sig-lnk{color:var(--c-aqua);text-transform:none;letter-spacing:0;font-weight:600;text-decoration:none}
.sig-lnk:hover{text-decoration:underline}
.sig-hl{font-family:var(--font-display);font-size:16px;line-height:1.3;letter-spacing:-.01em;margin:0}
.sig-hl a{color:var(--text-primary);text-decoration:none}
.sig-hl a:hover{color:var(--c-aqua)}
/* Two labelled rows per item — "The news" (the source's own words) and "What it means for you"
   (the model's impact line). The template from the wireframe. */
.sig-rows{display:flex;flex-direction:column;gap:9px;margin-top:3px}
.sig-row{display:grid;grid-template-columns:132px 1fr;gap:12px;align-items:baseline}
.sig-k{font-family:var(--font-display);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);font-weight:700;padding-top:3px}
.sig-v{font-size:14px;line-height:1.55;color:var(--text-secondary);min-width:0}
.sig-impact{color:var(--text-primary)}
@media(max-width:640px){.sig-row{grid-template-columns:1fr;gap:2px}.sig-k{padding-top:0}}

/* "More from today" — the rest of the sweep, collapsed behind a native <details>. */
.sig-more{border:1px solid var(--border);border-radius:12px;background:var(--surface-1);overflow:hidden}
.sig-more>summary{cursor:pointer;padding:14px 16px;font-family:var(--font-display);font-size:13.5px;
  color:var(--text-secondary);list-style:none;user-select:none}
.sig-more>summary::-webkit-details-marker{display:none}
.sig-more>summary::before{content:"▸ ";color:var(--muted)}
.sig-more[open]>summary::before{content:"▾ "}
.sig-more>summary b{color:var(--text-primary)}
.sig-more>summary:hover{color:var(--text-primary)}
.sig-more-cap{color:var(--muted);font-size:11.5px;font-weight:400}
.sig-more-list{display:flex;flex-direction:column;border-top:1px solid var(--border)}
.sig-more-item{display:flex;flex-direction:column;gap:4px;padding:12px 16px;text-decoration:none;
  border-bottom:1px solid var(--border)}
.sig-more-item:last-child{border-bottom:none}
.sig-more-item:hover{background:var(--surface-2)}
.sig-more-meta{display:flex;align-items:center;gap:7px;font-size:10px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);font-weight:600}
.sig-more-hl{font-size:13.5px;font-weight:600;line-height:1.35;color:var(--text-primary)}
.sig-more-sum{font-size:12.5px;line-height:1.5;color:var(--text-secondary)}
.sig-pill{display:inline-flex;align-items:center;font-family:var(--font-display);font-size:9.5px;
  font-weight:700;letter-spacing:.07em;text-transform:uppercase;padding:2.5px 7px;border-radius:20px;
  border:1px solid var(--border-strong);color:var(--text-secondary);background:var(--surface-3);white-space:nowrap}
/* Country pill: colour marks the bloc (US / China / any other nation), text names the country. */
.sig-p-us{color:var(--c-blue);border-color:color-mix(in srgb,var(--c-blue) 42%,transparent);background:color-mix(in srgb,var(--c-blue) 12%,transparent)}
.sig-p-cn{color:var(--c-red);border-color:color-mix(in srgb,var(--c-red) 42%,transparent);background:color-mix(in srgb,var(--c-red) 12%,transparent)}
.sig-p-natl{color:var(--c-green);border-color:color-mix(in srgb,var(--c-green) 42%,transparent);background:color-mix(in srgb,var(--c-green) 12%,transparent)}
/* Type pill: one colour per kind of change. */
.sig-t-cap{color:var(--c-aqua);border-color:color-mix(in srgb,var(--c-aqua) 42%,transparent);background:color-mix(in srgb,var(--c-aqua) 12%,transparent)}
.sig-t-price{color:var(--c-yellow);border-color:color-mix(in srgb,var(--c-yellow) 42%,transparent);background:color-mix(in srgb,var(--c-yellow) 12%,transparent)}
.sig-t-biz{color:var(--c-violet);border-color:color-mix(in srgb,var(--c-violet) 42%,transparent);background:color-mix(in srgb,var(--c-violet) 12%,transparent)}
.sig-t-res{color:var(--c-orange);border-color:color-mix(in srgb,var(--c-orange) 42%,transparent);background:color-mix(in srgb,var(--c-orange) 12%,transparent)}
.sig-t-pol{color:var(--c-magenta);border-color:color-mix(in srgb,var(--c-magenta) 42%,transparent);background:color-mix(in srgb,var(--c-magenta) 12%,transparent)}
.sig-p-vendor{color:var(--c-aqua);border-color:color-mix(in srgb,var(--c-aqua) 42%,transparent);background:color-mix(in srgb,var(--c-aqua) 12%,transparent)}
.sig-p-research{color:var(--c-violet);border-color:color-mix(in srgb,var(--c-violet) 42%,transparent);background:color-mix(in srgb,var(--c-violet) 12%,transparent)}
.sig-p-market{color:var(--c-yellow);border-color:color-mix(in srgb,var(--c-yellow) 42%,transparent);background:color-mix(in srgb,var(--c-yellow) 12%,transparent)}
.sig-p-practice{color:var(--c-aqua);border-color:color-mix(in srgb,var(--c-aqua) 42%,transparent);background:color-mix(in srgb,var(--c-aqua) 12%,transparent)}
.sig-p-analysis{color:var(--accent-2);border-color:color-mix(in srgb,var(--accent-2) 42%,transparent);background:color-mix(in srgb,var(--accent-2) 12%,transparent)}
.sig-p-digest{color:var(--text-secondary)}

/* Brief page — provenance, archive, empty state. */
.sig-prov{margin-top:26px;padding-top:14px;border-top:1px solid var(--border)}
.sig-prov p{font-size:12.5px;color:var(--muted);line-height:1.6;max-width:74ch}
.sig-arch{margin-top:24px;display:flex;gap:8px;flex-wrap:wrap;align-items:baseline}
.sig-arch-h{font-family:var(--font-display);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:700;margin-right:4px}
.sig-arch-lnk,.sig-arch-cur{font-size:12px;font-variant-numeric:tabular-nums;padding:3px 9px;border-radius:999px;border:1px solid var(--border)}
.sig-arch-lnk{color:var(--text-secondary);text-decoration:none;background:var(--surface-1)}
.sig-arch-lnk:hover{border-color:var(--c-aqua);color:var(--text-primary)}
.sig-arch-cur{color:var(--muted);opacity:.6;background:var(--surface-2)}
.sig-empty{padding:8px 0 20px}
.sig-empty h2{font-family:var(--font-display);font-size:20px;margin:0 0 8px}
.sig-empty p{color:var(--text-secondary);max-width:60ch}
@media(max-width:640px){.sig-item{grid-template-columns:26px 1fr;gap:8px;padding:13px}}

/* The burger is a member of the top-right cluster and reads the same two tokens as the rest of it.
   It escaped BOTH earlier sweeps — it kept a 10px radius when the row was unified on --nav-r, and
   it measured 37px when the row was unified on --nav-h — because it only renders below 1100px, so
   neither desktop check ever saw it. That is the argument for tokens over per-control values: a
   control you cannot see on the screen you are testing still drifts. */
.burger{display:none;background:var(--surface-1);border:1px solid var(--border-strong);color:var(--text-primary);
  border-radius:var(--nav-r);padding:0 11px;height:var(--nav-h);box-sizing:border-box;
  align-items:center;cursor:pointer;font-size:15px}
.lens-seg{display:inline-flex;background:var(--surface-1);border:1px solid var(--border-strong);border-radius:999px;padding:3px}
.lens-seg button{border:0;background:transparent;cursor:pointer;font:inherit;font-size:11.5px;font-weight:600;
  color:var(--text-secondary);padding:5px 9px;border-radius:999px}
.lens-seg button[aria-pressed="true"]{background:var(--text-primary);color:var(--page)}

/* mobile menu */
.mobile-menu{display:none}
@media(max-width:1180px){.lens-seg{display:none}}
/* 980, not 940. The desktop bar needs 982px at its tightest, so 941-980px was a seam where the
   burger had not taken over yet and the full bar could not fit — the header itself pushed
   document.scrollWidth out and the whole page scrolled sideways. Moving the breakpoint to meet
   the width the bar actually needs closes it; below this the burger owns the nav, above it the
   bar is verified to fit. Do not lower this without re-measuring the bar.
   ⚑⚑ 1280 SINCE 2026-08-26, AND THIS REVERSES A RECORDED DECISION — the ~1040px note below says
   in as many words that hiding controls was rejected because "the alternative was raising the
   hamburger breakpoint and losing the menu entirely on a laptop". That judgement was made for a
   SEVEN-tab bar and the eighth changed the arithmetic, measured rather than argued: fully
   tightened (padding 3px, labels 12.5px, wordmark tail hidden, .tn-right down to its own 212px
   minimum) the bar still ran 26-126px long at every width from 1000 to 1280. There is no knob
   left that does not delete a destination, and THAT is the rule this file will not break. So the
   burger owns the nav up to 1280 instead of 980.
   ⚠︎ NOTHING BECOMES UNREACHABLE. drawerHtml() iterates the same BAR array the desktop bar is
   built from, so all eight tabs — Cross-domain included — plus Signal, Learn, the Map and the
   account are in the drawer at every width below this. Re-measure before moving it again; the
   number is a measurement of the current bar, not a preference. */
@media(max-width:1280px){
  /* Everything here is already reachable from the burger menu, so it hides rather than fighting
     for width. The .cta ("Cheat sheet →") was the actual cause of the burger being pushed off
     the right edge on a phone: brand + search + a 14px-padded gradient button + burger does not
     fit, and .tn-right has no wrap, so the last child overflowed the viewport. */
  .menu,.tn-right .seg,.tn-right .lens-seg,.tn-right .tn-account,.tn-right .tn-signal,.tn-right .cta{display:none}
  .burger{display:inline-flex;flex:none}
  /* Belt and braces: the header must never be the thing that scrolls sideways. */
  .tn-inner{gap:8px;padding:0 14px;overflow:hidden}
  .tn-right{min-width:0;gap:7px}
  .tn-search{min-width:0;flex:1 1 auto}
  #foundry-q{width:100%;min-width:0}
  #foundry-q:focus{width:100%}
  .brand .wordmark{display:none}   /* logo mark alone carries the brand at this width */
  .mobile-menu{display:block;position:fixed;inset:var(--header-h) 0 0 0;z-index:90;background:var(--page);
    overflow-y:auto;padding:16px 20px 60px;transform:translateY(-8px);opacity:0;pointer-events:none;transition:all .18s}
  body.nav-open .mobile-menu{opacity:1;transform:none;pointer-events:auto}
  .mobile-menu .mg{font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin:18px 0 6px}
  .mobile-menu a{display:block;text-decoration:none;color:var(--text-primary);font-weight:600;padding:10px 8px;border-bottom:1px solid var(--border)}
  /* ⚑ THE DRAWER IS AN ACCORDION — 2026-08-24. It printed every group's rows flat, which after
     the kit menu grew was 111 links in one scroll. <details>/<summary> is native: it opens on
     tap, is keyboard-operable and is announced as expandable with no JS, so the drawer survives
     even if the desktop open/close controller never runs. */
  .mobile-menu .mg-acc{border-bottom:1px solid var(--border)}
  .mobile-menu .mg-acc summary.mg{display:flex;align-items:center;justify-content:space-between;
    gap:10px;margin:0;padding:14px 8px;font-size:13.5px;font-weight:700;letter-spacing:0;
    text-transform:none;color:var(--text-primary);cursor:pointer;list-style:none}
  .mobile-menu .mg-acc summary.mg::-webkit-details-marker{display:none}
  .mobile-menu .mg-acc summary.mg::after{content:"▾";font-size:11px;color:var(--muted);
    transition:transform .15s ease}
  .mobile-menu .mg-acc[open] summary.mg::after{transform:rotate(180deg)}
  .mobile-menu .mg-acc a{display:flex;align-items:center;gap:9px;font-weight:500;font-size:13.5px;
    padding:9px 8px 9px 18px;border-bottom:0;color:var(--text-secondary)}
  .mobile-menu .mg-acc a:last-child{padding-bottom:14px}
  .mobile-menu .mg-d{width:8px;height:8px;border-radius:50%;flex:none}
  .mobile-menu .mg-n{margin-left:auto;font-family:ui-monospace,Menlo,Consolas,monospace;
    font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}
  .mobile-menu .mg-all{display:flex;align-items:center;gap:9px;color:var(--accent)}
  /* A kit page's own sections, first in the drawer (nav.js fillPage). Lighter rows than the site
     links below them, and the panel being read is marked the way the desktop rail marks it. */
  .mobile-menu .mm-page .mg:first-child{margin-top:6px}
  .mobile-menu .mm-page a{font-weight:500;font-size:14px;padding:9px 8px;color:var(--text-secondary);
    font-variant-numeric:tabular-nums}
  .mobile-menu .mm-page a.is-here{color:var(--c-teal);font-weight:700}
  .mobile-menu .mm-page .mg:last-child{margin-top:22px}
  /* Theme row, first thing in the menu. Reuses the desktop .seg component rather than restyling
     a second toggle — one appearance, and the shared [data-theme-set] handler keeps both in step.
     The desktop hide rule targets `.tn-right .seg` specifically, so this copy is unaffected. */
  .mm-theme{display:flex;align-items:center;justify-content:space-between;gap:14px;
    padding:4px 8px 14px;margin-bottom:4px;border-bottom:1px solid var(--border)}
  .mm-theme-l{font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
  /* Bigger hit targets than the desktop toggle — this one is operated with a thumb. */
  .mobile-menu .seg button{font-size:13px;padding:8px 16px}
}

/* ---------------- Hero (index) ---------------- */
.hero{position:relative;overflow:hidden;border-bottom:1px solid var(--border);
  background:
    radial-gradient(900px 460px at 82% -8%,color-mix(in srgb,var(--accent-2) 26%,transparent),transparent 60%),
    radial-gradient(760px 420px at 8% 4%,color-mix(in srgb,var(--accent) 22%,transparent),transparent 58%)}
.hero .wrap{padding:64px 24px 54px;position:relative}
.eyebrow{font-family:var(--font-body);text-transform:uppercase;letter-spacing:.18em;font-size:12.5px;font-weight:700;
  color:var(--accent)}
.hero h1{font-size:clamp(38px,6.4vw,74px);line-height:1.02;margin:16px 0 20px;letter-spacing:-0.03em;max-width:15ch}
/* ⚑ THE INDEX HERO IS A FIGURE AND A LINE — approved 2026-08-30 (artifact 898da1e4): the kit count
   as a display number beside one short sentence, so the count IS the headline rather than a word in
   the eyebrow. The h1 keeps its role for structure and gates; the 15ch cap above is for a
   sentence-headline and is lifted here, which is what fills the right half of the fold. */
.hero h1.hero-head{display:flex;align-items:baseline;gap:22px;flex-wrap:wrap;max-width:none;font-size:inherit;line-height:1;margin:18px 0 22px}
.hero-big{font-family:var(--font-display);font-weight:700;font-size:clamp(72px,10.5vw,148px);line-height:.78;letter-spacing:-.05em;color:var(--accent);font-variant-numeric:tabular-nums}
.hero-words{font-family:var(--font-display);font-weight:700;letter-spacing:-.03em;line-height:1.02;font-size:clamp(26px,3.6vw,46px);color:var(--text-primary);text-wrap:balance;max-width:19ch}
@media(max-width:760px){.hero h1.hero-head{gap:10px}.hero-words{max-width:none}}
/* Follows --measure like all other prose. `.hero h1` above deliberately does NOT — a headline
   wants a short measure (15ch) whatever the body does, so it stays fixed. */
.hero .lead{font-size:clamp(16px,2vw,19px);color:var(--text-secondary);max-width:var(--measure);margin:0 0 28px}
.hero .lead strong{color:var(--text-primary);font-weight:600}
.hero-cta{display:flex;flex-wrap:wrap;gap:12px}
.btn{display:inline-flex;align-items:center;gap:8px;text-decoration:none;font-weight:650;font-size:15px;padding:13px 22px;border-radius:13px}
.btn.primary{color:var(--accent-fill-ink);background:linear-gradient(135deg,var(--accent-fill),color-mix(in srgb,var(--accent-fill) 65%,var(--accent-2)));
  box-shadow:0 8px 22px rgba(91,141,239,.4)}
.btn.primary:hover{filter:brightness(1.06)}
.btn.ghost{color:var(--text-primary);background:var(--surface-1);border:1px solid var(--border-strong)}
.btn.ghost:hover{border-color:var(--accent)}

/* content shell */
.content{padding:44px 0 10px}
.content .wrap>section{margin-bottom:30px}
.section-num{font-size:12px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.section-title{font-size:clamp(22px,3vw,30px);margin:8px 0 8px}
.section-lead{color:var(--text-secondary);max-width:var(--measure);margin:0 0 14px;font-size:15.5px}

/* figure / diagram */
.figure{background:var(--figure-bg);border:1px solid var(--border-strong);border-radius:18px;padding:24px;
  margin:10px 0;text-align:center;overflow-x:auto;box-shadow:var(--shadow)}
.figure img{max-width:100%;height:auto;display:block;margin:0 auto}
/* .figure centres its contents, which is right for a diagram and wrong for a table. text-align
   inherits, so a table dropped into a figure wrapper had its BODY cells centred while .ftable th
   and .dtable th set text-align:left explicitly — headers hard left, every data cell centred under
   them. 43 tables across 13 pages shipped that way, and the component standard is explicit:
   "Left-align every column. Mixed alignment forces the eye to hunt for column edges."
   Reset on the table rather than on each cell rule, so any table put in a figure later is covered
   without a new rule. */
.figure table{text-align:left}
/* Theme-swapped diagrams: every diagram is rendered twice (light + dark palette) and both <img>s
   are emitted; show the one matching the viewer's theme. Dark is the site default, so the dark
   render shows by default and the light render only under [data-theme="light"]. Specificity is
   img.dia-* so these beat the plain `.figure img` rule above. */
img.dia-light{display:none}
img.dia-dark{display:block;margin:0 auto}
html[data-theme="light"] img.dia-light{display:block;margin:0 auto}
html[data-theme="light"] img.dia-dark{display:none}
/* Tier-2 figures ship a narrow variant too, so their twins are <picture> rather than bare <img>
   (only <picture> can swap a different FILE by viewport). Same toggle, separate selectors: the
   rules above are element-qualified `img.dia-*` for specificity, so a <picture> would not match
   them and both themes would show at once. Mermaid diagrams keep the <img> path untouched. */
picture.dia-light{display:none}
picture.dia-dark{display:block;margin:0 auto}
html[data-theme="light"] picture.dia-light{display:block;margin:0 auto}
html[data-theme="light"] picture.dia-dark{display:none}
.figcap{font-size:12.5px;color:#6b7280;margin-top:14px;font-style:italic}

/* Lab output galleries. These are raster PNGs pulled straight out of notebook outputs, not
   authored vector like .figure — so they get a plain neutral frame rather than the diagram panel,
   and they are deliberately NOT theme-swapped: a matplotlib plot has a white canvas baked in and
   there is no dark twin to swap to. The white plate below keeps that canvas from floating on the
   dark site as a bright rectangle with no edge. auto-fit rather than a fixed column count so one
   surviving figure does not stretch to full width. */
.labfigs{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin:16px 0 0}
.labfig{margin:0;background:var(--figure-bg);border:1px solid var(--border-strong);
  border-radius:14px;padding:12px;box-shadow:var(--shadow);display:flex;flex-direction:column}
.labfig a{display:block;background:#fff;border-radius:8px;padding:6px;line-height:0}
.labfig img{width:100%;height:auto;display:block;border-radius:4px}
.labfig figcaption{font-size:11.5px;color:var(--muted);margin-top:10px;font-style:italic;line-height:1.45}
@media (max-width:560px){.labfigs{grid-template-columns:1fr}}

/* The copy-me line in a lab's "Run it" block. A command the reader is meant to paste, so it is
   set as one: monospace, selectable, scrolling rather than wrapping — a wrapped shell command is
   a command someone will paste broken. */
.labcode{margin:0;padding:14px 16px;background:var(--surface-2,var(--figure-bg));
  border:1px solid var(--border-strong);border-left:3px solid var(--gc,var(--accent));
  border-radius:0 10px 10px 0;overflow-x:auto;text-align:left}
.labcode code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;
  line-height:1.75;color:var(--text-primary);white-space:pre;background:none;border:0;padding:0}

/* Imported Atlas figures. 426 of the 629 carry an opaque light background rect baked into the
   file, so on the dark site they read as bright slabs with no edge. Stripping it would edit
   artwork we cannot regenerate — there is no .mmd behind any of these — so instead the figure sits
   on a deliberate white plate with a frame, the same move .labfig makes for matplotlib PNGs. It
   reads as an intentional plate in both themes and the original file is untouched.
   Single image, never theme-swapped: these have no dark twin and never will. */
.atlasfig{background:var(--figure-bg);border:1px solid var(--border-strong);border-radius:16px;
  padding:14px;margin:10px 0;box-shadow:var(--shadow)}
.atlasfig-plate{background:#fff;border-radius:10px;padding:10px;line-height:0}
.atlasfig img{width:100%;height:auto;display:block;border-radius:6px}
.atlasfig .figcap{text-align:left;margin-top:12px}

/* Phase waterfall (request-pipeline). A share-of-clock chart where each row is a control: clicking
   it filters the comparison grid below to that phase. Rows are <button> rather than <a> because the
   destination is a state of the table on this page, not another address — an <a> would promise a
   navigation that never happens and would break middle-click and "open in new tab". */
.wfall{display:flex;flex-direction:column;gap:1px;background:var(--border-strong);
  border:1px solid var(--border-strong);border-radius:14px;overflow:hidden;margin:16px 0 0}
.wfall .wf-row{display:grid;grid-template-columns:200px 1fr 84px;align-items:center;gap:14px;width:100%;
  background:var(--figure-bg);padding:11px 16px;text-align:left;border:0;font:inherit;color:inherit;
  transition:background .12s}
.wfall button.wf-row{cursor:pointer}
.wfall button.wf-row:hover{background:var(--surface-2,var(--figure-bg));filter:brightness(1.06)}
.wfall button.wf-row:focus-visible{outline:2px solid var(--gc);outline-offset:-2px}
.wf-lb{min-width:0}
.wf-nm{font-size:13.5px;font-weight:650;display:block}
.wf-nm small{font-weight:400;font-size:10.5px;color:var(--text-secondary);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;margin-left:7px}
.wf-lb em{display:block;font-style:normal;font-weight:400;font-size:11.5px;
  color:var(--text-secondary);margin-top:2px;line-height:1.35}
.wf-track{height:16px;background:var(--border);border-radius:5px;position:relative;overflow:hidden}
.wf-fill{position:absolute;top:0;bottom:0;background:var(--gc);border-radius:5px;opacity:.9}
.wf-ms{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;
  color:var(--text-secondary);text-align:right;font-variant-numeric:tabular-nums}
.wfall button.wf-row:hover .wf-ms{color:var(--gc)}
/* The first-token marker is a reading of the bars above it, not another phase — it is a div, not a
   button, so it is not clickable and does not claim to filter anything. */
.wf-mark{background:var(--border)}
.wf-mark .wf-nm,.wf-mark .wf-ms{font-weight:700}
@media (max-width:640px){
  .wfall .wf-row{grid-template-columns:1fr 62px;gap:8px;row-gap:7px}
  .wf-track{grid-column:1 / -1;order:3}
}
/* "Current state" block under a Tier-2 ground-level figure. The claim and the stories it rests
   on live here rather than inside the SVG, because an <img> cannot carry a working link and a
   sourced claim whose sources are not clickable is only half-sourced. */
.ground-state{margin-top:18px;padding:16px 18px;border:1px solid var(--border);
  border-left:3px solid var(--c-orange);border-radius:0 12px 12px 0;background:var(--figure-bg)}
.ground-state .gs-h{font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin:0 0 10px}
.ground-state .gs-row+.gs-row{margin-top:14px;padding-top:14px;border-top:1px solid var(--border)}
.ground-state .gs-claim{margin:0;font-size:14.5px;color:var(--text-primary)}
.ground-state .gs-src{list-style:none;margin:9px 0 0;padding:0}
.ground-state .gs-src li{margin:0 0 6px;font-size:13.5px;line-height:1.5}
.ground-state .gs-src a{color:var(--c-blue);text-decoration:none;border-bottom:1px solid transparent}
.ground-state .gs-src a:hover{border-bottom-color:currentColor}
.ground-state .gs-meta{display:block;font-size:11.5px;color:var(--muted)}

/* group cards (index) */
.legend{display:flex;flex-wrap:wrap;gap:14px;margin:8px 0 20px;font-size:12.5px;color:var(--text-secondary)}
.legend span{display:inline-flex;align-items:center;gap:6px}.legend i{width:11px;height:11px;border-radius:3px}
.grp{margin:24px 0}
.grp-head{display:flex;align-items:center;gap:10px;margin:0 0 12px}
.grp-head i{width:12px;height:12px;border-radius:4px;background:var(--gc)}
.grp-head h3{font-size:15px;margin:0}.grp-head span{font-size:13px;color:var(--muted)}
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px;grid-auto-rows:1fr}
.card{background:var(--surface-1);border:1px solid var(--border);border-left:3px solid var(--gc);border-radius:14px;
  padding:16px 17px;box-shadow:var(--shadow-sm);text-decoration:none;color:inherit;display:block;transition:transform .12s,border-color .12s}
.card:hover{transform:translateY(-3px);border-color:var(--gc)}
.card h4{margin:0 0 4px;font-size:15px;display:flex;justify-content:space-between;gap:8px;align-items:center}
.card h4 .ic{font-size:16px}.card h4 .go{color:var(--gc);font-weight:700}
/* heading link for non-anchor .card containers (cards whose body copy contains its own links) */
.card h4 .card-link{flex:1;display:flex;justify-content:space-between;gap:8px;align-items:center;
  color:inherit;text-decoration:none}
.card p{margin:0;font-size:13px;color:var(--text-secondary)}

/* deep-dive page head */
.page-head{position:relative;overflow:hidden;border-bottom:1px solid var(--border);
  background:
    radial-gradient(700px 320px at 88% -30%,color-mix(in srgb,var(--gc,var(--accent)) 26%,transparent),transparent 62%),
    linear-gradient(180deg,color-mix(in srgb,var(--gc,var(--accent)) 10%,transparent),transparent)}
.page-head .wrap{padding:34px 24px 30px}
/* ⚑ THE PATH READS AS NAVIGATION — OPTION C, OPERATOR'S PICK, 2026-08-15: "I would go with C, this
   need to be applied for all pages." Chosen off 2026-08-15-nav-WIREFRAME.html, which drew four
   readings of "like a Salesforce opportunity cycle" on the same six real pages.

   C IS: HOME IS A FIXED BUTTON, THE REST ARE CHEVRONS, THE CURRENT ONE IS FILLED. The way out is
   then in the same position on a 2-deep topic page and a 4-deep kit lens page — which is the only
   thing "standardised" can mean on a site whose page families genuinely differ in depth. A single
   bar sized for one depth pads the shallow pages or truncates the deep ones; that was option A,
   and it is why A was the prettiest and the wrong answer.

   ⚠︎ THE CHEVRON IS `.mk-stage`'S, NOT A NEW ONE. Same 9px notch, same "only the current segment is
   filled" rule as the Marketing tab's stage bar, which is the component he pointed at with a
   screenshot. Two bars that mean two different things — a PATH and a STATE — deliberately share a
   shape vocabulary and never share a bar.

   ⚠︎ THIS SAID "THE MINIMAL, REVERSIBLE VERSION ... the full chevron treatment is NOT shipped"
   UNTIL HE PICKED. The chips it describes were a holding pattern, and he called them out twice —
   "not more projected". They are gone.

   ⚑ THE MARKUP IS BUILT BY `nav.js`, LIKE THE REST OF THE NAVIGATION. The emitted HTML still
   carries `<a>Home</a> &rsaquo; …` from 28 places across 8 producers, whose separators and trailing
   label are bare text nodes no selector can reach. `nav.js` re-emits those same links in C's shape
   on load, exactly as it already builds the entire top nav into an empty `#site-header`. The rules
   below therefore style BOTH states: `.crumbs a` still gets a readable chip so a page whose script
   has not run yet is never unstyled, and `.cr-*` takes over once it has. */
.crumbs{font-size:12.5px;color:var(--muted);display:flex;flex-wrap:wrap;align-items:center;
  gap:6px;line-height:1.9}
/* the pre-upgrade state — plain, readable, and never seen once nav.js has run */
.crumbs:not([data-crumbs]) a{color:var(--text-secondary);text-decoration:none;font-weight:600;
  border:1px solid var(--border);border-radius:7px;padding:4px 10px;background:var(--surface-1)}
/* ── C, once nav.js has shaped it ─────────────────────────────────────────────────────────── */
.crumbs[data-crumbs="c"]{gap:3px}
/* HOME — the fixed element. A button, not a chevron, because it is the one destination that must
   never move and must never look like "one more step back". */
.cr-home{display:inline-flex;align-items:center;gap:7px;font:700 10px/1 ui-monospace,
  SFMono-Regular,Menlo,monospace;letter-spacing:.08em;text-transform:uppercase;color:#fff;
  background:var(--gc,var(--accent));border:1px solid var(--gc,var(--accent));border-radius:7px;
  padding:9px 14px;text-decoration:none;white-space:nowrap;margin-right:5px;
  transition:filter .12s}
.cr-home:hover,.cr-home:focus-visible{filter:brightness(1.12)}
/* the path segments — `.mk-stage`'s geometry, declaration for declaration */
.cr-seg{position:relative;font:700 9.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);background:var(--surface-2);
  border:1px solid var(--border);padding:8px 16px 8px 20px;text-decoration:none;white-space:nowrap;
  clip-path:polygon(0 0,calc(100% - 9px) 0,100% 50%,calc(100% - 9px) 100%,0 100%,9px 50%);
  transition:color .12s,background .12s}
/* ⚠︎ `.first`/`.last` ARE CLASSES `nav.js` SETS, NOT `:first-of-type`/`:last-of-type`. Those match
   per ELEMENT TYPE and a path mixes <a> with <span>, so the last <a> also matched and lost its
   arrow — visible on the kit lens page as a middle chevron with a straight right edge. Found by
   looking at the render, not by any gate. */
.cr-seg.first{padding-left:14px;
  clip-path:polygon(0 0,calc(100% - 9px) 0,100% 50%,calc(100% - 9px) 100%,0 100%)}
.cr-seg.last{clip-path:polygon(0 0,100% 0,100% 100%,0 100%,9px 50%)}
/* a one-segment path is both ends at once — no notch, no point, just a chip */
.cr-seg.first.last{padding-left:14px;clip-path:none}
a.cr-seg.done{color:var(--c-aqua);background:color-mix(in srgb,var(--c-aqua) 12%,transparent);
  border-color:color-mix(in srgb,var(--c-aqua) 30%,transparent)}
a.cr-seg.done:hover,a.cr-seg.done:focus-visible{color:var(--text-primary);
  background:color-mix(in srgb,var(--c-aqua) 22%,transparent)}
/* only where you ARE is filled — a bar where everything is filled says nothing */
.cr-seg.on{color:#fff;background:var(--gc,var(--accent));border-color:var(--gc,var(--accent))}
/* ⚠︎ A 4-DEEP PATH IN UPPERCASE MONO OVERRUNS A PHONE. It wraps rather than scrolls, and the notch
   is dropped on a wrapped row's first segment so a second line does not start with a bite taken
   out of it. */
@media (max-width:640px){
  .crumbs[data-crumbs="c"]{gap:4px 3px}
  .cr-seg{font-size:9px;padding:7px 12px 7px 16px}
  .cr-home{padding:7px 11px;font-size:9px}
}
.badge{display:inline-flex;align-items:center;gap:7px;font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:var(--gc,var(--accent));background:color-mix(in srgb,var(--gc,var(--accent)) 16%,transparent);
  border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 30%,transparent);padding:5px 11px;border-radius:999px;margin:14px 0 10px}
.page-head h1{font-size:clamp(28px,4.2vw,44px);margin:2px 0 10px;line-height:1.08}
.page-head .tagline{color:var(--text-secondary);font-size:17px;max-width:var(--measure);margin:0}

/* content sections */
.content h2{font-size:20px;margin:6px 0 10px}
.content h2 .k{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--accent);
  display:block;margin-bottom:3px;font-family:var(--font-body)}
.content p{font-size:15.5px;color:var(--text-secondary);margin:0 0 13px;max-width:var(--measure)}
.content p strong{color:var(--text-primary)}
/* Every page is one width. `.article` used to cap content pages at 860px while the homepage,
   tools and cheatsheet ran at --maxw, so the layout jumped as you navigated. It now inherits
   --maxw like everything else.
   Line length is protected by --measure (see the token at the top), not by this rule. */
.article{max-width:var(--maxw);margin:0 auto}

/* ---------------- Homepage map ----------------
   Native HTML, not an <img> of a compiled Mermaid diagram. It is the one screen that has to
   sell the site, so it hovers, links through to every deep dive, reflows on a phone, and uses
   the theme. See MAP_LAYERS in build/generate.py. */
.mapwrap{position:relative;overflow:hidden;background:var(--surface-1);
  border:1px solid var(--border);border-radius:18px;padding:26px 24px 24px}
/* One faint wash behind the whole card so it reads as a lit surface rather than a flat panel.
   Blue at 5% only — any stronger and it competes with the per-layer colour below. */
.mapwrap::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(900px 340px at 12% -20%,color-mix(in srgb,var(--c-blue) 9%,transparent),transparent 70%)}
.mapwrap>*{position:relative}
.mapflow-head,.maplayers-head{font-family:var(--font-body);text-transform:uppercase;letter-spacing:.14em;
  font-size:11px;font-weight:700;color:var(--text-secondary);margin:0 0 14px}
.maplayers-head{margin-top:30px}
.maplayers-hint{text-transform:none;letter-spacing:0;font-weight:500;opacity:.75}

/* ---- the request pipeline ----
   Interior steps are stages INSIDE the system and are filled with their own colour. The two
   endpoints are outside it — what the user hands in and gets back — so they are drawn as ghosts.
   That is the one real distinction in this row, so it is the one the styling encodes. */
/* ⚑ TWO LANES SINCE 2026-08-16. The strip used to be a single row and it described the query path
   only, under a heading claiming it was the whole system. The lanes are deliberately NOT padded to
   equal length — indexing is 5 steps and query is 6, and forcing them to match would draw a
   symmetry the system does not have. The rail on the left is what makes them read as two runtimes
   rather than one long wrapped row. */
.mapflow{display:flex;flex-direction:column;gap:14px}
.mapflow-lane{display:flex;align-items:flex-start;gap:14px;padding-left:13px;
  border-left:2px solid var(--border-strong)}
.mapflow-lk{flex:0 0 132px;padding-top:7px}
.mapflow-ln{display:block;font-family:var(--font-body);font-size:12px;font-weight:750;
  letter-spacing:.02em;color:var(--text-primary)}
.mapflow-lw{display:block;font-size:10.5px;line-height:1.4;color:var(--text-secondary);margin-top:2px}
.mapflow-row{display:flex;align-items:center;flex-wrap:wrap;gap:8px;flex:1 1 auto}
.mapflow-step{position:relative;display:inline-flex;align-items:center;font-size:13px;font-weight:650;
  white-space:nowrap;color:var(--text-primary);padding:9px 15px;border-radius:11px;letter-spacing:-.005em;
  background:linear-gradient(135deg,color-mix(in srgb,var(--gc) 26%,transparent),
                                    color-mix(in srgb,var(--gc) 11%,transparent));
  border:1px solid color-mix(in srgb,var(--gc) 52%,transparent);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--gc) 10%,transparent),
             0 6px 18px -8px color-mix(in srgb,var(--gc) 60%,transparent);
  transition:transform .16s,box-shadow .16s}
.mapflow-step:not(.neutral):hover{transform:translateY(-2px);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--gc) 26%,transparent),
             0 10px 24px -8px color-mix(in srgb,var(--gc) 75%,transparent)}
.mapflow-step.neutral{background:none;border:1px dashed var(--border-strong);color:var(--text-secondary);
  box-shadow:none;font-weight:600}
/* The chevron takes the colour of the step it points AT, so hue leads the eye downstream. */
.mapflow-arrow{font-size:15px;line-height:1;color:var(--gc,var(--text-secondary));opacity:.85}

/* ---- the five-layer stack ----
   A spine links the five badges so the rows read as one structure being built bottom-up, which is
   what the numbering already claims. Each row washes its own group colour in from the left and
   lets it fall away, so a layer is a BAND of its colour rather than a grey row with a colour edge. */
.maplayers{position:relative;display:flex;flex-direction:column;gap:9px}
.maplayers::before{content:"";position:absolute;left:28px;top:28px;bottom:28px;width:2px;border-radius:2px;
  background:linear-gradient(180deg,var(--c-red),var(--c-orange),var(--c-aqua),var(--c-violet),var(--c-blue));
  opacity:.5}
@media(max-width:820px){.maplayers::before{display:none}}
.maplayer{position:relative;display:grid;grid-template-columns:34px 1fr auto;align-items:center;gap:14px;
  padding:14px 16px;border-radius:13px;
  background:linear-gradient(90deg,color-mix(in srgb,var(--gc) 15%,var(--surface-2)) 0%,
                                   var(--surface-2) 46%);
  border:1px solid color-mix(in srgb,var(--gc) 22%,var(--border));
  transition:transform .16s,border-color .16s,background .16s,box-shadow .16s}
.maplayer:hover{transform:translateX(3px);
  border-color:color-mix(in srgb,var(--gc) 58%,transparent);
  background:linear-gradient(90deg,color-mix(in srgb,var(--gc) 26%,var(--surface-2)) 0%,
                                   var(--surface-2) 54%);
  box-shadow:0 8px 24px -14px color-mix(in srgb,var(--gc) 90%,transparent)}
.maplayer-num{position:relative;z-index:1;display:grid;place-items:center;width:28px;height:28px;
  border-radius:9px;font-size:12.5px;font-weight:800;color:#fff;
  background:linear-gradient(145deg,var(--gc),color-mix(in srgb,var(--gc) 62%,#000));
  box-shadow:0 0 0 3px var(--surface-1),0 2px 8px -2px color-mix(in srgb,var(--gc) 80%,transparent)}
.maplayer-title{font-family:var(--font-display);font-size:15px;font-weight:700;color:var(--text-primary);
  letter-spacing:-.01em}
.maplayer-blurb{font-size:12.5px;color:var(--text-secondary);margin-top:3px}
.maplayer-chips{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}
/* Chips and the layer size share the right-hand column. The chips came back when the tile grid
   went: they were only ever removed because the two duplicated each other. */
.maplayer-right{display:flex;align-items:center;gap:14px;justify-content:flex-end;flex-wrap:wrap}
/* The two groups that are not layers, under the ladder. Without them eleven pages would have no
   route in from the homepage for a reader with JS off. */
.mapside{margin-top:14px;display:flex;flex-direction:column;gap:9px}
.mapside-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:11px 14px;
  border:1px dashed var(--border-strong);border-radius:12px;background:var(--surface-1)}
.mapside-h{flex:none;min-width:190px}
.mapside-n{display:block;font-family:var(--font-display);font-size:14px;font-weight:700;color:var(--gc)}
.mapside-b{display:block;font-size:12px;color:var(--muted);margin-top:1px}
.mapside-row .maplayer-chips{justify-content:flex-start;flex:1}
/* The layer's page COUNT, where its list of page links used to be. The list moved to "Explore
   each topic" below — one index, not two — but the size of a layer is worth knowing at a glance,
   because it is the difference between "Operate is a chapter" and "Operate is the book". */
.maplayer-count{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;color:var(--muted);
  white-space:nowrap;font-variant-numeric:tabular-nums}
.maplayer-chip{text-decoration:none;font-size:12px;font-weight:600;white-space:nowrap;
  color:var(--text-secondary);background:color-mix(in srgb,var(--gc) 7%,var(--surface-1));
  border:1px solid color-mix(in srgb,var(--gc) 24%,var(--border-strong));
  padding:5px 11px;border-radius:999px;transition:color .15s,border-color .15s,background .15s}
.maplayer-chip:hover{color:var(--gc);border-color:var(--gc);
  background:color-mix(in srgb,var(--gc) 15%,var(--surface-1))}
@media(max-width:820px){
  .maplayer{grid-template-columns:26px 1fr;row-gap:10px}
  /* The chips row is NOT a grid child — it sits inside .maplayer-right — so a grid-column on it
     did nothing, which is why this looked handled and was not. The third grid item auto-placed
     onto row 2 still right-justified, and a grid item's default min-width:auto refuses to shrink
     below its widest chip, so the row grew past the viewport and the chips were clipped off the
     LEFT edge. Move the actual grid child, left-align it, and let it shrink. */
  .maplayer-right{grid-column:1/-1;justify-content:flex-start;min-width:0;width:100%}
  .maplayer-chips{justify-content:flex-start;min-width:0}
  .maplayer-body{min-width:0}
  /* A chip must be allowed to wrap its own text on a narrow screen. "After you hit Enter" on a
     360px viewport is wider than the column once padding is taken off, and white-space:nowrap
     turns that into overflow rather than two lines. */
  .maplayer-chip{white-space:normal}
  .mapflow-arrow{display:none}
  /* Same nowrap trap as the chips: "Retrieve context · RAG" cannot fit one line at 360px. */
  .mapflow-step{font-size:12px;padding:7px 10px;white-space:normal}
  /* The lane label cannot hold a 132px column beside wrapping chips at 360px — it stacks above
     the row instead, which keeps the two lanes distinguishable without a horizontal scroll. */
  .mapflow-lane{flex-direction:column;gap:7px}
  .mapflow-lk{flex:1 1 auto;padding-top:0}
  /* .mapside-h carries min-width:190px so its label and the chips sit side by side on a wide
     screen. At 360px, 190px plus the row's padding leaves the chips too little to wrap into,
     and the flex row grows instead. Let the header take the full width and the chips drop below. */
  .mapside-h{min-width:0;flex:1 1 100%}
  .mapside-row{padding:11px 12px}
  .mapside-row .maplayer-chips{flex:1 1 100%}
}
/* Last-resort guard, not a fix: the page body must never scroll sideways, whatever a future
   section does. Kept narrow — .maplayers only — so it cannot mask a real overflow elsewhere. */
.maplayers,.mapside{max-width:100%;overflow-x:clip}
.article section{margin:0 0 26px}
.article code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em;background:var(--surface-3);border:1px solid var(--border);border-radius:5px;padding:1px 6px;color:var(--text-primary);white-space:nowrap}
/* ===== Long-form pages: clean documentation style (matches the docs style used elsewhere in the estate) — NOT boxed cards =====
   Scoped to .lrn-main (topic sections + the costing dashboard), so the tile grid, dashboards and
   tools pages that reuse .arch/.callout elsewhere keep their card look. Here a long read reads as
   structured prose: ruled section titles, coloured H3 subsections, light left-accent notes. */
.lrn-main .article{max-width:none;margin:0}
.lrn-main .article>section{margin:0 0 30px}
.lrn-main .content h2{font-size:21px;margin:0 0 15px;padding-bottom:9px;border-bottom:1px solid var(--border)}
.lrn-main .content h2 .k{color:var(--gc,var(--accent))}
.lrn-main .content p{font-size:15.5px;line-height:1.72;max-width:var(--measure)}
/* .arch (was a bordered card with a gear) -> a plain subsection: a coloured H3 + a clean list. */
.lrn-main .arch{border:0;border-radius:0;background:none;box-shadow:none;padding:0;margin:18px 0 14px}
.lrn-main .arch h3,.lrn-main .article>section>h3{font-size:16px;font-weight:700;color:var(--gc,var(--accent));margin:20px 0 9px;display:block}
.lrn-main .arch h3::before{content:none}
/* These two are the BULLET treatment and must not reach a .steps list. .steps is a row component:
   it draws its own full-bleed dividers and zebra, so a 20px padding-left on the <ul> insets every
   row and the stripes stop short of the container edge, while margin-bottom on the <li> opens gaps
   between rows that are supposed to meet. Both rules outrank .steps on specificity (0,2,1 against
   0,1,0), so the row component lost silently on exactly the pages that use .arch.
   :not(.steps) rather than a new .steps override, because the bullet rules are the special case
   here — a list that is already a row component should simply not be styled as bullets. */
.lrn-main .arch ul:not(.steps),.lrn-main .arch ol:not(.steps){padding-left:20px;margin:0}
.lrn-main .arch :not(.steps)>li{font-size:15px;color:var(--text-secondary);margin-bottom:8px;max-width:var(--measure)}
/* .callout (was a full box) -> a light left-accent note, like a docs blockquote. */
.lrn-main .callout{display:block;border:0;border-left:3px solid var(--gc,var(--accent));border-radius:0 8px 8px 0;
  background:color-mix(in srgb,var(--gc,var(--accent)) 6%,var(--surface-1));padding:12px 18px;margin:16px 0}
.lrn-main .callout .k{display:block;margin-bottom:6px}
.lrn-main .callout h3{font-size:15px;color:var(--text-primary);margin:0 0 6px;display:block}
.lrn-main .callout h3::before{content:none}
.lrn-main .callout p{font-size:15px;font-weight:500;color:var(--text-secondary);max-width:var(--measure)}
/* .practice (was a box) -> plain prose rows. */
.lrn-main .practice{display:block;border:0;background:none;box-shadow:none;padding:0;margin:6px 0}
.lrn-main .practice .row{border:0;background:none;box-shadow:none;padding:0;margin:0 0 10px}
.lrn-main .practice .row p{font-size:15.5px;line-height:1.72;max-width:var(--measure)}
.lrn-main .article .pager{margin-top:14px}
/* Align the page header with the content column (H1 sits above the content, not above the rail). */
@media(min-width:821px){.page-head .lrn-wrap{padding-left:calc(212px + 32px + 24px)}}
.kpi small{display:block;font-size:11px;color:var(--muted);font-weight:500;text-transform:none;letter-spacing:0;margin-top:6px;line-height:1.35}
/* evals dashboard */
.evbars{display:flex;flex-direction:column;gap:12px;margin:6px 0}
.evrow{display:grid;grid-template-columns:220px 1fr 46px;align-items:center;gap:14px}
.evlab{font-size:14px;font-weight:650;color:var(--text-primary)}
.evlab small{display:block;font-size:11px;font-weight:500;color:var(--muted);margin-top:2px}
.evtrack{height:14px;border-radius:8px;background:var(--surface-2);border:1px solid var(--border);overflow:hidden}
.evfill{height:100%;border-radius:8px 0 0 8px;transition:width .35s ease}
.evfill.good{background:var(--c-green)}.evfill.warn{background:var(--c-yellow)}.evfill.bad{background:var(--c-red)}
.evpct{font-size:13.5px;font-weight:700;color:var(--text-primary);text-align:right}
.ecase{border:1px solid var(--border);border-radius:12px;margin:0 0 9px;overflow:hidden;background:var(--surface-1)}
.ecase-h{width:100%;display:flex;align-items:center;gap:11px;padding:12px 15px;background:transparent;border:0;cursor:pointer;font:inherit;color:var(--text-primary);text-align:left}
.ecase-h b{font-size:14px}.ecrit{font-size:12.5px;color:var(--muted);flex:1}
.echev{transition:transform .16s;color:var(--muted)}.ecase-h.open .echev{transform:rotate(180deg)}
.etag{font-size:10.5px;font-weight:800;letter-spacing:.03em;padding:3px 8px;border-radius:6px}
.etag.bad{color:var(--c-red);background:color-mix(in srgb,var(--c-red) 15%,transparent)}
.etag.good{color:var(--c-green);background:color-mix(in srgb,var(--c-green) 15%,transparent)}
.ecase-b{padding:4px 15px 14px;border-top:1px solid var(--border)}
.ekv{display:grid;grid-template-columns:130px 1fr;gap:12px;padding:8px 0;font-size:13.5px;border-bottom:1px solid var(--border)}
.ekv:last-child{border-bottom:0}.ekv b{color:var(--muted);font-weight:700;font-size:12px;text-transform:uppercase;letter-spacing:.04em}
.ekv span{color:var(--text-secondary)}.ekv.fix span{color:var(--text-primary)}.ekv.fix b{color:var(--c-green)}
@media(max-width:640px){.evrow{grid-template-columns:1fr 60px;grid-template-areas:"lab pct" "track track"}.evlab{grid-area:lab}.evpct{grid-area:pct}.evtrack{grid-area:track}.ekv{grid-template-columns:1fr}}
.callout{display:flex;gap:14px;align-items:flex-start;margin:2px 0 26px;padding:16px 18px;
  border-radius:14px;background:color-mix(in srgb,var(--gc,var(--accent)) 10%,var(--surface-1));
  border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 30%,transparent)}
.callout .k{flex:none}
.callout p{margin:0;font-size:16px;color:var(--text-primary);font-weight:600;max-width:none}

/* type chips */
.types{display:flex;flex-wrap:wrap;gap:7px;margin:4px 0 10px}
.type{font-size:12.5px;font-weight:600;color:var(--text-primary);
  background:color-mix(in srgb,var(--gc,var(--accent)) 16%,var(--surface-1));
  border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 34%,transparent);padding:4px 11px;border-radius:8px}
a.term-link{display:block;text-decoration:none;cursor:pointer;transition:all .12s;color:var(--text-primary)}
a.term-link:hover{border-color:color-mix(in srgb,var(--gc,var(--accent)) 55%,transparent);transform:translateY(-1px)}
a.term-link .ar{color:var(--gc,var(--accent))}
a.kv-link{text-decoration:none;display:block;transition:color .12s}
a.kv-link:hover b{color:var(--gc,var(--accent))}
a.type-link{text-decoration:none;cursor:pointer;display:inline-flex;align-items:center;gap:5px;transition:all .12s}
a.type-link .ar{opacity:.5;font-weight:700}
a.type-link:hover{border-color:var(--gc,var(--accent));color:var(--text-primary);
  background:color-mix(in srgb,var(--gc,var(--accent)) 26%,var(--surface-1))}
a.type-link:hover .ar{opacity:1}
/* Tools page chip states. A chip is a promise about what happens when you click it, so the
   three outcomes must be told apart at a glance and before the click:
     .type-link  internal deep-dive  — arrow, full colour   (the default above)
     .type-ext   leaves the site     — corner arrow, new tab
     .type-none  no destination      — dashed, muted, no arrow, no hover, default cursor.
   .type-none deliberately drops every affordance: an inert chip that still lights up on hover
   is a worse dead end than a plain word. */
a.type-ext .ar{font-size:11px}
.type-none{border-style:dashed;color:var(--muted);cursor:default;
  background:color-mix(in srgb,var(--gc,var(--accent)) 6%,var(--surface-1))}
.cheat-card .kv.learn{margin-top:8px;padding-top:8px;border-top:1px solid var(--border)}
.cheat-card .kv.learn a{color:var(--gc,var(--accent));text-decoration:none;font-weight:600;
  white-space:nowrap}
.cheat-card .kv.learn a:hover{text-decoration:underline}
.cheat-card .kv.learn .ar{opacity:.55;font-weight:700}
.hint{font-size:12.5px;color:var(--muted);margin:0 0 8px}

/* join band - a tile page's link down to the full course imported beneath it.
   Sized and coloured like .arch/.lrn-row on purpose: it is a signpost inside the article,
   not an advert, so it should read as part of the page furniture. --gc is set inline per
   course so the band picks up that course's group colour. */
.joinband{display:flex;align-items:center;gap:16px;margin:18px 0 4px;padding:16px 20px;
  text-decoration:none;border:1px solid var(--border-strong);border-left:3px solid var(--gc,var(--accent));
  border-radius:14px;background:var(--surface-1);box-shadow:var(--shadow-sm);
  transition:border-color .15s,background .15s,transform .15s}
.joinband:hover{border-color:color-mix(in srgb,var(--gc,var(--accent)) 60%,transparent);
  background:var(--surface-3);transform:translateX(2px)}
.jb-ic{font-size:22px;line-height:1;flex:none}
.jb-tx{display:flex;flex-direction:column;gap:2px;min-width:0}
.jb-tx b{font-size:14.5px;font-weight:700;color:var(--text-primary)}
.jb-tx small{font-size:12.5px;color:var(--text-secondary)}
.jb-go{margin-left:auto;flex:none;font-family:var(--font-display);font-size:12px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;color:var(--gc,var(--accent));white-space:nowrap}
@media(max-width:640px){.joinband{flex-wrap:wrap;gap:12px}.jb-go{margin-left:38px}}

/* architecture callout */
.arch{border:1px solid var(--border);border-left:3px solid var(--accent);background:var(--surface-1);
  border-radius:14px;padding:16px 18px;margin:6px 0 12px;box-shadow:var(--shadow-sm)}
.arch h3{margin:0 0 8px;font-size:15px;display:flex;align-items:center;gap:8px}
.arch h3::before{content:"\2699";color:var(--accent)}
/* Bullet treatment — must not reach a .steps list, which draws its own full-bleed dividers and
   zebra. This BASE rule (0,1,1) is the one that actually beat .steps (0,1,0); fixing only the
   .lrn-main variant above left 48 lists across 10 pages still inset by 18px with their stripes
   stopping short of the container edge. When excluding a component from an inherited treatment,
   check every rule that targets the element, not the one you happened to read first. */
.arch ul:not(.steps),.arch ol:not(.steps){margin:0;padding-left:18px}
.arch :not(.steps)>li{font-size:14.5px;color:var(--text-secondary);margin-bottom:7px}
.arch li strong{color:var(--text-primary)}

/* lenses */
.lens-wrap{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:4px 0 8px}
body[data-lens="pm"] .lens-wrap,body[data-lens="sa"] .lens-wrap{grid-template-columns:1fr}
.lens{border-radius:12px;padding:13px 15px;border:1px solid var(--border);background:var(--surface-1);box-shadow:var(--shadow-sm)}
.lens .who{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;display:flex;align-items:center;gap:6px;margin-bottom:5px}
.lens.pm .who{color:var(--c-violet)}.lens.sa .who{color:var(--c-blue)}
.lens .who i{width:8px;height:8px;border-radius:50%}
.lens.pm .who i{background:var(--c-violet)}.lens.sa .who i{background:var(--c-blue)}
.lens p{margin:0;font-size:14.5px;color:var(--text-secondary)}
body[data-lens="pm"] .lens.sa{display:none}body[data-lens="sa"] .lens.pm{display:none}

/* terms + qa */
.terms{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:6px 0 10px}
.term{background:var(--surface-1);border:1px solid var(--border);border-radius:11px;padding:12px 14px}
.term b{font-size:13.5px}.term span{display:block;font-size:13.5px;color:var(--text-secondary);margin-top:2px}
.qa{border-top:1px solid var(--border);padding:14px 0}.qa:first-of-type{border-top:0}
.qa .q{font-weight:700;font-size:15px;margin:0 0 5px;font-family:var(--font-display)}
.qa .a{font-size:14.5px;color:var(--text-secondary);margin:0}

/* pager */
.pager{display:flex;justify-content:space-between;gap:12px;border-top:1px solid var(--border);margin-top:26px;padding-top:18px}
.pager a{text-decoration:none;font-size:13.5px;font-weight:600;color:var(--text-secondary);border:1px solid var(--border-strong);
  border-radius:12px;padding:11px 15px;background:var(--surface-1);max-width:47%}
.pager a:hover{color:var(--text-primary);border-color:var(--accent)}
.pager a small{display:block;color:var(--muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
.pager a.next{text-align:right}

/* footer tagline */
.tagband{text-align:center;padding:40px 0 20px}
.tagband .tl{font-family:var(--font-display);font-weight:700;letter-spacing:.34em;text-transform:uppercase;
  font-size:13px;color:var(--gold)}
/* ---- site footer: a real index, not a sign-off line ----
   Columns are generated from GROUPS in build/generate.py, so this mirrors the top nav and
   cannot drift from it. Structure: a brand block + one column per group, then a base bar.
   Deliberately full-bleed background with the content on the normal .wrap, so the footer
   reads as a distinct band rather than more page. */
.site-footer{margin-top:56px;border-top:1px solid var(--border);background:var(--surface-1);
  color:var(--text-secondary);font-size:13px}
.foot-top{display:grid;grid-template-columns:minmax(210px,0.9fr) 3.4fr;gap:40px;padding:40px 24px 34px;align-items:start}
.foot-brand{display:flex;flex-direction:column;gap:12px;align-items:flex-start}
.foot-mark{display:inline-flex;align-items:center;gap:9px;text-decoration:none;
  font-family:var(--font-display);font-weight:700;font-size:17px;color:var(--text-primary);letter-spacing:-.01em}
.foot-mark img{display:block}
.foot-pos{margin:0;font-size:13px;line-height:1.6;color:var(--muted);max-width:38ch}
.foot-signal{display:inline-flex;align-items:center;gap:7px;text-decoration:none;font-size:12.5px;font-weight:600;
  color:var(--text-secondary);border:1px solid var(--border-strong);border-radius:999px;padding:6px 13px;
  transition:border-color .15s,color .15s}
.foot-signal:hover{color:var(--text-primary);border-color:var(--c-green)}
.foot-dot{width:7px;height:7px;border-radius:50%;background:var(--c-green);flex:none}
/* auto-fit so seven groups sit in one row on a wide display and reflow gracefully below it */
/* ⚠︎ THE COMMENT ABOVE SAID auto-fit AND THE RULE SAID repeat(5). The footer emits SEVEN
   .foot-col children (derived from the industry nav), so columns 6 and 7 wrapped onto a
   second row — the operator's "overlapping one underneath another one", 2026-08-30. A typed
   column count cannot track a derived child count; auto-fit reads the children instead, so
   one nav group is always one column and adding an eighth group cannot re-break it. */
.foot-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:26px 18px}
.foot-col h4{margin:0 0 11px;font-family:var(--font-display);font-size:10.5px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:var(--gc,var(--accent))}
.foot-col ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px}
.foot-col a{text-decoration:none;color:var(--text-secondary);font-size:12.5px;line-height:1.4;
  transition:color .12s}
.foot-col a:hover{color:var(--gc,var(--text-primary))}
.foot-base{display:flex;flex-wrap:wrap;gap:8px 18px;justify-content:space-between;align-items:baseline;
  padding:15px 24px 40px;border-top:1px solid var(--border);font-size:12px;color:var(--muted)}
.foot-note{font-style:italic}
/* THE LEGAL ROW. It had NO RULE AT ALL until 2026-09-17, which cost two things at once: the two
   anchors carry no separator in the markup, so with no gap they rendered as one word —
   "PrivacyTerms" — and with only `a{color:inherit}` above them they took .foot-base's
   var(--muted), measuring 3.88:1 on --surface-1 in dark and 3.59:1 in light, both under the
   4.5:1 minimum. The operator caught it on the live signed-in homepage: "terms is not visible
   yet". These are the links an anonymous audit reviewer has to FIND, so legibility here is the
   requirement and not polish. Shape mirrors .foot-social; var(--text-secondary) measures
   7.11:1 dark and 7.94:1 light. The signed-out front door carries its own copy of this row in
   functions/_middleware.js with its own inline CSS — a different document, so a separate rule,
   but keep the two legible in step. */
.foot-legal{display:inline-flex;flex-wrap:wrap;gap:6px 16px;align-items:baseline}
.foot-legal a{color:var(--text-secondary);text-decoration:underline;text-underline-offset:2px;
  transition:color .12s}
.foot-legal a:hover{color:var(--text-primary)}
.foot-legal a:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}
.site-footer code{background:var(--surface-2);border:1px solid var(--border);border-radius:5px;padding:1px 5px;font-size:12px}
@media(max-width:1100px){.foot-cols{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:860px){
  .foot-top{grid-template-columns:1fr;gap:30px;padding:32px 24px 26px}
  .foot-pos{max-width:none}
}
@media(max-width:520px){
  .foot-cols{grid-template-columns:repeat(2,minmax(0,1fr))}
  .foot-base{flex-direction:column;gap:6px}
}

/* Foundry wordmark */
.brand .logo{display:grid;place-items:center}
/* SHARPNESS. The wordmark was gradient-filled text — background-clip:text with
   color:transparent — and that was the softness, not the size. Clipped text is rasterised
   through a mask, so it loses the crisp greyscale antialiasing solid text gets; at 18px on a
   dark ground it reads faintly blurred no matter how large you set it. The gradient is worth
   keeping (it ties the wordmark to the mark beside it), so it stays and is made to render as
   sharply as a clip can: bigger (20px), antialiased explicitly, and geometricPrecision so the
   glyph outlines are not hinted onto a pixel grid that thickens them. If it still reads soft
   to you, the honest next step is a solid --text-primary fill — that is as sharp as type gets,
   and the cost is the gradient. */
.brand .wordmark{font-family:var(--font-display);font-weight:800;font-size:24px;letter-spacing:-0.03em;
  background:linear-gradient(120deg,var(--accent),var(--accent-2));-webkit-background-clip:text;background-clip:text;color:transparent;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:geometricPrecision}

/* references / sources line */
.refs{margin:10px 0 4px;font-size:13.5px;color:var(--muted);display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.refs .rlabel{font-weight:700;color:var(--text-secondary)}
.refs a{color:var(--accent);text-decoration:none;font-weight:600;border-bottom:1px dashed color-mix(in srgb,var(--accent) 50%,transparent)}
.refs a:hover{color:var(--text-primary)}

/* unified "in practice" block (was PM/Architect split) */
.practice{border:1px solid var(--border);border-radius:14px;background:var(--surface-1);padding:6px 4px;box-shadow:var(--shadow-sm)}
.practice .row{display:flex;gap:12px;padding:12px 16px;border-top:1px solid var(--border)}
.practice .row:first-child{border-top:0}
.practice .row .tag{flex:none;font-size:10.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  padding:4px 9px;border-radius:999px;height:fit-content;white-space:nowrap}
.practice .row.prod .tag{color:var(--c-violet);background:color-mix(in srgb,var(--c-violet) 15%,transparent)}
.practice .row.arch .tag{color:var(--c-blue);background:color-mix(in srgb,var(--c-blue) 15%,transparent)}
.practice .row p{margin:0;font-size:14.5px;color:var(--text-secondary)}

/* RAG (and other) method cards */
.methods{display:grid;grid-template-columns:1fr;gap:16px;margin:8px 0}
.method{border:1px solid var(--border-strong);border-radius:16px;background:var(--surface-1);overflow:hidden;box-shadow:var(--shadow-sm)}
.method-h{display:flex;align-items:baseline;gap:10px;padding:16px 18px 4px}
.method-h h4{margin:0;font-size:17px}
.method-h .lvl{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.method>p{padding:0 18px;margin:6px 0 10px;font-size:14.5px;color:var(--text-secondary)}
.method .mfig{background:var(--figure-bg);border-top:1px solid var(--border);border-bottom:1px solid var(--border);
  padding:16px;text-align:center;overflow-x:auto}
.method .mfig img{max-width:100%;height:auto}
.proscons{display:grid;grid-template-columns:1fr 1fr;gap:0}
.proscons>div{padding:14px 18px}
.proscons .pros{border-right:1px solid var(--border)}
.proscons h5{margin:0 0 7px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.proscons .pros h5{color:var(--c-green)} .proscons .cons h5{color:var(--c-red)}
.proscons ul:not(.steps),.proscons ol:not(.steps){margin:0;padding-left:16px}
.proscons :not(.steps)>li{font-size:13.5px;color:var(--text-secondary);margin-bottom:5px}
.verdict{padding:12px 18px;border-top:1px solid var(--border);font-size:13.5px;color:var(--text-secondary);
  background:color-mix(in srgb,var(--accent) 7%,transparent)}
.verdict b{color:var(--text-primary)}

/* frontier models table */
.ftable{width:100%;border-collapse:collapse;font-size:13.5px;min-width:720px}
.ftable th{text-align:left;font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted);padding:10px 12px;border-bottom:1px solid var(--border-strong)}
/* text-align is stated rather than inherited: .ftable is also used outside a .figure wrapper, and
   an inherited centre from any future container would silently un-align the body under a th that
   pins itself left. Matches .ftable th above. */
.ftable td{padding:11px 12px;border-bottom:1px solid var(--border);color:var(--text-secondary);vertical-align:top;text-align:left}
.ftable tr:hover td{background:color-mix(in srgb,var(--accent) 6%,transparent)}
.ftable .prov{color:var(--muted);font-weight:600}
/* The front-door fit block, "Should you use this?" — 2026-08-17.
   .qmoat is the row that names when NOT to use the kit. It is tinted because it is the one answer
   a reader is least expecting to find and most needs: on 15 of 15 kits every scored scenario
   carries its own `avoid`, and no vendor page makes that claim. The tint is derived from the
   existing --c-green through color-mix rather than a new token, so there is nothing to leave
   behind if the block is ever withdrawn.
   .qhand is the hand-off row: this block ends where companion 14 begins, and the shading says the
   section is over rather than that the row is special. */
.ftable tr.qmoat td{background:color-mix(in srgb,var(--c-green) 7%,transparent)}
.ftable tr.qmoat:hover td{background:color-mix(in srgb,var(--c-green) 12%,transparent)}
.ftable tr.qhand td{background:color-mix(in srgb,var(--text-primary) 3%,transparent)}
.ftable .mdl{color:var(--text-primary);font-weight:700;font-family:var(--font-display)}
.ftable .num{font-variant-numeric:tabular-nums;color:var(--text-primary);white-space:nowrap}
.ftable .bf{color:var(--text-secondary)}

/* ROI dashboard */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin:8px 0 20px}
.kpi{background:var(--surface-1);border:1px solid var(--border-strong);border-radius:14px;padding:16px 18px;box-shadow:var(--shadow-sm)}
.kpi .kv-n{font-family:var(--font-display);font-weight:700;font-size:24px;color:var(--text-primary);letter-spacing:-0.01em}
.kpi .kv-l{font-size:12px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.05em;margin-top:3px}
.roi-table td small{display:block;color:var(--muted);font-size:11.5px}
.roi-table .rrow{cursor:pointer}
.roi-table .rrow:hover td{background:color-mix(in srgb,var(--accent) 8%,transparent)}
.roi-table .exp{color:var(--muted);text-align:center;width:28px}
.roi-pos{color:var(--c-green);font-weight:700}
.roi-neg{color:var(--c-red);font-weight:700}
.roi-table .rdetail{display:none}
.roi-table .rdetail.open{display:table-row}
.roi-table .rdetail td{background:color-mix(in srgb,var(--accent) 5%,transparent)}
.dd-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px;padding:6px 2px}
.dd-grid h5{margin:0 0 6px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--accent)}
.dd-grid ul{margin:0;padding-left:16px}.dd-grid li{font-size:13px;color:var(--text-secondary);margin-bottom:4px}

/* cheat sheet */
.cheat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px;grid-auto-rows:1fr;margin-top:14px}
.cheat-card{border:1px solid var(--border);border-left:3px solid var(--gc,var(--accent));border-radius:12px;
  background:var(--surface-1);padding:14px 16px;box-shadow:var(--shadow-sm)}
.cheat-card h3{margin:0 0 6px;font-size:14.5px;display:flex;align-items:center;gap:8px}
/* Provider · context line under a Frontier model card's title. */
.cheat-card .fc-meta{font-family:var(--font-display);font-size:10.5px;letter-spacing:.03em;
  color:var(--gc,var(--accent));font-weight:600;margin:-3px 0 8px;text-transform:uppercase}
.cheat-card .one{font-size:12.5px;color:var(--muted);margin:0 0 8px}
.cheat-card dl{margin:0}
.cheat-card dt{font-size:12px;font-weight:700;color:var(--text-primary);margin-top:8px}
.cheat-card dd{margin:2px 0 0;font-size:12.5px;color:var(--text-secondary)}
.cheat-card .kv{font-size:12.5px;color:var(--text-secondary);margin:3px 0}
.cheat-card .kv b{color:var(--text-primary)}
.copy-note{font-size:12.5px;color:var(--muted);margin:2px 0 16px}

@media(max-width:720px){.terms,.lens-wrap,.cards,.proscons{grid-template-columns:1fr}.pager a{max-width:48%}
  .proscons .pros{border-right:0;border-bottom:1px solid var(--border)}}

/* ============================================================
   Imported Atlas courses  (.lrn-*)
   Everything here is namespaced .lrn- on purpose: the imported markdown arrives as raw
   <h2>/<table>/<pre> with no classes of its own, and the rest of this sheet styles
   hand-authored markup by class. Scoping under .lrn-prose lets generated HTML inherit a
   voice without either side reaching into the other's cascade.
   ============================================================ */

/* ---- course index: lessons left, labs in a persistent rail right ---- */
.lrn-grid{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:28px;align-items:start}
/* A course with no labs renders no rail at all — the grid collapses rather than reserving a
   column to announce its own emptiness. Set by build/atlas_import.py. */
.lrn-grid.lrn-solo{grid-template-columns:minmax(0,1fr)}
.lrn-h{font-family:var(--font-display);font-size:12px;font-weight:800;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);margin:0 0 12px;display:flex;align-items:center;gap:8px}
.lrn-count{font-size:11px;font-weight:700;letter-spacing:0;color:var(--gc,var(--accent));
  border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 40%,transparent);
  background:color-mix(in srgb,var(--gc,var(--accent)) 12%,transparent);
  border-radius:999px;padding:1px 7px}

.lrn-list{list-style:none;margin:0;padding:0;counter-reset:none}
.lrn-row{display:grid;grid-template-columns:34px minmax(0,1fr) auto;gap:12px;align-items:center;
  text-decoration:none;padding:11px 14px;border:1px solid var(--border);border-radius:12px;
  background:var(--surface-1);margin-bottom:8px;transition:border-color .15s,transform .15s,background .15s}
.lrn-row:hover{border-color:color-mix(in srgb,var(--gc,var(--accent)) 55%,transparent);
  background:var(--surface-3);transform:translateX(2px)}
.lrn-n{font-family:var(--font-display);font-size:12.5px;font-weight:800;color:var(--gc,var(--accent));
  text-align:center;font-variant-numeric:tabular-nums}
.lrn-t{font-size:14px;font-weight:600;color:var(--text-primary);line-height:1.4}
.lrn-meta{font-size:11.5px;color:var(--muted);white-space:nowrap}
.lrn-list-plain .lrn-row{background:transparent}
.lrn-refs{margin-top:36px;padding-top:24px;border-top:1px solid var(--border);scroll-margin-top:calc(var(--header-h) + 16px)}
.lrn-empty{font-size:13px;color:var(--muted)}

/* Rail stays with the reader down a 50-lesson list — that is the point of it. */
.lrn-rail-in{position:sticky;top:calc(var(--header-h) + 16px)}
.lrn-rail-note{font-size:11.5px;color:var(--muted);margin:-4px 0 13px;line-height:1.45}
.lrn-lab{border:1px solid var(--border);border-radius:14px;background:var(--surface-1);
  padding:13px 14px;margin-bottom:10px;box-shadow:var(--shadow-sm)}
.lrn-lab-t{display:block;font-size:13.5px;font-weight:600;color:var(--text-primary);
  text-decoration:none;line-height:1.4}
.lrn-lab-t:hover{color:var(--gc,var(--accent))}
.lrn-lab-m{font-size:11px;color:var(--muted);margin-top:4px}
.lrn-badge{margin-top:9px}
.lrn-badge img{height:20px;width:auto;display:block}
.lrn-norail b{color:var(--text-secondary)}

/* ---- Path tiles: the baseline lesson tile for a course index ----
   The lesson list rendered as cards (build/atlas_import.py course_index). Lives in the main
   column beside the 340px labs rail, so it flows ~3-up and reflows down as the column narrows. A
   lab bound to a lesson (map_labs_to_lessons) rides along as a "-> lab" pointer on its tile; the
   labs rail still lists every lab, so nothing is hidden — the pointer is alignment, not a move. */
.lrn-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(238px,1fr));gap:12px;grid-auto-rows:1fr}
.lrn-tile{position:relative;isolation:isolate;display:flex;flex-direction:column;
  border:1px solid var(--border);border-radius:16px;background:var(--surface-1);
  padding:17px 18px 15px;box-shadow:var(--shadow-sm);overflow:hidden;
  transition:border-color .15s,transform .15s,box-shadow .15s}
.lrn-tile::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  background:var(--gc,var(--accent));opacity:.7}
.lrn-tile:hover{transform:translateY(-3px);box-shadow:var(--shadow);
  border-color:color-mix(in srgb,var(--gc,var(--accent)) 55%,transparent)}
.lrn-gh{position:absolute;right:12px;top:-6px;font-family:var(--font-display);font-weight:800;
  font-size:56px;line-height:1;color:var(--gc,var(--accent));opacity:.10;z-index:-1;
  font-variant-numeric:tabular-nums;pointer-events:none}
/* the whole card clicks through to the lesson (stretched link); the lab pointer sits above it */
.lrn-tile-main{text-decoration:none;color:inherit;display:block}
.lrn-tile-main::after{content:"";position:absolute;inset:0;z-index:0}
.lrn-step{font-family:var(--font-display);font-size:11px;font-weight:800;letter-spacing:.13em;
  text-transform:uppercase;color:var(--gc,var(--accent))}
.lrn-tt{display:block;font-family:var(--font-display);font-size:15px;font-weight:700;
  letter-spacing:-.01em;line-height:1.32;margin:6px 0 12px;color:var(--text-primary);text-wrap:balance}
.lrn-chips{display:flex;gap:7px;flex-wrap:wrap}
.lrn-chip{display:inline-flex;align-items:center;gap:5px;font-size:10.5px;font-weight:600;
  color:var(--text-secondary);background:var(--surface-3);border:1px solid var(--border);
  border-radius:7px;padding:3px 8px;font-variant-numeric:tabular-nums}
.lrn-chip svg{width:12px;height:12px;flex:none}
.lrn-chip.dia{color:var(--c-violet)} .lrn-chip.code{color:var(--c-aqua)}
.lrn-labs{position:relative;z-index:1;display:flex;flex-direction:column;gap:6px;margin-top:12px}
.lrn-labs-more{display:flex;flex-direction:column;gap:6px}
.lrn-labs-more>summary{list-style:none;cursor:pointer;font-size:11px;font-weight:700;color:var(--gc,var(--accent));
  padding:6px 9px;border:1px dashed color-mix(in srgb,var(--gc,var(--accent)) 42%,transparent);border-radius:8px;user-select:none}
.lrn-labs-more>summary::-webkit-details-marker{display:none}
.lrn-labs-more>summary::marker{content:""}
.lrn-labs-more>summary:hover{background:color-mix(in srgb,var(--gc,var(--accent)) 8%,transparent)}
.lrn-labptr{position:relative;z-index:1;display:flex;align-items:center;gap:7px;text-decoration:none;
  font-size:11.5px;font-weight:600;color:var(--text-secondary);line-height:1.3;
  background:color-mix(in srgb,var(--gc,var(--accent)) 8%,transparent);
  border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 22%,transparent);
  border-radius:8px;padding:6px 9px;transition:border-color .15s,color .15s}
.lrn-labptr:hover{color:var(--text-primary);
  border-color:color-mix(in srgb,var(--gc,var(--accent)) 55%,transparent)}
.lrn-labptr svg{width:13px;height:13px;flex:none;color:var(--gc,var(--accent))}
.lrn-labptr-t{flex:1;min-width:0}
.lrn-labptr-go{color:var(--gc,var(--accent));font-weight:800;flex:none}

/* ---- course index: module grouping + left On-this-page rail + bottom case studies ---- */
.lrn-clayout{display:grid;grid-template-columns:214px minmax(0,1fr);gap:34px;align-items:start}
.lrn-cmain{min-width:0}
.lrn-toc-l small{display:block;font-weight:500;font-size:11px;color:var(--muted);margin-top:1px}
.lrn-toc-cs,.lrn-toc-cs.on,.lrn-toc-cs:hover{color:var(--c-aqua)}
.lrn-toc-cs.on{border-left-color:var(--c-aqua)}
.lrn-module{margin-bottom:30px;scroll-margin-top:calc(var(--header-h) + 16px)}
.lrn-mod-h{display:flex;align-items:baseline;gap:11px;margin:0 0 14px}
.lrn-mod-h h2{font-family:var(--font-display);font-size:18px;font-weight:700;letter-spacing:-.01em;border:0;margin:0;padding:0}
.lrn-mod-c{font-size:12px;color:var(--muted);font-weight:600;white-space:nowrap}
.lrn-mod-line{flex:1;height:1px;background:var(--border);align-self:center}
.lrn-cases{margin-top:36px;padding-top:26px;border-top:1px solid var(--border);scroll-margin-top:calc(var(--header-h) + 16px)}
.lrn-cases-h{display:flex;align-items:center;gap:10px;margin-bottom:4px}
.lrn-cases-h h2{font-family:var(--font-display);font-size:20px;font-weight:700;letter-spacing:-.01em;border:0;margin:0;padding:0}
.lrn-cases-c{font-family:var(--font-display);font-size:12px;font-weight:700;color:#fff;background:var(--c-aqua);border-radius:999px;padding:1px 9px}
.lrn-cases-sub{color:var(--muted);font-size:13px;margin:0 0 16px}
.lrn-cases-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px;grid-auto-rows:1fr}
.lrn-case{border:1px solid var(--border);border-left:4px solid var(--c-aqua);border-radius:14px;background:var(--surface-1);padding:15px 17px;box-shadow:var(--shadow-sm)}
.lrn-case-t{display:block;font-family:var(--font-display);font-weight:700;font-size:14.5px;line-height:1.3;color:var(--text-primary);text-decoration:none;text-wrap:balance}
.lrn-case-t:hover{color:var(--gc,var(--accent))}
.lrn-case-m{font-size:11.5px;color:var(--muted);margin:5px 0 13px;font-variant-numeric:tabular-nums}
.colab-btn{display:inline-flex;align-items:center;gap:8px;text-decoration:none;font-family:var(--font-display);font-weight:700;font-size:12.5px;
  color:var(--text-primary);background:var(--surface-3);border:1px solid var(--border-strong);border-radius:9px;padding:7px 12px;transition:border-color .15s,transform .15s}
.colab-btn:hover{transform:translateY(-1px);border-color:color-mix(in srgb,#f9ab00 60%,transparent)}
.colab-btn.colab-static{cursor:default}
.cb-ic{width:20px;height:13px;flex:none}
@media(max-width:820px){.lrn-clayout{grid-template-columns:1fr}.lrn-clayout .lrn-toc{display:none}}

/* ---- imported prose ---- */
/* Lesson layout — a pinned "On this page" rail on the left, content filling the rest of the page.
   Modelled on the docs-rail pattern used elsewhere in the estate: a bordered card that STAYS PUT as you scroll (an earlier version
   put position:sticky on an inner div inside a content-height column, so it scrolled away — "crawls
   up"). The content is left-anchored and fills the width; it is not a narrow centred column with
   empty gutters on both sides. */
.lrn-wrap{max-width:1600px}
.lrn-layout{display:grid;grid-template-columns:212px minmax(0,1fr);gap:32px;align-items:start}
/* Solo (no rail) used to pin the column at 920px inside a 1600px wrap — a ~680px empty
   gutter. It now fills the wrap like the two-column case; prose length is --measure's job. */
.lrn-layout.lrn-solo{grid-template-columns:minmax(0,1fr)}
.lrn-main{min-width:0}

/* The rail card. position:sticky on the ASIDE itself — its grid parent spans the full content
   height, so the card pins under the header and holds all the way down instead of scrolling off. */
.lrn-toc{position:sticky;top:calc(var(--header-h) + 18px);align-self:start;
  max-height:calc(100vh - var(--header-h) - 36px);overflow-y:auto;scrollbar-width:thin;
  background:color-mix(in srgb,var(--surface-1) 78%,transparent);
  border:1px solid var(--border);border-radius:14px;padding:16px 12px 16px 15px}
/* Back to the course lesson list — the persistent way out of a deep page. Always present. */
.lrn-toc-back{display:flex;align-items:center;gap:8px;text-decoration:none;
  font-family:var(--font-display);font-size:12.5px;font-weight:600;color:var(--text-primary);
  padding:8px 10px;border-radius:9px;border:1px solid var(--border-strong);
  background:color-mix(in srgb,var(--gc,var(--accent)) 10%,transparent)}
.lrn-toc-back:hover{border-color:var(--gc,var(--accent));
  background:color-mix(in srgb,var(--gc,var(--accent)) 16%,transparent)}
.lrn-toc-back-ic{font-size:15px;line-height:1;color:var(--gc,var(--accent))}
/* When an "On this page" list follows, separate it from the back link. */
.lrn-toc-back + .lrn-toc-h{margin-top:15px;padding-top:14px;border-top:1px solid var(--border)}
.lrn-toc-h{font-family:var(--font-display);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);font-weight:700;margin:0 0 11px;padding-left:11px}
.lrn-toc-nav{display:flex;flex-direction:column;gap:1px}
.lrn-toc-l{display:block;text-decoration:none;color:var(--text-secondary);font-size:12.5px;
  line-height:1.4;padding:6px 9px 6px 11px;border-left:2px solid transparent;border-radius:0 6px 6px 0;
  word-break:break-word;transition:color .12s,background .12s,border-color .12s}
.lrn-toc-l:hover{color:var(--text-primary);background:color-mix(in srgb,var(--gc,var(--accent)) 7%,transparent)}
.lrn-toc-h3{padding-left:24px;font-size:12px;color:var(--muted)}
/* GROUP HEADERS INSIDE A RAIL. .lrn-toc-h sits at padding-left:11px while .lrn-toc-l starts its
   text at 11px + a 2px transparent border — so a header printed above a list of links was two
   pixels to the left of every one of them, which is exactly enough to look like a mistake and not
   enough to look deliberate. Matched to the link text, and given air above so a group reads as a
   group rather than as another row. Not first-of-type: the first group follows "On this page". */
.lrn-toc-g{padding-left:13px;margin:16px 0 6px;font-size:9.5px;opacity:.72}
/* A rail group that is a set of OTHER pages, collapsed until asked for. The eight eval pages are
   real destinations, so they stay reachable; eight rows on a nine-row rail is what needed fixing,
   not the links. The summary reuses the group-header look and gains a caret and a hit target. */
.lrn-toc-more{margin-top:14px;border-top:1px solid var(--border);padding-top:12px}
.lrn-toc-more > summary{list-style:none;cursor:pointer;margin:0 0 4px;padding:2px 0 2px 13px;
  display:flex;align-items:center;gap:6px}
.lrn-toc-more > summary::-webkit-details-marker{display:none}
.lrn-toc-more > summary::after{content:"";width:5px;height:5px;border-right:1.5px solid currentColor;
  border-bottom:1.5px solid currentColor;transform:rotate(-45deg);opacity:.6;transition:transform .15s}
.lrn-toc-more[open] > summary::after{transform:rotate(45deg)}
.lrn-toc-more > summary:hover{color:var(--text-primary)}
.lrn-toc-nav > .lrn-toc-g:first-child{margin-top:2px}
.lrn-toc-l.is-active{color:var(--gc,var(--accent));font-weight:600;
  border-left-color:var(--gc,var(--accent));background:color-mix(in srgb,var(--gc,var(--accent)) 11%,transparent)}
/* Content fills the column — no narrow reading cap, so the page is used, not guttered.
   Prose follows --measure; tables, diagrams and cards run the full width regardless. */
.lrn-main .lrn-prose{max-width:none}
.lrn-main .lrn-prose p,.lrn-main .lrn-prose li{max-width:var(--measure)}
/* Jumping to an anchor clears the sticky header instead of hiding the heading under it. */
.lrn-prose :target,.lrn-main [id]{scroll-margin-top:calc(var(--header-h) + 16px)}
/* Below this width the "On this page" list would crowd the text, so it hides and the content
   goes full single column — but the back-to-course link STAYS, flowing inline at the top, so the
   way back is never lost on a laptop or phone. */
@media(max-width:820px){
  .lrn-layout,.lrn-layout.lrn-solo{grid-template-columns:1fr;gap:0}
  .lrn-toc{position:static;max-height:none;overflow:visible;background:none;border:0;
    padding:0;margin:0 0 20px;align-self:auto}
  .lrn-toc-nav,.lrn-toc-back + .lrn-toc-h{display:none}
  .lrn-toc-back{display:inline-flex}
  .lrn-main .lrn-prose p,.lrn-main .lrn-prose li{max-width:100%}
}

.lrn-prose{max-width:920px;font-size:15px;line-height:1.72;color:var(--text-secondary)}
.lrn-prose>h1:first-child{display:none} /* the page header already shows it */
.lrn-prose h1,.lrn-prose h2,.lrn-prose h3,.lrn-prose h4{color:var(--text-primary);line-height:1.3}
.lrn-prose h1{font-size:25px;margin:34px 0 12px}
.lrn-prose h2{font-size:20px;margin:32px 0 10px;padding-top:16px;border-top:1px solid var(--border)}
.lrn-prose h3{font-size:16px;margin:22px 0 8px}
.lrn-prose h4{font-size:14px;margin:18px 0 6px;color:var(--text-secondary)}
.lrn-prose p{margin:0 0 13px}
.lrn-prose a{color:var(--gc,var(--accent));text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--gc,var(--accent)) 35%,transparent)}
.lrn-prose a:hover{border-bottom-color:var(--gc,var(--accent))}
.lrn-prose ul,.lrn-prose ol{margin:0 0 13px;padding-left:22px}
.lrn-prose li{margin:4px 0}
.lrn-prose strong,.lrn-prose b{color:var(--text-primary)}
.lrn-prose hr{border:0;border-top:1px solid var(--border);margin:26px 0}
.lrn-prose blockquote{margin:14px 0;padding:2px 0 2px 15px;
  border-left:3px solid color-mix(in srgb,var(--gc,var(--accent)) 55%,transparent);color:var(--muted)}
.lrn-prose blockquote p:last-child{margin-bottom:0}
.lrn-prose code{background:var(--surface-3);border:1px solid var(--border);border-radius:5px;
  padding:1px 5px;font-size:12.5px;color:var(--text-primary)}
.lrn-prose pre{background:var(--surface-2);border:1px solid var(--border-strong);border-radius:12px;
  padding:14px 16px;overflow-x:auto;margin:0 0 16px}
.lrn-prose pre code{background:none;border:0;padding:0;font-size:12.5px;line-height:1.6;color:var(--text-primary)}
/* Atlas diagrams are authored on a light canvas — give them one instead of letting a dark
   page show through their transparent background.
   Left-aligned, NOT centred. 105 of the 629 atlas SVGs declare an intrinsic width (e.g.
   width="800"). While the prose column was capped at 78ch (763px) those were narrower than the
   column, so max-width:100% forced them to fill and they happened to line up. Once --measure
   opened the column to ~1308px they render at natural size, and a margin:auto centred them —
   a 239px indent that broke alignment with the heading and prose beside them. Left-aligning
   restores that edge. Forcing width:100% instead would upscale-blur them, which is the exact
   thing build/fix-svg.py exists to prevent. */
.lrn-prose img{max-width:100%;height:auto;display:block;margin:16px 0;
  background:var(--figure-bg);border:1px solid var(--border-strong);border-radius:14px;padding:14px}
.lrn-prose a img,.lrn-prose img[src*="colab-badge"],.lrn-prose img[src*="img.shields.io"]{
  background:none;border:0;border-radius:0;padding:0;display:inline-block;margin:0;vertical-align:middle}
/* ------------------------------------------------------------------ TABLES ----
   ONE table style for the whole site. Previously `.lrn-prose table` carried
   `display:block` — which is the bug behind every unreadable table on the site.
   display:block DISABLES the table layout algorithm, so columns stop aligning to
   a shared grid and cells collapse to their own content width; that is why a
   three-column data manifest rendered as three ragged runs of floating text with
   no visible structure.

   Overflow belongs on a WRAPPER (.tbl-wrap), never on the table itself. The
   wrapper scrolls; the table keeps `display:table` and can therefore honour
   min-width, column alignment and border-collapse.

   Applies to markdown-converted tables under .lrn-prose (pages/learn) and to
   authored tables carrying .dtable (pages/sub, pages/term). Both routes get the
   same result so a reader cannot tell which pipeline produced the page. */
.tbl-wrap{overflow-x:auto;margin:0 0 20px;border:1px solid var(--border);border-radius:11px;
  background:var(--surface-1)}
.tbl-wrap>table{margin:0}
.tbl-cap{display:block;font-size:12px;line-height:1.5;color:var(--muted);margin:-10px 0 20px;
  padding:0 2px}
.tbl-cap b{color:var(--text-secondary);font-weight:650}

.lrn-prose table,table.dtable{width:100%;border-collapse:collapse;margin:0 0 20px;
  font-size:13.5px;line-height:1.5;min-width:520px}
.lrn-prose th,table.dtable th{text-align:left;font-size:10.5px;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted);padding:11px 14px;white-space:nowrap;
  background:var(--surface-2);border-bottom:1px solid var(--border-strong);position:sticky;top:0}
.lrn-prose td,table.dtable td{padding:10px 14px;border-bottom:1px solid var(--border);
  vertical-align:top;color:var(--text-secondary)}
/* First column is the row's subject on nearly every table here — a file name, a
   test name, a model. Giving it the primary colour makes a wide table scannable
   down the left edge instead of forcing a read across every row. */
.lrn-prose tbody td:first-child,table.dtable tbody td:first-child{
  color:var(--text-primary);font-weight:600;white-space:nowrap}
/* Digits line up only with tabular figures; proportional numerals make a column
   of p-values impossible to compare at a glance. */
.lrn-prose td,table.dtable td{font-variant-numeric:tabular-nums}
.lrn-prose tbody tr:nth-child(even),table.dtable tbody tr:nth-child(even){
  background:color-mix(in srgb,var(--surface-2) 45%,transparent)}
.lrn-prose tbody tr:hover,table.dtable tbody tr:hover{
  background:color-mix(in srgb,var(--accent) 7%,transparent)}
.lrn-prose tbody tr:last-child td,table.dtable tbody tr:last-child td{border-bottom:0}
.lrn-prose table code,table.dtable code{white-space:nowrap;font-size:.88em}

@media(max-width:980px){
  .lrn-grid{grid-template-columns:1fr}
  .lrn-rail-in{position:static}
  .lrn-rail{order:-1}
}

/* ============================================================================
   Comparison grid (assets/js/grid.js) — the universal side-by-side component.
   Attributes down a sticky left column, items across sticky headers, grouped
   rows, live search + tabs. Used on Frontier Models and, in time, every
   comparison page. Mono stack is local (the system has no --mono token).
   ============================================================================ */
.cg-controls{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:0 0 16px}
.cg-searchwrap{position:relative;display:flex;align-items:center}
.cg-sicon{position:absolute;left:11px;width:14px;height:14px;pointer-events:none;
  background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7793' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E")}
.cg-search{font-family:var(--font-body);font-size:13px;padding:9px 13px 9px 32px;border:1px solid var(--border-strong);
  border-radius:999px;background:var(--surface-1);color:var(--text-primary);min-width:250px;outline:none;transition:border-color .15s}
.cg-search:focus{border-color:var(--c-blue)}
.cg-search::placeholder{color:var(--muted)}
.cg-selall{display:flex;gap:5px}
.cg-mini{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;padding:7px 12px;border:1px solid var(--border-strong);border-radius:999px;background:var(--surface-1);color:var(--text-secondary);cursor:pointer;transition:.12s}
.cg-mini:hover{color:var(--text-primary);border-color:var(--text-primary)}
/* multi-select picker: choose which items to compare, chips grouped by family/tier */
.cg-picker{display:flex;flex-direction:column;gap:9px;margin:0 0 16px;padding:13px 15px;border:1px solid var(--border);border-radius:14px;background:var(--surface-1)}
.cg-pickrow{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.cg-pick-grp{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);background:none;border:1px dashed var(--border-strong);border-radius:6px;padding:4px 9px;cursor:pointer;flex:none;min-width:92px;text-align:left}
.cg-pick-grp:hover{color:var(--text-primary);border-color:var(--text-primary)}
.cg-pick{font-family:var(--font-body);font-size:12px;padding:5px 11px;border-radius:999px;border:1px solid var(--border-strong);background:var(--surface-2);color:var(--text-secondary);cursor:pointer;transition:.12s;white-space:nowrap}
.cg-pick:hover{color:var(--text-primary)}
.cg-pick[aria-pressed="true"]{border-color:var(--gc);color:var(--text-primary);box-shadow:inset 0 0 0 1px var(--gc)}
.cg-pick[aria-pressed="true"]::before{content:"✓";color:var(--gc);font-weight:700;margin-right:5px;font-size:10px}
.cg-pick[aria-pressed="false"]{opacity:.5}
.cg-count{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;color:var(--muted);margin-left:auto}
.cg-scroll{overflow-x:auto;border:1px solid var(--border);border-radius:16px;background:var(--surface-1)}
.cg-table{border-collapse:separate;border-spacing:0;width:100%;min-width:760px;font-size:12.5px;color:var(--text-secondary)}
.cg-table th,.cg-table td{padding:10px 14px;border-bottom:1px solid var(--border);text-align:left;vertical-align:top}
.cg-table thead th{position:sticky;top:0;background:var(--surface-1);border-bottom:2px solid var(--border-strong);z-index:2}
.cg-attr{position:sticky;left:0;background:var(--surface-1);font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:10px;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);white-space:nowrap;border-right:1px solid var(--border-strong)}
.cg-table thead .cg-attr{z-index:3}
.cg-corner{color:var(--text-secondary)}
.cg-mh{border-top:3px solid var(--gc,var(--muted));min-width:152px}
.cg-nm{font-family:var(--font-display);font-weight:700;font-size:13.5px;color:var(--text-primary);display:flex;align-items:center;gap:6px;line-height:1.2}
.cg-fl{font-size:15px;line-height:1}
.cg-link{color:inherit;text-decoration:none;border-bottom:1.5px solid var(--gc,var(--muted));transition:opacity .12s}
.cg-link:hover{opacity:.68}
.cg-sub{display:block;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--gc,var(--muted));margin-top:3px}
.cg-mono{font-family:ui-monospace,Menlo,Consolas,monospace;color:var(--text-secondary);font-variant-numeric:tabular-nums}
.cg-val{color:var(--text-secondary)}
.cg-best{color:var(--text-primary)}
.cg-table ul{margin:0;padding-left:15px}
.cg-table li{margin:2px 0}
.cg-badge{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--tc,var(--muted));border:1px solid var(--tc,var(--muted));border-radius:4px;padding:1px 6px;white-space:nowrap}
.cg-ow{color:var(--c-aqua);font-weight:700}
.cg-table tr.cg-grouphead td{background:color-mix(in srgb,var(--text-primary) 5%,var(--surface-1));border-top:1px solid var(--border-strong)}
.cg-table tr.cg-grouphead .cg-attr{background:color-mix(in srgb,var(--text-primary) 5%,var(--surface-1));
  color:var(--text-primary);font-weight:700;letter-spacing:.08em}
.cg-none{padding:22px;color:var(--muted);font-family:ui-monospace,Menlo,Consolas,monospace}

/* A problem row in the header search. Visually distinct from a page hit because it is a
   different kind of answer: a page hit takes you somewhere, a problem row opens the palette
   on a shortlist. Styled as a button, not a link, for that reason. */
.tn-res.tn-prob{width:100%;text-align:left;background:none;border:0;cursor:pointer;
  font:inherit;color:inherit;border-left:2px solid var(--accent);padding-left:10px}
.tn-res.tn-prob .tn-rg{color:var(--accent)}


/* ---- comparison grid: the FACET row (an orthogonal filter, e.g. provider) ----
   Sits above the item picker and reads as a different kind of control on purpose: square
   corners against the picker's pills, so nobody mistakes "whose is it" for "show this one".
   Counts are baked in because a provider chip with a 1 next to it tells the reader whether
   narrowing is worth the click before they make it. */
.cg-facet{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin:0 0 12px;padding:10px 14px;border:1px solid var(--border);border-radius:14px;background:var(--surface-1)}
.cg-facet-l{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);flex:none;min-width:66px}
.cg-facet-b{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-body);font-size:12px;padding:5px 10px;border-radius:7px;border:1px solid var(--border-strong);background:var(--surface-2);color:var(--text-secondary);cursor:pointer;transition:.12s;white-space:nowrap}
.cg-facet-b:hover{color:var(--text-primary);border-color:var(--text-primary)}
.cg-facet-b[aria-pressed="true"]{border-color:var(--accent);color:var(--text-primary);background:var(--surface-3, var(--surface-2));box-shadow:inset 0 0 0 1px var(--accent)}
.cg-facet-n{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.cg-facet-b[aria-pressed="true"] .cg-facet-n{color:var(--accent)}
.cg-facet-clear{border-style:dashed;color:var(--muted)}
/* An item the facet has ruled out: still listed, visibly out of scope. Vanishing chips make a
   filter feel broken; a dimmed one shows the reader exactly what they narrowed away. */
.cg-pick-out{opacity:.32;text-decoration:line-through}

/* ---- the deep-page index under a comparison grid ----
   A wide grid's column headers are links, but reaching one means scrolling sideways first.
   This is the flat way in: every row's page, grouped by family, in reading order. */
.gidx{margin:22px 0 0;padding:18px 20px;border:1px solid var(--border);border-radius:14px;background:var(--surface-1)}
.gidx-l{margin:0 0 14px;font-size:13.5px;color:var(--text-secondary)}
.gidx-g{display:flex;gap:12px;align-items:flex-start;padding:9px 0;border-top:1px solid var(--border)}
.gidx-g:first-of-type{border-top:0;padding-top:0}
.gidx-f{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);flex:none;min-width:120px;padding-top:7px}
.gidx-g .types{margin:0;flex:1}

/* ---- homepage command palette (Treatment D) ----
   One input under the hero. Typing draws matches directly beneath it — no modal, no cards,
   nothing pre-selected. The reader who has never pressed a keyboard shortcut on a website
   still gets a box they can type into; the kbd badge is the door to the overlay for those
   who do reach for it. */
.ucp{position:relative;max-width:760px;margin:22px 0 0}
.ucp-bar{display:flex;align-items:center;gap:11px;padding:0 14px;height:54px;border:1px solid var(--border-strong);border-radius:13px;background:var(--surface-1);transition:border-color .14s,box-shadow .14s}
.ucp-bar:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 16%,transparent)}
.ucp-ic{flex:none;width:17px;height:17px;border:1.8px solid var(--muted);border-radius:50%;position:relative}
.ucp-ic::after{content:"";position:absolute;right:-6px;bottom:-5px;width:8px;height:1.8px;background:var(--muted);transform:rotate(45deg)}
.ucp-in{flex:1;min-width:0;border:0;outline:0;background:none;font:400 16px/1 var(--font-body);color:var(--text-primary)}
.ucp-in::placeholder{color:var(--muted)}
.ucp-in::-webkit-search-cancel-button{display:none}
.ucp-k{flex:none;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;color:var(--muted);border:1px solid var(--border-strong);border-radius:6px;padding:3px 7px;background:var(--surface-2);cursor:pointer}
.ucp-k:hover{color:var(--text-primary);border-color:var(--text-primary)}
.ucp-res{position:absolute;left:0;right:0;top:calc(100% + 7px);z-index:40;max-height:min(58vh,520px);overflow-y:auto;border:1px solid var(--border-strong);border-radius:13px;background:var(--surface-1);box-shadow:0 18px 44px rgba(0,0,0,.18);padding:7px}
/* The group header carries three things now — what kind of result this is, how many of them, and
   where the rows in it go. That last part is the whole of variant V1: the two libraries below it
   are disjoint (no problem route points at a kit board), so the reader is told which kind of thing
   they are about to open rather than left to infer it from a merged ranking that does not exist. */
.ucp-g{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);padding:10px 11px 6px;display:flex;align-items:baseline;gap:7px}
.ucp-g i{font-style:normal;font-weight:700;color:var(--accent);font-variant-numeric:tabular-nums}
.ucp-gd{margin-left:auto;text-transform:none;letter-spacing:0;font-size:10px;color:var(--muted)}
.ucp-r.kit .ucp-n{color:var(--accent)}
.ucp-r{display:grid;grid-template-columns:1fr auto;gap:2px 12px;width:100%;text-align:left;padding:9px 11px;border:0;border-radius:9px;background:none;cursor:pointer;text-decoration:none;font:inherit}
.ucp-r:hover,.ucp-r.on{background:var(--surface-2)}
.ucp-t{font-size:14px;font-weight:600;color:var(--text-primary)}
.ucp-n{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10px;color:var(--muted);white-space:nowrap;align-self:center}
.ucp-s{grid-column:1/-1;font-size:12.5px;color:var(--text-secondary);line-height:1.45}
.ucp-em{padding:18px 13px;font-size:13.5px;color:var(--muted)}
.uc-fallback{margin:18px 0 0;padding-left:20px;font-size:13.5px;color:var(--text-secondary);line-height:1.7}


/* ---- homepage: what's in here ----
   Replaced the 32-tile grid. That grid was a second taxonomy under a menu that now carries the
   taxonomy, its descriptions and its counts. This answers the two questions the menu cannot:
   how much is behind it, and when was any of it last checked. */
/* align-items:start, and the dividers are row borders rather than a background showing through
   1px gaps. Both halves of that are the same defect. The list is a grid item, so it STRETCHED to
   the height of the taller .cat-fresh card while its rows stayed content-height — and the residual
   80px+ at the bottom painted var(--border), a pale slab under the last row that read as a broken
   sixth row. It is not a rendering edge case: the sixth row is dropped whenever pages/learn is
   gated, which is always, so the two columns can never be the same height by accident.
   A divider colour must never double as a card background, or every pixel the content does not
   claim becomes a divider. */
/* ⚑ ONE CARD, TWO COLUMNS — 2026-08-14, operator direction: "one box of small other one is a
   bigger box doesn't make any sense". It was two separate cards with a 24px gap and
   align-items:start, so they could never share a baseline: the left sized to six rows, the right
   to four rows plus two paragraphs, and one always overhung the other. Making them the same
   height was never available — the fix is that they stop being two objects. The right column is
   now a SIDEBAR of one card: a shared border, a shared radius, one divider between them, and
   `stretch` so both columns are the card's height by construction rather than by luck.
   ⚠︎ THE SLAB DEFECT IS STILL THE THING TO WATCH. The old `align-items:start` was fixed here
   (bdb300372) because a stretched grid item painted its residual in the divider colour. That
   cannot come back — the card's background is --surface-1 and the divider is a border on the
   column, never a background showing through a gap. */
/* ⚑ THE SPLIT WAS 1.35 : .85 AND THE SPACE WAS ON THE WRONG SIDE — 2026-08-14, operator:
   "why are you leaving that much big space, you can align with proper way".
   MEASURED IN A BROWSER BEFORE AND AFTER, because "looks roomy" is not a number. At 1440px the
   left column took 853px to hold rows whose text is 207-281px wide, so 433-507px of EVERY row —
   61 to 71 per cent of its body cell — was empty; meanwhile the 537px sidebar was squeezing two
   of its six Checked notes onto a second line. One column had space it could not use and the
   other was short of it.
   1fr : minmax(320px,.95fr) moves ~140px per row across: dead space falls to 293-367px, all six
   notes come back to ONE line (8 rendered lines -> 6), nothing on the left wraps, and the card is
   32px shorter. ⚠︎ THE LEFT STAYS THE WIDER OF THE TWO ON PURPOSE (713 vs 677) — the rail is the
   primary content and the sidebar is provenance; an even split reads as two equal things and a
   .95:1.05 split inverts the hierarchy outright.
   ⚠︎ AND THE EQUAL-HEIGHT PROPERTY IS UNTOUCHED — measured 539/539 both themes, the same
   construction Option 2 was chosen for. This is a rebalance inside Option 2, not a re-opening of
   it: still one card, still two columns, still `stretch`. */
.cat-wrap{display:grid;grid-template-columns:1fr minmax(320px,.95fr);margin-top:6px;
  align-items:stretch;background:var(--surface-1);border:1px solid var(--border);
  border-radius:13px;overflow:hidden}
@media(max-width:860px){.cat-wrap{grid-template-columns:1fr}}
.cat-list{display:flex;flex-direction:column}
.cat-row+.cat-row{border-top:1px solid var(--border)}
/* ⚑ THE ROWS SHARE THE CARD'S HEIGHT — 2026-08-14. Option 2 makes both columns the height of the
   taller one, and the Checked sidebar is the taller one: that left 217px of dead air under the
   last rail row, which is exactly the "why is there so much space at the bottom" a reader asks
   before they ask anything else. `flex:1` lets the six rows absorb it evenly instead, and the
   content is already centred, so they read as generous rather than padded.
   ⚠︎ THE max-height IS THE POINT OF THE RULE, NOT A DETAIL. Without a cap, a Checked column that
   grows to a dozen rows would stretch six rail rows to 150px each and the fix becomes a worse
   defect than the gap. 104px holds today's card at zero residual and stops there. */
.cat-row{display:grid;grid-template-columns:66px 1fr auto;align-items:center;gap:14px;
  padding:13px 16px;background:var(--surface-1);text-decoration:none;color:inherit;
  transition:background .12s;flex:1 1 auto;max-height:104px}
.cat-row:hover{background:var(--surface-2)}
.cat-n{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:23px;font-weight:700;
  color:var(--gc);font-variant-numeric:tabular-nums;text-align:right}
/* The wrapper was a bare <span> with no rule, so its two block children collapsed into one
   inline run — "Request-pipeline stagesEverything between your API call and the first token".
   A grid cell does not save you from an inline parent. */
.cat-b{display:flex;flex-direction:column;min-width:0}
.cat-l{display:block;font-size:15px;font-weight:600;color:var(--text-primary);line-height:1.3}
.cat-s{display:block;font-size:11.5px;color:var(--muted);margin-top:1px}
.cat-go{color:var(--muted);font-size:14px}
.cat-row:hover .cat-go{color:var(--gc)}
/* The sidebar half of that one card. flex-column so the run line can sit on margin-top:auto and
   pin to the bottom, which is what keeps the two columns reading as one object when the Checked
   list is shorter than the rail. */
.cat-fresh{border-left:1px solid var(--border);background:var(--surface-2);padding:16px 18px;
  display:flex;flex-direction:column}
@media(max-width:860px){.cat-fresh{border-left:none;border-top:1px solid var(--border)}}
.cat-fresh h3{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted);margin:0 0 14px;font-weight:600}
.fr-row{display:flex;flex-direction:column;gap:2px;padding:9px 0}
.fr-row+.fr-row{border-top:1px solid var(--border)}
/* THE STATE CHIP, added 2026-08-14 with the currency run. A date on its own does not tell a
   reader whether it is recent — 2026-07-01 looks fine until you know today. The chip says so in a
   word, and it is derived from the same thresholds the run uses, never typed. */
.fr-k{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.fr-st{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:8.5px;font-weight:700;
       letter-spacing:.1em;border-radius:999px;padding:3px 7px;white-space:nowrap}
.fr-fresh  {color:#0a6b3d;background:rgba(10,107,61,.12)}
.fr-ageing {color:#8a5a06;background:rgba(138,90,6,.14)}
.fr-stale  {color:#a2251a;background:rgba(162,37,26,.13)}
.fr-unknown{color:var(--muted);background:var(--surface-2);border:1px solid var(--border)}
/* Dark needs the ink to come UP, not the ground to go down: those three inks are chosen against
   white and land at 2:1 or worse on a navy panel. Same three meanings, measured on --surface-1. */
html[data-theme="dark"] .fr-fresh {color:#6ddc9b;background:rgba(109,220,155,.13)}
html[data-theme="dark"] .fr-ageing{color:#e8bd6a;background:rgba(232,189,106,.13)}
html[data-theme="dark"] .fr-stale {color:#f0928a;background:rgba(240,146,138,.13)}
.fr-k{font-size:12.5px;color:var(--text-secondary)}
/* ⚠︎ THE DATE TAKES THE ROW'S STATE COLOUR, IT IS NOT ALWAYS GREEN. It was hardcoded to
   --c-green, which was defensible while every date here was an unjudged claim and is not now that
   the row carries a verdict: a row chipped AGEING printed its date in the same green as a row
   chipped FRESH, so the two halves of the same row disagreed and the reassuring half was the
   bigger one. Inherits from .fr-row, which the renderer classes. */
.fr-v{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:13px;font-weight:700;
  color:var(--fr-ink,var(--c-green));font-variant-numeric:tabular-nums}
.fr-row:has(.fr-ageing) {--fr-ink:#8a5a06}
.fr-row:has(.fr-stale)  {--fr-ink:#a2251a}
.fr-row:has(.fr-unknown){--fr-ink:var(--muted)}
html[data-theme="dark"] .fr-row:has(.fr-ageing){--fr-ink:#e8bd6a}
html[data-theme="dark"] .fr-row:has(.fr-stale) {--fr-ink:#f0928a}
.fr-n{font-size:11px;color:var(--muted);line-height:1.45}
/* The run line is machinery, not prose — it says when the job last ran and what it left for a
   person. Mono and small so it reads as a status bar rather than a second paragraph of copy. */
.cat-note{margin:14px 0 0;padding-top:13px;border-top:1px solid var(--border);
  font-size:11.5px;color:var(--muted);line-height:1.5}


/* ---- labs index ----
   One row per worked exercise. The summary is the lab's own opening sentence, read at build
   time, because 56 hand-written one-liners would be 56 chances to drift the first time the
   course material is re-imported. */
.lab-list{display:flex;flex-direction:column;gap:1px;background:var(--border);
  border:1px solid var(--border);border-radius:13px;overflow:hidden;margin-top:4px}
.lab-row{display:grid;grid-template-columns:34px 1fr auto;align-items:start;gap:13px;
  padding:12px 15px;background:var(--surface-1);text-decoration:none;color:inherit;transition:background .12s}
.lab-row:hover{background:var(--surface-2)}
.lab-n{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;color:var(--muted);
  padding-top:2px;font-variant-numeric:tabular-nums}
.lab-b{display:flex;flex-direction:column;min-width:0;gap:2px}
.lab-t{font-size:14px;font-weight:600;color:var(--text-primary);line-height:1.3}
.lab-s{font-size:12px;color:var(--muted);line-height:1.45}
.lab-cl{display:inline-block;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--c-green);border:1px solid var(--c-green);
  border-radius:5px;padding:1px 5px;margin-left:6px;vertical-align:1px}
.lab-go{color:var(--muted);font-size:14px;padding-top:2px}
.lab-row:hover .lab-go{color:var(--c-yellow)}


/* ---- Signal band: the pages today's brief actually changed ----
   The cards say what happened; these say where it landed. Derived from newslinks.json, which the
   morning pipeline writes, so the line is empty on a day the brief touched nothing rather than
   showing yesterday's. */
.sig-touch{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  margin-top:14px;padding-top:13px;border-top:1px solid var(--border)}
.sig-touch-l{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--c-green);flex:none}
.sig-touch-c{font-size:12.5px;font-weight:600;text-decoration:none;color:var(--text-secondary);
  border:1px solid var(--border-strong);border-radius:8px;padding:4px 11px;background:var(--surface-1);
  transition:color .12s,border-color .12s,background .12s;white-space:nowrap}
.sig-touch-c:hover{color:var(--c-green);border-color:var(--c-green);
  background:color-mix(in srgb,var(--c-green) 10%,var(--surface-1))}
@media(max-width:640px){.sig-touch-l{width:100%}}


/* ---- "What changed here" ----
   One block, replacing three surfaces a reader could not tell apart: a metric list mid-page, a
   curated digest near the foot, and an auto-linked headline list under that. Two of them looked
   identical and shared no stories, which reads worse than real duplication.
   Tiers run strongest claim first — Measured (a number with sources), Written in (approved and
   permanent), Recent (auto-linked, not vetted) — and the tier label is what tells them apart. */
.whatchanged{border:1px solid var(--border);border-left:3px solid var(--c-green);
  border-radius:0 14px 14px 0;background:var(--surface-1);padding:20px 24px;margin:26px 0}
.wc-tier{padding:14px 0}
.wc-tier+.wc-tier{border-top:1px solid var(--border)}
.wc-tier:first-of-type{padding-top:4px}
.wc-th{display:flex;align-items:baseline;gap:11px;flex-wrap:wrap;margin:0 0 9px}
.wc-tk{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--c-green);font-weight:700}
.wc-ts{font-size:11.5px;color:var(--muted)}
.wc-metric+.wc-metric{margin-top:11px}
.wc-claim{margin:0;font-size:13.5px;color:var(--text-secondary)}
.wc-claim b{color:var(--text-primary);font-variant-numeric:tabular-nums}
/* The sources under a Measured claim. Always open — it was a <details> and the disclosure bought
   nothing (identical DOM, identical bytes, 52 of them extra) while making a dated claim's proof
   need a click. `wc-ev-h` is the count as a plain label, so the heading that used to be a control
   still tells you how many there are. */
.wc-ev{margin-top:6px}
.wc-ev-h{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;color:var(--muted);
  margin:0}
.wc-ev-h::before{content:"— ";color:var(--c-green)}
.wc-ev ul{margin:8px 0 0;padding-left:16px;display:flex;flex-direction:column;gap:6px}
.wc-ev li{font-size:12.5px;line-height:1.45}
.wc-list{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:12px}
.wc-item{font-size:13.5px}
.wc-hl{font-weight:650;color:var(--text-primary);text-decoration:none;border-bottom:1px solid var(--border-strong)}
.wc-hl:hover{border-bottom-color:var(--c-green);color:var(--c-green)}
.wc-digest{margin:3px 0 0;font-size:13px;color:var(--text-secondary);line-height:1.55}
.wc-meta{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;color:var(--muted);margin-left:6px}
/* A PUSHED KNOWLEDGE ENTRY, not a citation. The operator's third approval says this is part of what
   the page teaches, so it is set apart from the references it sits above: a rule down the left edge,
   the digest in full text colour rather than secondary, and the change it made stated underneath.
   Reference-coloured styling here would erase the distinction the approval was made to express. */
.wc-item.wc-know{border-left:2px solid var(--c-green);padding-left:11px}
.wc-item.wc-know .wc-digest{color:var(--text-primary)}
.wc-upd{font:700 9.5px/1 var(--font-body);letter-spacing:.05em;text-transform:uppercase;color:var(--c-green);margin-right:7px;white-space:nowrap}
.wc-chg{margin:5px 0 0;font-size:12.5px;color:var(--text-secondary);line-height:1.5;font-style:italic}
.wc-none{margin:2px 0 0;font-size:13.5px;color:var(--text-secondary);line-height:1.6}
.wc-note{margin:14px 0 0;padding-top:12px;border-top:1px solid var(--border);
  font-size:11.5px;color:var(--muted)}

/* ============================================================
   Inline data charts (ROI dashboard, Build-vs-Buy)
   ============================================================
   These two figures are drawn as inline <svg> by the page's own script rather than compiled from
   Mermaid, because their marks are bound to numbers the page computes at render time. A .mmd file
   would freeze a picture that has to agree with the table beside it — and the whole reason these
   charts exist is that the table and the picture can never disagree. Everything below is shared
   chrome: the script emits class names and never a colour.

   --dv-1..4 are the four chart slots. In light mode they ARE the site accents, unchanged. In dark
   they are the same four hues stepped down in lightness. The --c-* darks were tuned for 1-2px
   Mermaid strokes and small accents; at that lightness a large filled area glares against
   --figure-bg. These steps hold the hue and the chroma and lower only L, which is what a big fill
   needs. Slot order is fixed (blue, orange, aqua, gold) and slots are assigned by MEANING, never
   by rank — so a filter or a re-sort can never repaint a series out from under a reader. */
:root{--dv-1:#5d8ff1;--dv-2:#db6f3c;--dv-3:#00ad80;--dv-4:#b88a00}
html[data-theme="light"]{--dv-1:var(--c-blue);--dv-2:var(--c-orange);--dv-3:var(--c-aqua);--dv-4:var(--c-yellow)}

/* .figure centres its contents, which is right for a diagram and wrong for a chart: the legend,
   the row labels and a two-line caption all read from the left edge. Hence the override. */
.dvfig{position:relative;text-align:left;padding:20px 22px}
.dv-legend{display:flex;flex-wrap:wrap;gap:7px 20px;margin:0 0 14px;font-size:12px;
  color:var(--text-secondary);line-height:1.45}
.dv-key{display:inline-flex;align-items:baseline;gap:7px}
.dv-key i{width:11px;height:11px;border-radius:3px;flex:none;position:relative;top:1px}
.dv-key b{font-weight:650;color:var(--text-primary)}
.dv-key.k1 i{background:var(--dv-1)}
.dv-key.k2 i{background:var(--dv-2)}
.dv-key.k3 i{background:var(--dv-3)}
.dv-key.k4 i{background:var(--dv-4)}
/* The plot div is what the script measures. It carries no padding of its own so clientWidth is the
   true drawing width — .figure's padding would otherwise be counted in and the svg would overflow. */
.dv-plot{overflow-x:auto}
.dv-svg{display:block}
/* Chrome stays recessive: hairline, solid, one step off the surface. Never dashed — a dashed grid
   reads as "threshold" or "projection" when it is only a grid. */
.dv-grid{stroke:var(--border);stroke-width:1}
.dv-base{stroke:var(--border-strong);stroke-width:1}
.dv-tick{fill:var(--muted);font-size:10.5px;font-family:var(--font-body);font-variant-numeric:tabular-nums}
.dv-lbl{fill:var(--text-secondary);font-size:11.5px;font-family:var(--font-body)}
.dv-hd{fill:var(--text-primary);font-size:11.5px;font-weight:650;font-family:var(--font-body)}
/* Values wear text tokens, never the series colour: a light gold or aqua is illegible as text on
   either surface. The coloured mark beside the number is what carries identity. */
.dv-val{fill:var(--text-primary);font-size:11px;font-weight:650;font-family:var(--font-body);
  font-variant-numeric:tabular-nums}
.dv-val.neg{font-weight:800}
.dv-f1{fill:var(--dv-1)}.dv-f2{fill:var(--dv-2)}.dv-f3{fill:var(--dv-3)}.dv-f4{fill:var(--dv-4)}
/* The 2px separator between stacked segments is the surface showing through, not a stroke drawn
   around each mark. A stroke would add ink that is not data, and on a segment only a few pixels
   wide (token cost, most rows) it would swallow the mark whole. */
.dv-gap{fill:var(--figure-bg)}
.dv-ring{fill:none;stroke:var(--border-strong);stroke-width:1}
.dv-svg [data-tip]{transition:filter .12s}
.dv-svg [data-tip]:hover{filter:brightness(1.14)}
.dv-tip{position:absolute;z-index:5;pointer-events:none;max-width:280px;background:var(--surface-1);
  border:1px solid var(--border-strong);border-radius:9px;box-shadow:var(--shadow);padding:7px 10px;
  font-size:11.5px;line-height:1.45;color:var(--text-secondary)}
.dv-tip b{color:var(--text-primary);font-weight:650}
.dvfig .figcap{text-align:left;margin-top:12px}

/* ================================================================= ENGAGE ====
   The two reader-facing asks drawn by assets/js/engage.js: the "Chip in" pill and
   the "What should we build next" tab/panel. Both are OFF by default (the FLAGS
   block in that file), so these rules match nothing until the flag is flipped.

   Namespaced fnd- because the obvious names were taken or too generic: `.pill`
   already exists in this file, and `.chips`/`.stars`/`.inner` are the kind of
   names a later component would reach for and silently collide with.

   Anchored to --header-h rather than a magic 64px so the pill still clears the
   bar if the header height ever changes. Both sit BELOW the nav's z-index (100)
   and above the page, so a dropdown always wins. */

.fnd-pill{position:fixed;top:calc(var(--header-h) + 14px);right:20px;z-index:80;
  display:flex;align-items:center;gap:12px;background:var(--surface-1);
  border:1px solid color-mix(in srgb,var(--c-green) 45%,transparent);
  border-radius:14px;padding:9px 8px 9px 16px;box-shadow:0 8px 26px rgba(0,0,0,.32);
  max-width:min(380px,calc(100vw - 40px))}
.fnd-pill-c b{display:block;font-size:13px;font-weight:750;color:var(--text-primary);line-height:1.25}
.fnd-pill-c small{display:block;font-size:10.5px;font-weight:500;color:var(--text-secondary);
  margin-top:2px;line-height:1.35}
.fnd-chip{flex:none;border:0;border-radius:10px;background:var(--c-green);color:#06210f;
  font:800 12px/1 var(--font-body);padding:10px 15px;cursor:pointer;white-space:nowrap;text-decoration:none}
.fnd-chip:hover{filter:brightness(1.08)}
.fnd-x{flex:none;background:transparent;border:0;color:var(--muted);font-size:16px;line-height:1;
  cursor:pointer;padding:2px 4px;align-self:flex-start}
.fnd-x:hover{color:var(--text-primary)}

/* The edge tab. Rotated about its right edge so it reads bottom-to-top and costs
   no horizontal room on a page that already has a TOC rail on the left. */
/* right:18px, not 0. Once rotated -90deg about its right edge this tab is vertical, so its
   horizontal footprint is its HEIGHT (12px padding x2 + 11.5px line = ~36px) centred on the
   origin — half of it landed past the viewport and pushed document.scrollWidth out by 18px.
   Offsetting by half that height sits it flush. Revisit if the padding or font-size changes. */
.fnd-tab{position:fixed;right:18px;top:52%;transform:rotate(-90deg) translateX(50%);
  transform-origin:right center;background:var(--c-violet);color:#0b0b18;
  font:800 11.5px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.14em;text-transform:uppercase;
  padding:12px 20px;border:0;border-radius:11px 11px 0 0;z-index:50;cursor:pointer}
.fnd-tab:hover{filter:brightness(1.08)}
/* Withdraw while the panel is open: the tab is pinned to the edge UNDER the panel, so an open
   panel would otherwise clip it into a sliver of unreadable rotated text. */
body.fnd-open .fnd-tab{opacity:0;pointer-events:none;transition:opacity .18s}
/* ⚑ AN OPEN PANEL MUST NOT SIT ON THE TEXT — 2026-08-30, operator: "when you expanded the text
   should not hit that submit feedback form." MEASURED before changing anything: the panel is
   position:fixed at right:20px and 352px wide, so it reaches 372px in from the right edge, while
   the column is capped at --maxw and centred. The two only clear each other once the viewport is
   wider than --maxw + 2x372 = 2424px, which is wider than any monitor here — so on EVERY real
   screen the open panel covered the end of every line it crossed.
   The precedent is .pres, which was position:fixed for the same reason and was moved into the
   reading column on 2026-08-29: an in-flow element makes its own room. This panel cannot move
   in-flow (it is a dialog, and it must stay reachable while the page scrolls), so the column
   yields instead, and only while the panel is actually open.
   ⚠︎ Below 1100px there is no room to yield, so the panel becomes a bottom sheet rather than
   squeezing the text into a gutter — the same choice the mobile menu already makes. */
@media(min-width:1100px){
  body.fnd-open .wrap,body.fnd-open .article{padding-right:404px}
  body.fnd-open .wrap,body.fnd-open .article{transition:padding-right .22s ease}
}
@media(max-width:1099px){
  .fnd-panel{right:12px;left:12px;width:auto;top:auto;bottom:12px;
    max-height:min(72vh,calc(100vh - var(--header-h) - 40px))}
  body.fnd-haspill .fnd-panel{top:auto}
}

.fnd-panel{position:fixed;right:20px;top:calc(var(--header-h) + 70px);width:352px;
  max-height:calc(100vh - var(--header-h) - 100px);overflow-y:auto;z-index:85;
  opacity:0;pointer-events:none;transform:translateY(12px);
  transition:opacity .22s,transform .22s}
.fnd-panel.open{opacity:1;pointer-events:auto;transform:none}
/* Clear the donate pill when it is on screen. Measured, not guessed: the pill lands at
   header+14 and stands ~66px tall, so anything under header+80 overlaps it — and the two close
   buttons ended up almost touching. engage.js adds .fnd-haspill only when the pill actually
   rendered, so a dismissed or flagged-off pill gives the panel its higher resting position back. */
body.fnd-haspill .fnd-panel{top:calc(var(--header-h) + 100px);
  max-height:calc(100vh - var(--header-h) - 130px)}
.fnd-inner{background:var(--surface-1);border:1px solid var(--border-strong);border-radius:16px;
  padding:19px;position:relative;box-shadow:0 22px 60px rgba(0,0,0,.5)}
.fnd-inner h3{margin:0 0 3px;font-size:15.5px;font-weight:760;color:var(--text-primary)}
.fnd-sub{margin:0 0 16px;font-size:12.5px;color:var(--text-secondary)}
.fnd-close{position:absolute;top:13px;right:13px;background:transparent;border:0;
  color:var(--muted);font-size:18px;line-height:1;cursor:pointer}
.fnd-close:hover{color:var(--text-primary)}
.fnd-row{margin-bottom:15px;padding-bottom:15px;border-bottom:1px solid var(--border)}
.fnd-row:last-of-type{border-bottom:0}
.fnd-row > span{display:block;font-size:11px;font-weight:800;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin-bottom:8px}
.fnd-chips{display:flex;flex-wrap:wrap;gap:6px}
.fnd-cf{font:500 11.5px/1 var(--font-body);padding:6px 11px;border:1px solid var(--border-strong);
  border-radius:20px;color:var(--text-secondary);background:transparent;cursor:pointer;
  transition:color .13s,border-color .13s,background .13s}
.fnd-cf:hover{color:var(--text-primary);border-color:var(--c-violet)}
.fnd-cf.on{border-color:var(--c-violet);color:var(--c-violet);
  background:color-mix(in srgb,var(--c-violet) 13%,transparent)}
.fnd-stars{display:flex;gap:5px}
.fnd-stars i{font-style:normal;font-size:23px;color:var(--border-strong);cursor:pointer;
  transition:color .1s,transform .1s}
.fnd-stars i.hot,.fnd-stars i.on{color:var(--gold)}
.fnd-stars i:hover{transform:scale(1.15)}
.fnd-starlab{display:block;font-size:11.5px;color:var(--muted);margin-top:6px;min-height:14px}
.fnd-ta{width:100%;min-height:64px;background:var(--surface-2);border:1px solid var(--border-strong);
  border-radius:10px;padding:10px;color:var(--text-primary);font:400 12.5px/1.5 var(--font-body);
  resize:vertical}
.fnd-ta:focus{outline:2px solid var(--c-violet);outline-offset:1px}
.fnd-optin{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--text-secondary);
  margin-bottom:13px;cursor:pointer}
.fnd-optin input{width:16px;height:16px;accent-color:var(--c-violet)}
.fnd-send{width:100%;padding:12px;border:0;border-radius:11px;background:var(--c-violet);
  color:#0b0b18;font:800 13.5px/1 var(--font-body);cursor:pointer}
.fnd-send:disabled{opacity:.6;cursor:default}
.fnd-priv{font-size:10.5px;color:var(--muted);margin:10px 0 0;line-height:1.45;text-align:center}
.fnd-done{font-size:13.5px;font-weight:650;color:var(--c-green);text-align:center;margin:14px 0 0}
/* The send-time message, beside the button that triggers it. It used to be written into
   .fnd-starlab at the top of a scrolling panel, where a reader pressing Send at the bottom
   never saw it — which is how a refused submission read as "nothing happened". */
.fnd-msg:empty{display:none}
.fnd-msg{display:block;margin:0 0 9px;padding:9px 12px;border-radius:10px;font-size:12.5px;
  line-height:1.5;border:1px solid var(--border-strong);background:var(--surface-2);
  color:var(--text-secondary)}
.fnd-msg-warn{border-color:color-mix(in srgb,var(--c-yellow) 48%,transparent);
  background:color-mix(in srgb,var(--c-yellow) 10%,transparent);color:var(--text-primary)}
.fnd-msg-bad{border-color:color-mix(in srgb,var(--c-red) 50%,transparent);
  background:color-mix(in srgb,var(--c-red) 10%,transparent);color:var(--text-primary)}

/* Light theme: the three solid buttons need their FOREGROUND flipped, not just re-tinted.
   These tokens invert lightness between themes — --c-green is #54b45a on dark but #008300 on
   light, --c-violet #9085e9 vs #4a3aa7 — so the near-black label that reads at 7:1 on the dark
   palette collapses to 3.4:1 (green) and 2.2:1 (violet) on the light one. Both fail AA at 12px.
   White fixes violet outright (8.6:1). White on #008300 is only 4.0:1, still short, so the chip
   also darkens its own background ~12% — locally, never by touching the shared token, which
   would drag every green on the site with it. */
html[data-theme="light"] .fnd-chip{background:color-mix(in srgb,var(--c-green) 88%,#000);color:#fff}
html[data-theme="light"] .fnd-tab,
html[data-theme="light"] .fnd-send{color:#fff}

/* Phone. The donate pill is REMOVED rather than shrunk: at 390px it would cover the
   first paragraph of whatever the reader came to read, and an ask that obscures the
   thing being asked about is not an ask. The feedback tab stops being a rotated edge
   strip (there is no edge to spare) and becomes a normal button above the thumb, and
   the panel becomes a bottom sheet. Neither of these can be verified from here —
   no 390px viewport in this environment — so they want a screenshot. */
@media (max-width:820px){
  .fnd-pill{display:none}
  .fnd-tab{top:auto;bottom:16px;right:14px;transform:none;transform-origin:center;
    border-radius:999px;padding:12px 18px;box-shadow:0 6px 20px rgba(0,0,0,.4)}
  /* Written as body.fnd-haspill too, NOT just .fnd-panel. Specificity beats source order, so
     the desktop `body.fnd-haspill .fnd-panel{top:…}` rule above (0,2,1) would otherwise win
     here (0,1,0) and leave the sheet floating at the top of a phone screen — even though the
     pill it was clearing is display:none at this width. */
  .fnd-panel,body.fnd-haspill .fnd-panel{left:10px;right:10px;width:auto;top:auto;bottom:0;
    max-height:min(82vh,calc(100vh - var(--header-h) - 20px))}
  .fnd-panel.open{transform:none}
  .fnd-inner{border-radius:16px 16px 0 0}
}

/* --------------------------------------------------------------- RUN CARD ----
   The "Run it" block on a lab page. It used to be three paragraphs, a monospace
   path and a run of filenames — body copy that read as prose when it is the one
   thing on the page you are meant to ACT on.

   The card states what the artefact is, then what you can do with it, then what
   it needs. Buttons are real destinations only: where Colab genuinely cannot open
   a file (every path here sits behind the Clerk gate, so an unauthenticated fetch
   from Colab is redirected to sign-in) the card offers download-then-upload rather
   than a button that looks live and is not. */
.runcard{border:1px solid var(--border-strong);border-radius:14px;background:var(--surface-1);
  padding:16px 18px;margin:0 0 16px}
.rc-hd{display:flex;gap:13px;align-items:flex-start;margin:0 0 14px}
.rc-ic{flex:none;width:40px;height:40px;border-radius:10px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--accent)}
.rc-t{min-width:0}
.rc-t b{display:block;font-size:15px;font-weight:700;color:var(--text-primary);line-height:1.3}
.rc-t small{display:block;font-size:12px;color:var(--muted);margin-top:3px;
  overflow-wrap:anywhere}
.rc-t small code{background:none;border:0;padding:0;font-size:12px;color:var(--text-secondary)}
.rc-acts{display:flex;flex-wrap:wrap;gap:9px}
.rc-btn{display:inline-flex;align-items:center;border:0;border-radius:10px;
  background:var(--accent-fill);color:var(--accent-fill-ink);font:700 13px/1 var(--font-body);
  padding:11px 16px;text-decoration:none;white-space:nowrap}
.rc-btn:hover{filter:brightness(1.09)}
.rc-ghost{background:transparent;color:var(--text-primary);border:1px solid var(--border-strong)}
.rc-ghost:hover{border-color:var(--accent);color:var(--accent);filter:none}
.rc-note{margin:12px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted)}
.rc-note b{color:var(--text-secondary);font-weight:650}

/* Data files as chips: a reader scanning for "is my file here" reads a chip row far
   faster than a bulleted list, and each chip is its own download. */
.rc-data{margin:0 0 16px}
.rc-k{display:block;font-size:10.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);margin:0 0 9px}
.dchips{display:flex;flex-wrap:wrap;gap:7px}
.dchip{display:inline-flex;align-items:center;gap:6px;font:600 12px/1 var(--font-mono,ui-monospace,monospace);
  padding:8px 12px;border-radius:8px;border:1px solid var(--border-strong);
  background:var(--surface-2);color:var(--text-secondary);text-decoration:none}
.dchip::before{content:"\2193";font-weight:800;color:var(--accent)}
.dchip:hover{border-color:var(--accent);color:var(--text-primary)}

@media (max-width:640px){
  .rc-acts{flex-direction:column;align-items:stretch}
  .rc-btn{justify-content:center}
}

/* ---------------------------------------------------------------- CODE BOX ----
   A block of code the reader is meant to COPY. The old treatment set it as one
   non-wrapping line behind a horizontal scrollbar, so eight shell commands became
   a 3000px strip showing about one and a half of them. You cannot read what you
   are copying, and you cannot count what you are about to run.

   Lines wrap. Long tokens (a Drive file id) break at the token edge rather than
   mid-token, so a wrapped command still pastes correctly. */
.codebox{border:1px solid var(--border-strong);border-radius:12px;background:var(--surface-2);
  overflow:hidden;margin:0 0 18px}
.cb-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:8px 10px 8px 14px;background:color-mix(in srgb,var(--surface-3,var(--surface-1)) 70%,transparent);
  border-bottom:1px solid var(--border)}
.cb-lbl{font:700 10.5px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted)}
.cb-copy{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border-strong);
  background:var(--surface-1);color:var(--text-secondary);border-radius:7px;padding:5px 10px;
  font:650 11.5px/1 var(--font-body);cursor:pointer;transition:color .12s,border-color .12s}
.cb-copy:hover{color:var(--text-primary);border-color:var(--accent)}
.cb-copy.ok{color:var(--c-green);border-color:var(--c-green)}
.cb-body{margin:0;padding:14px 16px;background:none;border:0;overflow:visible}
.cb-body code{font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  font-size:12.8px;line-height:1.85;color:var(--text-primary);background:none;border:0;padding:0;
  white-space:pre-wrap;overflow-wrap:break-word;display:block}

/* ------------------------------------------------------------- WIDE FIGURE ----
   Mermaid emits a canvas as wide as the graph demands — the lab diagrams run
   2000-3400px. `.figure img{max-width:100%}` then scales that into a ~950px
   column, i.e. down to about a third, which renders 15px label text at 5px. The
   figure looks present and is unreadable.

   A figure whose natural width is far beyond the column carries .wide: it renders
   at natural size and its container scrolls, so the type stays legible. The real
   fix is narrower diagrams — grouped and vertical rather than one long chain —
   and this is the floor that stops an unreadable one shipping in the meantime. */
.figure.wide{overflow-x:auto;padding-bottom:14px}
.figure.wide img{max-width:none;width:auto;height:auto}
.figure.wide .figcap{position:sticky;left:0}

/* ------------------------------------------------------------------ STEPS ----
   A walkthrough is a sequence of ACTIONS each with an OUTCOME, and the outcome is
   what the reader came for. As a plain <ol> the two run together in one paragraph
   and the numbers people actually want — the p-value, the verdict — sit buried
   mid-sentence. This sets each step as a row: what was done on the left, what came
   out on the right. */
.steps{list-style:none;margin:0 0 18px;padding:0;counter-reset:stp;
  border:1px solid var(--border);border-radius:12px;overflow:hidden}
.steps>li{counter-increment:stp;display:grid;grid-template-columns:44px 1fr;gap:0;
  border-bottom:1px solid var(--border);background:var(--surface-1)}
.steps>li:nth-child(even){background:color-mix(in srgb,var(--surface-2) 50%,transparent)}
.steps>li:last-child{border-bottom:0}
.steps>li::before{content:counter(stp);font:700 12px/1 var(--font-mono,ui-monospace,monospace);
  color:var(--muted);padding:16px 0 0 14px;font-variant-numeric:tabular-nums}
.step-b{padding:14px 16px 14px 2px;min-width:0}
.step-h{display:block;font-size:14px;font-weight:680;color:var(--text-primary);
  line-height:1.35;margin:0 0 4px}
.step-d{display:block;font-size:13.5px;line-height:1.6;color:var(--text-secondary)}
@media (max-width:620px){
  .steps>li{grid-template-columns:34px 1fr}
  .steps>li::before{padding-left:10px}
}

/* An unnumbered variant of .steps. "Where it breaks" is a set of independent failure
   modes, not a sequence, so it keeps the rows and drops the counter rail — the numbers
   would assert an order the content does not have. */
.steps-plain{counter-reset:none}
.steps-plain>li{grid-template-columns:22px 1fr}
.steps-plain>li::before{content:"";padding:0}
.steps-plain>li::after{content:"";position:absolute}
.steps-plain .step-b{padding-left:14px}

/* Caption for a figure swapped in by build/learn_upgrade.py. The study pages are imported
   markdown and have no <figure>/<figcaption> structure to hang a caption on, so the swap
   emits its own inline element rather than restructuring the surrounding prose. */
.figcap-swap{display:block;font-size:12.5px;line-height:1.55;color:var(--muted);
  margin:8px auto 22px;max-width:70ch;text-align:center}

/* Theme-swap inside the study prose.
   `.lrn-prose img` (0,1,1) sits LATER in this file than `img.dia-light` (0,1,1). Equal
   specificity, so source order decides — and it was setting display:block on both twins, so
   every swapped figure rendered TWICE, light stacked on top of dark. These rules are (0,2,1)
   and therefore win in both directions. */
.lrn-prose img.dia-light{display:none}
.lrn-prose img.dia-dark{display:block;margin:16px auto}
html[data-theme="light"] .lrn-prose img.dia-light{display:block;margin:16px auto}
html[data-theme="light"] .lrn-prose img.dia-dark{display:none}

/* ------------------------------------------------------------- LEARNING HUB ----
   Course tiles on pages/learn/index.html. Same tile language as the homepage grid,
   because a reader who has learned that shape should not have to learn a second one
   for the same job. Deliberately NOT a list: the courses are peers you choose
   between, and a list implies an order they do not have. */
.lrn-hub-g{margin:0 0 34px}
.lrn-hub{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px;
  margin-top:14px}
.lrn-hub-t{display:block;text-decoration:none;border:1px solid var(--border);
  border-top:3px solid var(--gc,var(--accent));border-radius:14px;
  background:var(--surface-1);padding:17px 18px;box-shadow:var(--shadow-sm);
  transition:border-color .13s,transform .13s}
.lrn-hub-t:hover{border-color:var(--gc,var(--accent));transform:translateY(-1px)}
/* Design B card internals. The stat row and the bar are the reason this tile beats a plain
   row: they say how big a course is and how much of it is hands-on BEFORE the click. A course
   with no labs gets a single full-width bar, which reads as "this is reading" rather than as a
   broken chart, and a figure count of 0 is left visible on purpose. */
.hub-top{display:flex;align-items:center;gap:11px;margin:0 0 12px}
.hub-ic{font-size:23px;line-height:1;flex:none}
.hub-nm{font-family:var(--font-display);font-weight:700;font-size:15.5px;line-height:1.25;
  color:var(--text-primary);text-wrap:balance}
.hub-stats{display:flex;gap:18px;margin:0 0 13px}
.hub-st b{display:block;font:700 19px/1 var(--font-mono,ui-monospace,monospace);
  color:var(--text-primary);font-variant-numeric:tabular-nums}
.hub-st span{font-size:10px;color:var(--muted);letter-spacing:.06em;text-transform:uppercase}
.hub-bar{display:flex;height:6px;border-radius:99px;overflow:hidden;background:var(--border)}
.hub-bar i{display:block;height:100%}
.hub-leg{display:block;font-size:11.5px;color:var(--muted);margin-top:8px;line-height:1.45}


/* Learning — a top-level nav destination, styled as a quiet sibling of the Signal pill.
   Deliberately NOT given the live dot: Signal changes every morning and the dot says so;
   Learning is a stable body of material and a pulsing dot would be a lie about it. */
.tn-learn{display:inline-flex;align-items:center;font:650 13px/1 var(--font-body);
  color:var(--text-secondary);text-decoration:none;padding:0 13px;height:var(--nav-h);box-sizing:border-box;border-radius:var(--nav-r);
  border:1px solid var(--border-strong);white-space:nowrap;transition:color .12s,border-color .12s}
.tn-learn:hover{color:var(--text-primary);border-color:var(--accent)}
/* The classroom doors start CLOSED and nav.js opens them for an account that carries the `learn`
   flag. An explicit rule is required, not just the `hidden` attribute: `.tn-learn` sets an
   element-level `display`, which beats the user-agent's `[hidden]{display:none}`, so the attribute
   alone leaves the link on screen for everyone. The attribute selector takes this to specificity
   0,2,0 so it wins on merit rather than on being further down the file. */
.tn-learn[hidden],.mm-learn[hidden]{display:none}

/* --------------------------------------------------------- COURSE SECTIONS ----
   Layout A: a course index shows its sections collapsed, so the shape of the
   course fits one screen instead of 80 tiles filling several. Built on
   <details>/<summary> so it works with no JavaScript at all — the "expand all"
   button is an enhancement, not the mechanism. */
.lrn-band{border:1px solid var(--border);border-radius:13px;background:var(--surface-1);
  margin:0 0 9px;overflow:hidden}
.lrn-band[open]{border-color:var(--border-strong)}
.lrn-band-s{display:flex;align-items:center;gap:13px;padding:14px 16px;cursor:pointer;
  list-style:none;user-select:none}
.lrn-band-s::-webkit-details-marker{display:none}
.lrn-band-s:hover{background:color-mix(in srgb,var(--gc,var(--accent)) 6%,transparent)}
.lrn-band-t{flex:1;font-family:var(--font-display);font-weight:700;font-size:15.5px;
  color:var(--text-primary);line-height:1.3}
.lrn-band-m{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
/* A chevron drawn in CSS rather than an icon font: it must rotate, and a glyph that
   rotates in one browser and not another is worse than a border triangle. */
.lrn-band-x{flex:none;width:9px;height:9px;border-right:2px solid var(--muted);
  border-bottom:2px solid var(--muted);transform:rotate(-45deg);transition:transform .16s;
  margin-right:3px}
.lrn-band[open] .lrn-band-x{transform:rotate(45deg)}
.lrn-band-b{padding:2px 16px 16px;border-top:1px solid var(--border)}
.lrn-expand{display:inline-flex;align-items:center;gap:7px;margin:0 0 14px;
  border:1px solid var(--border-strong);background:var(--surface-2);color:var(--text-secondary);
  border-radius:9px;padding:8px 14px;font:650 12.5px/1 var(--font-body);cursor:pointer}
.lrn-expand:hover{color:var(--text-primary);border-color:var(--accent)}
@media (max-width:640px){
  .lrn-band-s{padding:13px 13px;gap:9px}
  .lrn-band-m{font-size:11px}
}


/* ------------------------------------------------------- NAV, SLIMMED ----
   The bar needed 1354px and overflowed every viewport under ~1400px — most
   laptops. Three controls that were spelled out become icons, which is what a
   reader already expects them to be. Destinations (Learn, Signal, Chip in) stay
   as words, because a word is what makes a destination findable.
   Search 170->36px · theme pair 90->36px · Admin 60->36px = ~230px back. */
/* Search collapses to its icon below 1400px.
   Targeted as #foundry-q, not `.tn-search input`. The original rule is an ID selector — (1,0,0)
   against a class selector's (0,1,1) — so the class version I wrote first lost silently and the
   input stayed 170px wide while everything else shrank. Specificity, not source order, decided it.
   The input reopens on focus, and nav.js already binds "/" to focus it, so nothing is unreachable. */
@media (max-width:1500px){
  #foundry-q{width:0;padding-left:28px;padding-right:0;border-color:transparent;background:transparent}
  #foundry-q:focus{width:210px;padding-right:12px;border-color:var(--accent);background:var(--surface-1)}
  .tn-search .tn-sicon{left:8px}

  /* One theme control instead of a Dark/Light pair: only the INACTIVE option shows, so the
     control reads as "switch to the other theme". Both buttons stay in the DOM for the mobile
     menu and for assistive tech. */
  .tn-right .seg{border:0;background:none;padding:0}
  .tn-right .seg button{border:1px solid var(--border-strong);border-radius:var(--nav-r);padding:7px 10px}
  html[data-theme="dark"]  .tn-right .seg button[data-theme-set="dark"]{display:none}
  html[data-theme="light"] .tn-right .seg button[data-theme-set="light"]{display:none}
  /* With only one button showing, "pressed" is not a state the reader can act on — the control
     has stopped being a two-way segment and become a one-way action ("switch to Dark"). The
     aria-pressed fill made it read as filled in light and outlined in dark, i.e. the same control
     looking like two different things. Neutralised so it matches Learn/Signal in both themes. */
  .tn-right .seg button[aria-pressed]{background:transparent;color:var(--text-secondary)}
  .tn-right .seg button[aria-pressed]:hover{color:var(--text-primary);border-color:var(--text-primary)}

  /* The magnifier is now the ENTIRE search affordance, not a decoration inside a visible field,
     so it has to carry secondary-text weight rather than muted. */
  .tn-search .tn-sicon{color:var(--text-secondary);font-size:16px}
  #foundry-q{cursor:pointer}

  /* Admin keeps its count, as a dot rather than a numeral. */
  .tn-admin{font-size:0;padding:8px 10px}
  .tn-admin::before{content:"\1F510";font-size:13px}
  .tn-admin .tn-admin-badge{font-size:0;min-width:8px;height:8px;padding:0;margin-left:5px}
}
/* Between the mobile breakpoint (980px) and ~1120px the desktop bar was asked to render in less
   room than it needs: 1072px of brand + menu + controls inside 1024px. Nothing here was going to
   collapse on its own, so the group labels give up their horizontal padding — 7 groups x 10px a
   side is 140px, far more than the ~50px of the shortfall. Tightening the gap is invisible; the
   alternative was raising the hamburger breakpoint and losing the menu entirely on a laptop. */
@media (max-width:1200px){
  .navlink{padding:8px 5px}
  .menu{margin-left:0}
  /* The bar's own padding and inter-group gaps are the last air in the row. At 1024 the children
     summed to 1002 but the bar measured 1046 — 20px of side padding and two 12px gaps that my
     first sum had simply left out. They are worth 24px here and cost nothing visually. */
  .tn-inner{padding:0 12px;gap:8px}
  .tn-right{gap:6px}
}
/* The last 40px, in the sliver between the mobile breakpoint (980px) and ~1040px. Half a point
   off the group labels is worth ~20px across seven of them — twice the 9px shortfall. Deliberately
   NOT done by hiding Signal or Account: those are destinations, and a destination that vanishes at
   one width is a navigation bug, not a responsive design. Type gets smaller; nothing disappears. */
@media (max-width:1040px){
  .navlink{font-size:12.5px}
  /* 981-992px is the seam: the hamburger takes over at 980, so at 981 the DESKTOP bar still
     renders and needed 986px. Four more pixels a side closes the seam so there is no width where
     neither layout fits. */
  .tn-inner{padding:0 8px}
}
/* The wordmark's "adhana" tail is the first thing to go when space is genuinely tight — the
   mark and "AI Foundry" still identify the site without it. */
@media (max-width:1200px){
  .wm-sep,.wm-adhana{display:none}
}

/* The donation, in the bar. Quiet on purpose: a green solid pill beside the account
   icon would shout on every page of a site someone is trying to read. It is present
   and reachable; the FULL ask — with the reason — lives at the foot of the page,
   after the reader has had something. */
/* --give is the ONE knob for the whole ask. It is deliberately NOT a topic colour: this
   generator's rule is "colour = meaning", and green already means Playbook (GCV), plus the Signal
   dot, positive ROI, what-changed and eval fills — 19 components in all. The donate ask is not a
   topic, so it must not wear a topic colour. Change these two lines to move the whole surface.

   TEAL, replacing magenta — operator call 2026-07-28 ("I do not like the rose").
   The replacement had to clear the same bar magenta did, and that bar is measurable rather than
   aesthetic. The seven taxonomic hues sit at: Operate red 4, Build orange 19, Reference yellow 43,
   Playbook green 124, Ground aqua 162, Foundations blue 220, Models violet 247. That leaves three
   real gaps — 305 (where magenta lived, 117 wide), 83 (81 wide, lime), and 191 (58 wide, cyan).

   AMBER WAS TRIED FIRST AND REJECTED ON MEASUREMENT, not taste: #d6a94e lands at hue 40, which is
   THREE degrees from Reference yellow at 43. Same colour to any eye. It was proposed on the
   assumption that darkening it moved it clear of yellow; darkening changes lightness, not hue, so
   it did not. Recording that here because the mistake is easy to repeat.

   #35a8b5 sits at hue 186 — the middle of the 191 gap — giving 24 degrees of separation from its
   nearest neighbour (Ground aqua). Magenta itself only had 26. So this is as taxonomically safe as
   the colour it replaces, which is the actual test.

   Contrast, computed not eyeballed: dark #35a8b5 on near-black ink = 5.96:1; light #1c7684 on
   white = 5.28:1. Both clear the 4.5 floor, and the light pairing is BETTER than the magenta it
   replaces (4.72:1). Light darkens the fill and keeps white ink for the same reason --accent-fill
   does: a bright fill cannot carry white text. */
:root{ --give:#35a8b5; --give-ink:#04202a }
html[data-theme="light"]{ --give:#1c7684; --give-ink:#ffffff }

.tn-give{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;text-decoration:none;
  font:800 12.5px/1 var(--font-body);color:var(--give-ink);
  border:0;background:var(--give);
  border-radius:var(--nav-r);padding:0 15px;height:var(--nav-h);box-sizing:border-box;
  box-shadow:0 6px 14px -5px color-mix(in srgb,var(--give) 65%,transparent),
             0 1px 0 color-mix(in srgb,var(--give) 70%,#000);
  transition:box-shadow .15s ease,transform .15s ease}
.tn-give:hover{transform:translateY(-1px);
  box-shadow:0 10px 20px -5px color-mix(in srgb,var(--give) 75%,transparent),
             0 1px 0 color-mix(in srgb,var(--give) 70%,#000)}
@media (max-width:1100px){ .tn-give{display:none} }

/* The full ask, at the foot of a page. This is where it can explain itself. */
/* ONE ROW: the ask on the left, the button inline on the right.
   It used to be a two-column LEDGER — heading, sub-line and button stacked on the left against a
   three-item list on the right — which ran about 150px tall. The list was the sub-line enumerated,
   so folding it back into one sentence cost no claim and bought roughly 57% of the height back.
   Operator call 2026-07-28: "the height of the tile too big, short".
   grid-template-columns is 1fr auto so the button takes exactly its own width and the text takes
   the rest, rather than the text being squeezed into 1.25fr of a two-column split. */
.give-band{max-width:var(--maxw);margin:44px auto 0;padding:13px 20px;
  border:1px solid color-mix(in srgb,var(--give) 55%,transparent);border-radius:14px;
  background:linear-gradient(120deg,color-mix(in srgb,var(--give) 18%,transparent),
                                    color-mix(in srgb,var(--give) 7%,transparent) 70%);
  display:grid;grid-template-columns:1fr auto;gap:18px;align-items:center}
/* On a phone the button drops under the text — at that size an inline button beside two lines of
   prose leaves neither enough room. It also has to be re-aligned: justify-self:end is right for a
   button sitting in its own column, and wrong once it is stacked beneath left-aligned text, where
   it strands the CTA in the far corner. Stretched full width instead. The "NOT width:100%" note
   below applies to the TWO-COLUMN case only — there is no adjacent column here to bleed into. */
@media (max-width:760px){ .give-band{grid-template-columns:1fr;gap:12px;padding:14px 16px} }
.give-band-t{min-width:0}
.give-band-t b{display:block;font-family:var(--font-display);font-size:15.5px;font-weight:700;
  color:var(--text-primary)}
.give-band-t small{display:block;font-size:13px;color:var(--text-secondary);margin-top:2px;
  line-height:1.45}
/* NOT width:100%. A full-bleed button would run its glow under the text column. Natural width,
   vertically centred against the two lines of text now that it is a sibling rather than stacked
   beneath them — hence align-self:center and no margin-top. */
.give-band a{justify-self:end;align-self:center;
  background:var(--give);color:var(--give-ink);border-radius:10px;
  padding:13px 24px;font:800 13px/1 var(--font-body);text-decoration:none;white-space:nowrap;
  display:inline-flex;align-items:center;
  box-shadow:0 10px 22px -6px color-mix(in srgb,var(--give) 62%,transparent),
             0 3px 8px -2px color-mix(in srgb,var(--give) 45%,transparent),
             0 1px 0 color-mix(in srgb,var(--give) 70%,#000);
  transition:box-shadow .15s ease,transform .15s ease}
.give-band a:hover{transform:translateY(-1px);
  box-shadow:0 14px 28px -6px color-mix(in srgb,var(--give) 70%,transparent),
             0 4px 10px -2px color-mix(in srgb,var(--give) 50%,transparent),
             0 1px 0 color-mix(in srgb,var(--give) 70%,#000)}
/* MUST STAY BELOW `.give-band a` ABOVE, not up with the other phone rule. Both selectors have the
   same specificity, so at 390px the one written later wins — putting this beside the
   grid-template-columns override left justify-self:end in force and the button stranded in the
   far corner under left-aligned text. Measured: it stayed 92px wide until this moved down here. */
@media (max-width:760px){ .give-band a{justify-self:stretch;justify-content:center} }
/* .give-ledger removed 2026-07-28 with the three-item list it styled. Nothing emits it any more —
   verified by grep across js, py, css and html before deleting. */

/* Tile option C: what is IN the course, instead of a figure count nobody chooses by. */
.hub-subs{display:block;font-size:12.5px;color:var(--text-secondary);line-height:1.5;margin-top:2px}
.hub-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:10px}
.hub-chip{font-size:10.5px;padding:3px 9px;border:1px solid var(--border-strong);border-radius:999px;
  color:var(--muted);white-space:nowrap}

/* ---- credit band -------------------------------------------------------------
   One line at the foot of a page whose subject a course actually shaped, linking to
   pages/credits.html. Quiet on purpose: it is an acknowledgement, not a promotion,
   so it sits below the content and above the tagband without competing with either. */
.crband{display:flex;gap:14px;align-items:baseline;flex-wrap:wrap;
  margin:34px 0 6px;padding:14px 18px;border:1px solid var(--border);border-radius:12px;
  background:var(--surface-2)}
.crband-k{flex:0 0 auto;font:700 10.5px/1.6 var(--font-body);letter-spacing:1.5px;
  text-transform:uppercase;color:var(--c-yellow)}
.crband-t{flex:1 1 320px;font-size:13.5px;line-height:1.6;color:var(--muted)}
.crband-t a{color:var(--text-secondary);text-decoration:underline;text-underline-offset:2px}
.crband-t a:hover{color:var(--c-blue)}
.crband-go{white-space:nowrap;font-weight:600}

/* ================================================================ USE-CASE KIT REPORT PAGES
   The third data-driven page kind on this site, after the pipeline and skills grids. Everything
   here is furniture for values that were CAPTURED — so the honesty blocks get as much visual
   weight as the numbers, deliberately. A report whose caveats are set smaller than its wins is
   an advert with footnotes. */
.kstats{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));margin:14px 0}
.kstat{border:1px solid var(--border);border-radius:8px;padding:11px 13px;background:var(--card);
  display:flex;flex-direction:column;gap:3px}
.kstat b{font-size:21px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1.15}
.kstat span{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}

/* TWO ACROSS, not four. A 1280px page screenshot shrunk to 250px is unreadable by construction:
   the reader cannot see the thing the lens exists to show. Each shot also opens full size. */
/* min(420px,100%): a 420px column minimum is wider than a phone's content box, so every kit's App UI
   panel scrolled sideways at 390px (measured 444px) and dragged the fixed drawer with it. */
.kshots{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(min(420px,100%),1fr));margin:16px 0}
.kshot a{display:block}
.kshot-zoom{font-size:11px;color:var(--c-teal);font-weight:600}
.kshot{margin:0;border:1px solid var(--border);border-radius:10px;overflow:hidden;background:var(--card)}
.kshot img{display:block;width:100%;height:auto}
.kshot figcaption{padding:9px 11px;font-size:12.5px;line-height:1.5;color:var(--text-secondary);
  border-top:1px solid var(--border);display:flex;flex-direction:column;gap:5px}
.kshot-k{font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
/* A failure shot is marked, not hidden. Lens 01 requires one and validate_kit now enforces it. */
.kshot.is-fail{border-color:var(--c-red)}
.kshot.is-fail .kshot-k{color:var(--c-red);font-weight:700}

/* The honesty blocks — not_good_enough, breaks_at_scale, breaks_on, cost_cliffs, could_not_verify.
   One treatment for all of them, so a reader learns the shape once. */
.khonest{border:1px solid var(--border);border-left:3px solid var(--c-teal);border-radius:0 8px 8px 0;
  padding:12px 15px;margin:14px 0;background:var(--card)}
.khonest h3{margin:0 0 7px;font-size:13px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--c-teal)}
.khonest p,.khonest li{font-size:13.5px;line-height:1.65}
.khonest ul{margin:0;padding-left:18px;display:flex;flex-direction:column;gap:6px}

.kjudge{border:1px solid var(--border);border-radius:10px;padding:15px 18px;margin:18px 0;
  background:var(--card)}
.kjudge h3{margin:0 0 9px;font-size:15px}
.kjudge p{font-size:13.5px;line-height:1.7;margin:0 0 9px}
.kjudge ul{margin:0 0 9px;padding-left:18px;display:flex;flex-direction:column;gap:7px}
.kjudge li{font-size:13.5px;line-height:1.6}

.knote{font-size:12.5px;line-height:1.6;color:var(--muted)}
/* "What did work" on a kit board — the fitment rows, 2026-08-19. Added because the operator
   read UC012, met an honest headline saying the model lost to free rules, and had no way to
   see the configuration that beat both. The rows are the kit's own fitment entries; the two
   variants are not decoration — a green rule means a measured configuration does this job, a
   red one means nothing here does, and 13 of the 84 rows in the set are the red kind. */
.kfit{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-direction:column;gap:9px}
.kfit li{border:1px solid var(--border);border-left:3px solid var(--c-green);border-radius:8px;
  padding:11px 14px;background:var(--surface-2);font-size:14.5px;line-height:1.55}
.kfit li.kfit-no{border-left-color:var(--c-red)}
.kfit li strong{color:var(--text-primary)}
.kfit li em{font-style:normal;font-weight:600;color:var(--c-green)}
.kfit li.kfit-no em{color:var(--c-red)}
.kfit li span{display:block;margin-top:4px;color:var(--text-secondary);font-size:13.8px}
/* THE FLOW IS THE REPORT, so its stations are links. The anchors sit OVER the <img> at percentage
   coordinates written by figures.py, which is the only way to keep the light/dark twins intact --
   an inlined SVG cannot be swapped by theme, and clicks inside an <img> do nothing at all.
   A hit area a reader cannot SEE is a secret, so each one shows a ring and its lens name on
   hover/focus; without that the picture looks exactly as flat as it did before. */
.figmap{position:relative;display:block;line-height:0}
/* WIDTH ONLY -- never `display`. `img.dia-light{display:none}` is (0,1,1) and so is `.figmap>img`;
   equal specificity means the later rule wins, and this file is later. Setting display:block here
   un-hid the inactive twin, both images stacked, the container came out twice as tall, and every
   percentage hit area landed at half its intended height over empty canvas. The theme swap owns
   display; this rule owns size. */
.figmap>img,.figmap>picture{width:100%;height:auto}
.figmap-hit{position:absolute;display:block;border-radius:8px;text-decoration:none;
  outline:2px solid transparent;outline-offset:2px;transition:background .12s,outline-color .12s}
.figmap-hit>span{position:absolute;left:50%;top:100%;transform:translate(-50%,6px);
  white-space:nowrap;padding:4px 9px;border-radius:6px;font:600 11.5px/1.35 var(--font-ui,inherit);
  background:var(--surface-2);color:var(--text-primary);border:1px solid var(--border-strong);
  opacity:0;pointer-events:none;transition:opacity .12s;z-index:3}
.figmap-hit:hover,.figmap-hit:focus-visible{background:color-mix(in srgb,var(--c-teal) 14%,transparent);
  outline-color:var(--c-teal)}
.figmap-hit:hover>span,.figmap-hit:focus-visible>span{opacity:1}
/* Touch has no hover, so the ring is always faintly on -- otherwise a phone reader never learns
   the stations are tappable. */
@media (hover:none){.figmap-hit{outline-color:color-mix(in srgb,var(--c-teal) 42%,transparent)}}

.kdetail{border:1px solid var(--border);border-radius:8px;margin:10px 0;background:var(--card)}
.kdetail>summary{cursor:pointer;padding:10px 13px;font-size:13px;font-weight:600;
  list-style-position:inside}
.kdetail>summary:focus-visible{outline:2px solid var(--c-teal);outline-offset:-2px}
/* The disclosure IS the box, so the codebox inside it drops its own border and radius and sits
   flush under the summary. Replaces .kpre, which looked right and could not be copied -- the
   verbatim prompt is the block a reader most wants in their own editor. */
.kdetail>.codebox{margin:0;border:0;border-top:1px solid var(--border);border-radius:0 0 7px 7px;
  background:none}
.kdetail>.codebox .cb-body{max-height:420px;overflow-y:auto}

/* The cost-scenario controls. Inputs, not decoration: a reader changes their own volume and
   retrieval depth and watches the bill move, which is the only honest way to answer "what would
   this cost me" from a run that was not theirs. */
.kdash{display:flex;flex-wrap:wrap;gap:14px;margin:16px 0;padding:14px 16px;
  border:1px solid var(--border);border-radius:10px;background:var(--card)}
.kdash label{display:flex;flex-direction:column;gap:5px;font-size:11px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted);flex:1 1 180px;min-width:0;max-width:100%}
/* max-width:100%: a <select> sizes to its LONGEST option, and a kit's eval-technique option can run
   160 characters — the Cost model panel measured 1,506px wide on a 390px phone, which also dragged the
   fixed mobile drawer sideways. */
.kdash input,.kdash select{font:inherit;font-size:15px;padding:7px 9px;border-radius:7px;
  border:1px solid var(--border);background:var(--bg);color:var(--text-primary);min-width:0;max-width:100%}
.kdash input:focus-visible,.kdash select:focus-visible{outline:2px solid var(--c-teal);
  outline-offset:1px}
/* The walk between steps. */
.kwalk{display:flex;gap:12px;flex-wrap:wrap;margin:26px 0 8px}
.kwalk a{flex:1 1 240px;border:1px solid var(--border);border-radius:10px;padding:11px 14px;
  display:flex;flex-direction:column;gap:3px;background:var(--card)}
.kwalk a:hover{border-color:var(--c-teal)}
.kwalk span{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.kwalk b{font-size:14.5px;color:var(--text-primary)}
.kwalk .knext{text-align:right}

/* The kit contents block in the rail: every page of a kit, on every page of that kit, so nothing
   is two clicks from anything. Sits above "On this page", which stays the current page's outline. */
.lrn-toc-nav.kit-contents{margin-bottom:16px;padding-bottom:14px;border-bottom:1px solid var(--border)}
.lrn-toc-l.kit-step{font-variant-numeric:tabular-nums}
.lrn-toc-l.kit-step.is-here{color:var(--c-teal);font-weight:700}
/* A NAMED GROUP UNDER A STEP — UC0453's access pages and its lens (operator's option B). The caption
   aligns with the rows' text; the guide line ties the rows to the step above; ↗ marks a row that
   leaves the page. */
.kit-contents .kit-cap{font-family:var(--font-display);font-size:9.5px;line-height:1.4;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);font-weight:700;margin:6px 0 2px 39px;padding:0}
.kit-kids{margin:1px 0 3px 26px;border-left:1px solid var(--border-strong);display:flex;flex-direction:column;gap:1px}
.kit-kids .lrn-toc-l{font-size:12px;padding-left:12px;display:flex;align-items:baseline;gap:6px}
.kit-ext{margin-left:auto;font-size:11px;color:var(--muted)}

/* ---------------------------------------------------------------------------------------------
   THE KIT LANE BOARD. Twelve linked tiles in four lanes, grouped by the question a reader
   arrives with. HTML rather than an SVG figure on purpose: real anchors take keyboard focus,
   one markup serves both themes, and tiles wrap on a narrow screen where a fixed canvas would
   scroll sideways. See KIT_LANES in mcp/standards/use_case.py.

   Colour means the reader's QUESTION here and the corpus FORMAT on the ribbon flow, so these
   four hues are deliberately deeper and warmer than FLOW_PALETTE. A near-miss between two
   palettes that mean different things is the one option with no upside.
   --------------------------------------------------------------------------------------------- */
/* ⚑ --kchip IS A THEME PAIR, AND ONLY HALF OF IT WAS EVER WIRED — fixed 2026-08-05.
   .ktile-ix paints `background:var(--kchip); color:var(--surface-1)`, so the chip colour and the
   page surface must move in OPPOSITE directions. The dark slate below is the LIGHT-theme value
   (use_case.LANE_CHIP[0]) and it was declared unconditionally, so dark theme — the DEFAULT — drew
   a #121a2b number on a #3e4358 chip: 1.78:1, against 4.5:1 for 8px bold text. Its counterpart
   LANE_CHIP[1] was declared in the standard and applied nowhere, which is what three handoffs
   recorded as "apply it or delete it". Applied: 10.59:1 dark, 9.77:1 light. */
.kboard{background:var(--surface-1);border:1px solid var(--border);border-radius:14px;
        padding:20px 22px 16px;margin:18px 0 22px;--kchip:#c3c9e4}
html[data-theme="light"] .kboard{--kchip:#3e4358}
.kboard-head{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
             margin-bottom:16px;flex-wrap:wrap}
.kboard-head b{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;letter-spacing:.1em;
               text-transform:uppercase;color:var(--text-primary)}
.kboard-head span{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;color:var(--text-secondary);letter-spacing:.05em}
/* align-items:stretch, so the spine below runs the LANE's height rather than the label's. With
   `center` the rule was a stub floating beside a three-row tile group and read as an artifact. */
/* ⚑ THE LANE IS A BAND — Option C, 2026-08-14, replacing Option B's saturated tiles. B made the
   board LOUDER without making it easier to read: thirteen saturated blocks shout equally, so
   nothing is ranked and the lane — the structure a reader needs first — had to fight its own
   tiles. "More intuitive" is a hierarchy problem, not a saturation problem. Colour moves onto the
   GROUPING; the tiles go quiet; the eye gets lane, then figure, then label. */
.klane{display:grid;grid-template-columns:172px 1fr;align-items:stretch;margin-bottom:10px;
       background:var(--kl-band);border:1px solid var(--kl-bandln);border-radius:14px;
       padding:12px 14px 12px 0}
.klane-q{padding-right:16px;margin-right:0;text-align:right;
         display:flex;flex-direction:column;justify-content:center;align-items:flex-end}
.klane-q b{display:block;font-size:15px;letter-spacing:-.008em;line-height:1.25}
.klane-q span{display:block;font-size:10.5px;color:var(--text-secondary);font-family:ui-monospace,Menlo,Consolas,monospace;
              margin-top:3px;letter-spacing:.04em}
.klane-q i{display:none}
.ktiles{display:flex;gap:8px;flex-wrap:wrap}
/* ⚠︎ 132px, AND THE FLOOR IS WHAT DECIDES WHETHER A LANE WRAPS. "How is it built?" carries FIVE
   steps and the operator asked for it on one row — at 158px the fifth tile fell to a second line
   and Frameworks rendered as a full-width slab under the other four. The tile shrank to make room
   rather than the lane growing, which is what "shrink the tile" meant. Measured at the real board
   width, not guessed. */
a.ktile{flex:1 1 132px;min-width:132px;display:flex;flex-direction:column;text-decoration:none;
        color:inherit;border-radius:11px;padding:10px 12px 11px;box-shadow:none;
        transition:transform .12s ease,border-color .12s ease}
a.ktile:hover,a.ktile:focus-visible{transform:translateY(-2px);outline:none}
a.ktile:focus-visible{box-shadow:0 0 0 2px var(--c-teal)}
.ktile-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;order:0}
/* The number is an INDEX; the name is what you click. The chip was competing with the label
   it exists only to number. */
.ktile-ix{background:var(--kchip);color:var(--surface-1);border-radius:7px;padding:1px 6px;
          font-family:ui-monospace,Menlo,Consolas,monospace;font-size:8px;letter-spacing:.1em;font-weight:700;opacity:.85}
.ktile-go{font-size:13px;opacity:.5;transition:opacity .12s ease,transform .12s ease}
a.ktile:hover .ktile-go{opacity:1;transform:translateX(2px)}
/* order:2 — the NAME is the caption, not the headline. `order` flips it below the figure without
   touching a byte of markup, so a tile reads "2,628 ms median call / Observability": the number,
   then what it is a number of. */
.ktile-nm{display:block;font-size:12.5px;letter-spacing:0;font-weight:600;line-height:1.25;
          color:var(--text-secondary);order:2;margin-top:2px}
/* THE FIGURE IS THE POINT OF A DASHBOARD AND IT USED TO BE THE SMALLEST THING ON THE TILE — 11px
   secondary text under an 18px title. The two swapped weight: the title is a label you already
   know from the lane, the figure is the thing you came to read. 14px, bold, tabular, in its own
   readout. Lengths were checked against the longest figures the board emits ("2,628 ms median
   call") at 152px, which is why the tile floor moved with it. */
.ktile-val{display:block;margin-top:6px;background:none;border-radius:0;padding:0;order:1;
           font-family:ui-monospace,Menlo,Consolas,monospace;font-size:15px;
           font-weight:700;letter-spacing:-.025em;font-variant-numeric:tabular-nums;
           color:var(--text-primary);line-height:1.15}
.kboard-foot{margin-top:13px;padding-top:11px;border-top:1px solid var(--border);
             font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;color:var(--text-secondary);letter-spacing:.04em;
             display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap}

/* ONE HUE DECLARATION PER LANE. --kl is the bright end of the hue, --kl-deep the dark end, and
   every rule below derives from those two. They used to be written out six times each across the
   two themes, which is how the dark set drifted away from the light set in the first place.
   ⚑ --kl-sat JOINED THEM ON 2026-08-14 and the same rule holds: it is declared once per lane and
   every light-theme colour below is mixed out of it. It is NOT a fifth hue — it is the same four
   hues at full saturation, because colour on this board means the reader's QUESTION and
   re-picking them would break the one thing the board already got right. */
.klane-works{--kl:#a9c6b4; --kl-deep:#2c5546; --kl-sat:#10705a}
.klane-built{--kl:#a6aecf; --kl-deep:#333b6b; --kl-sat:#3a45b5}
.klane-cost {--kl:#dcc08a; --kl-deep:#6b4e18; --kl-sat:#8a5a06}
.klane-risk {--kl:#d3a396; --kl-deep:#743428; --kl-sat:#ad3524}

/* ⚑ OPTION C — THE COLOUR IS ON THE GROUPING, NOT ON THIRTEEN TILES. This replaces Option B
   (saturated tile, white title), which shipped for a few hours on 2026-08-14 and was rejected:
   "the current one that you post option B I don't like it". B was not a bad palette, it was the
   wrong LEVEL — every tile shouting equally ranks nothing. So the lane gets a tinted band and its
   question in the hue, and the tile goes back to being a quiet card whose loudest element is the
   measured figure.
   ⚠︎ MEASURED AFTER THE FACT, AND THE FIRST DRAFT OF THIS COMMENT WAS WRONG — it carried
   plausible ratios written before anything was computed, which is the exact habit the --kchip
   incident is here to stop. Computed: the lane question on its own band reads
   light 5.61 / 7.21 / 5.54 / 5.88 and dark 8.84 / 7.41 / 9.25 / 7.31, floor 4.5:1. The tile name
   on its card is 7.94 light and 7.39 dark.
   ⚑ ONE DECLARATION PER LANE STILL HOLDS: --kl-band and --kl-bandln are mixed from --kl-sat in
   light and --kl in dark, so a hue is written once and everything else derives. */
/* ⚑ MORE COLOUR, ON THE FOUR THINGS THAT CARRY MEANING — operator, 2026-08-14: "can you add a
   little more colour to the use case dashboard?" C's first cut was almost monochrome: a 5% band
   and a grey step chip, with the figure in near-black. The lift goes onto the FIGURE, the chip,
   the tile edge and the band — never back onto the tile fill, which is what made B unreadable.
   The name stays neutral on purpose: if the label and the number are both coloured, neither leads.
   ⚠︎ EVERY PAIR MEASURED BEFORE IT WAS APPLIED, and the floor is 4.5:1. Figure on its tile:
   light 6.02 / 7.78 / 5.92 / 6.34, dark 9.82 / 8.23 / 10.27 / 8.12. Step chip on its own wash:
   light 5.06 / 6.44 / 4.99 / 5.27, dark 7.08 / 6.17 / 7.38 / 6.10. Lane question on the 8% band:
   light 5.39 / 6.86 / 5.31 / 5.60. The lowest number anywhere here is 4.99. */
.klane{--kl-band:color-mix(in srgb,var(--kl-sat) 8%,transparent);
       --kl-bandln:color-mix(in srgb,var(--kl-sat) 20%,transparent);
       --kl-ink:var(--kl-sat)}
.klane .klane-q b{color:var(--kl-ink)}
.klane a.ktile{background:var(--surface-1);
               border:1px solid color-mix(in srgb,var(--kl-sat) 18%,transparent)}
.klane a.ktile:hover{border-color:var(--kl-ink)}
.klane .ktile-go{color:var(--kl-ink);opacity:.7}
.klane .ktile-ix{background:color-mix(in srgb,var(--kl-sat) 12%,transparent);
                 padding:2px 6px;border-radius:6px;opacity:1;color:var(--kl-ink);font-size:8.5px}
/* THE FIGURE TAKES THE LANE'S COLOUR. It is the one element on the tile a reader came for, and
   colouring it does the job B tried to do with a filled block — at a twentieth of the ink. */
.klane .ktile-val{color:var(--kl-ink)}

/* ⚑ DARK IS NOT LIGHT WITH THE LIGHTS OFF, and the reason has not changed since the note this
   block replaces: the old dark fills were the pastels dragged down in lightness, which leaves
   four warm mid-tone low-chroma slabs on a surface ladder that is entirely NAVY — the definition
   of dirty. Option C sidesteps that argument almost entirely, because the tile is no longer a
   filled block in either theme. Dark only needs its band to be a LIGHTENING rather than a tint of
   the hue (a 5% hue wash on #0a0e17 is invisible), and its ink to be the bright end of the hue
   rather than the saturated one. */
html[data-theme="dark"] .klane{
  --kl-band:color-mix(in srgb,var(--kl) 6%,transparent);
  --kl-bandln:color-mix(in srgb,var(--kl) 20%,transparent);
  --kl-ink:var(--kl)}
html[data-theme="dark"] .klane a.ktile{background:var(--surface-2);
  border:1px solid color-mix(in srgb,var(--kl) 22%,transparent)}
html[data-theme="dark"] .klane .ktile-ix{
  background:color-mix(in srgb,var(--kl) 16%,transparent);color:var(--kl)}
html[data-theme="dark"] .klane a.ktile:hover{border-color:var(--kl)}
/* THE FOCUS RING IS RESTATED, NOT INHERITED. These dark rules outrank the base
   a.ktile:focus-visible, and folding focus in with hover silently replaced the teal ring — a
   keyboard user would lose the only indicator of where they are. */
html[data-theme="dark"] .klane a.ktile:focus-visible{box-shadow:0 0 0 2px var(--c-teal)}

@media (max-width:760px){
  .klane{grid-template-columns:1fr;gap:8px;padding:12px 12px 12px 12px}
  /* ⚠︎ THIS CARRIED A 4px LEFT BORDER IN THE --kl-spine COLOUR UNTIL 2026-08-14, AND THAT TOKEN
     NO LONGER EXISTS. (Written without the var() spelling on purpose: build/smoke/csstokens.py
     scans for that form and cannot tell a reference from prose, so naming it the other way round
     is cheaper than teaching a strict gate to be lenient.) It belonged to Option B, whose lane identity was a rule beside the
     label; Option C's is the band, which needs nothing here because it already wraps the whole
     lane at any width. A dangling var() does not throw — the declaration is dropped at
     computed-value time and the page renders — so nothing would have said so except
     build/smoke/csstokens.py, which failed the board on it. Deleting a design means deleting its
     leftovers, including the ones inside a media query nobody re-opened. */
  .klane-q{text-align:left;padding-right:0;padding-left:2px;margin-right:0;align-items:flex-start;
           border-right:none;justify-content:flex-start}
}
@media (prefers-reduced-motion:reduce){
  a.ktile{transition:none} a.ktile:hover{transform:none}
}

/* ---------------------------------------------------------------------------------------------
   KIT STAT CARDS. FIGURE FIRST — see FIGURE_FIRST in mcp/standards/use_case.py.
   The table these replace put the number in the narrowest column and the caveat in the widest,
   so the smallest thing on the row was the only thing the row existed to report.
   --------------------------------------------------------------------------------------------- */
.kcards{display:grid;grid-template-columns:repeat(auto-fit,minmax(212px,1fr));gap:10px;grid-auto-rows:1fr;margin:14px 0}
.kcard{background:var(--surface-1);border:1px solid var(--border);border-radius:6px;padding:13px 14px;
       display:flex;flex-direction:column}
.kcard.is-empty{border-style:dashed;background:transparent}
.kpill{display:inline-block;align-self:flex-start;font-family:ui-monospace,Menlo,Consolas,monospace;
       font-size:9px;letter-spacing:.1em;padding:2px 7px;border-radius:9px;font-weight:700;
       margin-bottom:8px}
.kp-counted{background:#d9e7de;color:#2c5546}
.kp-judged{background:#f3e7ca;color:#7a5a16}
.kp-not{border:1px dashed var(--text-secondary);color:var(--text-secondary)}

/* ── the monitor board — 2026-08-02. The approved wireframe's language: status tiles, verdict
   chips, a coverage strip. Chips colour by SEMANTIC state (holding / noise / breach / not
   measured), which is separate from the group accent; all four read on both themes because they
   sit on the theme's own --c-* tokens. Dashed still means "nothing here". */
.kstat.na{border-style:dashed;background:transparent}
.kstat.na b{color:var(--text-secondary)}
.mchip{display:inline-block;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;
  padding:2px 8px;border-radius:999px;border:1px solid var(--border);
  color:var(--text-secondary);white-space:nowrap;line-height:1.5}
.m-ok{border-color:var(--c-green);color:var(--c-green)}
.m-warn{border-color:var(--c-yellow);color:var(--c-yellow)}
.m-bad{border-color:var(--c-red);color:var(--c-red)}
.m-na{border-style:dashed}
.mon-cov{display:flex;flex-wrap:wrap;gap:3px;margin:10px 0 4px}
.mon-cov i{width:12px;height:12px;border:1px dashed var(--border);border-radius:2px}
.mon-cov i.on{background:var(--c-aqua);border-color:var(--c-aqua)}

/* RUN THE APP — 2026-08-02, operator idea: show the thing working, not only the numbers about
   it. The button lives on the lead slide because that is the moment in a room where "does it
   actually run?" is asked. Three states, and the third is the honest one: idle, starting, and
   "the kit is not checked out", which is a real answer rather than a spinner that never ends. */
.runapp{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-top:22px;
  padding-top:20px;border-top:1px solid var(--border)}
.runapp-btn{display:inline-flex;align-items:center;gap:10px;font-size:15px;font-weight:700;
  padding:14px 22px;border-radius:12px;border:1px solid var(--c-aqua);cursor:pointer;
  background:var(--c-aqua);color:var(--bg);transition:.12s;font-family:inherit}
.runapp-btn:hover{filter:brightness(1.08)}
.runapp-btn[disabled]{opacity:.6;cursor:progress}
.runapp-note{font-size:13px;color:var(--muted);flex:1;min-width:220px;line-height:1.5}
.runapp-note b{color:var(--text-primary)}
.runapp-note code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px}
.runapp-dot{width:9px;height:9px;border-radius:50%;background:var(--muted);flex:none}
.runapp.is-up .runapp-dot{background:var(--c-aqua)}
.runapp.is-bad .runapp-dot{background:var(--c-red)}
/* TWO ROUTES TO AN APP, AND THE HOSTED ONE LEADS. The deck's only app control used to be the
   local start button, so "open the app" meant the kit's own UI — no Guardrails, no Evals. The
   hosted app is the one APP_BOARDS applies to, so it is the primary button; the local start stays
   because it is the only proof this runs on a laptop, and it is quieter. */
.runapp-primary{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-top:22px}
.runapp-btn.is-hosted{text-decoration:none}
.runapp-alt{margin-top:6px;padding-top:14px;border-top:1px solid var(--border)}
.runapp-alt .runapp{margin-top:0}
.runapp-alt .runapp-btn{background:transparent;color:var(--text-primary);
  border:1px solid var(--border)}
.runapp-alt .runapp-btn:hover{border-color:var(--c-teal);color:var(--c-teal);filter:none}

/* THE WAY BACK, MADE UNMISSABLE — 2026-08-02. The route home existed only as a small row in the
   contents rail, and the operator opened a document and could not find it: "I'm not able to go
   back to it." A control nobody sees is a control that is not there. So the header carries a
   real button on the right of the title, and it STAYS ON SCREEN — the pitch pages are ten
   screens tall, and a way back that scrolls away is only useful on the screen you did not need
   it on. */
.pitch-head{display:flex;gap:24px;align-items:flex-start;justify-content:space-between;
  flex-wrap:wrap}
.pitch-head-l{min-width:0;flex:1}
/* NOT position:sticky. It sits inside <header>, and a sticky element cannot outlive its parent
   — it would scroll away with the header and promise a persistence it does not have. The header
   button is the big obvious control on ARRIVAL; the contents rail carries the same route and IS
   sticky for the whole page, which covers the scrolled case. Two controls, two jobs. */
.pitch-back{display:inline-flex;
  align-items:center;gap:10px;flex:none;font-size:14px;font-weight:700;
  padding:14px 20px;border-radius:12px;text-decoration:none;
  background:var(--surface-2);border:1px solid var(--border-strong);color:var(--text-primary);
  transition:.12s;z-index:5}
.pitch-back:hover{border-color:var(--c-aqua);color:var(--c-aqua)}
.pitch-back .ic{font-size:17px;line-height:1}
.pitch-back small{display:block;font-size:11px;font-weight:600;color:var(--muted);
  letter-spacing:.04em;margin-top:2px}
@media(max-width:700px){.pitch-back{width:100%;justify-content:center}}

/* ── the pitch deck — rebuilt 2026-08-02 after "still the presentation do not follow the
   presentation board... it's not looking good." The first version set slide type large and left
   the content floating in a wide dark page, which reads as a long document, not a board. A slide
   is a BOUNDED PANEL: the Code Story tablecard shell (surface, 1px border, 14px radius), a mono
   eyebrow carrying its number, one claim-sized heading, and the measured tiles inside the frame.
   Same register as the register — that was the whole point of the reference. */
.deck section{background:var(--surface-1);border:1px solid var(--border);border-radius:14px;
  padding:34px 36px;margin:0 0 18px;scroll-margin-top:80px}
.deck section:last-child{margin-bottom:0}
.deck h2{font-size:clamp(24px,3vw,34px);letter-spacing:-.02em;line-height:1.14;margin:0 0 14px;
  text-wrap:balance}
.deck h2 .k{display:block;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin-bottom:10px;
  font-weight:600}
.slide-n{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10.5px;color:var(--c-yellow);
  letter-spacing:.09em;font-weight:600;margin-bottom:12px}
.deck-lede{font-size:clamp(15.5px,1.5vw,18px);line-height:1.6;max-width:62ch;
  color:var(--text-secondary)}
.deck-lede p{margin:0 0 12px}.deck-lede p:last-child{margin-bottom:0}
.deck-lede strong,.deck-lede b{color:var(--text-primary)}
.deck .kstats{margin:20px 0 0}
.deck .kstat{background:var(--surface-2)}
.deck .kstat b{font-size:clamp(22px,2.6vw,30px)}
.deck .kcard-fig{font-size:clamp(26px,3vw,38px)}
.deck section#lead{background:var(--surface-2);border-color:var(--border-strong)}
.deck section#lead h2{font-size:clamp(28px,4vw,44px)}

/* the preparation: claim cards a presenter scans in the minute before the room */
.prep-grid{display:grid;gap:14px;margin:0}
.prep-card{border:1px solid var(--border);border-radius:14px;background:var(--surface-1);
  padding:20px 22px;display:flex;flex-direction:column;gap:12px}
.prep-claim{font-size:16.5px;line-height:1.5;color:var(--text-primary);
  padding-bottom:12px;border-bottom:1px solid var(--border)}
.prep-row{display:flex;flex-wrap:wrap;gap:10px;align-items:baseline}
.prep-lab{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);min-width:104px;font-weight:600}
.prep-body{font-size:13.5px;color:var(--text-secondary);flex:1;min-width:240px;line-height:1.6}
.prep-body strong,.prep-body b{color:var(--text-primary)}
.prep-blank{border:1px dashed var(--border);border-radius:10px;padding:12px 14px;
  font-size:13px;color:var(--text-secondary);display:flex;gap:10px;flex-wrap:wrap}
.kcard-fig{font-size:30px;letter-spacing:-.03em;line-height:1.05;font-variant-numeric:tabular-nums}
.kcard.is-empty .kcard-fig{color:var(--text-secondary)}
.kcard-fig small{font-size:15px;color:var(--text-secondary);letter-spacing:0}
.kcard-lab{font-size:12.5px;color:var(--text-secondary);margin-top:5px;line-height:1.35}
.kcard-why{font-size:11.5px;color:var(--text-secondary);margin-top:8px;padding-top:8px;
           border-top:1px solid var(--border);line-height:1.4}
html[data-theme="dark"] .kp-counted{background:#1f3329;color:#8fc4a6}
html[data-theme="dark"] .kp-judged{background:#332913;color:#d9b366}

/* The step rail: prev / next / back to the board, instead of reprinting all thirteen pages. */
.lrn-toc-nav.kit-steps{display:flex;flex-direction:column;gap:5px;margin-top:14px;padding-top:12px;
                       border-top:1px solid var(--border)}
.kit-near,.kit-all{display:block;font-size:12.5px;padding:6px 9px;border-radius:4px;
                   text-decoration:none;color:var(--text-secondary);border:1px solid transparent}
.kit-near:hover,.kit-all:hover{color:var(--text-primary);background:var(--surface-2)}
.kit-near.is-next{text-align:right}
.kit-all{text-align:center;border-color:var(--border);color:var(--text-primary);margin-top:3px}

/* ── OBSERVABILITY (kit step 13) ────────────────────────────────────────────────────────────────
   Two small charts and a third state. Everything here is drawn with CSS boxes rather than an SVG
   figure ON PURPOSE: the numbers come from the run records at build time and change whenever a run
   lands, and a generated SVG would have to be recompiled and re-pinned by fix-svg.py to stay sharp.
   A bar whose width is a percentage cannot go stale and cannot upscale-blur.
   --------------------------------------------------------------------------------------------- */

/* The third state, wherever a reading is absent. NOT a zero and never styled like a value: it is
   muted and non-tabular so the eye skips it rather than reading it as a small number. */
.mdash{color:var(--muted)}

/* Stage split — one row per stage, width proportional to its share of the median call. */
.obs-bar{display:grid;grid-template-columns:110px 1fr auto;align-items:center;gap:10px;
         padding:5px 0}
.obs-k{font-size:12px;color:var(--text-secondary);text-transform:capitalize}
.obs-t{display:block;height:12px;border-radius:3px;background:var(--accent);opacity:.75;min-width:3px}
.obs-v{font-size:12px;color:var(--text-secondary);font-variant-numeric:tabular-nums;
       white-space:nowrap}

/* Drift — median call, run over run. */
.obs-drift{display:flex;align-items:flex-end;gap:10px;overflow-x:auto;padding:10px 0 0;
           border-bottom:1px solid var(--border-strong)}
.obs-col{flex:1 0 62px;display:flex;flex-direction:column;justify-content:flex-end;
         align-items:center;gap:5px;min-height:130px;text-align:center}
.obs-fill{display:block;width:100%;border-radius:3px 3px 0 0;background:var(--accent);opacity:.8}
.obs-col b{font-size:10.5px;font-weight:600;color:var(--text-secondary);word-break:break-all;
           line-height:1.25}
.obs-col i{font-size:11px;font-style:normal;color:var(--text-primary);
           font-variant-numeric:tabular-nums}
/* Not comparable with the latest run — drawn, but visibly not part of the trend. Hatched rather
   than merely faded, because a reader scanning quickly reads "faint" as "small" on a bar chart. */
.obs-col-x .obs-fill{opacity:.34;
  background:repeating-linear-gradient(135deg,var(--muted),var(--muted) 4px,
                                       transparent 4px,transparent 8px)}
.obs-col-x b,.obs-col-x i{color:var(--muted)}

/* Observability panel, inside the use-case app (step-13's board at app scale). */
.obs-row{display:grid;grid-template-columns:110px 1fr auto;align-items:center;gap:10px;padding:5px 0}
.obs-nm{font-size:12.5px;color:var(--text-secondary);text-transform:capitalize}
.obs-tr{display:block;background:var(--surface-3);border-radius:3px;height:13px;overflow:hidden}
.obs-fillbar{display:block;height:13px;background:var(--accent);opacity:.8;border-radius:3px}
.obs-vv{font-size:12.5px;color:var(--text-secondary);font-variant-numeric:tabular-nums;white-space:nowrap}
.uca-dash{color:var(--muted)}

/* ── The nine kits on the front door ──────────────────────────────────────────
   Added 2026-08-10 with the start-here retirement. These cards are the only
   content an anonymous visitor can actually open, and until this section existed
   the homepage did not link a single one of them. */
/* ⚑ EVERY TILE THE SAME SIZE — operator direction 2026-08-18: "the tile should be same size."
   Two rules do it, and both are needed. `grid-auto-rows:1fr` equalises the ROWS (an auto row sized
   1fr resolves to the tallest row's content, so row 3 is as tall as row 1); the line clamp on the
   description stops any single card from setting a height nobody else needs, because the kit
   titles run from "Redaction" to a full clause. `margin-top:auto` on the pill then pins it to the
   bottom edge of whatever height the card was given, so the stat line reads as a rule across the
   grid rather than floating wherever the prose stopped.
   ⚠︎ DO NOT "FIX" A SHORT CARD BY HAND-TUNING ITS MARKUP. The whole point is that the card is
   sized by the grid, not by its text — per-card padding is how this comes back the day a kit with
   a longer name lands. */
.uc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));
  grid-auto-rows:1fr;gap:12px;margin:0 0 18px}
.uc-card{display:flex;flex-direction:column;gap:4px;padding:14px 15px;border:1px solid var(--border);
  border-radius:12px;background:var(--surface-1);text-decoration:none;color:inherit;height:100%;
  transition:border-color .15s ease,transform .15s ease}
.uc-card:hover{border-color:var(--accent);transform:translateY(-1px)}
/* display:flex above beats the [hidden] user-agent rule, so the facet filter would set the
   attribute and nothing would happen. This is the rule that makes hiding actually hide. */
.uc-card[hidden]{display:none}
/* The vertical badge — added 2026-08-20, operator direction: "every use case tile should have
   the vertical name". First element in the card, above the id, so a scanning reader sees industry
   before anything else. Its background colour is set inline per-card from
   build/facts/verticals.py's colour token — the same idiom .uck-vert on the admin checklist uses. */
.uc-vert{align-self:flex-start;font:700 9px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.07em;text-transform:uppercase;padding:3px 7px;border-radius:5px;color:#fff;
  white-space:nowrap;margin-bottom:2px}
.uc-id{font:700 10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.1em;color:var(--accent)}
/* ⚠︎ THE NAME IS CLAMPED TOO, AND ITS ABSENCE IS WHAT BROKE THE GRID — 2026-09-02.
   The block above says the description's line clamp "stops any single card from setting a
   height nobody else needs". That was only ever half true: the clamp was on .uc-desc and the
   BOLD HEADING above it had none. Kit `name` had meanwhile drifted from "Document Q&A" to a
   933-character brief (141 kits over 60 chars, 96 over 100), so one card set a ~1000px height
   and `grid-auto-rows:1fr` handed it to ALL 265 tiles — on mobile, one column, every tile a
   screen tall with a void under two lines of text. Operator screenshot, 2026-09-02.
   THIS CLAMP IS THE GUARD, NOT THE FIX. The names themselves are being shortened; this only
   guarantees no future one can blow up every other card again. */
.uc-name{font-weight:700;font-size:13.5px;margin-top:3px;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.uc-desc{font-size:12.5px;line-height:1.5;color:var(--text-secondary);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}
/* margin-top:auto, not 8px — the pill itself is unchanged (it is the stat pill that shipped this
   morning); what changed is that it is now pushed to the bottom of an equal-height card. */
.uc-stat{margin-top:auto;align-self:flex-start;font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.08em;text-transform:uppercase;color:var(--c-green,#1c7a4b);
  border:1px solid currentColor;border-radius:999px;padding:4px 8px}
/* The three measured facts the stat pill above does not carry (coverage, p50, named failures) —
   restored 2026-08-19, see the dated comment in home_usecases_html(). Sits directly under the
   pill: both have margin-top:auto pull them to the card's bottom edge as one group. */
.uc-foot{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border)}
.uc-m{font:600 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.04em;
  color:var(--muted);border:1px solid var(--border);border-radius:6px;padding:4px 6px;white-space:nowrap}
.uc-m b{color:var(--text-primary);font-weight:700}

/* ── THE VERTICAL FACET BAR ──────────────────────────────────────────────────
   Operator direction 2026-08-18, variant V1 modification (a) ("the group should be in Verb not
   shape"), re-axed to vertical on 2026-08-20 operator direction ("group every use case based on
   the vertical"). The chips, their labels and every count are emitted by generate.py from
   build/facts/verticals.py — nothing here knows what a vertical is, and nothing here counts
   anything. The live count sits INSIDE this bar on purpose: a reader who has just narrowed 22 to
   4 should not have to scroll to the end of the grid to find out that the filter worked. */
/* ⚠︎ `.uc-fbar` IS THE FLEX PARENT `.uc-fsearch`/`.uc-facets` WERE ALWAYS WRITTEN FOR AND NEVER
   HAD — added 2026-08-19. Without it the two rendered as stacked block rows with ~0px between
   them regardless of the comment below; `.uc-facets` no longer carries its own bottom margin so
   the two are not stacked. */
/* ⚑ ONE GAP FROM THE RAIL TO THE TILES, ON EVERY PAGE — 2026-08-30, operator: the spacing
   "is really good in the homepage" and drifts elsewhere, so the homepage is the standard and
   this token is it. It is a token rather than a number because the rail is rendered by one
   component on several pages, and the last time this spacing was 'fixed' it was fixed on one
   of them. Row 2 (.uc-facets2) is display:none when hidden, so a page showing it and a page
   hiding it now meet the grid at the same distance. */
/* ⚠︎ P4, 2026-09-05 — THE RAIL GAP WAS BEING SPENT INSIDE THE RAIL. `--rail-gap` was put on
   .uc-fbar on 2026-08-30 as "ONE GAP FROM THE RAIL TO THE TILES", and it was that while .uc-fbar
   WAS the whole rail. Row 2 (2026-08-24) and row 3 (2026-09-05) were then added as SIBLINGS of
   .uc-fbar, not children — so the token stopped separating the rail from the grid and started
   separating row 1 from row 3, and the last chip row met the first card at a measured 0px.
   Measured, not eyeballed, against the painted boxes: fbar bottom 466.1 -> row 3 top 480.1 was
   exactly the 14px token, while row 3 bottom 515.1 -> grid top 515.1 was 0. It also made the two
   dashed rules inconsistent — row 2 sat 14px under the bar, row 3 sat 10px under row 2.
   The gap now hangs off the GRID, which is the one element that is always last no matter how
   many rows the rail grows. That is what makes this structural rather than another number. */
.uc-fbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0}
[data-uc-grid]{margin-top:var(--rail-gap)}
.uc-facets{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
/* ⚑ ROW 2 — 2026-08-24. Ships hidden and is revealed only once a group is picked; the dashed rule
   says it is a narrowing of the row above it, not a second independent filter. A group chip is
   weighted slightly heavier than a vertical chip because it is the coarser choice and the one a
   reader makes first. */
/* ⚠︎ THE [hidden] ATTRIBUTE LOSES TO .uc-facets{display:flex} ON SPECIFICITY, so without this
   rule row 2 renders at rest as an empty strip with a border and 20px of padding. It is invisible
   to any test that asks the ELEMENT whether it is hidden — `el.hidden` is still true — and only
   shows up when you look at the painted box or at what sits under a click. The same trap took the
   admin console's activation switch out of reach behind an overlapping header. */
.uc-facets2[hidden]{display:none}
.uc-facets2{margin-top:10px;padding-top:10px;border-top:1px dashed var(--border)}
.uc-fg{font-weight:650}
.uc-fg.on{border-color:var(--accent-2);color:var(--accent-2)}
.uc-fg.on b{color:var(--accent-2)}
/* The catalogue's own search — kits only, never problems. It sits on the same row as the verb
   chips because they AND together and a reader should see both controls at once; on a phone it
   takes the full width and the chips wrap under it. */
.uc-fsearch{position:relative;flex:1 1 240px;min-width:200px}
.uc-fsi{position:absolute;left:11px;top:50%;transform:translateY(-50%);font-size:13px;
  color:var(--muted);pointer-events:none}
.uc-fq{width:100%;padding:8px 12px 8px 30px;border:1px solid var(--border);border-radius:999px;
  background:var(--surface-1);color:var(--text-primary);font:500 13px/1.2 inherit;
  -webkit-appearance:none;appearance:none}
.uc-fq::placeholder{color:var(--muted)}
.uc-fq:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 18%,transparent)}
@media(max-width:640px){.uc-fsearch{flex:1 1 100%;margin:0 0 8px}}
.uc-fk{font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.11em;
  text-transform:uppercase;color:var(--muted);margin-right:2px}
.uc-fc{font-family:var(--font-body);font-size:11.5px;font-weight:600;color:var(--text-secondary);
  background:var(--surface-2);border:1px solid var(--border);border-radius:999px;padding:4px 10px;
  cursor:pointer;transition:border-color .15s ease,color .15s ease}
.uc-fc:hover:not(:disabled){border-color:var(--border-strong);color:var(--text-primary)}
/* P3 — a chip that recounts to 0 for the current view is disabled, the same treatment
   .uc-mc:disabled already gives a modality no kit takes yet. Same look for the same
   meaning: this control would filter to an empty grid. palette.js never disables an
   "All" chip or the chip that is currently on, so there is always a way back out. */
.uc-fc:disabled{opacity:.42;cursor:default}
/* ── B8: THE INPUT-MODALITY ROW ON THE CATALOGUE — 2026-09-05 ──────────────────────────────
   Row 3 is orthogonal to the two industry rows and is ANDed with them. It reuses the .uc-fc
   pill geometry deliberately: a reader should not have to learn a second kind of chip to use
   a second axis. Only two things differ, and both carry meaning —
     · the row is always visible (row 2 appears only once a group is picked);
     · a modality no kit has yet ships DISABLED rather than omitted, so the axis tells the
       truth about its own values without offering a control that filters to an empty grid.
   Every colour is a token defined in this file; build/smoke/css_tokens.py fails the build on
   a var() with no definition and no fallback. */
.uc-facets3{display:flex;flex-wrap:wrap;align-items:center;gap:6px;
  margin-top:10px;padding-top:10px;border-top:1px dashed var(--border)}
.uc-mc{font-family:var(--font-body);font-size:11.5px;font-weight:600;color:var(--text-secondary);
  background:var(--surface-2);border:1px solid var(--border);border-radius:999px;padding:4px 10px;
  cursor:pointer;transition:border-color .15s ease,color .15s ease}
.uc-mc.on{border-color:var(--accent);color:var(--text-primary);
  background:color-mix(in srgb,var(--accent) 12%,transparent)}
.uc-mc:hover:not(:disabled){border-color:var(--border-strong);color:var(--text-primary)}
.uc-mc:disabled{opacity:.42;cursor:default}
/* The card's own input chip. Emitted ONLY for a non-text kit, so 305 text cards are unchanged. */
.uc-mod{align-self:flex-start;margin-top:6px;
  font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.09em;text-transform:uppercase;color:var(--text-primary);
  background:color-mix(in srgb,var(--accent) 14%,transparent);
  border:1px solid var(--accent);border-radius:999px;padding:3px 8px}
.uc-fc b{font-family:var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);font-size:10px;
  font-weight:700;color:var(--muted);margin-left:4px;font-variant-numeric:tabular-nums}
.uc-fc.on{border-color:var(--accent);color:var(--text-primary);
  background:color-mix(in srgb,var(--accent) 12%,transparent)}
.uc-fc.on b{color:var(--accent)}
.uc-fcount{margin-left:auto;font-size:11.5px;color:var(--text-secondary);font-variant-numeric:tabular-nums}
.uc-fcount b{color:var(--text-primary)}
.uc-fclear{font-family:var(--font-body);font-size:11.5px;font-weight:600;color:var(--accent);
  background:none;border:0;border-bottom:1px solid currentColor;padding:0 0 1px;cursor:pointer}
.uc-fempty{padding:14px 16px;margin:var(--rail-gap) 0 18px;border:1px dashed var(--border-strong);border-radius:12px;
  font-size:13px;color:var(--text-secondary)}
@media(max-width:640px){.uc-fcount{margin-left:0;width:100%;order:9}}

/* ── LEARN ROUTES — the "Where to start" landing and the nine route pages ──────
   Added 2026-08-10 to the approved wireframe
   (build/design/2026-08-10-learn-where-to-start-REDESIGN.html).

   Every rule here is scoped `lrt-` and built on the theme tokens, so it flips with
   the light toggle with no overrides. The route colour rides on --rc, set per route
   to a --c-* token on the page's own wrapper — the same idiom .lrn-hub-t uses for
   --gc, deliberately copied rather than reinvented.

   ⚑ THE ONE RULE WITH A REASON BEHIND IT, AND IT WAS WRONG ON THE FIRST RENDER.
   .lrt-allc is the escape hatch for a reader who does not want to answer "who are
   you", so the first draft hoisted it with `order:-1` on narrow — reasoning that a
   card sitting after three screens of role cards is not an escape hatch. Opening the
   page on a 390px viewport settled it: hoisting put the escape hatch ABOVE the h1,
   so a phone reader met "See all courses" before learning what the page was. It now
   flows in DOM order, which on narrow lands it exactly where it should be — after
   the lead, before the role cards, one thumb-scroll in and impossible to miss. */
.lrt-hero{display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap;margin-top:6px}
.lrt-hero-l{flex:1 1 320px;min-width:min(100%,320px)}
.lrt-hero h1{font-size:clamp(28px,4.2vw,44px);margin:2px 0 10px;line-height:1.08}
.lrt-hero .tagline{color:var(--text-secondary);font-size:16.5px;max-width:64ch;margin:0}
.lrt-eyebrow{font:700 10.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.14em;text-transform:uppercase;color:var(--rc,var(--accent));margin:0 0 8px}
.lrt-allc{flex:0 0 268px;max-width:100%;order:2;border:1px solid var(--border-strong);
  border-radius:13px;background:var(--surface-1);padding:15px 16px;box-shadow:var(--shadow-sm)}
@media(max-width:760px){.lrt-allc{flex:1 1 100%}}
.lrt-allc p{margin:0}
.lrt-allc-k{font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin-bottom:7px}
.lrt-allc-h{font-family:var(--font-display);font-weight:700;font-size:15.5px;
  color:var(--text-primary);margin-bottom:4px}
.lrt-allc-p{font-size:12.5px;color:var(--text-secondary);line-height:1.5;margin-bottom:11px}
.lrt-allc-btn{display:block;text-align:center;font-weight:700;font-size:13px;padding:10px;
  border-radius:9px;background:var(--accent);color:#fff;text-decoration:none}
.lrt-allc-btn:hover{filter:brightness(1.08)}
.lrt-allc-mini{display:flex;gap:5px;flex-wrap:wrap;margin-top:10px}
.lrt-mchip{font:600 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  color:var(--muted);border:1px solid var(--border);border-radius:999px;padding:5px 7px}

/* the picker */
.lrt-qhead{margin:6px 0 16px}
.lrt-qhead h2{font-family:var(--font-display);font-size:19px;margin:0 0 3px}
.lrt-qhead p{color:var(--muted);font-size:13px;margin:0}
.lrt-roles{display:grid;grid-template-columns:repeat(auto-fill,minmax(244px,1fr));gap:12px}
.lrt-role{display:flex;flex-direction:column;gap:5px;background:var(--surface-1);
  border:1px solid var(--border);border-top:3px solid var(--rc,var(--accent));border-radius:12px;
  padding:15px 16px;text-decoration:none;color:inherit;
  transition:border-color .15s ease,transform .15s ease,box-shadow .15s ease}
.lrt-role:hover{border-color:var(--rc,var(--accent));transform:translateY(-2px);
  box-shadow:var(--shadow-sm)}
.lrt-role-ic{font-size:21px;line-height:1}
.lrt-role-nm{font-family:var(--font-display);font-weight:700;font-size:15px;
  color:var(--text-primary);margin-top:6px}
.lrt-role-sb{font-size:12.5px;color:var(--muted);line-height:1.5}
.lrt-role-row{display:flex;gap:6px;flex-wrap:wrap;margin-top:9px}
.lrt-role-go{margin-top:9px;font:700 10.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.05em;color:var(--rc,var(--accent))}
.lrt-tchip{font:600 10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  border:1px solid var(--border);border-radius:999px;padding:5px 8px;color:var(--text-secondary);
  white-space:nowrap}
.lrt-tchip.goal{color:var(--rc,var(--accent));border-color:var(--rc,var(--accent))}

/* a route page */
.lrt-rmeta{display:flex;gap:7px;flex-wrap:wrap;margin:0 0 18px}
.lrt-lay{display:grid;grid-template-columns:214px minmax(0,1fr);gap:26px;align-items:start}
@media(max-width:860px){.lrt-lay{grid-template-columns:1fr}}
.lrt-rail{position:sticky;top:78px;align-self:start;border-left:1px solid var(--border);
  padding-left:15px}
@media(max-width:860px){.lrt-rail{position:static;border-left:0;padding-left:0;
  border-bottom:1px solid var(--border);padding-bottom:12px}}
.lrt-rail-l{font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.11em;text-transform:uppercase;color:var(--muted);margin:0 0 10px}
.lrt-rail a{display:block;font-size:12.5px;color:var(--text-secondary);text-decoration:none;
  padding:5px 0}
.lrt-rail a:hover{color:var(--rc,var(--accent))}
/* The wireframe drew an active rail row and the first build shipped none. Driven by the SAME
   scroll-spy the study-page rail uses (nav.js), generalised rather than copied. The left border
   sits on a transparent 2px so the row does not shift by two pixels as it becomes active. */
.lrt-rail a{border-left:2px solid transparent;margin-left:-15px;padding-left:13px}
.lrt-rail a.is-active{color:var(--rc,var(--accent));font-weight:700;
  border-left-color:var(--rc,var(--accent))}
.lrt-rail .lrt-rail-o{margin-top:10px;color:var(--muted);font-weight:600}
.lrt-ph{border:1px solid var(--border);border-radius:13px;background:var(--surface-1);
  margin:0 0 14px;overflow:hidden}
.lrt-ph-h{display:flex;gap:12px;align-items:baseline;padding:13px 17px;background:var(--surface-3);
  border-bottom:1px solid var(--border);flex-wrap:wrap}
.lrt-ph-n{font:700 10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.1em;text-transform:uppercase;color:var(--rc,var(--accent));white-space:nowrap}
.lrt-ph-t{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--text-primary)}
.lrt-ph-w{margin-left:auto;font:11px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  color:var(--muted)}
.lrt-ph-b{padding:4px 17px 15px}
.lrt-stg{padding:14px 0 4px;border-top:1px solid var(--border)}
.lrt-stg:first-child{border-top:0}
.lrt-stg-h{display:flex;gap:10px;align-items:center;margin:0 0 3px}
.lrt-stg-n{flex:none;width:22px;height:22px;border-radius:50%;background:var(--rc,var(--accent));
  color:#fff;font:800 11px/22px var(--font-body);text-align:center}
.lrt-stg-t{font-family:var(--font-display);font-weight:600;font-size:14.5px;
  color:var(--text-primary)}
.lrt-stg-b{margin:0 0 11px 32px;font-size:12.5px;color:var(--muted);line-height:1.5}
.lrt-lbl{display:flex;align-items:center;gap:7px;margin:0 0 7px 32px;
  font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.lrt-dot{width:7px;height:7px;border-radius:2px;flex:none}
.lrt-dot.read{background:var(--accent)}
.lrt-dot.study{background:var(--gold)}
.lrt-lks{display:flex;gap:7px;flex-wrap:wrap;margin:0 0 13px 32px}
.lrt-lk{font-weight:600;font-size:12px;border:1px solid var(--border);border-radius:8px;
  padding:7px 11px;background:var(--surface-2);text-decoration:none;line-height:1.35}
.lrt-lk.read{color:var(--accent)}
.lrt-lk.read:hover{border-color:var(--accent)}
.lrt-lk.study{color:var(--gold);border-color:color-mix(in srgb,var(--gold) 40%,transparent)}
.lrt-lk.study:hover{border-color:var(--gold)}
.lrt-lab{font:700 8.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.09em;text-transform:uppercase;border:1px solid currentColor;border-radius:4px;
  padding:2px 4px;margin-left:4px;vertical-align:1px}
.lrt-done{display:flex;gap:10px;align-items:baseline;margin:0 0 4px 32px;padding-top:10px;
  border-top:1px dashed var(--border);font-size:12.5px;color:var(--text-secondary);flex-wrap:wrap}
.lrt-done b{color:var(--c-green);font:700 9.5px/1.6 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.08em;text-transform:uppercase;white-space:nowrap}
.lrt-dod{margin:20px 0 0;border-top:1px solid var(--border);padding:16px 0 0}
.lrt-dod-h{font:700 10.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin:0 0 11px}
.lrt-dod ul{margin:0;padding:0;list-style:none;display:grid;gap:9px}
.lrt-dod li{position:relative;padding-left:22px;font-size:13.5px;color:var(--text-secondary)}
.lrt-dod li::before{content:"";position:absolute;left:2px;top:7px;width:9px;height:9px;
  border-radius:2px;background:var(--rc,var(--accent));transform:rotate(45deg)}
.lrt-foot{margin:20px 0 0;padding:15px 17px;border:1px solid var(--border);border-radius:12px;
  background:var(--surface-1)}
.lrt-foot p{margin:0;font-size:13.5px;color:var(--text-secondary);line-height:1.6}
.lrt-foot-l{display:flex;gap:8px;flex-wrap:wrap;margin-top:11px!important}
.lrt-foot-l a{font-weight:600;font-size:12px;color:var(--accent);border:1px solid var(--border);
  border-radius:8px;padding:8px 11px;text-decoration:none}
.lrt-foot-l a:hover{border-color:var(--accent)}
.lrt-others{margin:16px 0 0}
.lrt-others p{margin:0;display:flex;gap:7px;flex-wrap:wrap}
.lrt-others-h{display:block!important;font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.11em;text-transform:uppercase;color:var(--muted);margin:0 0 9px!important}
.lrt-oth{font-weight:600;font-size:12px;color:var(--text-secondary);text-decoration:none;
  border:1px solid var(--border);border-left:3px solid var(--rc,var(--accent));border-radius:8px;
  padding:7px 10px;background:var(--surface-1)}
.lrt-oth:hover{color:var(--rc,var(--accent));border-color:var(--rc,var(--accent))}

/* The lesson plans a route draws on — added 2026-08-10 on operator direction, after measuring
   that 0 of 9 routes linked a single course index. Chips, not a list: they are peers you pick
   between, and the count is part of the label so a route cannot imply it covers a course it
   only touches. */
.lrt-lbl-p{font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.11em;text-transform:uppercase;color:var(--muted);margin:0 0 9px}
.lrt-plans{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 22px}
.lrt-plan{display:inline-flex;align-items:center;gap:8px;text-decoration:none;color:inherit;
  border:1px solid var(--border);border-left:3px solid var(--pc,var(--accent));border-radius:10px;
  background:var(--surface-1);padding:9px 12px;transition:border-color .15s ease,transform .15s ease}
.lrt-plan:hover{border-color:var(--pc,var(--accent));transform:translateY(-1px)}
.lrt-plan-ic{font-size:15px;line-height:1}
.lrt-plan-t{font-family:var(--font-display);font-weight:700;font-size:13px;color:var(--text-primary)}
.lrt-plan-n{font:600 10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  color:var(--pc,var(--accent));border:1px solid currentColor;border-radius:999px;padding:4px 7px}

/* ── THE PLATFORM SECTION INDEX — 2026-08-24 ──────────────────────────────────────────────────
   Operator, twice: clicking a Platform section must show that section's TILES. The first fix
   opened the section's first page; the second scrolled the homepage map. This is the page that
   actually answers it, and it deliberately reuses the kit grid's shape so the two indexes read
   as one system rather than two designs. */
.pf-bar{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 30px}
.pf-chip{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  font:600 12.5px/1 var(--sans,inherit);color:var(--text-secondary);
  background:var(--surface-2);border:1px solid var(--border);border-radius:999px;padding:8px 13px;
  transition:border-color .15s ease,color .15s ease,background .15s ease}
.pf-chip:hover{border-color:var(--gc,var(--accent));color:var(--text)}
.pf-chip.is-on{background:var(--gc,var(--accent));border-color:var(--gc,var(--accent));color:#fff}
.pf-n{font:700 10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);opacity:.75}
.pf-sec{margin:0 0 42px;scroll-margin-top:calc(var(--header-h) + 16px)}
.pf-sec[hidden]{display:none}
.pf-head{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:0 0 16px;
  padding-left:12px;border-left:3px solid var(--gc,var(--accent))}
.pf-head h2{margin:0;font-size:19px}
.pf-head p{margin:0;color:var(--text-secondary);font-size:13.5px;flex:1 1 260px}
.pf-count{font:700 10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.08em;text-transform:uppercase;color:var(--gc,var(--accent))}
/* auto-fill, not auto-fit: a section with one page keeps a card-width card rather than one
   stretched the full page width, which read as a broken layout on Reference. */
/* ⚑ `align-items:start` LIVED HERE AND CONTRADICTED THE LINE IT SAT ON, until 2026-09-17.
   `grid-auto-rows:1fr` makes every ROW TRACK the height of its tallest card; `align-items:start`
   then tells each card NOT to fill its track, so cards sized to their own content and a row came
   out ragged. Measured on pages/platform.html?section=Operate at 1600px: two rows with a 19px
   spread — a card needing a two-line title was 136px beside neighbours at 117px. The operator
   caught it on the live page ("why the tiles are different sizes"). Dropping the override lets
   `align-items` fall back to its default `stretch`, which is what `grid-auto-rows:1fr` was
   written to work with. Do not re-add it. */
.pf-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px;grid-auto-rows:1fr}
.pf-card{display:flex;flex-direction:column;gap:5px;min-height:104px;
  padding:14px 15px;border:1px solid var(--border);border-radius:12px;
  background:var(--surface-1);text-decoration:none;
  transition:border-color .15s ease,transform .15s ease,box-shadow .15s ease}
.pf-card:hover{border-color:var(--gc,var(--accent));transform:translateY(-1px);
  box-shadow:var(--shadow)}
.pf-t{font-weight:700;font-size:14px;color:var(--text)}
.pf-d{font-size:12.5px;line-height:1.5;color:var(--text-secondary);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}
.pf-f{margin-top:auto;padding-top:8px;font:700 9.5px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.08em;text-transform:uppercase;color:var(--gc,var(--accent))}
@media (max-width:560px){.pf-grid{grid-template-columns:1fr}}

/* ⚑ ANCHORS LAND UNDER THE STICKY HEADER WITHOUT THIS — measured 2026-08-24. .topnav is
   position:sticky at var(--header-h) (64px), and the ONLY scroll-margin rules on this site were
   the five .lrn-* / .deck / .pf-sec ones. Every other in-page anchor scrolled its target to y=0,
   i.e. underneath the header. The homepage map ids are dead now (the Platform rows go to
   pages/platform.html?section=), but #use-cases is a live fragment and a stranger may have
   bookmarked a #map-* one, so they are all given the offset rather than left as a trap. */
.maplayer,.mapside-row,#map,#whats-in,#use-cases{scroll-margin-top:calc(var(--header-h) + 16px)}

/* ============================================================================
   THE RIBBON LEDGER (pages/kits/*-02-architecture.html) -- added 2026-08-28.
   "The ribbon keeps the shape, the ledger keeps the words." The flow figure is an <img> drawn
   at the kit column's measured width (figures.RIBBON_COLUMN_PX); every sub line, failure and
   report field is in the .rl ledger under it, one row per station, joined to the picture by
   row id (a pill's .figmap-hit points at #<flow_key>; the row links to its lens).
   Every colour is a site token, except the palette the figure itself is drawn in: the number
   badges, swatches and bullets carry FLOW_PALETTE's (light, dark) pair inline as --l/--d and
   .rl-tone picks one per theme, so the ledger cannot disagree with the picture about a hue.
   ============================================================================ */
.rl-tone{background:var(--d)}
html[data-theme="light"] .rl-tone{background:var(--l)}
/* The figure card: a scroller around the picture, a legend and the hint under it. The figmap
   never drops below 900px (0.82x of natural, 10.7px station names); narrower columns scroll. */
.rl-fig{container-type:inline-size}
.rl-scrollwrap{position:relative}
.rl-scroll{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;
  padding-bottom:34px;margin-bottom:-34px}   /* room for a hit's tooltip below the canvas */
.rl-scroll .figmap{min-width:900px}
/* The affordance for a scrolling figure: a right-edge fade while there is more to the right,
   and a "scroll -> N stations" hint. Both only when the card is narrower than the floor. */
.rl-scrollwrap::after{content:"";position:absolute;top:0;right:0;bottom:34px;width:56px;
  pointer-events:none;opacity:0;transition:opacity .2s;
  background:linear-gradient(to right,transparent,var(--figure-bg))}
.content p.rl-hint,.rl-fig p.rl-hint{display:none;margin:10px auto 0;font:600 11.5px/1 var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.04em;color:var(--muted);border:1px dashed var(--border-strong);border-radius:999px;
  padding:6px 11px;width:max-content;max-width:100%}
@container (max-width:899px){
  .rl-scrollwrap:not(.rl-at-end)::after{opacity:1}
  .content p.rl-hint,.rl-fig p.rl-hint{display:block}
}
.rl-legend{display:flex;flex-wrap:wrap;justify-content:center;gap:6px 22px;margin:12px 0 0;padding:0;
  list-style:none;font-size:12.5px;line-height:1.5;color:var(--text-secondary);text-align:left}
.rl-legend li{display:inline-flex;align-items:center;gap:7px}
.rl-sw{width:14px;height:8px;border-radius:4px;display:inline-block;flex:none;opacity:var(--od)}
html[data-theme="light"] .rl-sw{opacity:var(--ol)}
.rl-hk{width:14px;height:6px;border-radius:3px;background:var(--c-red);display:inline-block;flex:none}
.rl-nb{font:700 10px var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);color:var(--surface-1);
  border-radius:999px;padding:2px 6px}
.rl-fig .figcap{text-align:center}
.figmap-hit.is-hot{background:color-mix(in srgb,var(--c-teal) 14%,transparent);outline-color:var(--c-teal)}
/* The ledger itself. */
.rl{margin:18px 0 0;text-align:left}
.rl-rows{list-style:none;margin:0;padding:0;border:1px solid var(--border);border-radius:14px;
  background:var(--surface-1);overflow:hidden}
.rl-row{display:grid;grid-template-columns:272px minmax(0,1fr);gap:4px 28px;padding:18px 22px 18px 18px;
  border-bottom:1px solid var(--border);scroll-margin-top:calc(var(--header-h) + 16px);transition:background .25s}
.rl-row:last-child{border-bottom:0}
.rl-row:target,.rl-row.is-hot{background:color-mix(in srgb,var(--c-teal) 8%,var(--surface-1));
  box-shadow:inset 3px 0 0 var(--c-teal)}
.rl-ln,.rl-lb{min-width:0}
.rl-num{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:24px;padding:0 6px;
  border-radius:999px;color:var(--surface-1);font:700 11.5px var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  font-variant-numeric:tabular-nums}
.rl-fail .rl-num{box-shadow:0 0 0 2px var(--surface-1),0 0 0 4px var(--c-red)}
.rl-src .rl-num{background:transparent;color:var(--muted);font-size:16px}
.rl-name{display:block;font-size:15.5px;font-weight:650;margin:6px 0 4px;line-height:1.3;color:var(--text-primary)}
.rl-lens{font-size:12.5px;font-weight:600;color:var(--c-teal);text-decoration:none}
.rl-lens:hover{text-decoration:underline}
.rl-none{font-size:12.5px;color:var(--muted);font-style:italic}
.rl-sub{margin:0;padding:0;list-style:none;display:grid;gap:6px}
.rl-sub li{font-size:14px;color:var(--text-secondary);line-height:1.5;padding-left:16px;position:relative;margin:0}
.rl-sub li::before{content:"";position:absolute;left:0;top:.6em;width:7px;height:7px;border-radius:50%;
  background:var(--sd)}
html[data-theme="light"] .rl-sub li::before{background:var(--sl)}
.rl p.rl-in{margin:0 0 8px;font-size:13px;line-height:1.5;font-style:italic;color:var(--text-secondary)}
.rl-in span{font-style:normal;font:700 10.5px var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-right:6px}
.rl p.rl-meter{margin:10px 0 0;font-size:12.5px;line-height:1.5;color:var(--text-secondary);display:flex;
  align-items:center;gap:10px;flex-wrap:wrap}
.rl-mono{font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);border:1px dashed var(--border-strong);
  border-radius:7px;padding:4px 10px}
.rl-fail-box{margin-top:12px;padding:11px 14px 12px;border:1px solid color-mix(in srgb,var(--c-red) 38%,transparent);
  border-left:3px solid var(--c-red);border-radius:10px;background:color-mix(in srgb,var(--c-red) 7%,var(--surface-1));
  font-size:14px;line-height:1.5;color:var(--text-primary)}
.rl-fk{display:block;font:800 10.5px var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.08em;
  text-transform:uppercase;color:var(--c-red);margin-bottom:5px}
.rl-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
.rl-chip{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;border:1px solid var(--border);
  border-radius:999px;padding:3px 9px 3px 6px;background:var(--surface-2)}
.rl-chip b{font-weight:600;font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace)}
.rl-cnt{color:var(--muted);font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace)}
.rl p.rl-srct{margin:4px 0 0;font-size:14px;line-height:1.5;color:var(--text-secondary)}
.rl p.rl-rhead{margin:4px 0 10px;font:700 10.5px var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.rl-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;grid-auto-rows:1fr}
.rl-tile{border:1px solid var(--border);border-radius:10px;padding:10px 12px;background:var(--surface-2)}
.rl-tile b{display:block;font-family:var(--font-display);font-size:24px;font-weight:700;letter-spacing:-.02em;
  line-height:1.1;font-variant-numeric:tabular-nums;color:var(--text-primary);overflow-wrap:anywhere}
.rl-tile-line b{font-size:15px;font-weight:600;line-height:1.35;letter-spacing:0}
.rl-tile span{display:block;font-size:12px;color:var(--muted);margin-top:4px;line-height:1.35}
.rl-foot{margin-top:22px}
.rl .rl-foot p{font-size:14px;line-height:1.6;color:var(--text-secondary);margin:0 0 10px;max-width:92ch}
@media (max-width:760px){
  .rl-row{grid-template-columns:1fr;gap:10px;padding:14px}
  .rl-tiles{grid-template-columns:1fr 1fr}
  .rl-tile b{font-size:20px}
}

/* ============================================================ CORPUS SAMPLE + PRESENTER ====
   Added 2026-08-29, with the private-repo rewording. Two surfaces, one cause: the kits repo
   went private, so "Browse the corpus" and "Read the whole file on GitHub" pointed at 404s.
   The sample renders the input HERE instead of sending the reader away; the presenter strip
   gives the operator the links that still work FOR HIM, and nobody else. */

/* One real corpus file, inside .arch under the swap line. It is a specimen, not a code block,
   so it is tinted with --c-teal rather than borrowing .codebox's chrome — a reader should not
   mistake the input for the implementation. */
.cs{margin-top:14px;border:1px solid var(--border-strong);border-radius:11px;
  background:var(--surface-2);overflow:hidden}
.cs-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding:9px 13px;border-bottom:1px solid var(--border);
  background:color-mix(in srgb,var(--c-teal) 9%,transparent)}
.cs-t{font:700 10.5px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.08em;
  color:var(--text-secondary)}
.cs-f{font:600 10.5px/1 var(--font-mono,ui-monospace,monospace);color:var(--muted)}
/* Capped and scrollable: a 56-pack corpus must not turn the page into the corpus. */
.cs-b{margin:0;padding:12px 14px;max-height:340px;overflow:auto;background:none;border:0}
.cs-b code{font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);
  font-size:11.5px;line-height:1.55;color:var(--text-secondary);white-space:pre;display:block}
.cs-more{margin:0;padding:9px 13px;border-top:1px solid var(--border);
  font-size:11.5px;color:var(--muted);background:color-mix(in srgb,var(--c-orange) 6%,transparent)}

/* ⚑ THE KIT PAGE-HEAD ROW — UID PLATE LEFT, PRESENTER RAIL RIGHT. Operator, 2026-08-29:
   "the UC number banner on the left, and those 4 admin button on the right top on every use
   cases". Both are DERIVED — the plate from the spec's own `uid`, the rail from the kit's slug
   and folder — so neither can drift from the case number the console, the Drive folders and the
   operator's own sentence all use. Declared in mcp/standards/use_case.py (KIT_HEAD) and gated,
   so every future kit inherits it rather than remembering it.
   The row degrades to a plain column on narrow screens: the plate stays above the title, the
   rail wraps under it, and neither ever overlaps the h1. */
.kh-row{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap}
.kh-main{flex:1 1 380px;min-width:0}
/* align-self:center — operator, 2026-09-26: the plate sat against the breadcrumb; it now centres
   between the breadcrumb and the header's bottom rule, beside the title block. */
.kh-uid{flex:none;display:flex;flex-direction:column;gap:3px;align-items:flex-start;align-self:center;
  padding:11px 15px 12px;border-radius:12px;
  background:color-mix(in srgb,var(--gc,var(--accent)) 17%,var(--surface-1));
  border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 46%,var(--border-strong));
  border-left:4px solid var(--gc,var(--accent))}
.kh-uid-k{font:700 9.5px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.15em;
  text-transform:uppercase;color:var(--text-secondary)}
.kh-uid-n{font:800 clamp(22px,2.7vw,30px)/1 var(--font-mono,ui-monospace,monospace);
  letter-spacing:.01em;color:var(--text-primary)}
a.kh-uid{text-decoration:none;color:inherit;transition:transform .15s,border-color .15s,box-shadow .15s}
a.kh-uid:hover{transform:translateY(-1px);border-color:var(--gc,var(--accent));box-shadow:0 6px 16px -10px var(--gc,var(--accent))}
a.kh-uid:focus-visible{outline:2px solid var(--gc,var(--accent));outline-offset:3px}
@media(max-width:720px){.kh-uid{padding:8px 12px 9px;align-self:flex-start}.kh-uid-n{font-size:20px}}

/* The presenter rail — TOP-RIGHT OF THE PAGE-HEAD (2026-08-29). It was a docked bar (Option A),
   then an in-column strip (Option B); it is now a compact 2x2 of buttons opposite the UID plate,
   present on EVERY panel so it survives a tab click mid-demo. Gold, because gold is already this
   site's "operator surface" token and nothing else on a kit page uses it.
   `hidden` in the markup; nav.js reveals it only after /api/me answers isAdmin. */
.pres[hidden]{display:none}
/* ⚑ IN THE READING COLUMN, NOT DOCKED — Option B, 2026-08-29. It was `position:fixed` at the
   foot of the window; it now sits under the kit title and scrolls away with the page. The old
   form was always reachable and never in the way, but it could not be seen in a full-page
   capture and the operator looked for it under the title, which is where a presenter's own eye
   goes. No `has-presenter` body padding is needed any more: an in-flow element makes its own
   room, and the rule that reserved 88px at the bottom of every kit page is gone with it. */
/* One column since the dismiss button went (2026-08-29). It was a two-column header row only
   so the × could sit opposite the label; with nothing to sit opposite, a second track just made
   the label stretch. */
.pres{flex:none;margin-left:auto;display:grid;gap:8px;
  padding:10px 12px 11px;border-radius:11px;
  background:var(--surface-1);
  border:1px solid var(--border-strong);
  border-left:3px solid var(--gold)}
.pres-l{display:inline-flex;align-items:center;gap:8px;flex:none;justify-self:start;
  font:700 10px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.13em;
  text-transform:uppercase;color:var(--gold);
  border:1px solid var(--gold);border-radius:999px;padding:6px 11px}
.pres-links{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.pres-links a{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  text-decoration:none;white-space:nowrap;
  font:600 12.5px/1 var(--font-body,inherit);color:var(--text-primary);
  background:var(--surface-2);border:1px solid var(--border-strong);
  border-radius:9px;padding:9px 12px}
.pres-links a:hover{border-color:var(--accent);color:var(--accent)}
.pres-links a:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.pres-n{grid-column:1 / -1;font-size:11px;color:var(--muted);max-width:26ch}
@media(max-width:900px){.pres{margin-left:0}}
@media(max-width:720px){.pres-n{display:none}}

/* The social row in the footer base — added 2026-08-29. Sits between the copyright and the
   build note, wraps on narrow screens, and stays quiet: these are wayfinding, not calls to
   action, so they take --muted until hovered. */
/* The social row is MARKS, not words — operator, 2026-09-17. Each <a> is still a real link with
   its own href; what changed is what it draws. The name is never deleted, only hidden: it stays in
   aria-label, in title, and in .foot-social-name, which a screen reader reads and in-page search
   finds. An icon-only link with no accessible name announces itself as "link", which is the single
   most common way a row like this breaks.
   ⚠︎ 44px IS THE TOUCH TARGET AND IT IS WHY THE BOX IS BIGGER THAN THE GLYPH. The mark is 18px;
   the tappable square around it is 44. Sizing the <a> to the glyph is how an icon row becomes
   unusable on a phone while looking perfect on a desktop. */
.foot-social{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-left:-10px}
.foot-social a{color:var(--muted);text-decoration:none;font-size:12.5px;
  display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;border-radius:8px;transition:color .14s ease,background .14s ease}
.foot-social a:hover{color:var(--text-primary);text-decoration:none;background:var(--surface-2,rgba(128,128,128,.12))}
.foot-social a:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:8px}
.foot-social-ico{display:block}
/* visually hidden, still announced and still findable by the browser's own find-in-page */
.foot-social-name{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
/* an account with no mark drawn falls back to its name, visible — never a blank square */
.foot-social-name--shown{position:static;width:auto;height:auto;margin:0;overflow:visible;
  clip:auto;clip-path:none;white-space:nowrap}
.foot-social a:has(.foot-social-name--shown){width:auto;padding:0 10px}
@media(max-width:640px){.foot-social{gap:2px;margin-left:-8px}.foot-social a{width:42px;height:42px}}

/* ══ THE HOMEPAGE INDEX HERO — approved 2026-08-30 ═══════════════════════════════════════════
   The 196-tile grid came off the front door; the vertical index and two marquee bands replaced
   it. Both bands are aria-hidden and duplicated in the markup — the duplicate is what makes the
   -50% translate loop seamless — so a screen reader is never read the same chip twice, and the
   real content is the index between them, which is links.
   ⚠︎ MOTION IS OPT-OUT, NOT DECORATION-ONLY. prefers-reduced-motion stops both tracks AND drops
   them to a wrapped static row, because a paused marquee at translateX(0) hides everything past
   the fold of the strip. */
.hb{border-top:1px solid var(--border);border-bottom:1px solid var(--border);
  background:var(--surface-2);overflow:hidden;margin:26px 0 0}
.hb + .hb{margin-top:0;border-top:0}
.hb-lab{display:flex;align-items:center;gap:9px;padding:10px 24px 0;
  font:700 9.5px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.15em;
  text-transform:uppercase;color:var(--muted)}
.hb-live{width:7px;height:7px;border-radius:50%;background:var(--c-green);flex:none;
  animation:hb-pulse 2.4s ease-in-out infinite}
@keyframes hb-pulse{0%,100%{opacity:1}50%{opacity:.35}}
.hb-track{overflow:hidden;padding:10px 0 13px}
.hb-in{display:flex;gap:10px;width:max-content;animation:hb-mq 52s linear infinite}
.hb-in.rev{animation:hb-mq2 58s linear infinite}
@keyframes hb-mq{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@keyframes hb-mq2{from{transform:translateX(-50%)}to{transform:translateX(0)}}
.hb-chip{display:inline-flex;align-items:center;gap:9px;background:var(--surface-1);
  border:1px solid var(--border);border-radius:999px;padding:7px 14px;font-size:12.5px;
  color:var(--text-secondary);white-space:nowrap}
.hb-chip i{font-style:normal;font:700 10.5px/1 var(--font-mono,ui-monospace,monospace);
  color:var(--accent);letter-spacing:.04em}
.hb-chip.news i{color:var(--c-amber,#d9a441)}
@media (prefers-reduced-motion:reduce){
  .hb-in,.hb-in.rev{animation:none;flex-wrap:wrap;width:auto;padding:0 24px}
  .hb-live{animation:none}
}
.hix-h{display:flex;justify-content:space-between;align-items:baseline;gap:14px;flex-wrap:wrap;
  margin:0 0 10px}
.hix-h h3{margin:0;font:700 10.5px/1 var(--font-mono,ui-monospace,monospace);letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.hix-h span{font-size:12.5px;color:var(--muted)}
.hix-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(152px,1fr));gap:7px;
  grid-auto-rows:1fr;margin:0 0 4px}
.hix{background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:9px 11px;
  display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-size:12.5px;
  color:var(--text-secondary);text-decoration:none;height:100%;
  transition:border-color .15s ease,transform .15s ease}
.hix:hover{border-color:var(--accent);color:var(--text-primary);transform:translateY(-1px)}
.hix b{font:700 12px/1 var(--font-mono,ui-monospace,monospace);color:var(--accent);
  font-variant-numeric:tabular-nums}

/* ===== The PAGE never scrolls sideways, at any width; wide content scrolls inside its own box =====
   Measured 2026-09-16 over every panel of every kit, switching panels by hash in headless Chrome.
   At 390px: 693 of 8,773 panels in 315 kits scrolled the whole page sideways. At 1440px: 174 panels
   in 121 kits did — chat-intake's #eval-slot-exact was 10,298px wide on a desktop.
   626 of the phone cases and all 174 desktop ones were one rule — `.article code{white-space:nowrap}`
   holding a long span (a command line, a snake_case field, a whole "the formula" sentence) on one
   unbreakable line. The two #threat panels (estoppel-package, oos-evidence) looked like the rail
   and were not: hiding the rail only gave the column more room; the element past the edge was a
   nowrap attack-wording <code> in the prose. So inline code wraps at every width, and breaks inside
   a token only when nothing else fits. A short token still reads as one piece: it wraps as a whole
   at its spaces first. Code inside <pre> is untouched, and code inside a table cell keeps nowrap —
   the table already scrolls inside its own .tbl-wrap, and a token broken mid-word there would
   squeeze the columns instead (326 table widths re-measured identical at 390 and 1440).
   The other 67 phone cases were prose with NO break opportunity at all — a comma-joined case list,
   a pipe-joined CLI flag set, a long run id — so body text breaks a word only when the word alone
   is wider than the line. break-word, not anywhere: it does not shrink min-content, so tables keep
   their width and scroll in their box rather than collapsing. */
.article,.kit-panel{overflow-wrap:break-word}
.article :not(pre)>code,.kit-panel :not(pre)>code{white-space:normal;overflow-wrap:anywhere}
.article td code,.article th code,.kit-panel td code,.kit-panel th code{white-space:nowrap;overflow-wrap:normal}

/* ── 404 ────────────────────────────────────────────────────────────────────────────────────
   `404.html`, emitted by generate.py's not_found_html(). The page does NOT load nav.js (it is
   served at every depth the site has, and nav.js builds links from a fixed per-page prefix), so
   it hand-rolls a header from .topnav/.brand/.seg above and everything else is scoped .nf-*.
   Nothing here leaks: every selector below is under .nf-body or .nf-*. */
.nf-main{padding:clamp(48px,9vh,96px) 24px 96px}
.nf-code{margin:0;font:700 11px/1 var(--font-body);letter-spacing:.14em;text-transform:uppercase;
  color:var(--gold)}
.nf-h1{margin:14px 0 0;font-size:clamp(30px,5.2vw,48px);line-height:1.1;text-wrap:balance}
.nf-lead{margin:14px 0 0;max-width:60ch;font-size:16.5px;color:var(--text-secondary)}
.nf-asked{margin:26px 0 0;font-size:13.5px;color:var(--muted)}
/* overflow-wrap, because the echoed path is whatever the reader typed and can be arbitrarily
   long — without it a pasted URL scrolls a phone sideways. */
.nf-asked code{font-size:13px;color:var(--text-primary);background:var(--surface-2);
  border:1px solid var(--border);border-radius:8px;padding:5px 10px;overflow-wrap:anywhere}
.nf-ways{display:grid;gap:12px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:34px;
  max-width:760px}
.nf-way{display:flex;flex-direction:column;gap:3px;text-decoration:none;padding:16px 18px;
  background:var(--surface-1);border:1px solid var(--border);border-radius:12px;
  transition:border-color .15s}
.nf-way:hover,.nf-way:focus-visible{border-color:var(--accent);outline:0}
.nf-way-t{font-family:var(--font-display);font-weight:700;font-size:15.5px;letter-spacing:-0.015em}
.nf-way-s{font-size:12.5px;color:var(--text-secondary)}
@media(max-width:640px){.nf-ways{grid-template-columns:1fr}}

/* ── THE USE-CASE FIRST PAGE — the kit page's `start` panel (kit_firstpage_panel in generate.py).
   Locked layout, operator 2026-09-25; the rules are mcp/standards/first_page.py. Full width, no
   rail. The crop is CSS over the kit's own screenshot: the frame takes the box's aspect ratio and
   the <img> is scaled and offset inside it, so nothing new is emitted and nothing is drawn on the
   picture — the numbers sit in the gutters beside it. */
.fp{--fp-inset:color-mix(in srgb,var(--text-primary) 4%,var(--surface-1));--fp-pin:var(--accent-fill);--fp-pin-ink:var(--accent-fill-ink);
  display:flex;flex-direction:column;gap:34px;padding-bottom:30px}
.fp section{margin:0}
.content .fp h2{font-size:22px;margin:0 0 6px}
.fp h3{margin:0 0 8px;font-size:17px;display:flex;gap:8px;align-items:center}
.fp-eyebrow{font:700 11px/1.4 var(--font-mono,ui-monospace,Menlo,monospace);letter-spacing:.14em;text-transform:uppercase;color:var(--gc,var(--accent));margin:0 0 6px!important}
.content .fp .fp-sub{margin:0 0 14px}
.fp-tags{display:flex;flex-wrap:wrap;gap:8px}
.fp-tag{font-size:13px;padding:5px 12px;border-radius:999px;border:1px solid var(--border-strong);color:var(--text-secondary)}
.fp-tag b{color:var(--text-primary)}
/* Before vs after — option D, the operator's pick (2026-09-26, build/design/2026-09-26-before-after-
   OPTIONS.html): today's manual process steps back (dashed, no fill, its steps NOT struck through since 2026-09-26, operator); the
   app is the one raised card, outlined in green and a little wider. Each side ends on its summary. */
.fp-vs{display:grid;grid-template-columns:.92fr 1.08fr;gap:14px;align-items:stretch}
.fp-col{border-radius:16px;padding:18px 20px;display:flex;flex-direction:column}
.fp-today{border:1px dashed var(--border-strong);color:var(--muted)}
.fp-app{background:var(--surface-1);border:1px solid color-mix(in srgb,var(--c-green) 55%,transparent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--c-green) 10%,transparent),var(--shadow-sm)}
.fp-mark{width:24px;height:24px;border-radius:7px;display:grid;place-items:center;font-size:13px}
.fp-today h3{color:var(--text-secondary)}
.fp-today .fp-mark,.fp-today .fp-i{color:var(--c-red)} .fp-app .fp-mark,.fp-app .fp-i{color:var(--c-green)}
.fp-row{display:grid;grid-template-columns:22px 1fr;gap:8px;padding:7px 0;font-size:14.5px;line-height:1.55}
.fp-today .fp-row{color:var(--muted)}
/* never struck through — operator, 2026-09-26: "I need not to strike the letters in Today Manual process" */
.fp-today .fp-row b{color:var(--text-secondary);font-weight:600}
.fp-app .fp-row{color:var(--text-secondary)} .fp-app .fp-row b{color:var(--text-primary)}
.fp-i{font:600 12px var(--font-mono,ui-monospace,Menlo,monospace)}
.fp-sum{margin-top:auto;padding-top:12px;border-top:1px solid var(--border);font-weight:600}
.fp-today .fp-sum{color:var(--c-red)} .fp-app .fp-sum{color:var(--c-green);font-size:16px}
.fp-row+.fp-sum,.fp-row:last-of-type{margin-bottom:10px}
.fp-frame{border-radius:14px;overflow:hidden;border:1px solid var(--border-strong);background:var(--fp-inset)}
.fp-tbar{display:flex;flex-wrap:wrap;gap:8px;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid var(--border)}
.fp-addr{font:500 12px var(--font-mono,ui-monospace,Menlo,monospace);color:var(--muted)}
.fp-ribbon{display:inline-flex;gap:8px;align-items:center;padding:4px 10px 4px 6px;border-radius:999px;background:var(--c-teal);color:var(--page);font-size:12px;font-weight:600}
.fp-ribbon i{font:700 10px var(--font-mono,ui-monospace,Menlo,monospace);font-style:normal;letter-spacing:.1em;text-transform:uppercase;background:color-mix(in srgb,var(--page) 22%,transparent);padding:2px 6px;border-radius:5px}
.fp-body{display:grid;grid-template-columns:44px minmax(0,1fr) 44px;justify-content:center}
.fp-gutter{position:relative;border-right:1px solid var(--border)}
.fp-gutter.fp-r{border-right:0;border-left:1px solid var(--border)}
.fp-gpin{position:absolute;left:50%;width:30px;height:30px;border-radius:50%;background:var(--fp-pin);color:var(--fp-pin-ink);display:grid;place-items:center;font-weight:700;font-size:13px;transform:translate(-50%,-50%)}
.fp-gpin::after{content:"";position:absolute;left:100%;top:50%;width:9px;border-top:2px solid var(--fp-pin)}
.fp-r .fp-gpin::after{left:auto;right:100%}
.fp-crop{position:relative;overflow:hidden}
/* ONE ANIMATED "SEE IT WORK" (operator, 2026-09-26): real-screen frames cropped, never drawn on; shown at the
   screens' CAPTURED size (.fp-awrap max-width, set per page), centred, never enlarged; rendered on the LAST
   frame so no-JS and reduced motion read correctly.
   ⛔ POSITION NEVER ANIMATES (2026-09-27): a transition on left/top/width slid the screen across every
   pixel BETWEEN two boxes, which no check reads — UC0001 swept past a withheld model name. Frames CUT;
   opacity (screen to screen), the reveal and the pin still move. build/firstpage/check.py enforces it. */
.fp-awrap{margin-inline:auto;width:100%}
.fp-anim{display:grid;grid-template-columns:44px minmax(0,1fr);gap:0}
.fp-astage{position:relative;overflow:hidden;width:100%;background:var(--surface-1)}
.fp-astage img{position:absolute;max-width:none;height:auto;display:block;opacity:0;
  transition:opacity .7s,clip-path 1.2s cubic-bezier(.3,.7,.2,1)}
.fp-astage img.on{opacity:1}
.fp-anim .fp-gpin{transition:top .9s cubic-bezier(.3,.7,.2,1),opacity .4s}
/* the number INSIDE the screen, on the thing the step names (first_page.py `pin_x`, operator 2026-09-27) */
.fp-anim.fp-inpic{grid-template-columns:minmax(0,1fr)}
.fp-inpic .fp-astage .fp-gpin{z-index:2;box-shadow:0 0 0 3px #fff,0 2px 8px rgba(0,0,0,.35);
  transition:top .9s cubic-bezier(.3,.7,.2,1),left .9s cubic-bezier(.3,.7,.2,1),opacity .4s}
.fp-inpic .fp-astage .fp-gpin::after{display:none}
.fp-anim .fp-gpin.off{opacity:0}
.fp-alegend{grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}
.fp-alegend li{transition:opacity .5s}
.fp-alegend.playing li{opacity:.4}.fp-alegend.playing li.on{opacity:1}
/* See it work on a dark stage — operator, 2026-09-26 ("your mix", layout options A + D). The band runs
   edge to edge behind the section; the content keeps the page's column. The side-by-side breakpoint is
   per kit (generate.py emits it beside the section), because it depends on the capture's own width. */
.fp-see{--stage:#141d33;position:relative;isolation:isolate;padding-block:34px}
html[data-theme="light"] .fp-see{--stage:#0b1220}
.fp-see::before{content:"";position:absolute;inset:0 calc(50% - 50vw);background:var(--stage);z-index:-1;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06),inset 0 -1px 0 rgba(255,255,255,.06)}
.content:has(.fp-see){overflow-x:clip}
.content .fp .fp-see h2{color:#f5f7fb} .content .fp .fp-see .fp-sub{color:#aab5cc} .fp-see .fp-eyebrow{color:#a99ff5}
.fp-see .fp-legend li{color:#aab5cc} .fp-see .fp-legend b{color:#fff}
.fp-see .fp-dots{background:#121a2b;border-color:rgba(255,255,255,.18)} .fp-see .fp-dots button{color:#aab5cc}
.fp-see .fp-dots button:hover{color:#fff} .fp-see .fp-dots button.on{color:var(--fp-pin-ink)}
.fp-seegrid>.fp-legend{max-width:var(--pic);margin-inline:auto}
.fp-actl{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:10px;margin-top:14px}
.fp-dots{display:inline-flex;gap:6px;padding:5px;border-radius:999px;border:1px solid var(--border-strong);background:var(--surface-1)}
.fp-dots button{width:32px;height:32px;border-radius:50%;border:0;background:none;color:var(--text-secondary);font:700 12px/1 var(--font-body,inherit);cursor:pointer;transition:background .2s,color .2s}
.fp-dots button:hover{color:var(--text-primary)}
.fp-dots button.on{background:var(--fp-pin);color:var(--fp-pin-ink)}
.fp-play{width:42px;height:42px;border-radius:50%;border:0;background:var(--fp-pin);color:var(--fp-pin-ink);display:grid;place-items:center;cursor:pointer;
  box-shadow:0 6px 18px -8px var(--fp-pin);transition:transform .15s}
.fp-play:hover{transform:translateY(-1px)} .fp-play svg{width:18px;height:18px}
.fp-dots button:focus-visible,.fp-play:focus-visible{outline:2px solid var(--gc,var(--accent));outline-offset:2px}
@media (prefers-reduced-motion:reduce){.fp-astage img,.fp-anim .fp-gpin,.fp-alegend li,.fp-dots button,.fp-play{transition:none}}
.fp-crop img{position:absolute;max-width:none;height:auto;display:block}
.fp-shot{position:relative;overflow:hidden;aspect-ratio:16/9;margin-inline:auto}
.fp-appcrop{margin-inline:auto}
.fp-shot img{width:100%;height:auto;display:block;max-width:none}
.fp-legend{list-style:none;margin:12px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.fp-legend li{display:grid;grid-template-columns:28px 1fr;gap:10px;color:var(--text-secondary);font-size:14.5px}
.fp-legend b{color:var(--text-primary)}
.fp-pin{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;background:var(--fp-pin);color:var(--fp-pin-ink);font-weight:700;font-size:12px}
.content .fp .fp-cap{font-size:14px;margin:10px 0 0}
/* For engineers — the build path (operator, 2026-09-26, option C+ of
   build/design/2026-09-26-firstpage-engineers-above-talk.html). Open, above the closing panel. */
.fp-eng{border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 45%,transparent);border-radius:20px;padding:26px 26px 22px;
  background:linear-gradient(180deg,color-mix(in srgb,var(--gc,var(--accent)) 10%,var(--surface-1)),var(--surface-1) 60%)}
.fp-eng-top{display:flex;flex-wrap:wrap;gap:16px 24px;justify-content:space-between;align-items:flex-start}
.content .fp .fp-eng h2{font-size:27px}
.content .fp .fp-eng .fp-sub{margin:0}
.fp-start{display:inline-flex;align-items:center;gap:12px;padding:11px 16px 11px 12px;border-radius:12px;background:var(--gc,var(--accent));color:var(--page);text-decoration:none;font-weight:700;white-space:nowrap}
.fp-start:focus-visible{outline:2px solid var(--text-primary);outline-offset:3px}
.fp-res{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin:18px 0 22px;border-block:1px solid var(--border-strong)}
.fp-res>div{padding:14px 16px 12px;border-left:1px solid var(--border)} .fp-res>div:first-child{border-left:0;padding-left:0}
.fp-res b{display:block;font:700 28px/1.1 var(--font-display,inherit);color:var(--c-green);font-variant-numeric:tabular-nums}
.fp-res span{display:block;font-size:13.5px;color:var(--text-primary);margin-top:2px}
.fp-res a{display:inline-block;margin-top:6px;font:600 11px var(--font-mono,ui-monospace,Menlo,monospace);color:var(--gc,var(--accent));text-decoration:none;letter-spacing:.04em}
.fp-res a:hover{text-decoration:underline}
.fp-pathk{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin:0 0 12px}
.content .fp .fp-pathk p{font:700 11px/1.4 var(--font-mono,ui-monospace,Menlo,monospace);letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:0}
.fp-pathk span{font-size:12.5px;color:var(--muted)}
.fp-path{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));row-gap:12px}
.fp-path a{position:relative;display:flex;flex-direction:column;gap:5px;padding:42px 12px 12px 0;color:var(--text-primary);text-decoration:none;border-radius:10px}
.fp-path a::before{content:"";position:absolute;top:14px;left:0;right:0;border-top:2px solid color-mix(in srgb,var(--gc,var(--accent)) 30%,transparent);transition:border-color .25s}
.fp-path a:nth-child(7n)::before,.fp-path a:last-child::before{right:auto;width:28px}
.fp-path a.lit::before{border-top-color:var(--gc,var(--accent))}
.fp-path i{position:absolute;top:0;left:0;width:30px;height:30px;border-radius:50%;background:color-mix(in srgb,var(--gc,var(--accent)) 16%,var(--surface-1));border:2px solid var(--gc,var(--accent));color:var(--text-primary);
  display:grid;place-items:center;font:700 11.5px var(--font-mono,ui-monospace,Menlo,monospace);font-style:normal;transition:background .2s,color .2s,transform .2s}
.fp-path a.lit i{background:var(--gc,var(--accent));color:var(--page)}
.fp-path a:hover i,.fp-path a:focus-visible i{transform:scale(1.12)}
.fp-path b{font:700 15px/1.25 var(--font-display,inherit)}
.fp-path b::after{content:" \2192";color:var(--gc,var(--accent));opacity:0;transition:opacity .2s}
.fp-path a:hover b::after,.fp-path a:focus-visible b::after{opacity:1}
.fp-path span{font-size:12.5px;color:var(--text-secondary);line-height:1.42}
.fp-path a:focus-visible{outline:2px solid var(--gc,var(--accent));outline-offset:2px}
.fp-path em{align-self:flex-start;font:600 10.5px var(--font-mono,ui-monospace,Menlo,monospace);font-style:normal;color:var(--gc,var(--accent));border:1px solid color-mix(in srgb,var(--gc,var(--accent)) 45%,transparent);border-radius:999px;padding:2px 8px;margin-top:2px}
.fp-kids{display:grid;grid-template-columns:auto 1fr;gap:8px 16px;align-items:center;margin-top:14px;padding:12px 14px;border-radius:12px;background:var(--fp-inset);border:1px dashed color-mix(in srgb,var(--gc,var(--accent)) 40%,transparent)}
.content .fp .fp-kids p{margin:0;font:700 11px/1.4 var(--font-mono,ui-monospace,Menlo,monospace);letter-spacing:.1em;text-transform:uppercase;color:var(--gc,var(--accent));white-space:nowrap}
.fp-kids nav{display:flex;flex-wrap:wrap;gap:6px}
.fp-kids a{font-size:12.5px;padding:5px 11px;border-radius:999px;border:1px solid var(--border-strong);color:var(--text-primary);text-decoration:none;background:var(--surface-1)}
.fp-kids a:hover,.fp-kids a:focus-visible{border-color:var(--gc,var(--accent));outline:none}
/* Make it yours + Talk to us — ONE closing panel (design 4, 2026-09-26). */
.fp-close{border-radius:20px;overflow:hidden;border:1px solid color-mix(in srgb,var(--accent) 40%,transparent);display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr)}
.fp-close-l{padding:26px;background:var(--surface-1)}
.fp-close-r{padding:26px;background:color-mix(in srgb,var(--accent) 14%,var(--surface-1));display:flex;flex-direction:column;justify-content:center;gap:12px}
.content .fp .fp-close-r h3{font:700 22px/1.25 var(--font-display,inherit);margin:0}
.content .fp .fp-close-r p{margin:0} .fp-close-r .fp-cta{align-self:flex-start}
.fp-yours{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 22px;margin-top:6px}
.fp-tile{display:grid;grid-template-columns:30px minmax(0,1fr);gap:10px}
.fp-tile b{display:block;font:700 15px var(--font-display,inherit);margin-bottom:2px;color:var(--text-primary)}
.fp-tile span{font-size:13.5px;color:var(--text-secondary)}
.fp-ico{width:22px;height:22px;margin-top:2px;stroke:var(--c-teal);fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.fp-cta{padding:10px 18px;border-radius:10px;background:var(--fp-pin);color:var(--fp-pin-ink);font-weight:600;text-decoration:none;white-space:nowrap}
.fp-cta:focus-visible{outline:2px solid var(--text-primary);outline-offset:3px}
@media (max-width:860px){.fp-legend{grid-template-columns:1fr}.fp-close{grid-template-columns:1fr}
  .fp-path{grid-template-columns:repeat(2,minmax(0,1fr))}.fp-path a::before{display:none}
  .fp-res{grid-template-columns:repeat(2,minmax(0,1fr))}.fp-res>div:nth-child(3){border-left:0;padding-left:0}.fp-kids{grid-template-columns:1fr}}
@media (max-width:560px){.fp-vs,.fp-yours{grid-template-columns:1fr}.fp-body{grid-template-columns:32px minmax(0,1fr) 32px!important}
  .fp-gpin{width:24px;height:24px;font-size:11px}.fp-eng{padding:18px 16px}.fp-close-l,.fp-close-r{padding:18px}}
@media (prefers-reduced-motion:reduce){.fp-path i,.fp-path a::before,.fp-path b::after{transition:none}.fp-path a:hover i{transform:none}}
