/**
 * THEME PALETTE + DERIVED ROLES
 * ============================================================================
 * A theme declares TWENTY values. Nothing else.
 *
 * It used to declare 62 roles, three times over — and 6 of the neutral pairs
 * were perceptually identical (#1a1a1a/#2a2a2a, #333333/#404040, …): 33 values
 * expressing 13 real levels. Every `-bg`, `-border`, `-hover` variant was
 * hand-written per theme, which is why adding one meant auditing 45 files.
 *
 * Layer 1 — PALETTE (per theme, 20 values)
 *   7 neutrals named by their place in the elevation stack, not by lightness,
 *   so the right one is obvious when writing a rule. 5 semantic hues. Plus 8
 *   chart series, which are a genuinely separate palette: a chart needs eight
 *   DISTINGUISHABLE colours and cannot borrow them from UI chrome.
 *
 *   Note that dark and light are MONOCHROME by design — their success/warning/
 *   error values are greys. That is a deliberate look, not missing colour;
 *   high-contrast is the theme that carries hue.
 *
 * Layer 2 — DERIVED ROLES (once, never per theme)
 *   The 54 roles components consume are computed from the palette with
 *   color-mix(). A theme never writes `--success-bg` again.
 *
 * Adding a theme = 20 lines. A user-defined theme = 20 form fields — which is
 * what makes that feature possible at all.
 *
 * Requires color-mix(): Chrome 111+, Safari 16.2+, Firefox 113+. The local
 * edition ships Electron 33, well past that.
 * ============================================================================
 */

/* ---------- DARK ---------- */
:root {
    /* Neutrals — elevation stack */
    --analysis-plot-bg: var(--n-canvas);
    --analysis-canvas-bg: var(--n-surface);
    --n-canvas: #1a1a1a;          /* page background */
    --n-surface: #2a2a2a;         /* panels, cards */
    --n-line: #404040;            /* borders */
    /* Bord et ombre des fenêtres (modaux) — sombre : un bord visible tiré du thème
       (le trait + 20 % du texte), une ombre plus dense. Les thèmes clairs remettent
       un bord transparent : l'ombre suffit sur fond clair. */
    --modal-edge: color-mix(in srgb, var(--n-line), var(--n-fg) 20%);
    --modal-shadow: rgba(0, 0, 0, 0.8);
    --n-dim: #b0b0b0;             /* secondary text */
    --n-fg: #e0e0e0;              /* primary text */

    /* Semantic */
    --accent: #888888;            /* interactive accent */
    --ok: #808080;                /* success */
    --warn: #a0a0a0;              /* warning */
    --err: #b0b0b0;               /* error */

    /* Chart series — a separate palette: charts need 8 distinguishable hues */
    --chart-series-1: #7ba3d8;
    --chart-series-2: #e8a87c;
    --chart-series-3: #7bc97b;
    --chart-series-4: #d4a85c;
    --chart-series-5: #b89cd8;
    --shadow-alpha: 0.40;         /* dark: shadows were 0.3/0.4/0.5 */

    /* La BANDE : ce que le pied de page (et toute bande d'extrémité) prend comme
       surface, comme encre et comme liseré. En sombre la page est déjà sombre,
       il n'y a rien à inverser : la bande est un panneau de la page, avec le
       filet de ses bordures. Les valeurs par thème vivent ICI, avec le reste de
       la palette — le composant ne porte aucune règle par thème. */
    --band-surface: var(--n-surface);
    --band-ink: var(--n-fg);
    --band-edge: var(--border);
}

/* ---------- LIGHT ---------- */
/* Encodage des états marche/arrêt — la valeur PLATE, volontairement plus
   sourde que `--ok` / `--err` : un interrupteur n'est pas une alerte. La
   doctrine qui l'accompagne (la couleur n'est jamais le seul canal ; la
   position du curseur et la bordure de l'actif portent l'état aussi) vit dans
   `_encoding.css`. */
:root {
    --signal-on: #2e9e4f;
    --signal-off: #c0392b;
}

[data-theme="light"] {
    --modal-edge: transparent;
    --modal-shadow: var(--shadow-tint-50);
    /* Neutrals — elevation stack */
    --analysis-plot-bg: var(--n-surface);
    --analysis-canvas-bg: var(--n-canvas);
    --n-canvas: #f5f5f5;          /* page background */
    --n-surface: #ffffff;         /* panels, cards */
    --n-line: #e0e0e0;            /* borders */
    --n-dim: #505050;             /* secondary text */
    --n-fg: #1a1a1a;              /* primary text */

    /* Semantic */
    --accent: #606060;            /* interactive accent */
    --ok: #505050;                /* success */
    --warn: #404040;              /* warning */
    --err: #303030;               /* error */

    /* Chart series — a separate palette: charts need 8 distinguishable hues */
    --chart-series-1: #4a7ab8;
    --chart-series-2: #d48a5c;
    --chart-series-3: #5ba95b;
    --chart-series-4: #b4884c;
    --chart-series-5: #9a7cb8;
    --shadow-alpha: 0.15;         /* light: 0.1/0.15/0.2 */

    /* En clair la bande est INVERSÉE : ardoise, encre claire (les valeurs de la
       palette marketing `--brand-slate` / `--brand-slate-ink`, qui garde la main
       sur ses pages). Son liseré prend la couleur de la surface : invisible. */
    --band-surface: #2d3748;
    --band-ink: #f5f5f5;
    --band-edge: var(--band-surface);
}

/* ---------- HIGH-CONTRAST ---------- */
[data-theme="high-contrast"] {
    /* Neutrals — elevation stack */
    --n-canvas: #000000;          /* page background */
    --n-surface: #0a0a0a;         /* panels, cards */
    --n-line: #ffffff;            /* borders */
    --n-dim: #e8e8e8;             /* secondary text */
    --n-fg: #ffffff;              /* primary text */

    /* Semantic */
    --accent: #ffd400;            /* interactive accent */
    --ok: #00e676;                /* success */
    --warn: #ffab00;              /* warning */
    --err: #ff5252;               /* error */

    /* Encodage des états marche/arrêt. Ce thème est le seul à les dériver :
       ses teintes sont plus franches que le vert et le rouge désaturés du
       défaut, et lui imposer ces derniers serait le rendre MOINS lisible —
       or c'est un thème d'accessibilité. Le reste de la doctrine (la forme
       porte l'état, jamais la couleur seule) vit dans `_encoding.css`. */
    --signal-on: var(--ok);
    --signal-off: var(--err);

    /* Chart series — a separate palette: charts need 8 distinguishable hues */
    --chart-series-1: #40c4ff;
    --chart-series-2: #ffab00;
    --chart-series-3: #00e676;
    --chart-series-4: #ffd400;
    --chart-series-5: #e040fb;
    --shadow-alpha: 1;            /* solid outline, no soft shadow */
}

/* ============================================================================
   DERIVED ROLES — declared ONCE. A theme never touches these.
   ========================================================================= */

:root {
    /* Collapsed from the palette — three fewer declared colours per theme.
       --n-sunken was a barely-contrasted surface and --n-muted a dimmed
       secondary text; both are mixes, not decisions. --info was a second blue
       doing --accent's job (151 uses against 774). */
    --n-sunken: color-mix(in srgb, var(--n-surface) 88%, var(--n-fg));
    --n-muted: color-mix(in srgb, var(--n-dim) 65%, var(--n-canvas));
    --info: var(--accent);


    /* Surfaces */
    --bg-primary: var(--n-canvas);
    --bg-secondary: var(--n-surface);
    --bg-panel: var(--n-surface);
    --bg-tertiary: var(--n-sunken);
    /* Une surface surélevée est une SURFACE, pas un trait. `var(--n-line)`
       marchait en sombre par coïncidence — l'ancien `--bg-elevated` y valait
       #404040, la couleur des bordures — et mentait partout ailleurs : #e0e0e0
       en clair là où il valait #ffffff avant, et #ffffff en contraste élevé, où
       --text-primary vaut lui aussi #ffffff (1,00:1, texte invisible sur les 88
       sites qui consomment ce rôle).

       Il n'existe pas de dérivation « un cran au-dessus de la surface » dans une
       palette à neuf couleurs : --n-line est PLUS CLAIRE que la surface en
       sombre et PLUS FONCÉE qu'elle en clair, donc aucun color-mix ne se
       comporte pareil dans les deux sens. Le rôle retombe donc sur --n-surface,
       ce qui restaure exactement la valeur d'avant en clair. */
    --bg-elevated: var(--n-surface);

    /* Text */
    --text-primary: var(--n-fg);
    --text-secondary: var(--n-dim);
    --text-tertiary: var(--n-muted);
    --text-inverse: var(--n-canvas);

    /* Borders */
    --border: var(--n-line);
    --border-color: var(--n-line);
    --border-light: color-mix(in srgb, var(--n-line) 55%, var(--n-canvas));
    --border-subtle: color-mix(in srgb, var(--n-line) 30%, transparent);
    --border-heavy: color-mix(in srgb, var(--n-line) 70%, var(--n-fg));

    /* Accent */
    /* --accent is a PALETTE token, declared per theme. Re-declaring it here
       as var(--accent) is a self-reference: CSS treats it as a cycle and the
       property becomes invalid, so every consumer fell back to nothing. */
    --color-primary: var(--accent);
    --color-secondary: var(--n-dim);
    --accent-hover: color-mix(in srgb, var(--accent) 85%, var(--n-fg));
    --accent-active: color-mix(in srgb, var(--accent) 70%, var(--n-canvas));
    --focus-ring: color-mix(in srgb, var(--accent) 60%, transparent);

    /* Semantics */
    --success: var(--ok);
    --color-success: var(--ok);
    --success-color: var(--ok);
    --success-dark: color-mix(in srgb, var(--ok) 80%, var(--n-canvas));
    --success-bg: color-mix(in srgb, var(--ok) 12%, var(--n-canvas));
    --success-border: color-mix(in srgb, var(--ok) 40%, var(--n-canvas));
    --warning: var(--warn);
    --warning-bg: color-mix(in srgb, var(--warn) 12%, var(--n-canvas));
    --warning-border: color-mix(in srgb, var(--warn) 40%, var(--n-canvas));
    --error: var(--err);
    --error-bg: color-mix(in srgb, var(--err) 12%, var(--n-canvas));
    --error-border: color-mix(in srgb, var(--err) 40%, var(--n-canvas));
    --info-bg: color-mix(in srgb, var(--info) 12%, var(--n-canvas));
    --info-border: color-mix(in srgb, var(--info) 40%, var(--n-canvas));

    /* Elevation */
    --overlay: color-mix(in srgb, var(--n-canvas) 90%, transparent);

    /* Charts */
    --chart-text: var(--n-fg);
    --chart-grid: var(--n-line);
    --chart-zeroline: color-mix(in srgb, var(--n-line) 70%, var(--n-fg));
    --chart-ramp-mid: color-mix(in srgb, var(--accent) 60%, var(--n-canvas));

    /* Optical canvas */
    --canvas-bg: var(--n-canvas);
    --canvas-grid: color-mix(in srgb, var(--n-fg) 5%, transparent);
    --canvas-axis: var(--n-fg);
    --canvas-axis-muted: var(--n-dim);
    --canvas-text: var(--n-fg);
    --canvas-text-muted: var(--n-dim);
    --canvas-label-bg: var(--n-sunken);
    --canvas-label-border: var(--n-line);
    --canvas-mirror: var(--n-muted);
    --canvas-mirror-back: color-mix(in srgb, var(--n-muted) 60%, var(--n-canvas));
    /* Plans de reference (plan image / plan objet) : un repere, pas une piece —
       gris attenue du theme, donc contraste sur les deux fonds sans etre lourd. */
    --canvas-reference-plane: var(--n-dim);

    /* Toggles — la piste d'un interrupteur est un ENCODAGE, pas du chrome :
       elle DIT lequel des deux mondes est actif. Les valeurs vivent donc dans
       `_encoding.css` (`--signal-on` / `--signal-off`) et NE SUIVENT PAS le
       thème, comme verre-vs-miroir. Les dériver ici de `--ok` / `--err` les
       faisait porter par une teinte volontairement désaturée — dark et light
       sont monochromes PAR CHOIX, cf. l'en-tête de ce fichier — et l'état
       ÉTEINT y contrastait plus que l'allumé. Les rôles de survol restent
       dérivés : un survol EST du chrome. */
    --toggle-on-color: var(--signal-on);
    --toggle-on-hover: color-mix(in srgb, var(--signal-on) 85%, var(--n-fg));
    --toggle-off-color: var(--signal-off);
    --toggle-off-hover: color-mix(in srgb, var(--signal-off) 85%, var(--n-fg));

    /* Scrims — the elevation/overlay ladder.
       441 rgba(0,0,0,α) and rgba(255,255,255,α) literals existed because the
       palette had no alpha token, spread over THIRTY-FIVE distinct alpha values.

       They derive from the FOREGROUND, not the canvas. A scrim exists to ADD
       CONTRAST — a shadow, a separator, a hover veil. Deriving it from the
       canvas made it match the background instead of contrasting with it, so
       in the light theme every shadow turned white-on-white and the auth
       header went invisible. Foreground-derived, a dark theme scrims light and
       a light theme scrims dark, which is what each one needs. */
    /* Shadows — same rule as the scrims: derived from the FOREGROUND so they
       stay visible in every theme. They were dropped entirely when this file
       was regenerated, which left `var(--shadow-lg)` unresolved across the app. */
    /* Shadows are BLACK in every theme. A drop shadow simulates occlusion —
       light is blocked — and occlusion does not invert with the palette. Only
       its STRENGTH varies, which is what --shadow-alpha carries (the original
       design used 0.3/0.4/0.5 in dark and 0.1/0.15/0.2 in light).

       Deriving them from --n-fg, as the scrims are, turned every shadow into a
       white glow in the dark theme and the header lost its only separation
       from the page. Scrims and shadows are NOT the same thing: a scrim
       contrasts with the background, a shadow darkens it. */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, calc(var(--shadow-alpha) * 0.75));
    --shadow-md: 0 4px 6px rgba(0, 0, 0, var(--shadow-alpha));
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, calc(var(--shadow-alpha) * 1.25));

    --scrim-05: color-mix(in srgb, var(--n-fg) 5%, transparent);
    --scrim-10: color-mix(in srgb, var(--n-fg) 10%, transparent);
    --scrim-20: color-mix(in srgb, var(--n-fg) 20%, transparent);
    --scrim-30: color-mix(in srgb, var(--n-fg) 30%, transparent);
    --scrim-50: color-mix(in srgb, var(--n-fg) 50%, transparent);

    /* Semantic tints — a role at low opacity, for highlight backgrounds.
       Same story: 311 tinted rgba() existed for want of these. */
    --accent-tint: color-mix(in srgb, var(--accent) 15%, transparent);
    --success-tint: color-mix(in srgb, var(--ok) 15%, transparent);
    --warning-tint: color-mix(in srgb, var(--warn) 15%, transparent);
    --error-tint: color-mix(in srgb, var(--err) 15%, transparent);
    --info-tint: color-mix(in srgb, var(--info) 15%, transparent);

    /* ── Legacy aliases ──────────────────────────────────────────────────
       Names that predate the role vocabulary and are still referenced across
       auth/ and the plugin pages, usually as `var(--old, <fallback>)`.

       They MUST be defined here. When the outer variable is undefined the
       fallback carries the value — and the colour codemod rewrote those
       fallbacks by nearest colour, without seeing that a fallback belongs to
       the semantics of the OUTER variable. That turned
       `color: var(--text-primary, #2d3748)` into a fallback holding a
       BACKGROUND colour, and the auth header went invisible.

       Defining the outer names makes the fallback unreachable, which fixes the
       whole class at once instead of auditing 1083 call sites. */
    --primary-color: var(--accent);
    --primary: var(--accent);
    --primary-dark: var(--accent-active);
    --accent-color: var(--accent);
    --accent-primary: var(--accent);

    --text-color: var(--text-primary);
    --text-muted: var(--text-tertiary);
    --text-primary-dark: var(--text-primary);
    --color-text-primary: var(--text-primary);
    --color-text-secondary: var(--text-secondary);

    --background: var(--bg-secondary);
    --background-secondary: var(--bg-primary);
    --color-background: var(--bg-primary);
    --color-surface: var(--bg-secondary);
    --card-bg: var(--bg-secondary);
    --bg-hover: var(--bg-tertiary);

    --color-border: var(--border);
    --border-secondary: var(--border);
    --border-color-dark: var(--border-heavy);

    --danger: var(--error);
    --danger-color: var(--error);
    --error-color: var(--error);
    --color-error: var(--error);
    --color-warning: var(--warning);
    /* Le pendant de --success-color / --error-color, absent de la serie.
       Quatre regles l'utilisent ; sans declaration la valeur est invalide
       et `border-left: 4px solid var(--warning-color)` devient `none`. */
    --warning-color: var(--warn);

    /* ── Structure ───────────────────────────────────────────────────────
       Spacing, radii, type scale, transitions, z-index. NOT part of the
       theme contract — they do not vary per theme — but they were dropped
       when this file was regenerated from the palette, leaving ~2850
       `var(--space-*)` / `var(--radius-*)` references unresolvable and the
       whole layout collapsing. Restored verbatim from the pre-refactor file. */
    --hover-opacity: 0.8;
    --active-opacity: 0.6;
    --disabled-opacity: 0.4;
    --transition-fast: 0.15s ease;
    --transition-base: 0.2s ease;
    --transition-normal: 0.3s ease;
    --transition-slow: 0.5s ease;
    --space-xs: 4px;
    --space-sm: 8px;
    --space-md: 12px;
    --space-lg: 16px;
    --space-xl: 20px;
    --space-2xl: 24px;
    --space-3xl: 32px;
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 8px;
    --radius-xl: 12px;
    --radius-2xl: 16px;
    --radius-round: 50%;
    --radius-pill: 999px;        /* forme allongée (pilule, barre de progression) ; --radius-round = cercle */
    --column-left-width: 25%;
    --column-middle-width: 25%;
    --column-right-width: 50%;
    --gap-size: 0;
    --header-height: 80px;
    /* Les surcouches flottantes du VISUALISEUR — règle de rayons, règle
       d'échelle, barre d'infos, bascule de vignettage, zone de dépôt, menu de
       variante. Elles doivent rester SOUS l'en-tête, et le piège mérite d'être
       écrit : `.app-header` est un ÉLÉMENT FLEX (son parent `.oa-container` est
       en `display: flex`), et un élément flex portant un `z-index` crée un
       contexte d'empilement MÊME en `position: static`. L'en-tête vaut donc 100
       pour de vrai, et le menu de navigation qu'il contient — `fixed`,
       `z-index: 1002` — est ENFERMÉ dedans : son 1002 ne l'ordonne qu'à
       l'intérieur de l'en-tête. Les six surcouches étaient à 100 elles aussi,
       donc à égalité avec l'en-tête, et l'ordre du DOM tranchait en leur faveur
       puisque le visualiseur vient après. Mesuré le 2026-08-20 : monter le menu
       à 999999 ne changeait rien, seul descendre la surcouche corrigeait.
       60 : au-dessus de tout ce qui vit dans le visualiseur (51 au plus haut),
       sous l'en-tête. */
    --z-viewer-overlay: 60;
    --z-app-header: 100;
    --z-dropdown: 1000;
    --z-sticky: 1020;
    --z-fixed: 1030;
    --z-modal-backdrop: 9990;
    --z-modal: 10000;
    --z-modal-content: 10001;
    --z-popover: 10010;
    --z-tooltip: 10020;
    --z-notification: 10030;
    --icon-filter: none;
    --icon-opacity: 1;

    /* Form fields — the only variables auth-overrides.css owned that the
       derived layer did not already provide. Rescued before deleting it. */
    --input-bg: var(--bg-secondary);
    --input-border: var(--border);
    --input-text: var(--text-primary);
    /* Shadow tints — black at fixed alphas, for the box-shadow sites whose
       offsets differ from the three --shadow-* presets. Black by design, so
       they are NOT theme colours and NOT part of the contract. */
    --shadow-tint-08: rgba(0, 0, 0, 0.08);
    --shadow-tint-12: rgba(0, 0, 0, 0.12);
    --shadow-tint-20: rgba(0, 0, 0, 0.2);
    --shadow-tint-30: rgba(0, 0, 0, 0.3);
    --shadow-tint-50: rgba(0, 0, 0, 0.5);
}

/* Official seasonal palettes. Decoration geometry lives in _seasonal.css. */
[data-theme="halloween"] {
    --n-canvas: #19151f;
    --n-surface: #272031;
    --n-line: #46394f;
    --n-dim: #bcaec6;
    --n-fg: #f5edf5;
    --accent: #f2a052;
    --ok: #7bc997;
    --warn: #e9bd65;
    --err: #ef929e;
    --chart-series-1: #7ba3d8;
    --chart-series-2: #e8a87c;
    --chart-series-3: #7bc97b;
    --chart-series-4: #d4a85c;
    --chart-series-5: #b89cd8;
    --decor-tint: #bca1d4;
    color-scheme: dark;
}

[data-theme="christmas"] {
    --n-canvas: #131f1d;
    --n-surface: #1e302b;
    --n-line: #3e5750;
    --n-dim: #adc5b9;
    --n-fg: #f2f5ed;
    --accent: #e7b967;
    --ok: #83c9a1;
    --warn: #e9bd65;
    --err: #ef929e;
    --chart-series-1: #7ba3d8;
    --chart-series-2: #e8a87c;
    --chart-series-3: #7bc97b;
    --chart-series-4: #d4a85c;
    --chart-series-5: #b89cd8;
    --decor-tint: #d9c78e;
    color-scheme: dark;
}

[data-theme="easter"] {
    --modal-edge: transparent;
    --modal-shadow: var(--shadow-tint-50);
    --n-canvas: #f6f2fa;
    --n-surface: #ffffff;
    --n-line: #d4c6df;
    --n-dim: #675674;
    --n-fg: #30253d;
    --accent: #7952a3;
    --ok: #267648;
    --warn: #8a5d10;
    --err: #b43f56;
    --chart-series-1: #4a7ab8;
    --chart-series-2: #d48a5c;
    --chart-series-3: #5ba95b;
    --chart-series-4: #b4884c;
    --chart-series-5: #9a7cb8;
    --decor-tint: #9b71b9;
    --shadow-alpha: 0.15;
    --analysis-plot-bg: var(--n-surface);
    --analysis-canvas-bg: var(--n-canvas);
    color-scheme: light;
}
