/* La feuille de style de Cockpit. Elle n'écrit aucune couleur en dur : tout
   passe par les jetons de tokens.css. */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-md);
  line-height: 1.55;
  color: var(--text-body);
  background: var(--bg);
}

a { color: var(--info); }

.bandeau {
  background: var(--hex-violet);
  color: var(--blanc);
  padding: var(--s4) var(--s6);
}
.bandeau h1 {
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: 800;
  letter-spacing: -.01em;
}
.bandeau p { margin: var(--s1) 0 0; font-size: var(--fs-sm); opacity: .82; }

.page { max-width: 960px; margin: 0 auto; padding: var(--s6) var(--s4) var(--s10); }

.carte {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-md);
  padding: var(--s5);
  margin-bottom: var(--s5);
}
.carte > h2 {
  margin: 0 0 var(--s2);
  font-size: var(--fs-lg);
  font-weight: 800;
  color: var(--hex-violet);
}
.carte > h2 + .sous { margin: 0 0 var(--s4); color: var(--text-muted); font-size: var(--fs-sm); }

table { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
th {
  text-align: left;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-strong);
  padding: var(--s2) var(--s3) var(--s2) 0;
}
td { padding: var(--s3) var(--s3) var(--s3) 0; border-bottom: 1px solid var(--divider); }
tr:last-child td { border-bottom: 0; }
.defile { overflow-x: auto; }

.etiq {
  display: inline-block;
  padding: 2px var(--s2);
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: 700;
  background: var(--chip-bg);
  color: var(--text-muted);
}
.etiq-libre    { background: var(--success-bg); color: var(--hex-green-deep); }
.etiq-retenu   { background: var(--info-bg);    color: var(--hex-blue-deep); }
.etiq-externe  { background: var(--warning-bg); color: var(--hex-orange-deep); }
.etiq-admin    { background: var(--primary-soft); color: var(--hex-pink-deep); }

/* Les deux tons des étiquettes de l'écran « Clients » (23/09/2026).
   ⚠️ Ils se nomment par la GRAVITÉ, pas par la couleur. Une classe
   « .etiq-rose » attacherait l'alerte à une teinte : le jour où la charte
   change, plus rien ne dirait laquelle des deux était la grave. */
.etiq-grave     { background: var(--danger-bg);  color: var(--hex-pink-deep); }
.etiq-attention { background: var(--warning-bg); color: var(--hex-orange-deep); }

/* ⚠️ Les étiquettes s'enroulent au lieu d'élargir la colonne. Un client qui
   en porte trois pousserait sinon la table au défilement horizontal, et la
   colonne « Nom » sortirait de l'écran — c'est-à-dire la seule qui dit de
   QUI on parle. */
.cl-etiqs { display: flex; flex-wrap: wrap; gap: 4px; max-width: 15rem; }

.btn {
  font: inherit;
  font-weight: 700;
  border: 1px solid var(--border-strong);
  background: var(--card);
  color: var(--text-strong);
  border-radius: var(--r-md);
  padding: var(--s2) var(--s4);
  cursor: pointer;
  transition: background .15s var(--ease);
}
.btn:hover { background: var(--bg-subtle); }
.btn-primaire { background: var(--primary); border-color: var(--primary); color: var(--blanc); }
.btn-primaire:hover { background: var(--primary-hover); }
.btn:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 2px; }

label { display: block; font-size: var(--fs-sm); font-weight: 700; color: var(--text-strong); margin-bottom: var(--s1); }
input, select {
  font: inherit;
  width: 100%;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--text-body);
}
input:focus-visible, select:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 1px; }

.champs { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--s4); align-items: end; }

.avis {
  border-radius: var(--r-lg);
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s4);
  font-size: var(--fs-base);
  border-left: 4px solid;
}
.avis-refus  { background: var(--danger-bg);  border-color: var(--danger);  color: var(--hex-pink-deep); }
.avis-bien   { background: var(--success-bg); border-color: var(--success); color: var(--hex-green-deep); }
.avis-info   { background: var(--info-bg);    border-color: var(--info);    color: var(--hex-blue-deep); }
.avis-manque { background: var(--warning-bg); border-color: var(--hex-orange); color: var(--hex-orange-deep); }

.vide { color: var(--text-muted); font-style: italic; }

.pied { color: var(--text-faint); font-size: var(--fs-xs); text-align: center; padding: var(--s6) var(--s4); }

/* ── La coquille des écrans internes ─────────────────────────────────────
   Une colonne de navigation à gauche, le travail à droite. C'est la grammaire
   de la maquette de pilotage, et elle vaut mieux que des onglets en haut : sur
   un écran, la barre latérale porte des compteurs qui disent où ça coince
   AVANT d'ouvrir l'écran. */

.app { display: grid; grid-template-columns: 220px 1fr; min-height: 100vh; }

.barre {
  background: var(--card);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: var(--s5) var(--s3) var(--s4);
  position: sticky;
  top: 0;
  height: 100vh;
}

/* La marque : le logogramme, puis le nom sur deux lignes. Le dessin fait
   30 px comme dans la maquette, et `flex:none` l'empêche d'être écrasé
   quand la barre latérale se resserre — un logo comprimé se lit comme un
   défaut d'affichage. */
.marque {
  padding: 0 var(--s3) var(--s5);
  line-height: 1.1;
  display: flex;
  align-items: center;
  gap: var(--s2);
}
.logogramme { width: 30px; height: 30px; flex: none; display: block; }
.marque b { font-size: var(--fs-lg); font-weight: 800; color: var(--text-strong); }
.marque-sous {
  display: block;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--text-faint);
  font-weight: 600;
  margin-top: 2px;
}

.nav-titre {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .1em;
  font-weight: 700;
  color: var(--text-faint);
  padding: var(--s4) var(--s3) var(--s2);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  border-radius: var(--r-md);
  margin-bottom: 2px;
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text-body);
  text-decoration: none;
}

.nav-item:hover { background: var(--chip-bg); }

/* L'écran regardé. Il se voit sans avoir à lire : une page où l'on ne sait
   pas où l'on est fait cliquer deux fois sur le même lien. */
.nav-item.nav-ici {
  background: var(--primary-soft);
  color: var(--hex-pink-deep);
  font-weight: 700;
}

.nav-item:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 2px; }
.nav-lab { flex: 1; }

/* L'icône de chaque entrée. Largeur FIXE : sans elle, les glyphes n'ont pas
   tous la même chasse et les libellés du menu ne s'alignent pas — un menu
   dont les mots dansent d'une ligne à l'autre se lit comme un défaut. */
.nav-ic {
  width: 16px;
  flex: none;
  text-align: center;
  color: var(--text-faint);
  font-size: var(--fs-sm);
}
.nav-item.nav-ici .nav-ic { color: var(--hex-pink-deep); }

/* Une pastille ne s'affiche jamais à zéro : elle attirerait l'œil pour rien. */
.nav-n {
  min-width: 20px;
  padding: 0 6px;
  border-radius: var(--r-full);
  background: var(--chip-bg);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: 700;
  text-align: center;
}

.nav-n-chaud { background: var(--danger); color: var(--blanc); }

/* Qui est connecté, et le bouton pour ressortir.
   Le bloc est poussé en bas de la colonne par « margin-top: auto » ; le pied
   qui le suit perd donc le sien, sinon les deux se partageraient l'espace
   libre et l'identité flotterait au milieu de la barre. */
.barre-qui {
  margin-top: auto;
  padding: var(--s3) var(--s3) 0;
  border-top: 1px solid var(--divider);
}

.barre-qui-nom {
  font-weight: 700;
  color: var(--text-strong);
  line-height: 1.3;
  margin: var(--s3) 0 0;
  display: flex;
  align-items: center;
  gap: var(--s2);
}

.barre-qui-role {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .09em;
  font-weight: 600;
  color: var(--text-faint);
  margin: 2px 0 var(--s2);
}

.barre-sortir {
  font-family: var(--font);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--s1) var(--s2);
  cursor: pointer;
  transition: color var(--ease), border-color var(--ease);
}

.barre-sortir:hover {
  color: var(--text-strong);
  border-color: var(--border-strong);
}

.barre-pied {
  margin-top: auto;
  padding: var(--s4) var(--s3) 0;
  font-size: var(--fs-xs);
  color: var(--text-faint);
  line-height: 1.5;
}

.barre-qui + .barre-pied { margin-top: var(--s3); }

.principal { min-width: 0; display: flex; flex-direction: column; }

.haut {
  background: var(--card);
  border-bottom: 1px solid var(--border);
  padding: var(--s5) var(--s6) var(--s4);
}

.fil {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-muted);
}

.haut h1 {
  margin: var(--s1) 0 0;
  font-size: var(--fs-2xl);
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--text-strong);
}

.haut-sous { margin: var(--s1) 0 0; font-size: var(--fs-sm); color: var(--text-muted); }
.haut-sous:empty { display: none; }

/* ⚠️ Le contenu interne ne se centre pas dans sa colonne : il s'aligne sur le
   titre de l'écran. Un bloc centré à 960 px sous un titre calé à gauche fait
   un décalage qu'aucun test ne voit et que l'œil ne rate jamais. */
.principal .page {
  max-width: 1180px;
  margin: 0;
  padding: var(--s6) var(--s6) var(--s10);
}

/* Sur un écran étroit, la barre repasse au-dessus : une colonne de 220 px
   prise sur 360 px de large ne laisse plus rien au travail. */
@media (max-width: 860px) {
  .app { grid-template-columns: 1fr; }
  .barre { position: static; height: auto; border-right: 0; border-bottom: 1px solid var(--border); }
  .marque { padding-bottom: var(--s3); }
  .barre nav { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
  .nav-titre { padding: 0 var(--s2) 0 var(--s3); }
  .barre-pied { display: none; }
  /* ⚠️ Le pied disparaît sur un écran étroit, l'identité NON. Le pied est une
     phrase de contexte ; savoir sous quel rôle on regarde l'écran décide de ce
     qu'on croit voir. Le bloc passe simplement sur une ligne, sans son trait
     de séparation ni sa marge automatique, qui n'ont plus de sens hors d'une
     colonne. */
  .barre-qui {
    margin-top: 0;
    padding: var(--s2) var(--s3) 0;
    border-top: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
    align-items: baseline;
  }
  .barre-qui-nom  { margin: 0; }
  .barre-qui-role { margin: 0; }
}

/* ── Une carte qui réclame un arbitrage ──────────────────────────────── */

.carte-alerte { box-shadow: inset 3px 0 0 var(--hex-pink); }

.liste { list-style: none; margin: var(--s4) 0 0; padding: 0; }

.liste li {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  padding: var(--s3) 0;
  border-top: 1px solid var(--divider);
}

.liste li:first-child { border-top: 0; }
.liste-corps { flex: 1; min-width: 220px; }
.liste-corps b { color: var(--text-strong); }
.liste-corps .sous { display: block; margin: 0; }

.pastille { width: 9px; height: 9px; border-radius: var(--r-full); flex: none; }
.pastille-chaud { background: var(--hex-pink); }
.pastille-tiede { background: var(--hex-yellow); }

.etiq-retard { background: var(--danger-bg); color: var(--hex-pink-deep); }

/* Les heures proposables d'une plage : des boutons, pas une liste. */
.heures { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s2); }

/* Le compte posé à côté d'un titre de groupe. */
.compte {
  display: inline-block;
  margin-left: var(--s2);
  padding: 0 var(--s2);
  border-radius: var(--r-full);
  background: var(--chip-bg);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* Un libellé que l'oeil n'a pas besoin de lire, mais que le lecteur d'écran
   doit entendre. ⚠️ Surtout pas « display:none » : ça le supprimerait aussi
   pour lui, et le champ deviendrait anonyme. */
.invisible {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.ligne-ajout {
  padding: var(--s3) 0;
  border-top: 1px solid var(--divider);
}

.ligne-ajout:first-of-type { border-top: 0; }

/* ══ LES PLANNINGS ═══════════════════════════════════════════════════════
   ⚠️ Un planning n'est pas un tableau trié par date. Sur une liste, « le 18
   et le 20 » se lisent comme deux lignes voisines ; sur une grille, on voit
   le trou du 19, le férié du 15, et la semaine vide du 24. Aucune de ces
   trois informations n'existe dans une liste. */

/* Le calendrier à gauche, ce qui n'a pas de date à droite. */
.planning { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--s5); }
.planning > .carte { margin-bottom: 0; }
.planning aside { min-width: 0; }

@media (max-width: 1100px) {
  .planning { grid-template-columns: 1fr; }
}

.cal-haut { margin-bottom: var(--s4); }
.cal-nav { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.cal-nav .btn { padding: var(--s1) var(--s3); }
.cal-mois {
  font-size: var(--fs-lg);
  font-weight: 800;
  color: var(--text-strong);
  margin: 0 var(--s2);
  text-transform: capitalize;
}

/* ── La grille du mois ───────────────────────────────────────────────── */

.cal { table-layout: fixed; min-width: 740px; border-collapse: separate; border-spacing: 0; }
.cal th {
  padding: var(--s2) var(--s3);
  border-bottom: 0;
  font-size: var(--fs-xs);
}

.jour {
  vertical-align: top;
  height: 96px;
  padding: var(--s2);
  border: 1px solid var(--divider);
  border-width: 1px 1px 0 0;
  background: var(--card);
}
.jour:first-child { border-left-width: 1px; }
.cal tbody tr:last-child .jour { border-bottom-width: 1px; }

.jour-n { font-size: var(--fs-sm); font-weight: 700; color: var(--text-muted); }
.jour-ailleurs { background: var(--bg-subtle); }
.jour-ailleurs .jour-n { color: var(--text-faint); }

/* Les week-ends sont grisés et les fériés marqués : une séance n'y tombe
   jamais, et ils ne comptent pas dans les délais. Le dire à l'écran évite de
   le redemander. */
.jour-weekend { background: var(--bg); }
.jour-ferie { background: var(--danger-bg); }
.jour-ferie-lab {
  display: inline-block;
  margin-left: var(--s1);
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--hex-pink-deep);
  text-transform: lowercase;
}
.jour-aujourdhui { box-shadow: inset 0 0 0 2px var(--primary); }

/* ── Une séance posée dans le calendrier de Marine ───────────────────── */

.sess {
  display: block;
  margin-top: var(--s1);
  padding: var(--s1) var(--s2);
  border-radius: var(--r-sm);
  border-left: 3px solid var(--text-faint);
  background: var(--chip-bg);
  font-size: var(--fs-xs);
  line-height: 1.35;
  text-decoration: none;
  color: var(--text-body);
}
.sess:hover { box-shadow: var(--shadow-sm); }
.sess:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 1px; }
.sess b { display: block; color: var(--text-strong); }
.sess span { display: block; }
.sess-cli { color: var(--text-muted); }
.sess-alerte { color: var(--hex-pink-deep); font-weight: 700; }

/* Une couleur par animateur — les six du symbole Hexagone, puis on
   recommence. Inventer une septième teinte, ce serait sortir de la charte. */
.teinte-1 { border-left-color: var(--hex-green);  background: color-mix(in srgb, var(--hex-green) 10%, var(--card)); }
.teinte-2 { border-left-color: var(--hex-blue);   background: color-mix(in srgb, var(--hex-blue) 10%, var(--card)); }
.teinte-3 { border-left-color: var(--hex-pink);   background: color-mix(in srgb, var(--hex-pink) 10%, var(--card)); }
.teinte-4 { border-left-color: var(--hex-yellow); background: color-mix(in srgb, var(--hex-yellow) 16%, var(--card)); }
.teinte-5 { border-left-color: var(--hex-orange); background: color-mix(in srgb, var(--hex-orange) 12%, var(--card)); }
.teinte-6 { border-left-color: var(--hex-violet); background: color-mix(in srgb, var(--hex-violet) 8%, var(--card)); }

/* ── La légende ──────────────────────────────────────────────────────── */

.legende {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  margin: var(--s4) 0 0;
  padding: 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.legende li { display: flex; align-items: center; gap: var(--s2); }

.puce { width: 10px; height: 10px; border-radius: var(--r-sm); flex: none; background: var(--chip-bg); }
.puce.teinte-1 { background: var(--hex-green); }
.puce.teinte-2 { background: var(--hex-blue); }
.puce.teinte-3 { background: var(--hex-pink); }
.puce.teinte-4 { background: var(--hex-yellow); }
.puce.teinte-5 { background: var(--hex-orange); }
.puce.teinte-6 { background: var(--hex-violet); }
.puce-pleine { background: var(--success); }
.puce-creuse { background: transparent; border: 1px dashed var(--success); }
.puce-grise  { background: var(--border-strong); }
.puce.mode-distanciel { background: var(--hex-blue); }
.puce.mode-presentiel { background: var(--hex-orange); }
.puce.mode-les_deux   { background: var(--hex-green); }

/* ── La semaine du formateur ─────────────────────────────────────────── */

.semaine {
  display: grid;
  grid-template-columns: repeat(5, minmax(150px, 1fr));
  gap: var(--s3);
  min-width: 760px;
}

.col-jour {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s3);
  background: var(--card);
  min-height: 150px;
}

.col-titre {
  font-size: var(--fs-sm);
  font-weight: 800;
  color: var(--text-strong);
  margin-bottom: var(--s3);
}
.col-titre span { font-weight: 600; color: var(--text-faint); margin-left: var(--s1); }

.plage {
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--s2);
  margin-bottom: var(--s2);
  font-size: var(--fs-xs);
  background: var(--card);
}
.plage-haut { display: flex; align-items: center; gap: var(--s2); }
.plage-haut b { color: var(--text-strong); }
.plage-mode {
  flex: 1;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  color: var(--text-muted);
  font-size: 10px;
}

/* La modalité se lit à la couleur du cadre : un formateur qui balaie sa
   semaine voit d'un coup où il a promis d'être sur place. */
.plage.mode-distanciel { border-color: var(--hex-blue);   background: color-mix(in srgb, var(--hex-blue) 6%, var(--card)); }
.plage.mode-presentiel { border-color: var(--hex-orange); background: color-mix(in srgb, var(--hex-orange) 8%, var(--card)); }
.plage.mode-les_deux   { border-color: var(--hex-green);  background: color-mix(in srgb, var(--hex-green) 7%, var(--card)); }

.plage-x {
  font: inherit;
  line-height: 1;
  border: 0;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  padding: 0 var(--s1);
  border-radius: var(--r-sm);
}
.plage-x:hover { color: var(--hex-pink-deep); background: var(--danger-bg); }
.plage-x:focus-visible { outline: 2px solid var(--hex-blue); outline-offset: 1px; }

.plage-seance {
  margin-top: var(--s2);
  padding: var(--s1) var(--s2);
  border-radius: var(--r-sm);
  background: var(--success-bg);
  color: var(--hex-green-deep);
}
.plage-seance b { display: block; }
.plage-reste { margin-top: var(--s2); color: var(--text-muted); }

/* « + une plage » : un <details> HTML, pas un bouton JavaScript. La pile est
   imposée — rendu côté serveur — et <details> fait exactement l'affaire. */
.ajout-plage > summary {
  list-style: none;
  cursor: pointer;
  text-align: center;
  padding: var(--s2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: 700;
}
.ajout-plage > summary::-webkit-details-marker { display: none; }
.ajout-plage > summary:hover { border-color: var(--primary); color: var(--hex-pink-deep); }
.ajout-plage[open] > summary { border-style: solid; margin-bottom: var(--s2); }
.ajout-plage label { font-size: var(--fs-xs); margin-top: var(--s2); }
.ajout-plage .btn { width: 100%; margin-top: var(--s3); }

/* ── Les totaux de la semaine ────────────────────────────────────────── */

.totaux {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: var(--s4);
  margin: var(--s5) 0 0;
  padding-top: var(--s4);
  border-top: 1px solid var(--divider);
}
.totaux dt {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  color: var(--text-faint);
}
.totaux dd {
  margin: var(--s1) 0 0;
  font-size: var(--fs-2xl);
  font-weight: 800;
  color: var(--text-strong);
}

/* ── Le calendrier du client : des créneaux à cliquer ────────────────── */

.offre {
  display: block;
  width: 100%;
  margin-top: var(--s1);
  padding: var(--s1) var(--s2);
  border-radius: var(--r-sm);
  font: inherit;
  font-size: var(--fs-xs);
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
}
.offre b { display: block; font-weight: 800; }
.offre span { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .04em; }

.offre-libre {
  border: 1px dashed var(--success);
  background: transparent;
  color: var(--hex-green-deep);
}
.offre-libre:hover { background: var(--success-bg); }
.offre-libre:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 1px; }

.offre-prise {
  border: 1px solid var(--success);
  background: var(--success);
  color: var(--blanc);
  cursor: default;
}

/* ── Petites pièces communes ─────────────────────────────────────────── */

.etape {
  display: inline-block;
  margin-right: var(--s2);
  padding: 2px var(--s2);
  border-radius: var(--r-full);
  background: var(--primary-soft);
  color: var(--hex-pink-deep);
  font-size: var(--fs-xs);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .06em;
  vertical-align: middle;
}

.sous-titre {
  margin: var(--s5) 0 0;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-faint);
  font-weight: 700;
}

.date-bloc {
  flex: none;
  width: 68px;
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--text-muted);
}

/* La fiche d'une formation : des couples libellé / valeur, pas un tableau
   d'une seule ligne — qui se lit très mal sur un écran étroit. */
.fiche {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--s4);
  margin: 0;
}
.fiche dt {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  color: var(--text-faint);
}
.fiche dd { margin: var(--s1) 0 0; color: var(--text-strong); font-weight: 600; }
.fiche dd .sous { display: block; font-weight: 400; }

/* ── Les tuiles de comptage (les déploiements) ───────────────────────── */

.tuiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s4);
  margin-bottom: var(--s5);
}

.tuile {
  display: block;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
  padding: var(--s5);
  text-decoration: none;
  color: var(--text-body);
}
.tuile:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.tuile:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 2px; }

/* Le filtre actif se voit : une page où l'on ne sait pas ce qu'on regarde
   fait cliquer deux fois sur la même tuile. */
.tuile-ici { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }

.tuile-titre {
  display: block;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .08em;
  font-weight: 700;
  color: var(--text-faint);
}
.tuile-n {
  display: block;
  margin-top: var(--s2);
  font-size: var(--fs-3xl);
  font-weight: 800;
  line-height: 1;
  color: var(--hex-violet);
}
.tuile-lab { display: block; font-size: var(--fs-sm); color: var(--text-muted); }
.tuile-sous {
  display: block;
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--divider);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--hex-pink-deep);
}
.tuile-ensemble .tuile-n { color: var(--primary); }

.tuile-mesure .tuile-n { color: var(--hex-pink-deep); }
.tuile-mesure .tuile-n small { font-size: var(--fs-lg); font-weight: 700; }
.tuile-n-vide { color: var(--text-faint); }

/* ── Les filtres du plateau ──────────────────────────────────────────── */

.filtres { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s5); }

.puce-filtre {
  padding: var(--s2) var(--s4);
  border-radius: var(--r-full);
  border: 1px solid var(--border-strong);
  background: var(--card);
  color: var(--text-body);
  font-size: var(--fs-sm);
  font-weight: 700;
  text-decoration: none;
}
.puce-filtre:hover { background: var(--chip-bg); }
.puce-filtre-ici { background: var(--hex-violet); border-color: var(--hex-violet); color: var(--blanc); }
.puce-filtre:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 2px; }

/* ── Où en est un projet ─────────────────────────────────────────────── */

.etape {
  display: inline-block;
  padding: 2px var(--s2);
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: 700;
  background: var(--chip-bg);
  color: var(--text-muted);
}
.etape-a_signer      { background: var(--chip-bg);      color: var(--text-muted); }
.etape-a_lancer      { background: var(--warning-bg);   color: var(--hex-orange-deep); }
.etape-en_cours      { background: var(--info-bg);      color: var(--hex-blue-deep); }
.etape-bureau_livre  { background: var(--info-bg);      color: var(--hex-blue-deep); }
.etape-bascule_engagee { background: var(--primary-soft); color: var(--hex-pink-deep); }
.etape-livre         { background: var(--success-bg);   color: var(--hex-green-deep); }

.pastille-verte { background: var(--hex-green); }

/* ── Le parcours d'un déploiement ────────────────────────────────────── */

.parcours {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--s3);
  margin: var(--s4) 0 0;
  padding: 0;
}

.parcours li {
  padding: var(--s3);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--bg-subtle);
  /* Le trait du haut se lit comme une frise : le franchi est plein, ce qui
     reste est en pointillé. On voit où on en est sans lire une date. */
  border-top: 3px solid var(--border-strong);
}
.parcours-fait { background: var(--card); border-top-color: var(--hex-green); }
.parcours-attente { border-top-style: dashed; }

.parcours-lab {
  display: block;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  color: var(--text-faint);
}
.parcours-date {
  display: block;
  margin-top: var(--s1);
  font-size: var(--fs-lg);
  font-weight: 800;
  color: var(--text-strong);
}
.parcours-attente .parcours-date { color: var(--text-faint); font-weight: 600; }

/* ── Les compteurs d'un conseiller ───────────────────────────────────── */

.compteurs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--s4);
  margin: var(--s4) 0 0;
}

.compteur {
  padding: var(--s4);
  border-radius: var(--r-lg);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
}
.compteur dt {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  color: var(--text-faint);
}
.compteur dd {
  margin: var(--s1) 0 0;
  font-size: var(--fs-3xl);
  font-weight: 800;
  line-height: 1;
  color: var(--text-strong);
}
.compteur-a_faire   { border-color: var(--hex-pink);   }
.compteur-a_faire dd   { color: var(--hex-pink-deep);  }
.compteur-planifiee { border-color: var(--hex-blue);   }
.compteur-planifiee dd { color: var(--hex-blue-deep);  }
.compteur-faite     { border-color: var(--hex-green);  }
.compteur-faite dd     { color: var(--hex-green-deep); }

/* ── L'état déduit d'une prestation ──────────────────────────────────── */

.etat {
  display: inline-block;
  min-width: 26px;
  padding: 2px var(--s2);
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: 700;
  text-align: center;
  background: var(--chip-bg);
  color: var(--text-muted);
}
.etat-a_faire   { background: var(--danger-bg);  color: var(--hex-pink-deep); }
.etat-planifiee { background: var(--info-bg);    color: var(--hex-blue-deep); }
.etat-faite     { background: var(--success-bg); color: var(--hex-green-deep); }
.etat-annulee   { background: var(--chip-bg);    color: var(--text-faint); }
.etat-soldee    { background: var(--warning-bg); color: var(--hex-orange-deep); }

/* ── La jauge d'avancement ───────────────────────────────────────────── *
   Deux segments : ce qui est fait, puis ce qui est posé. Le reste est le
   fond de la barre — donc « à faire » se lit comme le vide qu'il est. */

.jauge {
  display: flex;
  width: 110px;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--border);
  overflow: hidden;
}
.jauge-faite     { background: var(--hex-green); }
.jauge-planifiee { background: var(--hex-blue-light); }

code {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  background: var(--chip-bg);
  padding: 1px var(--s1);
  border-radius: var(--r-sm);
}

/* ── L'écran « Clients » ─────────────────────────────────────────────── *
   La liste cherchable du parc. Aucune couleur écrite à la main : tout passe
   par les jetons de la charte, pour que le jour où elle bouge, cet écran
   bouge avec elle sans qu'on ait à y penser. */

/* ── Le titre de l'écran et son bouton « Colonnes » ────────────────────
   La ligne de la maquette : « ▤ Clients (12) » à gauche, « Colonnes » collé
   à droite. */
.cl-tete {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s3);
}
.cl-tete-t {
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--text-strong);
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
}
.cl-tete-ic { color: var(--text-faint); font-weight: 400; }
.cl-tete-n { color: var(--text-muted); font-weight: 500; }
.cl-tete > .cl-colonnes { margin-left: auto; }

/* ── La barre de filtres, sur UNE ligne ────────────────────────────────

   ⚠️ C'EST LA REMARQUE DE MARINE DU 2026-09-23 : « ça prend beaucoup trop
   de place ». La barre précédente (`.chercheur`) portait quatre menus et un
   bouton « Chercher », donc deux niveaux dès que la fenêtre rétrécissait.

   ⚠️ `wrap` PLUTÔT QUE `nowrap`, ET C'EST UN RETOUR EN ARRIÈRE ASSUMÉ. La
   première version interdisait le repli et faisait défiler la barre : sur la
   photo, « Chantiers », « Tableau » et « Économie » étaient purement
   INVISIBLES, sortis du cadre à droite. Une commande hors champ est pire
   qu'une commande sur un second niveau — la première, on ne sait pas qu'elle
   existe. À la largeur de l'écran de Marine la barre tient sur une ligne ;
   plus étroit, elle se replie proprement au lieu de cacher.

   Ce que la remarque « ça prend trop de place » visait vraiment, et qui est
   réparé : cinq commandes épaisses empilées en permanence. Elles sont
   maintenant fines et sur une ligne. */
.cl-filtres {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s3);
}
/* ⚠️ `width: auto` EST INDISPENSABLE ICI, et son absence a coûté une photo.
   La règle générale de la feuille donne `width: 100%` à tout `input` et tout
   `select` — ce qui est juste dans un formulaire de saisie, et désastreux
   dans une barre en ligne : le premier menu prenait toute la largeur et
   chassait les quatre autres commandes hors de l'écran, sans rien casser ni
   rougir. Vu seulement en photographiant la page. */
.cl-f-sel {
  flex: 0 0 auto;
  width: auto;
  padding: 5px var(--s3);
  font-size: var(--fs-sm);
}
.cl-f-q {
  flex: 0 0 210px;
  width: 210px;
  padding: 5px var(--s3);
  font-size: var(--fs-sm);
}
/* ⚠️ `margin-left: auto` PLUTÔT QU'UN ESPACE ÉLASTIQUE, et la différence
   n'est pas cosmétique. Un élément vide en `flex: 1 1 auto` avale toute la
   place restante de la ligne ; avec `flex-wrap`, il renvoie donc ce qui le
   suit — ici les quatre vues — sur un second niveau. La marge automatique
   pousse le bloc à droite sans jamais prendre de place à elle seule. */
.cl-f-droite {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
}
.cl-f-n {
  flex: none;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  white-space: nowrap;
}

/* La pastille des filtres qui ne sont plus dans la barre (marque, état) :
   ils restent honorés depuis l'adresse, donc ils doivent se VOIR. Un filtre
   actif et invisible fait croire à des données manquantes. */
.cl-f-actif {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  background: var(--primary-soft);
  color: var(--hex-pink-deep);
  border-radius: var(--r-full);
  padding: 2px var(--s2);
  font-size: var(--fs-xs);
  white-space: nowrap;
}
.cl-f-actif a { color: inherit; text-decoration: none; font-weight: 700; }

/* ⚠️ Le bouton « Filtrer » reste, et petit. Sur la maquette, choisir un
   conseiller recalcule le tableau tout seul ; en HTML pur, changer un menu
   ne déclenche rien, et la charte du projet interdit le JavaScript dans les
   gabarits. On ne desserre pas une règle de la maison pour gagner un clic. */
.cl-filtres-ok { flex: none; }

/* ── Les quatre présentations ──────────────────────────────────────────
   ⚠️ Trois ne sont pas construites. Elles se voient pour que la barre ait la
   forme de la maquette, mais rien n'y est cliquable : un onglet qui ne mène
   nulle part se lit comme une panne. */
.cl-vues {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  background: var(--bg-subtle);
  border-radius: var(--r-full);
  padding: 3px;
}
.cl-vue {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  padding: 3px var(--s3);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  white-space: nowrap;
}
.cl-vue-ici {
  background: var(--card);
  color: var(--text-strong);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}
.cl-vue-off { color: var(--text-faint); cursor: not-allowed; }

/* ── Une colonne dont la donnée n'est pas encore arrivée ───────────────

   ⚠️ CE N'EST PAS UN TIRET, ET LA DIFFÉRENCE EST TOUT L'INTÉRÊT. « — » se
   lit « ce client n'a rien » ; « en attente de Mon Pilote » se lit « le
   tuyau n'est pas branché ». Les deux laissent une case vide à l'écran et ne
   veulent pas du tout dire la même chose — seule la seconde dit à Marine que
   ce n'est pas une panne.

   Pâle et en italique : présente, lisible, mais elle ne tire pas l'œil au
   milieu des colonnes qui, elles, portent une mesure. */
/* ⚠️ ELLE SE REPLIE SUR DEUX LIGNES, ET C'EST MESURÉ. En une seule ligne,
   la mention faisait 130 px de large ; multipliée par les quatre colonnes en
   attente d'une ligne, elle repoussait « Bascule » hors du cadre. Sur deux
   lignes étroites, les quatre colonnes tiennent. Le texte ne change pas :
   c'est lui que Marine a choisi, et il dit ce qu'il faut. */
/* ⚠️ DÉFAUT PAYÉ LE 2026-09-23 AU SOIR, TROUVÉ EN PHOTOGRAPHIANT LES DIX-HUIT
   COLONNES. « Agents » et « Boîtes » sont des colonnes de nombres, donc leurs
   cellules portent `.cl-num`, qui impose `white-space: nowrap` — c'est ce qui
   empêche « 1 238 » de se couper en deux. Mais le nowrap s'applique à TOUT le
   contenu de la cellule, mention d'attente comprise : elle ne se repliait plus,
   dépassait ses 6.5 rem, et allait se COLLER à celle de la colonne voisine. À
   l'écran on lisait « en attente de Mon Piloteen attente de Mon Pilote ».
   Aucun test ne bronchait : la classe était là, le texte était là.
   D'où ce `white-space: normal`, qui rend son repli à la mention quelle que
   soit la cellule qui la porte. */
.cl-attente {
  display: inline-block;
  max-width: 6.5rem;
  white-space: normal;
  color: var(--text-faint);
  font-style: italic;
  font-size: var(--fs-xs);
  line-height: 1.25;
}

/* La même mention, mais dite UNE fois pour toute la colonne, sous son titre.
   ⚠️ Elle reprend le titre à son compte : pas de majuscules, pas
   d'interlettrage — le titre crie, l'aveu murmure. Deux lignes de la même
   graisse se liraient comme deux titres. */
.cl-th-attente {
  display: block;
  margin-top: 2px;
  max-width: 8rem;
  white-space: normal;
  color: var(--text-faint);
  font-style: italic;
  font-weight: 400;
  font-size: var(--fs-xs);
  text-transform: none;
  letter-spacing: normal;
  line-height: 1.25;
}

/* ── Les largeurs du tableau ───────────────────────────────────────────

   ⚠️ DÉFAUT VU EN PHOTOGRAPHIANT LA PAGE, ET INVISIBLE AUTREMENT. Sans
   largeur minimale, « Mairie de Pouilly-sous-Charlieu » se repliait sur
   quatre lignes et son domaine sur trois : la colonne qui identifie la ligne
   était la plus illisible du tableau. Aucun test ne pouvait le voir — la
   version repliée porte exactement les mêmes classes que la bonne. */
.t-clients th:first-child,
.t-clients > tbody > tr:not(.cl-detail) > td:first-child { min-width: 15rem; }
.t-clients th { white-space: nowrap; }
.cl-domaine { white-space: nowrap; }

/* Le tableau défile horizontalement DANS sa carte plutôt que de pousser la
   page : avec dix-huit colonnes possibles, une page qui défile en largeur
   emmène aussi la barre latérale et le titre. */
.cl-defile { overflow-x: auto; }

/* ⚠️ ET LE CADRE NE SUFFIT PAS — défaut signalé par Marine le 2026-09-24.
   Un tableau HTML se TASSE par défaut pour tenir dans son cadre. Le cadre
   ci-dessus défilait donc bien, mais sur quelques pixels seulement, pendant
   que les colonnes s'écrasaient : « en attente de Mon Pilote » s'empilait sur
   quatre lignes dans une colonne large comme le pouce.

   Et le même réglage manquant produit le symptôme INVERSE quand on n'affiche
   que deux colonnes : elles s'étirent pour remplir la largeur, et le nom du
   client mange l'écran. C'est ce que Marine a vu en premier, et c'est ce qui
   rendait le défaut difficile à nommer : un seul manque, deux visages.

   Les deux valeurs viennent de sa maquette (`table.cl`, ligne 1503) et vont
   par paire : `max-content` donne à chaque colonne sa largeur naturelle,
   `min-width` empêche le tableau de se serrer à gauche quand les colonnes
   affichées ne remplissent pas le cadre. */
.t-clients { min-width: 100%; width: max-content; }

/* ⚠️ LE NOM DU CLIENT RESTE À GAUCHE PENDANT QU'ON DÉFILE — repris de la
   maquette (sa classe `.stick`, ligne 1516), et vérifié sur les captures que
   Marine a prises le 2026-09-24 : elle fait défiler ses dix-huit colonnes et
   « CC de Forez-Est » reste lisible au bord gauche.

   Sans ça, on arrive sur « Abonnement / mois » sans plus savoir de quel
   client on lit la ligne — et sur dix-huit colonnes, ça arrive vite.

   ⚠️ Le fond opaque n'est pas décoratif : sans lui, les colonnes qui défilent
   passeraient SOUS le nom et le rendraient illisible au lieu de le protéger.
   Le filet à droite montre où s'arrête la colonne figée. */
.t-clients th:first-child,
.t-clients > tbody > tr:not(.cl-detail) > td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--card);
  box-shadow: 1px 0 0 var(--divider);
}

/* ── La largeur de CET écran, et d'aucun autre ─────────────────────────

   ⚠️ Le cadre commun bride le contenu à 1180 px, et c'est un bon réglage :
   au-delà, une ligne de texte devient pénible à lire. Mais la maquette de
   Marine occupe toute la largeur, et pour cause — un tableau de dix-huit
   colonnes n'est pas un texte. À 1180 px, sa barre de filtres se repliait
   sur deux niveaux et « Bascule » sortait du cadre : le défaut même qu'elle
   signalait.

   ⚠️ La règle est PORTÉE PAR LE CONTENU (`:has(.cl-filtres)`) plutôt que par
   une classe posée sur la coquille. Elle ne peut donc pas s'appliquer par
   erreur à un écran qui n'est pas celui-ci, et les écrans de lecture gardent
   leur 1180 px. Un navigateur sans `:has()` garde aussi le 1180 px : plus
   étroit, jamais cassé. */
@supports selector(:has(*)) {
  .principal .page:has(.cl-filtres) { max-width: 1700px; }
}

/* Le nom du client porte le lien ; le domaine vit sous lui, en retrait.
   Deux lignes plutôt qu'une seule coupée par un point : le domaine est ce
   qui identifie sûrement un dossier quand deux communes se ressemblent. */
.cl-nom {
  font-weight: 600;
  display: block;
}
.cl-domaine {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* ⚠️ « non affecté » se VOIT. C'est la seule information qui n'apparaît
   nulle part ailleurs, et elle a un délai de 48 heures ouvrées. L'écrire en
   pâle comme une absence banale reviendrait à la masquer. */
.cl-personne {
  color: var(--hex-pink-deep);
  font-style: italic;
}

.t-clients > tbody > tr:not(.cl-detail) > td { vertical-align: top; }

/* ── Le dépliage par le chevron, SANS JavaScript ───────────────────────

   ⚠️ Le geste vient de la capture de Marine : le chevron ▶ collé au nom,
   comme dans un explorateur de fichiers. L'ancienne version posait une ligne
   « 7 prestations — voir le détail » SOUS chaque client, ce qui doublait la
   hauteur du tableau avant même qu'on ait rien ouvert.

   ⚠️ LA MÉCANIQUE, ET SON REPLI. Une case à cocher invisible porte l'état ;
   `:has()` permet à la ligne de détail de réagir à une case qui vit dans la
   ligne PRÉCÉDENTE. Un navigateur qui ne connaît pas `:has()` n'entre pas
   dans le `@supports` : il affiche alors TOUS les détails, dépliés. C'est le
   bon repli — tout montrer est gênant, ne rien pouvoir ouvrir est cassé. */
.cl-nom-ligne {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--s2);
}
.cl-exp {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}
.cl-chev {
  flex: none;
  width: 16px;
  cursor: pointer;
  color: var(--text-faint);
  font-size: var(--fs-xs);
  line-height: 1.5;
  user-select: none;
  transition: transform .12s var(--ease);
}
.cl-chev-vide { cursor: default; }
.cl-chev:hover { color: var(--primary); }
.cl-exp:focus-visible + .cl-chev {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.cl-exp:checked + .cl-chev {
  transform: rotate(90deg);
  color: var(--primary);
}
.cl-ico { flex: none; color: var(--text-faint); line-height: 1.5; }

@supports selector(:has(*)) {
  .t-clients > tbody > tr.cl-detail { display: none; }
  .t-clients > tbody > tr:has(.cl-exp:checked) + tr.cl-detail { display: table-row; }
}

/* La ligne de détail n'est pas une ligne de plus : c'est la suite de celle
   du dessus. D'où l'absence de bordure haute et le fond légèrement creusé. */
.cl-detail > td {
  border-top: none;
  background: var(--bg-subtle);
  padding: 0 var(--s4) var(--s4);
}

/* ⚠️ La jauge de charge n'est PAS redéfinie ici : l'écran réemploie
   `jauge-bloc` / `jauge-tete` / `jauge-pct`, qui existent déjà et servent
   ailleurs. Deux jauges à tenir, c'est une divergence programmée dont
   personne ne saurait dire laquelle des deux ment. */

/* ── La cellule d'avancement ───────────────────────────────────────────
   La `.tc` de la maquette (ligne 1535) : une barre DERRIÈRE le texte, et
   non à côté ni en dessous.

   ⚠️ Elle ne réemploie PAS `jauge-bloc` malgré la ressemblance du sujet.
   La jauge est un bloc à deux étages — une ligne de chiffres, puis une
   barre ; celle-ci est une seule boîte dont la barre est le FOND. Les
   détourner l'une pour l'autre donne un HTML juste, des tests verts et
   une cellule illisible : c'est exactement ce qui s'est payé le 25/09
   avec `.heures`. On lit ce qu'une classe FAIT, jamais ce que son nom
   suggère.

   ⚠️ `overflow: hidden` n'est pas décoratif : sans lui la barre déborde
   des coins arrondis et bave sur la cellule voisine. */
.cl-avance {
  position: relative;
  overflow: hidden;
  min-width: 8.5rem;
  padding: var(--s1) var(--s2);
  border-radius: var(--r-sm);
  background: var(--bg-subtle);
}
.cl-avance-part {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--info-bg);
}
/* Tout est fait : la barre passe au vert, sans que le texte change. */
.cl-avance-fini { background: var(--success-bg); }
/* ⚠️ `position: relative` sur les deux lignes de texte, sinon la barre —
   qui est en `absolute` — les recouvre et la cellule paraît vide. */
.cl-avance-pct {
  position: relative;
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
.cl-avance-reste {
  position: relative;
  display: block;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* La seconde ligne d'une cellule — « dont 19 h MAN ». */
.cl-sous {
  display: block;
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

/* ── Le détail d'un client ─────────────────────────────────────────────
   Pas d'en-tête : quatre colonnes qui se lisent d'elles-mêmes, et la
   maquette n'en met pas non plus. */
.cl-detail-tete {
  margin: var(--s3) 0 var(--s2);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-muted);
}
/* ⚠️ Bridé en largeur, et vu en photographiant la page : l'écran fait
   maintenant 1700 px, et sans ce plafond l'intitulé d'une prestation se
   retrouvait à un mètre de son statut. Le regard ne fait plus le lien entre
   les deux bouts de la même ligne. */
.t-prestations { width: 100%; max-width: 72rem; border-collapse: collapse; }
.t-prestations td {
  padding: var(--s2) var(--s2) var(--s2) 0;
  border-bottom: 1px solid var(--divider);
  font-size: var(--fs-sm);
  vertical-align: middle;
}
.t-presta-nom  { width: 48%; color: var(--text-strong); }
.t-presta-qui  { width: 14%; }
.t-presta-etat { width: 20%; }
.t-presta-h    { width: 18%; text-align: right; white-space: nowrap; }
.cl-fiche { margin-top: var(--s3); }

/* ── Les statuts d'une prestation ──────────────────────────────────────
   ⚠️ Préfixe `etiq-st-` distinct des TONS d'étiquette de client
   (`etiq-grave`, `etiq-attention`) : deux vocabulaires, donc deux préfixes.
   Les mélanger ferait qu'un statut nouveau hériterait en silence d'une
   couleur qui n'a rien à voir. */
.etiq-st-realisee    { background: var(--success-bg); color: var(--hex-green-deep); }
.etiq-st-en_cours    { background: var(--info-bg);    color: var(--hex-blue-deep); }
.etiq-st-planifiee   { background: var(--info-bg);    color: var(--hex-blue-deep); }
.etiq-st-a_planifier { background: var(--warning-bg); color: var(--hex-orange-deep); }
.etiq-st-differee    { background: var(--warning-bg); color: var(--hex-orange-deep); }
.etiq-st-bloquee     { background: var(--danger-bg);  color: var(--hex-pink-deep); }
.etiq-st-annulee     { background: var(--chip-bg);    color: var(--text-muted); }

.t-prestations {
  margin: var(--s2) 0 var(--s3);
  font-size: var(--fs-sm);
}
.t-prestations th {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* ── L'écran « Clients », deuxième passe ─────────────────────────────── *
   Écrit le 2026-09-23 en regardant `docs/maquette/cockpit-maquette-reference.html`,
   après que Marine a signalé que l'écran s'en écartait beaucoup. Rien ici
   n'est inventé : les formes, les intitulés et les états viennent de là.

   ⚠️ Aucune couleur écrite à la main, y compris pour les pastilles de
   personnes. Une teinte recopiée ne suit ni le thème sombre ni une
   évolution de la charte, et elle ne se signale jamais : elle est
   simplement un peu fausse. */

/* Le sélecteur de colonnes : un <details>, donc aucun JavaScript. Il
   s'ouvre au clavier et continue de marcher si les scripts sont refusés. */
.cl-colonnes { position: relative; }
.cl-colonnes > summary {
  cursor: pointer;
  list-style: none;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--s1) var(--s3);
  font-size: var(--fs-sm);
  color: var(--text-strong);
  background: var(--card);
  white-space: nowrap;
}
.cl-colonnes > summary::-webkit-details-marker { display: none; }
.cl-colonnes > summary:hover { border-color: var(--primary); color: var(--primary); }
.cl-colonnes[open] > summary { border-color: var(--primary); color: var(--primary); }

/* Le panneau flotte au-dessus du tableau plutôt que de le pousser vers le
   bas : une liste qui saute de 200 px à l'ouverture fait perdre la ligne
   qu'on était en train de lire. */
/* ⚠️ DÉFAUT CORRIGÉ LE 2026-09-23, ET IL EXPLIQUE UN MORCEAU DU « DÉCALAGE ».
   Ce fond était écrit `var(--surface)` — un jeton qui N'EXISTE PAS dans la
   charte. Une variable CSS inconnue ne produit aucune erreur : la déclaration
   est simplement ignorée, et le panneau flottait donc SANS FOND, par-dessus
   les lignes du tableau. Rien ne le signalait, aucun test ne pouvait le voir.
   C'est exactement le défaut que la règle de la charte décrit : « une couleur
   qui ne se signale jamais, elle est simplement un peu fausse ».
   Un test interdit désormais d'employer un jeton non défini. */
.cl-colpan {
  position: absolute;
  right: 0;
  z-index: 5;
  margin-top: var(--s1);
  min-width: 270px;
  max-height: 70vh;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: var(--s3);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.cl-colpan-h {
  margin: var(--s2) 0 var(--s1);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--text-faint);
  font-weight: 600;
}
.cl-colpan-h:first-child { margin-top: 0; }
.cl-colpan-f {
  margin: var(--s3) 0 0;
  padding-top: var(--s2);
  border-top: 1px solid var(--divider);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}
.cl-colpan .btn { margin-top: var(--s2); }

/* ── L'interrupteur de la maquette ─────────────────────────────────────

   ⚠️ C'est une VRAIE case à cocher, seulement repeinte. Un interrupteur
   dessiné en <div> perd le clavier, le lecteur d'écran et l'envoi du
   formulaire d'un coup — et ça ne se voit sur aucune capture. */
.cl-colrow {
  display: flex;
  align-items: center;
  gap: var(--s3);
  font-size: var(--fs-sm);
  cursor: pointer;
  padding: var(--s1) 0;
}
.cl-colrow-lab { flex: 1 1 auto; }
.cl-colrow input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}
.cl-sw {
  flex: none;
  width: 34px;
  height: 18px;
  border-radius: var(--r-full);
  background: var(--border-strong);
  position: relative;
  transition: background .15s var(--ease);
}
.cl-sw::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: var(--r-full);
  background: var(--blanc);
  transition: transform .15s var(--ease);
}
.cl-colrow input:checked ~ .cl-sw { background: var(--primary); }
.cl-colrow input:checked ~ .cl-sw::after { transform: translateX(16px); }
/* ⚠️ Le clavier doit VOIR où il est : la case est invisible, donc c'est
   l'interrupteur qui porte le halo. */
.cl-colrow input:focus-visible ~ .cl-sw {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
/* Le nom du client ne se retire pas : cent dix-sept lignes sans identifiant,
   ce n'est plus un tableau. L'interrupteur reste allumé et ne réagit pas. */
.cl-colrow-verrou { cursor: not-allowed; }
.cl-colrow-verrou .cl-colrow-lab { color: var(--text-muted); }
.cl-colrow-verrou .cl-sw { background: var(--primary-soft); }

/* ── Le tri par colonne ────────────────────────────────────────────────
   L'en-tête entier est cliquable, et la flèche dit dans quel sens on est.
   ⚠️ La flèche « ↕ » des colonnes non triées n'est pas décorative : sans
   elle, rien n'indique qu'un en-tête se clique, et la fonction n'existe
   que pour ceux qui l'ont déjà trouvée. */
.cl-tri {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  color: inherit;
  text-decoration: none;
}
.cl-tri:hover { color: var(--primary); }
.cl-tri-fleche { font-size: var(--fs-xs); color: var(--text-faint); }
.cl-tri-ici { color: var(--primary); }
.cl-tri-ici .cl-tri-fleche { color: var(--primary); }

/* ── La pastille d'initiales ───────────────────────────────────────────
   Quatre teintes de la charte, choisies par le nom, donc stables. */
.cl-personne-ligne { display: inline-flex; align-items: center; gap: var(--s2); }
.cl-av {
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: var(--r-full);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-xs);
  font-weight: 700;
  /* ⚠️ Était `var(--surface)`, un jeton inexistant : les initiales
     héritaient donc de la couleur du texte au lieu d'être en clair sur la
     pastille. Même défaut que le fond du panneau, même cause. */
  color: var(--blanc);
  letter-spacing: .02em;
}
.cl-av-1 { background: var(--hex-pink); }
.cl-av-2 { background: var(--hex-blue); }
.cl-av-3 { background: var(--hex-green-deep); }
.cl-av-4 { background: var(--hex-orange-deep); }

/* Le dossier que personne ne suit porte un rond CREUX, pas une pastille
   pleine d'une couleur quelconque : l'absence doit se voir comme une
   absence, sinon elle se lit comme une personne de plus. */
.cl-av-vide {
  background: transparent;
  border: 1px dashed var(--hex-pink-deep);
  color: var(--hex-pink-deep);
}

/* ── Charge & couverture ───────────────────────────────────────────────
   La jauge de la maquette : pointées, couvertes, pourcentage, barre.
   Trois états, seuil d'alerte à 80 % — le même que « Mon temps », importé
   et non recopié côté Python. */
.jauge-bloc { min-width: 190px; display: flex; flex-direction: column; gap: var(--s1); }
.jauge-tete {
  display: flex;
  align-items: baseline;
  gap: var(--s1);
  flex-wrap: wrap;
}
.jauge-de { color: var(--text-muted); font-size: var(--fs-xs); }
.jauge-pct { margin-left: auto; font-weight: 700; font-size: var(--fs-sm); }
.jauge-ok      { color: var(--hex-green-deep); }
.jauge-warn    { color: var(--hex-yellow-deep); }
.jauge-over    { color: var(--hex-pink); }
.jauge-inconnu { color: var(--text-faint); }

/* La barre reprend la couleur de l'état. ⚠️ Ces règles viennent APRÈS
   `.jauge-faite`, sinon la couleur verte du cas courant gagnerait sur les
   deux autres états et un dépassement s'afficherait en vert. */
.jauge-faite.jauge-ok   { background: var(--hex-green); }
.jauge-faite.jauge-warn { background: var(--hex-yellow); }
.jauge-faite.jauge-over { background: var(--hex-pink); }

.cl-num { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* La ligne d'en-tête du dépliage, et le bouton qui mène à la fiche. */
.cl-detail-tete {
  margin: var(--s2) 0 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.cl-fiche { margin-bottom: var(--s3); }

/* ── LE CATALOGUE ──────────────────────────────────────────────────────
   Un tableau où chaque ligne est son propre formulaire. Les colonnes de
   saisie sont étroites et le nom est large : c'est le nom qu'on cherche du
   regard, et c'est lui qui porte les intitulés de 60 caractères de HubSpot.

   ⚠️ Le tableau défile HORIZONTALEMENT dans son cadre plutôt que de pousser
   la page : sept colonnes dont quatre de saisie ne tiennent pas sur un
   portable, et une page qui déborde se lit collée au bord. */
.t-catalogue { table-layout: auto; }
.t-catalogue th,
.t-catalogue td { padding: var(--s2) var(--s3); vertical-align: middle; }
.t-catalogue tbody tr { border-top: 1px solid var(--divider); }

.ct-nom { min-width: 18rem; font-weight: 600; }

/* ⚠️ CES LARGEURS ONT ÉTÉ TROUVÉES EN PHOTOGRAPHIANT LA PAGE le 23/09/2026,
   et rien d'autre ne les aurait trouvées. Les listes déroulantes se
   réduisaient à leur colonne : on lisait « Inte », « MAN », « Onboardi »,
   « — pas tra ». La page n'était pas en erreur, aucun test n'était rouge, et
   l'écran était pourtant inutilisable — on ne pouvait pas savoir ce qui
   était sélectionné.

   Les valeurs viennent du contenu réel : « Onboarding & intégration SI » est
   le plus long libellé de lot, « — pas tranché » le plus long choix de
   « qui la fait ». */
.ct-h    { width: 7rem; }
.ct-qui  { width: 11rem; }
.ct-lot  { width: 16rem; }
.ct-note { min-width: 16rem; }
.t-catalogue select,
.t-catalogue input[type="text"] { width: 100%; box-sizing: border-box; }

/* ⚠️ LA PAGE S'ÉLARGIT POUR CET ÉCRAN, et sans ça les largeurs ci-dessus ne
   valent rien : à 960 px, le tableau comprime ses colonnes pour tenir et les
   listes déroulantes se réduisent à « Intern », « Onboarding ». Mesuré en
   photographiant la page le 23/09/2026 — deux fois, parce que la première
   correction n'avait traité que les largeurs et pas la place disponible.

   Même motif que l'écran des clients : la règle est PORTÉE PAR LE CONTENU
   plutôt que par une classe posée sur la coquille, donc elle ne peut pas
   s'appliquer par erreur ailleurs. Un navigateur sans `:has()` garde la page
   étroite et le tableau défile dans son cadre : plus serré, jamais cassé. */
@supports selector(:has(*)) {
  .principal .page:has(.t-catalogue) { max-width: 1500px; }
}

/* ⚠️ « Rien » s'écrit, et s'écrit en gris : une case vide se confondrait
   avec une valeur nulle, et « 0 h » se lit comme une mesure alors que c'est
   une absence. C'est la règle que porte déjà la base. */
.ct-rien { color: var(--text-muted); font-style: italic; }

/* La ligne qui attend quelqu'un. Teinte d'attention, pas de danger : ce
   n'est pas une panne, c'est du travail qui n'a pas encore été fait. */
.ct-a-faire { background: var(--warning-bg); }


/* ─────────────────────────────────────────────────────────────────────
   LA VUE CHANTIERS — les cartes de l'écran Clients

   Un client mène plusieurs chantiers de front, et une ligne de tableau les
   écrase en une seule santé. 52 clients sur 82 sont dans ce cas au
   23/09/2026.

   ⚠️ AUCUNE règle de largeur de page ici, et ce n'est pas un oubli : cet
   écran porte déjà `.cl-filtres`, qui lui donne ses 1700 px plus haut dans
   cette feuille. Une seconde règle serait une deuxième vérité sur la même
   chose, et c'est celle-là qui finirait par diverger.
   ───────────────────────────────────────────────────────────────────── */

.ch-client { margin-bottom: var(--s6); }
.ch-client:last-child { margin-bottom: 0; }

/* L'en-tête d'un client. ⚠️ `flex-wrap` et pas d'espace élastique : le
   défaut a été payé le 23/09 sur la barre de filtres — un espace élastique
   avale toute la place restante et renvoie la fin de la ligne au niveau
   suivant, ce qui ne se voit qu'en photographiant la page. */
.ch-client-h {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  padding-bottom: var(--s2); margin-bottom: var(--s3);
  border-bottom: 1px solid var(--border);
}

.ch-client-n {
  font-size: var(--fs-lg); font-weight: 800; color: var(--text-strong);
  letter-spacing: -.02em; text-decoration: none;
}
.ch-client-n:hover { color: var(--primary); text-decoration: underline; }
.ch-client-n:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.ch-client-m { font-size: var(--fs-xs); color: var(--text-muted); }

/* Le compte de chantiers se range à droite, poussé par une marge auto —
   pas par un élément d'espacement, qui compterait comme un enfant de plus
   dans le retour à la ligne. */
.ch-client-x {
  margin-left: auto; font-size: var(--fs-xs); color: var(--text-muted);
}

/* La grille. 268 px est la valeur de la maquette : trois cartes sur un
   écran large, une seule sur un portable, sans rupture à régler. */
.ch-grille {
  display: grid; gap: var(--s3);
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
}

.ch-carte {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--s4); min-width: 0;
}
.ch-carte:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }

.ch-carte-h {
  display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s3);
}

/* ⚠️ La pastille double le NOM du chantier écrit juste à côté, elle ne le
   remplace pas. Une couleur seule ne se lit pas quand on distingue mal les
   teintes, et ne survit pas à une impression en noir et blanc. Le mot reste,
   toujours. */
.ch-pastille {
  width: 9px; height: 9px; border-radius: 2px; flex: none;
  background: var(--text-faint);
}

/* ── Les cinq lots, et pourquoi la couleur dit le TYPE et non l'état ──
   Demande de Marine du 24/09/2026, née d'une comparaison entre sa maquette
   et l'écran livré. Les cartes se coloraient par ÉTAT ; comme 107 chantiers
   sur 174 sont livrés, la page entière était verte et plus rien ne s'y
   distinguait. Sa maquette colore par lot, et c'est ce qui la rend lisible
   d'un coup d'œil.

   ⚠️ L'ÉTAT N'EST PAS PERDU, il est porté ailleurs — par l'étiquette en
   toutes lettres, et par le liseré des cartes qui coincent. Un signal a
   changé de support, aucun n'a disparu.

   ⚠️ Les teintes de la maquette sont reprises SAUF pour la chefferie : la
   sienne est le violet que la charte INTERDIT nommément, voisin à un cheveu
   de la teinte du logo de Marine. On prend le violet officiel à la place.

   ⚠️⚠️ ET SON CODE NE S'ÉCRIT PAS ICI, PAS MÊME DANS CE COMMENTAIRE. Payé le
   24/09/2026 : trois tests rouges pour une explication. Un test qui lit un
   fichier ne sait pas ce qu'est un commentaire, et il a raison de ne pas le
   savoir — sinon la même explication servirait à cacher une vraie faute.
   Le code interdit est nommé dans `tests/test_charte.py`, à sa place. */
.ch-lot-chefferie .ch-pastille { background: var(--hex-violet-clair); }
.ch-lot-onboarding_si .ch-pastille { background: var(--hex-blue); }
.ch-lot-messagerie .ch-pastille { background: var(--hex-pink); }
.ch-lot-formations .ch-pastille { background: var(--hex-green); }
.ch-lot-cloture .ch-pastille { background: var(--text-muted); }

/* Le chantier qui demande un geste porte un liseré, pas un fond plein : un
   fond de couleur sur toute la carte rendrait son texte plus difficile à
   lire, pour un signal que la pastille et l'étiquette donnent déjà. */
.ch-bloque  { border-left: 3px solid var(--danger); }
.ch-differe { border-left: 3px solid var(--warning); }

.ch-carte-n {
  font-size: var(--fs-md); font-weight: 700; color: var(--text-strong);
  margin: 0; min-width: 0; overflow-wrap: anywhere;
}

/* Les cinq états, dans le vocabulaire des étiquettes de prestation —
   ⚠️ préfixe `etiq-ch-` et non `etiq-` : les tons de client (`grave`,
   `attention`) et les états de chantier sont deux vocabulaires, et les
   faire partager un préfixe ferait qu'un état neuf hériterait en silence
   d'une couleur qui n'a rien à voir. */
.etiq-ch-bloque  { background: var(--danger-bg);  color: var(--hex-pink-deep); }
.etiq-ch-differe { background: var(--warning-bg); color: var(--hex-orange-deep); }
.etiq-ch-encours { background: var(--info-bg);    color: var(--hex-blue-deep); }
.etiq-ch-avenir  { background: var(--chip-bg);    color: var(--text-muted); }
.etiq-ch-livre   { background: var(--success-bg); color: var(--hex-green-deep); }

.ch-avance {
  margin: 0 0 var(--s2); font-size: var(--fs-sm); color: var(--text-body);
  font-weight: 600;
}

.ch-barre {
  height: 6px; border-radius: var(--r-full); background: var(--chip-bg);
  overflow: hidden; margin-bottom: var(--s3);
}
.ch-barre > span {
  display: block; height: 100%; background: var(--text-faint);
  border-radius: var(--r-full);
}

/* La barre suit la teinte de son lot. ⚠️ C'est elle, et non la pastille,
   qu'on voit en balayant l'écran : elle occupe toute la largeur de la carte.
   Colorer l'une sans l'autre donnerait une carte à deux couleurs. */
.ch-lot-chefferie .ch-barre > span { background: var(--hex-violet-clair); }
.ch-lot-onboarding_si .ch-barre > span { background: var(--hex-blue); }
.ch-lot-messagerie .ch-barre > span { background: var(--hex-pink); }
.ch-lot-formations .ch-barre > span { background: var(--hex-green); }
.ch-lot-cloture .ch-barre > span { background: var(--text-muted); }

.ch-heures {
  margin: 0 0 var(--s2); font-size: var(--fs-xs); color: var(--text-muted);
}

/* L'aveu : combien de prestations n'ont pas d'heures connues. Il s'affiche
   parce que c'est lui qui empêche de lire un total comme complet. */
.ch-aveu { font-style: italic; }

.ch-coince {
  margin: 0 0 var(--s2); font-size: var(--fs-xs); font-weight: 700;
  color: var(--hex-pink-deep);
}

.ch-qui { margin: 0; font-size: var(--fs-xs); color: var(--text-muted); }

/* ── La vue Tableau ───────────────────────────────────────────────────────
   Les mêmes cartes que la vue Chantiers — `.ch-carte` et ses états sont
   réutilisés tels quels — mais rangées en cinq colonnes d'état.

   ⚠️ Le vocabulaire des COLONNES a son propre préfixe `tb-`, séparé de
   `ch-` : une colonne et une carte ne sont pas la même chose, et les faire
   partager un préfixe ferait qu'une règle de carte s'appliquerait un jour à
   une colonne sans que personne l'ait voulu.

   ⚠️ Les cinq colonnes tiennent de front sur un écran large et se replient
   ensuite. Elles ne disparaissent jamais : une colonne absente ferait croire
   que l'état n'existe pas. */
.tb {
  display: grid; gap: var(--s3); align-items: start;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
@media (max-width: 1400px) { .tb { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 900px)  { .tb { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .tb { grid-template-columns: 1fr; } }

.tb-col {
  background: var(--bg-subtle); border: 1px solid var(--border);
  border-radius: var(--r-lg); min-width: 0;
}

.tb-h {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s3); border-bottom: 1px solid var(--border);
}

/* ⚠️ La pastille double le mot de la colonne, elle ne le remplace pas :
   même raison que sur les cartes — une couleur seule ne se lit pas quand on
   distingue mal les teintes, et ne survit pas à une impression. */
.tb-d {
  width: 9px; height: 9px; border-radius: 2px; flex: none;
  background: var(--text-faint);
}
.tb-bloque  .tb-d { background: var(--danger); }
.tb-differe .tb-d { background: var(--warning); }
.tb-encours .tb-d { background: var(--info); }
.tb-avenir  .tb-d { background: var(--text-faint); }
.tb-livre   .tb-d { background: var(--success); }

.tb-l {
  margin: 0; font-size: var(--fs-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted);
}

.tb-n {
  margin-left: auto; font-size: var(--fs-xs); font-weight: 800;
  padding: 1px 7px; border-radius: var(--r-full);
  background: var(--card); color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

/* Le total d'heures de la colonne. Il se lit APRÈS le compte de cartes —
   « combien de chantiers » d'abord, « combien d'heures » ensuite — et il est
   volontairement discret : c'est un ordre de grandeur, pas une alerte. */
.tb-x {
  font-size: var(--fs-xs); color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* ⚠️ L'aveu vit dans le CORPS de la colonne, au-dessus des cartes — défaut
   trouvé en PHOTOGRAPHIANT l'écran : dans l'en-tête, il faisait grossir la
   barre de titre d'une seule colonne et les cinq ne commençaient plus à la
   même hauteur. Même italique que sur les cartes, pour qu'il se reconnaisse
   d'un écran à l'autre. */
.tb-aveu {
  margin: 0; font-style: italic;
  font-size: var(--fs-xs); color: var(--text-faint);
}

.tb-b {
  padding: var(--s2); display: flex; flex-direction: column; gap: var(--s2);
  min-height: 70px;
}

/* Une colonne vide le DIT. Vide et muette, elle se lirait comme un écran à
   moitié chargé. */
.tb-v {
  margin: 0; padding: var(--s4) 0; text-align: center;
  font-size: var(--fs-xs); font-style: italic; color: var(--text-faint);
}

/* Le nom du chantier est plus court ici que sur la vue Chantiers : la carte
   est dans une colonne, pas dans une grille pleine largeur. */
/* ⚠️ `align-items: baseline` et non `center` : le titre passe à deux lignes
   pour « Onboarding & intégration SI », et centrer collerait alors la pastille
   au milieu de la hauteur, loin du premier mot qu'elle qualifie. */
.tb-carte-n {
  font-size: var(--fs-sm);
  display: flex; align-items: baseline; gap: var(--s2);
}

.tb-client {
  display: block; margin: 3px 0 var(--s2);
  font-size: var(--fs-xs); color: var(--hex-blue-deep);
}

/* ── Le rattrapage des jalons ────────────────────────────────────────────

   L'écran de saisie groupée : tous les déploiements sur une page, pour ne
   pas en ouvrir cent dix-sept.

   ⚠️ LE TABLEAU DÉFILE DANS SON CADRE, il n'élargit pas la page. Sur 117
   lignes de quatre colonnes, élargir la coquille comme le fait l'écran du
   catalogue n'apporterait rien — les colonnes sont peu nombreuses — et
   rendrait la page inconfortable à lire de haut en bas, ce qui est
   justement ce qu'on y fait. */
.t-jalons { overflow-x: auto; }

/* ⚠️ La colonne des noms ne se comprime pas. Sans largeur, « Communauté de
   communes du Pays de ... » replie sur quatre lignes et le tableau devient
   deux fois plus haut qu'il n'a besoin.

   ⚠️⚠️ ET C'EST UN `th` DE LIGNE, DONC IL FAUT DÉFAIRE LE STYLE DES `th`.
   Trouvé en PHOTOGRAPHIANT la page le 2026-09-29, invisible autrement : la
   règle globale des `th` met en petites capitales grises — ce qui est juste
   pour un en-tête de COLONNE et faux pour un nom propre. « COMMUNAUTÉ DE
   COMMUNES DU PAYS DE MONTBÉLIARD AGGLOMÉRATION » se lisait mal sur deux
   lignes, et surtout le compte rendu des refus, lui, écrit le nom
   normalement : le même client s'écrivait de DEUX façons sur la même page, et
   on ne retrouvait plus du regard la ligne que le refus désignait.

   La bordure aussi : `th` la tire de `--border-strong` et `td` de
   `--divider`. Sur la dernière ligne, le trait changeait d'épaisseur au
   milieu du tableau. */
.tj-client {
  width: 22rem;
  text-align: left;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--text-strong);
  border-bottom: 1px solid var(--divider);
}

/* Combien de dates manquent, sous le nom. ⚠️ Écrit en toutes lettres et pas
   en pastille colorée : c'est une information de travail — « il te reste ça
   à faire » —, pas une alerte. Une pastille rouge sur 117 lignes ferait une
   page entièrement rouge, qui ne signale plus rien. */
.tj-manque {
  display: block; margin-top: 2px;
  font-size: var(--fs-xs); font-weight: 400; color: var(--text-muted);
}

.t-jalons input[type="date"] { width: 100%; box-sizing: border-box; }

.tj-envoi { margin: var(--s4) 0; }

/* ══ ADMINISTRATION — la barre des six onglets ═══════════════════════════
   ⚠️ LIGNES DE L'ONGLET « ADMINISTRATION ». Préfixe `ad-`, et lui seul : ce
   fichier est partagé en lignes entre les sessions (`CLAUDE.md` §6.1), et un
   préfixe commun rendrait une correction de l'un visible chez l'autre.

   ⚠️ Pourquoi des règles à soi plutôt que les classes `cl-vue*` de l'écran
   Clients, qui ressemblent à ça. Elles appartiennent à Clients : le jour où
   cette session-là les retouchera, l'écran Administration bougerait sans que
   personne n'ait rien demandé, et sans qu'aucun test ne rougisse.

   ⚠️ Et aucune couleur écrite à la main : que des jetons. Un code hexadécimal
   recopié ne suit ni le thème sombre ni une évolution de la charte — il est
   simplement un peu faux, et ne se signale jamais. */
.ad-onglets {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1);
  margin-bottom: var(--s5);
  border-bottom: 1px solid var(--divider);
}

/* ⚠️ Les cinq onglets sans contenu ont EXACTEMENT la même apparence que celui
   qui en a. Les griser dirait « indisponible » là où la vérité est « pas
   encore construit » — et un onglet qui a l'air désactivé ne se clique pas,
   donc Marine ne lirait jamais ce qu'il annonce. */
.ad-onglet {
  padding: var(--s2) var(--s3);
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-size: var(--fs-md);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--ease), border-color var(--ease);
}

.ad-onglet:hover { color: var(--text-strong); }

/* ⚠️ L'onglet où l'on est se marque par le trait ET par la graisse, pas par
   la seule couleur : un repère qui ne tient qu'à une teinte disparaît pour
   qui distingue mal les couleurs. */
.ad-onglet-ici {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 600;
}

/* Ce que l'onglet en chantier annonce. ⚠️ En retrait et en petit : c'est une
   promesse, pas une alerte — la mettre au même poids que l'avis ferait lire
   deux messages d'égale importance là où il n'y en a qu'un. */
.ad-promesse {
  margin: var(--s4) 0 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* ═══════════════════════════════════════════════════════════════════════
   LE PLANNING — le Gantt de tous les projets
   ═══════════════════════════════════════════════════════════════════════

   ⚠️ CE BLOC EST EN FIN DE FICHIER, ET IL Y RESTE. Plusieurs sessions
   écrivent dans cette feuille en même temps ; chacune ajoute à la fin et
   ne réordonne rien au-dessus de sa zone. Un simple reformatage transforme
   un ajout tranquille en conflit sur tout le fichier.

   ⚠️ LES SÉLECTEURS « dm-gantt2-* » VIENNENT DE LA MAQUETTE DE MARINE
   (`docs/maquette/cockpit-maquette-reference.html`), qui les tient
   elle-même de Mon Pilote. Ils ne sont PAS renommés aux noms de Cockpit :
   la maquette le demande, et elle en donne la raison — « une réécriture
   est une occasion de diverger ». Les valeurs sont les siennes aussi :
   26 px par jour, 400 px de libellés, barres de 20 px.
   Ce qui est propre à cet écran est préfixé « pl- ».

   ⚠️ AUCUNE COULEUR EN DUR. Les deux teintes de livraison sont celles que
   la maquette emploie dans sa propre prose : le bureau collaboratif en
   vert, la messagerie en rose — et ce sont des jetons de la charte, pas
   des codes recopiés de la feuille transplantée. */

/* ── La barre du haut ─────────────────────────────────────────────── */
.pl-barre {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s4);
}
.pl-periode { font-weight: 700; color: var(--text-strong); }
.pl-nav { display: inline-flex; gap: var(--s2); }
.pl-filtre { display: inline-flex; align-items: center; gap: var(--s2); }
.pl-lab { color: var(--text-muted); font-size: var(--fs-sm); }
.pl-compte { margin-left: auto; color: var(--text-muted); font-size: var(--fs-sm); }

/* ── La carte qui porte la grille ─────────────────────────────────── */
.dm-lot-client {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  /* ⚠️ La maquette écrit ici l'ombre en clair, « rgba(49,8,76,.05) ». C'est
     le jeton --shadow-sm de la charte à un centième près, et la batterie du
     projet l'a refusée à juste titre : un code recopié ne suit ni le thème
     sombre ni une évolution de la charte. On prend le jeton. */
  box-shadow: var(--shadow-sm);
  /* ⚠️ Le défilement horizontal vit ICI, pas sur la page. Un Gantt qui
     fait défiler le corps entier emmène la barre latérale avec lui. */
  overflow-x: auto;
}

/* ── La grille ────────────────────────────────────────────────────────
   ⚠️ LES FONDS DE JOURS SONT PEINTS PAR UN DÉGRADÉ, PAS PAR UN ÉLÉMENT
   PAR JOUR. La maquette pose un <div> par jour et par rangée ; elle
   montre huit clients, le parc réel en compte cent quarante, et le même
   procédé y produirait trente-neuf mille éléments. Le dégradé donne
   exactement le même rendu pour un seul.

   Le calage : `--jour0` est le jour de semaine du premier jour affiché
   (0 = lundi). Décaler l'origine de `jour0` colonnes vers la gauche fait
   tomber la bande grise sur samedi et dimanche, quelle que soit la
   fenêtre. Sans ce décalage, les week-ends se peignent un jour à côté —
   et rien ne le signale, la grille a simplement l'air normale. */
.dm-gantt2 {
  --daycol: 26px;
  --labelcol: 400px;
  /* ⚠️ `--njours` et `--jour0` ne sont PAS des jetons de la charte : ce sont
     deux COMPTES, posés en style sur l'élément par le gabarit — le nombre de
     colonnes affichées, et le jour de semaine de la première (0 = lundi).
     Ils sont déclarés ici avec une valeur de repli pour deux raisons : la
     grille tient debout si le gabarit oublie de les poser, et la batterie
     refuse — à juste titre — toute variable employée sans être définie, parce
     qu'un navigateur ignore une variable inconnue EN SILENCE. */
  --njours: 45;
  --jour0: 0;
  position: relative;
  min-width: calc(var(--labelcol) + var(--daycol) * var(--njours));
  background-image:
    repeating-linear-gradient(to right,
      transparent 0, transparent calc(var(--daycol) * 5),
      var(--bg-subtle) calc(var(--daycol) * 5), var(--bg-subtle) calc(var(--daycol) * 7)),
    repeating-linear-gradient(to right,
      var(--divider) 0, var(--divider) 1px,
      transparent 1px, transparent var(--daycol));
  background-position: calc(var(--labelcol) - var(--jour0) * var(--daycol)) 0;
}

.dm-gantt2-row {
  display: grid;
  grid-template-columns: var(--labelcol) repeat(var(--njours), var(--daycol));
  align-items: center;
  min-height: 34px;
  border-bottom: 1px solid var(--divider);
}
.dm-gantt2-row > * { grid-row: 1; }

/* ── Les deux bandes d'en-tête ───────────────────────────────────────
   Elles gardent UNE CELLULE PAR JOUR, contrairement au corps : elles
   portent du texte, un dégradé ne sait pas en écrire. */
.dm-gantt2-head {
  background: var(--bg-subtle);
  position: sticky;
  top: 0;
  z-index: 3;
  min-height: 26px;
}
.dm-gantt2-monthband { min-height: 22px; }
.dm-gantt2-month {
  text-align: center;
  font-size: 11px;
  font-weight: 800;
  color: var(--text-muted);
  border-left: 1px solid var(--border);
  background: var(--bg-subtle);
  text-transform: uppercase;
  letter-spacing: .03em;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dm-gantt2-daynum {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.1;
  font-size: 9.5px;
  color: var(--text-faint);
  border-left: 1px solid var(--divider);
}
.dm-gantt2-daynum .pl-num { font-weight: 700; }
.dm-gantt2-daynum.weekend { opacity: .7; }
.dm-gantt2-daynum.today {
  background: var(--primary-soft);
  color: var(--text-strong);
  font-weight: 800;
  border-radius: var(--r-md);
}

/* ── La colonne des libellés ─────────────────────────────────────────
   Collée à gauche : on fait défiler les mois, jamais le nom du client.
   Un Gantt dont le nom disparaît au défilement oblige à revenir en
   arrière pour savoir de qui on parle. */
.dm-gantt2-label {
  grid-column: 1;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: 0 var(--s3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  position: sticky;
  left: 0;
  background: var(--card);
  z-index: 7;
  height: 100%;
}
.dm-gantt2-head .dm-gantt2-label { background: var(--bg-subtle); z-index: 8; }
.dm-gantt2-label .name {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-strong);
  overflow: hidden;
  text-overflow: ellipsis;
}
.dm-gantt2-label.epic .name { font-weight: 800; }
.dm-gantt2-label.indent1 { padding-left: 26px; }
.pl-etape {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  flex-shrink: 0;
}

/* ── Les barres ───────────────────────────────────────────────────── */
.dm-gantt2-bar {
  height: 20px;
  border-radius: 5px;
  display: flex;
  align-items: center;
  padding: 0 7px;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--card);
  white-space: nowrap;
  overflow: hidden;
  z-index: 1;
}
.dm-gantt2-bar.encours { background: var(--hex-blue); }

/* ⚠️ Une barre coupée par le bord de la fenêtre le DIT. Sans ce repère,
   un projet de six mois vu sur six semaines a l'air de commencer le
   premier jour affiché — ce qui est faux, et se lit comme une mesure. */
.pl-coupe-g { border-top-left-radius: 0; border-bottom-left-radius: 0;
              border-left: 3px solid var(--hex-violet); }
.pl-coupe-d { border-top-right-radius: 0; border-bottom-right-radius: 0;
              border-right: 3px solid var(--hex-violet); }

/* Les lots : la même barre, en plus fin et en teintes douces — ils sont
   SOUS leur projet, ils ne doivent pas lui voler l'œil. */
.dm-lot-row .dm-gantt2-bar { height: 12px; font-size: var(--fs-xs); }
.pl-lot-chefferie     { background: var(--hex-violet-clair); }
.pl-lot-onboarding_si { background: var(--hex-blue-light-deep); }
.pl-lot-messagerie    { background: var(--hex-pink); }
.pl-lot-formations    { background: var(--hex-yellow-deep); }
.pl-lot-cloture       { background: var(--hex-green-deep); }

/* ⚠️ « Sans date » s'écrit, ne se masque pas : un portefeuille qui cache
   ses projets sans date a l'air plus avancé qu'il n'est. */
.pl-sans-date {
  font-size: var(--fs-xs);
  color: var(--text-faint);
  font-style: italic;
  padding-left: var(--s3);
}

/* ── Les deux dates surlignées ────────────────────────────────────────
   ⚠️ DEMANDE EXPLICITE DE MARINE, formulée plusieurs fois. Chacune porte
   un losange ET un trait, et la légende les annonce : la maquette note
   elle-même qu'un glyphe qu'aucune légende n'annonce est un glyphe
   qu'il faut deviner.

   Le trait est ancré sur le BLOC DU CLIENT, pas sur la grille entière :
   posé sur toute la grille, il traverserait les projets des voisins, qui
   n'ont pas basculé ce jour-là. */
.dm-gantt-epic { position: relative; }
.dm-gantt-epic + .dm-gantt-epic { border-top: 2px solid var(--border); }

/* ── Le pli d'un client ───────────────────────────────────────────────
   ⚠️ REPLIÉ PAR DÉFAUT, comme la maquette. Déplier d'office multiplierait
   la hauteur par six : cent quarante clients feraient huit cent quarante
   lignes. C'est l'écart le plus visible qu'a donné la comparaison
   côte à côte avec la maquette, le 2026-10-02.

   `<details>` : le pli marche sans JavaScript, au clavier comme à la
   souris, et un lecteur d'écran annonce « développé » / « réduit » seul. */
.pl-sommaire { cursor: pointer; list-style: none; }
.pl-sommaire::-webkit-details-marker { display: none; }
.pl-sommaire::marker { content: ""; }
.pl-sommaire:hover .name { color: var(--primary); }
.pl-sommaire:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: -3px; }
.dm-chevron {
  display: inline-block;
  transition: transform .15s;
  color: var(--text-muted);
  font-size: 11px;
  width: 11px;
  flex-shrink: 0;
}
.dm-gantt-epic[open] .dm-chevron { transform: rotate(90deg); }

/* Le conseiller, dans la ligne du client : la maquette le porte dans la
   barre ; ici il vit dans le libellé, parce qu'une barre d'un jour ne
   peut rien écrire — et une barre d'un jour, ça existe. */
.pl-cn {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  background: var(--chip-bg);
  border-radius: var(--r-full);
  padding: 1px 8px;
  flex-shrink: 0;
}

/* La légende, repliée elle aussi — la maquette la replie, et son résumé
   annonce ce qu'elle contient. */
.pl-leg { margin-top: var(--s4); }
.pl-leg > summary {
  cursor: pointer;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.dm-gantt2-marker {
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.dm-gantt2-marker .mk {
  width: 9px;
  height: 9px;
  transform: rotate(45deg);
  box-shadow: 0 0 0 2px var(--card);
}
.dm-gantt2-vline {
  position: absolute;
  /* ⚠️ Le trait démarre SOUS la ligne du projet, comme dans la maquette.
     Posé à partir du haut, son étiquette passe par-dessus la barre du
     projet et masque ses dates — vu dans le navigateur le 2026-10-02, et
     invisible pour la batterie : les classes sont les mêmes. */
  top: 34px;
  bottom: 0;
  width: 2px;
  z-index: 4;
  pointer-events: none;
}
.dm-gantt2-vline .vlbl {
  position: absolute;
  top: 0;
  left: 3px;
  font-size: 8.5px;
  font-weight: 800;
  white-space: nowrap;
  padding: 1px 5px;
  border-radius: 0 5px 5px 0;
  color: var(--card);
}
.pl-liv-vert .mk, .pl-liv-vert .vlbl { background: var(--hex-green-deep); }
.pl-liv-vert.dm-gantt2-vline { background: var(--hex-green-deep); }
.pl-liv-rose .mk, .pl-liv-rose .vlbl { background: var(--hex-pink); }
.pl-liv-rose.dm-gantt2-vline { background: var(--hex-pink); }

/* La colonne du jour, sur toute la hauteur. */
.pl-today {
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--daycol);
  background: var(--primary-soft);
  opacity: .45;
  z-index: 0;
  pointer-events: none;
}

/* ── La légende ───────────────────────────────────────────────────── */
.pl-legende {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s4);
  margin-top: var(--s4);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.pl-lg { display: inline-flex; align-items: center; gap: 6px; }
.pl-lg i { display: inline-block; width: 12px; height: 9px; border-radius: 3px; }
.pl-ex-projet { background: var(--hex-blue); }
/* ⚠️ Les losanges de la LÉGENDE portent leur teinte EUX-MÊMES.
   Défaut vu dans le navigateur le 2026-10-02 : la couleur n'était posée que
   par « .pl-liv-vert .mk », un sélecteur de DESCENDANT. Dans le Gantt il y a
   bien un `.mk` à l'intérieur ; dans la légende il n'y en a pas, et les deux
   losanges étaient donc invisibles — une légende qui n'annonce rien, c'est
   exactement le défaut qu'elle devait corriger. La batterie ne pouvait pas
   le voir : les classes étaient toutes présentes. */
.pl-ex-losange { width: 9px !important; height: 9px !important;
                 border-radius: 0 !important; transform: rotate(45deg); }
.pl-ex-losange.pl-liv-vert { background: var(--hex-green-deep); }
.pl-ex-losange.pl-liv-rose { background: var(--hex-pink); }
.pl-ex-today { background: var(--primary-soft);
               box-shadow: inset 0 0 0 1px var(--primary); }
.pl-ex-we { background: var(--bg-subtle);
            box-shadow: inset 0 0 0 1px var(--border); }
.pl-sep { width: 1px; height: 14px; background: var(--border); }

/* ⚠️ Le mot qui évite qu'une grille vide se lise comme une panne. En évidence,
   pas en petit : c'est la seule chose à lire quand il n'y a rien d'autre. */
.pl-rien {
  margin: 0 0 var(--s4);
  padding: var(--s3) var(--s4);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: var(--r-md);
  color: var(--text-body);
  font-size: var(--fs-sm);
}

/* ⚠️ La note qui dit ce que l'écran DÉDUIT. Une règle déduite qui ne se
   montre pas se lit comme une mesure, et personne ne pense à la
   contester. Elle est en petit, mais elle est là. */
.pl-note {
  margin-top: var(--s4);
  max-width: 78ch;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: 1.5;
}
/* ═══════════════════════════════════════════════════════════════════════════
   LA FEUILLE DE TEMPS EN GRILLE
   ───────────────────────────────────────────────────────────────────────────
   Repris de la maquette de Marine (docs/maquette/cockpit-maquette-reference.html,
   bloc « Feuille de temps — capture 5 de Teamwork »), regle par regle.

   ATTENTION : ne jamais poser « .heures » sur un <td> de cette grille. Malgre
   son nom, c'est un conteneur flex (plus haut dans ce fichier) : posee sur une
   cellule, elle la sort du tableau et empile les colonnes verticalement. Le
   tableau devient illisible avec une batterie entierement verte — c'est
   arrive deux fois, les 30/09 et 01/10/2026.
   ═════════════════════════════════════════════════════════════════════════ */

.feuille-bar {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s4); flex-wrap: wrap;
}
.feuille-periode {
  font-size: var(--fs-md); font-weight: 700; color: var(--text-strong);
  font-variant-numeric: tabular-nums; margin: 0 var(--s2);
}
.feuille-pousse { flex: 1; }

/* En pleine largeur, la premiere colonne prendrait tout : on borne son
   etirement et on donne le reste aux jours, dont les cases sont des champs de
   saisie qui gagnent a etre larges. */
.feuille { width: 100%; border-collapse: collapse; table-layout: fixed; }

.feuille th {
  text-align: center; font-size: var(--fs-xs); font-weight: 700;
  color: var(--text-muted); padding: var(--s2) var(--s1);
  border-bottom: 1px solid var(--border); text-transform: none; letter-spacing: 0;
}
.feuille th:first-child {
  text-align: left; padding-left: var(--s4); width: 38%; min-width: 250px;
}
.feuille th.tot {
  text-align: right; padding-right: var(--s4);
  border-left: 1px solid var(--border); width: 96px;
}
.feuille th .d {
  display: block; font-size: var(--fs-lg); font-weight: 800;
  color: var(--text-strong); letter-spacing: -.02em;
}
.feuille th[data-aujourdhui="1"] .d { color: var(--primary); }
.feuille th[data-aujourdhui="1"] {
  background: var(--primary-soft); border-radius: var(--r-md) var(--r-md) 0 0;
}

.feuille td {
  padding: var(--s2) var(--s1); border-bottom: 1px solid var(--divider);
  text-align: center;
}
.feuille td:first-child { text-align: left; padding-left: var(--s4); }
.feuille td.tot {
  text-align: right; padding-right: var(--s4);
  border-left: 1px solid var(--divider); font-weight: 700;
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}
.feuille tbody tr:last-child td { border-bottom: 1px solid var(--border); }

.feuille tfoot td {
  padding: var(--s3) var(--s1); font-weight: 800; color: var(--text-strong);
  text-align: center; font-variant-numeric: tabular-nums;
}
.feuille tfoot td:first-child {
  text-align: right; padding-right: var(--s4); font-size: var(--fs-sm);
  color: var(--text-muted); font-weight: 600;
}
.feuille tfoot td.tot {
  text-align: right; padding-right: var(--s4);
  border-left: 1px solid var(--border); font-size: var(--fs-lg);
}

.feuille-client { font-weight: 700; color: var(--text-strong); }
.feuille-activite { font-size: var(--fs-xs); color: var(--text-muted); }
.feuille-activite b { color: var(--text-body); font-weight: 600; }

/* La case saisissable. Le « max-width » l'empeche de s'etirer sur toute la
   colonne : une case de huit centimetres pour y ecrire « 1,5 » se lit mal. */
.case {
  width: 100%; max-width: 84px; padding: 7px 4px; text-align: center;
  font-family: var(--mono); font-size: var(--fs-md);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-subtle); color: var(--text-strong);
  font-variant-numeric: tabular-nums; box-sizing: border-box;
}
.case:hover { border-color: var(--border-strong); }
.case:focus-visible { outline: 3px solid var(--hex-blue); outline-offset: 1px; }
/* Le temps attribue a quelqu'un d'autre : present, et visiblement pas le sien. */
.case[data-mien="0"] { background: var(--chip-bg); color: var(--text-muted); }
/* Une case que l'ecran a refuse d'ecrire : elle porte plusieurs saisies. */
.case[readonly] {
  background: var(--warning-bg); border-color: var(--warning);
  color: var(--text-body); cursor: not-allowed;
}

/* Les periodes « mois » et « annee » se lisent, elles ne se saisissent pas :
   « deux heures en septembre » ne designe aucun jour. */
.feuille-lu {
  text-align: center; font-variant-numeric: tabular-nums;
  font-size: var(--fs-md); font-weight: 600; color: var(--text-body);
}
.feuille .z { font-weight: 400; color: var(--text-faint); }

@media (max-width: 860px) {
  .feuille th:first-child { min-width: 150px; }
}
/* La mention sous une TETE DE COLONNE - « en attente de Mon Pilote » sur
   l'ecran Bascules. Elle etait collee au titre de la colonne et criee en
   capitales : un <span> reste en ligne, et `th` met tout son contenu en
   majuscules. On lisait donc « BASCULE - MON PILOTE EN ATTENTE DE MON
   PILOTE » d'un seul bloc.
   ⚠️ Mesure faite dans un vrai navigateur le 05/10/2026 : AUCUN test ne le
   voyait, et les deux tests qui gardent cette colonne etaient verts. Un
   test verifie qu'un texte est present, pas qu'il est lisible.
   Meme forme que les precedents du fichier (`.liste-corps .sous`,
   `.fiche dd .sous`) : c'est le CONTEXTE qui remet `.sous` en bloc. */
th .sous {
  display: block;
  margin: var(--s1) 0 0;
  text-transform: none;
  font-weight: 400;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}


/* ── Le planning des bascules, en liste datée ─────────────────────────────
   Repris de la maquette (vue « liste » de vueDatee), demandée en entier par
   Marine le 2026-10-05. ⚠️ AUCUNE COULEUR À LA MAIN : chaque état pose deux
   jetons — un pour le trait, un pour le texte.

   ⚠️ Les deux ne sont pas interchangeables. Les couleurs vives de la charte
   (--hex-green, --hex-orange) sont faites pour des aplats, pas pour du texte
   de 10 px : sur fond clair elles tombent sous le contraste lisible. Les
   variantes « deep » existent pour ça, et c'est pour ça qu'elles portent le
   texte des étiquettes. Un libellé qu'on devine n'est pas un libellé. */
.vd-l{--vd-trait: var(--border); --vd-texte: var(--text-muted)}
.vd-pt-faite,.vd-t-faite,.vd-e-faite{
  --vd-trait: var(--hex-green); --vd-texte: var(--hex-green-deep)}
.vd-pt-retard,.vd-t-retard,.vd-e-retard{
  --vd-trait: var(--hex-pink); --vd-texte: var(--hex-pink-deep)}
.vd-pt-prerequis_tenus,.vd-t-prerequis_tenus,.vd-e-prerequis_tenus{
  --vd-trait: var(--hex-blue); --vd-texte: var(--hex-blue-deep)}
.vd-pt-prerequis_a_finir,.vd-t-prerequis_a_finir,.vd-e-prerequis_a_finir{
  --vd-trait: var(--hex-orange); --vd-texte: var(--hex-orange-deep)}

/* La légende. */
.vd-lg{display:flex; gap:var(--s4); flex-wrap:wrap; font-size:var(--fs-sm);
  color:var(--text-muted); margin:var(--s3) 0}
.vd-lg span{display:inline-flex; align-items:center; gap:6px}
.vd-pt{width:9px; height:9px; border-radius:var(--r-full); display:block;
  flex:none; background:var(--vd-trait)}

/* Le compte, et ce qu'il n'affiche pas. */
.vd-n{font-size:var(--fs-sm); color:var(--text-muted); margin-bottom:var(--s3)}
.vd-n b{color:var(--text-strong)}
/* ⚠️ Ce que la vue ne montre pas doit SE VOIR : une bascule sans date est
   absente de tout axe daté, et un total qui l'ignore est un total faux. */
.vd-hors{color:var(--hex-orange-deep); font-weight:600}

/* Les sections et les mois. */
.vd-sec{margin-top:var(--s4)}
.vd-sh{font-size:var(--fs-xs); font-weight:800; text-transform:uppercase;
  letter-spacing:.08em; color:var(--text-faint); padding-bottom:var(--s2);
  border-bottom:1px solid var(--divider); margin:0}
.vd-mois{font-size:var(--fs-sm); font-weight:800; color:var(--text-strong);
  margin:var(--s4) 0 var(--s2); text-transform:capitalize}

/* Une ligne. */
.vd-l{display:flex; align-items:center; gap:var(--s3); padding:var(--s2) 0;
  border-bottom:1px solid var(--divider)}
.vd-l:last-child{border-bottom:0}
.vd-d{flex:none; width:46px; text-align:center; line-height:1.1}
.vd-d b{display:block; font-size:var(--fs-lg); font-weight:800;
  color:var(--text-strong); font-variant-numeric:tabular-nums}
.vd-d em{display:block; font-size:10px; font-style:normal;
  text-transform:uppercase; letter-spacing:.04em; color:var(--text-faint)}
/* Le filet de couleur double l'étiquette : la colonne de gauche se balaie
   sans lire, ce qui est exactement ce qu'on fait devant trente lignes. */
.vd-t{flex:1 1 auto; min-width:0; border-left:3px solid var(--vd-trait);
  padding-left:var(--s3)}
.vd-t > b{display:block; font-size:var(--fs-sm); font-weight:700}
.vd-s{display:block; font-size:var(--fs-xs); color:var(--text-muted);
  margin-top:2px}
/* L'étiquette d'état. */
.vd-e{flex:none; font-size:var(--fs-xs); font-weight:800;
  text-transform:uppercase; letter-spacing:.02em; padding:3px 10px;
  border-radius:var(--r-full); color:var(--vd-texte);
  border:1px solid var(--vd-trait); white-space:nowrap}
/* ⚠️ La date de Mon Pilote vient d'AILLEURS : son étiquette est en pointillé
   pour qu'on ne la confonde jamais avec un de nos états. « Nous avons engagé
   une date » et « le client l'a acceptée » ne sont pas la même phrase. */
.vd-lu{flex:none; font-size:var(--fs-xs); font-weight:700; padding:2px 9px;
  border-radius:var(--r-full); background:var(--bg-subtle);
  border:1px dashed var(--border-strong); color:var(--text-muted);
  white-space:nowrap}

/* ⚠️ Sous 720 px la ligne se replie au lieu de déborder : une étiquette
   poussée hors de l'écran est une information perdue, pas déplacée. */
@media (max-width: 720px){
  .vd-l{flex-wrap:wrap}
  .vd-t{flex:1 1 100%; order:2; margin-top:var(--s2)}
}
