/**
 * @file   app.css
 * @role   Feuille de style applicative — systeme a DEUX themes
 *         (un jeu de NOMS, deux jeux de VALEURS ; le gabarit ne connait que les noms)
 * @author Kad
 * @stack  Symfony 7.3 / Twig / Bootstrap 5.3.8
 * @since  2026-09-13
 *
 * Charte : ~/www/studiokad_design/assets/turfgenius/design_turf.md (2026-09-20)
 * Charte precedente : ~/www/studiokad_design/projects/turfgeniuspro-refonte-2026-09-13.md
 * Maquettes de reference : mockup-course.html · mockup-reunions.html
 *
 * ⛔ LES 5 REGLES DE NON-TRANSPOSITION (charte §2) — a lire avant d'ajouter un composant.
 *    1. Un alpha ne se transpose pas : c'est le COMPOSITE qui se mesure dans chaque theme.
 *    2. La formule des fonds teintes change : 12 % en clair, 18 % en sombre.
 *    3. Le texte du bouton d'action s'inverse : --tg-on-cta, JAMAIS #fff en dur.
 *    4. Le tocard n'a PAS de fond teinte en sombre (il tomberait sous le seuil AA).
 *    5. Barre de chance : l'ordre de LUMINANCE des rampes s'inverse, le SENS reste identique.
 */

/* ----------------------------------------------------------------------------
   La police, servie par NOUS.
   [2026-09-23] Elle venait de Google Fonts : deux domaines tiers a joindre, une feuille de style
   bloquante, et l'adresse de chaque visiteur annoncee a un tiers a chaque chargement. Le fichier
   est le MEME (Google sert deja la forme variable), donc ce changement ne gagne pas un octet : il
   gagne un aller-retour, et il arrete d'annoncer nos visiteurs.

   La feuille demandait CINQ graisses (400, 500, 600, 700, 800) quand le projet n'en declare que
   quatre en tokens. La forme variable rend la question sans objet : un fichier les couvre toutes.

   Mesure du 2026-09-23 : latin 27 348 o, latin-ext 21 728 o — et le second ne part que s'il sert.
   ---------------------------------------------------------------------------- */

@font-face {
    font-family: 'Plus Jakarta Sans';
    font-style: normal;
    /* UNE police pour toutes les graisses : elle est variable, de 400 a 800. */
    font-weight: 400 800;
    /* Le texte s'affiche aussitot dans la pile de repli : invisible deux secondes serait pire. */
    font-display: swap;
    src: url('/assets/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
    /* La plage decide du telechargement : « latin-ext » ne part que si un caractere l'exige. */
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Plus Jakarta Sans';
    font-style: normal;
    /* UNE police pour toutes les graisses : elle est variable, de 400 a 800. */
    font-weight: 400 800;
    /* Le texte s'affiche aussitot dans la pile de repli : invisible deux secondes serait pire. */
    font-display: swap;
    src: url('/assets/fonts/plus-jakarta-sans-latin-ext.woff2') format('woff2');
    /* La plage decide du telechargement : « latin-ext » ne part que si un caractere l'exige. */
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ═══════════════════════════════════════════════════════════════
   1. THEME CLAIR « Le Programme » — valeurs par DEFAUT
   Palette imposee par la charte du 2026-09-20 : ardoise tres clair, bleu nuit,
   emeraude, orange PMU. Chaque valeur porte sa mesure de contraste, calculee —
   jamais estimee a l'oeil.
═══════════════════════════════════════════════════════════════ */
:root {
    color-scheme: light;

    /* Fonds */
    --tg-bg: #F8FAFC;          /* ardoise tres clair — fond global (charte) */
    --tg-card: #FFFFFF;        /* blanc pur — lignes de partants, blocs, ticket (charte) */
    --tg-subbg: #F1F5F9;       /* sous-section, piste de barre */
    --tg-bg-accent: #E2E8F0;   /* pied de page, bandeau */
    --tg-row-alt: #F8FAFC;     /* ligne paire de tableau */
    --tg-locked-bg: #F1F5F9;   /* carte de pari verrouille */

    /* Encres */
    --tg-text: #0F172A;        /* 17,85:1 sur la carte · 17,06:1 sur le fond */
    --tg-medium: #334155;      /* 10,35:1 */
    --tg-muted: #5A6779;       /* 5,75:1 carte · 5,50:1 fond · 5,25:1 sous-section · 4,67:1 bandeau — PLANCHER.
                                  ⚠️ La charte donne #64748B. Mesure du 2026-09-20 : il rend 4,34:1 sur la
                                  sous-section et 3,86:1 sur le bandeau accentue, donc SOUS le seuil AA la
                                  ou on l'emploie vraiment. Assombri du minimum necessaire pour tenir sur
                                  les QUATRE fonds du theme. Le gris acier de la charte reste reconnaissable ;
                                  un texte secondaire illisible trahirait davantage l'intention. */

    /* Filets — ⚠️ REGLE 1 : mesures, pas transpositions */
    --tg-line: #E2E8F0;          /* 1,23:1 — separateurs fins (charte) */
    --tg-line-strong: #CBD5E1;   /* 1,48:1 — separateurs marques */
    --tg-line-control: #8494A8;  /* 3,10:1 — bordure de CONTROLE, WCAG 1.4.11 (seuil 3,00).
                                    ⚠️ Le gris #94A3B8 de la famille n'y rend que 2,56 : il ne peut
                                    PAS servir de bordure de controle. Assombri jusqu'a passer. */
    --tg-rule: #0E2A47;          /* bleu nuit profond — tete d'article, bandeau (charte) */
    --tg-on-rule: #FFFFFF;       /* 14,57:1 sur le bleu nuit */
    --tg-on-rule-2: #C3D0E0;     /* 9,31:1 — secondaire sur aplat de bleu nuit */
    --tg-sw-border: rgba(15, 23, 42, .12);

    /* Roles — teintes d'ENCRE. L'emeraude de la charte (#10B981) ne rend que 2,54 sur la
       carte : elle est inutilisable comme texte. Elle vit dans les aplats et les bordures,
       jamais dans une lettre. */
    --tg-favori: #047857;      /* emeraude foncee — 5,48:1 */
    --tg-outsider: #B03A0B;    /* terre brulee — 6,08:1 */
    --tg-surprise: #6D28D9;    /* prune de casaque — 7,10:1 */
    --tg-value: #0369A1;       /* bleu profond — 5,93:1 */
    --tg-tocard: #556070;      /* gris acier plus dense — 6,38:1 sur la carte, 5,39:1 sur son aplat */

    /* Fonds teintes — ⚠️ REGLE 2 : formule 12 % de la teinte sur le blanc.
       Un couple derive qui echoue accuse son ENTREE, pas sa derivation : c'est la
       TEINTE qu'on assombrit, jamais le taux qu'on bricole pour un seul role.
       favori    #E1EFEB — la teinte dessus rend 4,63:1
       outsider  #F6E7E2 — la teinte dessus rend 5,05:1
       surprise  #EDE5FA — la teinte dessus rend 5,82:1
       value     #E1EDF4 — la teinte dessus rend 4,98:1
       tocard    #EBEDEF — la teinte dessus rend 4,90:1
    */
    --tg-favori-bg: #E1EFEB;
    --tg-outsider-bg: #F6E7E2;
    --tg-surprise-bg: #EDE5FA;
    --tg-value-bg: #E1EDF4;
    --tg-tocard-bg: #EBECEE;
    --tg-cta-bg: #FCEDE3;      /* sert de fond a .bg-danger / .bg-danger-subtle (§7) — l'encre du theme y rend 15,61:1 */

    /* Bouton d'action — l'orange PMU, couleur historique, reserve a la validation finale.
       ⚠️ DEUX mesures ont impose de s'ecarter de la lettre de la charte :
       · l'orange pur #F97316 ne rend que 2,68:1 contre le fond, sous le seuil de 3,00
         d'un composant (WCAG 1.4.11) — il est donc assombri de 6 % jusqu'a 3,02:1.
         L'ecart de teinte est imperceptible, l'ecart de conformite ne l'est pas.
       · la charte ecrit du BLANC dessus : 3,16:1, tres au-dessous du seuil d'un
         libelle. L'encre ardoise y rend 5,66:1. ⚠️ REGLE 3 : jamais #fff en dur. */
    --tg-cta: #EA6C15;
    --tg-cta-hover: #DB6513;   /* 3,41:1 contre le fond, encre dessus 5,00:1 */

    /* [ACTION 2026-09-24 KAD] « remplacer le orange des boutons par le vert logo ».
       Le bouton d'action ne prend plus l'orange : il prend l'emeraude de la marque, celle que
       porte « Genius ». L'orange reste la couleur d'ACCENT de l'interface — icones de titre,
       liseres, filets — et ces deux roles sont desormais separes par deux tokens.
       L'encre est celle que le projet mesure deja sur cette emeraude (`--tg-on-favori`). */
    --tg-action: var(--tg-favori);        /* #047857 — 5,48:1 avec l'encre blanche */
    --tg-action-hover: #03624A;           /* assombri : 6,80:1 avec l'encre blanche */
    --tg-on-action: var(--tg-on-favori);  /* blanc en clair, ardoise en sombre */
    --tg-on-cta: #0F172A;
    --tg-on-favori: #FFFFFF;   /* 5,48:1 sur l'emeraude foncee */

    /* Podium (post-course) */
    --tg-or: #A16207;           /* 4,92:1 */
    --tg-argent: #52606E;       /* 6,45:1 */
    --tg-bronze: #9A5B1C;       /* 5,40:1 */


    /* ── APLATS VIFS de la charte — les quatre signaux, tels qu'elle les donne ──
       [2026-09-20] Ils manquaient : les teintes de role ci-dessus sont choisies pour etre
       lisibles EN TEXTE (seuil 4,50), elles sont donc plus sourdes que la charte. Ses quatre
       couleurs vives servent d'APLATS, jamais de lettres. Deux familles, deux usages.
       ⛔ La charte ecrit du BLANC sur ces aplats. Mesure : 2,54 sur l'emeraude, 2,80 sur
       l'orange, 2,15 sur l'or, 3,76 sur le corail — les quatre echouent. L'encre ardoise
       passe partout (7,04 · 6,37 · 8,31 · 4,74), c'est elle qu'on pose.
       ⚠️ L'emeraude et l'or rendent 2,42 et 2,05 CONTRE LE FOND CLAIR : un badge pose nu sur
       la page serait sous le seuil de 3,00. Ils vivent sur l'en-tete sombre (5,75), ou
       portent une bordure. */
    --tg-vif-favori: #10B981;
    --tg-vif-cta: #F97316;
    --tg-vif-alerte: #EF4444;
    --tg-vif-or: #F59E0B;
    --tg-on-vif: #0F172A;

    /* Rampes de la barre de chance — 5 teintes d'UN role.
       ⚠️ REGLE 5 : en clair la proeminence vient du FONCE (segment 1 = le plus sombre). */
    --ramp-favori-1: #024230; --ramp-favori-2: #047857; --ramp-favori-3: #05A275; --ramp-favori-4: #07D298; --ramp-favori-5: #09FFC4;
    --ramp-outsider-1: #612006; --ramp-outsider-2: #B03A0B; --ramp-outsider-3: #EE4E0F; --ramp-outsider-4: #FF6613; --ramp-outsider-5: #FF8219;
    --ramp-surprise-1: #3C1677; --ramp-surprise-2: #6D28D9; --ramp-surprise-3: #9336FF; --ramp-surprise-4: #BF46FF; --ramp-surprise-5: #F55AFF;
    --ramp-value-1: #023A59; --ramp-value-2: #0369A1; --ramp-value-3: #048ED9; --ramp-value-4: #05B8FF; --ramp-value-5: #07ECFF;
    --ramp-neutre-1: #323943; --ramp-neutre-2: #5A6779; --ramp-neutre-3: #7A8BA3; --ramp-neutre-4: #9EB4D4; --ramp-neutre-5: #CAE8FF;
}

/* ═══════════════════════════════════════════════════════════════
   2. THEME SOMBRE « La Tribune »
   ⛔ La charte du 2026-09-20 ne decrit QUE le clair. Ce bloc est une CONCEPTION,
   derivee de son ancrage : le bleu nuit #0E2A47 devient la famille du fond, et les
   deux signaux de la charte — emeraude et orange PMU — sont conserves tels quels,
   parce qu'ils portent l'identite. Chaque valeur est mesuree ici, aucune n'est
   transposee depuis le clair.
═══════════════════════════════════════════════════════════════ */
:root[data-theme="dark"] {
    color-scheme: dark;

    /* Fonds — famille bleu nuit, derivee du #0E2A47 de la charte */
    --tg-bg: #0A1829;          /* nuit profonde */
    --tg-card: #0F2438;        /* feuillet */
    --tg-subbg: #16304A;
    --tg-bg-accent: #071220;
    --tg-row-alt: #13293E;     /* ligne paire — toutes les encres y sont remesurees */
    --tg-locked-bg: #122740;

    --tg-text: #E6EDF5;        /* 13,38:1 sur la carte · 12,58:1 sur la ligne paire */
    --tg-medium: #B4C2D4;      /* 8,73:1 · 8,21:1 */
    --tg-muted: #8FA3BC;       /* 6,12:1 · 5,75:1 · 5,23:1 en sous-section — PLANCHER */

    /* ⚠️ REGLE 1 : les filets sont des ALPHAS de l'encre sur la carte, et c'est le
       COMPOSITE qui se mesure. Recopier les valeurs du clair donnerait des filets
       plus faibles, pas equivalents. */
    --tg-line: #E6EDF529;         /* 16 % → #314456 · 1,57:1 */
    --tg-line-strong: #E6EDF54D;  /* 30 % → #506071 · 2,45:1 */
    --tg-line-control: #E6EDF56B; /* 42 % → #697887 · 3,49:1 — seuil 3,00 */
    --tg-rule: #E6EDF5;
    --tg-on-rule: #0A1829;       /* 15,14:1 */
    --tg-on-rule-2: #3B4A5C;     /* 7,67:1 */
    --tg-sw-border: rgba(230, 237, 245, .18);

    --tg-favori: #34D399;      /* emeraude de la charte, eclaircie pour le fond sombre — 8,21:1 */
    --tg-outsider: #FB923C;    /* orange de la charte — 6,98:1 */
    --tg-surprise: #C4B5FD;    /* 8,55:1 */
    --tg-value: #7DD3FC;       /* 9,47:1 */
    --tg-tocard: #94A3B8;      /* 6,16:1 */

    /* ⚠️ REGLE 2 : formule 18 % en SOMBRE (a 12 % le fond teinte ne se voit pas).
       favori    #164449 — la teinte dessus rend 5,58:1
       outsider  #393839 — la teinte dessus rend 5,16:1
       surprise  #303E5B — la teinte dessus rend 5,79:1
       value     #23445B — la teinte dessus rend 6,15:1
       ⚠️ REGLE 4 : le tocard n'a PAS de fond teinte ici. Sur son tint #273B4F il
       rendrait 4,49:1, sous le seuil AA de 4,50. Bordure + texte sur la
       surface nue, qui rend 6,16:1. */
    --tg-favori-bg: #164449;
    --tg-outsider-bg: #393839;
    --tg-surprise-bg: #303E5B;
    --tg-value-bg: #23445B;
    --tg-tocard-bg: transparent;
    --tg-cta-bg: #393232;      /* fond de .bg-danger / .bg-danger-subtle (§7) — l'encre y rend 10,62:1 */

    /* Bouton d'action — ici l'orange PUR de la charte tient sans retouche : il rend
       5,63:1 sur le feuillet, tres au-dessus du seuil de 3,00. C'est en CLAIR
       qu'il fallait l'assombrir, pas ici.
       ⚠️ REGLE 3 : l'encre du bouton est SOMBRE dans les deux themes — le blanc n'y rend
       que 2,80:1. Une teinte ne se remplace jamais seule ; ce qu'on ecrit dessus se
       remesure avec elle. */
    --tg-cta: #F97316;
    --tg-cta-hover: #FF7817;   /* ECLAIRCI, pas assombri : en sombre, assombrir rapprocherait le bouton de son fond (5,98:1) */

    /* [ACTION 2026-09-24] Meme regle qu'en clair, inversee : le survol ECLAIRCIT, sinon le
       bouton se rapprocherait de son fond au lieu de s'en detacher. */
    --tg-action: var(--tg-favori);        /* #34D399 — 9,29:1 avec l'encre ardoise */
    --tg-action-hover: #5FE3B5;           /* eclairci : 11,18:1 avec l'encre ardoise */
    --tg-on-action: var(--tg-on-favori);
    --tg-on-cta: #0A1829;
    --tg-on-favori: #0A1829;   /* 9,29:1 sur l'emeraude claire */

    --tg-or: #E3B341;           /* 8,11:1 */
    --tg-argent: #AFBACB;       /* 8,05:1 */
    --tg-bronze: #D08C4A;       /* 5,66:1 */


    /* ── APLATS VIFS — identiques au clair, et c'est voulu : ce sont les signaux de la
       marque. Mesures sur le feuillet sombre : emeraude 6,23 · orange 5,63 · corail 4,20 ·
       or 7,35. L'encre posee dessus reste SOMBRE dans les deux themes (7,04 · 6,37 · 4,75 ·
       8,32) — le blanc y echouerait exactement comme en clair. */
    --tg-vif-favori: #10B981;
    --tg-vif-cta: #F97316;
    --tg-vif-alerte: #EF4444;
    --tg-vif-or: #F59E0B;
    --tg-on-vif: #0A1829;

    /* ⚠️ REGLE 5 : en sombre la proeminence vient du CLAIR. L'ordre de LUMINANCE
       s'inverse, le SENS des segments reste identique. */
    --ramp-favori-1: #3DF9B5; --ramp-favori-2: #34D399; --ramp-favori-3: #2BAD7D; --ramp-favori-4: #228B65; --ramp-favori-5: #1B6E50;
    --ramp-outsider-1: #FFAC47; --ramp-outsider-2: #FB923C; --ramp-outsider-3: #CE7831; --ramp-outsider-4: #A66028; --ramp-outsider-5: #834C1F;
    --ramp-surprise-1: #E7D6FF; --ramp-surprise-2: #C4B5FD; --ramp-surprise-3: #A194CF; --ramp-surprise-4: #8177A7; --ramp-surprise-5: #665E84;
    --ramp-value-1: #94F9FF; --ramp-value-2: #7DD3FC; --ramp-value-3: #66ADCF; --ramp-value-4: #528BA6; --ramp-value-5: #416E83;
    --ramp-neutre-1: #AFC0D9; --ramp-neutre-2: #94A3B8; --ramp-neutre-3: #798697; --ramp-neutre-4: #626C79; --ramp-neutre-5: #4D5560;
}

/* ═══════════════════════════════════════════════════════════════
   3. Invariants de FORME — identiques dans les deux themes
   [2026-09-20] La charte change de langage formel : rayons 6/12/16 px et ombres
   douces bleutees, la ou la precedente imposait 3/4/6 px et AUCUNE ombre. Les anciens
   noms survivent avec de nouvelles valeurs — les gabarits ne connaissent que les noms.
═══════════════════════════════════════════════════════════════ */
:root {
    --r-xs: 4px;
    --r-sm: 6px;               /* $radius-sm de la charte */
    --r-md: 12px;              /* $radius-md — cartes et blocs */
    --r-lg: 16px;              /* $radius-lg */
    --r-full: 999px;
    --s-xs: 4px; --s-sm: 8px; --s-md: 16px; --s-lg: 24px; --s-xl: 32px; --s-xxl: 48px;

    /* Ombres — teintees du bleu nuit de la charte, jamais du noir pur : une ombre noire
       sur un fond ardoise rend gris sale. Elles ne portent AUCUNE information : retirees,
       la page reste comprehensible et conforme. */
    --sh-sm: 0 1px 3px rgba(14, 42, 71, .04);
    --sh-md: 0 10px 15px -3px rgba(14, 42, 71, .05), 0 4px 6px -4px rgba(14, 42, 71, .05);

    --t-smooth: all .2s ease-in-out;

    /* Tailles de texte. [2026-09-22] Elles n'etaient nommees NULLE PART : quatorze valeurs
       differentes vivaient en clair dans la feuille, nees une a une. L'echelle ci-dessous ne
       decide rien de neuf — elle NOMME les grappes qui existaient deja, et fait tomber les
       variations accidentelles. Les seuls ecarts reels : .70 -> .72, .74 -> .75, .78 et .825
       -> .80, 1,05 et 1,20 -> 1,15 et 1,25. Aucun ne depasse deux pixels. */
    --fs-xxs: .72rem;          /* micro-libelles en capitales : type de pari, titre de colonne */
    --fs-xs: .75rem;           /* titres de section, textes d'aide */
    --fs-sm: .8rem;            /* texte secondaire */
    --fs-md: .9rem;            /* libelle d'un element de liste */
    --fs-lg: .95rem;           /* icone dans un titre, libelle appuye */
    --fs-base: 1rem;
    --fs-xl: 1.15rem;
    --fs-xxl: 1.25rem;
    /* [2026-09-23] Le seul CHIFFRE qu'on lit de loin : le score de la page de course. Il vivait
       en clair dans le gabarit ; l'echelle s'arrete a 1,25 rem parce qu'aucun TEXTE ne va plus
       haut, mais un nombre d'affichage, si. Il est nomme ici pour ne pas reapparaitre isole. */
    --fs-affichage: 1.5rem;

    /* Espacement des lettres. Les capitales ont besoin d'air, le texte courant non. */
    --ls-sm: .05em;
    --ls-md: .1em;
    --ls-lg: .12em;
    --ls-marque: 1px;          /* la marque seule : un ecart fixe, pas proportionnel au corps */

    /* Hauteurs de ligne */
    --lh-serre: 1.2;
    --lh-bloc: 1;              /* un nombre d'affichage : aucune respiration au-dessus ni dessous */

    /* La pastille d'icone. UNE taille : c'est le meme objet dans un titre de section et dans
       un element de liste, il n'avait aucune raison de mesurer 28 px ici et 30 px la. */
    --ico: 28px;

    /* Graisses. Onze declarations portaient `700` en clair et trois `800` : le meme niveau
       d'insistance, ecrit a la main a chaque fois. */
    --fw-normal: 400;
    --fw-moyen: 500;
    /* [2026-09-23] 600 manquait a l'echelle alors que 25 emplois s'en servaient, par la classe
       Bootstrap `fw-semibold` — c'est-a-dire hors du systeme de tokens, sans que rien ne le dise.
       La police etant variable, cette graisse ne coute pas un fichier de plus. */
    --fw-semi: 600;
    --fw-fort: 700;
    --fw-titre: 800;

    /* Cible tactile. 44 px est le minimum des recommandations d'accessibilite, 48 celui de la
       charte de l'agence. Le chiffre etait ecrit en clair a chaque bouton concerne — et un
       chiffre ecrit a la main finit par etre ecrit a 40. */
    --cible-min: 44px;
    --cible: 48px;

    /* Le lisere d'accent a gauche : celui de `.tg-item`, celui de `.tg-card--signal`, celui de
       `.tg-note`. Trois epaisseurs pour le meme geste, jusqu'ici. */
    --accent-fin: 2px;
    --accent: 3px;
    --accent-fort: 4px;

    /* Typographie de la charte. « Plus Jakarta Sans » est chargee depuis Google Fonts
       dans base.html.twig ; la pile de repli suit, pour que la page reste lisible si la
       fonte distante ne repond pas. */
    --f-title: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --f-body: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --f-num: 'Plus Jakarta Sans', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;
}

/* ═══════════════════════════════════════════════════════════════
   4. ALIAS DE COMPATIBILITE — l'ancien jeu de noms survit
   Les gabarits qui consomment --tg-primary/accent/success/warning/danger ne sont
   PAS ouverts : ces noms pointent desormais sur les roles du nouveau systeme.
   La resolution des custom properties est paresseuse → l'alias suit la bascule seul.
   ⚠️ Dette a resorber : ces noms decrivent une palette « app », pas des roles turf.
═══════════════════════════════════════════════════════════════ */
:root {
    /* [2026-09-24] Cet alias sert aux gabarits qui posent `--bs-btn-bg: var(--tg-primary)` en
       ligne. Il suit le BOUTON, pas l'accent — sinon ces boutons-la seraient restes orange
       pendant que les autres passaient au vert, et le defaut ne se serait vu que sur deux pages. */
    --tg-primary: var(--tg-action);         /* bouton d'action → emeraude de la marque */
    --tg-primary-hover: var(--tg-cta-hover);
    --tg-accent: var(--tg-surprise);        /* [FIX 2026-09-13] le cyan #22d3ee est supprime */
    --tg-success: var(--tg-favori);
    --tg-success-dark: var(--tg-rule);      /* aplat d'encre (nameplate navbar) */
    --tg-warning: var(--tg-outsider);
    /* ⚠️ DECISION A ARBITRER : la charte ne definit AUCUN token « negatif / erreur ».
       --tg-danger portait deux sens melanges (role tocard + echec d'un pronostic).
       Le rouge etant declare EXCLUSIF a la conversion, le negatif est rendu en gris
       neutre : l'information reste portee par le mot et l'icone, jamais par la seule
       couleur. Alternative si KAD/designer tranchent autrement : un --tg-negative dedie. */
    --tg-danger: var(--tg-tocard);
}

/* ═══════════════════════════════════════════════════════════════
   5. BASE
═══════════════════════════════════════════════════════════════ */
html, body {
    height: 100%;
    background: var(--tg-bg);
    color: var(--tg-text) !important;
    /* [2026-09-20] La fonte de la charte s'applique ICI, au corps : jusqu'a ce jour les
       tokens de fonte etaient definis et n'etaient appliques nulle part. */
    font-family: var(--f-body);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* [ADM-09 2026-09-20] Les titres portent le bleu nuit de la charte, pas l'encre courante —
   c'est ce qui donne la hierarchie qui manquait.
   ⚠️ `--tg-rule` vaut le bleu nuit en CLAIR et la creme en SOMBRE : le titre se detache dans
   les deux themes sans qu'on ait besoin d'une seconde regle. Les deux couples sont mesures
   (14,57 et 13,38 sur la carte). */
h1, h2, h3, h4 {
    font-family: var(--f-title);
    font-weight: var(--fw-fort);
    color: var(--tg-rule);
    letter-spacing: -.01em;
}

/* Un titre pose sur un APLAT de bleu nuit ne peut pas rester bleu nuit. */
.tg-rule h1, .tg-rule h2, .tg-rule h3, .tg-rule h4,
[class*="bg-dark"] h1, [class*="bg-dark"] h2, [class*="bg-dark"] h3, [class*="bg-dark"] h4 {
    color: inherit;
}

a {
    text-decoration: none !important;
}

.bg-app {
    background: var(--tg-bg) !important;
}

main, .page, .content, .container, .row {
    background: transparent !important;
}

section {
    padding: 4rem 0;
    color: var(--tg-text);
}

.tg-hero {
    /* [FIX 2026-09-13] --tg-gradient supprime : les degrades radiaux de fond font
       partie des signaux « app » retires par la charte §4. */
    background: var(--tg-bg);
    color: var(--tg-text);
}

.tg-brand {
    font-weight: var(--fw-titre);
    letter-spacing: var(--ls-marque);
}

/* ----------------------------------------------------------------------------
   LA MARQUE
   [UI-08 2026-09-23] « Genius » etait pose sur un aplat bleu nuit. Dans une page de texte, un mot
   sur un aplat rectangulaire ne se lit pas comme un logo : il se lit comme la surbrillance qu'on
   obtient en selectionnant du texte. Le signe le plus reconnaissable du site passait pour une
   anomalie d'affichage. Le mot porte desormais sa couleur, il ne porte plus de fond.
   ---------------------------------------------------------------------------- */
.tg-logo {
    display: inline-flex;
    align-items: center;
    gap: var(--s-sm);
}

.tg-logo-signe { flex: 0 0 auto; }

/* La tuile prend l'encre du theme : bleu nuit en clair, et elle s'eclaircit en sombre — sinon
   elle deviendrait un trou noir dans une interface deja sombre. */
.tg-logo-tuile   { fill: var(--tg-text); }
.tg-logo-fer     { stroke: var(--tg-card); }

.tg-logo-mot {
    font-weight: var(--fw-titre);
    letter-spacing: var(--ls-marque);
    color: var(--tg-text);
    line-height: var(--lh-bloc);
}

/* L'emeraude de la charte — la meme que celle du favori. Elle DIT la marque sans reprendre
   l'orange du bouton d'action, qui doit rester le seul appel de la page. */
.tg-logo-mot-accent { color: var(--tg-favori); }

/* ═══════════════════════════════════════════════════════════════
   5 bis. CIBLES TACTILES DES TABLEAUX D'ADMINISTRATION
   [DESIGN-AUDIT 2026-09-20] Les boutons d'action des listes sont des `btn-sm` :
   environ 31 px de haut, pour une cible tactile recommandee a 44. Sur telephone, la
   difference n'est pas un confort — c'est la frequence a laquelle on active la mauvaise
   ligne, et l'une de ces actions supprime un compte.
   On agrandit la CIBLE sans grossir le bouton : le pseudo-element deborde du bouton
   jusqu'a 44 px, la mise en page ne bouge pas. La regle ne s'applique qu'au pointeur
   grossier — a la souris, un bouton de 31 px se vise tres bien.

   [FIX 2026-09-22] Cette regle a vise LE VIDE pendant quelques heures. La migration vers les
   primitives a remplace `class="table"` par `class="tg-table"` dans les dix-neuf tableaux, et
   le selecteur n'a pas suivi : zero `<table class="table` restait dans les gabarits. Les
   boutons « Supprimer le compte », « Verifier le KYC » et « Supprimer un contact » etaient
   revenus a 31 px de cible, sans que rien ne le signale.

   La regle existait toujours, parfaitement ecrite, dans la feuille. Elle ne protegeait plus
   personne. C'est la forme la plus silencieuse de regression : un garde-fou qu'un renommage
   rend muet ne leve aucune erreur, ne casse aucun test, et ne se voit qu'au doigt.
═══════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {
    .table td .btn,
    .table th .btn,
    .tg-table td .btn,
    .tg-table th .btn {
        position: relative;
    }

    .table td .btn::after,
    .table th .btn::after,
    .tg-table td .btn::after,
    .tg-table th .btn::after {
        content: '';
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        min-width: var(--cible-min);
        min-height: var(--cible-min);
        width: 100%;
        height: 100%;
    }
}

/* ═══════════════════════════════════════════════════════════════
   6. BASCULE DE THEME
═══════════════════════════════════════════════════════════════ */
/* [2026-09-22] La bascule de theme etait l'element le PLUS proeminent de la barre de tete :
   bordure pleine, fond opaque, texte a --fs-lg en graisse 600, quand les liens de navigation a
   cote sont a --fs-base en graisse normale. Une commande de confort dominait les destinations.

   Elle garde sa cible de 44 px — on allege le dessin, jamais la cible — et son libelle reste
   lisible : une icone seule aurait demande au visiteur de deviner. */
.themeswitch {
    display: inline-flex;
    align-items: center;
    gap: var(--s-sm);
    min-height: var(--cible-min);
    padding: 0 var(--s-sm);
    border: 1px solid transparent;
    background: transparent;
    color: var(--tg-muted);
    font: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-normal);
    border-radius: var(--r-sm);
    cursor: pointer;
}

.themeswitch:hover,
.themeswitch:focus {
    background: var(--tg-subbg);
    border-color: var(--tg-line);
    color: var(--tg-text);
}

.themeswitch .ico {
    font-size: var(--fs-base);
    line-height: 1;
}

:root .themeswitch .lbl-dark,
:root[data-theme="dark"] .themeswitch .lbl-light {
    display: none;
}

:root[data-theme="dark"] .themeswitch .lbl-dark {
    display: inline;
}

/* ═══════════════════════════════════════════════════════════════
   7. COUCHE ANTI-CORRUPTION BOOTSTRAP
   ⚠️ Une classe utilitaire de couleur est une couleur EN DUR ecrite dans une autre
   syntaxe : `text-white` ne bascule pas plus que `#fff`. Mesure du 2026-09-13 sur les
   gabarits applicatifs : 131 utilitaires de couleur dans 14 fichiers, dont 83 STRICTEMENT
   FIGES (ceux qui ne suivent pas data-bs-theme). On les neutralise ICI, en un seul
   endroit, plutot que d'ouvrir les gabarits — dette a resorber gabarit par gabarit.

   ⛔⛔ PIEGE ASSUME, A CONNAITRE AVANT D'ECRIRE UN GABARIT ⛔⛔
   Les regles ci-dessous DETOURNENT le sens de classes Bootstrap. Dans ce projet :
       `text-white`     ne rend PAS du blanc  → il rend l'encre du theme courant
       `text-white-50`  ne rend PAS du blanc translucide → l'encre secondaire
       `bg-dark`        ne rend PAS du sombre → la surface de carte du theme courant
   C'est deliberé : ces classes portent une couleur FIXE, et une couleur fixe est
   visiblement fausse dans l'un des deux themes. Les detourner ici evitait d'ouvrir
   14 gabarits ; le prix est ce decalage de nom.
   ✅ DANS UN NOUVEAU GABARIT : n'ecrire aucune de ces classes. Utiliser les tokens
      (`style="color:var(--tg-text)"`, `var(--tg-muted)`, `var(--tg-card)`…), qui disent
      ce qu'ils font et basculent seuls. Les classes ci-dessous n'existent que pour
      l'existant ; le jour ou le dernier gabarit est migre, toute cette section disparait.
═══════════════════════════════════════════════════════════════ */
/* ── a. Les utilitaires FIXES — ceux qui ne suivent PAS data-bs-theme ──
   text-white (42) · text-white-50 (25) · bg-dark (10) · text-dark (2) ·
   bg-dark-subtle (2) · text-light (1) · bg-light (1) = 83 occurrences. */
.text-white, .text-light, .text-dark {
    color: var(--tg-text) !important;
}

.text-white-50, .text-muted {
    color: var(--tg-muted) !important;
}

.bg-dark, .bg-dark-subtle {
    background-color: var(--tg-card) !important;
}

.bg-light {
    background-color: var(--tg-subbg) !important;
}

/* [FIX 2026-09-20] La famille `link-*` manquait a cet inventaire, et elle a mordu le jour
   meme de la refonte : `link-light` force une encre claire, les adresses e-mail du tableau
   de bord etaient donc invisibles sur fond blanc. Ces classes ne basculent pas plus que
   `text-white` — meme famille, meme neutralisation, meme piege.
   ⛔ Dans un NOUVEAU gabarit : ecrire `link-fort` ou `link-muted`, qui disent leur role. */
.link-light, .link-dark, .link-body, .link-body-emphasis, .link-secondary {
    color: var(--tg-text) !important;
}

/* ── b. La palette semantique de Bootstrap — elle bascule, mais vers SA palette
   (bleu, vert, rouge Bootstrap), pas vers nos roles. On la reroute sur les notres. */
.text-success { color: var(--tg-favori) !important; }
.text-warning { color: var(--tg-outsider) !important; }
.text-info    { color: var(--tg-value) !important; }
.text-primary { color: var(--tg-cta) !important; }
.text-danger  { color: var(--tg-tocard) !important; }  /* cf. --tg-danger, §4 */

.bg-success, .bg-success-subtle { background-color: var(--tg-favori-bg) !important; }
.bg-warning, .bg-warning-subtle { background-color: var(--tg-outsider-bg) !important; }
.bg-info,    .bg-info-subtle    { background-color: var(--tg-value-bg) !important; }
.bg-danger,  .bg-danger-subtle  { background-color: var(--tg-cta-bg) !important; }
.bg-secondary, .bg-secondary-subtle { background-color: var(--tg-subbg) !important; }

.border-success, .border-success-subtle { border-color: var(--tg-favori) !important; }
.border-warning, .border-warning-subtle { border-color: var(--tg-outsider) !important; }
.border-danger,  .border-danger-subtle  { border-color: var(--tg-cta) !important; }
.border-secondary, .border-secondary-subtle { border-color: var(--tg-line) !important; }

/* .text-bg-* pose un fond ET un texte. Le texte y est #fff EN DUR cote Bootstrap :
   ⚠️ REGLE 3, il faut donc le reprendre entierement, aplat par aplat. */
.text-bg-success { background-color: var(--tg-favori) !important;   color: var(--tg-on-favori) !important; }
.text-bg-warning { background-color: var(--tg-outsider-bg) !important; color: var(--tg-outsider) !important; border: 1px solid var(--tg-outsider); }
.text-bg-info    { background-color: var(--tg-value-bg) !important;  color: var(--tg-value) !important; border: 1px solid var(--tg-value); }
.text-bg-secondary { background-color: var(--tg-subbg) !important;   color: var(--tg-text) !important; }
/* ⚠️ ECART CONNU : .text-bg-danger porte DEUX sens dans les gabarits — conversion
   (« Acces premium ici », « Deverrouiller ») et marqueur de course (« Quinte+ »).
   La conversion l'emporte ici. Le drapeau Quinte+ devrait passer en encre pleine
   (charte §4, fuite n°1) — cela demande d'ouvrir deux gabarits hors perimetre :
   templates/reunions/index.html.twig:129 · templates/courses/unavailable.html.twig:11 */
.text-bg-danger  { background-color: var(--tg-cta) !important;      color: var(--tg-on-cta) !important; }

/* ── b-bis. LE BADGE. Bootstrap pose `color: #fff` sur `.badge` lui-meme, pas sur la classe
   de fond. Rerouter `.bg-*` ci-dessus change donc l'aplat SANS toucher a l'encre : en theme
   clair, ou tous ces aplats sont pales, le texte blanc reste blanc.
   [FIX 2026-09-17, signale par KAD sur les listes de diffusion] Contrastes mesures avant
   correctif, texte blanc sur l'aplat clair :
       bg-secondary 1,22 · bg-success 1,20 · bg-warning 1,21 · bg-info 1,20 · bg-danger 1,22
   Le seuil AA est 4,50 et le minimum absolu 1,00 : ces badges n'etaient pas peu lisibles,
   ils etaient INVISIBLES. Avec l'encre du theme : 14,26 a 14,55.
   Le theme sombre, lui, passait deja (11,3 a 14,8) — le defaut n'existait qu'en clair, donc
   depuis que le clair est devenu le theme par defaut, le 2026-09-15.
   Mesure a la portee : 21 occurrences dans 11 gabarits, dont trois pages PUBLIQUES
   (subscription/index, reunions/index, auth/form/profile) — pas seulement l'administration.
   Le selecteur est volontairement limite a `.badge` : ailleurs, `.bg-*` sert de fond a des
   blocs qui portent deja leur propre encre, et la forcer casserait ce qui marche. */
.badge.bg-secondary, .badge.bg-secondary-subtle,
.badge.bg-success,   .badge.bg-success-subtle,
.badge.bg-warning,   .badge.bg-warning-subtle,
.badge.bg-info,      .badge.bg-info-subtle,
.badge.bg-danger,    .badge.bg-danger-subtle,
.badge.bg-light,     .badge.bg-dark, .badge.bg-dark-subtle {
    color: var(--tg-text) !important;
    border: 1px solid var(--tg-line);
}

/* Aplat d'encre — le traitement « une de presse » (drapeau Quinte+, nameplate). */
.tg-flag-rule {
    background: var(--tg-rule) !important;
    color: var(--tg-on-rule) !important;
    border-radius: var(--r-xs);
}

.btn-outline-light {
    --bs-btn-color: var(--tg-text);
    --bs-btn-border-color: var(--tg-line-control);
    --bs-btn-hover-color: var(--tg-text);
    --bs-btn-hover-bg: var(--tg-subbg);
    --bs-btn-hover-border-color: var(--tg-line-control);
    --bs-btn-active-color: var(--tg-text);
    --bs-btn-active-bg: var(--tg-subbg);
    --bs-btn-active-border-color: var(--tg-line-control);
}

/* [FIX 2026-09-27] UI-16 — les boutons CONTOUR semantiques de l'administration echappaient a cette
   couche : seul `.btn-outline-light` y etait reroute. `.btn-outline-secondary` (21 emplois),
   `-danger` (8), `-warning` (3) et `-primary` (2) gardaient les `--bs-*` bruts de Bootstrap, que
   Bootstrap ne redefinit PAS sous [data-bs-theme=dark] pour la variante contour pleine. En theme
   sombre ils gardaient donc leur teinte claire et ne basculaient pas avec le reste de la page.
   On route chacun sur son token, exactement comme les boutons pleins plus haut : le SENS est
   preserve (danger corail, avertissement or), et l'encre de survol bascule via --tg-on-vif /
   --tg-on-action. Les couleurs et leurs contrastes sont ceux deja mesures en tete de fichier. */
.btn-outline-secondary {
    --bs-btn-color: var(--tg-muted);
    --bs-btn-border-color: var(--tg-line-control);
    --bs-btn-hover-color: var(--tg-text);
    --bs-btn-hover-bg: var(--tg-subbg);
    --bs-btn-hover-border-color: var(--tg-line-control);
    --bs-btn-active-color: var(--tg-text);
    --bs-btn-active-bg: var(--tg-subbg);
    --bs-btn-active-border-color: var(--tg-line-control);
    --bs-btn-disabled-color: var(--tg-muted);
    --bs-btn-disabled-border-color: var(--tg-line-control);
}

.btn-outline-danger {
    --bs-btn-color: var(--tg-vif-alerte);
    --bs-btn-border-color: var(--tg-vif-alerte);
    --bs-btn-hover-color: var(--tg-on-vif);
    --bs-btn-hover-bg: var(--tg-vif-alerte);
    --bs-btn-hover-border-color: var(--tg-vif-alerte);
    --bs-btn-active-color: var(--tg-on-vif);
    --bs-btn-active-bg: var(--tg-vif-alerte);
    --bs-btn-active-border-color: var(--tg-vif-alerte);
    --bs-btn-disabled-color: var(--tg-vif-alerte);
    --bs-btn-disabled-border-color: var(--tg-vif-alerte);
}

.btn-outline-warning {
    --bs-btn-color: var(--tg-vif-or);
    --bs-btn-border-color: var(--tg-vif-or);
    --bs-btn-hover-color: var(--tg-on-vif);
    --bs-btn-hover-bg: var(--tg-vif-or);
    --bs-btn-hover-border-color: var(--tg-vif-or);
    --bs-btn-active-color: var(--tg-on-vif);
    --bs-btn-active-bg: var(--tg-vif-or);
    --bs-btn-active-border-color: var(--tg-vif-or);
    --bs-btn-disabled-color: var(--tg-vif-or);
    --bs-btn-disabled-border-color: var(--tg-vif-or);
}

.btn-outline-primary {
    --bs-btn-color: var(--tg-action);
    --bs-btn-border-color: var(--tg-action);
    --bs-btn-hover-color: var(--tg-on-action);
    --bs-btn-hover-bg: var(--tg-action);
    --bs-btn-hover-border-color: var(--tg-action);
    --bs-btn-active-color: var(--tg-on-action);
    --bs-btn-active-bg: var(--tg-action);
    --bs-btn-active-border-color: var(--tg-action);
    --bs-btn-disabled-color: var(--tg-action);
    --bs-btn-disabled-border-color: var(--tg-action);
}

.table-dark {
    --bs-table-bg: var(--tg-card);
    --bs-table-color: var(--tg-text);
    --bs-table-border-color: var(--tg-line);
}

/* ⚠️ REGLE 3 — le texte du bouton d'action s'inverse. Bootstrap pose du blanc sur
   .btn-primary ; en theme sombre le fond est laiton et le blanc tombe a 2,75:1. */
.btn-primary {
    --bs-btn-bg: var(--tg-action);
    --bs-btn-border-color: var(--tg-action);
    --bs-btn-color: var(--tg-on-action);
    --bs-btn-hover-bg: var(--tg-action-hover);
    --bs-btn-hover-border-color: var(--tg-action-hover);
    --bs-btn-hover-color: var(--tg-on-action);
    --bs-btn-active-bg: var(--tg-action-hover);
    --bs-btn-active-border-color: var(--tg-action-hover);
    --bs-btn-active-color: var(--tg-on-action);
    --bs-btn-disabled-bg: var(--tg-action);
    --bs-btn-disabled-border-color: var(--tg-action);
    --bs-btn-disabled-color: var(--tg-on-action);
}

/* [FIX 2026-09-22] Les quatre boutons SEMANTIQUES echappaient a cette couche : seuls
   `.btn-primary` et `.btn-outline-light` y etaient reroutes. Mesure dans le Bootstrap servi :
   `.btn-warning` rend un fond #ffc107 et une encre #000, `.btn-info` un fond #0dcaf0 et une
   encre #000 — et ces valeurs sont IDENTIQUES sous `[data-bs-theme=dark]`, parce que Bootstrap
   ne redefinit que les variantes attenuees, jamais le bouton plein.

   Consequence : en theme sombre, le bouton « Creer mon compte gratuit » — la conversion la plus
   importante du produit, presente deux fois sur la page course et une fois sur la page des
   reunions — restait jaune vif sur noir pendant que tout le reste basculait en bleu nuit.

   Ce n'etait PAS un defaut de lisibilite : noir sur #ffc107 rend 12,88:1, tres au-dessus du
   seuil. C'etait une fracture de marque, et l'encre qui ne suit pas le theme.

   On route chacun sur son aplat VIF, dont les contrastes sont deja mesures dans les deux
   themes et ecrits plus haut : emeraude 6,23 · orange 5,63 · corail 4,20 · or 7,35, avec une
   encre sombre qui rend 7,04 · 6,37 · 4,75 · 8,32. On echange donc un contraste plus eleve
   contre la couleur de la maison et une encre qui bascule — un arbitrage, pas une correction.

   Le SENS est preserve : le danger reste corail, le succes reste emeraude. Les router tous sur
   l'accent d'interface aurait efface ce que ces boutons disent. */
.btn-success {
    --bs-btn-bg: var(--tg-vif-favori);
    --bs-btn-border-color: var(--tg-vif-favori);
    --bs-btn-color: var(--tg-on-vif);
    --bs-btn-hover-bg: var(--tg-vif-favori);
    --bs-btn-hover-border-color: var(--tg-vif-favori);
    --bs-btn-hover-color: var(--tg-on-vif);
    --bs-btn-active-bg: var(--tg-vif-favori);
    --bs-btn-active-border-color: var(--tg-vif-favori);
    --bs-btn-active-color: var(--tg-on-vif);
    --bs-btn-disabled-bg: var(--tg-vif-favori);
    --bs-btn-disabled-border-color: var(--tg-vif-favori);
    --bs-btn-disabled-color: var(--tg-on-vif);
}

.btn-danger {
    --bs-btn-bg: var(--tg-vif-alerte);
    --bs-btn-border-color: var(--tg-vif-alerte);
    --bs-btn-color: var(--tg-on-vif);
    --bs-btn-hover-bg: var(--tg-vif-alerte);
    --bs-btn-hover-border-color: var(--tg-vif-alerte);
    --bs-btn-hover-color: var(--tg-on-vif);
    --bs-btn-active-bg: var(--tg-vif-alerte);
    --bs-btn-active-border-color: var(--tg-vif-alerte);
    --bs-btn-active-color: var(--tg-on-vif);
    --bs-btn-disabled-bg: var(--tg-vif-alerte);
    --bs-btn-disabled-border-color: var(--tg-vif-alerte);
    --bs-btn-disabled-color: var(--tg-on-vif);
}

.btn-warning {
    --bs-btn-bg: var(--tg-vif-or);
    --bs-btn-border-color: var(--tg-vif-or);
    --bs-btn-color: var(--tg-on-vif);
    --bs-btn-hover-bg: var(--tg-vif-or);
    --bs-btn-hover-border-color: var(--tg-vif-or);
    --bs-btn-hover-color: var(--tg-on-vif);
    --bs-btn-active-bg: var(--tg-vif-or);
    --bs-btn-active-border-color: var(--tg-vif-or);
    --bs-btn-active-color: var(--tg-on-vif);
    --bs-btn-disabled-bg: var(--tg-vif-or);
    --bs-btn-disabled-border-color: var(--tg-vif-or);
    --bs-btn-disabled-color: var(--tg-on-vif);
}

.btn-info {
    --bs-btn-bg: var(--tg-vif-cta);
    --bs-btn-border-color: var(--tg-vif-cta);
    --bs-btn-color: var(--tg-on-vif);
    --bs-btn-hover-bg: var(--tg-vif-cta);
    --bs-btn-hover-border-color: var(--tg-vif-cta);
    --bs-btn-hover-color: var(--tg-on-vif);
    --bs-btn-active-bg: var(--tg-vif-cta);
    --bs-btn-active-border-color: var(--tg-vif-cta);
    --bs-btn-active-color: var(--tg-on-vif);
    --bs-btn-disabled-bg: var(--tg-vif-cta);
    --bs-btn-disabled-border-color: var(--tg-vif-cta);
    --bs-btn-disabled-color: var(--tg-on-vif);
}

/* [ADM-09 2026-09-20] Le bouton d'action porte l'ombre teintee de la charte et repond a
   l'appui. L'ombre n'est pas decorative : c'est ce qui le detache du fond sur un ecran de
   telephone en plein jour, la ou le contraste de 3,02 mesure est au plancher. */
.btn-primary {
    /* L'ombre suit la couleur du bouton, sinon elle porterait l'orange sous un bouton vert. */
    box-shadow: 0 4px 6px -1px color-mix(in srgb, var(--tg-action) 25%, transparent);
    transition: var(--t-smooth);
}

.btn-primary:hover {
    box-shadow: 0 10px 15px -3px color-mix(in srgb, var(--tg-action) 32%, transparent);
    transform: translateY(-1px);
}

.btn-primary:active {
    transform: translateY(0);
}

button.btn.opacity-75 {
    transition: background-color .25s ease, opacity .25s ease;
}

/* ═══════════════════════════════════════════════════════════════
   8. BANDEAU DE TETE ET PIED DE PAGE
═══════════════════════════════════════════════════════════════ */
.tg-navbar {
    background: var(--tg-card);
    border-bottom: 2px solid var(--tg-rule);
    --bs-navbar-color: var(--tg-medium);
    --bs-navbar-hover-color: var(--tg-text);
    --bs-navbar-active-color: var(--tg-text);
    --bs-navbar-brand-color: var(--tg-text);
    --bs-navbar-brand-hover-color: var(--tg-text);
    --bs-navbar-disabled-color: var(--tg-muted);
    --bs-navbar-toggler-border-color: var(--tg-line-control);
    --bs-navbar-toggler-icon-bg: none;
}

/* [UI-12 2026-09-23 KAD] « aligner font navbar comme celle du theme bouton ».
   Le bouton de bascule etait en --fs-sm et graisse normale ; les liens voisins heritaient du
   1 rem de Bootstrap. Trois typographies se cotoyaient donc sur une seule ligne, et la plus
   discrete etait celle du bouton — ce qui donnait a lire un bandeau desequilibre.
   Une seule mesure gouverne desormais la barre. L'etat actif reste marque, mais par la COULEUR
   et non par la taille : un lien qui grossit en devenant actif fait bouger toute la ligne. */
.tg-navbar .nav-link,
.tg-navbar .btn {
    font-size: var(--fs-sm);
    font-weight: var(--fw-normal);
}

.tg-navbar .nav-link.active {
    font-weight: var(--fw-semi);
}

.tg-navbar .navbar-toggler {
    color: var(--tg-text);
    border-color: var(--tg-line-control);
}

.tg-navbar .navbar-toggler::before {
    content: '\2630';
    font-size: var(--fs-xxl);
    line-height: 1;
}

.tg-navbar .dropdown-menu {
    --bs-dropdown-bg: var(--tg-card);
    --bs-dropdown-color: var(--tg-text);
    --bs-dropdown-border-color: var(--tg-line);
    --bs-dropdown-link-color: var(--tg-text);
    --bs-dropdown-link-hover-bg: var(--tg-subbg);
    --bs-dropdown-link-hover-color: var(--tg-text);
    --bs-dropdown-link-active-bg: var(--tg-subbg);
    --bs-dropdown-link-active-color: var(--tg-text);
}

/* ── ELEMENT DE LISTE — la primitive, partagee par toute l'application ──
   [2026-09-22] Ce motif est ne dans le menu d'administration (ADM-16) : une pastille d'icone,
   un libelle, une ligne d'aide dessous, un lisere d'accent quand c'est la page courante. KAD a
   demande de l'etendre a toutes les pages.

   Il est donc ecrit UNE fois, en `.tg-item`, et le menu n'en est qu'un employeur parmi
   d'autres. Le recopier sous un second nom aurait fabrique deux styles a maintenir — le meme
   defaut que les deux chaines de paris que l'audit du jour a fusionnees.

   AUCUNE valeur en clair : couleurs, rayons, espacements, tailles de texte, tout vient d'un
   token. Une valeur ecrite ici ne bascule pas avec le theme et ne suit pas la charte — c'est
   ainsi que `--tg-favori`, la couleur du favori d'une course, s'etait retrouvee a decorer une
   carte de pari. */
.tg-item {
    display: flex;
    align-items: center;
    gap: var(--s-sm);
    padding: var(--s-xs) var(--s-sm);
    border-radius: var(--r-sm);
    border-left: var(--accent-fin) solid transparent;
    color: var(--tg-text);
    text-decoration: none;
    transition: var(--t-smooth);
}

.tg-item:hover,
.tg-item:focus-visible {
    background: var(--tg-subbg);
    color: var(--tg-text);
}

.tg-item.est-actif {
    background: var(--tg-subbg);
    border-left-color: var(--tg-cta);
}

/* Un element VERROUILLE porte le meme dessin, sans les promesses du lien : pas de main au
   survol, pas d'accent. Il reste lisible — le masquer ferait croire que la course n'existe
   pas, alors que c'est l'acces qui manque. */
.tg-item--verrouille {
    cursor: default;
    opacity: .72;
}

.tg-item--verrouille:hover {
    background: transparent;
}

/* La cible doit faire 48 px de haut au doigt. La pastille en fait 28 et le remplissage 8 en
   haut comme en bas : on complete par une hauteur minimale, plutot qu'en gonflant le
   remplissage, pour que le dessin reste le meme sur un ecran large. */
.tg-item {
    min-height: var(--cible);
}

/* La pastille d'icone. Employee seule (`.tg-ico`) elle sert aussi aux titres de section. */
/* ----------------------------------------------------------------------------
   Les icones — SVG, et non plus une police.
   [2026-09-23] La police d'icones coutait 143 708 o sur le reseau pour ~2 000 dessins dont 109
   servaient, et sa feuille de style bloquait le rendu. Chaque page depose desormais les seuls
   dessins qu'elle emploie (service `Icones`). Detail et contraintes : `src/Service/Ui/Icones.php`.

   La taille suit `1em`, donc la TYPOGRAPHIE du contexte : une icone posee dans un titre grandit
   avec lui, sans qu'on la rhabille. C'est ce que la police faisait naturellement, et ce qu'un SVG
   a taille fixe aurait perdu.
   La couleur est `currentColor` : l'icone prend celle du texte, au survol et dans le theme sombre,
   sans une seule regle de plus.
   ---------------------------------------------------------------------------- */
/* La graisse intermediaire de Bootstrap passe par le token : une valeur, un seul endroit. */
.fw-semibold { font-weight: var(--fw-semi) !important; }

.tg-i {
    width: 1em;
    height: 1em;
    /* L'icone s'aligne sur l'oeil du texte, pas sur sa ligne de base. */
    vertical-align: -0.125em;
    fill: currentColor;
    flex: 0 0 auto;
}

/* Les teintes d'une icone. Elles remplacent des `style="color:var(--tg-x)"` ecrits dans les
   gabarits : la valeur etait deja un token, mais la DECISION vivait dans le balisage, donc elle
   s'y recopiait. Quatorze fois, dans la seule page de course. */
.tg-i--accent    { color: var(--tg-accent); }
.tg-i--succes    { color: var(--tg-success); }
.tg-i--attention { color: var(--tg-warning); }
.tg-i--danger    { color: var(--tg-danger); }
.tg-i--sourdine  { color: var(--tg-muted); }

/* Deux tailles au-dela du texte courant, exprimees en `em` pour rester solidaires du contexte. */
.tg-i--lg { width: 1.3em;  height: 1.3em; }
.tg-i--xl { width: 1.75em; height: 1.75em; }

/* ----------------------------------------------------------------------------
   Le verdict de la page de course — UNE teinte, nommee par l'etat.
   [2026-09-23] Elle etait recopiee cinq fois en `style=` dans le gabarit (icone, nombre, barre,
   bordure et texte de l'etiquette). Les valeurs etaient des tokens, mais la DECISION vivait dans
   le balisage, donc elle s'y repetait — et une decision prise cinq fois finit par diverger.
   ---------------------------------------------------------------------------- */
.tg-verdict--bon    { --verdict: var(--tg-success); }
.tg-verdict--moyen  { --verdict: var(--tg-warning); }
.tg-verdict--faible { --verdict: var(--tg-danger); }

.tg-verdict .tg-i          { color: var(--verdict); }
.tg-verdict .tg-conf-fill  { background: var(--verdict); }

.tg-verdict-score {
    font-weight: var(--fw-fort);
    font-size: var(--fs-affichage);
    line-height: var(--lh-bloc);
    color: var(--verdict);
    font-variant-numeric: tabular-nums;
}

.tg-conf-bar--fine {
    height: 6px;
    margin-bottom: var(--s-sm);
}

.tg-tag--verdict {
    background: transparent;
    border-color: var(--verdict);
    color: var(--verdict);
    font-size: var(--fs-xxs);
}

/* Le gris de second plan, nomme une fois plutot qu'ecrit a chaque emploi. */
.tg-texte-sourdine { color: var(--tg-muted); }

/* Un nom d'icone inconnu se VOIT — un trou silencieux passerait pour un choix de design. */
.tg-i--manquante {
    color: var(--tg-danger);
    opacity: .8;
}

/* Le sprite depose en fin de page ne doit ni s'afficher, ni pousser la mise en page. */
.tg-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

.tg-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: var(--ico);
    height: var(--ico);
    border-radius: var(--r-sm);
    background: var(--tg-card);
    border: 1px solid var(--tg-line);
    color: var(--tg-medium);
    transition: var(--t-smooth);
}

/* La pastille porte parfois un NUMERO plutot qu'une icone — le numero de course, par exemple.
   Il doit se lire comme un chiffre, pas comme un libelle : chasse fixe, largeur de chiffre
   constante, pour que huit lignes empilees s'alignent. */
.tg-ico--num {
    font-family: var(--f-num);
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-sm);
    font-weight: var(--fw-fort);
}

/* Une course DEJA COURUE reste lisible et cliquable — on va y chercher l'arrivee — mais elle
   ne doit pas peser autant que celles qui restent a courir. C'est l'information que la page
   ne donnait pas : a 21 h 30, quarante lignes se ressemblaient toutes, et rien ne disait
   lesquelles etaient encore devant. */
.tg-item--passe .tg-item-libelle {
    color: var(--tg-muted);
    font-weight: var(--fw-normal);
}

.tg-item--passe .tg-ico {
    opacity: .6;
}

.tg-item:hover .tg-ico,
.tg-item.est-actif .tg-ico {
    color: var(--tg-cta);
    border-color: var(--tg-line-strong);
}

.tg-item-texte {
    display: flex;
    flex-direction: column;
    line-height: var(--lh-serre);
    min-width: 0;
}

.tg-item-libelle {
    font-size: var(--fs-md);
    font-weight: var(--fw-moyen);
}

.tg-item.est-actif .tg-item-libelle {
    color: var(--tg-cta);
}

/* L'aide sous le libelle explique ce qu'on trouve derriere. Elle vit dans la page, pas dans
   une bulle au survol : une bulle ne se lit pas au doigt, et c'est la moitie du parc. */
.tg-item-aide {
    font-size: var(--fs-xs);
    color: var(--tg-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Les titres de section portent la meme pastille que les elements de liste : c'est ce qui fait
   qu'une page ressemble a la suivante. Avant, l'icone y flottait nue. */
/* [UI-11 2026-09-23 KAD] La pastille a ete retiree : cadre et fond. Un titre de section n'a pas
   besoin d'etre annonce par un bouton — le cadre faisait d'un simple reperage un objet
   cliquable, alors qu'il ne l'est pas. Le menu d'administration, qui sert de reference a la
   refonte, n'en a jamais eu : son icone de section est un signe colore, rien de plus. */
.tg-section-title .tg-section-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    color: var(--tg-cta);
    /* [FIX 2026-09-23] Le meme selecteur etait declare DEUX fois dans ce fichier, a 800 lignes
       d'ecart, avec deux tailles differentes — la seconde gagnait en silence. Une seule
       declaration desormais, avec la valeur qui s'appliquait reellement. */
    font-size: var(--fs-base);
}

/* ── INTITULE DE SECTION ──
   [2026-09-22] Le meme petit titre en capitales etait ecrit SIX fois en attribut `style` dans
   la page course, avec `.68rem`, `700` et `.08em` en clair a chaque fois — et une septieme
   variante pour la position au podium. Six declarations pour un seul objet : la septieme aurait
   ete differente.

   Il se distingue de `.tg-section-title` : celui-la ouvre une SECTION et porte une pastille et
   un filet ; celui-ci coiffe un BLOC a l'interieur d'une carte, et ne doit rien peser. */
.tg-kicker {
    display: block;
    margin-bottom: var(--s-sm);
    font-size: var(--fs-xxs);
    font-weight: var(--fw-fort);
    letter-spacing: var(--ls-md);
    text-transform: uppercase;
    color: var(--tg-muted);
}

/* Au podium, l'intitule porte la couleur du rang — or, argent, bronze. La teinte est la
   SEULE chose qui change : elle arrive par une variable posee sur l'element. */
.tg-kicker--rang {
    margin-bottom: 0;
    color: var(--rang, var(--tg-muted));
}

/* ── ZONE SENSIBLE ──
   [2026-09-22] « Supprimer mon compte definitivement » etait un bouton pleine largeur, colle
   sous « Enregistrer », de la meme taille et au meme endroit que lui. Une action IRREVERSIBLE
   a portee d'un clic de travers, sur la cible la plus large de la page.

   Elle vit desormais dans sa propre zone, detachee, a sa taille reelle. Le lisere rouge et le
   fond legerement teinte disent « ici, on ne clique pas par reflexe » — c'est le seul endroit
   de l'application ou l'on RALENTIT volontairement le geste. */
.tg-zone-danger {
    padding: var(--s-md);
    border-radius: var(--r-sm);
    border: 1px solid var(--tg-line);
    border-left: var(--accent) solid var(--tg-danger);
    background: var(--tg-subbg);
}

.tg-zone-danger .tg-kicker {
    color: var(--tg-danger);
}

/* ── BOUTON D'OEIL — afficher ou masquer un mot de passe ──
   Il etait pose trois fois avec le meme attribut `style` en ligne. Trois declarations pour un
   objet, et la cible tactile n'etait garantie par aucune. */
.tg-oeil {
    position: absolute;
    top: 50%;
    right: var(--s-sm);
    transform: translateY(-50%);
    min-width: var(--cible-min);
    min-height: var(--cible-min);
    --bs-btn-border-color: var(--tg-line-control);
}

/* [2026-09-23] Le bouton porte les DEUX dessins et dit lequel se voit. Avant, un script echangeait
   une classe de police d'icone ; en SVG il n'y a plus de classe a echanger, et surtout : un dessin
   qu'aucun rendu n'a demande n'entre pas dans le sprite de la page. Poser les deux est donc ce qui
   GARANTIT que la bascule a quelque chose a montrer. */
.tg-oeil .tg-oeil-barre           { display: none; }
.tg-oeil.est-devoile .tg-oeil-ouvert { display: none; }
.tg-oeil.est-devoile .tg-oeil-barre  { display: inline-block; }

/* ── EN-TETE DE PAGE ──
   [2026-09-22] Le meme objet s'ecrivait de HUIT facons : `h4 mb-1` seize fois, `h4 mb-3` cinq
   fois, puis `h3 mb-1`, `h5 mb-0`, `h6 mb-2`... Chacune etait juste, aucune n'etait la meme.
   Un titre de page n'est pas une decision a reprendre a chaque gabarit. */
.tg-page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-md);
    margin-bottom: var(--s-lg);
    padding-bottom: var(--s-sm);
    border-bottom: 1px solid var(--tg-line);
}

.tg-page-head .tg-ico {
    color: var(--tg-cta);
}

.tg-page-titre {
    display: flex;
    flex-direction: column;
    gap: var(--s-xs);
    min-width: 0;
    margin: 0;
    flex: 1 1 auto;
}

.tg-page-titre strong {
    font-size: var(--fs-xl);
    font-weight: var(--fw-fort);
    line-height: var(--lh-serre);
}

.tg-page-sous-titre {
    font-size: var(--fs-sm);
    color: var(--tg-muted);
}

/* Les actions de la page vivent a droite du titre, pas au-dessus ni en dessous : c'est la
   qu'on les cherche, et c'est la qu'elles ne poussent pas le contenu vers le bas. */
.tg-page-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-sm);
    margin-left: auto;
}

/* ── TABLEAU ──
   Les vingt tableaux de l'application portaient CINQ combinaisons de classes Bootstrap
   differentes. Aucune primitive maison n'existait.

   Pas de rayures : elles se battent avec la surbrillance de ligne, et deux fonds qui alternent
   rendent une colonne de chiffres plus difficile a suivre, pas plus facile. Un filet fin sous
   chaque ligne suffit a guider l'oeil. */
.tg-table {
    width: 100%;
    margin: 0;
    border-collapse: collapse;
    font-size: var(--fs-sm);
}

.tg-table thead th {
    padding: var(--s-sm);
    border-bottom: 1px solid var(--tg-line-strong);
    font-size: var(--fs-xxs);
    font-weight: var(--fw-fort);
    letter-spacing: var(--ls-md);
    text-transform: uppercase;
    color: var(--tg-muted);
    text-align: left;
    white-space: nowrap;
}

.tg-table tbody td {
    padding: var(--s-sm);
    border-bottom: 1px solid var(--tg-line);
    vertical-align: middle;
}

.tg-table tbody tr:last-child td {
    border-bottom: none;
}

.tg-table tbody tr:hover {
    background: var(--tg-subbg);
}

/* Les nombres s'alignent a droite et portent la fonte a chasse fixe : une colonne de montants
   ne se compare que si les unites sont l'une au-dessus de l'autre. */
.tg-table .tg-nombre {
    font-family: var(--f-num);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

/* ── ETAT VIDE ──
   Une table vide qui n'affiche rien se lit comme une page cassee. Elle doit DIRE qu'elle est
   vide, et pourquoi. */
.tg-vide {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--s-sm);
    padding: var(--s-xl) var(--s-md);
    color: var(--tg-muted);
    text-align: center;
    font-size: var(--fs-sm);
}

.tg-vide .tg-ico {
    color: var(--tg-muted);
}

/* ── MESSAGE ──
   Cinquante-deux alertes Bootstrap brutes. Le lisere d'accent a gauche est celui de
   `.tg-item` : c'est ce qui fait qu'un message appartient a la meme famille qu'un menu. */
.tg-note {
    display: flex;
    align-items: flex-start;
    gap: var(--s-sm);
    padding: var(--s-sm) var(--s-md);
    border-radius: var(--r-sm);
    border-left: var(--accent) solid var(--tg-cta);
    background: var(--tg-subbg);
    color: var(--tg-text);
    font-size: var(--fs-sm);
}

/* [FIX 2026-09-24] UI-07 — un flash de succes etait invisible sur device (KAD, R6 Belmont Park) :
   les variantes ne posaient qu'une bordure gauche de 3 px sur un fond identique a la page, dark
   sur dark. Le choix du 22/09 (unifier flash et note de page sur .tg-note) est garde, mais la
   TEINTE par etat est restauree : le fond est derive du token d'etat melange au fond de section,
   comme --tg-cta-bg le fait deja pour le danger (§2) et comme l'ombre de .btn-primary derive de
   --tg-action. Aucune valeur en clair, la teinte bascule avec le theme. */
.tg-note--succes {
    border-left-color: var(--tg-success);
    background: color-mix(in srgb, var(--tg-success) 18%, var(--tg-subbg));
}

.tg-note--attention {
    border-left-color: var(--tg-warning);
    background: color-mix(in srgb, var(--tg-warning) 18%, var(--tg-subbg));
}

.tg-note--danger {
    border-left-color: var(--tg-danger);
    background: color-mix(in srgb, var(--tg-danger) 18%, var(--tg-subbg));
}

/* ── PASTILLE — variantes de fond ──
   [2026-09-22] La page d'accueil habillait SEPT pastilles du meme couple fond/filet en
   attribut `style`. Le meme habillage ecrit sept fois est une decision prise sept fois.
   `.tg-chip` reste un marqueur de donnee et n'est pas touche : ces deux variantes ne
   changent que son fond. Le selecteur est compose (`.tg-chip.tg-chip--neutre`) parce que
   `.tg-chip` est declare PLUS BAS dans la feuille : a specificite egale, c'est lui qui
   gagnerait et la variante resterait muette. */
.tg-chip.tg-chip--neutre {
    background: var(--tg-subbg);
    border-color: var(--tg-line);
}

.tg-chip.tg-chip--accent {
    background: var(--tg-cta-bg);
    border-color: var(--tg-line);
    color: var(--tg-cta);
}

/* ── Menu d'administration : il ne garde que sa MISE EN PAGE ──
   Le decoupage en colonnes ne vaut qu'au-dessus de 992 px : en dessous, Bootstrap replie la
   barre et le menu se rend DANS le flux de la page. Lui imposer une largeur minimale la ferait
   deborder sur un telephone. */
.tg-admin-menu {
    padding: var(--s-sm);
}

.tg-admin-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-xs) var(--s-lg);
}

.tg-admin-titre {
    display: flex;
    align-items: center;
    gap: var(--s-sm);
    margin: var(--s-sm) 0;
    padding-bottom: var(--s-xs);
    border-bottom: 1px solid var(--tg-line);
    font-size: var(--fs-xxs);
    font-weight: var(--fw-fort);
    letter-spacing: var(--ls-md);
    text-transform: uppercase;
    color: var(--tg-muted);
}

/* [FIX 2026-09-23] Visait `.bi`, la classe de l'ancienne police d'icones. Au passage en SVG,
   l'element a change de classe et cette regle est devenue MUETTE : les icones de titre du menu
   d'administration avaient perdu leur couleur et leur taille, sans que rien ne le signale — une
   regle qui ne s'applique plus ne provoque aucune erreur, elle ne fait simplement plus rien.
   C'est le defaut que les invariants du projet nomment deja : « un renommage de classe rend
   MUETS les selecteurs qui la visent ». */
.tg-admin-titre .tg-i {
    font-size: var(--fs-lg);
    color: var(--tg-cta);
}

/* [UI-14 2026-09-24] S'appelait `.tg-admin-liste`. Elle est nee dans le menu d'administration,
   comme la primitive `.tg-item` qu'elle porte, mais la page des reunions et l'accueil s'en
   servaient deja : son nom mentait sur sa portee, et la page des partenaires allait etre la
   quatrieme a l'employer. Un nom qui ment fait hesiter — on se demande si on a le droit. */
.tg-liste {
    list-style: none;
    margin: 0;
    padding: 0;
}

@media (min-width: 992px) {
    .tg-admin-menu {
        min-width: 42rem;
        padding: var(--s-md);
    }

    .tg-admin-grid {
        grid-template-columns: repeat(3, minmax(12rem, 1fr));
    }

    .tg-admin-titre {
        margin-top: 0;
    }
}

footer {
    position: static;
    background: var(--tg-bg-accent);
    border-top: 1px solid var(--tg-line);
}

.legal small, .legal p {
    color: var(--tg-muted);
}

/* [FIX 2026-09-20] `link-fort` remplace `link-light`, ecrit dans le tableau de bord par
   reflexe du theme sombre : cette classe Bootstrap force une encre CLAIRE, et les adresses
   e-mail etaient donc illisibles sur le fond blanc — constate par KAD sur la page livree.
   Un lien qui porte l'encre du texte, c'est un role ; `link-light` etait une valeur. */
.link-fort {
    color: var(--tg-text);
    text-decoration: none;
    transition: var(--t-smooth);
}

.link-fort:hover {
    color: var(--tg-cta);
    text-decoration: underline;
}

.link-muted {
    color: var(--tg-muted);
    text-decoration: none;
}

/* [2026-09-20] Classe de ROLE qui remplace `text-white-50` dans les gabarits nettoyes :
   elle dit « secondaire », pas « blanc a moitie ». Meme valeur que le token, mais un nom
   qui survit a un changement de charte. */
.text-doux {
    color: var(--tg-muted) !important;
}

/* Un champ rempli automatiquement et verrouille : il se lit encore, mais il annonce qu'on
   n'y ecrit pas. [2026-09-20] Il portait `bg-dark`, qui ne disait rien de son etat. */
/* Encart d'aide contextuelle — discret par construction : il informe au premier passage et
   doit pouvoir etre ignore aux suivants. D'ou le fond de sous-section plutot qu'une couleur
   de role, qui ferait croire a une alerte. */
.tg-aide {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    background: var(--tg-subbg);
    border: 1px solid var(--tg-line);
    border-radius: var(--r-sm);
    padding: .7rem .9rem;
    margin-bottom: var(--s-md);
    font-size: var(--fs-md);
    color: var(--tg-medium);
}

.tg-aide i {
    color: var(--tg-muted);
    margin-top: var(--s-xs);
    flex-shrink: 0;
}

.champ-verrouille {
    background: var(--tg-subbg) !important;
    color: var(--tg-muted) !important;
    cursor: not-allowed;
}

.link-muted:hover {
    color: var(--tg-text);
    text-decoration: underline;
}

/* ── En-tete de carte et badge d'evenement — composants `race-header` / `race-badge`
   de la charte. Ils n'existaient pas : une carte de course s'ouvrait sans tete, et le vert
   emeraude de la charte n'apparaissait nulle part sur le site. ── */
.tg-entete {
    background: var(--tg-rule);
    color: var(--tg-on-rule);
    padding: .85rem 1rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--s-sm);
    border-radius: var(--r-md) var(--r-md) 0 0;
    margin: -1px -1px 0;
}

.tg-entete h1, .tg-entete h2, .tg-entete h3, .tg-entete h4, .tg-entete h5, .tg-entete h6 {
    color: inherit;
    margin: 0;
    font-size: var(--fs-xl);
}

/* Le badge d'evenement vit SUR l'en-tete sombre, ou l'emeraude rend 5,75. Pose nu sur le
   fond clair il ne rendrait que 2,42 — d'ou la bordure, pour le cas ou il en sorte. */
/* [2026-09-22] Ce badge portait l'EMERAUDE — la couleur qui, dans ce systeme, veut dire
   « favori ». Un evenement de course lui volait donc son sens, sur la page ou les deux se
   cotoient. Il passe a l'OR, qui est deja la teinte du Quinte sur la page course.

   Sa hauteur posait un second probleme : a --fs-sm avec .2rem de remplissage vertical, il
   depassait la ligne qui le contient et mordait sur le texte du dessous. Un badge se pose DANS
   une ligne, il ne la repousse pas. */
.tg-badge-event {
    display: inline-block;
    vertical-align: middle;
    background: var(--tg-vif-or);
    color: var(--tg-on-vif);
    border: 1px solid var(--tg-vif-or);
    padding: 0 var(--s-sm);
    border-radius: var(--r-full);
    font-size: var(--fs-xxs);
    font-weight: var(--fw-fort);
    line-height: 1.6;
    white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════
   9. PRIMITIVES
═══════════════════════════════════════════════════════════════ */
.tg-badge {
    background: var(--tg-subbg);
    border: 1px solid var(--tg-line);
    color: var(--tg-text);
}

/* [ADM-09 2026-09-20] La carte perd son filet GAUCHE de 4 px.
   C'etait le langage « papier/journal » de la charte precedente, et c'est ce qui datait le
   plus : chaque bloc de chaque page portait une barre bleu nuit sur son flanc. La nouvelle
   charte demande une carte a bordure fine tout autour, un rayon de 12 px et une ombre douce.
   ⛔ Le filet n'est pas supprime, il est DEPLACE au survol des elements qui en ont un sens
   (ligne de partant, carte de pari) : il devient une reponse a un geste au lieu d'un decor
   permanent. */
.tg-card {
    background: var(--tg-card);
    border: 1px solid var(--tg-line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-sm);
    transition: var(--t-smooth);
}

/* ⛔ [FIX 2026-09-20] Quatre gabarits posent `border-left-color` sur une carte pour SIGNALER
   quelque chose (une alerte, un encart d'information, un bloc premium). En retirant le filet
   permanent de `.tg-card`, leur declaration est devenue muette : ils demandaient la couleur
   d'un filet qui n'existait plus. Le filet reste donc disponible — mais il faut le DEMANDER,
   et c'est tout le changement : il etait un decor par defaut, il devient un signal explicite. */
.tg-card[style*="border-left"],
.tg-card--signal {
    border-left-width: var(--accent-fort);
    border-left-style: solid;
}

/* Une carte CLIQUABLE se souleve au survol — et seulement celle-la : une carte inerte qui
   bouge sous le pointeur promet une action qui n'existe pas. */
a > .tg-card:hover,
.tg-card--cliquable:hover {
    box-shadow: var(--sh-md);
    transform: translateY(-1px);
}

.tg-card h6 {
    letter-spacing: var(--ls-sm);
    font-weight: var(--fw-fort);
}

.tg-chip {
    border-radius: var(--r-full);
    padding: .35rem .7rem;
    font-size: var(--fs-sm);
    background: var(--tg-card);
    border: 1px solid var(--tg-line);
    color: var(--tg-medium);
}

.chip {
    border-radius: var(--r-full);
    padding: .3rem .6rem;
    font-size: var(--fs-sm);
    background: var(--tg-card);
    border: 1px solid var(--tg-line);
    color: var(--tg-medium);
}

.badge-soft {
    background: var(--tg-subbg);
    border: 1px solid var(--tg-line);
    color: var(--tg-text);
}

.title {
    letter-spacing: var(--ls-sm);
    color: var(--tg-medium);
    font-size: var(--fs-base);
    font-weight: var(--fw-fort);
}

.home header {
    height: 600px;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
}

.list-group-flush .list-group-item {
    background: transparent;
    border-color: var(--tg-line);
    transition: var(--t-smooth);
    color: var(--tg-text);
}

.list-group-item:hover {
    background: var(--tg-subbg);
}

/* Aplats de role — ⚠️ REGLE 3 : le texte s'inverse, jamais #fff en dur */
.tg-bg-success {
    background: var(--tg-favori) !important;
    color: var(--tg-on-favori) !important;
}

.tg-bg-success:hover {
    background: var(--tg-favori) !important;
    color: var(--tg-on-favori) !important;
    filter: brightness(.92);
}

.tg-bg-success-dark {
    background: var(--tg-rule) !important;
    color: var(--tg-on-rule) !important;
}

.tg-bg-success-dark:hover {
    background: var(--tg-rule) !important;
    color: var(--tg-on-rule) !important;
    filter: brightness(1.15);
}

.is-locked {
    opacity: 1;
    filter: grayscale(2%);
}

/* Mesures — aucun degrade : la couleur d'arrivee d'un degrade varie avec la
   longueur de la barre, ce qui rend la mesure moins lisible (charte §4). */
.meter {
    height: var(--s-sm);
    background: var(--tg-subbg);
    border-radius: var(--r-full);
    overflow: hidden;
}

.meter > div {
    height: 100%;
    background: var(--tg-rule);
}

progress {
    height: var(--s-sm);
    background: var(--tg-subbg);
}

.progress {
    --bs-progress-bg: var(--tg-subbg);
}

.progress-bar {
    background: var(--tg-rule);
}

.nav-pills .nav-link {
    color: var(--tg-text);
    background: var(--tg-card);
    border: 1px solid var(--tg-line-control);
    border-radius: var(--r-sm);
    transition: var(--t-smooth);
}

.nav-pills .nav-link:hover {
    background: var(--tg-subbg);
}

/* [ADM-09 2026-09-20] L'onglet actif porte le bleu nuit de la charte — un APLAT, pas une
   nuance de gris. Avant, actif et survol rendaient le meme fond : on ne savait pas lequel
   des deux on regardait.
   ⚠️ L'information n'est pas portee par la seule couleur : la graisse change aussi
   (correctif du 2026-09-13, a ne pas defaire). */
/* [2026-09-20] L'onglet actif porte l'EMERAUDE de la charte, qui la reserve a « l'etat actif
   des filtres ». C'est le seul endroit ou ce vert apparaissait dans le document et nulle part
   sur le site.
   ⚠️ L'encre dessus est ardoise (7,04), pas blanche : le blanc n'y rend que 2,54.
   ⚠️ L'information n'est pas portee par la seule couleur — la graisse change aussi
   (correctif du 2026-09-13, a ne pas defaire). */
.nav-pills .nav-link.active {
    background: var(--tg-vif-favori);
    color: var(--tg-on-vif);
    border-color: var(--tg-vif-favori);
    font-weight: var(--fw-fort);
}

/* [FIX 2026-09-13] l'etat actif etait porte par le cyan seul. Il l'est desormais
   par l'encre + la graisse : aucune information portee par la seule couleur. */
.active {
    color: var(--tg-text) !important;
    background: transparent !important;
    font-weight: bold !important;
}

.tg-spinner {
    display: none;
    transition: opacity .2s ease;
}

.tg-spinner.active {
    display: block;
    opacity: 1;
}

/* ═══════════════════════════════════════════════════════════════
   10. PAGE COURSE
═══════════════════════════════════════════════════════════════ */

/* ── Cartes de pari ── */
.tg-bet-card {
    background: var(--tg-card);
    border: 1px solid var(--tg-line);
    border-radius: var(--r-md);
    padding: 1.1rem 1.25rem;
    box-shadow: var(--sh-sm);
    transition: var(--t-smooth);
}

/* [ADM-09 2026-09-20] Le filet de couleur que portait la carte en permanence revient ICI,
   au survol, en marque interieure — c'est ce que la charte prevoit pour la ligne de partant.
   Une marque qui repond au geste se remarque ; la meme, permanente, devient du decor. */
/* [2026-09-22] Alignee sur `.tg-item` : fond qui se leve au survol, liseré d'accent a gauche.
   L'accent etait `--tg-favori`, c'est-a-dire la couleur SEMANTIQUE du favori d'une course —
   employee ici comme simple decor, sur une carte qui n'a rien d'un favori. C'est l'accent
   d'interface `--tg-cta` qui convient, et c'est celui du menu. */
.tg-bet-card:hover {
    background: var(--tg-subbg);
    border-color: var(--tg-line-control);
    box-shadow: var(--sh-md), inset 3px 0 0 0 var(--tg-cta);
}

.tg-bet-card .tg-bet-type {
    font-size: var(--fs-xxs);
    font-weight: var(--fw-titre);
    letter-spacing: var(--ls-md);
    text-transform: uppercase;
    color: var(--tg-muted);
}

.tg-bet-card .tg-bet-label {
    font-size: var(--fs-sm);
    color: var(--tg-muted);
    margin-top: var(--s-xs);
}

/* ── Dossards ── */
/* [ADM-09 2026-09-20] Le numero de partant passe du CERCLE au carre arrondi de la charte
   (« runner-number » : 36 px, rayon 6 px, fond plein, chiffre en clair).
   ⛔ La COULEUR reste celle du role — favori, outsider, surprise, valeur. C'est une
   information, pas une decoration : la charte la remplace par un bleu nuit uniforme parce
   qu'elle ne connait pas nos roles. Forme de la charte, sens du produit. */
.tg-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    height: 38px;
    border-radius: var(--r-sm);
    font-size: var(--fs-xl);
    font-weight: var(--fw-fort);
    border: 1px solid var(--tg-line-control);
    background: var(--tg-card);
    color: var(--tg-text);
    line-height: 1;
    flex-shrink: 0;
    transition: var(--t-smooth);
}

/* ⛔ Le numero ORDINAIRE reste discret, et c'est deliberement l'inverse de la charte, qui
   le veut plein bleu nuit. Dans une course, ce qui doit ressortir ce sont les chevaux
   REMARQUES — favori, outsider, surprise, valeur. Un numero banal en aplat sombre pese plus
   lourd a l'oeil qu'un favori en vert pale : la hierarchie se retournerait. La charte donne
   la FORME (carre arrondi, 38 px), le produit garde sa HIERARCHIE. */

.tg-num.favori {
    background: var(--tg-favori-bg);
    border-color: var(--tg-favori);
    color: var(--tg-favori);
}

.tg-num.outsider {
    background: var(--tg-outsider-bg);
    border-color: var(--tg-outsider);
    color: var(--tg-outsider);
}

.tg-num.surprise {
    background: var(--tg-surprise-bg);
    border-color: var(--tg-surprise);
    color: var(--tg-surprise);
}

.tg-num.value {
    background: var(--tg-value-bg);
    border-color: var(--tg-value);
    color: var(--tg-value);
}

.tg-num.lg {
    min-width: 48px;
    height: 48px;
    font-size: var(--fs-xxl);
}

/* ── Tags de role ── */
/* [ADM-09 2026-09-20] Pastille arrondie de la charte (`race-badge`), la ou l'etiquette
   portait l'angle dur de la charte precedente. Le contraste des couples teinte/aplat est
   inchange — il est mesure par PaletteContrastTest, qui doit rester vert. */
.tg-tag {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    padding: .26rem .7rem;
    border-radius: var(--r-full);
    font-size: var(--fs-xxs);
    font-weight: var(--fw-fort);
    letter-spacing: var(--ls-sm);
    text-transform: uppercase;
    border: 1px solid transparent;
}

.tg-tag--favori   { background: var(--tg-favori-bg);   border-color: var(--tg-favori);   color: var(--tg-favori); }
.tg-tag--outsider { background: var(--tg-outsider-bg); border-color: var(--tg-outsider); color: var(--tg-outsider); }
.tg-tag--surprise { background: var(--tg-surprise-bg); border-color: var(--tg-surprise); color: var(--tg-surprise); }
.tg-tag--value    { background: var(--tg-value-bg);    border-color: var(--tg-value);    color: var(--tg-value); }
/* ⚠️ REGLE 4 : --tg-tocard-bg vaut `transparent` en sombre — a 18 % le texte
   tomberait a 4,04:1. Le filet fort remplace la bordure de role. */
.tg-tag--tocard   { background: var(--tg-tocard-bg);   border-color: var(--tg-line-strong); color: var(--tg-tocard); }
.tg-tag--base     { background: var(--tg-favori-bg);   border-color: var(--tg-favori);   color: var(--tg-favori); }
.tg-tag--jockey   { background: transparent;           border-color: var(--tg-line);     color: var(--tg-muted); }

/* ── Indicateur de confiance ── */
.tg-conf {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .85rem;
}

.tg-conf-bar {
    flex: 1;
    height: 4px;
    background: var(--tg-subbg);
    border-radius: var(--r-full);
    overflow: hidden;
}

.tg-conf-fill {
    height: 100%;
    border-radius: var(--r-full);
    background: var(--tg-rule);
    transition: width .7s cubic-bezier(.4, 0, .2, 1);
}

.tg-conf-fill.is-quinte {
    background: var(--tg-outsider);
}

.tg-conf-pct {
    font-size: var(--fs-xxs);
    font-weight: var(--fw-fort);
    color: var(--tg-muted);
    min-width: 2.4rem;
    text-align: right;
}

/* ── Sur-titre de section — filet de presse ── */
.tg-section-title {
    display: flex;
    align-items: center;
    gap: var(--s-sm);
    font-size: var(--fs-xs);
    font-weight: var(--fw-titre);
    letter-spacing: var(--ls-lg);
    text-transform: uppercase;
    color: var(--tg-muted);
    margin-bottom: var(--s-md);
}

.tg-section-title::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--tg-line);
}


/* ── Cartes de partant ── */
.tg-horse-card {
    background: var(--tg-card);
    border: 1px solid var(--tg-line);
    border-radius: var(--r-md);
    border-left: 4px solid var(--tg-line-strong);
}

.tg-horse-card.is-favori   { border-left-color: var(--tg-favori); }
.tg-horse-card.is-outsider { border-left-color: var(--tg-outsider); }
.tg-horse-card.is-surprise { border-left-color: var(--tg-surprise); }
.tg-horse-card.is-value    { border-left-color: var(--tg-value); }

/* ── Barre de probabilite ── */
.tg-prob-bar {
    height: 5px;
    background: var(--tg-subbg);
    border-radius: var(--r-full);
    overflow: hidden;
}

.tg-prob-fill {
    height: 100%;
    border-radius: var(--r-full);
    background: var(--tg-rule);
    transition: width .5s cubic-bezier(.4, 0, .2, 1);
}

.tg-prob-fill.is-favori   { background: var(--tg-favori); }
.tg-prob-fill.is-outsider { background: var(--tg-outsider); }
.tg-prob-fill.is-surprise { background: var(--tg-surprise); }
.tg-prob-fill.is-value    { background: var(--tg-value); }

/* ── Barres de ponderation ── */
.tg-wbar {
    height: 3px;
    background: var(--tg-subbg);
    border-radius: var(--r-full);
    overflow: hidden;
    margin-top: .25rem;
}

.tg-wbar-fill {
    height: 100%;
    border-radius: var(--r-full);
    background: var(--tg-rule);
}

/* ── Bandeau d'alerte (flash) ──
   [2026-09-22] `.tg-flash` et ses quatre variantes n'avaient qu'un seul employeur,
   components/ui/alert.html.twig, passe sur la primitive `.tg-note`. Supprimees le jour meme
   plutot que laissees orphelines. */
