/* =====================================================================
   SOCLE S-PACE — v1 (§25)                                     2026-08-08
   ---------------------------------------------------------------------
   Couche de JETONS (variables CSS) commune à toute la suite S-PACE.
   PAS de composants : uniquement des variables + la famille typographique.
   Chaque application (statique OU Vite) importe ce fichier, puis dessine
   ses propres composants à partir de ces jetons.

   COHABITATION — règle d'or : ce fichier n'AJOUTE que des noms nouveaux,
   ou redéclare à l'IDENTIQUE des noms de charte déjà en place
   (--bordeaux, --rose, --fond). Il ne réaffecte JAMAIS une valeur dont
   dépend du code existant. On peut donc l'introduire dans une application
   non reprise sans rien casser.

   Deux familles de couleur, jamais mélangées :
     • IDENTITÉ (charte)      — colore le cliquable et la marque.
     • FONCTIONNEL (alerte)   — colore ce qui demande une décision.
   Le rouge d'alerte (#bb2a17, rouge-orangé) est à ΔE00 ≈ 27 du bordeaux
   (#920157, magenta) : « manifestement deux couleurs ». Ne pas rapprocher.
   ===================================================================== */

/* =====================================================================
   TYPOGRAPHIE — les fichiers, pas seulement les noms      1.119 · 05/09
   ---------------------------------------------------------------------
   CONSTAT DU 05/09 : ce fichier NOMMAIT --serif et --sans sans servir
   aucune police. Les 29 fronts du parc allaient chercher Inter et
   DM Serif Display chez Google (fonts.googleapis.com). Deux motifs de
   les rapatrier : le parc doit tenir sans reseau sortant, et le CDN
   transmet l'IP du visiteur a un tiers — S-PACE est centre agree
   LCB-FT n° 2023-02.

   TEMPS 1 (ici) : on POSE les @font-face. Le CDN reste en place dans
   les 29 fronts. TEMPS 2, plus tard : on retire les references.
   Jamais les deux d'un coup — un @font-face mal forme et une balise
   retiree le meme jour donnent un parc en Times New Roman sans qu'on
   sache lequel des deux a faute.

   INTER EST UNE POLICE VARIABLE — un seul fichier par sous-ensemble
   couvre 300 a 800. Le parc declare 300, 400, 500, 600, 650, 700, 800
   et `bold` : tout est couvert, sans choisir de graisses ni empiler
   sept fichiers statiques. DM Serif Display n'a qu'une graisse (400).

   unicode-range : le navigateur ne telecharge un fichier QUE si la page
   contient un caractere de sa plage. Une page francaise ne tire donc
   que « latin » — Inter 48 Ko + DM Serif 24 Ko = 72 Ko. Les quatre
   autres fichiers (latin-ext, italiques) sont poses sans etre servis.

   PROVENANCE : woff2 telecharges depuis fonts.gstatic.com le 05/09,
   Inter v20 et DM Serif Display v17. Licence SIL OFL — l'hebergement
   local est permis. woff2 seul : tous les navigateurs modernes le
   lisent, ni woff ni ttf ne sont necessaires.

   font-display:swap — le texte s'affiche IMMEDIATEMENT dans la police
   de repli puis bascule. Sans lui (defaut `auto`), le texte reste
   invisible pendant le chargement.

   URL RELATIVES (fonts/...) : elles se resolvent contre l'URL de CE
   fichier, pas contre celle de la page. Une app servie sous /scare/
   ou /sresa/ tire donc bien /fonts/... — et le socle reste deplacable.

   CES DIX BLOCS EXISTENT AUSSI DANS /fonts/polices.css (au disque :
   /var/www/vigie/fonts/polices.css). Cette feuille-la ne porte QUE des
   @font-face — aucun jeton, aucune regle, donc aucune surface de
   collision — et c'est ainsi qu'elle sert les 10 pages du parc qui ne
   chargent pas le socle (mesure du 09/09 : Vigie, S-EDL, S-CARBONE,
   S-LIVRET, l'admin S-CLIENT, le badge S-PRESENCES, client.s-pace.fr).
   Leur poser /socle.css a la place serait un changement de mise en page
   deguise en chantier de polices : P2 l'a mesure nuisible (61 boutons
   changeraient sur le seul S-EDL).

   TOUTE MODIFICATION DES DIX BLOCS CI-DESSOUS DOIT ETRE REPORTEE LA-BAS,
   aux url() pres : relatives ici (fonts/...), absolues la-bas
   (/fonts/...). C'est la seule difference entre les deux jeux — les dix
   font-family, font-weight et unicode-range sont identiques au caractere
   pres, et doivent le rester.

   Ce n'est pas theorique : le 05/09 a 18h26 ces blocs etaient six, le
   06/09 a 09h31 ils sont passes a dix (IBM Plex Mono 400 et 500).
   polices.css est ne cinq heures apres. Le geste qui ajoute une graisse
   commence ICI — d'ou cet avertissement, place ou il sera lu.

   polices.css epingle le md5 de CE fichier ; l'inverse n'existe pas, et
   ne doit pas exister : deux fichiers qui s'epinglent mutuellement ne
   peuvent plus evoluer. Modifier ce fichier rend donc cet epinglage-la
   faux — le mettre a jour fait partie du geste.
   ===================================================================== */

/* ---- Inter (texte) — variable, 300 a 800 ---- */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(fonts/inter-v20-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(fonts/inter-v20-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- DM Serif Display (titres) — une seule graisse, 400 ---- */
@font-face {
  font-family: 'DM Serif Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/dmserifdisplay-v17-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'DM Serif Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/dmserifdisplay-v17-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- DM Serif Display italique — 7 des 29 fronts la demandent au CDN.
        Aucune declaration italique du parc ne vise un titre serif au
        05/09 ; elle est posee pour que le TEMPS 2 ne change rien, et
        n'est telechargee que si un element serif devient italique. ---- */
@font-face {
  font-family: 'DM Serif Display';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/dmserifdisplay-v17-italic-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'DM Serif Display';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/dmserifdisplay-v17-italic-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- IBM Plex Mono (chiffres tabulaires) — 400 et 500     1.119 · 06/09
        Chasse fixe : heures, montants, pourcentages, quantites. S-RESA en
        porte les 18 usages du parc au 06/09 ; c'est aussi la police des
        etiquettes de la maquette S-CARE, d'ou son entree dans le socle
        plutot que dans une seule application.

        PAS DE VARIABLE — contrairement a Inter, Google rend HTTP 400 sur
        wght@100..700 pour cette famille : il faut des fichiers statiques,
        donc choisir. Recensement des 18 usages au 06/09 : quatorze
        calculent 400 (defaut du body, aucun conteneur ne pose de graisse),
        quatre calculent 500 — .step .circle, .hc-block .num, .ac-tourne b
        (explicites) et .equip-tag .badge-pret (herite de .equip-tag).
        Les deux graisses sont donc posees, et elles seules.

        CORRECTION ASSUMEE (Olivier, 06/09) : le CDN ne declarait QUE le
        500 (wght@500). Les quatorze usages en 400 etaient donc rendus
        depuis la face 500, plus gras que ne le demandait leur CSS. Poser
        un vrai 400 les allege : c'est un changement VISIBLE sur S-RESA,
        voulu. La chasse etant fixe, aucune largeur ne bouge — seule
        l'epaisseur du trait change.

        PROVENANCE : woff2 telecharges depuis fonts.gstatic.com le 06/09,
        IBM Plex Mono v20. Licence SIL OFL. Meme patron que le 05/09 :
        woff2 seul, font-display:swap, URL relatives. ---- */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/ibmplexmono-v20-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/ibmplexmono-v20-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(fonts/ibmplexmono-v20-500-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(fonts/ibmplexmono-v20-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root{
  /* ---- IDENTITÉ (charte — inchangée) ---- */
  --bordeaux:#920157;
  --rose:#bc5790;
  --bordeaux-fonce:#871a58;      /* survol de l'action principale */
  --fond:#fdf5f9;
  --encre:#1E1E1E;

  /* ---- FONCTIONNEL (palette d'alerte — §25) ----
     Chaque cran : teinte (texte/plein) · fond · bord. Contrastes AA vérifiés. */
  --alert:#bb2a17;  --alert-bg:#fbe9e6;  --alert-bd:#f1c6bf;   /* bloquant · 6,08:1 · ΔE00 27 / bordeaux */
  --warn:#8a5600;   --warn-bg:#fdf2df;   --warn-bd:#f0d9a8;    /* avertissement · 6,16:1 */
  --ok:#2f7d4f;     --ok-bg:#e9f2ec;     --ok-bd:#bcdcc8;      /* statut confirmé · 5,04:1 */
  --note:#5f6270;   --note-bg:#eef0f3;   --note-bd:#d5d9e0;    /* note neutre (remplace le prune) · 6,06:1 */

  /* Alias « sévérité » — mêmes valeurs, nommage orienté échelle d'attention.
     Utilisés par les tuiles du dashboard (cran bloc / avert). */
  --sev-bloc:#bb2a17;  --sev-bloc-bg:#fbe9e6;  --sev-bloc-bd:#f1c6bf;
  --sev-avert:#8a5600; --sev-avert-bg:#fdf2df; --sev-avert-bd:#f0d9a8;

  /* ---- SURFACES & LIGNES ---- */
  --papier:#ffffff;
  --surface:#f7ecf3;
  --surface-2:#f1e2ec;

  /* ---- FILET BORDEAUX (§25 V3) — l'identité passe par le trait, pas par l'aplat.
     Le filet gris devient un ALIAS du filet bordeaux : une seule valeur change,
     aucun appel `var(--ligne)`/`var(--ligne-forte)` existant n'est à réécrire.
     Additif et rétro-compatible ; se propage à toute la suite (dont S-RESA). */
  --filet:rgba(146,1,87,.14);          /* remplace #ecd8e4 partout */
  --filet-fort:rgba(146,1,87,.24);     /* champs, boutons 2ndaires, séparateurs (ex-#d9bccd) */
  --filet-faible:rgba(146,1,87,.09);   /* lignes internes de widget */
  --ligne:var(--filet);                /* ALIAS rétro-compatible (ex-#ecd8e4) */
  --ligne-forte:var(--filet-fort);     /* ALIAS rétro-compatible (ex-#d9bccd) */
  --encre-2:#5f5259;
  --encre-3:#8d7f87;

  /* ---- DENSITÉ DE TUILE (§25 V3) — deux pas, jamais trois ---- */
  --pas-large:13px 16px 12px;          /* tuile appelant une action */
  --pas-serre:10px 13px 11px;          /* tuile informative */

  /* ---- ÉCHELLE D'ESPACEMENT ---- */
  --e1:2px; --e2:4px; --e3:6px; --e4:8px; --e5:12px; --e6:16px; --e7:24px;

  /* ---- RAYONS ---- */
  --r1:3px; --r2:5px; --r3:8px;

  /* ---- RAIL ---- */
  --bordeaux-rail:#920157;             /* aplat du rail de navigation */

  /* ---- TYPOGRAPHIE ---- */
  --serif:"DM Serif Display", Georgia, serif;   /* titres */
  --sans:"Inter", system-ui, -apple-system, sans-serif;  /* texte */
}

/* =====================================================================
   COMPOSANT PARTAGÉ — BOUTON                                  2026-08-28
   ---------------------------------------------------------------------
   1re extension du socle au niveau COMPOSANT (jusqu'ici : jetons seuls +
   socle-session.js pour le comportement). Fait suite à la cartographie du
   26/08 (12 apps alignées socle, 12 mises en page différentes malgré
   des jetons communs) qui propose le bouton comme 1er composant partagé —
   pas la barre de nav, qui couple 3 mécanismes de routage incompatibles
   à réconcilier avant même le CSS.

   Recensement préalable (13 écrans / 8 apps vanille) : 2 à 27 variantes
   de bouton selon l'écran, 0 écran avec un focus clavier visible sur un
   bouton, 44px de hauteur atteint uniquement sur les 3 écrans publics/
   tactiles (staff = souris/clavier, jamais 44px, probablement volontaire
   mais jamais écrit nulle part).

   Couvre les 5 variantes retenues (primaire, secondaire, danger, texte
   seul, icône seule) + les 3 crans d'action du §25 :
     • anodin     → une variante seule suffit (.btn ou .btn-primary)
     • fréquent   → undo ~6s : le lien "Annuler" du toast réutilise
                    .btn-text, aucune classe dédiée à l'undo
     • conséquent → confirmation EN LIGNE (pas de modale) : .btn-group
                    associe un .btn seul ("Annuler") et un .btn-danger
                    ("Confirmer"), affichés à la place du déclencheur

   .btn SEUL (sans modificateur de couleur) EST le traitement "secondaire"
   — volontairement PAS de classe .btn-secondary séparée : S-CLEAN avait
   déjà 2 variantes concurrentes pour ce même rôle (.btn-outline et
   .btn-ghost) ; ne pas reproduire ce doublon ici.

   N'AJOUTE AUCUN JETON : consomme uniquement --bordeaux/--bordeaux-fonce/
   --papier/--fond/--filet-fort/--alert/--r3/--e3..e6/--sans déjà déclarés
   ci-dessus. Aucun `--x: var(--x, …)` — pas de cycle.

   Hors périmètre de ce composant (constats du recensement, non traités
   ici) : pas de variante "succès" (utilisée par endroits pour valider,
   mais absente de la liste des 5 variantes retenues) ; pas de traitement
   "sur surface de marque" (bouton clair sur fond bordeaux, ex. bouton de
   déconnexion d'une topbar) — deux besoins réels, à discuter avant une
   généralisation. .btn-text n'impose pas 44px (approprié en lien inline
   dans un tableau desktop ; insuffisant si un jour seule action d'un
   toast sur écran tactile — à surveiller, pas vérifié ici).
   ===================================================================== */

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--e4);
  font-family:var(--sans); font-size:14px; font-weight:600;
  padding:10px var(--e6);
  min-height:44px;
  border-radius:var(--r3);
  border:1px solid var(--filet-fort);
  background:var(--papier); color:var(--encre);
  cursor:pointer; white-space:nowrap;
  transition:background .15s, border-color .15s, color .15s, transform .05s;
}
.btn:hover{ border-color:var(--bordeaux); background:var(--fond); color:var(--bordeaux); }
.btn:active{ transform:translateY(1px); }
.btn:focus-visible{ outline:2px solid var(--bordeaux); outline-offset:2px; }
.btn:disabled{ opacity:.5; cursor:not-allowed; transform:none; }

/* ── LE TEXTE QUI DISPARAISSAIT AU SURVOL ──────────────────── 2026-09-15 ──
   .btn:hover (0,2,0) pose fond/filet/couleur du secondaire et l'emporte sur
   .btn-primary et .btn-danger (0,1,0) ; leurs :hover ne reposaient pas ce qui
   manquait. Mesuré au banc (getComputedStyle, transition finie) :
     • primaire : fond et filet reposés, PAS la couleur → texte #920157 sur
       #871a58 (1,02:1), le libellé disparaissait — 141 primaires, 9 apps ;
     • danger : filter seul → fond --fond, filet et texte bordeaux : le
       destructif devenait un secondaire au survol — 14 danger, 5 apps.
   Depuis le 28/08 (3a78ac9). Correction = déclarations AJOUTÉES, aucune
   existante ne change : color:#fff au primaire (9,06:1) ; background,
   border-color (--alert) et color:#fff au danger (#e6e6e6 sur #a82615, 5,7:1
   avec le filter). :focus-visible/:active/:disabled ne touchent pas ces
   propriétés : pas le même défaut. Le survol du primaire ne tient plus qu'au
   fond (#920157 → #871a58, ΔE00 2,5, sous les 4,9 du .btn nu) : perceptible
   mais faible — à trancher, pas élargi ici. */
.btn-primary{ background:var(--bordeaux); color:#fff; border-color:var(--bordeaux); }
.btn-primary:hover{ background:var(--bordeaux-fonce); border-color:var(--bordeaux-fonce); color:#fff; }

.btn-danger{ background:var(--alert); color:#fff; border-color:var(--alert); }
.btn-danger:hover{ filter:brightness(.9); background:var(--alert); border-color:var(--alert); color:#fff; }
.btn-danger:focus-visible{ outline-color:var(--alert); }

/* ── LA FORME DU DESTRUCTIF (§25) ─────────────────────────── 2026-09-05 ──
   Constat du 05/09 : .btn-danger et .btn-primary sont deux APLATS PLEINS
   qui ne different que par la TEINTE. Mesure : #bb2a17 (L=0,1228) et
   #920157 (L=0,0682) sont a 1,46:1 de contraste l'un de l'autre — tres en
   dessous du 3:1 exige pour distinguer deux elements non textuels. En
   niveaux de gris, ou pour une deuteranopie/protanopie, les deux boutons
   sont LE MEME OBJET. Or le §25 demande « #bb2a17 ET une forme ».

   La forme est posee par la CLASSE, jamais par le libelle : aucun HTML
   applicatif n'est a modifier, et la regle devient automatique. C'est
   exactement ce que le constat du 05/09 reproche au socle — « il declare
   --alert, il ne fournit pas la forme ».

   UN TRIANGLE, parce qu'il domine deja l'usage : S-CARE le pose en
   ::before sur ses puces d'echeance et de priorite. Meme idiome.

   DESSINE EN CSS, PAS ecrit en caractere U+25B2. Mesure le 05/09 : Inter
   NE CONTIENT PAS U+25B2 — le glyphe y mesure exactement la largeur qu'il
   mesure avec une police inexistante, il retombe donc systematiquement sur
   la police du SYSTEME. Un caractere dependrait d'une police que le socle
   ne fournit pas (0 @font-face ici ; Inter vient d'un CDN — cf. 1.119) :
   taille et alignement variables par plateforme, et tofu la ou le systeme
   n'a pas de police a symboles. Une forme en bordures est autonome et
   suit currentColor.

   ACCESSIBILITE — second motif du choix, decisif : `content:''` ne produit
   AUCUN texte pour un lecteur d'ecran, la ou `content:'▲'` serait annonce
   (« triangle pointant vers le haut, Supprimer »). aria-hidden ne peut pas
   se poser sur un pseudo-element : ne pas ecrire de caractere est le SEUL
   moyen de rester muet. La forme est purement visuelle ; le libelle reste
   seul porteur du sens.

   Le pseudo devient un enfant flex de .btn : le gap de 8px l'espace du
   libelle et min-height:44px est inchange (mesure : 44px avant / 44px
   apres, largeur 100,5 -> 118,5). EXCEPTION .btn-icon : largeur FIXE de
   44px (36px en .btn-sm), padding 0 et gap 0 — une forme de plus y
   deborderait. Les boutons destructifs a icone seule restent donc SANS
   forme, leur glyphe en tient lieu : a trancher a part.
   ───────────────────────────────────────────────────────────────────── */
.btn-danger::before{
  content:'';
  flex:none;
  width:0; height:0;
  border-left:5px solid transparent;
  border-right:5px solid transparent;
  border-bottom:9px solid currentColor;
}
.btn-danger.btn-icon::before{ display:none; }

.btn-text{
  background:transparent; border-color:transparent; color:var(--bordeaux);
  padding:var(--e3) var(--e4); min-height:auto;
}
.btn-text:hover{ background:transparent; text-decoration:underline; }

.btn-icon{ padding:0; width:44px; gap:0; }

.btn-sm{ padding:var(--e3) var(--e5); min-height:36px; font-size:13px; }
.btn-sm.btn-icon{ width:36px; min-height:36px; }

.btn-group{ display:inline-flex; align-items:center; gap:var(--e4); flex-wrap:wrap; }

/* =====================================================================
   COMPOSANT PARTAGÉ — BARRE D'ONGLETS                         2026-09-10
   ---------------------------------------------------------------------
   2e extension du socle au niveau COMPOSANT, après le bouton (28/08).
   Le bouton avait été choisi CONTRE la barre, et la raison est écrite
   ci-dessus (§ bouton) : « pas la barre de nav, qui couple 3 mécanismes
   de routage incompatibles à réconcilier avant même le CSS ». Cette
   raison tient toujours — et elle ne s'applique pas à ce bloc, qui ne
   touche PAS au routage : aucun href, aucun onclick, aucune classe
   posée par un routeur. Uniquement la FORME. Le couplage reste entier
   pour qui voudra un COMPOSANT de barre ; il ne l'est pas pour du CSS.

   EXTRAIT, PAS INVENTÉ — c'est le point.
   La remesure du 07/09 a compté 18 barres pour 20 applications et
   29 écrans, sans une ligne partagée : ce fichier ne portait AUCUNE
   règle de barre (ses 7 classes sont toutes le bouton ; ses occurrences
   de « nav » sont des commentaires et --bordeaux-rail). Mais TROIS
   écrans avaient déjà réécrit la même règle, chacun de son côté, et
   deux d'entre eux la NOMMENT mot pour mot dans leur propre CSS :

     • S-MAIL  — l'original, en style inline React (NavBar, App.jsx) :
                 #fff, borderBottom 1px, padding 8px 16px 0, gap 2 ;
                 onglet minHeight 44, padding 0 14px, marginBottom -1,
                 borderBottom 2px, 14px/600, roue en marginLeft:auto.
     • S-CLEAN — « TABS PRINCIPAUX — barre socle (modèle S-MAIL) :
                 blanc, filet bas, onglets >=44px, 14px semi-gras, actif
                 souligné 2px (margin-bottom:-1px) ».
     • S-RESA  — « Barre de navigation harmonisée sur la FORME S-MAIL :
                 fond blanc, filet bas, onglets >=44px soulignés à
                 l'actif (#920157) ».

   Trois réécritures indépendantes de la même règle. Et elles divergent
   ENCORE, sur deux propriétés exactement : gap 2 (MAIL, RESA) / 4
   (CLEAN) ; padding d'onglet 0 14px (MAIL, CLEAN) / 0 10px (RESA).
   Ce bloc tranche une valeur par propriété, et ne laisse variable que
   ce qui a une raison MESURÉE de varier (voir « les trois réglages »).

   CE QUE LE BLOC FAIT BOUGER AUJOURD'HUI : rien.
   Mesure du 10/09 : aucun fichier du parc — ni HTML servi, ni CSS, ni
   bundle React — ne porte la classe `barre-onglets` ni la classe
   `onglet` (0 occurrence sur les 20 pages qui chargent /socle.css).
   Les noms ont été choisis POUR CELA : `.tabs`/`.tab` auraient repeint
   S-PRÉSENCES, S-STOCK, S-VEILLE, S-CLIENT-ADMIN et S-LIVRET admin le
   jour de leur écriture, sans que personne l'ait demandé. Le patron est
   POSÉ, pas ADOPTÉ : migrer une application est un geste à part, qui se
   regarde à l'oeil, un écran à la fois — motif du 26/08, où P2 avait
   mesuré qu'imposer le socle au seul S-EDL changeait 61 boutons.

   AUCUN `.active` NU. La règle d'actif s'écrit `.onglet.active` : elle
   ne peut donc atteindre que ce qui porte déjà `.onglet`. Un `.active`
   seul, dans un fichier chargé par 20 pages, serait une bombe.

   ---- LES HAUTEURS, ET POURQUOI CELLE-CI EST 44 ----------------------
   Deux hauteurs seulement sont DÉCLARÉES sur une barre d'onglets du
   parc : 44 (S-MAIL, S-CLEAN x2, S-RESA, S-HEAT client) et 51 (S-CARE,
   apparue le 04/09 entre 12:18 et 14:57 — dans l'écran le plus retravaillé
   du parc : la divergence ne s'est pas arrêtée, elle s'est produite là).
   Les treize autres barres ne déclarent AUCUNE hauteur : elles la
   subissent de leur padding, en 11 couples distincts (de 8/14 à 14/20).
   44 n'est donc pas une moyenne : c'est la seule valeur qu'un écran ait
   choisie plus d'une fois — et c'est déjà le min-height de `.btn`
   ci-dessus. Une seule cible tactile pour toute la suite.

   Sous `box-sizing:border-box` — que portent les huit écrans vanille
   mesurés et le miroir S-MAIL — `min-height:44px` EST la hauteur totale,
   filet d'actif compris ; sans ce reset elle vaut 46. Le socle ne pose
   pas de reset global (`.btn` n'en pose pas davantage) et n'en pose pas
   ici : la page hôte tranche, comme aujourd'hui.

   ---- LES TROIS RÉGLAGES, ET RIEN D'AUTRE ----------------------------
   Trois propriétés varient pour une raison écrite ailleurs qu'ici. Elles
   se lisent avec un repli et NE SONT DÉCLARÉES NULLE PART dans ce
   fichier : `var(--x, valeur)` sur un nom jamais posé n'est PAS le
   `--x: var(--x, …)` que le bloc bouton s'interdit — il n'y a pas de
   cycle, seulement un repli. Une app qui n'en pose aucun obtient la
   forme S-MAIL exacte.

     --barre-marge   gouttière horizontale du conteneur. Mesurée de 8px
                     (S-EDL) à 28px (S-RESA, S-CARE) : c'est la gouttière
                     de PAGE de chaque app, pas une dérive. Repli 16px.
     --barre-fond    fond du conteneur. Repli --papier. S-CLEAN tient sa
                     SOUS-barre (bâtiments) sur --fond pour la distinguer
                     du premier niveau : c'est délibéré, ça se garde.
     --onglet-marge  padding horizontal de l'onglet. Repli 14px (MAIL,
                     CLEAN). S-RESA descend à 10px et dit pourquoi : ses
                     8 onglets doivent tenir dans l'iframe Vigie (992px
                     intrinsèques pour 1168px disponibles à 1240px).

   CE QUI NE VARIE PAS, et c'est le fond du geste : l'épaisseur du
   soulignement. Le parc en porte TROIS pour le même signal — 2px (MAIL,
   CLEAN, RESA, PRÉSENCES, ATTEST-adm, EDL, CONTENT), 2.5px (CLIENT-ADM,
   HEAT client), 3px (CARE, STOCK, CARBONE). Trois épaisseurs ne disent
   pas trois choses ; elles disent la même, trois fois. Le modèle nommé
   dit 2. Ce bloc dit 2.

   UN SEUL ÉCART ASSUMÉ AVEC LES TROIS SOURCES : l'espace entre l'émoji
   et le libellé. S-MAIL et S-CLEAN posent 7px, S-RESA 6px. 7px n'existe
   dans aucun jeton du socle ; le bloc prend --e3 (6px) et reste sur
   l'échelle d'espacement. Écart maximal mesuré : 1px sur deux écrans.

   ---- CE QUI N'EST PAS ICI, ET POURQUOI ------------------------------
   • La pastille de compteur. S-MAIL, S-CLEAN et S-CARE en portent une
     chacun, avec trois couleurs et trois formes : il n'y a pas de
     convergence à extraire, donc rien à poser. À traiter à part.
   • `position:sticky` (S-CARBONE, S-PRET, S-PRÉSENCES) : trois écrans
     sur dix-huit, et cela dépend de la mise en page de la page hôte.
   • Les pilules (S-LIVRET admin, S-HEAT admin, S-PRET, S-ASSET), les
     rails verticaux (S-VEILLE, Vigie) et la barre BASSE de S-CLIENT :
     ce ne sont pas des variantes de cette forme, ce sont d'AUTRES
     formes. Les absorber donnerait le patron que personne n'adopte.
   • `.actif` (S-CARBONE) n'est pas posé en alias de `.active` :
     S-CARBONE ne charge pas le socle et porte un vocabulaire privé,
     assumé (--muted, --gris, --bord, --card).

   N'AJOUTE AUCUN JETON : consomme --papier, --filet, --bordeaux,
   --encre-2, --sans, --e1, --e3, --e4, --e6, tous déclarés ci-dessus.

   MODIFIER CE FICHIER REND FAUX L'ÉPINGLAGE DE /fonts/polices.css
   (cf. l'avertissement en tête, l.82-85). Corrigé dans le même geste,
   le 10/09 : polices.css l.37 passe de f8a7fb0d au md5 d'ici.
   ===================================================================== */

.barre-onglets{
  display:flex; align-items:stretch;
  gap:var(--e1);
  padding:var(--e4) var(--barre-marge, var(--e6)) 0;
  background:var(--barre-fond, var(--papier));
  border-bottom:1px solid var(--filet);
  overflow-x:auto;                     /* défile sous ~950px, ne casse jamais */
  scrollbar-width:none; -ms-overflow-style:none;
}
.barre-onglets::-webkit-scrollbar{ width:0; height:0; display:none; }

.onglet{
  flex:none;
  display:inline-flex; align-items:center; gap:var(--e3);
  min-height:44px;
  padding:0 var(--onglet-marge, 14px);
  margin-bottom:-1px;                  /* le soulignement d'actif MANGE le filet */
  border:none; border-bottom:2px solid transparent;
  background:transparent; color:var(--encre-2);
  font-family:var(--sans); font-size:14px; font-weight:600;
  white-space:nowrap; text-decoration:none; cursor:pointer;
  transition:color .15s, border-color .15s;
}
.onglet:hover{ color:var(--bordeaux); }

/* Le focus clavier : le recensement du 26/08 relevait 0 écran sur 13 où
   il soit visible. `.btn` l'a corrigé le 28/08 avec outline-offset:2px ;
   ici l'offset est NÉGATIF, sinon le liseré déborde la barre et se fait
   rogner par overflow-x:auto. Seul écart de forme avec le bouton. */
.onglet:focus-visible{ outline:2px solid var(--bordeaux); outline-offset:-4px; }

.onglet.active,
.onglet[aria-current]:not([aria-current="false"]){
  color:var(--bordeaux); border-bottom-color:var(--bordeaux);
}
.onglet:disabled{ opacity:.5; cursor:not-allowed; }

/* Pousse l'onglet à droite (la roue « Paramètres »). Les trois écrans du
   modèle le font déjà, chacun à sa façon : marginLeft:"auto" (S-MAIL),
   .main-tab#tab-params{margin-left:auto} (S-CLEAN), .topbar-main
   .topbar-right{margin-left:auto} (S-RESA). Trois sur trois : le patron
   le porte. */
.onglet-fin{ margin-left:auto; }


/* =====================================================================
   COMPOSANT PARTAGÉ — ÉTIQUETTE                                2026-09-20
   ---------------------------------------------------------------------
   Troisième composant (bouton 28/08, barre d'onglets 10/09). EXTRAIT,
   pas conçu : c'est la forme que S-EDL nomme depuis le 14/09 — « Badges
   — le trio du socle (texte · fond · bord), forme étiquette --r2 (patron
   S-MAIL) », portail/sedl/public/index.html l.81-88 — et que S-MAIL
   porte en styles inline (smail-build/src/App.jsx l.1210, 1562, 3661 :
   fontSize 11, fontWeight 600, color T.note / background T.noteBg /
   border 1px T.noteBd, padding 2-3px 7-9px).

   CE QUI EST COMMUN aux deux sources, et que le patron reprend tel quel :
   • le TRIO : la couleur du texte, celle du fond et celle du bord sont
     les trois valeurs d'un même cran (--ok, --ok-bg, --ok-bd…) — jamais
     un fond sans bord, jamais un bord d'une autre teinte ;
   • 11px / 600, police héritée (Inter par le body) ;
   • padding --e1 --e4 (2px 8px) ;
   • un bord de 1px TOUJOURS présent, transparent tant qu'aucun cran
     n'est posé : la hauteur ne bouge pas quand le cran change.

   LA SEULE DIVERGENCE entre les deux sources : le rayon. S-MAIL arrondit
   en pilule (borderRadius:100), S-EDL en --r2 (5px — « --r2 badges et
   petites pièces », sa règle de rayons l.34). Le patron suit S-EDL : la
   seule page qui cite le patron, la seule à 0 couleur en dur, et la
   première convertie — elle doit rendre PAREIL. Le reste du parc est en
   pilule 20px SANS bord (S-STOCK, S-ATTEST admin, S-RESA confirm,
   S-CARE, S-CLIENT-ADMIN, client…) : ce n'est pas ce composant, c'est
   la forme d'avant le socle. L'adopter là-bas sera une décision
   visible, prise app par app — jamais un effet de bord de ce fichier.

   LE NOM. `.badge` a 20 pages porteuses sur 31 (57 règles) : une règle
   `.badge` ICI aurait repeint treize pages à leur prochaine ouverture
   — ce fichier est servi en Cache-Control: no-cache. `.etiquette` :
   0 occurrence comme classe sur tout /var/www le 20/09 (html, css, js,
   bundles React compris — les 13 hits du mot « etiquette » sont du texte
   ou des variables JS). Même précaution que `.tab` → `.onglet` le 10/09.
   `.etiq` existe (S-EDL, forme --r1 des types d'événement) : ce n'est
   pas la même pièce, elle n'est pas touchée.

   ÉTATS : une étiquette n'a ni « requis » ni « désactivé ». C'est un mot
   posé sur un cran. S-EDL en fait parfois un <button> ou un <a>
   (« Déposer », « Dossier de preuve ») : le composant ne l'interdit pas
   et ne pose rien pour cela (ni cursor, ni text-decoration, ni
   font-family) — la page hôte le dit, comme aujourd'hui.

   CRANS : les quatre trios fonctionnels + le trio de marque (texte
   --bordeaux, fond --surface-2, bord --filet-fort), présent tel quel
   chez S-MAIL (l.1210, « réexpédition ») et chez S-EDL (.b-occupe).

   N'AJOUTE AUCUN JETON : consomme --e1, --e4, --r2, les trios
   --ok/--warn/--alert/--note, --bordeaux, --surface-2, --filet-fort,
   tous déclarés ci-dessus. gap:3px est la valeur relevée (aucun pas de
   l'échelle ne vaut 3) — même statut que les 14px et 44px de la barre.

   POSÉ, PAS ADOPTÉ : au 20/09, S-EDL seule porte `.etiquette` (ses six
   crans locaux .b-* restent chez elle : quatre recouvrent les trios
   d'ici, .b-pdf (--surface) et .b-none (--encre-3) n'ont pas
   d'équivalent). Les autres pages gardent leur `.badge` local et ne
   voient rien. Vigie, qui recopie les jetons en ligne sans charger ce
   fichier, ne reçoit pas ce bloc : à recopier chez elle le jour où elle
   en a l'usage.

   MODIFIER CE FICHIER REND FAUX L'ÉPINGLAGE DE /fonts/polices.css
   (cf. l.82-85) : polices.css l.37 est mise à jour dans le même geste.
   Elle disait encore 300e825c alors que le socle était 19a58b81 depuis
   le 15/09 (correctif du survol) — l'oubli est rattrapé ici.
   ===================================================================== */

.etiquette{
  display:inline-flex; align-items:center; gap:3px;
  padding:var(--e1) var(--e4);
  border:1px solid transparent; border-radius:var(--r2);
  font-size:11px; font-weight:600;
}
.etiquette-ok{       color:var(--ok);       background:var(--ok-bg);     border-color:var(--ok-bd); }
.etiquette-warn{     color:var(--warn);     background:var(--warn-bg);   border-color:var(--warn-bd); }
.etiquette-alert{    color:var(--alert);    background:var(--alert-bg);  border-color:var(--alert-bd); }
.etiquette-note{     color:var(--note);     background:var(--note-bg);   border-color:var(--note-bd); }
.etiquette-bordeaux{ color:var(--bordeaux); background:var(--surface-2); border-color:var(--filet-fort); }

/* =====================================================================
   COMPORTEMENT PARTAGÉ — BARRE COLLANTE                        2026-09-23
   ---------------------------------------------------------------------
   UN SEUL CHANGEMENT : la barre de navigation reste visible quand on
   fait défiler l'écran. Aucune couleur, aucune taille, aucun espacement
   ne bouge : au repos (écran en haut), la page rend au pixel près ce
   qu'elle rendait avant. Arbitré par Olivier le 23/09 : collante
   seulement — la barre compacte viendra avec le projet tablette.

   POURQUOI UNE CLASSE À PART, et pas `position:sticky` dans
   `.barre-onglets` ci-dessus : le bloc barre l'a écrit le 10/09 —
   « cela dépend de la mise en page de la page hôte ». Mesuré le 23/09 :
   • chez S-RESA, `.barre-onglets` est l'UNIQUE enfant d'un conteneur
     `.app` à sa taille : collante, elle ne collerait à rien — c'est le
     conteneur qui doit porter la classe ;
   • chez S-CONTENT, `.barre-onglets` est un onglet INTERNE à une carte
     (overflow:hidden), pas la navigation de l'app ;
   • chez S-PRÉSENCES (nav 56px), S-CLEAN (header 60px) et S-CARE
     (header 64px), un bandeau collant existe DÉJÀ au-dessus de la
     barre : une seconde bande collante empilerait ~110px ;
   • `.param-rail` (S-CARE ×3) porte `.barre-onglets` sans être une
     barre de page.
   Une règle dans `.barre-onglets` aurait donc fait coller 13 barres sur
   8 apps le jour même (fichier servi en no-cache), dont une moitié à
   contresens. La classe est posée sur l'élément QUI DOIT COLLER, app par
   app, geste visible — même précaution que `.onglet` (10/09) et
   `.etiquette` (20/09). Nom libre : 0 occurrence de `barre-collante` sur
   tout /var/www le 23/09.

   CE QUE LA RÈGLE POSE :
   • position:sticky; top:0 — et non `fixed` : l'élément garde sa place
     dans le flux, rien ne se glisse dessous tant que l'écran est en
     haut, aucune marge à réserver en tête de page. Dans l'iframe Vigie
     (.app-iframe height:100%), chaque app défile dans son propre
     document : la barre colle au haut de l'iframe.
   • z-index:80 — au-dessus du contenu qui défile (menus déroulants
     S-RESA 60, en-têtes de calendrier 2, listes d'autocomplétion 10),
     au-dessous de TOUT ce qui doit la recouvrir : fenêtres de S-STOCK
     (100), fond et popover du calendrier S-RESA (90, 100), fenêtres
     S-RESA (120, 200, 1000). Relevé sur les pages converties le 23/09.
   • scroll-padding-top sur le document qui porte une barre collante
     — ce qui empêche un saut vers une section, un scrollIntoView() ou
     le focus clavier de poser l'élément visé SOUS la barre. N'agit
     qu'au défilement, jamais sur la mise en page. Le repli 60px est le
     cas d'origine : une barre seule (52px : --e4 + onglet 44px) et un
     pas --e4 d'air.
     24/09 — la valeur passe en réglage lu, `--hauteur-collante`, parce
     qu'un bloc collant N'A PAS TOUJOURS 52px : S-PRÉSENCES, S-CLEAN et
     S-CARE y mettent leur bandeau ET leur barre d'un seul tenant (108,
     112, 116px). Sans ce réglage, le socle retiendrait 60 et le focus
     clavier reposerait 48 à 56px sous le bloc — exactement le défaut
     que la règle est censée fermer. La page qui pose un bloc plus haut
     que 52px pose sa hauteur ; les trois pages converties le 23/09 ne
     déclarent rien et gardent 60.
   • @media print : la barre redevient statique et le décalage tombe —
     elle s'imprime une fois, en tête, et ne se répète pas.

   CE QUE LA RÈGLE NE POSE PAS : aucun fond (la barre a déjà le sien,
   --barre-fond repli --papier, opaque — c'est ce qui masque le contenu
   qui passe dessous), aucune ombre, aucune hauteur. Les éléments DÉJÀ
   collants dans une page convertie (S-RESA : .ledger top:28px,
   .param-nav top:24px) passeraient sous la barre : chaque page décale
   les siens de la hauteur de la barre, chez elle.

   ET SURTOUT PAS LA FUSION. Une page qui a déjà son propre bandeau
   collant ne reçoit pas ici une seconde couche : elle enveloppe son
   bandeau ET sa barre dans UN conteneur `.barre-collante`, et retire le
   `position:sticky` de son bandeau (S-PRÉSENCES, S-CLEAN, S-CARE, le
   24/09). Le socle ne peut pas le faire à sa place — c'est une question
   de structure HTML, différente dans chaque page. Ce qu'il fournit,
   c'est la règle unique et le réglage de hauteur.
   ⚠ PIÈGE MESURÉ LE 24/09 : retirer le `sticky` d'un bandeau lui retire
   aussi sa couche de peinture. Redevenu statique, il passe SOUS le fond
   opaque de la barre d'onglets qui le suit, et son OMBRE PORTÉE disparaît
   (12 798 pixels sur S-PRÉSENCES, écart max 32, 0 frange de lissage : une
   vraie perte, pas un artefact de rendu). Le bandeau garde donc
   `position:relative; z-index:1` — l'ordre de peinture que `z-index:100`
   lui donnait, sans aucune seconde couche collante ni aucun décalage.

   N'AJOUTE AUCUN JETON : `--hauteur-collante` est un réglage POSÉ PAR LA
   PAGE et lu ici, le même idiome que `--barre-marge` / `--onglet-marge` /
   `--barre-fond` ci-dessus, jamais déclaré dans ce fichier.
   `:has()` : Chrome/Edge 105, Safari 15.4,
   Firefox 121 — sans lui, seul le décalage des sauts manque, la barre
   colle quand même.

   MODIFIER CE FICHIER REND FAUX L'ÉPINGLAGE DE /fonts/polices.css
   (cf. l.82-85) : polices.css l.37 est mise à jour dans le même geste.
   ===================================================================== */

.barre-collante{
  position:sticky; top:0;
  z-index:80;
}
html:has(.barre-collante){ scroll-padding-top:var(--hauteur-collante, 60px); }

@media print{
  .barre-collante{ position:static; }
  html:has(.barre-collante){ scroll-padding-top:0; }
}
