/* Northern Moose — système de design. Toutes les couleurs passent par ces jetons. */
:root{
  /* Surfaces */
  --bg:#f6f5f2; --panel:#ffffff; --panel2:#faf9f5; --panel3:#f5f3ee;
  --line:#ebe8e1; --line2:#e0ddd4; --hover:#f1efe9; --topbar-bg:#ffffffee;
  /* Encres. --mut2 vise 4,65:1 au pire cas sur les huit surfaces où il se pose
     (voir test_contraste). --mut3 est décoratif : il ne rend aucun texte, seulement
     les traits du filigrane de patinoire. */
  --ink:#1a201d; --ink2:#2b332e; --sub:#3f4a44; --mut:#5f6b64; --mut2:#656e69; --mut3:#8a948e;
  /* Accents. La sémantique ne bouge jamais : vert = buts pour, rouge = buts contre. */
  --green:#2f7d56; --green-d:#1f6b45; --green-dd:#1f3a2c; --green-mint:#7fd3a6;
  --green-h:#1a5d3c; --on-green:#eaf7ef;
  /* --green-strong : encre verte forte, qui s'éclaircit la nuit.
     --on-green-dd : encre posée sur --green-dd, qui reste sombre dans les deux thèmes. */
  --green-strong:#1f3a2c; --on-green-dd:#eaf7ef;
  /* --gold foncé en jour : il ne tenait que 3,5:1 sur --gold-bg.
     --red-d : #b8442c valait 4,48:1 sur --ag-bg (podiums, cellule +/- surlignée,
     badge « À corriger ») ; #b2422b y tient 4,72. */
  --red:#c0492f; --red-d:#b2422b; --blue:#2a6fae; --gold:#7a6015;
  /* Séries 5 et 6 des graphiques, pour le cinquième gardien adverse et au-delà :
     au-dessus de 4,5:1 sur --panel, dans une teinte libre. */
  --serie5:#7b6bb5; --serie6:#4f7778;
  /* Fonds de camp et fonds neutres */
  --for-bg:#e7f1ea; --for-bg2:#f3f8f4; --for-line:#bcdcc9;
  --ag-bg:#f7e7e2;  --ag-bg2:#faf2ef;  --ag-line:#eccdc2; --ag-line2:#ddb8ab;
  --accent-soft:#eef3ef; --neutral-bg:#eef0ec; --track:#eef0ec; --tag-bg:#f4f3ef;
  /* Jetons venus des gabarits (croquis de patinoire, filet, aide, podiums) */
  --for-soft:#d6e6dc;
  --green-txt:#4a6a57; --green-txt2:#1f5236;
  --line3:#d8d3c8; --rink-bg:#edece7; --rink-line:#b49d92; --rink-mut:#8a97a8;
  --gold-bg:#f6efdc; --blue-bg:#f2f6fa;
  /* Détails */
  --avatar-bg:#e4e9e4; --avatar-ink:#3f5a4b; --barre:#cfcabd; --fleche:#b3a9a0;
  --logo-bg:#111; --ombre:26,32,29;
  /* Ombre des couches flottantes (palette, dialogue) ; lit --ombre du thème actif. */
  --ombre-flottante:0 30px 70px rgba(var(--ombre),.35);
  /* Ombre du menu du compte et du panneau de navigation du téléphone. */
  --ombre-menu:0 18px 40px -18px rgba(var(--ombre),.34), 0 2px 6px rgba(var(--ombre),.06);
  --green-glow:rgba(31,107,69,.3); --green-glow2:rgba(31,107,69,.12);
  /* Lueur des bords de tableau défilant : sombre le jour, claire la nuit. */
  --scroll-cue:rgba(26,32,29,.14);
  /* Mouvement : une seule courbe et une seule durée pour toute l'application ; la
     couverture (vitrine.css) les reprend. */
  --courbe:cubic-bezier(.2,.7,.2,1); --t:.24s var(--courbe);
  /* Retrait du contenu depuis le bord de sa colonne, commun à la page, à la barre du
     haut et au bandeau des nouveautés (30 contre 26 px décalait le logo de 4 px par
     rapport au titre ; voir UneSeuleVerticaleTest). */
  --marge-page:30px;
  /* La même marge, pour un conteneur pleine largeur seulement : sur un conteneur déjà
     centré par max-width et margin:auto, elle s'ajoute au centrage (96 px de trop à
     2000 px). `100%` et non `100vw`, qui compte la barre de défilement : 5 px d'écart
     mesurés à 1990 px. */
  --marge-colonne:calc(max(0px, 100% - var(--colonne)) / 2 + var(--marge-page));
  /* La colonne de contenu, partagée par la page et par la barre du haut. */
  --colonne:clamp(1400px, 90vw, 1900px);
  --sans:'Hanken Grotesk',-apple-system,BlinkMacSystemFont,sans-serif;
  --mono:'JetBrains Mono',ui-monospace,monospace;

  /* ── L'échelle ────────────────────────────────────────────────────────────
     L'ensemble fermé des valeurs autorisées, relevé sur les valeurs employées (il y
     en avait 24 de police et 26 d'espacement) ; le report coûte au plus 1 px en
     typographie et 2 px en espacement. Jamais redéclarés dans le bloc nuit. */
  --e1:4px; --e2:6px; --e3:8px; --e4:11px;
  --e5:14px; --e6:18px; --e7:24px; --e8:32px;

  /* Texte, ancré sur 13,5 px (corps de tableau). 14 et 13 px manquent exprès : le
     corps de tableau descend à 13,5 et les tables denses à 12,5, un cran plus bas.
     Rien sous 10,5 px ne porte de donnée. */
  --tx-1:10.5px; --tx-2:11.5px; --tx-3:12.5px; --tx-4:13.5px;
  --tx-5:15px;   --tx-6:17px;   --tx-7:20px;   --tx-8:28px;

  /* Chiffres en chasse fixe : échelle séparée, la mono n'a pas les mêmes métriques.
     Le cran de 24 px sert les compteurs d'import et les totaux de match. */
  --num-1:19px; --num-2:24px; --num-3:28px; --num-4:40px;

  /* Graisses nommées : `600` ne dit pas ce qu'il fait, `--gr-app` si. */
  --gr-cour:500; --gr-app:600; --gr-fort:700; --gr-titre:800;

  /* ── Les rôles de densité ─────────────────────────────────────────────────
     Deux rythmes mesurés : 14 px entre les blocs et les cartes, 11 px à l'intérieur
     d'une carte (lignes de détail des journaux). Les confondre ajoutait 4 px à
     chaque ligne de but. */
  --gouttiere:var(--e5); --gouttiere-x:var(--e5);
  --pile:var(--e4); --pile-serree:var(--e2);
  --mesure-prose:78ch;
  /* La mesure d'un formulaire, déclarée une fois (elle valait 620, 640 ou 680 selon
     le gabarit) ; les paliers larges s'en dérivent. */
  --mesure-formulaire:640px;

  /* Rembourrage des cartes : quatre registres pour les dix formes relevées, tous à
     18 px d'horizontal. Les cartes à 22 px y perdent 4 px, écart accepté plutôt
     qu'un cinquième registre. */
  --pad-carte:var(--e5) var(--e6);         /* 14 18 — le registre courant */
  --pad-carte-aere:var(--e6) var(--e6);    /* 18 18 — texte et formulaires */
  --pad-carte-dense:var(--e4) var(--e5);   /* 11 14 — cartes de distribution */
  --pad-carte-table:var(--e3) var(--e2);   /* 8 6  — cartes à table défilante */

  /* La ligne « libellé · jauge · n · % » : largeurs communes, pour que les pistes
     de cartes voisines commencent au même x. */
  --h-barre:var(--e2); --lbl:150px; --col-n:20px; --col-p:32px;

  /* Hauteurs de graphique. La large monte à 300 px au palier 1600 : à 230, une carte
     de 1628 px faisait un ruban de 7 pour 1. */
  --h-graphe:190px; --h-graphe-court:110px; --h-graphe-large:230px;
}

/* ── L'écran de référence ───────────────────────────────────────────────────
   Au-dessus de la plus haute max-width (1100), donc hors du domaine mobile. Il
   réassigne quatre jetons de rôle, sans toucher à la typographie ni au rythme
   vertical, 1920 étant aussi 1080 (voir PalierDeReferenceTest). */
@media (min-width:1600px){
  :root{
    --gouttiere-x:var(--e6);            /* 14 → 18 : les colonnes se séparent */
    --pad-carte:var(--e5) var(--e7);    /* latéral seul, la hauteur ne bouge pas */
    --lbl:170px;                        /* la piste de jauge respire */
    --h-graphe-large:300px;             /* le comparatif cesse d'être un ruban */
  }
}

/* Thème nuit : la glace de la page d'accueil, portée sur l'application. Seuls les
   jetons changent, hormis l'opacité du filigrane (.rk-fond). */
:root[data-theme="nuit"]{
  --bg:#07120e; --panel:#101f19; --panel2:#0d1a15; --panel3:#132620;
  --line:#1e332a; --line2:#274036; --hover:#16291f; --topbar-bg:#0a1611ee;
  --ink:#eaf7ef; --ink2:#d7e9df; --sub:#b6d0c2; --mut:#9bb8a8; --mut2:#8fae9d; --mut3:#7a9989;
  --green:#4fae7c; --green-d:#5cbd89; --green-dd:#0f2a1f; --green-mint:#8fd0ae;
  --green-h:#6bcf9a; --on-green:#06140e;
  --green-strong:#a5dcc0; --on-green-dd:#eaf7ef;
  --red:#e0705a; --red-d:#e88a76; --blue:#6aa8dd; --gold:#d3b45f;
  --serie5:#9b8ed0; --serie6:#7fb0b1;
  --for-bg:#12301f; --for-bg2:#0e2419; --for-line:#265f3f;
  --ag-bg:#3a1d17;  --ag-bg2:#2a1611;  --ag-line:#6b3327; --ag-line2:#8a4234;
  --accent-soft:#132e21; --neutral-bg:#17251f; --track:#1b2c24; --tag-bg:#152521;
  --for-soft:#1c4630;
  --green-txt:#8fd0ae; --green-txt2:#a5dcc0;
  --line3:#2a4438; --rink-bg:#183028; --rink-line:#416750; --rink-mut:#6d8a9b;
  --gold-bg:#2b2415; --blue-bg:#14232e;
  --avatar-bg:#1c3327; --avatar-ink:#9fd7b8; --barre:#263d32; --fleche:#7a9989;
  --logo-bg:#04100b; --ombre:0,0,0;
  --scroll-cue:rgba(234,247,239,.22);
  --green-glow:rgba(127,211,166,.28); --green-glow2:rgba(127,211,166,.18);
  color-scheme:dark;
}
*{ box-sizing:border-box; }
body{ margin:0; background:var(--bg); color:var(--ink); font-family:var(--sans); }
::-webkit-scrollbar{ width:10px; height:10px; }
::-webkit-scrollbar-thumb{ background:var(--barre); border-radius:8px; border:2px solid var(--bg); }
a{ text-decoration:none; color:inherit; }
/* Alpine retire x-cloak au montage sans rien masquer lui-même. Un panneau à id
   demande en plus un masque en ligne : voir CloakTest. */
[x-cloak]{ display:none !important; }
.mono{ font-family:var(--mono); }
@keyframes fadeIn{ from{ opacity:0; } to{ opacity:1; } }
@keyframes pop{ 0%{ transform:scale(.96); opacity:.4 } 100%{ transform:scale(1); opacity:1 } }
@keyframes flash{ 0%{ background:var(--for-bg) } 100%{ background:transparent } }

/* Patinoire en filigrane, fixe sous toute l'application : visible dans les seules
   marges (les cartes sont opaques), plus marquée en mode nuit. */
.rk-fond{ position:fixed; inset:0; width:100%; height:100%; z-index:-1;
  pointer-events:none; opacity:.5; }
.rk-fond *{ fill:none; vector-effect:non-scaling-stroke; }
.rk-fond .rk-bande{ stroke:var(--line2); stroke-width:1.5; }
.rk-fond .rk-but, .rk-fond .rk-cercle{ stroke:var(--red); stroke-width:1; opacity:.22; }
.rk-fond .rk-bleue{ stroke:var(--blue); stroke-width:5; opacity:.10; }
.rk-fond .rk-rouge{ stroke:var(--red); stroke-width:5; opacity:.12; }
.rk-fond .rk-zone{ stroke:var(--blue); stroke-width:1; opacity:.22; }
.rk-fond .rk-filet{ stroke:var(--mut3); stroke-width:1; opacity:.3; }
.rk-fond .rk-point{ fill:var(--red); opacity:.18; }
:root[data-theme="nuit"] .rk-fond{ opacity:.85; }

/* Pages de référence (Aide, Données, fiche d'un compte) : même colonne que les pages
   de données (plafonnées à 1240 et 1040 px, elles paraissaient plus étroites que les
   autres pages du même menu) ; seule la ligne de texte courant est plafonnée. */
.page-texte p, .page-texte .h-sub{ max-width:var(--mesure-prose); }
/* Deux cartes voisines de contenus inégaux : l'action descend au bas de chacune, et
   les deux boutons tombent sur la même ligne. */
.card.colonne{ display:flex; flex-direction:column; }
.card.colonne .pousse-bas{ margin-top:auto; }
/* La prose et le premier libellé se touchaient (page d'un compte, 375 et 1500 px) :
   `.h-sub` n'a pas de marge, `.pile` n'espace qu'entre ses enfants, et le
   `margin-top:auto` vaut zéro sans mou. Pas de `gap` sur `.card.colonne` : il
   s'ajouterait à la marge de `.entete-carte` et casserait le zéro entre titre et
   sous-titre de la page Données. */
.card.colonne > .h-sub{ margin-bottom:var(--pile); }

/* Page Effectif : la patinoire à gauche, la fiche du joueur à droite, à hauteur
   égale, puis une seule colonne sous 1100 px (bloc Responsive). minmax(0, …) et non
   1fr : une piste en 16/9 a une largeur préférée énorme et ferait déborder la page. */
.eff-pile{ display:grid; grid-template-columns:minmax(0, 1.25fr) minmax(0, 1fr); gap:var(--e5); }
/* La glace de nuit valait 1,03:1 contre la carte, invisible, et même le noir pur n'y
   donne que 1,23 : elle est éclaircie à 1,21, ses traits de 1,60 à 2,20. Le jour avait
   le même défaut (traits à 1,62), porté à 2,17. --rink-bg et --rink-line ne servent
   que cette page. */
.eff-glace{ position:relative; margin-top:16px; padding:26px 20px 28px; border-radius:14px;
  border:1px solid var(--line); background:var(--rink-bg); overflow:hidden;
  /* Les groupes s'étalent sur la glace au lieu de se masser au centre :
     les attaquants dans le tiers haut, les défenseurs dans le tiers bas. */
  display:grid; gap:var(--e7); align-content:space-evenly;
  width:100%; }
/* Un plancher seulement. Avec `aspect-ratio:16/9` et `max-height:760px`, trois
   rangées d'attaquants poussaient les gardiens sous le bord, tranchés en silence par
   `overflow:hidden`. */
@media (min-width:900px){
  .eff-glace{ min-height:420px; }
}
/* Croquis en « meet » (effectif.html) : il entre en entier quelle que soit la hauteur.
   En « slice », le cadre plus large que 16/9 rognait les bandes haute et basse. */
.eff-rink{ position:absolute; inset:0; width:100%; height:100%; opacity:.5; pointer-events:none; }
.eff-rink *{ fill:none; vector-effect:non-scaling-stroke; }
.eff-rink .rk-bande{ stroke:var(--rink-line); stroke-width:1.5; }
.eff-rink .rk-bleue{ stroke:var(--blue); stroke-width:6; opacity:.16; }
.eff-rink .rk-rouge{ stroke:var(--red); stroke-width:6; opacity:.18; }
.eff-rink .rk-cercle, .eff-rink .rk-but{ stroke:var(--red); stroke-width:1.2; opacity:.28; }
.eff-rink .rk-zone{ stroke:var(--blue); stroke-width:1.2; opacity:.3; }
.eff-rink .rk-filet{ stroke:var(--rink-mut); stroke-width:1.2; opacity:.5; }
.eff-rink .rk-point{ fill:var(--red); opacity:.25; }

.eff-zone{ position:relative; }
.eff-lbl{ font:var(--gr-fort) var(--tx-2) var(--sans); letter-spacing:.12em; text-transform:uppercase;
  color:var(--mut2); margin-bottom:9px; text-align:center; }
/* --mut2 tombait à 3,8:1 sur la glace ; le banc, sur --panel, le garde. */
.eff-glace .eff-lbl{ color:var(--mut); }
.eff-rang{ display:flex; flex-wrap:wrap; gap:var(--e3); justify-content:center; }

.eff-chip{ display:inline-flex; align-items:center; gap:var(--e3); min-height:44px;
  padding:var(--e2) var(--e5) var(--e2) var(--e2); border-radius:999px; cursor:pointer;
  border:1px solid var(--line2); background:var(--panel); color:var(--ink2);
  font:var(--gr-app) var(--tx-4) var(--sans);
  transition:transform var(--t), border-color var(--t), box-shadow var(--t); }
.eff-chip .n{ display:grid; place-items:center; min-width:32px; height:32px; border-radius:50%;
  background:var(--neutral-bg); font:var(--gr-fort) var(--tx-4) var(--mono); color:var(--ink); }
.eff-chip .nom{ white-space:nowrap; }
.eff-chip .pm{ font:var(--gr-fort) var(--tx-2) var(--mono); color:var(--mut); }
.eff-chip:hover{ transform:translateY(-2px); border-color:var(--green);
  box-shadow:0 10px 22px -14px rgba(var(--ombre),.55); }
.eff-chip:active{ transform:none; }
.eff-chip.pos{ background:var(--for-bg); border-color:var(--for-line); }
.eff-chip.pos .n{ background:var(--panel); color:var(--green-strong); }
.eff-chip.pos .pm{ color:var(--green-d); }
.eff-chip.neg{ background:var(--ag-bg); border-color:var(--ag-line); }
.eff-chip.neg .n{ background:var(--panel); color:var(--red-d); }
.eff-chip.neg .pm{ color:var(--red-d); }

.eff-num{ display:grid; place-items:center; width:46px; height:46px; border-radius:14px;
  background:linear-gradient(150deg, var(--green), var(--green-dd));
  color:var(--on-green-dd); font:var(--gr-fort) var(--num-1) var(--mono); letter-spacing:-.04em; flex:none; }

/* La fiche prend la hauteur de la patinoire (124 px à côté d'une carte de 443
   sinon). L'état vide se centre ; une fiche remplie coule depuis le haut. */
.eff-fiche{ display:flex; flex-direction:column; }
/* Rythme hiérarchique : un intitulé s'écarte plus de ce qui précède que du bloc
   qu'il annonce. Un hibou uniforme l'aurait laissé flotter entre les deux. */
.eff-fiche > * + *{ margin-top:var(--pile); }
.eff-fiche > * + .sectionlabel{ margin-top:var(--e7); }
.eff-fiche > .sectionlabel + *{ margin-top:var(--e3); }
.eff-fiche > .empty{ margin:auto; }
/* Le hx-indicator des pastilles vise la fiche : sans cette règle, sur un réseau
   lent, la carte gardait les chiffres du joueur précédent. Pas .htmx-indicator,
   qui la masquerait au repos. */
.eff-fiche.htmx-request{ opacity:.45; pointer-events:none; transition:opacity .15s ease; }

/* Le banc des affiliés : hors de la glace, et plus discret. */
.eff-banc{ margin-top:14px; padding-top:var(--e5); border-top:1px dashed var(--line2); }
.eff-banc .eff-chip{ background:transparent; border-style:dashed; color:var(--mut); }
.eff-banc .eff-chip .n{ background:var(--neutral-bg); color:var(--mut); }

/* Le nom ne disparaît que sous 430 px : masqué sous 900, il ne laissait que des
   numéros sur un iPad en portrait, où la carte est pourtant pleine largeur. */
@media (max-width:430px){
  .eff-chip .nom{ display:none; }
  .eff-chip{ padding-right:10px; }
}

/* Topbar / nav. Fond pleine largeur, contenu aligné sur la colonne de page : à
   2560 px, la marque et les actions filaient aux deux bords de l'écran. */
.topbar{ position:sticky; top:0; z-index:30; display:grid; grid-template-columns:1fr auto 1fr;
  align-items:center; gap:var(--e7);
  padding-block:13px;
  padding-inline:var(--marge-colonne);
  background:var(--topbar-bg); backdrop-filter:blur(8px); border-bottom:1px solid var(--line); }
.logo{ width:32px; height:32px; border-radius:9px; object-fit:cover; display:block;
  background:var(--logo-bg); }
.brand{ font:var(--gr-titre) var(--tx-5) var(--sans); letter-spacing:-.2px; }
.brand-sub{ font:var(--gr-app) var(--tx-2) var(--sans); color:var(--mut2); }
.nav{ display:flex; gap:2px; flex-wrap:wrap; justify-content:center; }
/* ── Le déclencheur du menu de navigation ───────────────────────────────────
   Invisible au-dessus de 900 px, où le ruban d'onglets tient seul. Même forme que
   le déclencheur du menu du compte, qui lui fait face : leur survol et leur état
   ouvert s'écrivent ici pour les deux. */
.nav-declencheur, .menu-declencheur{ align-items:center; min-height:44px;
  border:1px solid var(--line2); background:var(--panel); color:var(--ink2); cursor:pointer;
  transition:background var(--t), border-color var(--t); }
.nav-declencheur{ display:none; justify-content:center; width:44px; border-radius:12px; }
.nav-declencheur:hover, .menu-declencheur:hover{ background:var(--hover); border-color:var(--line3); }
/* Les deux icônes suivent `aria-expanded`, seule source de l'état : en CSS plutôt
   qu'en `x-show`, elles ne dépendent pas d'Alpine. */
.nav-declencheur .nav-icone-fermer{ display:none; }
.nav-declencheur[aria-expanded="true"] .nav-icone-ouvrir{ display:none; }
.nav-declencheur[aria-expanded="true"] .nav-icone-fermer{ display:inline; }
.nav-declencheur[aria-expanded="true"], .menu-declencheur[aria-expanded="true"]{ background:var(--hover); border-color:var(--green); }
.nav-tab{ padding:var(--e3) var(--e4); border-radius:8px; background:transparent; color:var(--mut);
  font:var(--gr-app) var(--tx-4) var(--sans); cursor:pointer; border:none; white-space:nowrap; }
.nav-tab:hover{ background:var(--hover); }
/* --green sur --accent-soft donnait 4,46:1, sur toutes les pages puisque la barre
   est partagée ; --green-d y tient 5,76. */
.nav-tab.on{ background:var(--accent-soft); color:var(--green-d); font-weight:700; }
.avatar{ width:28px; height:28px; border-radius:50%; background:var(--avatar-bg); display:flex;
  align-items:center; justify-content:center; font:var(--gr-fort) var(--tx-3) var(--sans); color:var(--avatar-ink); }
.role-chip{ font:var(--gr-app) var(--tx-2) var(--sans); color:var(--mut2); background:var(--accent-soft); padding:var(--e1) var(--e3); border-radius:20px; }
.topbar-right{ display:flex; align-items:center; gap:var(--e4); justify-self:end; flex-wrap:wrap; justify-content:flex-end; }

/* Le logo respire, et son cercle de mise au jeu se trace au chargement. */
.logo-vif{ position:relative; display:grid; place-items:center; width:32px; height:32px; }
.logo-vif .logo{ position:relative; z-index:1; animation:logo-souffle 7s ease-in-out infinite; }
.logo-cercle{ position:absolute; inset:-6px; width:44px; height:44px; overflow:visible; pointer-events:none; }
.logo-cercle circle{ fill:none; stroke:var(--green); stroke-width:1.2; opacity:.55;
  stroke-dasharray:1; stroke-dashoffset:1;
  animation:logo-trace 1.4s cubic-bezier(.25,.8,.3,1) .2s forwards; }
.topbar a:hover .logo-cercle circle{ opacity:1; stroke:var(--green-d); }
@keyframes logo-trace{ to{ stroke-dashoffset:0; } }
@keyframes logo-souffle{ 0%,100%{ transform:scale(1); } 50%{ transform:scale(1.06); } }

/* Chaque page entre en montant. Avec hx-boost, .page est un élément neuf à
   chaque navigation : l'animation se rejoue donc toute seule, sans JS. */
@keyframes page-entre{ from{ opacity:0; transform:translateY(9px); } to{ opacity:1; transform:none; } }

/* Layout : la colonne suit l'écran jusqu'à 1900 px (à 2560 px, un plafond à 1400
   laissait 45 % de l'écran vide) ; sur un petit écran, la fenêtre commande. */
.page{ max-width:var(--colonne); margin:0 auto; padding:24px var(--marge-page) 64px;
  animation:page-entre .42s var(--courbe) backwards; }

/* Pas de zoom CSS : il casse le dimensionnement des canvas Chart.js (boucle de
   redimensionnement dans Chrome). */
/* En-tête de page : `.sectionlabel` et `h1.pagetitle`, communs aux gabarits de page.
   Le sur-titre et son filet viennent de la couverture. */
.sectionlabel{ display:inline-flex; align-items:center; gap:var(--e3);
  font:var(--gr-app) var(--tx-2) var(--sans); color:var(--green-d); letter-spacing:.13em; text-transform:uppercase; }
.sectionlabel::before{ content:""; width:22px; height:1px; background:var(--for-line);
  flex:none; }

.card{ background:var(--panel); border:1px solid var(--line); border-radius:14px;
  padding:var(--pad-carte); }
.card.aere{ padding:var(--pad-carte-aere); }
.card.dense{ padding:var(--pad-carte-dense); }
/* `.plein` et non `.tbl-scroll`, qui dit que la carte défile et non qu'elle est
   serrée : les confondre ôtait 8 et 14 px aux cinq cartes d'analyse du Tableau. Ici
   la table est la carte (journaux, classement). */
.card.plein{ padding:var(--pad-carte-table); }
/* La seule carte sans rembourrage : le panneau de saisie de /logger/. */
.card.nu{ padding:0; }
/* Quatre niveaux de titre (volet et sous-carte n'étaient séparés que de 2,5 px) :
   le volet monte d'un cran, la sous-carte passe en capitales espacées. Propriétés
   longues, jamais le raccourci `font:`, qui remet `line-height` à `normal`. */
.h-title{ font-family:var(--sans); font-weight:var(--gr-fort); font-size:var(--tx-5);
  line-height:1.3; }
.h-title.h-volet{ font-size:var(--tx-6); font-weight:var(--gr-titre); }
.h-title.h-volet.pour{ color:var(--green-strong); }
.h-title.h-volet.contre{ color:var(--red-d); }
.h-title.h-sous{ font-size:var(--tx-2); font-weight:var(--gr-fort); color:var(--mut);
  text-transform:uppercase; letter-spacing:.07em; }
.h-sub{ font:var(--gr-cour) var(--tx-2) var(--sans); color:var(--mut2); }

/* KPI */
.kpi{ background:var(--panel); border:1px solid var(--line); border-radius:13px; padding:var(--e5) var(--e5); }
.kpi .v{ font:var(--gr-fort) var(--num-3) var(--mono); letter-spacing:-.8px; }
.kpi .l{ margin-top:5px; font:var(--gr-app) var(--tx-3) var(--sans); color:var(--sub); }
/* Le rythme appartient aux conteneurs : les marges de premier niveau des gabarits
   sont supprimées, jamais converties en classes chiffrées. */
.page > * + *{ margin-top:var(--gouttiere); }
/* Les partiels HTMX ne sont pas enfants de .page : ils ont leur propre pile. */
#goal-panel > * + *{ margin-top:var(--pile); }
.grid{ display:grid; gap:var(--gouttiere) var(--gouttiere-x); }
.grid.serre{ gap:var(--pile); }
.pile{ display:flex; flex-direction:column; gap:var(--pile); }
.pile.serre{ gap:var(--pile-serree); }
/* Marge du navigateur retirée : tous les titres de carte l'annulaient en ligne. */
.h-title, .card h2, .card h3, .card h4{ margin:0; }

/* Bars */
.bartrack{ height:var(--h-barre); background:var(--track); border-radius:4px; overflow:hidden; }
.barfill{ height:100%; border-radius:4px; }
/* Le camp de la jauge, écrit une fois (les gabarits le peignaient 92 fois). La
   largeur reste en ligne : c'est une donnée calculée par le serveur. */
.barfill.pour{ background:var(--green); }
.barfill.contre{ background:var(--red); }

/* Tables */
table{ width:100%; border-collapse:collapse; }
thead th{ font:var(--gr-fort) var(--tx-2) var(--sans); color:var(--mut2); text-transform:uppercase; letter-spacing:.5px;
  text-align:left; padding:0 var(--e4) var(--e4); }
/* En-tête de ligne : une cellule en <th scope="row"> prend la même cellule que
   `tbody td`, avec un text-align explicite, un <th> se centrant par défaut. */
tbody td, tbody th{ padding:var(--e4) var(--e4); border-top:1px solid var(--hover); font:var(--gr-app) var(--tx-4) var(--sans); color:var(--ink2); vertical-align:middle; }
tbody th{ text-align:left; }
tbody tr:hover{ background:var(--panel2); }

/* Badges */
.pill{ padding:var(--e1) var(--e3); border-radius:6px; font:var(--gr-fort) var(--tx-2) var(--sans); text-transform:uppercase; letter-spacing:.4px; }
.resbadge{ padding:var(--e1) var(--e3); border-radius:6px; font:var(--gr-fort) var(--tx-2) var(--mono); }
/* Les quatre paires de camp (pour, contre, neutre, or), écrites une fois pour toutes
   les familles qui les portent ; les formes restent avec chaque famille. Les couleurs
   ont quitté `nm.py`, hors de portée du thème et des media queries. CRIT et HIGH
   partagent --red-d : --red ne tenait que 4,13:1 sur --ag-bg, et le libellé porte
   déjà la distinction. */
.resbadge.res-gagne, .pv.w, .gstate.lead, .g-neuf, .val-for, .msg.ok{ background:var(--for-bg); color:var(--green-d); }
.resbadge.res-perdu, .pill.prio-haut, .pv.l, .gstate.trail, .g-corr, .val-ag,
  .podium.worst .row, .msg.error{ background:var(--ag-bg); color:var(--red-d); }
.resbadge.res-nul, .pill.prio-bas, .pv.t, .gstate.tied{ background:var(--neutral-bg); color:var(--mut); }
.pill.prio-moyen, .g-mieux, .msg.aviso{ background:var(--gold-bg); color:var(--gold); }

/* Buttons */
.btn-primary, .btn-ghost, .btn-danger{ border-radius:9px; font:var(--gr-fort) var(--tx-4) var(--sans); cursor:pointer; }
/* Le fantôme reste hors de inline-flex : ses liens changeraient de boîte. */
.btn-primary, .btn-danger{ padding:var(--e4) var(--e6); border:none;
  display:inline-flex; align-items:center; gap:var(--e2); }
.btn-primary{ background:var(--green-d); color:var(--on-green); box-shadow:0 1px 2px var(--green-glow); }
.btn-ghost{ padding:var(--e4) var(--e5); border:1px solid var(--line2); background:var(--panel); color:var(--mut); }
/* Le rouge des actions irréversibles avertit, là où celui des buts contre constate :
   les deux ne se croisent jamais sur une même page. */
.btn-danger{ background:var(--red-d); color:var(--panel); }
/* Un bouton désactivé ne réagit pas au survol. Ces règles pèsent (0,3,0) : une autre
   couleur de survol devra les égaler. */
.btn-primary:hover:not(:disabled){ background:var(--green-h); }
.btn-ghost:hover:not(:disabled){ background:var(--panel2); }
.btn-danger:hover:not(:disabled){ background:var(--red); }
/* Boutons désactivés par hx-disabled-elt pendant la requête : sans ces règles, rien
   ne les distinguait et on recliquait dans le vide. */
.btn-primary:disabled, .btn-ghost:disabled, .btn-danger:disabled{ opacity:.55; cursor:not-allowed; box-shadow:none; }

/* Forms */
.field{ width:100%; padding:var(--e3) var(--e4); background:var(--panel); border:1px solid var(--line2); border-radius:9px;
  font:var(--gr-app) var(--tx-4) var(--sans); color:var(--ink); appearance:none; }
.field:focus{ outline:none; border-color:var(--green); box-shadow:0 0 0 3px var(--green-glow2); }
.field-lbl{ font:var(--gr-app) var(--tx-2) var(--sans); color:var(--mut); margin-bottom:5px; display:block; }
.selwrap{ position:relative; }
.selwrap::after{ content:"▾"; position:absolute; right:11px; top:50%; transform:translateY(-50%);
  pointer-events:none; color:var(--fleche); font-size:var(--tx-3); }
/* Place réservée au chevron : avec les 12 px de .field, l'option la plus longue
   passait par-dessus le ▾. */
.selwrap > .field{ padding-right:var(--e8); }

/* Champ fichier natif : seul son bouton se stylise (`::file-selector-button`), le
   libellé « Aucun fichier sélectionné » appartient au navigateur. */
.fichier{ font:var(--gr-cour) var(--tx-3) var(--sans); color:var(--mut); max-width:100%; }
.fichier::file-selector-button{ margin-right:var(--e3); padding:var(--e2) var(--e4);
  border:1px solid var(--line2); border-radius:8px; background:var(--panel2);
  color:var(--ink2); font:var(--gr-fort) var(--tx-3) var(--sans); cursor:pointer;
  transition:background var(--t), border-color var(--t); }
.fichier::file-selector-button:hover{ background:var(--hover); border-color:var(--line3); }

/* La zone de dépôt de l'import, sortie du style en ligne : le repli mobile n'a plus
   à la viser par `label.fl.centre`. Ses valeurs (10, 12 px) tombent sur `--e4`, à un
   pixel près. */
.zone-depot{ display:flex; align-items:center; gap:var(--e4); padding:var(--e4);
  border:1px dashed var(--line2); border-radius:9px; background:var(--panel); cursor:pointer; }

/* Segments et pastilles */
.seg{ flex:1; padding:var(--e3) var(--e4); border:1px solid var(--line2); border-radius:9px; background:var(--panel);
  color:var(--mut); font:var(--gr-fort) var(--tx-3) var(--sans); cursor:pointer; text-align:center; }
.seg.on{ border-color:var(--green-d); background:var(--green-d); color:var(--on-green); }
/* Variante compacte des barres de tri (onze boutons sur une rangée). `flex:none`
   annule le `flex:1` de .seg, qui les étirait. */
.seg.seg-mini{ flex:none; padding:var(--e1) var(--e4); font-size:var(--tx-2); }
.chip{ position:relative; display:inline-flex; align-items:center; gap:var(--e2); padding:var(--e2) var(--e4) var(--e2) var(--e3); background:var(--panel);
  border:1px solid var(--line2); border-radius:20px; font:var(--gr-app) var(--tx-3) var(--sans); color:var(--ink2); cursor:pointer; user-select:none; }
.chip.on{ background:var(--accent-soft); border-color:var(--for-line); }
/* Filtre appliqué des journaux GF/GA : graisse et anneau doublent le fond vert, pour
   la vision monochrome. */
.chip[aria-current]{ background:var(--green-dd); border-color:var(--green-dd);
  color:var(--on-green-dd); font-weight:800; box-shadow:0 0 0 1px var(--green-dd); }
.chip .n{ font:var(--gr-fort) var(--tx-2) var(--mono); color:var(--green-d); }
/* Checkbox masquée mais focusable (tabulation + lecteurs d'écran) */
.chip > input[type=checkbox]{ position:absolute; opacity:0; width:1px; height:1px; pointer-events:none; }
.chip:focus-within{ outline:2px solid var(--green-d); outline-offset:2px; }
.chip.fault-chip.on{ background:var(--ag-bg); border-color:var(--ag-line); }
/* :not(.on) et :not([aria-current]) : sans eux, survoler une pastille cochée lui
   retirait son fond vert, comme si elle était décochée. */
.seg:hover:not(.on){ background:var(--panel2); border-color:var(--line3); }
.seg:active{ transform:translateY(1px); }
.chip:hover:not(.on):not([aria-current]){ background:var(--hover); border-color:var(--line3); }
.chip:active{ transform:translateY(1px); }

/* ── Deux motifs de formulaire sortis du style en ligne (game_form, donnees) ─
   Des composants et non des utilitaires : une case encadrée est une pièce du
   produit, pas une aide de mise en page. */
.case-bloc{ display:flex; align-items:center; gap:var(--e4); padding:var(--e4) var(--e5);
  background:var(--panel); border:1px solid var(--line2); border-radius:10px;
  cursor:pointer; }
.case-bloc:hover{ background:var(--hover); border-color:var(--line3); }
.case-bloc input[type=checkbox]{ flex:0 0 auto; accent-color:var(--green-d); }
/* La case du barrage (formulaire Match) : une case-bloc sur toute la rangée. */
.case-bandeau{ grid-column:1 / -1; }
/* Le filet sépare la décision de la saisie : sans lui, le bouton d'enregistrement
   se lisait comme un champ de plus. */
.barre-actions{ display:flex; align-items:center; justify-content:flex-end;
  gap:var(--e4); padding-top:var(--e5); border-top:1px solid var(--line); }

/* Focus clavier visible partout (les .field ont déjà le leur) */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible, .seg:focus-visible{
  outline:2px solid var(--green-d); outline-offset:2px; border-radius:6px; }
.toast{ display:flex;
  align-items:center; gap:var(--e4); padding:var(--e4) var(--e6); background:var(--green-dd); color:var(--on-green-dd); border-radius:11px;
  box-shadow:0 12px 30px rgba(var(--ombre),.3); font:var(--gr-fort) var(--tx-5) var(--sans); animation:pop .2s ease; }
/* `pointer-events:none` sur le conteneur, `auto` sur chaque pilule : fixe et large
   de 560 px, il avalait les clics pendant les 3,2 à 8 s d'affichage. */
.toast-root{ position:fixed; bottom:22px; left:50%; transform:translateX(-50%); z-index:60;
  flex-direction:column; gap:var(--e3); width:min(92vw, 560px); pointer-events:none; }
.toast-root > .toast{ pointer-events:auto; }
/* --red-d s'éclaircit la nuit : l'encre claire du toast y tombait à 2,29:1 ; --panel, celle
   de .btn-danger, y tient 6,76. */
.toast[data-toast="error"]{ background:var(--red-d); color:var(--panel); }
/* Premier cran de l'échelle, au lieu des 2px 3px hors échelle du style en ligne. */
.toast-x{ border:none; background:none; color:inherit; line-height:1; cursor:pointer;
  font:var(--gr-fort) var(--tx-5) var(--mono); padding:var(--e1); outline-color:currentColor; }

/* ---------------------------------------------------------------------------
   Composants « parité gabarit » : la grammaire visuelle du classeur Excel (camps
   Pour/Contre, tables denses, vocabulaires complets). Camps en --green/--red.
--------------------------------------------------------------------------- */

/* Cellules de valeurs teintées par camp (équivalent des fonds pâles du classeur) :
   la forme ici, la teinte avec les Badges. */
.val-for, .val-ag{ padding:2px var(--e3); border-radius:6px;
  font:var(--gr-fort) var(--tx-3) var(--mono); font-variant-numeric:tabular-nums; }
th.th-for{ color:var(--green-d); }
th.th-ag{ color:var(--red-d); }

/* Tuile KPI héro (totaux GF/GA jumeaux) — variante grand format du .kpi */
.kpi-hero{ border:1px solid var(--line); border-radius:13px; padding:var(--e5) var(--e6); background:var(--panel); }
.kpi-hero .v{ font:var(--gr-fort) var(--num-4) var(--mono); letter-spacing:-1.2px; line-height:1.05; }
.kpi-hero .s{ font:var(--gr-app) var(--tx-3) var(--mono); color:var(--mut); margin-top:2px; }
.kpi-hero .l{ margin-top:6px; font:var(--gr-app) var(--tx-3) var(--sans); color:var(--sub); }
.kpi-hero.for{ background:var(--for-bg2); } .kpi-hero.for .v{ color:var(--green-d); }
.kpi-hero.ag{ background:var(--ag-bg2); } .kpi-hero.ag .v{ color:var(--red-d); }

/* Accent de camp en tête de card (volets miroirs, journaux GF/GA) */
.card.acc-for{ border-top:3px solid var(--green); }
.card.acc-ag{ border-top:3px solid var(--red); }

/* Tables denses & en-têtes à 2 niveaux */
.table-dense tbody td, .table-dense tbody th{ padding:var(--e2) var(--e3); font:var(--gr-app) var(--tx-3) var(--sans); }
.table-dense thead th{ padding:0 var(--e3) var(--e3); }
.num{ font-family:var(--mono); font-variant-numeric:tabular-nums; }
th.grp{ letter-spacing:.6px; text-align:center; }
.grp-b{ border-left:1px solid var(--line2); }
/* En-têtes de groupe teintés de la Watchlist. L'encre est --sub et non --mut2, qui
   ne tient que 4,59:1 sur --gold-bg, sous la marge de 0,1 exigée par test_contraste
   (--sub : 8,04 en jour, 9,36 en nuit). */
th.grp-pour{ background:var(--for-bg2); color:var(--sub); }
th.grp-sp{ background:var(--blue-bg); color:var(--sub); }
th.grp-so{ background:var(--gold-bg); color:var(--sub); }
th.grp-ag{ background:var(--ag-bg2); color:var(--sub); }
th.grp-pts{ background:var(--accent-soft); color:var(--sub); }
.tbl-scroll{ overflow-x:auto; -webkit-overflow-scrolling:touch;
  /* Positionné : le <caption> sr-only de la table s'y confine et n'élargit plus la page. */
  position:relative;
  /* Ombres de défilement, en --scroll-cue : --ombre, noir la nuit, disparaissait
     sur un panneau sombre. */
  background:
    linear-gradient(90deg, var(--panel) 30%, transparent) left/40px 100% no-repeat local,
    linear-gradient(270deg, var(--panel) 30%, transparent) right/40px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--scroll-cue), transparent) left/14px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--scroll-cue), transparent) right/14px 100% no-repeat scroll,
    var(--panel); }
/* Pas d'en-tête collant : `overflow-x:auto` rend overflow-y automatique, et un thead
   sticky se réfère alors à .tbl-scroll, qui ne défile jamais verticalement. */
tfoot td{ padding:var(--e3) var(--e3); border-top:2px solid var(--line2); background:var(--panel2);
  font:var(--gr-fort) var(--tx-3) var(--mono); font-variant-numeric:tabular-nums; color:var(--ink2); }
/* La pastille de notes des matchs est un <summary> : les Safari antérieurs à 16.4
   (l'iPad du banc) ignorent `list-style:none` et ajoutaient un triangle au point doré. */
summary::-webkit-details-marker{ display:none; }

/* Grilles de colonnes ; leur repli est dans le bloc Responsive. */
.grid.cols-2{ grid-template-columns:1fr 1fr; }
.grid.cols-2a{ grid-template-columns:1.15fr 1fr; }
.grid.cols-3{ grid-template-columns:repeat(3,1fr); }
.grid.cols-4{ grid-template-columns:repeat(4,1fr); }
.grid.cols-ctx{ grid-template-columns:1.2fr 1fr 1fr; }
.grid.cols-pod{ grid-template-columns:repeat(5,1fr); }
.grid.cols-kpi{ grid-template-columns:repeat(6,1fr); }
.grid.cols-rec{ grid-template-columns:1.3fr repeat(7,1fr); }

/* Grille de formulaire (panneau de saisie, fiche match) */
.form-grid{ display:grid; grid-template-columns:1fr 1fr; gap:var(--e4); }
/* « + Joueur » du panneau de but : numéro, nom, position. */
.form-grid.ajout-joueur{ grid-template-columns:90px minmax(0,1fr) 140px; align-items:end; }

/* Micro-badges sémantiques */
.pv{ display:inline-block; min-width:18px; text-align:center; padding:2px var(--e1);
  border-radius:5px; font:var(--gr-fort) var(--tx-2) var(--mono); }
.gstate{ padding:2px var(--e2); border-radius:6px; font:var(--gr-fort) var(--tx-2) var(--sans);
  text-transform:uppercase; letter-spacing:.4px; white-space:nowrap; }
.flag{ display:inline-block; padding:2px var(--e2); border-radius:5px; font:var(--gr-fort) var(--tx-1) var(--mono);
  background:var(--accent-soft); color:var(--green-d); }
.pchip{ display:inline-block; padding:2px var(--e2); border-radius:6px; font:var(--gr-fort) var(--tx-3) var(--mono);
  background:var(--tag-bg); color:var(--ink2); }
.pchip.f{ color:var(--green-d); } .pchip.d{ color:var(--blue); } .pchip.g{ color:var(--gold); }
.pchip.fault{ background:var(--panel); border:1px solid var(--red); color:var(--red-d); }

/* Chevron déplier/replier des journaux, agrandi (trop discret sur tablette). C'est
   un <button> : styles système annulés. */
.rowtoggle{ display:inline-flex; align-items:center; justify-content:center;
  min-width:26px; min-height:26px; font-size:var(--tx-6); color:var(--mut);
  border:0; background:none; padding:0; cursor:pointer; font-family:inherit; }

/* Podiums Top / À surveiller (watchlist) */
.podium{ display:flex; flex-direction:column; gap:var(--e1); }
.podium .row{ display:flex; justify-content:space-between; align-items:center;
  padding:var(--e1) var(--e3); border-radius:7px; font:var(--gr-app) var(--tx-3) var(--sans); }
.podium .row .v{ font:var(--gr-fort) var(--tx-3) var(--mono); }
.podium.top .row{ background:var(--for-bg); color:var(--green-strong); }
.podium.top .row .v{ color:var(--green-d); }

/* Distributions vocabulaire complet (zéros grisés ; .vlist = version 2 colonnes) */
.vlist{ column-count:2; column-gap:22px; }
.vrow{ break-inside:avoid; display:flex; align-items:center; gap:var(--e3);
  padding:var(--e1) 0; }
/* Les quatre colonnes de la ligne « libellé · jauge · n · % » (voir --lbl). */
.vlbl{ flex:0 0 var(--lbl); font:var(--gr-app) var(--tx-3) var(--sans); color:var(--ink2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vrow .bartrack{ flex:1; }
.vn{ flex:0 0 var(--col-n); text-align:right;
  font:var(--gr-fort) var(--tx-4) var(--mono); font-variant-numeric:tabular-nums; }
.vp{ flex:0 0 var(--col-p); text-align:right;
  font:var(--gr-app) var(--tx-2) var(--mono); color:var(--mut2); }
/* --mut2 : ces lignes à zéro portent une information (« jamais en cycle »). */
.vrow.zero .vlbl, .vrow.zero .vn{ color:var(--mut2); }

/* Ancres (deep-links vers un match ou un but) : dégager la topbar sticky */
[id]{ scroll-margin-top: 74px; }
tbody[id]:target tr:first-child, tr[id]:target{ animation:flash 2.4s ease; }

/* Drill-down : toute ligne/carte agrégée cliquable vers son journal filtré */
a.vrow.drill{ margin:0 -6px; padding:var(--e1) var(--e2); border-radius:6px; }
a.vrow.drill:hover{ background:var(--hover); }
a.vrow.drill:hover .vlbl{ color:var(--green-strong); }
a.subcard.drill:hover{ border-color:var(--line2); background:var(--panel3); }
tbody td a:hover{ text-decoration:underline; text-underline-offset:3px; }

/* Barre duale (deux camps face à face dans la même piste) */
.dualbar{ display:flex; height:7px; border-radius:4px; overflow:hidden; background:var(--track); }
.dualbar .a{ background:var(--green); } .dualbar .b{ background:var(--ag-line2); }
/* `.b` : rouge sourd d'une fiche de match, où la défaite est un fait. `.vif` :
   rouge d'un compteur de buts contre, où elle est le sujet. */
.dualbar .b.vif{ background:var(--red); }
.dualbar .n{ background:var(--line3); }

/* Détail dépliable des journaux + sous-cartes coaching */
.subcard{ background:var(--panel2); border:1px solid var(--line); border-radius:11px; padding:var(--e4) var(--e5); }
.detail-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--e4); }
.detail-grid .dl{ font:var(--gr-app) var(--tx-2) var(--sans); color:var(--mut2); text-transform:uppercase; letter-spacing:.5px; }
.detail-grid .dv{ font:var(--gr-app) var(--tx-4) var(--sans); color:var(--ink2); margin-top:2px; }
.foot-quote{ border-top:1px solid var(--line); margin-top:12px; padding-top:var(--e3);
  font:var(--gr-cour) var(--tx-2) var(--sans); color:var(--mut2); }

/* En-tête de groupe de lignes (journaux regroupés par match) */
tr.grouphead td{ background:var(--panel2); border-top:1px solid var(--line2);
  font:var(--gr-fort) var(--tx-3) var(--sans); color:var(--ink2); padding:var(--e3) var(--e4); }

/* Barre de progression des navigations HTMX (hx-boost) */
#nprog{ position:fixed; top:0; left:0; height:2px; width:0; background:var(--green); z-index:99; opacity:0; }
#nprog.run{ opacity:1; width:70%; transition:width 8s cubic-bezier(.1,.7,.1,1); }
#nprog.done{ opacity:0; width:100%; transition:width .2s ease, opacity .4s ease .1s; }

/* Indicateurs de requête HTMX (boutons de formulaire) */
.htmx-indicator{ opacity:0; transition:opacity .15s ease; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator{ opacity:1; }

/* ── Couche superposée : palette de commandes et dialogue de suppression ─────
   Deux occupants, un seul voile et un seul z-index. */
.pal-overlay, .modale-voile{ position:fixed; inset:0; z-index:70;
  background:rgba(var(--ombre),.35); display:flex; align-items:flex-start;
  justify-content:center; animation:fadeIn .12s ease; }
/* Propre à la palette : elle se pose haut, comme un champ de recherche. */
.pal-overlay{ padding-top:12vh; }
/* Le dialogue de suppression défile dans le voile, pas dans la carte : un `overflow`
   intérieur rognerait l'ombre extérieure de 3 px de `.field:focus`.
   `overscroll-behavior` empêche le défilement de se chaîner à la page, ce que
   `inert` ne fait pas. */
.modale-voile{ padding:var(--e8) var(--e5); overflow-y:auto; overscroll-behavior:contain; }
.modale-voile > .card{ width:100%; box-shadow:var(--ombre-flottante); }
.pal{ width:560px; max-width:92vw; background:var(--panel); border-radius:14px;
  box-shadow:var(--ombre-flottante); overflow:hidden; }
.pal-input{ width:100%; border:none; outline:none; padding:var(--e5) var(--e6); font:var(--gr-app) var(--tx-5) var(--sans);
  color:var(--ink); border-bottom:1px solid var(--line); }
/* Sans anneau natif, le retour du focus dans le champ se marque par une ombre
   intérieure : .pal, en overflow:hidden, rognerait une ombre portée. */
.pal-input:focus{ border-bottom-color:var(--green); box-shadow:inset 0 -2px 0 var(--green-d); }
.pal-list{ max-height:330px; overflow-y:auto; padding:var(--e2); }
.pal-item{ display:flex; justify-content:space-between; align-items:center; gap:var(--e4);
  padding:var(--e4) var(--e4); border-radius:8px; font:var(--gr-app) var(--tx-4) var(--sans); color:var(--ink2); }
.pal-item.on{ background:var(--accent-soft); color:var(--green-strong); }
.pal-kind{ font:var(--gr-app) var(--tx-2) var(--sans); color:var(--mut2); white-space:nowrap; }
.pal-empty{ padding:var(--e6); text-align:center; font:var(--gr-cour) var(--tx-3) var(--sans); color:var(--mut2); }
.pal-foot{ padding:var(--e3) var(--e5); border-top:1px solid var(--line); font:var(--gr-cour) var(--tx-2) var(--sans);
  color:var(--mut2); background:var(--panel2); }

/* Lien d'évitement (navigation clavier / lecteurs d'écran) */
.skip{ position:absolute; left:-9999px; }
.skip:focus{ position:fixed; top:10px; left:10px; z-index:100; background:var(--green-dd);
  color:var(--on-green-dd); padding:var(--e4) var(--e5); border-radius:9px; font:var(--gr-fort) var(--tx-4) var(--sans); }

/* Bouton discret qui ressemble à du texte (copie de clip, etc.) */
.linklike{ border:none; background:none; padding:0; cursor:copy; font:inherit; color:inherit; }

/* Texte réservé aux lecteurs d'écran : les <caption> qui nomment les tableaux, les
   libellés qu'on ne veut pas voir deux fois. Pas de display:none ni de
   visibility:hidden, qui le retireraient aussi de la vocalisation. */
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0; }

/* ── Les rôles de texte ─────────────────────────────────────────────────────
   Une couleur et une police vont ensemble (226 blocs en ligne en faisaient 101
   formes). Propriétés longues, sans le raccourci `font:`. Spécificité (0,1,0) :
   un sélecteur double en fin de fichier surclasserait le bloc @media
   (pointer:coarse). Là où une règle existante gagne (`.kpi .l`, `.eff-chip .pm`,
   `.table-dense tbody td`), un composant ou le style en ligne, jamais un doublement. */
.t-lbl{ font-family:var(--sans); font-weight:var(--gr-app); font-size:var(--tx-3);
  line-height:1.3; color:var(--mut2); }
.t-meta{ font-family:var(--sans); font-weight:var(--gr-cour); font-size:var(--tx-3);
  line-height:1.45; color:var(--mut2); }
.t-hint{ font-family:var(--sans); font-weight:var(--gr-cour); font-size:var(--tx-1);
  line-height:1.4; color:var(--mut2); }
.t-prose{ font-family:var(--sans); font-weight:var(--gr-cour); font-size:var(--tx-4);
  line-height:1.55; color:var(--sub); max-width:var(--mesure-prose); }
.t-cap{ font-family:var(--sans); font-weight:var(--gr-app); font-size:var(--tx-1);
  text-transform:uppercase; letter-spacing:.06em; color:var(--mut2); }
.t-code{ font-family:var(--mono); font-weight:var(--gr-fort); font-size:var(--tx-4);
  color:var(--green-d); white-space:nowrap; }
.t-lien{ font-family:var(--sans); font-weight:var(--gr-app); font-size:var(--tx-3);
  color:var(--blue); }

/* Les valeurs sont nommées par le camp, jamais par la teinte : `.v-pour` et non
   `.v-vert`. */
.v-pour{ color:var(--green-d); }
.v-contre{ color:var(--red-d); }
.v-neutre{ color:var(--mut); }
.v-pour-vif{ color:var(--green); }
.v-contre-vif{ color:var(--red); }
.t-erreur{ font-family:var(--sans); font-weight:var(--gr-app); font-size:var(--tx-3);
  color:var(--red-d); margin-top:var(--e1); }

/* ── Les en-têtes ───────────────────────────────────────────────────────────
   Le titre à gauche, le compte ou l'action à droite. */
.entete-page{ display:flex; align-items:flex-end; justify-content:space-between;
  flex-wrap:wrap; gap:var(--e2) var(--e5); }
.entete-carte{ display:flex; align-items:center; justify-content:space-between;
  gap:var(--e3); flex-wrap:wrap; margin-bottom:var(--pile); }
.entete-carte.base{ align-items:baseline; }
.entete-carte > :first-child{ min-width:0; }
.barre-filtres{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--e2); }
/* Une rangée de boutons : l'action d'abord, l'échappatoire ensuite. */
.barre-boutons{ gap:var(--e3); }
/* Un formulaire ne s'étire pas : à 1728 px, une carte pleine largeur éloigne le
   champ de son libellé. Mesure unique, voir --mesure-formulaire ; la saisie et le
   match s'en écartent au palier de 1400 px, plus bas. */
.mesure-formulaire, .mesure-saisie, .mesure-match{ max-width:var(--mesure-formulaire);
  margin-inline:auto; }

/* ── La saisie sur écran large : deux colonnes de blocs ──────────────────────
   À 1990 px, le panneau occupait 620 px sur 1791 pour 1410 px de haut. Seule la
   disposition s'élargit : la largeur du palier se dérive de la mesure et de 46 px
   de chrome (bordures de `.card`, rembourrage en ligne du `<form>`), et le champ
   vaut 291,5 px des deux côtés (voir SaisieEnDeuxColonnesTest). Palier à 1400 px,
   au-dessus de la plus haute max-width (1100). */
.saisie-colonnes > .saisie-bloc{ min-width:0; }

/* ── Le formulaire de match : une troisième piste ────────────────────────────
   Une seule grille de 23 champs sur onze rangées : une piste de plus retire trois
   rangées. À 1990 px, 640 px de formulaire sur 1791 pour 909 px de haut. Relevé par
   le client : il porte plus de champs que la saisie. */
@media (min-width:1400px){
  .mesure-saisie{ max-width:calc(2 * (var(--mesure-formulaire) - 46px)
                                 + var(--e7) + 46px); }
  /* Trois pistes de la même largeur qu'à deux, `(mesure - chrome - gouttière) / 2`,
     plus deux gouttières et le chrome : le champ ne bouge pas. */
  .mesure-match{ max-width:calc(3 * ((var(--mesure-formulaire) - 46px - var(--e4)) / 2)
                                + 2 * var(--e4) + 46px); }
  .grille-large{ grid-template-columns:repeat(3, 1fr); }
  /* `align-items:start` : sinon la colonne courte s'étire à la hauteur de l'autre. */
  .saisie-colonnes{ display:grid; grid-template-columns:1fr 1fr; gap:0 var(--e7);
    align-items:start; }
}

/* ── Le menu du compte ──────────────────────────────────────────────────────
   Une cible au lieu de six : langue, ambiance et déconnexion, actions rares, ne
   poussent plus les onglets hors de vue sur un écran étroit. */
.menu-compte{ position:relative; }
/* 44 px sans media query : cible tactile minimale, qui ne gêne pas à la souris. */
.menu-declencheur{ display:inline-flex; gap:var(--e2);
  padding:var(--e1) var(--e3) var(--e1) var(--e1); border-radius:999px;
  font:var(--gr-app) var(--tx-3)/1 var(--sans); }
.menu-chevron{ color:var(--mut2); transition:transform var(--t); }
.menu-chevron.ouvert{ transform:rotate(180deg); }

/* Sans media query : le panneau ne dépasse jamais la fenêtre et ses entrées sont
   taillées pour le doigt à toutes les largeurs. */
.menu-panneau{ position:absolute; right:0; top:calc(100% + 7px); z-index:40;
  min-width:248px; max-width:calc(100vw - var(--e7)); padding:var(--e2);
  border:1px solid var(--line2); border-radius:13px; background:var(--panel);
  box-shadow:var(--ombre-menu); }
.menu-tete{ padding:var(--e3) var(--e4) var(--e4); border-bottom:1px solid var(--line);
  margin-bottom:var(--e2); display:flex; align-items:baseline;
  justify-content:space-between; gap:var(--e3); flex-wrap:wrap; }
.menu-tete-nom{ font:var(--gr-fort) var(--tx-4)/1.3 var(--sans); color:var(--ink); }
.menu-panneau form{ margin:0; }
.menu-item{ display:flex; align-items:center; gap:var(--e3); width:100%;
  min-height:44px; padding:var(--e3) var(--e4); border:0; border-radius:9px;
  background:none; color:var(--ink2); text-align:left; cursor:pointer;
  font:var(--gr-app) var(--tx-4)/1.35 var(--sans);
  transition:background var(--t), color var(--t); }
.menu-item svg{ color:var(--mut2); flex:none; }
.menu-item:hover{ background:var(--hover); }
.menu-item:hover svg{ color:var(--green-d); }
/* La page courante, quand elle vit dans le menu : sans marque, on rouvrait l'aide
   en croyant en sortir. */
.menu-item[aria-current]{ background:var(--for-bg2); color:var(--green-strong); }
.menu-item[aria-current] svg{ color:var(--green-d); }
.menu-touche{ margin-left:auto; padding:2px var(--e2); border:1px solid var(--line2);
  border-radius:6px; background:var(--panel2); color:var(--mut2);
  font:var(--gr-fort) var(--tx-1)/1.5 var(--mono); }
.menu-pied{ margin-top:var(--e2); padding-top:var(--e2); border-top:1px solid var(--line); }
.menu-sortie{ color:var(--red-d); }
.menu-sortie svg{ color:var(--red-d); }
.menu-sortie:hover{ background:var(--ag-bg2); }
.menu-sortie:hover svg{ color:var(--red-d); }

/* ── Comptes de l'équipe ────────────────────────────────────────────────── */
.liste-role{ margin:var(--e3) 0 0; padding-left:var(--e6); display:flex;
  flex-direction:column; gap:var(--e2); }
.liste-role li{ font:var(--gr-cour) var(--tx-3)/1.5 var(--sans); color:var(--sub); }
.champ-role{ width:auto; min-width:150px; }
.choix-role{ border:0; padding:0; margin:0; display:grid; gap:var(--e3); }
.choix-role legend{ padding:0; margin-bottom:var(--e3); }
/* Toute la ligne est cliquable : un bouton radio de 13 px se rate au doigt. */
.option-role{ display:flex; align-items:flex-start; gap:var(--e3);
  padding:var(--e4) var(--e5); border:1px solid var(--line2); border-radius:11px;
  cursor:pointer; transition:border-color var(--t), background var(--t); }
.option-role:hover{ background:var(--hover); border-color:var(--line3); }
.option-role:has(input:checked){ border-color:var(--green); background:var(--for-bg2); }
.option-role:has(input:focus-visible){ outline:2px solid var(--green); outline-offset:2px; }
.option-role > span{ display:flex; flex-direction:column; gap:2px; }
.option-titre{ font:var(--gr-fort) var(--tx-4)/1.3 var(--sans); color:var(--ink); }

/* ── Les tables de chiffres ─────────────────────────────────────────────────
   Colonnes numériques réduites à leur contenu, le libellé absorbe le mou : sur
   « Par force » (sept colonnes dans 827 px), chaque colonne recevait ~112 px pour
   afficher « 3 », et les nombres ne se comparaient plus. */
.tbl-chiffres td, .tbl-chiffres th{ width:1%; white-space:nowrap; }
.tbl-chiffres td:first-child, .tbl-chiffres th:first-child{ width:auto; }

/* ── Les graphiques ────────────────────────────────────────────────────────
   `position:relative` est porteur : Chart.js dimensionne son canvas sur le parent
   positionné. `min-width:0` : un graphique en `.grandit` (flex:1) n'élargit pas sa
   rangée. */
.graphe{ position:relative; height:var(--h-graphe); min-width:0; }
.graphe.court{ height:var(--h-graphe-court); }
.graphe.large{ height:var(--h-graphe-large); }
/* `souple` prend la hauteur de sa rangée. Le canvas hors flux n'apporte aucune
   hauteur : le plancher est celui d'un graphique normal (à 110 px, les barres d'une
   saison vide étaient illisibles). */
.graphe.souple{ height:auto; min-height:var(--h-graphe); }
/* Le canvas sort du flux pour briser une boucle de redimensionnement : htmx efface
   le style que Chart.js écrit sur un canvas à `id`, le canvas redevient inline et
   grandit son conteneur, que le ResizeObserver suit (154 px à 1 s, 2742 px à 5 s,
   sans borne). `display:block` posé ici survit à l'effacement. Voir GraphiqueTest. */
.graphe > canvas{ display:block; position:absolute; inset:0; }

/* ── Les journaux : l'identité du but reste visible au défilement latéral ────
   À 375 px, 52 % de la table est visible (680 px dans 351). `:not([colspan])` :
   voir JournalCollantTest. Fond opaque, qui suit le survol : sinon le texte des
   colonnes qui défilent dessous transparaît. */
.tbl-journal td:first-child:not([colspan]),
.tbl-journal tbody th:first-child:not([colspan]),
.tbl-journal thead th:first-child{ position:sticky; left:0; z-index:1;
  background:var(--panel); }
.tbl-journal thead th:first-child{ z-index:2; }
.tbl-journal tbody tr:hover td:first-child:not([colspan]),
.tbl-journal tbody tr:hover th:first-child:not([colspan]){ background:var(--hover); }
/* La bordure droite dit où s'arrête la colonne figée, donc qu'il reste à défiler. */
.tbl-journal td:first-child:not([colspan])::after,
.tbl-journal tbody th:first-child:not([colspan])::after,
.tbl-journal thead th:first-child::after{ content:""; position:absolute; inset-block:0;
  right:0; width:1px; background:var(--line); }

/* ── Le bandeau des nouveautés, et le journal des versions ──────────────────
   Un bandeau dans le flux et non une modale : au banc, rien ne doit s'interposer
   avant de logger un but. La seule modale confirme une suppression (D-13).
   Couleurs du camp « pour ». */
.neuf{ background:var(--for-bg2); border-bottom:1px solid var(--for-line); }
/* `--marge-page` et non `--marge-colonne` : ce conteneur est déjà centré. */
.neuf-in{ max-width:var(--colonne); margin:0 auto;
  padding:var(--e5) var(--marge-page); }
.neuf-tete{ display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--e2) var(--e4);
  margin-bottom:var(--e3); }
.neuf-cap{ font:var(--gr-fort) var(--tx-1) var(--sans); letter-spacing:.1em;
  text-transform:uppercase; color:var(--green-d); }
.neuf-t{ margin:0; font:var(--gr-titre) var(--tx-6) var(--sans); color:var(--ink); }
/* Pas de plafond de prose, à la demande du client : les notes à 590 px sous un titre
   et des boutons à 1079 laissaient un bord droit en escalier. */
.neuf-liste{ margin:0; padding-left:var(--e6); display:flex; flex-direction:column;
  gap:var(--e2); font:var(--gr-cour) var(--tx-4)/1.5 var(--sans); color:var(--sub); }
/* L'étiquette de genre dit si la ligne apporte ou répare ; ses couleurs (`.g-*`) sont
   les paires de camp des Badges. */
.neuf-genre{ display:inline-block; margin-right:var(--e2); padding:1px var(--e2);
  border-radius:5px; font:var(--gr-fort) var(--tx-1) var(--sans); text-transform:uppercase;
  letter-spacing:.04em; vertical-align:baseline; }
.neuf-pied{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--e3);
  margin-top:var(--e5); }
.neuf-pied form{ margin:0; }

/* ══ UTILITAIRES ═══════════════════════════════════════════════════════════
   Liste fermée (14 sélecteurs au plus), aucun nom chiffré, spécificité (0,1,0) :
   voir UtilitairesTest. Largeur, hauteur, fond, bordure, position et grille
   relèvent d'un composant. */
.ta-r{ text-align:right; }
.ta-c{ text-align:center; }
.fl{ display:flex; }
.role-ligne{ display:flex; gap:10px; padding:8px 0; }
.role-ligne + .role-ligne{ border-top:1px solid var(--panel3); }
.centre{ align-items:center; }
.entre{ justify-content:space-between; }
.enroule{ flex-wrap:wrap; }
.grandit{ flex:1; }
.insecable{ white-space:nowrap; }
.gras{ font-weight:var(--gr-fort); }
/* La rampe d'encre, du plus lu au plus effacé, nommée par sa place et non par son
   jeton. Les encres de camp sont `.v-pour` et `.v-contre`. */
.encre-forte{ color:var(--ink2); }
.encre-lue{ color:var(--sub); }
.encre-discrete{ color:var(--mut); }
/* `.encre-effacee` a quitté --mut3 (2,87:1 sur du texte de 12 px). Les deux derniers
   échelons sont proches (5,56 et 5,27 sur --panel) : au-dessus de 4,5:1, le thème
   jour n'a pas la place pour cinq niveaux d'encre. */
.encre-effacee{ color:var(--mut2); }
/* ══ FIN UTILITAIRES ══════════════════════════════════════════════════════ */

h1.pagetitle{ font-family:var(--sans); font-weight:var(--gr-titre); font-size:var(--tx-8);
  line-height:1.15; letter-spacing:-.028em; margin:3px 0 0; }

/* Messages et états vides (la connexion porte les classes de vitrine.css).
   Pas de marge propre : le hibou de .page l'espace déjà. */
.msg{ padding:10px 13px; border-radius:9px; font:var(--gr-app) var(--tx-4) var(--sans); }
.empty{ text-align:center; color:var(--mut2); padding:var(--e8); font:var(--gr-cour) var(--tx-4) var(--sans); }
/* L'action d'un état vide : saisir, ou retirer le filtre en cause. Sans elle, le
   journal des buts contre d'une saison neuve était une impasse. */
.empty .pile-action{ margin-top:var(--e5); }

/* ---------------------------------------------------------------------------
   Responsive. Sous 1100 px, les grilles se replient, la topbar se compacte, les
   tables défilent et les cibles tactiles grossissent. Usage réel : tablette
   derrière le banc, téléphone dans le bus. Empreinte gardée par ResponsiveTest.
--------------------------------------------------------------------------- */
@media (max-width:1100px){
  .grid.cols-kpi{ grid-template-columns:repeat(3,1fr); }
  .grid.cols-rec{ grid-template-columns:repeat(4,1fr); }
  .grid.cols-pod{ grid-template-columns:repeat(auto-fit,minmax(185px,1fr)); }
  .grid.cols-3, .grid.cols-ctx{ grid-template-columns:1fr 1fr; }
  .vlist{ column-count:1; }
  .eff-pile{ grid-template-columns:minmax(0, 1fr); }
}
@media (max-width:900px){
  /* Le retrait se resserre par le jeton, pour les trois conteneurs à la fois. */
  :root{ --marge-page:14px; }
  .topbar{ display:flex; flex-wrap:wrap; justify-content:space-between; gap:10px;
    padding:10px var(--marge-page); }
  /* Le filigrane (1600x900 en `slice`) ne laisse à 375x812 que deux ou trois traits
     en travers des cartes : il se retire sous 900 px. La couverture garde le sien. */
  .rk-fond{ display:none; }
  /* Le ruban (559 px de contenu pour 347 visibles) devient un panneau qui montre ses
     dix destinations. État par classe et non `x-show` : il survit au rétablissement
     d'attributs de htmx et repart fermé à chaque navigation. */
  .nav-declencheur{ display:inline-flex; }
  .nav{ display:none; position:absolute; top:calc(100% + 6px); left:var(--e5);
    right:var(--e5); z-index:40; flex-direction:column; padding:var(--e2);
    border:1px solid var(--line2); border-radius:13px; background:var(--panel);
    box-shadow:var(--ombre-menu); }
  .nav.ouvert{ display:flex; }
  /* Dans le panneau, un onglet est une entrée pleine largeur, taillée pour le doigt. */
  .nav .nav-tab{ min-height:44px; display:flex; align-items:center;
    padding-inline:var(--e4); border-radius:9px; }
  .brand-sub{ display:none; }
  .grid.cols-2, .grid.cols-2a{ grid-template-columns:1fr; }
  [id]{ scroll-margin-top: 110px; }
}
@media (max-width:768px){
  /* Dernier resserrement, toujours par le jeton. */
  :root{ --marge-page:12px; }
  .page{ padding:14px var(--marge-page) 56px; }
  .grid.cols-4{ grid-template-columns:1fr 1fr; }
  .detail-grid{ grid-template-columns:repeat(2,1fr); }
  .toast{ max-width:100%; }
}
@media (max-width:560px){
  /* Le libellé se replie, le « + » et aria-label restent (base.html) : la barre
     passe de trois rangées à deux et rend 47 px de hauteur à chaque page. */
  .topbar .btn-primary .btn-mot{ display:none; }
  /* Replié autour du « + », le bouton ne faisait que 38 px de large : plancher de 44,
     sans plus de rembourrage, la barre étant comptée au pixel. */
  .topbar .btn-primary{ padding-inline:var(--e5); min-width:44px; }
  .grid.cols-kpi, .grid.cols-rec{ grid-template-columns:1fr 1fr; }
  /* Une seule colonne : tables et listes de ces cartes ne se compriment pas, et à
     deux colonnes la page entière défilait de côté. */
  .grid.cols-3, .grid.cols-ctx, .grid.cols-4, .form-grid{ grid-template-columns:1fr; }
  /* Numéro et nom sur la première ligne, la position pleine largeur dessous. */
  .form-grid.ajout-joueur{ grid-template-columns:90px minmax(0,1fr); }
  .form-grid.ajout-joueur > :nth-child(3){ grid-column:1 / -1; }
  .detail-grid{ grid-template-columns:1fr; }
  /* Zone de dépôt : libellé insécable et champ de fichier de 238 px faisaient un
     minimum de 431 px, et `1fr` valant `minmax(auto, 1fr)`, la page Données défilait
     de côté dans 351 px. Empilé, le champ passe de 158 à 287 px et montre le nom du
     fichier. `label.fl.centre` reste : il vise aussi trois libellés du panneau de saisie. */
  label.fl.centre, .zone-depot, .case-bandeau{ flex-wrap:wrap; }
  .fichier{ width:100%; }
  .kpi-hero .v{ font-size:32px; }
  .vlbl{ flex-basis:118px; font-size:12px; }
}
/* ✎ et ✕ du sommaire des matchs : 10 x 17 px à la souris. La zone cliquable s'étend par
   pseudo-élément, sans toucher à la hauteur de ligne, et reste assez étroite pour que les deux
   zones ne se chevauchent pas. Le bloc tactile ci-dessous la redéfinit. */
.action-ligne{ position:relative; }
.action-ligne::after{ content:""; position:absolute; inset-block:-6px; inset-inline:-3px; }
/* Cibles tactiles : uniquement sur écran tactile, la densité desktop reste intacte */
@media (pointer:coarse){
  .nav-tab{ padding:11px 13px; }

  /* `.action-ligne` (✎ et ✕ du sommaire des matchs) : 17 x 10 px mesurés à 375 px,
     sous les 24 x 24 de WCAG 2.5.8. Une zone de 44 px centrée chevaucherait sa
     voisine et le ✕ supprimerait à la place du ✎ : l'élargissement est vertical par
     pseudo-élément, horizontal par rembourrage, sans hauteur de ligne en plus. */
  .action-ligne{ position:relative; padding-inline:var(--e3); }
  .action-ligne::after{ content:""; position:absolute; inset-block:-13px; inset-inline:0; }

  /* Liens de score et d'adversaire des tables denses : 17 x 7 px au plus étroit.
     Élargis verticalement seulement, deux liens de score se touchant (`3–2`). */
  .table-dense tbody a{ position:relative; }
  .table-dense tbody a::after{ content:""; position:absolute; inset-block:-11px; inset-inline:0; }

  /* Les neuf liens de 18 px du tour des pages de l'Aide, dans des cellules de prose. */
  .page-texte td a, .page-texte th a{ display:inline-block; min-height:24px; }
  .chip{ padding:10px 13px; font-size:14px; }
  .seg{ padding:12px; }
  /* À redéclarer : .seg.seg-mini (0,2,0) bat le .seg de ce bloc et annulerait
     l'agrandissement tactile. */
  .seg.seg-mini{ padding:11px 13px; font-size:13px; }
  .field{ padding:12px; min-height:44px; }
  /* Un plancher et pas seulement du rembourrage : sans bordure, `.btn-primary` faisait
     42 px, « Vider la saison » 40, et « Logger un but » replié 24, `.btn-mot` masqué
     et le « + » à `line-height:0` ne laissant que le rembourrage (voir
     PlancherTactileTest). Le centrage sert la forme repliée. */
  .btn-primary, .btn-ghost, .btn-danger{ padding:12px 20px; min-height:44px;
    min-width:44px; justify-content:center; }
  .rowtoggle{ min-width:44px; min-height:44px; font-size:21px; }
  /* 15 px mesurés pour le bouton de création d'un adversaire, 21 px pour la copie de
     clip des journaux : sous les 24 px de WCAG 2.5.8. Le plancher seul suffit. */
  .linklike{ min-height:44px; }
  /* La flèche ↺ du panneau de saisie (un `a.nav-tab`) faisait 38 px de large ; classe
     propre, pour ne pas élargir les onglets de la barre du haut. */
  .action-panneau{ min-width:44px; min-height:44px; }
}

/* Les actions au pied d'une ligne de détail dépliée. */
.actions-detail{ margin-top:var(--pile); }
/* Une carte qui porte une action irréversible se signale par son trait. */
.carte-danger{ border-color:var(--ag-line); }
/* Un bouton seul dans une pile n'a pas à s'étirer sur toute sa largeur. */
.btn-seul{ align-self:flex-start; }
/* Les petites actions collées à la fin d'une cellule : modifier, supprimer. */
.action-ligne{ margin-left:var(--e1); }

/* Gérer les joueurs et les gardiens : une ligne par personne, ses gestes à droite. Sous la barre
   collante, une section ouverte par son ancre garde son titre et son message en vue ; entre
   901 et 1279 px la barre passe sur deux lignes (140 px). */
.gest section{ scroll-margin-top:84px; }
@media (min-width:901px) and (max-width:1279px){ .gest section{ scroll-margin-top:156px; } }
.gest .empty{ padding:var(--e5); }
.gest .barre-filtres .chip{ text-decoration:none; }
.table-gest .col-num{ width:84px; white-space:nowrap; }
.table-gest tbody th.col-nom{ font-weight:var(--gr-fort); }
.table-gest .col-actions{ text-align:right; }
.table-gest .field{ padding:var(--e2) var(--e3); min-width:0; }
.table-gest tr.gest-retire th.col-nom, .table-gest tr.gest-retire td.num{ color:var(--mut2); }
.gest-actions{ display:flex; align-items:center; justify-content:flex-end; gap:var(--e3); flex-wrap:wrap; }
.gest-actions .btn-ghost, .gest-actions .btn-primary{ padding:var(--e2) var(--e4); font-size:var(--tx-3); }
.gest-ajout{ display:grid; grid-template-columns:minmax(0,1fr) 190px auto; gap:var(--e4); align-items:end; }
@media (max-width:700px){
  /* Une rangée repliée par personne : numéro et nom, puis le poste, puis les gestes. */
  .table-gest thead{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0);
    clip-path:inset(50%); }
  .table-gest, .table-gest tbody{ display:block; }
  .table-gest tbody tr{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--e2) var(--e4);
    padding:var(--e4) 0; border-top:1px solid var(--hover); }
  .table-gest tbody td, .table-gest tbody th{ border:0; padding:0; }
  .table-gest .col-num{ width:auto; min-width:44px; }
  .table-gest .col-num .field{ width:96px; }
  .table-gest .col-nom{ flex:1 1 0; min-width:0; overflow-wrap:anywhere; }
  .table-gest .col-poste{ flex:0 0 auto; }
  .table-gest .col-actions{ flex:1 0 100%; text-align:left; }
  .gest-actions{ justify-content:flex-start; }
  .gest-ajout{ grid-template-columns:1fr; }
}
@media (pointer:coarse){
  .gest-actions .btn-ghost, .gest-actions .btn-primary{ padding:12px 16px; min-height:44px; min-width:44px; }
}

/* Mouvement réduit, en un seul bloc et en dernier : aucune règle ne passe après lui. */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{ animation-duration:.01ms !important; transition-duration:.01ms !important; }
  .eff-chip{ transition:none; }
  .eff-chip:hover{ transform:none; }
  .page, .logo-vif .logo, .logo-cercle circle{ animation:none; }
  .logo-cercle circle{ stroke-dashoffset:0; }
}
