/**
 * Mary Design System — Dark Mode v4
 *
 * Architecture:
 * - Invert global tokens (--gray-*, --mary-*, etc.)
 * - Module silos (--bo-*, --ag-*, --pos-*, etc.) keep working
 *   because they reference global tokens OR are aliased here.
 * - No mega-selector card list: components that use variables
 *   get dark mode for free via token inversion.
 * - Targeted overrides only for elements that need special treatment.
 *
 * Surface hierarchy:
 *   Base  (body):     #000000
 *   S1    (cards):    #161b22
 *   S2    (elevated): #1c2128  — hover states, nested panels
 *   S3    (popovers): #242a33  — modals, dropdowns
 *   Border:           #2d333b
 *   Border subtle:    #21262d
 */

/* ========================================
   1. GLOBAL TOKEN INVERSION
   All components using these variables
   get dark mode automatically.
   ======================================== */
html.dark-mode {
  color-scheme: dark;

  /* --- SOCLE DE THÈME (cf. _variables.css) ---
     Toute feuille qui exprime sa palette en alias de ce socle bascule ici,
     sans une seule ligne d'override côté app et sans rien à déclarer plus
     bas. C'est la sortie de la dette des soixante palettes jumelles. */
  --sf-page: #000000;
  --sf-page-fade: rgba(0, 0, 0, 0);
  --sf-1: #161b22;
  --sf-1-fade: rgba(22, 27, 34, 0);
  --sf-2: #1c2128;
  --sf-3: #21262d;
  --sf-pop: #242a33;
  --sf-under: #0d1117;
  /* Fond d'un contrôle : cf. `_variables.css`. Le survol descend d'un cran
     au lieu de monter, le sombre travaillant dans l'autre sens. */
  --sf-ctl: var(--sf-3);
  --sf-ctl-hover: #2b3139;
  --sf-ctl-press: #343b44;
  --sf-line: #2d333b;
  --sf-line-strong: #444c56;
  --ct-line: #6e7681;
  --ct-rail: var(--ct-line);

  --fg-1: #f0f6fc;
  --fg-2: #adbac7;
  --fg-3: #8b949e;
  /* 4,46 pour 1 sur #161b22, à un cheveu du seuil AA : éclairci d'un cran. */
  --fg-4: #7b8894;
  --fg-5: #6e7681;

  --ac-brand: #3fb950;
  --ac-brand-strong: #56d364;
  --ac-brand-soft: rgba(63, 185, 80, 0.15);
  --ac-brand-pulse: rgba(63, 185, 80, 0.25);
  /* Le bouton principal : ici le vert du thème est trop lumineux pour du blanc
     (2,54 pour 1). Il prend une encre sombre, 7,45, et le survol ÉCLAIRCIT au
     lieu d'assombrir, 9,82. Cf. le commentaire de `_variables.css`. */
  --ac-cta-bg: var(--ac-brand);
  --ac-cta-fg: #0d1117;
  --ac-cta-bg-hover: var(--ac-brand-strong);
  /* Cf. `_variables.css` : le rouge et l'ambre du thème sombre sont CLAIRS,
     leur encre est donc sombre, comme celle du bouton principal. */
  --ac-danger-fg: #0d1117;
  --ac-warn-fg: #0d1117;
  --ac-warn: #e3b341;
  --ac-warn-soft: rgba(227, 179, 65, 0.15);
  --ac-danger: #f85149;
  /* Cf. `_variables.css` : l'encre d'alerte d'une surface plus claire que la page. */
  --ac-danger-strong: #ff7b72;
  --ac-danger-soft: rgba(248, 81, 73, 0.15);
  --ac-info: #22d3ee;
  /* Cf. `_variables.css` : le canard du thème sombre est CLAIR, son encre est
     donc sombre, comme celle de l'alerte et de l'ambre. */
  --ac-info-fg: #0d1117;
  --ac-info-soft: rgba(34, 211, 238, 0.15);
  --ac-neutre: #adbac7;
  --ac-neutre-soft: rgba(139, 148, 158, 0.15);
  --ac-focus: 0 0 0 3px rgba(63, 185, 80, 0.35);

  /* --- Gray scale (single source of truth) --- */
  --gray-50: #0d1117;
  --gray-100: #161b22;
  --gray-200: #2d333b;
  --gray-300: #444c56;
  --gray-400: #768390;
  --gray-500: #8b949e;
  --gray-600: #adbac7;
  --gray-700: #cdd9e5;
  --gray-800: #e6edf3;
  --gray-900: #f0f6fc;

  /* --- Warm grays ---
     --gray-warm-50 porte DEUX rôles en clair, où ils tombent sur la même
     valeur (#ffffff) : le fond de page (body, dashboard.css) et la surface
     des cartes (283 usages, presque tous écrits `var(--gray-warm-50, #fff)`).
     En sombre les deux rôles divergent : à #000 la carte se confondait avec
     la page et toute la hiérarchie s'aplatissait en noir sur noir.
     Le jeton suit donc la CARTE (#161b22) ; le fond de page vient de
     `.dark-mode body` (section 3), qui pose --sf-page. */
  --gray-warm-50: #161b22;
  --gray-warm-100: #1c2128;
  --gray-warm-200: #21262d;

  /*
   * Slate, neutral, mary-gray: alias to --gray-*
   * so any component using these scales gets dark mode.
   * TODO: migrate components to --gray-* directly, then remove.
   */

  /* slate : gray */
  --slate-50: var(--gray-50);
  --slate-100: var(--gray-100);
  --slate-200: var(--gray-200);
  --slate-300: var(--gray-300);
  --slate-400: var(--gray-400);
  --slate-500: var(--gray-500);
  --slate-600: var(--gray-600);
  --slate-700: var(--gray-700);
  --slate-800: var(--gray-800);
  --slate-900: var(--gray-900);

  /* neutral : gray */
  --neutral-50: var(--gray-50);
  --neutral-100: var(--gray-100);
  --neutral-200: var(--gray-200);
  --neutral-300: var(--gray-300);
  --neutral-400: var(--gray-400);
  --neutral-500: var(--gray-500);
  --neutral-600: var(--gray-600);
  --neutral-700: var(--gray-700);
  --neutral-800: var(--gray-800);
  --neutral-900: var(--gray-900);
  --neutral-950: var(--gray-900);

  /* mary-gray : gray */
  --mary-gray-50: var(--gray-50);
  --mary-gray-100: var(--gray-100);
  --mary-gray-200: var(--gray-200);
  --mary-gray-300: var(--gray-300);
  --mary-gray-400: var(--gray-400);
  --mary-gray-500: var(--gray-500);
  --mary-gray-600: var(--gray-600);
  --mary-gray-700: var(--gray-700);
  --mary-gray-800: var(--gray-800);
  --mary-gray-900: var(--gray-900);

  /* --- Mary semantic ---
     Même bascule de rôle que --gray-warm-50 : sur ses ~295 usages,
     --mary-bg-primary sert de BLANC (surface de carte, encre sur bouton
     coloré, `--white: var(--mary-bg-primary)`), pas de fond de page. À #000
     les cartes disparaissaient dans la page. Secondary/tertiary sont les
     creux posés SUR cette surface : en sombre ils montent d'un cran au lieu
     de descendre, sinon le creux se confondait avec le fond. */
  --mary-bg-primary: #161b22;
  --mary-bg-secondary: #1c2128;
  --mary-bg-tertiary: #21262d;
  --mary-bg-dark: #f0f6fc;
  --mary-text-primary: #e6edf3;
  --mary-text-secondary: #8b949e;
  --mary-text-tertiary: #768390;
  --mary-text-inverse: #000000;
  --mary-border-light: #21262d;
  --mary-border-medium: #2d333b;
  --mary-border-dark: #444c56;

  /* --- Shadows (glow-style for dark) --- */
  --shadow-color: rgba(0, 0, 0, 0.3);
  --shadow-color-strong: rgba(0, 0, 0, 0.5);
  --shadow-sm: 0 0 0 1px #21262d;
  --shadow-md: 0 3px 6px rgba(0, 0, 0, 0.4), 0 0 0 1px #21262d;
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.6);
  --shadow-2xl: 0 24px 64px rgba(0, 0, 0, 0.7);
  --shadow-brand-sm: 0 0 8px rgba(63, 185, 80, 0.15);
  --shadow-brand-md: 0 0 16px rgba(63, 185, 80, 0.2);
  --shadow-brand-lg: 0 0 32px rgba(63, 185, 80, 0.25);
  --mary-shadow-sm: var(--shadow-sm);
  --mary-shadow-md: var(--shadow-md);
  --mary-shadow-lg: var(--shadow-lg);
  --mary-shadow-xl: var(--shadow-xl);
  --focus-ring: 0 0 0 3px rgba(63, 185, 80, 0.4);

  /* --- Semantic: VIVID in dark (brighter, not darker) --- */
  --success-50: #0a1f0d;
  --success-100: #0d2f14;
  --success-500: #3fb950;
  --success-600: #3fb950;
  --success-700: #56d364;
  --warning-50: #1a1500;
  --warning-100: #2d2000;
  --warning-200: #c69026;
  --warning-500: #d29922;
  --warning-600: #e3b341;
  --danger-50: #1f0808;
  --danger-100: #310c0c;
  --danger-200: #da3633;
  --danger-500: #f85149;
  --danger-600: #f85149;
  --info-50: #0a1929;
  --info-100: #0d1f3c;
  --info-500: #58a6ff;
  --info-600: #58a6ff;

  --mary-success-light: #0d2f14;
  --mary-warning-light: #2d2000;
  --mary-error-light: #310c0c;
  --mary-info-light: #0d1f3c;

  /* --- Primary (vivid green) --- */
  --primary-50: #0a1f0d;
  --primary-100: #0d2f14;
  --primary-500: #3fb950;
  --primary-600: #3fb950;
  --primary-700: #56d364;
  --mary-primary-50: #0a1f0d;
  --mary-primary-100: #0d2f14;

  /* --- Secondary (vivid blue) --- */
  --secondary-50: #0a1929;
  --secondary-100: #0d1f3c;
  --mary-secondary-50: #0a1929;
  --mary-secondary-100: #0d1f3c;

  /* --- Layout --- */
  --rail-bg: #000000;
  --rail-border: #21262d;
  --top-bar-bg: #000000;
  --top-bar-border: #21262d;
  --tab-bar-bg: rgba(0, 0, 0, 0.92);
}

/* ========================================
   2. MODULE SILO ALIASES
   Each module defines its own --xx-* vars
   in its own CSS. Here we only override the
   ones that map to dark surface/text/border.
   This keeps silos independent.
   ======================================== */
html.dark-mode {
  /* Le back-office n'apparaît plus ici : static/css/backoffice.css déclare
     lui-même ses jetons ET leur bascule sombre (html.dark-mode). Redéclarer
     un --bo-* à cet endroit rouvrirait deux sources de vérité pour la même
     couleur, et celle-ci gagnerait selon l'ordre de chargement. */

  /* --- Agenda : plus rien ici. Les jetons --ag-primary-* et --ag-shadow-sm
     étaient déclarés par static/css/agenda.css, feuille supprimée le
     20/08/2026 — aucun gabarit ne la chargeait depuis le passage à
     agenda-v2.css, dont les jetons --ag-* dérivent des alias du socle
     (--fg-*, --sf-*, --ac-*) qui portent déjà leur bascule sombre. Une
     inversion sans déclaration d'origine est un poids mort. --- */

  /* --- Comptable : plus rien ici. Les jetons --cpt-* étaient déclarés par
     static/css/comptable.css, feuille supprimée le 20/08/2026 avec le gabarit
     base_accountant.html qu'elle habillait. Le portail comptable est passé à
     accountant-v2.css et ses jetons --acc-*, qui portent leur propre bascule
     sombre. Une inversion sans déclaration d'origine est un poids mort. --- */

  /* --- Finance --- */
}

/* POS — scoped to .pos-ui container */
html.dark-mode .pos-ui {

}

/* ========================================
   2b. MODULE SILOS — naming convention
   --xx-bg / --xx-bg-soft / --xx-bg-cream
   --xx-text / --xx-text-2 / --xx-text-3 / --xx-text-quiet / --xx-black
   --xx-border / --xx-border-strong
   --xx-mary / --xx-mary-soft / --xx-mary-pulse / --xx-mary-dark
   --xx-warn / --xx-warn-soft
   --xx-info / --xx-info-soft
   --xx-danger / --xx-danger-soft
   --xx-violet / --xx-violet-soft

   Used by 25+ apps following the same convention. Listing prefixes
   keeps the override idempotent — variables that don't exist in a
   given file are simply ignored.

   `html.dark-mode` (specificity 0,1,1) beats `:root` (0,1,0) declared
   inline in templates, so this works even for --rl-*, --ld-*, etc.
   defined in <style> blocks inside .html files.
   ======================================== */
html.dark-mode {
  /* --- ab- (sales/nouveau-abonnement) --- */
  /* --- acc- (accountant-v2) --- */

  /* --- ag- (agenda + agenda-v2) — extends section 2 above --- */

  --ag-cat-tache: #58a6ff;
  --ag-cat-perso: #e3b341;
  --ag-cat-rappel: #6fa8ff; --ag-cat-rappel-soft: rgba(111,168,255,0.18);
  --ag-cat-reunion: #f778ba; --ag-cat-reunion-soft: rgba(247,120,186,0.18);
   --ag-cat-autre-soft: rgba(139,148,158,0.18);
  --ag-backdrop: rgba(0,0,0,0.65);

  /* --- bk- (banking-v2) --- */

  /* --- cf- : plus rien à inverser. `category-form.css` est supprimée (aucune
     page ne la chargeait), et `.category-form-wrapper` n'existe plus dans aucun
     gabarit. Les fiches catégorie passent par categorie-record.css. --- */

  /* --- cp- (dashboard-mobile) — complété en 2c pour --cp-bg, qui passait
     par --mary-bg-primary et tombait donc à #000 pour une feuille. --- */
  /* --- cpt- (accountant / comptable) --- */
  /* --- db- (saas-dashboard) --- */

  --db-text-2: #adbac7;

  /* --- fd- (finance-detail-unified) --- */
  /* --- fn- (finance-v3) --- */
  /* --- fv- (finance-v2-tokens) --- */
  /* --fv- : finance-v2-tokens.css porte sa propre palette sombre complète.
     Ne rien redéclarer ici. */

  /* --- lp- : rien à habiller ICI, mais pas pour la raison écrite jusqu'au
     2026-08-29. `nouveau-lien-paiement.css` est bien partie ; en revanche
     `apps/catalog/produits.css` porte le même préfixe et EST chargée par la
     liste des produits. Elle déclarait `--lp-black: #1a1a1a` en littéral, dont
     `.lp-page` tirait la couleur de toute la page : du texte quasi noir sur
     fond sombre. Corrigé à la source, dans sa feuille, où le jeton alias
     désormais `var(--fg-1)`. Le garde-fou ne voit pas ce cas, il annonce
     lui-même ne pas vérifier la couverture jeton par jeton. --- */

  /* --- nc- (sales/nouvelle-commande) --- */

  /* --- of- (crm/opportunity-form) --- */
  /* --- pdv- : la feuille `pos/points_de_vente_form.css` a été SUPPRIMÉE le
     21/09/2026, morte depuis que `plan-salle.css` l'a remplacée. Aucun jeton
     `--pdv-*` n'était inversé ici : ce marqueur ne gardait qu'une place. --- */
     /* --- cm- : intentionnellement non surchargé en dark mode --------------
     Le namespace `cm-` est partagé par deux feuilles aux intentions opposées :
       - cuisine-mobile.css (KDS) : `--cm-bg: var(--slate-900)` : déjà
         dark-aware via les slate-*, pas besoin d'override ici.
       - pos-retail-mobile-v2.css (caisse retail) : light theme assumé
         (#f2f2f7 / #ffffff).
     Un override global ici écrasait les couleurs de la caisse retail et
     créait une « bande blanche » au-dessus de la zone search/menu. */

  /* --- pr- (saas/preferences) --- */
  /* --- pu- (purchasing-v2) --- */
  --pu-bg: #0d1117;

  /* --- rl- (crm/relations — declared inline in template) --- */
  /* --- sb- (sidebar-v2) --- */

  /* Grammaire Record : en sombre, une pastille active « surélevée » ne peut pas
     être plus blanche que le fond — elle est plus CLAIRE que le rail, avec un
     filet net et sans ombre portée (invisible sur fond sombre). */

  --sb-lift: 0 0 0 1px #444c56;
  --sb-lift-hover: 0 0 0 1px #586069;
  --sb-hover: rgba(255,255,255,0.06);

  /* --- tk- (tasks-v2) --- */

  --tk-danger: #f85149; /* --- tn- (tenant-v2) --- */

  /* --- tpe- (tpe-v2) --- */

  /* --- ob- (onboarding-v2) — extends section 2 --- */
  }

/* ========================================
   2c. SILOS RESTÉS EN CLAIR — déclarés sur :root
   Ces préfixes étaient posés par leur feuille sans jamais être repris ici :
   la page gardait ses cartes blanches et son encre noire au milieu d'une
   chrome sombre.

   Attention aux filets : `rgba(0,0,0,.07)` disparaît sur fond sombre — on
   les repasse en filet opaque, pas en noir transparent.
   ======================================== */
html.dark-mode {
  /* --- ps- (pos-modals : jetons posés sur :root pour que les modals
     tiennent seules sur mobile/TPE) --- */

  --ps-backdrop: rgba(0,0,0,0.72);

  /* --- auth- (saas-public : connexion, inscription, vérification) --- */

   --auth-green-bright: #56d364;

  /* --- achats- (purchasing) : `--achats-white` sert de fond de carte.
     Passé par --mary-bg-primary il tombait à #000, plus sombre que la page. --- */

  /* --- cp- (feuille mobile de dashboard-mobile) --- */

  --cp-overlay: rgba(0,0,0,0.6);
  --cp-handle-color: rgba(255,255,255,0.22);
  --cp-shadow: 0 -8px 32px rgba(0,0,0,0.6);
  /* `--mtb-bg` retiré le 2026-09-04 avec la barre du haut mobile, dont il
     inversait le fond. Le commentaire l'attribuait à « la barre d'onglets » :
     il n'a jamais rien fait pour elle. */
}

/* ========================================
   2d. SILOS POSÉS SUR UN ÉLÉMENT, PAS SUR :root
   Une variable personnalisée se résout par HÉRITAGE, pas par spécificité :
   quand `.cx-page { --cx-black: #1a1a1a }` la déclare, l'ancêtre le plus
   proche gagne pour ses descendants — un `html.dark-mode { --cx-black }`
   ne l'atteint JAMAIS, quelle que soit sa spécificité. Il faut reprendre
   le MÊME sélecteur.
   ======================================== */

/* Aide contextuelle — aucun bloc ici : tous les jetons de `aide-prose.css`
   renvoient au socle (`--fg-*`, `--sf-*`, `--ac-*`), qui bascule tout seul.
   Le seul qui n'y renvoyait pas, `--ah-link-rule` (le soulignement des liens),
   est parti avec ce soulignement le 25/09/2026. */

/* Grammaire Record des pages de consultation (shared/record-page.css).
   À ne pas confondre avec `.recd` (document-record.css), traité plus bas. */
html.dark-mode .rcd {

  --rcd-focus: 0 0 0 3px rgba(63,185,80,0.35);
}

/* CRM — pages globales. Les confirmations de suppression (.cd-page) sont
   passées sur la feuille Record (.recd), couverte plus haut. */
html.dark-mode .crm-page {

}

/* RETIRÉ le 21/09/2026 : le bloc `html.dark-mode .ti` n'existait que pour
   inverser `--tn-amber-border`, le seul jeton littéral que le cockpit
   d'invitation redéclarait chez lui. `invite-cockpit.css` ne déclare plus
   AUCUN alias `--tn-*` — il lit les jetons du socle directement, et ceux-là
   s'inversent déjà plus haut dans cette feuille. Le bloc était devenu du poids
   mort qui masquait la couverture réelle, exactement ce que le point 2 de
   `scripts/check_dark_mode.py` refuse ; c'est d'ailleurs lui qui l'a signalé. */

/* POS côté tableau de bord : sélecteur de client, encaissements en attente,
   états de paiement, page salle. */
html.dark-mode .cpk {

  --cpk-focus: 0 0 0 3px rgba(63,185,80,0.35);
}

html.dark-mode .eat {

}

html.dark-mode .pps {

}

html.dark-mode .tbl {

}

/* Écrans SaaS dont les jetons vivent dans un <style> de gabarit. */
html.dark-mode .billing-expired {

}

html.dark-mode .up-screen {

}

html.dark-mode .cx-page {

  --cx-focus: 0 0 0 3px rgba(63,185,80,0.35);
}

html.dark-mode .inv-page {

}

html.dark-mode .sc-page {

}

html.dark-mode #cookie-consent-banner {

}

/* Assistant IA (tenant/ai_assistant.html). */
html.dark-mode .aiq {

  --aiq-focus: 0 0 0 3px rgba(63,185,80,0.35);
}

/* Scoped silos: les templates sales (.ld-page) declarent leurs vars
   non-prefixees DANS le selecteur .ld-page, donc on cible le meme
   selecteur en dark mode pour pouvoir override. */
/* NE PAS purger comme `.recd` ci-dessous, tant que les jetons ne sont pas
   aliasés PARTOUT : `.ld-page` habille NEUF gabarits, dont sept déclarent encore
   `--mary: #00a86b` / `--text-muted: #86868b` en littéral (liste_devis,
   liste_contrats, liste_commande, liste_abonnement, liste_liens_paiement,
   liste_documents_commerciaux et leurs maquettes). Retirer ce bloc les rendrait
   en vert clair et en gris clair sur fond sombre. `liste_factures.html` alias
   désormais le socle : ce bloc n'y redit que les mêmes valeurs. */
html.dark-mode .ld-page {

  --text-muted: #8b949e;
  /* `--fg-4` et non #768390 : le relèvement de contraste du socle s'arrêtait
     ici, et ce gris sort à 4,46 pour 1 sur le fond sombre, sous le seuil AA de
     4,5 qui s'applique aux mentions de 10 et 11,5 px. Le socle rend 4,77. Vu
     sur `.tpz`, puis sur `.smx` le 17/10/2026 : le silo le redisait à chacun
     des vingt-quatre sélecteurs qu'il habille. */
  --text-quiet: var(--fg-4);

  --mary: #3fb950;

  --mary-dark: #56d364;

  --danger: #f85149;

  /* Le fond de page du socle (#000), comme les autres écrans : #0d1117 laissait
     sous chaque liste courte une bande noire, là où la page s'arrêtait. */
  background: #000000;
  color: var(--black);
}
html.dark-mode .ld-page .ld-msg.error { color: #f85149; }
html.dark-mode .ld-page .ld-msg.warning { color: #e3b341; }

/* Barre d'actions groupées des listes sales (factures ET devis, qui partagent ce
   bloc au caractère près). En clair c'est une pastille noire à texte blanc ;
   elle peignait son fond avec `var(--black)`, alias de `--fg-1`, qui vaut
   #f0f6fc en sombre : la barre virait au BLANC sous son propre texte blanc,
   soit 1,09 pour 1. Elle reste une surface sombre en sombre, simplement d'un
   cran au-dessus du fond de page pour se détacher.
   Même remarque pour `.ld-modal` : les deux vivent hors de `.ld-page`
   (position:fixed, enfants de <main>), donc le sélecteur ci-dessus ne les
   atteint pas. */
html.dark-mode .ld-bulk {
  --bulk-bg: #2d333b;
  --bulk-ink: #f0f6fc;
  --bulk-ink-quiet: #adbac7;
  --bulk-line: rgba(255, 255, 255, 0.16);
  --bulk-hover: rgba(255, 255, 255, 0.10);
  /* #f85149 ne fait que 3,80 pour 1 sur ce fond, sous le seuil pour du 12 px. */
  --bulk-danger: #ffa198;
  /* L'ombre portée ne se voit pas sur un fond noir : un filet la détache. */
  border: 1px solid var(--sf-line-strong);
}

/* Meme silo pour .recd (grammaire Record des ~25 fiches de consultation :
   devis, facture, contrat, lien de paiement, abonnement, CRM…) : les variables
   non prefixees sont declarees DANS le selecteur .recd, donc seul le meme
   selecteur peut les reprendre. Sans ce bloc la fiche restait blanche au milieu
   d'une chrome sombre. `--surface` pilote tous les fonds de la feuille. */
/* Six de ces sept variables redisaient MOT POUR MOT la valeur sombre du socle,
   parce que la feuille Record en recopiait la valeur CLAIRE au lieu d'y
   renvoyer. Elle y renvoie maintenant (`--text-muted: var(--fg-3)`, `--mary:
   var(--ac-brand)`, etc.), donc ce bloc n'a plus rien à redire — pire, il
   figerait le socle : le relèvement de contraste de `--fg-4` s'arrêtait ici,
   shadowé par un `--text-quiet` en dur. Seul l'or reste, l'ambre clair du socle
   (#b45309) n'étant pas cette couleur-là. */
html.dark-mode .recd {

  --gold: #e3b341;
}
/* `.recd .btn.primary` est SORTI de cette règle : il lit `--ac-cta-fg`, que le
   socle décline par thème (blanc en clair, #0d1117 en sombre). Le rattrapage
   ici figeait l'encre sombre et redisait, dans une feuille de thème, une
   décision que le jeton porte déjà. */
html.dark-mode .recd .recd-step.done .dot { color: #0d1117; }
/* `.dark-mode a:not([class])` (plus bas, 0,2,1) BATTAIT les deux règles par
   lesquelles le socle signale ses liens — `.recd-sub a` et `.recd-ph a`, toutes
   deux (0,1,1) : en sombre, le nom du client sous le titre et « Refaire le
   point » rendaient exactement le gris de leur voisinage, et plus rien ne disait
   qu'ils cliquent. Mesuré le 13/10/2026 sur la fiche d'affaire, #7b8894 contre
   le #56d364 que record-detail.css déclare. La règle du thème garde sa portée,
   et ces deux-là reprennent la leur. */
html.dark-mode .recd .recd-sub a,
html.dark-mode .recd .recd-ph a { color: var(--mary-dark); }
/* Deux fonds restent blancs par nature — un QR doit se scanner, et le viewer
   affiche un PDF a fond blanc : on les laisse, mais on les detache du sombre. */
html.dark-mode .recd .recd-qr,
html.dark-mode .recd .recd-viewer iframe { border-color: var(--border-strong); }

/* --- Topbar CTA dropdown panels (defined inline dans 6 _topbar_*.html) ---
   Le préfixe des achats était `pu-`, un nom que personne ne porte : le
   gabarit écrit `purchasing-cta-menu`. Six sélecteurs ne visaient donc
   rien, et le menu « + Nouveau » des achats s'ouvrait en blanc au milieu
   d'une barre sombre (constaté le 2026-08-26). */
.dark-mode .crm-cta-menu__panel,
.dark-mode .catalog-cta-menu__panel,
.dark-mode .ventes-cta-menu__panel,
.dark-mode .fv-cta-menu__panel,
.dark-mode .purchasing-cta-menu__panel,
.dark-mode .sales-cta-menu__panel {
  background: #1c2128;
  border-color: #2d333b;
  box-shadow: 0 12px 40px rgba(0,0,0,0.5), 0 2px 6px rgba(0,0,0,0.25);
}
.dark-mode .crm-cta-menu__item,
.dark-mode .catalog-cta-menu__item,
.dark-mode .ventes-cta-menu__item,
.dark-mode .fv-cta-menu__item,
.dark-mode .purchasing-cta-menu__item,
.dark-mode .sales-cta-menu__item { color: #e6edf3; }
.dark-mode .crm-cta-menu__item:hover,
.dark-mode .catalog-cta-menu__item:hover,
.dark-mode .ventes-cta-menu__item:hover,
.dark-mode .fv-cta-menu__item:hover,
.dark-mode .purchasing-cta-menu__item:hover,
.dark-mode .sales-cta-menu__item:hover { background: #242a33; color: #3fb950; }
.dark-mode .crm-cta-menu__item-icon,
.dark-mode .catalog-cta-menu__item-icon,
.dark-mode .ventes-cta-menu__item-icon,
.dark-mode .fv-cta-menu__item-icon,
.dark-mode .purchasing-cta-menu__item-icon,
.dark-mode .sales-cta-menu__item-icon { background: #161b22; color: #adbac7; }
.dark-mode .crm-cta-menu__item:hover .crm-cta-menu__item-icon,
.dark-mode .catalog-cta-menu__item:hover .catalog-cta-menu__item-icon,
.dark-mode .ventes-cta-menu__item:hover .ventes-cta-menu__item-icon,
.dark-mode .fv-cta-menu__item:hover .fv-cta-menu__item-icon,
.dark-mode .purchasing-cta-menu__item:hover .purchasing-cta-menu__item-icon,
.dark-mode .sales-cta-menu__item:hover .sales-cta-menu__item-icon { background: rgba(63,185,80,0.15); color: #3fb950; }

/* ========================================
   2f. GRAMMAIRE RECORD À JETONS NON PRÉFIXÉS
   Une vingtaine de feuilles « autonomes » posent leur palette sous des noms
   NUS (--black, --border, --mary…) sur leur propre wrapper, pour rester
   indépendantes du reste. Le corollaire : rien dans dark-mode.css ne
   pouvait les atteindre, et ces pages restaient blanches en sombre.
   Deux cas connus le rappelaient déjà — les fiches `.recd` et les listes
   `.ld-page`, traitées plus bas depuis longtemps.

   Un seul bloc pour tous ces wrappers : la grammaire est identique d'une
   feuille à l'autre, et poser un jeton qu'une feuille ne déclare pas ne
   coûte rien (il n'est simplement jamais lu). Une seule source de vérité,
   pas une règle par page.
   ======================================== */
html.dark-mode .pfr,      /* fiche produit          */
html.dark-mode .ssx,      /* miroir des sessions    */
html.dark-mode .tnr,      /* fiches tenant          */
html.dark-mode .ig-hub,   /* hub d'intégrations     */
html.dark-mode .dcf,      /* générateur de document */
html.dark-mode .rcr,
html.dark-mode .rcr-modal,/* réception de commande  */
html.dark-mode .rec,      /* formulaires CRM        */
html.dark-mode .ck,       /* cockpit CRM            */
/* `.ql` est la modale de journal du cockpit. Elle est posée EN SŒUR de `.ck`
   dans le gabarit, pas dedans : sans sa propre ligne ici, elle gardait le vert
   clair et les gris clairs au milieu d'une page sombre. */
html.dark-mode .ql,
html.dark-mode .ql-back,
html.dark-mode .sg,       /* segments CRM           */
html.dark-mode .pp,
html.dark-mode .pp-modal,
html.dark-mode .pp-pop,
html.dark-mode .pp-back,  /* prospection CRM        */
html.dark-mode .rl,       /* relations CRM ET liste des retours POS */
/* `.tpz` (session clôturée et rapport X) est SORTI de cette liste : sa feuille
   exprime désormais toute sa palette en alias du socle, exactement comme `.recd`
   plus bas. Les cinq jetons que ce bloc lui redisait valaient MOT POUR MOT la
   valeur sombre du socle — sauf un, `--text-quiet`, figé à #768390 : le
   relèvement de contraste de `--fg-4` s'arrêtait ici. Mesuré au navigateur sur
   « ENCAISSÉ », « TIROIR » et la ligne qui dit qui a ouvert la caisse : 4,46
   pour 1, sous le seuil AA de 4,5 qui s'applique à ce corps de texte. Rendu au
   socle : 4,77. */
html.dark-mode .pcr,      /* création de PDV        */
/* `.smx` (sessions de caisse sur TPE) est SORTI de cette liste le 17/10/2026,
   pour la même raison que `.tpz` ci-dessus : sa feuille exprime désormais toute
   sa palette en alias du socle. Les jetons que ce bloc lui redisait valaient mot
   pour mot la valeur sombre du socle, sauf `--text-quiet`, figé à #768390 : le
   relèvement de contraste de `--fg-4` s'arrêtait ici aussi. Mesuré au navigateur
   sur « ENCAISSÉ », la sous-ligne qui dit qui a ouvert la caisse et l'écart d'une
   clôture : 4,46 pour 1, sous le seuil AA de 4,5. Rendu au socle : 4,77. */
/* Mêmes noms, mais posés dans un <style> de gabarit plutôt que dans une
   feuille : 2FA, politique de consentement, résultats de recherche,
   tableau de bord des ventes. */
html.dark-mode .tfa-page,
html.dark-mode .ckp-page,
html.dark-mode .search-container,
html.dark-mode .s-page {

   --text-2: #adbac7;
  --text-muted: #8b949e; --text-3: #8b949e;
  /* `--fg-4` et non #768390 : le relèvement de contraste du socle s'arrêtait
     ici, et ce gris sort à 4,46 pour 1 sur le fond sombre, sous le seuil AA de
     4,5 qui s'applique aux mentions de 10 et 11,5 px. Le socle rend 4,77. Vu
     sur `.tpz`, puis sur `.smx` le 17/10/2026 : le silo le redisait à chacun
     des vingt-quatre sélecteurs qu'il habille. */
  --text-quiet: var(--fg-4);

  --mary: #3fb950; --mary-dark: #56d364;

  /* `--mary-line` : plus aucune feuille ne le déclare ni ne le lit. Son dernier
     lecteur était la réception par scan, dont les traits de contour sont partis
     le 12/10/2026 — le cadre vert d'un article suivi au numéro de série est
     devenu l'aplat vert tendre de la rangée. Même sort que `--mary-bright`
     ci-dessous : retiré pour rendre check_dark_mode vert. */

  --danger: #f85149;
  --red: #f85149;

  /* Le violet est banni du produit : ce qui portait ce nom retombe au neutre. */

  /* `--mary-bright` : plus aucune feuille ne le déclare ni ne le lit. Déjà mort
     avant cette passe ; retiré ici pour rendre check_dark_mode vert. */

  --focus: 0 0 0 3px rgba(63,185,80,0.35);
}

/* PATRON DE LISTE PARTAGÉ (shared/liste-record.css) — devis, factures,
   contrats, commandes, abonnements, liens de paiement, documents commerciaux…
   Le fichier contenait UNE règle `html.dark-mode` (pour .lr-ctl), ce qui
   suffisait à le faire passer pour traité : sa palette --lr-*, posée sur
   `.lr`, n'était en réalité jamais reprise. Le tableau et ses lignes
   restaient blancs au milieu d'une page sombre.
   Ne jamais conclure « ce fichier gère le sombre » parce qu'il MENTIONNE
   dark-mode : c'est jeton par jeton que ça se vérifie. */
html.dark-mode .lr {

  --lr-focus: 0 0 0 3px rgba(63,185,80,0.35);
}

/* Compléments de palettes dont la feuille ne porte pas encore son propre
   bloc sombre. Quand une feuille EN A un (finance-apple, _status,
   finance-v2-tokens, backoffice, pan…), rien ne doit être redéclaré ici :
   deux valeurs pour un même jeton se départagent à l'ordre de chargement. */
html.dark-mode {
  /* --db-mary-bright retiré avec la refonte du tableau de bord (2026-08-26) :
     saas-dashboard.css ne le déclarait ni ne le consommait plus, il ne restait
     que cette inversion sombre, orpheline. */

  /*

  --nc-focus: 0 0 0 3px rgba(63,185,80,0.35);
    --nc-g200: #1c2128; --nc-g300: #21262d;
  --nc-g400: #444c56; --nc-g500: #768390;
  --nc-g800: #cdd9e5;

  --nc-danger: #f85149;

  --nc-shadow: 0 0 0 1px #21262d, 0 12px 34px rgba(0,0,0,0.5);

  /* --pos- posé sur :root par pos-pdv-v2 : la section 2 ne le reprenait que
     sous .pos-ui, qui n'existe pas sur ces pages. */

  /* Fiche de profil / ticket : la « feuille » --tk-paper reste BLANCHE, elle
     mime un ticket imprimé — donc son encre reste noire. Seul le fond de page
     autour d'elle bascule. */

  /* Panier de caisse (_pos-tokens.css) : deux fonds écrits en blanc
     translucide, donc un panneau blanc laiteux au-dessus d'un écran noir. */
  --pos-cart-card-bg: rgba(28, 33, 40, 0.95);
  --pos-cart-frosted-bg: rgba(13, 17, 23, 0.92);
  --pos-cart-frosted-border-top: 0.5px solid rgba(255, 255, 255, 0.10);
  --pos-cart-card-shadow: 0 8px 24px rgba(0,0,0,0.55), 0 2px 6px rgba(0,0,0,0.35);

}

/* Onboarding (tenant/onboarding/main.html) : le gabarit ajoute sa propre
   palette nue par-dessus les jetons --ob-* de la feuille. */
html.dark-mode #onboarding-app {
     --ink4: #768390;

  --accent: #3fb950; --accent-d: #56d364;
}

/* Clôture de caisse (_cloturer_style.html) : encore d'autres noms, dont un
   « creux » (--sunk) qui doit rester PLUS clair que la carte en sombre,
   sinon la zone en retrait se confond avec le fond. */
html.dark-mode .cl3 {
  /* même cas que #tk-reg : #9a6400 ne s'aliase pas sur --ac-warn. */
  --amber: #e3b341;

   --ink-2: #adbac7; --ink-3: #8b949e;

  --accent: #3fb950;
  --red: #f85149;
}

/* Miroir Finance et Recouvrement : même intention, autres noms
   (--ink / --hair / --frbg / --card). */
html.dark-mode .fr,
html.dark-mode .rcv,
html.dark-mode .rca,
html.dark-mode .rcp {
   --ink-2: #adbac7; --ink-3: #8b949e;

   --soft-line: rgba(63,185,80,0.38);
  --red: #f85149; --warn-fill: #e3b341;
   --warn-line: rgba(227,179,65,0.38);
}

/* ========================================
   2e. LES TROIS CAISSES PLEIN ÉCRAN
   Les quatre écrans d'encaissement héritent d'une base DÉJÀ sombre
   (retail_desktop et restaurant_desktop de base_dashboard.html,
   retail_mobile et restaurant_mobile de base_mobile_pos.html) : la chrome,
   le corps, les champs natifs et les tables basculaient donc, mais chaque
   caisse gardait sa propre palette claire posée sur son wrapper. Résultat :
   des panneaux blancs au milieu d'un écran noir.

   Le KDS n'apparaît pas ici : il est sombre PAR NATURE (--kds-bg: #0a0a0a),
   en clair comme en sombre. Le convertir n'aurait aucun sens.
   ======================================== */

/* Restaurant v3 — salle, atelier, correctifs (.rv3 sur le wrapper page). */
html.dark-mode .rv3 {

   --rv3-accent-line: rgba(63,185,80,0.38);

   --rv3-warn-line: rgba(227,179,65,0.38);

   --rv3-danger-line: rgba(248,81,73,0.38);

  /* L'alerte « addition demandée » doit rester plus vive que le destructif. */

   --rv3-alert-line: rgba(255,123,114,0.42);

   --rv3-info-line: rgba(88,166,255,0.38);

  /* Une ombre portée ne se voit pas sur fond sombre : on garde une profondeur
     franche et on ajoute un filet, comme ailleurs dans la feuille. */
  --rv3-shadow-sm: 0 0 0 1px #21262d;
  --rv3-shadow-md: 0 4px 14px rgba(0,0,0,0.5), 0 0 0 1px #21262d;
  --rv3-shadow-lg: 0 12px 40px rgba(0,0,0,0.6), 0 0 0 1px #21262d;
  --rv3-shadow-glow-accent: 0 4px 14px rgba(63,185,80,0.35);
}

/* Restaurant mobile v4 (.rm-app). */
html.dark-mode .rm-app {

  --rm-overlay: rgba(0,0,0,0.62);

  --rm-mary-line: rgba(63,185,80,0.38);

  --rm-warn-line: rgba(227,179,65,0.38);

  --rm-alert-line: rgba(255,123,114,0.42);

  /* Les pastilles de catégorie sont des repères : elles doivent rester
     distinctes entre elles, donc on monte en luminosité sans changer de teinte. */
  --rm-cat-entrees: #3fb950;
  --rm-cat-plats: #e3b341;
  --rm-cat-desserts: #f778ba;
  --rm-cat-boissons: #58a6ff;

  /* Le chevron « retour » est un SVG en data: dont le trait est écrit en dur
     (stroke='%23000') : invisible sur fond sombre tant qu'on ne réécrit pas
     l'URL entière. */
  --rm-chevron-back: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e6edf3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 18l-6-6 6-6'/%3E%3C/svg%3E");

  --rm-shadow-md: 0 4px 12px rgba(0,0,0,0.5);
  --rm-shadow-lg: 0 8px 24px rgba(0,0,0,0.55);
  --rm-shadow-xl: 0 12px 40px rgba(0,0,0,0.65);
  --rm-shadow-dark: 0 8px 20px rgba(0,0,0,0.6);
}

/* Caisse retail mobile (.caisse-mobile-app) — grammaire iOS.
   Scopé au wrapper de la page et NON à :root : le namespace `cm-` est
   partagé avec cuisine-mobile.css, qui est déjà sombre (--cm-bg: slate-900).
   Un override global écraserait cette feuille-là. */
html.dark-mode .caisse-mobile-app {
  /* Les encres et les filets ne sont plus repris ici : `pos-retail-mobile-v2.css`
     les exprime en alias du socle (`--fg-*`, `--sf-line`), qui bascule tout seul.
     Deux sources pour un même jeton, c'est l'ordre de chargement qui départage,
     et les deux caisses finissaient sur deux gris différents en sombre.
     Ne restent que les deux teintes qui n'ont pas d'équivalent au socle. */

  /* Le rouge et l'orange systèmes iOS ont quitté la caisse le 2026-09-09, en
     clair comme en sombre. --cm-danger et --cm-warn pointent maintenant sur
     --ac-danger et --ac-warn, qui ont déjà leur variante sombre trente lignes
     plus haut : les redéclarer ici, c'était la troisième définition d'une même
     couleur, et celle qui gagnait. --cm-warning n'existe plus du tout, son nom
     était à une lettre de --cm-warn et c'est lui qui peignait les alertes. */
}

/* ========================================
   3. GLOBAL BASE
   ======================================== */
/* Le fond de page vient de --sf-page, pas de --mary-bg-primary : ce dernier
   suit désormais la surface des cartes (cf. section 1). */
.dark-mode body {
  background-color: var(--sf-page);
  color: var(--gray-800);
}

/* ========================================
   4. ELEVATED SURFACES
   Modals / dropdowns / command palette
   need S3 (#242a33), not S1.
   ======================================== */
.dark-mode .command-palette,
.dark-mode .cc-modal,
.dark-mode .cc-modal__body,
.dark-mode .dropdown-menu,
.dark-mode .popover,
.dark-mode .modal-content,
.dark-mode .mary-modal-content {
  background-color: #242a33;
  border-color: var(--gray-200);
  color: var(--gray-800);
  box-shadow: var(--shadow-xl);
}

.dark-mode .mary-modal-overlay,
.dark-mode .modal-overlay,
.dark-mode .cc-backdrop {
  background-color: rgba(0, 0, 0, 0.65);
}

/* ========================================
   5. CATCH-ALL: hardcoded white backgrounds
   Components using CSS variables don't need
   this. This only catches legacy components
   that use `background: white` or #fff.
   ======================================== */
.dark-mode .card,
.dark-mode .mary-card,
.dark-mode .mary-design-card,
/* `.notif-toast` et `.toast` sont ABSENTS de cette liste à dessein : ils sont
   bâtis sur les tokens --sb-*, déjà déclinés en sombre plus haut. Les y ajouter
   leur donnerait un fond --gray-100 pendant que les pilules à filet qu'ils
   contiennent resteraient sur --sb-surface, et le bouton se détacherait de sa
   propre carte. Cette règle-ci l'emporterait par spécificité (0,2,0 contre
   0,1,0), l'ordre de chargement n'y changerait rien.
   Ne reste ici que `.toast-notification`, dont le seul consommateur historique
   (apps/payments/tpe-detail.js) n'utilise pas ces tokens. */
.dark-mode .toast-notification {
  background-color: var(--gray-100);
  border-color: var(--gray-200);
  color: var(--gray-800);
}

/* ========================================
   6. FORM INPUTS
   Native elements don't use CSS variables.
   ======================================== */
.dark-mode input,
.dark-mode select,
.dark-mode textarea {
  background-color: var(--gray-50);
  border-color: var(--gray-200);
  color: var(--gray-800);
}

.dark-mode input::placeholder,
.dark-mode textarea::placeholder {
  color: var(--gray-400);
}

.dark-mode input:focus,
.dark-mode select:focus,
.dark-mode textarea:focus {
  border-color: var(--primary-500);
  box-shadow: var(--focus-ring);
}

.dark-mode select option {
  background-color: var(--gray-100);
  color: var(--gray-800);
}

/* ========================================
   7. TABLES
   ======================================== */
.dark-mode table {
  border-color: var(--mary-border-light);
}

/* L'APLAT A ÉTÉ RETIRÉ LE 19/10/2026. Cette règle peignait l'en-tête de TOUTE
   table du produit en #0d1117, et elle était seule à le faire : aucune feuille
   ne pose de fond sur `table th` en clair. Le mode sombre inventait donc une
   bande que le mode clair n'a pas, derrière des intitulés de colonne qu'un
   filet sépare déjà de leur contenu — « un trait sépare deux natures », et
   l'aplat en ajoutait un second par-dessus. Les en-têtes collants (import,
   prospection, portail) posent chacun leur propre fond, à une spécificité plus
   forte : ils ne bougent pas. Vu la première fois en septembre depuis la
   feuille des imports, qui devait repeindre `background:none` par-dessus. */
.dark-mode table th {
  border-color: var(--gray-200);
  color: var(--gray-800);
}

.dark-mode table td {
  border-color: var(--mary-border-light);
  color: var(--gray-600);
}

.dark-mode table tbody tr:hover td {
  background-color: var(--gray-100);
}

/* ========================================
   8. NOTIFICATIONS
   ======================================== */
.dark-mode .notif-panel {
  background: var(--gray-100);
  border-color: var(--gray-200);
  box-shadow: var(--shadow-lg);
}

/* Les règles sombres de l'ancien panneau (en-tête, segments, cartes, digest)
   visaient des classes que plus rien ne pose : retirées le 27/09/2026. */

/* ========================================
   9. COMMAND CENTER
   ======================================== */
.dark-mode .cc-search-input {
  background: var(--gray-50);
  border-color: var(--gray-200);
  color: var(--gray-800);
}

.dark-mode .cc-item:hover,
.dark-mode .cc-item.is-active {
  background: #1c2128;
}

.dark-mode .cc-section-title { color: var(--gray-400); }

/* ========================================
   10. PREFERENCES
   ======================================== */
.dark-mode .pref-avatar__img { background: #1c2128; color: var(--gray-800); }

.dark-mode .pref-qa-card.is-active {
  border-color: var(--primary-500);
  background: var(--primary-50);
}

.dark-mode .pref-select,
.dark-mode .pref-container select.form-control {
  background-color: var(--gray-50);
  border-color: var(--gray-200);
  color: var(--gray-800);
}

/* ========================================
   11. MISC
   ======================================== */
.dark-mode .skip-link { background: var(--gray-800); color: var(--mary-bg-primary); }
.dark-mode code, .dark-mode pre { background-color: var(--gray-100); color: var(--gray-800); border-color: var(--gray-200); }
.dark-mode hr { border-color: var(--mary-border-light); }
/* Ne vise QUE les liens nus. Avec `.dark-mode a`, la règle (0,1,1) battait la
   couleur que tout composant pose sur une seule classe : en sombre, l'onglet
   de période sélectionné de l'agenda rendait exactement la même couleur que
   les trois autres, et rien ne disait plus lequel était choisi. Relevé sur
   716 liens de six écrans ; aucun ne retombe sur le bleu du navigateur, les
   composants reprennent simplement la couleur qu'ils déclarent. */
.dark-mode a:not([class]) { color: inherit; }
.dark-mode a:hover { color: var(--primary-500); }
.dark-mode .mary-pagination-link.active { color: white; }

/* ========================================
   12. IMAGES — reduce glare on content images only
   ======================================== */
.dark-mode .main-content img:not([src*=".svg"]):not(.logo):not(.avatar):not(.pref-avatar__img):not(.profile-icon) {
  filter: brightness(0.9) contrast(1.05);
}

/* ========================================
   13. SCROLLBAR & SELECTION
   ======================================== */
.dark-mode ::-webkit-scrollbar { width: 8px; height: 8px; }
.dark-mode ::-webkit-scrollbar-track { background: var(--sf-page); }
.dark-mode ::-webkit-scrollbar-thumb { background: var(--gray-200); border-radius: 4px; }
.dark-mode ::-webkit-scrollbar-thumb:hover { background: var(--gray-300); }
.dark-mode ::selection { background: rgba(63, 185, 80, 0.25); color: var(--gray-900); }

/* ========================================
   14. THEME TOGGLE BUTTON
   ======================================== */
.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--gray-500);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
  padding: 0;
}

.theme-toggle:hover {
  background: var(--gray-100);
  color: var(--gray-700);
}

.theme-toggle svg {
  width: 18px;
  height: 18px;
  transition: transform 0.3s ease;
}

.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }
.dark-mode .theme-toggle .icon-sun { display: block; }
.dark-mode .theme-toggle .icon-moon { display: none; }
.dark-mode .theme-toggle:hover svg { transform: rotate(15deg); }

/* ========================================
   15. SMOOTH TRANSITION (toggle only)
   Targeted — only top-level surfaces,
   not every element in the DOM.
   ======================================== */
html.dark-mode-transition body,
html.dark-mode-transition .card,
html.dark-mode-transition .mary-card,
html.dark-mode-transition .mary-design-card,
html.dark-mode-transition .toast,
html.dark-mode-transition nav,
html.dark-mode-transition header,
html.dark-mode-transition .sidebar,
html.dark-mode-transition .desktop-rail,
html.dark-mode-transition .desktop-top-bar,
html.dark-mode-transition .mobile-tab-bar,
html.dark-mode-transition .modal-content,
html.dark-mode-transition .notif-panel {
  transition: background-color 0.2s ease,
              color 0.15s ease,
              border-color 0.2s ease;
}

/* ========================================
   16. PREFERS-REDUCED-MOTION (a11y)
   Couvre toutes les animations infinites
   du projet : pulse KPI, spinners, shimmers,
   pulse-action, etc. Place ici car dark-mode.css
   est charge dans tous les base_*.html templates.
   ======================================== */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
