/*
 * Design tokens (adapted from astrolabe styles/tokens.css). A single source of
 * truth for type, spacing, color, shape, and motion, themed by overriding the role
 * tokens on a `[data-mode]` root. Components consume these tokens ONLY — never raw
 * hexes.
 *
 * Inspired by the IBM Design Language / Carbon (structure borrowed, color free);
 * Carbon is not a dependency — the values are transcribed. Divergences: square
 * chrome (--radius: 0), an open/swappable accent.
 *
 * :root carries the theme-agnostic tokens AND the LIGHT theme, so light is the
 * default with no `[data-mode]` attribute (and an explicit `[data-mode='light']`
 * inherits it). `[data-mode='dark']` overrides the neutral/status/accent roles.
 */
:root {
  /* Type — IBM Plex with system fallbacks. NOTE: not self-hosted yet this slice;
     the fallbacks render until @fontsource imports are wired in. */
  --font-sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, monospace;
  --font-size-base: 14px;

  /* Spacing — 8px base unit (2/4 as sub-steps) */
  --space-1: 2px;
  --space-2: 4px;
  --space-3: 8px;
  --space-4: 12px;
  --space-5: 16px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 48px;
  --space-9: 64px;

  /* Shape — square chrome (icons keep their own rounded geometry) */
  --radius: 0px;
  --border-width: 1px;

  /* Control scale — every interactive control is one of exactly two heights.
     32px is THE control height (toolbar/form controls); 40px is reserved for
     standalone primary CTAs and modal footers. A third value is drift. */
  --control-height: 32px;
  --control-height-lg: 40px;

  /* Motion — productive only. A transition takes its duration from these
     tokens, and the reduced-motion rule at the end of this file stills all of
     them at once. A transition with a raw duration (`.ds-toggle svg`) and
     every keyframe animation carry their own reduced-motion rule beside
     them. */
  --dur-fast: 70ms;
  --dur-fast-2: 110ms;
  --dur-moderate: 150ms;
  --ease: cubic-bezier(0.2, 0, 0.38, 0.9);

  /* Focus ring defaults to the accent. */
  --focus: var(--accent);

  /* Contextual field fill — elevated surfaces set `--field: var(--field-02)`. */
  --field: var(--field-01);
  --field-hover: var(--field-hover-01);

  /* --- Neutral roles: LIGHT theme (Carbon gray ramp) — the default --- */
  --bg: #ffffff;
  --layer-01: #f4f4f4;
  --layer-02: #e0e0e0;
  --border: #e0e0e0;
  /* Component boundaries need 3:1 against the surface (WCAG 1.4.11); gray-50 is
     3.32:1 on the canvas (Carbon's $border-strong-01). */
  --border-strong: #8d8d8d;
  --field-01: #f4f4f4;
  --field-02: #ffffff;
  --field-hover-01: #e8e8e8;
  --field-hover-02: #e8e8e8;
  --text: #161616;
  --text-secondary: #525252;
  --text-placeholder: #a8a8a8;

  /* Status — color carries meaning only (light values; overridden in dark). */
  --support-error: #da1e28;
  --support-success: #198038;
  --support-warning: #f1c21b;
  /* Warning foreground: the raw yellow fails contrast on light surfaces, so status
     glyphs/text use a darkened amber. Dark theme keeps the yellow. */
  --support-warning-fg: #896c00;
  --support-info: #0043ce;
  --on-status: #ffffff;

  /* Accent — the FREE, swappable layer. Deep teal is the default (verified AA in
     both themes). An accent switcher can add `[data-accent]` overrides later. */
  --accent: #0e7490;
  --accent-hover: #0c5f77;
  --accent-contrast: #ffffff;
  /* Translucent accent for non-interactive emphasis washes (inspector reverse
     linkage, §01K) — pre-mixed per theme, content stays readable through it. */
  --accent-wash: rgba(14, 116, 144, 0.14);
  /* Warehouse — the source-table nodes in the model tab (spec §03R): a paper
     tint that reads as "the tables", apart from the datasources' layer grey.
     Not an accent and not a status: the fill is identity, never emphasis. */
  --warehouse-fill: #fbf3dc;
  --warehouse-ink: #6b4f00;

  /* Alignment guidelines (spec §01B): a hue deliberately distinct from the
     accent so a guide never blends with the dragged block's own selection
     outline (Figma's red-vs-blue split). Carbon magenta 60 / 40. */
  --snap-guide: #d02670;

  /* Elevation — exactly two shadow roles, one depth rule: floating = shadow,
     docked = seam + cast. Overlay: surfaces floating over content (menus,
     popovers, notices, canvas bars). Docked: the docked panels' cast onto the
     canvas — direction fixed per edge, so two tokens. */
  --shadow-overlay: 0 4px 16px rgba(0, 0, 0, 0.25);
  --shadow-docked-left: -6px 0 14px rgba(0, 0, 0, 0.1);
  --shadow-docked-up: 0 -6px 14px rgba(0, 0, 0, 0.1);

  /* Paper — the public pages' printed look (spec §07A): an off-white sheet,
     near-black ink, and four ink colors for the drifting charts and the
     sample dashboard. The page's surface only; app chrome stays on the roles
     above. The paper grain is an image (styles/paper/), blended over --paper. */
  --font-prose: 'Fixel Text', var(--font-sans);
  --font-display: 'Fixel Display', 'Fixel Text', var(--font-sans);
  --paper: #f6f5f1;
  --paper-sheet: #fffffd;
  --paper-rule: #dcd9d0;
  --ink: #1c1c1a;
  --ink-2: #4f4e49;
  --ink-3: #807e77;
  --ink-blue: #2f5bd3;
  --ink-vermilion: #e0603a;
  --ink-green: #1f8a70;
  --ink-ochre: #c48a00;
  --ink-muted: color-mix(in srgb, var(--ink) 28%, transparent);
  --paper-shadow:
    0 0 0 1px rgba(30, 25, 10, 0.05), 0 1px 2px rgba(30, 25, 10, 0.06),
    0 12px 32px -12px rgba(30, 25, 10, 0.18);
}

/* --- DARK theme: neutral, status, and accent overrides --- */
[data-mode='dark'] {
  --bg: #161616;
  --layer-01: #262626;
  --layer-02: #393939;
  --border: #393939;
  /* 3.60:1 on the dark canvas (Carbon g100 $border-strong-01). */
  --border-strong: #6f6f6f;
  --field-01: #262626;
  --field-02: #393939;
  --field-hover-01: #333333;
  --field-hover-02: #474747;
  --text: #f4f4f4;
  --text-secondary: #a8a8a8;
  --text-placeholder: #6f6f6f;

  --support-error: #fa4d56;
  --support-success: #42be65;
  --support-warning: #f1c21b;
  --support-warning-fg: #f1c21b;
  --support-info: #78a9ff;
  --on-status: #161616;

  --accent: #2dd4bf;
  --accent-hover: #5eead4;
  --accent-contrast: #161616;
  --accent-wash: rgba(45, 212, 191, 0.18);
  --warehouse-fill: #3a3212;
  --warehouse-ink: #f1d27a;

  --snap-guide: #ff7eb6;

  /* Shadows read weaker on dark surfaces; the docked cast steps up. */
  --shadow-docked-left: -6px 0 14px rgba(0, 0, 0, 0.35);
  --shadow-docked-up: 0 -6px 14px rgba(0, 0, 0, 0.35);

  --paper: #18181a;
  --paper-sheet: #202023;
  --paper-rule: #34343a;
  --ink: #ecebe6;
  --ink-2: #c2c0b9;
  --ink-3: #8e8c85;
  --ink-blue: #6f93f0;
  --ink-vermilion: #f08560;
  --ink-green: #3fb894;
  --ink-ochre: #e0b03a;
  --paper-shadow: 0 0 0 1px rgba(255, 255, 255, 0.05), 0 12px 32px -12px rgba(0, 0, 0, 0.6);
}

/* --- Reduced motion: the duration tokens go to zero, so a transition built
   on them changes state at once. A delay stays: it keeps a quick state from
   showing at all, and is no motion of its own. --- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0ms;
    --dur-fast-2: 0ms;
    --dur-moderate: 0ms;
  }
}
