/* ==========================================================================
   EntropyCast — GLOBAL DESIGN SYSTEM
   --------------------------------------------------------------------------
   This file contains ONLY global, product-wide primitives:
     1.  Design tokens (CSS custom properties): color, type, space, radius,
         elevation, motion.
     2.  Theme definitions (dark = default, light = optional/secondary).
     3.  Reset + element base styles.
     4.  A tiny set of layout/utility helpers used across every page.

   Component-specific styles live in `components.css` and each component
   block there names the tokens it depends on.

   Art direction: GitHub density (1px borders, quiet cards, mono for data)
   blended with Perplexity calm (whitespace around a central input,
   restrained color, typography over decoration).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS — DARK THEME (default)
   Backgrounds are never flat black: deep slate lifted with a teal undertone,
   then dressed with a low-opacity film-grain (see `body::before`).
   -------------------------------------------------------------------------- */
:root {
  color-scheme: dark;

  /* ---- Base / background ---- */
  --bg-950: #080b0e;                 /* deepest — page base behind gradient   */
  --bg-900: #0b1116;                 /* slate-900 with teal undertone         */
  --bg-850: #0d151a;                 /* dark-teal end of the gradient         */
  --bg-gradient: radial-gradient(
      120% 90% at 15% -10%,
      #0e1a1e 0%, transparent 55%),
    linear-gradient(168deg, var(--bg-950) 0%, var(--bg-900) 46%, var(--bg-850) 100%);

  /* ---- Surfaces / elevation (2–3 levels) ---- */
  --surface-1: #10171d;              /* quiet cards, table rows               */
  --surface-2: #151d25;              /* raised cards, popovers, topbar        */
  --surface-3: #1b2530;              /* modals, menus, active states          */
  --surface-inset: #0c1217;         /* wells, code, inputs                   */

  /* ---- Hairlines / borders ---- */
  --border-hairline: rgba(233, 241, 247, 0.09);   /* default 1px separators  */
  --border-soft:     rgba(233, 241, 247, 0.06);
  --border-strong:   rgba(233, 241, 247, 0.16);   /* focused / emphasised    */

  /* ---- Text ---- */
  --text-primary:   #e7eef4;
  --text-secondary: #9db0bd;
  --text-tertiary:  #667581;
  --text-on-accent: #04120f;
  --text-link:      #58afc9;

  /* ---- Brand accent (restrained, calm cyan) ---- */
  --accent-500: #2f98b8;
  --accent-400: #46aecd;
  --accent-300: #7bc5dc;
  --accent-soft-bg:     rgba(47, 152, 184, 0.12);
  --accent-soft-border: rgba(47, 152, 184, 0.30);

  /* ------------------------------------------------------------------
     SEMANTIC STATES — this product needs more than success/error.
     Four layer/status colors + a reserved pair for movement only.
     ------------------------------------------------------------------ */

  /* verified — HISTORICAL, settled. Calm, desaturated teal. */
  --verified-fg:     #5fb8a9;
  --verified-bg:     rgba(95, 184, 169, 0.12);
  --verified-border: rgba(95, 184, 169, 0.34);

  /* live / pending — PRESENT, unresolved. Active, not alarming. Amber, pulses. */
  --live-fg:     #e0a53f;
  --live-bg:     rgba(224, 165, 63, 0.13);
  --live-border: rgba(224, 165, 63, 0.36);
  --live-glow:   rgba(224, 165, 63, 0.45);

  /* predictive — FUTURE, priced by the market. Distinct violet/indigo so it
     is never mistaken for a plain success/error state. */
  --predictive-fg:     #9a8cf2;
  --predictive-bg:     rgba(154, 140, 242, 0.14);
  --predictive-border: rgba(154, 140, 242, 0.36);
  --predictive-glow:   rgba(154, 140, 242, 0.40);

  /* MOVEMENT ONLY — pure green/red is reserved for probability deltas and
     P&L. Never use these for generic UI status. */
  --move-up:   #3fb950;
  --move-down: #f4544a;
  --move-up-bg:   rgba(63, 185, 80, 0.13);
  --move-down-bg: rgba(244, 84, 74, 0.13);

  /* informational / neutral system messages (frequent, expected) */
  --info-fg:     #6ab0e6;
  --info-bg:     rgba(106, 176, 230, 0.12);
  --info-border: rgba(106, 176, 230, 0.34);

  /* warning (below-threshold contribution, low liquidity, …) */
  --warn-fg:     #e0a53f;
  --warn-bg:     rgba(224, 165, 63, 0.12);
  --warn-border: rgba(224, 165, 63, 0.34);

  /* danger (destructive confirm, hard errors) */
  --danger-fg:     #f4544a;
  --danger-bg:     rgba(244, 84, 74, 0.12);
  --danger-border: rgba(244, 84, 74, 0.36);

  /* principal identity — quiet, consistent badge wherever authorship shows */
  --human-fg:  #9db0bd;
  --human-bg:  rgba(157, 176, 189, 0.10);
  --agent-fg:  #7cc6d6;
  --agent-bg:  rgba(124, 198, 214, 0.12);
  --agent-border: rgba(124, 198, 214, 0.32);

  /* --------------------------------------------------------------
     2. TYPOGRAPHY
     UI  = clean sans.   MONO = every number that is *data*
     (probabilities, prices, timestamps, ledger rows, Brier scores).
     -------------------------------------------------------------- */
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu,
    Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", "JetBrains Mono", "Roboto Mono",
    Menlo, Consolas, "Liberation Mono", monospace;

  --text-2xs: 0.6875rem;   /* 11 — dense table meta, breadcrumb trail        */
  --text-xs:  0.75rem;     /* 12 — captions, badges                          */
  --text-sm:  0.8125rem;   /* 13 — secondary body, table cells              */
  --text-base:0.9375rem;   /* 15 — default body                             */
  --text-md:  1.0625rem;   /* 17 — lead paragraph                           */
  --text-lg:  1.25rem;     /* 20 — card titles / h3                         */
  --text-xl:  1.5rem;      /* 24 — section headings / h2                    */
  --text-2xl: 2rem;        /* 32 — page titles / h1                         */
  --text-3xl: 2.75rem;     /* 44 — hero                                     */
  --text-4xl: 3.5rem;      /* 56 — marketing hero, large screens           */

  --leading-tight: 1.2;
  --leading-snug:  1.35;
  --leading-normal:1.55;
  --leading-relaxed:1.7;

  --weight-regular: 400;
  --weight-medium:  500;
  --weight-semibold:600;
  --weight-bold:    700;

  --tracking-tight: -0.011em;
  --tracking-wide:  0.04em;
  --tracking-caps:  0.08em;

  /* --------------------------------------------------------------
     3. SPACE  (4px base grid)
     -------------------------------------------------------------- */
  --space-0: 0;
  --space-1: 0.25rem;   /*  4 */
  --space-2: 0.5rem;    /*  8 */
  --space-3: 0.75rem;   /* 12 */
  --space-4: 1rem;      /* 16 */
  --space-5: 1.5rem;    /* 24 */
  --space-6: 2rem;      /* 32 */
  --space-7: 2.5rem;    /* 40 */
  --space-8: 3rem;      /* 48 */
  --space-9: 4rem;      /* 64 */
  --space-10:6rem;      /* 96 */

  /* --------------------------------------------------------------
     4. RADIUS
     -------------------------------------------------------------- */
  --radius-xs:  3px;
  --radius-sm:  5px;
  --radius-md:  8px;
  --radius-lg:  12px;
  --radius-xl:  18px;
  --radius-pill:999px;

  /* --------------------------------------------------------------
     5. ELEVATION — shadows + the semantic glows
     -------------------------------------------------------------- */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 4px 16px -4px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.4);
  --shadow-pop: 0 16px 48px -12px rgba(0, 0, 0, 0.65),
    0 2px 8px rgba(0, 0, 0, 0.5);

  --glow-focus: 0 0 0 3px rgba(47, 152, 184, 0.32);
  --glow-command: 0 0 0 4px rgba(47, 152, 184, 0.16),
    0 8px 40px -8px rgba(47, 152, 184, 0.28);
  --glow-live: 0 0 0 0 var(--live-glow);
  --glow-stake: 0 0 0 3px rgba(154, 140, 242, 0.30);

  /* --------------------------------------------------------------
     6. MOTION — durations + easings.
     The "live" pulse is defined ONCE here as a token, not per component
     (present-layer indicators, price ticks all reuse it).
     -------------------------------------------------------------- */
  --dur-fast:  120ms;
  --dur-base:  200ms;
  --dur-slow:  340ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);

  --pulse-dur: 2.4s;
  --pulse-ease: cubic-bezier(0.4, 0, 0.6, 1);
  --flash-dur: 900ms;   /* live-update highlight flash on a changed value    */

  /* --------------------------------------------------------------
     7. LAYOUT
     -------------------------------------------------------------- */
  --content-max: 1180px;
  --reading-max: 720px;
  --wide-max:    1440px;
  --sidebar-w:   244px;
  --sidebar-w-collapsed: 60px;
  --topbar-h:    56px;
  --bottomnav-h: 68px;
  --z-sticky:  100;
  --z-topbar:  200;
  --z-drawer:  300;
  --z-popover: 400;
  --z-modal:   500;
  --z-toast:   600;

  /* --------------------------------------------------------------
     8. NOISE TEXTURE
     Monochromatic SVG turbulence, tiled, kept at very low opacity by the
     element that paints it (`body::before`). Declared as a token so light
     mode can swap it for a lighter-weight grain.
     -------------------------------------------------------------- */
  --noise-opacity: 0.035;
  --noise-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   LIGHT THEME — optional / secondary.
   Not a blind variable flip: the gradient becomes a soft paper wash, the
   noise is lighter, and the glow effects are dialled down (they read as
   dirt on light surfaces).
   Applied either by explicit opt-in (`data-theme="light"`) or by system
   preference when the user has not chosen.
   -------------------------------------------------------------------------- */
:root[data-theme="light"] {
  color-scheme: light;

  --bg-950: #eef2f1;
  --bg-900: #f4f6f5;
  --bg-850: #eef3f2;
  --bg-gradient: radial-gradient(120% 90% at 12% -10%, #e7f0ee 0%, transparent 55%),
    linear-gradient(168deg, #f6f8f7 0%, #eef2f1 60%, #e9f1ef 100%);

  --surface-1: #ffffff;
  --surface-2: #ffffff;
  --surface-3: #ffffff;
  --surface-inset: #f0f3f2;

  --border-hairline: rgba(9, 20, 26, 0.12);
  --border-soft:     rgba(9, 20, 26, 0.07);
  --border-strong:   rgba(9, 20, 26, 0.22);

  --text-primary:   #10181d;
  --text-secondary: #47555e;
  --text-tertiary:  #75828b;
  --text-on-accent: #04120f;
  --text-link:      #0f6883;

  --accent-500: #176e89;
  --accent-400: #1a7c9a;
  --accent-300: #4f9fb7;
  --accent-soft-bg:     rgba(23, 110, 137, 0.10);
  --accent-soft-border: rgba(23, 110, 137, 0.28);

  --verified-fg:     #1f7d6e;
  --verified-bg:     rgba(31, 125, 110, 0.10);
  --verified-border: rgba(31, 125, 110, 0.30);

  --live-fg:     #a9711a;
  --live-bg:     rgba(196, 132, 33, 0.12);
  --live-border: rgba(196, 132, 33, 0.34);
  --live-glow:   rgba(196, 132, 33, 0.35);

  --predictive-fg:     #6152c8;
  --predictive-bg:     rgba(107, 92, 214, 0.10);
  --predictive-border: rgba(107, 92, 214, 0.32);
  --predictive-glow:   rgba(107, 92, 214, 0.28);

  --move-up:   #1a7f37;
  --move-down: #cf222e;
  --move-up-bg:   rgba(26, 127, 55, 0.10);
  --move-down-bg: rgba(207, 34, 46, 0.10);

  --info-fg:     #1667b8;   --info-bg: rgba(22, 103, 184, 0.09);   --info-border: rgba(22, 103, 184, 0.30);
  --warn-fg:     #a9711a;   --warn-bg: rgba(196, 132, 33, 0.11);   --warn-border: rgba(196, 132, 33, 0.30);
  --danger-fg:   #cf222e;   --danger-bg: rgba(207, 34, 46, 0.09);  --danger-border: rgba(207, 34, 46, 0.30);

  --human-fg:  #47555e;  --human-bg: rgba(71, 85, 94, 0.09);
  --agent-fg:  #1a7f8c;  --agent-bg: rgba(26, 127, 140, 0.10);  --agent-border: rgba(26, 127, 140, 0.30);

  --shadow-1: 0 1px 2px rgba(16, 24, 29, 0.08);
  --shadow-2: 0 4px 14px -4px rgba(16, 24, 29, 0.14), 0 1px 3px rgba(16, 24, 29, 0.08);
  --shadow-pop: 0 16px 44px -14px rgba(16, 24, 29, 0.22), 0 2px 8px rgba(16, 24, 29, 0.10);

  --glow-focus: 0 0 0 3px rgba(23, 110, 137, 0.26);
  --glow-command: 0 0 0 4px rgba(23, 110, 137, 0.12), 0 8px 30px -10px rgba(23, 110, 137, 0.20);
  --glow-stake: 0 0 0 3px rgba(107, 92, 214, 0.24);

  --noise-opacity: 0.02;
  --noise-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* Same light palette when the user has NOT chosen a theme but their OS is light. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --bg-950: #eef2f1; --bg-900: #f4f6f5; --bg-850: #eef3f2;
    --bg-gradient: radial-gradient(120% 90% at 12% -10%, #e7f0ee 0%, transparent 55%),
      linear-gradient(168deg, #f6f8f7 0%, #eef2f1 60%, #e9f1ef 100%);

    --surface-1: #ffffff; --surface-2: #ffffff; --surface-3: #ffffff;
    --surface-inset: #f0f3f2;

    --border-hairline: rgba(9, 20, 26, 0.12);
    --border-soft: rgba(9, 20, 26, 0.07);
    --border-strong: rgba(9, 20, 26, 0.22);

    --text-primary: #10181d; --text-secondary: #47555e; --text-tertiary: #75828b;
    --text-on-accent: #04120f; --text-link: #0f6883;

    --accent-500: #176e89; --accent-400: #1a7c9a; --accent-300: #4f9fb7;
    --accent-soft-bg: rgba(23, 110, 137, 0.10);
    --accent-soft-border: rgba(23, 110, 137, 0.28);

    --verified-fg: #1f7d6e; --verified-bg: rgba(31, 125, 110, 0.10); --verified-border: rgba(31, 125, 110, 0.30);
    --live-fg: #a9711a; --live-bg: rgba(196, 132, 33, 0.12); --live-border: rgba(196, 132, 33, 0.34); --live-glow: rgba(196, 132, 33, 0.35);
    --predictive-fg: #6152c8; --predictive-bg: rgba(107, 92, 214, 0.10); --predictive-border: rgba(107, 92, 214, 0.32); --predictive-glow: rgba(107, 92, 214, 0.28);

    --move-up: #1a7f37; --move-down: #cf222e;
    --move-up-bg: rgba(26, 127, 55, 0.10); --move-down-bg: rgba(207, 34, 46, 0.10);

    --info-fg: #1667b8; --info-bg: rgba(22, 103, 184, 0.09); --info-border: rgba(22, 103, 184, 0.30);
    --warn-fg: #a9711a; --warn-bg: rgba(196, 132, 33, 0.11); --warn-border: rgba(196, 132, 33, 0.30);
    --danger-fg: #cf222e; --danger-bg: rgba(207, 34, 46, 0.09); --danger-border: rgba(207, 34, 46, 0.30);

    --human-fg: #47555e; --human-bg: rgba(71, 85, 94, 0.09);
    --agent-fg: #1a7f8c; --agent-bg: rgba(26, 127, 140, 0.10); --agent-border: rgba(26, 127, 140, 0.30);

    --shadow-1: 0 1px 2px rgba(16, 24, 29, 0.08);
    --shadow-2: 0 4px 14px -4px rgba(16, 24, 29, 0.14), 0 1px 3px rgba(16, 24, 29, 0.08);
    --shadow-pop: 0 16px 44px -14px rgba(16, 24, 29, 0.22), 0 2px 8px rgba(16, 24, 29, 0.10);

    --glow-focus: 0 0 0 3px rgba(23, 110, 137, 0.26);
    --glow-command: 0 0 0 4px rgba(23, 110, 137, 0.12), 0 8px 30px -10px rgba(23, 110, 137, 0.20);
    --glow-stake: 0 0 0 3px rgba(107, 92, 214, 0.24);

    --noise-opacity: 0.02;
  }
}

/* ==========================================================================
   RESET + ELEMENT BASE
   ========================================================================== */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  tab-size: 2;
  scroll-behavior: smooth;
  /* SPA safety net: one future component with an unshrinkable child
     (a wide table, a rigid flex row, …) shouldn't be able to push the
     whole app sideways — it should overflow *inside itself*, not here. */
  overflow-x: clip;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

body {
  min-height: 100vh;
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  background-color: var(--bg-950);
  background-image: var(--bg-gradient);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Film-grain / noise overlay — fixed, non-interactive, very low opacity. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--noise-image);
  background-repeat: repeat;
  opacity: var(--noise-opacity);
  mix-blend-mode: overlay;
}

/* Keep real content above the grain. */
body > * { position: relative; z-index: 1; }

/* ---- Headings ---- */
h1, h2, h3, h4, h5, h6 {
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  text-wrap: balance;
}
h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-md); }
h5 { font-size: var(--text-base); }
h6 { font-size: var(--text-sm); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--text-secondary); }

p { text-wrap: pretty; }

/* ---- Links ---- */
a {
  color: var(--text-link);
  text-decoration: none;
  text-underline-offset: 0.16em;
  transition: color var(--dur-fast) var(--ease-standard);
}
a:hover { text-decoration: underline; }

/* ---- Media ---- */
img, svg, video, canvas { display: block; max-width: 100%; }
svg { fill: currentColor; }

/* ---- Forms inherit type ---- */
button, input, select, textarea { font: inherit; color: inherit; }

/* ---- Mono is a semantic signal: the value is DATA, not copy ---- */
code, kbd, samp, pre, .u-mono, [data-mono] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

/* ---- Selection ---- */
::selection { background: var(--accent-soft-bg); color: var(--text-primary); }

/* ---- Focus: always visible, uses the focus-glow token ---- */
:focus-visible {
  outline: 2px solid var(--accent-400);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}
:focus:not(:focus-visible) { outline: none; }

/* ---- Scrollbars (WebKit) — thin, quiet ---- */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--radius-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-track { background: transparent; }

/* ==========================================================================
   KEYFRAMES — global, token-driven
   ========================================================================== */

/* The single "live" pulse. Present-layer dots, price-tick indicators, and the
   live-update badge all animate with this. Ring expands + fades. */
@keyframes ec-pulse-live {
  0%   { box-shadow: 0 0 0 0 var(--live-glow); }
  70%  { box-shadow: 0 0 0 7px rgba(224, 165, 63, 0); }
  100% { box-shadow: 0 0 0 0 rgba(224, 165, 63, 0); }
}

/* Predictive/market tick — same shape, violet glow. */
@keyframes ec-pulse-predictive {
  0%   { box-shadow: 0 0 0 0 var(--predictive-glow); }
  70%  { box-shadow: 0 0 0 7px rgba(154, 140, 242, 0); }
  100% { box-shadow: 0 0 0 0 rgba(154, 140, 242, 0); }
}

/* Highlight flash when a value updates in place (no layout jump). */
@keyframes ec-value-flash {
  0%   { background-color: var(--accent-soft-bg); }
  100% { background-color: transparent; }
}

/* Skeleton shimmer for loading states. */
@keyframes ec-skeleton {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* Indeterminate progress sweep. */
@keyframes ec-indeterminate {
  0%   { transform: translateX(-100%) scaleX(0.4); }
  50%  { transform: translateX(0%) scaleX(0.55); }
  100% { transform: translateX(100%) scaleX(0.4); }
}

@keyframes ec-spin { to { transform: rotate(360deg); } }

@keyframes ec-toast-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ==========================================================================
   LAYOUT / UTILITY HELPERS  (kept intentionally minimal — this is not a
   utility framework; components own their own layout)
   ========================================================================== */

/* Accessible skip link — first focusable element on every page. */
.skip-link {
  position: absolute;
  left: var(--space-3);
  top: var(--space-3);
  z-index: var(--z-toast);
  padding: var(--space-2) var(--space-4);
  background: var(--surface-3);
  color: var(--text-primary);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  transform: translateY(-160%);
  transition: transform var(--dur-base) var(--ease-out);
}
.skip-link:focus { transform: translateY(0); }

/* Screen-reader only. */
.u-visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* Centered content column. */
.u-container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--space-4);
}
@media (min-width: 768px) { .u-container { padding-inline: var(--space-6); } }
.u-container--wide    { max-width: var(--wide-max); }
.u-container--reading { max-width: var(--reading-max); }

/* Vertical rhythm between direct children. */
.u-stack > * + * { margin-top: var(--space-4); }
.u-stack-sm > * + * { margin-top: var(--space-2); }
.u-stack-lg > * + * { margin-top: var(--space-6); }

/* Simple inline cluster with wrap. */
.u-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Section spacing on public pages. */
.u-section { padding-block: var(--space-9); }
@media (min-width: 768px) { .u-section { padding-block: var(--space-10); } }

/* Text helpers. */
.u-text-secondary { color: var(--text-secondary); }
.u-text-tertiary  { color: var(--text-tertiary); }
.u-text-sm  { font-size: var(--text-sm); }
.u-text-xs  { font-size: var(--text-xs); }
.u-lead { font-size: var(--text-md); color: var(--text-secondary); line-height: var(--leading-relaxed); }
.u-eyebrow {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--accent-400);
}
.u-numeric { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Hairline divider. */
.u-hr {
  height: 1px;
  border: 0;
  background: var(--border-hairline);
  margin-block: var(--space-5);
}

/* Responsive visibility. */
.u-hide-mobile { display: none; }
@media (min-width: 768px) { .u-hide-mobile { display: revert; } .u-only-mobile { display: none; } }

/* Wide element that must scroll inside itself, never the page. */
.u-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
