/* ──────────────────────────────────────────────────────────────────
   Probily / Bureau — tokens
   OKLCH warm-gray scale, amber accent, dark-first
   ────────────────────────────────────────────────────────────────── */

:root {
  /* Type */
  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --font-serif: "Source Serif 4", "IBM Plex Serif", Georgia, serif;

  /* Warm-gray scale (OKLCH) */
  --gray-50:   oklch(0.985 0.002 264);
  --gray-100:  oklch(0.965 0.003 264);
  --gray-200:  oklch(0.925 0.004 264);
  --gray-300:  oklch(0.870 0.005 264);
  --gray-400:  oklch(0.715 0.007 264);
  --gray-500:  oklch(0.570 0.008 264);
  --gray-600:  oklch(0.460 0.009 264);
  --gray-700:  oklch(0.355 0.009 264);
  --gray-800:  oklch(0.245 0.008 264);
  --gray-900:  oklch(0.175 0.007 264);
  --gray-950:  oklch(0.120 0.005 264);
  --gray-1000: oklch(0.080 0.004 264);

  /* Surfaces */
  --bg-0: var(--gray-1000);
  --bg-1: var(--gray-950);
  --bg-2: var(--gray-900);
  --bg-3: var(--gray-800);

  /* Borders */
  --border-subtle:  color-mix(in oklch, white 6%, transparent);
  --border-default: color-mix(in oklch, white 9%, transparent);
  --border-strong:  color-mix(in oklch, white 14%, transparent);

  /* Text */
  --text-primary:   oklch(0.97 0.003 264);
  --text-secondary: oklch(0.83 0.010 70);
  /* alpha618 — bumped tertiary/disabled luminance for WCAG 1.4.3 AA.
     Old tertiary 0.58 vs bg-0 0.13 ≈ 4.6:1 (just passes), disabled
     0.42 ≈ 3.8:1 fails normal-text AA. Bumped tertiary→0.63 (~5.4:1)
     and disabled→0.50 (~4.6:1) so dim labels still read «secondary»
     visually but no longer fail screen-reader / low-vision use. */
  --text-tertiary:  oklch(0.72 0.013 70);
  --text-disabled:  oklch(0.62 0.012 70);

  /* ── Type system (alpha1055) — founder «нет системы шрифтов — построй СИСТЕМУ».
     A FINITE semantic ramp. Every font-size references one of these — no arbitrary
     px anywhere. Tuned so the old 8-11px tiny bulk now reads at 12px+. To resize a
     role, change its token here — never per-line. система-в-системе for type. */
  --fs-2xs: 14px;    /* chips, dots, micro-labels (alpha1097 +~15%: founder «мелкого текста много») */
  --fs-xs:  15px;    /* captions, secondary meta */
  --fs-sm:  16.5px;  /* body / reading text — bigger + more readable */
  --fs-md:  19.5px;  /* lead, emphasised */
  --fs-lg:  24px;    /* h3 / section heads */
  --fs-xl:  30px;    /* h2 */
  --fs-2xl: 39px; --fs-3xl: 50px; --fs-4xl: 68px; --fs-5xl: 88px;    /* h1 / hero */

  /* ── Card rhythm tokens (Stage 1, founder 2026-07-09) — ADDITIVE ONLY.
     Report cards lost their small register when --fs-2xs was bumped to 14px
     (alpha1097): the smallest card text became larger than the sidebar's
     primary nav (13px), so nothing on a card could recede. These tokens give
     cards a fine ladder again (title > body > meta > label, hierarchy by
     weight/case like the sidebar) WITHOUT touching any existing token.
     Consumed only by report-card rules in report-bureau.css. */
  --fs-card-title: 16.5px;  /* card title / section heading (matches --fs-sm) */
  --fs-card-body:  15px;    /* intro / context / quotes (matches --fs-xs) */
  --lh-card-body:  1.55;    /* the ONE calm reading line-height */
  --fs-card-meta:  13px;    /* params, identifier rows, foot, accordion summaries */
  --fs-card-label: 10px;    /* kickers / micro-labels — one voice */
  --fs-card-chip:  11px;    /* chips inside cards */

  /* ── Spacing / layout system (alpha1068) — founder «нужна СИСТЕМА по верстке и
     расположению элементов, как с шрифтами». A FINITE 2px-grid ramp. Every
     margin/padding/gap references one of these — no arbitrary px. To retune the
     spacing rhythm globally, change a token here, never per-line. система-в-системе
     for layout. */
  --space-px:  1px;    /* hairlines, fine separators */
  --space-2xs: 2px;    /* tightest internal gaps */
  --space-xs:  4px;    /* chip padding, tight gaps */
  /* alpha1247 — aligned to the values the report actually renders (legacy-tokens.css
     used to clobber these with its larger «alpha189» scale). Both files now AGREE =
     ONE spacing vocabulary; zero visual change. */
  --space-sm:  8px;    /* compact gaps, small padding */
  --space-md:  12px;   /* default gap / padding */
  --space-lg:  16px;   /* comfortable padding */
  --space-xl:  24px;   /* card padding, section gaps */
  --space-2xl: 32px;   /* block padding */
  --space-3xl: 48px;   /* section padding */
  --space-4xl: 28px;   /* large block separation */
  --space-5xl: 36px;   /* major section gaps */
  --space-6xl: 44px;   /* hero / top-level rhythm */


  /* Accent — amber, the only chromatic accent */
  --brand-400: oklch(0.84 0.14 82);
  --brand-500: oklch(0.78 0.155 78);
  --brand-600: oklch(0.69 0.16 70);
  --brand-700: oklch(0.58 0.14 60);
  /* `--accent` is the ONE chromatic accent, aliased to the amber ramp so any
     surface (Report scopes it in `.rep`; the Dossier/shell had no value) reads
     the same amber. Every surface loads tokens-bureau.css, so this is the
     single source. */
  --accent: var(--brand-500);

  /* Semantics */
  --success: oklch(0.72 0.16 145);
  --warning: oklch(0.82 0.15 75);
  --danger:  oklch(0.63 0.22 22);
  --info:    oklch(0.68 0.13 232);
  /* Money — its own dollar-green identity («follow the money»): BRIGHT on dark.
     Distinct from --success (verified) by a vivid, slightly cooler green. */
  --money:   oklch(0.82 0.18 150);

  /* Entity-type colors — coherent with graph node palette (blue/red/yellow/green/white) */
  --et-person:  #5b9cff;   /* blue   */
  --et-email:   oklch(0.78 0.12 200);
  --et-phone:   oklch(0.74 0.14 165);
  --et-domain:  #ffd23f;   /* yellow */
  --et-company: #d4d7dd;   /* org = light/white — coherent with the graph node (founder: organisations are WHITE, not red; #ff5b5b had drifted to crime's colour). alpha1180 */
  /* alpha1184 — the rest of the entity-type colours as tokens (= GRAPH_COLOR in entity_registry.py),
     so EVERY widget / mini-card / dot references ONE systemic value, not hardcoded hex (founder:
     «цветовая схема выделения везде на всех виджетах и миникарточках»). */
  --et-place:    #22d3ee;  /* cyan  */
  --et-materiel: #c9a227;  /* gold  */
  --et-money:    #2dd98a;  /* green */
  --et-crime:    #ff5b5b;  /* red   */
  --et-event:    #d29922;  /* amber */
  --et-wallet:  var(--brand-500);
  --et-social:  oklch(0.74 0.13 330);
  --et-unknown: var(--gray-500);
  /* Outlet / author / statement — the Report scopes these in report-bureau.css;
     the Dossier/Project shells never load that sheet, so promote them here (the
     one sheet every surface loads) or the Dossier's `.rel-row.outlet/.author`
     and `.etd.*` rendered invalid colours. */
  --et-outlet:    #ffd23f;  /* yellow, = domain */
  --et-author:    #3fe08a;  /* green */
  --et-statement: #eef0f4;  /* near-white */

  /* Radii */
  --r-xs: 2px;
  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;

  /* Public-site width contract — recovered from the frozen homepage canon
     (.mkt-wrap = max-width 1080px / padding 0 34px, marketing-bureau.css:639)
     and named so every public page measures from ONE source instead of a
     per-template literal. Before this, in-scope public routes ran five
     unrelated widths and the content left edge jumped 170–394px between
     pages at 1440. Consumed by .mkt-wrap and by public-site.css.
     --pub-gutter steps down at the two shared public breakpoints. */
  --pub-w-wide: 1080px;   /* the public container — every family */
  --pub-w-content: 720px; /* marketing prose column (.mkt-body) */
  --pub-w-read: 760px;    /* reference + legal reading measure */
  --pub-w-form: 400px;    /* auth / purchase form column */
  --pub-gutter: 34px;

  /* Public-site typography contract — the ENTIRE anonymous external site
     resolves to these five size roles (founder decision 2026-07-19: five is
     the absolute maximum; hierarchy differentiates via family / weight /
     colour / spacing, never by inventing a sixth size). Values are recovered
     from the frozen homepage canon, not designed fresh:
       display  = .home-display   (homepage display heading + big numerals)
       title    = shared page-h1 clamp (unchanged from the unification pass)
       section  = .home-h2 clamp  (h2 / major section headings, all families)
       body     = 1rem            (paragraphs, nav, buttons, forms, h3, legal)
       meta     = 0.875rem        (labels, eyebrows, captions, mono chips)
     display/title/section resolve per-viewport through their clamps; body
     and meta are constant, so each tested viewport's computed union stays
     within five values. Consumed by marketing-bureau.css, public-site.css
     and the page-family stylesheets — pages never define their own scale. */
  --pub-type-display: clamp(2.5rem, 1.525rem + 3.25vw, 4.125rem);
  --pub-type-title:   clamp(2.125rem, 1.3rem + 2.75vw, 3.5rem);
  --pub-type-section: clamp(1.5rem, 1.125rem + 1.25vw, 2.125rem);
  --pub-type-body:    1rem;
  --pub-type-meta:    0.875rem;
  /* Role line-heights — one intentional value per role family, shared by
     every page (display/title share the tight display leading). */
  --pub-lh-tight: 1.05;   /* display + title */
  --pub-lh-snug:  1.25;   /* section headings + compact headings */
  --pub-lh-body:  1.6;    /* running text */
  --pub-lh-meta:  1.45;   /* labels, captions, mono meta */

  /* Public-site spacing contract — layout-closure pass (2026-07-19). One
     vertical-rhythm and inner-spacing vocabulary for the anonymous site,
     recovered from the reference geometry rather than invented:
       hero-top/bottom   = the document family's 66/48 (heroes and reference
                           pages open identically across families)
       sec-y             = the marketing chapter rhythm (product pillars 78)
       sec-y-band        = the homepage band rhythm (canon 58)
       sec-y-roomy       = methodology chapter rhythm (116)
       card-pad(-sm)     = panel inner breathing room (dominant 22 / 16)
       gap-split         = two-column feature splits (canon 56)
       gap-grid          = card grids (16)
     Values step down at the two shared public breakpoints in
     marketing-bureau.css — same owner pattern as --pub-gutter and the
     display type step. Sections consume the tokens as padding-top/bottom
     LONGHANDS: the root cause of the broken outer grid was vertical rhythm
     written as `padding: <y> 0 <y>` shorthand on elements that also carry
     the container class, silently zeroing the shared gutter (content at
     x=180 instead of 214 on desktop bands, x=0 on tablet). */
  --pub-hero-top: 66px;
  --pub-hero-bottom: 48px;
  --pub-sec-y: 78px;
  --pub-sec-y-band: 58px;
  --pub-sec-y-roomy: 116px;
  --pub-card-pad: 22px;
  --pub-card-pad-sm: 16px;
  --pub-gap-split: 56px;
  --pub-gap-grid: 16px;

  /* Shadow (popovers only) */
  --shadow-popover: 0 12px 32px -8px rgb(0 0 0 / 0.6), 0 0 0 1px var(--border-strong);

  /* Density */
  --row-h: 32px;
  --section-pad: 12px;

  /* Motion — one shared vocabulary (alpha929 art-direction pass).
     Three speeds + a signature easing so every surface moves the same
     way instead of 80–700ms ad-hoc. The report system (probily.css)
     mirrors these exact names so the whole product shares one feel. */
  --ease-out:     cubic-bezier(.2, .7, .2, 1);   /* Bureau spring — decisive settle */
  --ease-in-out:  cubic-bezier(.65, 0, .35, 1);  /* symmetric, for toggles */
  --ease-emphasis: cubic-bezier(.16, 1, .3, 1);  /* expressive entrances/reveals */
  --dur-1: 90ms;    /* micro   — colour / background on hover */
  --dur-2: 160ms;   /* standard — focus, small transforms, press */
  --dur-3: 240ms;   /* entrance — expand / collapse */
  --dur-4: 420ms;   /* deliberate — reveals */
  --lift:  -1px;    /* shared hover lift for cards & buttons */

  color-scheme: dark;
}

/* ── Day theme (alpha990) — high-contrast light. Inverting the warm-gray scale
   flips both the semantic --bg-* (which reference --gray) AND any direct
   --gray-* usage in one move; the literal text/border/brand tokens are
   overridden below. Founder's palette rule: high contrast, no muddy gray —
   white page, near-black ink, amber accent, the same verdict colours. ── */
:root[data-theme="light"] {
  color-scheme: light;
  --gray-50:   oklch(0.120 0.005 264);
  --gray-100:  oklch(0.175 0.007 264);
  --gray-200:  oklch(0.245 0.008 264);
  --gray-300:  oklch(0.355 0.009 264);
  --gray-400:  oklch(0.500 0.009 264);
  --gray-500:  oklch(0.575 0.008 264);
  --gray-600:  oklch(0.660 0.008 264);
  --gray-700:  oklch(0.760 0.006 264);
  --gray-800:  oklch(0.885 0.005 264);
  --gray-900:  oklch(0.940 0.004 264);
  --gray-950:  oklch(0.970 0.003 264);
  --gray-1000: oklch(0.992 0.001 264);
  --border-subtle:  color-mix(in oklch, black 10%, transparent);
  --border-default: color-mix(in oklch, black 15%, transparent);
  --border-strong:  color-mix(in oklch, black 24%, transparent);
  --text-primary:   oklch(0.18 0.012 264);
  --text-secondary: oklch(0.36 0.012 264);
  --text-tertiary:  oklch(0.47 0.011 264);
  --text-disabled:  oklch(0.60 0.009 264);
  --brand-400: oklch(0.72 0.155 74);
  --brand-500: oklch(0.64 0.165 68);
  --brand-600: oklch(0.56 0.15 62);
  --brand-700: oklch(0.48 0.13 56);
  --success: oklch(0.56 0.16 145);
  --warning: oklch(0.60 0.15 72);
  --danger:  oklch(0.54 0.22 22);
  --info:    oklch(0.54 0.14 232);
  /* Money — DARK dollar-green on the light theme (deep, saturated). */
  --money:   oklch(0.48 0.17 150);
  --shadow-popover: 0 12px 32px -8px rgb(0 0 0 / 0.16), 0 0 0 1px var(--border-strong);
}

[data-density="comfortable"] {
  --row-h: 40px;
  --section-pad: 16px;
}

/* Reset */
*, *::before, *::after { box-sizing: border-box; }
html, body, #root { height: 100%; margin: 0; }

body {
  background: var(--bg-0);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size:var(--fs-sm);
  line-height: 18px;
  font-weight: 400;
  font-feature-settings: "tnum" 1, "ss01" 1, "cv11" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;
}

/* alpha720 — Bureau anchor reset. Owner audit: «не выделять ссылки
   подчёркиванием — это выглядит недоделано». Default browser `<a>`
   styling (underline, blue/purple visited) reads as 90s/unfinished
   on a dark designed surface. Bureau pattern: link color = brand-500
   (or inherit for context-colored chrome), NO underline by default.
   Hover state can re-introduce underline if useful, but as a deliberate
   affordance, not a default. Individual components can still override
   when underline IS the right signal (e.g. inline body prose where
   distinguishing link from text matters). */
a {
  color: var(--brand-500);
  text-decoration: none;
}
a:visited { color: var(--brand-500); }
a:hover { color: var(--brand-400); }

button, input, select, textarea {
  font: inherit;
  color: inherit;
}
button { background: none; border: none; padding: 0; cursor: pointer; }

/* alpha733 — a11y baseline per Vercel web-interface-guidelines.
   - touch-action: manipulation kills the 300ms double-tap zoom delay
     on mobile for every interactive element.
   - Default :focus-visible ring for keyboard nav. Components are free
     to override with a more contextual ring; this is the floor so a
     missed override never leaves a control without visible focus. */
button, a, input, select, textarea, [tabindex]:not([tabindex="-1"]) {
  touch-action: manipulation;
}
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--brand-500);
  outline-offset: 2px;
  border-radius: 2px;
}

/* alpha733 — skip-link target. Hidden by default, visible on focus
   so keyboard users can jump past the topbar/navrail into the
   main content. Position fixed so it overlays everything else. */
.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 1000;
  padding: 8px 14px;
  background: var(--brand-500);
  color: var(--bg-0);
  font-family: var(--font-mono);
  font-size:var(--fs-xs);
  font-weight: 600;
  text-decoration: none;
  border-radius: 4px;
  transform: translateY(-200%);
  transition: transform 120ms ease;
}
.skip-link:focus-visible {
  transform: translateY(0);
  color: var(--bg-0);
  outline: 2px solid var(--bg-0);
  outline-offset: 2px;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-default);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: padding-box; }

::selection { background: color-mix(in oklch, var(--brand-500) 35%, transparent); }

/* Focus */
*:focus-visible {
  outline: 2px solid color-mix(in oklch, var(--brand-500) 70%, transparent);
  outline-offset: 1px;
  border-radius: inherit;
}

/* Mono utility */
.mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1, "ss01" 1; }
.tnum { font-variant-numeric: tabular-nums; }
.upper { text-transform: uppercase; letter-spacing: 0.04em; }
.muted { color: var(--text-secondary); }
.dim { color: var(--text-tertiary); }
.faint { color: var(--text-disabled); }

/* App layout */
.app {
  display: grid;
  /* Footer row is `auto`: it takes its content height when a statusbar element
     is present (Jinja surfaces; React dev-only), and collapses to 0 with no
     reserved gap when it is absent (normal React cabinet — the technical status
     strip is not rendered in normal runtime). */
  grid-template-rows: 40px 1fr auto;
  grid-template-columns: 248px 1fr;
  height: 100vh;
  /* NO 1280px floor. The mobile drawer engages at 900px, so a 1280px minimum
     left every viewport from 901px to 1279px — the whole tablet and small-
     laptop band — scrolling the entire application sideways, with the rail
     half off-screen and no burger to fall back to. Measured at 1024px:
     scrollWidth 1280 against a 1024 viewport. The grid is `248px + 1fr` and
     shrinks perfectly well; the floor was a legacy assumption, not a
     requirement. */
  min-height: 720px;
  background: var(--bg-0);
}
body { overflow: auto; }
/* 2026-07-01 — the LEFT nav (old `.navrail` icon rail OR the new unified
   `.cbsb` sidebar) owns column 1 for the FULL height (Anthropic layout);
   the topbar + statusbar sit over the CONTENT column only. Without an
   explicit placement the `.cbsb` sidebar auto-flowed AFTER the explicitly-
   placed `.main` and landed in column 2 (the «menu in the middle» defect). */
.app > .topbar { grid-column: 2; }
.app > .statusbar { grid-column: 2; }
.app > .navrail, .app > .cbsb { grid-column: 1; grid-row: 1 / -1; }
/* `overflow-y: auto`, NOT `hidden`. `.app` is `height: 100vh`, so the content
   column is the only thing that can scroll — and it was clipped. That worked
   only for surfaces which happen to build their own inner scroll region
   (Search's columns, the Project graph); every DOCUMENT-shaped surface simply
   lost everything past the fold. Measured on production: /dossiers rendered
   5969px of content inside an 860px box with nothing scrollable — 62 entities,
   of which about eight were reachable, and `window.scrollTo` did nothing. The
   founder hit the same wall on /cabinet/reports with 19 Reports.

   The mobile rule below already said `auto`; this is the desktop half of the
   same contract, and it is one rule for every `.app` surface rather than a
   per-page scroll container.

   `overflow-x` stays hidden: unbounded external strings must not widen the
   workspace (CLAUDE.md §9.3). */
.app > .main { grid-row: 2; min-width: 0; overflow-x: hidden; overflow-y: auto; }

/* ── Cabinet MOBILE (≤900px) — universal, one rule for EVERY `.app` surface ──
   React cabinet (AppShell) AND every Jinja cabinet/dossier/search page share
   this grid + the `.cbsb` sidebar, so this single breakpoint makes them all
   usable on a phone. Founder 2026-07-03. Defect it fixes: `.app` is hard-locked
   to `min-width:1280px`, so on a 375px phone the whole cabinet overflowed with a
   1280px horizontal scroll and the 248px sidebar ate two-thirds of the screen.
   Fix: drop the desktop lock, collapse to a single column, and slide the sidebar
   off-canvas into a drawer toggled by the fixed `.app-burger` (injected by
   /static/cabinet-mobile.js). Backdrop = the drawer's own huge box-shadow spread
   (no extra element); close-on-outside-tap handled in the JS. */
.app-burger {
  display: none;
  position: fixed; top: 0; left: 0; z-index: 61;
  width: 46px; height: 44px;
  align-items: center; justify-content: center;
  border: 0;
  border-right: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-0); color: var(--text-secondary);
  cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.app-burger:hover { color: var(--text-primary); }
.app-burger:active { background: var(--bg-1); }
@media (max-width: 900px) {
  .app {
    grid-template-rows: 44px 1fr auto;
    grid-template-columns: 1fr;
    min-width: 0;
    height: 100dvh;
  }
  .app > .topbar { grid-column: 1; padding-left: 46px; }   /* clear the fixed burger */
  .app > .statusbar { grid-column: 1; }
  .app > .main { grid-column: 1; overflow: auto; -webkit-overflow-scrolling: touch; }
  /* sidebar out of grid flow → off-canvas slide-in drawer */
  .app > .navrail, .app > .cbsb {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 60;
    width: min(86vw, 300px);
    transform: translateX(-100%);
    transition: transform 0.24s cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .app.nav-open > .navrail, .app.nav-open > .cbsb {
    transform: none;
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.55);   /* dim backdrop, no extra node */
  }
  .app-burger { display: inline-flex; }
  /* NB: the topbar-search mobile override lives AFTER the base `.topbar .cmdk`
     rule (below) — same specificity means source order decides, and the base
     `min-width:280px` must not win over it. */
}

/* ── Unified Level-1 sidebar (.cbsb) — SINGLE SOURCE ──────────────────────
   Used by BOTH the Jinja `cabinet/_partials/cabinet_sidebar.html` AND the
   React `frontend/src/components/Navrail.tsx` (both load this file), so the
   cabinet, reports and dossiers render one identical 248px sidebar. Probily's
   own system: amber #efb24a · Geist · dark bureau. Placement comes from the
   `.app > .cbsb` rule above. */
.cbsb{width:248px;flex:none;height:100%;background:var(--bg-0,#0a0a0b);border-right:1px solid var(--border-subtle,rgba(255,255,255,.06));display:flex;flex-direction:column;padding:12px 10px;overflow:auto;font-family:var(--font-sans,system-ui,-apple-system,sans-serif)}
.cbsb-brand{display:flex;align-items:center;gap:10px;padding:6px 8px 12px}
.cbsb-brand .mk{width:25px;height:25px;display:block;object-fit:contain;flex:none}
.cbsb-brand .wm{font:600 15.5px/1 var(--font-sans,system-ui);color:var(--text-primary,#f4f4f5);letter-spacing:-.01em}
.cbsb-new{display:flex;align-items:center;gap:9px;height:37px;margin:2px 2px 10px;padding:0 12px;border-radius:var(--r-sm,8px);background:var(--brand-500,#efb24a);color:#0a0a0b;font:600 13px/1 var(--font-sans,system-ui);text-decoration:none}
.cbsb-new:hover{background:var(--brand-400,#f2c368)}
/* The CTA label owns its visible-text contract on the label element itself, so
   the text cannot be blanked by an inherited colour/text-fill, a focus override,
   opacity/visibility inheritance, or a blend/filter effect. The Geist stack has a
   system fallback, so the glyphs paint regardless of webfont timing. */
.cbsb-new-label{color:#0a0a0b;-webkit-text-fill-color:#0a0a0b;opacity:1;visibility:visible;mix-blend-mode:normal;filter:none;display:inline-block;line-height:1}
.cbsb a.it{position:relative;display:flex;align-items:center;gap:11px;height:33px;padding:0 10px;border-radius:var(--r-sm,8px);color:var(--text-secondary,#cbc5b9);text-decoration:none;font:500 13px/1 var(--font-sans,system-ui);margin:1px 0}
.cbsb a.it svg{color:var(--text-tertiary,#a29a89);flex:none}
.cbsb a.it:hover{background:var(--bg-1,#151518);color:var(--text-primary,#f4f4f5)}
.cbsb a.it.on{background:var(--bg-2,#1c1c20);color:var(--text-primary,#f4f4f5);font-weight:600}
.cbsb a.it.on::before{content:"";position:absolute;left:-10px;top:7px;bottom:7px;width:3px;border-radius:0 3px 3px 0;background:var(--brand-500,#efb24a)}
.cbsb a.it.on svg{color:var(--brand-500,#efb24a)}
.cbsb a.it .ct{margin-left:auto;font:600 10px/1 var(--font-mono,ui-monospace,Menlo,monospace);color:var(--text-tertiary,#a29a89);background:var(--bg-3,#26262b);padding:2px 7px;border-radius:999px}
.cbsb .grp{display:flex;align-items:center;gap:7px;font:700 9px/1 var(--font-mono,ui-monospace,Menlo,monospace);letter-spacing:.13em;text-transform:uppercase;color:var(--text-disabled,#6f6a5e);padding:13px 10px 5px}
.cbsb .grp.wk{color:var(--brand-500,#efb24a)}
.cbsb a.sub{display:flex;align-items:center;gap:10px;height:29px;padding:0 10px 0 12px;border-radius:var(--r-sm,8px);color:var(--text-tertiary,#a29a89);text-decoration:none;font:500 12.5px/1 var(--font-sans,system-ui);margin:1px 0}
.cbsb a.sub .dt{width:5px;height:5px;border-radius:50%;background:var(--text-disabled,#6f6a5e);flex:none;margin-left:4px}
.cbsb a.sub:hover{background:var(--bg-1,#151518);color:var(--text-secondary,#cbc5b9)}
.cbsb a.sub:hover .dt{background:var(--brand-500,#efb24a)}
.cbsb .sp{flex:1;min-height:6px}
/* auth/shell Phase 1 — the Project currently open, shown under Workspace. Only
   rendered where a route genuinely has a Project (`viewer_project`), so it can
   never claim one the viewer is not in. */
.cbsb-ctx{display:flex;align-items:center;gap:7px;margin:1px 0 3px 26px;padding:3px 8px 3px 6px;min-width:0}
.cbsb-ctx .dot{width:5px;height:5px;border-radius:50%;background:var(--brand-500,#efb24a);flex:none}
.cbsb-ctx .lbl{font-size:var(--fs-2xs,11px);color:var(--text-tertiary,#8b8578);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cbsb-acct{border-top:1px solid var(--border-subtle,rgba(255,255,255,.06));padding-top:8px;margin-top:6px}
.cbsb-acct .row{display:flex;align-items:center;gap:10px;padding:5px 8px;border-radius:var(--r-sm,8px)}
.cbsb-acct .av{width:28px;height:28px;border-radius:50%;background:var(--bg-3,#26262b);border:1px solid var(--border-default,rgba(255,255,255,.12));display:flex;align-items:center;justify-content:center;font:600 11px/1 var(--font-sans,system-ui);color:var(--text-secondary,#cbc5b9);flex:none}
.cbsb-acct .em{font:600 12px/1.2 var(--font-sans,system-ui);color:var(--text-primary,#f4f4f5);max-width:118px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cbsb-acct .pl{font:600 9px/1 var(--font-mono,ui-monospace,Menlo,monospace);color:var(--text-disabled,#6f6a5e);margin-top:3px;letter-spacing:.05em}
.cbsb-acct .so{margin-left:auto;color:var(--text-tertiary,#a29a89);display:flex;background:none;border:0;cursor:pointer;padding:4px}
.cbsb-acct .so:hover{color:var(--text-primary,#f4f4f5)}

/* Topbar */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px 0 0;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-0);
  height: 40px;
  white-space: nowrap;
  overflow: hidden;
}
.topbar > * { flex-shrink: 0; }
.statusbar > * { flex-shrink: 0; }
.topbar .brand {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  width: 56px;
  justify-content: center;
  border-right: 1px solid var(--border-subtle);
  height: 100%;
}
.topbar .crumbs {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size:var(--fs-xs);
  color: var(--text-secondary);
}
.topbar .crumbs .sep { color: var(--text-disabled); }
.topbar .crumbs .case { color: var(--text-primary); }
.topbar .crumbs .tlp {
  margin-left: 8px;
}
.topbar .spacer { flex: 1; }

.topbar .cmdk {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px 4px 10px;
  border: 1px solid var(--border-default);
  border-radius: var(--r-sm);
  background: var(--bg-1);
  color: var(--text-secondary);
  font-size:var(--fs-xs);
  min-width: 280px;
  height: 26px;
  cursor: pointer;
}
.topbar .cmdk:hover { background: var(--bg-2); }
.topbar .cmdk kbd {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  padding: 1px 5px;
  border: 1px solid var(--border-default);
  border-radius: 3px;
  color: var(--text-tertiary);
  background: var(--bg-0);
}
/* Mobile topbar search — placed AFTER the base rule so it beats `min-width:280px`
   (equal specificity → source order wins). Collapse to an icon-only 34px button
   (label + ⌘K hidden) so it stays a clean tap target and never clips off-edge. */
@media (max-width: 900px) {
  .topbar .cmdk { min-width: 0; width: 34px; padding: 0; justify-content: center; }
  .topbar .cmdk span, .topbar .cmdk kbd { display: none; }
}

.topbar .session {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  padding: 0 4px;
}
.topbar .session .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--success) 25%, transparent);
}

/* alpha724 — Language switcher. Globe button + dropdown anchored
   off the button. Pro-gated visually via the locked-icon variant
   on .langsw-btn when data-pro-gate="1" is set on the wrapper. */
.langsw { position: relative; display: inline-flex; }
.langsw-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  letter-spacing: 0.04em;
}
.langsw-cur { font-weight: 600; }
.langsw[data-pro-gate="1"] .langsw-btn {
  opacity: 0.72;
  cursor: not-allowed;
}
.langsw-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 180px;
  background: var(--bg-0);
  border: 1px solid var(--border-default);
  border-radius: 4px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32);
  padding: 4px 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
}
.langsw-menu[hidden] { display: none; }
.langsw-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 12px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-secondary);
  text-decoration: none;
  letter-spacing: 0.04em;
}
.langsw-item:hover { background: var(--bg-1); color: var(--text-primary); }
.langsw-item .langsw-name {
  font-family: var(--font-sans);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  letter-spacing: 0;
}
.langsw-item.lang-cur {
  color: var(--brand-500);
  background: color-mix(in oklch, var(--brand-500) 6%, transparent);
}
.langsw-item.lang-cur::before {
  content: "→ ";
  margin-right: -2px;
  color: var(--brand-500);
}

/* Nav rail */
.navrail {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  border-right: 1px solid var(--border-subtle);
  background: var(--bg-0);
  padding: 4px 0;
  gap: 1px;
}
.navrail .item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: 52px;
  color: var(--text-tertiary);
  border-left: 2px solid transparent;
  position: relative;
}
.navrail .item .label {
  font-size:var(--fs-2xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 500;
}
.navrail .item:hover { color: var(--text-primary); background: var(--bg-1); }
.navrail .item.active {
  color: var(--text-primary);
  border-left-color: var(--brand-500);
  background: linear-gradient(90deg,
    color-mix(in oklch, var(--brand-500) 6%, transparent),
    transparent 70%);
}
.navrail .item .badge {
  position: absolute;
  top: 8px;
  right: 8px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  background: var(--brand-500);
  color: var(--gray-1000);
  padding: 0 4px;
  border-radius: 999px;
  line-height: 12px;
}
.navrail .divider {
  height: 1px;
  background: var(--border-subtle);
  margin: 4px 8px;
}

/* Status bar */
.statusbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 12px;
  height: 24px;
  background: var(--bg-0);
  border-top: 1px solid var(--border-subtle);
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
}
.statusbar > * { flex-shrink: 0; }
.statusbar .spacer { flex: 1 1 auto; min-width: 8px; }
.statusbar .group {
  display: flex; align-items: center; gap: 6px;
}
.statusbar .group .k { color: var(--text-disabled); text-transform: uppercase; letter-spacing: 0.06em; }
.statusbar .group .v { color: var(--text-secondary); }
.statusbar .dot {
  width: 5px; height: 5px; border-radius: 50%; background: var(--success);
}
.statusbar .dot.warn { background: var(--warning); }
.statusbar .dot.danger { background: var(--danger); }
.statusbar .spacer { flex: 1; }

/* Main content frame */
.main {
  display: grid;
  height: 100%;
}

/* Common primitives */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 18px;
  padding: 0 6px;
  border-radius: var(--r-xs);
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid var(--border-default);
  color: var(--text-secondary);
  background: var(--bg-1);
  line-height: 1;
  white-space: nowrap;
}
.chip.solid { background: var(--bg-2); }
.chip.amber { color: var(--brand-500); border-color: color-mix(in oklch, var(--brand-500) 30%, transparent); background: color-mix(in oklch, var(--brand-500) 8%, var(--bg-1)); }
.chip.success { color: var(--success); border-color: color-mix(in oklch, var(--success) 30%, transparent); background: color-mix(in oklch, var(--success) 8%, var(--bg-1)); }
.chip.warning { color: var(--warning); border-color: color-mix(in oklch, var(--warning) 30%, transparent); background: color-mix(in oklch, var(--warning) 8%, var(--bg-1)); }
.chip.danger { color: var(--danger); border-color: color-mix(in oklch, var(--danger) 35%, transparent); background: color-mix(in oklch, var(--danger) 10%, var(--bg-1)); }
.chip.info { color: var(--info); border-color: color-mix(in oklch, var(--info) 30%, transparent); background: color-mix(in oklch, var(--info) 8%, var(--bg-1)); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-default);
  background: var(--bg-2);
  color: var(--text-primary);
  font-size:var(--fs-xs);
  font-weight: 500;
  cursor: pointer;
  transition: background 120ms ease;
}
.btn:hover { background: var(--bg-3); }
.btn.primary {
  background: var(--brand-500);
  color: var(--gray-1000);
  border-color: var(--brand-600);
  font-weight: 600;
}
.btn.primary:hover { background: var(--brand-400); }
.btn.ghost { background: transparent; }
.btn.ghost:hover { background: var(--bg-2); }
.btn.danger:hover { background: color-mix(in oklch, var(--danger) 20%, var(--bg-2)); border-color: color-mix(in oklch, var(--danger) 40%, transparent); }
.btn .kbd {
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  padding: 0 4px;
  border: 1px solid var(--border-default);
  border-radius: 2px;
  color: var(--text-tertiary);
}
.btn[disabled] { color: var(--text-disabled); pointer-events: none; }
.btn.sm { height: 22px; padding: 0 7px; font-size:var(--fs-2xs); }
.btn.icon { width: 28px; padding: 0; }

/* ════════════════════════════════════════════════════════════════════════
   CANONICAL ACTION · LINK · LABEL CONTRACT   (founder 2026-07-24)
   ONE vocabulary across shell · Report · Dossier · Project. One accent
   (amber). Roles are told apart by STRUCTURE, not colour:
     primary   → solid amber fill, near-black text, weight 600  .act.act--primary
     secondary → transparent, 1px border, no fill               .act.act--secondary
     tertiary  → text only, amber, no box                       .act.act--tertiary
     link      → inline amber text, underlined                  a / .lnk
     ext link  → link + trailing ↗                              .lnk.lnk--ext
     evidence  → source/verify pill (success-toned, structural) .lnk-evidence
     label     → neutral mono chip, NON-interactive, no amber   .chip
   ════════════════════════════════════════════════════════════════════════ */
.act {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 34px; padding: 0 16px; border-radius: var(--r-sm);
  font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: 500;
  line-height: 1; text-decoration: none; white-space: nowrap; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--text-primary);
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.act--sm { height: 28px; padding: 0 11px; font-size: var(--fs-2xs); gap: 5px; }
/* Compound `.act.act--*` (0,2,0) so the button's own colour beats the base
   `a:link`/`a:visited` link colour (0,1,1) when `.act` is used on an anchor —
   otherwise a primary <a> button renders amber text on an amber fill. */
.act.act--primary { background: var(--brand-500); color: var(--gray-1000); font-weight: 600; }
.act.act--primary:hover { background: var(--brand-400); color: var(--gray-1000); }
.act.act--secondary { border-color: var(--border-strong); color: var(--text-primary); }
.act.act--secondary:hover { border-color: var(--brand-500); color: var(--brand-400); background: color-mix(in oklch, var(--brand-500) 8%, transparent); }
.act.act--tertiary { padding-inline: 4px; color: var(--brand-500); font-weight: 500; }
.act.act--tertiary:hover { color: var(--brand-400); text-decoration: underline; text-underline-offset: 3px; }
.act:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }
.act[disabled], .act[aria-disabled="true"], .act.is-disabled {
  color: var(--text-disabled); background: transparent; border-color: var(--border-subtle);
  cursor: not-allowed; pointer-events: none;
}
.act--primary[disabled], .act--primary.is-disabled {
  background: color-mix(in oklch, var(--brand-500) 22%, var(--bg-2)); color: var(--text-disabled);
}

/* Links — inline amber text, underlined. A link has NO box, which is what tells
   it apart from a button that shares the amber accent. */
.lnk { color: var(--brand-500); text-decoration: underline;
  text-decoration-color: color-mix(in oklch, var(--brand-500) 40%, transparent);
  text-underline-offset: 3px; }
.lnk:visited { color: var(--brand-600); }
.lnk:hover { color: var(--brand-400); text-decoration-color: var(--brand-400); }
.lnk--ext::after { content: " \2197"; font-size: 0.82em; }

/* Evidence / verify link — a source-check pill (success-toned + structural), so
   "check the source" never competes with the amber primary action. Matches the
   Report's existing `.said-verify` semantics. */
.lnk-evidence {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px;
  border-radius: 999px; border: 1px solid color-mix(in oklch, var(--success) 42%, transparent);
  background: color-mix(in oklch, var(--success) 9%, transparent);
  color: var(--success); font-family: var(--font-mono); font-size: var(--fs-2xs);
  text-decoration: none; white-space: nowrap;
}
.lnk-evidence:hover { border-color: var(--success); background: color-mix(in oklch, var(--success) 14%, transparent); }

/* A label chip is inert; a chip that is genuinely a link opts back in. This is
   the structural line between a static label and a clickable one. */
.chip { cursor: default; }
a.chip, button.chip, .chip[role="button"] { cursor: pointer; }

.divider-h { height: 1px; background: var(--border-subtle); }
.divider-v { width: 1px; background: var(--border-subtle); align-self: stretch; }

/* Table */
.table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size:var(--fs-xs);
}
.table thead th {
  text-align: left;
  font-weight: 500;
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  padding: 6px 12px;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-0);
  position: sticky;
  top: 0;
  z-index: 1;
}
.table tbody td {
  padding: 0 12px;
  height: var(--row-h);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  vertical-align: middle;
}
.table tbody tr:hover td { background: var(--bg-1); cursor: pointer; }
.table tbody tr.selected td { background: color-mix(in oklch, var(--brand-500) 8%, var(--bg-1)); }
.table tbody tr.selected td:first-child { box-shadow: inset 2px 0 0 var(--brand-500); }
.table .num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.table .id { font-family: var(--font-mono); color: var(--text-primary); }
.table .primary { color: var(--text-primary); }

/* Page header */
.pagehead {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border-subtle);
}
.pagehead h1 {
  font-size:var(--fs-md);
  font-weight: 500;
  letter-spacing: -0.01em;
  margin: 0;
}
.pagehead .sub {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
}
.pagehead .spacer { flex: 1; }

/* Card */
.card {
  background: var(--bg-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-md);
}
.card .head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-subtle);
}
.card .head .title {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  font-weight: 500;
}
.card .head .spacer { flex: 1; }
.card .body { padding: 12px; }

/* Inspector */
.inspector {
  width: 360px;
  background: var(--bg-1);
  border-left: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
.inspector .ins-head {
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--border-subtle);
}
.inspector .ins-tabs {
  display: flex;
  padding: 0 8px;
  gap: 0;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-1);
}
.inspector .ins-tabs .tab {
  padding: 8px 10px;
  font-size:var(--fs-2xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  margin-bottom: -1px;
}
.inspector .ins-tabs .tab.active {
  color: var(--text-primary);
  border-bottom-color: var(--brand-500);
}
.inspector .ins-tabs .tab:hover:not(.active) { color: var(--text-secondary); }
.inspector .ins-body {
  flex: 1;
  overflow: auto;
  padding: 0;
}
.inspector .section {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
}
.inspector .section .label {
  font-size:var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  font-weight: 500;
  margin-bottom: 6px;
}
.inspector .kv {
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 4px 12px;
  font-size:var(--fs-xs);
}
.inspector .kv .k { color: var(--text-tertiary); }
.inspector .kv .v { color: var(--text-primary); }

/* Confidence gauge */
.gauge {
  display: flex;
  align-items: center;
  gap: 8px;
}
.gauge .bar {
  flex: 1;
  height: 4px;
  background: var(--bg-3);
  border-radius: 999px;
  overflow: hidden;
}
.gauge .fill {
  height: 100%;
  background: var(--brand-500);
  border-radius: 999px;
}
.gauge .num { font-family: var(--font-mono); font-size:var(--fs-2xs); color: var(--text-primary); min-width: 32px; text-align: right; }
.gauge.danger .fill { background: var(--danger); }
.gauge.warning .fill { background: var(--warning); }
.gauge.success .fill { background: var(--success); }

/* Risk badge */
.risk {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  padding: 3px 8px;
  border-radius: var(--r-xs);
}
.risk .dot { width: 6px; height: 6px; border-radius: 50%; }
.risk.high { color: var(--danger); background: color-mix(in oklch, var(--danger) 12%, transparent); }
.risk.high .dot { background: var(--danger); }
.risk.med { color: var(--warning); background: color-mix(in oklch, var(--warning) 12%, transparent); }
.risk.med .dot { background: var(--warning); }
.risk.low { color: var(--success); background: color-mix(in oklch, var(--success) 12%, transparent); }
.risk.low .dot { background: var(--success); }
.risk.critical { color: var(--danger); background: color-mix(in oklch, var(--danger) 20%, transparent); font-weight: 600; }
.risk.critical .dot { background: var(--danger); box-shadow: 0 0 0 2px color-mix(in oklch, var(--danger) 35%, transparent); }

/* Hash component */
.hash {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-secondary);
  cursor: copy;
}
.hash:hover { color: var(--text-primary); }
.hash .copy { color: var(--text-disabled); }
.hash:hover .copy { color: var(--brand-500); }

/* Cmd palette overlay */
.cmdk-overlay {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 0.5);
  backdrop-filter: blur(2px);
  z-index: 100;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
}
.cmdk-panel {
  width: 640px;
  max-width: 90vw;
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-popover);
  overflow: hidden;
}
.cmdk-panel input {
  width: 100%;
  height: 44px;
  background: transparent;
  border: 0;
  outline: 0;
  padding: 0 18px;
  font-size:var(--fs-sm);
  color: var(--text-primary);
  border-bottom: 1px solid var(--border-subtle);
}
.cmdk-panel input::placeholder { color: var(--text-disabled); }
.cmdk-panel .group {
  padding: 4px 0;
}
.cmdk-panel .group-label {
  padding: 6px 12px 2px;
  font-size:var(--fs-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-disabled);
  font-weight: 500;
}
.cmdk-panel .cmd {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  height: 32px;
  font-size:var(--fs-xs);
  color: var(--text-secondary);
  cursor: pointer;
}
.cmdk-panel .cmd .icon { color: var(--text-tertiary); }
.cmdk-panel .cmd .kbd {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
}
.cmdk-panel .cmd.active { background: var(--bg-2); color: var(--text-primary); }
.cmdk-panel .cmd.active .icon { color: var(--brand-500); }
.cmdk-panel .footer {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-top: 1px solid var(--border-subtle);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
}
.cmdk-panel .footer .spacer { flex: 1; }
.cmdk-panel .footer .kbd {
  padding: 1px 5px;
  border: 1px solid var(--border-default);
  border-radius: 2px;
}

/* Graph */
.graph-wrap {
  position: relative;
  width: 100%;
  height: 100%;
  background:
    radial-gradient(circle at 50% 35%, color-mix(in oklch, var(--brand-500) 4%, transparent), transparent 60%),
    var(--bg-0);
  overflow: hidden;
}
.graph-wrap .grid-bg {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--border-subtle) 1px, transparent 1px),
    linear-gradient(90deg, var(--border-subtle) 1px, transparent 1px);
  background-size: 32px 32px;
  background-position: -1px -1px;
  opacity: 0.4;
  pointer-events: none;
  mask-image: radial-gradient(ellipse 90% 80% at 50% 50%, black 30%, transparent 90%);
}
.graph-toolbar {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  gap: 6px;
  z-index: 2;
}
.graph-toolbar .group {
  display: flex;
  background: var(--bg-1);
  border: 1px solid var(--border-default);
  border-radius: var(--r-sm);
  padding: 2px;
  gap: 1px;
}
.graph-toolbar .group .b {
  padding: 4px 8px;
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  border-radius: 2px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.graph-toolbar .group .b:hover { color: var(--text-primary); background: var(--bg-2); }
.graph-toolbar .group .b.active { color: var(--text-primary); background: var(--bg-2); }
.graph-toolbar .group .b.active .icon { color: var(--brand-500); }

.zoom-ctrl {
  position: absolute;
  bottom: 12px;
  right: 12px;
  display: flex;
  flex-direction: column;
  z-index: 2;
  background: var(--bg-1);
  border: 1px solid var(--border-default);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.zoom-ctrl .b {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  cursor: pointer;
  border-bottom: 1px solid var(--border-subtle);
}
.zoom-ctrl .b:last-child { border-bottom: 0; }
.zoom-ctrl .b:hover { color: var(--text-primary); background: var(--bg-2); }
.zoom-ctrl .pct {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  text-align: center;
  padding: 2px 0;
  border-bottom: 1px solid var(--border-subtle);
}

.minimap {
  position: absolute;
  bottom: 12px;
  right: 56px;
  width: 200px;
  height: 120px;
  background: var(--bg-1);
  border: 1px solid var(--border-default);
  border-radius: var(--r-sm);
  z-index: 2;
  padding: 6px;
  overflow: hidden;
}
.minimap .label {
  position: absolute;
  top: 4px;
  left: 6px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-disabled);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  z-index: 2;
}

.legend {
  position: absolute;
  bottom: 12px;
  left: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  z-index: 2;
  max-width: 460px;
}
.legend .item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  background: var(--bg-1);
  border: 1px solid var(--border-default);
  border-radius: var(--r-sm);
  font-size:var(--fs-2xs);
  color: var(--text-secondary);
}
.legend .item .swatch {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

/* Graph nodes */
.gnode { cursor: pointer; transition: opacity 200ms ease; }
.gnode.dimmed { opacity: 0.18; }
.gnode .ring { fill: none; stroke-width: 1.5; }
.gnode .core { fill-opacity: 0.18; }
.gnode .glyph { font-family: var(--font-mono); font-size:var(--fs-2xs); fill: var(--text-primary); pointer-events: none; }
.gnode .lbl { font-family: var(--font-mono); font-size:var(--fs-2xs); fill: var(--text-secondary); pointer-events: none; }
.gnode .sub { font-family: var(--font-mono); font-size:var(--fs-2xs); fill: var(--text-tertiary); pointer-events: none; }
.gnode.selected .ring { stroke-width: 2.2; }
.gnode.selected .halo { stroke: var(--brand-500); fill: none; stroke-opacity: 0.25; stroke-width: 4; }

.gedge { transition: opacity 200ms ease; }
.gedge.dimmed { opacity: 0.06; }

/* Cards / dossier */
.dossier {
  display: grid;
  grid-template-columns: 1fr 360px;
  height: 100%;
  overflow: hidden;
}
.dossier .main-col {
  overflow: auto;
  padding: 20px 24px 40px;
}
.dossier .hero {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  gap: 20px;
  align-items: start;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border-subtle);
}
.dossier .hero .avatar {
  width: 96px;
  height: 96px;
  border-radius: var(--r-md);
  background:
    linear-gradient(135deg,
      color-mix(in oklch, var(--brand-500) 20%, var(--bg-2)),
      var(--bg-2));
  border: 1px solid var(--border-default);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  color: var(--text-primary);
  font-size:var(--fs-xl);
  position: relative;
  overflow: hidden;
}
.dossier .hero .avatar::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(45deg,
      transparent 0 6px,
      color-mix(in oklch, white 4%, transparent) 6px 7px);
  pointer-events: none;
}

/* Report */
.report-wrap {
  display: grid;
  grid-template-columns: 280px 1fr 320px;
  height: 100%;
}
.report-sections {
  background: var(--bg-1);
  border-right: 1px solid var(--border-subtle);
  padding: 8px 0;
  overflow: auto;
}
.report-sections .group-label {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-disabled);
  padding: 12px 16px 4px;
  font-weight: 500;
}
.report-sections .section-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  font-size:var(--fs-xs);
  color: var(--text-secondary);
  cursor: pointer;
  position: relative;
}
.report-sections .section-item:hover { background: var(--bg-2); color: var(--text-primary); }
.report-sections .section-item.active { color: var(--text-primary); background: var(--bg-2); }
.report-sections .section-item.active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0; bottom: 0;
  width: 2px;
  background: var(--brand-500);
}
.report-sections .section-item .n {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  width: 18px;
}
.report-sections .section-item .check {
  margin-left: auto;
  color: var(--success);
  font-size:var(--fs-2xs);
}
.report-canvas {
  overflow: auto;
  background:
    repeating-linear-gradient(0deg, var(--bg-0), var(--bg-0) 24px, color-mix(in oklch, white 1%, var(--bg-0)) 24px 25px);
  padding: 32px 0;
  display: flex;
  justify-content: center;
}
.report-paper {
  width: 720px;
  background: oklch(0.96 0.005 84);
  color: oklch(0.20 0.01 84);
  font-family: var(--font-serif);
  border-radius: var(--r-sm);
  padding: 48px 56px;
  min-height: 940px;
  font-size:var(--fs-2xs);
  line-height: 1.5;
  box-shadow: 0 24px 60px -16px rgb(0 0 0 / 0.6);
  position: relative;
}
.report-paper h1, .report-paper h2 {
  font-family: var(--font-sans);
  letter-spacing: -0.01em;
}
.report-paper h1 { font-size:var(--fs-xl); margin: 0 0 6px; font-weight: 500; }
.report-paper h2 {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: oklch(0.45 0.01 84);
  margin: 24px 0 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid oklch(0.85 0.01 84);
  font-weight: 600;
}
.report-paper .accent {
  display: block;
  width: 40px;
  height: 2px;
  background: var(--brand-600);
  margin: 8px 0 18px;
}
.report-paper .cover-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px 24px;
  margin-top: 16px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: oklch(0.35 0.01 84);
}
.report-paper .cover-meta .k { color: oklch(0.55 0.01 84); text-transform: uppercase; letter-spacing: 0.06em; }
.report-paper .classification {
  position: absolute;
  top: 24px;
  right: 24px;
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  letter-spacing: 0.1em;
  padding: 3px 6px;
  border: 1px solid var(--danger);
  color: var(--danger);
  text-transform: uppercase;
  background: oklch(0.96 0.005 84);
}
.report-paper .exhibit {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid oklch(0.88 0.01 84);
}
.report-paper .exhibit .ex-id {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: oklch(0.45 0.01 84);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.report-paper .exhibit .ex-body {
  font-family: var(--font-serif);
}
.report-paper .exhibit .ex-meta {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: oklch(0.5 0.01 84);
}
.report-paper .conf {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: oklch(0.4 0.01 84);
  background: oklch(0.93 0.01 84);
  padding: 1px 5px;
  border-radius: 2px;
  white-space: nowrap;
}
.report-paper .footer {
  margin-top: 40px;
  padding-top: 12px;
  border-top: 1px solid oklch(0.85 0.01 84);
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: oklch(0.5 0.01 84);
  display: flex;
  justify-content: space-between;
}

.report-side {
  background: var(--bg-1);
  border-left: 1px solid var(--border-subtle);
  padding: 16px;
  overflow: auto;
}

/* Evidence */
.evidence-grid {
  display: grid;
  grid-template-columns: 1fr 380px;
  height: 100%;
  overflow: hidden;
}
.evidence-list {
  overflow: auto;
}
.evidence-row {
  display: grid;
  grid-template-columns: 32px 28px 1fr auto auto auto;
  gap: 12px;
  align-items: center;
  padding: 10px 20px;
  border-bottom: 1px solid var(--border-subtle);
  cursor: pointer;
}
.evidence-row:hover { background: var(--bg-1); }
.evidence-row.selected { background: color-mix(in oklch, var(--brand-500) 8%, var(--bg-1)); box-shadow: inset 2px 0 0 var(--brand-500); }
.evidence-row .ex-id {
  font-family: var(--font-mono);
  font-size:var(--fs-2xs);
  color: var(--text-tertiary);
  text-transform: uppercase;
}
.evidence-row .icon-cell {
  width: 28px; height: 28px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-2);
  color: var(--text-tertiary);
}
.evidence-row .title-cell .t1 { font-size:var(--fs-sm); color: var(--text-primary); }
.evidence-row .title-cell .t2 { font-family: var(--font-mono); font-size:var(--fs-2xs); color: var(--text-tertiary); margin-top: 2px; }
.evidence-detail {
  border-left: 1px solid var(--border-subtle);
  background: var(--bg-1);
  overflow: auto;
}

/* Spark */
.spark-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 6px 0;
}

/* Animations */
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}
.pulse { animation: pulse-dot 1.4s ease-in-out infinite; }

@keyframes trace-march {
  to { stroke-dashoffset: -16; }
}
.trace-edge {
  stroke-dasharray: 4 4;
  animation: trace-march 600ms linear infinite;
}

/* Tweaks panel positioning override */
.tweaks-fab { z-index: 200; }

/* ──────────────────────────────────────────────────────────────────
   Motion & interaction layer — alpha929 art-direction pass.
   One consistent feel across every Bureau surface (login · signup ·
   attest · dashboard · workspace · marketing · pricing · admin). Re-tunes
   the shared components with the motion tokens above; placed last in the
   cascade so it augments their earlier definitions without rewriting them.
   Ends with a global prefers-reduced-motion guarantee for comfort.

   The interaction language, in two gestures:
   • Buttons feel SOLID — colour/border shift + a tactile press-down.
   • Cards & rows feel CLICKABLE — a subtle lift + a brighter border.
   ────────────────────────────────────────────────────────────────── */

/* Buttons — snappy, tactile. */
.btn {
  transition:
    background var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    filter var(--dur-1) var(--ease-out),
    transform var(--dur-1) var(--ease-out);
}
.btn:hover { filter: brightness(1.06); }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] { filter: none; transform: none; }

/* Form fields — one calm focus everywhere. The floor; a page's own
   richer field (.lg-input etc.) still wins where it defines its own. */
input, select, textarea {
  transition:
    border-color var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out),
    background var(--dur-2) var(--ease-out);
}

/* Cards, tiles & panels — invite the click. Opt in with .u-lift or
   [data-lift] on any clickable container. */
.u-lift, [data-lift] {
  transition:
    transform var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    background var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out);
}
.u-lift:hover, [data-lift]:hover {
  transform: translateY(var(--lift));
  border-color: var(--border-strong);
}

/* Smooth the existing interactive primitives (were instant / one-prop). */
.chip,
.navrail .item,
.topbar .cmdk,
.langsw-item,
.report-sections .section-item,
.evidence-row,
.table tbody tr td,
.hash,
a {
  transition:
    background var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out);
}

/* Shared entrance — opt-in, JS-free. Add data-reveal to settle a block
   in on load; stagger siblings with an inline --reveal-delay. Meaningful
   motion only: one subtle settle, never a load-spinner gimmick. */
@keyframes bureau-reveal {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
[data-reveal] {
  animation: bureau-reveal var(--dur-4) var(--ease-emphasis) both;
  animation-delay: var(--reveal-delay, 0ms);
}

/* Comfort & accessibility — honour the OS "reduce motion" request in one
   place: neutralise every transition/animation and smooth-scroll. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] { animation: none !important; opacity: 1 !important; transform: none !important; }
}
