/* ============================================================
   The Whitley Brand System — components.css v0.1 (2026-07-26)
   Component Canon, rounds C1 + C1b. Requires tokens.css.
   Anatomy is constant across vibes; color flows from tokens.
   Naming: wb- = Whitley Brand.
   ============================================================ */

/* ---------- Tables (C1-Q1: role split) ----------
   Working table  → dashboards, interactive artifacts (hover, density)
   Reading table  → memos, reports, artifacts meant to be read
   Office (.docx/.pptx) keeps the banded anatomy via theme.yaml.   */
.wb-table-wrap { overflow-x: auto; }
table.wb-table { border-collapse: collapse; width: 100%; font-size: 0.86rem; font-family: var(--font-sans); }
.wb-table caption { caption-side: top; text-align: left; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-soft); padding-bottom: 8px; }
.wb-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.wb-table .pos { color: var(--chart-positive, var(--accent)); }
.wb-table .neg { color: var(--negative, #C0302B); }
/* Row-key emphasis is OPT-IN (.key), not automatic — pending the C2
   emphasis-hierarchy decision, do not blanket-bold first columns. */
.wb-table td.key { font-weight: 600; }
/* Gutters (Round P, 2026-07-28): base gutter 16px working / 24px reading;
   an OPPOSED-ALIGNMENT boundary (right-aligned .num followed by a
   left-aligned column — the case that collides) gets DOUBLE: 32px / 40px.
   Whitespace carries the separation; no vertical rules. */
.wb-table th.num:has(+ th:not(.num)), .wb-table td.num:has(+ td:not(.num)) { padding-right: 32px; }

.wb-table--working th { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--accent); text-align: left; border-bottom: 2px solid var(--accent); padding: 6px 16px 6px 0; }
.wb-table--working th.num { text-align: right; }
.wb-table--working td { border-bottom: 1px solid var(--rule); padding: 8px 16px 8px 0; }
.wb-table--working tbody tr:hover { background: var(--surface); }

.wb-table--reading { font-family: var(--font-serif); }
.wb-table--reading th { font-family: var(--font-sans); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--ink-soft); text-align: left; border-top: 3px solid var(--ink); border-bottom: 1px solid var(--rule); padding: 8px 24px 8px 0; }
.wb-table--reading th.num { text-align: right; }
.wb-table--reading td { padding: 9px 24px 9px 0; }
.wb-table--reading tbody tr:first-child td { padding-top: 12px; }
.wb-table--reading th.num:has(+ th:not(.num)), .wb-table--reading td.num:has(+ td:not(.num)) { padding-right: 40px; }

/* ---------- Charts (C1-Q2/Q3 + C1b) ----------
   Anatomy: G-A Open — horizontal gridlines only (dashed, --chart-grid),
   solid zero/base line (--chart-zero), NO axis cage, series labeled
   directly at line-end in the series color; legend only when direct
   labels physically don't fit.
   Implementation canon (C1b): hand-rolled inline SVG + chart-helper.js
   for editorial/print surfaces; vendored uPlot (vendor/) for
   interactive time-series dashboards; bar/mixed charts stay hand-rolled.
   Bar category labels: never truncate — rotate (~-35°, or 90° if the
   surface is dense) via WBCharts.rotatedLabel when horizontal doesn't fit. */
/* Type minimums (Round P, 2026-07-28): these are RENDERED-pixel floors —
   ticks & category labels ≥12px, value & series labels ≥14px. SVG type
   scales with the viewBox, so declared sizes lie unless the viewBox width
   ≈ the intended CSS display width; author that way and verify at render.
   Horizontal bar charts: left label column up to ~30% of chart width
   (min 120px); labels never truncate. */
svg.wb-chart { width: 100%; height: auto; display: block; }
.wb-chart text { font-family: var(--font-sans); font-size: 12px; fill: var(--chart-axis); }
.wb-chart .glab { font-weight: 600; font-size: 14px; }
.wb-chart .grid { stroke: var(--chart-grid); stroke-width: 1; stroke-dasharray: 2 4; }
.wb-chart .zero { stroke: var(--chart-zero); stroke-width: 1.2; }
.wb-chart .s1 { stroke: var(--chart-1); fill: none; stroke-width: 2.2; }
.wb-chart .s2 { stroke: var(--chart-2); fill: none; stroke-width: 2.2; }
.wb-chart .s3 { stroke: var(--chart-3); fill: none; stroke-width: 2.2; }
.wb-chart .s4 { stroke: var(--chart-4); fill: none; stroke-width: 2.2; }
.wb-chart .s5 { stroke: var(--chart-5); fill: none; stroke-width: 2.2; }
.wb-chart .b1 { fill: var(--chart-1); } .wb-chart .b2 { fill: var(--chart-2); }
.wb-chart .b3 { fill: var(--chart-3); } .wb-chart .b4 { fill: var(--chart-4); }
.wb-chart .b5 { fill: var(--chart-5); }
.wb-chart-title { font-family: var(--font-sans); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-soft); margin-bottom: 8px; }
/* Tooltip bubble used by chart-helper.js (position: parent must be relative) */
.wb-chart-wrap { position: relative; }
.wb-chart-tip { position: absolute; pointer-events: none; background: var(--accent-2, var(--accent)); color: var(--bg); font-family: var(--font-sans); font-size: 12px; padding: 7px 10px; border-radius: 5px; opacity: 0; transition: opacity 0.1s; white-space: nowrap; z-index: 5; }

/* ---------- Stat tiles (C1-Q4: role split, one family) ----------
   --summary → landing/summary pages    (rule-top, open ground)
   --card    → dashboards               (surface panel, hover accent)
   --strip   → inside documents/memos   (inline between hairlines)   */
.wb-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; }
.wb-tile .n { font-family: var(--font-display); font-style: var(--display-style, normal); font-size: 1.7rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--accent); line-height: 1.1; }
.wb-tile .lb { font-family: var(--font-sans); font-size: 0.64rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-soft); margin-top: 4px; }
.wb-tile .ft { font-size: 0.72rem; color: var(--ink-soft); margin-top: 4px; font-family: var(--font-serif); font-style: italic; }
.wb-tiles--summary .wb-tile { border-top: 2.5px solid var(--accent); padding-top: 10px; }
.wb-tiles--card .wb-tile { background: var(--surface); border: 1px solid var(--rule); border-radius: 6px; padding: 14px 16px; }
.wb-tiles--card .wb-tile:hover { border-color: var(--accent); }
.wb-tiles--strip { display: flex; gap: 28px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 12px 0; }
.wb-tiles--strip .wb-tile .n { font-size: 1.35rem; }

/* ---------- Meters (C1-Q5: strict role split) ----------
   Continuous → true magnitudes/percentages only.
   Segmented  → ordinal scores (3/5) only. Never interchangeable.   */
.wb-meter-row { display: grid; grid-template-columns: 130px 1fr 56px; gap: 14px; align-items: center; font-size: 0.8rem; margin-bottom: 12px; max-width: 560px; }
.wb-meter-row .mlb { font-family: var(--font-sans); font-weight: 600; }
.wb-meter-row .val { font-family: var(--font-mono); font-size: 0.78rem; text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-soft); }
.wb-meter { height: 8px; background: var(--surface); border: 1px solid var(--rule); border-radius: 3px; overflow: hidden; }
.wb-meter .fill { height: 100%; background: var(--accent); }
.wb-meter-segs { display: flex; gap: 4px; }
.wb-meter-segs span { width: 26px; height: 9px; border-radius: 2px; background: var(--surface); border: 1px solid var(--rule); }
.wb-meter-segs span.on { background: var(--accent); border-color: var(--accent); }

/* ============================================================
   C2 — Structure & text (locked 2026-07-26)
   ============================================================ */

/* ---------- Layout (C2-Q6) ----------
   Reading surfaces (memos, reports, reading artifacts): M-0.5 —
   centered book page at measure; exhibits may .wb-breakout to the
   container edge only when they need the width (a privilege, not
   the default). Working surfaces (dashboards): M-B — rows of 1-3
   columns run edge to edge; prose keeps its measure because asides
   share its row. Full-measure prose (M-C) is never canon.
   Justification: left-aligned ragged-right EVERYWHERE (web + Office). */
.wb-page { max-width: 1080px; margin: 0 auto; padding: 0 28px; }
.wb-read { max-width: var(--measure); margin-left: auto; margin-right: auto; }
.wb-read p, .wb-prose { font-family: var(--font-serif); line-height: 1.55; text-align: left; }
.wb-breakout { max-width: none; margin-left: 0; margin-right: 0; }
.wb-row-2 { display: grid; grid-template-columns: 3fr 2fr; gap: 20px; align-items: start; }
.wb-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }
@media (max-width: 720px) { .wb-row-2, .wb-row-3 { grid-template-columns: 1fr; } }

/* ---------- Section boxes (C2-Q1: three codified roles) ----------
   --reading  → documents & reading artifacts (rule + whitespace)
   --panel    → dashboards (operable card sections)
   --refbar   → dense reference sheets only (CARLA front-desk register) */
.wb-sec--reading { border-top: 1px solid var(--rule); padding-top: 14px; }
.wb-sec--panel { background: var(--surface); border: 1px solid var(--rule); border-radius: 6px; padding: 18px 20px; }
.wb-sec--refbar { border: 1px solid var(--rule); border-radius: 6px; overflow: hidden; }
.wb-sec--refbar .hb { background: var(--accent); color: var(--bg); padding: 8px 16px; font-family: var(--font-sans); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; font-size: 0.72rem; }
.wb-sec--refbar .inner { padding: 16px 20px; }
.wb-sec-title { font-family: var(--font-display); font-style: var(--display-style, normal); font-size: 1.2rem; font-weight: 700; }

/* ---------- Callouts (C2-Q2: dual anatomy, per-vibe mapping) ----------
   Anatomies: --framed (full border, label tab) and --topped (semantic
   rule above, no box). Semantic colors via --co-c: accent = insight/edge,
   warn tone (chart-2) = watch, negative = kill/critical.
   Vibe mapping (BRAND.md §6.5): Trusted = topped in reading, framed on
   working · Corporate = topped default, framed for kill only ·
   Exclusive = topped always · Cutting Edge = framed always ·
   Playful = framed (radius dial applies). */
.wb-callout { max-width: var(--measure); font-family: var(--font-serif); font-size: 0.9rem; margin: 14px 0; --co-c: var(--accent); }
.wb-callout .lab { font-family: var(--font-sans); font-size: 0.66rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--co-c); margin-bottom: 3px; }
.wb-callout--warn { --co-c: var(--chart-2); }
.wb-callout--kill { --co-c: var(--negative, #C0302B); }
.wb-callout--framed { border: 1px solid var(--co-c); border-radius: 4px; padding: 13px 16px 11px; position: relative; margin-top: 18px; }
.wb-callout--framed .lab { position: absolute; top: -9px; left: 12px; background: var(--bg); padding: 0 8px; }
.wb-callout--topped { border-top: 2.5px solid var(--co-c); padding-top: 8px; }

/* ---------- Pull-quotes & captions (C2-Q3) ----------
   Primary: centered block between hairlines with oversized mark —
   but the TEXT is left-aligned (Don: never center multi-line text).
   Secondary (sanctioned): margin-ruled (--margin variant). */
.wb-pullquote { max-width: 540px; margin: 20px auto; padding: 16px 24px 14px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); font-family: var(--font-serif); font-style: italic; font-size: 1.25rem; text-align: left; }
.wb-pullquote::before { content: "\201C"; display: block; font-size: 2.4rem; line-height: 0.4; color: var(--accent-2, var(--accent)); font-style: normal; }
.wb-pullquote--margin { margin: 20px 0; padding: 0 0 0 18px; border-top: none; border-bottom: none; border-left: 3px solid var(--accent-2, var(--accent)); font-size: 1.15rem; }
.wb-pullquote--margin::before { content: none; }
.wb-quote-cite { font-family: var(--font-sans); font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-soft); margin-top: 8px; font-style: normal; }
.wb-figcap { font-family: var(--font-sans); font-size: 0.74rem; color: var(--ink-soft); margin-top: 7px; text-align: left; }
.wb-figcap .fno { font-weight: 600; color: var(--accent); }
.wb-figcap-src { font-size: 0.7rem; opacity: 0.75; margin-top: 2px; }

/* ---------- Label voice + emphasis (C2-Q4/Q5) ----------
   Furniture voice: uppercase tracked sans, constant across vibes;
   Cutting Edge's dial may swap it to lowercase mono.
   Emphasis: italic-first, one cue per element. Bold is rationed to
   ~one load-bearing phrase per section. Table row keys distinguish
   by voice (sans, .key) — never blanket-bolded. Never bold+color
   the same span unless it is the page's single most important fact. */
.wb-label { font-family: var(--font-sans); font-size: 0.7rem; font-weight: 600; letter-spacing: var(--label-tracking); text-transform: uppercase; }

/* ============================================================
   C3 — Interaction canon (locked 2026-07-27)
   Companion JS for accordion/modal/tabs/zones: interactions.js
   ============================================================ */

/* ---------- Buttons (C3-Q1) ----------
   Four ranks; ONE primary per view. Voice: uppercase tracked (the
   furniture voice). Radius follows the vibe dial (--radius-btn). */
.wb-btn { font-family: var(--font-sans); font-size: 0.74rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; padding: 9px 16px; border-radius: var(--radius-btn); cursor: pointer; border: 1px solid transparent; transition: filter .12s, background .12s; }
.wb-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.wb-btn--primary { background: var(--accent); color: var(--bg); }
.wb-btn--primary:hover:not(:disabled) { filter: brightness(0.9); }
.wb-btn--secondary { background: transparent; border-color: var(--accent); color: var(--accent); }
.wb-btn--secondary:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.wb-btn--tertiary { background: none; border: none; color: var(--accent-2, var(--accent)); padding-left: 0; padding-right: 0; }
.wb-btn--tertiary:hover:not(:disabled) { text-decoration: underline; text-underline-offset: 3px; }
.wb-btn--destructive { background: transparent; border-color: var(--negative, #C0302B); color: var(--negative, #C0302B); }
.wb-btn--destructive:hover:not(:disabled) { background: color-mix(in srgb, var(--negative, #C0302B) 10%, transparent); }

/* ---------- Pills (C3-Q2: role system) ----------
   Anatomy tells you the information kind:
   --status = tinted + dot (semantic color) · --tag = outlined,
   neutral · --count = solid. Set color via --pc. */
.wb-pill { font-family: var(--font-sans); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.06em; border-radius: 999px; padding: 3px 11px; display: inline-flex; gap: 6px; align-items: center; --pc: var(--accent); }
.wb-pill .dt { width: 7px; height: 7px; border-radius: 50%; background: var(--pc); flex: none; }
.wb-pill--status { background: color-mix(in srgb, var(--pc) 13%, var(--bg)); color: var(--pc); }
.wb-pill--tag { border: 1px solid var(--pc); color: var(--pc); background: transparent; --pc: var(--ink-soft); }
.wb-pill--count { background: var(--pc); color: var(--bg); }
.wb-pill--warn { --pc: var(--chart-2); }
.wb-pill--neg { --pc: var(--negative, #C0302B); }

/* ---------- Links (C3-Q3) ----------
   In prose: ink text, permanent accent underline; color on hover.
   Standalone action links use the arrow form. */
.wb-link { color: inherit; text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
.wb-link:hover { color: var(--accent); }
.wb-link-arrow { font-family: var(--font-sans); font-size: 0.8rem; font-weight: 600; color: var(--accent-2, var(--accent)); text-decoration: none; }
.wb-link-arrow:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- Forms (C3-Q4) ----------
   Label-pill radios (.wb-radio-pills) when options carry hint text /
   teach; plain native radios permitted for dense compact lists. */
.wb-field { margin-bottom: 14px; }
.wb-field > .wb-label { display: block; margin-bottom: 5px; color: var(--ink-soft); }
.wb-input, .wb-select { background: var(--bg); border: 1px solid var(--rule); border-radius: 4px; padding: 8px 10px; font-family: var(--font-sans); font-size: 0.85rem; color: var(--ink); width: 100%; box-sizing: border-box; }
.wb-input:focus, .wb-select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.wb-radio-pills { display: flex; gap: 8px; }
.wb-radio-pills label { flex: 1; border: 1px solid var(--rule); border-radius: 4px; padding: 8px 12px; font-family: var(--font-sans); font-size: 0.8rem; cursor: pointer; display: flex; gap: 8px; align-items: flex-start; }
.wb-radio-pills label:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 5%, transparent); }
.wb-radio-pills .hint { display: block; font-size: 0.7rem; color: var(--ink-soft); margin-top: 2px; }
input[type="radio"], input[type="checkbox"] { accent-color: var(--accent); }

/* ---------- Disclosure trio (C3-Q5) ----------
   WHEN-rules: native title= for incidental hints · footnote bubble
   for cited asides · accordion for secondary/ARCHIVE content only ·
   modal for RECORD DETAIL only (never forms, never confirmations —
   confirm inline). Accordion anatomy: animated max-height (A-2). */
sup.wb-fn { color: var(--accent); border-bottom: 1px dotted var(--accent); cursor: help; position: relative; font-family: var(--font-sans); font-size: 0.7rem; }
sup.wb-fn .bub { position: absolute; bottom: 140%; left: -8px; width: max-content; max-width: min(270px, 70vw); background: var(--ink); color: var(--bg); font-family: var(--font-sans); font-size: 0.76rem; font-weight: 400; line-height: 1.45; padding: 8px 11px; border-radius: 6px; opacity: 0; pointer-events: none; transition: opacity .12s, transform .12s; transform: translateY(4px); z-index: 20; }
sup.wb-fn:hover .bub, sup.wb-fn:focus .bub { opacity: 1; transform: none; }
.wb-acc { border: 1px solid var(--rule); border-radius: 6px; margin: 8px 0; }
.wb-acc > button { all: unset; box-sizing: border-box; width: 100%; cursor: pointer; padding: 11px 16px; font-family: var(--font-sans); font-size: 0.85rem; font-weight: 600; display: flex; gap: 10px; align-items: center; }
.wb-acc .chev { color: var(--accent); transition: transform .18s; }
.wb-acc[data-open="1"] .chev { transform: rotate(90deg); }
.wb-acc .wb-acc-body { max-height: 0; overflow: hidden; transition: max-height .22s ease; }
.wb-acc .wb-acc-inner { padding: 0 16px 13px 34px; font-family: var(--font-serif); font-size: 0.87rem; }
.wb-modal-scrim { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: none; z-index: 90; align-items: center; justify-content: center; }
.wb-modal-scrim.open { display: flex; }
.wb-modal { background: var(--bg); color: var(--ink); border: 1px solid var(--rule); border-radius: 8px; max-width: 480px; width: 92%; max-height: 80vh; overflow: auto; padding: 22px 24px; position: relative; }
.wb-modal h4 { font-family: var(--font-serif); font-size: 1.15rem; margin: 0 0 4px; border-bottom: 2px solid var(--accent); padding-bottom: 8px; padding-right: 40px; }
.wb-modal-close { position: absolute; top: 14px; right: 14px; width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--rule); background: none; color: var(--ink); cursor: pointer; font-size: 1rem; }
.wb-modal-close:focus-visible { outline: 2px solid var(--accent); }

/* ---------- Navigation + signature (C3-Q6) ----------
   View toggle = alternate renderings of the SAME data · underline
   tabs = genuinely different panels only · long documents = scroll-spy
   section nav, never tabs · CLICK-TO-DETAIL is the signature: click a
   visual → the detail region fills in place; preferred over modals and
   navigation whenever the detail fits on the page. */
.wb-vtoggle { display: inline-flex; border: 1px solid var(--rule); border-radius: 4px; overflow: hidden; }
.wb-vtoggle button { border: none; background: transparent; color: var(--ink-soft); font-family: var(--font-sans); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; padding: 6px 14px; cursor: pointer; }
.wb-vtoggle button.active { background: var(--accent); color: var(--bg); }
.wb-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--rule); }
.wb-tabs button { border: none; background: none; font-family: var(--font-sans); font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); padding: 8px 14px; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.wb-tabs button[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }
/* Mode toggle (Round P, 2026-07-28) — furniture rank, top-right of the
   masthead after any nav; present on standalone artifacts & dashboards,
   omitted on print surfaces. Artifacts OPEN IN THE VIBE'S PRIMARY MODE
   regardless of OS preference (the vibe is a deliberate world); the
   reader's election persists via localStorage (see interactions.js
   WB.modeToggle). Icon-only ghost circle, stroke half-disc per the
   icon canon. */
.wb-mode-toggle { width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--rule); background: transparent; color: var(--ink-soft); display: inline-flex; align-items: center; justify-content: center; padding: 0; cursor: pointer; }
.wb-mode-toggle:hover { border-color: var(--accent); color: var(--ink); }
.wb-mode-toggle svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 1.6; fill: none; }
.wb-mode-toggle svg .half { fill: currentColor; stroke: none; }

.wb-zone { background: var(--surface); border: 1.5px solid var(--rule); border-radius: 6px; padding: 12px 14px; cursor: pointer; }
.wb-zone:hover { border-color: var(--accent); }
.wb-zone.active { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.wb-detail { border-top: 2px solid var(--accent); margin-top: 14px; padding-top: 10px; font-family: var(--font-serif); font-size: 0.88rem; }

/* ============================================================
   C4 — Diagrams & media (locked 2026-07-27)
   ============================================================ */

/* Heatmaps — cells colored by the ramp formulas in tokens.css.
   Sequential: mix accent into bg. Diverging: accent-poled positive,
   red negative, bg midpoint. Text flips to var(--bg) above ~60% mix. */
.wb-heat { border-collapse: collapse; font-family: var(--font-sans); font-size: 0.72rem; }
.wb-heat th { font-size: 0.64rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); padding: 4px 8px; text-align: center; }
.wb-heat td { min-width: 52px; height: 34px; text-align: center; font-variant-numeric: tabular-nums; border: 2px solid var(--bg); }

/* Matrix / 2×2 (role split): zone-card grid when quadrants CLASSIFY
   (click-to-detail applies); plotted SVG scatter when positions are
   real data. Matrices as DOM grids, geometry as SVG — the C1 rule. */
.wb-quad-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.wb-quad { background: var(--surface); border: 1.5px solid var(--rule); border-radius: 6px; padding: 12px 14px; cursor: pointer; min-height: 92px; }
.wb-quad:hover, .wb-quad.active { border-color: var(--accent); }
.wb-quad.active { background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.wb-quad .qt { font-family: var(--font-serif); font-size: 0.98rem; font-weight: 700; color: var(--accent); }
.wb-quad .qs { font-family: var(--font-sans); font-size: 0.7rem; color: var(--ink-soft); margin-top: 2px; }
.wb-quad-axis { display: flex; justify-content: space-between; font-family: var(--font-sans); font-size: 0.64rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-soft); margin-top: 6px; }

/* Venn — hand-rolled SVG: circles in chart-1/2/3 at 0.28 opacity,
   accent-2 stroke 1.2, counts on ground chips (fill bg, stroke rule).
   Region positions are hand-tuned per diagram — documented limitation. */

/* Exhibits/images (role split): framed in documents & reports,
   bare on dashboards & marketing pages. ALWAYS captioned with
   .wb-figcap (+ source line) — no uncaptioned images on branded
   surfaces. */
.wb-exhibit { border: 1px solid var(--rule); }

/* Icons — inline SVG stroke: 1.6px, currentColor, ~22px grid,
   round caps/joins. Accent color only when the icon IS the action.
   EMOJI ARE BANNED as UI furniture (section markers, bullets, status);
   permitted in prose only when they carry actual meaning. */
.wb-icon { width: 22px; height: 22px; stroke: currentColor; stroke-width: 1.6; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* Code blocks — surface panel, mono, prompt marker in accent, output
   soft. No syntax-rainbow highlighting. */
.wb-code { background: var(--surface); border: 1px solid var(--rule); border-radius: 4px; padding: 12px 16px; font-family: var(--font-mono); font-size: 0.78rem; line-height: 1.6; overflow-x: auto; }
.wb-code .pr { color: var(--accent); }
.wb-code .out { color: var(--ink-soft); }

/* Empty states — dashed boundary, one quiet italic line, one tertiary
   action. Never an illustration, never an apology. */
.wb-empty { border: 1px dashed var(--rule); border-radius: 6px; padding: 26px 20px; }
.wb-empty .msg { font-family: var(--font-serif); font-style: italic; color: var(--ink-soft); font-size: 0.9rem; }

/* ============================================================
   Round M — Minimalist vibe licenses (locked 2026-07-28)
   Scoped to [data-vibe="minimalist"] so they never leak.
   ============================================================ */
/* Title register 1 — the chapter opener ("Eddie the Chop House Boy"):
   Source Serif 4 Black, title case, centered, massive. */
[data-vibe="minimalist"] .wb-title-chapter { font-family: var(--font-serif); font-weight: 900; text-align: center; font-size: 2.4rem; line-height: 1.08; text-wrap: balance; }
[data-vibe="minimalist"] .wb-title-sub { font-family: var(--font-serif); font-style: italic; text-align: center; font-size: 0.95rem; color: var(--ink-soft); margin-top: 14px; }
/* Title register 2 — the title page (The Money Culture):
   swash-italic lead word over tracked all-caps, tracked imprint line. */
[data-vibe="minimalist"] .wb-title-lead { font-family: var(--font-serif); font-style: italic; text-align: center; font-size: 2.2rem; line-height: 1; }
[data-vibe="minimalist"] .wb-title-page { font-family: var(--font-serif); font-weight: 700; text-align: center; font-size: 2rem; letter-spacing: 0.12em; text-transform: uppercase; line-height: 1.25; margin-top: 10px; }
[data-vibe="minimalist"] .wb-imprint { font-family: var(--font-serif); font-size: 0.72rem; letter-spacing: 0.22em; text-transform: uppercase; text-align: center; color: var(--ink-soft); }
/* Justification license — Minimalist READING surfaces only; working
   surfaces stay ragged even in this vibe.
   CASCADE TRAP (CARLA feedback 2026-07-28): this element-level justify
   rule silently beats text-align INHERITED from any centered wrapper.
   Any centered element on a justified reading surface must declare its
   own text-align. The title registers below re-assert theirs at higher
   specificity; do the same for any new centered element. */
[data-vibe="minimalist"] .wb-read p, [data-vibe="minimalist"] .wb-prose { text-align: justify; hyphens: auto; }
[data-vibe="minimalist"] .wb-read .wb-title-chapter, [data-vibe="minimalist"] .wb-read .wb-title-sub,
[data-vibe="minimalist"] .wb-read .wb-title-lead, [data-vibe="minimalist"] .wb-read .wb-title-page,
[data-vibe="minimalist"] .wb-read .wb-imprint { text-align: center; hyphens: none; }
[data-vibe="minimalist"] .wb-read .wb-figcap, [data-vibe="minimalist"] .wb-read figcaption { text-align: left; hyphens: none; }
/* Flare discipline — the Wren-blue accent-2 appears at most once per
   page (a link, a dot, a marginal figure number). Enforced by usage,
   not CSS. */

/* ============================================================
   Round C — Classic vibe licenses (locked 2026-08-03)
   Scoped to [data-vibe="classic"] so they never leak.
   ============================================================ */
/* Textures, role-split: university stripe is SURFACE cloth (mastheads,
   panels — never behind body prose); repp regimental is the ACCENT
   band (top-of-card, dividers). Body content sits on plain ground. */
[data-vibe="classic"] .wb-cloth { background: var(--stripe-oxford); }
[data-vibe="classic"] .wb-band { height: 8px; background: var(--stripe-repp); }
[data-vibe="classic"] .wb-anchor { background: var(--anchor); color: #EFF2F7; }
/* Script license — ONE flourish per surface: a lead word or a
   signature line, never body text, never navigation. */
[data-vibe="classic"] .wb-flourish { font-family: "Edwardian Script ITC", "Kunstler Script", "Snell Roundhand", cursive; font-size: 2.6em; line-height: 0.9; letter-spacing: 0; text-transform: none; }
[data-vibe="classic"] .wb-title-smallcaps { font-family: var(--font-serif); font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; text-align: center; }
