/**
 * CSS Variables - Design Tokens
 * PixULA
 *
 * This file declares the cascade-layer order for the whole app (it is the
 * first stylesheet loaded) and defines every design token. Precedence is
 * by @layer, never by <link> order.
 */

@layer tokens, reset, layout, components, themes, utilities;

@layer tokens {

:root {
    /* Tell the browser this is a dark UI so native widgets (scrollbars,
       form-control popups, default focus rings) render in dark mode.
       Themes.css overrides this for light variants. */
    color-scheme: dark;
    /* Themes the native parts of checkboxes, radios, range thumbs, and
       progress bars without per-control overrides. */
    accent-color: var(--accent-primary);

    /* ===== COLORS ===== */
    /* ZX Spectrum palette — the indexed tokens --zx-0 … --zx-15 are written
       to :root by ColorManager at init from the single palette source
       (constants.js / the active palette). CSS defines only readable
       aliases; no palette hex value may appear in any stylesheet. */
    --zx-black:          var(--zx-0);
    --zx-blue:           var(--zx-1);
    --zx-red:            var(--zx-2);
    --zx-magenta:        var(--zx-3);
    --zx-green:          var(--zx-4);
    --zx-cyan:           var(--zx-5);
    --zx-yellow:         var(--zx-6);
    --zx-white:          var(--zx-7);
    --zx-black-bright:   var(--zx-8);
    --zx-blue-bright:    var(--zx-9);
    --zx-red-bright:     var(--zx-10);
    --zx-magenta-bright: var(--zx-11);
    --zx-green-bright:   var(--zx-12);
    --zx-cyan-bright:    var(--zx-13);
    --zx-yellow-bright:  var(--zx-14);
    --zx-white-bright:   var(--zx-15);

    /* UI Colors (Dark Theme) */
    --bg-primary: #1a1a1a;
    --bg-secondary: #2d2d2d;
    --bg-tertiary: #3d3d3d;
    --bg-hover: #4d4d4d;
    --bg-active: #5d5d5d;

    --text-primary: #e0e0e0;
    --text-secondary: #a0a0a0;
    --text-muted: #707070;

    --border-color: #404040;
    --border-light: #505050;

    --accent-primary: #3ecf6e;
    --accent-primary-rgb: 62, 207, 110;
    --accent-secondary: #88dca4;
    --accent-success: #00b894;
    --accent-warning: #fdcb6e;
    --accent-error: #d63031;
    --accent-error-rgb: 214, 48, 49;

    /* Semantic aliases (referenced by JS and component CSS) */
    --accent-color: var(--accent-primary);   /* backward-compat alias */
    --input-bg:     var(--bg-tertiary);
    --btn-bg:       var(--bg-secondary);
    --bg-panel:     var(--bg-primary);
    --warning-color: var(--accent-warning);
    --error-color:   var(--accent-error);
    --canvas-bg:    var(--zx-7);             /* ZX paper */
    --accent-bg:    rgba(var(--accent-primary-rgb), 0.15);

    /* Component-state tokens (shared contract for toggle/state buttons —
       replaces the rgba literals repeated per button class in the old tree) */
    --on-accent:       #ffffff;
    --state-dim-bg:    rgba(255, 255, 255, 0.15);
    --state-dim-fg:    rgba(255, 255, 255, 0.5);
    --state-active-bg: rgba(255, 255, 255, 0.25);
    --checker-light:   #666666;
    --checker-dark:    #444444;

    /* Tool icon identity colours (dark theme — the default). One hue per
       tool, spaced by the golden angle (137.508deg) so any two RAIL-ADJACENT
       tools land far apart on the wheel, then each lightness nudged until it
       clears 3.3:1 contrast against both --btn-bg and --bg-hover (measured,
       WCAG relative luminance). The icon's own shape is still the primary
       identifier — this set is vividness, not a second identity channel, so
       it does not attempt full pairwise CVD distinctness across all 20.
       Applied by .tool-btn[data-tool] in components.css; every other theme
       in themes.css overrides the whole block for its own surfaces. */
    --tool-color-brush:           #e08c7b;
    --tool-color-spray:           #6adc9e;
    --tool-color-fade:            #ce8be4;
    --tool-color-pattern:         #d7dc6a;
    --tool-color-hatch:           #6ab6dc;
    --tool-color-eraser:          #e387aa;
    --tool-color-fill:            #74dc6a;
    --tool-color-gradient:        #a898e7;
    --tool-color-shape:           #dca36a;
    --tool-color-eyedropper:      #6adcc5;
    --tool-color-selection:       #e17fd9;
    --tool-color-select-ellipse:  #b1dc6a;
    --tool-color-select-lasso:    #83a3e2;
    --tool-color-select-wand:     #e48b8f;
    --tool-color-select-cell:     #6adc87;
    --tool-color-text:            #be8fe5;
    --tool-color-pattern-creator: #dcc96a;
    --tool-color-zoom:            #6acedc;
    --tool-color-transform:       #e387bc;
    --tool-color-line:            #8bdc6a;

    /* Same system, continued for the top colour bar's icon buttons — draw
       modes, the two attribute ops (Swap/Recolour) and the Bright/Flash
       toggles. Golden-angle index picks up where the tool set left off. */
    --tool-color-dm-normal:       #9c9ce8;
    --tool-color-dm-ink:          #dd8f6e;
    --tool-color-dm-paper:        #6adcad;
    --tool-color-dm-pixel-only:   #d683e2;
    --tool-color-dm-xor:          #c9dc6a;
    --tool-color-attr-swap:       #6aa8dc;
    --tool-color-attr-recolour:   #e3879e;
    --tool-color-attr-bright:     #6adc6f;
    --tool-color-attr-flash:      #af94e6;

    /* Hairline around the picture itself, separating it from the ZX border
       colour that fills the rest of the canvas iframe. It follows the theme
       accent (every theme defines one), and CanvasSystem.syncBackdropColor
       mirrors the resolved value into the iframe — custom properties do not
       cross the srcdoc document boundary on their own. */
    --canvas-edge: var(--accent-primary);

    /* Canvas overlay colours — used by grid-overlay.js (read via getComputedStyle) */
    --overlay-handle-bg:        #ffffff;
    --overlay-handle-stroke:    rgba(0,0,0,0.7);
    --overlay-rotation-handle:  #ffcc00;
    --overlay-outline:          rgba(255,255,255,0.85);
    --overlay-outline-brush:    rgba(255,255,255,0.6);
    --overlay-info-bg:          rgba(0,0,0,0.65);
    --overlay-info-text:        #ffffff;
    /* The selection border overlays ZX artwork, not app chrome, so it does
       NOT vary per theme like the tokens around it — every ZX_PALETTE entry
       (constants.js) is built from {0, 215, 255} per channel, and #3399ff
       lands on none of them (its G channel, 153, is on no ZX entry), so the
       border stays visible against any colour the artist can actually draw. */
    --overlay-selection-border: #3399ff;
    --overlay-dim:              rgba(0,0,0,0.15);
    --overlay-selection-fill:   rgba(255,255,255,0.07);

    /* Grid overlay colours */
    --grid-pixel-color: #000000;
    --grid-cell-color:  #FF0000;
    --grid-block-color: #0000FF;

    /* ===== GLASSMORPHISM ===== */
    --glass-bg: rgba(26, 26, 26, 0.85);
    --glass-bg-solid: rgba(26, 26, 26, 0.95);
    --glass-border: rgba(255, 255, 255, 0.1);
    --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
    --glass-blur: blur(12px);

    /* ===== SPACING ===== */
    --space-xs: 4px;
    --space-sm: 8px;
    --space-md: 16px;
    --space-lg: 24px;
    --space-xl: 32px;

    /* ===== TYPOGRAPHY ===== */
    --font-family: 'Jura', 'Exo 2', system-ui, -apple-system, sans-serif;
    --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
    /* User-adjustable UI scale (set on :root by the header control + Ctrl-wheel).
       Drives `zoom` on every chrome region and multiplies the #app grid tracks,
       so the entire interface (icons, swatches, spacing, text) scales together
       while the drawing canvas keeps its own separate zoom. Default 1 = no change. */
    --ui-scale: 1;
    /* Legacy text-only scale. Kept at 1 — the UI now scales via --ui-scale/zoom,
       which already scales text, so this must not double-scale fonts. */
    --ui-font-scale: 1;
    --font-size-xs: calc(10px * var(--ui-font-scale));
    --font-size-sm: calc(12px * var(--ui-font-scale));
    --font-size-md: calc(14px * var(--ui-font-scale));
    --font-size-lg: calc(16px * var(--ui-font-scale));
    --font-size-xl: calc(20px * var(--ui-font-scale));
    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-bold: 700;
    --line-height: 1.5;

    /* ===== SIZING ===== */
    --toolbar-width: 128px;         /* 2-wide tool grid + padding + room for the vertical scrollbar */
    /* The one icon size shared by every fixed-size icon control app-wide:
       #color-rail's swatches/pickers/Bright-Flash AND #color-bar's draw
       modes/Mirror/Swap-Recolour/Border (--clut-btn-size, below, aliases
       this rather than carrying its own value — 2026-08-26, on request, the
       two regions used to size independently, deliberately; now they are
       meant to always match, so one token is the single source instead of
       two numbers someone has to remember to keep equal). [M] 2026-08-26,
       chosen to match the left tool rail's Ink/Paper preview wells
       (#color-preview .clut-preview, css/components.css), measured at
       53.5px at default settings — rounded to 54px. Every mode BELOW 256
       colours uses this size; the 256-entry indexed grid stays its own
       small "dense" size regardless (css/components.css .indexed-dense) —
       at this size 256 swatches would scroll for a very long way for no
       benefit, since there is no meaningful per-swatch detail to see at
       54px that isn't already visible at 18-22px. */
    --rail-icon-size: 54px;
    /* Swatch ROWS are one column (--rail-icon-size, above) and scroll for
       anything taller than the rail — but the ULAplus CLUT picker and the
       GigaScreen view picker (css/components.css .clut-picker/.giga-picker)
       are TWO columns of icons, and the rail has to be wide enough for
       whichever of its contents is widest, not just the swatches. The
       actual widest content is the ULAplus/ULANext divider pair (two
       --rail-icon-size channels + two 4px .clut-pair gaps either side of
       the divider + the divider itself, 1px plus 4px margin each side):
       54+4+(1+4+4)+4+54 = 125px [C] 2026-08-27 — 140px (2026-08-26's figure)
       covered only the plain two-icon-column case, 2x54+3=111px, and left
       the divider pair silently clipping 2px, undetected because the old
       width-sweep test measured #color-rail's own scrollWidth rather than
       the scrolling box's (#color-rail-content, css/layout.css) — masked
       by a browser quirk where a plain (non-overflow) wrapper's overflowing
       child does not register in an ancestor's scrollWidth the way an
       overflow-establishing one does. 125px content + padding (both sides)
       + border-right + a few px slack for zoom rounding + room for the
       vertical scrollbar (#color-rail-content sets scrollbar-width: thin,
       css/layout.css) leaves comfortable headroom at 148px; re-verify
       against tests/browser/color-rail.spec.js's per-mode width sweep
       before treating this as measured. */
    --colorrail-width: 148px;
    /* #color-bar's buttons/select (draw modes, Mirror, Swap/Recolour,
       Border) — aliases --rail-icon-size above, the single source, so the
       top strip and the rail can never drift out of sync with each other. */
    --clut-btn-size: var(--rail-icon-size);
    --panel-width: 280px;
    --header-height: 40px;
    --status-height: 24px;
    --panel-header-height: 32px;
    /* Minimum interactive-control hit size on coarse pointers (touch/pen).
       layout.css applies it under @media (pointer: coarse). */
    --hit-target: 44px;

    /* ===== BORDERS ===== */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-round: 50%;

    /* ===== TRANSITIONS ===== */
    --transition-fast: 100ms ease;
    --transition-normal: 200ms ease;
    --transition-slow: 300ms ease;

    /* ===== Z-INDEX LAYERS ===== */
    --z-canvas: 1;
    --z-grid: 2;
    --z-selection: 3;
    --z-cursor: 4;
    --z-panels: 10;
    --z-toolbar: 20;
    --z-header: 30;
    --z-dropdown: 40;
    --z-modal: 50;
    --z-tooltip: 60;
    --z-loading: 100;
}

/* Respect the user's reduced-motion preference: collapse the transition
   tokens to zero. (Canvas overlay animations run in the iframe via JS, not
   these CSS tokens, so functional cues like marching ants are unaffected.)
   The universal *,*::before,*::after !important override that actually
   enforces this for every element lives once, in reset.css. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --transition-fast: 0s;
        --transition-normal: 0s;
        --transition-slow: 0s;
    }
}

} /* @layer tokens */
