/* Securex Suivi — feuille de la PWA.
   Tokens repris du thème securex-2026 (--sx-*) + mode sombre « base »
   documenté dans le handoff design_handoff_suivi_v1/README.md. */

@font-face{font-family:'Hanken Grotesk';font-style:normal;font-weight:700;font-display:swap;src:url('../assets/fonts/hanken-700-latin.woff2') format('woff2')}
@font-face{font-family:'Hanken Grotesk';font-style:normal;font-weight:800;font-display:swap;src:url('../assets/fonts/hanken-800-latin.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/plexsans-400-latin.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url('../assets/fonts/plexsans-500-latin.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/plexsans-600-latin.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:700;font-display:swap;src:url('../assets/fonts/plexsans-700-latin.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/plexmono-400-latin.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/plexmono-600-latin.woff2') format('woff2')}

:root{
  --sx-rouge:#d11b2a; --sx-rouge-hover:#b3121f; --sx-encre:#0f1b2d; --sx-human:#1e3a5f;
  --mono:'IBM Plex Mono',monospace; --sans:'IBM Plex Sans',sans-serif; --titres:'Hanken Grotesk',sans-serif;
}
/* Thème clair (terrain, direction, planificateur) */
.theme-clair{
  --fond:#eaeef3; --surface:#ffffff; --surface2:#f5f7fa;
  --bordure:#d7dee6; --bordure2:#c8d0da;
  --texte:#44566b; --titres-c:#0f1b2d; --muted:#5b6b7f; --muted2:#5b6b7f;
  --ok:#2e7d55; --ok-fond:#eaf3ed; --ok-bordure:#bcd8c9;
  --attente-mat:#9a5b00; --attente-mat-fond:#faf1e2; --attente-mat-bordure:#e6cf9f;
  --pret:#16688d; --pret-fond:#e7f1f6; --pret-bordure:#bfd9e6;
  --alerte:#b3121f; --alerte-fond:#fbeaea;
  --nav-actif:#f5f7fa; --nav-actif-texte:#0f1b2d;
}
/* Thème sombre (base opérateur, 16h–6h) */
.theme-sombre{
  --fond:#060d15; --surface:#0a1119; --surface2:#080f18;
  --bordure:#121c29; --bordure2:#1c2a3c;
  --texte:#b3c0cf; --titres-c:#eaeef3; --muted:#8494ab; --muted2:#707f97;
  --ok:#3f8f68; --ok-fond:#0b1420; --ok-bordure:#1c2a3c;
  --attente-mat:#d99a4e; --attente-mat-fond:#151009; --attente-mat-bordure:#3d2f1a;
  --pret:#5aa7cc; --pret-fond:#0b1420; --pret-bordure:#1c2a3c;
  --alerte:#ff5a66; --alerte-fond:rgba(209,27,42,.07);
  --nav-actif:#101c2c; --nav-actif-texte:#eaeef3;
}

*{box-sizing:border-box}
[hidden]{display:none !important}
html,body{height:100%}
body{margin:0;background:var(--fond);color:var(--texte);font-family:var(--sans);font-size:14px;-webkit-font-smoothing:antialiased}
a{color:var(--sx-human);text-decoration:none}
.theme-sombre a{color:#8fb3c9}
a:hover{color:var(--titres-c)}
::selection{background:var(--sx-rouge);color:#fff}
button{font-family:var(--sans)}
/* Transitions d'état douces sur les éléments interactifs (le hover était abrupt).
   Couleur seulement (jamais la mise en page) ; movement-free, ok reduced-motion. */
.nav-item,.onglet,.btn-primaire,.btn-secondaire,.btn-action,.btn-clore,.btn-fiche,.ligne-site,.ligne-bip,.ligne-appel,.pilule-langue,.pilule-filtre,.bandeau-nav,.pilule-variante,.seg,.btn-mini{transition:background-color .15s ease,border-color .15s ease,color .15s ease}
:focus-visible{outline:2px solid var(--sx-rouge);outline-offset:1px;box-shadow:0 0 0 4px rgba(209,27,42,.12)}
.mono{font-family:var(--mono)}
.kicker{font-size:10.5px;letter-spacing:.2em;color:var(--muted)}
.flex1{flex:1}
#root{height:100%}

/* ===== Mention d'amorçage « page non servie en HTTPS » (S219, 05/08/2026) =====
   Posée par le garde-fou d'index.html, donc AVANT tout module ES : ni t() ni
   dictionnaire, français en dur, seul texte de l'interface dans ce cas.
   Elle remplace un mur qui accusait le téléphone (« Navigateur trop ancien »)
   là où c'est la PAGE qui n'est pas en contexte sécurisé. Elle ne bloque pas.

   Pourquoi en FLUX et non en position:fixed — même leçon que le badge démo
   (l. 222) : en bas c'est la barre d'onglets, en haut c'est le bandeau ; aucune
   bande superposée ne peut se poser sans recouvrir quelque chose, et la hauteur
   du texte varie avec la largeur (2 ou 3 lignes), donc aucun décalage fixe ne
   tient. Le body devient une colonne flex, la mention prend sa hauteur
   naturelle, #root prend le reste : rien n'est recouvert, à toute largeur. */
.mention-amorcage{display:flex;align-items:flex-start;gap:12px;flex:none;padding:9px 13px;padding-top:calc(9px + env(safe-area-inset-top,0));background:#3d2f14;color:#f6ead2;font-size:12.5px;line-height:1.45;text-wrap:pretty}
.mention-amorcage b{color:#fff;font-weight:600}
.mention-amorcage button{margin-left:auto;flex:none;min-height:32px;background:transparent;border:1px solid rgba(246,234,210,.5);color:inherit;border-radius:8px;padding:5px 11px;font-size:12px;cursor:pointer}
.mention-amorcage button:hover{background:rgba(246,234,210,.14)}
/* 🔴 La classe est sur BODY, jamais sur <html> : coquilles.js et connexion.js
   RÉASSIGNENT documentElement.className à chaque changement de coquille, ce qui
   effaçait tout ce qu'on y posait. Voir le commentaire d'index.html. */
/* #root reçoit une hauteur EXPLICITE — pas flex:1, pas auto : .coquille-terrain
   est en height:100%, et un pourcentage ne se résout que contre une hauteur
   résolue. --mention-h est publiée par le garde-fou d'index.html (hauteur réelle
   de la bande, suivie au redimensionnement) et vaut 0 quand il n'y a pas de
   mention : toutes ces règles sont donc inertes hors HTTP simple. */
body.page-non-securisee #root{height:calc(100% - var(--mention-h,0px))}
/* 100dvh/100vh = TOUT le viewport : sous la mention, les coquilles débordent
   d'exactement sa hauteur et poussent les onglets hors de l'écran — l'incident
   même que le repli height:100% a corrigé (l. 133). Mesuré ici à 91 px de
   débordement, « Absences » et « Demandes » sous le bord. On y retombe. */
body.page-non-securisee .coquille-terrain,
body.page-non-securisee .coquille-base{height:100%}
@supports (height:100dvh){body.page-non-securisee .coquille-terrain{height:100%}}
/* Le badge démo et l'alerte globale sont fixés au HAUT du viewport : sans ceci
   ils se posent PAR-DESSUS la mention (mesuré — « Page non servie en… »
   illisible sous le badge « DÉMO »). Empilés, jamais superposés : même règle
   que celle écrite l. 262 pour ces deux-là. */
.racine-terrain .en-demo.page-non-securisee .badge-demo{top:calc(var(--mention-h,0px) + 5px)}
.racine-terrain .en-demo.page-non-securisee .alerte-globale{top:calc(var(--mention-h,0px) + 40px)}
body.page-non-securisee .alerte-globale{top:calc(var(--mention-h,0px) + 14px)}
@media (max-width:760px){.racine-connexion .en-demo.page-non-securisee .badge-demo{top:calc(var(--mention-h,0px) + 5px)}}

/* ===== Bandeau « bac à sable » (S459) =====================================
   Une COPIE de la production, sur le même hébergement. Deux confusions coûtent
   cher, et la seconde est la plus probable : s'exercer sur la vraie base, ou
   composer une vraie nuit dans la copie et rentrer chez soi — rien ne s'est
   passé. Ce bandeau est posé par js/environnement.js sur document.body, hors de
   la racine que le routeur vide : il survit à la navigation.

   ⛔ LE THÈME NE SUFFIT PAS : le sombre est déjà pris par le rôle opérateur.
   D'où une encre qui n'existe NULLE PART AILLEURS dans l'interface (violet) et
   des hachures — le signal universel du « ceci n'est pas le réel », lisible en
   vision périphérique, sans avoir à lire.

   EN FLUX, jamais en position:fixed — même leçon que la mention d'amorçage
   (l. 59) et que le badge démo (l. 303) : aucune bande superposée ne se pose
   sans recouvrir quelque chose. Il prend sa hauteur, #root prend le reste.

   ⚠️ IL NE DOIT PAS MANGER L'ÉCRAN : la composition du planning est déjà
   dense. Une seule ligne, 11,5 px, padding serré — mesuré à 26 px sur poste de
   bureau et 26 px à 390 px de large (le texte tient sur une ligne grâce au
   `min-width:0` + ellipse de la seconde moitié). */
.bandeau-base{display:flex;align-items:center;gap:9px;flex:none;padding:5px 12px;padding-top:calc(5px + env(safe-area-inset-top,0));font-size:11.5px;line-height:1.35;color:#ede9fe;background:#4c1d95;background-image:repeating-linear-gradient(135deg,rgba(255,255,255,.11) 0 7px,transparent 7px 15px)}
.bandeau-base-marque{flex:none;font-weight:700;letter-spacing:.13em;font-size:10.5px;color:#fff;background:rgba(0,0,0,.32);border-radius:4px;padding:2px 7px}
/* L'ellipse plutôt que le retour à la ligne : la marque « BAC À SABLE » est le
   signal, la phrase est l'explication. Sur un écran étroit, c'est la phrase qui
   cède — jamais la marque, jamais une seconde ligne prise à l'écran de travail. */
.bandeau-base-texte{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* #root reçoit une hauteur EXPLICITE, pas flex:1 : .coquille-terrain est en
   height:100% et un pourcentage ne se résout que contre une hauteur résolue.
   --bandeau-base-h est publiée par js/environnement.js (hauteur réelle, suivie
   au redimensionnement) et n'existe PAS hors bac à sable : toutes ces règles
   sont inertes en production. */
body.en-bac-a-sable #root{height:calc(100% - var(--bandeau-base-h,0px))}
/* Les deux bandes peuvent coexister (bac à sable servi en HTTP simple) :
   empilées, jamais superposées — #root cède la somme. */
body.en-bac-a-sable.page-non-securisee #root{height:calc(100% - var(--bandeau-base-h,0px) - var(--mention-h,0px))}
/* 100dvh/100vh = TOUT le viewport : sous le bandeau les coquilles déborderaient
   d'exactement sa hauteur et pousseraient la barre d'onglets hors de l'écran —
   l'incident que le repli height:100% a corrigé. */
body.en-bac-a-sable .coquille-terrain,
body.en-bac-a-sable .coquille-base{height:100%}
@supports (height:100dvh){body.en-bac-a-sable .coquille-terrain{height:100%}}
/* Le badge démo et l'alerte globale sont fixés au HAUT du viewport : sans ceci
   ils se posent PAR-DESSUS le bandeau. Même règle que pour la mention (l. 95) :
   empilés, jamais superposés. Les deux variables valent 0 quand la bande
   correspondante est absente, la somme est donc toujours juste. */
.racine-terrain .en-demo.en-bac-a-sable .badge-demo{top:calc(var(--bandeau-base-h,0px) + var(--mention-h,0px) + 5px)}
.racine-terrain .en-demo.en-bac-a-sable .alerte-globale{top:calc(var(--bandeau-base-h,0px) + var(--mention-h,0px) + 40px)}
body.en-bac-a-sable .alerte-globale{top:calc(var(--bandeau-base-h,0px) + var(--mention-h,0px) + 14px)}
@media (max-width:760px){.racine-connexion .en-demo.en-bac-a-sable .badge-demo{top:calc(var(--bandeau-base-h,0px) + var(--mention-h,0px) + 5px)}}

/* ===== Mention « une version plus fraîche est prête » (S492) ===============
   Le service worker bascule quand une coquille est mise en service ; l'onglet
   déjà ouvert, lui, continue d'exécuter les modules chargés à son démarrage.
   Personne ne le lui dit — d'où cette mention, posée par js/version-fraiche.js
   sur document.body, hors de la racine que le routeur vide : elle survit à la
   navigation entre écrans.

   ⛔ DISCRÈTE, ET C'EST LE MOT QUI COMMANDE : rien qui interrompe, aucune
   fenêtre modale, aucun rechargement automatique. Une bande d'une ligne, une
   encre sourde (l'ardoise de l'interface, pas une alarme), et un bouton — le
   rechargement appartient à l'utilisateur, qui seul sait s'il a un geste en
   cours. Une alerte rouge, la nuit, ferait cliquer dans l'urgence : exactement
   ce qu'on cherche à éviter.

   EN FLUX, jamais en position:fixed — troisième fois que ce projet paie la
   leçon (mention d'amorçage, badge démo, bandeau bac à sable) : aucune bande
   superposée ne se pose sans recouvrir quelque chose. Elle prend sa hauteur,
   #root prend le reste. */
.bandeau-version{display:flex;align-items:center;gap:10px;flex:none;padding:5px 12px;font-size:11.5px;line-height:1.35;color:#e6edf5;background:#243447;border-bottom:1px solid rgba(255,255,255,.08)}
/* L'ellipse plutôt qu'une seconde ligne : sur un écran étroit c'est la phrase
   qui cède, jamais le bouton — sans lui, la mention dit un problème et n'offre
   pas la sortie. */
.bandeau-version-texte{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bandeau-version button{margin-left:auto;flex:none;min-height:30px;background:transparent;border:1px solid rgba(230,237,245,.5);color:inherit;border-radius:8px;padding:4px 11px;font-size:11.5px;cursor:pointer}
.bandeau-version button:hover{background:rgba(230,237,245,.14)}
/* 🔴 LA CLASSE EST RÉPÉTÉE, ET C'EST VOULU. Les règles de hauteur de #root
   ci-dessus montent jusqu'à (0,3,1) — `body.en-bac-a-sable.page-non-securisee
   #root`. Une règle en (0,2,1) perdrait contre elles dans le cas même où elle
   compte : les trois bandes ensemble. Répétée, celle-ci pèse (0,4,1) et gagne
   dans les huit combinaisons, sans qu'on ait à écrire les huit — les trois
   variables valent 0px quand leur bande est absente, la somme est donc toujours
   juste. */
body.a-version-fraiche.a-version-fraiche.a-version-fraiche #root{height:calc(100% - var(--bandeau-version-h,0px) - var(--bandeau-base-h,0px) - var(--mention-h,0px))}
/* 100dvh/100vh = TOUT le viewport : sous la bande, les coquilles déborderaient
   d'exactement sa hauteur et pousseraient la barre d'onglets hors de l'écran. */
body.a-version-fraiche .coquille-terrain,
body.a-version-fraiche .coquille-base{height:100%}
@supports (height:100dvh){body.a-version-fraiche .coquille-terrain{height:100%}}
/* Le badge démo et l'alerte globale sont fixés au HAUT du viewport : sans ceci
   ils se poseraient PAR-DESSUS la bande. Empilés, jamais superposés — même
   règle que pour ses deux voisines. */
.racine-terrain .en-demo.a-version-fraiche .badge-demo{top:calc(var(--bandeau-version-h,0px) + var(--bandeau-base-h,0px) + var(--mention-h,0px) + 5px)}
.racine-terrain .en-demo.a-version-fraiche .alerte-globale{top:calc(var(--bandeau-version-h,0px) + var(--bandeau-base-h,0px) + var(--mention-h,0px) + 40px)}
body.a-version-fraiche .alerte-globale{top:calc(var(--bandeau-version-h,0px) + var(--bandeau-base-h,0px) + var(--mention-h,0px) + 14px)}
@media (max-width:760px){.racine-connexion .en-demo.a-version-fraiche .badge-demo{top:calc(var(--bandeau-version-h,0px) + var(--bandeau-base-h,0px) + var(--mention-h,0px) + 5px)}}

/* ===== Coquille base ===== */
.coquille-base{display:flex;height:100vh;min-width:1280px;overflow:hidden}
/* min-height:0 : sans lui, un enfant flex refuse de passer sous sa taille de
   contenu et RIEN ne défile. La colonne se tronque alors en silence. 17/07/2026 :
   un compte multi-rôles (navPourRoles fait l'UNION des rôles, pas 4-6 items) a
   jusqu'à 20 entrées → la colonne réclamait 1092px, plus qu'aucun écran du parc.
   Le badge de synchro, le profil et la bascule FR/MG étaient hors d'atteinte —
   overflow:hidden de .coquille-base, ni barre ni molette pour les rejoindre. */
.sidebar{width:210px;flex:none;display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--bordure);background:var(--surface2)}
/* La nav est la SEULE zone élastique et elle défile ; logo et pied ne se
   compriment jamais (flex:none) : le pied reste toujours visible en bas. */
.sidebar-logo{display:flex;flex-direction:column;gap:9px;padding:20px 18px 16px;flex:none}
.sidebar-logo img{width:100px;display:block}
.sidebar-nav{display:flex;flex-direction:column;gap:2px;padding:6px 10px;flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain}
/* Affordance de défilement : une barre fine, visible SEULEMENT quand la nav
   déborde (sinon le navigateur ne la peint pas). Une colonne qui défile sans le
   dire reprend en silence le défaut d'origine. CSS pur, sans écouteur — un
   masque piloté au scroll rouvrirait le risque de fuite (badge/horloge du 17/07). */
.sidebar-nav{scrollbar-width:thin;scrollbar-color:var(--bordure2) transparent}
.sidebar-nav::-webkit-scrollbar{width:7px}
.sidebar-nav::-webkit-scrollbar-thumb{background:var(--bordure2);border-radius:4px}
.sidebar-nav::-webkit-scrollbar-track{background:transparent}
.nav-item{display:flex;align-items:center;gap:10px;min-height:40px;padding:0 12px;border-radius:8px;color:var(--muted);font-size:14px}
.nav-item:hover{background:var(--nav-actif);color:var(--texte)}
.nav-item.actif{background:var(--nav-actif);color:var(--nav-actif-texte);font-weight:600}
/* ————— V1-66 — les sections du menu (coquille base) ————— */
/* Un repère, pas une entrée : aucun fond, aucun bord, aucun hover, aucun focus
   — rien de ce qui promet un clic (un intertitre qui ressemble à un lien
   produit des clics dans le vide). La voix est celle des kickers de la maison
   (mono, capitales espacées — .matrice-zone, .conge-fiche-titre) : partout
   ailleurs elle dit déjà « ceci regroupe », jamais « ceci s'ouvre ».
   Tokens seuls : les deux thèmes sont servis sans règle .theme-sombre dédiée.
   ⛔ Pas de position:sticky — le scrollIntoView({block:'nearest'}) du montage
   (coquilles.js) amènerait l'entrée active SOUS la bande collée : l'écran
   courant caché pile au moment où on cherche où on est (V1-66 §1b). */
.nav-section{margin:16px 0 3px;padding:0 12px;font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;line-height:1.6;color:var(--muted2);cursor:default;user-select:none}
.nav-section:first-child{margin-top:6px}
.sidebar-pied{display:flex;flex-direction:column;gap:12px;padding:16px 18px 18px;border-top:1px solid var(--bordure);flex:none}
.sidebar-user{display:flex;flex-direction:column;gap:2px;color:inherit}
.sidebar-nom{font-weight:600;font-size:13.5px;color:var(--titres-c)}
.sidebar-role{font-size:12px;color:var(--muted)}
.colonne-principale{flex:1;display:flex;flex-direction:column;min-width:0}
.contenu{flex:1;overflow:auto;padding:22px 26px}
.contenu-etroit{max-width:560px}
/* Veille BIP (v1.9) : bandeau couverture, bannière et corps vont bord à bord et
   gèrent leur propre padding (maquette : conteneur à padding:0). On annule donc
   le padding de .contenu, sinon les bordures pleine largeur ne portent pas.
   La classe était livrée par la vue sans règle (classe fantôme, corrigée à l'intégration). */
.veille-conteneur{margin:-22px -26px}

/* S353 — l'indicateur d'incidents, posé dans les `extras` du bandeau de la
   veille (donc hors du corps, que rendre() remplace toutes les 15 s).
   `flex:none` : le bandeau est en flex-wrap et le sélecteur de date avait déjà
   payé l'absence de cette ligne — seul enfant compressible, il absorbait 100 %
   du débordement. Deux lignes valent mieux qu'un compteur rogné.
   Les couleurs passent par les variables de thème : cet indicateur est vu en
   sombre par l'opérateur et en clair par la direction. */
.veille-incidents{display:flex;align-items:center;gap:8px;flex:none}
.veille-incidents-lien{display:flex;align-items:center;gap:7px;height:38px;padding:0 13px;border-radius:9px;border:1px solid var(--bordure2);background:var(--surface2);color:var(--muted);font-size:13px;white-space:nowrap}
.veille-incidents-lien b{font-size:15px}
.veille-incidents-lien.alerte{background:var(--alerte-fond);border-color:rgba(209,27,42,.4);color:var(--alerte)}
.veille-incidents-lien.calme{background:var(--ok-fond);border-color:var(--ok-bordure);color:var(--ok)}
.veille-incidents-lien.sourd{color:var(--muted2)}
/* Le bouton dit l'état du son EN TOUTES LETTRES, jamais par une seule icône :
   un dispositif muet dont personne ne sait qu'il est muet est pire que rien. */
.veille-incidents-son{height:38px;padding:0 11px;border-radius:9px;border:1px solid var(--bordure2);background:none;color:var(--muted);font-size:10.5px;letter-spacing:.04em;cursor:pointer;white-space:nowrap}
.veille-incidents-son:hover{border-color:var(--muted2);color:var(--titres-c)}
.veille-incidents-son.coupe{color:var(--alerte);border-color:rgba(209,27,42,.4)}
.veille-incidents-son.bloque{color:var(--attente-mat);border-color:var(--attente-mat-bordure);background:var(--attente-mat-fond)}

/* Bandeau du service */
/* `flex-wrap:wrap` : le bandeau BIP porte 8 éléments — sous 1440px ils ne
   tiennent plus sur une ligne. Sans repli, le débordement était rogné en
   silence (bascule File/Matériel hors écran à 1366, filtres à 1280) : un
   bouton invisible mais focusable, le pire des cas. Mieux vaut deux lignes
   qu'un contrôle inaccessible. */
.bandeau{display:flex;align-items:center;flex-wrap:wrap;gap:20px;padding:12px 22px;border-bottom:1px solid var(--bordure);background:var(--surface);flex:none;min-height:62px}
/* `flex:none` : la navigation de date ne se comprime JAMAIS. Seul enfant du
   bandeau capable de passer sous sa taille min (min-width:0), le sélecteur
   absorbait 100% du débordement des écrans chargés — sur #/bip il tombait de
   319px à 61px, le libellé se réduisait à « Servi… » et le ▸ était rogné à
   13px sur 19. C'est le champ de recherche qui est élastique à sa place. */
.bandeau-selecteur{display:flex;align-items:center;border:1px solid var(--bordure2);border-radius:9px;overflow:hidden;flex:none}
.bandeau-nav{display:flex;align-items:center;justify-content:center;width:34px;height:38px;color:var(--muted);cursor:pointer;background:none;border:none;font-size:14px}
.bandeau-nav:hover:not(:disabled){background:var(--nav-actif);color:var(--titres-c)}
.bandeau-nav:disabled{color:var(--bordure2);cursor:default}
.bandeau-libelle{padding:0 14px;font-family:var(--titres);font-weight:700;font-size:15px;color:var(--titres-c);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Accès direct à une date (composition, jusqu'à J+7) — séparé des flèches. */
.bandeau-date{border:none;border-left:1px solid var(--bordure2);background:none;color:var(--titres-c);font-size:13px;padding:0 8px;height:38px;cursor:pointer}
/* S423 — « Service terminé » / « Service à venir », juste à droite du libellé.
   🔴 `bandeau-peremption` et NON `bandeau-mention` : ce nom-là est pris plus bas
   (l. ~690) par les mentions en prose de la synthèse, des effectifs, des sites et
   des demandes — sept usages dans cinq vues. Les deux règles ne se recouvrant
   que sur la taille et la couleur, la pilule se serait posée sur elles sans que
   rien ne s'annule. Un nom de classe est une interface : on n'en réemploie pas
   un sans regarder qui le porte déjà.
   AMBRE et non rouge : un cadre temporel périmé est une mise au point, pas une
   alarme — le rouge reste réservé à l'anormal, sinon il perd son signal. Les
   jetons --attente-mat* sont définis dans les DEUX thèmes : ce bandeau est vu en
   sombre par l'opérateur et en clair par tous les autres.
   `flex:none` : le bandeau est en flex-wrap et le sélecteur de date avait déjà
   payé l'absence de cette ligne — seul enfant compressible, il absorbait 100 %
   du débordement et le libellé se réduisait à « Servi… ». Rien de neuf ne doit
   redevenir ce maillon-là.
   `:empty` : un service en cours n'affiche RIEN, pas même le `gap` du bandeau —
   une mention qui s'affiche toujours ne marque rien. */
.bandeau-peremption{flex:none;display:flex;align-items:center;height:38px;padding:0 13px;border-radius:9px;
  background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);color:var(--attente-mat);
  font-size:13px;font-weight:600;white-space:nowrap}
.bandeau-peremption:empty{display:none}
.horloge{font-weight:600;font-size:21px;color:var(--titres-c)}

/* Badge synchro — 3 états */
.badge-synchro{font-family:var(--mono);font-size:11px;padding:5px 11px;border-radius:999px;white-space:nowrap;align-self:flex-start}
.badge-synchro.ok{background:var(--ok-fond);color:var(--ok);border:1px solid var(--ok-bordure)}
.badge-synchro.encours{background:#eaeef3;border:1px solid #c8d0da;color:var(--sx-human)}
.theme-sombre .badge-synchro.encours{background:#101c2c;border-color:#2c3f57;color:#b3c0cf}
.badge-synchro.horsligne{background:var(--sx-encre);color:#fff;border:1px solid var(--sx-encre)}
/* S677 / D-40 — la file NE PART PAS. Ambre (--attente-mat), pas rouge : la
   règle du dépôt réserve le rouge à l'anormal (coquilles.js), et une file
   retenue est d'abord une chose à voir, pas une panne. Les deux jetons sont
   définis dans les DEUX thèmes — ce badge est vu de nuit sur le terrain. */
.badge-synchro.bloque{background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);color:var(--attente-mat);font-weight:600}
/* S677 / D-39 — au-delà d'une NUIT entière, le rouge. C'est le seul palier qui
   le mérite : à ce stade le dispositif a lu zéro pour ce superviseur sur un
   service complet — le dommage exact du 20/08, pas un retard. Posé APRÈS les
   états pour gagner la cascade à spécificité égale (il s'ajoute à `bloque`
   comme à `horsligne`). */
.badge-synchro.grave{background:var(--alerte-fond);border:1px solid rgba(209,27,42,.45);color:var(--alerte);font-weight:700}

/* Bascule FR/MG */
.bascule-langue{display:flex;gap:6px}
.pilule-langue{font-family:var(--mono);font-size:11px;padding:5px 11px;border-radius:6px;border:1px solid var(--bordure2);color:var(--muted);cursor:pointer;background:none;min-height:28px}
.pilule-langue:hover{color:var(--texte)}
.pilule-langue.active{background:var(--sx-human);border-color:var(--sx-human);color:#fff;font-weight:600}
.bascule-langue.large .pilule-langue{min-height:44px;flex:1;font-size:12px}

/* ===== Coquille terrain (mobile ≤ 420 px) ===== */
/* height:100% (et non 100vh) : sur mobile, 100vh inclut la zone de la barre
   du navigateur — les onglets du bas se retrouvaient cachés derrière. */
.coquille-terrain{max-width:420px;margin:0 auto;height:100%;display:flex;flex-direction:column;background:var(--fond)}
@supports (height:100dvh){.coquille-terrain{height:100dvh}}
.terrain-entete{display:flex;align-items:center;gap:12px;padding:14px 16px 12px;background:var(--surface);border-bottom:1px solid var(--bordure)}
.terrain-titres{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.terrain-titre{font-family:var(--titres);font-weight:800;font-size:18px;color:var(--titres-c)}
.terrain-soustitre{font-size:11px;color:var(--muted);letter-spacing:.06em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.terrain-contenu{flex:1;overflow:auto;padding:14px 14px 20px}
/* Rappel de passation : le SIGNAL qui a remplacé le mur de navigation
   (26/07/2026). Les onglets ne mentent plus sur leur href, la seule porte
   restante est sur la prise de service — il fallait donc que la formalité reste
   VISIBLE partout. Ambre (--attente-mat), pas rouge : une passation à accuser
   est une attente, pas une anomalie. */
.rappel-passation{display:block;flex:none;padding:9px 16px;background:var(--attente-mat);border-bottom:1px solid var(--bordure);color:var(--titres-c);font-size:13px;font-weight:600;text-decoration:none}
.rappel-passation:hover{filter:brightness(.97)}
/* Aide sous un champ de saisie. Posée pour la fiche de site (26/07/2026) : un
   champ « Téléphone » tout court ne disait ni DE QUEL numéro il s'agit ni à quoi
   il sert, et le site partait sans numéro exploitable. Avec trois téléphones sur
   la même fiche, l'explication cesse d'être un confort. */
.champ-aide{display:block;margin-top:4px;font-size:11.5px;line-height:1.45;color:var(--muted)}
/* Cellule de grille BIP non dépointable : pointage AUTOMATIQUE vu par un
   non-admin (26/07/2026). Le curseur dit « pas cliquable » ; l'infobulle dit
   pourquoi. Volontairement DISCRET : la cellule reste une preuve valide, elle
   n'est pas en défaut — on ne l'alarme pas, on la fige. */
.cellule.figee{cursor:default}
.cellule.figee:hover{filter:none}
/* padding-bottom safe-area : sur téléphone à encoche/home-indicator, la barre
   d'onglets ne doit pas être poussée sous l'indicateur d'accueil. */
.barre-onglets{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;background:var(--surface);border-top:1px solid var(--bordure);padding-bottom:env(safe-area-inset-bottom,0)}
/* 6 onglets depuis le 14/07 (Absences) : à 360 px de large ça fait 60 px par
   onglet — « Événements » débordait à 12,5 px. La cible tactile reste 52 px. */
.onglet{display:flex;align-items:center;justify-content:center;min-height:52px;padding:0 2px;font-size:10.5px;letter-spacing:-.2px;font-weight:500;color:var(--muted);border-top:2px solid transparent;text-align:center;line-height:1.15;overflow:hidden}
@media (min-width:380px){.onglet{font-size:11.5px;letter-spacing:0;padding:0 3px}}
@media (min-width:420px){.onglet{font-size:12.5px}}
.onglet.actif{color:var(--sx-human);border-top-color:var(--sx-human);font-weight:600}

/* ===== Boutons & formulaires ===== */
.btn-primaire{display:flex;align-items:center;justify-content:center;min-height:50px;width:100%;background:var(--sx-rouge);color:#fff;border:none;border-radius:10px;font-size:15px;font-weight:600;cursor:pointer}
.btn-primaire:hover:not(:disabled){background:var(--sx-rouge-hover)}
.btn-primaire:disabled{background:var(--bordure2);cursor:default}
.btn-texte-rouge{background:none;border:none;color:var(--sx-rouge);font-size:14px;font-weight:600;cursor:pointer;padding:12px 4px;text-align:left;min-height:44px}
.btn-texte-rouge:hover{color:var(--sx-rouge-hover)}
.champ{display:flex;flex-direction:column;gap:6px}
.champ-libelle{font-size:12.5px;font-weight:600;color:var(--titres-c)}
.champ input{min-height:46px;padding:0 13px;border:1px solid var(--bordure2);border-radius:9px;font-family:var(--sans);font-size:15px;color:var(--titres-c);background:var(--surface)}
.champ input::placeholder{color:var(--muted2)}
.champ-erreur{font-size:11px;color:var(--alerte)}
.form-erreur{padding:11px 13px;border-radius:9px;background:var(--alerte-fond);color:var(--alerte);font-size:13px;border:1px solid rgba(209,27,42,.35)}

/* ===== Connexion — 3 variantes ===== */
.connexion{min-height:100vh;display:flex}
.form-connexion{display:flex;flex-direction:column;gap:16px}
.connexion-marque{display:flex;flex-direction:column;gap:10px;margin-bottom:22px}
.connexion-carte{background:#fff;border-radius:14px;padding:34px 32px;width:min(400px,92vw);box-shadow:0 18px 50px rgba(15,27,45,.18)}
.connexion-carte.nue{box-shadow:none;padding:0}
.connexion-carte.compacte{padding:28px 24px;border:1px solid #d7dee6;box-shadow:none}
.connexion-titre{font-family:var(--titres);font-weight:800;font-size:22px;color:var(--sx-encre);margin:0 0 20px}
/* A — Encre */
.connexion-encre{background:var(--sx-encre);align-items:center;justify-content:center}
/* B — Deux volets */
.connexion-volets .volet-encre{flex:1.1;background:var(--sx-encre);color:#b3c0cf;display:flex;flex-direction:column;justify-content:center;gap:18px;padding:56px 64px}
.connexion-volets .volet-encre .kicker{color:#8494ab}
.volet-phrase{font-family:var(--titres);font-weight:700;font-size:26px;line-height:1.35;color:#eaeef3;max-width:420px;margin:0;text-wrap:pretty}
.volet-pied{font-size:10.5px;letter-spacing:.2em;color:#5c6f86;margin-top:26px}
.connexion-volets .volet-form{flex:1;background:#fff;display:flex;align-items:center;justify-content:center;padding:40px}
/* C — Terrain */
.connexion-terrain{background:#eaeef3;align-items:flex-start;justify-content:center;padding-top:9vh}
@media (max-width:760px){.connexion-volets{flex-direction:column}.connexion-volets .volet-encre{padding:36px 28px;flex:none}}

.indice-demo{margin-top:18px;font-size:10px;letter-spacing:.05em;color:#5b6b7f;background:#f5f7fa;border:1px dashed #c8d0da;border-radius:8px;padding:9px 11px;line-height:1.6}
.selecteur-variante{position:fixed;bottom:14px;right:14px;display:flex;align-items:center;gap:6px;font-size:10px;letter-spacing:.12em;color:#8494ab;background:rgba(15,27,45,.88);padding:7px 10px;border-radius:999px;z-index:50}
.pilule-variante{font-family:var(--mono);font-size:10px;border:1px solid #2c3f57;background:none;color:#b3c0cf;border-radius:999px;padding:4px 10px;cursor:pointer}
.pilule-variante.active{background:#fff;color:#0f1b2d;border-color:#fff;font-weight:600}

/* ===== Cartes, profil, chantier ===== */
.carte{background:var(--surface);border:1px solid var(--bordure);border-radius:12px;padding:18px;display:flex;flex-direction:column;gap:10px}
.carte-titre{font-family:var(--titres);font-weight:700;font-size:15px;color:var(--titres-c)}
.profil{display:flex;flex-direction:column;gap:12px}
.profil-nom{font-family:var(--titres);font-weight:800;font-size:20px;color:var(--titres-c)}
.profil-role{font-size:13px;color:var(--muted)}
.profil-matricule,.profil-email{font-size:11.5px;color:var(--muted2)}
.synchro-detail{display:flex;flex-direction:column}
.synchro-ligne{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:36px;border-bottom:1px solid var(--bordure)}
.synchro-ligne:last-child{border-bottom:none}
.synchro-libelle{font-size:13px}
.synchro-valeur{font-size:11.5px;color:var(--titres-c)}
.synchro-valeur.alerte{color:var(--alerte)}
.badge-demo{position:fixed;left:50%;transform:translateX(-50%);bottom:14px;z-index:60;font-size:10px;letter-spacing:.14em;font-weight:600;color:#fff;background:var(--sx-rouge);border-radius:999px;padding:6px 12px;box-shadow:0 4px 14px rgba(209,27,42,.35);pointer-events:none;white-space:nowrap}
/* En coquille TERRAIN, le bas de l'écran n'est pas de l'espace libre : c'est la
   barre d'onglets. Mesuré le 30/07/2026 en démo superviseur (390×844) : badge
   [805;830], onglets [791;844] — « Absences » et « Demandes » entièrement
   recouverts, « Évènements » et « Passation » rognés. Le badge ne bloque pas les
   clics (pointer-events:none), mais on ne vise pas ce qu'on ne voit pas. Il monte
   donc en tête d'écran, où la coquille lui réserve sa bande : il ne recouvre
   alors ni la nav, ni l'en-tête.
   La coquille BASE reste inchangée — le bas y est vide (la nav est à gauche), et
   déplacer le badge dérèglerait les habitudes de revue.
   Le repère est le GABARIT RENDU, jamais une largeur de viewport : un superviseur
   qui ouvre la démo sur un écran de bureau garde la coquille terrain (420 px
   centrés, nav en bas du viewport) — une media query aurait manqué exactement le
   cas de la revue design. */
.racine-terrain .en-demo .badge-demo{top:5px;bottom:auto}
.racine-terrain .en-demo .coquille-terrain{padding-top:35px}
/* L'alerte globale (top:14px) cohabite alors avec le badge en haut d'écran.
   Empilés, jamais superposés : l'alerte descend d'une valeur FIXE sous le badge.
   C'est le badge qui tient sa place et l'alerte qui cède — un repère permanent
   qui saute à chaque écriture refusée serait pire que le mal, et l'alerte reste
   entièrement lisible 26 px plus bas. */
.racine-terrain .en-demo .alerte-globale{top:40px}
/* Écran de connexion étroit : même geste, autre voisin. Le sélecteur de variante
   (fixed bottom right, démo seule) fait 270 px de large ; le badge en fait 194,
   centré. Ils se croisent dès que la fenêtre passe sous 761 px — la même bascule
   que le gabarit de connexion lui-même (@media max-width:760px plus haut), et
   c'est bien le même phénomène : sous ce seuil, le bas de l'écran ne tient plus
   deux éléments côte à côte. Au-dessus, aucun contact : on n'y touche pas. */
@media (max-width:760px){.racine-connexion .en-demo .badge-demo{top:5px;bottom:auto}}
.chantier{border:1px dashed var(--bordure2);border-radius:12px;padding:26px 24px;max-width:520px}
.chantier-titre{font-family:var(--titres);font-weight:700;font-size:16px;color:var(--titres-c)}
.chantier-texte{font-size:13.5px;color:var(--muted);line-height:1.6;margin:8px 0 0;text-wrap:pretty}

/* ===== Phase 2 — terrain superviseur ===== */
.pile{display:flex;flex-direction:column;gap:12px}
.pile-serree{display:flex;flex-direction:column;gap:6px}
.pile-nulle{display:flex;flex-direction:column;gap:2px}
.etat-vide{border:1px dashed var(--bordure2);border-radius:9px;padding:16px 14px;font-size:14px;color:var(--muted);text-wrap:pretty}
.etat-vide.ok{color:var(--ok)}
.encart-erreur{display:flex;flex-direction:column;gap:10px;background:var(--alerte-fond);border:1px solid rgba(209,27,42,.35);border-radius:9px;padding:12px 14px;font-size:13.5px;color:var(--alerte)}
/* Onglet sous verrou de passation (S217). Le href reste le vrai — la décision
   du 26/07 n'est pas rouverte — et le lien reste actionnable : c'est app.js qui
   refuse, et il répond désormais. Ce qui change ici, c'est ce que l'onglet DIT.
   `cursor:not-allowed` sert la souris ; il ne se voit pas au doigt, et cette
   barre est celle d'un téléphone de terrain — d'où le second signal.
   🔴 CE SIGNAL NE PEUT PAS ÊTRE UNE OPACITÉ DE PLUS. Le `#c8d0da` d'origine
   mesure 1,56:1 sur le blanc de la barre : le nom de l'écran est déjà à la
   limite du lisible, et cinq onglets sur six portent la classe quand le verrou
   joue — c'est presque toute la navigation. Une opacité par-dessus tombait à
   1,29:1 (mesuré) : on aurait payé le signal avec le libellé, la nuit, dehors.
   On REMONTE donc la couleur au gris courant et on l'atténue : 3,25:1 en clair
   (3,94:1 en sombre), contre 5,45:1 pour un onglet ouvert. Lisible, et
   nettement en retrait. */
.onglet.verrouille{color:var(--muted);opacity:.75;cursor:not-allowed}
.point-rouge-onglet{width:7px;height:7px;border-radius:50%;background:var(--sx-rouge);display:inline-block;margin-left:5px}

.ligne-progression{display:flex;align-items:center;gap:10px}
.progression-texte{font-size:12px;color:var(--texte);white-space:nowrap}
.progression-texte b{color:var(--titres-c)}
.barre-progression{height:6px;background:var(--bordure);border-radius:999px;overflow:hidden}
.ligne-progression .barre-progression{flex:1}
.barre-progression-remplie{height:100%;background:var(--sx-human);border-radius:999px}

.carte-prochain{border-radius:14px;padding:16px;gap:8px}
.kicker-bleu{font-size:10.5px;letter-spacing:.14em;color:var(--sx-human);font-weight:600}
.prochain-nom{font-family:var(--titres);font-weight:800;font-size:21px;color:var(--titres-c)}
.prochain-meta{font-size:13.5px;color:var(--texte)}
.encart-consigne{display:flex;gap:8px;align-items:flex-start;background:var(--surface2);border:1px solid var(--bordure2);border-radius:9px;padding:9px 11px;font-size:13px;color:var(--titres-c)}
.encart-consigne.blanc{background:var(--surface);padding:10px 12px;font-size:13.5px}
.consigne-picto{font-weight:700}

.ligne-site{display:flex;align-items:center;gap:12px;width:100%;min-height:52px;padding:8px 14px;background:var(--surface);border:1px solid var(--bordure);border-radius:11px;cursor:pointer;text-align:left;color:var(--titres-c);font-family:var(--sans);font-size:15px}
.ligne-site:hover{border-color:#8494ab}
.ligne-site-num{font-size:12px;color:var(--muted);width:14px}
.ligne-site-nom{font-weight:600}
.ligne-site-dist{font-size:11px;color:var(--muted)}
.chevron{color:#8494ab}
.ligne-visite{display:flex;align-items:center;gap:10px;padding:9px 14px;font-size:14px;color:var(--muted)}
.ligne-visite-heure{font-size:11px}
.coche-verte{color:var(--ok)}
.point-rouge{color:var(--sx-rouge);font-weight:700}
.chip-attente{font-size:10.5px;padding:3px 9px;border-radius:999px;background:var(--fond);border:1px solid var(--bordure2);color:var(--sx-human);white-space:nowrap}
.chip-ok{font-size:10.5px;padding:3px 9px;border-radius:999px;background:var(--ok-fond);color:var(--ok);white-space:nowrap}
/* Écart de rattachement (S86) : un matricule saisi désignait plusieurs agents.
   Distinct de .chip-attente (synchro en cours, rien à faire) — ici il y a
   quelque chose à lever, et seul le superviseur qui était sur place le peut. */
.chip-ecart{font-size:10.5px;padding:3px 9px;border-radius:999px;background:var(--alerte-fond);border:1px solid rgba(209,27,42,.35);color:var(--alerte);white-space:nowrap}
.lien-passation{font-size:14px;font-weight:600;padding:10px 14px}

.btn-retour{align-self:flex-start;display:flex;align-items:center;gap:6px;min-height:44px;padding:0 6px;background:none;border:none;color:var(--sx-human);font-family:var(--sans);font-weight:600;font-size:14.5px;cursor:pointer;white-space:nowrap}
.fiche-nom{font-family:var(--titres);font-weight:800;font-size:22px;color:var(--titres-c)}
.fiche-meta{font-size:11.5px;color:var(--muted)}
.ligne-agent{display:flex;align-items:baseline;gap:9px}
.agent-nom{font-weight:700;font-size:16px;color:var(--titres-c)}
.agent-matricule{font-size:11.5px;color:var(--muted)}
.pilule-role{font-size:10.5px;letter-spacing:.08em;color:var(--sx-human);border:1px solid var(--bordure2);border-radius:999px;padding:3px 9px;white-space:nowrap}
.champ-nom-libre{flex:1;min-height:40px;padding:0 11px;border:1px solid var(--bordure2);border-radius:8px;font-family:var(--sans);font-size:15px;color:var(--titres-c);background:var(--surface2)}

.grille-segments{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.grille-segments.trois{grid-template-columns:repeat(3,1fr)}
.seg{min-height:46px;border-radius:9px;font-family:var(--sans);font-weight:600;font-size:14.5px;cursor:pointer;border:1.5px solid var(--bordure2);background:var(--surface);color:var(--texte)}
.seg-present{background:var(--sx-human);border-color:var(--sx-human);color:#fff}
.seg-absent{background:var(--sx-rouge);border-color:var(--sx-rouge);color:#fff}

.ligne-signature{display:flex;align-items:baseline}
.libelle-signature{font-size:13px;font-weight:600;color:var(--texte);white-space:nowrap}
.signee{font-size:11px;color:var(--ok)}
.canvas-signature{width:100%;height:115px;background:var(--surface2);border:1.5px dashed var(--bordure2);border-radius:9px;touch-action:none;display:block;cursor:crosshair}
.btn-effacer{align-self:flex-end;min-height:36px;padding:0 12px;background:none;border:none;color:var(--muted);font-family:var(--sans);font-size:13px;cursor:pointer}
.encart-absence{background:var(--alerte-fond);border:1px solid var(--sx-rouge);border-radius:9px;padding:10px 12px;font-size:13px;color:var(--alerte);line-height:1.5}
.champ-motif{min-height:42px;padding:0 12px;border:1px solid var(--bordure2);border-radius:8px;font-family:var(--sans);font-size:14px;color:var(--titres-c);background:var(--surface)}
/* S189 — la puce de motif, en tournée. Elle REMPLACE le champ libre et en garde
   la hauteur (42px, au-dessus des 44px de cible tactile avec sa bordure) : le
   pouce du superviseur la trouve au même endroit qu'avant. Alignée à gauche et
   soulignée en pointillé — elle doit se lire comme une valeur DÉJÀ POSÉE qu'on
   peut changer, pas comme un champ vide à remplir. */
.puce-motif{display:block;width:100%;min-height:42px;padding:0 12px;text-align:left;border:1px solid var(--bordure2);border-radius:8px;font-family:var(--sans);font-size:14px;color:var(--titres-c);background:var(--surface);cursor:pointer;text-decoration:underline dotted var(--muted);text-underline-offset:3px}
.puce-motif:hover{background:var(--surface2)}
.btn-secondaire{min-height:48px;background:var(--surface);border:1px solid var(--bordure2);border-radius:10px;color:var(--titres-c);font-family:var(--sans);font-weight:600;font-size:14px;cursor:pointer}
.btn-secondaire:hover{background:var(--surface2)}
.mention-offline{font-size:10.5px;line-height:1.6;color:#8494ab;text-align:center}
.note-offline{font-size:12.5px;line-height:1.6;color:#8494ab;padding:0 4px;text-wrap:pretty}

.carte-evenement{gap:5px;padding:13px 14px}
.ligne-evenement{display:flex;align-items:center;gap:8px}
.evenement-heure{font-size:11.5px;color:var(--muted)}
.evenement-titre{font-weight:600;font-size:15px;color:var(--titres-c);overflow-wrap:anywhere}
.evenement-site{font-size:13px;color:var(--muted)}
.zone-texte{width:100%;box-sizing:border-box;background:var(--surface2);border:1px solid var(--bordure2);border-radius:9px;padding:11px 12px;font-family:var(--sans);font-size:14px;color:var(--titres-c);resize:vertical;outline:none}
.champ-select{min-height:46px;padding:0 12px;border:1px solid var(--bordure2);border-radius:9px;font-family:var(--sans);font-size:14.5px;color:var(--titres-c);background:var(--surface)}
/* S327 — la liste des sites de tournée, et le bouton qui ouvre tous les autres.
   Le bouton est `flex:none` : il ne se comprime JAMAIS. C'est la leçon du
   sélecteur de date, seul enfant du bandeau à pouvoir rétrécir, qui absorbait
   100 % du débordement et finissait rogné. Ici c'est la liste qui cède
   (`min-width:0`), et un nom de site tronqué reste choisissable — un bouton
   rogné, non. */
.ligne-site-choix{display:flex;gap:8px;align-items:stretch}
.ligne-site-choix .champ-select{flex:1;min-width:0}
.ligne-site-choix .btn-secondaire{flex:none;white-space:nowrap}
.grille-photos{display:flex;gap:8px;flex-wrap:wrap}
.grille-photos:empty{display:none}
.photo-apercu{width:64px;height:64px;object-fit:cover;border-radius:8px;border:1px solid var(--bordure2)}

.banniere-encre{background:var(--sx-encre);border-radius:12px;padding:14px 16px;color:#fff;font-size:14px;line-height:1.5;text-wrap:pretty}
.passation-sortant{font-weight:700;font-size:16px;color:var(--titres-c)}
.pile-faits{display:flex;flex-direction:column;gap:7px;font-size:14px;line-height:1.5;color:var(--texte)}
.ligne-fait{display:flex;gap:8px}
.fait-gras{color:var(--titres-c)}
.encart-consignes-libres{background:var(--surface2);border-radius:9px;padding:10px 12px;font-size:13.5px;font-style:italic;color:var(--texte)}
.accuse-fait{font-size:12px;color:var(--ok)}
.passation-intro{font-size:14px;line-height:1.6;color:var(--texte)}
.passation-resume{font-size:14px;color:var(--titres-c)}
.btn-clore{min-height:50px;background:var(--surface);border:1.5px solid var(--sx-encre);border-radius:10px;color:var(--sx-encre);font-family:var(--sans);font-weight:600;font-size:15px;cursor:pointer}
.btn-clore:hover{background:var(--surface2)}
.btn-clore:disabled{border-color:var(--bordure2);color:var(--bordure2);cursor:default}
/* Thème sombre : --sx-encre (bordure+texte) est invisible sur surface sombre —
   on bascule sur l'encre claire du thème (titres-c) + une bordure lisible. */
.theme-sombre .btn-clore{border-color:var(--bordure2);color:var(--titres-c)}
.theme-sombre .btn-clore:disabled{border-color:var(--bordure);color:var(--muted)}

/* ===== Phase 3 — base opérateur ===== */
@keyframes sxPulse{0%,100%{opacity:1}50%{opacity:.4}}
.bip-compteurs{display:flex;align-items:baseline;gap:16px;font-size:13px;color:var(--texte)}
.bip-compteurs b{color:var(--titres-c)}
.bip-compteurs .att{color:var(--muted2)}
.alerte-txt{color:var(--alerte)}
/* Élastique : c'est la recherche qui cède la place quand le bandeau est chargé,
   pas le sélecteur de date (un champ de saisie rétréci reste utilisable ; une
   flèche de navigation rognée, non). */
.champ-recherche{flex:0 1 168px;min-width:72px;background:var(--surface2);border:1px solid var(--bordure2);border-radius:8px;padding:9px 12px;font-family:var(--sans);font-size:13px;color:var(--titres-c);outline:none}
.champ-recherche::placeholder{color:var(--muted2)}
.groupe-bascule{display:flex;border:1px solid var(--bordure2);border-radius:9px;overflow:hidden}
.bascule-vue{min-height:38px;padding:0 16px;border:none;font-family:var(--sans);font-weight:600;font-size:13px;cursor:pointer;background:transparent;color:var(--muted)}
.bascule-vue.active{background:var(--sx-human);color:#fff}

.bip-conteneur{margin:-22px -26px;min-height:calc(100vh - 62px)}
.bip-vue-file{display:flex;align-items:stretch;min-height:calc(100vh - 62px)}
.bip-rail{width:104px;flex:none;border-right:1px solid var(--bordure);padding:14px 10px;display:flex;flex-direction:column;gap:3px;background:var(--surface2)}
.rail-heure{display:flex;align-items:center;justify-content:space-between;padding:6px 9px;border-radius:7px;font-family:var(--mono);font-size:12px;color:var(--muted2);background:none;border:1px solid transparent;cursor:pointer;text-align:left}
.rail-heure.courante{background:var(--nav-actif);border-color:#2c3f57;color:var(--titres-c);font-weight:600}
.theme-clair .rail-heure.courante{border-color:var(--bordure2)}
.rail-heure.future{color:#33414f}
.rail-bilan{font-size:10.5px}
.rail-bilan.bon{color:var(--ok)}
.rail-bilan.mauvais{color:var(--alerte)}
.rail-bilan.futur{color:#33414f}

.bip-file{flex:1.35;min-width:0;overflow:auto;padding:18px 24px}
.bip-file-entete{display:flex;align-items:baseline;gap:12px}
.bip-file-titre{font-family:var(--titres);font-weight:800;font-size:20px;color:var(--titres-c)}
.bip-file-reste{font-family:var(--mono);font-size:12px;color:var(--muted)}
.bip-file-reste b{color:var(--titres-c)}
.bip-file-aide{font-size:12.5px;color:var(--muted2);margin-top:4px}
.ligne-bip{display:flex;align-items:center;gap:12px;width:100%;min-height:46px;padding:8px 14px;background:var(--surface);border:1px solid var(--bordure);border-radius:9px;color:var(--titres-c);cursor:pointer;font-family:var(--sans);text-align:left;font-size:14.5px}
.ligne-bip:hover{border-color:#2c3f57}
.theme-clair .ligne-bip:hover{border-color:#8494ab}
.ligne-bip-nom{font-weight:500}
.ligne-bip-zone{font-size:11px;color:var(--muted2)}
.case-bip{width:19px;height:19px;border:1.5px solid #3a516b;border-radius:5px;flex:none;display:flex;align-items:center;justify-content:center;font-size:12px}
.theme-clair .case-bip{border-color:var(--bordure2)}
.case-bip.cochee{background:var(--ok);border-color:var(--ok);color:#fff}
.ligne-pointe{display:flex;align-items:center;gap:10px;padding:7px 14px;font-size:13px;color:var(--muted)}
.ligne-pointe-heure{font-size:11px;color:var(--muted2)}
.ligne-pointe-plus{padding:7px 14px;font-size:12.5px;color:var(--muted2)}

.bip-panneau{width:318px;flex:none;border-left:1px solid var(--bordure);padding:18px;background:var(--surface2);display:flex;flex-direction:column;gap:10px}
.bip-panneau-titre{display:flex;align-items:center;gap:9px;font-family:var(--titres);font-weight:700;font-size:15px;color:var(--titres-c)}
.point-pulse{width:8px;height:8px;border-radius:50%;background:var(--sx-rouge);animation:sxPulse 1.6s ease-in-out infinite;flex:none}
.carte-anomalie{border:1px solid rgba(209,27,42,.55);background:rgba(209,27,42,.07);border-radius:10px;padding:13px 14px;display:flex;flex-direction:column;gap:8px}
.carte-anomalie-kicker{font-size:10.5px;letter-spacing:.1em;color:var(--alerte)}
.carte-anomalie-nom{font-weight:600;font-size:15px;color:var(--titres-c)}
.carte-anomalie-detail{font-size:12.5px;line-height:1.5;color:var(--texte)}
/* S428 (14/08) — `.carte-anomalie-boutons` et `.btn-action` retirées avec leur
   unique producteur : les deux boutons de qualification du panneau « Manqués »
   de `#/bip`, que le lot enlève à l'opérateur. Aucun autre appelant (vérifié
   sur tout `public/pwa/js/`). Une règle sans producteur fait croire au lecteur
   suivant qu'il reste des boutons à cet endroit. */
.btn-action:hover{border-color:#3a516b}
.ligne-consignee{font-size:11px;color:var(--muted);padding:1px 0}
.bip-panneau-note{font-size:11.5px;line-height:1.55;color:var(--muted2);margin-top:2px;text-wrap:pretty}
/* Bandeau santé passerelle (C2-bis) — discret : un avertissement, pas une
   alarme rouge (l'opérateur ne peut rien faire d'un témoin mort). Amber doux. */
.bip-passerelle{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px;
  padding:9px 14px;border-radius:9px;background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure)}
.bip-passerelle-puce{width:8px;height:8px;border-radius:50%;background:var(--attente-mat);flex:none}
.bip-passerelle-txt{font-size:13px;color:var(--titres-c);font-weight:600}
.bip-passerelle-note{font-size:11px;color:var(--muted2);text-wrap:pretty}

/* Grille PRÉVISIONNELLE (S106) : la nuit à venir, avant la gravure du soir.
   🔴 Était en pointillés gris, 11,5 px, texte `--muted2` — une note de bas de
   page (S224, 05/08/2026). Devant une grille où rien n'est cliquable, c'est ce
   bandeau qui dit POURQUOI : Kamile a conclu « pas pointable » sans le trouver.
   Il a désormais le poids d'une explication d'état, avec l'habillage du bandeau
   passerelle. AMBRE et non rouge : une formalité de calendrier n'est pas une
   alarme, et le rouge reste réservé à l'anormal. */
.bip-previsionnel{display:flex;align-items:center;gap:10px;margin-bottom:12px;
  padding:9px 14px;border-radius:9px;background:var(--attente-mat-fond);
  border:1px solid var(--attente-mat-bordure)}
.bip-previsionnel-puce{width:8px;height:8px;border-radius:50%;background:var(--attente-mat);flex:none}
.bip-previsionnel-txt{font-size:13px;color:var(--titres-c);font-weight:600;text-wrap:pretty}

.bip-matrice{padding:14px 24px 28px;overflow:auto}
/* Grille au QUART (Portillon) : nom + 10 BLOCS d'heure (4 quarts chacun) + note.
   Le gap entre blocs regroupe visuellement les 4 quarts d'une même heure. */
.matrice-entete{display:grid;grid-template-columns:200px repeat(10,minmax(46px,1fr)) minmax(0,2fr);gap:6px;position:sticky;top:0;background:var(--fond);padding:6px 0;z-index:2}
.matrice-heure{display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--muted2);height:22px;border-radius:4px}
.matrice-heure.courante{background:var(--nav-actif);color:var(--titres-c);font-weight:600}
.matrice-zone{grid-column:1/-1;padding:16px 6px 5px;font-size:10.5px;letter-spacing:.18em;color:var(--muted2)}
.matrice-ligne{display:grid;grid-template-columns:200px repeat(10,minmax(46px,1fr)) minmax(0,2fr);gap:6px;align-items:center;padding:1px 0}
.matrice-nom{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:0 6px;color:var(--texte)}
.matrice-nom.epinglee{color:var(--titres-c);font-weight:600}
/* V1-42 — la note de queue au registre NEUTRE. À 62 % de manqués elle était
   rouge sur 128 lignes : une colonne entière, donc un fond de plus. Le rouge de
   cette colonne est rendu à la seule ligne qui l'exige (`.forte`, site muet
   toute la nuit). Le compteur d'en-tête, lui, garde le sien : il est unique. */
/* ⚠️ La colonne de queue passe de 1.1fr à 2fr, et elle abrège désormais au lieu
   de se faire couper. « muet toute la nuit » est plus long que « manqué
   20h00 » : à 1 440 px il SORTAIT DE L'ÉCRAN, tronqué net au bord droit — vu à
   la capture, invisible à toutes les épreuves de ce lot, qui ne mesurent que le
   DOM et les couleurs. À 2fr la colonne fait 153 px et plus aucune note n'est
   abrégée ; les dix colonnes d'heure gardent 80 px, très au-dessus de leur
   minimum de 46. L'ellipsis reste comme filet aux petites largeurs.
   🔴 La largeur est déclarée aux DEUX endroits (.matrice-entete et
   .matrice-ligne) : elles ne se dissocient jamais, sinon l'en-tête ne coiffe
   plus ses colonnes. */
.matrice-note{font-size:11px;color:var(--muted2);padding-left:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.matrice-note.forte{color:var(--alerte);font-weight:600}
/* ═══ V1-42 — LA LIGNE ENTIÈREMENT MUETTE, la vraie exception de cet écran.
   Un site sans AUCUN pointage de toute la nuit (7 sur la nuit du 13→14 en
   production) — à distinguer d'une ligne à trous épars, qui est la normale.
   Liseré + nom à l'encre forte : la marque SIGNALE SANS RÉORDONNER, parce que
   l'ordre alphabétique est l'ordre de recherche de l'opérateur au téléphone. */
.matrice-ligne.muette,.ligne-bip.muette{background:rgba(209,27,42,.06);border-left:3px solid var(--sx-rouge);border-radius:4px;padding-left:5px;margin-left:-8px}
.matrice-ligne.muette .matrice-nom,.ligne-bip.muette .ligne-bip-nom{color:var(--alerte);font-weight:700}
/* Un bloc d'heure = 4 quarts serrés. */
.matrice-bloc{display:flex;gap:2px;min-width:0}
.matrice-bloc .cellule{flex:1;min-width:9px;height:22px;font-size:10px}
.cellule{height:25px;display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:12px;border-radius:4px;border:1px solid transparent}
.cellule.pointee{color:var(--ok);background:var(--ok-fond);cursor:pointer}
/* Pointage HUMAIN (repli manuel, maille horaire) : une ASSERTION, pas la preuve
   passerelle. Double codage — AMBRE (famille « attente », définie en :root clair ET
   sombre) + glyphe ✎ (posé par cellule()). Distinct de l'auto sans jamais paraître
   « plus validé » ; le rouge (--alerte) reste réservé au manqué. Remplace un
   box-shadow inset var(--ok) imperceptible (auto et manuel étaient identiques). */
.cellule.pointee.manuelle{color:var(--attente-mat);background:var(--attente-mat-fond);border-color:var(--attente-mat-bordure)}
/* ═══ V1-42 (14/08/2026) — LE MANQUÉ PERD SON PAVÉ PLEIN.
   Il portait `background:var(--sx-rouge)` et du blanc dessus. Sur une nuit
   ordinaire — 1 507 pointés sur 4 000 — cela peignait 62 % de l'écran en rouge
   opaque, toutes les nuits : un signal qui couvre les deux tiers de la surface
   n'est plus un signal, c'est un fond, et le bandeau passerelle s'y noyait
   (mesuré : 3 566 contre 55 717 avant le lot). Cellule CREUSE désormais —
   contour d'alerte affaibli, fond transparent.
   ⛔ Le ✗ RESTE (posé par cellule()) : le double codage forme + couleur ne se
   perd jamais, et aucun manqué n'est caché — la grille fait preuve, on baisse
   l'encre, jamais l'information. */
.cellule.manquee{background:transparent;color:var(--alerte);font-weight:600;border-color:rgba(209,27,42,.4);cursor:pointer}
.cellule.attendue{border:1px dashed #3a516b;color:var(--muted);cursor:pointer}
.theme-clair .cellule.attendue{border-color:var(--bordure2)}
.cellule.future{color:#2c3a49}
.theme-clair .cellule.future{color:var(--bordure2)}
/* Née après sa propre fenêtre (S193) : le site est entré au référentiel en
   pleine nuit. NEUTRE et non cliquable — ni le rouge du manqué (un reproche que
   personne ne pouvait éviter) ni le vert du pointé. Hachurée pour se distinguer
   du « futur », qui est vide pour une tout autre raison. */
.cellule.hors-dispositif{color:var(--muted2);background:repeating-linear-gradient(45deg,transparent,transparent 3px,rgba(127,143,166,.18) 3px,rgba(127,143,166,.18) 6px);cursor:default}
/* V1-42 §4 — INJOIGNABLE CONNU. Posée maintenant, ALIMENTÉE PLUS TARD : aucune
   cellule ne la porte aujourd'hui, le drapeau `hors_atteinte` n'est servi par
   personne. Grise et unie — à distinguer du « hors dispositif » hachuré, qui
   dit autre chose (créneau né après sa propre fenêtre). ⛔ Jamais déduite au
   front : un site 100 % manqué N nuits n'est pas un injoignable prouvé. */
.cellule.hors-atteinte{color:var(--muted2);background:transparent;cursor:default}
/* Légende de la grille au quart (auto / manuel / manqué). */
.bip-legende{display:flex;gap:14px;flex-wrap:wrap;font-family:var(--mono);font-size:11px;color:var(--muted2);padding:2px 6px 10px}
.bip-legende b{color:var(--ok);font-weight:600}
/* Marque « manuel » de la légende : ambre, comme la coche manuelle (double codage). */
.bip-legende b.marque-manuel{color:var(--attente-mat)}
/* Le liseré du site muet, repris tel quel dans la légende — c'est une MARQUE de
   ligne, pas un glyphe : la montrer sous forme de glyphe ne la ferait pas
   reconnaître. */
.legende-muet{display:inline-block;width:18px;height:4px;border-radius:2px;background:var(--sx-rouge);margin-right:5px;vertical-align:middle}

.voile{position:fixed;inset:0;background:rgba(6,13,21,.55);display:flex;align-items:center;justify-content:center;z-index:80}
/* 🔴 S736 — LA CLASSE DE BASE EST BORNÉE, ET SON CORPS DÉFILE.
   `.dialogue` n'avait NI `max-height` NI `overflow-y` : une boîte plus haute
   que la fenêtre débordait du voile — qui est `position:fixed` et ne défile
   pas. Rien ne ramenait les boutons à l'écran : le geste n'était pas pénible,
   il était IMPOSSIBLE. Mesuré au visa d'un congé de trois semaines, fenêtre
   1280×720 : boîte de 1493 px, haut à −387 px, bouton de validation à 1086 px,
   soit 366 px sous le bord. Le titre et le champ de recherche étaient coupés en
   haut du même mouvement.
   ⚠️ `min(86vh, 900px)` sur le MODÈLE des trois variantes qui bornaient déjà
   (`.dialogue-fiche` 82vh/760, `.dialogue-selecteur` 80vh, `.dialogue-feries`
   84vh/860) : la base est le plafond le plus HAUT, pour ne contredire aucune —
   toutes sont déclarées plus bas dans ce fichier et gagnent donc la cascade à
   spécificité égale. */
.dialogue{background:var(--surface);border:1px solid var(--bordure2);border-radius:12px;padding:20px;width:min(380px,90vw);display:flex;flex-direction:column;gap:12px;max-height:min(86vh,900px);overflow-y:auto}
/* Jamais `vh` seul : la barre d'adresse du navigateur mobile ne s'en retire
   pas, et la boîte redéborde exactement là où l'on est le plus à l'étroit.
   Même règle que `.dialogue-selecteur` (l. 1177) et `.dialogue-feries`. */
@supports (height:100dvh){.dialogue{max-height:min(86dvh,900px)}}
.dialogue-titre{font-family:var(--titres);font-weight:700;font-size:15px;color:var(--titres-c)}
/* 🔴 S736 — LA RANGÉE DE BOUTONS NE PART JAMAIS AVEC LE CONTENU.
   Borner ne suffit pas : avec le seul `overflow-y:auto` ci-dessus, les boutons
   défilent AVEC le corps, et sur le visa d'un congé de trois semaines il faut
   traverser une grille d'une vingtaine de cartes pour les atteindre. Le geste
   redevient possible, il reste pénible.
   ⇒ `position:sticky` — UNE structure, pas vingt retouches dans les vues : les
   20 dialogues de `public/pwa/js/` portent tous la même rangée, aucun n'a eu à
   changer. Le fond opaque est celui de la boîte : sans lui, le contenu défilant
   passerait EN TRANSPARENCE sous les boutons.
   ⚠️ `bottom:-20px` + `padding-bottom:20px` : le scrollport d'une boîte qui
   défile est sa PADDING-box, donc `bottom:0` collerait les boutons au ras du
   bord, sous les 20 px de respiration. La rangée porte elle-même cet espace, et
   `margin-bottom:-20px` évite de le compter deux fois quand rien ne défile. */
.dialogue-boutons{display:flex;gap:8px;justify-content:flex-end;position:sticky;bottom:-20px;background:var(--surface);padding-bottom:20px;margin-bottom:-20px;z-index:1}
.dialogue-boutons .btn-secondaire{min-height:40px;padding:0 14px}
.btn-primaire.compact{min-height:40px;width:auto;padding:0 16px;font-size:13.5px}

.contenu-appels,.contenu-mc{max-width:860px;display:flex;flex-direction:column;gap:14px}
.appels-entete{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap}
.appels-titre{font-family:var(--titres);font-weight:800;font-size:20px;color:var(--titres-c)}
.appels-bilan{font-size:13px;color:var(--texte)}
.appels-bilan b{color:var(--titres-c)}
.appels-aide{font-size:12.5px;color:var(--muted2);text-wrap:pretty}
.bloc-vague{display:flex;flex-direction:column;gap:8px;margin-top:6px}
/* ===== S351 — En-tête de vague REPLIABLE, et filtre de statut =====
   L'en-tête était un `div.mono.kicker` décoratif. Il devient le contrôle du
   pli : c'est un vrai <button> (clavier, aria-expanded, focus-visible hérité),
   et il garde son compte `appelés/total` — replié, c'est tout ce qui reste à
   l'écran de la vague, donc il ne peut pas être une ligne muette.
   `min-height:38px` : même gabarit tactile que .bascule-vue et .bandeau-nav.
   Deux en-têtes coûtent ~76 px de haut ; replier la vague de 16h en rend
   plusieurs milliers à l'opérateur de 18h. Le chevron est en `aria-hidden` —
   l'état est déjà porté par aria-expanded, le lire deux fois est du bruit. */
.entete-vague{display:flex;align-items:center;gap:8px;width:100%;min-height:38px;padding:6px 2px;background:none;border:none;border-radius:8px;cursor:pointer;text-align:left}
.entete-vague:hover:not(:disabled) .kicker{color:var(--titres-c)}
.entete-vague:disabled{cursor:default}
.chevron-vague{flex:none;width:12px;font-size:11px;line-height:1;color:var(--muted)}
.entete-vague .kicker{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.etat-vide.vague-vide{padding:10px 12px;font-size:13px}
/* Trois pilules de plus dans le bandeau : il en portait déjà cinq sur #/bip,
   mais le retour à la ligne est posé ICI et pas sur `.ligne-filtres`, partagée
   par dix écrans — même prudence que pour `.pilules-sites` (l. 829) et que le
   `flex:none` du sélecteur de date : un enfant qui absorbe seul tout le
   débordement se rogne en silence. */
.ligne-filtres.appels-filtres{flex-wrap:wrap;row-gap:6px}
.ligne-appel{display:flex;align-items:center;gap:12px;width:100%;min-height:46px;padding:8px 14px;background:var(--surface);border:1px solid var(--bordure);border-radius:9px;color:var(--titres-c);cursor:pointer;font-family:var(--sans);text-align:left;font-size:14px}
.ligne-appel:hover:not(:disabled){border-color:#2c3f57}
.theme-clair .ligne-appel:hover:not(:disabled){border-color:#8494ab}
.ligne-appel.avenir{opacity:.55;cursor:default}
.ligne-appel.cochee .ligne-appel-site{color:var(--muted)}
.ligne-appel-site{font-weight:600}
.ligne-appel-agent{font-size:13px;color:var(--texte)}
.ligne-appel-mat{font-size:11px;color:var(--muted2)}
.ligne-appel-tel{font-size:11.5px;color:var(--muted)}
.ligne-appel-heure{font-size:11px;color:var(--muted2)}

.ligne-filtres{display:flex;gap:6px}
.pilule-filtre{font-family:var(--mono);font-size:11px;padding:6px 12px;border-radius:999px;border:1px solid var(--bordure2);background:none;color:var(--muted);cursor:pointer}
.pilule-filtre.active{background:var(--sx-human);border-color:var(--sx-human);color:#fff;font-weight:600}
.mc-carte{background:var(--surface);border:1px solid var(--bordure);border-radius:11px;overflow:hidden}
.mc-ligne{display:flex;align-items:center;gap:12px;width:100%;min-height:54px;padding:8px 16px;background:none;border:none;cursor:pointer;font-family:var(--sans);text-align:left}
.mc-titre{font-weight:600;font-size:14.5px;color:var(--titres-c)}
.mc-compte{font-size:11px;color:var(--muted2)}
.chip-etat{font-size:10.5px;letter-spacing:.06em;padding:4px 10px;border-radius:999px;white-space:nowrap}
/* S320 — LA GRAVITÉ DÉCLARÉE. Trois poids, et un quatrième habillage qui n'est
   pas une gravité.
   · `immediat` : alerte PLEINE (comme .chip-carence, l'autre « il faut y aller »),
     jamais le rouge clair de .chip-ouverte — celui-ci dit « pas encore traité »,
     pas « maintenant ». ⚠️ .chip-fraude était cité ici : elle est passée à l'ambre
     de l'attente en S444 et n'est plus un exemple d'alerte pleine.
   · `jour` : la même attente que le matériel à préparer. Ce n'est pas une alerte.
   · `information` : neutre. Rien à faire, et l'écran ne doit pas prétendre le
     contraire — c'est justement ce que le compteur ne compte pas.
   · `non_precise` : POINTILLÉ, et c'est tout l'écart. Un trait plein dirait une
     réponse « rien de particulier » ; ici il n'y a pas de réponse du tout — la
     question n'était pas posée quand ces ~455 signalements ont été écrits, et on
     ne leur en invente aucune. Bâti sur les seules variables neutres du thème,
     donc juste en clair comme en sombre. */
.chip-gravite-immediat{background:var(--alerte);color:#fff;border:1px solid var(--alerte)}
.chip-gravite-jour{background:var(--attente-mat-fond);color:var(--attente-mat);border:1px solid var(--attente-mat-bordure)}
.chip-gravite-information{background:var(--surface2);color:var(--muted2);border:1px solid var(--bordure)}
.chip-gravite-non_precise{background:var(--surface2);color:var(--muted2);border:1px dashed var(--bordure2)}
/* La file des incidents (#/incidents). Cartes PLATES : les deux gestes du cycle
   sont sur la ligne, jamais derrière un dépliage — c'est la seule liste dont le
   but est qu'on la vide, un clic de plus par ligne la condamnerait. */
.incident-carte{display:flex;flex-direction:column;gap:8px;padding:13px 16px}
.incident-ligne{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.incident-actions{display:flex;align-items:center;gap:8px;flex:none}
.incident-age{font-size:11.5px;color:var(--muted2)}
.incident-texte{font-size:14px;color:var(--texte);line-height:1.45}
/* Le rappel de gravité posé sous la déclaration terrain : segments pleine
   largeur, cibles au pouce (la déclaration se fait sur un téléphone, la nuit). */
.gravite-choix{display:flex;flex-direction:column;gap:6px}
.gravite-choix .seg{text-align:left;padding:11px 13px}
.gravite-aide{font-size:11.5px;color:var(--muted2)}
.chip-ouverte{background:var(--alerte-fond);color:var(--alerte);border:1px solid rgba(209,27,42,.4)}
.chip-traitee{background:var(--ok-fond);color:var(--ok);border:1px solid var(--ok-bordure)}
.chip-a-traiter{background:var(--attente-mat-fond);color:var(--attente-mat);border:1px solid var(--attente-mat-bordure)}
.chip-prete{background:var(--pret-fond);color:var(--pret);border:1px solid var(--pret-bordure)}
/* S103 — la permutation est un FAIT, pas un état à traiter : ni alerte, ni
   attente, ni succès. Bâti sur les seules variables NEUTRES du thème, donc
   juste en clair comme en sombre sans règle dédiée. */
.chip-neutre{background:var(--surface2);color:var(--muted2);border:1px solid var(--bordure)}
/* S138 — la marque « nom actuel » sur une trace dont le nom d'époque n'a pas
   été conservé. DÉLIBÉRÉMENT DISCRÈTE, et délibérément PRÉSENTE : ce n'est ni
   une alerte (rien n'est en faute) ni un état à traiter, c'est une réserve sur
   la valeur probante de ce qui est écrit à côté. Bâtie sur les seules variables
   neutres du thème, donc juste en clair comme en sombre. `white-space:nowrap`
   pour qu'elle ne se détache jamais du nom qu'elle qualifie. */
.nom-site-actuel{margin-left:6px;font-size:10px;letter-spacing:.04em;padding:2px 6px;border-radius:999px;white-space:nowrap;background:var(--surface2);color:var(--muted2);border:1px solid var(--bordure);vertical-align:baseline}
.mc-fil{background:var(--surface2);border-top:1px solid var(--bordure);padding:12px 16px;display:flex;flex-direction:column;gap:8px}
.mc-action{display:flex;align-items:baseline;gap:10px;font-size:13.5px;color:var(--texte)}
.mc-action-heure{width:40px;flex:none;font-size:11.5px;color:var(--muted2)}
.mc-action-auteur{color:var(--titres-c);font-size:12.5px}
.mc-form{display:flex;flex-direction:column;gap:8px;margin-top:6px}
.mc-form-ligne{display:flex;align-items:center;gap:10px}
.mc-cloture{display:flex;align-items:center;gap:7px;font-size:13px;color:var(--texte);cursor:pointer}

/* ===== Phases 4-5 — direction & planificateur ===== */
.contenu-synthese{display:flex;flex-direction:column;gap:18px;min-width:960px}
.contenu-etroit-large{max-width:960px}
.bandeau-mention{font-size:11.5px;color:var(--muted)}
.grille-compteurs{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.grille-compteurs.trois{grid-template-columns:repeat(3,1fr)}
.carte-compteur{border-radius:13px;padding:16px 18px;gap:4px}
.compteur-valeur{font-size:30px;font-weight:600;color:var(--titres-c)}
.compteur-valeur.rouge,.compteur-sous.rouge{color:var(--sx-rouge)}
.theme-sombre .compteur-valeur.rouge{color:var(--alerte)}
.compteur-valeur.vert{color:var(--ok)}
.compteur-total{font-size:15px;color:#8494ab}
.compteur-libelle{font-size:13px;color:var(--texte)}
.compteur-sous{font-size:11.5px;color:var(--muted)}
.grille-synthese{display:grid;grid-template-columns:1.5fr 1fr;gap:18px;align-items:start}
.encart-calme{background:var(--surface);border:1px dashed var(--bordure2);border-radius:13px;padding:28px;text-align:center;color:var(--ok);font-size:15px}
/* S365 — le renvoi vers la main courante, entre le compteur et la liste. Ton
   posé : c'est une explication, pas une alerte — il dit où sont les lignes que
   la liste ne montre plus, il n'annonce pas un problème. D'où la surface neutre
   et le texte en `--muted`, et non le rouge des anomalies. `display:block` :
   c'est un vrai lien (`<a href="#/main-courante">`), pas un paragraphe décoré —
   la porte doit être cliquable sur toute sa surface, y compris au pouce. */
/* 🔴 S496 — `.renvoi-ecran` PARTAGE CETTE RÈGLE, elle n'en crée pas une seconde.
   Le renvoi vers la relecture des passations passées est le même objet que celui
   de S365 : une porte discrète vers un autre écran, pas une alerte. AUCUNE
   déclaration nouvelle, aucune couleur nouvelle — trois sélecteurs de plus, rien
   d'autre. ⚠️ Le nom historique reste : renommer la classe toucherait l'écran de
   synthèse, qui n'est pas dans le périmètre de ce lot. */
.renvoi-main-courante,.renvoi-ecran{display:block;background:var(--surface);border:1px solid var(--bordure2);border-left:3px solid var(--bordure2);border-radius:10px;padding:10px 13px;color:var(--muted);font-size:12.5px;line-height:1.5;text-decoration:none}
.renvoi-main-courante:hover,.renvoi-ecran:hover{border-left-color:var(--pret);color:var(--texte)}
.renvoi-main-courante b,.renvoi-ecran b{color:var(--texte)}
.mc-colonne{display:flex;flex-direction:column;gap:1px;min-width:0}
.mc-soustitre{font-size:12.5px;color:var(--muted)}
.ligne-couverture{display:flex;flex-direction:column;gap:5px;padding:7px 0}
.ligne-couverture-tete{display:flex;align-items:baseline;gap:8px}
.couverture-nom{font-weight:600;font-size:13.5px;color:var(--titres-c);white-space:nowrap}
.couverture-zone{font-size:10.5px;color:var(--muted);white-space:nowrap}
.couverture-score{font-size:11.5px;color:var(--texte);white-space:nowrap}
.ligne-couverture .barre-progression{flex:none;width:100%}
/* « pas encore complet » = ambre (en attente), pas rouge (alarme) : le rouge est
   réservé à l'anormal (manqués, retards, incidents), sinon il perd son signal. */
.barre-progression-remplie.incomplete{background:var(--attente-mat)}
.rondes-texte{font-size:13.5px;line-height:1.6;color:var(--texte)}
.rondes-texte b{color:var(--titres-c)}
.point-vert{width:7px;height:7px;border-radius:50%;background:var(--ok);flex:none;display:inline-block}

.graphe-barres{display:flex;align-items:flex-end;gap:8px;height:120px;padding:8px 0 2px}
.graphe-barres.serre{gap:3px}
.barre-jour{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:5px;height:100%;min-width:0}
.barre-valeur{width:100%;max-width:36px;background:var(--sx-human);border-radius:4px 4px 0 0}
.barre-valeur.zero{background:var(--bordure);height:4px !important}
.barre-libelle{font-size:10px;color:var(--muted2)}
.barre-chiffre{font-size:11px;font-weight:600;color:var(--titres-c);line-height:1}
.barre-chiffre.zero{color:var(--muted2)}
.grille-deux{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.ligne-top{display:flex;align-items:baseline;gap:10px;min-height:34px}
.ligne-top-nom{font-weight:600;font-size:13.5px;color:var(--titres-c)}
.ligne-top-detail{font-size:11px;color:var(--muted)}

/* La RAISON d'un requis (S141). Volontairement la voix la plus basse de
   l'écran : `--muted2`, plus petite que le détail, jamais en gras, jamais
   colorée — elle ne se lit que si on la cherche. Elle n'apparaît QUE hors de
   l'ordinaire (aucune exception → aucune mention), sinon elle couvrirait de
   bruit les 189 sites sur 209 qui n'ont rien de particulier à dire.
   `text-wrap:balance` : ces libellés sont des phrases, pas des étiquettes — sur
   un téléphone ils passent à la ligne, et une veuve d'un mot se lit mal. */
.mention-regle{font-size:10.5px;color:var(--muted2);line-height:1.35;text-wrap:balance}
/* Sous le CHIFFRE, pas sous le nom du site : sur les deux écrans où le requis
   est poussé à droite de la ligne, une raison alignée à gauche se lisait comme
   un commentaire du site. */
.mention-regle.sous-le-chiffre{text-align:right}

/* 🔴 Une raison doit coller à SA ligne, pas à la suivante. `.ligne-top` réserve
   34 px de hauteur pour un texte de 17 : les ~9 px d'air qui restent en dessous
   éloignaient la mention de son site et la collaient au site d'après — vérifié
   sur capture, elle se lisait comme l'en-tête du voisin. C'est la même faute
   qu'accuser le mauvais site, en typographie. */
.bloc-verdict{gap:0}
.bloc-verdict .mention-regle{margin-top:-9px;margin-bottom:7px}

.ligne-form-rapport{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap}
.champ-rapport{display:flex;flex-direction:column;gap:5px;min-width:150px}
.champ-rapport:first-child{flex:1}
.ligne-rapport{display:flex;align-items:center;gap:12px;min-height:52px;padding:8px 14px;background:var(--surface);border:1px solid var(--bordure);border-radius:11px}
.ligne-rapport-site{font-weight:600;font-size:14.5px;color:var(--titres-c)}
.ligne-rapport-periode{font-size:11.5px;color:var(--texte)}
.ligne-rapport-meta{font-size:11px;color:var(--muted2)}
.btn-secondaire.compact-liste{min-height:38px;padding:0 14px;font-size:13px}
/* 🔴 S190 — « Viser » NE DOIT PAS RESSEMBLER À « Signalée à tort ». Deux faits
   opposés : viser laisse le sous-effectif en place, « signalée à tort » l'efface.
   Un superviseur pressé, de nuit, sur un petit écran, doit les séparer sans lire.

   Le signal est la COULEUR DU TEXTE, pas la bordure — première tentative faite
   et MESURÉE FAUSSE : `.btn-clore` porte une bordure `--sx-encre` (#0f1b2d), qui
   est quasi le fond du thème sombre (#060d15). En clair les deux boutons se
   distinguaient ; en SOMBRE — le thème de l'opérateur, donc l'écran de NUIT,
   donc le pire endroit pour rater — ils étaient jumeaux (capture à l'appui).

   Palette `--pret` et non `--ok` : le vert dirait « c'est réglé », or viser ne
   règle rien du tout. Le bleu dit « pris en compte », ce qui est exactement le
   sens du geste. Les deux thèmes la définissent avec un contraste travaillé. */
.btn-viser{min-height:38px;padding:0 14px;background:var(--pret-fond);border:1px solid var(--pret-bordure);border-radius:10px;color:var(--pret);font-family:var(--sans);font-weight:600;font-size:13px;cursor:pointer}
.btn-viser:hover{border-color:var(--pret)}

.contenu-composition{min-width:900px}
.grille-tournees{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:14px;align-items:start}
.colonne-tournee{gap:8px}
.colonne-tournee-tete{display:flex;align-items:baseline;gap:8px;padding-bottom:4px;border-bottom:1px solid var(--bordure)}
.ligne-compo{display:flex;align-items:center;gap:9px;min-height:42px;padding:2px 4px;border-bottom:1px solid var(--surface2)}
.ligne-compo-nom{font-weight:500;font-size:14px;color:var(--titres-c)}
.ligne-compo-zone{font-size:10.5px;color:var(--muted2)}
.btn-mini{width:30px;height:30px;border:1px solid var(--bordure2);border-radius:7px;background:none;color:var(--texte);cursor:pointer;font-size:13px;flex:none}
.btn-mini:hover:not(:disabled){background:var(--surface2)}
.btn-mini:disabled{opacity:.35;cursor:default}
.btn-mini.rouge{color:var(--sx-rouge);border-color:rgba(209,27,42,.35)}
.compact-select{min-height:42px;font-size:13.5px}
.encart-controle{background:var(--alerte-fond);border:1px solid rgba(209,27,42,.35);border-radius:9px;padding:10px 13px;font-size:13px;color:var(--alerte);line-height:1.5}
.encart-controle.pliable{padding:0}
.controle-bascule{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:10px 13px;background:none;border:none;cursor:pointer;font-family:var(--sans);font-size:13px;font-weight:600;color:var(--alerte);text-align:left}
.controle-chevron{color:var(--alerte);transition:transform .15s}
.controle-chevron.ouvert{transform:rotate(90deg)}
.controle-corps{display:flex;flex-direction:column;gap:8px;padding:0 13px 12px}
.controle-recherche{width:100%}
.controle-liste{display:flex;flex-direction:column;max-height:300px;overflow:auto}
.controle-item{display:flex;align-items:center;gap:10px;padding:7px 2px;font-size:13px;color:var(--titres-c);border-bottom:1px solid var(--bordure)}
.controle-item:last-child{border-bottom:none}
.controle-zone{font-size:11px;color:var(--muted2)}
.mc-groupe-corps{padding:2px 10px 10px}

/* Demandes matériel (logisticien) + rôles secondaires (v1.1) */
.pastille-nav{margin-left:auto;font-family:var(--mono);font-size:10.5px;font-weight:600;background:var(--sx-rouge);color:#fff;border-radius:999px;padding:2px 7px;line-height:1.4}
.ligne-cases{display:flex;flex-wrap:wrap;gap:6px 14px;min-height:34px;align-items:center}
.case-role{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--texte);cursor:pointer;white-space:nowrap}
.pilule-role-sec{opacity:.65}
.demande-traitement{font-size:13.5px;color:var(--texte);line-height:1.55}
.demande-traitement-meta,.evenement-traitement-meta{font-size:11px;color:var(--muted2)}
.evenement-traitement{font-size:12.5px;color:var(--ok);line-height:1.5}
.etat-vide.compact-vide{padding:10px 12px;font-size:13px}

/* Exclusions OGP + rondes par site (v1.3) */
.chip-exclue{background:var(--surface2);color:var(--muted);border:1px solid var(--bordure2)}
.chip-terminee{background:none;color:var(--muted2);border:1px solid var(--bordure)}
.ligne-exclusion{display:flex;align-items:center;gap:10px;min-width:0}
.exclusion-cible{font-size:14px;color:var(--titres-c)}
.exclusion-motif{font-size:13.5px;color:var(--texte);line-height:1.55}
.exclusion-passee{opacity:.62}

/* ===== S542 — LES RETENUES D'ÉQUIPEMENT (écran #/retenues) =====
   ⛔ AUCUNE COULEUR LITTÉRALE : tout passe par les jetons, qui portent déjà le
   thème sombre. Les trois états de ligne réutilisent des chips existantes
   (.chip-a-traiter, .chip-traitee, .chip-neutre) — rien de neuf de ce côté.
   Ces deux règles-ci ne font que poser le bloc d'une LIGNE de retenue : sans
   séparateur, dix lignes sous un même agent se lisent comme un paragraphe. */
.retenue-entete{display:flex;align-items:center;gap:10px;min-width:0;flex-wrap:wrap}
.retenue-ligne{border-top:1px solid var(--bordure);padding-top:8px;display:flex;flex-direction:column;gap:6px}
/* Une ANNULÉE reste LISIBLE — c'est un dossier, pas un compteur. Elle
   s'estompe, elle ne disparaît pas : c'est elle qui explique pourquoi un total
   a changé entre deux relectures. */
.retenue-annulee{opacity:.62}
.retenue-motif{font-size:13.5px;color:var(--texte);line-height:1.55}

/* ===== S218 — LE BLOC D'UN SITE EST UN BLOC (rapport d'exception rondes) =====
   🔴 Six boutons classent les fraudes d'un site — dont un qui s'appelle
   « Fraude ». Ils sont le DERNIER enfant du bloc, après toutes ses cartes
   d'anomalies, et RIEN ne disait à quel site ils se rattachaient : le seul
   indice était 6 px de gouttière (`.pile-serree`) contre 12 px entre les blocs
   (`.pile`). `.mc-carte` encadre chaque RONDE, jamais le bloc. Kamile, qui a
   conçu ce dispositif, a demandé AVANT DE CLIQUER si la barre appartenait au
   site du dessus ou du dessous — elle ne pouvait pas le savoir.
   Le cadre + la barre latérale disent où un site commence et où il finit, y
   compris quand ~29 blocs s'enchaînent. En sombre, `--sx-human` (#1e3a5f) est
   presque le fond : la barre passe sur `--pret`, le seul bleu du thème qui s'y
   détache. Cadre et fond restent sur les variables neutres, donc justes dans
   les deux thèmes sans règle dédiée. */
.bloc-site{border:1px solid var(--bordure);border-left:3px solid var(--sx-human);background:var(--surface2);border-radius:10px;padding:12px 14px 14px;gap:8px}
.theme-sombre .bloc-site{border-left-color:var(--pret)}
/* Le nom du site était le titre le MOINS visible de l'écran, et le seul à dire
   de qui on parle : `.kicker` nu, 10,5 px, `color:var(--muted)`. */
.bloc-site-nom{font-size:11.5px;letter-spacing:.14em;color:var(--titres-c);font-weight:600}
/* La barre de classement se détache du flux des rondes : c'est un geste, pas
   une ligne de rapport. Le trait la sépare de la dernière carte du bloc. */
.barre-classement{margin-top:4px;padding-top:10px;border-top:1px dashed var(--bordure2)}

/* Le glossaire des verdicts — rendu UNE FOIS en tête, jamais dans chaque bloc. */
/* 🔴 S444 — LE GLOSSAIRE EST UN PLI, ET `display:block` N'EST PAS DÉCORATIF.
   `.carte` pose `display:flex`, ce qui ferait de chaque définition un flex item
   du <details> : le pli n'aurait plus de contenu à replier de façon fiable, et
   le marqueur du <summary> se comporterait selon le navigateur. On rend donc la
   boîte au flux normal et on remplace le `gap` par une marge entre frères —
   même respiration, sans dépendre du contexte flex. */
details.glossaire-verdicts{display:block}
.glossaire-verdicts{gap:7px}
.glossaire-verdicts>*+*{margin-top:7px}
/* La ligne qui se clique : c'est elle qui dit qu'il y a quelque chose dessous. */
.glossaire-verdicts>summary{cursor:pointer;padding:2px 0}
.def-verdict{font-size:13px;line-height:1.55;color:var(--texte);text-wrap:pretty}
.def-verdict-nom{font-weight:700;color:var(--titres-c)}
.def-verdict-nom::after{content:' — '}
.def-verdict-effet{color:var(--muted);font-size:12px}
.def-verdict-effet::before{content:'· '}
/* Le seul verdict qui NE FERME PAS doit se repérer sans lire les six lignes :
   c'est la soupape du dispositif, celle qu'on prend quand on ne sait pas. */
.def-verdict-ouvre{color:var(--attente-mat);font-weight:600}

/* S311 — LES VERDICTS DÉJÀ POSÉS, ET CEUX QU'ON A RETIRÉS.
   Ils vivaient dans la ligne d'état, en texte concaténé. Depuis le retrait, un
   verdict porte DEUX gestes et DEUX auteurs, plus un bouton : une phrase ne
   pouvait plus les tenir. Chaque verdict est un bloc, et le retrait s'y lit
   SOUS l'accusation — jamais à sa place, sinon on l'aurait effacée deux fois. */
.verdicts-poses{gap:8px;margin-top:8px}
.verdict-pose{display:flex;flex-direction:column;gap:3px;font-size:13px;line-height:1.5;color:var(--texte);text-wrap:pretty}
.verdict-pose-titre{color:var(--titres-c)}
/* Le démenti se voit : c'est ce qui distingue une accusation qui tient d'une
   accusation retirée, et l'œil doit faire la différence sans lire la phrase. */
.verdict-pose-retrait{color:var(--attente-mat);font-weight:600}
/* Et ce qu'il n'établit PAS, en retrait typographique : un retrait relu comme
   un blanchiment serait aussi faux que l'accusation qu'il défait. */
.verdict-pose-portee{color:var(--muted);font-size:12px}
.verdict-retirer{align-self:flex-start;margin-top:2px}

/* Documents de site (v1.3) */
.ligne-document{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:6px 4px;background:none;border:none;cursor:pointer;font-family:var(--sans);text-align:left;color:var(--texte)}
.ligne-document:disabled{opacity:.5;cursor:wait}
.document-picto{font-size:10px;font-weight:600;letter-spacing:.08em;border:1px solid var(--bordure2);border-radius:5px;padding:3px 6px;color:var(--muted)}
.document-nom{font-size:14px;font-weight:600;color:var(--titres-c)}

/* Circuit matériel complet v1.2 (a_traiter → prete → livree) */
.ligne-actions-demande{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.demande-livreur{font-size:12.5px;color:var(--texte)}
.demande-livreur b{color:var(--titres-c)}
.demande-livreur .indicatif{font-size:11px;color:var(--muted2)}

/* S390 — les trois jalons datés d'une demande (demandée / prête / livrée).
   Le nom du jalon est à largeur fixe pour que les trois dates s'alignent : on
   compare des moments, l'œil doit les lire en colonne. Le jalon NON atteint est
   en italique et en gris : il se distingue d'une date au premier regard, sans
   jamais ressembler à un blanc — « pas encore livrée » n'est pas une donnée
   manquante, c'est une étape qui n'a pas eu lieu. */
.demande-jalons{display:flex;flex-direction:column;gap:3px;padding:8px 10px;border-radius:8px;background:var(--surface2);border:1px solid var(--bordure)}
.demande-jalon{display:flex;gap:8px;align-items:baseline;font-size:11.5px;line-height:1.5}
.demande-jalon-nom{flex:none;min-width:74px;color:var(--muted2);letter-spacing:.03em}
.demande-jalon-date{color:var(--titres-c)}
.demande-jalon-attente{color:var(--muted2);font-style:italic}

/* Correctifs revue v1.1 reportés dans les sources */
.encart-confirmation{background:var(--ok-fond);border:1px solid var(--ok-bordure);color:var(--ok);border-radius:9px;padding:10px 13px;font-size:12.5px}
.duo-hors-planning{display:flex;gap:8px;flex:1;min-width:0}
.champ-matricule-libre{max-width:132px}

.ligne-filtres-sites{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
/* S121 : la ligne de filtres de l'écran Sites passe de trois à QUATRE pilules
   (½ jour, ½ nuit, BIP, rondes). En malgache elle dépasse la largeur d'un
   téléphone. Le retour à la ligne est posé ici et pas sur `.ligne-filtres`,
   partagée par dix écrans — même prudence que le `flex:none` du sélecteur de
   date : un enfant qui absorbe seul tout le débordement se rogne en silence. */
.ligne-filtres.pilules-sites{flex-wrap:wrap;row-gap:6px}
.marqueurs-site{display:flex;gap:6px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
.marqueur-rondes{color:var(--muted);border-color:var(--bordure2)}

/* ===== Fiche site lecture seule + accès opérateur (v1.4, chantier D) ===== */
.ligne-appel-rangee{display:flex;gap:6px;align-items:stretch}
.ligne-appel-rangee .ligne-appel{flex:1}
.btn-fiche{flex:none;min-width:64px;padding:0 12px;border:1px solid var(--bordure2);border-radius:9px;background:var(--surface);color:var(--muted);font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;cursor:pointer}
.btn-fiche:hover{background:var(--surface2);color:var(--titres-c);border-color:#8494ab}
.btn-lien-fiche{align-self:flex-start;margin:2px 0 8px;padding:8px 12px;min-height:40px;background:var(--surface2);border:1px solid var(--bordure2);border-radius:9px;color:var(--sx-human);font-family:var(--sans);font-weight:600;font-size:13px;cursor:pointer}
.btn-lien-fiche:hover{border-color:var(--sx-human)}
.dialogue-fiche{width:min(460px,92vw);max-height:min(82vh,760px);overflow-y:auto;display:flex;flex-direction:column;gap:14px}
.fiche-entete{display:flex;align-items:flex-start;gap:10px;justify-content:space-between}
.fiche-titre{font-size:18px}
.chip-lecture{background:var(--surface2);color:var(--muted);border:1px solid var(--bordure2)}
.fiche-meta{font-size:12.5px;color:var(--muted);text-wrap:pretty}
.fiche-effectifs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13px;color:var(--texte)}
.fiche-sep{color:var(--muted2)}
.fiche-consignes{background:var(--alerte-fond);border:1px solid rgba(209,27,42,.28);border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:6px}
.fiche-consignes-txt{font-size:14px;color:var(--titres-c);line-height:1.5;text-wrap:pretty}
.fiche-bloc{display:flex;flex-direction:column;gap:6px}
.fiche-bloc-txt{font-size:13.5px;color:var(--texte);line-height:1.5;text-wrap:pretty}

/* ===== Tournée éditable (v1.4, chantier A) ===== */
.tournee-barre{display:flex;align-items:center;gap:8px}
.ligne-compo-terrain{min-height:52px;gap:8px;padding:6px 4px}
.ligne-compo-terrain .ligne-compo-nom{font-size:15px}
.btn-mini-terrain{width:44px;height:44px;font-size:16px}
.chip-terrain{background:var(--sx-human);color:#fff;border:1px solid var(--sx-human)}
.theme-clair .chip-terrain{background:#e7edf5;color:var(--sx-human);border-color:#c7d6e6}

/* ===== Absences (v1.4, chantier B) ===== */
.carte-absence{gap:8px;padding:14px}
.absence-tete{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.absence-agent{font-weight:700;font-size:15px;color:var(--titres-c)}
.absence-site{font-size:12px;color:var(--muted)}
.absence-motif{font-size:14px;color:var(--texte);line-height:1.5;text-wrap:pretty}
.absence-remplacant{font-size:13px;color:var(--ok)}
.absence-meta{font-size:11px;color:var(--muted2)}
.agent-absent{text-decoration:line-through;color:var(--muted)}
.ligne-appel-rempl{font-size:11px;color:var(--ok)}
/* Neutre au repos : ce bouton est sur TOUTES les lignes sans absence — peint en
   rouge, il faisait lire « absent » partout. Le rouge est réservé à l'état réel
   (.chip-ouverte, sur la ligne). Il ne s'allume qu'au survol, à l'intention. */
.btn-signaler{white-space:nowrap}
.btn-signaler:hover{background:var(--alerte-fond);color:var(--alerte);border-color:var(--alerte)}
.carte-absent{opacity:.72;gap:6px}
.pilule-remplacant{color:var(--ok);border-color:var(--ok-bordure)}
.ligne-site-nom.inactif{color:var(--muted);text-decoration:line-through}
.carte-attendus{gap:8px;padding:14px}

/* ===== Administration ===== */
.encart-provisoire{background:var(--sx-encre);border-radius:11px;padding:14px 16px;display:flex;flex-direction:column;gap:9px;color:#b3c0cf}
.encart-provisoire .kicker{color:#8494ab}
.encart-provisoire .note-offline{color:#8494ab}
.provisoire-ligne{display:flex;align-items:center;gap:12px}
.provisoire-mdp{font-size:17px;font-weight:600;color:#fff;letter-spacing:.04em}
.encart-provisoire .btn-secondaire{background:transparent;border-color:#2c3f57;color:#eaeef3}
.inactif-txt{color:var(--muted);text-decoration:line-through}
.ligne-audit{display:flex;align-items:baseline;gap:12px;min-height:38px;padding:5px 2px;border-bottom:1px solid var(--surface2)}
.ligne-audit:last-child{border-bottom:none}
.ligne-audit-date{font-size:11px;color:var(--muted2);flex:none;width:84px}
.ligne-audit-texte{font-size:13px;color:var(--texte);min-width:0}
.ligne-audit-texte b{color:var(--titres-c)}
.ligne-audit-ip{font-size:10.5px;color:var(--muted2)}

/* ===== Sélecteur cherchable (v1.4) =====
   Réutilise .voile / .dialogue / .ligne-site : le sélecteur ne doit pas
   ressembler à un écran d'une autre application. */
.dialogue-selecteur{width:min(440px,92vw);max-height:80vh;gap:10px}
/* Jamais 100vh seul : la barre du navigateur mobile rogne la fenêtre. */
@supports (height:100dvh){.dialogue-selecteur{max-height:80dvh}}
.selecteur-entete{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.selecteur-compte{font-size:11px;color:var(--muted2);white-space:nowrap}
.selecteur-aide{font-size:12.5px;color:var(--muted2);text-wrap:pretty}
/* 16px : en dessous, iOS zoome au focus du champ — le superviseur est sur téléphone. */
.selecteur-recherche{width:100%;font-size:16px;padding:11px 12px}
/* 🔴 `flex:none` — S223, « zone recherche trop grande » (Kamile, 05/08/2026).
   `.champ-recherche` est un utilitaire de LIGNE : son `flex:0 1 168px` (l. 368)
   vaut 168 px de LARGEUR dans un bandeau de filtres horizontal. Le dialogue,
   lui, est une COLONNE (`.dialogue{flex-direction:column}`) — la même
   déclaration y vaut 168 px de HAUTEUR, et le champ absorbe tout le vide que la
   liste ne prend pas. Mesuré sur une fenêtre de 390 × 844 : 168 px sur les six
   motifs d'absence (un tiers du dialogue, pour un champ vide), contre 73 px sur
   les 21 agents. Plus la liste était COURTE, plus la recherche était GROSSE.
   Même correctif que `.circuits-banque .champ-recherche` (l. 976) et que le
   sélecteur de date du bandeau : un utilitaire élastique ne traverse pas un
   changement d'axe sans qu'on le reborne. */
.selecteur-recherche{flex:none}
.selecteur-liste{display:flex;flex-direction:column;gap:6px;overflow-y:auto;min-height:0;-webkit-overflow-scrolling:touch}
/* Sous le seuil de recherche, c'est la liste qui porte le focus clavier : il
   doit se voir, sinon les flèches agissent sur un écran qui ne dit rien. */
.selecteur-liste:focus-visible{outline:2px solid var(--sx-human);outline-offset:3px;border-radius:8px}
.selecteur-liste .ligne-site{flex:none}
.ligne-site.actif{border-color:var(--sx-human);background:var(--nav-actif)}
/* Mode « plusieurs » (S388) — la case, et la ligne cochée.
   🔴 LA COCHE SE VOIT SANS LA COULEUR : le symbole ☐/☑ change de FORME, et le
   nom passe en gras avec lui. Une teinte seule serait perdue pour un daltonien,
   et perdue tout court sur un téléphone à 3 h du matin, luminosité au minimum.
   `.actif` (curseur clavier) et `.cochee` partagent le même fond : ils ne se
   confondent pas pour autant, seule la seconde porte une case pleine. */
.selecteur-case{flex:none;width:16px;font-size:15px;line-height:1;color:var(--muted)}
.ligne-site.cochee{border-color:var(--sx-human);background:var(--nav-actif)}
.ligne-site.cochee .selecteur-case{color:var(--sx-human)}
.ligne-site.cochee .ligne-site-nom{font-weight:700}
.selecteur-meta{margin-left:auto;font-size:11.5px;color:var(--muted);white-space:nowrap}
/* S743 / `A209` — « inconnu de TimeTrex », à côté du nom.
   🔴 OCRE, PAS ROUGE, ET PAS GRIS. Rouge (`--alerte`) dirait qu'il y a une
   faute ou un danger : il n'y en a pas, l'homme est embauché et le poste est
   couvrable par lui. Gris (`--muted`, la couleur de `.ligne-site-dist`) le
   rangerait avec le site habituel — une information de contexte qu'on survole.
   C'est ni l'un ni l'autre : un état à connaître avant de choisir, parce qu'un
   seul geste lui est refusé. `--attente-mat` porte déjà exactement ce registre
   ailleurs dans l'app, et il est défini dans LES DEUX thèmes — la base
   opérateur tourne en sombre de 16 h à 6 h, c'est-à-dire pendant toute la nuit
   où ce sélecteur sert. */
.selecteur-mention{font-size:11px;color:var(--attente-mat);background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);border-radius:999px;padding:2px 8px;white-space:nowrap;flex:none}

/* ===== Main courante = registre chronologique (14/07) ===== */
.mc-ecrire{align-self:flex-start;margin-bottom:2px}
.mc-entree{padding:10px 14px;display:flex;flex-direction:column;gap:6px}
.mc-entree-ligne{display:flex;align-items:baseline;gap:10px}
.mc-entree-heure{font-size:11.5px;color:var(--muted2);flex:none;width:42px}
.mc-entree-texte{font-size:14px;color:var(--titres-c);line-height:1.5;text-wrap:pretty;min-width:0}
.chip-entree{background:var(--surface2);color:var(--muted);border:1px solid var(--bordure2);flex:none}
.mc-entree-pied{display:flex;align-items:center;gap:8px;padding-left:52px;font-size:11.5px;color:var(--muted2)}
.mc-entree-sans-site{color:var(--muted2)}
/* Cycle de traitement d'une entrée (S63) — sous le pied de l'entrée, aligné
   sur lui (52px) pour que l'état se lise dans la même colonne que l'auteur.
   `flex-wrap` : sur un écran étroit, la cause et les boutons passent à la
   ligne plutôt que d'écraser le chip d'état, qui est l'information première. */
.mc-cycle{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-left:52px;padding-top:2px}
.mc-cycle-meta{font-size:11.5px;color:var(--muted2)}
.mc-cycle-cause{font-size:12.5px;color:var(--titres-c);font-weight:600}
.mc-cycle-note{font-size:12px;color:var(--muted);font-style:italic;min-width:0}
/* Hors du registre (carte d'évènement du superviseur) : pas de gouttière. */
.mc-cycle.sans-retrait{padding-left:0}
.dialogue-composeur{width:min(520px,94vw);gap:10px}
.dialogue-composeur .zone-texte{width:100%;font-size:16px}
.mc-ligne-site{display:flex;align-items:center;gap:10px}
.mc-site-choisi{font-size:13px;color:var(--muted)}
/* La couleur porte l'information : un incident ne se lit pas comme une observation. */
.chip-entree.chip-incident{background:var(--alerte-fond);color:var(--alerte);border-color:rgba(209,27,42,.4)}
.chip-entree.chip-besoin_materiel{background:var(--attente-mat-fond);color:var(--attente-mat);border-color:var(--attente-mat-bordure)}
/* Téléphone de l'AGENT dans la file d'appel (14/07) : c'est lui qu'on compose. */
.tel-agent{color:var(--sx-human);font-weight:600;white-space:nowrap}
.theme-sombre .tel-agent{color:#8fb3c9}
/* Quelle nuit la grille montre-t-elle ? En service jour, le bandeau dit « Jour »
   alors que le contenu est la nuit écoulée — l'écran doit le nommer. */
.bip-etiquette-nuit{font-size:11px;color:var(--muted);white-space:nowrap}
.bip-etiquette-nuit.rappel{color:var(--attente-mat);background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);border-radius:999px;padding:5px 11px}
/* 🔴 La RAISON de cette pastille, LUE et non survolée (S224). Elle vivait dans
   l'attribut `title` de l'étiquette — donc au survol de souris seulement, et
   nulle part au doigt. Elle ne paraît que sur un service de jour (`hidden`
   sinon) : une mention permanente n'est plus un signal. Elle se replie sur sa
   propre ligne quand le bandeau déborde (`flex-wrap` de `.bandeau`). */
.bip-mention-jour{font-size:12px;line-height:1.35;color:var(--attente-mat);max-width:34ch;text-wrap:pretty}
.encart-nuit-ecoulee{background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);color:var(--attente-mat);border-radius:9px;padding:9px 12px;font-size:12.5px;text-wrap:pretty}

/* Alerte globale : un geste refusé doit se voir (14/07 — l'opérateur cliquait
   dans le vide, toutes les écritures avalaient leurs erreurs en silence). */
.alerte-globale{position:fixed;top:14px;left:50%;transform:translateX(-50%);z-index:120;display:flex;align-items:center;gap:12px;max-width:min(680px,92vw);padding:12px 14px;border-radius:10px;background:var(--alerte-fond);border:1px solid rgba(209,27,42,.45);color:var(--alerte);font-size:13.5px;box-shadow:0 6px 24px rgba(6,13,21,.28);text-wrap:pretty}
.theme-sombre .alerte-globale{background:#2a0d11;border-color:#5e1a22;color:#ff8a92}
/* Ton « attente » (S217, 05/08/2026) : une formalité en cours, pas une panne.
   Ambre (--attente-mat), comme le rappel de passation — le rouge reste réservé
   à l'anormal, sinon il perd son signal. Surcharge et ne remplace pas : sans
   `.ton-attente`, le bandeau est celui de toujours, rouge.
   Les couleurs passant par des variables DÉJÀ thémées, la variante sombre porte
   les mêmes déclarations que la claire. Elle n'est pas décorative pour autant :
   `.theme-sombre .alerte-globale` (le rouge sombre) a la MÊME spécificité que
   `.alerte-globale.ton-attente` — seul l'ordre source les départage. La règle
   sombre dédiée ci-dessous ferme ce point : déplacer le bloc rouge ne peut plus
   repeindre l'attente en rouge à l'insu de tous. */
.alerte-globale.ton-attente{background:var(--attente-mat-fond);border-color:var(--attente-mat-bordure);color:var(--attente-mat)}
.theme-sombre .alerte-globale.ton-attente{background:var(--attente-mat-fond);border-color:var(--attente-mat-bordure);color:var(--attente-mat)}
/* Ton « ok » (S326) : un abonnement aux notifications qui a RÉUSSI. Sans lui,
   `alerte(…, 'ok')` retombait sur le bandeau rouge — annoncer une réussite en
   rouge, c'est faire croire à un échec, sur le seul geste où la personne a
   besoin de savoir que ça a marché. Même précaution que l'attente : la variante
   sombre est déclarée explicitement, faute de quoi `.theme-sombre
   .alerte-globale` (rouge) la repeindrait à spécificité égale. */
.alerte-globale.ton-ok{background:var(--ok-fond);border-color:var(--ok-bordure);color:var(--ok)}
.theme-sombre .alerte-globale.ton-ok{background:var(--ok-fond);border-color:var(--ok-bordure);color:var(--ok)}
.alerte-texte{flex:1;min-width:0}
.alerte-fermer{flex:none;min-height:28px;min-width:28px;background:none;border:none;color:inherit;cursor:pointer;font-size:13px}
.profil-version{font-size:10.5px;color:var(--muted2);letter-spacing:.04em}
.profil-version{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:10.5px;color:var(--muted2);letter-spacing:.04em}
.profil-verdict.a-jour{color:var(--ok)}
.profil-verdict.perimee{color:var(--alerte);font-weight:600}
/* Note de la carte « Mode démonstration » (S120). Sur variables de thème, donc
   lisible en clair comme en sombre — à la différence de `.indice-demo`, figé en
   clair parce qu'il ne sert que l'écran de connexion. */
.profil-demo-note{font-size:12.5px;color:var(--muted);line-height:1.55;text-wrap:pretty}
/* Bascule Jour/Nuit sur la coquille terrain (elle n'a pas de bandeau). */
.tournee-services{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.tournee-services .bascule-vue{min-height:44px;padding:0 18px}
.tournee-service-libelle{font-size:11px;color:var(--muted2)}

/* Rondes électro en temps réel (v1.4) — écran rondes-tr */
.grille-compteurs.cinq{grid-template-columns:repeat(5,1fr)}
@media(max-width:760px){.grille-compteurs.cinq{grid-template-columns:repeat(2,1fr)}}
.rtr-live{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;color:var(--muted)}
.rtr-live .point-vert{animation:rtr-pulse 2s ease-in-out infinite}
@keyframes rtr-pulse{0%,100%{opacity:1}50%{opacity:.3}}
.rtr-site{gap:11px;padding:14px 16px}
.rtr-site-tete{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.rtr-site-nom{font-weight:700;font-size:15.5px;color:var(--titres-c)}
.rtr-site-zone{font-size:10px;color:var(--muted2);letter-spacing:.06em}
.rtr-site-score{font-size:12.5px;color:var(--texte)}
.rtr-site-score b{color:var(--titres-c)}
/* 🔴 S444 — CETTE PASTILLE CHANGE DE REGISTRE : l'alerte devient l'AMBRE DE
   L'ATTENTE, le même que la gravité `jour` et le rappel de passation.
   Pourquoi : elle habille une DÉDUCTION DE MACHINE non instruite. Les
   explications ordinaires d'une ronde sans points sont le contrôleur mort, le
   QR illisible, le téléphone en panne — et sur les 1 665 accusations de
   production, 938 n'ont jamais reçu la moindre action, une seule porte un
   verdict. Le rouge est une affirmation ; ici il n'y a qu'une chose à aller
   voir. LE ROUGE N'ARRIVE QU'AVEC UN FAIT INSTRUIT.
   ⛔ Ce qui NE bouge PAS, et c'est le contrôle négatif du lot : le bandeau du
   TROU DE SURVEILLANCE reste plein d'alerte (posé en style dans `rondes-tr.js`
   et `main-courante.js`). Un service non rendu est un fait constaté, pas une
   déduction — c'est le seul des deux griefs qui désigne juste, et les deux ne
   se fusionnent pas. */
.chip-fraude{background:var(--attente-mat-fond);color:var(--attente-mat);border:1px solid var(--attente-mat-bordure)}
/* Carence de queue : un site laissé DÉCOUVERT au bout d'une chaîne de
   remplacement. Alerte PLEINE, pas le rouge clair de .chip-ouverte — les deux
   absences sont « à pourvoir », mais celle-ci est un poste non tenu, pas un
   point de départ. Les confondre, c'est laisser la carence se noyer dans la
   liste et le site passer la nuit sans personne. */
.chip-carence{background:var(--alerte);color:#fff;border:1px solid var(--alerte)}
/* Un maillon de chaîne, décalé selon sa profondeur (le décalage lui-même est
   posé en style, il dépend du rang). Le trait à gauche donne le fil. */
.chaine-maillon{border-left:2px solid var(--bordure2);padding-left:10px}
.chaine-fin{font-size:11px;letter-spacing:.05em}
.rtr-creneau{display:flex;flex-direction:column;gap:5px;border-top:1px solid var(--surface2);padding-top:9px}
.rtr-creneau-titre{font-size:10px;letter-spacing:.07em;color:var(--muted2)}
.rtr-ronde-bloc{min-width:0}
.rtr-ronde-preuve{font-size:11px;color:var(--muted);padding-bottom:3px}
.rtr-ronde{display:flex;align-items:center;gap:10px;min-width:0;padding:3px 0}
.rtr-ronde-route{font-size:12px;color:var(--titres-c);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rtr-ronde-pts{font-size:11.5px;color:var(--muted);white-space:nowrap}
.rtr-ronde-pts b{color:var(--texte)}
.rtr-ronde-fraude{font-size:11px;color:var(--alerte);font-weight:600;white-space:nowrap}
.chip-complete{background:var(--ok-fond);color:var(--ok);border:1px solid var(--ok-bordure)}
.chip-partielle{background:var(--surface2);color:var(--muted);border:1px solid var(--bordure2)}
.chip-manquee{background:var(--alerte-fond);color:var(--alerte);border:1px solid rgba(209,27,42,.4)}
.rtr-creneau-vide{font-size:12px;color:var(--muted2)}

/* Squelettes de chargement (états async) — shimmer discret, respecte reduced-motion */
@keyframes skShimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
.sk{background:linear-gradient(90deg,var(--surface2) 25%,var(--bordure) 50%,var(--surface2) 75%);background-size:200% 100%;animation:skShimmer 1.5s ease-in-out infinite;border-radius:10px}
.sk-wrap{gap:14px}
.sk-titre{height:26px;width:200px}
.sk-carte{height:92px;border-radius:13px}
.sk-ligne{height:52px}
@media (prefers-reduced-motion:reduce){.sk{animation:none;opacity:.65}}

/* Cas de fraude dans la main courante */
/* `flex-wrap` + `flex-basis:100%` sur la preuve : elle passe SOUS la ligne
   règle/route plutôt que de la comprimer. C'est l'écart « prévue 02:00 ·
   badgée 03:03 → 03:08 » qui se juge — le cacher revenait à afficher
   « 7 ronde(s) suspecte(s) » sans rien d'exploitable (16/07, Confecta). */
.mc-fraude-cas{display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12px;flex-wrap:wrap}
.mc-fraude-detail{color:var(--texte)}
.mc-fraude-preuve{flex-basis:100%;font-size:11px;color:var(--muted)}

/* ===== Réconciliation BIP (v1.6) — le rapport du mode témoin ===== */
/* Règle du brief : la COUVERTURE se lit AVANT les écarts. Un écran qui
   montre « 0 coché sans appel » sans montrer « 8 créneaux sans témoin »
   ment par omission. D'où l'ordre : pertes → créneaux aveugles → compteurs. */
.rec-aide{font-size:12.5px;color:var(--muted2);text-wrap:pretty;max-width:520px}
/* Bloc couverture — d'abord. Accent gauche rouge quand il y a des pertes. */
.rec-couverture{gap:14px}
.rec-pertes{border-left:3px solid var(--alerte);padding-left:14px;display:flex;flex-direction:column;gap:9px}
.rec-pertes-tete{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.rec-pertes-total{font-family:var(--mono);font-size:32px;font-weight:600;color:var(--alerte);line-height:1}
.rec-pertes-titre{font-weight:700;font-size:14.5px;color:var(--titres-c)}
.rec-pertes-note{font-size:12.5px;line-height:1.55;color:var(--texte);text-wrap:pretty}
.rec-perte{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;font-size:12.5px;padding:6px 0;border-top:1px solid var(--surface2)}
.rec-perte-vol{font-family:var(--mono);font-weight:600;color:var(--titres-c);min-width:58px}
.rec-perte-vol.bruit{color:var(--muted2);font-weight:400}
.rec-perte-appareil{color:var(--texte)}
.rec-perte-saut{font-family:var(--mono);font-size:11.5px;color:var(--muted)}
.rec-perte-fenetre{font-family:var(--mono);font-size:11.5px;color:var(--muted2);margin-left:auto;white-space:nowrap}
/* C2-quater — rappels rapprochés. NEUTRE, jamais rouge : un état du réseau, pas
   une fraude. Bordure discrète (pas la bordure d'alerte des pertes). */
.rec-rappels{border-left:3px solid var(--bordure2);padding-left:14px;display:flex;flex-direction:column;gap:7px}
.rec-rappels-note{font-size:12.5px;line-height:1.55;color:var(--texte);text-wrap:pretty}
.rec-rappel{display:flex;align-items:baseline;gap:10px;font-size:12.5px;padding:5px 0;border-top:1px solid var(--surface2)}
.rec-rappel-vol{font-family:var(--mono);font-weight:600;color:var(--titres-c);min-width:44px}
.rec-rappel-cible{color:var(--texte)}
.rec-rappel-fenetre{font-family:var(--mono);font-size:11.5px;color:var(--muted2);white-space:nowrap}
/* Frise des heures de la nuit (20..23, 0..5) — ordre donné par l'API. */
.rec-frise{display:flex;flex-direction:column;gap:7px}
.rec-frise-tete{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.rec-frise-titre{font-weight:600;font-size:13.5px;color:var(--titres-c)}
.rec-frise-compte{font-family:var(--mono);font-size:11.5px;color:var(--muted)}
.rec-heures{display:flex;flex-wrap:wrap;gap:5px}
.rec-heure{font-family:var(--mono);font-size:11.5px;min-width:34px;text-align:center;padding:5px 4px;border-radius:7px}
.rec-heure.couvert{background:var(--ok-fond);color:var(--ok);border:1px solid var(--ok-bordure)}
/* Aveugle = ni vert ni rouge. Une absence, pas un verdict. Hachuré, dashed. */
.rec-heure.aveugle{color:var(--muted2);border:1px dashed var(--bordure2);
  background:repeating-linear-gradient(-45deg,transparent,transparent 4px,var(--surface2) 4px,var(--surface2) 8px)}
.rec-verdict{font-size:13px;line-height:1.55;text-wrap:pretty;padding-top:2px}
.rec-verdict.ok{color:var(--ok)}
.rec-verdict.aveugle{color:var(--texte)}
/* Note « non rattachés » collée au compteur « coché sans appel ». */
.rec-compteur-note{font-size:11px;line-height:1.45;color:var(--muted2);text-wrap:pretty;margin-top:2px}
.rec-compteur-note b{color:var(--attente-mat)}
/* Le compteur « sans témoin » ne peut pas ressembler aux quatre autres : c'est
   une absence de preuve, pas un décompte. Hachuré + dashed, comme la cellule et
   l'heure aveugles. La vue posait déjà la classe `aveugle` — mais cette règle
   n'existait pas : la carte rendait EXACTEMENT comme les autres (fond blanc,
   bordure solide), mesuré le 17/07. Le cas qui existe pour ne pas accuser à
   tort se fondait dans les décomptes normaux : le trou redevenait invisible. */
.carte-compteur.aveugle{border:1px dashed var(--bordure2);
  background:repeating-linear-gradient(-45deg,var(--surface),var(--surface) 5px,var(--surface2) 5px,var(--surface2) 10px)}
/* Grille par site : une pastille par créneau, cas → couleur. */
.rec-site{gap:9px;padding:13px 16px}
.rec-site-tete{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.rec-site-nom{font-weight:700;font-size:15px;color:var(--titres-c)}
.rec-site-meta{font-family:var(--mono);font-size:10.5px;color:var(--muted2);letter-spacing:.04em}
.rec-site-ecarts{font-family:var(--mono);font-size:11.5px;color:var(--texte)}
.rec-site-ecarts b{color:var(--titres-c)}
.rec-creneaux{display:flex;flex-wrap:wrap;gap:4px}
.rec-cell{position:relative;font-family:var(--mono);font-size:11px;min-width:32px;text-align:center;padding:5px 4px;border-radius:6px;border:1px solid transparent;cursor:default}
.rec-cell.concordant_pointe{background:var(--ok-fond);color:var(--ok);border-color:var(--ok-bordure)}
.rec-cell.concordant_manque{background:var(--surface2);color:var(--muted);border-color:var(--bordure2)}
.rec-cell.coche_sans_appel{background:var(--alerte-fond);color:var(--alerte);border-color:rgba(209,27,42,.4);font-weight:600}
.rec-cell.appel_non_saisi{background:var(--attente-mat-fond);color:var(--attente-mat);border-color:var(--attente-mat-bordure);font-weight:600}
.rec-cell.temoin_aveugle{color:var(--muted2);border:1px dashed var(--bordure2);
  background:repeating-linear-gradient(-45deg,transparent,transparent 3px,var(--surface2) 3px,var(--surface2) 7px)}
.rec-legende{display:flex;flex-wrap:wrap;gap:12px;padding:2px 4px}
.rec-legende-item{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:var(--muted)}
.rec-legende-pastille{width:14px;height:14px;border-radius:4px;flex:none}
.rec-note-bas{background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);border-radius:9px;padding:11px 13px;font-size:12px;line-height:1.55;color:var(--attente-mat);text-wrap:pretty}

/* ===== Circuits ===== */
/* Éditeur de circuit (planificateur, thème clair en usage — variables seules,
   donc le sombre suit). Deux panneaux bornés en hauteur : banque à gauche,
   itinéraire à droite. Chacun défile EN INTERNE (une seule zone défilante par
   panneau) pour que l'en-tête et le fil ne se perdent jamais — pas de scroll
   croisé. La zone est l'unité visible : bloc identifiable, ordre manipulable. */

/* — Barre d'action (retour · titre · enregistrer) */
.circuits-barre{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.circuits-titre-edit{flex:1;min-width:0;font-family:var(--titres);font-weight:800;font-size:20px;color:var(--titres-c);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* — Identité : nom + description sur une ligne (les <input> héritent de .champ input) */
.circuits-identite{display:flex;align-items:flex-end;gap:14px;flex-wrap:wrap}
.circuits-ch{flex:1 1 240px;min-width:0}
.circuits-champ-nom,.circuits-champ-desc{width:100%}

/* — Case « voir inactifs » de la liste #/circuits */
.circuits-inactifs{width:16px;height:16px;accent-color:var(--sx-human)}

/* — Les deux panneaux côte à côte, hauteur bornée (chacun défile en interne) */
.circuits-panneaux{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;align-items:stretch;min-width:860px;height:calc(100vh - 236px);min-height:460px}
.circuits-banque,.circuits-itineraire{display:flex;flex-direction:column;min-height:0;background:var(--surface);border:1px solid var(--bordure);border-radius:12px;overflow:hidden}

/* — En-tête de panneau (commun aux deux) */
.circuits-pan-tete{display:flex;align-items:center;gap:10px;flex:none;padding:13px 16px;border-bottom:1px solid var(--bordure)}
.circuits-pan-titre{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;font-family:var(--titres);font-weight:700;font-size:15px;color:var(--titres-c)}
.circuits-pan-compte{font-family:var(--mono);font-size:11.5px;font-weight:400;color:var(--muted);letter-spacing:.02em}

/* — Recherche de la banque : l'utilitaire .champ-recherche est élastique en
     RANGÉE (flex:0 1 168px) ; en colonne ça fixait sa hauteur. On la neutralise
     dans ce contexte uniquement. */
.circuits-banque .champ-recherche{flex:none;width:auto;margin:10px 14px 2px}

/* — Liste des zones : SEULE partie défilante de la banque */
.circuits-zone-liste{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:8px;padding:8px 14px 14px}

/* — Une zone = accordéon. flex:none : ne se comprime JAMAIS — sans lui, les
     lignes dépliées étaient rognées et la liste refusait de défiler. */
.circuits-zone{flex:none;border:1px solid var(--bordure);border-radius:10px;overflow:hidden;background:var(--surface)}
.circuits-zone-tete{display:flex;align-items:center;gap:9px;width:100%;min-height:46px;padding:8px 12px;background:var(--surface2);border:none;cursor:pointer;font-family:var(--sans);text-align:left;color:var(--titres-c)}
.circuits-zone-tete:hover{background:var(--nav-actif)}
.circuits-zone-tete .controle-chevron{color:var(--muted2)}
.circuits-zone-nom{font-weight:600;font-size:14px;color:var(--titres-c)}
.circuits-zone-meta{font-family:var(--mono);font-size:11px;color:var(--muted2);white-space:nowrap}
.circuits-zone-corps{display:flex;flex-direction:column;gap:4px;padding:8px;border-top:1px solid var(--bordure)}

/* — Ajouter la zone entière : le geste qui remplace 44 clics par 5. Bleu human
     (le rouge reste réservé au submit / au destructif). */
.circuits-add-zone{flex:none;margin-left:auto;min-height:32px;padding:0 12px;background:var(--sx-human);color:#fff;border:1px solid var(--sx-human);border-radius:8px;font-family:var(--sans);font-weight:600;font-size:12px;cursor:pointer;white-space:nowrap}
.circuits-add-zone:hover{background:var(--sx-encre);border-color:var(--sx-encre)}
.circuits-add-zone.complet{background:var(--ok-fond);color:var(--ok);border-color:var(--ok-bordure);cursor:default}

/* — Un site dans la banque : bouton bascule (coché = dans le circuit) */
.circuits-bank-site{display:flex;align-items:center;gap:10px;width:100%;min-height:42px;padding:6px 10px;background:var(--surface);border:1px solid var(--bordure);border-radius:9px;cursor:pointer;font-family:var(--sans);text-align:left;font-size:14px;color:var(--titres-c)}
.circuits-bank-site:hover{border-color:var(--bordure2);background:var(--surface2)}
.circuits-bank-site.ajoute{background:var(--ok-fond);border-color:var(--ok-bordure)}
.circuits-bank-nom{flex:1;min-width:0;font-weight:500;color:var(--titres-c);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.circuits-check{width:18px;height:18px;flex:none;display:flex;align-items:center;justify-content:center;border:1.5px solid var(--bordure2);border-radius:5px;font-size:11px;color:transparent}
.circuits-check.on{background:var(--ok);border-color:var(--ok);color:#fff}
.circuits-dans{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--muted2);white-space:nowrap}

/* — Circuits secteur 22/07 : séparateur de quartier (zone) rendu DANS le corps
   d'un secteur, avec son « + » de quartier (chemin fin). 4 classes neuves ; le
   reste réutilise .circuits-zone*/.circuits-bloc*. Variables existantes. */
.circuits-zone-sep{display:flex;align-items:center;gap:8px;padding:7px 4px 3px;margin-top:2px}
.circuits-zone-sep-nom{font-family:var(--mono);font-size:10.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--muted2)}
.circuits-zone-sep-meta{font-family:var(--mono);font-size:10.5px;color:var(--muted2)}
.circuits-add-quartier{flex:none;min-height:24px;padding:0 9px;background:transparent;color:var(--sx-human);border:1px solid var(--bordure2);border-radius:7px;font-family:var(--sans);font-weight:600;font-size:11.5px;cursor:pointer;white-space:nowrap}
.circuits-add-quartier:hover{background:var(--sx-human);border-color:var(--sx-human);color:#fff}
.circuits-add-quartier.complet{color:var(--ok);border-color:var(--ok-bordure);cursor:default;background:transparent}

/* — Bouton « trier par zone » (hérite de .btn-mini, mais porte un libellé) */
.circuits-trier{width:auto;padding:0 12px;white-space:nowrap}

/* — Aide d'ordre + note « modèle » de l'itinéraire */
.circuits-ordre-aide{flex:none;padding:9px 16px 0;font-size:12px;color:var(--muted2);line-height:1.5;text-wrap:pretty}
.circuits-note-modele{flex:none;margin:0 16px 14px;padding:9px 11px;background:var(--surface2);border:1px solid var(--bordure2);border-radius:9px;font-size:12px;color:var(--texte);line-height:1.5;text-wrap:pretty}

/* — Corps de l'itinéraire : SEULE partie défilante */
.circuits-it-corps{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:10px;padding:10px 16px}

/* — Bloc de zone dans l'itinéraire = l'unité de réordonnancement */
.circuits-bloc{flex:none;border:1px solid var(--bordure);border-radius:10px;overflow:hidden;background:var(--surface)}
.circuits-bloc-tete{display:flex;align-items:center;gap:9px;min-height:40px;padding:6px 10px;background:var(--surface2);border-bottom:1px solid var(--bordure)}
.circuits-bloc-ord{width:22px;height:22px;flex:none;display:flex;align-items:center;justify-content:center;background:var(--sx-encre);color:#fff;border-radius:6px;font-size:12px;font-weight:600}
.circuits-bloc-nom{font-weight:700;font-size:13.5px;color:var(--titres-c)}
.circuits-bloc-compte{font-family:var(--mono);font-size:11px;color:var(--muted2);white-space:nowrap}

/* — Ligne de site dans l'itinéraire (numéro courant · nom · nuit · flèches · ✕) */
.circuits-it-site{display:flex;align-items:center;gap:9px;min-height:40px;padding:5px 10px;border-top:1px solid var(--surface2)}
.circuits-it-num{width:22px;flex:none;text-align:right;font-family:var(--mono);font-size:12px;color:var(--muted)}
.circuits-it-nom{flex:1;min-width:0;font-weight:500;font-size:14px;color:var(--titres-c);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* — État vide de l'itinéraire (hérite de .etat-vide) */
.circuits-vide{flex:none}
/* ===== fin Circuits ===== */

/* ===== Fiches agents (S60) — recherche + fiche à cinq blocs ===== */
/* Douze classes, aucune couleur en dur : tokens seulement, donc les deux thèmes
   suivent sans règle dédiée. La grammaire des lignes (.ligne-site), des filtres
   (.pilule-filtre, .ligne-filtres) et des cartes (.carte, .kicker) est celle des
   autres écrans de gestion — un écran de plus ne réinvente pas la sienne. */

/* Colonne de gauche des lignes : matricule, date. Largeur FIXE et flex:none —
   sans elle, un matricule à 8 chiffres et un « sans matricule » décalent le nom
   d'une ligne à l'autre, et la colonne des noms cesse de se lire en balayant.
   104 px + nowrap : à 88 px, « lun. 27 juil. » repliait sur deux lignes et
   faisait respirer la ligne d'affectation de travers (vu au balayage). */
.agent-cle{flex:none;width:104px;white-space:nowrap;font-size:12px;color:var(--muted)}
/* Méta de second rang (groupe, type de service, détail d'une pièce) : présente,
   jamais concurrente du nom. */
.agent-meta{font-size:12px;color:var(--muted);min-width:0;text-wrap:pretty}

/* Actif / sorti. Le sorti n'est PAS en rouge : partir n'est pas une faute, et
   le rouge reste réservé à l'anormal (même règle que le rappel de passation). */
.agent-pastille{flex:none;padding:2px 8px;border-radius:999px;font-size:11px;background:var(--ok-fond);color:var(--ok);border:1px solid var(--ok-bordure)}
.agent-pastille.sorti{background:var(--surface2);color:var(--muted);border-color:var(--bordure)}

/* Couple libellé/valeur des blocs Identité et Parcours. baseline : le libellé
   en petit et la valeur en normal restent alignés sur la même ligne de base. */
.agent-paire{display:flex;align-items:baseline;gap:10px}
.agent-paire-cle{flex:none;width:132px;font-size:12px;color:var(--muted)}
.agent-paire-valeur{flex:1;min-width:0;font-size:14px;color:var(--titres-c);text-wrap:pretty}

/* LA RÉSERVE DU BLOC. Séparée par un filet et posée en pied de carte : c'est
   une note de lecture, pas une donnée — mais elle doit rester lisible, pas
   décorative. C'est elle qui empêche la fiche de devenir une pièce à charge. */
.agent-reserve{margin-top:2px;padding-top:6px;border-top:1px solid var(--bordure);font-size:12px;color:var(--muted);line-height:1.5;text-wrap:pretty}

/* Une transition du journal : date à gauche, « avant → après » à droite. */
.agent-mouvement{display:flex;align-items:baseline;gap:10px;min-height:24px}
.agent-mouvement-corps{flex:1;min-width:0;font-size:13.5px;color:var(--texte);text-wrap:pretty}

/* Une pièce du dépôt Snipe-IT. */
.agent-piece{display:flex;align-items:baseline;gap:10px;min-height:24px}
.agent-piece-nom{min-width:0;font-size:13.5px;color:var(--titres-c);text-wrap:pretty}
/* ===== fin Fiches agents ===== */

/* ===== Orphelines 21/07 ===== */
/* Semis b15004b — 5 classes orphelines relevées par couverture-classes.cjs.
   3 règles ; 2 exclusions motivées (rien à styler que les voisines ne fassent
   déjà). Variables existantes seulement ; couvre .theme-clair et .theme-sombre. */

/* 3. .fiche-carte — bloc « voir sur la carte » (fiche-site.js:35, sites.js:205).
   Wrapper d'un lien maps secondaire, posé dans une pile flex (dialogue-fiche /
   carte.pile-serree). Le lien hérite déjà de la couleur `a` (var(--sx-human) ;
   #8fb3c9 en sombre). On le pose en action lisible et distincte du méta voisin :
   compact, semi-gras. Tient dans les deux contextes (aucune contrainte de
   parent). */
.fiche-carte{font-size:13px}
.fiche-carte a{font-weight:600}

/* 4. .marqueur-bip — 3e marqueur de site (sites.js:67), variante de .pilule-role
   manquante. Base .pilule-role = var(--sx-human) ; .marqueur-rondes = var(--muted)
   (dé-emphasé, ronde électronique de routine). Le marqueur BIP est le périmètre
   le plus exigeant (appel toutes les 15 min) : on le hisse au registre d'alerte
   var(--sx-rouge), au-dessus du bleu (demi-poste) et du gris (rondes). Hiérarchie
   à trois crans, sans couleur en dur. var(--sx-rouge) est en :root — identique
   sur les deux thèmes. */
.marqueur-bip{color:var(--sx-rouge);border-color:var(--sx-rouge)}

/* S723 — le jour réclamé par DEUX lignes de régime (V1-74 §2.3). Variante de
   .pilule-role, comme .marqueur-bip juste au-dessus : registre d'alerte
   (var(--alerte)) et fond d'alerte, parce que la ligne ne s'enregistrera pas.
   ⛔ LA COULEUR N'EST PAS LE SEUL SIGNE — le bandeau .encart-erreur nomme les
   jours en toutes lettres juste dessous : un daltonien ou un écran délavé à
   3 h du matin doit pouvoir lire le refus. */
.pilule-jour-double{color:var(--alerte);border-color:rgba(209,27,42,.45);background:var(--alerte-fond);font-weight:700}

/* 5. .mc-action-libelle — libellé d'action de main courante (main-courante.js:355,
   synthese.js:131), seul enfant non stylé de .mc-action (baseline, gap:10px).
   Voisins fixes : heure (width:40px;flex:none), auteur (contenu). Le libellé est
   le contenu élastique : flex:1 le fait remplir l'espace et pousse l'auteur à
   droite dans les DEUX vues (avec ou sans le .flex1 intercalé) ; min-width:0
   autorise le retour à la ligne d'un long libellé au lieu du débordement.
   Couleur/taille héritées de .mc-action (var(--texte), 13.5px). */
.mc-action-libelle{flex:1;min-width:0;text-wrap:pretty}

/* S311 — UN VERDICT RETIRÉ, DANS LA MAIN COURANTE ET LA SYNTHÈSE.
   BARRÉ, PAS EFFACÉ : le texte reste lisible — c'est toute la doctrine du
   retrait additif, et l'œil doit voir en une fraction de seconde que
   l'accusation ne tient plus, sans avoir à lire la ligne suivante. */
.mc-action-retiree .mc-action-libelle{text-decoration:line-through;color:var(--muted)}
.mc-action-retiree .mc-action-auteur{color:var(--muted)}
/* Le démenti, dans la couleur qui appelle l'attention sans crier à l'alerte :
   ce n'est pas un incident, c'est une correction assumée. */
.mc-action-retrait{color:var(--attente-mat)}
.mc-action-retrait .mc-action-auteur{color:var(--attente-mat)}
/* Et ce que le retrait n'établit PAS — une fois par carte. Aligné sur le
   libellé (48px = 40 de la colonne d'heure + 10 de gap, arrondi), pour se lire
   comme une note du fil et non comme une action de plus. */
.mc-action-portee{margin-left:50px;font-size:12px;line-height:1.45;color:var(--muted);text-wrap:pretty}

/* EXCLUSION — .bip-filtres (bip.js:84 : class="ligne-filtres bip-filtres").
   .ligne-filtres porte déjà toute la mise en page (display:flex;gap:6px) ; aucune
   variante propre à l'écran BIP n'est justifiée. Reliquat de portée d'écran, pas
   de règle. Une règle vide serait décorative. (Si la rangée de filtres débordait
   un jour sur mobile étroit, l'ajout serait flex-wrap:wrap — à trancher sur
   preuve d'overflow, pas à l'aveugle.) */

/* EXCLUSION — .btn-connexion (connexion.js:18 : class="btn-primaire btn-connexion").
   .btn-primaire est complet (min-height:50px, width:100%, fond var(--sx-rouge)) et
   .form-connexion espace déjà le bouton (gap:16px). Aucun ajustement propre au
   formulaire n'est nécessaire ; un margin-top serait purement décoratif. Reliquat,
   pas de règle. */

/* États CSV (S49) — une ligne par état : libellé + phrase à gauche, bornes de
   période au milieu (états périodiques seulement), bouton à droite.
   Calquée sur .ligne-rapport, avec deux différences assumées :
   · align-items:center et non flex-start — la hauteur des lignes varie selon
     qu'elles portent ou non les deux champs de date, et un bouton qui remonte
     ferait sautiller la colonne de droite d'une ligne à l'autre ;
   · flex-wrap:wrap — sur une fenêtre étroite, les champs se replient sous le
     texte au lieu de rogner le bouton (le motif du sélecteur de date réduit à
     « Servi… », 21/07). */
.ligne-etat{flex-direction:row;align-items:center;gap:14px;flex-wrap:wrap;padding:14px 16px}
.ligne-etat-texte{flex:1;min-width:220px;display:flex;flex-direction:column;gap:3px}
.ligne-etat-libelle{font-weight:600;font-size:14.5px;color:var(--titres-c)}
.ligne-etat-description{font-size:12.5px;line-height:1.45;color:var(--texte);text-wrap:pretty}
.ligne-etat-periode{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap}
/* ===== Écran Effectifs (S55) — courbes SVG, réserves, barres de répartition =====
   Aucune bibliothèque de graphes : la PWA est en ES modules natifs, zéro build.
   Le SVG est généré par la vue (js/vues/effectifs.js) et n'a besoin ici que de
   ses couleurs et de ses épaisseurs. */
.section-titre{font-family:var(--titres);font-weight:700;font-size:16px;color:var(--titres-c);margin:14px 0 0}

/* La courbe s'étire sur la carte ; sa hauteur suit le viewBox (ratio conservé). */
.courbe-svg{width:100%;height:auto;display:block;overflow:visible}
.courbe-def{margin:0;font-size:12.5px;line-height:1.5;color:var(--muted);text-wrap:pretty}
.courbe-repere line{stroke:var(--bordure);stroke-width:1}
.courbe-repere text{font-family:var(--mono);font-size:9px;fill:var(--muted)}
/* Le zéro d'une série signée se distingue des bornes : c'est lui qui sépare le
   solde positif du négatif. */
.courbe-repere.zero line{stroke:var(--bordure2);stroke-dasharray:none}
.courbe-abscisse{font-family:var(--mono);font-size:9px;fill:var(--muted)}

/* 🔴 Le trou : une abscisse SANS mesure. Il se voit (hachure verticale) et le
   tracé s'y rompt — relier deux points de part et d'autre dessinerait une
   donnée qui n'existe pas. Sur cet écran, « non observé » et « zéro site en
   sous-effectif » sont précisément les deux lectures à ne pas confondre. */
.courbe-trou{stroke:var(--bordure2);stroke-width:1;stroke-dasharray:2 3}

.courbe-trace{stroke-width:1.8;stroke-linejoin:round;stroke-linecap:round}
.courbe-trace.encre{stroke:var(--sx-human)}
.courbe-trace.vert{stroke:var(--ok)}
.courbe-trace.rouge{stroke:var(--sx-rouge)}
.theme-sombre .courbe-trace.encre{stroke:var(--pret)}
.theme-sombre .courbe-trace.rouge{stroke:var(--alerte)}
.courbe-point{fill:var(--surface);stroke-width:1.4}
.courbe-point.encre{stroke:var(--sx-human)}
.courbe-point.vert{stroke:var(--ok)}
.courbe-point.rouge{stroke:var(--sx-rouge)}
.theme-sombre .courbe-point.encre{stroke:var(--pret)}
.theme-sombre .courbe-point.rouge{stroke:var(--alerte)}

/* 🔴 Les valeurs EN CLAIR sous chaque courbe (S227). Jusqu'à ce lot elles
   n'existaient à l'écran que dans l'`aria-label` du <svg> : calculées,
   formatées, et lisibles par un lecteur d'écran seulement.

   Une ligne par abscisse : 24 mois ne tiennent pas côte à côte sur 390 px, ils
   tiennent l'un sous l'autre.

   🔴 UNE SEULE GRILLE POUR TOUT LE TABLEAU, ET PAS UNE PAR LIGNE. Avec une
   grille par ligne, `max-content` se recalculait ligne à ligne : « sept. 24 »
   élargissait SA ligne, « oct. 24 » non, et les nombres cessaient de s'aligner
   verticalement. Les cellules sont donc toutes enfants directs du conteneur.
   D'où aussi la bordure posée sur la CELLULE et non sur la ligne, et la cellule
   de fin, vide, qui prolonge le trait jusqu'au bord.

   La colonne de gauche est en `max-content` : à largeur fixe (4,6em),
   « sept. 24 » sortait tronqué en « sept. … » — 24 cellules rognées, mesurées.
   Elle n'a que deux formes possibles ici, aucune ne peut emballer la piste.

   Les colonnes de valeurs sont bornées (`minmax(0,6.5em)`) et une piste `1fr`
   ferme la grille : sur écran large les chiffres restent groupés au lieu de
   s'écarter jusqu'aux bords ; le `minmax(0,…)` — et non `6.5em` sec — les laisse
   se comprimer sur 390 px au lieu de pousser la grille hors de l'écran, même
   famille que le sélecteur de date à `flex:none` du bandeau. */
.courbe-valeurs{display:grid;grid-template-columns:max-content repeat(var(--cv-n,1),minmax(0,6.5em)) minmax(0,1fr);font-family:var(--mono);font-size:11px;margin-top:2px}
.cv-c{padding:3px 5px;border-top:1px solid var(--bordure);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cv-abscisse{text-align:left;color:var(--muted);padding-left:0}
/* L'en-tête revient à la ligne — seul de tout le tableau : un libellé de colonne
   tronqué par l'ellipsis ne se devine pas, et le malgache est plus long que le
   français sur ces mots-là (« Andrasana / ilaina » contre « Att. / req. »). */
.cv-entete{border-top:none;font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.03em;white-space:normal;line-height:1.25;align-self:end}
/* L'en-tête reprend la couleur du tracé : c'est ce qui rattache la colonne à sa
   courbe, sans imposer une seconde légende. */
.cv-entete.vert{color:var(--ok)}
.cv-entete.rouge{color:var(--sx-rouge)}
.cv-entete.encre{color:var(--sx-human)}
.theme-sombre .cv-entete.rouge{color:var(--alerte)}
.theme-sombre .cv-entete.encre{color:var(--pret)}
/* 🔴 Une abscisse SANS mesure : le tiret que rend `nombre(null)` se confondrait
   avec un trait de mise en page. Toute la ligne s'atténue et s'italise — un mois
   à zéro entrée, lui, garde son « 0 » en pleine encre. C'est la distinction que
   tout cet écran défend. */
.cv-c.absent{color:var(--muted);font-style:italic}
/* Un RUN d'abscisses non observées, replié en une ligne datée et comptée : sur
   la fenêtre de 30 jours, 18 jours précèdent la première mesure du 24/07 et
   pousseraient les 12 jours observés hors de l'écran. C'est une phrase, pas une
   valeur : elle traverse la grille et revient à la ligne. */
.cv-c.cv-replie{grid-column:1/-1;text-align:left;color:var(--muted);font-style:italic;white-space:normal;overflow:visible;text-wrap:pretty;padding-left:0}

.courbe-legende{display:flex;flex-wrap:wrap;gap:14px;font-size:12px;color:var(--texte)}
.courbe-legende-item{display:inline-flex;align-items:center;gap:6px}
.courbe-puce{width:10px;height:3px;border-radius:2px;flex:none}
.courbe-puce.encre{background:var(--sx-human)}
.courbe-puce.vert{background:var(--ok)}
.courbe-puce.rouge{background:var(--sx-rouge)}
.theme-sombre .courbe-puce.encre{background:var(--pret)}
.theme-sombre .courbe-puce.rouge{background:var(--alerte)}

/* La réserve : ambre, pas rouge. Ce n'est pas une alarme — c'est ce que la
   donnée ne dit pas, et il faut le lire AVANT les chiffres, pas après. */
/* V1-43 §2 — le pli « Comment lire ces chiffres ». La précaution ne quitte pas
   la page, elle quitte les trois premières secondes : elle vit sous un chevron
   au plus près du chiffre qu'elle borne. Fermé par défaut — la routine se tait ;
   c'est l'exception qui se déplie. Même registre que `.nuits-repli`, dont il ne
   se distingue que par sa place (en tête d'écran, pas au fil d'une liste). */
.repli-lecture{margin:2px 0 0}
.repli-lecture>summary{cursor:pointer;font-size:12.5px;color:var(--muted);padding:4px 0;min-height:32px;display:flex;align-items:center}
.repli-lecture>summary:hover{color:var(--titres-c)}
.repli-lecture>*+*{margin-top:6px}
.encart-reserve{margin:0;border-left:3px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);border-radius:0 8px 8px 0;padding:9px 12px;font-size:12px;line-height:1.5;color:var(--attente-mat);text-wrap:pretty}
.encart-reserve.fort{display:flex;flex-direction:column;gap:7px;font-size:12.5px}

/* Répartitions (tranches d'ancienneté, fonctions) : la barre est SOUS la ligne,
   pleine largeur — un site à long nom ne comprime jamais la mesure. */
.ligne-tranche{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;min-height:30px}
.ligne-tranche.absent .ligne-top-nom{color:var(--muted);font-style:italic}
.tranche-barre{flex:0 0 100%;height:4px;border-radius:3px;background:var(--surface2);overflow:hidden}
.tranche-barre-remplie{display:block;height:100%;border-radius:3px;background:var(--sx-human)}
.theme-sombre .tranche-barre-remplie{background:var(--pret)}
/* ===== fin Effectifs ===== */

/* ===== Exclusions BIP visibles (S64) ===== */
/* L'égalité écrite du périmètre : gardés − contrôleur − sans nuit − exclus =
   BIP. Ton neutre et discret — elle EXPLIQUE un chiffre, elle n'alerte pas. */
/* S223 — l'en-tête du cartouche EST la bascule du pli. Le bouton n'a pas de
   peau propre : il reprend `.ligne-top` et se dépouille des décorations natives
   du <button>. Zone de frappe pleine largeur : sur un téléphone, viser un
   chevron de 12 px est un geste raté sur deux. */
.perimetre-bascule{width:100%;background:none;border:0;margin:0;padding:2px 0;font:inherit;color:inherit;text-align:left;cursor:pointer}
.perimetre-bascule .chevron{font-size:15px}
.perimetre-bascule:hover .chevron{color:var(--titres-c)}
.perimetre-egalite{font-size:12.5px;line-height:1.6;color:var(--muted);padding:2px 4px;text-wrap:pretty}
/* L'OBSERVATION, pas un terme de l'égalité (S215). Elle se lit UN CRAN plus
   bas que la soustraction — même famille, moins de poids : la remonter au même
   niveau ferait relire un « − » là où il n'y en a plus. Pas de couleur d'alerte :
   un site contrôlé et non déclaré est un travail à faire, jamais une panne. */
.perimetre-observation{font-size:11.5px;line-height:1.55;color:var(--muted);opacity:.85;padding:0 4px 2px;text-wrap:pretty}
/* Une exclusion motivée est une décision assumée, pas une panne : surface
   calme et bordure sobre. `.encart-absence` (fond et bordure rouges) dirait
   l'inverse et ferait lire une faute là où il y a un choix documenté. */
.encart-exclusion{display:flex;flex-direction:column;gap:5px;background:var(--surface2);border:1px solid var(--bordure2);border-radius:9px;padding:10px 12px}
/* Le motif court sur plusieurs lignes quand il le faut (verbatim, jamais
   tronqué) : on accroche le nom et le chevron en haut plutôt que de les
   centrer sur un bloc dont la hauteur dépend du texte saisi. */
.ligne-site-exclu{align-items:flex-start;padding:11px 14px}
/* 🔴 `.carte` (l.209) impose flex-direction:column ; `.ligne-exclusion`
   (l.555) ne redresse que `display` et `align-items`. Combinées — et elles le
   sont dans rondes.js, rondes-tr.js et reconciliation-bip.js — la ligne
   s'empilait CENTRÉE : le libellé au-dessus, son compte en dessous, et le
   `flex1` censé les écarter poussant dans le vide. Invisible tant que le bloc
   dormait en bas de page ; S64 le remonte en tête, où ça se voit. */
.carte.ligne-exclusion{flex-direction:row;align-items:center}
/* ===== fin Exclusions BIP visibles ===== */

/* ===== Matricule cliquable (S89) ===== */
/* S78 a fait du matricule un lien vers la fiche agent sur #/agents et
   #/tendances. En production, ce lien est INVISIBLE : il s'affiche
   rgb(91,107,127) — var(--muted), la couleur du méta gris voisin — et sans
   soulignement. Personne ne peut deviner qu'il est cliquable ; la
   fonctionnalité existe et ne sert à rien.

   La cause est une spécificité, pas un oubli : `.ligne-top-detail` (l.506)
   est une CLASSE, `a` (l.45) est un ÉLÉMENT. La classe gagne, la couleur de
   lien est écrasée. Poser la classe la reprend à égalité de spécificité, et
   plus tard dans le fichier — c'est l'ordre qui tranche.

   Trois signaux, tous empruntés au vocabulaire existant :
   · la couleur d'accent des liens, var(--sx-human) — règle `a` l.45 ;
   · le semi-gras de `.fiche-carte a` (l.985), qui dit déjà « ce lien est une
     action, pas du méta » ;
   · le soulignement — le seul ajout, et il est nécessaire. La couleur SEULE
     ne suffit pas ici : mesuré au navigateur, #1e3a5f (le lien) contre
     #0f1b2d (le nom voisin) ne fait que 1,50:1, très en deçà des 3:1 sous
     lesquels la couleur ne peut pas être le seul indice. La couleur
     rapproche même le lien du nom (3,17:1 avant) : ce qui le distingue,
     c'est le trait. `text-decoration:none` (l.45) a été décidé pour les
     liens-BLOCS de l'app — nav, lignes de liste, boutons — dont l'affordance
     vient de la surface et du chevron. Le matricule est le premier lien
     INLINE, posé au milieu de texte qui n'est pas cliquable : le cas exact
     où le soulignement est le signal.

   Pas de variante `.theme-sombre` : `.theme-sombre a` (l.46, une classe + un
   élément) l'emporte déjà sur cette classe seule et sert #8fb3c9, la couleur
   de lien du thème nuit. C'est mesuré : en sombre le lien était DÉJÀ à la
   bonne couleur, et c'est le seul signal qui lui manquait. Une seule source
   de vérité, pas deux à tenir d'accord. Idem pour le survol, laissé à
   `a:hover` (l.47) — le soulignement demeure, l'affordance ne clignote pas.

   Contraste lien/fond mesuré au navigateur : 11,50:1 sur var(--surface)
   blanc en clair, 8,54:1 sur #0a1119 en sombre. */
.lien-matricule{color:var(--sx-human);font-weight:600;text-decoration:underline;text-underline-offset:2px}
/* ===== fin Matricule cliquable ===== */

/* ===== Jours fériés (S240, DESIGN-V1-10 §6) =====

   Quatre classes structurantes, plus une pour la coïncidence de génération.
   Tout le reste est réutilisé tel quel : `carte pile-serree`, `kicker mono`,
   `champ champ-libelle champ-aide`, `encart-consigne`, `encart-erreur`,
   `etat-vide`, `btn-primaire`, `btn-secondaire compact`, `btn-texte-rouge`,
   `mention-regle`, `chip-etat`, `contenu-etroit-large pile`.

   🔴 AUCUN COUPLE TEXTE/FOND NEUF, EN CLAIR COMME EN SOMBRE. Uniquement les
   tokens existants (--surface --bordure --bordure2 --muted --muted2 --texte
   --titres-c --attente-mat-*). L'audit de contraste du thème sombre n'a jamais
   été fait : ce lot n'aggrave rien parce qu'il n'introduit rien.

   Les colonnes tiennent la structure, donc les enfants n'ont pas de classe à
   eux : date · libellé (+ sa mention de règle) · source · geste. Une ligne a
   toujours ces quatre-là, dans cet ordre. */
.ligne-ferie{display:grid;grid-template-columns:230px 1fr auto 92px;align-items:center;gap:14px;padding:11px 4px}
.ligne-ferie + .ligne-ferie{border-top:1px solid var(--bordure)}
.ligne-ferie > :first-child{font-size:13px;color:var(--titres-c)}
.ligne-ferie > :nth-child(2){font-weight:700;font-size:14.5px;color:var(--titres-c);min-width:0}
.ligne-ferie > :nth-child(3){font-size:12px;color:var(--muted)}
.ligne-ferie > :last-child{justify-self:end}
/* La mention du dimanche passe SOUS le libellé (elle le complète, elle ne le
   prolonge pas) — même forme que sous un chiffre d'effectif. */
.ligne-ferie .mention-regle{display:block;font-weight:400;margin-top:2px}

/* Le passé se MONTRE, il ne se cache pas : atténué, jamais masqué. Un
   calendrier qui masque l'immuable se lit comme un calendrier vide — c'est
   l'incident « 0/0 » du rapport client, lu comme un sans-faute. */
.ferie-passe{opacity:.92}
.ferie-passe .ligne-ferie > :nth-child(2){font-weight:600;font-size:14px;color:var(--texte)}
.ferie-passe .ligne-ferie > :first-child{color:var(--muted)}

/* La pilule « FIGÉ » — calque de `.chip-terminee`, tokens identiques. */
.chip-fige{background:none;color:var(--muted);border:1px solid var(--bordure2)}

/* La ligne-frontière : deux filets et une date en toutes lettres. Les filets
   sont des pseudo-éléments, pas des nœuds — un séparateur n'a rien à dire à un
   lecteur d'écran, et le contenu du texte suffit à le situer. */
.frontiere-ferie{display:flex;align-items:center;gap:14px;padding:2px 0}
.frontiere-ferie::before,.frontiere-ferie::after{content:'';flex:1;height:1px;background:var(--bordure2)}
.frontiere-ferie > span{font-size:10.5px;letter-spacing:.16em;color:var(--muted)}

/* S688 — LES RENDEZ-VOUS DE PAIE. L'écran est le cousin des fériés (un
   calendrier de dates DÉCLARÉES, montré à venir puis passé) et hérite de
   `.ligne-ferie` : mêmes colonnes, mêmes séparateurs, même atténuation du passé.
   DEUX écarts, et pas un de plus.
   ① La première colonne descend de 230px à 150px : elle porte une date nue
      (« 16/09/2026 »), là où un férié porte son jour de semaine en toutes
      lettres. 230px y laissaient un vide large comme la colonne suivante.
   ② La dernière passe de 92px à `auto` : une ligne à venir porte DEUX gestes —
      corriger, fermer — quand un férié n'en porte qu'un, et 92px les faisaient
      déborder de leur cellule. Ils sont groupés, poussés à droite comme
      `.ligne-ferie > :last-child` le fait déjà. */
.ligne-echeance{grid-template-columns:150px 1fr auto auto}
.gestes-echeance{display:flex;gap:10px;align-items:center;justify-content:flex-end}

/* Coïncidence fixe/mobile dans la prévisualisation d'une année : ambre, comme
   partout où l'app dit « attention, pas anomalie ». Le rouge reste réservé à
   l'anormal — ici rien n'est anormal, deux fériés tombent le même jour. */
.ferie-coincidence{background:var(--attente-mat-fond);border-radius:8px;padding-left:10px;padding-right:10px}
.ferie-coincidence > :nth-child(3),.ferie-coincidence .mention-regle{color:var(--attente-mat)}

/* La modale de génération porte une LISTE : `.dialogue` (380 px) et
   `.dialogue-fiche` (460 px) écrasaient la colonne du libellé à un mot par
   ligne — mesuré à la capture, illisible. Elle est donc large, et ses lignes
   n'ont pas de colonne de geste (un chip d'état, pas un bouton). */
.dialogue-feries{width:min(760px,94vw);max-height:min(84vh,860px);overflow-y:auto;gap:12px}
@supports (height:100dvh){.dialogue-feries{max-height:min(84dvh,860px)}}
.dialogue-feries .ligne-ferie{grid-template-columns:165px minmax(0,1.5fr) minmax(0,1fr) auto;gap:12px;padding:9px 4px}
/* La source d'une coïncidence est longue (« fixe (coïncide avec le lundi de
   Pâques) ») : sa colonne s'enroule au lieu d'étrangler celle du libellé. */
.dialogue-feries .ligne-ferie > :nth-child(3){text-wrap:pretty}
/* ===== fin Jours fériés ===== */

/* ===== fin ===== */

/* ===== Écarts au roulement (S384) =====
   Le ROULEMENT, c'est la suite des sites d'un agent, dans l'ordre, qui revient
   (A44). L'écran dit qui n'y est pas — et il le dit SANS CRIER.

   🔴 AUCUN ROUGE D'ALERTE ICI, ET C'EST DÉLIBÉRÉ. `--alerte` est réservé à
   l'anormal dans toute l'application. Or le sous-effectif est chronique et
   structurel (A45) : une bonne part de ces lignes sont des remplacements
   décidés le jour même, pas des fautes. Peindre en rouge quatre-vingt-dix
   lignes tous les soirs, c'est garantir que plus personne ne les lit au bout
   d'une semaine — et que le jour où l'écart compte, personne ne le voit. Les
   étiquettes empruntent donc l'ambre de l'attente (« attention », pas
   « anomalie »), et le lieu — les trois quarts du volume — reste neutre. */
/* 🔴 S491 — LA JOURNÉE OUVRE LA CARTE, AU-DESSUS DU GRAND NOMBRE. Lire « 125 »
   sans savoir de quelle journée il s'agit était le défaut exact que ce bloc
   répare : le sujet vient donc avant le chiffre, pas en note sous lui. Le trait
   du bas le sépare du dénominateur — deux informations, un seul bloc de tête. */
.ecarts-journee{margin:0 0 10px;padding:0 0 10px;border-bottom:1px solid var(--bordure2)}
.ecarts-journee-titre{margin:0;font-family:var(--titres);font-size:14px;font-weight:600;
  color:var(--titres-c);text-wrap:pretty}
/* ⚠️ L'ÉTAT NE CRIE PAS. Une journée close est le cas ORDINAIRE (c'est le défaut
   de l'écran) : la peindre en couleur ferait lire une alerte là où il n'y a
   qu'un repère. Seule celle qui court se distingue — c'est la seule dont le
   compte va encore bouger. */
.ecarts-journee-etat{margin:3px 0 0;text-wrap:pretty}
.ecarts-journee-etat.en_cours{color:var(--attente-mat)}
.ecarts-tete{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.ecarts-nombre{font-family:var(--mono);font-size:30px;font-weight:700;color:var(--titres-c);line-height:1}
.ecarts-nombre-libelle{font-size:15px;color:var(--titres-c)}
/* 🔴 Le dénominateur n'est jamais en petit caractère gris décoratif : sans lui
   le numérateur au-dessus se lit comme une note sur le dispositif entier. */
.ecarts-denominateur{font-size:14px;color:var(--texte);margin:0}
.ecarts-hors-perimetre{font-size:13.5px;color:var(--muted);margin:0}
.ecarts-ventilation{color:var(--muted2)}
.ecarts-repartition{display:flex;align-items:center;flex-wrap:wrap;gap:4px;font-size:13.5px;color:var(--texte);margin:2px 0 0}
.ecarts-sep{color:var(--bordure2)}
.ecarts-reserve{margin:6px 0 0;text-wrap:pretty}

/* Les étiquettes de nature — ce qui rend la distinction lisible d'un coup
   d'œil. Le JOUR (le plus grave, et le plus rare) porte l'ambre ; le LIEU, qui
   est le régime ordinaire, reste neutre. */
.ecarts-etiquette{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  padding:3px 8px;border-radius:999px;white-space:nowrap;border:1px solid var(--bordure2);
  background:var(--surface2);color:var(--muted)}
.ecarts-etiquette.jour{background:var(--attente-mat-fond);border-color:var(--attente-mat-fond);color:var(--attente-mat)}
.ecarts-etiquette.lieu{background:var(--surface2);border-color:var(--bordure2);color:var(--texte)}

.ecarts-groupe-titre{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:14px 0 0;
  font-family:var(--titres);font-size:13px;font-weight:600;color:var(--titres-c)}
.ecarts-groupe-quoi{font-family:var(--sans);font-weight:400;font-size:13px;color:var(--muted);text-wrap:pretty}
.ecarts-groupe-compte{margin-left:auto;font-size:13px;color:var(--muted)}

.carte-ecart{gap:9px;padding:14px}
.ecarts-ligne-tete{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ecarts-matricule{font-size:12.5px;color:var(--muted);letter-spacing:.04em}
.ecarts-nom{font-weight:600;font-size:15px;color:var(--titres-c)}

/* 🔴 CÔTE À CÔTE, ET QUI S'EMPILE AU TÉLÉPHONE. C'est la moitié du lot : trois
   quarts des lignes disent « bon jour du cycle, autre site », et cette
   information n'existe que si le prévu et le porté se lisent d'un seul regard.
   `minmax(0,1fr)` et non `1fr` : un nom de site long ferait sinon déborder la
   grille au lieu de s'enrouler. */
.ecarts-confrontation{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
  align-items:center;gap:10px}
.ecarts-colonne{display:flex;flex-direction:column;gap:2px;min-width:0}
.ecarts-colonne-titre{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.ecarts-colonne-valeur{font-size:14px;color:var(--titres-c);text-wrap:pretty;overflow-wrap:anywhere}
.ecarts-colonne-valeur.prevu{color:var(--texte)}
.ecarts-fleche{color:var(--bordure2);font-size:15px}
.ecarts-modele{font-size:12.5px;color:var(--muted);margin:0}

/* 🔴 S477 — CE QUE LA SOURCE DIT DU POSTE VIDE. Discrète comme `.note-offline`,
   dont elle hérite la taille et la couleur : c'est un complément, pas un
   verdict — l'écran constate, il n'accuse pas.
   ⛔ SAUF `sans_cause`, ET C'EST TOUT L'OBJET DU LOT : quand TimeTrex ne dit
   rien non plus, la ligne devient la SEULE qui mérite qu'on lève la tête. Elle
   reprend la couleur du texte courant plutôt que le gris des notes — aucune
   couleur d'alerte, qui ferait de ces 5,8 % un reproche. */
.ecarts-absence{margin:0}
.ecarts-absence.sans_cause{color:var(--texte)}

/* Sous 560 px la grille à trois colonnes réduit chaque nom de site à un mot
   par ligne. Elle s'empile, et la flèche pivote pour garder son sens. */
@media (max-width:560px){
  .ecarts-confrontation{grid-template-columns:minmax(0,1fr);gap:6px}
  .ecarts-fleche{transform:rotate(90deg);justify-self:start}
}
/* ===== fin Écarts au roulement ===== */

/* ————— S404 — LES NUITS QUI VIENNENT —————
   Même sobriété que l'écran des écarts au roulement : une carte par nuit, le
   dénominateur avant les comptes, et rien qui clignote. Cet écran se consulte,
   il ne réveille personne. */
.carte-nuit{gap:8px;padding:14px}
.nuits-tete{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.nuits-quand{font-family:var(--titres);font-size:15px;font-weight:600;color:var(--titres-c)}
.nuits-date{font-size:13px;color:var(--muted)}
/* 🔴 LA FIABILITÉ N'EST PAS UN PETIT GRIS DÉCORATIF : sans elle, le compte
   au-dessous se lit comme un constat de manque. Elle passe AVANT, et elle a la
   couleur du texte, pas celle des notes. */
.nuits-fiabilite{margin:2px 0 0;font-size:13.5px;color:var(--texte);text-wrap:pretty}
.nuits-photo{margin:6px 0 0;text-wrap:pretty}
.nuits-compte{margin:0;font-size:14px;color:var(--texte)}
.nuits-nombre{font-family:var(--mono);font-size:24px;font-weight:700;color:var(--titres-c);line-height:1}
.nuits-precision{color:var(--muted)}
/* Le seul chiffre de l'écran qui appelle un geste. Les deux autres comptes
   restent en texte courant : les mettre au même niveau les ferait tous lire
   comme des alertes, et c'est ainsi qu'un écran de contrôle cesse d'être lu. */
.nuits-manque{display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;margin:4px 0 0}
.nuits-personne,.nuits-rien{font-size:13.5px;color:var(--muted)}
.nuits-repli{margin:6px 0 0}
.nuits-repli>summary{cursor:pointer;font-size:13px;color:var(--muted);padding:4px 0}
.nuits-liste{display:flex;flex-direction:column;gap:2px;padding:4px 0 0}
.nuits-ligne{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:5px 0;
  border-top:1px solid var(--bordure2);font-size:13.5px}
.nuits-site-nom{font-weight:600;color:var(--titres-c)}
.nuits-site-secteur{color:var(--muted2);font-size:12.5px}
/* `prévus / requis` en chasse fixe : deux nuits l'une sous l'autre s'alignent,
   donc l'écart se voit sans lire les chiffres. */
.nuits-chiffres{color:var(--texte);white-space:nowrap}
.nuits-etiquette{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  padding:3px 8px;border-radius:999px;white-space:nowrap;border:1px solid var(--bordure2);
  background:var(--surface2);color:var(--muted)}
.nuits-etiquette.manque{background:var(--attente-mat-fond);border-color:var(--attente-mat-fond);color:var(--attente-mat)}

/* ————— V1-45 — LE PIRE ÉTAT SE VOIT —————
   Un site à UN poste dont l'unique agent part en congé ne devient pas
   « incomplet » : il bascule dans « personne ». 18 des 23 sites touchés le
   14/08 y sont passés sans qu'un compteur bouge. Ce bloc ne fait qu'une chose :
   donner au pire état la place et la voix qu'il n'avait pas. ⛔ Il n'ajoute
   AUCUNE couleur à la liste hormis la marque — si tout rougit, plus rien ne
   signale (la grille BIP, V1-42). */

/* LIGNE 1 — la pastille pleine : c'est le « à traiter maintenant », un appel ou
   une réaffectation. Le seul registre d'alerte de l'écran. */
.nuits-sans-personne{display:flex;align-items:baseline;gap:7px;font-weight:600;color:var(--alerte)}
.nuits-sans-personne::before{content:'●';font-size:11px;line-height:1.4;color:var(--alerte)}
/* 🔴 ET QUAND IL N'Y EN A AUCUN, ÇA SE DIT AUSSI. Une ligne qui ne paraît que
   dans les mauvais cas rend son ABSENCE illisible : on ne sait plus si la nuit
   est saine ou si l'écran a omis de compter. Vert CONSTATÉ, pas vert félicité —
   même graisse que le texte courant, aucune emphase. */
.nuits-sans-personne-aucun{display:flex;align-items:baseline;gap:7px;font-size:13.5px;color:var(--ok)}
.nuits-sans-personne-aucun::before{content:'✓';font-size:12px;line-height:1.4}
/* La marque d'évènement du pire état (T4, la forme déjà posée juste au-dessus
   pour « il manque »), en registre alerte. */
.nuits-etiquette.personne{background:var(--alerte-fond);border-color:var(--alerte-fond);color:var(--alerte)}
/* « 1 requis · personne prévue » remplace le « 0 / 1 » mono : à l'œil, deux
   chiffres se lisent comme un dégradé, et un poste que personne ne tient n'est
   pas un degré. Pas de chasse fixe — il n'y a plus rien à aligner. */
.nuits-chiffres-clairs{color:var(--texte);text-wrap:pretty}

/* ————— LE BANDEAU DES SEPT NUITS (V1-11 §2) —————
   « Par quelle nuit je commence ? » se payait sept défilements : la carte de la
   nuit courante dépasse un écran à elle seule. Rien ne défile
   horizontalement — sur un téléphone, les sept tuiles passent en deux rangées. */
.nuits-semaine{display:grid;grid-template-columns:repeat(7,1fr);gap:8px;margin:2px 0}
.nuits-tuile{display:flex;flex-direction:column;gap:3px;align-items:flex-start;
  border:1px solid var(--bordure);border-radius:9px;padding:9px 10px;background:var(--surface);
  text-align:left;min-height:44px;cursor:pointer;font:inherit;color:inherit}
.nuits-tuile:hover{border-color:var(--bordure2);background:var(--surface2)}
.nuits-tuile-date{font-size:11px;color:var(--muted)}
.nuits-tuile-compte{font-size:12.5px;color:var(--texte)}
/* 🔴 LE COMPTE ÉCRIT, JAMAIS LE POINT SEUL — cinq nuits sur sept en porteraient
   un, et une marque presque toujours allumée cesse de distinguer. Le nombre
   hiérarchise ; le point, non. ⛔ Et PAS de « ● 0 » : une nuit sans site vide
   ne porte rien, sinon on refait sept marques au lieu de deux. */
.nuits-tuile-personne{display:flex;align-items:baseline;gap:5px;font-size:12.5px;
  font-weight:600;color:var(--alerte)}
.nuits-tuile-personne::before{content:'●';font-size:9px;line-height:1.5}
.nuits-tuile-ok{font-size:12.5px;color:var(--ok)}
@media (max-width:900px){
  .nuits-semaine{grid-template-columns:repeat(4,1fr)}
}

/* ————————————————————————————————————————————————————————————————————————
   S430 — RÉPÉTITION DES PRISES DE POSTE SANS APPEL ENREGISTRÉ
   ———————————————————————————————————————————————————————————————————— */
.repetition-tete{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.repetition-nombre{font-family:var(--mono);font-size:30px;font-weight:700;color:var(--titres-c);line-height:1}
.repetition-nombre-libelle{font-size:15px;color:var(--titres-c)}
/* 🔴 Le dénominateur n'est jamais en petit caractère gris décoratif : sans lui
   le numérateur au-dessus se lit comme une note sur le dispositif entier. */
.repetition-denominateur{font-size:14px;color:var(--texte);margin:0}
.repetition-periode{font-size:13.5px;color:var(--muted);margin:0}
/* Écarté ≠ conforme : ces lignes se lisent, elles ne se décorent pas. */
.repetition-ecartees{font-size:13.5px;color:var(--muted);margin:2px 0 0;text-wrap:pretty}
.repetition-ecartees-titre{color:var(--muted2)}
.repetition-reserve{margin:6px 0 0;text-wrap:pretty}
/* Le séparateur des deux champs de date, dans le bandeau. */
.repetition-tiret{color:var(--muted2);padding:0 2px}

.carte-repetition{gap:7px;padding:14px}
.repetition-ligne-tete{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.repetition-matricule{font-size:12.5px;color:var(--muted);letter-spacing:.04em}
.repetition-nom{font-weight:600;font-size:15px;color:var(--titres-c)}

/* 🔴 LES DEUX NOMBRES SONT UN SEUL BLOC, ET RIEN NE PEUT LES SÉPARER.
   `white-space:nowrap` : « 4 fois » d'un côté d'un retour à la ligne et « sur
   22 nuits attendues » de l'autre rendrait le premier lisible seul — or « 4 sur
   5 » et « 4 sur 22 » ne se lisent pas pareil, et c'est tout l'objet du lot.
   `flex-shrink:0` pour la même raison face à un nom long. */
.repetition-compte{display:inline-flex;align-items:baseline;gap:4px;white-space:nowrap;flex-shrink:0}
.repetition-compte-numerateur{font-family:var(--mono);font-size:19px;font-weight:700;color:var(--titres-c);line-height:1}
.repetition-compte-sur{font-size:13.5px;color:var(--texte)}

.repetition-nuits{font-size:13px;color:var(--muted);margin:0;text-wrap:pretty}
.repetition-nuits-titre{color:var(--muted2)}

/* ————————————————————————————————————————————————————————————————————————
   S451 — COMPOSER UN SERVICE (V1-46, V1-47, V1-48, V1-49)

   🔴 AUCUN FOND DE LIGNE COLORÉ, ET C'EST LA RÈGLE DU LOT. Quatorze postes
   sans personne sur une mauvaise nuit sont quatorze choses à traiter — mais
   quatorze fonds rouges tapisseraient, et c'est la grille BIP qui
   recommencerait (V1-42, V1-48 §3). Le rouge reste sur la MARQUE seule.

   ⛔ ET AUCUN INDICATEUR SUR LE SOCLE : un nom et un compte. Trois cents
   lignes ne supportent pas trois cents indicateurs (V1-46 §5) — tout ce qui
   mérite un mot est déjà remonté dans la file.
   ———————————————————————————————————————————————————————————————————— */
.composer-service-tete{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.composer-service-libelle{font-family:var(--titres);font-size:16px;font-weight:600;color:var(--titres-c)}

.composer-tete{display:flex;flex-direction:column;gap:2px}
.composer-titre{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.composer-nombre{font-family:var(--mono);font-size:30px;font-weight:700;color:var(--titres-c);line-height:1}
.composer-titre-phrase{font-size:15px;color:var(--titres-c)}
/* ⛔ Les trois comptes ne s'additionnent jamais : ils se lisent d'affilée, dans
   l'ordre de la gravité, et aucun n'est mis en avant sur les autres. */
.composer-detail{margin:2px 0 0;font-size:13.5px;color:var(--texte)}
.composer-source{margin:6px 0 0}
.composer-photo,.composer-conges,.composer-conges-sans-agent,.composer-prises{margin:3px 0 0;text-wrap:pretty}
/* 🔴 « CONGÉS NON LUS » N'EST PAS UNE NOTE GRISE : la file affichée est
   SOUS-ESTIMÉE, et un écran qui affirme là où il ne sait pas est la faute de
   S427. Registre d'attente (ambre), jamais alerte — rien n'est à traiter, c'est
   une lacune de lecture. */
.composer-conges-muets{margin:3px 0 0;color:var(--attente-mat);font-weight:600;text-wrap:pretty}

.composer-secteurs{flex-wrap:wrap;row-gap:6px}

.composer-file{display:flex;flex-direction:column;gap:2px}
.composer-groupe{margin:8px 0 0}
.composer-groupe-tete{display:flex;align-items:baseline;gap:8px;padding:4px 0 2px}
/* Le titre du groupe en chasse fixe et espacé : c'est un intertitre de registre,
   pas un titre de carte — il sépare sans peser. */
.composer-groupe-titre{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
/* 🔴 LE COMPTE DU GROUPE (V1-48 §4.2). À 19 on s'en passait ; à 61, sans lui,
   il faut défiler pour connaître la forme du problème. Sous filtre il dit
   « 7 sur 24 » : le filtre CACHE, il ne fait jamais disparaître (V1-49 §2). */
.composer-groupe-compte{font-size:12px;color:var(--muted2);white-space:nowrap}

.composer-ligne{padding:6px 0;border-top:1px solid var(--bordure2)}
.composer-ligne-tete{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13.5px}
.composer-site{font-weight:600;color:var(--titres-c)}
.composer-poste{color:var(--muted2);font-size:12.5px}
/* `prévus / requis` en chasse fixe : deux lignes l'une sous l'autre s'alignent,
   donc l'écart se voit sans lire les chiffres. */
.composer-chiffres{color:var(--texte);white-space:nowrap}
/* 🔴 LA CAUSE EN TOUTES LETTRES, SUR CHAQUE LIGNE (V1-46 §2.1). C'est elle qui
   sépare cet écran d'une table de trous : « il manque quelqu'un » n'aide pas,
   « congé écrit le 02/08 » se traite. Petit gris — elle explique, elle n'alerte
   pas. */
.composer-cause{margin:2px 0 0;font-size:12.5px;color:var(--muted);text-wrap:pretty}

/* La marque d'évènement (T4) — la forme des étiquettes de l'écran des nuits. */
.composer-marque{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  padding:3px 8px;border-radius:999px;white-space:nowrap;border:1px solid var(--bordure2);
  background:var(--surface2);color:var(--muted)}
.composer-marque.manque{background:var(--attente-mat-fond);border-color:var(--attente-mat-fond);color:var(--attente-mat)}
.composer-marque.attente{background:var(--surface2);border-color:var(--bordure2);color:var(--muted)}
/* 🔴 LE SEUL REGISTRE D'ALERTE DE L'ÉCRAN, et il tient sur 12 px de pilule. */
.composer-marque.personne{background:var(--alerte-fond);border-color:var(--alerte-fond);color:var(--alerte)}

/* ⛔ UNE FILE VIDE NE SE DESSINE PAS COMME UN SUCCÈS (V1-48 §3) : pas de coche,
   pas de vert. Une phrase datée qui dit sur quoi elle repose. */
.composer-file-vide .carte-titre{color:var(--titres-c)}

/* ————— LE SOCLE, REPLIÉ PAR SECTEUR (V1-46 §2.2) —————
   ~150 lignes derrière un pli, et elles se taisent. Un `<button>` et non un
   `<details>` : le pli garde le focus sur le bouton cliqué et ne reconstruit
   rien — c'est la condition du rendu par ligne, pas un détail d'habillage. */
.composer-socle-entete{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.composer-socle-groupe{border-top:1px solid var(--bordure2)}
.composer-socle-tete{display:flex;align-items:center;gap:8px;width:100%;min-height:34px;
  padding:5px 0;background:none;border:0;cursor:pointer;font:inherit;color:inherit;text-align:left}
.composer-socle-tete:hover .composer-socle-secteur{color:var(--sx-human)}
.composer-pli{font-size:11px;color:var(--muted2);width:10px}
.composer-socle-secteur{font-size:13.5px;font-weight:600;color:var(--titres-c)}
.composer-socle-compte{font-size:12.5px;color:var(--muted2);white-space:nowrap}
.composer-socle-lignes{display:flex;flex-direction:column;gap:2px;padding:0 0 6px 18px}
.composer-socle-ligne{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--texte)}
.composer-socle-nom{color:var(--texte)}

/* ————— LE BANDEAU DES SEPT SERVICES DU TYPE REGARDÉ (V1-47 §2) —————
   Le registre des nuits (V1-45) vaut tel quel pour les journées : le rendu l'a
   confirmé, il ne l'a pas corrigé (V1-48 §4.4). Rien ne défile horizontalement —
   sur un téléphone, les sept tuiles passent en deux rangées. */
.composer-semaine{display:grid;grid-template-columns:repeat(7,1fr);gap:8px;margin:2px 0}
.composer-tuile{display:flex;flex-direction:column;gap:3px;align-items:flex-start;
  border:1px solid var(--bordure);border-radius:9px;padding:9px 10px;background:var(--surface);
  text-align:left;min-height:44px;cursor:pointer;font:inherit;color:inherit}
.composer-tuile:hover{border-color:var(--bordure2);background:var(--surface2)}
.composer-tuile.courant{border-color:var(--sx-human)}
.composer-tuile-date{font-size:11px;color:var(--muted)}
.composer-tuile-ici{font-size:11px;color:var(--sx-human);font-weight:600}
.composer-tuile-compte{font-size:12.5px;color:var(--texte)}
/* 🔴 LE COMPTE ÉCRIT, JAMAIS LE POINT SEUL, et ⛔ RIEN quand il est nul : une
   marque presque toujours allumée cesse de distinguer (V1-42). */
.composer-tuile-personne{display:flex;align-items:baseline;gap:5px;font-size:12.5px;
  font-weight:600;color:var(--alerte)}
.composer-tuile-personne::before{content:'●';font-size:9px;line-height:1.5}
.composer-tuile-ok{font-size:12.5px;color:var(--ok)}
@media (max-width:900px){
  .composer-semaine{grid-template-columns:repeat(4,1fr)}
}

/* ————————————————————————————————————————————————————————————————————————
   S452 — LE GESTE : POURVOIR, LE PANNEAU, LE JOURNAL (V1-46 §3, V1-48 §2,
   V1-49 §1)

   🔴 LA RÈGLE DE FORME DU PANNEAU, ET ELLE EST CONTRE-INTUITIVE. Sur les
   25 candidats d'un poste réel, VINGT-DEUX ne portent aucun fait de présence.
   La carte est donc RÉSERVÉE à qui a quelque chose à dire ; les autres ont une
   LIGNE — même geste, autre peau.

   ⛔ AUCUNE ÉGALISATION : les deux peaux ne partagent aucun gabarit, aucune
   grille, aucune case vide. Une case vide par candidat aurait transformé la
   majorité du panneau en tableau de manques (V1-48 §3) — « c'est le FAIT qui
   manque, pas le candidat qui faute ».

   ⛔ AUCUN SCORE : ni note, ni pourcentage, ni barre de progression. Rien dans
   cette feuille ne sait dessiner une jauge de candidat, et c'est voulu.
   ———————————————————————————————————————————————————————————————————— */

/* ————— LE GESTE, SUR LA LIGNE DE FILE —————
   ⚠️ 40 px de haut, comme partout ailleurs : c'est une cible tactile, et le
   planificateur compose aussi sur une tablette. */
.composer-geste{min-height:40px;padding:0 12px;white-space:nowrap}
/* 🔴 LE SECOND CLIC NOMME CE QU'IL FAIT. L'état armé se voit — sans quoi le
   bouton aurait changé de sens sans changer d'aspect. */
.composer-geste.arme,.geste-affecter.arme{background:var(--attente-mat);border-color:var(--attente-mat)}

/* Ce que la décision a fait, dit sur SA ligne. La ligne est masquée du flux,
   mais son nœud reste : *annuler* la rend telle quelle. */
.composer-ligne-decidee{margin:3px 0 0;font-size:12.5px;color:var(--ok);font-weight:600}
.composer-ligne-refus{margin:4px 0 0;font-size:12.5px;text-wrap:pretty}

/* ————— 🔴 LE JOURNAL — UNE LISTE DE DELTAS, PAS UN ÉTAT (V1-46 §3.5) —————
   Il naît masqué et grandit ligne à ligne. C'est lui qui donne *annuler* pour
   rien, et c'est la condition pour qu'on OSE s'exercer au bac à sable. */
.composer-journal{display:flex;flex-direction:column;gap:8px}
.journal-lignes{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.journal-ligne{display:flex;align-items:baseline;gap:8px;font-size:13px;color:var(--texte);
  padding:4px 0;border-top:1px solid var(--bordure2)}
.journal-geste{font-weight:600;color:var(--titres-c)}
.journal-ou{color:var(--muted2)}
.journal-heure{font-size:12px;color:var(--muted2);white-space:nowrap}
/* ⛔ JAMAIS DE SUPPRESSION : défaire est une décision. La ligne annulée reste
   lisible, barrée — un journal qui perd ses lignes ne se relit pas. */
.journal-ligne.annulee{opacity:.55}
.journal-ligne.annulee .journal-geste{text-decoration:line-through}
.journal-annuler{min-height:40px;align-self:flex-start}
.journal-pas-annulable,.journal-erreur{margin:0;font-size:12.5px;text-wrap:pretty}

/* 🔴 S453 — L'ÉTAT D'UN GESTE, SUR SA LIGNE. Un geste refusé et un geste écrit
   se ressemblent trait pour trait au journal : sans cette marque, le second
   croirait avoir enregistré ce qui attend encore. ⛔ Pas de fond coloré sur la
   ligne — la marque seule, comme les marques de la file (V1-48 §3). */
.journal-etat{font-size:11.5px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;
  white-space:nowrap;padding:1px 6px;border-radius:5px}
.journal-ligne.en-attente .journal-etat{color:var(--attente-mat);background:var(--attente-mat-fond);
  border:1px solid var(--attente-mat-bordure)}
.journal-ligne.tombee .journal-etat{color:var(--alerte);background:var(--alerte-fond);
  border:1px solid rgba(209,27,42,.35)}
/* Le geste sans objet reste LISIBLE : il n'est pas barré comme un geste annulé,
   parce qu'il n'a pas été défait — il n'a simplement plus d'objet. */
.journal-ligne.tombee .journal-ou{color:var(--texte)}

/* ————— 🔴 S453 — LE BANDEAU DU CROISEMENT (V1-46 §4.1) —————
   Il NOMME, il DATE, et il offre UN geste. Il se pose sous les compteurs : ce
   qui arrête la main se lit avant ce qu'elle a fait. */
.composer-refus{display:flex;flex-direction:column;gap:8px;
  border-color:rgba(209,27,42,.35);background:var(--alerte-fond)}
.composer-refus .carte-titre{color:var(--alerte)}
.composer-refus-qui{margin:0;font-size:13px;font-weight:600;color:var(--titres-c)}
.composer-refus-faits{margin:0;font-size:13.5px;color:var(--texte);text-wrap:pretty}
.composer-rejouer{min-height:44px;align-self:flex-start}
.composer-rejeu-note{margin:0;font-size:12.5px;text-wrap:pretty}
/* 🟢 UN REJEU OÙ TOUT PASSE NE CRIE PAS : le bandeau perd son alerte, sa cause
   et son geste, et il ne reste qu'une note. Laisser le rouge au-dessus d'un
   rejeu entièrement réussi ferait durer une alerte qui n'a plus d'objet. */
.composer-refus.calme{border-color:var(--bordure);background:var(--surface)}
/* ⛔ CE QUI NE PASSE PLUS EST NOMMÉ, LIGNE PAR LIGNE — le patron des conflits de
   circuit, repris tel quel. Un compte agrégé ne dit pas LESQUELLES. */
.composer-rejeu-tombee{font-size:12.5px;text-wrap:pretty}

/* ————— LE PANNEAU DE CANDIDATS —————
   Plus large que le dialogue ordinaire : les faits sont des PHRASES, pas des
   codes, et une phrase coupée en trois lignes cesse d'être lue. */
.panneau-candidats{width:min(620px,94vw);max-height:min(86vh,880px);gap:10px}
.panneau-corps{display:flex;flex-direction:column;gap:8px;overflow-y:auto;min-height:0}
.panneau-poste{margin:0}
/* ⚠️ LA BORNE EST SERVIE, et les écartés COMPTÉS avec leur motif — ⛔ jamais
   listés, jamais cliquables : un écarté cliquable serait un candidat. Aucun
   `cursor:pointer` ici, et c'est délibéré. */
.panneau-borne,.panneau-ecartes,.panneau-muet{margin:0;text-wrap:pretty}
.panneau-muet{color:var(--attente-mat)}
.panneau-vide{margin:8px 0;font-size:13.5px;color:var(--texte);text-wrap:pretty}

/* 🔴 L'ABSENCE, DITE UNE FOIS, AU NIVEAU OÙ ELLE EST VRAIE (V1-49 §1.1).
   En tête du bloc des lignes — ⛔ jamais répétée par ligne, ce serait le
   nouveau bug. Registre de constat (gris), pas d'alerte : il n'y a rien à
   traiter, il y a quelque chose à savoir. */
.panneau-sans-fait{margin:10px 0 2px;font-size:12.5px;color:var(--muted);text-wrap:pretty;
  border-top:1px solid var(--bordure2);padding-top:8px}

/* ————— LA CARTE — RÉSERVÉE À QUI A QUELQUE CHOSE À DIRE ————— */
.candidat-carte{display:flex;flex-direction:column;gap:6px;padding:10px 12px}
.candidat-tete{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.candidat-matricule{font-size:13px;font-weight:600;color:var(--titres-c)}
/* ④ Son rattachement — un secteur, jamais un score. */
.pilule-rattachement{font-size:11px;padding:2px 8px;border-radius:999px;
  border:1px solid var(--bordure2);background:var(--surface2);color:var(--muted);white-space:nowrap}
.pilule-rattachement.muet{font-style:italic}
/* 🔴 ① LES FAITS SONT UNE LISTE, PAS UNE GRILLE (V1-48 §1) : les cartes n'ont
   pas la même hauteur et l'œil l'accepte, parce qu'AUCUNE CASE VIDE N'EXISTE. */
.candidat-faits{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:3px}
.candidat-fait{font-size:13px;color:var(--texte);line-height:1.5;text-wrap:pretty}
/* ⛔ UN FAIT SANS SOURCE EST UNE AFFIRMATION. Elle se lit en petit gris, à côté
   de la phrase — jamais à sa place. */
.candidat-fait-source{color:var(--muted2);font-size:11.5px}
.candidat-fait-source::before{content:' ('}
.candidat-fait-source::after{content:')'}
/* ⚠️ LE FAIT NOCTURNE N'EST PAS PROMU EN FAIT DE JOUR : il est classé sous les
   faits du service par le serveur, et rien ici ne le remonte ni ne l'égalise. */
.candidat-fait.source-tenue_nocturne .candidat-fait-phrase{color:var(--muted)}

/* ② son repos, ③ son roulement — condensés sur une ligne. */
.candidat-condense,.candidat-condense-ligne{display:flex;gap:8px;flex-wrap:wrap;
  font-size:12.5px;color:var(--muted);margin:0;text-wrap:pretty}
.candidat-condense-ligne{flex:1 1 240px;min-width:0}
/* 🔴 L'ÉCART DE ROULEMENT EST DIT EN AMBRE, AVANT LE CLIC (V1-46 §5). Après, ce
   serait un reproche. Ambre et non rouge : ce n'est pas une faute, c'est une
   conséquence qu'on choisit d'assumer. */
.candidat-roulement.ambre{color:var(--attente-mat);font-weight:600}

/* ————— LA LIGNE — LE MÊME GESTE, UNE AUTRE PEAU —————
   ⛔ Rien de plus n'y est dit : pas de case vide, pas de tiret, pas de « aucune
   trace ». Il n'y a pas de fait, donc il n'y a pas de place pour un fait. */
.candidats-lignes{display:flex;flex-direction:column}
.candidat-ligne{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:6px 2px;border-top:1px solid var(--bordure2)}

/* ————— V1-53 — désigner l'agent d'une ronde manquée ————— */
/* Le bloc appareil — ambre : une mise en garde, pas une faute. Il se lit AVANT les candidats. */
.designation-appareil{border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:6px}
.designation-appareil-titre{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;color:var(--attente-mat)}
.designation-appareil-fait{font-size:13px;color:var(--texte);line-height:1.5}
.designation-appareil-limite{font-size:12px;color:var(--muted);border-top:1px solid var(--attente-mat-bordure);padding-top:6px;line-height:1.5}
/* Un candidat — la peau des cartes du panneau de composition, faits sourcés. */
.designation-candidat{border:1px solid var(--bordure);border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:6px}
.designation-candidat-tete{display:flex;align-items:center;gap:10px}
/* L'absent : su, jamais offert au geste — gris qui se dit, pas un retrait de la liste. */
.designation-candidat.absent{background:var(--surface2)}
.designation-candidat.absent .designation-nom{color:var(--muted)}
.designation-nom{font-size:14px;font-weight:600;color:var(--titres-c)}
/* S743 / `A209` — même mention, même registre, sur la carte de candidat : ici
   la tête ne porte qu'un MATRICULE (cet écran ne connaît pas les noms), donc
   la mention se pose à côté de lui. */
.designation-mention{font-size:11px;color:var(--attente-mat);background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);border-radius:999px;padding:2px 8px;white-space:nowrap;flex:none}
.designation-fait{font-size:13px;color:var(--texte);line-height:1.5}
.designation-source{font-size:12px;color:var(--muted)}
/* La répétition — ambre : un fait daté, pas un verdict. « Jamais désigné » en gris. */
.designation-repetition{font-size:13px;color:var(--attente-mat);border-top:1px solid var(--bordure);padding-top:6px}
.designation-jamais{font-size:13px;color:var(--muted);border-top:1px solid var(--bordure);padding-top:6px}
.designation-autre-agent{font-size:13px;color:var(--pret)}
/* Le reçu sur la ligne, et le retrait — additif, même famille visuelle que les verdicts posés. */
.designation-recu{font-size:12.5px;color:var(--texte);border-top:1px solid var(--bordure);padding-top:6px}
.designation-retrait{font-size:12.5px;color:var(--texte)}
.designation-portee{font-size:12px;color:var(--muted)}
/* ————————————————————————————————————————————————————————————————————
   S514 — V1-52 : rattachement au roulement.
   Contenu EXACT du fichier d'ajouts de la conception
   (AJOUTS-FICHIERS-PARTAGES-V1-51-52.md, §3), bloc V1-52 SEUL — le bloc V1-51
   du même fichier appartient à un autre écran et à un autre lot.
   Les pilules de départ réutilisent `.pilule-filtre` / `.active`, les boutons
   `.btn-primaire` / `.btn-secondaire` / `.compact` / `.arme` : aucune classe
   neuve hors de ce bloc.
   ———————————————————————————————————————————————————————————————————— */
/* ————— V1-52 — rattachement au roulement : la grille des nuits ————— */
.roul-recherche{width:min(520px,100%);padding:11px 14px;border:1px solid var(--bordure2);border-radius:9px;background:var(--surface);color:var(--titres-c);font-size:14px;font-family:var(--sans)}
.roul-desaccords{color:var(--attente-mat)}
.roul-etat-vide{color:var(--muted);line-height:1.5}
/* S699 — le site ÉCARTÉ paraît, et il ne se clique pas (D-94, V1-67 §6.1).
   Un site fermé qu'on tairait ferait croire qu'il n'existe pas ; rendu avec le
   curseur d'un bouton, il ferait croire qu'on peut y placer quelqu'un. Il est
   donc là, atténué, en curseur normal, avec son motif écrit à côté. */
.pilule-ecartee{cursor:default;opacity:.6;border-style:dashed}
/* La grille : le nombre de nuits est une donnée (--roul-nuits posé en style inline par la vue). */
.roul-grille{border:1px solid var(--bordure);border-radius:10px;overflow-x:auto}
.roul-rangee{display:grid;grid-template-columns:170px repeat(var(--roul-nuits,14),60px)}
.roul-rangee-tete{background:var(--surface2);border-bottom:1px solid var(--bordure)}
.roul-rangee-pied{background:var(--surface2);border-top:1px solid var(--bordure)}
.roul-col{display:flex;align-items:center;justify-content:center;height:30px;font-family:var(--mono);font-size:10px;color:var(--muted2)}
.roul-col.choisie{background:var(--sx-encre);color:#fff;border-radius:6px;margin:3px 2px;font-weight:600}
.theme-sombre .roul-col.choisie{background:var(--nav-actif);color:var(--nav-actif-texte)}
.roul-label{padding:4px 12px;display:flex;flex-direction:column;justify-content:center;border-top:1px solid var(--bordure)}
.roul-label-nom{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--titres-c)}
.roul-label-sub{font-size:10px;color:var(--muted)}
.roul-cellule{display:flex;align-items:center;justify-content:center;height:30px;border-left:1px solid var(--bordure);border-top:1px solid var(--bordure);font-family:var(--mono);font-size:11px;color:var(--titres-c)}
.roul-cellule.repos{color:var(--muted2)}
/* « pas encore rattaché » : gris qui se dit (légende), jamais un blanc. */
.roul-cellule.hors{color:var(--bordure2);background:var(--surface2)}
/* Doublé : ambre AVANT le clic — après, ce serait un reproche. */
.roul-cellule.double{background:var(--attente-mat-fond);color:var(--attente-mat);font-weight:600}
.roul-rangee.fantome .roul-label-nom,.roul-rangee.fantome .roul-cellule{background:var(--pret-fond);color:var(--pret)}
.roul-rangee.fantome .roul-cellule.repos{color:var(--muted2)}
.roul-rangee.retiree .roul-label-nom,.roul-rangee.retiree .roul-cellule{color:var(--muted2)}
.roul-pied-cellule{display:flex;flex-direction:column;align-items:center;gap:1px;padding:5px 0;border-left:1px solid var(--bordure)}
.roul-pied-compte{font-family:var(--mono);font-size:10.5px;font-weight:600;color:var(--muted)}
.roul-pied-compte.trou{color:var(--alerte)}
.roul-pied-vide{font-size:9px;color:var(--alerte);font-weight:600}
.roul-pied-double{font-size:9px;color:var(--attente-mat);font-weight:600}
/* Le verdict — une phrase, au-dessus du geste. Vert seulement avec sa réserve de fiabilité. */
.roul-verdict{border-radius:9px;padding:10px 14px;font-size:13.5px;line-height:1.55}
.roul-verdict.calme{border:1px solid var(--ok-bordure);background:var(--ok-fond);color:var(--ok)}
.roul-verdict.charge{border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);color:var(--attente-mat)}
.roul-legende{font-size:11px;color:var(--muted);line-height:1.5}
/* ═══ 🔴 S516 — LE SOCLE MODIFIABLE : LA LIGNE DEVIENT UNE PORTE (V1-51) ═══
   Bloc de `AJOUTS-FICHIERS-PARTAGES-V1-51-52.md`, PARTIE V1-51 SEULE — les
   règles `.roul-*` du même fichier relèvent de V1-52, qui est un autre lot.

   ⛔ AU REPOS, LE SOCLE NE CHANGE PAS D'UN PIXEL. C'est la garde qui porte le
   lot : un bouton par ligne sur 150 lignes, c'est une table de 150 boutons, et
   la file de décisions redevient invisible (ce que V1-46 évite depuis le 27/07).

   🔴 ÉCART AVOUÉ AU BLOC LIVRÉ, ET IL SERT LA GARDE : CDesign écrit
   `font:inherit;color:inherit` sur le bouton. La propriété raccourcie `font`
   RÉINITIALISE `font-size`, et `button.composer-socle-ligne` (0,1,1) l'emporte
   sur `.composer-socle-ligne` (0,1,0) qui pose `font-size:13px` depuis S451 :
   le texte du socle aurait changé de taille — exactement le pixel que la garde
   interdit. On neutralise donc les défauts du `<button>` en REPOSANT les
   valeurs de la règle existante, sans jamais les écraser. Mesuré par
   `outils/sonde-socle-au-repos.cjs`. */
/* ⚠️ `text-align:inherit`, PAS `left` — mesuré par la sonde : le `<div>` du
   témoin calcule `start`, et `left` calcule `left`. Identiques en LTR, mais
   « identique en pratique » n'est pas « identique », et la règle du lot est la
   seconde. `inherit` fait hériter le bouton exactement comme le div héritait. */
button.composer-socle-ligne{width:100%;margin:0;padding:0;background:none;border:none;
  cursor:pointer;text-align:inherit;font-family:inherit;font-size:13px;line-height:inherit;
  color:var(--texte)}
.composer-socle-ligne:hover,.composer-socle-ligne:focus-visible{background:var(--surface2)}
/* Le chevron est une aide au survol/focus, JAMAIS le chemin : au clavier et au
   doigt il n'existe pas, et c'est la ligne focusable qui porte le geste. */
.composer-socle-chevron{font-family:var(--mono);color:var(--muted);opacity:0}
.composer-socle-ligne:hover .composer-socle-chevron,
.composer-socle-ligne:focus-visible .composer-socle-chevron{opacity:1}
.composer-socle-sorties{color:var(--attente-mat)}

/* Le poste déplié — même famille que le panneau de candidats (`.dialogue`),
   jamais une deuxième famille de modale. */
.poste-du-socle{width:min(640px,92vw)}
.poste-occupants{display:flex;flex-direction:column;gap:12px}
.poste-occupant{border:1px solid var(--bordure);border-radius:10px;padding:12px 14px;
  display:flex;flex-direction:column;gap:6px}
.poste-occupant-tete{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.poste-rang{font-size:12px;color:var(--muted)}
.poste-provenance{font-size:12.5px;color:var(--muted)}
.poste-borne{font-size:12px;color:var(--muted)}
.poste-motifs{display:flex;flex-wrap:wrap;gap:6px;border-top:1px solid var(--bordure);padding-top:8px}
.poste-renvoi-regle{font-size:12.5px;color:var(--muted);border-top:1px solid var(--bordure);
  padding-top:10px;line-height:1.5}
/* La trace sur la ligne née dans la file — ambre : un fait du service, pas une faute. */
.composer-ligne-nee{font-size:13px;color:var(--attente-mat)}

/* ═══ S527 — V1-54 : créer et modifier un modèle de roulement ═══
   Posé tel que versé dans .design/suivi-v1/AJOUTS-FICHIERS-PARTAGES-V1-54-55-56.md §3.
   ⛔ Les blocs V1-55 et V1-56 du même document ne sont PAS de ce lot. */
/* ————— V1-54 — la bande du cycle : une règle qui recommence, pas un calendrier ————— */
.bande-cycle{display:flex;align-items:stretch;gap:8px;flex-wrap:wrap}
.bande-cellule{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;width:104px;height:74px;border:1px solid var(--bordure);border-radius:10px;background:var(--surface);cursor:pointer}
.bande-cellule:hover,.bande-cellule:focus-visible{border-color:var(--bordure2);background:var(--surface2)}
.bande-cellule.ouverte{background:var(--pret-fond);border-color:var(--pret-bordure)}
.bande-cellule.repos{background:var(--surface2)}
/* « à définir » : pointillé gris qui se dit — jamais un blanc. */
.bande-cellule.vide{border-style:dashed;background:var(--surface2)}
.bande-jour{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--muted)}
.bande-site{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--titres-c)}
.bande-cellule.repos .bande-site,.bande-cellule.vide .bande-site{color:var(--muted2)}
.bande-sens{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;color:var(--muted)}
.bande-recommence{display:flex;align-items:center;padding:0 12px;font-size:12.5px;color:var(--muted);white-space:nowrap}
/* La cellule qui change, cerclée d'ambre AVANT le geste — après, ce serait un reproche. */
.roul-cellule.changee{box-shadow:inset 0 0 0 2px var(--attente-mat)}
/* L'encart d'armement — gris posé, jamais un rouge : une information, pas une alerte. */
.modeles-ne-defait-pas{border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;font-size:12.5px;color:var(--texte);line-height:1.6;background:var(--surface2)}
.modeles-ne-defait-pas-titre{font-family:var(--mono);font-size:10px;letter-spacing:.14em;color:var(--muted)}

/* ═══ 🔴 S528 — LES VUES DU PLANNING : QUATRE NATURES DE CELLULE (V1-55) ═══
   Bloc de `AJOUTS-FICHIERS-PARTAGES-V1-54-55-56.md`, PARTIE V1-55 SEULE — les
   règles `.modeles-*` et `.conge-*` du même fichier relèvent de V1-54 et V1-56,
   deux autres lots.

   🔴 LA PEAU DES CELLULES EST CELLE DE V1-52 (`.roul-*`), APPRISE UNE FOIS. Un
   axe n'est pas un onglet décoratif : il change LA LIGNE, rien d'autre —
   cellules, pieds et légende sont identiques d'un axe à l'autre. Deux jeux de
   règles auraient fait deux grilles jumelles, le prix que V1-29 a déjà payé.

   ⛔ AUCUNE COULEUR LITTÉRALE : tout passe par les jetons, donc par les deux
   thèmes. Une couleur en dur ici, et la grille se lit à contre-jour la nuit.

   ⛔ ET AUCUNE COULEUR D'ALERTE DE MASSE. Le rouge reste au pied et sur le mot
   « vide » ; le congé est ambre CALME — c'est un fait TimeTrex, pas un manque.
   L'écran se consulte, il n'alarme pas (refus V1-11, reconduit). */
/* gravé = surface pleine · composé = pret-fond (le bleu calme du « décidé ») · projeté = surface2. */
.roul-cellule.nature-grave{background:var(--surface)}
.roul-cellule.nature-compose{background:var(--pret-fond)}
.roul-cellule.nature-projete{background:var(--surface2)}
.planning-nature-marque{font-size:9px;color:var(--muted)}
.planning-cellule-sub{font-size:8.5px;color:var(--muted)}
/* Le congé : un fait TimeTrex, ambre calme — jamais un manque, jamais un rouge. */
.roul-cellule.conge{background:var(--attente-mat-fond);color:var(--attente-mat);font-weight:600}
/* Le vide se dit sur la cellule (axe site, jours composés) ; le rouge de masse reste interdit. */
.roul-cellule.vide-dit{color:var(--alerte);font-weight:600}
.roul-cellule.ecart-grave .planning-cellule-sub{color:var(--attente-mat)}
.planning-etat-vide{border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;background:var(--surface2);color:var(--muted);font-size:13px;line-height:1.55}
.planning-borne{border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;background:var(--surface2);color:var(--muted);font-size:13px;line-height:1.6}
/* 🔴 ÉCARTS AVOUÉS AU BLOC LIVRÉ, ET ILS SONT DEUX — tous deux imposés par la
   grille de V1-52, que ce bloc réutilise plutôt que de s'en refaire une :

   ① LA CELLULE DOIT POUVOIR PORTER DEUX LIGNES. `.roul-cellule` est un
      `flex` en ligne, à hauteur fixe de 30 px : le sous-titre (« posé : Gare »,
      « à pourvoir », le matricule d'un congé) s'y serait posé À CÔTÉ du
      libellé, et la cellule aurait débordé sans le dire. La règle ci-dessous
      empile les deux ET rend la hauteur souple. ⛔ Elle ne vaut QUE sur les
      cellules du planning : `.roul-cellule` seule n'est pas touchée, la grille
      de rattachement garde sa hauteur au pixel.

   ② LA GRILLE PORTE JUSQU'À 31 COLONNES, pas 14. `--roul-nuits` existe déjà et
      la vue la pose ; mais une plage arrière de 31 jours à 60 px déborde de
      l'écran, et `.roul-grille` défile déjà en X. Rien à ajouter, c'est dit
      pour que personne ne « répare » un défilement qui est voulu. */
.roul-cellule.planning-cellule{flex-direction:column;gap:1px;height:auto;min-height:34px;padding:3px 2px;line-height:1.15;text-align:center}
/* ===== Périmètre BIP — exclusions BIP (V1-57) ===== */
/* Gris = hors du compte : l'exclusion active n'est pas une faute. L'ambre dit
   la formalité en attente (la relecture) ; le rouge n'apparaît pas sur cet
   écran. Réutilisés tels quels : .carte, .chip-etat, .kicker, .pilule-filtre,
   .btn-primaire/.btn-secondaire, .etat-vide, .encart-controle, .champ,
   .exclusion-motif (le verbatim, même peau que l'écran des rondes).
   ⛔ TOKENS SEULS, aucune couleur littérale : les onze tokens lus ici sont
   définis dans LES DEUX thèmes (l. 21-25 clair, l. 32-36 sombre), vérifié. */
.chip-provenance{font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;border:1px solid var(--bordure2);border-radius:999px;padding:2px 10px;color:var(--muted);white-space:nowrap}
.chip-provenance.synchro{border-style:dashed}
.carte.exclusion-a-relire{border-color:var(--attente-mat-bordure)}
.marque-rdv-passe{font-family:var(--mono);font-size:10.5px;font-weight:600;border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);color:var(--attente-mat);border-radius:999px;padding:2px 10px}
.exclusion-condition{font-size:12.5px;color:var(--texte)}
.exclusion-condition b{color:var(--titres-c)}
.exclusion-inconnu{font-size:12.5px;color:var(--muted)}
.encart-deux-ecrivains{border:1px solid var(--pret-bordure);background:var(--pret-fond);color:var(--pret);border-radius:9px;padding:10px 14px;font-size:13px;line-height:1.55}
.encart-consequence{border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);color:var(--attente-mat);border-radius:9px;padding:10px 14px;font-size:13px;line-height:1.55}
/* ===== fin Périmètre BIP (V1-57) ===== */
/* ————————————————————————————————————————————————————————————————————————
   S541 — COUPURES À VALIDER (conception V1-50).

   ⛔ AUCUNE COULEUR LITTÉRALE : tout passe par les jetons, donc le thème sombre
   suit sans audit séparé.

   🔴 LES QUATRE TEINTES DE REÇU, ET CE QU'ELLES DISENT (V1-50 §6) :
     · `recu-neutre`  — COUPÉE. Sombre et neutre : traité, pas anormal. Une
       coupure n'est pas une alerte, c'est l'issue normale de la règle des sept
       jours ; la peindre en rouge ferait de chaque décision un incident.
     · `recu-garde`   — GARDÉE. Vert, motif en toutes lettres.
     · `recu-report`  — REPOUSSÉE. Ambre, datée : elle revient.
     · `recu-solde`   — SOLDÉE. Vert, et comptée à part : rien n'a été coupé.
   ———————————————————————————————————————————————————————————————————————— */
.coupures-totaux{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.coupures-photo{font-size:11.5px;color:var(--muted2)}
.chip-vague{border:1px solid var(--pret-bordure);background:var(--pret-fond);color:var(--pret)}
.chip-a-trancher{border:1px solid var(--bordure2);background:var(--surface2);color:var(--titres-c);font-weight:600}
.chip-source{border:1px solid var(--pret-bordure);background:var(--pret-fond);color:var(--pret)}
.chip-rattachement{border:1px solid var(--bordure);background:var(--surface2);color:var(--muted)}

.coupures-secteurs{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.coupures-compte-filtre{font-size:11.5px;color:var(--muted)}

.coupures-bloc{display:flex;flex-direction:column;gap:10px;margin-top:18px}
.coupures-bloc-tete{display:flex;align-items:baseline;gap:10px;border-bottom:1px solid var(--bordure);padding-bottom:6px}
.coupures-bloc-titre{font-family:var(--titres);font-size:15px;font-weight:700;color:var(--titres-c)}
.coupures-bloc-comptes{font-size:11.5px;color:var(--muted)}
/* La note du bloc « pièce produite » : il part VIDE, et sans cette phrase il se
   lirait comme une panne le jour de la mise en service. */
.coupures-note{font-size:12.5px;color:var(--muted);line-height:1.5;text-wrap:pretty}

.coupures-dossier{display:flex;flex-direction:column;gap:10px}
.coupures-tete{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
/* ⛔ L'IDENTITÉ NE PORTE JAMAIS DE COULEUR D'ÉTAT (V1-50 §5.1). */
.coupures-nom{font-weight:600;color:var(--titres-c)}
.coupures-matricule{font-size:12px;color:var(--muted)}
.coupures-nb{font-size:12px;color:var(--muted)}

.coupures-journee{border-top:1px solid var(--bordure);padding-top:10px;display:flex;flex-direction:column;gap:8px}
.coupures-journee:first-child{border-top:none;padding-top:0}
.coupures-journee-faits{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.coupures-date{font-size:12.5px;color:var(--titres-c);font-weight:600}
.coupures-site{font-size:13.5px;color:var(--texte)}
.coupures-age{font-size:12px;color:var(--muted)}
.coupures-piece{font-size:12px;color:var(--ok)}
/* ⛔ L'INCONNU SE DIT, EN GRIS — jamais un blanc (leçon V1-48). */
.coupures-inconnu{font-size:12.5px;color:var(--muted2);font-style:italic}

.coupures-gestes{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.coupures-gestes-ensemble{border-top:1px dashed var(--bordure2);padding-top:10px}
/* ⛔ UN GESTE HORS DU RÔLE N'EXISTE PAS — il n'est pas grisé. Ce qui reste,
   c'est cette phrase, qui le DIT (V1-50 §2 et §11). */
.coupures-hors-gestes{font-size:12px;color:var(--muted2)}
.coupures-renvoi{font-size:12.5px;color:var(--muted);border-top:1px solid var(--bordure);padding-top:8px}

.coupures-recu{border-left:3px solid var(--bordure2);padding:6px 0 6px 10px;display:flex;
  flex-direction:column;gap:4px}
.coupures-recu-mot{font-size:12px;font-weight:600;letter-spacing:.04em}
.coupures-recu-auteur{font-size:11.5px;color:var(--muted)}
/* Le motif, VERBATIM — accents, apostrophes et retours à la ligne compris. */
.coupures-recu-motif{font-size:13px;color:var(--texte);line-height:1.5;white-space:pre-wrap;text-wrap:pretty}
.recu-neutre{border-left-color:var(--bordure2)}
.recu-neutre .coupures-recu-mot{color:var(--titres-c)}
.recu-garde{border-left-color:var(--ok-bordure)}
.recu-garde .coupures-recu-mot{color:var(--ok)}
.recu-report{border-left-color:var(--attente-mat-bordure)}
.recu-report .coupures-recu-mot{color:var(--attente-mat)}
.recu-solde{border-left-color:var(--ok-bordure)}
.recu-solde .coupures-recu-mot{color:var(--ok)}
/* Les mêmes teintes sur les pastilles de compte, sans les répéter à la main. */
.chip-etat.recu-report{background:var(--attente-mat-fond);color:var(--attente-mat);border:1px solid var(--attente-mat-bordure)}
.chip-etat.recu-solde{background:var(--ok-fond);color:var(--ok);border:1px solid var(--ok-bordure)}

/* 🔴 LE PANNEAU DU « NON ». Son aide naît AVEC le champ : 240 motifs libres sur
   442, à l'écran des absences, portent un prénom, un nom complet ou un
   matricule. Posée après, elle serait posée trop tard. */
.coupures-motif{border:1px solid var(--bordure2);border-radius:9px;padding:12px;
  display:flex;flex-direction:column;gap:8px;background:var(--surface2)}
.coupures-motif-titre{font-weight:600;color:var(--titres-c);font-size:13.5px}
.coupures-motif textarea.champ-motif{min-height:64px;padding:10px 12px;line-height:1.5;resize:vertical}
.coupures-motif-aide{font-size:12.5px;color:var(--pret);font-weight:600}
.coupures-motif-pourquoi{font-size:12px;color:var(--muted);line-height:1.5;text-wrap:pretty}
.coupures-motif-pied{display:flex;align-items:center;gap:10px}
.coupures-motif-reste{font-size:11.5px;color:var(--muted)}
/* ═══ S543 — LES SOLDES DE DÉPART ═══════════════════════════════════════════
 * ⛔ AUCUNE COULEUR LITTÉRALE : tout passe par les jetons du thème, comme le
 * reste de cette feuille. Une couleur écrite en dur ici tiendrait en clair et
 * mentirait en sombre — et l'écran se lit à 3 h du matin.
 *
 * ⚠️ Une seule règle NEUVE (`.champ-lot`) ; le reste de l'écran réutilise
 * `.carte`, `.etat-vide`, `.chip-ok`, `.chip-ecart`, `.seg`. Une classe de plus
 * pour ce qui existe déjà est une divergence de style qui s'installe. */
.ligne-soldes{display:flex;align-items:center;gap:10px;min-width:0;flex-wrap:wrap}
/* La zone de collage du lot — même grammaire que `.champ-motif`, en plusieurs
 * lignes. `font-family:var(--mono)` parce qu'on y relit des matricules alignés :
 * une colonne qui ne s'aligne pas se relit mal, et c'est là qu'on cherche la
 * ligne fautive après un dépôt. */
.champ-lot{min-height:88px;padding:10px 12px;border:1px solid var(--bordure2);border-radius:8px;
  font-family:var(--mono);font-size:13px;color:var(--titres-c);background:var(--surface);
  resize:vertical;width:100%;box-sizing:border-box}

/* ————— V1-56 — congés : les badges d'état et le tuyau TimeTrex ————— */
.conge-carte{border:1px solid var(--bordure);border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:6px}
.conge-carte.refusee{background:var(--surface2)}
.conge-badge{border-radius:999px;padding:2px 10px;font-family:var(--mono);font-size:10.5px;font-weight:600}
.conge-badge.vise{border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);color:var(--attente-mat)}
.conge-badge.refuse{border:1px solid var(--bordure2);background:var(--alerte-fond);color:var(--alerte)}
.conge-badge.accepte{border:1px solid var(--ok-bordure);background:var(--ok-fond);color:var(--ok)}
.conge-attente{font-size:12px;color:var(--muted)}
.conge-conflit{font-size:12.5px;color:var(--attente-mat)}
.conge-solde{font-size:12.5px;color:var(--texte)}
.conge-solde-absent{font-size:13px;color:var(--muted);line-height:1.55}
.conge-tuyau{font-size:12.5px;color:var(--muted);line-height:1.55}
.conge-tuyau.accepte{color:var(--ok)}

/* ————— V1-58 — la recopie humaine : remplace le bloc « tuyau » de V1-56 ————— */
/* Ambre = formalité en attente (à recopier, retrouvé-différent, horizon).
   Le SEUL rouge : un congé commencé non recopié — une personne est déjà lésée. */
.conge-badge.a-recopier{border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);color:var(--attente-mat)}
.conge-badge.different{border:1px solid var(--attente-mat-bordure);background:var(--attente-mat-fond);color:var(--attente-mat)}
.conge-badge.commence{border:1px solid var(--bordure2);background:var(--alerte-fond);color:var(--alerte)}
.conge-carte.dans-horizon{border-color:var(--attente-mat-bordure)}
.conge-carte.commence{border-color:var(--alerte)}
.conge-fiche{border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;background:var(--surface2);display:flex;flex-direction:column;gap:4px}
.conge-fiche-titre{font-family:var(--mono);font-size:10px;letter-spacing:.14em;color:var(--muted)}
.conge-fiche-ligne{font-family:var(--mono);font-size:12.5px;color:var(--titres-c)}
.conge-fiche-horaires{font-size:12px;color:var(--attente-mat);line-height:1.5}
.conge-horizon-note{font-size:12.5px;color:var(--attente-mat)}
.conge-commence-note{font-size:12.5px;color:var(--alerte)}
.conge-versions{display:flex;gap:10px}
.conge-version{flex:1;border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;background:var(--surface2)}
.conge-version.timetrex{border-color:var(--attente-mat-bordure)}
/* ————— fin V1-58 ————— */

/* ⚠️ AJOUT D'INTÉGRATION (S549), hors conception — sous 560 px les deux
   versions s'EMPILENT. Côte à côte, deux blocs mono de dates font déborder la
   carte horizontalement, ce que le projet n'admet nulle part (le débordement
   scrolle dans son conteneur, jamais la page). L'ordre ne change pas :
   « chez nous » d'abord, « chez TimeTrex » ensuite — c'est le sens de lecture
   de l'écart. */
@media (max-width:560px){.conge-versions{flex-direction:column}}
/* ⚠️ AJOUT D'INTÉGRATION (S549), hors conception — la bande des jours demandés
   réutilise `.bande-cellule` (V1-54) ; il lui manquait le ton du congé. Ambre,
   comme la cellule de congé du planning (`.roul-cellule.conge`) : un congé est
   un FAIT, jamais un manque, jamais un rouge. Tokens seuls. */
.bande-cellule.conge-demande{background:var(--attente-mat-fond);border-color:var(--attente-mat-bordure)}
.bande-cellule.conge-demande.repos .bande-site{color:var(--muted)}

/* 🔴 S666 — LES QUATRE NATURES SE DISTINGUENT, ET « AUCUNE RÈGLE » EN PREMIER.
   L'écran n'en lisait que deux : posté, et « le reste », qui rangeait dans la
   même cellule grise un REPOS (un fait établi) et un jour qu'AUCUN rattachement
   ne couvre (on ne sait rien). Confondre les deux, c'est affirmer.

   ⚠️ Le mot porte déjà la distinction — « repos » contre « aucune règle », là où
   les deux disaient « — ». Ces règles ne font que la rendre visible de loin :
   POINTILLÉ pour ce qu'on ne sait pas (le trait interrompu du projet, celui de
   `.bande-cellule.vide`), plein pour ce qu'on sait.

   ⛔ Aucune couleur en dur : tokens seuls, et aucun rouge — un lieu inconnu
   n'est pas un incident, c'est une lacune de la règle. */
.bande-cellule.conge-demande.lieu-inconnu{border-style:dashed}
.bande-cellule.conge-demande.lieu-inconnu .bande-site{color:var(--attente-mat)}
.bande-cellule.conge-demande.sans-regle{background:var(--surface2);border-style:dashed;border-color:var(--bordure2)}
.bande-cellule.conge-demande.sans-regle .bande-site{color:var(--muted2);font-style:italic}
/* La 3ᵉ ligne — le service. Il ne se lisait qu'en REPLI, quand le site manquait :
   « posté sur DÉPÔT MAHAVOKY » ne disait pas si c'était la nuit ou le jour, ce
   qui est la moitié du fait pour un dispositif de gardiennage de nuit. */
.bande-service{font-family:var(--mono);font-size:10px;letter-spacing:.08em;color:var(--muted)}
.bande-cellule.conge-demande .bande-service{color:var(--attente-mat)}

/* 🔴 S736 — DANS UN DIALOGUE, LA GRILLE DES JOURS A SA PROPRE ZONE.
   Sur le visa d'un congé, `blocDeConflit()` insère une carte PAR JOUR entre les
   champs et les boutons : une vingtaine pour trois semaines, 104 px de large
   dans une boîte de 380 px, donc trois par ligne et sept rangées. Bornée à la
   seule boîte, elle repousse le solde, les trois avertissements et la rangée de
   boutons hors de vue, et il faut la traverser pour atteindre quoi que ce soit.
   ⇒ Elle défile CHEZ ELLE. Les champs restent au-dessus, ce qui la suit reste
   atteignable sans la traverser.
   ⛔ Elle n'est ni supprimée ni repliée : c'est la ligne de l'agent sur la plage
   demandée, et la règle du site s'y lit — elle est là pour être vue avant de
   viser. Le compte des jours est dit juste dessous (`conges.natures_legende`) :
   personne ne peut croire la grille complète parce qu'elle s'arrête au bord.
   ⚠️ `.dialogue` en tête du sélecteur : hors dialogue, `.bande-cycle` est la
   bande du cycle d'un modèle de roulement (V1-54, `#/modeles-roulement`), qui
   dispose de toute la largeur d'un écran et n'a rien à borner. */
.dialogue .bande-cycle{max-height:min(34vh,246px);overflow-y:auto;-webkit-overflow-scrolling:touch;padding:2px;margin:-2px;border-radius:10px}
@supports (height:100dvh){.dialogue .bande-cycle{max-height:min(34dvh,246px)}}
/* Compactage SANS PERTE : la cellule gardait 74 px de haut pour trois lignes de
   texte qui en occupent 45 — c'est du vide, pas de l'information. Elle se règle
   sur son contenu, plancher à 58 px pour rester une cible tactile honnête.
   ⛔ LE NOM DU SITE N'EST PAS DÉDUPLIQUÉ, même répété vingt fois : une carte se
   lit isolément (« 11/09, Usine Soatex, nuit »), et le retirer des jours
   consécutifs ferait perdre à ces cartes-là ce qu'on est venu lire. */
.dialogue .bande-cellule{height:auto;min-height:58px;padding:6px 4px}

/* ===== S600 — réglages de flotte (V1-62) =====
   V1-62 §11 ne demande AUCUNE règle partagée : chips et jetons existants
   suffisent au dessin. Ces quatre règles sont LOCALES à l'écran, et elles ne
   servent qu'à une chose — donner leur poids aux DEUX phrases qui disent ce
   que les réglages coûtent. Aucune couleur en dur : tokens seuls.

   ⚠️ `.cout-crieraient` prend l'ambre de l'ATTENTE, jamais le rouge de
   l'alerte. Ce n'est pas un incident : c'est un constat qui appelle une
   décision (« ces véhicules crieraient si vous retiriez ces réglages »). Le
   rouge est réservé à ce qui appelle un geste maintenant — l'écran de réglage
   n'en porte aucun. */
.cout-phrase{font-size:13.5px;color:var(--titres-c);line-height:1.5}
.cout-detail{margin:0;padding-left:18px;font-size:12.5px;color:var(--texte);line-height:1.6}
.cout-crieraient{font-size:12.5px;color:var(--attente-mat);line-height:1.5}
/* La ligne d'une période : même grammaire que `.retenue-entete` — une ligne
   d'en-tête qui ne se comprime pas et qui passe à la ligne plutôt que de faire
   déborder sa carte (le débordement scrolle dans son conteneur, jamais la
   page). */
.mc-ligne-fixe{display:flex;align-items:center;gap:10px;min-width:0;flex-wrap:wrap}

/* ═══════════════════════════════════════════════════════════════════════════
   S601 — MA FLOTTE (V1-59 §5) : l'accueil du CLIENT
   ═══════════════════════════════════════════════════════════════════════════
   🔴 POURQUOI LES MUETS SONT AMBRE ET PAS ROUGES. Chez HRF, 23 balises GPS sur 35
   sont muets : un écran aux deux tiers rouge en permanence cesse d'être lu en
   une semaine — l'argument exact de l'ambre de V1-58, et A100 par-dessus
   (« généralement le client est celui qui coupe » : il n'y a rien à reprocher
   à personne). L'ambre du projet dit « à traiter, pas encore advenu » ; c'est
   la PHRASE DATÉE, en tête et comptée, qui porte la gravité — pas la couleur.

   🔴 ET AUCUN ÉTAT NE TIENT À SA SEULE COULEUR. Chaque pastille porte UN MOT :
   un daltonien, un écran au soleil de Tananarive et une capture en noir et
   blanc doivent tous la lire. La couleur ne fait que hiérarchiser. */

.fl-entete{display:flex;flex-direction:column;gap:6px;padding:14px 16px;background:var(--surface);border:1px solid var(--bordure);border-radius:11px}
.fl-compte{margin:0;font-size:15px;font-weight:600;color:var(--titres-c);text-wrap:pretty}
/* L'égalité vérifiable (V1-62 §5.1). En mono et plus discrète que la phrase
   au-dessus : c'est un contrôle, pas le message. */
.fl-egalite{margin:0;font-size:12px;color:var(--muted);text-wrap:pretty}

.fl-section{display:flex;flex-direction:column;gap:8px}
.fl-section-titre{display:flex;align-items:center;gap:9px;margin:0;font-size:12.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.fl-section-compte{font-size:11.5px;font-weight:600;color:var(--muted2);background:var(--surface2);border-radius:999px;padding:1px 8px}
/* Les muets ouvrent l'écran, et leur titre le dit : c'est le seul groupe dont
   l'intitulé porte la couleur de l'attente. */
.fl-section-muets>.fl-section-titre{color:var(--attente-mat)}

.fl-vehicule{display:flex;flex-direction:column;gap:6px;padding:12px 16px;background:var(--surface);border:1px solid var(--bordure);border-left:3px solid var(--bordure2);border-radius:11px}
.fl-groupe-muets{border-left-color:var(--attente-mat);background:var(--attente-mat-fond)}
.fl-groupe-endormis{border-left-color:var(--pret)}
.fl-groupe-sans_position{border-left-color:var(--bordure2)}
.fl-groupe-en_service{border-left-color:var(--ok)}

.fl-vehicule-tete{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.fl-nom{font-size:15px;font-weight:600;color:var(--titres-c)}
.fl-plaque{font-size:12px;color:var(--muted);letter-spacing:.04em}

.fl-etat{flex:none;font-size:10.5px;letter-spacing:.06em;padding:4px 10px;border-radius:999px;white-space:nowrap;border:1px solid transparent}
.fl-etat-muet{background:var(--attente-mat-fond);color:var(--attente-mat);border-color:var(--attente-mat-bordure)}
.fl-etat-endormi{background:var(--pret-fond);color:var(--pret);border-color:var(--pret-bordure)}
.fl-etat-mouvement{background:var(--ok-fond);color:var(--ok);border-color:var(--ok-bordure)}
.fl-etat-arret{background:var(--surface2);color:var(--muted);border-color:var(--bordure2)}
/* ⛔ La non confirmée n'emprunte AUCUNE couleur d'état sain. V1-59 §3bis : elle
   ne doit jamais avoir le même rendu qu'une position mesurée — gris, comme le
   marqueur en pointillé de la carte. */
.fl-etat-non-confirmee{background:var(--surface2);color:var(--muted);border-style:dashed;border-color:var(--bordure2)}
.fl-etat-sans-position{background:var(--surface2);color:var(--muted2);border-color:var(--bordure2)}

.fl-phrases{display:flex;flex-direction:column;gap:3px}
.fl-phrase{margin:0;font-size:13.5px;line-height:1.55;color:var(--texte);text-wrap:pretty}
/* La porte « Signaler à Securex » (A100). Une phrase, pas un bouton : sa
   destination est Q9 et le canal n'existe pas — un bouton mort est refusé ici. */
.fl-signaler{margin:4px 0 0;font-size:12.5px;line-height:1.5;color:var(--muted);text-wrap:pretty}
.fl-signaler strong{color:var(--titres-c)}

/* ⛔ LE REFUS N'EST PAS UN PARC CALME. Il occupe la place du contenu, il porte
   `role=status`, et sa première ligne dit « nous ne savons pas ». */
.fl-refus{display:flex;flex-direction:column;align-items:flex-start;gap:8px;padding:16px;background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);border-radius:11px}
.fl-refus-titre{margin:0;font-size:15px;font-weight:600;color:var(--attente-mat);text-wrap:pretty}
.fl-refus-phrase{margin:0;font-size:13.5px;line-height:1.55;color:var(--texte);text-wrap:pretty}

/* ═══════════════════════════════════════════════════════════════════════════
   S641 — LE PLAN DES FAITS EN COURS (V1-61 §§1–3)
   ═══════════════════════════════════════════════════════════════════════════
   🔴 DEUX AXES, ET ILS NE SE MÉLANGENT JAMAIS.
     · LA COULEUR dit l'ÉTAT DU FAIT — rouge : à prendre · ambre : pris. Le
       même vocabulaire que la file, et les mêmes jetons (--alerte,
       --attente-mat) : deux nuances de rouge sur le même écran se liraient
       comme deux états différents.
     · LA FORME dit la CONFIANCE DANS LA POSITION — plein : mesurée récente ·
       anneau creux : dernière connue, ancienne · anneau POINTILLÉ : réémise.
   ⛔ Un point réémis ne se dessine JAMAIS comme un point mesuré : « le point a
   l'air frais et ne l'est pas » (V1-61 §2).
   ⚠️ Et la forme ne porte JAMAIS le sens seule : chaque point a son étiquette
   permanente, en toutes lettres, avec son âge. */

/* La veille à DEUX COLONNES — la file et le plan côte à côte (V1-61 §1 : un
   panneau DANS la veille, ⛔ pas un quatrième onglet).
   ⚠️ `minmax(0,…)` sur les deux : sans lui, une étiquette de plan longue
   ferait déborder la grille au lieu de se replier — le défaut exact du
   sélecteur de date rogné par un enfant à min-width auto. */
.veille-flotte-deux{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px;align-items:start}
@media (max-width:900px){
  /* Sur téléphone, la FILE d'abord : c'est elle qui porte les gestes. Le plan
     est une seconde lecture, il passe dessous. */
  .veille-flotte-deux{grid-template-columns:minmax(0,1fr)}
}

.plan-cadre{position:relative;display:flex;flex-direction:column;gap:8px}

/* 🔴 LA GRILLE DE REPÈRE, SOUS LES TUILES — elle est le fond de secours.
   Quand aucune tuile n'arrive, il reste un quadrillage régulier : sans lui,
   l'œil n'a plus AUCUNE référence d'échelle et deux points séparés de trois
   centimètres peuvent être à 40 m comme à 4 km. Avec l'échelle de Leaflet en
   bas à gauche, c'est ce qui garde le plan LISIBLE sans son fond. */
.plan-toile{height:480px;border-radius:11px;border:1px solid var(--bordure);background-color:var(--surface2);
  background-image:linear-gradient(var(--bordure) 1px,transparent 1px),linear-gradient(90deg,var(--bordure) 1px,transparent 1px);
  background-size:48px 48px;background-position:-1px -1px}
@media (max-width:900px){.plan-toile{height:320px}}

/* 🔴 ET LA GRILLE EST REDÉCLARÉE ICI, SUR LE SÉLECTEUR DOUBLE. Ce n'est pas une
   redondance : `leaflet.css` est injecté dans le <head> APRÈS `app.css` et pose
   `.leaflet-container{background:#ddd}` — à spécificité égale, c'est LUI qui
   gagne, et il recouvrait la grille d'un aplat. Mesuré : sans cette règle, le
   plan privé de ses tuiles rendait un rectangle uni, sans un seul repère
   d'échelle — exactement le carré gris que ce lot existe pour refuser. */
.plan-toile.leaflet-container{background-color:var(--surface2);
  background-image:linear-gradient(var(--bordure) 1px,transparent 1px),linear-gradient(90deg,var(--bordure) 1px,transparent 1px);
  background-size:48px 48px;background-position:-1px -1px}

/* L'annonce du fond manquant. Ambre — « à traiter », pas un péril (V1-58) :
   ce n'est pas une panne de l'application, et les points restent justes. */
.plan-fond-absent{padding:8px 11px;border-radius:9px;background:var(--attente-mat-fond);
  border:1px solid var(--attente-mat-bordure);color:var(--attente-mat);font-size:12.5px;line-height:1.5;text-wrap:pretty}

.plan-aucun{padding:8px 11px;font-size:12.5px;line-height:1.5;color:var(--muted);text-wrap:pretty}

/* ─── LE POINT ─────────────────────────────────────────────────────────── */
.plan-point{display:block;width:14px;height:14px;border-radius:50%;box-sizing:border-box}

/* LA COULEUR — l'état du fait. */
.plan-point-a-prendre{background:var(--alerte);border:2px solid var(--alerte)}
.plan-point-pris{background:var(--attente-mat);border:2px solid var(--attente-mat)}

/* LA FORME — la confiance dans la position. ⚠️ `background:transparent` REPREND
   la couleur posée juste au-dessus : c'est la forme qui creuse le point, la
   couleur ne bouge pas. */
.plan-point-mesuree{}
.plan-point-ancienne{background:transparent}
/* ⛔ POINTILLÉ, ET PAS SEULEMENT PLUS CLAIR : une nuance ne survit ni au soleil
   de Tananarive sur un écran de téléphone, ni à une capture en noir et blanc.
   La différence est de FORME, donc elle tient partout. */
.plan-point-reemise{background:transparent;border-style:dashed}

/* L'étiquette permanente. 🔴 Elle porte l'âge — « AUCUN point sans son âge,
   jamais ». ⛔ Pas d'infobulle au survol : elle n'existerait pas sur un écran
   tactile, et pas du tout pour un opérateur qui balaie l'écran du regard. */
.plan-etiquette.leaflet-tooltip{background:var(--surface);border:1px solid var(--bordure);color:var(--texte);
  /* ⚠️ PROPORTIONNELLE, pas monospace : à 10 px, « dernière position il y a
     52 min » prend un tiers de moins de place en Plex Sans qu'en Plex Mono, et
     c'est ce tiers qui décide qu'une étiquette tient sur deux lignes au lieu de
     cinq. Le monospace reste pour les chiffres alignés en colonne, pas ici. */
  font-family:var(--sans);font-size:10.5px;line-height:1.4;padding:3px 7px;border-radius:6px;box-shadow:none;
  /* ⚠️ BORNÉE ET REPLIABLE. Mesuré sur le panneau : « Camion 8 · dernière
     position il y a 52 min » sur une seule ligne fait 400 px, soit la largeur
     entière du plan — trois points suffisaient à couvrir la carte. ⛔ Et on ne
     coupe pas le texte : l'âge est la moitié de ce que le point a le droit de
     dire. Il se replie. */
  white-space:normal;width:max-content;max-width:196px;text-wrap:pretty;opacity:.94}
.plan-etiquette.leaflet-tooltip::before{display:none}

/* ─── LE GROUPE ────────────────────────────────────────────────────────── */
/* Un halo POINTILLÉ qui englobe ses points, jamais un aplat : le groupe est
   une OBSERVATION, pas un objet — rien ne s'y accroche, rien ne s'y prend en
   charge. Un aplat plein se lirait comme une zone qu'on aurait traitée. */
.plan-halo{fill:var(--attente-mat);fill-opacity:.06;stroke:var(--attente-mat);stroke-width:1.5;
  stroke-dasharray:5 5;stroke-opacity:.75}

.plan-etiquette-groupe.leaflet-tooltip{background:var(--attente-mat-fond);border:1px solid var(--attente-mat-bordure);
  color:var(--attente-mat);font-size:10.5px;line-height:1.4;padding:4px 8px;border-radius:7px;box-shadow:none;
  width:max-content;max-width:210px;white-space:normal;text-wrap:pretty}
.plan-etiquette-groupe.leaflet-tooltip::before{display:none}

/* Le bandeau du groupe DANS LA FILE — la MÊME phrase que sur le plan. C'est ce
   qui garde la carte et la file en UNE SEULE lecture (V1-61 §3). */
.plan-bandeau-groupe{padding:8px 11px;border-radius:9px;background:var(--attente-mat-fond);
  border:1px dashed var(--attente-mat-bordure);color:var(--attente-mat);font-size:12.5px;line-height:1.5;text-wrap:pretty}

/* 🔴 LE FAIT MIS EN ÉVIDENCE PAR UN CLIC SUR SON POINT. Un liseré, deux
   secondes — ⛔ pas un clignotement : « pas de clignotement, pas de son »
   (V1-61 §4), et un écran de veille qui clignote la nuit cesse d'être lu. */
.mc-carte.plan-vise{outline:2px solid var(--attente-mat);outline-offset:2px}

/* L'attribution OpenStreetMap : une CONDITION D'USAGE, pas une politesse.
   ⛔ Elle n'est jamais masquée — seulement rendue lisible dans les deux thèmes. */
.leaflet-container .leaflet-control-attribution{background:var(--surface);color:var(--muted);font-size:10px}
.leaflet-container .leaflet-control-attribution a{color:var(--muted)}
.leaflet-container .leaflet-control-scale-line{background:var(--surface);border-color:var(--bordure2);color:var(--texte)}

/* ————— V1-65 (S662) — le solde de tout compte —————
   Recopié de la livraison de conception : jetons seuls, aucun `#`, aucun
   `rgb(`. Le reste de l'écran réemploie sans copier — `.carte`, `.pile`,
   `.ligne-site`, `.etat-vide`, `.champ-aide`, `.kicker`, `.mono`, et les chips
   `chip-ok` / `chip-attente` / `chip-ecart` pour les paliers. */
/* Les deux colonnes du premier bloc : jamais un troisième nombre entre elles. */
.stc-colonnes{display:flex;gap:10px}
.stc-colonne{flex:1;border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;background:var(--surface2);display:flex;flex-direction:column;gap:6px}
.stc-colonne-titre{font-family:var(--mono);font-size:10px;letter-spacing:.14em;color:var(--muted)}
.stc-fait{font-size:13px;line-height:1.5;color:var(--titres-c)}
/* L'inconnue est une PHRASE en gris — jamais un blanc, jamais un zéro. */
.stc-fait-absent{font-size:12.5px;line-height:1.5;color:var(--muted)}
/* La trace de fermeture (verte : un constat) et la réouverture (ambre :
   la porte d'A137 est rouverte) — additives, l'une ne remplace pas l'autre. */
.stc-trace{border:1px solid var(--bordure);border-radius:9px;padding:10px 14px;background:var(--ok-fond);font-size:13px;line-height:1.5;color:var(--ok)}
.stc-trace.rouverte{background:var(--attente-mat-fond);border-color:var(--attente-mat-bordure);color:var(--attente-mat)}
/* ————— fin V1-65 ————— */

/* ————— A152 (S691) — les salaires de référence —————
   Jetons seuls, aucun `#`, aucun `rgb(`. L'écran réemploie sans copier —
   `.carte`, `.pile-serree`, `.etat-vide`, `.kicker`, `.mono`, `.chip-etat`,
   `.chip-fige` et la `.frontiere-ferie`, qui n'a rien de propre aux fériés :
   deux filets et une date en toutes lettres. */

/* La grille du formulaire a QUATRE segments : tranche, mensuel, journalier,
   date d'effet. ⛔ Le journalier ne se déduit pas du mensuel — il a son propre
   champ, de même largeur, et c'est la forme qui le dit. */
.grille-segments.quatre{grid-template-columns:repeat(4,1fr)}

/* Une ligne : la tranche, les DEUX montants de MÊME RANG, la date, l'état.
   ⛔ Le journalier n'est pas atténué par rapport au mensuel : aucun des deux ne
   dérive de l'autre, et une hiérarchie visuelle laisserait croire le
   contraire. */
.ligne-salaire{display:grid;grid-template-columns:190px auto auto 1fr auto;align-items:center;gap:14px;padding:11px 4px}
.ligne-salaire + .ligne-salaire{border-top:1px solid var(--bordure)}
.ligne-salaire > :first-child{font-weight:700;font-size:14.5px;color:var(--titres-c);min-width:0}
.ligne-salaire > :last-child{justify-self:end}
/* La signature (« déclaré par …, le … ») passe SOUS la tranche : elle la
   complète, elle ne la prolonge pas. */
.ligne-salaire .mention-regle{display:block;font-weight:400;margin-top:2px}
.montant-salaire{display:flex;align-items:baseline;gap:6px;font-size:14.5px;color:var(--titres-c);white-space:nowrap}

/* Une tranche SANS valeur : une phrase en gris qui tient toute la ligne.
   ⛔ Jamais « 0 Ar », qui se lirait « on ne lui doit rien ». */
.ligne-salaire-vide{grid-template-columns:190px 1fr}
.ligne-salaire-vide > :first-child{color:var(--muted);font-weight:600}

/* Ce qui ne vaut plus s'atténue — il ne se cache pas. Une déclaration
   remplacée reste ce qui explique les chiffres de son époque : la masquer
   reviendrait à effacer, et c'est exactement ce qu'A152 interdit. */
.ligne-salaire-remplacee,.ligne-salaire-corrigee{opacity:.92}
.ligne-salaire-remplacee > :first-child,.ligne-salaire-corrigee > :first-child{font-weight:600;font-size:14px;color:var(--texte)}
.ligne-salaire-remplacee .montant-salaire,.ligne-salaire-corrigee .montant-salaire{color:var(--muted)}
/* ————— fin A152 ————— */
