/* ═══════════════════════════════════════════════════════════════════════════
   TickPlunge Terminal - Gruvbox Dark Theme System
   ═══════════════════════════════════════════════════════════════════════════ */

/* UI density: rem-based tokens scale with the root font size, so a density
   change cascades through every component. Charts are deliberately IMMUNE -
   they size in device px from their containers (Sizing.chartGrid/chartTypo),
   so axis labels stay full-size legible while the chrome densifies (the
   advantage over browser zoom, which shrinks the canvas too). Applied early
   from localStorage('tp-density') by an inline head script (no FOUC);
   toggled from the nav. The base html{font-size:16px} lives in the critical
   CSS in base.html. */
html[data-density="compact"] { font-size: 14px; }
html[data-density="dense"]   { font-size: 12.5px; }

/* Vendored 7-glyph color-emoji subset (spec/options-flow/CARDS.md closed set
   🟢⚠️🔴✅❌🎯🚨 + VS16/ZWJ) - Noto Color Emoji COLRv1, subset via pyftsubset
   (source: github.com/googlefonts/noto-emoji, OFL). unicode-range makes it
   inert for every other codepoint, so leading the font stacks is safe; it
   exists because Linux hosts routinely ship NO system emoji font and the
   status glyphs otherwise render as tofu boxes. */
@font-face {
  font-family: 'TP Emoji';
  src: url('/static/css/fonts/tp-emoji.woff2') format('woff2');
  unicode-range: U+1F7E2, U+26A0, U+FE0F, U+1F534, U+2705, U+274C, U+1F3AF, U+1F6A8, U+200D;
  font-display: swap;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('/static/fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/static/fonts/jetbrains-mono-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/static/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/static/fonts/ibm-plex-mono-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist Mono';
  src: url('/static/fonts/geist-mono-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist Mono';
  src: url('/static/fonts/geist-mono-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Typeface choice (Display menu): density-boot.js sets data-face on html. Only
   --font-mono changes, so no size, line-height or tracking token moves. An
   unused face is never requested, so System mono downloads no font file. */
html[data-face="ibm-plex-mono"] { --font-mono: 'TP Emoji', 'IBM Plex Mono', monospace; }
html[data-face="geist-mono"]    { --font-mono: 'TP Emoji', 'Geist Mono', monospace; }
html[data-face="system-mono"]   { --font-mono: 'TP Emoji', ui-monospace, Menlo, Consolas, monospace; }

:root {
  /* ═══════════════════════════════════════════════════════════════
     TYPOGRAPHY
     ═══════════════════════════════════════════════════════════════ */
  --font-mono: 'TP Emoji', 'JetBrains Mono', monospace;

  --font-size-xs:   0.75rem;
  --font-size-sm:   0.875rem;
  --font-size-base: 1rem;
  --font-size-lg:   1.125rem;
  --font-size-xl:   1.25rem;
  --font-size-2xl:  1.5rem;
  --font-size-3xl:  2rem;
  --font-size-4xl:  3rem;

  /* Chart fonts: device px, immune to density (DS-TYPE-17). Never rem,
     never redeclared under html[data-density]. */
  --chart-font-sm:  10px; /* ticks */
  --chart-font-md:  11px; /* axis name, legend */
  --chart-font-lg:  12px; /* tooltip */
  --chart-font-xl:  14px; /* title, gauge */

  /* ═══════════════════════════════════════════════════════════════
     SPACING SCALE
     ═══════════════════════════════════════════════════════════════ */
  --space-1:  0.25rem;
  --space-2:  0.5rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.25rem;
  --space-6:  1.5rem;
  --space-8:  2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --w-narrow: 25rem;
  --w-prose:  45rem;
  --w-wide:   1200px;
  --w-full:   100%;
  --board-scale: 1;
  --rail-offset: 0px;

  /* ═══════════════════════════════════════════════════════════════
     BORDER RADIUS
     ═══════════════════════════════════════════════════════════════ */
  --radius-none: 0;
  --radius-sm:   2px;
  --radius-md:   4px;

  /* ═══════════════════════════════════════════════════════════════
     MOTION
     ═══════════════════════════════════════════════════════════════ */
  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-toast: 6s;
  --dur-undo: 8s;
  --debounce-input: 150ms;
  --debounce-save: 500ms;

  /* ═══════════════════════════════════════════════════════════════
     VISUAL EFFECTS - GRADIENTS
     ═══════════════════════════════════════════════════════════════ */
  --gradient-hero: linear-gradient(135deg, var(--primary) 0%, var(--info) 50%, var(--series-hv) 100%);
  --gradient-subtle: linear-gradient(180deg, var(--surface) 0%, var(--canvas) 100%);
  --gradient-card-hover: linear-gradient(145deg, var(--raised) 0%, var(--line) 100%);

  /* ═══════════════════════════════════════════════════════════════
     VISUAL EFFECTS - GLOWS
     ═══════════════════════════════════════════════════════════════ */
  --glow-aqua: 0 0 20px color-mix(in oklab, var(--primary) 26%, transparent);
  --glow-aqua-subtle: 0 0 15px color-mix(in oklab, var(--primary) 16%, transparent);
  --glow-blue: 0 0 20px color-mix(in oklab, var(--info) 26%, transparent);
  --glow-error: 0 0 20px color-mix(in oklab, var(--negative) 26%, transparent);

  /* ═══════════════════════════════════════════════════════════════
     ELEVATION SHADOWS
     ═══════════════════════════════════════════════════════════════ */
  --shadow-sm: var(--shadow-raised);

  --z-raised: 10;
  --z-menu: 100;
  --z-drawer: 200;
  --z-modal: 300;
  --z-toast: 400;
  --z-tooltip: 500;
}

:root { --gutter: 16px; }

@media (min-width: 40em) {
  :root { --gutter: 24px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   TYPOGRAPHY CLASSES
   ═══════════════════════════════════════════════════════════════════════════ */

.text-display {
  font-size: var(--font-size-4xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  text-transform: none;
}

.text-h1 {
  font-size: var(--font-size-3xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-transform: none;
}

.text-h2 {
  font-size: var(--font-size-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-transform: none;
}

.text-h3 {
  font-size: var(--font-size-lg);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.4;
  text-transform: none;
}

.text-body {
  font-size: var(--font-size-base);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.6;
  text-transform: none;
}

.text-data {
  font-size: var(--font-size-sm);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.4;
  text-transform: none;
}

.text-label {
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-transform: uppercase;
}

.text-caption {
  font-size: var(--font-size-xs);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.4;
  text-transform: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   TEXT EFFECTS
   ═══════════════════════════════════════════════════════════════════════════ */

.text-gradient {
  background: var(--gradient-hero);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.text-glow {
  text-shadow: 0 0 2px currentColor, 0 0 4px color-mix(in oklab, var(--primary) 26%, transparent);
}

.text-glow-strong {
  text-shadow: 0 0 5px currentColor, 0 0 10px color-mix(in oklab, var(--primary) 26%, transparent), 0 0 20px color-mix(in oklab, var(--primary) 26%, transparent);
}

/* ═══════════════════════════════════════════════════════════════════════════
   KEYFRAME ANIMATIONS
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes shimmer {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

@keyframes typing {
  from { width: 0; }
  to { width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ANIMATION UTILITY CLASSES
   ═══════════════════════════════════════════════════════════════════════════ */

.animate-shimmer {
  background-size: 200% 200%;
  animation: shimmer 3s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0s;
    --dur-base: 0s;
  }

  .animate-shimmer {
    animation: none;
  }
}

/* Theme slots: 7 themes x 18 slots (spec/design-system/colour.md, board 03). */

:root,
html[data-theme="gruvbox-high"] {
  color-scheme: dark;
  --canvas: #141617;
  --surface: #1d2021;
  --raised: #282828;
  --line: #504945;
  --ink: #fbf1c7;
  --ink-dim: #d5c4a1;
  --ink-faint: #a89984;
  --primary: #8ec07c;
  --on-primary: #141617;
  --positive: #b8bb26;
  --negative: #ff5c6c;
  --caution: #fabd2f;
  --info: #83a598;
  --series-iv: #83a598;
  --series-hv: #d3869b;
  --series-vrp: #fe8019;
  --series-spot: #ebdbb2;
  --series-fwd: #7c6f64;
  --shadow-raised: 0 4px 12px rgba(0,0,0,.4);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,.5);
}

html[data-theme="gruvbox-dark"] {
  color-scheme: dark;
  --canvas: #1d2021;
  --surface: #282828;
  --raised: #32302f;
  --line: #504945;
  --ink: #ebdbb2;
  --ink-dim: #bdae93;
  --ink-faint: #a5988c;
  --primary: #8ec07c;
  --on-primary: #1d2021;
  --positive: #b8bb26;
  --negative: #fc6c5b;
  --caution: #fabd2f;
  --info: #83a598;
  --series-iv: #83a598;
  --series-hv: #d3869b;
  --series-vrp: #fe8019;
  --series-spot: #ebdbb2;
  --series-fwd: #7c6f64;
  --shadow-raised: 0 4px 12px rgba(0,0,0,.4);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,.5);
}

html[data-theme="gruvbox-light"] {
  color-scheme: light;
  --canvas: #f9f5d7;
  --surface: #fbf1c7;
  --raised: #ebdbb2;
  --line: #d5c4a1;
  --ink: #282828;
  --ink-dim: #504945;
  --ink-faint: #685d54;
  --primary: #38694b;
  --on-primary: #fbf1c7;
  --positive: #66610c;
  --negative: #9d0006;
  --caution: #84560f;
  --info: #076678;
  --series-iv: #076678;
  --series-hv: #8f3f71;
  --series-vrp: #d65d0e;
  --series-spot: #282828;
  --series-fwd: #928374;
  --shadow-raised: none;
  --shadow-overlay: none;
}

html[data-theme="slate"] {
  color-scheme: dark;
  --canvas: #0c0f12;
  --surface: #12171b;
  --raised: #182026;
  --line: #2a353d;
  --ink: #e8eef3;
  --ink-dim: #a2b3bf;
  --ink-faint: #788a9a;
  --primary: #2fd4bd;
  --on-primary: #06110f;
  --positive: #5fd08a;
  --negative: #ff5b52;
  --caution: #f2b13c;
  --info: #6aa9ff;
  --series-iv: #6aa9ff;
  --series-hv: #c69bff;
  --series-vrp: #ff8fc8;
  --series-spot: #e8eef3;
  --series-fwd: #8597a6;
  --shadow-raised: 0 4px 12px rgba(0,0,0,.4);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,.5);
}

html[data-theme="amber-black"] {
  color-scheme: dark;
  --canvas: #000000;
  --surface: #0a0a0a;
  --raised: #141414;
  --line: #2b2b2b;
  --ink: #f5e6c8;
  --ink-dim: #d6a94a;
  --ink-faint: #927d4c;
  --primary: #ffa726;
  --on-primary: #0a0a0a;
  --positive: #57c96a;
  --negative: #ff4d3d;
  --caution: #ffd54a;
  --info: #64b5f6;
  --series-iv: #64b5f6;
  --series-hv: #d68fb0;
  --series-vrp: #b388ff;
  --series-spot: #f5e6c8;
  --series-fwd: #8a8a8a;
  --shadow-raised: 0 4px 12px rgba(0,0,0,.4);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,.5);
}

html[data-theme="ink-amber"] {
  color-scheme: dark;
  --canvas: #08090a;
  --surface: #101113;
  --raised: #191b1e;
  --line: #31343a;
  --ink: #f2ede3;
  --ink-dim: #b3aca0;
  --ink-faint: #8a847b;
  --primary: #ffb020;
  --on-primary: #0a0906;
  --positive: #7cc47f;
  --negative: #e8503a;
  --caution: #f0e442;
  --info: #5ec8e6;
  --series-iv: #5ec8e6;
  --series-hv: #c58fd8;
  --series-vrp: #ff7ab8;
  --series-spot: #f2ede3;
  --series-fwd: #8a847b;
  --shadow-raised: 0 4px 12px rgba(0,0,0,.4);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,.5);
}

html[data-theme="paper"] {
  color-scheme: light;
  --canvas: #ffffff;
  --surface: #fafaf8;
  --raised: #f1f0ec;
  --line: #dcdad2;
  --ink: #1b1a18;
  --ink-dim: #52504a;
  --ink-faint: #6e6c65;
  --primary: #0f6b57;
  --on-primary: #ffffff;
  --positive: #1d7a3f;
  --negative: #b3261e;
  --caution: #8a6100;
  --info: #1a5fb4;
  --series-iv: #1a5fb4;
  --series-hv: #7a3d86;
  --series-vrp: #d9480f;
  --series-spot: #1b1a18;
  --series-fwd: #8a877e;
  --shadow-raised: none;
  --shadow-overlay: none;
}

/* Button Component Styles */

/* Base button */
.btn {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  font-weight: 600;
  height: 2rem;
  padding: 0 var(--space-3);
  box-sizing: border-box;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: all var(--dur-fast) ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
}

.btn-sm {
  height: 1.5rem;
  padding: 0 var(--space-2);
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.btn-lg {
  height: 2.5rem;
  padding: 0 var(--space-4);
  font-size: var(--font-size-base);
}

/* Primary variant */
.btn-primary {
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
}

.btn-primary:hover {
  color: var(--on-primary);
  box-shadow: var(--glow-aqua);
}

.btn-primary:focus {
  box-shadow: var(--glow-aqua);
}

/* Secondary variant */
.btn-secondary {
  background: var(--raised);
  color: var(--ink);
  border-color: var(--line);
}

.btn-secondary:hover {
  background: var(--line);
}

.btn-secondary:focus {
  border-color: var(--ink-faint);
}

/* Danger variant */
.btn-danger {
  background: transparent;
  color: var(--negative);
  border-color: var(--negative);
}

.btn-danger:hover {
  background: var(--negative);
  color: var(--canvas);
  box-shadow: var(--glow-error);
}

.btn-danger:focus {
  box-shadow: var(--glow-error);
}

/* Ghost variant */
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}

.btn-ghost:hover {
  border-color: var(--ink-faint);
}

.btn-ghost:focus {
  border-color: var(--ink-faint);
}

/* Disabled state */
.btn:disabled,
.btn[aria-disabled="true"] {
  background: var(--raised);
  color: var(--ink-faint);
  border-color: var(--line);
  cursor: not-allowed;
  box-shadow: none;
}

.btn:disabled:hover,
.btn[aria-disabled="true"]:hover {
  box-shadow: none;
}

/* Full width size */
.btn-block {
  display: block;
  width: 100%;
}

/* Panel and Card Component Styles */

/* ═══════════════════════════════════════════════════════════════════════════
   PANEL CONTAINER
   ═══════════════════════════════════════════════════════════════════════════ */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.panel-header {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  color: var(--ink);
}

.panel-body {
  padding: var(--space-4);
}

/* ═══════════════════════════════════════════════════════════════════════════
   STAT CARD
   ═══════════════════════════════════════════════════════════════════════════ */

.stat-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  text-align: center;
}

.stat-card .stat-label {
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: var(--space-2);
}

.stat-card .stat-value {
  font-size: var(--font-size-3xl);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.1;
}

.stat-suffix {
  font-size: var(--font-size-lg);
  font-weight: 600;
  color: var(--ink-faint);
  margin-left: var(--space-1);
}

/* ═══════════════════════════════════════════════════════════════════════════
   ALERTS
   ═══════════════════════════════════════════════════════════════════════════ */

.alert {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
}

.alert-error {
  background: color-mix(in oklab, var(--negative) 10%, transparent);
  border: 1px solid var(--negative);
  color: var(--negative);
}

.alert-warning {
  background: color-mix(in oklab, var(--caution) 10%, transparent);
  border: 1px solid var(--caution);
  color: var(--caution);
}

.alert-info {
  background: color-mix(in oklab, var(--info) 10%, transparent);
  border: 1px solid var(--info);
  color: var(--info);
}

/* ═══════════════════════════════════════════════════════════════════════════
   PANEL VARIANTS
   ═══════════════════════════════════════════════════════════════════════════ */

.panel-elevated {
  background: var(--raised);
  box-shadow: var(--shadow-raised);
}

.panel-accent-aqua {
  border-left: 3px solid var(--primary);
}

.panel-accent-purple {
  border-left: 3px solid var(--series-hv);
}

.panel-hoverable {
  transition: background var(--dur-base) ease, box-shadow var(--dur-base) ease;
}

.panel-hoverable:hover {
  background: var(--gradient-card-hover);
  box-shadow: var(--shadow-raised);
}

/* Table Component Styles */

/* Base table */
.table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--ink);
}

/* Header row styling */
.table th {
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--raised);
  padding: var(--space-3) var(--space-4);
  text-align: left;
  border-bottom: 1px solid var(--line);
}

/* Table cells */
.table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
}

/* Alternating row colors */
.table tr:nth-child(even) {
  background: var(--surface);
}

.table tr:nth-child(odd) {
  background: var(--raised);
}

/* Row hover state */
.table tbody tr:hover {
  background: var(--line);
}

/* Status indicator base */
.status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.status-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: var(--space-2);
  flex-shrink: 0;
}

.status-dot.operational {
  background: currentColor;
  color: var(--positive);
  box-shadow: 0 0 6px var(--positive);
}

.status-dot.degraded {
  background: var(--caution);
  box-shadow: 0 0 6px var(--caution);
}

.status-dot.outage {
  background: var(--negative);
  box-shadow: 0 0 6px var(--negative);
}

.status-label {
  font-size: var(--font-size-sm);
  color: var(--ink-dim);
}

/* Status variants */
.status-idle .status-dot {
  background: var(--ink-faint);
}

.status-idle .status-label {
  color: var(--ink-faint);
}

.status-error .status-dot {
  background: var(--negative);
}

.status-error .status-label {
  color: var(--negative);
}

/* Compact table variant */
.table-compact th,
.table-compact td {
  padding: var(--space-2) var(--space-3);
}

/* Borderless table variant */
.table-borderless td {
  border-bottom: none;
}

/* Form Component Styles */

/* Form group container */
.form-group {
  margin-bottom: var(--space-4);
}

/* Form label */
.form-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-transform: none;
  color: var(--ink-dim);
  margin-bottom: var(--space-2);
}

/* Forms recipe: every label in a form is sentence case, whatever the page
   stylesheet sets on a bare .form-group label. */
form .form-group label {
  text-transform: none;
}

/* Text input, email, password: the frame is in fields.css; this sets the width. */
.form-input {
  width: 100%;
}

/* Select dropdown */
.form-select {
  width: 100%;
  padding: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  background: var(--raised);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-faint) 50%), linear-gradient(135deg, var(--ink-faint) 50%, transparent 50%);
  background-repeat: no-repeat;
  background-size: 6px 6px, 6px 6px;
  background-position: right calc(var(--space-3) + 6px) center, right var(--space-3) center;
  padding-right: var(--space-8);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.form-select:focus {
  border-color: var(--primary);
  box-shadow: var(--glow-aqua);
}

.form-select:disabled {
  background-color: var(--canvas);
  color: var(--ink-faint);
  cursor: not-allowed;
}

.form-select.error {
  border-color: var(--negative);
}

/* Helper text */
.form-help {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  margin-top: var(--space-1);
}

/* Textarea */
.form-textarea {
  width: 100%;
  padding: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  background: var(--raised);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  resize: vertical;
  min-height: 6rem;
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.form-textarea::placeholder {
  color: var(--ink-faint);
}

.form-textarea:focus {
  border-color: var(--primary);
  box-shadow: var(--glow-aqua), inset 0 0 8px color-mix(in oklab, var(--primary) 10%, transparent);
}

/* Checkbox and radio */
.form-checkbox,
.form-radio {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--ink);
  cursor: pointer;
}

.form-checkbox input,
.form-radio input {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
  cursor: pointer;
}

/* Field frame (DS-COMP-18, DS-COMP-19, DS-INT-6). One rule gives every text
   input the same background, border, radius, text and height; each owner sets
   only its width. .field is the class for new inputs; the listed selectors are
   the inputs that predate it. */

.field,
.form-input,
.calc-input,
.calc-tvm-grid input,
.sheet-formula-input,
.chip-search-input,
.tab-rename-input,
.chart-control-date,
#layout-name {
  box-sizing: border-box;
  height: 2rem;
  padding: 0 var(--space-2);
  background: var(--canvas);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  transition: border-color var(--dur-fast) ease;
}

/* sm: every field except the form input, plus any field that opts in. */
.field--sm,
.calc-input,
.calc-tvm-grid input,
.sheet-formula-input,
.chip-search-input,
.tab-rename-input,
.chart-control-date,
#layout-name {
  height: 1.5rem;
  font-size: var(--font-size-xs);
}

/* The chip search input alone has a dashed border. */
.chip-search-input {
  border-style: dashed;
}

.field::placeholder,
.form-input::placeholder,
.calc-input::placeholder,
.sheet-formula-input::placeholder,
.chip-search-input::placeholder {
  color: var(--ink-faint);
}

.field:focus,
.form-input:focus,
.calc-input:focus,
.calc-tvm-grid input:focus,
.sheet-formula-input:focus,
.chip-search-input:focus,
.tab-rename-input:focus,
.chart-control-date:focus,
#layout-name:focus {
  border-color: var(--primary);
}

.chip-search-input:focus {
  border-style: solid;
}

.field:disabled,
.form-input:disabled,
.calc-input:disabled,
.calc-tvm-grid input:disabled,
.sheet-formula-input:disabled,
.chip-search-input:disabled,
.tab-rename-input:disabled,
.chart-control-date:disabled,
#layout-name:disabled {
  background: var(--raised);
  color: var(--ink-faint);
  cursor: not-allowed;
}

/* Error: negative border (also while focused) and the message under the field. */
.field.field--error,
.form-input.field--error,
.form-textarea.field--error,
.calc-input.field--error,
.sheet-formula-input.field--error,
.chip-search-input.field--error,
.tab-rename-input.field--error,
.chart-control-date.field--error,
#layout-name.field--error {
  border-color: var(--negative);
}

.field-message {
  display: block;
  margin-top: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--negative);
}

/* docs.css - Documentation page styles */

.docs-shell {
  display: flex;
  flex: 1;
}

/* The article head type roles (DS-PAGE-18): the breadcrumb eyebrow is 12px
 * caps in the faint ink; the lede is 16px in the dim ink, 18px from 640. */
.docs-breadcrumb {
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  color: var(--ink-faint);
}

.docs-lede {
  font-size: var(--font-size-base);
  color: var(--ink-dim);
}

@media (min-width: 40em) {
  .docs-lede {
    font-size: var(--font-size-lg);
  }
}

/* The meta row under the lede (DS-PAGE-18): outlined .chip spans, then the
 * Open in a dashboard text link at the far right. */
.docs-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.docs-meta-link {
  margin-left: auto;
  color: var(--primary);
  text-decoration: none;
}

.docs-meta-link:hover {
  text-decoration: underline;
}

/* The docs body is the wide width, centred. From 64em it is two grid
 * columns: a 264px side nav, a 48px gap, and main (888px at 1200). */
.docs-layout {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
  max-width: var(--w-wide);
  margin-inline: auto;
}

@media (min-width: 64em) {
  .docs-layout {
    display: grid;
    grid-template-columns: 264px minmax(0, 1fr);
    column-gap: var(--space-12);
    align-items: start;
  }
}

/* Side nav (the pattern is components/side-nav.css): below 64em it stacks
 * above the content, from 64em it is a 264px sticky column. */
.docs-side-nav {
  margin-bottom: 0;
}

/* The docs bar (DS-PAGE-26): below 64em docs-page.js marks the nav
 * .is-enhanced, which hides its list (side-nav.css) and shows this 44px bar,
 * sticky at the top of the viewport once the site header scrolls away. */
.docs-bar {
  display: none;
  align-items: center;
  gap: var(--space-2);
  box-sizing: border-box;
  width: 100%;
  height: 2.75rem;
  padding: 0 var(--space-3);
  border: 0;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--font-size-sm);
  text-align: left;
  cursor: pointer;
}

.docs-side-nav.is-enhanced .docs-bar {
  display: flex;
}

.docs-bar__section {
  flex: none;
  color: var(--ink-faint);
}

.docs-bar__page {
  min-width: 0;
  overflow: hidden;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.docs-bar__caret {
  margin-left: auto;
  color: var(--ink-faint);
}

@media (max-width: 63.99em) {
  .docs-side-nav {
    position: sticky;
    top: 0;
    z-index: var(--z-raised);
    background: var(--surface);
  }
}

/* The docs menu rows are 44px touch targets; a long section scrolls. */
.docs-menu {
  max-height: 70vh;
}

.docs-menu .menu-item {
  height: 2.75rem;
}

@media (min-width: 64em) {
  .docs-side-nav.is-enhanced .docs-bar {
    display: none;
  }

  .docs-side-nav {
    width: 264px;
    box-sizing: border-box;
    padding: var(--space-6) var(--space-6) var(--space-6) 0;
    border-right: 1px solid var(--line);
    position: sticky;
    top: 0;
    align-self: flex-start;
    max-height: 100vh;
    overflow-y: auto;
    background-color: var(--surface);
  }
}

.docs-section {
  margin-bottom: var(--space-4);
}

.docs-section-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: var(--space-2);
  background: none;
  border: none;
  padding: 0;
  width: 100%;
  text-align: left;
  font-family: inherit;
}

.docs-section-header:hover {
  color: var(--primary);
}

.docs-toggle {
  font-size: 0.75rem;
  color: var(--ink-faint);
  transition: transform var(--dur-base);
  display: inline-block;
}

.docs-section.collapsed .docs-toggle {
  transform: rotate(-90deg);
}

.docs-section-items {
  margin-left: var(--space-4);
}

.docs-section.collapsed .docs-section-items {
  display: none;
}

.docs-item {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  padding: var(--space-1) 0;
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
  text-decoration: none;
}

.docs-item:hover {
  color: var(--ink);
  text-decoration: none;
}

/* In-page list under the current entry (docs-page.js): indented h2 links; the
 * one in view carries the primary line and ink colour. */
.docs-toc {
  display: flex;
  flex-direction: column;
  margin-left: var(--space-3);
}

.docs-toc__link {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
  text-decoration: none;
}

.docs-toc__link:hover {
  color: var(--ink);
  text-decoration: none;
}

.docs-toc__link[aria-current="location"] {
  color: var(--ink);
  box-shadow: inset 2px 0 0 var(--primary);
}

/* On this page (DS-PAGE-27): the phone's in-page list, a disclosure after the
 * lede with 44px link rows. From 64em the side nav list carries the links. */
.docs-onpage {
  margin-bottom: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

.docs-onpage summary {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 var(--space-3);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

.docs-onpage__link {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 var(--space-3);
  border-top: 1px solid var(--line);
  font-size: var(--font-size-sm);
  color: var(--primary);
  text-decoration: none;
}

@media (min-width: 64em) {
  .docs-onpage {
    display: none;
  }
}

/* A guide job group: a label line, not a link */
.docs-group-label {
  padding: var(--space-2) 0 var(--space-1) 0;
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--ink);
}

/* Previous and next page */
.docs-pager {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.docs-pager-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--primary);
}

.docs-pager-card[rel="next"] {
  grid-column: 2;
  text-align: right;
}

.docs-pager-label {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
}

/* Content area */
.docs-content {
  flex: 1;
  min-width: 0;
  padding-block: var(--space-8);
}

/* Main is the full column; prose blocks stop at the prose width and the
 * example figure breaks out to the column. */
.docs-content > * {
  max-width: var(--w-prose);
}

.docs-content > .docs-example-figure {
  max-width: none;
}

.docs-content h1 {
  color: var(--ink);
  margin-bottom: var(--space-4);
}

.docs-content h2 {
  color: var(--ink);
  margin-top: var(--space-8);
  margin-bottom: var(--space-4);
}

.docs-content p {
  margin-bottom: var(--space-4);
  line-height: 1.6;
}

.docs-content pre {
  margin-bottom: var(--space-4);
  overflow-x: auto;
}

/* Body links and inline code: chrome.css makes every anchor inherit its
   colour, so a link inside a paragraph, list, or table cell needs its own */
.docs-content p a,
.docs-content li a,
.docs-content td a {
  color: var(--primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.docs-content code {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 0 var(--space-1);
  border-radius: var(--radius-sm);
  color: var(--ink);
  overflow-wrap: anywhere;
}

.docs-content pre code {
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
}

/* An entry of an entries reference page: the call, its arguments, the
   example and its result */
.docs-entry {
  margin-bottom: var(--space-6);
  padding-top: var(--space-2);
  border-top: 1px solid var(--line);
}

.docs-entry-args {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  margin-bottom: var(--space-4);
}

.docs-entry-args dd {
  margin: 0;
  line-height: 1.6;
}

.docs-entry h3 code {
  font-size: inherit;
}

/* The example and its result read as one block: the typed line, then what
   it returned */
.docs-content .docs-entry-example {
  background: var(--raised);
  border-left: 2px solid var(--primary);
  padding: var(--space-2) var(--space-4);
  margin-bottom: 0;
}

.docs-entry-example + .docs-entry-result {
  margin: 0 0 var(--space-4) 0;
  padding: var(--space-1) var(--space-4);
  border-left: 2px solid var(--line);
  color: var(--ink-dim);
}

.docs-entry-note {
  color: var(--ink-dim);
}

/* An endpoint entry: the request line, then the recorded response, which
   scrolls inside its own box so a long body keeps the next entry in reach */
.docs-content .docs-entry-request {
  background: var(--raised);
  border-left: 2px solid var(--primary);
  padding: var(--space-2) var(--space-4);
  margin-bottom: var(--space-2);
  overflow-x: auto;
}

.docs-content .docs-entry-response {
  max-height: 24rem;
  overflow: auto;
  background: var(--raised);
  border-left: 2px solid var(--line);
  padding: var(--space-2) var(--space-4);
  margin-bottom: var(--space-4);
}

.docs-entry-label {
  margin: 0 0 var(--space-1) 0;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--ink-dim);
}

/* A measure on the measures page: its meaning, the fact list, thresholds,
   where it appears and its caveats */
.docs-measure {
  margin-bottom: var(--space-6);
  padding-top: var(--space-2);
  border-top: 1px solid var(--line);
}

.docs-measure-facts {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  margin-bottom: var(--space-4);
}

.docs-measure-facts dd {
  margin: 0;
  line-height: 1.6;
}

/* Below 640 a label and its value stack, so a long value wraps in the column
   instead of widening the page (DS-PAGE-28). */
.docs-entry-args dd,
.docs-measure-facts dd,
.docs-content p,
.docs-content li {
  overflow-wrap: anywhere;
}

@media (min-width: 40em) {
  .docs-entry-args,
  .docs-measure-facts {
    grid-template-columns: max-content 1fr;
  }
}

/* The index at the top of the measures page: one row per group, its
   entries as links */
.docs-measure-index dl {
  margin: 0 0 var(--space-6) 0;
}

.docs-measure-index dt {
  margin-top: var(--space-2);
  font-weight: 600;
}

.docs-measure-index dd {
  margin: 0;
  line-height: 1.6;
}

.docs-measure-also {
  color: var(--ink-dim);
  font-size: var(--font-size-sm);
}

/* The reference table docgen writes and a pipe table in a section body */
.docs-table,
.docs-content table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: var(--space-4);
  font-size: var(--font-size-sm);
}

.docs-table th,
.docs-table td,
.docs-content table th,
.docs-content table td {
  padding: var(--space-2) var(--space-4);
  text-align: left;
  border: 1px solid var(--line);
}

.docs-table th,
.docs-content table th {
  background-color: var(--raised);
  font-weight: 600;
  color: var(--ink);
}

.docs-table tr:nth-child(even) td,
.docs-content table tr:nth-child(even) td {
  background-color: var(--raised);
}

/* Below 640 a docs table stacks (DS-PAGE-28): one bordered block per body
   row, each cell its own line. The header row leaves the layout but stays in
   the accessibility tree; the first cell of a row leads it in bold. From 640
   the table is a table again. */
.docs-table,
.docs-content table,
.docs-table tbody,
.docs-content table tbody {
  display: block;
}

.docs-table thead,
.docs-content table thead {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.docs-table tr,
.docs-content table tr {
  display: block;
  margin-bottom: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

.docs-table td,
.docs-content table td {
  display: block;
  border: 0;
  overflow-wrap: anywhere;
}

.docs-table td:first-child,
.docs-content table td:first-child {
  font-weight: 600;
  color: var(--ink);
}

@media (min-width: 40em) {
  .docs-table,
  .docs-content table {
    display: table;
  }

  .docs-table tbody,
  .docs-content table tbody {
    display: table-row-group;
  }

  .docs-table thead,
  .docs-content table thead {
    position: static;
    display: table-header-group;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
  }

  .docs-table tr,
  .docs-content table tr {
    display: table-row;
    margin-bottom: 0;
    border: 0;
    border-radius: 0;
  }

  .docs-table td,
  .docs-content table td {
    display: table-cell;
    border: 1px solid var(--line);
    overflow-wrap: normal;
  }

  .docs-table td:first-child,
  .docs-content table td:first-child {
    font-weight: 400;
    color: inherit;
  }
}

.docs-see-also {
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.docs-see-also h3 {
  font-size: var(--font-size-base);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-2);
}

.docs-see-also-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.docs-see-also-list a {
  display: block;
  padding: var(--space-1) 0;
  color: var(--primary);
}

/* Docs links list (See Also) */
.docs-links {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-4) 0;
}

.docs-links li {
  margin-bottom: var(--space-1);
}

.docs-links a {
  color: var(--primary);
}

.docs-links a:hover {
  text-decoration: underline;
}

/* Lists in docs content */
.docs-content ol,
.docs-content ul:not(.docs-links) {
  margin-bottom: var(--space-4);
  padding-left: var(--space-6);
}

.docs-content li {
  margin-bottom: var(--space-1);
  line-height: 1.6;
}

/* How to read it (DS-PAGE-20): the item number is a marker element carrying
   the number of its figure marker, so the ol draws no native numbering. */
.docs-content ol.docs-reading {
  list-style: none;
  padding-left: 0;
}

/* The lag callout ending How to read it (DS-PAGE-23): a 3px info left rule,
   a caps Lag label, the lag sentence and a link to the pipeline page. */
.docs-callout {
  margin: var(--space-4) 0;
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--info);
  background: var(--surface);
}

.docs-callout__label {
  margin-right: var(--space-2);
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--info);
}

.docs-reading-marker {
  margin-right: var(--space-2);
  vertical-align: baseline;
  box-sizing: border-box;
  min-width: 18px;
  height: 18px;
  border-radius: var(--radius-md);
  background: var(--caution);
  color: var(--canvas);
  font-size: var(--chart-font-md);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Formula box */
.docs-formula {
  background-color: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
}

.docs-formula-main {
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.docs-formula-vars {
  color: var(--ink-faint);
  font-size: var(--font-size-sm);
}

/* Frozen example (site-docs FR-12 to FR-15). The mount root and the two
   wrappers docs-mount.js adds (.docs-example-grid, .docs-example-item) are
   the doc page's stand-in for a dashboard tile, so they carry the tile's job:
   hand the widget a box with a height. A chart widget sizes its canvas to the
   box it is given, so an auto-height box yields a zero-height canvas and an
   invisible chart; the min-height is the floor that box never drops below.
   It is a floor, not a height: a table widget taller than the floor grows the
   box instead of scrolling inside it, which is what a reader of a doc page
   needs. */
.docs-example {
  display: flex;
  flex-direction: column;
  min-height: 360px;
  margin: 0;
}

.docs-example-grid,
.docs-example-item,
.docs-example-item > .widget,
.docs-example .widget-shell {
  flex: 1 1 auto;
  min-height: 0;
}

.docs-example-grid,
.docs-example-item {
  display: flex;
  flex-direction: column;
}

/* Callout gutter (site-docs FR-15, wave-6 ruling 6-4). docs-mount.js adds
   this class only when the example carries callouts, before it measures the
   root for rail placement; the pad must equal MARKER_SIZE (18px) + RAIL_GAP
   (2px) there so the rail strip never sits over widget content. */
.docs-example-callout-gutter {
  padding: 20px;
}

/* Chart-canvas containment floor (chrome-callouts-fix-5-fix-2, wave-20
   ruling 20-5). framework/docs-mount.js now reserves the callout gutter
   before the widget mounts, so ECharts measures the settled box at init and
   this rule is normally a no-op; it stays as the floor of last resort so a
   craft that inits its chart ahead of layout still cannot draw wider than
   .widget-shell-chart. trader-dashboard.css's `.widget-shell-chart canvas`
   rule alone cannot do this: max-width there resolves against the ECharts
   wrapper div (the canvas's own containing block), not this settled shell. */
.docs-example .widget-shell-chart > div {
  max-width: 100%;
}

.docs-example-figure {
  margin: 0 0 var(--space-4) 0;
}

/* A guide picture or clip, capped to the prose column */
.docs-picture {
  display: block;
  max-width: 100%;
  height: auto;
  margin: var(--space-4) 0;
  border: 1px solid var(--line);
}

.docs-example-caption {
  display: flex;
  align-items: baseline;
  white-space: nowrap;
  color: var(--ink-faint);
  font-size: var(--chart-font-lg);
  padding-top: var(--space-2);
}

/* The date is the caption's trailing text node, so the pointer comes first in
   the source and sits at the right edge here. */
.docs-example-caption-live {
  order: 1;
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A callout marker's perpendicular stacking offset (docs-mount.js sets
 * --rail-offset per marker, unclamped). The browser resolves this against
 * the example box's LIVE size at every layout, so a resize the placement
 * pass's one-time snapshot could miss never pushes a marker outside the
 * box. 18px matches docs-mount.js's MARKER_SIZE. */
.docs-callout-marker[data-rail-axis="top"] {
  top: clamp(0px, var(--rail-offset, 0px), calc(100% - 18px));
}

.docs-callout-marker[data-rail-axis="left"] {
  left: clamp(0px, var(--rail-offset, 0px), calc(100% - 18px));
}

/* The arrowhead takes the token the leader line's stroke takes, so one
 * theme edit moves both marks. */
.docs-callout-arrow {
  fill: var(--caution);
}

/* side-nav.css - the side nav pattern (DS-LAY-20 to DS-LAY-22).
 * A labelled nav. From 64em its list stacks vertically and the current item
 * carries an inset 2px --primary bar. Below 64em side-nav.js adds
 * .is-enhanced, hides the list and shows the trigger that opens the menu
 * component; without the script the list stays visible. */

.side-nav {
  display: block;
  margin-bottom: var(--space-6);
}

.side-nav__trigger {
  display: none;
  width: 100%;
  justify-content: space-between;
}

.side-nav.is-enhanced .side-nav__trigger {
  display: inline-flex;
}

.side-nav.is-enhanced .side-nav__list {
  display: none;
}

.side-nav__list {
  display: flex;
  flex-direction: column;
}

.side-nav__item {
  display: block;
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-sm);
  text-decoration: none;
  color: var(--ink-faint);
}

.side-nav__item:hover {
  color: var(--ink);
  text-decoration: none;
}

.side-nav__item[aria-current="page"] {
  color: var(--primary);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--primary);
}

.side-nav__title {
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink);
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--line);
}

.side-nav.is-enhanced .side-nav__title {
  display: none;
}

@media (min-width: 64em) {
  .side-nav.is-enhanced .side-nav__title {
    display: block;
  }

  .side-nav.is-enhanced .side-nav__trigger {
    display: none;
  }

  .side-nav.is-enhanced .side-nav__list {
    display: flex;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Stats Panel Component - Grouped sections with interpretations
   ═══════════════════════════════════════════════════════════════════════════ */

/* Section container with separator */
.stats-section {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
}

.stats-section:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.stats-section:first-child {
  padding-top: 0;
}

/* Section header */
.stats-section-header {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--ink-dim);
  margin-bottom: var(--space-2);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* Stats row grid: columns of quote-lines. Each stat-item is a single
   label-left / value-right LINE (2026-07 redesign) - lines reflow into 1..N
   columns with the container and never break internally, unlike the old
   stacked label-over-value cards that went ragged at narrow widths. */
.stats-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px var(--space-4);
}

/* Individual stat item: one quote-line */
.stat-item {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
  min-width: 0;
  padding: 1px 0;
}

.stat-item-wide {
  grid-column: span 2;
}

/* Stat label */
.stat-label {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  text-transform: uppercase;
  letter-spacing: 0;
  white-space: nowrap;
}

/* Stat value */
.stat-value {
  font-size: var(--font-size-sm);
  color: var(--ink);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Stat interpretation text: guidance, quiet but readable (no italics -
   slanted mono strains at small sizes) */
.stat-interpretation {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  line-height: 1.4;
  margin-top: var(--space-1);
}

/* The model-assumption disclaimer (Language Contract): always present,
   always quiet */
.stats-assumption {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  margin-top: var(--space-2);
  padding-top: var(--space-1);
  border-top: 1px dashed var(--line);
}

/* Context bar: the panel's identity line (symbol / tenor / spot / date) */
.stats-context {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
}

.stats-context-symbol {
  font-size: var(--font-size-lg);
  font-weight: 600;
  color: var(--primary);
  letter-spacing: 0;
}

.stats-context-item {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.stats-context-date {
  margin-left: auto;
  color: var(--ink-faint);
}

/* Hint text at section bottom */
.stats-hint {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  margin-top: var(--space-2);
  line-height: 1.4;
}

/* Peak exposure highlight */
.stats-peak-exposure {
  border-left: 3px solid var(--caution);
  padding-left: var(--space-3);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Signal Box - Trading signal with color coding
   ═══════════════════════════════════════════════════════════════════════════ */

/* Compact signal row (2026-07 redesign): a quote-line with a colored value
   chip, not a padded card - cards refused to reflow in small tiles */
.stats-signal-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-1) 0;
}

.signal-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  min-width: 0;
}

.signal-label {
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--ink-faint);
  text-transform: uppercase;
  letter-spacing: 0;
  white-space: nowrap;
}

.signal-value {
  font-size: var(--font-size-sm);
  font-weight: 600;
  font-family: var(--font-mono);
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  text-align: right;
}

.signal-interpretation {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  line-height: 1.4;
}

.signal-strength {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
}

/* Signal color variants */
.signal-green {
  color: var(--positive);
  border: 1px solid color-mix(in oklab, var(--positive) 26%, transparent);
}

.signal-yellow {
  color: var(--caution);
  background: color-mix(in oklab, var(--caution) 16%, transparent);
  border: 1px solid color-mix(in oklab, var(--caution) 26%, transparent);
}

.signal-red {
  color: var(--negative);
  background: color-mix(in oklab, var(--negative) 16%, transparent);
  border: 1px solid color-mix(in oklab, var(--negative) 26%, transparent);
}

.signal-neutral {
  color: var(--ink-faint);
  background: color-mix(in oklab, var(--ink-faint) 10%, transparent);
  border: 1px solid color-mix(in oklab, var(--ink-faint) 16%, transparent);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Range Box - Price/value ranges with percentages
   ═══════════════════════════════════════════════════════════════════════════ */

.stats-range-box {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
}

.range-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) 0;
}

.range-row:first-child {
  border-bottom: 1px solid var(--line);
}

.range-label {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  min-width: 70px;
}

.range-value {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--ink);
  flex: 1;
}

.range-pct {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Threshold Hint - Shows threshold values inline
   ═══════════════════════════════════════════════════════════════════════════ */

.threshold-hint {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  margin-top: var(--space-2);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Container-aware densification (platform session 2026-07)

   Panels reflow with their TILE, not the viewport. The widget body is the
   query container; presentation:'panel' widgets are the only non-chart-mode
   bodies, so charts are untouched. The tiers re-scope the font-size/space
   variables the panel rules already consume, so every descendant (including
   page-level overrides) densifies together. Outside a widget (no ancestor
   container) the media query below still applies unchanged.
   ═══════════════════════════════════════════════════════════════════════════ */

.widget-body:not(.chart-mode) {
  container-type: inline-size;
}

.stat-item {
  min-width: 0;
}

.stat-value {
  overflow-wrap: anywhere;
}

@container (max-width: 420px) {
  .info-widget-content {
    --space-2: 0.25rem;
    --space-3: 0.5rem;
    padding: var(--space-1) var(--space-2);
    line-height: 1.4;
  }

  .stats-row {
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  }
}

@container (max-width: 300px) {
  .info-widget-content {
    --space-3: 0.375rem;
    line-height: 1.4;
  }

  .stats-row {
    grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
    gap: var(--space-1);
  }

  .stats-section {
    padding: var(--space-1) 0;
  }

  /* micro tier: interpretations and strength hints yield to the numbers */
  .stat-interpretation,
  .signal-interpretation,
  .signal-strength,
  .stats-context-date,
  .stats-hint {
    display: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Responsive
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {
  .stats-row {
    grid-template-columns: repeat(2, 1fr);
  }

  .stat-item-wide {
    grid-column: span 1;
  }

  .signal-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .threshold-hint {
    flex-direction: column;
  }
}

/* Flag dots: one 6px dot or ring per data-quality cause, top-right of the flagged
   cell (widget body, panel section, or stat item). Spec:
   spec/design-system/components.md, row "flag dot". */

.has-flag-dots {
  position: relative;
}

.stat-item.has-flag-dots {
  padding-right: var(--space-3);
}

.flag-dots {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  display: inline-flex;
  gap: var(--space-1);
}

.flag-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.flag-dot--caution {
  background-color: var(--caution);
}

/* A ring, not a second fill: shape separates the causes without colour. */
.flag-dot--info {
  box-sizing: border-box;
  background-color: transparent;
  border: 1px solid var(--info);
}

.chart-container {
  width: 100%;
  min-height: 150px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

/* Remove padding when panel-body wraps a chart */
.panel-body:has(> .chart-container) {
  padding: 0;
}

.panel-body .chart-container {
  border: none;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}

/* When a legend follows the chart, chart has no bottom corners */
.panel-body:has(> .chart-legend, > .ts-legend) > .chart-container {
  border-radius: 0;
}

/* Legend extends full width with bottom corners */
.panel-body > .chart-legend,
.panel-body > .ts-legend {
  padding: var(--space-2) var(--space-4);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}

/* Subtle TradingView attribution */
.tv-lightweight-charts a[href*="tradingview"] {
  opacity: 0.25;
  transform: scale(0.7);
  transform-origin: bottom right;
  transition: opacity var(--dur-base), transform var(--dur-base);
}

.tv-lightweight-charts a[href*="tradingview"]:hover {
  opacity: 0.5;
  transform: scale(0.85);
}

/* Shared chart legends */
.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    padding: var(--space-2) var(--space-3);
    font-size: var(--font-size-sm);
    color: var(--ink-faint);
}

.legend-item {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.legend-color {
    width: 12px;
    height: 3px;
    border-radius: var(--radius-sm);
}

.legend-color.legend-dashed {
    background: repeating-linear-gradient(
        90deg,
        currentColor 0,
        currentColor 3px,
        transparent 3px,
        transparent 5px
    ) !important;
    background-color: transparent !important;
}

.legend-color.legend-vertical {
    width: 3px;
    height: 12px;
}

/* Signal indicator styles - shared across explorer, analysis pages */

.signal-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.signal-label {
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    text-transform: uppercase;
}

.signal-value {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    font-weight: 600;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
}

.signal-value.signal-green {
    color: var(--positive);
}

.signal-value.signal-yellow {
    background: color-mix(in oklab, var(--caution) 16%, transparent);
    color: var(--caution);
}

.signal-value.signal-red {
    background: color-mix(in oklab, var(--negative) 16%, transparent);
    color: var(--negative);
}

.signal-value.signal-neutral {
    background: var(--raised);
    color: var(--ink-faint);
}

.signal-interpretation {
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    font-style: italic;
}

.signal-strength {
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    font-family: var(--font-mono);
}

/* Chart page control bar patterns - shared across explorer, analysis, distribution, greek-flow */

/* Control group layout */
.control-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.control-group label {
    font-size: var(--font-size-sm);
    color: var(--ink-dim);
}

/* Compact form controls inside control groups (overrides full-width form styles) */
.control-group .form-select {
    padding: var(--space-2) var(--space-3);
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    color: var(--ink);
    font-family: var(--font-mono);
    min-width: 140px;
    width: auto;
}

.control-group .form-select:focus {
    border-color: var(--primary);
    box-shadow: none;
}

.control-group .form-input {
    min-width: 140px;
    width: auto;
}

/* Dashboard Page Styles */

/* ═══════════════════════════════════════════════════════════════════════════
   PAGE TITLE
   ═══════════════════════════════════════════════════════════════════════════ */

.page-title {
  margin-bottom: var(--space-6);
  color: var(--ink);
}

/* ═══════════════════════════════════════════════════════════════════════════
   WELCOME BANNER
   ═══════════════════════════════════════════════════════════════════════════ */

.welcome-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* ═══════════════════════════════════════════════════════════════════════════
   STATS GRID
   ═══════════════════════════════════════════════════════════════════════════ */

.stats-grid {
  display: grid;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.stat-plan {
  font-size: var(--font-size-lg);
  text-transform: capitalize;
}

/* Responsive stats grid */
@media (max-width: 1023px) {
  .stats-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 639px) {
  .stats-grid {
    grid-template-columns: 1fr;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PANEL HEADER WITH BUTTON
   ═══════════════════════════════════════════════════════════════════════════ */

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DATA TABLE
   ═══════════════════════════════════════════════════════════════════════════ */

.data-table {
  width: 100%;
  border-collapse: collapse;
}

.data-table th,
.data-table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  border-bottom: 1px solid var(--line);
}

.data-table th {
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--ink-faint);
}

.data-table td {
  font-size: var(--font-size-sm);
}

.data-table tbody tr:hover {
  background: var(--line);
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

/* Token prefix styling */
.token-prefix {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  background: var(--line);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
}

/* Status dots: .status-dot lives in components/tables.css */
.status-recent {
  background: var(--caution);
}

.status-idle {
  background: var(--ink-faint);
}

/* ═══════════════════════════════════════════════════════════════════════════
   ACTIVITY TABLE
   ═══════════════════════════════════════════════════════════════════════════ */

.activity-table .timestamp {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
}

.activity-table .latency {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
}

.status-code {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  font-weight: 600;
}

.status-code.status-success {
  color: var(--positive);
}

.status-code.status-warning {
  color: var(--caution);
}

.status-code.status-error {
  color: var(--negative);
}

/* ═══════════════════════════════════════════════════════════════════════════
   EMPTY STATES
   ═══════════════════════════════════════════════════════════════════════════ */

.empty-state {
  text-align: center;
  padding: var(--space-12) var(--space-8);
  background:
    radial-gradient(circle at 50% 0%, color-mix(in oklab, var(--primary) 10%, transparent) 0%, transparent 50%),
    var(--raised);
}

.empty-state-ascii {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  white-space: pre;
  line-height: 1.2;
  margin-bottom: var(--space-6);
  opacity: 0.6;
}

.empty-state-title {
  font-size: var(--font-size-lg);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-2);
}

.empty-state p {
  margin-bottom: var(--space-2);
}

.empty-state p:first-child {
  font-weight: 600;
}

.empty-state .text-muted {
  color: var(--ink-faint);
  font-size: var(--font-size-sm);
}

.empty-state .btn {
  margin-top: var(--space-6);
}

.empty-state .btn-primary {
  box-shadow: var(--glow-aqua);
}

.empty-state-sm {
  padding: var(--space-4);
}

.empty-state-sm p {
  color: var(--ink-faint);
  font-size: var(--font-size-sm);
  margin-bottom: 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT SPACING
   ═══════════════════════════════════════════════════════════════════════════ */

.panel {
  margin-bottom: var(--space-6);
}

.panel:last-child {
  margin-bottom: 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   CHART ATTRIBUTION
   ═══════════════════════════════════════════════════════════════════════════ */

/* Subtle TradingView attribution */
.tv-lightweight-charts a[href*="tradingview"] {
  opacity: 0.25;
  transform: scale(0.7);
  transform-origin: bottom right;
  transition: opacity var(--dur-base), transform var(--dur-base);
}

.tv-lightweight-charts a[href*="tradingview"]:hover {
  opacity: 0.5;
  transform: scale(0.85);
}

/* Explorer Page Styles - term-structure legend */

.chart-container {
    height: clamp(320px, 40vh, 450px);
    min-height: 320px;
    position: relative;
}

/* Term Structure legend */
.ts-legend {
    display: flex;
    gap: var(--space-4);
    padding: var(--space-2) var(--space-3);
    font-size: var(--font-size-sm);
    color: var(--ink-faint);
}

/* Responsive */
@media (max-width: 768px) {
    .ts-legend {
        flex-wrap: wrap;
    }
}

/* HTMX indicator styles */
.htmx-indicator {
    opacity: 0;
    transition: opacity var(--dur-base) ease-in;
}

.htmx-request .htmx-indicator {
    opacity: 1;
}

.htmx-request.htmx-indicator {
    opacity: 1;
}

/* Form feedback */
.form-error {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    margin-bottom: var(--space-4);
    background: color-mix(in oklab, var(--negative) 10%, transparent);
    border: 1px solid var(--negative);
    border-radius: var(--radius-sm);
    color: var(--negative);
}

/* display: flex above outranks the hidden attribute's UA rule. */
.form-error[hidden] {
    display: none;
}

.form-error-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    background: var(--negative);
    color: var(--negative);
    border-radius: 50%;
    font-size: 0.75rem;
    font-weight: 600;
}

.form-success {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    background: var(--surface);
    border: 1px solid var(--positive);
    border-radius: 0.375rem;
    color: var(--positive);
}

.form-success-icon {
    font-size: 1rem;
}

/* Modal styles */
.modal {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-backdrop {
    position: absolute;
    inset: 0;
    background: color-mix(in oklab, var(--canvas) 26%, transparent);
    animation: modalFadeIn 150ms ease-out;
}

.modal[aria-hidden="true"] {
    display: none !important;
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4);
    border-bottom: 1px solid var(--line);
}

.modal-header h2 {
    margin: 0;
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--ink);
}

.modal-header h3 {
    margin: 0;
    font-size: var(--font-size-base);
    color: var(--ink);
}

.modal-close {
    background: none;
    border: none;
    font-size: var(--font-size-2xl);
    cursor: pointer;
    color: var(--ink-faint);
    line-height: 1.1;
}

.modal-close:hover {
    color: var(--ink);
}

.modal-body {
    padding: var(--space-4);
}

.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    padding: var(--space-4);
    border-top: 1px solid var(--line);
}

@media (hover: none) {
    .modal-close:active {
        color: var(--ink);
    }
}

/* List styles */
.list-item {
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--line);
}

.list-item:last-child {
    border-bottom: none;
}

/* Modal animations */
@keyframes modalFadeIn {
    from { opacity: 0; }
}

@keyframes modalScaleIn {
    from { opacity: 0; transform: scale(.95) translateY(8px); }
}

/* Scrollbar styling */
::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: var(--canvas);
}

::-webkit-scrollbar-thumb {
    background: var(--line);
    border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--ink-faint);
}

/* Firefox scrollbar */
* {
    scrollbar-color: var(--line) var(--canvas);
    scrollbar-width: thin;
}

/* Semantic data color utility classes */
.data-positive { color: var(--positive); }
.data-negative { color: var(--negative); }
.data-neutral { color: var(--ink); }
.data-accent { color: var(--primary); }

/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT - the four page shells and the page header recipe
   The one owner of these selectors (DS-LAY-33). Widths come from the
   --w-* tokens and the side gutter from --gutter (theme.css).
   ═══════════════════════════════════════════════════════════════════════════ */

/* Viewport fill: body is at least the viewport tall, main grows to fill it,
   and a page that wants the whole area (docs, workspace, login, error) sets
   flex: 1 on its root instead of subtracting a guessed chrome height. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--space-6) 0;
}

main > :where(*) {
  width: 100%;
}

/* Skip link: the first focusable element, visible on focus only. The global
   focus ring (chrome.css) draws its outline. */
.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-toast);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

/* The shared box: nav, shell and footer content sit in one --w-wide box with
   the gutter inside it, so the nav logo, the page h1 and the first footer
   column share one left edge at every viewport. */
.shell-box {
  box-sizing: border-box;
  width: 100%;
  max-width: var(--w-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Workspace pages run edge to edge, so their nav and footer box does too. */
body:has(.page--workspace) .shell-box {
  max-width: var(--w-full);
}

/* Shells: .page applies the gutter once; a modifier picks the width. No block
   inside a shell pads its own sides. .container is the retired name of .page
   (layout-owner.test.mjs still lists it); no template uses it. */
.page,
.container {
  box-sizing: border-box;
  width: 100%;
  padding-inline: var(--gutter);
}

/* Document: the prose column is --w-prose; content-box sizing puts the gutter
   outside that cap. The start margin is the offset of the shared --w-wide box,
   so the column starts at the same edge as the nav logo. */
.page--document {
  box-sizing: content-box;
  width: auto;
  max-width: var(--w-prose);
  margin-inline-start: calc((100% - min(100%, var(--w-wide))) / 2);
}

.page--wide {
  max-width: var(--w-wide);
  margin-inline: auto;
}

/* Focus: one card, --w-narrow wide, centred in main (flex growth gives the
   vertical centre, the footer sits at the viewport bottom). */
.page--focus {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: min(100%, calc(var(--w-narrow) + 2 * var(--gutter)));
  margin-inline: auto;
}

.page--workspace {
  max-width: var(--w-full);
}

/* Page header: eyebrow, h1 title, lede. */
.page-header {
  padding: var(--space-6) 0;
}

.page-header h1 {
  margin: 0;
}

/* Heading sizes: the values of .text-h1, .text-h2 and .text-h3 (theme.css).
   The landing hero sets its own 48px (.text-display) in landing.css. */
main h1 {
  font-size: var(--font-size-3xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

main h2 {
  font-size: var(--font-size-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-align: left;
}

main [class*="card"] h3 {
  font-size: var(--font-size-lg);
  font-weight: 600;
  line-height: 1.4;
}

.page-eyebrow {
  margin: 0 0 var(--space-1);
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.page-lede {
  max-width: var(--w-prose);
  margin: var(--space-2) 0 0;
  color: var(--ink-dim);
}

/* ═══════════════════════════════════════════════════════════════════════════
   TickPlunge Terminal - Responsive Layout
   Mobile-first responsive styles with breakpoints at 640px and 1024px
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   NAVIGATION - Mobile hamburger toggle
   ═══════════════════════════════════════════════════════════════════════════ */

.nav-toggle {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: none;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--font-size-lg);
  cursor: pointer;
}

/* Below 1024: hide nav links, show toggle */
.nav-links {
  display: none;
}

.nav-toggle {
  display: flex;
}

/* Mobile: expanded nav menu */
.nav-links.is-open {
  display: flex;
  flex-direction: column;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: var(--space-4);
  gap: var(--space-8);
  z-index: var(--z-menu);
}

.nav {
  position: relative;
}

/* Mobile: dropdown items show inline */
.nav-dropdown-menu {
  display: flex !important;
  position: static;
  transform: none;
  background: transparent;
  border: none;
  box-shadow: none;
  min-width: auto;
  padding: 0;
  flex-direction: column;
  gap: var(--space-6);
}

.nav-dropdown-toggle {
  display: none;
}

/* 1024 and up: show nav links, hide toggle */
@media (min-width: 64em) {
  .nav-links {
    display: flex;
    position: static;
    flex-direction: row;
    background: transparent;
    border: none;
    padding: 0;
  }

  .nav-links.is-open {
    position: static;
  }

  .nav-toggle {
    display: none;
  }

  .nav-dropdown-toggle {
    display: inline;
  }

  .nav-dropdown-menu {
    display: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   GRID LAYOUTS
   ═══════════════════════════════════════════════════════════════════════════ */

/* Stats grid: 1 column below 640 and 2 below 1024 (pages/dashboard.css), 4 from 1024 */
.stats-grid {
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 1024px) {
  .stats-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Generic responsive grid */
.grid {
  display: grid;
  gap: var(--space-4);
}

.grid-2 {
  grid-template-columns: 1fr;
}

.grid-3 {
  grid-template-columns: 1fr;
}

.grid-4 {
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 640px) {
  .grid-2 {
    grid-template-columns: repeat(2, 1fr);
  }

  .grid-3 {
    grid-template-columns: repeat(2, 1fr);
  }

  .grid-4 {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 1024px) {
  .grid-3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   FORMS - Full width on mobile
   ═══════════════════════════════════════════════════════════════════════════ */

.form-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

@media (min-width: 640px) {
  .form-row {
    flex-direction: row;
  }

  .form-row > .form-group {
    flex: 1;
  }
}

/* Inline form elements */
.form-inline {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

@media (min-width: 640px) {
  .form-inline {
    flex-direction: row;
    align-items: flex-end;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PANELS & CARDS - Stack on mobile
   ═══════════════════════════════════════════════════════════════════════════ */

.panel-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .panel-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .panel-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Sidebar layout */
.layout-sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

@media (min-width: 1024px) {
  .layout-sidebar {
    flex-direction: row;
  }

  .layout-sidebar-main {
    flex: 1;
  }

  .layout-sidebar-aside {
    width: 300px;
    flex-shrink: 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   TOUCH TARGETS (DS-LAY-27) - below 1024 every control in the page chrome,
   outside .widget-body, has a 44px square hit area centred on it. Buttons,
   links and chips get it from a pseudo element, so their visual size is the
   1440 size; fields take min-height 44px. :where() keeps every selector at
   zero specificity, so a component's own position or min-height wins.
   .nav-link uses ::before because chrome.css draws its current-page
   underline on ::after.
   ═══════════════════════════════════════════════════════════════════════════ */

:where(a, button, [role="button"], [role="tab"]):where(:not(.widget-body *)) {
  position: relative;
}

:where(a, button, [role="button"], [role="tab"]):where(:not(.widget-body *, .nav-link))::after,
:where(.nav-link)::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

:where(input:not([type="hidden"]), select, textarea):where(:not(.widget-body *)) {
  min-height: 44px;
}

:where(input[type="checkbox"], input[type="radio"]):where(:not(.widget-body *)) {
  min-width: 44px;
}

@media (min-width: 64em) {
  :where(a, button, [role="button"], [role="tab"]):where(:not(.widget-body *)) {
    position: static;
  }

  :where(a, button, [role="button"], [role="tab"]):where(:not(.widget-body *, .nav-link))::after,
  :where(.nav-link)::before {
    content: none;
  }

  :where(input:not([type="hidden"]), select, textarea):where(:not(.widget-body *)) {
    min-height: auto;
  }

  :where(input[type="checkbox"], input[type="radio"]):where(:not(.widget-body *)) {
    min-width: auto;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   UTILITIES - Responsive visibility
   ═══════════════════════════════════════════════════════════════════════════ */

/* Hide on mobile */
.hide-mobile {
  display: none;
}

@media (min-width: 640px) {
  .hide-mobile {
    display: initial;
  }
}

/* Show only on mobile */
.show-mobile {
  display: initial;
}

@media (min-width: 640px) {
  .show-mobile {
    display: none;
  }
}

/* Hide on tablet and below */
.hide-tablet {
  display: none;
}

@media (min-width: 1024px) {
  .hide-tablet {
    display: initial;
  }
}

/* Show only on tablet and below */
.show-tablet {
  display: initial;
}

@media (min-width: 1024px) {
  .show-tablet {
    display: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE TYPOGRAPHY
   ═══════════════════════════════════════════════════════════════════════════ */

.text-display {
  font-size: var(--font-size-2xl);
}

.text-h1 {
  font-size: var(--font-size-xl);
}

@media (min-width: 640px) {
  .text-display {
    font-size: var(--font-size-3xl);
  }

  .text-h1 {
    font-size: var(--font-size-2xl);
  }
}

@media (min-width: 1024px) {
  .text-display {
    font-size: var(--font-size-4xl);
  }

  .text-h1 {
    font-size: var(--font-size-3xl);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE SPACING
   ═══════════════════════════════════════════════════════════════════════════ */

.section {
  padding: var(--space-8) 0;
}

@media (min-width: 640px) {
  .section {
    padding: var(--space-12) 0;
  }
}

@media (min-width: 1024px) {
  .section {
    padding: var(--space-16) 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PREVENT HORIZONTAL SCROLL
   ═══════════════════════════════════════════════════════════════════════════ */

.overflow-x-auto {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ═══════════════════════════════════════════════════════════════════════════
   BREADCRUMBS
   ═══════════════════════════════════════════════════════════════════════════ */

.breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
  margin-bottom: var(--space-2);
}

.breadcrumb a {
  color: var(--ink-faint);
  text-decoration: none;
}

.breadcrumb a:hover {
  color: var(--primary);
}

.breadcrumb-sep {
  color: var(--ink-faint);
}

/* ═══════════════════════════════════════════════════════════════════════════
   TOKEN DETAIL LAYOUT
   ═══════════════════════════════════════════════════════════════════════════ */

.token-detail-grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .token-detail-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* Token info definition list */
.token-info {
  margin: 0;
}

.info-row {
  display: flex;
  justify-content: space-between;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
}

.info-row:last-child {
  border-bottom: none;
}

.info-row dt {
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
}

.info-row dd {
  font-size: var(--font-size-sm);
  color: var(--ink);
  margin: 0;
}

.info-row code {
  font-family: var(--font-mono);
  background: var(--line);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
}

/* Status badges */
.status-revoked {
  color: var(--negative);
}

/* Desktop notice: app pages below the 1024px design width; one 32px line. */
.desktop-notice {
  display: none;
  align-items: center;
  box-sizing: border-box;
  height: 2rem;
  padding: 0 var(--space-4);
  overflow-x: auto;
  white-space: nowrap;
  background: var(--raised);
  border-bottom: 1px solid var(--line);
  color: var(--ink-dim);
  font-size: var(--font-size-sm);
}

@media (max-width: 1023px) {
  .desktop-notice {
    display: flex;
  }
}

/* Long identifiers in page prose break instead of widening the page at 360 (DS-LAY-24). */
main code {
  overflow-wrap: anywhere;
}

/* ═══════════════════════════════════════════════════════════════════════════
   BASE RESET & DEFAULTS
   ═══════════════════════════════════════════════════════════════════════════ */

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

html {
  font-size: 16px;
}

body {
  font-family: var(--font-mono);
  background: var(--canvas);
  color: var(--ink);
  line-height: 1.6;
}

a {
  color: inherit;
  text-decoration: none;
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

a:hover {
  color: var(--primary);
}

/* ═══════════════════════════════════════════════════════════════════════════
   TYPOGRAPHY HIERARCHY
   ═══════════════════════════════════════════════════════════════════════════ */

h1, h2, h3, h4, h5, h6, th, b, strong {
  font-weight: 600;
}

/* ═══════════════════════════════════════════════════════════════════════════
   NAVIGATION
   ═══════════════════════════════════════════════════════════════════════════ */

.nav {
  display: flex;
  align-items: center;
  padding-block: var(--space-4);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

/* The shared box (components/layout.css) holds the gutter. */
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.nav-logo {
  font-family: var(--font-mono);
  font-size: var(--font-size-lg);
  font-weight: 600;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nav-logo:hover {
  color: var(--ink);
}

.logo-prompt {
  color: var(--primary);
}

.logo-text {
  color: var(--ink);
}

.logo-brand {
  margin-left: var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.nav-links {
  align-items: center;
  gap: var(--space-4);
}

.nav-link {
  font-size: var(--font-size-sm);
  color: var(--ink-dim);
  text-decoration: none;
  transition: color var(--dur-fast) ease;
}

.nav-link:hover {
  color: var(--ink);
}

.nav-link[aria-current="page"] {
  color: var(--primary);
  position: relative;
}

.nav-link[aria-current="page"]::after {
  content: '';
  position: absolute;
  bottom: -4px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--primary);
}

.nav-link-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
}

/* Nav dropdown */
.nav-dropdown {
  position: relative;
}

.nav-caret {
  font-size: 0.6em;
  margin-left: var(--space-1);
  opacity: 0.6;
}

.nav-dropdown-menu {
  display: none;
  z-index: var(--z-menu);
}

.nav-dropdown-item {
  display: block;
  padding: var(--space-2) var(--space-4);
  font-size: var(--font-size-sm);
  color: var(--ink-dim);
  text-decoration: none;
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}

.nav-dropdown-item:hover {
  background: var(--line);
  color: var(--ink);
}

.nav-dropdown-item[aria-current="page"] {
  color: var(--primary);
}

/* Settings shell (DS-PAGE-46, DS-PAGE-47): below 64em the side nav is the
 * sticky 44px settings bar; from 64em a 264px column beside the page. */
.settings-layout > .side-nav {
  position: sticky;
  top: 0;
  z-index: var(--z-raised);
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  margin-bottom: var(--space-4);
  background: var(--canvas);
}

@media (min-width: 64em) {
  .settings-layout {
    display: grid;
    grid-template-columns: 264px minmax(0, 1fr);
    gap: var(--space-8);
    align-items: start;
  }

  .settings-layout > .side-nav {
    display: block;
    margin-bottom: 0;
  }
}

/* Cache status indicator */
.cache-indicator {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.cache-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  box-sizing: border-box;
  border: 1px solid var(--ink-faint);
  border-radius: 50%;
  flex-shrink: 0;
}

.cache-dot--warming {
  border-color: var(--caution);
  animation: cache-pulse 1.4s ease-in-out infinite;
}

.cache-dot--ready {
  border-color: var(--positive);
}

.cache-dot--error {
  border-color: var(--negative);
}

.cache-dot--partial {
  border-color: var(--caution);
}

.cache-dot--idle {
  border-color: var(--ink-faint);
}

@keyframes cache-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .cache-dot--warming { animation: none; }
}

.cache-pct {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  min-width: 2.2em;
  text-align: right;
}

.cache-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-raised);
  width: 220px;
  z-index: var(--z-menu);
  padding: var(--space-2) var(--space-3);
}

.cache-panel-header {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-dim);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-2);
}

.cache-panel-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 2px 0;
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
}

.cache-panel-name {
  flex: 1;
  color: var(--ink-faint);
}

.cache-panel-val {
  color: var(--ink-faint);
  min-width: 2.8em;
  text-align: right;
}

.cache-panel-row-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border: 1px solid;
  border-radius: 50%;
  flex-shrink: 0;
}

.cache-panel-divider {
  border-top: 1px solid var(--line);
  margin: var(--space-2) 0;
}

.cache-panel-section-title {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--negative);
  margin-bottom: var(--space-1);
}

.cache-refresh-btn {
  display: block;
  width: 100%;
  margin-top: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: var(--line);
  border: none;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  cursor: pointer;
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}

.cache-refresh-btn:hover {
  background: var(--line);
  color: var(--ink);
}

/* ═══════════════════════════════════════════════════════════════════════════
   FOOTER
   ═══════════════════════════════════════════════════════════════════════════ */

.footer {
  background: var(--canvas);
  border-top: 1px solid var(--line);
  padding-block: var(--space-6);
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-inline: auto;
}

.footer-links a {
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
  text-decoration: none;
  transition: color var(--dur-fast) ease;
}

.footer-links a:hover {
  color: var(--ink);
}

.footer-year {
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
}


/* Calculator widget (spec/pages/calculator.md) */

.calc-widget {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    /* Natural height: the widget is content-sized (metadata.sizeToContent) -
       the grid cell fits the content (e.g. expanding TVM grows the cell),
       so nothing scrolls or overflows here. */
    height: auto;
    padding: var(--space-2);
    font-family: var(--font-mono);
}

.calc-input {
    width: 100%;
}

.calc-result {
    min-height: 1.5em;
    padding: 0 var(--space-2);
    color: var(--ink);
    font-size: var(--font-size-lg);
    overflow-wrap: anywhere;
}

.calc-result-error {
    color: var(--negative);
    font-size: var(--font-size-sm);
}

/* Matrix results (calc FR-18): multi-line right-aligned grid render;
   pre keeps the padded columns, scroll guards wide matrices. */
.calc-result-matrix {
    white-space: pre;
    overflow-x: auto;
    overflow-wrap: normal;
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
}

.calc-plot {
    /* Definite height (comment refreshed, #318 FR-2 chain): the calculator
       widget is `.widget--fit`, and at NATURAL size - the size `fitItem`
       measures, and the common case since the window starts sized to fit -
       wm.css keeps that ancestor `height: auto` (no FR-2 clamp engaged, the
       window is >= content), so flex:1 still has no definite basis to fill.
       The FR-2 `max-height: 100%` clamp only introduces a bound once a user
       shrinks the window below its natural content height; the plot's own
       explicit height stays independent of that shrink state either way -
       it declares its height and the cell fits it. */
    height: clamp(160px, 22vh, 280px);
}

.calc-controls {
    display: flex;
    gap: var(--space-1);
    align-items: center;
}

.calc-controls button {
    padding: var(--space-1) var(--space-2);
    background: var(--raised);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    cursor: pointer;
}

.calc-controls button:hover {
    border-color: var(--primary);
}

.calc-step {
    display: inline-flex;
    gap: var(--space-1);
}

.calc-tvm {
    border-top: 1px solid var(--line);
    padding-top: var(--space-2);
    font-size: var(--font-size-xs);
}

.calc-tvm summary {
    cursor: pointer;
    color: var(--ink-dim);
}

.calc-tvm-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
    gap: var(--space-1);
    margin: var(--space-2) 0;
}

.calc-tvm-grid label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    color: var(--ink-dim);
}

.calc-tvm-grid input {
    width: 100%;
}

.calc-tvm-grid .opt-select {
    width: 100%;
}

.calc-tvm-solve {
    padding: var(--space-1) var(--space-3);
    background: var(--raised);
    color: var(--primary);
    border: 1px solid var(--primary);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    /* buttons do NOT inherit font-size - without this it renders at the
       browser's default button size, larger than everything around it */
    font-size: var(--font-size-xs);
    cursor: pointer;
}

.calc-tvm-error {
    min-height: 1.2em;
    margin-top: var(--space-1);
    color: var(--negative);
}

/* Sheet widget (spec/pages/sheet.md) */

.sheet-widget {
    display: flex;
    flex-direction: column;
    height: 100%;
    font-family: var(--font-mono);
}

.sheet-formula-bar {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1);
}

.sheet-formula-cell {
    min-width: 5ch;
    text-align: center;
    color: var(--ink-dim);
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-xs);
    padding: 2px var(--space-1);
}

.sheet-formula-wrap {
    position: relative;
    flex: 1;
}

.sheet-formula-input {
    width: 100%;
}

.sheet-grid-wrap {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

/* Column resize: JS toggles sheet-col-resize while the pointer is over a
   column boundary and sheet-col-dragging while the drag is active. */
.sheet-grid-wrap.sheet-col-resize {
    cursor: col-resize;
    touch-action: none;
}

.sheet-grid-wrap.sheet-col-dragging {
    cursor: grabbing;
}

.sheet-grid-wrap:focus {
    box-shadow: inset 0 0 0 1px var(--line);
}

.sheet-canvas {
    display: block;
}

/* the DOM edit overlay - positioned over the active cell by the widget */
.sheet-edit {
    box-sizing: border-box;
    background: var(--canvas);
    color: var(--ink);
    border: 1px solid var(--primary);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 0 6px; /* matches the paint kernel's PAD */
    z-index: calc(var(--z-raised) + 2);
}

/* Edit-time ref colouring (#292): a coloured mirror renders the formula
   text BEHIND the input, whose own text goes transparent (caret kept).
   The mirror boxes must match the inputs glyph-for-glyph: same font,
   border thickness (transparent) and padding. */
.sheet-input-hl {
    position: relative;
    z-index: calc(var(--z-raised) + 2);
    background: transparent;
    color: transparent;
    caret-color: var(--ink);
}

.sheet-edit-hl,
.sheet-formula-hl {
    position: absolute;
    box-sizing: border-box;
    background: var(--canvas);
    color: var(--ink);
    border: 1px solid transparent;
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    white-space: pre;
    overflow: hidden;
    z-index: calc(var(--z-raised) + 1);
}

.sheet-edit-hl {
    padding: 0 6px; /* matches .sheet-edit and the paint kernel's PAD */
    line-height: 1.6;
}

.sheet-formula-hl {
    inset: 0;
    padding: 2px var(--space-2); /* matches .sheet-formula-input */
    border-radius: var(--radius-sm);
}

.sheet-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-1) 0;
}

.sheet-tabs {
    display: flex;
    gap: var(--space-1);
    overflow-x: auto;
}

.sheet-name,
.sheet-tab,
.sheet-tab-add,
.sheet-timemode,
.sheet-fmtctl button,
.sheet-step button {
    background: var(--raised);
    color: var(--ink-dim);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 2px var(--space-2);
    cursor: pointer;
}

.sheet-tab.active {
    background: var(--canvas);
    color: var(--ink);
    border-color: var(--primary);
}

.sheet-tab {
    display: inline-flex;
    align-items: center;
}

.sheet-tab-close {
    margin-left: var(--space-1);
    padding: 0;
    background: none;
    border: none;
    font: inherit;
    cursor: pointer;
    color: var(--ink-faint);
}

.sheet-tab-close:hover {
    color: var(--negative);
}

/* workbook name chip - top row, left of the A1 cell label (FR-18) */
.sheet-name {
    color: var(--primary);
    cursor: default;
    white-space: nowrap;
}

.sheet-tab-rename,
.sheet-name-rename {
    width: 8ch;
    background: var(--canvas);
    color: var(--ink);
    border: 1px solid var(--primary);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 2px var(--space-1);
}

.sheet-timectl,
.sheet-fmtctl {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

/* range aggregates (#294): count/sum/avg of the selected range. Always in
   the row (empty when the selection is a single cell) and owner of the
   auto margin, so tabs sit left and aggs+fmt+time controls pack right. */
.sheet-aggs {
    margin-left: auto;
    color: var(--ink-faint);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    white-space: nowrap;
}

.sheet-fmtctl button.active {
    background: var(--canvas);
    color: var(--primary);
    border-color: var(--primary);
}

.sheet-toast {
    position: absolute;
    bottom: var(--space-6);
    left: 50%;
    transform: translateX(-50%);
    background: var(--canvas);
    color: var(--caution);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: var(--space-1) var(--space-3);
    font-size: var(--font-size-xs);
    z-index: calc(var(--z-raised) + 3);
}

/* ---- defined names (#293, FR-21) ----------------------------------- */

/* the A1 chip doubles as the Excel-style name box (click to edit) */
.sheet-formula-cell {
    cursor: text;
}

.sheet-namebox {
    width: 10ch;
    background: var(--canvas);
    color: var(--ink);
    border: 1px solid var(--primary);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 2px var(--space-1);
}

/* inline name-manager panel between the grid and the footer */
.sheet-names {
    border-top: 1px solid var(--line);
    background: var(--canvas);
    padding: var(--space-1) var(--space-2);
    max-height: 8rem;
    overflow-y: auto;
    font-size: var(--font-size-xs);
}

.sheet-names-add {
    display: flex;
    gap: var(--space-1);
    margin-bottom: var(--space-1);
}

.sheet-names-add input,
.sheet-names-edit {
    background: var(--surface);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 2px var(--space-1);
    width: 12ch;
}

.sheet-names-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 1px 0;
}

.sheet-names-nm {
    color: var(--primary);
    min-width: 10ch;
}

.sheet-names-ref {
    color: var(--ink-faint);
}

.sheet-names-dangling .sheet-names-ref {
    color: var(--negative);
}

.sheet-names-del {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--ink-faint);
    cursor: pointer;
    font-family: var(--font-mono);
}

.sheet-names-del:hover {
    color: var(--negative);
}

/* BoardKit generic classes (static/js/framework/shell/board-kit.js) - the
   shared dense-table chrome for symbol-less "board" widgets. Lifted from
   macro-board.css's .macro-* rules (spec/pages/macro-board.md);
   consumers add their own semantic classes (subheader rows, etc.) on top.
   Godel quote-monitor disciplines: 21px rows, single font-weight, mono,
   right-aligned numerics. */

.board {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: auto;
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
}

.board-table {
    width: 100%;
    border-collapse: collapse;
    font-weight: 400;
}

.board-table th,
.board-table td {
    height: 21px;
    padding: 0 var(--space-2);
    line-height: 1.6;
    white-space: nowrap;
    font-weight: 400;
}

.board-table thead th {
    color: var(--ink-faint);
    border-bottom: 1px solid var(--line);
    text-align: right;
    position: sticky;
    top: 0;
    background: var(--surface);
}

.board-table thead th.board-cell-name {
    text-align: left;
}

.board-cell-name {
    text-align: left;
    color: var(--ink);
}

.board-cell-num {
    text-align: right;
    color: var(--ink-dim);
    font-variant-numeric: tabular-nums;
}

.board-cell-spark {
    text-align: right;
    color: var(--ink-faint);
}

/* Text adaptation of the chart-standards canonical z gradient: positive
   green family / negative red family, faded below |z|=1 (canonical <1
   alpha band), bright at >=1; the >=2 row accent is the third step. */
.board-z-pos {
    color: var(--positive);
}

.board-z-neg {
    color: var(--negative);
}

.board-z-pos.board-z-faded {
    color: var(--positive); opacity: 0.5; /* canonical <1 band */
}

.board-z-neg.board-z-faded {
    color: var(--negative); opacity: 0.5; /* canonical <1 band */
}

.board-z-muted {
    color: var(--ink-faint);
}

/* macro-residue #315 sub-slice R2 (FR-R2.1(c)/DECIDE-R2 item 1): a
   regime-conditional disclosure (rev21_reason=5, exactly one vol-bucket
   passed) is NOT a fully-eligible forecast - the Rev21 cell must stay
   visually distinguishable without requiring hover. No new color family:
   reuses the existing muted qualifier var plus a dotted underline (the
   title attribute still carries the full explanation on hover). */
.board-rev21-regime {
    color: var(--ink-faint);
    border-bottom: 1px dotted var(--ink-faint);
}

.board-row-accent {
    border-left: 2px solid var(--caution);
    background: color-mix(in oklab, var(--caution) 10%, transparent);
}

.board-spark {
    color: var(--ink-faint);
    vertical-align: middle;
}

.board-footer {
    display: flex;
    justify-content: flex-end;
    padding: var(--space-2);
    border-top: 1px solid var(--raised);
}

.board-copy-btn.board-copy-flash {
    color: var(--positive);
    border-color: var(--positive);
}

/* Ticker (board-kit.js Layer D): a duplicated-run marquee. The keyframe
   scrolls exactly -50% of the TRACK width; since the track holds two
   identical runs back to back, -50% lands precisely at the start of the
   second (identical) run, so the loop seam is invisible. wireTicker sets
   the per-instance `animation-duration` inline (pixels-per-second math);
   only the shape lives here. */
.board-ticker {
    overflow: hidden;
    white-space: nowrap;
    /* Attention scale (BoardKit.wireScale): --board-scale defaults to 1 (the
       unscaled render - unwired consumers are pixel-identical); a wired
       widget dragged larger than its natural size raises the var and the
       whole 21px/12px board metric set follows. */
    height: calc(21px * var(--board-scale, 1));
    line-height: 1.6;
    font-family: var(--font-mono);
    /* Same type size as .board-table/.board-strip: without this the tape
       inherits the page 16px (seen live on the tile strips) - the one
       board-family surface that drifted from the 12px mono discipline. */
    font-size: calc(var(--font-size-xs) * var(--board-scale, 1));
    /* Accent seam slot, matching .board-strip: transparent until a consumer
       (tile strips) paints border-left-color inline; costs macro-board an
       imperceptible 2px inset. */
    border-left: 2px solid transparent;
    width: 100%;
    position: relative;
}

.board-ticker-track {
    display: inline-flex;
    width: max-content;
    animation: board-ticker-scroll linear infinite;
}

@keyframes board-ticker-scroll {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}

.board-ticker-run {
    display: inline-flex;
}

/* The item's trailing padding IS the inter-item gap - the run carries no
   extra margin of its own, so consecutive items (including the seam between
   the last item of one run and the first item of its duplicate) space
   identically. */
.board-ticker-item {
    display: inline-block;
    white-space: nowrap;
    padding-right: var(--space-4);
}

.board-ticker:hover .board-ticker-track,
.board-ticker.board-ticker-off .board-ticker-track {
    animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
    .board-ticker-track {
        animation: none;
    }
}

/* Inline column labels inside every tape item (the full set: last/D1w/z/
   pct/HL/rev21) - muted so the values stay dominant. They ride WITH the
   data (a static legend above the tape scrolls out of step, leaving
   mid-stream numbers unlabeled). The trailing spark carries no label - it
   is the end-of-dataset delimiter between items, not a column. */
.board-ticker-lbl {
    color: var(--ink-faint);
}

/* Strip (board-kit.js Layer E): a single 21px board-family line, the
   static (non-scrolling) counterpart to .board-ticker for the same item
   markup. border-left is the glanceable signal edge (consumer sets its
   own accent.border color inline); transparent by default so an unset
   strip has no visible seam. */
.board-strip {
    display: block;
    height: calc(21px * var(--board-scale, 1));
    line-height: 1.6;
    padding: 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: calc(var(--font-size-xs) * var(--board-scale, 1));
    white-space: nowrap;
    overflow: hidden;
    border-left: 2px solid transparent;
}

.board-strip-sym {
    color: var(--ink);
}

/* Tile (tile-widget.js tile mode): the SAME column set as the tape, one
   21px row per column - a compact vertical card. Label left (muted, the
   .board-ticker-lbl idiom), value right. border-left is the same accent
   seam slot as .board-strip/.board-ticker (consumer paints inline). */
.board-tile {
    font-family: var(--font-mono);
    font-size: calc(var(--font-size-xs) * var(--board-scale, 1));
    padding: 0 var(--space-2);
    border-left: 2px solid transparent;
}

.board-tile-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-2);
    height: calc(21px * var(--board-scale, 1));
    line-height: 1.6;
    white-space: nowrap;
}

.board-tile-val {
    text-align: right;
}

/* Attention scale on the spark: the svg's own width/height attrs are the
   base 60x16; inside a scaled shape the CSS size follows --board-scale and
   the viewBox (sparkSvg emits one) scales the polyline instead of clipping.
   Scoped to the three scalable shapes so the macro-board table spark keeps
   its attribute size. */
.board-strip .board-spark,
.board-tile .board-spark,
.board-ticker .board-spark {
    width: calc(60px * var(--board-scale, 1));
    height: calc(16px * var(--board-scale, 1));
}

/* Macro Board widget (spec/pages/macro-board.md) - macro-specific
   chrome ONLY. The generic dense-table surface (wrapper, table, cells, z
   gradient, row accent, spark, footer, copy button) is
   `components/board.css` / `framework/shell/board-kit.js` (`.board-*`); this
   file owns just the MANIFEST section subheader (staleness-tinted) and the
   absent-row name dimming. */

.macro-subheader td {
    padding-top: var(--space-2);
    color: var(--ink-faint);
    border-bottom: 1px solid var(--raised);
    background: var(--raised);
}

.macro-subheader-label {
    color: var(--ink);
}

.macro-subheader-stat {
    color: var(--ink-faint);
}

.macro-subheader-asof {
    color: var(--ink-faint);
}

.macro-subheader-asof.stale {
    color: var(--negative);
}

.macro-row-absent .board-cell-name {
    color: var(--ink-faint);
}

/* Narrowness (2026-08-02): subheader + Read rows are single colspan cells;
   nowrap (board.css default) would make the longest prose line set the whole
   table's min-content width (~800px live), killing narrow resize. Wrapping
   makes these rows contribute ~nothing to min-content, so the DATA columns
   own the floor; data rows never wrap. line-height stays 1.6 per line;
   the td height acts as a min-height, so wrapped rows grow cleanly. */
.macro-subheader td,
.macro-row-read td {
    white-space: normal;
}

/* Vol Board widget (spec/pages/vol-board.md) - vol-board-specific
   chrome ONLY. The shared `.board-footer` (components/board.css) is a
   right-aligned flex row built for one child (the copy button); vol-board
   puts two block children (disclosure + degrade reasons) into it, so they
   wrap them in one `.vol-board-footer` container - this file stacks that
   container's children full-width and left-aligned instead of the inherited
   flex-row layout. */

.vol-board-footer {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    gap: var(--space-1);
}

.vol-board-disclosure,
.vol-board-degrade-reasons {
    white-space: normal;
    text-align: left;
}

.vol-board-degrade-reasons {
    color: var(--ink-faint);
}

/* Monetary Plumbing widget (spec/pages/plumbing-app.md) -
   plumbing-app-specific chrome ONLY. The generic dense-table surface
   (wrapper, table, cells, z gradient, row accent, spark, copy button) is
   `components/board.css` / `framework/shell/board-kit.js` (`.board-*`);
   this file owns the verdict banner, the card grid, and the stub-view
   placeholder. */

.plumbing-banner {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--raised);
    background: var(--raised);
}

.plumbing-banner-headline {
    color: var(--ink);
    font-weight: 600;
    font-size: var(--font-size-lg);
}

.plumbing-banner-read {
    color: var(--ink-dim);
    margin-top: var(--space-1);
}

.plumbing-banner-claim {
    color: var(--ink-faint);
    margin-top: var(--space-1);
}

.plumbing-banner-lang {
    margin-top: var(--space-2);
}

.plumbing-lang-chip {
    display: inline-block;
    color: var(--ink-faint);
    background: var(--raised);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-2);
    margin-right: var(--space-1);
    font-size: var(--font-size-xs);
}

.plumbing-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
}

.plumbing-card {
    border: 1px solid var(--raised);
    border-radius: var(--radius-md);
    background: var(--raised);
    padding: var(--space-3);
    cursor: pointer;
}

.plumbing-card:hover {
    border-color: var(--line);
}

.plumbing-card-title {
    color: var(--ink);
    font-weight: 600;
    margin-bottom: var(--space-1);
}

.plumbing-factor-absent {
    color: var(--ink-faint);
}

.plumbing-state-line {
    color: var(--ink-dim);
    font-size: var(--font-size-sm);
}

.plumbing-basis-z {
    display: inline-block;
    font-family: var(--font-mono);
    margin-top: var(--space-1);
}

.plumbing-members {
    margin-top: var(--space-2);
}

.plumbing-member {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
}

.plumbing-member-name {
    color: var(--ink-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.plumbing-spark {
    margin-top: var(--space-2);
    color: var(--ink-faint);
}

.plumbing-freshness-dot {
    display: inline-block;
    margin-top: var(--space-2);
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-1);
}

.plumbing-key-rows {
    padding: 0 var(--space-4) var(--space-3);
}

.plumbing-row-group td {
    padding-top: var(--space-2);
    color: var(--ink-faint);
    background: var(--raised);
    border-bottom: 1px solid var(--raised);
}

.plumbing-view-stub {
    padding: var(--space-6) var(--space-4);
    color: var(--ink-faint);
    text-align: center;
}

/* Drill-down (plumbing-app Slice B, #323, FR-C11): Bridge + Corridor panels,
   chart containers, focus highlight, and the absent-bridge literal. The
   spread strip reuses .plumbing-key-rows/.plumbing-row styling above - it
   only needs its own wrapper class for test/DOM addressing. */

.plumbing-drilldown {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.plumbing-panel {
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--raised);
}

.plumbing-panel-heading {
    color: var(--ink);
    font-weight: 600;
    margin-bottom: var(--space-2);
}

/* Documented deviation from the standard clamp(320px, 40vh, 450px) - three
   stacked charts plus a table in one content-sized widget would otherwise
   force a ~1400px window (the analysis secondary-chart deviation precedent,
   spec/plumbing-app/SPEC-B.md FR-C11). */
.plumbing-waterfall,
.plumbing-levels-chart,
.plumbing-corridor-chart {
    height: clamp(220px, 28vh, 340px);
    margin-bottom: var(--space-3);
}

.plumbing-chart-subtitle,
.plumbing-explainer {
    color: var(--ink-faint);
    font-size: var(--font-size-sm);
    margin-bottom: var(--space-2);
}

.plumbing-bridge-absent,
.plumbing-bridge-window-absent {
    color: var(--ink-faint);
    padding: var(--space-3) 0;
}

.plumbing-anchor-active {
    outline: 2px solid var(--primary);
    outline-offset: -2px;
    border-radius: var(--radius-sm);
}

.plumbing-spread-strip {
    margin-top: var(--space-2);
}

/* Research (plumbing-app Slice C, #324, FR-F10): the path chart + effects
   table, the three fixed absent-state literals, and the disabled event-type
   chip state. Chart height reuses the Slice-B clamp(220px, 28vh, 340px)
   deviation (one chart, still content-sized). */

.plumbing-research {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.plumbing-path-chart {
    height: clamp(220px, 28vh, 340px);
    margin-bottom: var(--space-3);
}

.plumbing-effects-table {
    margin-top: var(--space-2);
}

.plumbing-events-absent,
.plumbing-event-thin,
.plumbing-series-absent {
    color: var(--ink-faint);
    padding: var(--space-3) 0;
}

/* A disabled event-type chip (a below-the-n-floor inventory row, still
   present per FR-F3 - never hidden) is an OptChipBar per-chip `disabled`
   button; its dimmed/non-interactive styling comes from the EXISTING
   `.opt-chip-disabled` rule (trader-dashboard.css) - no second class here. */

/* Daily Dispatch widget (spec/pages/daily-dispatch.md) -
   daily-dispatch-specific chrome ONLY (P2-4 newsy terminal redesign). A
   small, content-sized widget: a masthead, then one newsy segment block per
   pinned segment (an optional bold headline over readable body paragraphs),
   or a muted absence line when a segment was not published today. Ticker
   mode needs NO new CSS here - BoardKit's `.board-ticker-*` classes own it
   entirely; this file styles board mode only. Reflow is CSS-owned: no JS
   text manipulation, widths from `--w-prose`, type from the shared type tokens. */

.dispatch-widget {
    padding: var(--space-4);
}

/* ---- masthead: mono, uppercase tracking, strong weight, bottom border - */

.dispatch-masthead {
    max-width: var(--w-prose);
    font-family: var(--font-mono);
    font-size: var(--font-size-lg);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink);
    padding-bottom: var(--space-3);
    margin-bottom: var(--space-4);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.dispatch-dateline {
    font-family: var(--font-mono);
    font-weight: 400;
    letter-spacing: 0;
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
}

/* ---- segment blocks: hairline rule + spacing separates them ------------ */

.dispatch-segment {
    padding-top: var(--space-4);
    margin-bottom: var(--space-5);
    border-top: 1px solid var(--raised);
}

.dispatch-segment:first-of-type {
    padding-top: 0;
    border-top: none;
}

.dispatch-segment:last-child {
    margin-bottom: 0;
}

/* ---- kicker: small muted uppercase label ABOVE the headline ------------ */

.dispatch-heading {
    max-width: var(--w-prose);
    font-family: var(--font-mono);
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin: 0 0 var(--space-2) 0;
}

/* ---- headline: the visual lead - xl size token, bold, tight ----------- */

.dispatch-headline {
    max-width: var(--w-prose);
    color: var(--ink);
    font-weight: 600;
    font-size: var(--font-size-xl);
    line-height: 1.2;
    margin: 0 0 var(--space-3) 0;
}

/* ---- body: measure max-width --w-prose, readable line-height --------------- */

.dispatch-body {
    color: var(--ink-dim);
    font-size: var(--font-size-sm);
}

.dispatch-body p {
    max-width: var(--w-prose);
    line-height: 1.6;
    margin: 0 0 var(--space-3) 0;
}

.dispatch-body p:first-child {
    margin-top: 0;
}

.dispatch-body p:last-child {
    margin-bottom: 0;
}

/* ---- entity chip (P3-3): subtle inline affordance, keyboard-focusable -- */

/* ---- opportunities section (DESIGN-4 R8): whole-row clickable strips ---- */

.dispatch-opportunities {
    margin-top: var(--space-3);
    border-top: 1px dashed var(--line);
    padding-top: var(--space-3);
}

.dispatch-opp-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-3);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--ink-dim);
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: 3px;
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-2);
    cursor: pointer;
}

.dispatch-opp-row:last-child {
    margin-bottom: 0;
}

.dispatch-opp-row:hover {
    background: var(--line);
    border-color: var(--primary);
}

.dispatch-opp-symbol {
    color: var(--ink);
    font-weight: 600;
}

.dispatch-opp-structure {
    color: var(--ink-faint);
    text-transform: uppercase;
}

/* ---- absence: muted italic (kept treatment) ----------------------------- */

.dispatch-absent {
    color: var(--ink-faint);
    font-size: var(--font-size-sm);
    font-style: italic;
    margin: 0;
}

/* Trade Cards widget (spec/pages/trade-cards.md) - narrow
   monospace card grammar per spec/options-flow/CARDS.md. Reuses existing
   mono/board vars only - no new hex. */

.trade-cards-widget {
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    padding: var(--space-2) var(--space-3);
    color: var(--ink);
}

.tc-strip-header {
    margin: 0 0 var(--space-2) 0;
    color: var(--ink-dim);
    white-space: pre-wrap;
}

.tc-blocks {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.tc-block {
    border: 1px solid var(--raised);
    border-radius: var(--radius-sm);
    background: var(--raised);
}

.tc-strip-row {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
    padding: 0;
}

.tc-strip-row:hover {
    background: var(--raised);
}

.tc-strip-row pre,
.tc-detail {
    margin: 0;
    padding: var(--space-2);
    white-space: pre-wrap;
    line-height: 1.4;
}

.tc-detail {
    border-top: 1px solid var(--raised);
    color: var(--ink-dim);
}

.tc-detail[hidden] {
    display: none;
}

.tc-none {
    color: var(--ink-faint);
    padding: var(--space-2) 0;
}

/* Options Dispatch + Card Detail widgets (spec/pages/options-dispatch.md)
   per spec/options-flow/CARDS.md "Presentation - Options Dispatch". Reuses
   the existing plumbing-card idiom's spacing/color vars - no new hex. */

.od-widget {
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    padding: var(--space-2) var(--space-3);
    color: var(--ink);
}

.od-headline {
    font-weight: 600;
    color: var(--ink);
    margin-bottom: var(--space-2);
}

.od-body p {
    margin: 0 0 var(--space-2) 0;
    line-height: 1.6;
    color: var(--ink-dim);
}

.od-absent,
.od-none {
    color: var(--ink-faint);
    padding: var(--space-2) 0;
}

.od-cards {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

/* Curated cards - the plumbing-card visual idiom */
.od-card {
    display: block;
    width: 100%;
    border: 1px solid var(--raised);
    border-radius: var(--radius-md);
    background: var(--raised);
    padding: var(--space-3);
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.od-card:hover {
    border-color: var(--line);
}

.od-card-header {
    color: var(--ink);
    font-weight: 600;
    margin-bottom: var(--space-1);
}

.od-card-emoji {
    margin-left: var(--space-1);
}

.od-card-state {
    color: var(--ink-dim);
    font-size: var(--font-size-sm);
}

.od-card-chips {
    color: var(--ink-faint);
    font-size: var(--font-size-sm);
    margin-top: var(--space-1);
}

/* S10 (spec/vol-board/S10-DISPATCH-GATES.md): the pinned Curated header,
   styled like the existing honest-absence literals - a fixed line, not a
   value. */
.od-curated-header {
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
    margin: 0 0 var(--space-2) 0;
}

/* S10: inline earnings-gate chip on an All-screened row: a reference chip
   (text --ink, border --line; spec/design-system/components.md:63). */
.od-card-footer {
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
    margin-top: var(--space-1);
}

/* All-screened compact rows, grouped by symbol */
.od-group {
    margin-bottom: var(--space-2);
}

.od-group-heading {
    color: var(--ink);
    font-weight: 600;
    margin-bottom: var(--space-1);
}

/* All-screened rows are now BoardKit dense-table <tr> elements
   (board.css owns .board-table/.board-cell-*); .od-row/.od-group carry only
   the whole-row activation affordance + group layout on top. */
.od-row {
    cursor: pointer;
}

.od-row:hover td {
    color: var(--ink);
}

/* A collapsed group's tail rows (past GROUP_PREVIEW_ROWS) - hidden until the
   "+N more" expander is clicked (options-dispatch-widget.js wireCards). */
.od-row-hidden {
    display: none;
}

/* The expander itself - a quiet inline text button, not a bordered card
   action; existing theme vars only, no new hex. */
.od-more {
    display: block;
    background: none;
    border: none;
    color: var(--ink-faint);
    font: inherit;
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    cursor: pointer;
    padding: var(--space-1) 0;
}

.od-more:hover {
    color: var(--ink);
}

/* Card Detail pop-out (DESIGN-5 R7). overflow:auto + max-height:100% so a
   manually shrunk card-detail window scrolls its content instead of
   clipping it silently. */
.card-detail-widget {
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    padding: var(--space-2) var(--space-3);
    color: var(--ink);
    overflow: auto;
    max-height: 100%;
}

.cd-card {
    border: 1px solid var(--raised);
    border-radius: var(--radius-md);
    background: var(--raised);
    padding: var(--space-3);
}

.cd-body {
    margin: 0;
    /* A <pre>'s UA default `font-family: monospace` beats inheritance and
       skips the 'TP Emoji' fallback - the status/🎯/mark glyphs tofu'd
       without this (live finding, 2026-08-17). */
    font-family: var(--font-mono);
    white-space: pre-wrap;
    line-height: 1.4;
    color: var(--ink-dim);
}

.cd-absent {
    color: var(--ink-faint);
    padding: var(--space-2) 0;
}

/* WM (WindowManager) desktop - the owned free-float shell replacing GridStack
   (free-float shell cutover, docs/ops/free-float-2026-07/PROGRAM.md S3).
   .wm-desktop is the container the WindowManager stamps on init; .wm-window
   is one absolutely-positioned window (WMGeometry owns all layout math, this
   file is presentation only). */

.wm-desktop {
    position: relative;
    flex: 1;
}

.wm-window {
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    /* `clip`, not `hidden` (#318 root-cause finding): a window is never
       meant to be USER-scrollable - it's a fixed-size visual clip only
       (WMGeometry owns all layout math). `overflow: hidden` still makes an
       element a real scroll container (scrollTop/scrollLeft stay live even
       with no visible scrollbar), and a short window's absolutely-
       positioned resize furniture (the 30px drag band, the corner handles'
       -5px negative edge offsets) gives it genuine scrollable overflow on
       every axis. Live-reproduced: the credible trigger is an unqualified
       `.focus()` call with no `{preventScroll: true}` (ChipBar
       chip-bar.js:377,400,538 - the search input focused after a chip
       select/add, and `focusSearch()`) - NOT hover, which merely reveals
       the in-frame chrome and does not itself move focus. A browser's
       default "scroll the focused element into view" behavior auto-scrolled
       the window to `scrollTop/scrollLeft: 5`, matching the bottom/right
       corner handles' -5px inline offsets (window-manager.js
       HANDLE_CORNER/2) - the nearest scrollable overflow at that distance -
       shifting the ENTIRE rendered widget (and therefore every resize
       handle) 5px off from where the window's own box says it should be -
       silently breaking the handle-priority fringe FR-1 depends on and any
       other geometry math keyed off the window's own rect. `overflow: clip`
       clips identically but is never a scroll container -
       `scrollTop`/`scrollLeft` cannot become non-zero, so this class of
       drift is impossible by construction, not just unlikely. */
    overflow: clip;
    display: flex;
    flex-direction: column;
    box-shadow: var(--shadow-sm);
    animation: widgetIn 250ms ease-out;
}

@keyframes widgetIn {
    from { opacity: 0; transform: translateY(12px); }
}

.wm-window > .widget {
    flex: 1;
    min-height: 0;
}

/* Content-fit widgets (.widget--fit) keep their NATURAL height inside the
   window so the WM can measure it (fitItem measures the in-flow widget
   child) - flex:1 above would compress/stretch them to the window box and
   the measured height could never differ from the current one.
   FR-2 containment (#318): `max-height: 100%` + `overflow: hidden` let the
   SAME box also respect a user-shrunk window - height stays `auto` (still
   the natural/unclamped size whenever the window is >= content, so this is
   a no-op at rest) but clamps down when the window is smaller, and the
   widget's own flex-fill chain (widget-body/widget-shell/widget-shell-
   chart, trader-dashboard.css) redistributes into that clamped box so a
   deep scroll container (e.g. `.board`, board.css) becomes the actual
   scroll boundary instead of silently clipping. `fitItem` (window-
   manager.js) needs the TRUE natural size to grow back after a shrink, so
   it toggles `wm-window--measuring` (below) around its measurement read -
   the clamp is otherwise always live. */
.wm-window > .widget--fit {
    flex: none;
    height: auto;
    max-height: 100%;
    overflow: hidden;
}

/* Measurement escape hatch (#318): fitItem briefly lifts the FR-2 clamp so
   it reads the widget's TRUE natural height (not whatever the clamp left
   it at from a prior shrink) before recomputing the window's fit height.
   Specificity note (verify hole 5): `.wm-window > .widget--fit`
   above is (0,2,0); a plain `.wm-window.wm-window--measuring >
   .widget--fit` selector, which would then only win by appearing later in
   the file (a source-order dependency an unrelated reorder could silently
   break). Repeating `.widget--fit` (`.widget--fit.widget--fit`) is a
   no-op selector-wise but bumps this rule to (0,4,0), so it wins on
   specificity alone regardless of file order. */
.wm-window.wm-window--measuring > .widget--fit.widget--fit {
    max-height: none;
    overflow: visible;
}

/* Drag-through: the WM's transparent 30px .wm-drag-band is appended AFTER
   the widget content so it paints above the header - the header must let
   drags through while keeping its own controls clickable. pointer-events
   alone is not enough: the band is a SIBLING stacked over the whole header,
   so the controls must also stack ABOVE the band (z-index) or real pointer
   hit-testing lands on the band and close/expand/actions are dead (S3 live
   finding - synthetic .click() in the e2e gates bypasses hit-testing and
   could not catch this). */
.wm-window > .wm-drag-band {
    z-index: calc(var(--z-raised) + 1);
    cursor: move;
    touch-action: none;
}

/* Resize wins at the window fringe over the z:1 drag band (the 5px edges /
   10px corners are the resize zone - desktop-WM convention). Without this
   the band eats the whole window on a <=30px strip (its corners'
   outside halves are clipped by overflow:hidden), so a minimum-size
   window could never be drag-resized again (live finding, follows the
   same real-hit-testing moral as the S3 note above). Interactive control
   carve-outs stack ABOVE the handles at z:4 (below): the fringe belongs
   to resize except directly over a control. */
.wm-window > .wm-handle {
    z-index: calc(var(--z-raised) + 3);
    touch-action: none;
}

.wm-handle[data-edge="n"],
.wm-handle[data-edge="s"] { cursor: ns-resize; }
.wm-handle[data-edge="e"],
.wm-handle[data-edge="w"] { cursor: ew-resize; }
.wm-handle[data-edge="ne"],
.wm-handle[data-edge="sw"] { cursor: nesw-resize; }
.wm-handle[data-edge="nw"],
.wm-handle[data-edge="se"] { cursor: nwse-resize; }

/* Active drag (class set from pointerdown to pointerup): grabbing wins over
   the per-edge cursors by specificity. */
.wm-window.wm-dragging > .wm-drag-band,
.wm-window.wm-dragging > .wm-handle {
    cursor: grabbing;
}

.wm-window .widget-header {
    pointer-events: none;
}

.wm-window .widget-header .widget-controls,
.wm-window .widget-header button,
.wm-window .widget-header select,
.wm-window .widget-header a,
.wm-window .widget-header input {
    pointer-events: auto;
    position: relative;
    /* Stack above BOTH the z:1 drag band and the z:3 resize handles - the
       fringe belongs to resize EXCEPT directly over a control (controls are
       small islands; an >=80px-wide window always has free edge to grab). */
    z-index: calc(var(--z-raised) + 4);
}

/* The ChipBar search menu rides with its input: same carve-out. It is
   position:fixed (set by Menu), so the one-row window's overflow:hidden
   does not clip it, and --z-menu stacks it above the z:1 drag band and the
   z:3 resize handles. */
.wm-window .widget-header .chip-search-panel .menu {
    pointer-events: auto;
}

/* Header band:
   ChipBar symbol chips (framework/chip-bar.js) are `<span role="button">`,
   not real `<button>` elements, so they need the same carve-out as the
   button/select/a list above or they are inert behind the header's
   pointer-events:none inside the band. */
.wm-window .widget-header .ticker-chip {
    pointer-events: auto;
    position: relative;
    /* Stack above BOTH the z:1 drag band and the z:3 resize handles - the
       fringe belongs to resize EXCEPT directly over a control. */
    z-index: calc(var(--z-raised) + 4);
}

/* Keyboard focus ring (S6, D7): Tab/Shift+Tab cycle the z stack via
   .wm-focused - exactly one window carries it at a time. A subtle border
   shift keeps the gruvbox chrome quiet rather than adding a glow/outline. */
.wm-window.wm-focused {
    border-color: var(--primary);
}

/* Stacked view (DS-LAY-29): below 1024 the windows share one column in saved
   array order. The window manager clears the inline geometry and sets each
   window's saved height; the drag band and handles stay inert. */
@media not all and (min-width: 64em) {
    .wm-desktop {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
    }

    .wm-window {
        flex: none;
    }

    .wm-window > .wm-drag-band,
    .wm-window > .wm-handle {
        cursor: default;
    }
}

/* Workspace bar: one 48px band under the nav on every workspace page. */

/* Scoped to workspace pages; beats the inline critical `.nav{min-height}` by specificity. */
body:has(.trader-dashboard) .nav {
  box-sizing: border-box;
  height: 3rem;
  min-height: 3rem;
  padding-block: 0;
}

main:has(> .trader-dashboard) {
  padding: 0;
}

.workspace-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  box-sizing: border-box;
  min-height: 3rem;
  margin: 0 calc(-1 * var(--ws-pad));
  padding: var(--space-1) var(--ws-pad);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.workspace-bar .page-title {
  margin: 0 var(--space-2) 0 0;
  font-size: var(--font-size-xl);
  color: var(--ink);
  white-space: nowrap;
}

.workspace-bar .tab-list {
  align-items: center;
  min-height: 2rem;
  min-width: 0;
}

.workspace-bar .tab-item {
  box-sizing: border-box;
  height: 2rem;
  padding-block: 0;
}

.workspace-bar .tab-item.tab-dragging {
  opacity: 0.6;
}

.workspace-bar .tab-item.tab-drop {
  box-shadow: inset 2px 0 0 var(--primary);
}

.workspace-bar .tab-add {
  box-sizing: border-box;
  height: 2rem;
  padding: 0 var(--space-3);
}

.workspace-symbol,
.workspace-layout {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
}

.workspace-symbol {
  margin-left: auto;
}

.workspace-symbol .widget-ticker-bar {
  flex-wrap: nowrap;
  padding: 0;
}

.workspace-bar .ticker-chip,
.workspace-bar .chip-search-input,
.workspace-bar .form-select {
  box-sizing: border-box;
  height: 2rem;
  font-family: var(--font-mono);
}

.workspace-bar .ticker-chip {
  padding-block: 0;
}

.workspace-bar .ticker-chip.active {
  background-color: transparent;
  border: 1px solid var(--primary);
  color: var(--primary);
}

.workspace-bar .form-select {
  width: auto;
  padding-block: 0;
}

.workspace-bar .layout-menu-mark {
  margin-left: var(--space-2);
  color: var(--caution);
}

.layout-name-field {
  position: fixed;
  z-index: var(--z-menu);
  padding: var(--space-2);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-raised);
}

.form-banner {
  margin-bottom: var(--space-2);
  padding: var(--space-2);
  color: var(--negative);
  border: 1px solid var(--negative);
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
}

.workspace-bar #add-widget-btn {
  flex-shrink: 0;
  white-space: nowrap;
}

/* Below 1024 the bar is read-only: the h1, the page menu and the symbol field.
   The page menu stands in for the tabs; Add widget, Layout and the picker go. */
.workspace-bar #page-menu-btn {
  flex-shrink: 0;
  max-width: var(--w-narrow);
  white-space: nowrap;
}

.workspace-bar #page-menu-btn .page-menu-label {
  display: inline-block;
  max-width: 100%;
  vertical-align: bottom;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (min-width: 64em) {
  .workspace-bar {
    flex-wrap: nowrap;
    height: 3rem;
    padding-block: 0;
  }

  .workspace-bar #page-menu-btn {
    display: none;
  }
}

@media not all and (min-width: 64em) {
  .workspace-bar .tab-list,
  .workspace-bar .tab-add,
  .workspace-bar .workspace-layout,
  .workspace-bar #add-widget-btn,
  #widget-sidebar {
    display: none;
  }
}

.toast-stack {
  position: fixed;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  z-index: var(--z-toast);
  pointer-events: none;
}

.toast-stack--bottom-right {
  right: var(--space-4);
  bottom: var(--space-4);
  align-items: flex-end;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  max-width: var(--w-narrow);
  padding: var(--space-2) var(--space-4);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--ink-faint);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  pointer-events: auto;
}

.toast--failure {
  border-color: var(--negative);
}

.toast__action,
.toast__retry,
.toast__dismiss {
  font: inherit;
  color: var(--primary);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
}

.toast__dismiss {
  color: var(--ink-dim);
}

.confirm-dialog {
  max-width: var(--w-narrow);
  padding: var(--space-4);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--ink-faint);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
}

.confirm-dialog::backdrop {
  background: var(--canvas);
  opacity: 0.7;
}

.confirm-dialog__title {
  margin: 0 0 var(--space-3);
  font-size: var(--font-size-sm);
}

.confirm-dialog__body {
  margin: 0 0 var(--space-3);
}

.confirm-dialog__message {
  margin: var(--space-1) 0 0;
  color: var(--negative);
}

.confirm-dialog__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}

.keyboard-sheet {
  max-width: var(--w-narrow);
  max-height: 90vh;
  overflow-y: auto;
  padding: var(--space-4);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--ink-faint);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
}

.keyboard-sheet::backdrop {
  background: var(--canvas);
  opacity: 0.7;
}

.keyboard-sheet__title {
  margin: 0 0 var(--space-3);
  font-size: var(--font-size-sm);
}

.keyboard-sheet__list {
  margin: 0 0 var(--space-3);
}

.keyboard-sheet__row {
  display: grid;
  grid-template-columns: 12rem 1fr;
  gap: var(--space-3);
  padding: var(--space-1) 0;
}

.keyboard-sheet__keys {
  color: var(--ink);
  font-weight: 600;
}

.keyboard-sheet__action {
  margin: 0;
  color: var(--ink-dim);
}

/* Menu: select, combobox, action and context menus (spec/design-system/components.md, Menu). */

.menu {
    --menu-hi: color-mix(in oklab, var(--ink) 10%, transparent);
    box-sizing: border-box;
    min-width: 120px;
    padding: var(--space-1) 0;
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-raised);
    z-index: var(--z-menu);
    overflow-y: auto;
    font-family: var(--font-mono);
}

.menu-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    box-sizing: border-box;
    height: 32px;
    padding: 0 var(--space-3);
    font-size: var(--font-size-sm);
    color: var(--ink-dim);
    background: transparent;
    white-space: nowrap;
    cursor: pointer;
}

.menu-widget .menu-item {
    height: 24px;
    font-size: var(--font-size-xs);
}

.menu-item[data-highlight] {
    background: var(--menu-hi);
    color: var(--ink);
}

.menu-item[data-current] {
    color: var(--ink);
    box-shadow: inset 2px 0 0 var(--primary);
}

.menu-item[aria-disabled="true"] {
    color: var(--ink-faint);
    cursor: default;
}

.menu-item.menu-danger {
    color: var(--negative);
}

.menu-match {
    font-weight: 600;
    color: var(--ink);
}

.menu-hint {
    margin-left: auto;
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
}

.menu-group {
    box-sizing: border-box;
    height: 24px;
    padding: 0 var(--space-3);
    display: flex;
    align-items: center;
    font-size: var(--font-size-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-faint);
}

.menu-group-sub {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
}

.menu-divider {
    height: 1px;
    margin: var(--space-1) 0;
    background: var(--line);
}

.menu-swatches {
    display: flex;
    gap: var(--space-1);
}

.menu-swatch {
    width: 16px;
    height: 16px;
    border: 1px solid var(--line);
    border-radius: 2px;
}

.menu-theme .menu-item {
    justify-content: flex-start;
    height: 44px;
}

.menu-item[data-face] {
    height: 44px;
    font-size: var(--font-size-sm);
}

.menu-item[data-face] .menu-hint {
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
}

.menu-control {
    padding: var(--space-2) var(--space-3);
}

.menu-theme .menu-label {
    flex: 1;
}

.segmented {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  flex-wrap: wrap;
  max-width: 100%;
}

.segmented .segmented__option {
  height: 1.5rem;
  padding: 0 8px;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: transparent;
  border-radius: 0;
  cursor: pointer;
  white-space: nowrap;
}

.segmented .segmented__option:first-child {
  border-top-left-radius: var(--radius-sm);
  border-bottom-left-radius: var(--radius-sm);
}

.segmented .segmented__option:last-child {
  border-top-right-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
}

.segmented .segmented__option + .segmented__option {
  margin-left: -1px;
}

.segmented .segmented__option {
  color: var(--ink-faint);
  border: 1px solid var(--line);
}

.segmented .segmented__option:hover {
  color: var(--ink);
}

.segmented .segmented__option.active {
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
}


/* One chip recipe, three roles (DS-COMP-12 to DS-COMP-16, DS-COL-15).
   Toggle: ticker chip, option chip, chart control button.
   Reference: dispatch chip, earnings chip.
   Status: quality badge, cache pill.
   The old class names stay as selectors beside `.chip`. */

.chip,
.ticker-chip,
.chart-control-btn,
.dispatch-chip,
.od-chip-earn,
.widget-quality-badge,
.cache-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  box-sizing: border-box;
  height: 1.5rem;
  padding: 0 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  vertical-align: middle;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-faint);
  user-select: none;
}

/* Toggle role */
.chip--toggle,
.ticker-chip,
.chart-control-btn {
  cursor: pointer;
  transition: border-color var(--dur-fast) ease, color var(--dur-fast) ease, background var(--dur-fast) ease;
}

.chip--toggle:hover:not(.active, [aria-pressed="true"]),
.ticker-chip:hover:not(.active),
.chart-control-btn:hover:not(.active) {
  border-color: var(--ink-faint);
  color: var(--ink);
}

.chip--toggle.active,
.chip--toggle[aria-pressed="true"],
.ticker-chip.active,
.chart-control-btn.active {
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
}

.chart-control-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Remove mark: shown at rest */
.chip-remove {
  background: none;
  border: none;
  padding: 0;
  color: inherit;
  font-family: inherit;
  cursor: pointer;
  font-size: 12px;
  line-height: 1.2;
  opacity: 0.7;
}

.ticker-chip:hover .chip-remove {
  opacity: 1;
}

/* Reference role: never selected */
.chip--ref,
.dispatch-chip,
.od-chip-earn {
  color: var(--ink);
}

.chip--ref,
.dispatch-chip {
  cursor: pointer;
}

.chip--ref:hover,
.dispatch-chip:hover {
  border-color: var(--primary);
}

/* Status role: transparent, text and border in one slot */
.chip--status,
.widget-quality-badge,
.cache-pill {
  --chip-slot: var(--ink-faint);
  background: transparent;
  color: var(--chip-slot);
  border-color: var(--chip-slot);
}

.chip--positive { --chip-slot: var(--positive); }

.chip--caution,
.widget-quality-badge--degraded,
.widget-quality-badge--caution,
.widget-quality-badge--stale { --chip-slot: var(--caution); }

.chip--negative,
.widget-quality-badge--blocked { --chip-slot: var(--negative); }

.chip--info { --chip-slot: var(--info); }

.chip--neutral,
.widget-quality-badge--skipped { --chip-slot: var(--ink-faint); }

.widget-quality-badge {
  margin-left: auto;
}

.widget-quality-badge--stale {
  cursor: help;
}

.cache-pill {
  cursor: pointer;
}

/* State component: the one block the widget shell writes for empty, loading
   and error (DS-COMP-41 to 43). Legacy classes widget-loading, widget-empty
   and widget-error stay on the same elements for the callers ds-35b moves. */

.state-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 100%;
  padding: var(--space-4);
  box-sizing: border-box;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--ink-dim);
}

.state-block--loading {
  flex-direction: row;
  gap: var(--space-2);
}

.state-block__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--primary);
}

.state-block__title {
  font-weight: 600;
}

.state-block--empty .state-block__title {
  color: var(--ink-dim);
}

.state-block--error .state-block__title {
  color: var(--negative);
}

.state-block__actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* Canvas slot: fills the empty workspace canvas; only its buttons take the
   pointer, so drops and canvas gestures reach the desktop beneath. */
.canvas-state {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.canvas-state .state-block__action {
  pointer-events: auto;
}

.state-block__hint {
  color: var(--ink-dim);
  font-size: var(--font-size-xs);
}

/* Auth Pages - login, register, forgot-password */

/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT - the 400px column; .page--focus centres it, no panel
   ═══════════════════════════════════════════════════════════════════════════ */

.login-box {
  width: 100%;
}

/* ═══════════════════════════════════════════════════════════════════════════
   TITLES
   ═══════════════════════════════════════════════════════════════════════════ */

.login-title {
  font-size: var(--font-size-2xl);
  margin-bottom: var(--space-6);
  text-align: center;
  color: var(--ink);
}

.login-subtitle {
  font-size: var(--font-size-sm);
  margin-bottom: var(--space-6);
  text-align: center;
  color: var(--ink-faint);
}

.login-title + .login-subtitle {
  margin-top: calc(var(--space-6) * -1 + var(--space-2));
}

/* ═══════════════════════════════════════════════════════════════════════════
   FORM FIELDS - the login column holds the form on the canvas, no panel.
   ═══════════════════════════════════════════════════════════════════════════ */

.login-box .form-group {
  margin-bottom: var(--space-4);
}

.login-box .form-input {
  width: 100%;
  font-size: var(--font-size-base);
}

.form-hint {
  font-size: var(--font-size-xs);
  color: var(--ink-faint);
  margin-top: var(--space-1);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SUBMIT BUTTONS
   ═══════════════════════════════════════════════════════════════════════════ */

/* Look comes from .btn; these set the full-width placement in the login card. */
.login-submit,
.login-passkey {
  width: 100%;
}

.login-submit {
  margin-top: var(--space-4);
}

.login-passkey {
  background: transparent;
  border-color: var(--line);
}

.login-passkey:hover {
  background: transparent;
  border-color: var(--ink-faint);
}

/* "or" between the passkey and the email fields; absent with the button. */
.login-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0;
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
}

.login-divider::before,
.login-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}

#passkey-signin[hidden] ~ .login-divider {
  display: none;
}

.recovery-codes {
  list-style: none;
  margin: 0 0 var(--space-4) 0;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--ink);
}

.recovery-codes li {
  padding: var(--space-1) 0;
  letter-spacing: 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   FOOTER LINKS
   ═══════════════════════════════════════════════════════════════════════════ */

.login-links {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-4);
  font-size: var(--font-size-sm);
}

.login-links a {
  color: var(--primary);
}

.login-links a:hover {
  text-decoration: underline;
}

.auth-footer {
  text-align: center;
  margin-top: var(--space-6);
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
}

.auth-footer a {
  color: var(--info);
  text-decoration: none;
}

.auth-footer a:hover {
  text-decoration: underline;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ERROR / SUCCESS BANNERS
   ═══════════════════════════════════════════════════════════════════════════ */

.form-error-message {
  color: var(--negative);
  font-size: var(--font-size-sm);
}

.form-error-banner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: color-mix(in oklab, var(--negative) 10%, transparent);
  border: 1px solid var(--negative);
  border-radius: var(--radius-sm);
  color: var(--negative);
  font-size: var(--font-size-sm);
  margin-bottom: var(--space-4);
}

.form-success {
  background: color-mix(in oklab, var(--primary) 10%, transparent);
  border: 1px solid var(--primary);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
  text-align: center;
}

.form-success-message {
  color: var(--primary);
  font-size: var(--font-size-sm);
}

/* ═══════════════════════════════════════════════════════════════════════════
   HTMX INDICATOR TOGGLES
   ═══════════════════════════════════════════════════════════════════════════ */

.htmx-indicator {
  display: none;
}

.htmx-request .htmx-indicator {
  display: inline;
}

.htmx-request .htmx-not-loading {
  display: none;
}

.htmx-request .login-submit {
  opacity: 0.7;
}

/* Pricing Page Styles */

/* ═══════════════════════════════════════════════════════════════════════════
   PRICING COMPARISON TABLE
   ═══════════════════════════════════════════════════════════════════════════ */

.pricing-plans {
  margin-bottom: var(--space-16);
}

.pricing-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--raised);
}

.pricing-label {
  width: 300px;
}

.pricing-col {
  padding: var(--space-3) var(--space-4);
  font-size: var(--font-size-sm);
  font-weight: 400;
  color: var(--ink);
  text-align: left;
  vertical-align: top;
  border-top: 1px solid var(--line);
}

thead .pricing-col,
thead .pricing-label {
  border-top: 0;
  padding-top: var(--space-6);
}

.pricing-col--featured {
  background: color-mix(in oklab, var(--primary) 10%, transparent);
}

thead .pricing-col--featured {
  box-shadow: inset 0 2px 0 var(--primary);
}

.pricing-plan,
.pricing-price,
.pricing-period {
  display: block;
}

.pricing-badge {
  display: inline-flex;
  margin-bottom: var(--space-2);
}

.pricing-plan {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--ink-faint);
  margin-bottom: var(--space-2);
}

.pricing-price {
  font-size: var(--font-size-3xl);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.1;
}

.pricing-period {
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
}

.pricing-cta .btn {
  width: 100%;
}

/* ═══════════════════════════════════════════════════════════════════════════
   FAQ
   ═══════════════════════════════════════════════════════════════════════════ */

.pricing-intro {
  max-width: var(--w-prose);
}

.faq-section {
  max-width: var(--w-prose);
  padding-bottom: var(--space-16);
}

.faq-title {
  color: var(--ink);
  margin-bottom: var(--space-8);
}

.faq-item {
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-3);
}

.faq-question {
  width: 100%;
  padding: var(--space-4);
  background: none;
  border: none;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.faq-question:hover {
  color: var(--primary);
}

.faq-question::before {
  content: "\25B8";
  transition: transform var(--dur-base) ease;
}

.faq-item.open .faq-question::before {
  transform: rotate(90deg);
}

.faq-answer {
  display: none;
  padding: 0 var(--space-4) var(--space-4);
  padding-left: calc(var(--space-4) + 1em);
  color: var(--ink-faint);
  font-size: var(--font-size-sm);
  line-height: 1.6;
}

.faq-item.open .faq-answer {
  display: block;
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE: below 640 one block per plan, same facts in table order
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 639px) {
  .pricing-table {
    display: grid;
    grid-template-columns: 1fr;
  }

  .pricing-table thead,
  .pricing-table tbody,
  .pricing-table tr {
    display: contents;
  }

  .pricing-label,
  .pricing-col:empty {
    display: none;
  }

  /* a gap before the second and third plan block */
  thead .pricing-col:nth-child(n+3) {
    margin-top: var(--space-4);
  }

  /* order = plan * 10 + row (head 0, features 1 to 4, buttons 5) */
  thead .pricing-col:nth-child(2) { order: 10; }
  thead .pricing-col:nth-child(3) { order: 20; }
  thead .pricing-col:nth-child(4) { order: 30; }
  tbody tr:nth-child(1) .pricing-col:nth-child(2) { order: 11; }
  tbody tr:nth-child(2) .pricing-col:nth-child(2) { order: 12; }
  tbody tr:nth-child(3) .pricing-col:nth-child(2) { order: 13; }
  tbody tr:nth-child(4) .pricing-col:nth-child(2) { order: 14; }
  tbody tr:nth-child(5) .pricing-col:nth-child(2) { order: 15; }
  tbody tr:nth-child(1) .pricing-col:nth-child(3) { order: 21; }
  tbody tr:nth-child(2) .pricing-col:nth-child(3) { order: 22; }
  tbody tr:nth-child(3) .pricing-col:nth-child(3) { order: 23; }
  tbody tr:nth-child(4) .pricing-col:nth-child(3) { order: 24; }
  tbody tr:nth-child(5) .pricing-col:nth-child(3) { order: 25; }
  tbody tr:nth-child(1) .pricing-col:nth-child(4) { order: 31; }
  tbody tr:nth-child(2) .pricing-col:nth-child(4) { order: 32; }
  tbody tr:nth-child(3) .pricing-col:nth-child(4) { order: 33; }
  tbody tr:nth-child(4) .pricing-col:nth-child(4) { order: 34; }
  tbody tr:nth-child(5) .pricing-col:nth-child(4) { order: 35; }
}

/* Landing Page Styles */

/* ═══════════════════════════════════════════════════════════════════════════
   HERO
   ═══════════════════════════════════════════════════════════════════════════ */

/* Bands alternate canvas and surface fills, split by a 1px rule (landing only) */
.band {
  background: var(--canvas);
  border-top: 1px solid var(--line);
}

.band:nth-of-type(even) {
  background: var(--surface);
}

.hero {
  padding: var(--space-12) 0;
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}

.hero h1 {
  font-size: var(--font-size-4xl);
  line-height: 1.1;
  text-align: start;
}

.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: var(--space-4) 0 var(--space-6);
}

.hero-facts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--ink-dim);
}

.hero-window {
  margin: 0;
  min-width: 0;
}

/* The window is a frozen capture: its symbol bar, option chips and window
   menu would drive a read seam that serves one symbol. */
.hero-window .widget-header .chip-bar-mount,
.hero-window .widget-header .widget-ticker-bar,
.hero-window .widget-header .widget-shell-controls,
.hero-window .widget-header .widget-controls {
  display: none;
}

@media (min-width: 1024px) {
  .hero-grid {
    grid-template-columns: 520px minmax(0, 1fr);
    gap: var(--space-16);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   FEATURES
   ═══════════════════════════════════════════════════════════════════════════ */

.features {
  padding: var(--space-16) 0;
}

.section-title {
  margin-bottom: var(--space-12);
}

.family-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}

.family-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-6);
}

.family-title {
  margin: 0;
}

.sparkline {
  display: block;
  width: 100%;
  height: 3rem;
}

.sparkline polyline {
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}

.family-caption {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
}

.family-text {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--ink-dim);
  line-height: 1.6;
}

.family-link {
  margin-top: auto;
  white-space: nowrap;
  font-size: var(--font-size-sm);
}

/* ═══════════════════════════════════════════════════════════════════════════
   STEPS
   ═══════════════════════════════════════════════════════════════════════════ */

.steps {
  padding: var(--space-16) 0;
}

.steps-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
  list-style: none;
  margin: 0 0 var(--space-8);
  padding: 0;
  counter-reset: step;
}

.step {
  counter-increment: step;
}

.step-title {
  font-size: var(--font-size-sm);
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.step-title::before {
  content: counter(step) ". ";
  color: var(--ink-faint);
}

.step-text {
  font-size: var(--font-size-sm);
  color: var(--ink-faint);
  line-height: 1.6;
}

.curl-window {
  margin: 0 0 var(--space-8);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.curl-window-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--line);
  font-size: var(--font-size-sm);
}

.curl-window-code {
  margin: 0;
  padding: var(--space-4);
  overflow-x: auto;
  font-family: inherit;
  font-size: var(--font-size-sm);
  line-height: 1.6;
}

.closing-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 639px) {
  .hero h1 { font-size: var(--font-size-3xl); }
  .family-grid { grid-template-columns: 1fr; }
  .steps-list { grid-template-columns: 1fr; }
  .closing-row { flex-direction: column; align-items: stretch; }
  .closing-row .btn { width: 100%; min-height: 2.75rem; justify-content: center; }
  .hero-ctas { flex-direction: column; align-items: stretch; }
  .hero-ctas .btn { width: 100%; min-height: 2.75rem; justify-content: center; }
}

/* Tokens Page Styles */

/* ═══════════════════════════════════════════════════════════════════════════
   TOKEN ROW
   ═══════════════════════════════════════════════════════════════════════════ */

.token-table {
  width: 100%;
  border-collapse: collapse;
}

.token-table th,
.token-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--line);
  text-align: left;
}

.token-table th {
  color: var(--ink-faint);
  font-weight: 600;
}

.token-prefix {
  font-family: var(--font-mono);
  color: var(--ink-faint);
}

.charts-usage {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
}

.token-actions {
  display: flex;
  gap: var(--space-2);
}

.status-row {
  padding-top: 0;
  padding-bottom: var(--space-3);
}

.status-row td {
  border-bottom: none;
  padding-top: var(--space-1);
}

.empty-state {
  text-align: center;
  padding: var(--space-12) var(--space-6);
  color: var(--ink-faint);
}

.empty-state p {
  margin-bottom: var(--space-4);
}

/* ═══════════════════════════════════════════════════════════════════════════
   TOKEN DISPLAY + WARNING
   ═══════════════════════════════════════════════════════════════════════════ */

.token-display {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  word-break: break-all;
  margin-bottom: var(--space-3);
}

.token-copy-row {
  display: flex;
  justify-content: flex-end;
  margin-bottom: var(--space-4);
}

.token-warning {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--line);
  border: 1px solid var(--caution);
  border-radius: var(--radius-sm);
  color: var(--caution);
  font-size: var(--font-size-sm);
}

.token-warning-icon {
  flex-shrink: 0;
  font-weight: 600;
}

/* ═══════════════════════════════════════════════════════════════════════════
   NEW-TOKEN CALLOUT (DS-PAGE-10)
   ═══════════════════════════════════════════════════════════════════════════ */

.token-callout {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--positive);
  background: transparent;
}

.token-callout p {
  margin: 0;
}


/* ═══════════════════════════════════════════════════════════════════════════
   REVOKE (red text, DS-PAGE-48) + STACKED ROWS (below 640, DS-PAGE-49)
   ═══════════════════════════════════════════════════════════════════════════ */

.token-revoke {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--negative);
  background: transparent;
  border: 0;
  padding: var(--space-2) 0;
  cursor: pointer;
}

.token-revoke:hover {
  text-decoration: underline;
}

.token-table,
.token-table tbody,
.token-table tr {
  display: block;
  width: 100%;
  box-sizing: border-box;
}

.token-table thead {
  display: none;
}

.token-table tr {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
}

.token-table td {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  border-bottom: none;
  padding: var(--space-1) 0;
  overflow-wrap: anywhere;
}

.token-table td[data-label]::before {
  content: attr(data-label);
  flex-shrink: 0;
  color: var(--ink-faint);
  font-weight: 600;
}

@media (min-width: 40em) {
  .token-table {
    display: table;
  }

  .token-table tbody {
    display: table-row-group;
  }

  .token-table thead {
    display: table-header-group;
  }

  .token-table tr {
    display: table-row;
    padding: 0;
    border-bottom: none;
  }

  .token-table td {
    display: table-cell;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--line);
    overflow-wrap: normal;
  }

  .token-table td[data-label]::before {
    content: none;
  }
}

/* Changelog Page Styles */

.doc-section {
  margin-bottom: var(--space-8);
}

.doc-section h2,
.changelog-body h2 {
  margin: 0 0 var(--space-3);
}

.doc-section p,
.changelog-body p {
  margin: 0 0 var(--space-3);
  line-height: 1.6;
}

.doc-section ul,
.changelog-body ul {
  margin: 0 0 var(--space-3) var(--space-6);
  padding: 0;
  line-height: 1.6;
}

.doc-note {
  color: var(--ink-faint);
  font-size: var(--font-size-xs);
}

.changelog-entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3);
  padding: var(--space-6) 0;
  border-top: 1px solid var(--line);
}

.changelog-rail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.changelog-date {
  font-weight: 600;
  color: var(--ink);
}

@media (min-width: 64em) {
  .changelog-entry {
    grid-template-columns: 264px minmax(0, 1fr);
    gap: 0;
    width: min(calc(264px + var(--w-prose)), calc(100vw - 2 * var(--gutter)));
  }

  .changelog-rail {
    align-items: flex-start;
    flex-direction: column;
  }
}

/* Trader Dashboard - GridStack widget layout */

.trader-dashboard {
    --ws-pad: var(--gutter);
    flex: 1;
    display: flex;
    flex-direction: column;
    background: var(--canvas);
    padding-block: 0 var(--ws-pad);
}

.control-group {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.control-group label {
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
}

.tab-list {
    display: flex;
    align-items: stretch;
    gap: 2px;
    overflow-x: auto;
    flex: 1;
    min-height: 32px;
}

.tab-item {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--ink-faint);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    user-select: none;
    transition: color var(--dur-fast), border-color var(--dur-fast);
}

.tab-item:hover {
    color: var(--ink);
}

.tab-item.active {
    color: var(--primary);
    border-bottom-color: var(--primary);
}

.tab-close {
    background: none;
    border: none;
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
    cursor: pointer;
    padding: 0;
    line-height: 1.1;
}

.tab-item:hover .tab-close {
    color: var(--ink);
}

.tab-close:hover {
    color: var(--negative);
}

.tab-add {
    background: none;
    border: 1px dashed var(--line);
    color: var(--ink-faint);
    font-size: var(--font-size-sm);
    font-family: var(--font-mono);
    cursor: pointer;
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    line-height: 1.4;
    flex-shrink: 0;
}

.tab-add:hover {
    border-color: var(--primary);
    color: var(--primary);
}

.tab-rename-input {
    font-weight: 600;
    width: 80px;
}

#dashboard-grid.tab-switching {
    opacity: 0;
    transition: opacity var(--dur-fast);
}

/* Widget structure */
.widget {
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
}

/* Content-sized widgets (metadata.sizeToContent, e.g. the calculator): the
   wrapper chain takes its NATURAL height so the WM can measure it
   (adapter.fitItem sets the .wm-window height directly from the measured
   content px - there is no resizeToContent cell to fit into anymore). height
   is content-driven; width stays user-driven. */
.widget--fit {
    height: auto;
    min-height: 0;
    /* .wm-window is a fixed-height flex column: without this, flex-shrink
       compresses the widget back to the window and the WM can never measure
       the natural content height. */
    flex-shrink: 0;
}

/* FR-2 containment (#318): these three used to opt fully out of the fill
   chain (flex:none/height:auto/flex:none) so a content-fit widget always
   rendered at its natural size. They now join the SAME flex:1/min-height:0
   fill pattern the base (non-fit) rules already use below - at rest this is
   a no-op (an auto-height .widget--fit gives flex:1 children no extra space
   to grow into, so they still size to content exactly as before), and it
   only diverges once wm.css's `.widget--fit` max-height clamps the window
   smaller than content, at which point the fill chain lets `.board`
   (board.css, height:100%/overflow:auto) become the real scroll boundary
   instead of `.wm-window`'s overflow:hidden silently clipping it.
   widget-body keeps `overflow: visible` untouched (nothing needs to clip at
   THIS level - the outer .widget--fit clamp above already does, and an
   escaping overlay like a dropdown keeps its existing clip radius). */
.widget--fit .widget-body {
    flex: 1;
    min-height: 0;
}

.widget--fit .widget-shell {
    height: 100%;
    min-height: 0;
}

.widget--fit .widget-shell-chart {
    flex: 1;
    min-height: 0;
}

/* One header band (DS-WS-30): title, symbol chips, primary controls, then the
   window controls. Height equals the WM drag band (BAND_H = 30). */
.widget-header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    box-sizing: border-box;
    height: 30px;
    padding: 0 var(--space-3);
    background: var(--raised);
    border-bottom: 1px solid var(--line);
    cursor: move;
    flex-shrink: 0;
    overflow: hidden;
}

.widget-title {
    flex: 0 1 auto;
    min-width: 8ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--ink);
}

.widget-header .chip-bar-mount,
.widget-header .widget-shell-controls {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
}

.widget-header--folded .widget-shell-controls {
    display: none;
}

.widget-primary-value {
    flex: 0 0 auto;
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
    white-space: nowrap;
}

.widget-controls {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
    flex: 0 0 auto;
}

.chart-control-overlay:disabled {
    display: none;
}

.widget-menu-btn {
    background: none;
    border: none;
    color: var(--ink-faint);
    cursor: pointer;
    padding: 0 2px;
    font-size: var(--font-size-base);
    line-height: 1.1;
}

.widget-menu-btn:hover {
    color: var(--primary);
}

.widget-close {
    background: none;
    border: none;
    color: var(--ink-faint);
    cursor: pointer;
    padding: 0;
    font-size: var(--font-size-base);
    line-height: 1.1;
}

.widget-close:hover {
    color: var(--negative);
}

.widget-ticker-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) 0;
    flex-shrink: 0;
    position: relative;
}

.ticker-chip.primary {
    border-color: var(--caution);
}

.widget-ticker-bar.single-mode .chip-remove {
    display: none !important;
}

.chip-search-panel {
    position: relative;
    margin-left: auto;
}

.chip-search-input {
    font-weight: 600;
    width: 100px;
}

.widget-body {
    flex: 1;
    overflow: hidden;
    position: relative;
    padding: var(--space-2);
    display: flex;
    flex-direction: column;
}

.widget-chart-controls {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding-top: var(--space-1);
    padding-bottom: var(--space-1);
}

.chart-control-select {
    border: 1px solid var(--line);
    background: var(--canvas);
    color: var(--ink-dim);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 2px 4px;
    min-height: 22px;
}

.chart-control-select:focus {
    border-color: var(--primary);
}

.widget-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--ink-faint);
    font-size: var(--font-size-sm);
    gap: var(--space-2);
}

.widget-loading-dot {
    width: 8px;
    height: 8px;
    border-radius: 999px;
    background: var(--primary);
    box-shadow: 0 0 0 0 color-mix(in oklab, var(--primary) 26%, transparent);
    animation: widgetPulse 1.6s ease-out infinite;
}

@keyframes widgetPulse {
    0% { transform: scale(0.95); box-shadow: 0 0 0 0 color-mix(in oklab, var(--primary) 26%, transparent); }
    70% { transform: scale(1); box-shadow: 0 0 0 8px transparent; }
    100% { transform: scale(0.95); box-shadow: 0 0 0 0 transparent; }
}

.widget-error {
    display: grid;
    gap: var(--space-1);
    height: 100%;
    color: var(--negative);
    font-size: var(--font-size-sm);
    padding: var(--space-4);
    text-align: center;
    align-content: center;
}

.widget-error-title {
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--negative);
}

.widget-error-message {
    color: var(--ink-dim);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
}

.widget-error-hint {
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
}

.widget-inline-note {
    border-top: 1px solid var(--line);
    background: color-mix(in oklab, var(--line) 26%, transparent);
    color: var(--ink-dim);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    padding: 4px 8px;
}

/* Widget shell zones (defineWidget) - controls / chart / footer stacked. */
.widget-shell {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.widget-shell-controls {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
}

.widget-shell-chart {
    flex: 1;
    min-height: 0;
}

/* ECharts measures container.clientWidth at init (chart-theme.js
   createThemedChart, no explicit width opt). A max-width floor never lets
   the drawn canvas overflow its own containing block regardless of the
   measured width; the doc example's own overflow (its containing block is
   the ECharts wrapper div, not this shell) is fixed at the source
   (framework/docs-mount.js reserves the callout gutter before the widget
   mounts) with a matching floor on the wrapper itself, scoped to
   .docs-example (docs.css), chrome-callouts-fix-5-fix-2. */
.widget-shell-chart canvas {
    max-width: 100%;
}

.widget-shell-footer {
    flex-shrink: 0;
}

/* Empty state - a FIRST-CLASS state (design 3.6): "what happened + what to do
   next". Never the red error path. */
.widget-empty {
    display: grid;
    gap: var(--space-1);
    height: 100%;
    color: var(--ink-faint);
    font-size: var(--font-size-sm);
    padding: var(--space-4);
    text-align: center;
    align-content: center;
}

.widget-empty-title {
    font-weight: 600;
    color: var(--ink-dim);
}

.widget-empty-hint {
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
}

/* Quality badge (design 3.5 / 5.7, ruling 7). Rendered for any quality_status
   other than published; an unknown token fails safe to --caution. */

/* Chart container within widgets */
.widget-chart {
    width: 100%;
    height: 100%;
}

.widget-body.chart-mode {
    padding: 0;
}

/* Vol Surface 2D/3D widget */
.widget-body:has(.vs3d-controls) {
    display: flex;
    flex-direction: column;
    padding: 0;
}

.vs3d-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: 3px var(--space-2);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    flex-shrink: 0;
}

.vs3d-toggle-group { display: flex; gap: 2px; }

.vs3d-toggle-btn,
.vs3d-metric-btn {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    font-weight: 600;
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--line);
    background: transparent;
    color: var(--ink-faint);
    cursor: pointer;
    transition: all var(--dur-fast) ease;
    line-height: 1.4;
}

.vs3d-toggle-btn:hover,
.vs3d-metric-btn:hover { border-color: var(--ink-faint); color: var(--ink); }

.vs3d-toggle-btn.active,
.vs3d-metric-btn.active { background: var(--primary); color: var(--canvas); border-color: var(--primary); }

.vs3d-chart, .vrp-chart, .zs-chart, .ivhv-chart, .vix-chart,
.dist-chart, .gf-chart, .ts-chart, .fc-chart,
.vs-chart, .ca-chart { flex: 1; min-height: 0; }

.gf-footer { flex-shrink: 0; }

.gf-stats-footer {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-1) var(--space-2);
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    border-top: 1px solid var(--line);
    flex-wrap: wrap;
}

.gf-stats-footer b { color: var(--ink); }

/* Table widget (cross-asset) */
.widget-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-xs);
}

.widget-table th,
.widget-table td {
    padding: var(--space-1) var(--space-2);
    text-align: right;
    border-bottom: 1px solid var(--line);
}

.widget-table th {
    background: var(--raised);
    color: var(--ink-faint);
    font-weight: 600;
    font-size: var(--font-size-xs);
}

.widget-table th:first-child,
.widget-table td:first-child {
    text-align: left;
}

.widget-table tr:hover {
    background: var(--raised);
}

/* Widget picker sidebar (replaces the tabbed add-widget modal): a right-side
   drawer showing EVERY category at once; stays open across adds. */
.widget-sidebar {
    position: fixed;
    top: 6rem;
    right: 0;
    bottom: 0;
    width: 320px;
    max-width: 90vw;
    display: flex;
    flex-direction: column;
    background: var(--canvas);
    border-left: 1px solid var(--line);
    box-shadow: var(--shadow-raised);
    transform: translateX(100%);
    transition: transform var(--dur-base) ease;
    z-index: var(--z-drawer);
}

.widget-sidebar.open {
    transform: translateX(0);
}

/* Docked: the grid gives up the panel's width instead of sitting under it. */
body:has(.widget-sidebar.open) #dashboard-grid {
    margin-right: calc(320px - var(--ws-pad));
}

#add-widget-btn[aria-expanded="true"] {
    background: var(--raised);
    color: var(--ink);
    border-color: var(--primary);
}

.widget-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
}

.widget-sidebar-header h3 {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--ink);
}

.widget-sidebar-close {
    background: none;
    border: none;
    color: var(--ink-faint);
    font-size: var(--font-size-lg);
    line-height: 1.1;
    cursor: pointer;
    font-family: inherit;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
}

.widget-sidebar-close:hover {
    color: var(--ink);
    background: var(--raised);
}

.widget-sidebar-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-3) var(--space-3) var(--space-4);
}

.widget-sidebar-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.widget-sidebar-section-title {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--ink-faint);
    padding-bottom: var(--space-1);
    border-bottom: 1px solid var(--line);
}

.widget-sidebar-filters {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    border-bottom: 1px solid var(--line);
}

.widget-sidebar-filters .field {
    width: 100%;
}

.widget-sidebar-filters .segmented {
    width: 100%;
}

.widget-sidebar-filters .segmented__option {
    flex: 1;
}

.widget-sidebar-body .widget-sidebar-section[hidden],
.widget-sidebar-body .widget-type-btn[hidden] {
    display: none;
}

.widget-sidebar-footer {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-top: 1px solid var(--line);
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
}

.widget-type-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-4);
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: inherit;
    transition: border-color var(--dur-fast), background var(--dur-fast);
}

.widget-type-btn:hover {
    background: var(--line);
    border-color: var(--primary);
}

/* Sidebar entries: 32px rows (label | count). The description shows only on
   the active row (aria-current), as an overlay under the row: it takes no
   layout space and no pointer events, so rows never shift under the pointer. */
.widget-sidebar-body .widget-type-btn {
    position: relative;
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: var(--space-3);
    align-items: center;
    text-align: left;
    width: 100%;
    box-sizing: border-box;
    height: 32px;
    padding: 0 var(--space-3);
}

.widget-sidebar-body .widget-type-btn .widget-type-desc {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: var(--z-raised);
    padding: var(--space-1) var(--space-3);
    background: var(--raised);
    border: 1px solid var(--line);
    text-align: left;
    pointer-events: none;
}

.widget-sidebar-body .widget-type-btn[aria-current="true"] .widget-type-desc {
    display: block;
}

.widget-sidebar-body .widget-type-btn .widget-type-count {
    grid-area: count;
}

.widget-type-count {
    flex: 0 0 auto;
    min-width: 20px;
    text-align: center;
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--surface);
    border-radius: var(--radius-sm);
    padding: 1px var(--space-1);
}

.widget-type-count:not(:empty) {
    background: var(--primary);
}

/* Click feedback: flash the entry when its widget lands on the workspace. */
@keyframes widget-added-flash {
    0% { background: var(--primary); border-color: var(--primary); }
    100% { background: var(--raised); border-color: var(--line); }
}

.widget-sidebar-body .widget-type-btn.added {
    animation: widget-added-flash 0.5s ease-out;
}

.widget-type-label {
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--ink);
}

.widget-type-desc {
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    text-align: center;
}

/* Form elements */
.form-group {
    margin-bottom: var(--space-4);
}

.form-group label {
    display: block;
    margin-bottom: var(--space-1);
    color: var(--ink-faint);
    font-size: var(--font-size-xs);
}


.checkbox-label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    color: var(--ink);
    font-size: var(--font-size-sm);
}

.checkbox-label input[type="checkbox"] {
    accent-color: var(--primary);
}

/* Stats panel shared content */
.info-widget-content {
    padding: var(--space-2) var(--space-3);
    overflow-y: auto;
    height: 100%;
    font-size: var(--font-size-xs);
    color: var(--ink-faint);
    line-height: 1.4;
}

.info-widget-title {
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--ink);
    margin-bottom: var(--space-2);
}

.info-widget-body p { margin: 0 0 var(--space-2) 0; }
.info-widget-body ul { margin: 0 0 var(--space-2) 0; padding-left: var(--space-4); }
.info-widget-body li { margin-bottom: var(--space-1); }
.info-widget-body strong { color: var(--ink); }

/* Value coloring */
.value-positive {
    color: var(--positive);
}

.value-negative {
    color: var(--negative);
}

.value-caution {
    color: var(--caution);
}

.value-aqua {
    color: var(--ink);
}

.value-neutral {
    color: var(--ink-faint);
}

/* Tighter stats spacing inside info panels */
.info-widget-content .stats-section { padding: var(--space-2) 0; }
.info-widget-content .stats-section-header { font-size: var(--font-size-xs); margin-bottom: var(--space-1); }
.info-widget-content .stats-row { gap: var(--space-2); }
.info-widget-content .stat-value { font-size: var(--font-size-sm); }
.info-widget-content .stats-signal-box { padding: var(--space-2); }
.info-widget-content .signal-value { font-size: var(--font-size-sm); padding: var(--space-1); }
.info-widget-content .stats-range-box { padding: var(--space-1) var(--space-2); }

/* Responsive - Tablet */
@media (max-width: 768px) {
    .control-group {
        flex: 1;
        min-width: 120px;
    }

    /* Widget touch targets */
    .widget-close {
        padding: var(--space-2);
        font-size: var(--font-size-xl);
    }

    .widget-controls select {
        padding: 0.25rem 0.5rem;
        font-size: var(--font-size-xs);
    }
}

/* Responsive - Mobile */
@media (max-width: 480px) {
    .vs3d-controls {
        flex-wrap: wrap;
        gap: var(--space-1);
    }

    .workspace-bar .page-title {
        font-size: var(--font-size-base);
    }

    /* Widget header compact */
    .widget-header {
        padding: var(--space-1) var(--space-2);
    }

    .widget-title {
        font-size: var(--font-size-xs);
    }

    /* Table compact */
    .widget-table {
        font-size: var(--font-size-xs);
    }

    .widget-table th,
    .widget-table td {
        padding: var(--space-1) var(--space-1);
    }
}

/* Touch-friendly hover states */
@media (hover: none) {
    .widget-type-btn:active {
        background: var(--line);
        border-color: var(--primary);
    }

    .widget-close:active {
        color: var(--negative);
    }
}

/* ── OptChipBar ── */

.opt-chipbar {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.opt-select {
    height: 1.5rem;
    padding: 0 8px;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    white-space: nowrap;
}

.opt-select:disabled {
    color: var(--ink-faint);
    cursor: default;
}

.opt-chip-disabled {
    opacity: 0.35;
    pointer-events: none;
}

.opt-divider {
    width: 1px;
    height: 16px;
    background: var(--line);
    flex-shrink: 0;
}

.widget-chart-wrapper {
    display: flex;
    flex-direction: row;
    flex: 1;
    min-height: 0;
}

/* Error pages: the Focus shell column, header recipe from layout.css, two buttons. */

.error-column {
  width: 100%;
  max-width: var(--w-narrow);
}

.error-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.error-actions .btn-secondary {
  background: transparent;
  border-color: var(--ink-faint);
}

@media (min-width: 40em) {
  .error-actions {
    flex-direction: row;
  }
}
