/**
 * V2T Design System, token contract.
 * Light Glass: Precision Industrial x Future Tech
 *
 * COPIED VERBATIM from docs/V2T_DESIGN_SYSTEM.md section 3. Do not edit values here.
 * This file is the contract; if a value needs to change, that is a change to the
 * design system applied V2T-wide, not a local edit. Domain additions go in
 * tokens.domain.css, which loads immediately after this file.
 *
 * Must be the first stylesheet loaded.
 */
:root {
    /* ---- Brand accent (teal). Contrast ratios measured against #FFFFFF.
           See 6.2: this ramp is LIGHT. Only the -darker stop is text-safe. ---- */
    --color-primary:        #00D4AA;   /* 1.91:1  large fills w/ dark text, dark-theme accents */
    --color-primary-dark:   #00A888;   /* 3.02:1  borders + focus rings on light. NOT text */
    --color-primary-darker: #007A63;   /* 5.30:1  the text stop. Links, labels, active nav */
    --color-primary-light:  #33DDB9;   /* 1.72:1  dark-theme focus ring, subtle hover only */

    /* ---- AI voice (electric violet). Machine-generated content only ---- */
    --color-ai:       #A855F7;
    --color-ai-dark:  #9333EA;
    --color-ai-light: #C084FC;         /* SOLID swatch: text + gradients only */
    --color-ai-tint:  rgba(168, 85, 247, 0.08);  /* panel backgrounds carrying body copy */

    /* ---- Semantic ---- */
    --color-success:  #00D68F;
    --color-warning:  #FFB020;
    --color-danger:   #FF4757;
    --color-critical: #FF4757;         /* alias of danger */
    --color-info:     #4DA6FF;

    /* Soft surfaces. Formula: rgba(<accent>, 0.15). See 6.4 */
    --color-success-light: rgba(0, 214, 143, 0.15);
    --color-warning-light: rgba(255, 176, 32, 0.15);
    --color-danger-light:  rgba(255, 71, 87, 0.15);
    --color-info-light:    rgba(77, 166, 255, 0.15);

    /* The DEEP STOP of each semantic. Two roles, both verified (see 6.2):
         1. text on that semantic's tint      (>= 4.5:1)
         2. solid fill under WHITE text       (>= 4.5:1)
       The signal colours above are too light for either. Never put words in
       --color-success and never put white text on it. */
    --color-success-text: #047857;   /* on tint 4.89:1 | white on it 5.48:1 */
    --color-warning-text: #B45309;   /* on tint 4.57:1 | white on it 5.02:1 */
    --color-danger-text:  #B91C1C;   /* on tint 5.36:1 | white on it 6.47:1 */
    --color-info-text:    #1E40AF;   /* on tint 7.66:1 | white on it 8.72:1 */

    /* ---- Neutral ramp. Inverts wholesale in dark theme. See Section 4 ---- */
    --color-charcoal:  #0D1517;
    --color-gray-900:  #1A2224;
    --color-gray-800:  #2D3436;
    --color-gray-700:  #4A5568;
    --color-gray-600:  #718096;
    --color-gray-500:  #A0AEC0;
    --color-gray-400:  #CBD5E0;
    --color-gray-300:  #E2E8F0;
    --color-gray-200:  #EDF2F7;
    --color-gray-100:  #F7FAFC;
    --color-gray-50:   #FCFDFE;
    --color-white:     #FFFFFF;
    --color-off-white: #F8FAFA;

    /* ---- Semantic surface aliases. Application CSS consumes THESE, not the
           raw ramp, wherever the meaning is "a surface" rather than "a shade". */
    --color-surface:        var(--color-white);
    --color-surface-hover:  var(--color-gray-100);   /* visible row/hover wash */
    /* "Nothing here" surfaces: empty states, disabled fills, a canvas ground.
       Derived from the neutral ramp so it inverts with the theme like every other
       neutral. Declared HERE and not in base.css, which is where it used to live
       with its own dark branch: a token definition and a theme branch, both in
       component CSS, both DESIGN 17 items. */
    --color-surface-sunken: var(--color-gray-100);
    --color-bg:             var(--color-off-white);
    --color-border:         var(--color-gray-200);
    --color-border-hover:   var(--color-gray-300);

    /* Text roles are NOT aliases of the grey ramp: the ramp's mid stops fail AA
       on white (gray-600 = 4.02:1, gray-500 = 2.26:1). These are pinned to the
       lightest value that still clears 4.5:1. See 6.2. */
    --color-text:           var(--color-charcoal);   /* 18.47:1 */
    --color-text-secondary: #5A6B7F;                 /*  5.46:1 */
    --color-text-muted:     #6E7781;                 /*  4.55:1 */

    /* THE ACCENT AS TEXT, WHICH IS A DIFFERENT STOP IN EACH THEME.
       ------------------------------------------------------------------------
       DESIGN 6.2 gives the light-theme answer in a table and the dark-theme answer
       in a sentence: "On dark surfaces the relationship reverses: --color-primary
       measures 8.60:1 on --color-surface, so it is the correct accent there and
       needs no substitution." Both halves are true and the contract only ever
       encoded the first, so every component that wanted an accent-coloured word
       reached for --color-primary-darker and was correct on white and wrong on the
       dark surface.

       Measured in a browser, dark theme, against the real backdrop: the -darker
       stop lands at 3.10:1 on --color-surface and 2.89:1 on --color-surface-sunken.
       Both fail AA for body text outright. That was every link in the product, the
       active rail label, the sortable header hover, the powered-bay marker and the
       floor map's disclosure, on a theme one seeded role runs by default.

       This is the same correction DESIGN 3.4 records for --color-*-text: components
       were hand-rolling a WCAG-safe value that was invisible to theming. The accent
       had exactly that problem and no such token. It belongs HERE and not in a
       component, because DESIGN 4.1 is explicit that a per-component dark override
       is a signal that the component used a raw value. Components consume one name
       and get both themes for free. */
    --color-accent-text:    var(--color-primary-darker);   /* 5.30:1 on white */

    /* ---- Chart series. Seven, solved, and reserved hues avoided ----
       SOLVED, NOT CHOSEN BY EYE. Same binary search and the same interval as the
       client colours: contrast on white fixed at 4.2, the middle of [3.2, 5.2],
       which guarantees at least 3:1 on the dark surface too, so one value serves
       both themes. See DevOps/scripts/solve_client_colours.py; check_contrast
       asserts every one of these.

       TWO NEIGHBOURHOODS ARE OUT OF BOUNDS. Nothing within 30 degrees of the AI
       violet at 285, because a chart series that reads as machine-generated content
       cheapens the one marking that means something. Nothing within 25 degrees of
       the brand teal at 165, because a category must not read as the brand. That
       leaves 0 to 140, 190 to 255 and 315 to 360, and the seven hues are spread at
       roughly forty degrees through what is left.

       COLOUR IS NEVER THE ONLY CARRIER. Every series is labelled in a legend, and
       the chart tag refuses to render one without. Seven hues is already more than
       a reader can hold, and a monochrome printout has to work. */
    --color-series-1: #DF4426;   /* hue  10 */
    --color-series-2: #9C760F;   /* hue  44 */
    --color-series-3: #5E8720;   /* hue  84 */
    --color-series-4: #298D30;   /* hue 124 */
    --color-series-5: #1E84B6;   /* hue 200 */
    --color-series-6: #7070DD;   /* hue 240 */
    --color-series-7: #DB3F7D;   /* hue 336 */

    /* The series a chart element is drawing, set inline per element by the chart tag
       from one of the seven above. Declared here with a default so it resolves even
       if something renders a chart element outside the tag, and so check_design can
       see that --series is a real token rather than a typo. */
    --series: var(--color-series-1);

    /* ---- Typography ---- */
    --font-display: 'DM Serif Display', Georgia, serif;
    --font-body:    'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    --font-mono:    'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace;

    /* The density extension, DESIGN 16.4. Dense metadata only: a basis line under a
       charge, a rail-capacity note, a legend key. Never body copy and never a label
       somebody has to act on.

       ADDED IN P6, AND IT WAS ALREADY BEING USED. Fifteen rules across the
       stylesheet referenced --text-2xs while nothing defined it, so every one of
       them resolved to an invalid font-size and silently inherited its parent. The
       affected text was not broken, it was simply not smaller, which is exactly the
       kind of failure that never gets reported. */
    --text-2xs:  0.6875rem;  /* 11px */
    --text-xs:   0.75rem;    /* 12px */
    --text-sm:   0.875rem;   /* 14px */
    --text-base: 1rem;       /* 16px */
    --text-lg:   1.125rem;   /* 18px */
    --text-xl:   1.25rem;    /* 20px */
    --text-2xl:  1.5rem;     /* 24px */
    --text-3xl:  1.875rem;   /* 30px */
    --text-4xl:  2.25rem;    /* 36px */

    --leading-tight:   1.2;   /* headings */
    --leading-snug:    1.3;   /* dialog titles, dense labels */
    --leading-normal:  1.5;   /* body */
    --leading-relaxed: 1.55;  /* long-form prose */

    --font-light:    300;
    --font-normal:   400;
    --font-medium:   500;
    --font-semibold: 600;
    --font-bold:     700;

    /* ---- Spacing. 0.25rem step ---- */
    --space-0:  0;
    --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;

    /* ---- Radius ---- */
    --radius-sm:   4px;
    --radius-md:   8px;
    --radius-lg:  12px;
    --radius-xl:  16px;
    --radius-full: 9999px;

    /* ---- Elevation ---- */
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1),  0 1px 2px rgba(0, 0, 0, 0.06);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
    --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
    --shadow-glow-primary: 0 0 20px rgba(0, 212, 170, 0.3);
    --shadow-glow-ai:      0 0 20px rgba(168, 85, 247, 0.3);

    /* ---- Gradients ----
       The unsuffixed pair spans the full brand range and is DECORATIVE: it must
       not carry white text, because its light stop measures 1.91:1 (teal) and
       2.64:1 (violet) against white. The -safe pair is the one for filled
       controls; both stops clear 4.5:1. See 6.2 and 7.1. */
    --gradient-primary:      linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-darker) 100%);
    --gradient-ai:           linear-gradient(135deg, var(--color-ai-light) 0%, var(--color-ai-dark) 100%);
    --gradient-primary-safe: linear-gradient(135deg, var(--color-primary-darker) 0%, #005E4C 100%);
    --gradient-ai-safe:      linear-gradient(135deg, var(--color-ai-dark) 0%, #7E22CE 100%);
    --gradient-glass:        linear-gradient(135deg, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0.05) 100%);

    /* A --gradient-primary-bright (--color-primary to --color-primary-dark, carrying
       BLACK text at 11.00:1 and 6.96:1) briefly lived here, so the primary button
       could be the bright brand teal rather than the flat dark green white text
       forces it to be. It was removed when the product chose white text.

       Recorded rather than deleted silently, because the measurement is the useful
       part and it will be asked again: a filled control can be bright teal, or it
       can carry white text. It cannot do both. White needs 4.5:1 and measures
       1.91:1 on --color-primary and 3.02:1 on --color-primary-dark, and the
       brightest teal that carries white at AA is --color-primary-darker, which is
       where --gradient-primary-safe already starts. DESIGN 7.1's "the button takes
       dark text" is the only door out, and this product does not take it.

       Do not reintroduce the token without a caller. DESIGN 17: one canonical name
       per value, and a token nothing uses is drift waiting to be miscopied. */

    /* ---- Motion ---- */
    --transition-fast:   150ms ease;   /* colour, opacity, small state flips */
    --transition-normal: 200ms ease;   /* default */
    --transition-slow:   300ms ease;   /* panel slide, entrance */
    --ease-entrance: cubic-bezier(0.2, 0.7, 0.2, 1);

    /* ---- Z-index. One named slot per real layer. Never use a bare number. ---- */
    --z-base:      0;
    --z-raised:    1;
    --z-dropdown:  100;
    --z-sticky:    200;
    --z-nav:       300;
    --z-drawer:    1000;
    --z-modal:     9000;
    --z-toast:     9999;
    /* Within-container layering. A label drawn over a canvas and a tip that has
       to clear that label are still layers, and a bare 2 or 5 in component CSS is
       still a bare z-index. Named generically rather than after the floor map, so
       the next component that needs to sit over its own siblings has a slot. */
    --z-overlay:   2;
    --z-tooltip:   5;
    --z-dialog:    10001;  /* branded alert/confirm/prompt: above everything */

    /* ---- Layout ---- */
    --nav-height:        64px;
    --sidebar-width:    280px;
    --content-max-width: 1440px;

    /* The vendor signature at the foot of the rail. A TOKEN AND NOT A NUMBER
       because two rules have to agree on it and they are 1600 lines apart: the
       footer sets its own height and the rail subtracts the same value from its
       own. Two literals that must match is one literal that will not, and the
       failure mode is a signature drawn over the last three navigation links,
       which are the three the projector measurement already found to be the ones
       that fall off the bottom.

       The projector value is smaller and is set with the rest of the rail's
       compression under max-height: 800px in base.css, not here, so the two halves
       of that decision stay in one place. */
    --footer-height:     52px;  /* MEASURED, not chosen: check_p14_chrome reads the block back */

    /* ---- Inheritance affordances: dotted = inherited, solid = overridden ---- */
    --color-inherited-border: var(--color-border);
    --color-override-border:  var(--color-primary);
    --color-override-tint:    rgba(0, 212, 170, 0.06);
}

/* Applied via body[data-theme="dark"] at runtime and
   html[data-theme-loading="dark"] pre-paint. Both selectors are required. */
body[data-theme="dark"],
html[data-theme-loading="dark"] {
    /* The neutral ramp INVERTS. No new token names are introduced. */
    --color-charcoal:  #e8ecf1;
    --color-gray-900:  #f1f5f9;
    --color-gray-800:  #e2e8f0;
    --color-gray-700:  #cbd5e1;
    --color-gray-600:  #94a3b8;
    --color-gray-500:  #64748b;
    --color-gray-400:  #475569;
    --color-gray-300:  #334155;
    --color-gray-200:  #253042;
    --color-gray-100:  #1e2535;
    --color-gray-50:   #161b27;
    --color-white:     #1a1f2e;
    --color-off-white: #0f1219;

    --color-surface:        #1a1f2e;
    --color-surface-hover:  #212838;
    --color-surface-sunken: #1e2535;
    --color-bg:             #0f1219;
    --color-border:         #253042;
    --color-border-hover:   #334155;
    --color-text:           #e8ecf1;   /* 13.83:1 on surface */
    --color-text-secondary: #94a3b8;   /*  6.40:1 */
    --color-text-muted:     #7C8CA0;   /*  4.78:1. #64748b was 3.45:1 and failed AA */

    /* The reversal DESIGN 6.2 describes. The bright stop is the legible one here:
       8.60:1 on --color-surface, against the -darker stop's 3.10:1. This is the
       whole reason the token exists; see the note beside its light-theme value. */
    --color-accent-text:    var(--color-primary);   /* 8.60:1 on surface */

    /* Legible-on-tint text brightens; the dark hexes above would vanish. */
    --color-success-text: #34D399;
    --color-warning-text: #FBBF24;
    --color-danger-text:  #FCA5A5;
    --color-info-text:    #93C5FD;

    /* Shadows deepen against dark backgrounds. */
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.2);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3),  0 1px 2px rgba(0, 0, 0, 0.2);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3),  0 2px 4px rgba(0, 0, 0, 0.2);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.35), 0 4px 6px rgba(0, 0, 0, 0.2);
    --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.4),  0 10px 10px rgba(0, 0, 0, 0.2);

    --gradient-glass: linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%);

    /* Tints brighten so they stay perceptible on a dark surface. */
    --color-success-light: rgba(0, 214, 143, 0.20);
    --color-warning-light: rgba(255, 176, 32, 0.20);
    --color-danger-light:  rgba(255, 71, 87, 0.20);
    --color-info-light:    rgba(77, 166, 255, 0.20);
    --color-ai-tint:       rgba(168, 85, 247, 0.16);
    --color-override-tint: rgba(0, 212, 170, 0.12);
}
