/*
 * DiaMap Web — socle de style commun.
 *
 * Pourquoi ce fichier existe : chaque écran redéfinissait ses boutons, ses
 * tableaux et ses témoins d'enregistrement, avec des valeurs légèrement
 * différentes — trois bleus, deux rayons d'angle, deux tailles de libellé
 * pour la même chose. Rien ne cassait, mais l'application donnait
 * l'impression d'avoir été assemblée par plusieurs mains.
 *
 * Règle : tout ce qui apparaît sur DEUX écrans ou plus vit ici. Une règle
 * propre à un écran reste dans son gabarit — la déplacer ici la rendrait
 * fragile pour les autres.
 *
 * ---------------------------------------------------------------------
 * D101 — le vocabulaire vient de DiaMap CRM V2 (07/08/2026).
 *
 * Consigne de Jean-Pascal : « utilise systématiquement les templates de
 * CRM quand je ne te dis rien ». Ce n'est pas une préférence esthétique :
 * les deux produits sont la même suite, vus par les mêmes personnes, et
 * une carte qui ne se dessine pas pareil d'un produit à l'autre se
 * re-apprend à chaque fois.
 *
 * Concrètement, les VARIABLES portent désormais les noms du CRM
 * (`--bg-card`, `--text-muted`, `--radius`, `--badge-*`…), si bien qu'un
 * gabarit repris du CRM s'affiche ici sans retouche. Les anciens noms
 * français restent, en alias : les huit écrans existants s'en servent, et
 * les renommer d'un coup aurait mélangé deux chantiers.
 *
 * **Ce qui change à l'œil** : les couleurs d'état, les rayons d'angle et
 * l'ombre des cartes sont ceux du CRM ; le bleu de DiaMap Web devient
 * l'accent, là où le CRM utilise son doré. On garde donc l'identité de ce
 * produit avec la grammaire de l'autre.
 */

:root {
  /* ================================================================
     LA GRILLE TYPOGRAPHIQUE — D1, arbitrée par Jean-Pascal 09/08/2026.

     SIX tailles, là où l'application en comptait TRENTE-QUATRE pour
     quinze écrans. Parmi les anciennes : 0,60 · 0,62 · 0,63 · 0,65 rem
     — quatre valeurs qu'aucun œil ne distingue, et qui ne servaient
     qu'à empêcher deux écrans de se ressembler.

     RIEN SOUS 1 REM. C'est la règle qui compte le plus : 101 des
     228 déclarations relevées étaient sous 13 px. « Le texte est
     souvent petit » — le constat était mesurable.

     Un rapport d'environ 1,2 entre deux tailles voisines. L'œil perçoit
     une hiérarchie quand les écarts sont réguliers ; il ne perçoit rien
     entre 0,78 et 0,80.
     ================================================================ */

  /* ================================================================
     TROIS TAILLES, ET TROIS SEULEMENT — D197, 10/08/2026.

     Demande de Jean-Pascal : « une passe sur TOUTE l'application pour
     avoir du texte avec une taille standard — titre : grande ;
     indicateur, libellé de carte : moyen ; commentaire : petit ».

     **Ce qui n'allait pas.** Six jetons, et une hiérarchie CASSÉE :
     `--t-chiffre`, censé porter « le chiffre qu'on vient lire », valait
     1,20 rem — plus PETIT que `--t-titre` (1,44) et ÉGAL à `--t-texte`.
     Quelqu'un avait mis l'échelle à plat sans la refaire, et l'écart
     entre un titre et un commentaire ne se voyait plus.

     **Les trois rôles.** Le nombre d'un bandeau compte comme un TITRE :
     c'est ce qu'on vient lire, et un cockpit dont les chiffres ont la
     taille des libellés cesse d'être lisible. Son LIBELLÉ, lui, est un
     indicateur.

     Les trois anciens noms restent, en ALIAS. Les remplacer partout
     toucherait des centaines de lignes, et un oubli passerait inaperçu :
     un alias, lui, ne peut pas diverger.
     ================================================================ */
  --t-grande: 1.40rem;     /* TITRE d'écran, de section, et chiffre d'un bandeau */
  --t-moyenne: 1.05rem;    /* INDICATEUR, libellé de carte, en-tête, corps */
  --t-petite: 0.92rem;     /* COMMENTAIRE, note, mention, source */

  /* LES DEUX FAMILLES DE CARACTÈRES (D215, 11/08/2026).

     Une pour le TEXTE, une pour les TITRES — et pas une de plus. Le serif
     vient de la maquette M06, validée : il donne aux titres un poids que la
     graisse seule ne donnait pas, sans les grossir.

     **Nommées ici, jamais écrites en clair ailleurs.** Une famille recopiée
     dans un gabarit, c'est la police de l'application décidée écran par
     écran — exactement ce que les tailles ont vécu avant D201.

     Aucune police n'est CHARGÉE : ni fichier, ni requête réseau. Les deux
     listes ne contiennent que des familles présentes sur les systèmes.
     Charger une fonte demanderait de la servir, de gérer son cache et son
     rendu pendant le chargement — pour un écran de travail, ce n'est pas le
     bon prix. */
  --police: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --police-titre: Georgia, "Iowan Old Style", "Times New Roman", serif;
  /* Pour un CODE seulement, où l'alignement des caractères porte du sens. */
  --police-code: ui-monospace, Menlo, Consolas, monospace;

  /* La hauteur du bandeau d'atelier (D206). Écrite ici parce que la boîte
     de commandes posée sur la carte doit se placer JUSTE EN DESSOUS : deux
     valeurs qui doivent rester égales n'en font qu'une. */
  --h-bandeau-atelier: 3rem;

  /* Les anciens noms, désormais alias — aucune valeur propre. */
  --t-chiffre: var(--t-grande);
  --t-titre: var(--t-grande);
  --t-section: var(--t-grande);
  --t-texte: var(--t-moyenne);
  --t-libelle: var(--t-moyenne);
  --t-note: var(--t-petite);

  /* ---- Les jetons du CRM, sous leurs noms d'origine ---- */
  --bg-page: #f1f3f3;
  --bg-card: #ffffff;
  --text: #16233f;
  --text-muted: #5b6472;
  --text-faint: #8b93a1;
  --border: #dde2e6;

  /* L'accent. Le CRM y met son doré ; DiaMap Web garde son bleu, qui
     porte déjà l'identité des cartes et des zones de chalandise. */
  --accent: #0e4c7c;
  --accent-soft: #e6f1fb;

  /* Les états, repris tels quels du CRM : ce sont les mêmes situations
     dans les deux produits, elles doivent avoir la même couleur. */
  --haute: #2f7d5a;      --haute-bg: #e6f1eb;
  --moyenne: #c97c1f;    --moyenne-bg: #fbeedc;
  --basse: #a33b3b;      --basse-bg: #f7e7e7;
  --tres-haute: #b3261e; --tres-haute-bg: #fbdada;
  --info: #185fa5;       --info-bg: #e6f1fb;

  --primary: #0e4c7c;
  --primary-hover: #0b3d63;
  --primary-light: var(--accent-soft);
  --vert-bg: var(--haute-bg);    --vert-text: var(--haute);
  --rouge-bg: var(--basse-bg);   --rouge-text: var(--basse);
  --ambre-bg: var(--moyenne-bg); --ambre-text: var(--moyenne);
  --gris-bg: #eef0f2;            --gris-text: var(--text-muted);
  --tres-haute-text: var(--tres-haute);

  --radius: 10px;
  --shadow-card: 0 1px 3px rgba(22, 35, 63, 0.06), 0 1px 2px rgba(22, 35, 63, .05);

  /* ---- Les anciens noms, en ALIAS ----
     Les huit écrans existants s'en servent. Les renommer d'un coup aurait
     mélangé deux chantiers : on les fait pointer sur les jetons du CRM, et
     ils s'éteindront d'eux-mêmes au fil des reprises d'écran. */
  --bleu: var(--primary);
  --bleu-fonce: var(--primary-hover);
  --ardoise: #33415c;
  --encre: var(--text);
  --texte-doux: var(--text-muted);
  --texte-discret: var(--text-faint);
  --fond: var(--bg-page);
  --blanc: var(--bg-card);
  --trait: var(--border);
  --trait-clair: #e6eaee;
  --survol: var(--gris-bg);

  /* États. Le vert et le rouge ne servent QU'À ça : un vert décoratif
     ailleurs rendrait le vert de succès illisible. */
  --succes: var(--vert-text);
  --succes-fond: var(--vert-bg);
  --succes-trait: #bcd9c9;
  --alerte: var(--ambre-text);
  --alerte-fond: var(--ambre-bg);
  --alerte-trait: #eed4ab;
  --danger: var(--rouge-text);
  --danger-fond: var(--rouge-bg);
  --danger-trait: #e3c4c4;

  /* Zones de chalandise — les mêmes trois couleurs partout : légende de
     carte, pastilles du formulaire de zonage, en-têtes du tableau. C'est
     ce qui relie un chiffre à ce qu'on voit sur la carte. */
  --zone-proximite: #dc2626;
  --zone-combat: #f97316;
  --zone-complementaire: #facc15;

  /* Formes */
  --rayon: var(--radius);
  --rayon-petit: 8px;
  --ombre: var(--shadow-card);
}

/* ---------- La carte, brique de base du CRM ----------
   Tout ce qui est un objet — un flux d'import, une source à géocoder, un
   outil d'administration — se pose sur une carte. Huit écrans en
   redéfinissaient une version légèrement différente. */
.card, .carte-admin {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 1.25rem 1.5rem;
  margin: 1rem 0;
}

/* ---------- Pastilles d'état ----------
   Reprises du CRM avec leurs noms : `badge-vert`, `badge-ambre`… Un même
   état porte ainsi la même couleur dans les deux produits. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.18rem 0.6rem;
  border-radius: 100px;
  font-size: var(--t-note);
  font-weight: 500;
  white-space: nowrap;
}
.badge-vert { background: var(--vert-bg); color: var(--vert-text); }
.badge-rouge { background: var(--rouge-bg); color: var(--rouge-text); }
.badge-ambre { background: var(--ambre-bg); color: var(--ambre-text); }
.badge-gris { background: var(--gris-bg); color: var(--gris-text); }
.badge-bleu { background: var(--info-bg); color: var(--info); }

/* ---------- État vide ----------
   Remplace le « Aucun X » nu. Un écran qui ne dit rien quand il n'a rien
   se lit comme un écran cassé. */
.etat-vide {
  text-align: center;
  padding: 2.25rem 1.25rem;
  color: var(--text-faint);
  background: var(--bg-card);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  margin: 1rem 0;
}
.etat-vide p { margin: 0; font-size: var(--t-note); }
.etat-vide .etat-vide-action { margin-top: 0.75rem; }

/* ---------- Boutons ----------
   Un bouton d'action dangereuse est DISCRET à texte rouge, jamais rouge
   plein : un bouton massif attire le clic, et on veut l'inverse. */
.bouton {
  display: inline-block;
  background: var(--bleu);
  color: var(--blanc);
  border: 1px solid var(--bleu);
  border-radius: var(--rayon-petit);
  padding: 0.3rem 0.75rem;
  font-size: var(--t-note);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.bouton:hover { background: var(--bleu-fonce); }
.bouton-discret { background: var(--blanc); color: var(--ardoise); border-color: var(--trait); }
.bouton-discret:hover { background: var(--survol); }
.bouton-danger { background: var(--blanc); color: var(--danger); border-color: var(--danger-trait); }
.bouton-danger:hover { background: var(--danger-fond); border-color: var(--danger); }
.bouton-inactif { background: var(--survol); color: #9aa7b8; border-color: var(--trait-clair); cursor: not-allowed; }

/* ---------- Témoin d'enregistrement champ par champ ----------
   Succès ÉPHÉMÈRE, erreur PERSISTANTE. Le succès s'efface au bout de 4 s ;
   l'erreur reste tant que le champ n'est pas corrigé, sans quoi elle
   disparaîtrait avant d'être lue. */
.champ-auto-etat { font-size: var(--t-note); font-weight: 400; margin-left: 0.4rem; }
.champ-ok { color: var(--succes); animation: champ-disparait 4s ease forwards; }
.champ-erreur { color: var(--danger); font-weight: 600; }
@keyframes champ-disparait { 0%, 60% { opacity: 1; } 100% { opacity: 0; } }

/* ---------- Bandeau d'état ----------
   Sert aussi bien à l'état de santé de l'administration qu'à la portée
   d'une modification : même objet visuel, même code couleur. */
.sante { border-radius: var(--rayon); padding: 0.7rem 0.95rem; margin-bottom: 1.2rem; border: 1px solid; }
.sante-ok { background: var(--succes-fond); border-color: var(--succes-trait); }
.sante-alerte { background: var(--alerte-fond); border-color: var(--alerte-trait); }
.sante-bloquant { background: var(--danger-fond); border-color: var(--danger-trait); }
.sante h3 { margin: 0 0 0.35rem; font-size: var(--t-note); }
.sante ul { margin: 0; padding-left: 1.1rem; }
.sante li { margin-bottom: 0.35rem; font-size: var(--t-note); }
.sante .constat-titre { font-weight: 700; }
.sante .constat-action { color: var(--texte-doux); font-style: italic; }
.manque { color: var(--alerte); }

/* ---------- Paires libellé / valeur ----------
   Libellé AU-DESSUS de la valeur : les valeurs s'alignent alors entre
   elles, ce que « Enseigne : bidule » sur une ligne ne permet pas. */
.fiche-entete { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 0.75rem; background: var(--ardoise); border-radius: var(--rayon); padding: 0.55rem 0.9rem; margin-bottom: 0.75rem; }
.fiche-champ { min-width: 0; }
.fiche-champ-label { display: block; font-size: var(--t-note); text-transform: uppercase; letter-spacing: 0.06em; color: #c8d2de; }
.fiche-champ-valeur { display: block; font-size: var(--t-note); font-weight: 700; color: var(--blanc); overflow-wrap: anywhere; }

/* ---------- Tableau de données ---------- */
.table-admin { width: 100%; border-collapse: collapse; font-size: var(--t-note); background: var(--blanc); }
.table-admin th { text-align: left; background: var(--ardoise); color: var(--blanc); font-size: var(--t-note); text-transform: uppercase; letter-spacing: 0.05em; padding: 0.35rem 0.6rem; }
.table-admin td { padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--trait-clair); }
.table-admin tr:hover td { background: #f6f8fb; }

/* Les colonnes de chiffres, PARTOUT (07/08/2026 : « aligne tous les
   tableaux »).
   
   L'en-tête était à gauche et les valeurs à droite : sur trois colonnes de
   chiffres côte à côte, plus rien ne tombe en face, et l'œil doit recompter
   les colonnes pour savoir ce qu'il lit.
   
   `tabular-nums` fixe la largeur des chiffres : sans lui, 111 est plus
   étroit que 999 et la colonne tremble d'une ligne à l'autre.
   
   La règle vient APRÈS `.table-admin th` : à spécificité égale, c'est la
   dernière qui l'emporte. */
th.nombre, td.nombre,
table th.nombre, table td.nombre { text-align: right; font-variant-numeric: tabular-nums; }

/* UN IDENTIFIANT SE CALE À GAUCHE — règle posée le 13/08/2026.
   « cale tous les ident par défaut à gauche pour éviter les pb »

   **Un identifiant ressemble à un nombre sans en être un.** `96176HA`,
   `80021`, `C0198342` : le premier réflexe est de le ranger dans la colonne
   des chiffres, à droite et en chasse tabulaire. C'est faux pour deux
   raisons.

   D'abord parce qu'aligner à droite invite à COMPARER des grandeurs, et
   qu'un identifiant ne se compare pas : `80021` n'est ni plus grand ni plus
   petit que `96176HA`, il est autre.

   Ensuite parce que la question qu'on se pose devant une colonne
   d'identifiants est « lequel commence par 8002… ? » — et c'est le DÉBUT
   qu'on lit. À droite, les débuts ne s'alignent plus.

   *Le même raisonnement a produit le passage de `id_referentiel` en texte le
   13/08/2026 : ce champ était un `BigIntegerField`, et Géodata émet
   `96176HA`.* Le type et l'alignement disent la même chose — **un identifiant
   n'est pas un nombre**, et le traiter comme tel casse tôt ou tard. */
th.ident, td.ident, .ident {
  text-align: left;
  font-variant-numeric: normal;
  font-family: var(--police-code);
  white-space: nowrap;
}

/* ---------- Sections et cartes ---------- */
/* D222 (11/08/2026) — LE CHAPEAU D'UN ÉCRAN PREND LA LARGEUR.

   Il était borné à 60 caractères. C'est la bonne mesure pour du texte SUIVI,
   celui qu'on lit ligne après ligne — mais un chapeau d'écran se parcourt
   une fois, puis on descend au contenu. Borné, il tombait sur quatre ou cinq
   lignes étroites dans le coin d'une page de 1 800 px, et se lisait comme
   une colonne ratée : « des titres sont lus dans un coin ».

   La règle des 70 caractères n'est pas abandonnée, elle est rendue à son
   objet : `.texte-suivi`, pour l'aide et les notes longues. */
.page-sous-titre { margin: 0 0 1.1rem; color: var(--texte-doux); }
.texte-suivi { max-width: 70ch; }
.section-admin { margin-bottom: 1.6rem; scroll-margin-top: 1rem; }
.section-admin-titre { margin: 0 0 0.15rem; font-size: var(--t-libelle); color: #1e293b; }
.section-admin-sous-titre { margin: 0 0 0.7rem; font-size: var(--t-note); color: var(--texte-discret); }
/* `auto-fit` et non `auto-fill` (D217) : `auto-fill` CRÉE des colonnes vides
   quand il reste de la place et laisse les cartes à 290 px, serrées à gauche.
   Sur l'Administration, en 1 800 px de large, cela faisait six colonnes pour
   deux cartes — « plein de place à droite » inutilisée. `auto-fit` replie les
   colonnes vides et répartit ce qui existe. */
.grille-cartes { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 0.9rem; }
.carte-admin { background: var(--blanc); border: 1px solid var(--trait); border-radius: var(--rayon); padding: 0.85rem 1rem; display: flex; flex-direction: column; }
/* `:only-child` — et le sélecteur EST le raisonnement, 12/08/2026.
   Vu à l'écran sous `consultant.multi` : D260 ne lui laisse qu'un thème, et
   sa carte unique s'étirait sur 1 800 px, bouton perdu à gauche d'un aplat.
   Mesuré en corrigeant : borner TOUTES les cartes à 30rem creuse le mal
   ailleurs — chez le super admin, les colonnes font 892 px et les cartes
   bornées à 514 laissaient 378 px de vide dans chacune. Et borner la COLONNE
   (`minmax(290px, 30rem)`) est déjà interdit par
   `test_les_grilles_de_cartes_repartissent_au_lieu_de_reserver` : le
   navigateur compte alors les colonnes sur leur maximum et n'en crée que deux.
   Une carte SEULE n'a personne avec qui répartir : c'est le seul cas, et le
   sélecteur ne dit rien de plus. */
.grille-cartes > .carte-admin:only-child { max-width: 30rem; }
.carte-admin h4 { margin: 0 0 0.1rem; font-size: var(--t-note); color: #1e293b; }
.carte-admin .chiffre { font-size: var(--t-note); color: var(--texte-discret); text-transform: uppercase; letter-spacing: 0.05em; }
.carte-admin .meta { margin: 0.4rem 0 0.8rem; font-size: var(--t-note); color: var(--texte-doux); flex: 1; }
.carte-admin .bouton { align-self: flex-start; }

/* Badge de profil (D174) : le rôle d'un utilisateur, à côté de son email. */
.liste-comptes li { margin: 0.15rem 0; }
.badge-profil { display: inline-block; font-size: var(--t-petite); font-weight: 600;
  background: var(--accent-soft); color: var(--accent); border-radius: 999px;
  padding: 0.03rem 0.5rem; margin-left: 0.25rem; vertical-align: 0.05em; }

/* Bascule (segmented control) — un choix EXCLUSIF entre deux options, façon
   CRM (D173). Réutilisable : Phase 2 en aura besoin pour les profils. */
.bascule { display: inline-flex; background: var(--gris-bg); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px; gap: 2px; max-width: 100%; }
.bascule-opt { border: 0; background: transparent; color: var(--text-muted);
  font: inherit; font-size: var(--t-note); font-weight: 600; padding: 0.4rem 1rem;
  border-radius: 999px; cursor: pointer; white-space: nowrap; transition: background .12s, color .12s; }
.bascule-opt.actif { background: var(--accent); color: #fff; box-shadow: var(--shadow-card); }
.bascule-opt:not(.actif):hover { color: var(--text); }

/* Aperçu live du filtre Géodata (D166) : une bande discrète sous la grille. */
.apercu-geodata { margin: 0.9rem 0 0; padding: 0.55rem 0.8rem; font-size: var(--t-note);
  color: var(--texte-doux); background: #f1f5f9; border: 1px solid var(--trait);
  border-radius: var(--rayon); }
.apercu-geodata strong { color: #1e293b; }
.apercu-geodata .apercu-detail { color: var(--texte-discret); }

/* ---------- Aide de champ ---------- */
.aide-champ { margin: 0.45rem 0 0; font-size: var(--t-note); color: var(--texte-discret); font-style: italic; }

/* ---------- Fil d'Ariane ---------- */
.admin-entete { display: flex; align-items: baseline; gap: 0.8rem; flex-wrap: wrap; margin-bottom: 0.2rem; }
.admin-entete h2 { margin: 0; }
.admin-fil { font-size: var(--t-note); color: var(--texte-discret); }
.admin-fil a { color: var(--bleu); }
/* Sommaire d'ancres : sur une page longue, on saute au thème voulu plutôt
   que de la parcourir. */
.admin-sommaire { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1.3rem; }
.admin-sommaire a { font-size: var(--t-note); background: var(--survol); border: 1px solid #dbe3ec; border-radius: 999px; padding: 0.2rem 0.7rem; color: var(--ardoise); text-decoration: none; }
.admin-sommaire a:hover { background: #dbe3ec; }

/* ---------- Pastille de zone ----------
   Reprend exactement les couleurs de la carte : c'est ce qui relie un
   champ ou une ligne de tableau à ce que l'on voit. */
.pastille { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 0.3rem; }
.pastille-proximite { background: var(--zone-proximite); }
.pastille-combat { background: var(--zone-combat); }
.pastille-complementaire { background: var(--zone-complementaire); }

/* ---------- Aide (D46) ----------
   Même grammaire visuelle que l'administration : l'aide était la seule
   page à utiliser des `fieldset`, ce qui donnait deux styles pour une même
   application. */
.carte-aide { background: var(--blanc); border: 1px solid var(--trait); border-radius: var(--rayon); padding: 0.9rem 1.1rem; }
.carte-aide details { margin-top: 0.5rem; }
.carte-aide summary { cursor: pointer; font-size: var(--t-note); color: var(--bleu); }
.carte-aide summary:hover { text-decoration: underline; }
.carte-aide details p { font-size: var(--t-note); color: var(--texte-doux); }

/* ---------- Largeur des pages (D58, D89) ----------
   Une liste d'exceptions vivait ici : les pages faites de grilles
   s'élargissaient, les autres non. Elle se périmait à chaque nouvel écran,
   et l'oubli ne se voyait que sur une capture — l'import refondu ne
   s'élargissait pas parce que sa grille n'était pas dans la liste
   (07/08/2026).
   Depuis le 08/08/2026, `base.html` déclare 1440 px pour tout le monde et
   plus personne ne le redéfinit. Il n'y a donc plus rien à tenir à jour.

   Le texte suivi reste borné séparément (`.page-sous-titre`, 60ch) : c'est
   le CONTENANT qui est large, pas la ligne de lecture. */

/* ---------- Cases à cocher ----------
   La règle globale `input { width: 100%; max-width: 26rem }` visait les
   champs de saisie ; appliquée aux cases, elle leur donnait 26 rem de
   large et les envoyait à des centaines de pixels de leur libellé, qui
   partait alors à la ligne (constaté sur l'écran de l'infobulle, 06/08).

   Une case se dimensionne toute seule, et se lit COLLÉE à son texte. */
input[type="checkbox"], input[type="radio"] {
  width: auto;
  max-width: none;
  margin: 0;
  flex: none;
}
/* Libellé porteur d'une case : la case et le texte sur une ligne, alignés
   sur la première ligne du texte et non sur son milieu — sinon un libellé
   de deux lignes décale la case vers le bas. */
.ligne-case {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
  font-weight: 400;
  max-width: 70ch;
}
.ligne-case strong { font-weight: 700; }

/* Onglets de l'aide (D71) — l'aide et le dictionnaire de données.
   Dans le socle et non dans une page : ils apparaissent sur les deux, et
   c'est la règle du fichier (ce qui sert deux écrans vit ici). */
.onglets-aide { display: flex; gap: 0.25rem; border-bottom: 1px solid #d9dee3; margin: 0 0 1.25rem; }
.onglets-aide .onglet { display: inline-block; padding: 0.45rem 1rem; border: 1px solid transparent; border-bottom: none; border-radius: 6px 6px 0 0; color: var(--bleu); text-decoration: none; font-weight: 600; font-size: var(--t-note); margin-bottom: -1px; }
.onglets-aide a.onglet:hover { background: #eef2f7; }
/* L'onglet courant est un <span> : un lien vers la page où l'on est déjà
   promet un déplacement qui n'aura pas lieu. */
.onglets-aide .onglet.actif { background: #fff; border-color: #d9dee3; border-bottom-color: #fff; color: var(--encre); cursor: default; }

/* Messages de l'administration. Ils n'étaient rendus nulle part : un
   `messages.error` y disparaissait sans trace, et l'écran répondait
   normalement. Une panne se dit. */
.messages-admin { margin: 0 0 1rem; }
.message-admin { margin: 0 0 0.4rem; padding: 0.55rem 0.9rem; border-radius: 6px; border: 1px solid; }
.message-admin.erreur { background: #fef2f2; border-color: #fca5a5; color: #991b1b; }
.message-admin.champ-ok { background: #f0fdf4; border-color: #86c99a; color: #14532d; }


/* D90 — les actions s'alignent d'une carte à l'autre.
   -------------------------------------------------------------------------
   Les textes n'ont pas la même longueur : sans colonne flexible ni
   `margin-top: auto`, le bouton descend plus ou moins bas selon la carte et
   la rangée paraît désordonnée. C'est le genre de détail qui ne se répare
   pas carte par carte — il se répare ici, une fois. */
.grille-cartes { align-items: stretch; }
.grille-cartes > * { display: flex; flex-direction: column; }
/* Le corps du texte pousse l'action vers le bas ; l'action s'y accroche. */
.grille-cartes .carte-texte, .grille-cartes > * > p { flex: 1 1 auto; }
.grille-cartes .carte-action { margin-top: auto; align-self: flex-start; }

/* La navigation entre phases (D102, 07/08/2026).
   -------------------------------------------------------------------------
   Dans la feuille COMMUNE et non dans chaque écran : trois pages la
   partagent, et une barre recopiée finit toujours par diverger — c'est
   exactement ce qui s'est passé avec les largeurs de page (D89). */
.navigation-phase { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin: 2rem 0 0; padding-top: 1rem; border-top: 1px solid #d9dee3; }
.navigation-phase .cotes { display: flex; align-items: center; gap: 0.5rem; flex: 1 1 auto; }
.navigation-phase a { display: inline-flex; align-items: baseline; gap: 0.35rem; padding: 0.4rem 0.85rem; border: 1px solid #c8d6e5; border-radius: 6px; color: #0e4c7c; text-decoration: none; font-size: var(--t-note); }
.navigation-phase a:hover { background: #eef2f7; border-color: #0e4c7c; text-decoration: none; }
.navigation-phase .numero { font-weight: 600; }
.navigation-phase .titre { color: #55637a; }
.navigation-phase .vide { flex: 0 0 auto; }
/* La suite est le geste attendu : elle est pleine, les autres en contour. */
.navigation-phase .suivante { margin-left: auto; background: #0e4c7c; border-color: #0e4c7c; color: #fff; }
.navigation-phase .suivante:hover { background: #0b3d63; }
.navigation-phase .suivante .titre { color: #d6e4f0; }
/* La sortie change de CONTEXTE, elle ne navigue pas entre phases : elle est
   donc séparée et discrète. La confondre avec les phases ferait croire
   qu'elle en est une. */
.navigation-phase .sortie { border-style: dashed; color: #55637a; }

/* La sortie vers la solution, depuis l'administration (D102). */
.sortie-solution { margin: 2.5rem 0 0; padding-top: 1rem; border-top: 1px solid #d9dee3; }
.sortie-solution a { display: inline-flex; padding: 0.4rem 0.85rem; border: 1px dashed #c8d6e5; border-radius: 6px; color: #55637a; text-decoration: none; font-size: var(--t-note); }
.sortie-solution a:hover { background: #eef2f7; border-color: #0e4c7c; color: #0e4c7c; text-decoration: none; }

/* --- D200 : le bandeau d'alerte de l'administration, REPLIÉ par défaut ----
   Il occupait le haut de l'écran et repoussait les thèmes — ce qu'on vient
   faire — sous la ligne de flottaison. Replié, il annonce toujours COMBIEN
   de points attendent : c'est ce qui manquait au CRM (§12.2), on ne le perd
   pas. Le détail se déplie d'un clic. */
.sante-repliable { padding: 0.55rem 0.9rem; }
.sante-repliable > summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; gap: 0.6rem; }
.sante-repliable > summary::-webkit-details-marker { display: none; }
.sante-repliable > summary::before { content: "▸"; color: var(--texte-doux); }
.sante-repliable[open] > summary::before { content: "▾"; }
.sante-repliable .sante-deplier { font-size: var(--t-petite); color: var(--texte-doux); }
.sante-repliable[open] .sante-deplier { visibility: hidden; }
.sante-repliable > ul { margin: 0.6rem 0 0; }


/* ------------------------------------------------------------------ D201
   L'HABILLAGE DE LA CARTE SUIT LA MÊME GRILLE QUE LE RESTE.

   MapLibre livre sa propre feuille de style, avec ses propres tailles :
   l'échelle en 10 px, l'attribution en 12 px, l'infobulle au gré du
   navigateur. Sur un écran d'étude, la moitié droite parlait donc une
   autre langue typographique que la moitié gauche — c'est exactement ce
   qui se remarque sans qu'on sache le nommer.

   L'échelle, l'attribution et le crédit sont des MENTIONS : petite. Le
   contenu d'une infobulle est du texte courant : moyenne.

   Écrit ici plutôt que dans la feuille du fournisseur : celle-ci est du
   code livré, qu'une mise à jour écraserait sans prévenir. */
/* D222 : la FAMILLE en plus de la taille. MapLibre écrit `font: 12px/20px
   Helvetica Neue, …` — un raccourci qui pose la police ET la taille d'un
   coup. Surcharger `font-size` seul laissait donc une TROISIÈME police vivre
   sur les trois écrans qui portent une carte : la bibliothèque, la fiche
   d'étude et les zones contractuelles.

   Trouvé en mesurant les huit écrans un par un, pas en relisant le CSS —
   c'est exactement ce que la règle A52 demande. */
.maplibregl-map,
.maplibregl-ctrl-scale,
.maplibregl-ctrl-attrib,
.maplibregl-ctrl-attrib-inner,
.maplibregl-ctrl-attrib a,
.maplibregl-popup-content { font-family: var(--police); }
.maplibregl-ctrl-scale,
.maplibregl-ctrl-attrib,
.maplibregl-ctrl-attrib-inner,
.maplibregl-ctrl-attrib a { font-size: var(--t-petite); }
.maplibregl-popup-content { font-size: var(--t-moyenne); }


/* ------------------------------------------------------------------ D207
   LE MENU D'ÉTAT D'UNE ÉTUDE — un seul habillage, deux écrans.

   Le composant (`etudes/_menu_etat.html`) est inclus sur la FICHE et sur la
   LISTE. Son style était recopié dans les deux gabarits, à l'identique. Deux
   copies ne tiennent que jusqu'à la première correction — celle-ci, D207,
   aurait été faite d'un côté seulement.

   **Le volet est en `position: fixed`, et c'est le correctif.** En
   `absolute`, il vivait dans la cellule du tableau et se faisait découper
   trois fois : par `td.actions` (`overflow: hidden`, qui coupe les libellés
   d'enseigne trop longs), par `.tableau-scroll` (`overflow-x: auto`) et par
   `.tableau-cadre` (`overflow: hidden`, qui donne au tableau ses coins
   arrondis). Mesuré à l'écran le 11/08/2026 : 204 px de volet, 28 px
   visibles — un mince bandeau blanc, d'où « quand on clique sur Brouillon on
   voit pas la liste, blanc ».

   Aucune de ces trois règles n'est fautive : chacune sert. C'est
   l'empilement qui découpe, et `fixed` est ce qui en sort — un élément fixe
   se place par rapport à la fenêtre, pas par rapport à ses parents.

   Ses coordonnées sont posées à l'ouverture, depuis le bouton (voir le
   gabarit). Le menu se referme au défilement : rouvrir coûte un clic, un
   volet resté en l'air à côté de sa ligne se lit comme un défaut. */
.menu-etat { position: relative; display: inline-block; }
.menu-etat-declencheur { margin: 0; padding: 0.3rem 0.7rem; font-size: var(--t-petite); font-weight: 600; background: #fff; color: #0e4c7c; border: 1px solid #c8d2de; border-radius: 8px; cursor: pointer; white-space: nowrap; }
.menu-etat-declencheur:hover { border-color: #0e4c7c; background: #eef4fb; }
.menu-etat-declencheur .chevron { color: #8b98a8; }
.menu-etat-volet { position: fixed; z-index: 60; min-width: 17rem; max-width: 24rem; background: #fff; border: 1px solid #c8d2de; border-radius: 8px; box-shadow: 0 4px 14px rgba(16,42,67,.14); padding: 0.3rem; text-align: left; }
.menu-etat-volet form { margin: 0; }
.etat-choix { display: block; width: 100%; text-align: left; padding: 0.4rem 0.6rem; border: 0; border-radius: 6px; background: none; font: inherit; font-size: var(--t-petite); font-weight: 600; color: #1a2233; cursor: pointer; margin: 0; }
button.etat-choix:hover { background: #e6f1fb; }
.etat-choix.engageant { color: #6d4bb5; }
button.etat-choix.engageant:hover { background: #efe9fb; }
/* L'état IMPOSSIBLE reste VISIBLE, grisé, avec sa raison sous le libellé.
   C'est ce qui remplace le silence d'un bouton absent (D191). */
.etat-choix.impossible { color: #9aa4b2; cursor: default; font-weight: 600; }
.etat-choix.impossible.courant { color: #0e4c7c; background: #eef4fb; }
.etat-choix .raison { display: block; font-style: normal; font-weight: 400; font-size: var(--t-petite); color: #8b98a8; margin-top: 0.1rem; }


/* ------------------------------------------------------------------ D206
   LE BANDEAU D'ATELIER — un seul gabarit, deux bandeaux.

   Sur l'écran d'une étude, deux bandeaux se font face en haut : au CENTRE
   l'état de l'étude et sa validation, à DROITE la légende de la carte et ses
   commandes. Ils commencent à la même hauteur — à 1 px près — et c'est
   justement ce qui rendait leur différence criante.

   Mesuré le 11/08/2026 : 51 px de haut contre 37, police 16,8 contre 14,72,
   marges 8/11 contre 6/12, bordures #dbe2ea contre #c8d2de. Six écarts pour
   deux objets qui font la même chose : porter l'état et les commandes de ce
   qu'on regarde. La ligne du haut de l'écran paraissait cassée en deux.

   D'où UN gabarit, ici, appliqué aux deux — et non deux réglages qui se
   ressemblent.

   **La taille est la PETITE de la grille**, et le choix se mesure. Essayée
   en moyenne d'abord — « libellé de carte → moyenne » —, la barre de la
   carte passait à DEUX lignes : huit groupes de commandes (trois couleurs de
   zone, deux calques, trois boutons) ne tiennent pas sur 796 px. L'écart de
   hauteur passait de 14 px à 19, l'inverse de ce qu'on corrigeait.

   Petite est d'ailleurs ce que ces bandeaux disaient déjà à l'intérieur : le
   badge d'état, le libellé de validation et les boutons secondaires étaient
   tous en petite. Seule la BOÎTE prétendait le contraire. Un bandeau de
   commandes est de l'habillage, pas du contenu — la moyenne reste pour ce
   qu'on vient lire, les indicateurs et le nom d'une carte thématique.

   La hauteur est posée en `min-height` plutôt que `height` : une fenêtre
   étroite fait passer les commandes à la ligne, et un bandeau à hauteur fixe
   les couperait. Sa valeur — 3 rem — est celle que le bandeau central
   atteint DÉJÀ par son contenu, le bouton du menu d'état étant plus haut
   que les boutons de la carte. On aligne donc le plus court sur le plus
   grand, plutôt que d'imposer une hauteur qu'aucun des deux n'aurait. */
.bandeau-atelier {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.6rem; row-gap: 0.35rem;
  min-height: var(--h-bandeau-atelier);
  padding: 0.45rem 0.75rem;
  background: #fff;
  border-color: #c8d2de;
  font-size: var(--t-petite);
  color: #1a2233;
  box-sizing: border-box;
}


/* ------------------------------------------------------------------ D210
   LE BADGE D'ÉTAT — il se lit, et c'est lui qu'on clique.

   Il y avait trois objets par ligne pour une seule question : un badge
   « BROUILLON » dans la colonne ÉTAT, un bouton bleu portant le MÊME mot
   juste à côté, et « Archiver ». L'état s'écrivait deux fois, la ligne
   débordait de l'écran, et le bouton foncé se lisait comme l'action
   principale alors qu'il ne fait qu'ouvrir un menu.

   Un seul objet désormais, à l'endroit où l'on cherche l'état. On lit et on
   agit au même endroit — et « Archiver » est entré dans le menu, où il a
   toujours eu sa place : ranger une étude est la fin de sa vie, pas une
   action d'un autre genre. */
/* LE BADGE D'ÉTAT EST UNE INFORMATION (M08) — il ne se clique plus.
   Largeur FIXE : « Brouillon » et « Zone contractuelle » n'ont pas la même
   longueur, et sans elle la colonne dansait d'une ligne à l'autre. Une SEULE
   règle : la version M08 était d'abord venue s'ajouter en fin de fichier, et
   le badge se réglait alors à deux endroits — exactement la divergence qu'on
   corrige partout ailleurs. */
.wf-etat { display: inline-block; width: 10.5rem; text-align: center; font-size: var(--t-petite); font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.16rem 0.55rem; border-radius: 999px; white-space: nowrap; }
.wf-brouillon { background: #eef1f6; color: #475569; }
.wf-soumise { background: #fbf1de; color: #b6791d; }
.wf-validee { background: #e7f2ec; color: #2f7d5a; }
.wf-contractee { background: #efe9fb; color: #6d4bb5; }
/* D337 (M26) : les étapes de VIE — projet (bleu), affaire conclue (vert),
   abandon (rouge, l'historique qu'on garde). Palette de la maquette M26. */
.wf-projet { background: #e8f0fe; color: #0e4c7c; }
.wf-conclue { background: #e7f2ec; color: #2f7d5a; }
.wf-abandonnee { background: var(--danger-fond); color: var(--danger); }
/* Le badge devenu bouton : il garde EXACTEMENT l'aspect du badge, sinon on
   ne le reconnaît plus. Seul le chevron dit qu'il s'ouvre. */


/* ------------------------------------------------------------------ D217
   LES WIDGETS DÉPLAÇABLES ET MASQUABLES — formalisme repris du CRM.

   « Widget, ça doit se replier en bas — regarde le CRM ; tu vas maintenant te
   fier au formalisme du CRM. »

   **Masquer ne replie pas sur place : le widget DESCEND.** Il rejoint une
   barre « Widgets masqués » créée sous la grille, en puce cliquable qui le
   rétablit. C'est la différence avec un `<details>` refermé, qui laisse un
   en-tête vide occuper la place de ce qu'on veut voir — le tableau de bord ne
   se recomposait pas, il se trouait.

   La mécanique vit dans `static/js/widgets-deplacables.js`, repris tel quel
   du CRM : deux implémentations d'un même geste divergent au premier
   correctif, et l'utilisateur qui passe d'une solution à l'autre réapprend un
   geste qu'il connaît déjà.

   Les VALEURS, elles, sont les nôtres : les tailles viennent de la grille des
   trois tailles, les couleurs des jetons DiaMap. Reprendre le formalisme
   n'est pas importer une seconde charte. */
.widget-controles { display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0; margin-left: auto; }
.widget-poignee { cursor: grab; color: #8b98a8; font-size: var(--t-moyenne); user-select: none; }
.widget-poignee:active { cursor: grabbing; }
.widget-masquer { background: none; border: none; cursor: pointer; color: #8b98a8; font-size: var(--t-moyenne); line-height: 1; padding: 0 0.1rem; margin: 0; }
.widget-masquer:hover { color: #a33b3b; }
.widget-deplacable.en-cours-glisser { opacity: 0.4; }
.widget-deplacable.widget-masque { display: none; }

/* La barre où les widgets masqués descendent. En pointillé : c'est une zone
   de rangement, pas un bloc de contenu — la bordure le dit avant qu'on lise. */
.widgets-masques-barre {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
  margin-top: 1rem; padding: 0.6rem 0.9rem;
  border: 1px dashed #c8d2de; border-radius: 12px; background: #fff;
  font-size: var(--t-petite); color: #55637a;
}
.chip-widget-masque {
  background: #e6f1fb; border: 1px solid transparent; border-radius: 999px;
  padding: 0.2rem 0.75rem; font-size: var(--t-petite); color: #0e4c7c;
  cursor: pointer; margin: 0; font-weight: 600;
}
.chip-widget-masque:hover { border-color: #0e4c7c; }

/* L'en-tête d'un widget : le titre à gauche, les commandes à droite. Une
   seule règle pour l'accueil, l'Administration et l'Aide — trois écrans, un
   geste (D217). */
.widget-entete { display: flex; align-items: flex-start; gap: 0.6rem; }
.widget-entete > :first-child { margin-top: 0; }


/* ------------------------------------------------------------------ D218
   LES ONGLETS DE VUE — formalisme du CRM (Liste / Pipeline / Carte).

   Trois vues sur les MÊMES données. Un bouton isolé « Voir sur la carte » ne
   disait ni qu'il existait une troisième vue, ni laquelle on regardait.

   Dans la feuille commune parce que trois écrans les portent : les recopier
   serait la même divergence que pour le menu d'état (D207). */
.onglets-vue { display: flex; gap: 0.3rem; border-bottom: 1px solid #c8d2de; margin: 0.8rem 0 1rem; flex-wrap: wrap; }
.onglets-vue a { padding: 0.45rem 0.9rem; text-decoration: none; color: #55637a; font-weight: 600; border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap; }
.onglets-vue a:hover { color: #0e4c7c; }
.onglets-vue a.actif { color: #0e4c7c; border-bottom-color: #0e4c7c; }
.onglets-vue .compte { font-variant-numeric: tabular-nums; color: #8b98a8; font-weight: 700; margin-left: 0.3rem; }


/* ------------------------------------------------------------------ D218
   LE FIL D'ARIANE — un seul habillage, sous un seul nom.

   Il en existait TROIS, identiques au caractère près : `.liste-ariane`,
   `.biblio-ariane` et `.fil`, recopiés dans trois gabarits. Trois noms pour
   un même objet, c'est trois endroits à corriger et deux qu'on oubliera.

   Il dit d'où l'on vient, et c'est ce qui manquait quand les onglets
   passaient devant lui : on savait où l'on était, plus comment y revenir.
   L'ordre est le même sur les trois vues — fil, titre, onglets. */
.fil-ariane { font-size: var(--t-petite); color: #55637a; margin: 0 0 0.6rem; }
.fil-ariane a { color: #0e4c7c; font-weight: 600; text-decoration: none; }
.fil-ariane a:hover { text-decoration: underline; }
.fil-ariane .ici { color: #1a2233; font-weight: 700; }


/* ------------------------------------------------------------------ D221
   L'EN-TÊTE DES TROIS VUES SUR LES ÉTUDES.

   Trois écrans montrent les MÊMES études, et chacun s'annonçait autrement :
   « Liste des études d'implantation », « Études d'implantation »,
   « Bibliothèque ». Trois titres pour un seul objet, et l'on croit changer
   de sujet en changeant d'onglet — alors qu'on change de point de vue.

   Un seul en-tête (`etudes/_entete_vues.html`), un seul habillage ici. */
.entete-vues { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin: 0 0 0.2rem; }
.entete-vues h1 { margin: 0 0 0.15rem; }
.entete-vues .nouvelle { background: #0e4c7c; color: #fff; text-decoration: none; font-weight: 700; padding: 0.5rem 1.05rem; border-radius: 10px; white-space: nowrap; }
.entete-vues .nouvelle:hover { background: #0b3d63; }


/* ------------------------------------------------------------------ M08
   LE MENU D'ACTIONS D'UNE ÉTUDE — formalisme du CRM, validé le 11/08/2026.

   **L'état se LIT, les gestes se FONT — et pas au même endroit.**

   Le composant précédent faisait du badge d'état le déclencheur du menu
   (D210 — « le badge d'état est la commande »). C'était mon idée, et elle
   était fausse : un objet qui informe ET commande fait hésiter à chaque
   ligne. Les gestes restants s'alignaient à côté, de longueurs différentes,
   si bien que la fin de ligne n'était jamais au même endroit.

   Le CRM sépare : le statut est un badge qu'on ne clique pas, et tout ce
   qu'on peut faire vit derrière un « ⋯ » à place fixe. C'est ce qui donne au
   tableau un bord droit.

   Le volet est en `position: fixed` — les `overflow` du tableau le
   découperaient sinon (D207 : 204 px de volet, 28 px visibles). */
.menu-actions { position: relative; display: inline-block; }
.menu-actions-declencheur {
  margin: 0; padding: 0.35rem 0.75rem; line-height: 1;
  border: 1px solid #c8d2de; border-radius: 8px; background: #fff;
  color: #55637a; font-weight: 700; font-size: var(--t-moyenne);
  cursor: pointer;
}
.menu-actions-declencheur:hover { border-color: #0e4c7c; color: #0e4c7c; }
.menu-actions-declencheur[aria-expanded="true"] { background: #eef1f6; border-color: #55637a; }
.menu-actions-volet {
  position: fixed; z-index: 60; min-width: 19rem; max-width: 26rem;
  background: #fff; border: 1px solid #c8d2de; border-radius: 10px;
  box-shadow: 0 6px 20px rgba(16,42,67,.16); padding: 0.3rem; text-align: left;
  /* D226 : `position: fixed` change le PLACEMENT, pas l'HÉRITAGE. Le volet
     reste enfant de `td.actions`, qui porte `white-space: nowrap` pour
     empêcher ses boutons de passer à la ligne — et cette règle traversait le
     menu. La plus longue raison demandait 569 px dans une case de 416 :
     « Une zone contractuelle ne s'archive pas : archivez la zone, qui fermera
     le p… », coupée net.

     Trouvé en CLIQUANT dans la vraie application (A55) : un rendu figé ne
     l'aurait pas montré, il fallait ouvrir le menu d'une étude contractée. */
  white-space: normal;
}
.menu-actions-volet form { margin: 0; }
.menu-actions-volet hr { border: 0; border-top: 1px solid #eef2f7; margin: 0.25rem 0.3rem; }
.menu-titre { font-size: var(--t-petite); font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: #8b98a8; padding: 0.4rem 0.6rem 0.2rem; }
.menu-actions-volet .action {
  display: block; width: 100%; text-align: left; margin: 0;
  padding: 0.4rem 0.6rem; border: 0; border-radius: 6px; background: none;
  font: inherit; font-size: var(--t-petite); font-weight: 600; color: #1a2233;
  text-decoration: none; cursor: pointer;
}
a.menu-actions-volet .action:hover, .menu-actions-volet a.action:hover,
.menu-actions-volet button.action:hover { background: #e6f1fb; }
.menu-actions-volet .action.engageant { color: #6d4bb5; }
.menu-actions-volet button.action.engageant:hover { background: #efe9fb; }
/* Ce qui n'est PAS possible reste visible, grisé, AVEC sa raison (A24) :
   un bouton absent ne dit rien, et l'on cherche ce qu'on a mal fait. */
.menu-actions-volet .action.impossible { color: #9aa4b2; cursor: default; }
.menu-actions-volet .action.impossible:hover { background: none; }
.menu-actions-volet .raison { display: block; font-style: normal; font-weight: 400; font-size: var(--t-petite); color: #8b98a8; margin-top: 0.1rem; }



/* ------------------------------------------------------------------ D225
   L'ÉCRAN « RIEN À MONTRER » — un seul nom, un seul habillage.

   Il s'appelait `.vide`, et ce nom servait à CINQ choses différentes dans
   cinq gabarits : ce cadre en pointillés, un message « aucune donnée » en
   italique sur l'accueil, un espaceur dans le fil des étapes, une source
   sans valeur sur l'écran de géocodage.

   Le jour où la liste des études a marqué ses CA manquants d'un
   `class="ca vide"`, ces cellules ont hérité du cadre : un filet pointillé
   vertical apparaissait autour de la colonne « CA estimé », mais seulement
   sur les lignes sans montant. Aucune règle n'était fautive ; c'est le NOM
   qui l'était.

   Deuxième fois que ce mécanisme se paie — après `.pastille`, qui existait
   déjà en légende de carte et que les chips de filtre ont percuté.

   Le style vivait par ailleurs en double, recopié à l'identique dans la
   liste et dans la bibliothèque. Il est ici, une fois. */
.ecran-vide { background: #fff; border: 1px dashed #b9c4d1; border-radius: 8px; padding: 2rem 1.5rem; text-align: center; color: #55637a; }
.ecran-vide p { margin: 0.35rem 0; }


/* ------------------------------------------------------------------- A12
   LA PASTILLE « DÉMONSTRATION ».

   Ambre plutôt que rouge : ce n'est pas une alerte, c'est un contexte. Elle
   doit se remarquer sans crier, parce qu'on la côtoie toute la journée en
   recette.

   **Ici et non dans le `nav` de `base.html`** (11/08/2026) : la première
   version l'avait écrite `nav .pastille-demo`. Elle s'affichait donc dans la
   barre du haut, et NULLE PART AILLEURS — la même pastille, posée sur la
   carte du client dans l'administration, y apparaissait en texte nu. Un
   style enfermé dans un sélecteur de contexte ne suit pas son composant. */
.pastille-demo { display: inline-block; background: #fdf1dc; color: #6b4a13;
  border: 1px solid #c99a4a; border-radius: 999px; padding: 0.05rem 0.5rem;
  font-size: var(--t-petite); font-weight: 600; letter-spacing: .02em;
  white-space: nowrap; }

/* ------------------------------------------------------------------- A16
   LE FILTRE PAR ENSEIGNE (lot 7, 11/08/2026).

   Posé au-dessus des onglets de vue, et dans le même esprit : des liens
   qu'on parcourt du regard, celui qui est actif portant le contraste. Il
   n'apparaît que si le compte porte plusieurs enseignes — un client
   mono-enseigne garde exactement l'écran qu'il avait (D248). */
.filtre-enseigne { display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.5rem; margin: 0 0 0.6rem; }
.filtre-enseigne .filtre-titre { font-size: var(--t-petite); color: #7a8699;
  font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.filtre-enseigne a { padding: 0.15rem 0.7rem; border: 1px solid var(--trait);
  border-radius: 999px; color: var(--encre); text-decoration: none;
  font-size: var(--t-petite); background: var(--blanc); }
.filtre-enseigne a:hover { border-color: #b9c4d1; }
.filtre-enseigne a.actif { background: var(--bleu); border-color: var(--bleu);
  color: #fff; font-weight: 600; }

/* ---- ADM-05 · Concurrence d'une enseigne (M18, 12/08/2026) --------------
   Un flux vertical d'étapes numérotées, à la place de quatre panneaux côte à
   côte. Mesuré avant de refondre : deux panneaux de même hauteur portaient 2
   cases (172 px chacune) et 16 cases (21 px chacune) — la place était
   distribuée à l'envers, et la liste des types défilait pour cette raison. */
.etape-reglage { border:1px solid var(--trait); border-radius: var(--rayon);
  padding: 0.85rem 1rem; margin: 0.55rem 0; background: var(--blanc); }
.etape-reglage > h4 { margin: 0 0 0.15rem; font-size: var(--t-note); color: #1e293b; }
.etape-reglage > .meta { margin: 0 0 0.7rem; font-size: var(--t-note);
  color: var(--texte-doux); }
.rang-reglage { display: inline-flex; align-items: center; justify-content: center;
  width: 1.45rem; height: 1.45rem; border-radius: 999px; background: var(--bleu);
  color: #fff; font-size: var(--t-petite); font-weight: 700; margin-right: 0.45rem;
  vertical-align: 0.05rem; }

/* L'avertissement qui évite de fausser toutes les études d'un client. Il était
   en italique gris SOUS une boîte à défilement — invisible à qui il vise. */
.garde-reglage { background: #fdf1dc; border: 1px solid #c99a4a; color: #6b4a13;
  border-radius: 8px; padding: 0.55rem 0.85rem; margin: 0.7rem 0 0;
  font-size: var(--t-note); }

.bascule-precision { font-size: var(--t-petite); opacity: 0.85; margin-left: 0.3rem; }

/* Les deux rôles, côte à côte. Ils REMPLACENT le panneau « Tables Géodata » :
   ses deux cases étaient exactement ces deux rôles. */
.deux-roles { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem;
  margin-top: 0.9rem; }
@media (max-width: 820px) { .deux-roles { grid-template-columns: 1fr; } }
.role-concurrence > h5 { margin: 0 0 0.1rem; font-size: var(--t-note);
  color: #1e293b; font-weight: 600; }
.role-concurrence > .meta { margin: 0 0 0.5rem; font-size: var(--t-note);
  color: var(--texte-doux); }

/* Deux colonnes de cases : les seize catégories tiennent à l'écran, sans
   ascenseur. C'est le défaut principal que M18 corrige — on voyait UN type
   coché sur les quatre annoncés. */
.cases-types { display: grid; grid-template-columns: 1fr 1fr; gap: 0.05rem 0.8rem; }
@media (max-width: 1100px) { .cases-types { grid-template-columns: 1fr; } }
.case-type { display: flex; align-items: baseline; gap: 0.45rem;
  padding: 0.17rem 0.3rem; border-radius: 5px; font-size: var(--t-note);
  cursor: pointer; }
.case-type:hover { background: var(--survol); }
.case-type input { flex: none; }
.case-nom { flex: 1 1 auto; }
.case-glose { display: block; font-size: var(--t-petite); color: var(--texte-discret);
  font-style: normal; }
.case-eff { margin-left: auto; color: var(--texte-doux); font-size: var(--t-petite);
  font-variant-numeric: tabular-nums; }

/* Quatre chiffres séparés, chacun avec son titre collé — l'aperçu était une
   phrase où deux nombres comptaient des points et le troisième des catégories. */
.compteur-geodata { display: flex; gap: 2.2rem; flex-wrap: wrap;
  background: var(--survol); border: 1px solid var(--trait);
  border-radius: var(--rayon); padding: 0.7rem 1rem; margin: 0.9rem 0 0; }
.compteur-geodata > div { text-align: center; }
.compteur-lib { display: block; font-size: var(--t-petite); font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--texte-doux); }
.compteur-val { display: block; font-size: var(--t-grande); font-weight: 700;
  font-variant-numeric: tabular-nums; }
.compteur-val.compteur-rien { color: var(--texte-doux); font-weight: 400;
  font-size: var(--t-moyenne); }

/* Les catégories de concurrence, repliées — même `<details>` que le bandeau
   de santé (`.sante-repliable`) et le menu ⋯ des comptes. Seize cases
   occupent la moitié de l'écran pour un réglage qu'on touche une fois par
   enseigne ; le COMPTE et le détail de ce qui est coché restent lisibles
   replié, ce qui distingue un repli d'un masquage. */
.categories-repliable { border: 1px solid var(--trait); border-radius: var(--rayon);
  padding: 0.5rem 0.8rem; margin-top: 0.7rem; background: var(--survol); }
.categories-repliable > summary { list-style: none; cursor: pointer;
  display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.categories-repliable > summary::-webkit-details-marker { display: none; }
.categories-repliable > summary::before { content: "▸"; color: var(--texte-doux); }
.categories-repliable[open] > summary::before { content: "▾"; }
.categories-repliable[open] { background: var(--blanc); }
.categories-repliable .resume-coche { color: var(--texte-doux);
  font-size: var(--t-petite); flex: 1 1 auto; }
.categories-repliable .deplier { color: var(--bleu);
  font-size: var(--t-petite); font-weight: 600; margin-left: auto; }

/* LES JALONS DU PARCOURS (M15, 12/08/2026) — remontés du `<style>` de la
   Liste, où ils vivaient seuls. La Carte a reçu le même gabarit sans ces
   quatre règles : ses pastilles s'affichaient TRANSPARENTES, présentes dans
   le DOM et invisibles à l'œil.

   Troisième fois du même jour qu'un morceau partagé ne l'est qu'à moitié
   parce que sa mise en forme est restée chez l'un des trois écrans. */
.jalons { display: inline-flex; gap: 0.3rem; }
.jalons i { width: 0.7rem; height: 0.7rem; border-radius: 50%;
  border: 2px solid var(--bleu); display: inline-block; }
.jalons i.ok { background: var(--bleu); }
.jalons i.todo { border-color: var(--trait); }

/* LE TROISIÈME ÉTAT D'UN JALON (M15, 12/08/2026) : l'étape ne peut pas se
   faire, la donnée manque EN AMONT. Hachuré — il ne se confond ni avec le
   plein ni avec le vide, alors qu'un demi-ton se lirait comme « en cours ».
   Et il porte un MOT à côté : le survol n'existe pas sur mobile. */
.jalons i.bloque { background: repeating-linear-gradient(45deg,
  var(--texte-doux) 0, var(--texte-doux) 1px, transparent 1px, transparent 3px);
  border-color: var(--texte-doux); }
.jalon-manque { display: inline-block; margin-left: 0.4rem;
  font-size: var(--t-petite); color: var(--texte-doux); font-style: italic; }


/* ------------------------------------------------------------------ M15
   LA BARRE COMMUNE AUX TROIS VUES DES ÉTUDES (12/08/2026).

   Ces règles vivaient dans le `<style>` de `etude_liste.html` et de
   `bibliotheque.html`. Le Pipeline a reçu le gabarit commun
   (`_barre_filtres.html`) SANS le style : vu à l'écran, ses pastilles
   s'affichaient en rectangles bleus pleins, la recherche sans son cadre, le
   bandeau de portée sans son fond.

   **A67 à l'envers** : là-bas un rendu commun ajouté n'avait pas retiré les
   rendus locaux ; ici un gabarit commun a été ajouté sans que le style
   suive. Le même défaut par l'autre bout — un morceau partagé ne l'est
   qu'à moitié tant que sa mise en forme reste chez l'un des trois.
   ------------------------------------------------------------------ */
.barre-filtres { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin: 0 0 0.9rem; }
.filtres-droite { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.recherche-biblio { display: inline-flex; align-items: center; gap: 0.4rem; background: #fff; border: 1px solid #c8d2de; border-radius: 8px; padding: 0.3rem 0.6rem; color: #8b98a8; }
.recherche-biblio input { border: 0; background: transparent; font: inherit; font-size: var(--t-note); color: #1a2233; outline: none; width: 13rem; margin: 0; padding: 0; max-width: none; }
.filtre-expansion { display: inline-flex; align-items: center; gap: 0.4rem; font-size: var(--t-note); color: #55637a; }
.filtre-expansion .role { font-size: var(--t-petite); font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; background: #e6f1fb; color: #0e4c7c; border-radius: 999px; padding: 0.08rem 0.45rem; }
.filtre-expansion select { margin: 0; font-size: var(--t-note); padding: 0.25rem 0.4rem; }
.bandeau-perimetre { display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap;
  margin: 0 0 1rem; padding: 0.5rem 0.85rem; background: #eef4fb; border: 1px solid #d3e2f2;
  border-radius: 8px; font-size: var(--t-note); color: #33415c; }
.bandeau-perimetre .a-valider { margin-left: auto; background: #c97c1f; color: #fff;
  border-radius: 999px; padding: 0.1rem 0.6rem; font-weight: 700; }
.pastilles-etat { display: flex; gap: 0.35rem; flex-wrap: wrap; margin: 0 0 1rem; }
.filtre-pastille { display: inline-flex; align-items: center; gap: 0.4rem; white-space: nowrap; font-size: var(--t-note); font-weight: 600; color: #55637a; background: #fff; border: 1px solid #c8d2de; border-radius: 999px; padding: 0.3rem 0.7rem; cursor: pointer; }
.filtre-pastille .n { font-weight: 700; background: #eef2f7; color: #1a2233; border-radius: 999px; padding: 0.02rem 0.4rem; font-variant-numeric: tabular-nums; }
.filtre-pastille[aria-pressed="true"] { background: #0e4c7c; border-color: #0e4c7c; color: #fff; }
.filtre-pastille[aria-pressed="true"] .n { background: rgba(255,255,255,.25); color: #fff; }
.filtre-pastille.soumise .n { background: #fbf1de; color: #b6791d; }
.filtre-pastille.validee .n { background: #e7f2ec; color: #2f7d5a; }
.filtre-pastille.contractee .n { background: #efe9fb; color: #6d4bb5; }
.bouton-filtrer { font-size: var(--t-note); font-weight: 600; color: #fff;
  background: #0e4c7c; border: 1px solid #0e4c7c; border-radius: 8px;
  padding: 0.3rem 0.9rem; cursor: pointer; }
.effacer-filtres { font-size: var(--t-note); color: #55637a; text-decoration: none;
  border: 1px dashed #c8d2de; border-radius: 999px; padding: 0.25rem 0.7rem; }
.effacer-filtres:hover { border-color: #0e4c7c; color: #0e4c7c; }
a.filtre-pastille { text-decoration: none; }

/* LE VOILE DE CHARGEMENT DE LA CARTE (M15) : plusieurs secondes de blanc
   sans rien passaient pour une panne. Retiré au premier `load` de MapLibre —
   il ne peut donc pas survivre à une carte qui a fini. */
.carte-chargement { position: absolute; inset: 0; z-index: 3;
  display: flex; align-items: center; justify-content: center;
  background: var(--fond); color: var(--texte-doux); font-size: var(--t-note); }
/* Les jalons du rail : plus serrés qu'en tableau, la colonne est étroite. */
.rail .jalons { display: inline-flex; gap: 0.15rem; flex: none; }
.rail .jalons i { width: 0.42rem; height: 0.42rem; }
/* Le CA estimé porte un pointillé : il signale qu'il y a quelque chose à
   lire au survol. Sans lui, personne ne survole — et « 39 concurrents » à
   côté de « 6,8 M€ » fait croire que le second tient compte du premier. */
.ca-saisi { border-bottom: 1px dotted var(--texte-doux); cursor: help; }

/* LE MENU ⋯ D'UNE ZONE CONTRACTUELLE (M16, 12/08/2026).

   Un formulaire de fermeture était logé DANS la cellule — champ date,
   sélecteur, bouton — et le bouton débordait de 33 px hors du tableau,
   coupé à « Fer… ». Mesuré à l'écran.

   Même `<details>` que le menu des comptes et le repli des catégories : le
   formalisme existait, il suffisait de s'en servir. */
.zc-col-gestes { width: 3.5rem; }
.gestes-zone { position: relative; display: inline-block; }
.gestes-declencheur { margin: 0; cursor: pointer; text-align: center;
  background: var(--blanc); border: 1px solid var(--trait); border-radius: 6px;
  padding: 0.1rem 0.5rem; color: var(--texte-doux); font-weight: 700;
  letter-spacing: 0.06em; }
.gestes-declencheur:hover { border-color: var(--bleu); color: var(--bleu); }
/* `fixed` et non `absolute` : D207, le même empilement d'`overflow` qui a
   découpé le menu d'état des études découpe ici. Coordonnées posées à
   l'ouverture depuis le bouton. */
.gestes-volet { position: fixed; z-index: 60; min-width: 15rem;
  background: var(--blanc); border: 1px solid var(--fort, var(--trait));
  border-radius: 9px; padding: 0.35rem; text-align: left;
  box-shadow: 0 8px 22px rgba(20, 30, 50, 0.16); }
.gestes-volet a, .gestes-volet button { display: block; width: 100%;
  text-align: left; padding: 0.35rem 0.55rem; border-radius: 6px;
  font-size: var(--t-petite); text-decoration: none; }
.gestes-volet a:hover { background: var(--survol); text-decoration: none; }
.gestes-volet .gestes-separateur { border-top: 1px solid var(--trait);
  margin: 0.3rem 0; }
.gestes-volet .gestes-titre { display: block; padding: 0.2rem 0.55rem;
  font-size: var(--t-petite); font-weight: 700; color: var(--texte-doux); }
.gestes-volet label { display: block; padding: 0.15rem 0.55rem;
  font-size: var(--t-petite); color: var(--texte-doux); }
.gestes-volet input, .gestes-volet select { width: 100%; margin: 0.1rem 0 0; }
.gestes-volet button.danger { background: var(--blanc); border: 1px solid #d06666;
  color: #7a2020; font-weight: 600; cursor: pointer; margin-top: 0.35rem; }
.gestes-volet button.danger:hover { background: #fdecec; }

/* ------------------------------------------------------------------ D206
   LA RANGÉE DU COCKPIT — composant PARTAGÉ depuis le 13/08/2026.

   Ces règles vivaient dans `templates/accueil.html`, en `<style>` local,
   seul écran à s'en servir — jusqu'à ce que le super administrateur ait SON
   cockpit (SOC-01, matrice de recette : « chacun voit le sien »), qui
   montre les volumes du parc au lieu des états d'étude.

   Recopiées, elles auraient divergé au premier correctif. *Un composant
   partagé a UN habillage.*                                                */
.cockpit { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 0.8rem; margin: 0 0 1.3rem; }
.stat { border: 1px solid #c8d2de; border-radius: 12px; padding: 0.75rem 0.9rem;
  text-align: center; display: block; text-decoration: none; color: inherit; }
a.stat:hover { border-color: #0e4c7c; }
.stat .k { display: block; font-size: var(--t-grande); font-weight: 800;
  letter-spacing: -0.02em; line-height: 1.05; font-variant-numeric: tabular-nums; }
.stat .l { display: block; font-size: var(--t-petite); color: #55637a;
  margin-bottom: 0.25rem; text-transform: uppercase; letter-spacing: 0.06em;
  font-weight: 700; }
.stat.neutre { background: #e6f1fb; } .stat.neutre .k { color: #0e4c7c; }
.stat.brouillon { background: #eef1f6; } .stat.brouillon .k { color: #33415c; }
.stat.avalider { background: #fdf4e4; } .stat.avalider .k { color: #b6791d; }
.stat.validee { background: #eaf4ee; } .stat.validee .k { color: #2f7d5a; }
.stat.contrat { background: #f1edfa; } .stat.contrat .k { color: #6d4bb5; }
.stat.ca { background: #e6f1fb; } .stat.ca .k { color: #1f6fb0; }

/* ------------------------------------------------------------------ D313
   LE TABLEAU DU PARC — la forme M23, transposée du CRM (15/08/2026).

   Partagé par SUP-01 (le parc) et SUP-03 (le cockpit) via le fragment
   `_ligne_parc.html`. Les cinq choix validés sur maquette M23 : en-tête à
   fond, nombres en colonne (`.faits`), jauge de sièges, badges à point
   (`.pdot` — le « pill-dot » du CRM), tiret pour l'absence.

   Fichier de Mr C depuis la réorganisation : reprends la forme à ta main,
   la structure (les classes) est le contrat avec les gabarits de MrB.    */
.tableau-parc { border-collapse: collapse; width: 100%; }
.tableau-parc th { background: #e4e8ec; font-size: var(--t-petite);
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--encre);
  font-weight: 600; text-align: left; padding: 0.55rem 0.9rem; }
.tableau-parc td { padding: 0.7rem 0.9rem; border-top: 1px solid var(--trait);
  vertical-align: top; font-variant-numeric: tabular-nums; }
.tableau-parc tbody tr { transition: background-color 0.14s ease; }
.tableau-parc tbody tr:hover { background: var(--survol); }
.tableau-parc tr.attente td { background: var(--danger-fond); }
.tableau-parc .col-etat { width: 8rem; }
.tableau-parc .col-gestes { width: 3.5rem; text-align: center; }

/* L'AÉRATION (D323 suite, 15/08/2026) : « ce qui est au milieu est tassé »
   — les colonnes d'un mot rendent leur large au milieu, qui parle. Les
   largeurs fixes vont aux colonnes courtes ; les planchers (`min-width`)
   empêchent les colonnes bavardes de replier « 27 sans CA » au milieu du
   mot. `.insecable` garde ensemble ce qui n'a pas de sens coupé. */
.tableau-parc .col-donnees { min-width: 16rem; }
.tableau-parc .col-contrat { min-width: 14rem; }
.tableau-parc .col-consultant { white-space: nowrap; }
.tableau-parc .col-modele { width: 9.5rem; }
.tableau-parc .col-import { min-width: 10.5rem; }
.insecable { white-space: nowrap; }

.nom-compte { font-weight: 700; }

/* Les chiffres tombent en colonne : nombre à droite, libellé à gauche. */
.faits { display: grid; grid-template-columns: auto 1fr; gap: 0 0.45rem; }
.faits .n { text-align: right; font-weight: 700;
  font-variant-numeric: tabular-nums; }
.faits .l { color: var(--texte-doux); font-size: var(--t-petite);
  align-self: baseline; }

/* La jauge de sièges — un contrat se voit, il ne se lit pas. */
.jauge { width: 120px; height: 6px; border-radius: 4px;
  background: var(--trait); margin: 0.3rem 0; overflow: hidden; }
.jauge i { display: block; height: 100%; background: var(--succes); }
.jauge.pleine i { background: #8a5f14; }
.jauge.deborde i { background: var(--danger); }
.sieges { font-variant-numeric: tabular-nums; }
.sieges.plein { color: #8a5f14; }
.sieges.deborde { color: var(--danger); }

/* Le badge à point du CRM : la couleur se lit avant le mot. */
.pdot { display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.16rem 0.6rem; border-radius: 100px; font-size: var(--t-petite);
  font-weight: 600; white-space: nowrap; }
.pdot::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex-shrink: 0; }
.pdot-termine { background: var(--succes-fond); color: var(--succes); }
.pdot-echec { background: var(--danger-fond); color: var(--danger); }
.pdot-depose, .pdot-a_verifier, .pdot-en_cours {
  background: var(--alerte-fond); color: #8a5f14; }
.pdot-gris { background: var(--survol); color: var(--texte-doux); }
.pdot-modele-pas_demarre { background: var(--survol); color: var(--texte-doux); }
.pdot-modele-en_cours { background: var(--alerte-fond); color: #8a5f14; }
.pdot-modele-en_recette { background: #e8f0fe; color: #0e4c7c; }
.pdot-modele-operationnel { background: var(--succes-fond); color: var(--succes); }

/* La pastille de module `.mod` a été RETIRÉE ici (D343, 16/08/2026, MrDev) :
   le parc affiche ses modules en `.pdot`/`.insecable`, plus personne ne la
   portait — sauf les CARTES de l'accueil, qui s'appellent aussi `.mod` et
   héritaient de son `white-space: nowrap` : le descriptif sortait de la
   carte sans revenir à la ligne. Si la pastille doit renaître, lui donner
   un autre nom que celui des cartes. */

/* Bloc socle ajouté par MrDev (D344, 16/08/2026) — LES FAITS ÉTIQUETÉS.
   Le composant « étiquette + valeur » du cockpit (CONNECTÉ · PROFIL ·
   CLIENT, D209) devient partagé : la fiche d'un compte du parc l'adopte
   (CODE · ÉTUDES · UTILISATEURS). Il vivait dans le <style> de
   `accueil.html` ; monté ici pour n'exister qu'UNE fois (la leçon d'A97 :
   deux définitions d'un même composant finissent par diverger). */
.qui-suis-je { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0 0 1.5rem; padding: 0; }
.qsj { display: inline-flex; align-items: center; gap: 0.45rem; background: #fff; border: 1px solid #c8d2de; border-radius: 999px; padding: 0.22rem 0.75rem 0.22rem 0.3rem; font-size: var(--t-petite); color: #1a2233; }
.qsj-etiq { font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; background: #eef2f7; color: #0e4c7c; border-radius: 999px; padding: 0.1rem 0.5rem; }

/* L'ÉTAT CALME (M24, D323, 15/08/2026) : quand tout va bien, un point et le
   mot — la capsule `.pdot` est réservée à ce qui réclame l'œil. « Quand
   tout est badge, plus rien n'en est un. » Fichier de Mr C : reprends la
   forme à ta main, les classes sont le contrat. */
.calme { white-space: nowrap; }
.calme::before { content: ""; display: inline-block; width: 7px; height: 7px;
  border-radius: 50%; margin-right: 0.4rem; vertical-align: 0.05rem; }
.calme.vert::before { background: var(--succes); }
.calme.ambre::before { background: #8a5f14; }
.calme.gris { color: var(--texte-doux); }
.calme.gris::before { background: #b9c4d1; }
.rien { color: #b9c4d1; }
/* Une absence qui APPELLE un geste se dit en mots, pas en tiret. */
.rien-action { color: #8a5f14; font-style: italic; }

/* ------------------------------------------------------------------ D322
   LE FORMULAIRE LARGE — le standard des formulaires de carte (15/08/2026).

   « Étendre sur toute la largeur — faire systématiquement, à mettre dans le
   template standard. » Un formulaire posé dans une carte étroite laisse la
   moitié droite de l'écran vide (vécu sur « Fermer ce compte ») ; celui-ci
   s'étale en colonnes séparées d'un filet, et s'empile sous 980 px.

   S'applique à tout formulaire de carte à plusieurs groupes de champs —
   les écrans existants migrent au fil des retouches. Fichier de Mr C :
   reprends la forme à ta main, les classes sont le contrat.              */
.formulaire-large { display: grid;
  grid-template-columns: 1fr 1px 1fr 1px 1fr; gap: 1.1rem;
  align-items: start; }
.formulaire-large .barre { background: var(--trait); align-self: stretch; }
@media (max-width: 980px) {
  .formulaire-large { grid-template-columns: 1fr; }
  .formulaire-large .barre { height: 1px; }
}
