
@import url('https://fonts.googleapis.com/css2?family=Source+Serif+4:opsz,wght@8..60,400;8..60,600;8..60,700&display=swap');
/* ============================================================
   Broadsheet — Design System for Briefed
   Root entry point. Import order: fonts → tokens → base.
   This file contains @import lines only.
   ============================================================ */
/* ---- Editorial serif (headline-only exception — see design.md) ---- */

/* ============================================================
   Broadsheet — Brown typeface (Lineto)
   The single voice of the Briefed brand.
   ------------------------------------------------------------
   Families exposed to consumers:
     "Brown"             — primary, weights 100/300/400/700 + italics
     "Brown Backslanted" — distinctive reverse-slant display cut
     "Brown Alt"         — single-story alternates for display lockups
   ============================================================ */

/* ---- Brown (upright) ---- */
@font-face {
  font-family: "Brown";
  font-weight: 100;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-Thin.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 100;
  font-style: italic;
  font-display: swap;
  src: url("../assets/fonts/Brown-ThinItalic.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 300;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-Light.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 300;
  font-style: italic;
  font-display: swap;
  src: url("../assets/fonts/Brown-LightItalic.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-Regular.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  src: url("../assets/fonts/Brown-RegularItalic.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-Bold.woff2") format("woff2");
}
@font-face {
  font-family: "Brown";
  font-weight: 700;
  font-style: italic;
  font-display: swap;
  src: url("../assets/fonts/Brown-BoldItalic.woff2") format("woff2");
}

/* ---- Brown Backslanted (reverse italic display cut) ---- */
@font-face {
  font-family: "Brown Backslanted";
  font-weight: 100;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-ThinBackslanted.woff2") format("woff2");
}
@font-face {
  font-family: "Brown Backslanted";
  font-weight: 300;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-LightBackslanted.woff2") format("woff2");
}
@font-face {
  font-family: "Brown Backslanted";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-RegularBackslanted.woff2") format("woff2");
}
@font-face {
  font-family: "Brown Backslanted";
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-BoldBackslanted.woff2") format("woff2");
}

/* ---- Brown Alt (single-story alternates, for display lockups) ---- */
@font-face {
  font-family: "Brown Alt";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-RegularAlt.woff2") format("woff2");
}
@font-face {
  font-family: "Brown Alt";
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  src: url("../assets/fonts/Brown-BoldAlt.woff2") format("woff2");
}
/* ============================================================
   Broadsheet — Color
   Charcoal (Ink) · Paper (White) · Signal (Blue)
   A restrained, editorial palette for a media & intelligence brand.
   ============================================================ */

:root {
  /* ---------- Ink (charcoal, blue-tinted neutral) ---------- */
  --ink-950: #0E0F13;
  --ink-900: #16181D;
  --ink-800: #1E212A;
  --ink-700: #2A2E3A;
  --ink-600: #3B414F;
  --ink-500: #545B6B;
  --ink-400: #717889;
  --ink-300: #9AA0AD;
  --ink-200: #C3C7D0;
  --ink-100: #E6E8EC;
  --ink-150: #DDE0E6;  /* hairline */
  --ink-50:  #F1F3F5;  /* tint */

  /* ---------- Paper (crisp, cool whites) ---------- */
  --paper-0:  #FFFFFF;  /* card / sheet */
  --paper-50: #F7F8FA;  /* app background — cool, crisp off-white */
  --paper-100:#EEF0F3;  /* sunken surface */
  --paper-200:#E3E6EB;  /* hairline fill */

  /* ---------- Signal (Briefed royal ink — editorial, not electric) ---------- */
  --blue-950: #0A1A3D;
  --blue-900: #0E2559;
  --blue-800: #123478;
  --blue-700: #17429B;  /* press */
  --blue-600: #1E4FC4;  /* primary signal — deep royal, ink-leaning */
  --blue-500: #2A5FDB;
  --blue-400: #5A82EE;
  --blue-300: #8AA6F5;
  --blue-200: #BACDFA;
  --blue-100: #DEE7FD;
  --blue-50:  #EFF3FE;

  /* ---------- Anya (deep space · purple — the AI sub-brand) ----------
     This ramp was an electric-blue scale ("precision blue"), which put the
     design system in direct contradiction with the brand. Anya renders purple
     everywhere a user can actually see her: the marketing page at
     briefedmedia.com/research/anya, the Research terminal, and her email. This
     ramp rendered for nobody — no package depends on @harrisonmedia/broadsheet
     and no consumer references --anya-*, so the blue was aspirational while
     three slightly different purples were in circulation downstream.

     The authority is that marketing page's own sheet
     (briefedmedia.com/app/research/anya/AnyaMarketing.module.css), which
     carries three real values and, importantly, distinguishes the dark-surface
     purple from the light-surface one — the distinction everything downstream
     got wrong:

       --star       #9B87E0   dark surfaces only (2.65:1 on light — never text)
       --star-deep  #5C3AA8   solid fills AND light-surface text
       --star-dim   #5A4785   quiet borders on charcoal

     Five steps below are those values plus the sheet's two near-blacks
     (--void / --void-2). The remaining six are straight sRGB interpolations
     between adjacent anchors, so no step was chosen independently of the
     brand. Regenerate the same way if an anchor moves rather than hand-tuning
     one step — a ramp with one hand-tuned step is how palettes drift. */
  --anya-950: #0B0D10;   /* brand: --void, near-black stamp ground */
  --anya-900: #0F1216;   /* brand: --void-2 */
  --anya-800: #28233B;   /* interpolated */
  --anya-700: #5A4785;   /* brand: --star-dim */
  --anya-600: #5C3AA8;   /* brand: --star-deep — solid fills, light-surface text */
  --anya-500: #765AC0;   /* interpolated */
  --anya-400: #9B87E0;   /* brand: --star — primary accent ON DARK ONLY */
  --anya-300: #B9ABE9;   /* interpolated */
  --anya-200: #D2C9F1;   /* interpolated */
  --anya-100: #E9E5F8;   /* interpolated */
  --anya-50:  #F7F5FD;   /* interpolated */

  /* ---------- Intelligence (navy — the enterprise tier) ----------
     Anchored on the brand's named Intelligence navy, #0B1B3A. Deliberately
     DESATURATED against the royal signal ramp: Plus is signal blue, so the
     Intelligence tier has to separate by value and chroma rather than hue, or
     the two premium tiers read as the same badge in two lightnesses. */
  --intel-950: #060E1E;
  --intel-900: #0B1B3A;  /* Intelligence navy — the tier surface */
  --intel-800: #12274C;
  --intel-700: #1B355F;
  --intel-600: #2A4872;  /* tier label on light */
  --intel-400: #56749E;  /* accent — steel, never royal */
  --intel-200: #B6C3D6;
  --intel-100: #DBE2EC;
  --intel-50:  #EEF2F7;

  /* Named brand alias — design.md calls this colour "Intelligence navy". */
  --navy: var(--intel-900);

  /* ---------- Semantic hues (restrained) ---------- */
  --green-600: #1E8A5B;
  --green-100: #DCF1E6;
  --amber-600: #B57514;
  --amber-100: #F8ECD4;
  --red-600:   #C8443B;
  --red-100:   #FAE2E0;

  /* ============================================================
     Semantic aliases — reference these in components
     ============================================================ */

  /* Text */
  --text-strong:   var(--ink-900);
  --text-body:     var(--ink-700);
  --text-muted:    var(--ink-500);
  --text-subtle:   var(--ink-400);
  --text-inverse:  var(--paper-0);
  --text-link:     var(--blue-600);
  --text-on-blue:  var(--paper-0);

  /* Surfaces */
  --surface-page:    var(--paper-50);
  --surface-card:    var(--paper-0);
  --surface-sunken:  var(--paper-100);
  --surface-inverse: var(--ink-900);
  --surface-brand:   var(--blue-600);
  --surface-intel:   var(--intel-900);

  /* Borders / lines */
  --border-hairline: var(--ink-100);
  --border-strong:   var(--ink-200);
  --border-rule:     var(--ink-900);   /* broadsheet column rule */
  --border-brand:    var(--blue-600);
  --border-focus:    var(--blue-500);

  /* Accents */
  --accent:          var(--blue-600);
  --accent-hover:    var(--blue-700);
  --accent-press:    var(--blue-900);
  --accent-soft:     var(--blue-50);
  --accent-soft-bd:  var(--blue-100);

  /* Status */
  --status-positive: var(--green-600);
  --status-positive-soft: var(--green-100);
  --status-caution:  var(--amber-600);
  --status-caution-soft: var(--amber-100);
  --status-critical: var(--red-600);
  --status-critical-soft: var(--red-100);

  /* Neutral soft fill (Badge neutral tone, quiet chips) */
  --neutral-soft:    var(--ink-100);
  --neutral-soft-bd: var(--ink-200);

  /* Skeleton (loading placeholders) */
  --skeleton-base:  var(--ink-100);

  /* Chart up/down — deeper than the status greens/reds. Status colours are for
     badges on white; a candle field needs ink-weight hues that hold at 1px and
     don't vibrate when thousands of them sit side by side. */
  --chart-up:   #0F7B45;
  --chart-down: #A8232B;

  /* Control fills — invert on dark so "on" always contrasts the surface */
  --control-on:      var(--ink-900);
  --control-on-fg:   var(--paper-0);
  --control-off:     var(--paper-0);
  --control-off-bd:  var(--ink-300);
  --control-track:   var(--ink-200);

  /* Accent hover/press recalibrated for the deeper ramp */

  /* ---------- Sourcing tiers ----------
     The signature vocabulary. Named here rather than inside ProvenanceBar so
     that anything else rendering sourcing agrees with it — a primary document
     has to look like a primary document wherever it appears.
     Height/weight carries the same rank — see ProvenanceBar. */
  --tier-primary:   var(--ink-900);   /* filed primary document */
  --tier-secondary: var(--ink-400);   /* corroborating reporting */
  --tier-wire:      var(--blue-400);  /* wire / unconfirmed */

  /* Toast shell — always dark, and deliberately NOT --ink-900: on ink that is
     also --surface-card, so a toast over a card would vanish. */
  --toast-surface: var(--ink-900);

  /* Focus ring — the ring itself is an `outline` (see base.css), not a shadow,
     so there is deliberately no shadow token for it: a box-shadow ring gets
     clipped by `overflow: hidden` and must not be reachable by accident.
     Its colour is --border-focus, declared with the other borders above. */
}
/* ============================================================
   Broadsheet — Theme layer
   Dark ("ink") is a THEME, not a per-component prop. Set
   data-theme="ink" on <html>, <body>, or any subtree and every
   component that references semantic tokens inverts correctly.

     <body data-theme="ink">            → whole app dark
     <section data-theme="ink">…        → one dark region

   Only the SEMANTIC aliases are remapped here. The raw ramps
   (--ink-*, --paper-*, --blue-*) never change meaning — that's
   what makes the inversion predictable.
   ============================================================ */

[data-theme="ink"] {
  /* Text — pure white is reserved for headlines; body steps down */
  --text-strong:   #FFFFFF;
  --text-body:     rgba(255, 255, 255, 0.76);
  --text-muted:    rgba(255, 255, 255, 0.56);
  --text-subtle:   rgba(255, 255, 255, 0.40);
  --text-inverse:  var(--ink-900);
  --text-link:     var(--blue-300);
  --text-on-blue:  #FFFFFF;

  /* Surfaces — the page is the deepest value; cards lift toward the viewer */
  --surface-page:    var(--ink-950);
  --surface-card:    var(--ink-900);
  --surface-sunken:  #0A0B0E;
  --surface-inverse: var(--paper-0);
  --surface-brand:   var(--blue-600);
  --surface-intel:   var(--intel-900);

  /* Borders — on dark, hairlines are light-on-dark washes, not grey fills */
  --border-hairline: rgba(255, 255, 255, 0.10);
  --border-strong:   rgba(255, 255, 255, 0.20);
  --border-rule:     rgba(255, 255, 255, 0.88);
  --border-brand:    var(--blue-400);
  --border-focus:    var(--blue-400);

  /* Accents — the ramp shifts UP on dark so blue stays legible on charcoal */
  --accent:          var(--blue-500);
  --accent-hover:    var(--blue-400);
  --accent-press:    var(--blue-600);
  --accent-soft:     rgba(42, 95, 219, 0.16);
  --accent-soft-bd:  rgba(90, 130, 238, 0.32);

  /* Status — soft fills become low-alpha washes of the same hue */
  --status-positive:      #4CC38A;
  --status-positive-soft: rgba(76, 195, 138, 0.16);
  --status-caution:       #E0A83B;
  --status-caution-soft:  rgba(224, 168, 59, 0.16);
  --status-critical:      #EE6A60;
  --status-critical-soft: rgba(238, 106, 96, 0.16);

  /* Neutral soft fill */
  --neutral-soft:    rgba(255, 255, 255, 0.10);
  --neutral-soft-bd: rgba(255, 255, 255, 0.20);

  /* Skeleton */
  --skeleton-base:  rgba(255, 255, 255, 0.09);

  /* Chart up/down — lifted on ink so 1px candles stay legible on charcoal */
  --chart-up:   #3FBE7D;
  --chart-down: #E8635C;

  /* Sourcing tiers — primary flips to white on charcoal, secondary to a wash.
     Wire stays blue: it is a hue signal, not a value signal. */
  --tier-primary:   #FFFFFF;
  --tier-secondary: rgba(255, 255, 255, 0.55);
  --tier-wire:      var(--blue-400);

  /* Toast lifts one step ABOVE the card so it still reads as floating on a
     near-black page (--ink-900 is --surface-card here). */
  --toast-surface: var(--ink-800);

  /* Focus ring colour lifts on ink so the outline reads against charcoal. */
  --border-focus: var(--blue-400);

  /* Control fills — "on" becomes white on charcoal, and the knob/glyph goes dark */
  --control-on:      #FFFFFF;
  --control-on-fg:   var(--ink-900);
  --control-off:     rgba(255, 255, 255, 0.06);
  --control-off-bd:  rgba(255, 255, 255, 0.26);
  --control-track:   rgba(255, 255, 255, 0.18);

  /* Elevation — shadows barely read on dark; borders carry elevation instead.
     Keep the same token names so components need no changes. */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.40);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.36), 0 2px 6px rgba(0, 0, 0, 0.30);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.34), 0 8px 22px rgba(0, 0, 0, 0.38);
  --shadow-lg: 0 4px 8px rgba(0, 0, 0, 0.36), 0 18px 44px rgba(0, 0, 0, 0.46);
  --shadow-xl: 0 8px 16px rgba(0, 0, 0, 0.40), 0 36px 80px rgba(0, 0, 0, 0.60);

  --scrim: rgba(0, 0, 0, 0.68);
}

/* Raised surfaces on dark need a top-edge catchlight to read as lifted —
   a shadow alone disappears against a near-black page. */
[data-theme="ink"] .bs-surface--raised,
[data-theme="ink"] .bs-modal-panel,
[data-theme="ink"] .bs-drawer-panel {
  border: 1px solid rgba(255, 255, 255, 0.09);
}

/* Set the page background + text from the theme so a bare
   data-theme="ink" region paints correctly with no extra classes. */
[data-theme="ink"] { background: var(--surface-page); color: var(--text-body); color-scheme: dark; }
/* ============================================================
   Broadsheet — Typography
   One typeface (Brown), used with editorial discipline.
   ============================================================ */

:root {
  /* ---------- Families ---------- */
  --font-sans: "Brown", "Helvetica Neue", Arial, system-ui, sans-serif;
  --font-display: "Brown", "Helvetica Neue", Arial, sans-serif;
  --font-backslant: "Brown Backslanted", "Brown", sans-serif; /* reverse-slant display */
  --font-alt: "Brown Alt", "Brown", sans-serif;               /* single-story lockups */
  --font-editorial: "Source Serif 4", Georgia, "Times New Roman", serif; /* headline-only exception — the front page moment */
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* ---------- Weights ----------
     Brown ships EXACTLY four faces. There is no 500 and no 600 — asking for
     them silently renders 400 and 700, which is how a "medium" rule can look
     applied in code and be absent on screen. Only use these four tokens. */
  --weight-thin: 100;      /* display-scale numerals only */
  --weight-light: 300;     /* deks and lead paragraphs, >=17px only */
  --weight-regular: 400;   /* body AND all interactive chrome */
  --weight-bold: 700;      /* headlines, brand, tracked-caps labels, overlay titles */

  /* DEPRECATED alias. Kept defined ONLY so that any lingering reference resolves
     to a real value instead of nothing: an unresolved var() inside a `font:`
     shorthand invalidates the WHOLE declaration (size and family too), not just
     the weight. Never use this in new code. */
  --weight-medium: 400;

  /* ---------- Type scale (1.250 major-third, 16px base) ---------- */
  --text-2xs: 11px;
  --text-xs:  12px;
  --text-sm:  14px;
  --text-base:16px;
  --text-md:  18px;
  --text-lg:  21px;
  --text-xl:  26px;
  --text-2xl: 33px;
  --text-3xl: 42px;
  --text-4xl: 54px;
  --text-5xl: 68px;
  --text-6xl: 88px;

  /* ---------- Line heights ---------- */
  --leading-tight: 1.05;
  --leading-snug: 1.18;
  --leading-normal: 1.5;
  --leading-relaxed: 1.65;

  /* ---------- Tracking ---------- */
  --tracking-display: -0.035em; /* 68–88px grotesk — tighten hard, optical */
  --tracking-tight: -0.022em;
  --tracking-snug: -0.012em;
  --tracking-normal: 0em;
  --tracking-wide: 0.04em;
  --tracking-caps: 0.14em;   /* eyebrows / kickers — a touch more air */
  --tracking-editorial: -0.008em; /* serif headlines track looser than grotesk */

  /* ============================================================
     Semantic text roles
     ============================================================ */
  --type-display:  var(--weight-bold) var(--text-6xl)/var(--leading-tight) var(--font-sans);
  --type-h1:       var(--weight-bold) var(--text-4xl)/var(--leading-tight) var(--font-sans);
  --type-h2:       var(--weight-bold) var(--text-3xl)/var(--leading-snug) var(--font-sans);
  --type-h3:       var(--weight-bold) var(--text-2xl)/var(--leading-snug) var(--font-sans);
  --type-h4:       var(--weight-bold) var(--text-xl)/var(--leading-snug) var(--font-sans);
  --type-lead:     var(--weight-light) var(--text-lg)/var(--leading-relaxed) var(--font-sans);
  --type-body:     var(--weight-regular) var(--text-base)/var(--leading-normal) var(--font-sans);
  --type-body-sm:  var(--weight-regular) var(--text-sm)/var(--leading-normal) var(--font-sans);
  --type-caption:  var(--weight-regular) var(--text-xs)/var(--leading-normal) var(--font-sans);
}

/* Kicker / eyebrow utility — the broadsheet "section label" */
.broadsheet-kicker {
  font-family: var(--font-sans);
  font-weight: var(--weight-bold);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}
/* ============================================================
   Broadsheet — Spacing, Radius, Shadow, Layout
   8px base grid. Near-square radii. Crisp, short-throw shadows.
   ============================================================ */

:root {
  /* ---------- Spacing (8px base grid) ---------- */
  --space-0: 0;
  --space-1: 2px;
  --space-2: 4px;
  --space-3: 8px;
  --space-4: 12px;
  --space-5: 16px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --space-9: 48px;
  --space-10: 64px;
  --space-11: 80px;
  --space-12: 112px;

  /* ---------- Radius (four steps, near-square — this is a newspaper) ----------
     A broadsheet has square corners. Rounded panels are the SaaS card idiom and
     the single loudest generic signal a system can send, so Broadsheet sits as
     close to square as a screen interface can without reading as unfinished:
     containers are sheets of paper, controls get 2px so they read as objects.

     FOUR steps, not six. Every token here is a distinct value — a scale with two
     names for the same number is slack pretending to be semantics, and it lets
     a consumer believe there's a choice where there isn't.
     Going UP from these values is a decision to look like everyone else. */
  --radius-none: 0;    /* checkboxes, count chips, inline marks, full-bleed */
  --radius-sm: 2px;    /* THE workhorse — buttons, inputs, menu rows, day cells */
  --radius-md: 3px;    /* panels, cards, popovers, drawers */
  --radius-lg: 4px;    /* modals, the command palette */
  /* Reserved for the switch track and avatars ONLY — a pill is a physical
     metaphor (a toggle, a face), not a default shape for chips and buttons. */
  --radius-pill: 999px;

  /* ---------- Controls (one scale — Button, Input, Select must align) ----------
     Any control that can sit in a row with another control uses these. */
  --control-h-sm: 32px;
  --control-h-md: 38px;
  --control-h-lg: 44px;
  --control-radius: var(--radius-sm);

  /* ---------- Borders ---------- */
  --border-width-hair: 1px;
  --border-width-rule: 2px;
  --border-width-heavy: 3px;

  /* ---------- Shadows (crisp, short-throw — paper lifted, not glass floating)
     Long soft blurs read as the default modern app. Editorial elevation is a
     tighter, slightly darker shadow: the surface sits just off the page rather
     than hovering above it. */
  --shadow-xs: 0 1px 1px rgba(12, 16, 33, 0.06);
  --shadow-sm: 0 1px 2px rgba(12, 16, 33, 0.07), 0 1px 1px rgba(12, 16, 33, 0.04);
  --shadow-md: 0 2px 6px rgba(12, 16, 33, 0.09), 0 1px 2px rgba(12, 16, 33, 0.05);
  --shadow-lg: 0 6px 16px rgba(12, 16, 33, 0.12), 0 2px 4px rgba(12, 16, 33, 0.06);
  --shadow-xl: 0 16px 40px rgba(12, 16, 33, 0.20), 0 4px 8px rgba(12, 16, 33, 0.08);

  /* ---------- Scrim (overlay backdrop) ---------- */
  --scrim: rgba(9, 12, 20, 0.52);

  /* ---------- Layout ---------- */
  --container-narrow: 720px;   /* article column */
  --container-base: 1040px;
  --container-wide: 1280px;
  --container-full: 1440px;
  --gutter: 24px;

  /* ---------- Motion ---------- */
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);   /* @kind other */
  --ease-entrance: cubic-bezier(0.16, 1, 0.3, 1); /* @kind other */
  --ease-exit: cubic-bezier(0.4, 0, 1, 1);        /* @kind other */
  --dur-fast: 120ms;  /* @kind other */
  --dur-base: 200ms;  /* @kind other */
  --dur-slow: 320ms;  /* @kind other */

  /* ---------- Z-index ---------- */
  --z-base: 1;        /* @kind other */
  --z-sticky: 100;    /* @kind other */
  --z-overlay: 1000;  /* @kind other */
  --z-modal: 1100;    /* @kind other */
  --z-toast: 1200;    /* @kind other */
}
/* ============================================================
   Broadsheet — Base layer
   Light reset + brand defaults + a few editorial utilities.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  font: var(--type-body);
  color: var(--text-body);
  background: var(--surface-page);
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  font-variant-numeric: proportional-nums;
}

h1, h2, h3, h4, h5, h6, p, figure { margin: 0; }

a { color: var(--text-link); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

::selection { background: color-mix(in srgb, var(--blue-500) 22%, transparent); color: var(--ink-900); }

/* ---------- Heading helpers ---------- */
.bs-display { font: var(--type-display); color: var(--text-strong); letter-spacing: var(--tracking-display); }
.bs-h1 { font: var(--type-h1); color: var(--text-strong); letter-spacing: var(--tracking-tight); }
.bs-h2 { font: var(--type-h2); color: var(--text-strong); letter-spacing: var(--tracking-snug); }
.bs-h3 { font: var(--type-h3); color: var(--text-strong); letter-spacing: var(--tracking-snug); }
.bs-h4 { font: var(--type-h4); color: var(--text-strong); }
.bs-lead { font: var(--type-lead); color: var(--text-body); }
.bs-body { font: var(--type-body); color: var(--text-body); }
.bs-caption { font: var(--type-caption); color: var(--text-muted); }

/* ---------- The broadsheet rule: a heavy top hairline ---------- */
.bs-rule {
  border-top: var(--border-width-rule) solid var(--border-rule);
}
.bs-hairline {
  border-top: var(--border-width-hair) solid var(--border-hairline);
}

/* ---------- Editorial kicker with a leading rule-mark ---------- */
/* The signature broadsheet device: a short blue rule, then the tracked label. */
.bs-kicker {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: var(--weight-bold) var(--text-xs)/1 var(--font-sans);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-900);
}
.bs-kicker::before {
  content: "";
  width: 16px;
  height: 2px;
  background: var(--blue-600);
  flex: none;
}
.bs-kicker--blue { color: var(--blue-700); }
.bs-kicker--inverse { color: #fff; }
.bs-kicker--inverse::before { background: var(--blue-400); }

/* ---------- Section header: heavy rule + label, newspaper style ---------- */
.bs-section-head {
  border-top: var(--border-width-heavy) solid var(--ink-900);
  padding-top: 10px;
  display: flex;
  align-items: baseline;
  gap: 12px;
}

/* ---------- Focus visibility ----------
   ONE focus mechanism system-wide: a 2px outline at 2px offset.

   This used to be `outline: none; box-shadow: var(--ring)`. Two reasons it had
   to go, not just be overridden:
   · A box-shadow ring is painted inside the border box's paint area, so an
     ancestor's `overflow: hidden` clips it — table rows, menu items and graph
     plates all silently lost their focus ring.
   · `:where()` contributes zero specificity, so the class rules in
     components.css won `outline` but could not reset `box-shadow`, and every
     focused control rendered BOTH rings.
   It also no longer sets `border-radius` — a focus style must never change an
   element's geometry. */
:where(button, a, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
/* ============================================================
   Broadsheet — Component interaction states
   Hover / press / focus for every interactive primitive.
   ============================================================ */

.bs-btn { -webkit-tap-highlight-color: transparent; }
@keyframes bs-scrim-in { from { opacity: 0 } to { opacity: 1 } }
@keyframes bs-skeleton-pulse { 0%,100% { opacity: 1 } 50% { opacity: .45 } }
.bs-skeleton { animation: bs-skeleton-pulse 1.6s var(--ease-standard) infinite }
@keyframes bs-spin { to { transform: rotate(360deg) } }
.bs-spinner { animation: bs-spin 620ms linear infinite; transform-origin: 50% 50% }
@media (prefers-reduced-motion: reduce) { .bs-skeleton { animation: none } .bs-spinner { animation-duration: 2.4s } }
@keyframes bs-modal-in { from { opacity: 0; transform: translateY(8px) scale(0.98) } to { opacity: 1; transform: translateY(0) scale(1) } }
@keyframes bs-drawer-in { from { transform: translateX(100%) } to { transform: translateX(0) } }
.bs-scrim { animation: bs-scrim-in var(--dur-base) var(--ease-standard) both }
.bs-modal-panel { animation: bs-modal-in var(--dur-slow) var(--ease-entrance) both }
.bs-drawer-panel { animation: bs-drawer-in var(--dur-slow) var(--ease-entrance) both }
@media (prefers-reduced-motion: reduce) { .bs-scrim, .bs-modal-panel, .bs-drawer-panel { animation-duration: 1ms } }

/* ============================================================
   FOCUS — keyboard only, and it must never move layout.

   Three rules the whole system obeys:

   1. `:focus-visible`, never bare `:focus`. A mouse click on a button should
      not leave a ring behind it; a Tab press must. Bare `:focus` cannot tell
      those apart, so it either rings on click (noisy) or gets suppressed with
      `outline: none` (inaccessible) — and this system was doing the latter
      everywhere except Input.
   2. The ring is an `outline` with an `outline-offset`, not a `box-shadow`.
      An outline is painted outside the border box, so it can't be clipped by an
      ancestor's `overflow: hidden` — which is exactly what happens to a
      box-shadow ring on a table row, a menu item, or a graph plate.
   3. One ring, everywhere. A single `.bs-focusable` contract means a new
      component gets correct focus by adding a class, not by inventing a style.
   ============================================================ */

.bs-btn:focus-visible,
.bs-input:focus-visible,
.bs-tab:focus-visible,
.bs-icon-btn:focus-visible,
.bs-menu-item:focus-visible,
.bs-chip:focus-visible,
.bs-chip-x:focus-visible,
.bs-page-btn:focus-visible,
.bs-crumb:focus-visible,
.bs-segment:focus-visible,
.bs-range-btn:focus-visible,
.bs-graph-node:focus-visible,
.bs-nav-item:focus-visible,
.bs-accordion-trigger:focus-visible,
.bs-day:focus-visible,
.bs-story:focus-visible,
.bs-focusable:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}
/* Tight-fitting controls sit flush against neighbours; a 2px offset there would
   overlap the next control, so they ring on the border box itself. */
.bs-menu-item:focus-visible,
.bs-table-row:focus-visible,
.bs-segment:focus-visible,
.bs-range-btn:focus-visible { outline-offset: -1px; }

/* Inputs keep a border-colour change as well: the field is large enough that a
   ring alone reads as decoration rather than "this is where typing goes". */
.bs-input:focus-visible { border-color: var(--border-focus); }
/* A mouse click into a text field gets the border cue WITHOUT the ring. This
   must be `:focus:not(:focus-visible)`, never bare `:focus` — `:focus-visible`
   is a subset of `:focus`, so a bare-`:focus` rule also matches keyboard focus
   and (at equal specificity, later in source order) would strip the ring the
   rule above just set. */
.bs-input:focus:not(:focus-visible) { outline: none; border-color: var(--border-focus); }

/* Buttons */
.bs-btn--primary:hover:not(:disabled)   { background: var(--ink-700) !important; border-color: var(--ink-700) !important; }
.bs-btn--primary:active:not(:disabled)  { background: var(--ink-800) !important; transform: translateY(0.5px); }
.bs-btn--accent:hover:not(:disabled)    { background: var(--accent-hover) !important; border-color: var(--accent-hover) !important; }
.bs-btn--accent:active:not(:disabled)   { background: var(--accent-press) !important; transform: translateY(0.5px); }
.bs-btn--secondary:hover:not(:disabled) { background: var(--surface-sunken) !important; border-color: var(--text-subtle) !important; }
.bs-btn--secondary:active:not(:disabled){ background: var(--surface-sunken) !important; transform: translateY(0.5px); }
.bs-btn--ghost:hover:not(:disabled)     { background: var(--surface-sunken) !important; }
.bs-btn--ghost:active:not(:disabled)    { background: var(--surface-sunken) !important; transform: translateY(0.5px); }
.bs-btn--danger:hover:not(:disabled)    { background: #b03a32 !important; border-color: #b03a32 !important; }
.bs-btn--danger:active:not(:disabled)   { transform: translateY(0.5px); }

/* Inputs */
.bs-input { transition: border-color var(--dur-fast) var(--ease-standard); }
.bs-input:hover:not(:focus) { border-color: var(--border-strong); }
.bs-input::placeholder { color: var(--text-subtle); }

/* Tabs */
.bs-tab { transition: color var(--dur-fast), border-color var(--dur-fast); }
.bs-tab:hover { color: var(--text-strong); }

/* Editorial story: headline turns blue on hover (link behavior), no card lift */
.bs-story { transition: opacity var(--dur-fast) var(--ease-standard); }
.bs-story-head { transition: color var(--dur-fast) var(--ease-standard); }
.bs-story:hover .bs-story-head { color: var(--accent); }

/* Icon buttons (Modal / Drawer / Toast / Alert close) */
.bs-icon-btn { transition: background var(--dur-fast) var(--ease-standard); }
.bs-icon-btn:hover { background: var(--surface-sunken) !important; }
.bs-icon-btn:active { transform: translateY(0.5px); }
.bs-icon-btn--inverse:hover { background: rgba(255,255,255,.1) !important; }

/* Table rows */
.bs-table-row { transition: background var(--dur-fast) var(--ease-standard); }
.bs-table-row:hover { background: var(--surface-sunken) !important; }

/* Menu / chip / pagination / breadcrumb / segmented / tree / split */
.bs-menu-item { transition: background var(--dur-fast) var(--ease-standard); }
.bs-menu-item:hover:not(:disabled) { background: var(--surface-sunken); }
.bs-chip { transition: border-color var(--dur-fast), color var(--dur-fast), background var(--dur-fast); }
.bs-chip:hover { border-color: var(--text-subtle); }
.bs-chip-x { transition: background var(--dur-fast), color var(--dur-fast); }
.bs-chip-x:hover { background: var(--surface-sunken); color: var(--text-strong) !important; }
.bs-page-btn { transition: background var(--dur-fast), border-color var(--dur-fast); }
.bs-page-btn:hover:not(:disabled):not([aria-current]) { background: var(--surface-sunken); }
.bs-page-btn:active:not(:disabled) { transform: translateY(0.5px); }
.bs-crumb { transition: color var(--dur-fast); }
.bs-crumb:hover { color: var(--text-strong); }
.bs-segment { transition: color var(--dur-fast), background var(--dur-fast); }
.bs-segment:hover:not([aria-checked="true"]) { color: var(--text-strong); }
.bs-range-btn { transition: color var(--dur-fast), background var(--dur-fast); }
.bs-range-btn:hover:not([aria-pressed="true"]) { color: var(--text-strong); }
.bs-graph-node:hover { border-color: var(--border-strong); }
.bs-day { transition: background var(--dur-fast) var(--ease-standard); }
.bs-day:hover:not(:disabled) { background: var(--surface-sunken); }
.bs-stepper { transition: background var(--dur-fast), color var(--dur-fast); }
.bs-stepper:hover:not(:disabled) { background: var(--surface-sunken); color: var(--text-strong); }
.bs-slider-handle { transition: box-shadow var(--dur-fast) var(--ease-standard); }
.bs-slider-handle:hover:not([aria-disabled="true"]) { box-shadow: 0 0 0 4px var(--accent-soft); }
.bs-slider-handle:active { cursor: grabbing; }
.bs-tree-row { transition: background var(--dur-fast) var(--ease-standard); }
.bs-tree-row:hover:not([aria-selected="true"]) { background: var(--surface-sunken); }
.bs-inline-edit { transition: background var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast); }
.bs-inline-edit:hover:not(:disabled) { background: var(--surface-sunken); box-shadow: inset 0 -1px 0 var(--border-strong); }
.bs-inline-edit:hover:not(:disabled) .bs-inline-edit-pencil { opacity: 1 !important; }
.bs-inline-edit-pencil { transition: opacity var(--dur-fast) var(--ease-standard); }
.bs-split-handle:hover span, .bs-split-handle:focus-visible span { background: var(--accent) !important; }
.bs-dropzone:hover:not(:disabled) { border-color: var(--text-subtle); }
.bs-numfield::placeholder { color: var(--text-subtle); }
.bs-popover { animation: bs-pop-in var(--dur-fast) var(--ease-entrance) both }
@keyframes bs-pop-in { from { opacity: 0; transform: translateY(-3px) } to { opacity: 1; transform: translateY(0) } }
@media (prefers-reduced-motion: reduce) { .bs-popover { animation-duration: 1ms } }
.bs-nav-item { transition: background var(--dur-fast) var(--ease-standard), color var(--dur-fast); }
.bs-nav-item:hover:not([aria-current]) { background: var(--surface-sunken); color: var(--text-strong) !important; }
.bs-accordion-trigger { transition: color var(--dur-fast); }
.bs-accordion-trigger:hover { color: var(--accent); }

/* Anything disabled stops responding — no hover, no press, no pointer. */
.bs-btn:disabled, .bs-page-btn:disabled, .bs-menu-item:disabled { cursor: not-allowed; }
.bs-btn:disabled:active, .bs-page-btn:disabled:active { transform: none; }

/* Press feedback is a 0.5px nudge, which reads as a physical push without
   moving neighbours. Suppress it for anyone who asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .bs-btn:active, .bs-icon-btn:active, .bs-page-btn:active { transform: none !important; }
}

/* ---- Dark-theme interaction states ----
   Hovers that read as "slightly darker fill" on paper must read as
   "slightly lighter fill" on ink, so they're remapped rather than inherited. */
[data-theme="ink"] .bs-btn--primary:hover:not(:disabled)   { background: #fff !important; border-color: #fff !important; color: var(--ink-900) !important; }
[data-theme="ink"] .bs-btn--primary:active:not(:disabled)  { background: rgba(255,255,255,.88) !important; }
[data-theme="ink"] .bs-btn--secondary:hover:not(:disabled) { background: rgba(255,255,255,.07) !important; border-color: var(--border-strong) !important; }
[data-theme="ink"] .bs-btn--secondary:active:not(:disabled){ background: rgba(255,255,255,.12) !important; }
[data-theme="ink"] .bs-btn--ghost:hover:not(:disabled)     { background: rgba(255,255,255,.07) !important; }
[data-theme="ink"] .bs-btn--ghost:active:not(:disabled)    { background: rgba(255,255,255,.12) !important; }
[data-theme="ink"] .bs-table-row:hover  { background: rgba(255,255,255,.05) !important; }
[data-theme="ink"] .bs-icon-btn:hover   { background: rgba(255,255,255,.09) !important; }
[data-theme="ink"] .bs-story:hover .bs-story-head { color: var(--blue-300); }
[data-theme="ink"] .bs-menu-item:hover:not(:disabled) { background: rgba(255,255,255,.07); }
[data-theme="ink"] .bs-chip-x:hover { background: rgba(255,255,255,.09); }
[data-theme="ink"] .bs-page-btn:hover:not(:disabled):not([aria-current]) { background: rgba(255,255,255,.07); }
[data-theme="ink"] .bs-nav-item:hover:not([aria-current]) { background: rgba(255,255,255,.07); }
