/*
 * ═══════════════════════════════════════════════════════════════════════════
 * regard pro — LE SYSTÈME DE DESIGN, APPLIQUÉ
 *
 * Anatomie des composants de DESIGN.md § 7 et § 8, écrite avec les jetons de
 * « jetons.css ». Aucune valeur en dur : tout passe par une variable.
 *
 * ───────────────────────────────────────────────────────────────────────────
 * TOUT EST SOUS PORTÉE « .systeme »
 *
 * Un écran adopte le système en passant `systeme: true` à son gabarit. Les
 * autres gardent l'habillage actuel, au pixel près.
 *
 * C'est ce qui permet de juger un écran pilote sur pièce sans faire bouger les
 * huit autres, et de revenir en arrière en retirant un drapeau — le projet n'a
 * pas de gestion de versions, une bascule générale serait irréversible.
 *
 * Le jour où tous les écrans auront basculé : retirer « .systeme » de ces
 * sélecteurs, supprimer le :root de style.css, et fondre ce fichier dedans.
 * ═══════════════════════════════════════════════════════════════════════════
 */

/* ───────────────────────────────────────────────────────────────────────────
 * Le conteneur
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme {
  max-width: var(--largeur-contenu);
  margin: 0 auto;
  padding: var(--e-6) var(--e-5);
  font-size: var(--t-corps);
  font-weight: var(--g-normal);
  line-height: var(--i-corps);
}

/* ⚠️ LE TITRE DE PAGE EST DÉCLARÉ UNE SEULE FOIS, section « Titres ».
   Cette règle y était écrite une SECONDE fois, mot pour mot. Deux copies
   identiques ne se voient pas — elles se voient le jour où l'une des deux
   change. Retirée le 16/09/2026 en relevant le palier à 30 px : sans ce
   ménage, le titre aurait grossi ou non selon celle qui gagne. */

.systeme h2 {
  font-size: var(--t-section);
  line-height: var(--i-section);
  font-weight: var(--g-demi);
  letter-spacing: -0.01em;
}

/* Le texte d'introduction d'un écran : une seule phrase, largeur de lecture. */
.systeme .chapeau {
  margin-top: var(--e-2);
  max-width: var(--largeur-lecture);
  color: var(--gris);
}

.systeme .titre-ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
  flex-wrap: wrap;
}

.systeme .secondaire {
  font-size: var(--t-secondaire);
  line-height: var(--i-secondaire);
  color: var(--gris);
  font-weight: var(--g-normal);
}

/* ⚠️ « --gris-clair » est SOUS le seuil AA : réservé à ce qui ne porte
   aucune information — un tiret d'absence de valeur, un espace réservé. */
.systeme .absent,
.systeme .manquant { color: var(--gris-clair); }

.systeme .etiquette-jeton {
  font-family: var(--mono);
  font-size: var(--t-micro);
  line-height: var(--i-micro);
  text-transform: uppercase;
  letter-spacing: var(--approche-micro);
  color: var(--gris);
}

/* ───────────────────────────────────────────────────────────────────────────
 * Compteurs — § 4.2, grille auto-ajustable
 *
 * Compter les cartes dans le gabarit pour choisir une classe se trompe dès
 * qu'une carte devient conditionnelle. C'est arrivé, deux fois.
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .compteurs {
  display: grid;
  /* « min(100%, 190px) » : sous 190 px de large, la grille passe a UNE colonne
     au lieu d'ecraser les cartes. Mesure a 375 px : les compteurs tombaient a
     157 px et « 4 960,00 € » se coupait sur trois lignes. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  gap: 14px;
  margin-top: var(--e-5);
}
.systeme .compteurs > * { min-width: 0; }

/*
 * ⚠️⚠️ LA TEINTE D'ACCENT EST RETIRÉE DU COMPTEUR — 10/09/2026.
 *
 * Cette règle mélangeait 6 % d'accent au fond et 18 % à la bordure, et son
 * commentaire disait l'avoir « relevé dans le DOM de Regard AI ». C'était une
 * lecture trop large : dans Regard AI, la teinte `from-primary/5` est posée
 * sur UN SEUL bloc — le briefing du matin, en tête de cockpit. Toutes les
 * autres cartes, y compris les blocs de chiffres, sont le composant `Card` :
 * `rounded-2xl border-border/60 bg-card p-4 shadow-card`. BLANC.
 *
 * Le défaut ne se voyait pas tant que l'accent était un ardoise : 6 % de gris
 * bleu sur du blanc ne se remarque pas. Passé au rouge REGARD, chaque compteur
 * du produit est devenu rose. **Une teinte dérivée d'une couleur variable
 * cache son propre défaut tant que la couleur est discrète.**
 */
.systeme .compteur {
  padding: var(--e-4);                        /* ← Card : p-4                */
  border: var(--trait) solid var(--ligne);    /* ← border-border/60          */
  background: var(--blanc);                   /* ← bg-card                   */
  border-radius: var(--rayon-grand);          /* ← rounded-2xl               */
}

/* ⚠️ LIBELLÉ ET VALEUR SUR LA MÊME LIGNE DE BASE, AUX DEUX BORDS.
   C'est LE trait du motif de Regard AI, et le seul que je n'avais nulle part :
   nos compteurs empilaient la valeur PUIS l'étiquette, l'une sous l'autre.
   Le libellé porte l'accent du club ; la valeur reste en encre. */
.systeme .compteur-tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
}

.systeme .compteur .nombre {
  /* ⚠️ OUTFIT, PAS DM MONO — mesuré dans le DOM de Regard AI.
     Le produit écrivait le MÊME chiffre de deux façons : `<strong>` en DM Mono
     18 px sur six écrans, `.nombre` en Outfit 30 px sur trois autres, parce que
     seul « style.css » stylait `.nombre`. Un seul nom, une seule règle. */
  font-family: var(--sans);
  font-size: var(--t-chiffre);
  font-weight: var(--g-noir);
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--encre);
  font-variant-numeric: tabular-nums;
  /* Un montant ne se coupe jamais entre le nombre et sa devise. */
  white-space: nowrap;
  text-align: right;
}

.systeme .compteur .etiquette {
  /* `min-width: 0` : sans lui, un libellé long (« quatre mille sept cent… »)
     pousse la valeur hors de la carte au lieu de passer à la ligne. */
  min-width: 0;
  font-family: var(--sans);
  font-size: var(--t-petit);
  font-weight: var(--g-gras);
  line-height: var(--i-petit);
  text-transform: uppercase;
  letter-spacing: var(--approche-micro);
  /* ⚠️ Le libellé portait l'accent du club. Dans Regard AI, un libellé de carte
     est `text-muted-foreground` — jamais le primaire : le rouge y désigne une
     ACTION, pas une étiquette. Un écran où dix libellés sont rouges n'a plus
     de rouge disponible pour dire « clique ici ». */
  color: var(--gris);
}

/* La ligne de précision — facultative. Elle dit ce que le chiffre ne dit pas
   tout seul : un reste, un dénominateur, une échéance. */
.systeme .compteur .precision {
  display: block;
  margin-top: 3px;
  font-size: var(--t-micro);
  line-height: var(--i-micro);
  color: var(--gris);
  text-transform: none;
  letter-spacing: normal;
  font-weight: var(--g-normal);
}

/* Un seul cas colore une valeur : de l'argent en retard, ou un reste à livrer. */
.systeme .compteur-erreur { border-color: var(--etat-retard-bord); }
.systeme .compteur-erreur .nombre { color: var(--etat-retard-texte); }

/* Imbriqué dans une carte, le compteur se resserre — Regard AI passe de `p-4`
   à `p-3` dès qu'une carte en contient d'autres. */
.systeme .carte-cockpit .compteurs { margin-top: var(--e-4); gap: var(--e-2); }
.systeme .carte-cockpit .compteur { padding: var(--e-3); }

/* ───────────────────────────────────────────────────────────────────────────
 * Boutons — § 7.1
 * ─────────────────────────────────────────────────────────────────────────── */
/*
 * LE BOUTON — porté de `components/ui/Button.tsx` (Regard AI), 10/09/2026.
 *
 * ⚠️ Regard AI a SIX variantes et TROIS tailles ; regard pro en avait deux et
 * une. Le portage n'ajoute pas ce qui ne sert pas : on porte l'ANATOMIE — les
 * hauteurs, les rayons, les textes, les états — et les variantes qui ont un
 * emploi réel ici. `success` (« Approuver / Terminer ») n'en a pas encore.
 */
.systeme .bouton,
.systeme .bouton-discret,
.systeme .bouton-danger {
  display: inline-flex;              /* ← inline-flex                          */
  align-items: center;
  justify-content: center;
  gap: var(--e-2);                   /* ← gap-2                                */
  min-height: var(--h-bouton-m);     /* ← h-9 (36 px)                          */
  padding: 0 14px;                   /* ← px-3.5                               */
  font-family: inherit;
  font-size: var(--t-corps);         /* ← text-[12.5px]                        */
  font-weight: var(--g-demi);        /* ← font-semibold                        */
  text-decoration: none;
  border: none;
  /*
   * ⚠️⚠️ PASTILLE PLEINE — 17/09/2026, troisième passe sur la maquette.
   *
   * Tous ses boutons sont des pastilles ; les nôtres avaient 12 px. C'est le
   * signal de matière le plus répandu de l'écran — il y a des boutons partout,
   * donc le rayon se lit partout, et c'est lui qui fait qu'une interface
   * « ressemble » à une autre bien avant la disposition.
   *
   * ⚠️ 999 px et non une valeur : un rayon fixe change de sens avec la hauteur
   * (12 px sur 28 px de haut n'est pas le même arrondi que sur 44). La
   * pastille est la seule forme qui reste la même aux trois tailles.
   *
   * ⚠️ `--rayon` (12 px) reste le rayon des CHAMPS et des entrées de nav : un
   * champ de saisie en pastille se lit comme un bouton, et on ne clique pas
   * dans un bouton.
   */
  border-radius: var(--rayon-plein);
  cursor: pointer;                   /* ← cursor-pointer                       */
  user-select: none;                 /* ← select-none                          */
  transition: background-color var(--duree) var(--courbe),
              opacity var(--duree) var(--courbe);
}

/* ─── Les tailles de Regard AI ─────────────────────────────────────────────
   ⚠️ `petit` descend à 28 px. DESIGN.md § 7.1 porte la règle de compensation :
   elle est réservée aux actions SECONDAIRES d'une ligne dense sur écran large.
   Jamais un geste qu'on peut avoir à faire depuis un téléphone. */
.systeme .bouton.petit,
.systeme .bouton-discret.petit {
  min-height: var(--h-bouton-s);     /* ← h-7 (28 px)                          */
  padding: 0 10px;                   /* ← px-2.5                               */
  gap: 6px;                          /* ← gap-1.5                              */
  font-size: var(--t-petit);         /* ← text-[11.5px]                        */
  border-radius: var(--rayon-petit); /* ← rounded-lg                           */
}
.systeme .bouton.grand,
.systeme .bouton-discret.grand {
  min-height: var(--h-bouton-l);     /* ← h-11 (44 px)                         */
  padding: 0 20px;                   /* ← px-5                                 */
  font-size: var(--t-section);       /* ← text-[14px] → notre palier 13        */
}

/* ─── Les variantes ───────────────────────────────────────────────────────
   `primary` = l'accent. `secondary` de Regard AI est `bg-foreground` : l'encre,
   pas une seconde couleur — c'est ce que porte `.bouton-discret.sombre`. */
.systeme .bouton {
  background: var(--accent);         /* ← bg-primary                           */
  color: var(--texte-sur-accent);
  box-shadow: 0 1px 2px rgba(10, 10, 10, 0.05);   /* ← shadow-sm               */
}
.systeme .bouton:hover {
  /* ⚠️ Regard AI éclaircit le FOND (`hover:bg-primary/90`), il ne baisse pas
     l'opacité de tout le bouton : le texte blanc resterait à 90 % sur un fond
     à 90 %, et le contraste baisserait des deux côtés à la fois. */
  background: color-mix(in srgb, var(--accent) 90%, var(--blanc));
}
.systeme .bouton-discret {
  background: var(--blanc);          /* ← outline : bg-white                   */
  color: var(--encre);
  border: var(--trait) solid var(--ligne);
}
.systeme .bouton-discret:hover { background: var(--sourdine); }  /* ← hover:bg-muted */
.systeme .bouton-discret.sombre {
  background: var(--encre);          /* ← secondary : bg-foreground            */
  color: var(--blanc);
  border-color: var(--encre);
}
.systeme .bouton-discret.sombre:hover {
  background: color-mix(in srgb, var(--encre) 90%, var(--blanc));
}
/* ⚠️ LE DANGER N'EST PAS L'ACCENT, et Regard AI fait la même séparation : son
   `danger` est `rose-600`, jamais son primaire. Un « Supprimer » du même rouge
   que « Enregistrer » se clique par erreur. */
.systeme .bouton-danger {
  background: var(--etat-retard-texte);
  color: var(--blanc);
}
.systeme .bouton-danger:hover {
  background: color-mix(in srgb, var(--etat-retard-texte) 88%, #000);
}

/* ⚠️ L'ANNEAU DE FOCUS PASSE À L'ACCENT — ← focus-visible:ring-ring/50.
   Il était en encre parce que l'accent appartenait au club et pouvait être
   illisible ; il ne peut plus l'être. */
.systeme .bouton:focus-visible,
.systeme .bouton-discret:focus-visible,
.systeme .bouton-danger:focus-visible,
.systeme .lien-bouton:focus-visible,
.systeme .pastille:focus-visible {
  outline: var(--trait-fort) solid var(--accent);
  outline-offset: 1px;               /* ← ring-offset-1                        */
}

/* ← disabled:opacity-50 disabled:pointer-events-none */
.systeme .bouton[disabled],
.systeme .bouton-discret[disabled],
.systeme .bouton-danger[disabled] {
  opacity: 0.5;
  pointer-events: none;
}

/* Une action tertiaire, en apparence de lien — mais à 40 px de haut. */
.systeme .lien-bouton {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  padding: 0 var(--e-2);
  background: none;
  border: none;
  font-family: inherit;
  font-size: var(--t-secondaire);
  color: var(--gris);
  text-decoration: underline;
  cursor: pointer;
  border-radius: var(--rayon);
}
.systeme .lien-bouton:hover { color: var(--encre); background: var(--papier); }

.systeme .petit-lien {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  font-size: var(--t-secondaire);
  color: var(--gris);
}
.systeme .petit-lien:hover { color: var(--encre); }

/* ───────────────────────────────────────────────────────────────────────────
 * Pastilles de filtre
 *
 * L'actif est en ENCRE, jamais en accent : un filtre actif en accent devient
 * illisible avec un accent pâle et hurle avec un accent saturé.
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .pastilles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-2);
  margin-top: var(--e-5);
}
/* ⚠️ 28 PX, LA TAILLE `sm` DE REGARD AI. Une pastille de filtre est une action
   SECONDAIRE dans une rangée dense — le cas que DESIGN.md § 7.1 autorise
   expressément pour `sm`. Elles étaient à 40. */
.systeme .pastille {
  display: inline-flex;
  align-items: center;
  gap: 6px;                          /* ← gap-1.5                              */
  min-height: var(--h-bouton-s);     /* ← h-7                                  */
  padding: 0 12px;
  font-size: var(--t-petit);         /* ← text-[11.5px]                        */
  font-weight: var(--g-demi);
  text-decoration: none;
  color: var(--gris);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-plein);
  transition: background var(--duree) var(--courbe), color var(--duree) var(--courbe);
}
.systeme .pastille:hover { color: var(--encre); background: var(--sourdine); }
/*
 * ⚠️ L'ÉTAT ACTIF RESTE EN ENCRE, PAS EN ACCENT — et le motif a changé.
 *
 * Il disait : « sur le fond encre, un accent sombre tombe à 1,41:1 — un
 * ornement que la moitié des clubs ne verrait pas ». Ce motif est mort avec la
 * personnalisation. Le nouveau : un écran d'inventaire porte QUINZE pastilles
 * de filtre. Les allumer en rouge mettrait quinze appels à l'action sur un
 * écran qui n'en a qu'un — le bouton principal. Regard AI réserve son primaire
 * de la même façon : son entrée de navigation active est `bg-muted`, pas
 * `bg-primary`, et seul un rail de 2 px porte le rouge.
 */
.systeme .pastille.active {
  background: var(--encre);
  color: var(--blanc);
  border-color: var(--encre);
}
.systeme .pastille .compte {
  font-family: var(--mono);
  font-size: var(--t-petit);
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}
.systeme .pastille-alerte { border-color: var(--etat-retard-bord); color: var(--etat-retard-texte); }
.systeme .pastille-alerte.active {
  background: var(--etat-retard-texte);
  border-color: var(--etat-retard-texte);
  color: var(--blanc);
}

/* ───────────────────────────────────────────────────────────────────────────
 * Étiquettes d'état — § 7.2, palette FIXE
 *
 * Toujours accompagnées de leur libellé écrit : daltonisme, écran mal réglé,
 * impression en noir et blanc — la même information doit passer.
 * ─────────────────────────────────────────────────────────────────────────── */
/*
 * ⚠️ PORTÉ DE `components/ui/Badge.tsx` — `rounded-full px-2 py-0.5
 * text-[10px] font-bold`, un aplat pastel SANS bordure.
 *
 * ⚠️ DEUX ÉCARTS, TOUS DEUX MOTIVÉS :
 *
 *   · la TAILLE. Regard AI écrit ses badges à 10 px ; le plancher du produit
 *     est 11 (DESIGN.md § 3.2), et son propre `MASTER.md` documente « micro
 *     10–10,5 ». Un état — « impayée », « en retard » — est une information
 *     qu'on doit lire, pas une décoration : c'est exactement ce que le
 *     plancher protège.
 *
 *   · la BORDURE, gardée. Regard AI s'en passe parce que ses badges vivent sur
 *     du blanc. Les nôtres se posent aussi sur `--papier` et dans des cellules
 *     survolées en `--sourdine`, où un aplat très pâle perd son contour. La
 *     bordure est ce qui fait qu'un état reste un objet distinct, et non une
 *     nuance de fond.
 */
.systeme .etat {
  display: inline-flex;
  align-items: center;
  gap: 4px;                          /* ← gap-1                                */
  padding: 2px 8px;                  /* ← px-2 py-0.5                          */
  font-size: var(--t-micro);         /* ← text-[10px] → plancher 11            */
  line-height: var(--i-micro);
  font-weight: var(--g-gras);        /* ← font-bold                            */
  border-radius: var(--rayon-plein); /* ← rounded-full                         */
  border: var(--trait) solid;
  white-space: nowrap;
}

.systeme .etat-fa-brouillon,
.systeme .etat-fa-annulee {
  color: var(--etat-neutre-texte);
  background: var(--etat-neutre-fond);
  border-color: var(--etat-neutre-bord);
}
.systeme .etat-fa-emise {
  color: var(--etat-alerte-texte);
  background: var(--etat-alerte-fond);
  border-color: var(--etat-alerte-bord);
}
.systeme .etat-fa-partiellement_payee {
  color: var(--etat-info-texte);
  background: var(--etat-info-fond);
  border-color: var(--etat-info-bord);
}
.systeme .etat-fa-payee {
  color: var(--etat-succes-texte);
  background: var(--etat-succes-fond);
  border-color: var(--etat-succes-bord);
}

/* Le retard : le SEUL signal de cet écran. */
.systeme .en-retard { color: var(--etat-retard-texte); font-weight: var(--g-demi); }
.systeme .complet { color: var(--etat-succes-texte); font-weight: var(--g-demi); }

/* ───────────────────────────────────────────────────────────────────────────
 * Tableau — § 7.4, lignes de 40 px
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .liste {
  width: 100%;
  border-collapse: collapse;
  margin-top: var(--e-5);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  overflow: hidden;
}
/* ⚠️ L'EN-TÊTE DE REGARD AI : `px-3 py-2 text-left font-semibold`, en police
   de texte et non en monospace. Le produit l'écrivait en DM Mono, capitales
   espacées — un trait qui n'existe nulle part chez lui, et qu'on remarque
   immédiatement en ouvrant les deux logiciels l'un après l'autre. La monospace
   reste où elle sert : les CHIFFRES alignés. */
.systeme .liste th {
  text-align: left;
  padding: 8px 12px;                 /* ← px-3 py-2                            */
  font-family: var(--sans);
  font-size: var(--t-petit);         /* ← text-[11.5px]                        */
  font-weight: var(--g-demi);        /* ← font-semibold                        */
  text-transform: none;
  letter-spacing: normal;
  color: var(--gris);                /* ← text-muted-foreground                */
  border-bottom: var(--trait) solid var(--ligne);
}
.systeme .liste td {
  padding: 10px 12px;                /* ← px-3 py-2.5                          */
  font-size: var(--t-corps);
  border-bottom: var(--trait) solid var(--ligne);
  vertical-align: middle;
}
.systeme .liste tbody tr:last-child td { border-bottom: 0; }
.systeme .liste tbody tr { transition: background var(--duree) var(--courbe); }
.systeme .liste tbody tr:hover { background: var(--sourdine); }  /* ← hover:bg-muted */

.systeme .liste .principal { font-weight: var(--g-demi); }
.systeme .liste .principal a { color: var(--encre); text-decoration: none; }
.systeme .liste .principal a:hover { text-decoration: underline; }

/* ─── LA LIGNE ENTIÈRE EST LA CIBLE ────────────────────────────────────────
 *
 * Mesuré : le lien de référence faisait 18 px de haut, celui du partenaire
 * 19 px — très loin du plancher de 40 px. Un lien en ligne dans une cellule
 * n'est pas cliquable au pouce, et c'est le geste le plus fréquent de cet
 * écran.
 *
 * Le lien principal s'étire sur toute la ligne : la cible devient la ligne
 * elle-même. Motif standard, accessible — le lien reste un vrai lien pour le
 * clavier et le lecteur d'écran, seule sa surface de clic change.
 * ───────────────────────────────────────────────────────────────────────── */
.systeme .liste tbody tr { position: relative; }
.systeme .liste td.principal > a::after {
  content: '';
  position: absolute;
  inset: 0;
}

/* ⚠️ TOUT CE QUI EST CLIQUABLE DANS UNE LIGNE DOIT REPRENDRE LA MAIN
   ------------------------------------------------------------------------
   La surface étirée ci-dessus recouvre la ligne ENTIÈRE, boutons compris. Un
   bouton posé dans une cellule sans reprendre la main est parfaitement visible,
   parfaitement stylé — et parfaitement inerte : le clic part sur la fiche.

   Le défaut est apparu sur « Aujourd'hui » : « Marquer comme faite », le bouton
   le plus cliqué de l'écran d'accueil, ne faisait rien. Aucun test ne pouvait le
   voir, et à l'écran tout paraissait normal. Vérifié par
   `document.elementFromPoint` au centre du bouton.

   La règle vise donc la CELLULE d'action, pas une classe de lien : une nouvelle
   commande y sera couverte sans qu'on ait à y penser. */
.systeme .liste td.actions,
.systeme .liste td.actions form {
  position: relative;
  z-index: 1;
}

/* ⚠️ LA COMPOSITION D'UNE VENTE — migration 060, 10/09/2026.
   Une seconde ligne sous celle du pack, qui déplie ce que le partenaire reçoit.
   Un RETRAIT visuel plutôt qu'une carte : c'est le détail de la ligne du
   dessus, pas un objet à part — « tout n'est pas une carte », DESIGN.md § 7. */
.systeme .liste td.composition {
  background: var(--sourdine);
  padding-left: var(--e-5);
}
.systeme .composition-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-2) 0;
}
.systeme .composition-ligne + .composition-ligne {
  border-top: var(--trait) solid var(--ligne);
}
/* ⚠️ Les formulaires en ligne : sans « display: contents » ils empileraient
   leur propre boîte et casseraient l'alignement de la rangée. */
.systeme .composition-geste { display: flex; align-items: center; gap: var(--e-2); }

/* ⚠️⚠️ LA CELLULE DE SÉLECTION EST DU MÊME BOIS QUE « td.actions ».
   ------------------------------------------------------------------------
   Ajoutée le 10/09/2026 avec la pose collective, elle a repris le défaut que
   le commentaire ci-dessus décrit : la case à cocher était visible, stylée, et
   INERTE — le clic partait sur la fiche du partenaire. Mesuré par
   `document.elementFromPoint` au centre de la case : elle rendait un « A ».

   ⚠️ Le commentaire ci-dessus disait « une nouvelle commande y sera couverte
   sans qu'on ait à y penser ». C'était vrai pour une cellule nommée
   « actions », faux pour toute autre. La règle est donc ÉTENDUE, et un témoin
   la tient désormais pour chaque cellule d'un tableau-liste qui porte une
   commande — c'est le gardien, pas la mémoire, qui couvre la prochaine.

   ⚠️⚠️ ET LA LARGEUR. La colonne des cases prenait 597 px sur 1188 — la moitié
   du tableau — en écrasant le nom du partenaire à 124 px. C'est CE défaut que
   Charles a vu, et il l'a vu avant moi.

   ⚠️⚠️ « width: 1% » NE MARCHE PAS ICI, et c'est mesuré : la largeur calculée
   restait 596,78 px. Un pourcentage se résout contre la largeur du tableau, et
   tant que la somme des largeurs déclarées reste sous 100 %, le navigateur
   REDISTRIBUE le surplus — une colonne à 1 % en reçoit sa part comme les
   autres. Une largeur en PIXELS, elle, tient. Vérifié dans le navigateur en
   forçant les deux valeurs tour à tour : 597 px avec le pourcentage, 71 px
   avec des pixels.

   ⚠️ ET IL FAUT DÉSIGNER QUI ABSORBE le reste, sinon il revient à la première
   colonne. Le nom du partenaire prend 100 %. La portée est bornée par
   « :has(th.choix) » — les dizaines d'autres tableaux-listes du produit ne
   bougent pas d'un pixel.

   44 px : la cible tactile de `DESIGN.md § 7.1`. La case fait 20 px ; c'est sa
   CELLULE qui porte la cible, comme le dit la règle des cases en liste. */
.systeme .liste th.choix,
.systeme .liste td.choix {
  width: 44px;
  white-space: nowrap;
}

/* ⚠️⚠️ 44 PX EST UNE LARGEUR DE COLONNE — SOUS 760 px IL N'Y A PLUS DE COLONNES.
 *
 * 17/09/2026, mesuré sur un écran de 375 px. La liste s'y replie en BLOCS et
 * chaque cellule affiche son intitulé par un « ::before ». La cellule de choix
 * gardait ses 44 px : son intitulé « Choisir » en demande 67, et il était
 * COUPÉ — sur l'écran où l'on lit le plus mal.
 *
 * ⚠️ MÊME FAMILLE, À VINGT-QUATRE HEURES D'INTERVALLE. Le 16/09, « td.principal »
 * portait le même défaut par le même mécanisme : une part de tableau appliquée à
 * un bloc. Je l'avais corrigée là-bas sans regarder ici. *Une règle qui couvre
 * un cas ne couvre pas l'autre du seul fait qu'elle existe* — et le voisin
 * immédiat n'est pas mieux protégé que le lointain.
 *
 * ⚠️ Le repli est posé JUSTE APRÈS la règle qu'il annule, et non dans le bloc
 * « max-width: 760px » de la section Tableau : à spécificité égale, c'est la
 * dernière règle du fichier qui gagne. Écrit plus haut, il serait inerte —
 * mesuré le 16/09 sur exactement cette erreur. */
@media (max-width: 760px) {
  .systeme .liste th.choix,
  .systeme .liste td.choix { width: auto; }
}
/* ⚠️ Pas de règle « :has » ici : « td.principal » porte déjà le 100 % vingt
   lignes plus haut. Une seconde déclaration du même effet diverge le jour où
   l'une des deux change. */
.systeme .liste td.choix {
  position: relative;
  z-index: 1;
}

/* Le bouton d'une ligne est une cible comme une autre : 40 px, jamais moins.
   Mesuré à 20 px avant correction — la moitié du plancher. */
.systeme .liste td.actions button,
.systeme .liste td.actions .lien-bouton {
  min-height: var(--h-cible);
  padding: 0 12px;
  font-size: var(--t-secondaire);
  font-weight: var(--g-demi);
  color: var(--encre);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  /* ⚠️ Pastille, comme tout bouton du produit depuis le 17/09 — un rayon
     laissé ici serait un orphelin : deux boutons voisins, deux arrondis. */
  border-radius: var(--rayon-plein);
  cursor: pointer;
}

.systeme .liste td.actions button:hover { border-color: var(--gris); }

.systeme .liste td.actions button:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

/* Les liens SECONDAIRES d'une ligne doivent rester atteignables par-dessus la
   surface étirée, et atteindre eux aussi les 40 px. */
.systeme .liste td .lien-discret {
  position: relative;
  z-index: 1;
  display: inline-block;
  padding: 11px 0;
  margin: -11px 0;
}
.systeme .liste .secondaire { display: block; }

/* ⚠️ « display: block » vise le rappel placé SOUS un nom. Sur un <td>, il sort
   la cellule de la mise en table : sa bordure basse flotte au milieu de la
   ligne. Défaut déjà rencontré sur la liste des packs — il revient dès qu'on
   réécrit la règle ailleurs. */
.systeme .liste td.secondaire { display: table-cell; }
.systeme .liste .a-droite { text-align: right; }
.systeme .liste .montant {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* ⚠️ « border: 0 » : la feuille historique donne une bordure basse a ce lien
   pour le souligner. Combinee a la marge negative qui lui donne ses 40 px,
   elle dessinait un trait parasite au milieu de la carte en petit ecran. */
.systeme .lien-discret { color: var(--gris); text-decoration: none; border: 0; }
.systeme .lien-discret:hover { color: var(--encre); text-decoration: underline; }

.systeme .denombrement {
  margin-top: var(--e-3);
  font-family: var(--mono);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: var(--approche-micro);
  color: var(--gris);
}

/* Sous 760 px : l'en-tête disparaît, chaque cellule porte son intitulé.
   Sans lui, un « 1 » isolé ne veut plus rien dire — défaut constaté. */
@media (max-width: 760px) {
  .systeme .liste thead { display: none; }
  .systeme .liste tr { display: block; border-bottom: var(--trait) solid var(--ligne); }
  .systeme .liste tr:last-child { border-bottom: 0; }
  .systeme .liste td { display: block; border: 0; padding: var(--e-1) var(--e-4); }
  .systeme .liste td:first-child { padding-top: var(--e-3); }
  .systeme .liste td:last-child { padding-bottom: var(--e-3); text-align: left; }
  .systeme .liste td[data-intitule]::before {
    content: attr(data-intitule);
    display: block;
    margin-bottom: 1px;
    font-family: var(--mono);
    /* ⚠️ Écrit à 10 px, SOUS le plancher de 11 — et sur téléphone, là où on lit
       le plus mal. C'est le rappel d'intitulé de colonne : le retirer rendrait
       la cellule incompréhensible, le rendre illisible revient au même. */
    font-size: var(--t-micro);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--gris);
  }
}

/* ───────────────────────────────────────────────────────────────────────────
 * Filtre par partenaire
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .filtre-ligne {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  flex-wrap: wrap;
  margin-top: var(--e-4);
}
.systeme .filtre-ligne .etiquette-champ {
  font-family: var(--mono);
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: var(--approche-micro);
  color: var(--gris);
}
.systeme .filtre-ligne select {
  min-height: var(--h-champ);
  padding: 0 14px;
  font-family: inherit;
  font-size: var(--t-corps);
  color: var(--encre);
  background: var(--champ);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
}
.systeme .filtre-ligne select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}

/* ───────────────────────────────────────────────────────────────────────────
 * Messages et état vide — § 7.7 et § 7.8
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .confirmation {
  margin-bottom: var(--e-5);
  padding: 14px 18px;
  border-radius: var(--rayon);
  border-left: 3px solid var(--etat-succes-texte);
  background: var(--etat-succes-fond);
  color: var(--etat-succes-texte);
}

/*
 * L'ÉTAT VIDE — porté de `components/ui/EmptyState.tsx` (Regard AI).
 *
 * Sa forme : colonne centrée, icône en gris très pâle, titre 13 px, explication
 * 11,5 px sur une largeur courte, action en dessous. `gap-2 px-6 py-10`.
 *
 * ⚠️ L'ICÔNE EST FACULTATIVE ET DÉCORATIVE. Elle porte `aria-hidden` : ce qui
 * dit quoi faire, c'est la PHRASE. Une icône qui remplacerait le texte
 * laisserait un écran vide entièrement muet — exactement le moment où l'on a
 * le plus besoin qu'on nous parle. DESIGN.md § 7.8 l'exige déjà : « les états
 * vides disent QUOI FAIRE ».
 */
.systeme .vide {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e-2);                   /* ← gap-2                                */
  margin-top: var(--e-5);
  padding: 40px 24px;                /* ← px-6 py-10                           */
  text-align: center;
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand); /* ← rounded-2xl                          */
  font-size: var(--t-petit);         /* ← text-[11.5px]                        */
  line-height: 1.6;                  /* ← leading-relaxed                      */
  color: var(--gris);
}
/* ⚠️ Une explication qui traverse tout l'écran ne se lit pas : Regard AI la
   borne à `max-w-xs`. La nôtre suit la mesure de lecture du produit. */
.systeme .vide > * { max-width: 34ch; }
.systeme .vide .vide-icone {
  color: var(--ligne);               /* ← text-muted-foreground/30             */
  margin-bottom: var(--e-1);
}
.systeme .vide .vide-titre {
  font-size: var(--t-section);       /* ← text-[13px]                          */
  font-weight: var(--g-demi);        /* ← font-semibold                        */
  color: var(--encre);
  margin: 0;
}
.systeme .vide a { color: var(--encre); }

/* ───────────────────────────────────────────────────────────────────────────
 * Écran « Aujourd'hui »
 *
 * Les alertes sont des CARTES, pas des bandeaux empilés : un bandeau pleine
 * largeur se lit comme un message système qu'on chasse, une carte se lit comme
 * un dossier à traiter. Chacune porte son libellé écrit — jamais la couleur
 * seule (daltonisme, écran mal réglé, impression en noir et blanc).
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .alertes {
  display: grid;
  /* Même garde que les compteurs : sous 375 px, une grille en fractions pures
     écrasait les cartes au lieu de les empiler. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--e-4);
  margin-top: var(--e-5);
}

/* ───────────────────────────────────────────────────────────────────────────
 * ⚠️⚠️ LE BANDEAU PORTE CE QUI CLOCHE — 16/09/2026, demande de Charles sur une
 * maquette. DESIGN.md, § « L'écran d'entrée », porte le motif.
 *
 * Avant, il occupait le premier tiers de l'écran pour dire « Aujourd'hui — ce
 * qu'il y a à faire » : le nom de la page, et rien de plus. Il fallait passer
 * dessous pour apprendre quoi que ce soit. Un grand aplat qui ne porte aucune
 * information est de la place prise à ce qu'on vient chercher.
 *
 * Le titre est sorti au-dessus, à 30 px ; les tuiles d'alerte sont entrées.
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .entete-jour {
  /* Le rembourrage du bandeau vient de « .bandeau-couleurs », dans style.css.
     Ici on ne règle que ce qui touche à son NOUVEAU contenu. */
  margin-top: var(--e-5);
}

/*
 * ⚠️⚠️ L'ÉTIQUETTE DU BANDEAU — 17/09/2026, troisième passe sur la maquette.
 *
 * La maquette ouvre son bandeau par une PASTILLE : un petit bloc arrondi, plus
 * clair que le fond, qui dit d'où vient ce qu'on lit (« Scan LinkedIn 24h/24 »).
 * C'est elle qui fait lire le bandeau comme un bloc COMPOSÉ plutôt que comme un
 * rectangle de couleur, et nous n'avions rien à cet endroit.
 *
 * ⚠️ ELLE PORTE LA DATE, ET CE N'EST PAS DE L'ORNEMENT. L'écran s'appelle
 * « Aujourd'hui » et ne disait NULLE PART quel jour on est — un bénévole qui
 * l'ouvre le lundi et le jeudi voit deux fois le même mot. La pastille de la
 * maquette est décorative ; la nôtre répond à la question que le titre pose.
 *
 * ⚠️⚠️ LA MAQUETTE ÉCLAIRCIT SA PASTILLE ; NOUS L'ASSOMBRISSONS, ET C'EST UNE
 * MESURE QUI L'IMPOSE. Sa pastille est un voile BLANC sur un bandeau bleu.
 * Recopié tel quel sur notre rouge, du texte blanc dessus rend :
 *
 *   voile blanc 12 %  →  4,39:1      voile NOIR 12 %  →  5,86:1
 *   voile blanc 16 %  →  4,23:1      voile NOIR 16 %  →  6,30:1
 *   voile blanc 18 %  →  4,16:1      voile NOIR 18 %  →  6,56:1
 *
 * (pire des deux extrémités du dégradé, `#E8001D` et `#A80015`)
 *
 * Les trois valeurs blanches sont SOUS le seuil AA de 4,5:1. Un voile blanc
 * rapproche le fond du blanc, donc rapproche le fond du TEXTE : il ne peut
 * qu'abaisser le contraste. Le voile sombre fait l'inverse — 6,56:1 au pire,
 * soit MIEUX que l'accent nu (4,72:1). La pastille devient le texte le plus
 * lisible du bandeau.
 *
 * ⚠️ C'est le genre d'emprunt qui se recopie sans y penser : on prend une
 * maquette bleue et on garde ses alphas. La teinte change tout, et ici elle
 * aurait coûté deux crans de contraste sur le seul élément du bandeau qui dit
 * la date.
 */
.systeme .entete-jour-date {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  margin: 0 0 var(--e-4);
  padding: 7px 14px;
  border-radius: var(--rayon-plein);
  background: rgba(0, 0, 0, 0.18);
  font-size: var(--t-petit);
  font-weight: var(--g-demi);
  letter-spacing: 0.02em;
  color: var(--texte-sur-accent);
}
.systeme .entete-jour-date svg {
  width: 14px; height: 14px;
  flex: none;
  opacity: 0.9;
}

/* La phrase qui compte — c'est elle que le bandeau existe pour porter. */
.systeme .entete-jour-compte {
  margin: 0;
  /*
   * ⚠️⚠️ 28 px — RELEVÉ DE 17 LE 17/09/2026, TROISIÈME PASSE.
   *
   * À 17 px cette phrase était la TROISIÈME chose qu'on lisait, après le titre
   * et le chapeau, alors que c'est la seule que le bandeau existe pour porter.
   * Dans la maquette elle fait 28 px et domine son bloc.
   *
   * ⚠️ ELLE RESTE SOUS LE TITRE DE PAGE (44 px), et c'est la borne : deux
   * textes de même taille sur un écran ne se hiérarchisent plus. C'était le
   * défaut du 09/09 — cinq cartes qui criaient ensemble.
   */
  font-size: var(--t-bandeau);
  line-height: var(--i-bandeau);
  font-weight: var(--g-noir);
  letter-spacing: -0.015em;
  max-width: 34ch;
  color: var(--texte-sur-bandeau, var(--encre));
}
/* ⚠️ Le NOMBRE sort de l'échelle du texte, comme tout chiffre du produit :
   DM Mono, chasse tabulaire. C'est la règle des jetons, pas un effet. */
.systeme .entete-jour-compte strong {
  font-family: var(--mono);
  font-size: 1em;
  font-variant-numeric: tabular-nums;
  font-weight: var(--g-noir);
}

.systeme .entete-jour-chapeau {
  margin: var(--e-3) 0 0;
  max-width: 52ch;
  font-size: var(--t-corps);
  line-height: var(--i-corps);
  color: var(--texte-sur-bandeau, var(--encre));
  opacity: 0.78;
}

/*
 * ⚠️ LES TUILES DANS LE BANDEAU RESTENT DES CARTES BLANCHES, et c'est ce qui
 * les rend lisibles : le bandeau est un voile teinté, pas un fond sur lequel
 * on aurait mesuré un contraste de texte. Poser les libellés directement
 * dessus aurait demandé de remesurer les cinq couleurs de gravité sur un fond
 * qui n'est plus le papier. Une carte blanche ramène chaque tuile au fond pour
 * lequel les états ONT été mesurés — « le plus faible des quinze contrastes
 * vaut 6,45:1 » (jetons.css).
 */
.systeme .entete-jour .alertes {
  margin-top: var(--e-4);
  /* Plus serré que sur le papier : à l'intérieur d'un bloc, l'écart entre deux
     tuiles n'a pas à valoir l'écart entre deux sections. */
  gap: var(--e-3);
}
.systeme .entete-jour .alerte-carte {
  /*
   * ⚠️ PAS DE FILET DE GRAVITÉ ICI — il redeviendrait un second rouge dans le
   * bloc, et la borne n° 2 du § 2.4 l'interdit : aucun contrôle d'accent dans
   * le bandeau.
   *
   * ⚠️⚠️ L'OMBRE, ELLE, REVIENT — 17/09/2026. « La tuile blanche se détache
   * seule » était vrai et insuffisant : elle se détachait PLATE. Dans la
   * maquette les tuiles sont POSÉES sur le bandeau, avec une ombre portée
   * franche, et c'est ce relief qui distingue un bloc composé d'un aplat
   * découpé. L'ombre est plus dense qu'ailleurs (0,16 contre 0,07) parce
   * qu'elle tombe sur une couleur saturée, pas sur du papier : la même valeur
   * y serait invisible.
   */
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);
  border-left-width: var(--trait);
  border-left-color: var(--ligne);
  gap: var(--e-2);
  /* La maquette donne de l'air à ses tuiles : le chiffre a besoin de respirer
     au-dessus et au-dessous pour se lire de loin. */
  padding: var(--e-5);
}

/* ⚠️ LE CHIFFRE — 17/09/2026, DESIGN.md § 2.4. Il se lit de loin ; la phrase
   dessous dit de quoi il s'agit. DM Mono, chasse tabulaire : deux tuiles
   voisines alignent leurs chiffres. */
.systeme .alerte-nombre {
  font-family: var(--mono);
  font-size: var(--t-compteur);
  line-height: 1;
  font-weight: var(--g-noir);
  font-variant-numeric: tabular-nums;
  color: var(--encre);
  margin-left: auto;
}
.systeme .entete-jour .alerte-tete { align-items: center; }
.systeme .entete-jour .alerte-titre { margin: 0; }

/* Le texte du bandeau est celui qui a été MESURÉ contre l'accent, pas l'encre. */
.systeme .entete-jour-compte,
.systeme .entete-jour-chapeau { color: var(--texte-sur-accent); }
.systeme .entete-jour-chapeau { opacity: 0.88; }

/*
 * ⚠️⚠️ REPRISES EN DISCRÉTION LE 10/09/2026 — DEMANDE DE CHARLES.
 *
 * Elles avaient été GROSSIES le 09/09, à sa demande aussi : titre 24 px,
 * bouton 44 px, couleur de gravité sur le texte. Cinq cartes de ce poids sur
 * un écran qui n'a qu'UNE action principale : chacune réclamait le regard, et
 * plus rien ne ressortait. C'est le défaut classique d'une page où tout est
 * important.
 *
 * Ce qui porte la gravité maintenant : le FILET de gauche et le MOTIF. Le
 * titre revient à l'encre et à l'échelle du produit. Un signal se lit d'autant
 * mieux qu'il est seul de son espèce.
 */
.systeme .alerte-carte {
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
  padding: var(--e-4);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  /* Le filet de gauche porte la gravité. 3 px : il se voit sans peser, la
     couleur du motif le redit juste à côté. */
  border-left: 3px solid var(--ligne);
  border-radius: var(--rayon-grand);
  box-shadow: var(--ombre-carte);
}

/* Le motif et le titre sur une seule ligne de base. */
.systeme .alerte-tete {
  display: flex;
  align-items: flex-start;
  gap: var(--e-3);
  margin: 0;
}

/* ⚠️ LE MOTIF DANS UNE PASTILLE TEINTÉE, pas nu : posé seul sur du blanc, un
   trait de 15 px se perd. La pastille lui donne la surface minimale pour se
   lire, et c'est elle qui porte la couleur de gravité. */
.systeme .alerte-motif {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: var(--rayon-petit);
  background: var(--sourdine);
  color: var(--gris);
}

.systeme .alerte-bloquant    { border-left-color: var(--etat-retard-texte); }
.systeme .alerte-attention   { border-left-color: var(--etat-alerte-texte); }
.systeme .alerte-information { border-left-color: var(--etat-info-texte); }

/* La pastille du motif reprend le triplet de l'état — fond pâle, texte foncé.
   Ce sont les mêmes couleurs que partout ailleurs dans le produit (§ 2.3) :
   un retard se lit du même rouge sur une vignette et sur une étiquette. */
.systeme .alerte-bloquant  .alerte-motif {
  background: var(--etat-retard-fond); color: var(--etat-retard-texte);
}
.systeme .alerte-attention .alerte-motif {
  background: var(--etat-alerte-fond); color: var(--etat-alerte-texte);
}
.systeme .alerte-information .alerte-motif {
  background: var(--etat-info-fond); color: var(--etat-info-texte);
}

/* ⚠️ LE TITRE REVIENT DANS L'ÉCHELLE — `--t-alerte` (24 px) est retiré.
   C'était la seule exception typographique du produit, née le 09/09 pour
   grossir ces vignettes ; elle disparaît avec la raison qui l'avait créée.
   Une exception qu'on garde après son motif devient une dette. */
.systeme .alerte-titre {
  font-size: var(--t-chiffre);
  font-weight: var(--g-demi);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--encre);
}

.systeme .alerte-detail {
  font-size: var(--t-secondaire);
  line-height: var(--i-secondaire);
  color: var(--gris);
  /* Pousse le lien en bas : sans cela, des cartes de hauteurs différentes
     alignent leurs liens n'importe où et l'œil ne trouve plus l'action. */
  flex: 1;
}

/* ⚠️ L'ACTION D'UNE ALERTE EST UN BOUTON, PLUS UN LIEN SOULIGNÉ.
   Demande de Charles, 09/09/2026 : « agrandis les boutons ». C'est la variante
   « contour » de DESIGN.md § 7.1 — fond blanc, trait de 1 px, encre — celle
   des « actions courantes ». Pas « principal » : il n'y en a qu'un par écran,
   et une alerte peut en porter cinq.
   Hauteur 44 px et marges 0 20px : la taille MOYENNE du § 7.1, pas une
   quatrième inventée pour l'occasion. */
/* ⚠️ 44 → 36 PX. C'est la taille MOYENNE de Regard AI (`h-9`), pas une
   quatrième inventée : voir DESIGN.md § 7.1. Elle avait été portée à 44 le
   09/09 avec les titres, pour la même demande, et redescend avec eux.
   ⚠️ PAS 28 : une alerte du matin se traite aussi depuis un téléphone, et
   `sm` est réservée aux actions secondaires d'une ligne dense sur grand
   écran. C'est la règle de compensation du § 7.1, appliquée. */
.systeme .alerte-lien {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  min-height: var(--h-bouton-m);
  padding: 0 14px;
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
  font-size: var(--t-corps);
  font-weight: var(--g-demi);
  color: var(--encre);
  text-decoration: none;
  transition: background var(--duree) var(--courbe);
}

.systeme .alerte-lien:hover { background: var(--sourdine); }

/* ⚠️ « .rien-a-signaler » A ÉTÉ RETIRÉE — 16/09/2026. Elle habillait le
   paragraphe vert « rien ne cloche » qui remplaçait la rangée d'alertes quand
   il n'y avait rien à signaler. Depuis que le bandeau porte les alertes, c'est
   LUI qui dit « Rien n'attend » : un écran dont le haut disparaît selon la
   journée se lit comme un écran cassé.

   Retirer une fonctionnalité, c'est trois gestes — le gabarit, la route, et le
   style qui la dessinait. Le troisième s'oublie parce qu'il ne casse rien. */

/* Une échéance qui tombe le jour même n'est pas un retard : elle ne prend pas
   la couleur du retard, sinon tout paraît en retard tout le temps. */
.systeme .echeance-du-jour {
  font-weight: var(--g-demi);
  color: var(--encre);
}

.systeme .note-basse {
  margin-top: var(--e-3);
  font-size: var(--t-secondaire);
  color: var(--gris);
  max-width: var(--largeur-lecture);
}

/* ─── Jauge d'objectif ───────────────────────────────────────────────────────
 * L'un des quatre endroits où l'accent du club a le droit d'être un aplat.
 * `--accent-lisible` et non `--accent` : sur le fond clair de la piste, un
 * accent pâle disparaîtrait — mesure faite sur la barre de navigation.
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .jauge {
  margin-top: var(--e-4);
  height: 10px;
  background: var(--champ);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-plein);
  overflow: hidden;
}

.systeme .jauge-remplie {
  height: 100%;
  background: var(--accent-lisible);
  border-radius: var(--rayon-plein);
}

/* ─── Voyant de conformité, en résumé ─────────────────────────────────────── */

.systeme .conformite-resume {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-3);
  margin-top: var(--e-4);
  padding: var(--e-3) var(--e-4);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  font-size: var(--t-corps);
}

.systeme .conformite-resume .conformite-pastille {
  width: 10px;
  height: 10px;
  border-radius: var(--rayon-plein);
  flex: none;
}

.systeme .conformite-ok .conformite-pastille        { background: var(--etat-succes-texte); }
.systeme .conformite-attention .conformite-pastille { background: var(--etat-alerte-texte); }

.systeme .conformite-resume a {
  /* Repoussé à droite, et à 40 px de haut comme toute cible. */
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  font-weight: var(--g-demi);
  color: var(--encre);
  text-underline-offset: 3px;
}

.systeme .deconnexion {
  margin-top: var(--e-6);
  padding-top: var(--e-4);
  border-top: var(--trait) solid var(--ligne);
  /*
   * ⚠️⚠️ `align-items` MANQUAIT, ET LE COMMENTAIRE CI-DESSOUS DÉCRIVAIT UNE
   * PROTECTION À MOITIÉ ABSENTE — constaté le 17/09/2026, en le regardant.
   *
   * Il annonce « sans cette règle il s'affichait large et centré ». Elle
   * empêchait le CENTRÉ, jamais le LARGE : `.formulaire` est un `flex` en
   * colonne sans `align-items`, donc le bouton s'étirait sur les 384 px de la
   * colonne — une grande barre bordée, plus voyante que les alertes, ce que la
   * règle dit exister pour empêcher.
   *
   * ⚠️ C'est la même famille que l'en-tête de `cookie-dev.ts`, qui affirmait
   * une protection inexistante : un commentaire qui décrit une garantie absente
   * est pire que pas de commentaire — il éteint la question chez le lecteur
   * suivant. Il l'a éteinte chez moi jusqu'à ce que je voie la page.
   */
  align-items: flex-start;
}

/* Se déconnecter n'est pas une action de l'écran d'accueil : le bouton reste
   atteignable à 40 px, mais il ne pèse pas plus que le reste. */
.systeme .deconnexion button {
  min-height: var(--h-cible);
  padding: 0 14px;
  font-size: var(--t-secondaire);
  color: var(--gris);
  background: transparent;
  border: var(--trait) solid var(--ligne);
  /* Pastille, comme tout bouton du produit depuis le 17/09 — un rayon laissé
     ici serait un orphelin de plus. */
  border-radius: var(--rayon-plein);
  cursor: pointer;
}

.systeme .deconnexion button:hover { color: var(--encre); border-color: var(--gris); }

.systeme .deconnexion button:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

/* ───────────────────────────────────────────────────────────────────────────
 * Les CINQ autres familles d'états — même palette fixe que les factures
 *
 * Chaque famille dit la même chose avec ses propres mots : un contrat « signé »
 * et une contrepartie « livrée » et une facture « payée » sont trois succès. Ils
 * doivent donc porter la même couleur, sinon on réapprend l'outil à chaque
 * écran.
 *
 * ⚠️ Les couleurs d'avant étaient écrites en dur, hors palette. Mesure sur la
 * liste des partenaires : « Actif » tombait à 4,58:1 — le minimum strict pour du
 * texte de 11 px. La palette fixe le porte à 6,52:1.
 *
 * Le NEUTRE sert à ce qui n'est pas commencé ou plus actif ; l'INFO à ce qui est
 * en cours ; le SUCCÈS à ce qui est tenu ; l'ALERTE à ce qui attend une suite ;
 * le RETARD à ce qui a échoué ou été annulé.
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .etat-prospect,
.systeme .etat-inactif,
.systeme .etat-cp-a_faire,
.systeme .etat-cp-annulee,
.systeme .etat-contrat-brouillon,
.systeme .etat-ec-a_venir {
  color: var(--etat-neutre-texte);
  background: var(--etat-neutre-fond);
  border-color: var(--etat-neutre-bord);
}

.systeme .etat-en_negociation,
.systeme .etat-cp-planifiee,
.systeme .etat-contrat-envoye,
.systeme .etat-contrat-actif {
  color: var(--etat-info-texte);
  background: var(--etat-info-fond);
  border-color: var(--etat-info-bord);
}

.systeme .etat-actif,
.systeme .etat-cp-livree,
.systeme .etat-cp-prouvee,
.systeme .etat-preuve,
.systeme .etat-contrat-signe,
.systeme .etat-contrat-termine,
.systeme .etat-ec-payee {
  color: var(--etat-succes-texte);
  background: var(--etat-succes-fond);
  border-color: var(--etat-succes-bord);
}

.systeme .etat-contacte {
  color: var(--etat-alerte-texte);
  background: var(--etat-alerte-fond);
  border-color: var(--etat-alerte-bord);
}

.systeme .etat-perdu,
.systeme .etat-contrat-annule,
.systeme .etat-ec-en_retard {
  color: var(--etat-retard-texte);
  background: var(--etat-retard-fond);
  border-color: var(--etat-retard-bord);
}

/* ⚠️ « Inactif » n'avait AUCUN fond : seule étiquette sur six à flotter sans
   pastille. Le sélecteur générique ci-dessus ne suffit pas — il faut que la
   règle de forme s'applique aussi, sinon la couleur arrive sur rien. */
.systeme [class*='etat-'] {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  font-size: var(--t-petit);
  font-weight: var(--g-demi);
  line-height: var(--i-petit);
  border-radius: var(--rayon-plein);
  border: var(--trait) solid;
  white-space: nowrap;
}

/* ─── Tri des colonnes ───────────────────────────────────────────────────────
 * ⚠️ Mesuré à 15 px de haut : un en-tête de colonne cliquable est une cible
 * comme une autre. Le remplissage est repris en marge négative pour ne pas
 * gonfler l'en-tête.
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .liste th a {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  margin: -12px 0;
  color: inherit;
  text-decoration: none;
}

.systeme .liste th a:hover { color: var(--encre); }

/* L'ACTIF EN ENCRE, jamais en accent — la règle vaut aussi pour le tri. */
.systeme .liste th a.tri-actif {
  color: var(--encre);
  font-weight: var(--g-gras);
}

.systeme .liste th a:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

/* ───────────────────────────────────────────────────────────────────────────
 * Fiches — blocs, fil d'Ariane, commandes en ligne
 *
 * ⚠️ MESURE SUR LA FICHE PARTENAIRE : le fil d'Ariane faisait 17 px, le bouton
 * « Marquer comme faite » 37 px, et l'adresse e-mail d'un contact 22 px. Trois
 * cibles sous le plancher, sur l'écran qu'un bénévole ouvre le plus souvent.
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .fil {
  font-size: var(--t-secondaire);
  margin-bottom: var(--e-3);
}

.systeme .fil a {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  /* Le remplissage est repris en marge : le fil ne pousse pas le titre. */
  margin: -11px 0;
  color: var(--gris);
  text-decoration: none;
}

.systeme .fil a:hover { color: var(--encre); text-decoration: underline; }

.systeme .fil a:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

.systeme .petit-bouton {
  min-height: var(--h-cible);
  padding: 0 14px;
  font-size: var(--t-secondaire);
  font-weight: var(--g-demi);
  border-radius: var(--rayon);
  cursor: pointer;
}

/* Une adresse e-mail ou un téléphone dans une fiche est un lien : on l'appelle,
   on lui écrit. C'est donc une cible, pas du texte. */
.systeme .fiche-contact a,
.systeme .bloc a[href^='mailto:'],
.systeme .bloc a[href^='tel:'] {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  margin: -11px 0;
  color: var(--encre);
  text-underline-offset: 3px;
}

/* ⚠️ « principal » qualifie un contact — ce n'est ni une action ni l'identité
   du club. Il portait un aplat d'accent, soit le quatrième de l'écran. Une
   qualification se dit avec la palette d'états, comme partout ailleurs. */
.systeme .jeton-principal {
  color: var(--etat-info-texte);
  background: var(--etat-info-fond);
  border: var(--trait) solid var(--etat-info-bord);
}

/* Le filet du bloc « prochaine action » n'est pas un des quatre emplois
   autorisés de l'accent. En encre, il dit « c'est ici » sans emprunter la
   couleur du club — et il reste lisible chez un club à l'accent pâle. */
.systeme .bloc-action { border-left-color: var(--encre); }

/* ⚠️⚠️ PLUSIEURS ACTIONS DANS LE MÊME BLOC — migration 058, 10/09/2026.
   Elles étaient au singulier ; il faut maintenant les SÉPARER, sinon deux
   échéances se lisent comme une seule phrase. Un filet entre elles, pas de
   cartes : ce sont des lignes du même sujet, pas des objets distincts —
   « tout n'est pas une carte », DESIGN.md § 7. */
.systeme .bloc-action .action-ligne + .action-ligne {
  margin-top: var(--e-4);
  padding-top: var(--e-4);
  border-top: var(--trait) solid var(--ligne);
}

/* ═══════════════════════════════════════════════════════════════════════════
 * FORMULAIRES
 *
 * C'est là que la densité compte le plus : saisir une fiche partenaire sur un
 * téléphone, dans les tribunes, est le geste le plus ingrat du produit.
 * ═══════════════════════════════════════════════════════════════════════════ */

.systeme .bloc {
  margin-top: var(--e-5);
  padding: var(--e-5);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  box-shadow: var(--ombre-carte);
}

.systeme .bloc-entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
  margin-bottom: var(--e-4);
}

/* ⚠️ Mesurée à 9,5 px. Le plancher est 11, et il ne se négocie pas : nos
   utilisateurs ne sont pas des experts qui viennent tous les jours. */
.systeme .etiquette {
  font-family: var(--mono);
  font-size: var(--t-micro);
  line-height: var(--i-micro);
  font-weight: var(--g-normal);
  text-transform: uppercase;
  letter-spacing: var(--approche-micro);
  color: var(--gris);
  margin: 0;
}

.systeme .champ { margin-top: var(--e-4); }
.systeme .champ:first-of-type { margin-top: var(--e-2); }

.systeme .champ > label {
  display: block;
  font-size: var(--t-secondaire);
  font-weight: var(--g-demi);
  line-height: var(--i-secondaire);
  color: var(--encre);
  margin-bottom: var(--e-2);
}

.systeme .champ input:not([type='file']):not([type='checkbox']):not([type='radio']),
.systeme .champ select,
.systeme .champ textarea {
  font: inherit;
  font-size: var(--t-corps);
  width: 100%;
  min-height: var(--h-champ);
  padding: 0 var(--e-3);
  color: var(--encre);
  background: var(--champ);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
}

.systeme .champ textarea { padding: var(--e-3); line-height: var(--i-corps); }

.systeme .champ input:hover,
.systeme .champ select:hover,
.systeme .champ textarea:hover { border-color: var(--gris); }

.systeme .aide {
  font-size: var(--t-petit);
  line-height: var(--i-petit);
  color: var(--gris);
  margin-top: var(--e-1);
  max-width: var(--largeur-lecture);
}

/* ⚠️ DEUX CHAMPS CÔTE À CÔTE ÉTAIENT DÉCALÉS DE 10 PX
   -------------------------------------------------------------------------
   `.champ:first-of-type` porte 4 px de marge haute, les suivants 14. Dans une
   grille à deux colonnes, le premier est « first-of-type » et le second ne
   l'est pas : les deux champs ne commencent donc jamais à la même hauteur.
   Mesuré sur QUATRE paires du seul formulaire partenaire, et présent sur tous
   les autres. À l'œil, on voit juste « quelque chose de bâclé » sans savoir
   quoi. L'espacement passe sur la grille, où il est le même pour les deux. */
.systeme .deux {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--e-4);
  align-items: start;
  margin-top: var(--e-4);
}

.systeme .deux > .champ,
.systeme .deux > .champ:first-of-type { margin-top: 0; }

/* ───────────────────────────────────────────────────────────────────────────
 * Quatre classes employées par les gabarits et stylées NULLE PART
 *
 * ⚠️ Trouvées par le test « toute classe posée dans un gabarit est stylée
 * quelque part », écrit après avoir constaté que ma propre classe `.etroit`
 * ne faisait rien. Trois d'entre elles étaient là AVANT aujourd'hui : le
 * balisage les portait, la feuille les ignorait, et personne ne l'avait vu —
 * un paragraphe sans style reste un paragraphe lisible.
 * ─────────────────────────────────────────────────────────────────────── */

/* Une valeur qu'on montre sans pouvoir la modifier ici. Elle doit se lire
   comme une valeur, pas comme un champ désactivé — il n'y a rien à activer. */
.systeme .valeur-figee {
  margin-top: 2px;
  font-size: var(--t-corps);
  line-height: var(--i-corps);
  font-weight: var(--g-demi);
  color: var(--encre);
}

/* Un lien ou une précision qui suit un bloc, et qui lui appartient encore. */
.systeme .apres-bloc {
  margin-top: var(--e-3);
  font-size: var(--t-petit);
  line-height: var(--i-petit);
  color: var(--gris);
}

/* ⚠️ « archivé » n'est pas une erreur : c'est un ÉTAT NEUTRE. En rouge, il
   ferait croire à un problème alors que rien n'est perdu — et le texte dit
   précisément le contraire. */
.systeme .bandeau-archive {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-2);
  margin-top: var(--e-4);
  padding: var(--e-3) var(--e-4);
  border: var(--trait) solid var(--etat-neutre-bord);
  border-radius: var(--rayon);
  background: var(--etat-neutre-fond);
  color: var(--etat-neutre-texte);
  font-size: var(--t-secondaire);
  line-height: var(--i-secondaire);
}

/* Un champ qui prend toute la largeur, y compris dans une grille à deux
   colonnes — un motif d'annulation ne se saisit pas dans une demi-ligne. */
.systeme .champ.champ-large { grid-column: 1 / -1; }

/* ───────────────────────────────────────────────────────────────────────────
 * Une ligne de tableau qui se corrige sur place
 *
 * Le détail d'une facture en brouillon se modifie dans le tableau lui-même.
 * Deux règles suffisent, et elles manquaient toutes les deux :
 *
 * ⚠️ Le champ doit REMPLIR sa cellule. Sans cela il gardait la largeur par
 * défaut d'un champ de formulaire — mesuré : 143 px dans une cellule de
 * 199 px — et « Panneau bord de terrain 3 m » s'affichait « Panneau bord de
 * terrai ». On corrige un libellé qu'on ne peut pas lire en entier.
 *
 * ⚠️ Une colonne de nombres n'a pas besoin de la même place qu'un libellé.
 * Le tableau distribuait tout également : « Qté » recevait 198 px pour deux
 * caractères, pendant que le libellé étouffait dans la même largeur.
 * ─────────────────────────────────────────────────────────────────────── */

.systeme .liste td input[type='text'],
.systeme .liste td input[type='date'] {
  width: 100%;
  min-width: 0;
}

/* Un champ qui ne porte que des chiffres. La classe était posée dans le
   gabarit et n'existait NULLE PART dans la feuille : elle ne faisait rien. */
/* ⚠️ Un MINIMUM autant qu'un maximum. Sans plancher, la colonne des libellés
   — qui prend tout l'espace restant — écrasait celle des montants : « 1200,00 »
   s'affichait « 1200 ». Un champ qui coupe la valeur qu'il contient invite à la
   ressaisir de travers. */
.systeme .liste td input.etroit { min-width: 5.5rem; max-width: 7rem; }

/* ───────────────────────────────────────────────────────────────────────────
 * LA LARGEUR DES COLONNES D'UNE LISTE — PLUS AUCUNE N'EST RÉCLAMÉE
 *
 * ⚠️⚠️ CETTE RÈGLE A ÉTÉ RETIRÉE LE 16/09/2026, APRÈS MESURE. Elle disait :
 *
 *     .systeme .liste td.principal,
 *     .systeme .liste th:first-child:not(.choix) { width: 100%; }
 *
 * sous le titre « la colonne des libellés prend ce que les autres ne réclament
 * pas ». L'intention était juste. Le moyen ne la servait pas : dans
 * l'algorithme de table AUTOMATIQUE, 100 % ne veut pas dire « le reste », il
 * veut dire « TOUT ». La colonne emporte le surplus entier, et les autres
 * retombent à leur MIN-content — pas à leur max.
 *
 * Écran du matin, 1440 px, tableau de 1188 :
 *
 *     colonne        rendu   max-content
 *     Partenaire      807         142     ← 665 px de vide
 *     Action          110         232     ← cassée en trois lignes
 *     Échéance         94         197     ← « en retard depuis le 26/08/2026 »
 *     (bouton)        176         154
 *
 * Somme des max-content : 725 px pour 1188 disponibles. 463 px de surplus, et
 * pourtant deux colonnes comprimées — les deux qui portent le sens de l'écran,
 * quoi faire et pour quand. Même défaut sur Contrats (732 px pour une référence
 * de 97 px de contenu), Factures (656), Partenaires (649).
 *
 * ⚠️ LE CHOIX A ÉTÉ MESURÉ, PAS ARBITRÉ. Sur les quinze écrans du produit, à
 * 1440 px et à 1024 px, chaque table de liste, en sommant sur toutes ses
 * colonnes les pixels de contenu qui ne tiennent pas :
 *
 *     width: 100%   3 533 px manquants
 *     width: 40%    2 109 px
 *     width: auto   1 119 px   ← et ZÉRO sur les dix tables à 1440 px
 *
 * Le retrait gagne partout. Il ne gagne pas d'un cheveu : il divise par trois.
 *
 * ⚠️⚠️ ET IL N'INTRODUIT AUCUN NOMBRE. 40 % avait d'abord été retenu, à la
 * mesure des quatre premières listes — c'était déjà une constante qui aurait
 * vieilli, et elle affamait encore /packs et /equipe. Un plafond exprimé en
 * pourcentage a de plus une seconde vie qu'on n'attendait pas : sous 760 px la
 * liste se replie en BLOCS, où 40 % de la ligne serrait le nom du partenaire
 * dans 136 px sur un écran de 375. L'absence de règle n'a pas ce problème,
 * parce qu'elle n'a rien à annuler au point de rupture.
 *
 * Ce que l'algorithme fait à sa place : il répartit le surplus au prorata des
 * max-content. La colonne des libellés ne domine plus — c'est le prix, et il
 * est payé volontiers : une colonne large et vide ne dit rien, une colonne
 * repliée en trois lignes coûte une lecture.
 *
 * Gardien : « aucune colonne de liste ne réclame de largeur », plus loin dans
 * tests/gabarits.test.ts, avec la mesure ci-dessus en commentaire.
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .liste td.actions { white-space: nowrap; }
/* Une période « du … au … » coupée en quatre lignes se déchiffre au lieu de se
   lire. Elle tient sur une ligne, la colonne des libellés absorbe le reste. */
.systeme .liste td.periode { white-space: nowrap; }

/* Plusieurs liens discrets au bout d'un titre de section. */
.systeme .liens-section { display: flex; align-items: baseline; gap: var(--e-4);
                          flex-wrap: wrap; }

/* Une mention neutre sur une ligne — « vous », un rappel sans jugement.
   Palette d'état FIXE, jamais l'accent du club : ce n'est pas une couleur de
   marque, c'est une information. */
.systeme .etat-neutre {
  color: var(--etat-neutre-texte);
  background: var(--etat-neutre-fond);
  border-color: var(--etat-neutre-bord);
}

/* ═══════════════════════════════════════════════════════════════════════════
 * ⚠️ LE PREMIER ENFANT D'UN <fieldset> S'EFFONDRE S'IL EST EN GRILLE
 *
 * Mesuré dans le navigateur, sur l'écran d'identité fiscale : un `.deux` placé
 * juste après le `<legend>` faisait 0 px de large, ses deux colonnes 22 px,
 * et les champs se tassaient contre le bord droit. Le MÊME `.deux` placé plus
 * bas dans le même fieldset faisait 638 px.
 *
 * Ce n'est ni le contenu ni une règle de la feuille : c'est la POSITION.
 * Vérifié en insérant trois éléments neufs en tête du fieldset :
 *
 *     <div> ordinaire        → 638 px
 *     <div display:grid>     →   0 px
 *     <div display:flex>     →   0 px
 *
 * Un bloc ordinaire va bien ; un contexte de grille ou de boîte flexible
 * s'effondre. `min-inline-size: 0`, `display: flow-root` et une cale devant
 * n'y changent rien — seule une largeur explicite corrige.
 *
 * ⚠️ CE DÉFAUT ÉTAIT DÉJÀ EN PRODUCTION, sur `actif-formulaire` (deux fois) et
 * `partenaire-formulaire`. Personne ne l'avait signalé : un formulaire dont
 * deux champs sont écrasés à droite se lit comme un formulaire mal dessiné,
 * pas comme un défaut.
 * ═══════════════════════════════════════════════════════════════════════════ */
.systeme fieldset > legend + * { width: 100%; }

/*
 * ⚠️⚠️ ET IL FRAPPE AUSSI UN NIVEAU PLUS BAS — QUATRIÈME ÉCRAN, 10/09/2026.
 *
 * La règle ci-dessus ne rattrape que l'ENFANT DIRECT du `<legend>`. Sur
 * l'identité fiscale, le bloc `.champ` juste après la légende mesure bien ses
 * 514 px — mais le `<label>` en boîte flexible qu'il contient s'effondre à
 * **0 px**. Le texte « La structure est déclarée éligible au mécénat » se
 * casse alors sur SEPT lignes d'un mot, et la case à cocher, centrée
 * verticalement, flotte au milieu de cette colonne.
 *
 * ⚠️ Signalé par Charles, pas par le banc : « la case est mal alignée sur la
 * fiche ». C'est exactement ce que dit le commentaire ci-dessus — *un
 * formulaire écrasé se lit comme un formulaire mal dessiné, pas comme un
 * défaut*. Trois écrans l'avaient déjà porté sans que personne ne le nomme.
 *
 * Le remède est le même — une largeur explicite — et il vaut pour toute
 * rangée à cocher, où qu'elle soit : une case suivie de son libellé occupe
 * TOUJOURS la largeur de son conteneur.
 */
.systeme .champ-case > label,
.systeme .case-role { width: 100%; }

/* ⚠️ Et la case se cale sur la PREMIÈRE LIGNE, pas au milieu. Sur un libellé
   qui passe à la ligne — écran étroit, texte long — `align-items: center`
   pose la case à mi-hauteur du paragraphe, loin du mot qu'elle coche. */
.systeme .champ-case > label,
.systeme .case-role { align-items: flex-start; }
.systeme .champ-case > label > input,
.systeme .case-role > input { margin-top: 1px; }

/* Sous 760 px, deux colonnes de saisie font des champs trop étroits pour un
   pouce : elles s'empilent. */
@media (max-width: 760px) {
  .systeme .deux { grid-template-columns: 1fr; gap: var(--e-4); }
}

/* ⚠️ LA CASE À COCHER MESURAIT 13 PX
   -------------------------------------------------------------------------
   Intouchable au pouce. On agrandit la case ET on fait du LIBELLÉ ENTIER une
   cible de 40 px : viser une case de 20 px reste difficile, viser une ligne de
   texte ne l'est pas. */
.systeme .champ-case > label,
.systeme .case-role {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  min-height: var(--h-cible);
  font-size: var(--t-corps);
  font-weight: var(--g-normal);
  line-height: var(--i-corps);
  cursor: pointer;
}

.systeme .champ-case input[type='checkbox'],
.systeme .case-role input[type='checkbox'],
.systeme .champ input[type='radio'] {
  width: 20px;
  height: 20px;
  flex: none;
  accent-color: var(--encre);
  cursor: pointer;
}

.systeme .cases { display: flex; flex-wrap: wrap; gap: var(--e-1) var(--e-4); }

/*
 * ⚠️⚠️ CINQUIÈME ÉCRAN DU MÊME EFFONDREMENT — 10/09/2026, signalé par Charles :
 * « Parrainage — Facturé, avec TVA / Mécénat — Don, ouvre droit à un reçu
 * fiscal » paraissait de travers.
 *
 * MESURÉ, dans le navigateur, sur la vraie page :
 *
 *     .cases (boîte flexible), PREMIER enfant de .champ   →   0 px
 *     le MÊME élément cloné, déplacé en second            → 402 px
 *     un <div> neuf inséré au même endroit                → 402 px
 *
 * C'est exactement le défaut décrit trente lignes plus haut, encore un cran
 * plus bas : la règle `fieldset > legend + *` rattrape le `.champ`, qui mesure
 * bien ses 402 px ; la règle sur `.case-role` donne 100 % — mais 100 % de la
 * boîte flexible intermédiaire, qui vaut ZÉRO. Les deux correctifs existants
 * se croisent sans se rencontrer.
 *
 * ⚠️ J'AI D'ABORD ACCUSÉ `flex-wrap: wrap` en direction colonne, et écrit une
 * règle pour ça. Mesure faite : `nowrap` appliqué, largeur toujours nulle. La
 * fausse règle a été retirée — une correction qui ne corrige rien, justifiée
 * par une cause inventée, est pire que le défaut : elle ferme l'enquête.
 *
 * Le remède est celui que ce fichier connaît déjà : une largeur EXPLICITE.
 */
.systeme .cases { width: 100%; }

.systeme .pied-formulaire,
.systeme .actions-formulaire {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-4);
  margin-top: var(--e-5);
}

.systeme .message-erreur,
.systeme .erreur-bandeau {
  margin-top: var(--e-3);
  padding: var(--e-3) var(--e-4);
  font-size: var(--t-secondaire);
  color: var(--etat-retard-texte);
  background: var(--etat-retard-fond);
  border: var(--trait) solid var(--etat-retard-bord);
  border-radius: var(--rayon);
  max-width: var(--largeur-lecture);
}

.systeme .champ.en-erreur input,
.systeme .champ.en-erreur select,
.systeme .champ.en-erreur textarea { border-color: var(--etat-retard-texte); }

.systeme .champ .requis { color: var(--etat-retard-texte); }

/* Le contour de focus est en ENCRE, jamais en accent : un club à l'accent pâle
   n'aurait aucun repère au clavier. 19,80:1 quelle que soit la couleur. */
.systeme .champ input:focus-visible,
.systeme .champ select:focus-visible,
.systeme .champ textarea:focus-visible,
.systeme .champ-case input:focus-visible,
.systeme .case-role input:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
  border-color: var(--encre);
}

/* ─── Les sections d'un formulaire sont des <fieldset> ───────────────────────
 * Et non des « .bloc » : les règles écrites pour les fiches ne les touchent
 * pas. La légende native se pose SUR la bordure et la coupe — un titre à
 * cheval sur un trait, illisible à 9,5 px. On la sort du cadre : elle devient
 * un micro-libellé posé au-dessus de la carte, comme les en-têtes de colonne.
 * ─────────────────────────────────────────────────────────────────────────── */

.systeme .formulaire-large fieldset {
  padding: var(--e-5);
  margin-bottom: var(--e-4);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  box-shadow: var(--ombre-carte);
}

.systeme .formulaire-large legend {
  /* « float: left » sort la légende du flux réservé par le navigateur, donc
     elle cesse d'entailler la bordure ; le padding du fieldset la remet dans
     le cadre. `width: 100%` force le champ suivant à passer à la ligne. */
  float: left;
  width: 100%;
  padding: 0;
  margin-bottom: var(--e-2);
  font-family: var(--mono);
  font-size: var(--t-micro);
  line-height: var(--i-micro);
  text-transform: uppercase;
  letter-spacing: var(--approche-micro);
  color: var(--gris);
}

/* Le rappel du catalogue : ses deux liens sont le SEUL chemin vers les actifs
   et les packs depuis que la barre est passée à cinq entrées. Mesurés à 17 px
   — c'est-à-dire la hauteur de leur texte, et rien de plus. */
.systeme .rappel-catalogue {
  margin-top: var(--e-2);
  font-size: var(--t-secondaire);
  color: var(--gris);
  max-width: var(--largeur-lecture);
}

.systeme .rappel-catalogue a {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  margin: -11px 0;
  color: var(--encre);
  text-underline-offset: 3px;
}

.systeme .rappel-catalogue a:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

/* Le dépôt de fichier de l'import : le sélecteur des champs exclut
   explicitement « type=file », donc il gardait la boîte native de 22 px. */
.systeme .champ input[type='file'],
.systeme input[type='file'] {
  font: inherit;
  font-size: var(--t-secondaire);
  width: 100%;
  min-height: var(--h-champ);
  padding: var(--e-2) var(--e-3);
  background: var(--champ);
  border: var(--trait) dashed var(--ligne);
  border-radius: var(--rayon);
  cursor: pointer;
}

.systeme input[type='file']:hover { border-color: var(--gris); }

.systeme input[type='file']:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

/* Le sous-titre d'une fiche porte des liens — le partenaire, le contrat
   d'origine. Mesurés à 22 px : la hauteur de leur texte. Ce sont les chemins
   de navigation les plus empruntés du produit, ils méritent une vraie cible. */
.systeme .sous-titre {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e-3);
  font-size: var(--t-secondaire);
  color: var(--gris);
}

.systeme .sous-titre a {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-cible);
  margin: -11px 0;
  color: var(--encre);
  text-underline-offset: 3px;
}

.systeme .sous-titre a:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * LARGEUR : les écrans de DONNÉES respirent, les écrans de LECTURE se tiennent
 *
 * Mesuré à 1440 px : le contenu occupait 992 px et laissait 224 px de vide de
 * chaque côté, pendant que le tableau des partenaires serrait six colonnes.
 * Une largeur de lecture appliquée à un tableau n'est pas de la sobriété,
 * c'est une mesure prise pour autre chose.
 *
 * La classe vient du gabarit, pas d'une devinette sur le contenu : un écran
 * sait s'il montre des données ou du texte.
 * ═══════════════════════════════════════════════════════════════════════════ */

.systeme.large { max-width: var(--largeur-large); }

/* En dessous, la largeur large ne change plus rien : le contenu prend déjà
   toute la place. La règle n'a donc pas besoin de media query. */

/* ═══════════════════════════════════════════════════════════════════════════
 * AFFÛTAGE — sept défauts mesurés sur un écran de 1440 px
 *
 * Aucun arbitrage de DESIGN.md n'est rouvert : densité de bénévole, actif en
 * encre, six paliers typographiques, palette d'états fixe. Ce qui change, c'est
 * la PRÉSENCE — le produit avait la qualité sans l'assurance.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ─── 1. L'en-tête de page : une zone, pas trois éléments qui flottent ─────
 * Le titre, le chapeau et les actions partagent une ligne de base et une
 * séparation nette avec le contenu. Avant, « Importer un fichier » et le bouton
 * principal flottaient à des hauteurs différentes du titre.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .titre-ligne {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--e-5);
  flex-wrap: wrap;
}

.systeme .titre-ligne > :first-child { flex: 1 1 24rem; }

/* Les actions d'en-tête s'alignent sur la HAUTEUR DU TITRE, pas sur son haut :
   un bouton de 44 px calé sur la première ligne d'un titre de 26 px paraît
   toujours trop haut. */
.systeme .titre-ligne .bouton,
.systeme .titre-ligne .bouton-discret,
.systeme .boutons-titre {
  align-self: center;
  flex: none;
}

.systeme .boutons-titre {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  flex-wrap: wrap;
}

/* Le chapeau appartient à l'en-tête : il ne doit pas s'en détacher. */
.systeme .chapeau {
  margin-top: var(--e-2);
  font-size: var(--t-secondaire);
  line-height: var(--i-secondaire);
  color: var(--gris);
  max-width: var(--largeur-lecture);
}

/* ─── 2. Le tableau : un en-tête qui se voit, un survol qui répond ────────
 * L'en-tête de colonne était à 11 px gris pâle sur blanc, indiscernable de la
 * première ligne. Un tableau de données a besoin qu'on distingue l'étiquette
 * de la donnée sans y penser.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .liste thead th {
  background: var(--champ);
  border-bottom: var(--trait) solid var(--ligne);
  color: var(--gris);
  /* Le repos vertical vient du remplissage, pas d'une hauteur imposée : une
     colonne triable porte un lien de 40 px qui doit tenir dedans. */
  padding-top: var(--e-2);
  padding-bottom: var(--e-2);
}

.systeme .liste thead th:first-child { border-top-left-radius: var(--rayon-grand); }
.systeme .liste thead th:last-child  { border-top-right-radius: var(--rayon-grand); }

/* Le survol dit « cette ligne entière est cliquable ». Sans lui, la surface
   étirée sous la ligne est une promesse invisible. */
.systeme .liste tbody tr:hover { background: var(--champ); }

/* ─── 3. La recherche : un groupe, pas un champ et un bouton posés côte à côte */

.systeme .barre-recherche {
  display: flex;
  gap: var(--e-2);
  margin-top: var(--e-5);
  max-width: 34rem;
}

.systeme .barre-recherche input {
  flex: 1;
  min-height: var(--h-champ);
  padding: 0 var(--e-4);
  font-size: var(--t-corps);
  color: var(--encre);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
}

.systeme .barre-recherche input:focus-visible {
  outline: var(--trait-fort) solid var(--encre);
  outline-offset: 2px;
  border-color: var(--encre);
}

.systeme .barre-recherche button {
  flex: none;
  min-height: var(--h-champ);
  padding: 0 var(--e-5);
  font-size: var(--t-corps);
  font-weight: var(--g-demi);
  color: var(--encre);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
  cursor: pointer;
}

.systeme .barre-recherche button:hover { border-color: var(--gris); }

/* ─── 4. La profondeur : les ombres existaient, on ne les voyait pas ──────
 * 2 px de décalage et 7 % d'opacité sur un fond crème ne produisent aucune
 * séparation. Une carte doit se détacher de son fond, sinon elle n'est qu'un
 * rectangle blanc.
 * ───────────────────────────────────────────────────────────────────────── */

/* ⚠️ L'ombre de Regard AI, telle quelle : `shadow-card`. Le produit en avait
   fabriqué une à deux couches, plus douce ; deux surfaces voisines venues de
   deux logiciels ne doivent pas se poser différemment. */
.systeme .bloc,
.systeme .liste,
.systeme .alerte-carte,
.systeme .compteur,
.systeme .formulaire-large fieldset {
  box-shadow: var(--ombre-carte);
}

/* ─── 5. La grille d'alertes : jamais une carte orpheline ─────────────────
 * Quatre alertes donnaient 3 + 1, avec un trou béant à droite et une quatrième
 * carte plus courte que ses voisines. Deux colonnes se remplissent toujours
 * proprement, et laissent plus de place au texte de chaque alerte.
 * ───────────────────────────────────────────────────────────────────────── */

/*
 * ⚠️ LE NOMBRE DE COLONNES EST DÉCIDÉ, PAS DEVINÉ
 *
 * `auto-fit` remplit ce qu'il peut : à 1344 px et 380 px minimum, il tient
 * trois colonnes — donc quatre alertes donnent 3 + 1, avec une carte orpheline
 * et un trou béant à droite. Élargir le minimum ne fait que déplacer le
 * problème vers un autre compte.
 *
 * On compte donc les cartes. Quatre alertes se rangent en 2 × 2, trois en une
 * ligne, cinq en 3 + 2. Aucune configuration ne laisse une carte seule sur sa
 * ligne, et l'écran ne change pas de forme d'un jour à l'autre pour une alerte
 * de plus ou de moins.
 */
.systeme .alertes { grid-template-columns: repeat(3, 1fr); }

.systeme .alertes:has(> :nth-child(1):last-child) { grid-template-columns: 1fr; }
.systeme .alertes:has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, 1fr); }
.systeme .alertes:has(> :nth-child(4):last-child) { grid-template-columns: repeat(2, 1fr); }

/* Une alerte seule ne s'étale pas sur toute la largeur : au-delà, son texte
   dépasse la mesure de lecture et devient pénible à parcourir. */
.systeme .alertes .alerte-carte:only-child { max-width: 46rem; }

/*
 * ⚠️⚠️ DANS LE BANDEAU, LES TUILES TIENNENT SUR UNE SEULE LIGNE — 17/09/2026.
 *
 * La règle au-dessus range cinq alertes en 3 + 2 et quatre en 2 × 2. Sur le
 * PAPIER c'est le bon arbitrage : les cartes y sont larges et leur texte doit
 * rester lisible. DANS LE BANDEAU c'est le défaut le plus visible de l'écran —
 * une demi-rangée vide sous un aplat rouge, là où la maquette aligne quatre
 * tuiles d'un seul tenant.
 *
 * ⚠️⚠️ LE SEUIL EST MESURÉ, ET MA PREMIÈRE MESURE ÉTAIT FAUSSE. J'avais écrit
 * ici « à 1280 px, ~196 px utiles » — un chiffre que je n'avais pas pris. Le
 * banc rendait l'écran en `large: false` alors que la route passe
 * `large: true` : je mesurais une colonne de 992 px là où le produit en donne
 * 1344. C'est la même faute que le 16/09, à un cran en amont — non plus un
 * seuil choisi au jugé, mais un seuil mesuré sur le mauvais écran.
 *
 * Les vraies mesures, à `large: true`, sur la tuile et sur la marge qui reste
 * sous le plus long des cinq liens (« Ouvrir la conformité ») :
 *
 *   1280 px   tuile 185 px   marge  8 px      1440 px   tuile 217   marge 40
 *   1360 px   tuile 201 px   marge 24 px      1728 px   tuile 242   marge 65
 *
 * Aucune largeur ne déborde. Le seuil est posé à 1360 et non à 1280 : 8 px de
 * marge n'est pas une marge, c'est une coïncidence — le vocabulaire est réglé
 * PAR CLUB (« saison », « exercice », « olympiade »), donc ces libellés
 * s'allongent chez quelqu'un que je ne mesure pas. À 1360, la marge triple.
 *
 * ⚠️ La borne : ceci ne vaut QUE dans le bandeau. Ailleurs, une rangée de cinq
 * cartes écraserait le texte sous la mesure de lecture.
 */
@media (min-width: 1360px) {
  .systeme .entete-jour .alertes:has(> :nth-child(4):last-child) {
    grid-template-columns: repeat(4, 1fr);
  }
  .systeme .entete-jour .alertes:has(> :nth-child(5):last-child) {
    grid-template-columns: repeat(5, 1fr);
  }
}

/* Sous 760 px, tout s'empile — trois colonnes de 380 px n'y tiennent pas, et
   `:has()` ne doit pas ressusciter une grille impossible. */
@media (max-width: 760px) {
  .systeme .alertes,
  .systeme .alertes:has(> :nth-child(2):last-child),
  .systeme .alertes:has(> :nth-child(4):last-child) { grid-template-columns: 1fr; }
}

/* ─── 6. Ce qui pesait plus lourd que son importance ───────────────────────
 * « Me déconnecter » s'affichait large et centré, en bas de l'écran d'accueil :
 * il attirait l'œil avant les alertes. Se déconnecter n'est pas une action de
 * l'écran d'entrée — le bouton reste atteignable à 40 px, mais rentre dans le
 * rang.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .deconnexion { display: flex; }
.systeme .deconnexion button { flex: none; }

/* ─── 7. La respiration en haut de page ───────────────────────────────────
 * Le titre démarrait à 20 px du filet de la barre. Un écran qui commence
 * immédiatement sous sa navigation paraît serré, quelle que soit la qualité de
 * ce qu'il contient.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme { padding-top: var(--e-6); }

/* ─── 8. La ligne de conformité : deux blocs, pas deux bords ──────────────
 * Le texte à gauche et le lien à droite laissaient 1 200 px de vide entre eux
 * sur un écran large. Le lien suit maintenant son texte.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .conformite-resume { max-width: 48rem; }
.systeme .conformite-resume a { margin-left: var(--e-4); }

/* ─── 9. La jauge dit où elle en est ──────────────────────────────────────
 * Un trait rempli à 19 % sans chiffre oblige à estimer à l'œil. Le pourcentage
 * est déjà connu du serveur : il s'écrit.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .jauge-ligne {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  margin-top: var(--e-4);
}

.systeme .jauge-ligne .jauge { flex: 1; margin-top: 0; max-width: 42rem; }

.systeme .jauge-part {
  font-family: var(--mono);
  font-size: var(--t-corps);
  font-weight: var(--g-demi);
  font-variant-numeric: tabular-nums;
  color: var(--encre);
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * ALIGNEMENT SUR REGARD AI — petites tailles, graisses fortes
 *
 * Ce qui suit annule la transposition « pour bénévoles » de l'échelle et des
 * graisses. Le crème, les rayons, Outfit, DM Mono et les ombres étaient déjà
 * identiques au pixel près : ce qui manquait était le CONTRASTE DE GRAISSE.
 *
 * Regard AI met du semibold et du bold partout, à des tailles que nous avions
 * doublées. C'est ce qui lui donne son assurance — et c'est exactement ce qui
 * nous manquait.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Titres ──────────────────────────────────────────────────────────────
 * Titre de page 30px/800 depuis le 16/09 (DESIGN.md § 3.2 bis) ;
 * titre de carte 13px en `font-bold`, porté de Regard AI.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme h1 {
  font-size: var(--t-titre);
  line-height: var(--i-titre);
  /* ⚠️ 800, pas 700 — DESIGN.md § 3.2 bis. À 30 px, le 700 d'Outfit paraît
     mou : la signature portée de Regard AI est « graisses fortes », et elle
     vaut d'autant plus quand la taille monte. */
  font-weight: var(--g-noir);
  letter-spacing: -0.025em;
  /*
   * ⚠️⚠️ CONSÉQUENCE DIRECTE DU PASSAGE À 44 PX — 17/09/2026.
   *
   * Ce jeton gouverne TOUS les `h1` du produit, et plusieurs ne sont pas des
   * mots à nous : la fiche partenaire y met la raison sociale saisie par le
   * club. À 44 px sur un téléphone de 390, une raison sociale d'un seul tenant
   * — « SARLCHARPENTESETMENUISERIESDUSUDOUEST », c'est-à-dire ce que les gens
   * saisissent vraiment — dépasse la boîte et pousse la page latéralement.
   *
   * ⚠️ Le défaut ne se serait PAS vu sur l'écran du matin, dont le titre est
   * « Aujourd'hui » et que j'ai mesuré ; il serait apparu chez un club, sur une
   * fiche, sur un téléphone. C'est la leçon de la sonde inerte du 17/09 :
   * mesurer un écran n'est pas mesurer le produit.
   */
  overflow-wrap: anywhere;
  /* Équilibre les lignes d'un titre long plutôt que d'en laisser une orpheline. */
  text-wrap: balance;
}

/*
 * ⚠️ LE TITRE REDESCEND SUR TÉLÉPHONE — et ce n'est pas un palier de plus.
 *
 * 44 px vient d'un rapport mesuré sur un ÉCRAN LARGE : 3,1 % de 1440. Sur 390,
 * le même jeton pèse 11,3 % de la largeur — trois fois la proportion voulue,
 * et deux à trois lignes rien que pour dire où l'on est.
 *
 * 32 px rend 8,2 % : plus haut qu'un écran large en proportion, ce qui est
 * juste (on lit un téléphone de plus près et le titre y est plus seul), sans
 * manger l'écran. La valeur est le JETON, redéfini pour ce contexte — pas une
 * taille en dur, que le témoin « aucune taille hors de l'échelle » refuserait.
 */
@media (max-width: 760px) {
  .systeme h1 { --t-titre: 32px; }
}

.systeme h2,
.systeme .titre-section {
  font-size: var(--t-section);
  line-height: var(--i-section);
  font-weight: var(--g-gras);
  letter-spacing: -0.01em;
  margin-top: var(--e-6);
}

.systeme .chapeau,
.systeme .note-haute {
  font-size: var(--t-secondaire);
  font-weight: var(--g-normal);
  color: var(--gris);
}

/* ─── Étiquettes d'état : 10 px en GRAS, comme les badges de Regard AI ────
 * Une étiquette de 12 px en 600 occupe la place d'un mot ; à 10 px en 700 elle
 * devient un repère, et la ligne du tableau respire.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme [class*='etat-'] {
  padding: 1px 8px;
  font-size: var(--t-micro);
  font-weight: var(--g-gras);
  line-height: var(--i-micro);
  letter-spacing: 0.01em;
}

/* ─── Le tableau se resserre ──────────────────────────────────────────────
 * Les cellules gardent 40 px de hauteur — la cible ne bouge pas — mais le
 * texte descend à 12,5 px et les intitulés à 10 px en gras.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .liste { font-size: var(--t-corps); }

.systeme .liste thead th {
  font-size: var(--t-micro);
  font-weight: var(--g-gras);
  letter-spacing: var(--approche-micro);
}

.systeme .liste td { padding-top: var(--e-2); padding-bottom: var(--e-2); }
.systeme .liste .principal a { font-weight: var(--g-demi); }
.systeme .liste .secondaire { font-size: var(--t-petit); }

/* ─── Boutons : le texte rétrécit, la cible reste ────────────────────────── */

.systeme .bouton,
.systeme .bouton-discret,
.systeme .lien-bouton,
.systeme .petit-bouton,
.systeme .liste td.actions button {
  font-size: var(--t-corps);
  font-weight: var(--g-demi);
}

/* ─── Compteurs et cartes ─────────────────────────────────────────────────
 * Regard AI tient ses cartes en 16 px de padding. Une carte trop matelassée
 * fait paraître son contenu maigre.
 * ───────────────────────────────────────────────────────────────────────── */

.systeme .bloc,
.systeme .alerte-carte,
.systeme .formulaire-large fieldset { padding: var(--e-5); }

/* Les tailles du compteur sont définies une seule fois, avec le composant.
   Elles l'étaient ici AUSSI, et les deux endroits divergeaient. */

/* ⚠️ DOUBLON RETIRÉ LE 09/09/2026. Ces trois règles répétaient, à l'identique
   et sans contexte différent, celles posées avec le composant plus haut. Le
   commentaire juste au-dessus dénonce exactement ce piège pour les compteurs —
   « les deux endroits divergeaient » — et l'alerte le portait encore. Un
   composant, un endroit. */

/* ─── Formulaires ────────────────────────────────────────────────────────── */

.systeme .champ > label { font-size: var(--t-petit); font-weight: var(--g-demi); }
.systeme .champ input:not([type='file']),
.systeme .champ select,
.systeme .champ textarea { font-size: var(--t-corps); }
.systeme .aide { font-size: var(--t-petit); }

/* ─── Navigation : 56 px de barre, texte serré ───────────────────────────── */

.systeme ~ * .navigation a,
.navigation a { font-size: var(--t-corps); }

/* ═══════════════════════════════════════════════════════════════════════════
 * L'ENTRÉE — connexion, lien envoyé, confirmation
 *
 * ⚠️ Ces écrans étaient restés hors du système par une distinction qui ne
 * tenait pas : « écrans sans structure ». Or la structure est parfaitement
 * connue ici — c'est le sous-domaine qui la donne. Seuls le domaine racine et
 * la page « structure inconnue » n'en ont réellement pas.
 *
 * C'est le premier écran qu'un bénévole voit, et longtemps le seul dont il se
 * souviendra. Il portait encore l'ancienne échelle.
 * ═══════════════════════════════════════════════════════════════════════════ */

.systeme.centre {
  display: flex;
  align-items: center;
  justify-content: center;
  /* La barre fait 56 px : on retire sa hauteur pour centrer sur ce qui reste,
     sinon la carte descend d'une demi-barre. */
  min-height: calc(100vh - var(--h-barre) - var(--e-6) * 2);
  padding-top: var(--e-6);
  padding-bottom: var(--e-6);
}

.carte-accueil {
  width: 100%;
  max-width: 25rem;
  padding: var(--e-6) var(--e-5) var(--e-5);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  box-shadow:
    0 1px 2px rgba(10, 10, 10, 0.04),
    0 8px 32px rgba(10, 10, 10, 0.08);
}

.carte-accueil-tete {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--e-1);
  margin-bottom: var(--e-5);
}

/* La couleur du club, en petit et une seule fois : elle dit « vous êtes bien
   chez vous » avant même que le nom soit lu. */
/* ⚠️ LA PASTILLE PORTE L'INITIALE DU CLUB — 17/09/2026. Elle était VIDE :
   un carré rouge de 34 px qui se lit comme une image cassée, sur les trois
   écrans d'entrée. Quand le club a déposé un logo, c'est le logo qui vient à
   sa place — voir `_marque-structure.eta`.

   ⚠️⚠️ ET ELLE PASSE DE L'ACCENT À L'ENCRE. La barre latérale peint DÉJÀ la
   même chose — l'initiale du club quand il n'a pas de logo — et elle la peint
   en encre (`.rail-pastille`). Deux traitements pour un seul objet, dans deux
   écrans qui se suivent. Le gardien « un seul aplat d'accent » a refusé le
   rouge ici, et c'est en cherchant s'il fallait élargir l'exception que
   l'incohérence est apparue : il ne fallait pas l'élargir, il fallait aligner.
   *Une exception qu'on s'apprête à écrire est souvent une divergence qu'on
   n'a pas vue.* */
.carte-accueil-pastille {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--rayon);
  background: var(--encre);
  color: var(--blanc);
  font-size: var(--t-section);
  font-weight: var(--g-noir);
  line-height: 1;
  margin-bottom: var(--e-3);
}

/* Le logo du club, quand il y en a un. Même traitement que dans la barre : le
   fond vient de la clarté MESURÉE de son encre, jamais d'un goût. */
.carte-accueil-logo {
  display: grid;
  place-items: center;
  min-width: 34px;
  height: 34px;
  padding: 0 var(--e-2);
  border-radius: var(--rayon);
  margin-bottom: var(--e-3);
}
.carte-accueil-logo.logo-sur-encre { background: var(--encre); padding: var(--e-1) var(--e-2); }
.carte-accueil-logo img { max-height: 28px; max-width: 132px; object-fit: contain; display: block; }

.carte-accueil h1 { font-size: var(--t-titre); font-weight: var(--g-gras); }
.carte-accueil .chapeau { margin: 0; font-size: var(--t-secondaire); }

.carte-accueil .formulaire { display: flex; flex-direction: column; gap: var(--e-4); }
.carte-accueil .champ { margin-top: 0; }
.carte-accueil .bouton { width: 100%; justify-content: center; }

.carte-accueil-pied {
  margin-top: var(--e-5);
  padding-top: var(--e-4);
  border-top: var(--trait) solid var(--ligne);
  font-size: var(--t-petit);
  line-height: var(--i-petit);
  color: var(--gris);
  text-align: center;
}

/* Les deux écrans qui suivent — lien envoyé, confirmation — partagent la même
   forme sans avoir la carte : ils tiennent en une phrase. */
.systeme.centre > h1,
.systeme.centre > .chapeau,
.systeme.centre > .fiche,
.systeme.centre > .formulaire,
.systeme.centre > p { max-width: 30rem; }

.systeme.centre > * { margin-left: auto; margin-right: auto; }
.systeme.centre { flex-direction: column; text-align: center; }
.systeme.centre .carte-accueil { text-align: left; }
.systeme.centre .fiche { text-align: left; }





/* ═══════════════════════════════════════════════════════════════════════════
 * LA CARTE DE COCKPIT — le motif de Regard AI
 *
 * Relevé dans « components/cockpit/CeoCockpit.tsx », bloc « Business Score » :
 *
 *   Card (rounded-2xl · border-border/60 · p-4 · shadow-card)
 *     ├ en-tête : icône 16 px en accent + titre 12 px gras
 *     ├ corps   : chiffre 40 px font-black à GAUCHE, badge + résumé à DROITE
 *     └ détails : lignes de 10,5 px
 *
 * ⚠️ UN SEUL chiffre est énorme. Les autres restent petits — c'est ce qui le
 * fait ressortir. J'avais agrandi les quatre à la fois, ce qui revenait à n'en
 * grandir aucun.
 *
 * ⚠️ Et une carte de Regard AI commence TOUJOURS par une icône. Le produit
 * n'en avait aucune, nulle part : rien n'aidait à repérer un bloc du regard.
 * ═══════════════════════════════════════════════════════════════════════════ */

.systeme .carte-cockpit {
  margin-top: var(--e-4);
  padding: var(--e-5);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  box-shadow:
    0 1px 2px rgba(10, 10, 10, 0.04),
    0 4px 16px rgba(10, 10, 10, 0.06);
}

/* ─── En-tête : icône + titre ─────────────────────────────────────────── */

.systeme .carte-cockpit-tete {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  /* ⚠️ Les dates se replient sous le titre quand la carte est étroite plutôt
     que de le comprimer : c'est le titre qui dit de quoi il s'agit. */
  flex-wrap: wrap;
  margin-bottom: var(--e-4);
}

/* ⚠️ `margin-top: 0` : `.titre-section` porte une marge de section, et dans
   un en-tête de carte elle décollerait le titre de son icône. Même défaut que
   la `.titre-ligne` du 17/09, au même endroit du raisonnement. */
.systeme .carte-cockpit-tete h2 { margin-top: 0; }

/* La période qualifie le cycle : petite, grise, sur la même ligne que lui. */
.systeme .carte-cockpit-dates {
  font-size: var(--t-petit);
  line-height: var(--i-petit);
  color: var(--gris);
  font-variant-numeric: tabular-nums;
}

.systeme .carte-cockpit-tete svg {
  width: 16px;
  height: 16px;
  flex: none;
  /* L'icône porte la couleur du club — `--accent-lisible` et non `--accent` :
     un accent pâle disparaîtrait sur le blanc de la carte. */
  color: var(--accent-lisible);
}

.systeme .carte-cockpit-tete h2,
.systeme .carte-cockpit-tete h3 {
  font-size: var(--t-secondaire);
  font-weight: var(--g-gras);
  line-height: var(--i-secondaire);
  margin: 0;
}

/* ─── Corps : le chiffre, puis son résumé ─────────────────────────────── */

.systeme .carte-cockpit-corps {
  display: flex;
  align-items: center;
  gap: var(--e-5);
}

/* ⚠️ ALIGNÉ À GAUCHE, PAS CENTRÉ.
   Regard AI centre parce que sa légende — « / 100 » — est plus ÉTROITE que son
   chiffre. La nôtre — « % de l'objectif » — est trois fois plus large : centrée,
   elle débordait des deux côtés et le chiffre ne tenait plus le bord gauche du
   bloc. Reprendre le centrage aurait été copier la forme sans la raison. */
.systeme .score { text-align: left; flex: none; }

.systeme .score-valeur {
  display: block;
  /* ⚠️ OUTFIT, PAS DM MONO.
     Mesuré dans le DOM de Regard AI : son « 39 » est en Outfit 900, jamais en
     mono. Le chiffre géant de regard pro était le SEUL élément du produit à
     s'écrire dans une autre police que le reste de la page — c'était l'écart
     visuel principal avec Regard AI, et je l'avais mis là de moi-même.
     Notre Outfit est une variable plafonnée à 800 : mesuré, 82,05 px de large
     là où Regard AI en fait 83,32. L'écart de graisse est de 1,5 %. */
  font-family: var(--sans);
  font-size: var(--t-score);
  font-weight: var(--g-noir);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

/* ⚠️ LE GRAND CHIFFRE PORTE LE VERDICT — mesuré : `rgb(225, 29, 72)` sur le
   score « fragile » de Regard AI. Ce n'est pas une entorse à la règle « actif
   en noir » : celle-là vise l'ÉTAT DE NAVIGATION, pas un jugement. Ici la
   couleur EST l'information, et elle vient de la palette FIXE à ≥ 6,45:1 —
   jamais de l'accent du club, qui varie et ne veut rien dire. */
.systeme .score-valeur.est-faible { color: var(--etat-retard-texte); }
.systeme .score-valeur.est-moyen  { color: var(--etat-alerte-texte); }
.systeme .score-valeur.est-bon    { color: var(--etat-succes-texte); }

.systeme .score-sur {
  display: block;
  margin-top: 2px;
  font-size: var(--t-micro);
  line-height: var(--i-micro);
  color: var(--gris);
}

.systeme .score-resume { min-width: 0; flex: 1; }

/* Le libellé du cycle prend la forme d'une étiquette d'état — Regard AI met un
   Badge à cet endroit. */
.systeme .etat-cycle {
  display: inline-flex;
  align-items: center;
  padding: 1px 8px;
  border-radius: var(--rayon-plein);
  border: var(--trait) solid var(--etat-info-bord);
  background: var(--etat-info-fond);
  color: var(--etat-info-texte);
  font-size: var(--t-micro);
  font-weight: var(--g-gras);
  line-height: var(--i-micro);
}

.systeme .score-resume p {
  margin-top: var(--e-1);
  font-size: var(--t-petit);
  line-height: var(--i-petit);
  color: var(--gris);
}

.systeme .score-resume strong {
  font-weight: var(--g-gras);
  color: var(--encre);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Les trois autres repères de la saison utilisent le composant `.compteur`.
   Ils avaient d'abord leur propre jeu de règles `.releve-*` — c'est-à-dire le
   MÊME composant sous un second nom, donc deux endroits où il pouvait dériver. */


@media (max-width: 760px) {
  .systeme .carte-cockpit-corps { flex-direction: column; align-items: flex-start; gap: var(--e-3); }
}

/* ─── Inventaire ─────────────────────────────────────────────────────────── */

/* ⚠️⚠️ LA JAUGE EN TROIS SEGMENTS — engagé, réservé, disponible.
   Trois segments et pas un de plus : ils répondent aux trois seuls états
   qu'un stock peut avoir. Aucune animation — DESIGN.md l'interdit, et une
   barre qui bouge attire l'œil sur la ligne qui bouge, pas sur celle qui
   compte.

   ⚠️ LA COULEUR NE PORTE JAMAIS SEULE L'INFORMATION. La jauge est doublée
   d'un « aria-label » et d'un « title » qui disent les mêmes chiffres en
   toutes lettres, et la colonne voisine les répète en texte. Une barre de
   couleur seule ne se lit ni par un lecteur d'écran, ni par qui distingue
   mal le rouge du vert. */
.systeme .jauge {
  display: flex;
  width: 100%;
  min-width: 7rem;
  height: 10px;
  border-radius: var(--rayon-petit, 3px);
  overflow: hidden;
  background: var(--ligne);
}

/* L'accent du club pour l'ENGAGÉ : c'est ce qui est vendu, donc ce dont le
   club est fier. Son voile pour le RÉSERVÉ : même famille, moins d'affirmation
   — une promesse n'est pas une signature. */
.systeme .jauge-engage  { background: var(--couleur-principale); }
.systeme .jauge-reserve { background: var(--voile-accent, var(--champ)); }
.systeme .jauge-libre   { background: transparent; }

/* ⚠️ TROIS CLICS POUR AJUSTER UN STOCK : le champ vit DANS la ligne. Cible de
   40 px comme partout — un pavé numérique se manque sur un téléphone. */
.systeme .stock-en-ligne {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  justify-content: flex-end;
}
.systeme .stock-en-ligne input {
  width: 5rem;
  min-height: var(--h-cible);
  padding: 0 var(--e-2);
  text-align: right;
  font-variant-numeric: tabular-nums;
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
  background: var(--blanc);
  color: var(--encre);
}
.systeme .stock-en-ligne button { min-height: var(--h-cible); }

/* ⚠️ Un libellé lu par les lecteurs d'écran et invisible à l'œil. Chaque champ
   de stock en porte un : « Stock de Panneau bord de terrain ». Sans lui, une
   colonne de champs numériques identiques est indéchiffrable à l'oreille. */
.systeme .visuellement-cache {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ─── Inventaire · les vignettes ─────────────────────────────────────────── */

/* ⚠️ UNE GRILLE QUI SE REMPLIT, JAMAIS UN NOMBRE DE COLONNES FIGÉ.
   « auto-fill » avec une largeur minimale : trois vignettes sur un écran
   large, une sur un téléphone, sans point de rupture à maintenir. Le contenu
   décide, pas une liste de tailles d'écran. */
.systeme .inventaire-grille {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--e-4);
  margin-bottom: var(--e-6);
}

.systeme .carte-actif {
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
  padding: var(--e-4);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
}

/* ⚠️ Un actif COMPLET se signale par un trait, pas par un fond rouge : il n'y
   a rien d'anormal à avoir tout vendu — c'est même le but. Le trait dit
   « celui-ci n'a plus rien », il n'alarme pas. */
.systeme .carte-actif.est-complet { border-color: var(--encre); }

.systeme .carte-actif-nom {
  font-size: var(--t-section);
  font-weight: var(--g-demi);
  line-height: 1.25;
  margin: 0;
}
.systeme .carte-actif-nom a { color: var(--encre); text-decoration: none; }
.systeme .carte-actif-nom a:hover { text-decoration: underline; }

.systeme .carte-actif-meta {
  margin: 0;
  font-size: var(--t-micro);
  font-family: var(--police-mono, monospace);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gris-clair);
}

/* LE CHIFFRE — ce que l'écran répond. Le reste de la vignette l'explique. */
.systeme .carte-actif-chiffre {
  display: flex;
  align-items: baseline;
  gap: var(--e-2);
  margin: var(--e-2) 0 0;
}
.systeme .carte-actif-chiffre .valeur {
  font-size: var(--t-compteur);
  font-weight: var(--g-gras);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.systeme .carte-actif-chiffre .unite { font-size: var(--t-secondaire); color: var(--gris); }

/* ⚠️ Un actif complet garde son chiffre à ZÉRO en encre, pas en rouge. Le
   rouge du produit dit « quelque chose ne va pas » ; ici tout va bien. */
.systeme .carte-actif-detail {
  margin: 0;
  font-size: var(--t-secondaire);
  color: var(--gris);
}

.systeme .carte-actif-argent {
  display: flex;
  justify-content: space-between;
  gap: var(--e-2);
  margin: 0;
  font-size: var(--t-secondaire);
  color: var(--gris);
}
.systeme .carte-actif-argent strong { color: var(--encre); font-variant-numeric: tabular-nums; }

/* Le champ de stock ferme la vignette, aligné à gauche comme le reste. */
.systeme .carte-actif .stock-en-ligne {
  justify-content: flex-start;
  margin-top: var(--e-2);
  padding-top: var(--e-3);
  border-top: var(--trait) solid var(--ligne);
}

/* ─── Inventaire · la fiche et la reprise ────────────────────────────────── */

/* Sur la FICHE, l'ajustement de stock porte un libellé visible : on est venu
   pour comprendre, pas pour corriger — le champ doit se nommer. Sur la liste
   il est nu, entouré du nom de l'actif ; ici il est seul. */
.systeme .stock-fiche {
  justify-content: flex-start;
  margin: var(--e-4) 0 var(--e-6);
  padding-top: var(--e-3);
  border-top: var(--trait) solid var(--ligne);
}
.systeme .stock-fiche label {
  font-size: var(--t-secondaire);
  color: var(--gris);
}

/* ⚠️ LES CHAMPS DE LA REPRISE VIVENT DANS UN TABLEAU, et gardent la cible de
   40 px. Un tableau serré tente de rétrécir ses champs ; un pavé numérique de
   28 px se manque sur un téléphone, et c'est un prix qu'on saisit. */
.systeme .liste input[type="number"] {
  width: 6.5rem;
  min-height: var(--h-cible);
  padding: 0 var(--e-2);
  text-align: right;
  font-variant-numeric: tabular-nums;
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
  background: var(--blanc);
  color: var(--encre);
}
.systeme .liste input[type="checkbox"] {
  width: 20px;
  height: 20px;
  /* La case elle-même ne peut pas faire 40 px sans devenir une tache : c'est
     sa CELLULE qui porte la cible, et le libellé caché la rend cliquable. */
  margin: var(--e-2);
}
.systeme .champ-centimes + .secondaire {
  display: block;
  margin-top: 2px;
}


/* ═══════════════════════════════════════════════════════════════════════════
 * L'ENTRÉE DES ÉCRANS — DESIGN.md § 9 (17/09/2026)
 *
 * Demande de Charles : « je veux que ce soit beaucoup plus dynamique ». Zéro
 * JavaScript, comme partout : `@keyframes` et `animation-delay` suffisent, et
 * ils ne peuvent pas tomber en panne.
 *
 * ⚠️⚠️ LA QUATRIÈME BORNE EST LA PLUS DANGEREUSE À OUBLIER : rien ne commence
 * invisible sans finir visible. `animation-fill-mode: both` pose l'état final
 * dès la fin ; sans lui — ou avec un `opacity: 0` posé en dur en attendant un
 * déclencheur — la moitié de l'écran ne s'afficherait JAMAIS, puisqu'aucun
 * script ne viendrait la réveiller. Un témoin garde ce point.
 * ═══════════════════════════════════════════════════════════════════════════ */

/*
 * ⚠️⚠️ L'ENTRÉE NE PART PAS DE L'INVISIBLE, ET C'EST MESURÉ.
 *
 * Première écriture : `from { opacity: 0 }`. En la vérifiant, j'ai relevé un
 * environnement où l'horloge des animations NE TOURNE PAS — l'onglet du
 * panneau de développement, jamais rendu : `playState: "running"`,
 * `currentTime: 0`, en permanence. L'élément reste alors figé sur son état de
 * DÉPART, et dix-sept blocs de l'écran étaient à `opacity: 0` après 1,5 s.
 *
 * ⚠️ Ce cas-là est bénin — personne ne regarde un onglet qui n'est pas rendu.
 * Ce qu'il prouve n'est pas bénin : **l'état de départ est ce qu'on voit quand
 * quelque chose empêche l'animation de tourner**, et aucune forme sans
 * JavaScript n'est immunisée. `fill-mode`, `backwards`, l'absence de `fill` :
 * toutes appliquent le `from` pendant la phase active.
 *
 * D'où la forme retenue : **le départ est VISIBLE**. 0,4 d'opacité et 12 px de
 * décalage. Le pire cas devient « le texte est pâle et décalé de douze
 * pixels », jamais « l'écran est blanc ». C'est la quatrième borne du § 9,
 * tenue par la construction plutôt que par une promesse.
 *
 * ⚠️ Et je n'ai pas pu regarder cette animation tourner : le panneau ne rend
 * pas son onglet. C'est aussi pour cela que sa forme est la plus prudente des
 * deux — on ne livre pas un effet qu'on n'a pas vu en pariant sur son cas
 * favorable.
 */
@keyframes entree {
  from { opacity: 0.4; transform: translateY(var(--entree-decalage)); }
  to   { opacity: 1; transform: none; }
}

/* Les blocs de premier niveau d'un écran entrent l'un après l'autre. */
.systeme > * {
  animation: entree var(--entree-duree) var(--entree-courbe) both;
}

/*
 * ⚠️ L'ÉCHELONNEMENT S'ARRÊTE AU HUITIÈME. 40 × 8 + 380 = 700 ms : au-delà,
 * quelqu'un attendrait que sa page finisse d'arriver. Les blocs suivants
 * entrent avec le huitième — ils ne sont pas oubliés, ils ne sont pas retardés.
 */
.systeme > *:nth-child(1) { animation-delay: 0ms; }
.systeme > *:nth-child(2) { animation-delay: calc(var(--entree-echelon) * 1); }
.systeme > *:nth-child(3) { animation-delay: calc(var(--entree-echelon) * 2); }
.systeme > *:nth-child(4) { animation-delay: calc(var(--entree-echelon) * 3); }
.systeme > *:nth-child(5) { animation-delay: calc(var(--entree-echelon) * 4); }
.systeme > *:nth-child(6) { animation-delay: calc(var(--entree-echelon) * 5); }
.systeme > *:nth-child(7) { animation-delay: calc(var(--entree-echelon) * 6); }
.systeme > *:nth-child(n + 8) { animation-delay: calc(var(--entree-echelon) * 7); }

/* Les tuiles d'alerte entrent DANS le bandeau, après lui. */
.systeme .entete-jour .alerte-carte {
  animation: entree var(--entree-duree) var(--entree-courbe) both;
}
.systeme .entete-jour .alerte-carte:nth-child(1) { animation-delay: calc(var(--entree-echelon) * 2); }
.systeme .entete-jour .alerte-carte:nth-child(2) { animation-delay: calc(var(--entree-echelon) * 3); }
.systeme .entete-jour .alerte-carte:nth-child(3) { animation-delay: calc(var(--entree-echelon) * 4); }
.systeme .entete-jour .alerte-carte:nth-child(4) { animation-delay: calc(var(--entree-echelon) * 5); }
.systeme .entete-jour .alerte-carte:nth-child(n + 5) { animation-delay: calc(var(--entree-echelon) * 6); }

/*
 * SOUS LA MAIN — 150 ms, et rien que la couleur, l'opacité et l'ombre.
 * ⚠️ La carte ne se SOULÈVE pas : ce serait un déplacement pendant qu'on vise,
 * exactement ce que § 9 continue d'interdire. C'est l'ombre qui monte.
 */
.systeme .alerte-carte { transition: box-shadow var(--duree) var(--courbe); }
.systeme .entete-jour .alerte-carte:hover { box-shadow: var(--ombre-survol); }


/* ═══════════════════════════════════════════════════════════════════════════
 * L'ÉCRAN DU MATIN — DEUX COLONNES (17/09/2026)
 *
 * Demande de Charles sur sa maquette. À gauche ce qu'on vient faire, à droite
 * où en est la saison.
 *
 * ⚠️⚠️ LA BORNE EST DANS LA GRILLE ELLE-MÊME : la colonne des repères est la
 * SECONDE, et elle est plus étroite. La règle « les repères viennent en
 * dernier » existe parce qu'« un chiffre d'affaires en haut de l'écran
 * d'accueil transforme un outil de suivi en tableau de bord de direction ».
 * Elle est tenue : le bandeau reste premier, le travail garde la colonne
 * large, les repères se posent À CÔTÉ — jamais au-dessus.
 * ═══════════════════════════════════════════════════════════════════════════ */

.systeme .deux-colonnes-jour {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--e-6);
  align-items: start;
  margin-top: var(--e-6);
}
/* ⚠️ `minmax(0, …)` et non `2fr` seul : une piste de grille a une taille
   minimale AUTOMATIQUE, et un tableau large la pousse au lieu de défiler.
   C'est la même mécanique que l'effondrement à 0 px, prise par l'autre bout. */

.systeme .colonne-travail > :first-child,
.systeme .colonne-reperes > :first-child { margin-top: 0; }

/* La colonne des repères se lit comme un aparté : un filet la sépare du
   travail, elle ne porte ni fond ni ombre qui la mettrait au même rang. */
.systeme .colonne-reperes {
  display: flex;
  flex-direction: column;
  gap: var(--e-5);
  padding-left: var(--e-6);
  border-left: var(--trait) solid var(--ligne);
}

/*
 * ⚠️⚠️ LE SEUIL EST MESURÉ, PAS CHOISI — ET LE PREMIER ÉTAIT FAUX.
 *
 * Posé d'abord à 1100 px « au jugé ». La sonde du 16/09 — les pixels de
 * contenu qui ne tiennent pas, colonne par colonne — a montré que la seconde
 * colonne RÉINTRODUISAIT le défaut corrigé la veille, dans une bande de
 * largeurs :
 *
 *     1200 px   131 px manquants      1320 px    10 px
 *     1280 px    32 px manquants      1360 px     0
 *
 * Le déficit s'annule à 1360 et ne revient pas. Le seuil est donc porté à
 * 1400 : la valeur mesurée, plus une marge — parce que le déficit dépend de la
 * LONGUEUR DU CONTENU (noms de partenaires, libellés d'action) et que je n'ai
 * mesuré qu'un club. Un club aux libellés plus longs franchirait 1360.
 *
 * Sous ce seuil, la colonne repasse dessous dans l'ordre d'origine : l'écran
 * du matin redevient exactement ce qu'il était.
 */
@media (max-width: 1399px) {
  .systeme .deux-colonnes-jour { grid-template-columns: minmax(0, 1fr); }
  .systeme .colonne-reperes {
    padding-left: 0;
    border-left: 0;
    border-top: var(--trait) solid var(--ligne);
    padding-top: var(--e-5);
  }
}

/* ───────────────────────────────────────────────────────────────────────────
 * L'ACTION EN BOUT DE LIGNE — 17/09/2026
 *
 * La maquette pose de vrais boutons au bout de chaque ligne. Le produit y
 * mettait un lien-bouton discret, qu'on ne voyait pas.
 *
 * ⚠️ IL RESTE SECONDAIRE, et ce n'est pas un détail : DESIGN.md § 7.1 dit
 * « un seul bouton plein par écran ». Celui-ci est bordé, pas plein — sinon
 * huit lignes donneraient huit actions principales, et plus rien ne
 * ressortirait. C'est le défaut du 09/09, pris par un autre bout.
 * ─────────────────────────────────────────────────────────────────────────── */
.systeme .liste td.actions button.discret {
  padding: 0 var(--e-4);
  height: var(--h-bouton-m);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon);
  background: var(--blanc);
  color: var(--encre);
  font-size: var(--t-petit);
  font-weight: var(--g-demi);
  white-space: nowrap;
  transition: border-color var(--duree) var(--courbe),
              background var(--duree) var(--courbe);
}
.systeme .liste td.actions button.discret:hover {
  border-color: var(--gris);
  background: var(--sourdine);
}

/* ═══════════════════════════════════════════════════════════════════════════
 * L'ANATOMIE D'UNE LIGNE — 17/09/2026, TROISIÈME PASSE SUR LA MAQUETTE
 *
 * Charles, après deux livraisons : « ça ne ressemble toujours pas assez à ça ».
 * Il avait raison les trois fois, et à chaque fois pour une raison différente :
 *
 *   1ʳᵉ passe — j'ai lu « pas le bleu » comme « pas d'aplat saturé ». Teinte et
 *               saturation sont deux décisions ; il n'en avait écarté qu'une.
 *   2ᵉ  passe — j'ai livré la COMPOSITION (deux colonnes, bandeau porteur) en
 *               croyant que c'était ce qui manquait.
 *   3ᵉ  passe — c'est la MATIÈRE. La composition était juste ; ce qui ne
 *               ressemblait pas, c'étaient les rayons, les reliefs, les
 *               pastilles, les voyants. On reconnaît une interface à sa peau
 *               avant de reconnaître son plan.
 *
 * Ce bloc porte la peau d'une LIGNE. La maquette n'a pas un tableau, elle a des
 * lignes composées : une pastille ronde, un nom, une méta-ligne avec un point
 * de couleur, puis les actions en pastilles à droite.
 *
 * ⚠️ CE QU'ON NE LUI PREND PAS, ET C'EST ÉCRIT POUR QU'ON NE REVIENNE PAS
 * DESSUS : ses lignes portent chacune un BOUTON PLEIN bleu. Huit lignes, huit
 * actions principales — plus aucune n'est principale. La règle « un seul bouton
 * plein par écran » (DESIGN.md § 7.1) tient, et nos boutons de ligne restent
 * bordés. C'est la seule chose que je refuse de copier pour des raisons de
 * produit, et non de mesure.
 * ═══════════════════════════════════════════════════════════════════════════ */

/*
 * LE COMPTEUR DU TITRE DE SECTION.
 *
 * La maquette pose un carré sombre arrondi portant le nombre, AVANT le titre
 * (« 38 · Prochains départs »). Ce n'est pas un ornement : il répond à « combien
 * en ai-je ? » avant même qu'on ait lu de quoi il s'agit.
 *
 * ⚠️ CHIFFRE EN MONO, comme tout chiffre du produit. Deux sections empilées
 * alignent alors leurs compteurs.
 */
.systeme .compteur-section {
  display: inline-grid;
  place-items: center;
  min-width: 28px;
  height: 28px;
  padding: 0 7px;
  margin-right: var(--e-3);
  border-radius: var(--rayon-petit);
  background: var(--encre);
  color: var(--blanc);
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: var(--g-noir);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  vertical-align: middle;
}

/*
 * L'ÉTIQUETTE D'ÉTAT, À DROITE DU TITRE.
 *
 * La maquette met « ACTION REQUISE » en pastille claire au bout de son en-tête.
 *
 * ⚠️⚠️ ELLE NE S'AFFICHE QUE SI ELLE EST VRAIE. Une étiquette permanente qui
 * dit « action requise » ne dit plus rien au bout d'une semaine — c'est la
 * définition d'un champ creux, appliquée à un état. Elle porte le nombre de
 * lignes EN RETARD, et disparaît quand il n'y en a aucune.
 *
 * ⚠️ Elle prend la palette « retard » du § 2.3, PAS l'accent : le rouge du
 * produit ne porte aucun état sémantique (DESIGN.md § 2.4).
 */
.systeme .etiquette-section {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  padding: 5px 12px;
  border-radius: var(--rayon-plein);
  background: var(--etat-retard-fond, var(--sourdine));
  color: var(--etat-retard-texte, var(--encre));
  font-size: var(--t-micro);
  font-weight: var(--g-gras);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}

/*
 * LA PASTILLE D'INITIALE, EN TÊTE DE LIGNE.
 *
 * ⚠️ `aria-hidden` : le nom est écrit juste à côté. Sans cela un lecteur
 * d'écran annoncerait « C. Charpentes Vidal ».
 *
 * ⚠️ FOND SOURDINE, PAS ACCENT. Une pastille rouge par ligne ferait huit
 * aplats d'accent sur l'écran — exactement ce que la borne n° 1 du § 2.4
 * interdit. La maquette a des photos ; nous avons des entreprises, qui n'en
 * ont pas.
 */
.systeme .liste .pastille-ligne {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: var(--rayon-plein);
  background: var(--sourdine);
  color: var(--gris);
  font-size: var(--t-petit);
  font-weight: var(--g-noir);
  line-height: 1;
  text-transform: uppercase;
}

/* La cellule principale devient une ligne : pastille à gauche, textes à droite. */
.systeme .liste td.principal .bloc-ligne {
  display: flex;
  align-items: center;
  gap: var(--e-3);
}
.systeme .liste td.principal .bloc-ligne > span:last-child { min-width: 0; }

/*
 * LE VOYANT D'ÉCHÉANCE.
 *
 * La maquette pose un point de couleur devant chaque méta-ligne
 * (« ● Signal détecté »). Ici il précède l'échéance.
 *
 * ⚠️⚠️ IL DOUBLE LE TEXTE, IL NE LE REMPLACE JAMAIS. « en retard depuis le 13/09 »
 * reste écrit en toutes lettres à côté. C'est la règle du produit — l'information
 * n'est jamais portée par la seule couleur — et elle vaut aussi pour un point de
 * 7 px, que 8 % des hommes ne distinguent pas du vert voisin.
 */
.systeme .liste .voyant-echeance {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: var(--e-2);
  border-radius: var(--rayon-plein);
  background: currentColor;
  vertical-align: 1px;
}

/*
 * ⚠️ LA MARGE DE SECTION APPARTIENT À LA LIGNE, PAS AU TITRE.
 *
 * `.titre-section` porte `margin-top: var(--e-6)`. Dans une `.titre-ligne`,
 * cette marge ne pousse QUE le titre : l'étiquette voisine, elle, reste calée
 * en haut du conteneur et flotte 32 px au-dessus du texte qu'elle qualifie.
 *
 * On reporte donc la marge sur la ligne et on l'annule sur le titre qu'elle
 * contient. Rien ne bouge pour un `.titre-section` employé seul.
 *
 * ⚠️ C'est le même genre de défaut que la règle téléphone du 16/09, écrite dans
 * un `@media` antérieur et donc inerte : une valeur posée au bon endroit dans
 * l'absolu, mais au mauvais endroit pour ce qu'elle doit gouverner.
 */
.systeme .titre-ligne:has(> .titre-section) {
  margin-top: var(--e-6);
  align-items: center;
}
.systeme .titre-ligne > .titre-section { margin-top: 0; }

/* ═══════════════════════════════════════════════════════════════════════════
 * L'EN-TÊTE DE PAGE — 17/09/2026, QUATRIÈME PASSE, CHOIX DE CHARLES
 *
 * Après trois lectures fautives, je lui ai demandé ce qui restait le plus loin
 * de sa maquette. Il a désigné DEUX choses : le fond de page, et CECI.
 *
 * Sa maquette pose une rangée de pastilles en haut à droite du titre
 * (« Faire une démo », « 29 crédits », « Prospection active ● »). Chez nous ce
 * coin était VIDE sur les quinze écrans : le titre à gauche, puis rien.
 *
 * ⚠️⚠️ CE QUE LES PASTILLES PORTENT EST VRAI, ET C'EST TOUTE LA DIFFÉRENCE.
 * Celles de la maquette sont pour partie du décor commercial (« 29 crédits »).
 * Recopier la FORME en inventant un contenu serait fabriquer des champs creux
 * en série — et « un champ creux finit par être cru ». Les nôtres portent deux
 * choses que le produit sait déjà et qu'il montrait mal :
 *
 *   — LE CYCLE EN COURS. Tout s'y rattache — contrats, actifs, contreparties —
 *     et il ne se lisait qu'au tiers inférieur de la colonne de droite. Un club
 *     dont deux cycles se chevauchent doit savoir dans lequel il travaille.
 *   — LA CONFORMITÉ. Elle n'est pas ajoutée ici, elle est DÉPLACÉE : elle
 *     vivait en bas de la colonne de droite. Son motif écrit est « un voyant
 *     qu'on croise tous les matins alerte mieux qu'un onglet qu'on n'ouvre
 *     qu'en janvier » — il est mieux servi en haut qu'en bas.
 *
 * ⚠️ DÉPLACÉE, PAS DUPLIQUÉE. Deux voyants de conformité sur un écran, c'est
 * deux endroits où l'un peut dire autre chose que l'autre.
 * ═══════════════════════════════════════════════════════════════════════════ */

.systeme .entete-page {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--e-5);
  flex-wrap: wrap;
}
/* Le bloc titre garde la mesure de lecture ; les pastilles prennent le reste. */
.systeme .entete-page-titre { flex: 1 1 22rem; min-width: 0; }
.systeme .entete-page-titre h1 { margin: 0; }

.systeme .entete-actions {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  flex-wrap: wrap;
  /* ⚠️ Alignées sur la PREMIÈRE ligne du titre, pas sur son haut : un titre de
     44 px qui passe sur deux lignes laisserait sinon les pastilles flotter. */
  margin-top: 6px;
}

/*
 * LA PASTILLE D'EN-TÊTE.
 *
 * ⚠️ FOND BLANC ET FILET, jamais un aplat d'accent : § 2.4, borne n° 1 — le
 * bandeau est le SEUL aplat d'accent de l'écran, et une pastille rouge en haut
 * à droite lui ferait concurrence sur la même ligne de regard.
 */
.systeme .pastille-entete {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  height: var(--h-bouton-m);
  padding: 0 14px;
  border-radius: var(--rayon-plein);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  box-shadow: var(--ombre-carte);
  font-size: var(--t-secondaire);
  font-weight: var(--g-demi);
  color: var(--encre);
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--duree) var(--courbe);
}
.systeme a.pastille-entete:hover { border-color: var(--gris); }
.systeme a.pastille-entete:focus-visible {
  outline: var(--trait-fort) solid var(--accent);
  outline-offset: 2px;
}
.systeme .pastille-entete svg { width: 14px; height: 14px; flex: none; color: var(--gris); }

/*
 * LE VOYANT DE LA PASTILLE.
 *
 * ⚠️⚠️ IL DOUBLE LE TEXTE, IL NE LE REMPLACE JAMAIS. « Conformité » et son
 * verdict sont écrits à côté. C'est la règle du produit — l'information n'est
 * jamais portée par la seule couleur — et elle vaut d'autant plus ici que le
 * vert et le rouge sont les deux états.
 */
.systeme .pastille-voyant {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: var(--rayon-plein);
  background: currentColor;
}
.systeme .pastille-entete.est-ok      .pastille-voyant { color: var(--etat-succes-texte); }
.systeme .pastille-entete.est-attente .pastille-voyant { color: var(--etat-retard-texte); }

/*
 * LE PIED DE LA CARTE DE SAISON — 19/09/2026.
 *
 * Les portes de ce que la carte résume : les cycles, l'équipe. Elles vivaient
 * AU-DESSUS d'elle, dans une rangée de petits liens qui suivait un titre de
 * section — soit deux registres de plus dans une colonne qui en comptait
 * quatre avant d'arriver à son contenu.
 *
 * ⚠️ Un filet les sépare du corps : sans lui, les liens se lisent comme la
 * suite du dernier compteur au lieu d'une sortie de la carte.
 */
.systeme .carte-cockpit-pied {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-4);
  margin-top: var(--e-4);
  padding-top: var(--e-4);
  border-top: var(--trait) solid var(--ligne);
}

/*
 * LA CARTE DE L'ÉCRAN DU MATIN — 19/09/2026.
 *
 * Elle enveloppe l'en-tête « À faire », sa note et le tableau, pour que la
 * colonne de gauche soit UN objet — comme celle de droite depuis le même jour.
 * Deux colonnes côte à côte qui ne se composent pas pareil se lisent comme
 * deux écrans.
 *
 * ⚠️⚠️ SA PORTÉE EST ÉTROITE, ET C'EST TOUT L'INTÉRÊT. `.liste` est partagée
 * par DIX-HUIT gabarits : lui retirer sa bordure et son rayon les toucherait
 * tous pour un besoin qui n'existe qu'ici. Les règles ci-dessous n'agissent
 * qu'à l'intérieur de `.carte-travail`.
 */
.systeme .carte-travail {
  margin-top: var(--e-6);
  padding: var(--e-5);
  background: var(--blanc);
  border: var(--trait) solid var(--ligne);
  border-radius: var(--rayon-grand);
  box-shadow: var(--ombre-carte);
}

/* Le titre n'a plus à pousser une section : il ouvre une carte. */
.systeme .carte-travail > .titre-ligne { margin-top: 0; }

/*
 * ⚠️ LE TABLEAU EST APLATI DANS LA CARTE, PAS AILLEURS. Une carte dans une
 * carte donne deux bordures parallèles à 16 px d'écart — le défaut qu'on
 * reconnaît immédiatement sans savoir le nommer.
 */
.systeme .carte-travail .liste {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  /* Le tableau s'étend jusqu'aux bords intérieurs de la carte : un filet de
     séparation qui s'arrête avant le bord se lit comme une erreur. */
  width: calc(100% + var(--e-5) * 2);
  margin-left: calc(var(--e-5) * -1);
  margin-right: calc(var(--e-5) * -1);
}
/* ⚠️ …mais les CELLULES gardent le retrait, sinon le texte touche le bord. */
.systeme .carte-travail .liste th:first-child,
.systeme .carte-travail .liste td:first-child { padding-left: var(--e-5); }
.systeme .carte-travail .liste th:last-child,
.systeme .carte-travail .liste td:last-child { padding-right: var(--e-5); }

/* La note de bas de tableau reste dans la carte, sous le dernier filet. */
.systeme .carte-travail .note-basse { margin-bottom: 0; }
