:root {
  /* Indique au navigateur que l'UI tourne par defaut en sombre.
     Effet : les widgets natifs (scrollbars, <input type="date|time">,
     <select> popup, autofill) prennent un theme sombre coherent
     au lieu de flasher en blanc. */
  color-scheme: dark;

  /* ─── Police d'interface et de lecture (selecteur Calme / Lisible / Confort) ───
     Onest : dessinee pour les ecrans, hauteur d'x genereuse, lisible des 9px.
     Depuis 2.11 elle sert TOUT : corps, titres et marque. Une seule famille
     chargee, 41,9 Ko pour les deux sous-ensembles (cf. src/css/fonts.css).
     La hierarchie vient des graisses (400 a 800), jamais d'un changement de
     famille. */
  --font-body: "Onest", "Onest Fallback", system-ui, -apple-system, sans-serif;

  /* ─── Police des titres / labels d'interface ───
     Token distinct de --font-body pour deux raisons : le selecteur de police
     (data-font="lisible"/"confort") ne redefinit que --font-body, et les
     titres gardent ainsi Onest quand le corps passe en police systeme. */
  --font-display: "Onest", "Onest Fallback", system-ui, sans-serif;

  /* ─── Police de marque (logo / wordmark uniquement) ───
     Meme famille que l'interface depuis 2.11 : la marque se distingue par la
     graisse 800 et le crenage manuel de la paire pT (--brand-kern-pt), pas
     par une seconde police a telecharger. */
  --font-brand: "Onest", "Onest Fallback", system-ui, sans-serif;

  /* ─── Crenage manuel du mot-symbole, paire « pT » ───
     La jambe du p et la barre du T laissent un trou optique en graisse 800 :
     Onest ne corrige pas cette paire. Valeur en em pour suivre la taille du
     mot-symbole (20px en barre laterale, 32px sur l'ecran de connexion).
     Consomme par .brand-word__t (layout.css). */
  --brand-kern-pt: -0.045em;

  /* ─── Police monospace (compteurs, chronos, codes UE) ───
     Permet d'aligner verticalement les chiffres tabulaires sans dependre
     d'une police web supplementaire. */
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", "Menlo", "Consolas", monospace;

  /* ─── Echelle typographique : 7 pas, construite sur les GRAPPES mesurees ───
     L'ancienne echelle etait une progression theorique : 6 de ses 9 pas
     n'ont jamais ete consommes et aucune des tailles reellement employees
     (9, 10.5, 11, 11.5, 12.5, 13, 13.5, 14.5, 15, 17, 19, 21) n'y figurait.
     Celle-ci part de la distribution reelle des 573 font-size mesurees :
     trois pics dominent (12px x108, 13px x101, 11px x89) et 87 % de la
     population vit entre 10 et 16px.
     PLANCHER 12px : rien en dessous pour du texte lu. Le gras a 11px sur un
     Android d'entree de gamme est sous le seuil de confort, et l'app sert a
     lire des cours. Ce qui reste sous 12px est une exclusion motivee
     (pastille, compteur, widget dense), listee dans audit-exclusions.json,
     jamais un pas d'echelle.
     Doctrine complete : DESIGN.md. */
  --text-xs:   12px;   /* plancher : libelles, meta, capitales d'accroche */
  --text-sm:   13px;   /* interface courante : listes, cartes, boutons */
  --text-base: 14px;   /* corps : la taille que body declare */
  --text-md:   16px;   /* lecture confortable, cible tactile, saisie */
  --text-lg:   20px;   /* titres de section, valeurs mises en avant */
  --text-xl:   28px;   /* titres de page, grands nombres */
  --text-2xl:  40px;   /* chiffres heros (chrono, compteur de revision) */

  /* ─── Graisses : echelle FERMEE a 4 pas ───
     Onest est servi en `font-weight: 400 800` (fonts.css) : au-dela, l'axe
     variable est simplement borne par le navigateur. La fermeture est le
     point : une variable permet n'importe quelle valeur, et c'est
     exactement ce qui a produit 343 declarations dispersees sur
     500/600/700/800. Toute valeur intermediaire (450, 550...) est une
     regression, pas une nuance. 500 et 600 occupaient la meme bande de
     taille (11 a 13px) : c'etait un role ecrit deux fois, ils fusionnent
     sur emphasis.
     La marque garde sa constante hors echelle, elle arrivera avec son
     premier consommateur. */
  --weight-body:     400;  /* texte courant : paragraphes, notes, cours */
  --weight-emphasis: 600;  /* libelles, boutons, titres secondaires */
  --weight-heading:  700;  /* titres de section et de carte */
  --weight-display:  800;  /* grands nombres, titres heros */

  /* ─── Interlignage d'interface ───
     L'interlignage depend de la TAILLE, pas du composant : mesure avant
     migration, a 13px le projet portait NEUF valeurs differentes. Ce
     n'etait pas une hierarchie, c'etait du bruit. Ce pas-ci couvre
     l'interface courante (11 a 16px) et sert de base au body.
     Pourquoi 1.5 : boites de ligne ENTIERES aux tailles usuelles
     (12->18, 14->21, 16->24). Sur un panneau basse densite, un
     interlignage fractionnaire fait sautiller les lignes d'un pixel par
     arrondi. C'est aussi le plancher de confort de WCAG 1.4.12.
     tight : titres et grands nombres, ET toute valeur d'origine <= 1.25,
     qui est une intention serree explicite de l'auteur (la rabattre sur le
     defaut du pas serait une refonte, pas une migration).
     loose : texte long lu en continu (notes, cours, markdown assistant,
     pages legales), aligne sur ce que les reglages Lisible (1.6) et
     Confort (1.72) appliquent deja au body.
     Le pas `none` (ligne unique, centrage et non lecture) arrivera avec son
     premier consommateur. Doctrine complete : DESIGN.md. */
  --leading-tight:  1.2;
  --leading-normal: 1.5;
  --leading-loose:  1.7;

  /* ─── Interlettrage : resserrer les grandes tailles, ecarter les capitales ───
     Le zero n'est PAS un token : aux petites tailles en casse normale, on
     supprime la declaration. 48 interlettrages positifs vivaient sur du
     texte en casse normale, marqueur de mise en page reglee a l'oeil.
     tight : titres et grands nombres, l'unique pas negatif (les micro-
     resserrements de -0,005 a -0,015em ont ete supprimes : illisibles a
     l'ecran, reglages a l'oeil). */
  --tracking-caps:      0.06em;  /* capitales courantes : libelles, tags */
  --tracking-tight:    -0.02em;  /* grands titres et grands nombres */
  --tracking-code:      0.2em;   /* codes a recopier (partage) : chaque signe isole */

  /* ─── Motion (durees + easings) ───
     Source unique du mouvement UI (lot 1 refonte). Le choix base/screen se
     fait par la DISTANCE PARCOURUE, pas par le type de composant :
       fast   : feedback immediat (hovers, etats, tactile)
       base   : l'element apparait SUR PLACE (fondu, leger scale, changement
                d'etat ; modales centrees et overlays immobiles inclus)
       slow   : apparition ample mais sur place (pages, cartes, loaders)
       screen : l'element TRAVERSE une distance significative (feuille qui
                monte du bas, panneau qui glisse d'un bord, ecran plein,
                ~40 % d'une dimension ecran ou plus) + barres de progression
       flip   : geste signature, flip 3D des flashcards (tout ajout dans
                cette famille doit etre un geste identitaire, pas un
                contournement de l'echelle)
     Une seule courbe UI : --ease-out. Ce qui vit hors echelle (boucles
     d'ambiance, suivi temps reel, kill-switch, celebrations, ressorts)
     est liste avec motif dans design/audit-exclusions.json. Doctrine
     complete : DESIGN.md. */
  --dur-fast:   140ms;
  --dur-base:   200ms;
  --dur-slow:   320ms;
  --dur-screen: 450ms;
  --dur-flip:   550ms;
  --ease-out:  cubic-bezier(.2, .8, .2, 1);  /* signature physique deja en usage */

  /* ─── Couches (z-index) ───
     Six bandes, du bas vers le haut ; aucun z-index en dur ailleurs. Dans
     une bande, un decalage par calc() garde l'ordre fin entre voisins
     (table complete : design/qa/2.12.0/CORRECTIFS.md, section 2).
       base    empilement local a l'interieur d'un composant (tuile, carte)
       sticky  bandeaux et barres a l'interieur d'une page ou d'une surface
       barre   chrome de l'app : barre du haut, onglets, tiroir, capsule d'appel
       feuille surfaces qui recouvrent une page : Apte, lecteur, partage, cartes
       modale  ce qui bloque et attend une reponse : couche commune (couche.js),
               confirmation, selecteur, portes de connexion et des conditions
       toast   messages et chargeurs, au-dessus de tout
     Une fenetre ouverte depuis une autre ne choisit pas son z-index : la
     couche commune l'empile au-dessus de celle qui l'a ouverte. */
  --z-base: 0;
  --z-sticky: 10;
  --z-barre: 100;
  --z-feuille: 1000;
  --z-modale: 2000;
  --z-toast: 3000;

  /* ─── Arrière-plans ─── */
  --bg: #070a08;
  --bg2: #0c1209;
  --bg3: #10160e;
  --surface: #141d12;
  --surface2: #192416;
  --border: #1d2b1a;

  /* ─── Accent principal ─── */
  --green: #3dd68c;
  --green2: #1fc47a;
  --green3: #0e9f6e;
  --green-dim: #3dd68c18;
  --green-glow: #3dd68c30;
  /* A11Y-01 : accent utilisable en PETIT TEXTE (WCAG AA 4.5:1). Sur fond
     sombre le vert clair passe largement (10.6:1) ; le theme light le
     redefinit en version assombrie (#0a7d55 -> 5.15:1 sur blanc). */
  --green-text: #3dd68c;

  /* ─── Couleurs fixes ─── */
  --red: #f87171;
  --red-dim: #f8717118;
  --orange: #fb923c;
  --orange-dim: #fb923c22;
  --orange3: #ea580c;
  --white: #f0f4ef;
  --black: #000000;
  /* Pastilles du selecteur de theme : la couleur de chaque theme, fixe. */
  --swatch-light: #edf1eb;
  --swatch-blue: #38bdf8;
  --swatch-green: #0e9f6e;
  --swatch-rose: #c75a7a;
  /* Podium des classements : or, argent, bronze (teintes maison). */
  --medal-gold: #d69a1e;
  --medal-silver: #8d9aa6;
  --medal-bronze: #a8632a;
  /* Surlignage de recherche dans le lecteur (jaune papier, ambre courant). */
  --viewer-mark: #ffd60085;
  --viewer-mark-current: #ff8800c7;
  /* Note "Facile" du moteur de revision (bleu ardoise maison, stable cross-theme). */
  --rev-easy: #6f8fd8;
  /* Reflet de lumiere ascendant du bouton assistant ("Up qui monte"). */
  --fab-sheen: rgba(255, 255, 255, 0.22);

  /* ─── Texte ─── */
  /* Contrastes calibres WCAG sur la surface la plus CLAIRE ou le texte
     peut vivre (--surface2, chips et lignes), pas sur --bg (DESIGN.md,
     section Contraste). Mesure par scratchpad/contrast.cjs :
     - --text   #e2ede0 -> 13,4:1 sur surface2 (AAA)
     - --muted  #899d89 -> 5,5:1 (AA texte courant, avec marge)
     - --muted2 #798d77 -> 4,5:1 : le pas le plus discret reste AA. Avant,
       3,7:1 sur --bg et 3,0:1 sur surface2 alors qu'il portait des
       libelles de 11 px. */
  --text: #e2ede0;
  --muted: #899d89;
  --muted2: #798d77;

  /* ─── Rayons : une valeur par ROLE (DESIGN.md, section Rayons) ───
     Le meme arrondi partout est un aveu de gabarit. Chaque pas porte un
     role et une justification :
       xs   : ce qui doit rester presque exact (barres, pastilles, tags)
       sm   : controles (boutons, champs, options, items de liste)
       base : cartes et panneaux
       lg   : modales, feuilles, surfaces heros et couches flottantes
       pill : capsules (badges, chips, segments) */
  --radius-xs:   4px;
  --radius-sm:   8px;
  --radius:      14px;
  --radius-lg:   20px;
  --radius-pill: 999px;

  /* ─── Espacement : echelle sur base 4 (DESIGN.md, section Tableau de bord) ───
     Lot 4 ouvert sur un seul ecran : chaque pas est ne avec son premier
     consommateur (dashboard.css), aucun n'a ete declare en avance.
       1 : respiration interne d'une ligne (libelle sous une valeur)
       2 : ecart entre deux lignes d'un meme bloc
       3 : ecart entre deux elements d'une liste
       4 : marge interne d'un bloc de contexte
       5 : marge interne du bloc « maintenant », ecart entre blocs de contexte
       6 : ecart entre deux niveaux de l'ecran */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  /* ─── Ombre : une seule, pour les couches flottantes ───
     La lumiere vient d'en haut : le decalage vertical depasse le flou, et
     le spread negatif garde l'ombre sous l'element au lieu de l'auréoler.
     Les surfaces posees (cartes) n'ont pas d'ombre : la valeur du fond
     fait la profondeur. */
  --shadow: 0 20px 16px -14px #00000066;

  /* ─── Sémantiques ─── */
  --accent-logo-end: #0a7550;
  --tip-bg-a: #0e9f6e14;
  --tip-border: #0e9f6e30;

  /* ─── Icônes (duotone) ───
     `--icon-tint` : wash de remplissage derrière le tracé, donne le rendu
     duotone façon Supabase Studio / Notion. Duotone renforce (decision
     M. PASKOD 2026-09-17, valide sur la navigation puis generalise) : ~41 %
     sur fond sombre, le point milieu entre l'ancien repos (32 %) et l'actif
     (50 %), pour tenir face a la densite des cartes. */
  --icon-tint: #3dd68c69;
  --icon-tint-active: #3dd68c80;
  /* Epaisseur unique du trait (DESIGN.md, section Icones). Heritee par les
     clones <use> ; avec vector-effect="non-scaling-stroke" dans le sprite,
     elle rend la meme largeur en px a toutes les tailles. */
  --icon-stroke: 1.75px;
  /* Cible tactile minimale (decision M. PASKOD 2026-09-16, minimum store) :
     tout controle qui ne porte qu'une icone, et chaque ligne de navigation,
     offre au moins cette boite, meme si le glyphe fait 16 a 24px. */
  --tap-min: 44px;
  /* Place reservee sous le contenu par la barre d'onglets mobile (barre
     d'environ 58 px et sa respiration), hors zone systeme. Consommee par le
     contenu, les toasts et les elements flottants poses au-dessus d'elle
     (utilities.css, components.css). */
  --bottom-tabs-space: 76px;
  /* Diametre de l'orbe d'Apte (components.css). */
  --fab-size: 58px;
  /* Au telephone, l'orbe a sa propre case au bout de la barre d'onglets :
     un peu plus petite pour tenir dans la barre sans la deborder, toujours
     au-dessus de la cible tactile minimale (utilities.css, components.css). */
  --fab-size-barre: 48px;
  /* Monogramme de la marque dans la sidebar (DESIGN.md, section Marque) :
     le favicon a l'echelle 1, la meme forme que la future icone d'app. */
  --brand-mark: 32px;
  /* Hauteur du bandeau hors connexion (layout.css) : 0 en ligne ; hors
     ligne, Sync._renderOfflineBar y ecrit la hauteur mesuree du bandeau, et
     la coquille (topbar collante, sidebar, contenu) descend d'autant, pour
     que le bandeau ne recouvre jamais l'en-tete ni le bouton du menu. */
  --offline-bar-h: 0px;
  /* Zones systeme (barre d'etat, barre de navigation, encoche). Deux sources
     selon la plateforme, d'ou le max() :
     - env(safe-area-inset-*) : iOS, web mobile, et Android quand le WebView
       est en edge-to-edge (Chromium 140+ avec viewport-fit=cover) ;
     - var(--safe-area-inset-*) : injecte sur <html> par le pont Capacitor 8
       (plugin SystemBars, insetsHandling "css") pour les WebView ou env()
       renvoie zero a tort.
     Quand le pont decale deja le WebView nativement, les deux valent zero :
     le max() n'ajoute donc jamais de retrait en double. */
  --safe-top: max(env(safe-area-inset-top, 0px), var(--safe-area-inset-top, 0px));
  --safe-right: max(env(safe-area-inset-right, 0px), var(--safe-area-inset-right, 0px));
  --safe-bottom: max(env(safe-area-inset-bottom, 0px), var(--safe-area-inset-bottom, 0px));
  --safe-left: max(env(safe-area-inset-left, 0px), var(--safe-area-inset-left, 0px));
  /* Retrait haut restant a la charge de la coquille. Quand le bandeau hors
     connexion est visible, il occupe deja la zone systeme et publie sa
     hauteur (safe area comprise) dans --offline-bar-h ; la topbar et la
     sidebar, deja descendues d'autant, ne doivent alors rien ajouter. */
  --safe-top-shell: max(0px, calc(var(--safe-top) - var(--offline-bar-h)));
  /* Vert de la marque (DESIGN.md, section Marque) : le fond du monogramme
     partout ou il represente l'app et non l'interface, favicon, icone du
     launcher, splash natif et web. Constant dans les quatre themes, a la
     difference de --green3 qui suit le theme. Lu par les generateurs
     (favicon, ressources Android, capacitor.config.ts). */
  --brand: #0e9f6e;

  /* ─── Tokens sémantiques (T28) ─────────────────────────────────────
     Couche d'aliases nommés par INTENTION, pas par couleur. Permet aux
     composants (page Examens en premier) de declarer "danger" / "warning"
     / "primary" sans dependre du token technique sous-jacent. Les tokens
     existants (--green, --red, --orange) restent utilisables — c'est une
     surcouche, pas un remplacement. */
  --color-primary: var(--green);
  /* Texte d'accent : --green est une couleur de remplissage ; en theme
     clair, ecrite en texte, elle tombait a 3,3:1. */
  --color-primary-text: var(--green-text);
  --color-primary-soft: var(--green-dim);
  --color-primary-strong: var(--green3);
  --color-surface: var(--surface);
  --color-surface-soft: var(--surface2);
  --color-danger: var(--red);
  --color-danger-soft: var(--red-dim);
  --color-warning: var(--orange);
  --color-warning-soft: var(--orange-dim);
  --color-muted: var(--muted);
  --color-text: var(--text);

  /* ─── Assistant (overlay / boutons primaires) ─── */
  --overlay-scrim: #00000073;
  --overlay-scrim-solid: #000000c2;
  /* Texte pose sur l'accent (boutons primaires). Sur les themes sombres
     l'accent est clair : le texte est SOMBRE (5,9:1), le blanc ne
     faisait que 3:1. Le theme clair remet le blanc (5,1:1 sur #0a7550). */
  --on-primary: var(--bg);

  /* ─── Sevérité d'echeance (T28) ─────────────────────────────────────
     4 niveaux + passe. Utilises sur la border-left des cards, le compteur
     de temps et les pulses critiques. Calm = "rien d'urgent". Soon = "OK
     mais c'est dans la fenetre de revision". Warn = "tu dois t'y mettre".
     Urgent = "<24h ou critique mark explicite". Passed = archivable. */
  --severity-soon: var(--green);
  --severity-warn: var(--orange);
  --severity-urgent: var(--red);
  --severity-passed: var(--muted2);

  /* ─── Fonds de salon (lot A salons) ─────────────────────────────────
     8 aplats presets, identiques dans tous les themes (l'identite d'un
     salon ne change pas avec le theme du visiteur). Teintes maison, pas
     les valeurs par defaut d'un framework. Consommes par rooms.css
     (.room-cover--*) et le picker de creation. Le texte blanc pose dessus
     tient 4,5:1 sur chacun. */
  --roomcover-aurora: #0f7f58;
  --roomcover-ocean: #1f5f9a;
  --roomcover-sunset: #b8542a;
  --roomcover-violet: #5f4fae;
  --roomcover-foret: #2b6b3d;
  --roomcover-sable: #8a6236;
  --roomcover-nuit: #2c3644;
  --roomcover-rose: #a8396a;
}

/* ─── Thème Bleu ─── */
[data-theme="blue"] {
  --bg: #060c14;
  --bg2: #0a1628;
  --bg3: #0c1a30;
  --surface: #0f1f3d;
  --surface2: #132847;
  --border: #1a3356;
  --green: #7dd3fc;
  --green2: #38bdf8;
  --green3: #0ea5e9;
  --green-dim: #38bdf820;
  --green-glow: #38bdf840;
  --green-text: #7dd3fc;
  --text: #e2eeff;
  /* Calibre sur surface2 #132847 : muted 5,5:1, muted2 4,5:1. */
  --muted: #88a1bb;
  --muted2: #7991a8;
  --accent-logo-end: #0369a1;
  --tip-bg-a: #0ea5e918;
  --tip-border: #0ea5e940;
  --icon-tint: #38bdf869;
  --icon-tint-active: #38bdf880;
}

/* ─── Thème Clair ─── */
[data-theme="light"] {
  color-scheme: light;
  /* Neutres teintes vert (jamais un gris pur ni un blanc pur) : le fond
     est assez sombre pour que les cartes se detachent SANS bordure. */
  --bg: #edf1eb;
  --bg2: #f6f8f5;
  --bg3: #e4eae2;
  --surface: #fbfcfa;
  --surface2: #e8ede6;
  --border: #cfd8cc;
  --green: #0e9f6e;
  --green2: #0c8a5f;
  --green3: #0a7550;
  --green-dim: #16a34a18;
  --green-glow: #16a34a30;
  /* Petit texte vert : #0e9f6e ne fait que 3.4:1 sur blanc -> assombri
     jusqu'a 4,5:1 au moins sur la surface la plus sombre (bg3 #e4eae2) et
     sur le lavis --green-dim pose sur --bg (5,3:1, finitions 2.12.0). */
  --green-text: #086a47;
  --text: #1a2118;
  /* Calibre sur bg3 : muted 5,8:1, muted2 4,5:1 (avant 2,3:1). */
  --muted: #4c5d49;
  --muted2: #5e6c5c;
  /* Rouge et orange en TEXTE sur fond clair : les valeurs sombres passent
     4,5:1 ; les versions -dim (fonds) suivent. */
  --red: #a84c4c;
  --red-dim: #a84c4c1a;
  --orange: #985824;
  --orange-dim: #9858241f;
  --on-primary: var(--white);
  --shadow: 0 18px 14px -14px #1a211840;
  --accent-logo-end: #0a7550;
  --tip-bg-a: #0e9f6e10;
  --tip-border: #0e9f6e30;
  /* Mode clair : wash sur fond blanc, un peu plus discret que sombre (28 %)
     mais toujours franc, pour rester lisible. */
  --icon-tint: #0e9f6e47;
  --icon-tint-active: #0e9f6e54;
  --overlay-scrim: #1a211866;
  --overlay-scrim-solid: #1a2118c2;
}

/*
 * Thème Rose — même famille « pro » que Vert / Bleu : fond sombre profond,
 * surfaces superposées, accent #FFBBC9 en lueur (pas un mode clair teinté).
 */
[data-theme="rose"] {
  --bg: #0f080b;
  --bg2: #140c10;
  --bg3: #1a1115;
  --surface: #22181d;
  --surface2: #2a1f25;
  --border: #3d2e36;
  /* Accent = rose poudré lumineux (icônes, hover) ; boutons = rose soutenu */
  --green: #ffbbc9;
  --green2: #f0a0b8;
  --green3: #c75a7a;
  --green-dim: #ffbbc922;
  --green-glow: #ffbbc948;
  --green-text: #ffbbc9;
  --text: #f7eaee;
  --muted: #b89aa4;
  /* Calibre sur surface2 #2a1f25 : 4,5:1 (avant 3,7:1). */
  --muted2: #97838d;
  --shadow: 0 20px 16px -14px #1a050a80;
  --accent-logo-end: #8b3d52;
  --tip-bg-a: #ffbbc914;
  --tip-border: #ffbbc938;
  --icon-tint: #ffbbc96d;
  --icon-tint-active: #ffbbc985;
}

html {
  /* Sans cette regle, l'overscroll/rubber-band laisse voir le fond
     blanc par defaut du navigateur derriere le body sombre — flash
     visible au scroll rapide sur mobile. */
  background-color: var(--bg);
  transition: background-color var(--dur-slow) var(--ease-out);
}

/* Coupe les transitions pendant un switch de theme rapide (evite l'effet
   "bizarre" quand on clique plusieurs fois sur le bouton theme). */
html.theme-switching,
html.theme-switching * {
  transition-duration: 0.001ms !important;
  animation-duration: 0.001ms !important;
}

/* ─── Modes de police (selecteur de lecture) ───
   calme = defaut (Onest, deja dans :root). Les deux autres ne font que
   redefinir le token --font-body + un rythme de lecture leger. Aucune police
   distante : on s'appuie sur les polices systeme presentes partout. */
html[data-font="lisible"] {
  /* Police native de l'appareil : la plus familiere et la plus nette, surtout
     sur Android d'entree de gamme. */
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
html[data-font="lisible"] body {
  line-height: 1.6;
}
html[data-font="confort"] {
  /* Verdana : grande hauteur d'x, lettres larges -> parait plus grand et plus
     reposant a px egal. Presente sur quasi tous les appareils ; DejaVu Sans en
     repli metrique sur Linux/Android. */
  --font-body: Verdana, "DejaVu Sans", system-ui, sans-serif;
}
html[data-font="confort"] body {
  line-height: 1.72;
}

::backdrop {
  background: var(--bg);
}

/* ─── Transition plein écran ─── */
html:-webkit-full-screen {
  background: var(--bg);
}

html:-moz-full-screen {
  background: var(--bg);
}

html:fullscreen {
  background: var(--bg);
}

html:-webkit-full-screen::backdrop {
  background: var(--bg);
}

html:-moz-full-screen::backdrop {
  background: var(--bg);
}

html::backdrop {
  background: var(--bg);
}

/* ─── Sélection de texte ─── */
::selection {
  background: var(--green-dim);
  color: var(--green);
}

/* ─── Curseur personnalisé desktop ─── */
@media (pointer: fine) {
  html { cursor: default; }

  a, button, [onclick], label[for],
  .nav-item, .tab, .doc-item,
  .slot, .course-item, .session-item,
  .cm-day, .wg-mobile-tab, .wg-mobile-slot,
  .pomo-btn, .icon-btn, .ntb-btn,
  .color-dot, .combo-option {
    cursor: pointer;
  }

  input, textarea, [contenteditable] {
    cursor: text;
  }

  :disabled, [disabled] {
    cursor: not-allowed;
  }
}

::-moz-selection {
  background: var(--green-dim);
  color: var(--green);
}

/* ─── Focus ring premium ─── */
:focus-visible {
  outline: 2px solid var(--green3);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* ─── Scrollbar premium ─── */
::-webkit-scrollbar {
  width: 4px;
  height: 4px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 99px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--green3);
}

* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}