/* ============================================================
   CareerToolbox.AI - Unified Stylesheet
   ============================================================

   DESIGN SYSTEM: Voir design-system.css pour la documentation
   complete des variables, patterns et guidelines.

   REGLES:
   - Utiliser uniquement les variables CSS definies dans :root
   - Ne jamais hardcoder de couleurs (#xxx) dans les composants
   - Respecter les rayons (--radius-*) et ombres (--shadow-*)
   - Consulter design-system.css avant toute modification

   ============================================================ */

:root {
  /* Safe area insets (for mobile notch/home indicator) */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);

  /* Typography */
  --font-body: 'Outfit', ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Fira Code', monospace;

  /* Type scale */
  --text-2xs: 0.625rem;   /* 10px — micro labels (overlines, status pills, keyboard hint) */
  --text-xs: 0.75rem;     /* 12px */
  --text-sm: 0.8125rem;   /* 13px */
  /* Letter spacing tokens — Sprint 1.A.1 audit fix */
  --letter-tight: 1.2px;  /* uppercase overlines (e.g. UPPERCASE LABELS in cd-grid, cd-comms-status) */
  --letter-loose: 1.6px;  /* uppercase headlines (e.g. KPI tile titles) */
  --text-base: 0.875rem;  /* 14px */
  --text-md: 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 */

  /* Spacing scale */
  --space-2xs: 2px;
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px;
  --space-4: 16px; --space-5: 20px; --space-6: 24px;
  --space-7: 32px; --space-8: 48px; --space-9: 64px;

  /* Border widths (semantic, theme-agnostic) */
  --border-width-hairline: 1px;  /* conventional hairline divider / cell border */
  --border-width-medium: 2px;    /* tab underline, stepper dot/connector */
  --border-accent-width: 3px;    /* accent filet on calm encarts / coverage rails */

  /* Interaction sizing */
  --touch-target-min: 44px;      /* WCAG 2.5.5 minimum touch target */
  --focus-ring-spread: 3px;      /* focus halo spread (matches --shadow-focus) */

  /* Layout breakpoints — single source. CSS @media cannot consume custom properties, so the
     module media queries keep the literal value with a comment referencing the token below; these
     are here for documentation + JS matchMedia reuse. */
  --bp-mobile: 480px;
  --bp-mobile-wide: 600px;
  --bp-tablet: 768px;
  --bp-desktop: 1024px;

  /* ATSIQ candidate module — component dimensions (theme-agnostic) */
  --candidate-card-panel-max: 960px;     /* person-card drawer max width */
  --candidate-card-avatar: 5rem;         /* hero avatar (= loading skel--a height) */
  --candidate-card-action-min: 10.5rem;  /* action-bar grid column min */
  --candidate-field-min: 4rem;           /* textarea / consider hint min height */
  --candidate-select-basis: 12rem;       /* consider job-picker flex-basis */
  --candidate-select-min: 10rem;         /* consider job-picker min width */
  --candidate-mini-panel-max: 560px;     /* mini-modal : largeur PLANCHER (confort de lecture) */
  --candidate-mini-panel-wide: 860px;    /* mini-modal : plafond hérité (2026-07-31) — conservé, plus consommé par le panneau */
  /* P3 L3① (§18.10, `F-023`/`F-149`/`F-186`) — plafond de la fiche PAR RÔLE. Le panneau s'élargit,
     et c'est `.ct-mini-prose` (--candidate-mini-prose-max) qui borne la mesure de LIGNE : la
     dissociation prose/blocs remplace le plafond unique. */
  --candidate-mini-panel-xwide: 1180px;
  --candidate-mini-prose-max: 68ch;      /* mini-modal : mesure de ligne du texte suivi */
  --candidate-mini-score-font: 2.75rem;  /* mini-modal hero score (hors échelle) */
  --candidate-step-dot: 1.1rem;          /* stepper dot diameter */
  --candidate-step-connector: 0.5rem;    /* stepper connector vertical offset (dot radius) */
  --candidate-header-icon: 2.5rem;       /* candidates-pane header icon box */
  --candidate-skel-row: 64px;            /* list skeleton row height */
  --candidate-skel-sm: 2rem;             /* skeleton bar heights */
  --candidate-skel-md: 4rem;
  --candidate-skel-lg: 6rem;
  --candidate-skel-xl: 9rem;
  --candidate-skel-2xl: 12rem;

  /* Background palette — V2: deeper, more atmospheric */
  --bg-abyss: #020307;
  --bg0: #050810;
  --bg1: #080d1a;
  --bg2: #0c1222;
  --card: rgba(20,30,52,0.72);
  --card2: rgba(26,38,62,0.76);
  --card-hover: rgba(26,38,62,0.55);
  --text: #f1f5f9;
  /* WCAG AA: Contrast ratio minimum 4.5:1 */
  --muted: rgba(241,245,249,0.82);
  --btn: rgba(99,102,241,0.20);
  --btn2: rgba(99,102,241,0.32);
  /* Primary: Indigo - deeper & more professional */
  --accent: #6366f1;
  --accent-light: #818cf8;
  --accent-dark: #4f46e5;
  /* --accent COMME COULEUR DE TEXTE (R3, promu ici au re-gate P2-Z pour da-11) : en Obsidian
     l'accent natif #6366f1 sur les fonds sombres ne fait que 3,3-3,9:1 — SOUS AA. Tout texte
     ou glyphe accentué passe par --accent-text ; l'accent natif reste réservé aux APLATS.
     Le token vivait dans components-recruiter.css (kit recruteur) : les surfaces globales qui
     en avaient besoin (`.btn--help` de components.css, `.rdash-rec__fees` du tableau de bord)
     ne pouvaient pas le consommer sur les shells qui ne chargent pas cette feuille. Déclaré
     une seule fois PAR THÈME ici et dans atsiq-theme.css — jamais dupliqué ailleurs.
     Obsidian, --accent-light #818cf8 : 6,50:1 sur --bg1 · 5,86:1 sur --card · 5,45:1 sur --card2. */
  --accent-text: var(--accent-light);
  /* Secondary: Cyan - tech accent */
  --accent2: #22d3ee;
  --accent2-light: #67e8f9;
  --accent2-rgb: 34, 211, 238;
  /* Tertiary: Amber for highlights (unchanged) */
  --accent3: #fbbf24;
  /* Semantic colors */
  --info: rgba(59,130,246,0.18);
  --info-text: #60a5fa;
  --danger: rgba(244,63,94,0.18);
  --danger-text: #fb7185;
  /* Solid destructive controls carrying white text need the deeper AA-safe red. */
  --danger-solid-contrast: #b91c1c;
  --success: rgba(34,197,94,0.18);
  --success-text: #4ade80;
  --warning: rgba(251,191,36,0.18);
  --warning-text: #fbbf24;
  /* Shadows and effects — V2: deeper shadows, sharper corners */
  --shadow: 0 25px 50px -12px rgba(0,0,0,0.55);
  --shadow-sm: 0 10px 25px -5px rgba(0,0,0,0.40);
  --shadow-glow: 0 0 40px rgba(139,92,246,0.18);
  --radius: 14px;
  --radius-sm: 10px;
  --radius-lg: 20px;
  /* Opaque backgrounds — V2: violet-tinted */
  --bg-opaque: rgba(8, 13, 26, 0.97);
  --bg-opaque-light: rgba(12, 18, 36, 0.94);
  --bg-popup: linear-gradient(170deg, rgba(28,42,65,0.98) 0%, rgba(18,28,45,0.98) 100%);
  --border: rgba(139,92,246,0.10);
  --line: var(--border); /* F-1248: hairline divider alias */
  --border-accent: rgba(139,92,246,0.35);
  /* Resting outline for secondary (plain) `.btn` pills. On Obsidian the violet-tinted --border
     (10% alpha) was too faint and the pill outline vanished on dark; a neutral text-based tone
     keeps it visible. Light themes (Bento/ATSIQ) override this back to --border (already visible). */
  --btn-border: rgba(var(--text-rgb), 0.22);
  /* L2 T2.7 — canon disabled opacity (promotion de .btn:disabled F-1612, seule
     valeur théme-neutre déjà cohérente sur 90% des sites disabled du repo). */
  --btn-disabled-opacity: 0.5;
  /* L2 — button variant tokens (D-2 : 1 définition par variante, thémée par
     remap de tokens plutôt que par re-déclaration de sélecteur). Valeurs
     ci-dessous = extraction verbatim des règles Obsidian de components.css
     pré-L2. Remaps par thème : voir body.bento-theme (variables.css) et
     html.atsiq-theme (atsiq-theme.css). */
  --btn-secondary-bg: rgba(var(--accent-rgb), 0.08);
  --btn-secondary-border: 1px solid rgba(var(--accent-rgb), 0.18);
  /* P3 FIX-R ter L1/L3 (`GAt-1`) — L'ENCRE DES COMMANDES SECONDAIRES PASSE PAR --accent-text.
     La doctrine est écrite 45 lignes plus haut, à la déclaration du jeton : « en Obsidian
     l'accent natif #6366f1 sur les fonds sombres ne fait que 3,3-3,9:1 — SOUS AA. Tout texte
     ou glyphe accentué passe par --accent-text ; l'accent natif reste réservé aux APLATS. »
     `--btn-link-fg` a été migré pour EXACTEMENT ce motif (P2-Z 1b-E, ci-dessous) ; `secondary`
     avait été oublié. Mesure du re-juge ter sur la fiche par rôle, thème sombre, au pixel :
     « Ouvrir le dossier complet de cette personne » 3,55:1 (1440) / 3,47:1 (390), « ‹ Précédent /
     Suivant › » 3,47:1, « Voir les N autres » 3,61:1 — trois COMMANDES d'un écran de décision,
     toutes sous AA (WCAG 1.4.3). La doctrine `F-008` du Lot 3 a délibérément fait passer TOUTES
     les actions de cette fiche en `--secondary` : c'est la surface où le jeton fautif frappe le
     plus fort. Avec --accent-text (= --accent-light #818cf8 en Obsidian) : 5,32 / 5,72 / 5,20 /
     5,40:1 sur les mêmes fonds. ⛔ Aucun coût en thème clair — `--accent-text: var(--accent)`
     y est un NO-OP (bento :778, atsiq-theme.css:130). */
  --btn-secondary-fg: var(--accent-text);
  --btn-secondary-hover-bg: rgba(var(--accent-rgb), 0.16);
  --btn-secondary-hover-border: 1px solid rgba(var(--accent-rgb), 0.35);
  /* T2.2 — canon SOLIDE (promotion enterprise/phase3, décision figée spec §8-4) :
     hover = opacity/filter verbatim (enterprise/phase3), pas de bg/border swap. */
  --btn-danger-bg: var(--status-danger);
  --btn-danger-border: transparent;
  --btn-danger-fg: var(--text-inverse);
  --btn-success-bg: var(--status-ok);
  --btn-success-border: transparent;
  --btn-success-fg: var(--bg1);
  --btn-warn-bg: rgba(var(--status-warn-rgb), 0.15);
  --btn-warn-border: 1px solid rgba(var(--status-warn-rgb), 0.30);
  --btn-warn-fg: var(--status-warn);
  --btn-warn-hover-bg: rgba(var(--status-warn-rgb), 0.25);
  --btn-warn-hover-border: 1px solid rgba(var(--status-warn-rgb), 0.45);
  --btn-outline-bg: transparent;
  --btn-outline-border: 1px solid var(--border);
  --btn-outline-fg: var(--text);
  --btn-outline-hover-bg: rgba(var(--accent-rgb), 0.08);
  --btn-outline-hover-border: 1px solid var(--accent);
  /* P3 FIX-R quater L1/L3 — MÊME DÉFAUT D'ENCRE QUE `--btn-secondary-fg`, MÊME GESTE, MÊME SOURCE.
     `.btn--outline:hover` (`components.css:3979-3982`) peint son texte avec `--btn-outline-hover-fg`
     SUR UNE SURFACE TEINTÉE D'ACCENT (`--btn-outline-hover-bg: rgba(var(--accent-rgb), 0.08)`).
     Mesuré en Obsidian sur `--card` au-dessus de `--bg1` (fond composé rgb(23,31,60)) :
     l'accent natif #6366f1 = 3,61:1 — SOUS AA ; `--accent-text` (#818cf8) = 5,40:1.
     Deux surfaces le portent : « Voir plus » du Kanban (`recruiter-pipeline.js:281`) et le lien de
     mandat de la fiche personne (`recruiter-candidate-card.js:3529`). La doctrine du jeton est
     écrite 90 lignes plus haut : l'accent natif est réservé aux APLATS — ici la BORDURE le garde. */
  --btn-outline-hover-fg: var(--accent-text);
  --btn-ghost-bg: transparent;
  --btn-ghost-border: 1px solid transparent;
  --btn-ghost-fg: var(--text-secondary);
  --btn-ghost-hover-bg: rgba(var(--white-rgb), 0.06);
  --btn-ghost-hover-fg: var(--text);
  /* P2-Z 1b-E (mesure du re-rendu) — `.btn.btn--link` peignait avec `--accent`
     (#6366f1 en Obsidian) : 4,18:1 sur la carte et 4,34:1 sur le fond de pane, SOUS AA,
     sur « Réessayer » et « Voir tout » — deux contrôles qui portent une ACTION.
     `--accent-text` existe precisement pour le texte accentue (Obsidian : --accent-light
     #818cf8 → 5,3 a 6,3:1 ; themes clairs : --accent, deja tres contraste). */
  --btn-link-fg: var(--accent-text);
  --btn-danger-outline-bg: transparent;
  --btn-danger-outline-border: 1px solid rgba(var(--status-danger-rgb), 0.30);
  --btn-danger-outline-fg: var(--danger-text);
  --btn-danger-outline-hover-bg: rgba(var(--status-danger-rgb), 0.10);
  --btn-danger-outline-hover-border: 1px solid rgba(var(--status-danger-rgb), 0.50);
  --btn-ai-bg: linear-gradient(135deg, rgba(var(--purple-rgb), 0.60) 0%, rgba(var(--fuchsia-rgb), 0.55) 40%, rgba(var(--cyan-rgb), 0.45) 100%);
  --btn-ai-border: 1px solid rgba(var(--fuchsia-rgb), 0.35);
  --btn-ai-fg: var(--text-inverse);
  --btn-ai-shadow: 0 4px 20px rgba(var(--fuchsia-rgb), 0.30), inset 0 1px 0 rgba(var(--white-rgb), 0.20);
  --btn-ai-hover-bg: linear-gradient(135deg, rgba(var(--purple-rgb), 0.80) 0%, rgba(var(--fuchsia-rgb), 0.75) 40%, rgba(var(--cyan-rgb), 0.65) 100%);
  --btn-ai-hover-shadow: 0 8px 40px rgba(var(--fuchsia-rgb), 0.40), 0 0 20px rgba(var(--cyan-rgb), 0.15);
  --btn-ai-hover-border: 1px solid rgba(var(--cyan-rgb), 0.50);
  --btn-primary-fg: var(--text-inverse);
  /* P2-Z re-gate (finding « CTA primaire », WCAG 1.4.3) — le CTA primaire ne peut plus être
     peint par --gradient-primary : mesuré 4,47:1 en Obsidian (arrêt #6366f1) et 3,05:1 en
     Sage & Forest (arrêt clair #7A9A83) contre le texte inverse, donc SOUS AA. Fond dédié,
     PLEIN, même canon que le kit (.ctk-btn.ctk-btn--primary, components-recruiter.css) :
     --accent-dark #4f46e5 → blanc 6,29:1. --gradient-primary reste le dégradé DÉCORATIF
     (liseré de carte, jauge de complétude) — jamais un fond porteur de texte.
     REDÉCLARÉ dans CHAQUE thème : un token :root de la forme var(--x) reste figé sur la
     valeur racine de --x (cf. la note --btn-ai-fg du bloc bento). */
  --btn-primary-bg: var(--accent-dark);
  --btn-primary-border: 1px solid rgba(var(--accent-purple-rgb), 0.35);
  --btn-primary-shadow: 0 4px 18px rgba(var(--accent-rgb), 0.35), 0 1px 3px rgba(var(--black-rgb), 0.25);
  --btn-primary-hover-shadow: 0 8px 36px rgba(var(--accent-rgb), 0.50), 0 2px 8px rgba(var(--black-rgb), 0.25);
  --btn-base-bg: var(--card);
  --btn-base-border: 1px solid var(--btn-border, var(--border));
  --btn-base-hover-bg: var(--card2);
  --btn-base-hover-border: 1px solid var(--border-accent);
  --btn-base-hover-shadow: none;
  --btn-disabled-opacity: 0.5;
  /* Gradients */
  --gradient-primary: linear-gradient(135deg, #6366f1 0%, #4f46e5 50%, #6366f1 100%);
  --gradient-ai: linear-gradient(135deg, #8b5cf6 0%, #c026d3 35%, #06b6d4 100%);
  --gradient-accent: linear-gradient(135deg, #22d3ee 0%, #06b6d4 100%);
  --gradient-warm: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
  /* Data-color gradient strips (stat cards, KPI bars) */
  --grad-indigo: linear-gradient(90deg, var(--primary), #818cf8);
  --grad-cyan: linear-gradient(90deg, #06b6d4, var(--accent2));
  --grad-amber: linear-gradient(90deg, #f59e0b, #fbbf24);
  --grad-green: linear-gradient(90deg, #10b981, #34d399);
  --grad-purple: linear-gradient(90deg, #8b5cf6, #a78bfa);
  --grad-rose: linear-gradient(90deg, #f43f5e, #fb7185);
  --grad-info: linear-gradient(90deg, #3b82f6, #60a5fa);
  --grad-red: linear-gradient(90deg, #dc2626, #ef4444);
  --grad-red-hover: linear-gradient(90deg, #ef4444, #f87171);

  /* Status colors */
  --status-ok: #22c55e;
  --status-warn: #f59e0b;
  --status-danger: #ef4444;
  --status-info: #3b82f6;
  --status-muted: #64748b;

  /* Severity palette: brighter/lighter variants for high-density badges. */
  --severity-critical: #f87171;
  --severity-critical-rgb: 248, 113, 113;
  --severity-high: #fb923c;
  --severity-high-rgb: 251, 146, 60;
  --severity-medium: #fbbf24;
  --severity-medium-rgb: 251, 191, 36;
  --severity-low: #a78bfa;
  --severity-low-rgb: 167, 139, 250;
  --severity-info: #94a3b8;
  --severity-info-rgb: 148, 163, 184;
  /* Glass + scrim — common transparent layers used by .sc-* widgets */
  --bg-glass: rgba(255, 255, 255, 0.04);
  --bg-glass-strong: rgba(255, 255, 255, 0.08);
  --bg-glass-bento: rgba(255, 255, 255, 0.55);  /* glassy on warm-cream bg */
  --bg-scrim: rgba(0, 0, 0, 0.4);
  --bg-scrim-soft: rgba(0, 0, 0, 0.12);          /* lighter overlay */
  --border-soft: rgba(255, 255, 255, 0.06);      /* hairline border, dark theme */

  /* Surface — subtle background for hover rows, gauges, etc. */
  --surface: rgba(20,30,52,0.35);

  /* ── Aliases design-system `--ds-*` ─────────────────────────────────────────────────────────
     Définis NULLE PART jusqu'ici → les usages retombaient sur des fallbacks HARDCODÉS (#1a1a1a,
     #888, rgba(0,0,0,…)) qui cassaient le sombre + ATSIQ (contraste ~1,05:1 ; cf. memory
     reference_undefined_ds_tokens_silent_fallback). On les ALIASE aux tokens CANONIQUES (déjà
     theme-aware) : une SEULE définition en :root suffit — `var(--text)`/`var(--border)`/… se
     re-résolvent par thème (bento/atsiq/obsidian). Consommés par `.ct-export-modal__*`,
     `.job-fullview__*`, `.ds-ring`. Les 3 tokens de ring sont numériques (theme-agnostiques). */
  --ds-text-primary: var(--text);
  --ds-text-secondary: var(--text-secondary);
  --ds-text-tertiary: var(--text-muted);
  --ds-border-subtle: var(--border);
  --ds-border-default: var(--border);
  --ds-bg-subtle: var(--surface);
  --ds-bg-default: var(--card);
  --ds-bg-surface: var(--card);
  --ds-color-primary: var(--accent);
  --ds-color-focus: var(--accent);
  --ds-color-danger: var(--danger-text);
  --ds-color-danger-soft: var(--danger);
  --ds-ring-size: 44px;
  --ds-ring-thickness: 6px;
  --ds-ring-pct: 0;

  /* Data visualization palette (statCard data-color variants) */
  /* --data-*       : text/value color (light tint in dark, saturated in light) */
  /* --data-*-deep  : gradient start (saturated base) */
  /* --data-*-light : gradient end (lighter tint) */
  --data-indigo: #a5b4fc;
  --data-indigo-deep: #6366f1;
  --data-indigo-light: #818cf8;
  --data-cyan: #67e8f9;
  --data-cyan-deep: #06b6d4;
  --data-cyan-light: #67e8f9;
  --data-green: #6ee7b7;
  --data-green-deep: #10b981;
  --data-green-light: #34d399;
  --data-amber: #fcd34d;
  --data-amber-deep: #f59e0b;
  --data-amber-light: #fbbf24;
  --data-purple: #c4b5fd;
  --data-purple-deep: #8b5cf6;
  --data-purple-light: #a78bfa;
  --data-rose: #fda4af;
  --data-rose-deep: #f43f5e;
  --data-rose-light: #fb7185;
  --data-rose-light-rgb: 251, 113, 133;
  --data-blue: #93c5fd;
  --data-blue-deep: #3b82f6;
  --data-blue-light: #60a5fa;
  --data-red: #fca5a5;
  --data-red-deep: #ef4444;
  --data-red-light: #f87171;
  --data-pink-deep: #ec4899;
  --data-pink-deep-rgb: 236, 72, 153;
  --data-orange-deep: #f97316;
  --data-gray-deep: #64748b;
  /* Teal — distinct from cyan/green; used by admin finance charts
     (hume_evi / transcribe-diarize / personality_assessment bars). DA-0048. */
  --data-teal-deep: #14b8a6;

  /* Interview call dark backgrounds (Obsidian Cosmos) */
  --call-bg: #0f1628;
  --call-bg-deep: #0a0f1e;
  --call-border: rgba(139, 92, 246, 0.15);
  --call-hangup: #dc2626;
  --call-surface: rgba(30, 41, 59, 0.7);
  --call-surface-border: rgba(255, 255, 255, 0.08);
  --call-panel-bg: rgba(15, 22, 40, 0.85);
  --call-accent: #8b5cf6;
  --call-accent-hover: #7c3aed;
  --call-accent-rgb: 139, 92, 246;
  --call-text-muted: #94a3b8;
  --call-text-dim: #64748b;

  /* Text RGB for rgba() patterns in call UI */
  --text-rgb: 241, 245, 249;
  /* RGB companions for common rgba() patterns */
  --white-rgb: 255, 255, 255;
  /* Universal white token (companion to --white-rgb on line above).
     Used by lint-ui-premium to allow `color: var(--white)` instead of
     hardcoded `#ffffff` / `#fff`. */
  --white: #ffffff;
  /* Companion RGB triplets for accent-light + warm cream surfaces. */
  --accent-light-rgb: 129, 140, 248;
  --paper-rgb: 255, 253, 250;
  --warm-cream-rgb: 245, 240, 232;
  --warm-amber-rgb: 254, 243, 199;
  /* Display serif token for the few headings that intentionally use
     a Georgia stack (brand-guide / landing showcase blocks).
     Lint-compliant alternative to hardcoded `font-family: Georgia, ...`. */
  --font-display: Georgia, 'Times New Roman', serif;
  /* Generic brand accent tokens shared by public surfaces. */
  --brand-success-deep: #357a47;
  --brand-info-deep: #2c66c8;

  --success-rgb: 74, 222, 128;
  --info-rgb: 80, 160, 255;
  --severity-critical-soft: #8f2b2b;
  --warm-gold-mid: #c9a154;
  --warm-gold-mid-rgb: 201, 161, 84;
  --warm-dark-rgb: 86, 64, 24;
  --bg-deep-overlay-rgb: 8, 10, 16;
  --paper-warm-rgb: 247, 241, 231;
  /* 2026-05-07 — additional canonical tokens for residual literals
     left after the variables.css→bulk-replace migration. Each one
     resolves a multi-occurrence hex/rgba that didn't have a token. */
  --warm-amber-light: #fde68a;
  --warm-amber-light-rgb: 253, 230, 138;
  --lavender-100: #e0e7ff;
  --lavender-200: #c7d2fe;
  --slate-light: #c9d1d9;
  --slate-800: #1e293b;
  --green-300: #86efac;
  --green-300-rgb: 134, 239, 172;
  --green-700: #15803d;
  --green-700-rgb: 21, 128, 61;
  --blue-600: #2563eb;
  --blue-600-rgb: 37, 99, 235;
  --emerald-600: #059669;
  --emerald-600-rgb: 5, 150, 105;
  --bento-warm-stone: #f5f0e8;
  --bento-warm-stone-rgb: 245, 240, 232;
  --grey-soft-rgb: 100, 116, 139;
  --grey-text: #888;
  --grey-text-light: #c9d1d9;
  --neutral-50: #f4f4f5;
  --neutral-soft: #f8f9fb;
  --black-rgb: 0, 0, 0;
  /* Theme-aware table surface tokens (global table{} in components.css).
     :root keeps the PRIOR literal values → Obsidian byte-identical.
     Light themes (bento/atsiq/light) override these with warm/ink-tinted,
     visible-on-light equivalents in their own token blocks. */
  --table-tint: rgba(var(--black-rgb), 0.15);
  --table-edge: rgba(var(--white-rgb), 0.08);
  --slate-rgb: 45, 55, 72;
  --slate-dark-rgb: 30, 41, 59;
  --card-base-rgb: 20, 30, 52;
  --card2-base-rgb: 26, 38, 62;
  --fuchsia-rgb: 192, 38, 211;
  --purple-rgb: 168, 85, 247;
  --cyan-rgb: 6, 182, 212;
  --data-rose-rgb: 244, 63, 94;
  --amber-rgb: 251, 191, 36;
  --amber-dark-rgb: 217, 119, 6;
  --emerald-rgb: 16, 185, 129;
  --red-light-rgb: 255, 90, 90;
  --red-soft-rgb: 255, 107, 107;
  --red-mid-rgb: 255, 100, 100;
  --green-bright-rgb: 46, 204, 113;
  --green-mid-rgb: 22, 163, 74;
  --green-dark-rgb: 21, 128, 61;
  --gray-rgb: 156, 163, 175;
  --gray-blue-rgb: 148, 163, 184;
  --yellow-rgb: 255, 193, 7;
  --purple-pastel-rgb: 196, 181, 253;
  --indigo-pastel-rgb: 176, 191, 253;
  --lavender-rgb: 241, 237, 252;
  --lavender-deep-rgb: 227, 222, 242;
  --lavender-mid-rgb: 233, 229, 245;
  --lavender-dark-rgb: 221, 216, 237;
  --lavender-darker-rgb: 216, 211, 233;
  --bg-deep-rgb: 6, 10, 22;
  --bg-deep2-rgb: 12, 20, 38;

  /* ATS brand colors */
  --brand-greenhouse: #43a047;
  --brand-greenhouse-rgb: 67, 160, 71;
  --brand-lever: #1a73e8;
  --brand-lever-rgb: 26, 115, 232;
  --brand-bullhorn: #ef5623;
  --brand-bullhorn-rgb: 239, 86, 35;
  --brand-linkedin: #0a66c2;
  --brand-linkedin-rgb: 10, 102, 194;
  --brand-linkedin-dark: #004182;
  --brand-twitter: #000000;
  --brand-twitter-rgb: 0, 0, 0;
  --brand-whatsapp: #25d366;
  --brand-whatsapp-rgb: 37, 211, 102;
  /* Confetti / decoration palette — used by Step 5 celebration sequence
     (recruiter-jobintake-stepper.css §11). Subset of Tailwind 500/700 scales
     for vivid contrast without depending on theme primary. */
  --decor-purple: #7c3aed;
  --decor-pink: #ec4899;
  --decor-amber: #d97706;
  --decor-cyan: #06b6d4;
  --decor-yellow: #fbbf24;
  --decor-gray-700: #374151;
  --decor-gray-700-rgb: 55, 65, 81;
  --brand-recruitee: #6c5ce7;
  --brand-recruitee-rgb: 108, 92, 231;
  --brand-flatchr: #ff6b6b;
  --brand-flatchr-rgb: 255, 107, 107;
  --brand-teamtailor: #00bfa5;
  --brand-teamtailor-rgb: 0, 191, 165;
  --brand-wttj: #ffcd00;
  --brand-wttj-rgb: 255, 205, 0;
  --brand-github: #24292e;
  --brand-github-rgb: 36, 41, 46;
  /* Fixed "online" indicator — theme-stable green */
  --online-rgb: 16, 185, 129;

  /* Interactive state shadows */
  --shadow-hover: 0 4px 12px rgba(99, 102, 241, 0.12);
  --shadow-focus: 0 0 0 3px rgba(99, 102, 241, 0.15);
  --shadow-card-hover: 0 6px 20px rgba(99, 102, 241, 0.15);

  /* Semantic shadow tokens (hybrid — repeated patterns only) */
  --shadow-inset-accent: inset 3px 0 0 var(--accent);
  --shadow-modal: 0 18px 52px rgba(0, 0, 0, 0.50);
  --shadow-dropdown: 0 8px 32px rgba(0, 0, 0, 0.3);
  --shadow-ring-primary: 0 0 0 2px rgba(99, 102, 241, 0.15);
  --shadow-ring-primary-lg: 0 0 0 3px rgba(99, 102, 241, 0.15);
  --shadow-subtle: 0 4px 12px rgba(0, 0, 0, 0.06);
  --shadow-card: 0 4px 16px rgba(99, 102, 241, 0.06);
  --shadow-accent-glow: 0 2px 8px rgba(99, 102, 241, 0.3);

  /* Radius scale */
  --radius-2: 2px;
  --radius-3: 3px;
  --radius-4: 4px;
  --radius-xs: 6px;
  --radius-8: 8px;
  --radius-12: 12px;
  --radius-md: 16px;
  --radius-full: 9999px;

  /* Soft text (subdued, for secondary labels) */
  --text-soft: rgba(241,245,249,0.65);
  /* Accent soft (for subtle backgrounds) */
  --accent-soft: rgba(99,102,241,0.5);
  /* Accent purple (for decorative accents) */
  --accent-purple: #a78bfa;
  --accent-purple-rgb: 167, 139, 250;
  /* AI identity colours — FIXED per theme, never remapped */
  --ai-color-1: #a78bfa;
  --ai-color-1-rgb: 167, 139, 250;
  --ai-color-2: #38bdf8;
  --ai-color-2-rgb: 56, 189, 248;

  /* Foreground muted (subdued text for secondary content) */
  --fg-muted: #94a3b8;
  /* Card border alias */

  /* Missing aliases used in components */
  --bg-darker: var(--bg0);
  --bg-subtle: var(--surface);
  --shadow-lg: var(--shadow);

  /* Aliases (deprecated — use canonical names) */
  --bg: var(--bg1);
  --fg: var(--text);
  --text-secondary: rgba(241,245,249,0.75);
  --card-bg: var(--bg2);
  --primary: var(--accent);
  --primary-hover: var(--accent-dark);
  --primary-rgb: 99, 102, 241;

  /* Phase 4 aliases — map to canonical variables for consistent theming */
  --text-primary: var(--text);
  --text-muted: var(--muted);
  --bg-hover: var(--card-hover);
  --bg-card: var(--card);
  --bg-input: var(--bg2);
  --bg-elevated: var(--card2);
  --bg-secondary: var(--bg2);
  --bg-tertiary: rgba(255,255,255,0.06);
  --on-primary: #fff;
  --text-inverse: #fff;

  /* DA-0047 — aliases for legacy token names referenced (without inline
     fallback) by live .csp-* helper classes in ui-primitives.css. Each maps
     to an existing canonical token so the value re-resolves per theme
     (bento / atsiq / Obsidian). Purely additive — no existing token changes. */
  --error: var(--danger-text);        /* error text → themed red */
  --paper: var(--ds-paper);           /* light paper tint (color-mix) */
  --ctj-text-muted: var(--text-muted);
  --bg-alt: var(--bg2);               /* surface fallback for --surface-raised */
  /* REWORK-2 2026-06-13: --input-bg and --ink-rgb aliases REMOVED. A global
     :root definition hijacked fallback-bearing consumers
     (job-input-widget.css → var(--input-bg, var(--surface)) and
     excluded CT demo stylesheet → rgba(var(--ink-rgb, 28,25,23), …)) which need
     the token UNDEFINED. The .csp-* sites in ui-primitives.css now carry
     inline fallbacks instead — Option A, theme-invariance-safe. */

  /* Status RGB companions (for rgba() usage in Phase 4 badges) */
  --status-ok-rgb: 34, 197, 94;
  --status-danger-rgb: 239, 68, 68;
  --status-warn-rgb: 245, 158, 11;
  --status-info-rgb: 59, 130, 246;
  --status-muted-rgb: 100, 116, 139;
  --accent-rgb: 99, 102, 241;

  /* ── Phase 3 Lot 1 — ÉCHELLE DE COULEUR DU SCORE DE CORRESPONDANCE (backlog §20.1) ───────
     Décision owner du 04/09 : < 50 rouge · 50-70 orange · 70-85 vert · 85-100 vert INTENSE.
     Quatre bandes, `low|mid|high|top`, chacune = un TEXTE (seuil AA 4,5:1), un FOND et un TRAIT.
     Les trois premières réutilisent les tokens de statut existants (⛔ aucune couleur en dur, et
     aucune nouvelle famille chromatique) ; seule la 4ᵉ — « vert plus intense et soutenu », mot de
     l'owner — a besoin d'un couple propre : un vert PLEIN, donc un texte inversé.
     ⚖️ D12 est RÉVOQUÉE (§23.1) : `low` est bel et bien rouge. Rouge = mauvais score, PAS exclu.
     ⛔ La couleur n'est jamais seule porteuse d'information : le nombre, l'unité et le mot sont
     rendus à côté d'elle par `ctMatchScore` (core-utils.js).
     Bloc :root = thème Obsidian (sombre). Voir atsiq-theme.css pour « Sage & Forest ». */
  --score-band-low-fg: var(--danger-text);
  --score-band-low-bg: rgba(var(--status-danger-rgb), 0.14);
  --score-band-low-border: var(--status-danger);
  --score-band-mid-fg: var(--warning-text);
  --score-band-mid-bg: rgba(var(--status-warn-rgb), 0.14);
  --score-band-mid-border: var(--status-warn);
  --score-band-high-fg: var(--success-text);
  --score-band-high-bg: rgba(var(--status-ok-rgb), 0.14);
  --score-band-high-border: var(--status-ok);
  --score-band-top-fg: #052e16;              /* vert-950 — 6,5:1 sur le vert plein ci-dessous */
  --score-band-top-bg: #22c55e;              /* = --status-ok, PLEIN (la bande « soutenue ») */
  --score-band-top-border: #16a34a;

  /* Radar chart theming */
  --radar-grid: rgba(255,255,255,0.13);
  --radar-axis: rgba(255,255,255,0.20);
  --radar-label: #cbd5e1;
  --radar-tick: #475569;
  --radar-dot-ring: rgba(255,255,255,0.95);
  --radar-pill-bg: rgba(0,0,0,0.55);
  --radar-pill-shadow: none;

  /* Z-index scale */
  --z-base: 0;
  --z-decoration: 1;
  --z-raised: 2;
  --z-content: 10;
  --z-dropdown: 50;
  --z-sticky: 90;
  --z-topbar: 99;
  --z-sidebar: 100;
  --z-sidebar-overlay: 109;
  --z-sidebar-panel: 110;
  --z-sidebar-hamburger: 120;
  --z-overlay: 200;
  --z-popover: 1000;
  --z-modal-backdrop: 9999;
  --z-modal: 10000;
  /* Modal stack levels (Plan job-intake-stepper P0). Each pushed modal
     escalates by 10 to leave room for per-modal overlays (drawers, popovers)
     that sit just above their parent modal. Topmost modal uses
     --z-modal-stack-{depth-1}; max supported stack depth = 3 (0..2). */
  --z-modal-stack-0: 10000;
  --z-modal-stack-1: 10010;
  --z-modal-stack-2: 10020;
  --z-toast: 10031;        /* bump above max stack to keep toasts visible */
  --z-spotlight: 99999;

  /* ── Transition & Motion Tokens ── */
  --ease-default: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-decel: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --duration-fast: 150ms;
  --duration-base: 250ms;
  --duration-slow: 400ms;
  --duration-pulse: 1200ms;
  /* Stagger interval: base step for cascading children entrance animations.
     Use as `animation-delay: calc(var(--stagger-step) * N)` on nth-child rules. */
  --stagger-step: 20ms;

  /* ── Loading Animation Tokens (Career Toolbox) ── */
  --ct-load-body-1: #8b5cf6;
  --ct-load-body-2: #ec4899;
  --ct-load-handle-1: #a78bfa;
  --ct-load-handle-2: #f472b6;
  --ct-load-terminal: #0d1117;
  --ct-load-prompt: #10b981;
  --ct-load-badge-bg: #fbbf24;
  --ct-load-badge-text: #0f1628;
  --ct-load-text-101: rgba(255,255,255,0.55);
  --ct-load-glow-1: rgba(139,92,246,0.25);
  --ct-load-glow-2: rgba(236,72,153,0.10);
  --ct-load-ring: rgba(139,92,246,0.45);
  --ct-load-ring-shadow: rgba(139,92,246,0.2);
  --ct-load-shadow-1: rgba(139,92,246,0.4);
  --ct-load-shadow-2: rgba(236,72,153,0.15);
  --ct-load-text-shadow: rgba(var(--black-rgb), 0.45);
  --ct-load-stage-shadow: rgba(var(--black-rgb), 0.34);
  --ct-load-bit-1: #8b5cf6;  --ct-load-gbit-1: rgba(139,92,246,.5);
  --ct-load-bit-2: #ec4899;  --ct-load-gbit-2: rgba(236,72,153,.5);
  --ct-load-bit-3: #22d3ee;  --ct-load-gbit-3: rgba(34,211,238,.5);
  --ct-load-bit-4: #10b981;  --ct-load-gbit-4: rgba(16,185,129,.5);
  --ct-load-bit-5: #a78bfa;  --ct-load-gbit-5: rgba(167,139,250,.5);
  --ct-load-bit-6: #f472b6;  --ct-load-gbit-6: rgba(244,114,182,.5);
  --ct-brain-accent-rgb: 142, 245, 192;
  --ct-brain-aura-1: rgba(var(--ct-brain-accent-rgb), 0.20);
  --ct-brain-aura-2: rgba(40, 110, 74, 0.16);
  --ct-brain-aura-3: rgba(29, 58, 39, 0.10);
  --ct-brain-shadow-clear: rgba(var(--ct-brain-accent-rgb), 0);
  --ct-brain-shadow-glow: rgba(var(--ct-brain-accent-rgb), 0.42);
  --ct-flask-stage-shadow: rgba(var(--black-rgb), 0.42);
  --ct-flask-accent: #8ef5c0;
  --ct-flask-glass: rgba(124, 58, 237, 0.07);
  --ct-flask-rim: #2a1d44;
  --ct-flask-rim-glow: rgba(124, 58, 237, 0.28);
  --ct-flask-liquid: rgba(190, 242, 255, 0.92);
  --ct-flask-liquid-soft: rgba(190, 242, 255, 0.9);
  --ct-flask-shine: rgba(var(--white-rgb), 0.16);

  /* === DS surface tokens ===
     Centralised theme-resolved surface/ink/overlay tokens. */
  /* Overlays on light surfaces (subtle to strong tint) */
  --ds-overlay-faint: rgba(0, 0, 0, 0.03);
  --ds-overlay-soft: rgba(0, 0, 0, 0.04);
  --ds-overlay-light: rgba(0, 0, 0, 0.05);
  --ds-overlay-divider-soft: rgba(0, 0, 0, 0.06);
  --ds-overlay-border-soft: rgba(0, 0, 0, 0.08);
  --ds-scrim-medium: rgba(0, 0, 0, 0.5);
  --ds-scrim-strong: rgba(0, 0, 0, 0.62);
  /* Glass overlays on dark backgrounds */
  --ds-glass-ghost: rgba(255, 255, 255, 0.02);
  --ds-glass-faint: rgba(255, 255, 255, 0.03);
  --ds-glass: rgba(255, 255, 255, 0.04);
  --ds-glass-divider-faint: rgba(255, 255, 255, 0.06);
  --ds-glass-strong: rgba(255, 255, 255, 0.08);
  --ds-glass-stronger: rgba(255, 255, 255, 0.10);
  --ds-glass-divider-strong: rgba(255, 255, 255, 0.12);
  --ds-glass-bento-strong: rgba(255, 255, 255, 0.18);
  --ds-glass-bento-stronger: rgba(255, 255, 255, 0.22);
  /* Solid card surfaces */
  --ds-card-dark-86: rgba(20, 20, 28, 0.86);
  --ds-card-dark-96: rgba(20, 20, 28, 0.96);
  --ds-card-dark-98: rgba(20, 20, 28, 0.98);
  --ds-paper: #ffffff;
  --ds-paper-warm: #fffdfa;
  /* Ink colors per theme background */
  --ds-ink-on-dark: #f1f5f9;
  --ds-ink-on-cream: #1a1a1a;
  --ds-ink-on-cream-warm: #1c1917;
  --shadow-md: var(--shadow-card);
  --radius-xl: var(--radius-lg);
  --surface-alt: var(--surface);
  --hover-bg: rgba(var(--accent-rgb), 0.08);
  --bg-primary: var(--bg1);
  --text-default: var(--text);
  --font-sm: var(--text-sm);
  --font-xs: var(--text-xs);
  --text-5xl: var(--text-4xl);
  --ds-muted-on-dark-65: rgba(241, 245, 249, 0.65);
  --ds-muted-on-dark-70: rgba(241, 245, 249, 0.7);
  --ds-muted-on-dark-75: rgba(241, 245, 249, 0.75);
  --ds-muted-on-dark-82: rgba(241, 245, 249, 0.82);
  --ds-muted-on-cream-65: rgba(28, 25, 23, 0.65);
  --ds-muted-on-cream-78: rgba(28, 25, 23, 0.78);

  /* Card surface dark variant (50% opacity for wizard step bg) */
  --ds-card-dark-50: rgba(20, 20, 28, 0.5);
  --ds-card-dark-70: rgba(20, 20, 28, 0.7);

  /* Light-paper cream alternative (ji-wizard step bg) */
  --ds-paper-cream-light: #fcfbf8;

  /* Sivel-labs cookie-banner extra tokens (lint-ui-premium 2026-05-12) */
  --ds-card-night: rgba(15, 16, 26, 0.94);
  --ds-card-night-opaque: rgba(15, 16, 26, 0.98);
  --ds-card-ink-warm: #1a1410;
  --ds-scrim-bento: rgba(0, 0, 0, 0.66);
  --ds-paper-warm-96: rgba(255, 253, 250, 0.96);
  --ds-paper-warm-98: rgba(255, 253, 250, 0.98);
  --ds-overlay-medium: rgba(0, 0, 0, 0.10);
  --ds-overlay-strong: rgba(0, 0, 0, 0.12);
  --ds-glass-bento-medium: rgba(255, 255, 255, 0.15);
  --ds-muted-on-dark-72: rgba(241, 245, 249, 0.72);
  --ds-muted-on-dark-85: rgba(241, 245, 249, 0.85);
  --ds-muted-on-cream-70: rgba(28, 25, 23, 0.7);
  --ds-muted-on-cream-72: rgba(28, 25, 23, 0.72);
  --ds-gold-92: rgba(200, 163, 90, 0.92);
  --ds-gold-85: rgba(200, 163, 90, 0.85);

}

/* === Light Theme — "Slate Mist" === */
/* Atmospheric slate-lavande backgrounds — professional, NOT "AI purple"
 * 2026-05-18 : `html.bento-theme` + `html.light-theme` are listed alongside
 * the body selectors so the theme variable overrides cascade down from
 * documentElement during the first paint. The inline head script
 * (index.html line ~26) sets the class on documentElement BEFORE the
 * body parses, which is what kills the FOUC where the dark Obsidian
 * theme flashed under #ctInitLoader during page boot.
 *
 * Body-scoped selectors are kept for backwards-compat (theme switcher
 * toggles classes on body at runtime). Both layers stay in sync because
 * the variables are the same. */
html.light-theme,
html.bento-theme,
body.light-theme,
body.bento-theme {
  /* Background palette — V3 Light: warm slate-lavande, neutral yet atmospheric */
  --bg0: #ddd8ed;        /* Lavender base */
  --bg1: #e3def2;        /* Lavender midtone */
  --bg2: #d8d3e9;        /* Deeper lavender */
  --fg: #1e1b4b;
  --bg: var(--bg1);
  --card-bg: rgba(255,255,255,0.65);
  --text-secondary: rgba(30,27,75,0.65);
  --card: rgba(255,255,255,0.62);
  --card2: rgba(255,255,255,0.70);
  --card-hover: rgba(79,70,229,0.12);
  --text: #1e1b4b;
  --muted: rgba(30,27,75,0.68);
  --btn: rgba(100,116,139,0.14);
  --btn2: rgba(100,116,139,0.26);
  --accent: #4f46e5;
  --accent-light: #6366f1;
  --accent-dark: #4338ca;
  /* R3 / da-11 : sur fonds CLAIRS l'accent natif est déjà AA comme texte — pas de variante. */
  --accent-text: var(--accent);
  --accent2: #0891b2;
  --accent2-light: #22d3ee;
  --accent2-rgb: 8, 145, 178;
  --accent3: #d97706;
  --danger: rgba(244,63,94,0.14);
  --danger-text: #be123c;
  --success: rgba(34,197,94,0.14);
  --success-text: #15803d;
  --warning: rgba(251,191,36,0.16);
  --warning-text: #b45309;
  --info: rgba(59,130,246,0.14);
  --info-text: #2563eb;
  --shadow: 0 25px 50px -12px rgba(30,41,59,0.18);
  --shadow-sm: 0 10px 25px -5px rgba(30,41,59,0.14);
  --shadow-glow: 0 0 40px rgba(100,116,139,0.10);
  --shadow-hover: 0 4px 12px rgba(30,41,59,0.14);
  --shadow-focus: 0 0 0 3px rgba(79,70,229,0.18);
  --shadow-card-hover: 0 6px 20px rgba(30,41,59,0.16);
  --bg-opaque: rgba(227,222,242,0.98);
  --bg-opaque-light: rgba(233,229,245,0.95);
  /* Drawer / popup background — light gradient pour rester lisible en bento.
     Évite le "dark bleed" sur drawers, popovers, modal, sticky head. */
  --bg-popup: linear-gradient(170deg, rgba(255,255,255,0.96) 0%, rgba(243,240,252,0.96) 100%);
  --border: rgba(100,116,139,0.20);
  --line: var(--border); /* F-1248: hairline divider alias */
  --border-accent: rgba(79,70,229,0.38);
  /* Theme-aware table surface — ink tint + visible hairline on light.
     Covers light-theme (Slate Mist, deprecated). Bento overrides --text-rgb /
     --border later in its own block, so its tables stay warm. */
  --table-tint: rgba(var(--text-rgb), 0.07);
  --table-edge: var(--border);
  --gradient-primary: linear-gradient(135deg, #4f46e5 0%, #6366f1 50%, #7c3aed 100%);
  /* P2-Z re-gate — fond PLEIN du CTA primaire (cf. la note du :root) : --accent #4f46e5,
     blanc 6,29:1. Le dégradé de la ligne au-dessus reste DÉCORATIF. */
  --btn-primary-bg: var(--accent);
  --gradient-ai: linear-gradient(135deg, rgba(124,58,237,0.95) 0%, rgba(192,38,211,0.90) 38%, rgba(6,182,212,0.82) 100%);
  --primary: var(--accent);
  --primary-hover: var(--accent-dark);
  --primary-rgb: 79, 70, 229;
  /* Call UI — light-mode equivalents */
  --call-bg: rgba(255,255,255,0.55);
  --call-bg-deep: var(--bg2);
  --call-border: rgba(100,116,139,0.18);
  --call-hangup: #dc2626;
  --call-surface: rgba(255,255,255,0.5);
  --call-surface-border: rgba(100,116,139,0.18);
  --call-panel-bg: rgba(255,255,255,0.72);
  --call-accent: #6366f1;
  --call-accent-hover: #4f46e5;
  --call-accent-rgb: 99, 102, 241;
  --call-text-muted: #64748b;
  --call-text-dim: #94a3b8;
  --text-rgb: 30, 27, 75;
  --text-soft: rgba(30,27,75,0.68);
  --accent-soft: rgba(79,70,229,0.5);
  --accent-purple: #7c3aed;
  --accent-purple-rgb: 124, 58, 237;
  --ai-color-1: #7c3aed;
  --ai-color-1-rgb: 124, 58, 237;
  --ai-color-2: #0891b2;
  --ai-color-2-rgb: 8, 145, 178;
  --text-inverse: #fff;
  --accent-rgb: 79, 70, 229;
  /* Data visualization palette — light theme (deeper for contrast) */
  --data-indigo: #4338ca;
  --data-indigo-deep: #4338ca;
  --data-indigo-light: #6366f1;
  --data-cyan: #0891b2;
  --data-cyan-deep: #0891b2;
  --data-cyan-light: #22d3ee;
  --data-green: #059669;
  --data-green-deep: #059669;
  --data-green-light: #10b981;
  --data-amber: #d97706;
  --data-amber-deep: #d97706;
  --data-amber-light: #f59e0b;
  --data-purple: #7c3aed;
  --data-purple-deep: #7c3aed;
  --data-purple-light: #8b5cf6;
  --data-rose: #e11d48;
  --data-rose-deep: #e11d48;
  --data-rose-light: #f43f5e;
  --data-blue: #2563eb;
  --data-blue-deep: #2563eb;
  --data-blue-light: #3b82f6;
  --data-red: #dc2626;
  --data-red-deep: #dc2626;
  --data-red-light: #ef4444;
  --data-pink-deep: #db2777;
  --data-pink-deep-rgb: 219, 39, 119;
  --data-orange-deep: #ea580c;
  --data-gray-deep: #475569;
  /* Teal — darker (teal-700) for WCAG AA on light/bento backgrounds. DA-0048. */
  --data-teal-deep: #0f766e;
  /* Status colors — darker for WCAG AA on light backgrounds (4.5:1 min) */
  --status-ok: #15803d;
  --status-warn: #b45309;
  /* Ambre profond (amber-800) pour le chip panel dégradé, AA sur son fond ambre TEINTÉ (§5.4). */
  --panel-chip-warn-fg: #92400e;
  --status-danger: #dc2626;
  --status-info: #1d4ed8;
  /* --status-muted: #64748b already passes AA (5.1:1 on white) */
  --status-ok-rgb: 21, 128, 61;
  --status-warn-rgb: 180, 83, 9;
  --status-danger-rgb: 220, 38, 38;
  --status-info-rgb: 29, 78, 216;

  /* Phase 3 Lot 1 — bande « vert intense » du score (§20.1) sur fond CLAIR. Les trois autres
     bandes héritent des tokens de statut redéfinis juste au-dessus, donc rien à redire ici.
     ⚠️ Ce bloc couvre light/bento (hôtes CT) : la surface recruteur ATSIQ, elle, est peinte par
     `body.atsiq-theme` (atsiq-theme.css). Défini quand même pour qu'AUCUN `--score-band-*` ne
     retombe silencieusement sur une valeur du thème sombre (piège des tokens non définis). */
  --score-band-top-fg: #ffffff;              /* 7,1:1 sur le vert forestier plein ci-dessous */
  --score-band-top-bg: #166534;              /* forest-800 — le « vert soutenu » en clair */
  --score-band-top-border: #14532d;

  /* Severity palette — darker variants for WCAG AA on light/bento bg.
     Same semantic order as :root values, shifted toward saturation. */
  --severity-critical: #b91c1c;       /* red-700 */
  --severity-critical-rgb: 185, 28, 28;
  --severity-high: #c2410c;           /* orange-700 */
  --severity-high-rgb: 194, 65, 12;
  --severity-medium: #b45309;         /* amber-700 */
  --severity-medium-rgb: 180, 83, 9;
  --severity-low: #6d28d9;            /* violet-700 */
  --severity-low-rgb: 109, 40, 217;
  --severity-info: #475569;           /* slate-600 */
  --severity-info-rgb: 71, 85, 105;
  /* Glass on bright bg : darker tint */
  --bg-glass: rgba(0, 0, 0, 0.03);
  --bg-glass-strong: rgba(0, 0, 0, 0.06);
  --bg-glass-bento: rgba(255, 255, 255, 0.55);  /* explicit override */
  --bg-scrim: rgba(0, 0, 0, 0.25);
  --bg-scrim-soft: rgba(0, 0, 0, 0.06);
  --border-soft: rgba(0, 0, 0, 0.06);            /* hairline on bright bg */

  /* Radar chart theming — light */
  --radar-grid: rgba(0,0,0,0.10);
  --radar-axis: rgba(0,0,0,0.16);
  --radar-label: #334155;
  --radar-tick: #94a3b8;
  --radar-dot-ring: rgba(255,255,255,1);
  --radar-pill-bg: rgba(255,255,255,0.92);
  --radar-pill-shadow: rgba(0,0,0,0.12);

  /* Surface — light-theme equivalent */
  --surface: rgba(100,116,139,0.08);

  /* Foreground muted — light theme override */
  --fg-muted: #64748b;
  /* Card border alias — light theme */

  /* Component aliases — light theme overrides */
  --bg-darker: var(--bg0);
  --bg-subtle: var(--surface);
  --shadow-lg: var(--shadow);

  /* Phase 4 aliases — explicit for light theme (var() chains from :root don't re-resolve) */
  --text-primary: var(--text);
  --text-muted: var(--muted);
  --bg-hover: var(--card-hover);
  --bg-card: var(--card);
  --bg-input: var(--bg2);
  --bg-elevated: var(--card2);
  --bg-secondary: var(--bg2);
  --bg-tertiary: rgba(0,0,0,0.06);
  --on-primary: #fff;
  /* Background set in effects.css for proper cascade */

  /* ── Loading Animation Tokens — Ink & Gold ── */
  --ct-load-body-1: #92400e;
  --ct-load-body-2: #d97706;
  --ct-load-handle-1: #b45309;
  --ct-load-handle-2: #f59e0b;
  --ct-load-terminal: #1c1917;
  --ct-load-prompt: #d97706;
  --ct-load-badge-bg: #d97706;
  --ct-load-badge-text: #fef3c7;
  --ct-load-text-101: rgba(254,243,199,0.6);
  --ct-load-glow-1: rgba(217,119,6,0.22);
  --ct-load-glow-2: rgba(251,191,36,0.08);
  --ct-load-ring: rgba(217,119,6,0.40);
  --ct-load-ring-shadow: rgba(217,119,6,0.15);
  --ct-load-shadow-1: rgba(217,119,6,0.4);
  --ct-load-shadow-2: rgba(251,191,36,0.12);
  --ct-load-bit-1: #d97706;  --ct-load-gbit-1: rgba(217,119,6,.5);
  --ct-load-bit-2: #fbbf24;  --ct-load-gbit-2: rgba(251,191,36,.5);
  --ct-load-bit-3: #eab308;  --ct-load-gbit-3: rgba(234,179,8,.5);
  --ct-load-bit-4: #f59e0b;  --ct-load-gbit-4: rgba(245,158,11,.5);
  --ct-load-bit-5: #b45309;  --ct-load-gbit-5: rgba(180,83,9,.45);
  --ct-load-bit-6: #a16207;  --ct-load-gbit-6: rgba(161,98,7,.4);
}

body.light-theme select,
body.bento-theme select,
body.light-theme input,
body.bento-theme input,
body.light-theme textarea,
body.bento-theme textarea {
  /* `C48` — les deux `color-scheme: light` qui vivaient ici n'existaient que pour ANNULER le
     `select, input, textarea { color-scheme: dark }` global de `base.css`, supprimé (encadré
     `base.css`). Le schéma est désormais déclaré à la RACINE par thème : Slate Mist et
     Ink & Gold n'en avaient AUCUNE au niveau document — leur page héritait donc du schéma du
     système d'exploitation. Ils l'ont maintenant, et les contrôles en héritent. */
  background: rgba(255,255,255,0.82);
  color: var(--text);
}

body.light-theme .topbar,
body.bento-theme .topbar,
body.light-theme .topbar-slim,
body.bento-theme .topbar-slim {
  background: rgba(241,237,252,0.88);
  border-bottom-color: rgba(100,116,139,0.18);
  color: var(--text);
}
body.light-theme .card,
body.bento-theme .card {
  background: var(--card);
  box-shadow: var(--shadow-sm);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
}

body.light-theme .landing-hero::before,
body.bento-theme .landing-hero::before {
  background: radial-gradient(circle, rgba(var(--status-muted-rgb),0.16) 0%, transparent 70%);
}

/* Light theme: Modal backgrounds */
body.light-theme .modal::before,
body.bento-theme .modal::before {
  background: rgba(var(--lavender-dark-rgb),0.60);
}

body.light-theme .modalCard,
body.bento-theme .modalCard {
  background: linear-gradient(170deg, rgba(var(--white-rgb),0.88) 0%, rgba(var(--lavender-mid-rgb),0.82) 100%) !important;
  border: 1px solid rgba(var(--status-muted-rgb),0.24);
  box-shadow: 0 25px 60px rgba(var(--slate-dark-rgb),0.20), 0 10px 30px rgba(var(--black-rgb),0.08);
}

body.light-theme .modalHead,
body.bento-theme .modalHead {
  border-bottom-color: rgba(100,116,139,0.16);
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   P3 FIX-B (`L2-B4` / `C29` / `JB-022`) — LA HIÉRARCHIE DES ONGLETS ÉTAIT INVERSÉE EN OBSIDIAN.

   Mesure du juge sur `04-poste-candidats__dark__1440.png` (fond `#111D32`) :
     « Candidats » (ACTIF)              `#818CF8`  →  **5,65 : 1**
     « Piloter le sourcing » (inactif)  `#C9CED4`  →  **10,65 : 1**
   L'onglet SÉLECTIONNÉ était deux fois MOINS contrasté que ses frères non sélectionnés. Le volet
   clair, lui, est correct (12,45 actif contre 6,99 inactif — rapport 1,78).

   CAUSE AU NIVEAU DU TOKEN, pas de la surface : `components-recruiter.css:369-372` peint l'actif
   en `--accent-text` et l'inactif en `--muted` ; en Obsidian `--muted: rgba(241,245,249,0.82)`
   est presque blanc (10,65:1, à 1,45 de `--text`) tandis que `--accent-text` = `--accent-light`
   `#818cf8` plafonne à 5,66:1.

   LE GESTE — un REMAP DE TOKENS, borné au rail d'onglets et au SEUL thème fautif :
     · ⛔ on ne touche PAS `--muted` globalement : il peint des centaines de surfaces, et le
       défaut mesuré est celui d'UNE hiérarchie, pas de tout le thème ;
     · ⛔ on ne touche PAS `--accent-text` globalement : il porte l'encre accentuée de tout le
       produit (liens, `.btn--help`, honoraires du tableau de bord) ;
     · ⛔ on ne touche PAS la feuille du kit (`components-recruiter.css`) : elle appartient à une
       autre passe de cette vague. Les custom properties HÉRITENT : redéfinies sur le rail, elles
       gouvernent `.ctk-tab` et `.ctk-tab.active` sans qu'une seule règle du kit change.
   Le sélecteur exclut explicitement les deux thèmes CLAIRS (sur `html` ET sur `body` — la classe
   est posée aux deux endroits selon les coques) : leurs valeurs restent BYTE-IDENTIQUES.

   Contrastes obtenus sur le même fond `#111D32` (calculés WCAG 2.1, relative luminance) :
     actif   `#a5b4fc`                      →  **8,47 : 1**
     inactif `rgba(241,245,249,0.52)`       →  **5,06 : 1**
   Hiérarchie 1,67 — l'ordre est rétabli, dans le même sens que le thème clair (1,78), et les
   DEUX restent au-dessus du 4,5:1 d'AA.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
html:not(.atsiq-theme):not(.bento-theme):not(.light-theme)
  body:not(.atsiq-theme):not(.bento-theme):not(.light-theme) .ctk-tabs--section {
  --muted: rgba(241,245,249,0.52);
  --accent-text: #a5b4fc;
}

/* Light theme: Tabs */
body.light-theme .tab,
body.bento-theme .tab {
  background: rgba(100,116,139,0.10);
  color: var(--muted);
}

body.light-theme .tab:hover,
body.bento-theme .tab:hover {
  background: rgba(100,116,139,0.16);
}

body.light-theme .tab.active,
body.bento-theme .tab.active {
  background: rgba(79,70,229,0.16);
  color: var(--accent);
  border-color: var(--accent);
}

/* Light theme: Form fields */
body.light-theme .field input,
body.bento-theme .field input,
body.light-theme .field textarea,
body.bento-theme .field textarea,
body.light-theme .field select,
body.bento-theme .field select {
  background: rgba(255,255,255,0.82);
  border-color: rgba(100,116,139,0.22);
}
/* Re-gate finding (2026-07-24): restored, corrected. An earlier pass here
   deleted this as "dead code" on the mistaken claim that no select ever uses
   the wrapper-div pattern — false: admin/mentor/scheduling/CV-rework modules
   use it extensively (`<div class="field"><select class="w100">`, confirmed
   via grep). `currentColor` doesn't resolve in a data-URI SVG though, so hex
   here matches Bento's actual --muted (rgba(28,25,23,0.68) → #1c1917).
   Not !important: effects.css's own `.field select` reapply (!important,
   loads after this file) is the one that actually wins in practice; this is
   defense-in-depth in case that ever changes. */
body.light-theme .field select,
body.bento-theme .field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%231c1917' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' stroke-opacity='0.68'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  background-size: 10px 6px;
}

body.light-theme .field input:focus,
body.bento-theme .field input:focus,
body.light-theme .field textarea:focus,
body.bento-theme .field textarea:focus,
body.light-theme .field select:focus,
body.bento-theme .field select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(79,70,229,0.16);
}

/* Light theme: Buttons — source unique components.css, thémé par tokens --btn-* (L2) */

/* Light theme: Sidebar/Nav — Frosted Slate */
body.light-theme .sidebar,
body.bento-theme .sidebar,
body.light-theme .app-sidebar,
body.bento-theme .app-sidebar {
  background: rgba(241,237,252,0.88);
  border-right-color: rgba(100,116,139,0.18);
  color: var(--text);
}

body.light-theme .sidebar .navItem,
body.bento-theme .sidebar .navItem,
body.light-theme .app-sidebar .sidebar__item,
body.bento-theme .app-sidebar .sidebar__item {
  color: var(--muted);
}

body.light-theme .sidebar .navItem:hover,
body.bento-theme .sidebar .navItem:hover,
body.light-theme .app-sidebar .sidebar__item:hover,
body.bento-theme .app-sidebar .sidebar__item:hover {
  background: rgba(100,116,139,0.10);
}

body.light-theme .sidebar .navItem.active,
body.bento-theme .sidebar .navItem.active,
body.light-theme .app-sidebar .sidebar__item.active,
body.bento-theme .app-sidebar .sidebar__item.active {
  background: rgba(79,70,229,0.14);
  color: var(--accent-dark);
}

/* Light theme: Tables */
body.light-theme table th,
body.bento-theme table th {
  background: rgba(100,116,139,0.12);
  color: var(--text);
}

body.light-theme table tr:hover,
body.bento-theme table tr:hover {
  background: rgba(100,116,139,0.08);
}

body.light-theme table td,
body.bento-theme table td {
  border-color: rgba(100,116,139,0.12);
}

/* Light theme: Dropdowns/Menus */
body.light-theme .dropdown,
body.bento-theme .dropdown,
body.light-theme .userMenu,
body.bento-theme .userMenu {
  background: linear-gradient(168deg, rgba(var(--lavender-rgb),0.98) 0%, rgba(var(--lavender-deep-rgb),0.98) 100%);
  border-color: rgba(var(--status-muted-rgb),0.22);
  box-shadow: 0 10px 40px rgba(var(--slate-dark-rgb),0.18);
}

body.light-theme .dropdown li:hover,
body.bento-theme .dropdown li:hover,
body.light-theme .menuItem:hover,
body.bento-theme .menuItem:hover {
  background: rgba(100,116,139,0.10);
}

/* Light theme: Badges */
body.light-theme .badge,
body.bento-theme .badge {
  background: rgba(100,116,139,0.14);
  color: var(--muted);
}

body.light-theme .badge.success,
body.bento-theme .badge.success {
  background: rgba(34,197,94,0.20);
  color: var(--success-text);
}

body.light-theme .badge.danger,
body.bento-theme .badge.danger {
  background: rgba(239,68,68,0.20);
  color: var(--danger-text);
}

body.light-theme .badge.warning,
body.bento-theme .badge.warning {
  background: rgba(251,191,36,0.26);
  color: var(--warning-text);
}

/* Light/bento theme: dominant badge variants (.ok/.warn/.bad/.subtle).
   The generic `body.{light,bento}-theme .badge` override above (0,2,1) was
   flattening these to grey because only the legacy .success/.danger/.warning
   names were re-styled. These parallel rules restore the status colors on the
   light surface, mirroring the success/danger/warning treatment but mapped to
   the dominant variant names + the same status tokens components.css uses.
   Tokens resolve in bento: --status-ok-rgb (21,128,61 forest), --amber-rgb
   (251,191,36), --red-light-rgb (255,90,90), --slate-rgb (68,64,60 warm stone),
   --success-text/--warning-text/--danger-text (warm Ink & Gold). */
body.light-theme .badge.ok,
body.bento-theme .badge.ok {
  background: rgba(var(--status-ok-rgb),0.18);
  color: var(--success-text);
}

body.light-theme .badge.warn,
body.bento-theme .badge.warn {
  background: rgba(var(--amber-rgb),0.20);
  color: var(--warning-text);
}

body.light-theme .badge.bad,
body.bento-theme .badge.bad {
  background: rgba(var(--red-light-rgb),0.18);
  color: var(--danger-text);
}

body.light-theme .badge.subtle,
body.bento-theme .badge.subtle {
  background: rgba(var(--slate-rgb),0.12);
  color: var(--muted);
  /* Gate Codex finding 4 — bord ink visible sur fond clair (la base `.badge.subtle` a un bord blanc 10 %
     invisible ici). `--border` = ink 18 % (bento) / slate 20 % (light) → contour net. */
  border: 1px solid var(--border);
}

/* Light theme: Toast notifications */
body.light-theme .toast,
body.bento-theme .toast {
  background: rgba(255,255,255,0.85);
  border-color: rgba(100,116,139,0.22);
  box-shadow: 0 10px 40px rgba(30,41,59,0.16);
}

/* Light theme: Scrollbar */
body.light-theme ::-webkit-scrollbar-track,
body.bento-theme ::-webkit-scrollbar-track {
  background: rgba(100,116,139,0.08);
}

body.light-theme ::-webkit-scrollbar-thumb,
body.bento-theme ::-webkit-scrollbar-thumb {
  background: rgba(100,116,139,0.22);
}

body.light-theme ::-webkit-scrollbar-thumb:hover,
body.bento-theme ::-webkit-scrollbar-thumb:hover {
  background: rgba(100,116,139,0.34);
}

/* ============================================================
   Ink & Gold — Bento Theme Warm Override Layer
   Overrides cold Slate Mist values inherited from the shared
   body.light-theme/body.bento-theme block above.
   Two strategies:
     1. RGB companion variable overrides (fixes all rgba(var(--x),...) patterns)
     2. Explicit component overrides (fixes literal hardcoded cold rgba values)
   ============================================================ */

/* --- Strategy 1: Override RGB companion variables --- */
/* 2026-05-18 — html.bento-theme listed too, so the warm-palette overrides
 * cascade from documentElement during first paint (anti-FOUC). */
html.bento-theme,
body.bento-theme {
  /* Warm backgrounds (replaces lavender) */
  --lavender-rgb: 245, 240, 235;
  --lavender-deep-rgb: 240, 235, 227;
  --lavender-mid-rgb: 242, 237, 230;
  --lavender-dark-rgb: 235, 228, 218;
  --lavender-darker-rgb: 230, 223, 213;
  /* Warm neutrals (replaces cool slate) */
  --slate-dark-rgb: 28, 25, 23;
  --slate-rgb: 68, 64, 60;
  --status-muted-rgb: 120, 113, 108;
  /* Warm accents (replaces fuchsia/purple) */
  --fuchsia-rgb: 161, 98, 7;
  --purple-rgb: 124, 98, 64;
  /* Warm base palette overrides */
  --bg0: #ddd5c8;
  --bg1: #e8e0d4;
  --bg2: #d9d0c3;
  --bg: var(--bg1);
  --fg: #1c1917;
  --text: #1c1917;
  --bento-ink: var(--text);
  --muted: rgba(28,25,23,0.68);
  --text-secondary: rgba(28,25,23,0.65);
  --card: rgba(255,253,250,0.62);
  --card2: rgba(255,253,250,0.70);
  --card-bg: rgba(255,253,250,0.65);
  --card-hover: rgba(161,98,7,0.12);
  --btn: rgba(68,64,60,0.14);
  --btn2: rgba(68,64,60,0.26);
  --border: rgba(28,25,23,0.18);
  --line: var(--border); /* F-1248: hairline divider alias */
  --border-accent: rgba(161,98,7,0.38);
  --btn-border: var(--border); /* light theme: --border is already a visible pill outline */
  /* L2 — button variant remaps, ground truth = capture Playwright empirique du
     rendu réel pré-L2 (cascade complète 54 fichiers, transitions désactivées)
     plutôt que lecture manuelle : secondary/danger gagnants = effects.css
     "Light: Buttons" (:4637+, même spécificité que les ex-blocs variables.css,
     mais chargé après → l'emporte) ; primary = effects.css bloc thémé
     :4657 (idem) ; ai = ex-bloc variables.css btn.btn--ai (pas de concurrent
     effects.css sur ce variant) ; ghost/outline/warn/success/link héritent
     déjà d'un rendu correct via --text/--border/--accent-rgb/--status-*-rgb,
     eux-mêmes remappés ci-dessus. */
  /* CT-C5-F11: bento remapped btn--secondary to --status-muted/--muted → every secondary
     button (e.g. "Choisir ce mentor") read as DISABLED grey-brown, inconsistent with the
     :root default which uses --accent. Match :root: a subtle-accent tint (still de-emphasized
     vs primary, but clearly an actionable button, and coherent across themes). */
  --btn-secondary-bg: rgba(var(--accent-rgb), 0.08);
  --btn-secondary-border: 1px solid rgba(var(--accent-rgb), 0.22);
  /* P3 FIX-R ter L1/L3 (`GAt-1`) — même jeton de texte qu'au :root. En bento
     `--accent-text: var(--accent)` (:778) : substitution NO-OP, teinte inchangée à l'octet.
     Elle est écrite ici pour que les deux thèmes lisent la MÊME règle — un seul jeton d'encre
     accentuée, jamais l'accent natif sur du texte. */
  --btn-secondary-fg: var(--accent-text);
  --btn-secondary-hover-bg: rgba(var(--accent-rgb), 0.14);
  --btn-secondary-hover-border: 1px solid rgba(var(--accent-rgb), 0.28);
  /* T2.2 — canon SOLIDE, re-déclaré ici (formule identique au :root) pour
     forcer la ré-résolution de --status-danger/--text-inverse à cette échelle
     (cf. commentaire --btn-ai-fg plus haut). */
  --btn-danger-bg: var(--status-danger);
  --btn-danger-border: transparent;
  --btn-danger-fg: var(--text-inverse);
  --btn-ai-bg: var(--gradient-ai);
  --btn-ai-hover-bg: var(--gradient-ai);
  --btn-ai-border: 1px solid rgba(var(--fuchsia-rgb), 0.45);
  --btn-ai-hover-border: 1px solid rgba(var(--status-muted-rgb), 0.36);
  --btn-ai-shadow: 0 4px 22px rgba(var(--fuchsia-rgb), 0.30);
  --btn-ai-hover-shadow: 0 8px 30px rgba(var(--fuchsia-rgb), 0.30);
  /* --btn-ai-fg / --btn-primary-fg re-déclarés ici (formule identique au :root) :
     --text-inverse n'est PAS re-résolu à travers une chaîne var() héritée —
     un token :root qui référence var(--text-inverse) reste figé sur la valeur
     de --text-inverse au point de déclaration (ici html/:root), pas sur celle
     de l'élément qui le consomme. Vérifié empiriquement (repro minimale). */
  --btn-ai-fg: var(--text-inverse);
  --btn-primary-fg: var(--text-inverse);
  /* P2-Z re-gate — fond PLEIN du CTA primaire (cf. la note du :root) : --accent-dark #854d0e,
     texte inverse #fffbeb 6,7:1. Le dégradé ambre reste DÉCORATIF. */
  --btn-primary-bg: var(--accent-dark);
  --btn-primary-border: 1px solid rgba(var(--accent-rgb), 0.50);
  --btn-primary-shadow: 0 4px 18px rgba(var(--accent-rgb), 0.35), 0 2px 6px rgba(var(--accent-rgb), 0.20);
  --btn-primary-hover-shadow: 0 8px 30px rgba(var(--accent-rgb), 0.45), 0 3px 8px rgba(var(--accent-rgb), 0.25);
  --btn-base-bg: rgba(var(--white-rgb), 0.68);
  --btn-base-border: 1px solid rgba(var(--status-muted-rgb), 0.22);
  --btn-base-hover-bg: rgba(var(--white-rgb), 0.85);
  --btn-base-hover-border: 1px solid rgba(var(--status-muted-rgb), 0.36);
  --btn-base-hover-shadow: rgba(var(--text-rgb), 0.12) 0 4px 14px;
  /* Re-déclarations forcées (même formule qu'au :root) pour les variantes qui
     référencent un token de base thémé (--text/--border/--accent/--status-*) :
     un token :root de la forme var(--x) reste figé sur la valeur racine de
     --x, il ne se ré-évalue PAS sur celle de l'élément consommateur (cf.
     commentaire --btn-ai-fg plus haut). Sans ceci, ghost/outline/warn/
     success/link/danger-outline fuitent les couleurs Obsidian. */
  /* T2.2 — canon SOLIDE (idem --btn-danger-* ci-dessus). */
  --btn-success-bg: var(--status-ok);
  --btn-success-border: transparent;
  --btn-success-fg: var(--bg1);
  --btn-warn-bg: rgba(var(--status-warn-rgb), 0.15);
  --btn-warn-border: 1px solid rgba(var(--status-warn-rgb), 0.30);
  --btn-warn-fg: var(--status-warn);
  --btn-warn-hover-bg: rgba(var(--status-warn-rgb), 0.25);
  --btn-warn-hover-border: 1px solid rgba(var(--status-warn-rgb), 0.45);
  --btn-outline-border: 1px solid var(--border);
  --btn-outline-fg: var(--text);
  --btn-outline-hover-bg: rgba(var(--accent-rgb), 0.08);
  --btn-outline-hover-border: 1px solid var(--accent);
  /* P3 FIX-R quater L1/L3 — même substitution qu'en Obsidian, NO-OP ici : `--accent-text:
     var(--accent)` en bento (`variables.css:791`). Le jeton reste écrit une seule fois par thème. */
  --btn-outline-hover-fg: var(--accent-text);
  --btn-ghost-fg: var(--text-secondary);
  --btn-ghost-hover-fg: var(--text);
  --btn-link-fg: var(--accent);
  --btn-danger-outline-border: 1px solid rgba(var(--status-danger-rgb), 0.30);
  --btn-danger-outline-fg: var(--danger-text);
  --btn-danger-outline-hover-bg: rgba(var(--status-danger-rgb), 0.10);
  --btn-danger-outline-hover-border: 1px solid rgba(var(--status-danger-rgb), 0.50);
  /* Theme-aware table surface — warm ink tint (preserves sand hue) + visible
     hairline on light. Resolves via --text-rgb (28,25,23) / --border above. */
  --table-tint: rgba(var(--text-rgb), 0.07);
  --table-edge: var(--border);
  --accent: #a16207;
  --accent-light: #ca8a04;
  --accent-dark: #854d0e;
  --accent-rgb: 161, 98, 7;
  --accent2: #b45309;
  --accent2-light: #d97706;
  --accent2-rgb: 180, 83, 9;
  --accent3: #92400e;
  --primary: var(--accent);
  --primary-hover: var(--accent-dark);
  --primary-rgb: 161, 98, 7;
  --accent-purple: #92400e;
  --accent-purple-rgb: 146, 64, 14;
  --accent-soft: rgba(161,98,7,0.5);
  --gradient-primary: linear-gradient(135deg, #a16207 0%, #ca8a04 50%, #d97706 100%);
  --gradient-ai: linear-gradient(135deg, rgba(146,64,14,0.95) 0%, rgba(180,83,9,0.90) 38%, rgba(161,98,7,0.82) 100%);
  /* AI identity colours — warm indigo/teal that bridges bento warmth with AI cool */
  --ai-color-1: #7e5bef;
  --ai-color-1-rgb: 126, 91, 239;
  --ai-color-2: #14b8a6;
  --ai-color-2-rgb: 20, 184, 166;
  /* Shadows — warm undertone */
  --shadow: 0 25px 50px -12px rgba(28,25,23,0.18);
  --shadow-sm: 0 10px 25px -5px rgba(28,25,23,0.14);
  --shadow-glow: 0 0 40px rgba(161,98,7,0.08);
  --shadow-hover: 0 4px 12px rgba(28,25,23,0.14);
  --shadow-focus: 0 0 0 3px rgba(161,98,7,0.18);
  --shadow-card-hover: 0 6px 20px rgba(28,25,23,0.16);
  --bg-opaque: rgba(232,224,212,0.98);
  --bg-opaque-light: rgba(238,231,220,0.95);
  /* Drawer / popup background — warm gradient pour le thème light.
     Empêche le "dark bleed" sur drawers, popovers, modal, sticky head. */
  --bg-popup: linear-gradient(170deg, rgba(254,252,247,0.96) 0%, rgba(245,238,225,0.96) 100%);
  --surface: rgba(68,64,60,0.08);
  --fg-muted: #78716c;
  --text-rgb: 28, 25, 23;
  --text-soft: rgba(28,25,23,0.55);
  --text-inverse: #fffbeb;
  /* Call UI — warm equivalents */
  --call-bg: rgba(255,253,250,0.55);
  --call-bg-deep: var(--bg2);
  --call-border: rgba(28,25,23,0.18);
  --call-surface: rgba(255,253,250,0.5);
  --call-surface-border: rgba(28,25,23,0.18);
  --call-panel-bg: rgba(255,253,250,0.72);
  --call-accent: #ca8a04;
  --call-accent-hover: #a16207;
  --call-accent-rgb: 202, 138, 4;
  --call-text-muted: #78716c;
  --call-text-dim: #a8a29e;
  /* Data visualization palette — vivid colors for readability on warm backgrounds */
  /* Exception to warm theme: data-viz MUST use distinct colors for accessibility */
  --data-indigo: #4f46e5;
  --data-indigo-deep: #4338ca;
  --data-indigo-light: #6366f1;
  --data-purple: #7c3aed;
  --data-purple-deep: #6d28d9;
  --data-purple-light: #8b5cf6;
  /* Component aliases */
  --bg-darker: var(--bg0);
  --bg-subtle: var(--surface);
  --shadow-lg: var(--shadow);
  --text-primary: var(--text);
  --text-muted: var(--muted);
  --bg-hover: var(--card-hover);
  --bg-card: var(--card);
  --bg-input: var(--bg2);
  --bg-elevated: var(--card2);
  --bg-secondary: var(--bg2);
  --bg-tertiary: rgba(0,0,0,0.08);
  --on-primary: #fff;
  /* Radar chart theming — warm (complete set) */
  --radar-grid: rgba(0,0,0,0.10);
  --radar-axis: rgba(0,0,0,0.16);
  --radar-label: #44403c;
  --radar-tick: #a8a29e;
  --radar-dot-ring: rgba(28,25,23,0.85);
  --radar-pill-bg: rgba(255,253,250,0.85);
  --radar-pill-shadow: 0 2px 8px rgba(0,0,0,0.08);

  /* ── Warm replacements for cool accent RGB companions ── */
  --cyan-rgb: 180, 83, 9;           /* warm amber (was teal 6,182,212) */
  --emerald-rgb: 120, 113, 108;     /* warm stone (was green 16,185,129) */
  --gray-blue-rgb: 168, 162, 158;   /* warm gray (was cool blue-gray 148,163,184) */

  /* ── Data-viz palette — vivid for readability (not warm-shifted) ── */
  --data-cyan: #0891b2;
  --data-cyan-deep: #0e7490;
  --data-cyan-light: #06b6d4;
  --data-green: #059669;
  --data-green-deep: #047857;
  --data-green-light: #10b981;
  --data-blue: #2563eb;
  --data-blue-deep: #1d4ed8;
  --data-blue-light: #3b82f6;
  --data-gray-deep: #57534e;

  /* ── Semantic text colors — warm, readable, mutually distinct ── */
  /* These are used for 100+ UI elements (badges, statuses, checkmarks).
     Data-viz colors are handled by --data-* variables above (vivid, not warm-shifted).
     Each must be: (a) WCAG AA on #e8e0d4 sand bg, (b) distinct from each other, (c) warm-compatible. */
  --info-text: #1e3a5f;        /* navy warm — 8.8:1 contrast — distinct from gold/amber */
  --success-text: #166534;     /* forest green — 5.4:1 contrast — warm green, not cool emerald */
  --danger-text: #b91c1c;      /* red-700 warm — 4.9:1 contrast */
  --warning-text: #92400e;     /* amber-800 warm — 5.4:1 contrast */

  /* ── Gradient accent — warm ── */
  --gradient-accent: linear-gradient(135deg, #d97706 0%, #b45309 100%);

  /* === UI Unity W1 — variables sémantiques de fidélité (audit 2026-06-11) ===
   * Valeurs d'origine retrouvées dans git (commits 4fdb8603 / 9a46795d) — la
   * traduction hardcodé→var de juin avait rabattu ces nuances sur des tokens
   * trop proches (ΔE 25+). Exception « fidélité » validée par le propriétaire. */
  --bento-espresso: #451a03;        /* brun torréfié — départ du dégradé bannière */
  --bento-mahogany: #78350f;        /* acajou — point médian bannière */
  /* Tuiles outils IA landing — échelle ambre→espresso perceptuellement distincte
   * (ΔE > 7 entre chaque), chaque bouton assorti à l'icône de sa tuile. */
  --bento-tile-accent-1: #a16207;   --bento-tile-accent-1-rgb: 161, 98, 7;
  --bento-tile-accent-2: #b45309;   --bento-tile-accent-2-rgb: 180, 83, 9;
  --bento-tile-accent-3: #92400e;   --bento-tile-accent-3-rgb: 146, 64, 14;
  --bento-tile-accent-4: #ca8a04;   --bento-tile-accent-4-rgb: 202, 138, 4;
  --bento-tile-accent-5: #78350f;   --bento-tile-accent-5-rgb: 120, 53, 15;
  --bento-tile-accent-6: #451a03;   --bento-tile-accent-6-rgb: 69, 26, 3;
  /* --call-accent / --call-accent-hover / --call-accent-rgb already defined above
   * (lines 1109-1111) — OR en Ink & Gold, violet conservé en Obsidian. */

  /* === UI Unity W1.10 — fuites Slate-Mist comblées (couleurs froides uniquement) ===
   * Script de diff (node -e blockVars) : 69 vars Slate-Mist non couvertes par le bloc
   * bento-only (Strategy 1). Décisions var par var :
   *
   * LEAVE — valeur neutre/sémantique universelle ou déjà chaude :
   *   --danger/success/warning/info : rgba tints sémantiques (<0.16 opacity), couleur
   *     source importe peu → bento lisible sans override.
   *   --call-hangup : rouge universel d'urgence.
   *   --data-amber/rose/red/pink-deep/orange-deep : palette data-viz intentionnellement
   *     vive (commentaire code « vivid colors for readability, not warm-shifted »).
   *   --status-ok/warn/danger + RGBs : vert/ambre/rouge → déjà dans la gamme chaude.
   *   --status-muted : #64748b slate-600 → near-neutral, commentaire « already passes AA ».
   *   --severity-critical/high/medium + RGBs : rouge/orange/ambre → chauds.
   *   --severity-info : #475569 slate-600 → near-neutral, impact visuel faible.
   *   --bg-glass*, --bg-scrim*, --border-soft : rgba(0,0,0,…) / rgba(255,255,255,…) → achromatiques.
   *   --ct-load-* : déjà surchargés par le bloc Slate-Mist avec palette ambre/or (anti-FOUC correct).
   *
   * OVERRIDE — couleurs froides réelles (lavande/indigo/violet) qui tachent le fond chaud :
   *   --status-info : #1d4ed8 (bleu-600 froid) → navy warm #1e3a5f (8.8:1 sur #e8e0d4)
   *   --severity-low : #6d28d9 (violet-700 froid) → ambre-800 warm #92400e (cohérent --warning-text)
   */
  --status-info: #1e3a5f;           /* navy warm — était bleu-600 #1d4ed8 (froid) ; 8.8:1 sur bg sable */
  --status-info-rgb: 30, 58, 95;
  --severity-low: #92400e;          /* amber-800 warm — était violet-700 #6d28d9 (froid) ; cohérent --warning-text */
  --severity-low-rgb: 146, 64, 14;

  /* === UI Unity W1.11 — focus rings & ombres de cartes bento ===
   * --shadow-hover / --shadow-focus / --shadow-card-hover existent déjà dans ce bloc
   * (vérification grep : lignes ~1089-1091 ci-dessus) → pas de doublon.
   * Manquants : --shadow-ring-primary / -lg (héritage :root indigo) et --shadow-card.
   * rgba sur la base ambre --accent (#a16207 = rgb(161,98,7)). */
  --shadow-ring-primary: 0 0 0 2px rgba(161, 98, 7, 0.18);
  --shadow-ring-primary-lg: 0 0 0 3px rgba(161, 98, 7, 0.18);
  --shadow-card: 0 4px 16px rgba(161, 98, 7, 0.06);
}

/* --- Strategy 2: Override literal hardcoded cold rgba values --- */
/* These selectors override properties where the shared light/bento block
   uses literal rgba(100,116,139,...), rgba(241,237,252,...), or rgba(79,70,229,...)
   instead of CSS variables. */

/* Topbar */
body.bento-theme .topbar,
body.bento-theme .topbar-slim {
  background: rgba(245,240,235,0.88);
  border-bottom-color: rgba(28,25,23,0.18);
}

/* Card — warm shadow + stronger border for Ink & Gold contrast */
body.bento-theme .card {
  -webkit-backdrop-filter: blur(8px) saturate(1.1);
  backdrop-filter: blur(8px) saturate(1.1);
  border-color: rgba(28,25,23,0.12);
  box-shadow: 0 2px 8px rgba(28,25,23,0.06), 0 0 0 1px rgba(28,25,23,0.04);
}

/* Modal head */
body.bento-theme .modalHead {
  border-bottom-color: rgba(28,25,23,0.16);
}

/* Tabs */
body.bento-theme .tab {
  background: rgba(68,64,60,0.10);
}

body.bento-theme .tab:hover {
  background: rgba(68,64,60,0.16);
}

body.bento-theme .tab.active {
  background: rgba(161,98,7,0.16);
  color: var(--accent);
  border-color: var(--accent);
}

/* Form fields */
body.bento-theme .field input,
body.bento-theme .field textarea,
body.bento-theme .field select {
  background: rgba(255,253,250,0.82);
  border-color: rgba(28,25,23,0.22);
}
/* Re-gate finding (2026-07-24): restored, corrected — same as the shared
   light/bento block above. Not !important for the same reason (effects.css
   wins in practice); kept for defense-in-depth / consistency. */
body.bento-theme .field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%231c1917' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' stroke-opacity='0.68'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  background-size: 10px 6px;
}

body.bento-theme .field input:focus,
body.bento-theme .field textarea:focus,
body.bento-theme .field select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(161,98,7,0.16);
}

/* Buttons — source unique components.css, thémé par tokens --btn-* (L2) */

/* Sidebar/Nav — Warm Sand */
body.bento-theme .sidebar,
body.bento-theme .app-sidebar {
  background: rgba(245,240,235,0.88);
  border-right-color: rgba(28,25,23,0.18);
}

/* Sidebar nav hover/active */
body.bento-theme .sidebar .navItem:hover,
body.bento-theme .app-sidebar .sidebar__item:hover {
  background: rgba(68,64,60,0.10);
}

body.bento-theme .sidebar .navItem.active,
body.bento-theme .app-sidebar .sidebar__item.active {
  background: rgba(161,98,7,0.14);
  color: var(--accent-dark);
}

/* Tables */
body.bento-theme table th {
  background: rgba(68,64,60,0.12);
}

body.bento-theme table tr:hover {
  background: rgba(68,64,60,0.08);
}

body.bento-theme table td {
  border-color: rgba(68,64,60,0.12);
}

/* Dropdowns/Menus — already fixed via variable overrides (--lavender-rgb etc.) */

/* Menu item hover */
body.bento-theme .dropdown li:hover,
body.bento-theme .menuItem:hover {
  background: rgba(68,64,60,0.10);
}

/* Badges */
body.bento-theme .badge {
  background: rgba(68,64,60,0.14);
}

/* Toast notifications */
body.bento-theme .toast {
  background: rgba(255,253,250,0.85);
  border-color: rgba(28,25,23,0.22);
  box-shadow: 0 10px 40px rgba(28,25,23,0.16);
}

/* Scrollbar */
body.bento-theme ::-webkit-scrollbar-track {
  background: rgba(68,64,60,0.08);
}

body.bento-theme ::-webkit-scrollbar-thumb {
  background: rgba(68,64,60,0.22);
}

body.bento-theme ::-webkit-scrollbar-thumb:hover {
  background: rgba(68,64,60,0.34);
}

/* Form inputs (standalone selector) */
body.bento-theme select,
body.bento-theme input,
body.bento-theme textarea {
  background: rgba(255,253,250,0.82);
}

/* Theme toggle button */
/* ── <details>/<summary> topbar menus (iOS Safari fix) ─────── */
/* Browser-native open/close — immune to iOS phantom click events */
.topbar-details {
  position: relative;
  display: inline-flex;
}
/* Remove default <details> marker/triangle in all browsers */
.topbar-details > summary { list-style: none; }
.topbar-details > summary::-webkit-details-marker { display: none; }
.topbar-details > summary::marker { display: none; content: ''; }

.themeToggle {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--fg);
  cursor: pointer;
  /* iOS Safari: see .langToggle / .userBtn--avatar — prevents 300ms tap delay
     + phantom click synthesis that would re-toggle immediately. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  line-height: 1;
  padding: 0;
  transition: all var(--duration-base);
}

.themeToggle:hover {
  background: var(--card2);
  border-color: var(--accent); /* un APLAT : l'accent natif y reste, doctrine du jeton (:107-115) */
  /* P3 FIX-R quater L1/L3 — 3ᵉ occurrence de la MÊME cause, dans le MÊME fichier : le GLYPHE du
     bouton de thème sur `--card2` (fond composé rgb(22,32,53) en Obsidian) faisait 3,64:1 —
     SOUS AA ; `--accent-text` le porte à 5,45:1. NO-OP en bento et en Sage & Forest
     (`--accent-text: var(--accent)`). */
  color: var(--accent-text);
}

/* When lang-picker dropdown is moved to <body> by JS (escapes topbar stacking context),
   ensure it's visible above everything. JS sets top/left dynamically. */
body > .lang-picker {
  position: fixed !important;
  z-index: 99999 !important;
  max-width: calc(100vw - 16px);
}
/* Notif dropdown & user menu — same escape pattern as theme/lang pickers.
   position:absolute inside .topbar-slim (z-index:100 stacking context) traps
   these elements, causing them to be hidden behind content on iOS Safari. */
body > .notif-dropdown {
  position: fixed !important;
  z-index: 99999 !important;
  max-height: calc(100vh - 80px);
  max-height: calc(100dvh - 80px);
}
@media (min-width: 769px) {
  body > .notif-dropdown {
    max-width: calc(100vw - 16px);
  }
}
@media (max-width: 768px) {
  body > .notif-dropdown {
    border-radius: 0 0 var(--radius-12) var(--radius-12);
  }
}
body > .userMenu {
  position: fixed !important;
  z-index: 99999 !important;
  max-width: calc(100vw - 16px);
}
@keyframes topbar-picker-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* ── Language picker ──────────────── */
.langToggle {
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-xs, 6px);
  padding: 4px 8px;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  color: var(--text);
  /* iOS Safari: ensure tap works reliably + prevent 300ms tap delay + phantom click synthesis.
     Same pattern as .userBtn--avatar (layout.css:103). Without this, Safari iOS waits ~300ms
     for double-tap-to-zoom detection and may synthesize a phantom click that immediately
     toggles <details> a 2nd time, closing the lang picker right after opening.
     Reference: memory/feedback_safari_phantom_tap_topbar_regression.md */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: background var(--duration-fast), border-color var(--duration-fast);
}
.langToggle:hover { background: var(--card-hover); border-color: var(--accent); }

.lang-picker {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 180px;
  max-width: calc(100vw - 16px);
  background: var(--bg-opaque, rgba(12,18,36,0.97));
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  padding: 6px;
  z-index: var(--z-dropdown, 50);
  display: none;
  animation: topbar-picker-in var(--duration-fast) ease;
}
.lang-picker.open,
.topbar-details[open] > .lang-picker { display: block; }

.lang-picker-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-xs, 6px);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-default);
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--text-sm, 13px);
}
.lang-picker-item:hover { background: var(--card-hover); }
.lang-picker-item.active {
  background: rgba(var(--primary-rgb, 99,102,241), 0.12);
  font-weight: 600;
}

/* ── P2-Z 1b-E (dossier D19) — SÉLECTEUR DE LANGUE EN LIBELLÉS, pas en drapeaux ──────
   L'item D19 « drapeaux → libellés FR/EN/ES/NL » était coché sans preuve visuelle. Il ne
   l'était pas : `.lang-picker-flag` peignait un drapeau en dégradés CSS et MASQUAIT son
   propre texte (`font-size: 0; color: transparent`). Le déclencheur du menu (#langFlag)
   n'affichait donc AUCUN libellé — on ne pouvait pas savoir quelle langue était active
   sans ouvrir le menu — et un drapeau ne désigne pas une langue (le néerlandais est parlé
   en Belgique, l'anglais hors du Royaume-Uni, l'espagnol hors d'Espagne).
   La pastille porte désormais le CODE de langue, lisible, thémé par tokens, et le menu
   garde le nom complet à côté. Verrou : ui/__tests__/p2z_1b_e_surfaces.test.mjs. */
.lang-picker-flag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 18px;
  padding: 0 4px;
  border-radius: var(--radius-xs, 4px);
  flex-shrink: 0;
  font-family: var(--font-mono, monospace);
  font-size: var(--text-2xs, 10px);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  color: var(--text);
  background: var(--card2);
  border: 1px solid var(--border);
}
/* P3 L8 (J-083) — « sélecteur FR avec une BORDURE IMBRIQUÉE DANS UNE AUTRE BORDURE ». Le
   déclencheur `#langToggle` porte déjà sa bordure et son rayon ; la pastille de code qu'il
   contient en ajoutait une seconde, à 2 px de la première. Dans le MENU la pastille garde sa
   boîte (elle y sépare le code du nom de la langue) ; sur le DÉCLENCHEUR, où elle est seule,
   elle n'est plus qu'un libellé. ⛔ Aucun texte perdu : le code de langue reste affiché.
   ⚠️ `border: 0`, et surtout PAS une bordure rendue transparente : ① une bordure transparente
   laisserait ses 2 px de boîte, c'est-à-dire exactement l'imbrication constatée ; ② la
   déclaration `border-color:` suivie de `transparent` CONTIENT, caractère pour caractère, le
   motif que le gardien D19 de P2-Z cherche dans ce bloc pour interdire à la pastille de masquer
   son propre texte (`ui/__tests__/p2z_1b_e_surfaces.test.mjs:600`). Le texte n'était pas masqué,
   mais le gardien avait raison de rougir : la formulation était ambiguë, elle ne l'est plus. */
.langToggle > .lang-picker-flag {
  background: transparent;
  border: 0;
  padding: 0;
  min-width: 0;
}
.lang-picker-label { flex: 1; }
.lang-picker-check {
  width: 16px;
  font-size: 13px;
  text-align: center;
  /* P3 FIX-R quater L1/L3 — 4ᵉ et DERNIÈRE occurrence de la cause dans ce fichier : la coche de la
     langue active est un GLYPHE, sur `--card`/`--card2` (3,91:1 / 3,64:1 en Obsidian, SOUS AA) ⇒
     5,86:1 / 5,45:1. NO-OP dans les deux thèmes clairs. */
  color: var(--accent-text);
}

@media (max-width: 480px) {
  .lang-picker { right: -8px; min-width: 160px; }
  .lang-picker-item { padding: 12px; min-height: 44px; }
}

/* ── Topbar menu close overlay (iOS Safari fix) ───────────── */
/* Transparent full-screen overlay behind open topbar menus.
   Catches genuine "outside" taps to close the menu.
   Immune to iOS Safari phantom click events on document/body. */
.topbar-menu-overlay {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-dropdown, 50) - 1);
  background: transparent;
  /* Allow scroll-through on the overlay — only capture taps */
  touch-action: auto;
  -webkit-tap-highlight-color: transparent;
  cursor: default;
}
