/* ─────────────────────────────────────────────────────────────────────────
   design-tokens.css — SINGLE TOKEN AUTHORITY (E0, epic #20)

   Every colour, space, type step, radius, shadow and safe-area value used by
   any page lives here. No template or module may redeclare these.

   Naming:
     --color-*   canonical (use these in new code)
     --space-*   fluid spacing scale (clamp)
     --step-*    fluid type scale (clamp)
   Legacy aliases (--accent, --text-warm, --bg-card, …) are kept ONLY so old
   template rules keep resolving during the migration burn-down (tracked in
   epic #20 / E4). Do not use them in new code.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  /* ── Colors (canonical) ── */
  --color-accent: #d4a853;
  --color-accent-dark: #b8913a;
  --color-accent-glow: rgba(212,168,83,0.18);
  --color-accent-strong: rgba(212,168,83,0.35);
  --color-bg: #0a0a0f;
  --color-surface: rgba(15,15,18,0.62);
  --color-surface-hover: rgba(30,30,40,0.8);
  --color-card: rgba(15,15,18,0.65);
  --color-text: #f8f2e7;
  --color-text-muted: #94a3b8;
  --color-text-dim: #64748b;
  --color-border: rgba(255,255,255,0.08);
  --color-border-strong: rgba(255,255,255,0.12);
  --color-error-bg: rgba(127,29,29,0.4);
  --color-error-border: rgba(185,28,28,0.5);
  --color-error-text: #fecaca;
  --color-input-bg: rgba(255,255,255,0.06);
  --color-input-border: rgba(255,255,255,0.10);

  /* ── Semantic palette ──
     These were previously UNDEFINED — the engine's inline CSS relied solely on
     `var(--color-purple, #7c3aed)`-style fallbacks, so they could not be
     themed. Now they resolve from here. */
  --color-text-bright: #fff;
  --color-overlay: rgba(0,0,0,0.85);
  --color-purple: #7c3aed;
  --color-purple-light: #a78bfa;
  --color-purple-dark: #4c1d95;
  --color-purple-bg: #1e1b4b;
  --color-success-bg: #064e3b;
  --color-success-light: #a7f3d0;
  --color-success-border: #059669;
  --color-warning: #fcd34d;
  --color-warning-bg: #451a03;
  --color-danger: #ef4444;
  --color-danger-text: #dc2626;
  --color-info: #60a5fa;
  --color-info-dark: #1e40af;

  /* ── Legacy aliases (DEPRECATED — migrate to --color-*; burn-down in #20/E4) ── */
  --accent: var(--color-accent);
  --accent-dark: var(--color-accent-dark);
  --accent-glow: var(--color-accent-glow);
  --accent-strong: var(--color-accent-strong);
  --text-warm: var(--color-text);
  --text-muted: var(--color-text-muted);
  --bg-card: var(--color-card);
  --border-subtle: var(--color-border);
  --input-bg: var(--color-input-bg);
  --input-border: var(--color-input-border);

  /* ── Typography ── */
  --font-heading: 'Space Grotesk', 'Inter', sans-serif;
  --font-body: 'Space Grotesk', 'Inter', sans-serif;
  --font-mono: 'Courier New', monospace;

  /* ── Fluid type scale (DERIVED: clamp between a 320px and 1280px viewport;
        see docs/ui-contract.md). Prefer these over raw font-size. ── */
  --step--1: clamp(0.8rem, 0.76rem + 0.2vw, 0.9rem);
  --step-0:  clamp(0.9rem, 0.85rem + 0.25vw, 1rem);
  --step-1:  clamp(1.1rem, 1rem + 0.5vw, 1.35rem);
  --step-2:  clamp(1.35rem, 1.15rem + 1vw, 1.9rem);
  --step-3:  clamp(1.7rem, 1.35rem + 1.75vw, 2.6rem);

  /* ── Fluid spacing scale (DERIVED, same reference widths) ── */
  --space-2xs: clamp(0.25rem, 0.23rem + 0.1vw, 0.3rem);
  --space-xs:  clamp(0.5rem, 0.46rem + 0.2vw, 0.6rem);
  --space-sm:  clamp(0.75rem, 0.7rem + 0.25vw, 0.9rem);
  --space-md:  clamp(1rem, 0.93rem + 0.35vw, 1.2rem);
  --space-lg:  clamp(1.5rem, 1.35rem + 0.75vw, 2rem);
  --space-xl:  clamp(2rem, 1.7rem + 1.5vw, 3rem);

  /* ── Radius ── */
  --radius-sm: 0.5rem;
  --radius-md: 1rem;
  --radius-lg: 1.5rem;
  --radius-xl: 2rem;

  /* ── Shadows ── */
  --shadow-card: 0 8px 40px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.04);
  --shadow-glow: 0 4px 20px var(--color-accent-glow);

  /* ── Transitions (respect reduced motion at use site) ── */
  --transition-fast: 0.15s ease;
  --transition-normal: 0.25s ease;

  /* ── Stacking scale (S1 / epic #20) ──
     The ONLY sanctioned z-index authority. Ordering is the contract; the
     numeric values preserve the pre-S1 layout exactly, so behaviour is
     unchanged. Raw `z-index:` outside this file is a UI-contract violation
     (enforced by scripts/check_ui_contract.mjs). */
  --z-base: 0;
  --z-content: 10;
  --z-sticky: 20;
  --z-overlay: 30;      /* content-level overlays: fretboard drag handles / drill
                           regions — above the surfaces, below EVERY chrome layer
                           (scrim 49, nav 50, toolbar 55, rails 60). Content never
                           floats over chrome; chrome never floats over tooltips. */
  --z-dropdown: 49;
  --z-nav: 50;
  --z-toolbar: 55;
  --z-rail: 60;
  --z-shell-handle: 70;
  --z-modal: 100;
  --z-tooltip: 9999;
  --z-tooltip-above: 10000;
  --z-tooltip-top: 10001;

  /* ── Shell geometry (S1 → A8 / epic #20) ──
     --shell-header-h is the sticky shell header's height. That height is
     FLUID — the navbar wraps on phones and the toolbar panels grow — so this
     declared value is only the pre-JS fallback. shell-layout.js measures the
     real height with a ResizeObserver and overwrites it on the root. No
     consumer may hardcode a sticky offset (that was issue #29's root cause). */
  --shell-header-h: 3.625rem;  /* fallback until measured */

  /* ── Rail geometry (A10 / epic #20; amended 2026-10-12) ──
     The visual width of an open rail. Rails are OVERLAYS at every tier (owner
     decision 2026-10-12): the shell grid no longer reserves a track, so
     #main-content never shrinks and opening a rail never re-layouts the score.
     Geometry lives here; JS toggles state, never a pixel offset. */
  --shell-rail-w: 18rem;

  /* ── Rail surfaces (U1, panel revamp 2026-10-12) ──
     Rails are SOLID (100% opaque); translucency is reserved for the scrim.
     --color-panel is the rail surface; --color-scrim is the only alpha
     surface (compact overlay); the rail shadows express elevation. */
  --color-panel: #13161f;
  --color-scrim: rgba(0, 0, 0, 0.45);
  --shadow-rail-left: 12px 0 32px rgba(0, 0, 0, 0.55);
  --shadow-rail-right: -12px 0 32px rgba(0, 0, 0, 0.55);

  /* ── Interaction geometry (P-4) ──
     Minimum touch hit area. Not a magic number: it is the documented, validated
     WCAG 2.5.5 / Apple HIG 44px anchor (Android 48dp). Hit areas are sized from
     this per capability (`pointer: coarse`) and are decoupled from the visual
     size of the glyph. The surface contract asserts the same value
     (shell-surfaces.js TOUCH_TARGET_MIN). */
  --touch-target-min: 44px;

  /* ── Containment (S1 / epic #20) ──
     Overlap is only legal where declared; shell surfaces clip their own bleed. */
  --shell-overflow: clip;

  /* ── Safe area (E0): applied ONLY at the shell root, never per-widget ── */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);

  /* ── Composition (S5 / #34) — the visible-surface budget ──
     How the content pane is split between the co-protagonist score and the
     instrument regions, plus the fixed chrome budget. These are POLICY values:
     documented and adjustable, never hardcoded at a use site. See
     docs/ui-contract.md §10.8. The score share is bounded below by a floor;
     the floor is S5 product policy and is INDEPENDENT of S2's px legibility
     warning (ADR-004 / SL-4: the raster floor is a warning, not a clamp). */
  /* RETIRED (Unit 1b / M(a)): the 0.25 share floor is no longer a clamp. The
     score floor is a px height measured by score-floor.js and published as
     --composition-score-floor-px by composition-view.js. */
  --composition-score-share-target: 0.5333; /* S5 vision, human-confirmed: stacked score 375 /
                                               instruments 328 at 393w = 0.533 (s5-reference.json) */
  --composition-region-min-block: 5rem;     /* min block size of a protagonist region */

  /* Wide composition axis (S5 / #34) — at ≥ 64rem the two protagonists sit side
     by side (docs/vision/s5-reference.json multiViewport 1280x800: score
     {737x719} LEFT / instruments {533x719} RIGHT). A COLUMN axis, independent of
     --composition-score-share (which governs the STACKED rows). 737/1270 =
     0.5803. fr values are unit-bearing because they reach the grid as <flex>. */
  --composition-wide-score-col: 0.5803fr;
  --composition-wide-instrument-col: 0.4197fr;

  /* ── Composition interaction geometry (S5 / #34) ──
     The draggable limit bar and the docking rows above each instrument. Sizes
     are the visual thickness; hit areas are enlarged per --touch-target-min. */
  --composition-limit-bar-h: 1rem;   /* draggable score/instrument limit bar */
  --composition-dock-strip-h: 1rem;  /* instrument horizontal scroll strip */
  --composition-zoom-row-h: 1.25rem; /* instrument zoom row (icon · - · slider · + · value) */
  --composition-control-row-h: 1.625rem; /* merged fretboard zoom + dock control row (Unit 1c) */

  /* ── Scrollbars (S5 / #34, P8) — thin, rounded, transparent track ──
     The thumb derives from the text colour and highlights with the accent.
     Consumed by the global scrollbar rule; no raw scrollbar colours elsewhere. */
  --scrollbar-size: 10px;
  --scrollbar-track: transparent;
  --scrollbar-thumb: rgba(248,242,231,0.16);
  --scrollbar-thumb-hover: var(--color-accent-strong);
}

/* ── Self-hosted Space Grotesk (single source; templates must NOT redeclare) ── */
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ── Motion policy (E0): global reduced-motion honour ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
