/* =====================================================================
   Écrans de l'application — accueil, journal, et les modules générés par
   `make:module`. Trois des seize gabarits aujourd'hui ; les treize autres
   sont des écrans d'authentification et vivent dans auth.css.
   ===================================================================== */
/* =====================================================================
   COQUILLE DE BACK-OFFICE — portée de css/layout/{shell,sidebar,topbar}.css de
   la charte fournie, avec quatre écarts. Trois sont des corrections de contraste,
   le quatrième est une suppression.

   1. L'élément COURANT du menu portait du blanc sur l'aplat de marque : 2,07:1,
      l'état le plus important du menu et le moins lisible. Il porte désormais
      l'encre de marque, à 7,32:1.
   2. Les titres de section étaient à 3,13:1. Ils prennent l'encre douce (6,83:1)
      et se distinguent par la graisse et l'interlettrage, pas par la couleur.
   3. Le bouton de déconnexion était un `<span role="button">`. C'est un vrai
      bouton, dans un formulaire POST — la déconnexion du socle refuse le GET.
   4. La recherche globale et la cloche de notifications ne sont PAS reprises :
      le socle n'a ni l'une ni l'autre, et un champ qui ne cherche rien est un
      mensonge d'interface.

   Les items du menu sont des LIENS et non des boutons : la maquette est une
   application d'une seule page, le socle a de vraies routes.
   ===================================================================== */
.coque{display:flex;min-height:100dvh}

/* ---- Menu latéral ---- */
/* LE RAIL TIENT LA HAUTEUR DE LA FENÊTRE, JAMAIS CELLE DU DOCUMENT, et c'est `position:sticky`
   qui l'obtient — pas `height:100dvh` seul. `.coque` est un conteneur flex : son enfant s'étire
   par défaut sur toute la hauteur du CONTENU, si bien que sur une longue page le pied du rail —
   le compte et la déconnexion — descendait avec elle. Il fallait dérouler l'écran entier pour
   se déconnecter, et `.menu-nav{overflow-y:auto}` ne servait jamais puisque rien ne débordait
   plus : le rail s'allongeait au lieu de faire défiler.

   Les trois déclarations vont ensemble. `align-self:flex-start` retire l'étirement, sans quoi
   la hauteur imposée n'aurait aucun effet. `height:100dvh` — l'unité DYNAMIQUE, parce que sur
   téléphone la barre d'adresse se rétracte au défilement : avec `100vh` le pied se serait rangé
   sous le bord bas de l'écran, hors de vue, précisément là où on le cherche. Et `top:0` fait
   coller le rail pendant que la page défile à côté.

   Ce qui déborde, alors, c'est `.menu-nav` — la liste des modules et des sections — et lui seul.
   C'est le comportement voulu : la navigation défile quand un client en installe vingt, la tête
   et le pied restent posés. */
.menu{width:var(--l-menu);min-width:var(--l-menu);background:var(--nav);color:var(--sur-nav-doux);display:flex;flex-direction:column;overflow:hidden;position:sticky;top:0;align-self:flex-start;height:100dvh;transition:width var(--duree) ease,min-width var(--duree) ease}
.menu-tete{display:flex;align-items:center;gap:var(--e-3);padding:var(--e-4) var(--e-4) var(--e-3);color:var(--sur-nav);white-space:nowrap;font-weight:var(--gras-titre);font-size:var(--fs-md)}
.menu-tete img{height:var(--e-6);width:auto;display:block}
.menu-tete small{display:block;font-weight:var(--gras-menu);font-size:var(--fs-xs);color:var(--marque);letter-spacing:var(--interlettrage-etiquette);text-transform:var(--casse-etiquette)}
/* Pastille claire derrière le logo : un logo dessiné pour un fond blanc disparaît sur le
   charbon du menu. La base fournie livrait DEUX fichiers pour cette raison ; une pastille en
   demande un seul, et le client dépose le sien sans se demander sur quel fond il atterrit. */
.menu-cartouche{display:inline-flex;align-items:center;justify-content:center;background:var(--surface);border-radius:var(--radius-sm);padding:var(--e-1) var(--e-2);flex-shrink:0}
/* `overscroll-behavior:contain` : arrivé en butée de la navigation, la molette ne se reporte
   PAS sur la page derrière. Sans lui, dérouler la liste des modules jusqu'au bout emmène l'écran
   principal avec elle — on croit avoir raté sa cible alors qu'on a fait défiler autre chose. */
.menu-nav{flex:1;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;padding:var(--e-2)}
/* La base fournie employait #8C8882 ici : 3,13:1 sur le charbon, sous les 4,5:1 qu'un texte
   doit tenir. On reprend son rythme — capitales, interlettrage large, petite taille — avec
   l'encre douce du menu, qui vaut 6,83:1. */
.menu-section{font-size:var(--fs-xs);letter-spacing:var(--interlettrage-etiquette);text-transform:var(--casse-etiquette);color:var(--sur-nav-doux);padding:var(--e-4) var(--e-3) var(--e-1);white-space:nowrap;margin:0}
.menu-item{display:flex;align-items:center;gap:var(--e-3);padding:var(--e-2) var(--e-3);border-radius:var(--radius-sm);color:var(--sur-nav-doux);text-decoration:none;font-size:var(--fs-sm);font-weight:var(--gras-menu);white-space:nowrap;margin-bottom:var(--e-1)}
.menu-item svg{flex-shrink:0}
.menu-item:hover{background:var(--nav-survol);color:var(--sur-nav);text-decoration:none}
/* L'élément courant se signale par `aria-current`, que le lecteur d'écran annonce.
   Le styler sur cet attribut plutôt que sur une classe rend les deux indissociables :
   on ne peut plus mettre l'un sans l'autre. */
.menu-item[aria-current="page"]{background:var(--marque);color:var(--sur-marque-fort);font-weight:var(--gras-etiquette)}
/* Le pied porte la personne connectée, comme la base fournie : avatar, nom, rôle, et la
   sortie. DEUX cibles côte à côte et non imbriquées — la maquette posait un `role="button"`
   à l'intérieur d'un `<button>`, ce qu'aucun navigateur ne restitue : le clavier n'atteignait
   qu'une des deux, et le lecteur d'écran annonçait un bouton dans un bouton. */
.menu-pied{padding:var(--e-3);border-top:1px solid var(--nav-survol);display:flex;align-items:center;gap:var(--e-2)}
.menu-qui{flex:1;min-width:0;display:flex;align-items:center;gap:var(--e-3);padding:var(--e-2);border-radius:var(--radius-sm);color:var(--sur-nav-doux);text-decoration:none}
.menu-qui:hover{background:var(--nav-survol);text-decoration:none}
.menu-qui[aria-current="page"]{background:var(--nav-survol);color:var(--sur-nav)}
.menu-qui-texte{min-width:0}
.menu-qui-texte b{display:block;color:var(--sur-nav);font-size:var(--fs-sm);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.menu-qui-texte small{display:block;font-size:var(--fs-xs);color:var(--marque);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Bouton à icône seule, 36×36 — au-delà des 24×24 du SC 2.5.8. Son libellé est MASQUÉ À
   L'ŒIL et jamais retiré : `display:none` l'ôterait de l'arbre d'accessibilité, et le bouton
   deviendrait un dessin sans nom. C'est le même procédé que pour les libellés du menu réduit. */
.menu-sortie{display:flex;align-items:center;justify-content:center;width:var(--h-icone);height:var(--h-icone);flex-shrink:0;background:none;border:none;border-radius:var(--radius-sm);color:var(--sur-nav-doux);cursor:pointer;padding:0}
.menu-sortie .menu-libelle{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.menu-sortie:hover{background:var(--nav-survol);color:var(--sur-nav)}

/* ---- Menu réduit : icônes seules ----
   Les libellés sont MASQUÉS À L'ŒIL, pas retirés : `display:none` les ôterait de
   l'arbre d'accessibilité, et chaque lien deviendrait un dessin sans nom. */
.menu.reduit{width:var(--l-menu-reduit);min-width:var(--l-menu-reduit)}
.menu.reduit .menu-tete{justify-content:center;padding:var(--e-4) var(--e-2)}
.menu.reduit .menu-libelle,.menu.reduit .menu-marque,.menu.reduit .menu-qui-texte{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.menu.reduit .menu-item{justify-content:center;padding:var(--e-3) 0}
.menu.reduit .menu-section{height:0;padding:0;margin:var(--e-2) var(--e-3);border-top:1px solid var(--nav-survol);overflow:hidden}
.menu.reduit .menu-pied{flex-direction:column;gap:var(--e-1);padding:var(--e-2)}
.menu.reduit .menu-qui{justify-content:center;padding:var(--e-1)}

/* ---- Avatar ----
   Les initiales portent une information — elles identifient quelqu'un — donc 4,5:1 leur est
   dû. La base fournie écrivait en blanc sur l'orange : 2,07:1. L'encre ancrée de l'aplat de
   marque vaut 7,32:1 et garde la même valeur dans le lot sombre. */
.avatar{display:flex;align-items:center;justify-content:center;width:var(--h-avatar);height:var(--h-avatar);min-width:var(--h-avatar);border-radius:50%;background:var(--marque);color:var(--sur-marque-fort);font-weight:700;font-size:var(--fs-sm);flex-shrink:0;line-height:1}
.avatar.petit{width:var(--h-avatar-petit);height:var(--h-avatar-petit);min-width:var(--h-avatar-petit);font-size:var(--fs-xs)}

/* ---- Cellule d'identité dans un tableau ----
   Avatar + nom + adresse en dessous, dans une seule colonne. La base fournie fait ainsi, et
   elle a raison : une colonne « adresse » séparée double la largeur du tableau pour une
   donnée qu'on ne lit qu'en second. */
/* Une seule déclaration : elle vivait en deux morceaux à cent lignes d'écart, trace d'un
   portage par couches successives. */
.qui{display:flex;align-items:center;gap:var(--e-3);min-width:0;text-decoration:none;color:inherit}
.qui:hover{text-decoration:none}
.qui:hover .qui-texte b{color:var(--marque-encre)}
.qui-texte{min-width:0}
.qui-texte b{display:block;font-weight:600;color:var(--texte-fort)}
.qui-texte small{display:block;font-size:var(--fs-xs);color:var(--texte);font-family:var(--font-mono);overflow:hidden;text-overflow:ellipsis}
/* L'annuaire du groupe : une entrée par rattachement, l'endroit devant ses rôles, les unes sous
   les autres. Sans la marge nulle, la liste gardait les marges d'un paragraphe et chaque ligne
   de l'annuaire s'étirait d'autant. */
.rattachements-et-roles{margin:0;display:flex;flex-direction:column;gap:var(--e-1)}
/* Une entrée par ENSEMBLE de rôles : les pastilles, puis les sociétés où ils valent, sur une ligne
   qui passe à la ligne d'elle-même — « Product specialist — OPHTAZON CAMEROUN · OPHTAZON CI · … ».
   La société que la portée retient ressort en gras (`b`). */
.rattachements-et-roles li{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-1) var(--e-2)}
.rattachements-et-roles b{font-weight:var(--gras-etiquette);color:var(--texte-fort)}

/* En-tête d'écran : ce qu'on regarde à gauche, ce qu'on peut faire à droite. La rangée est
   `flex-wrap` pour que sur un écran étroit l'action descende au lieu de déborder. */
.entete{display:flex;align-items:center;gap:var(--e-3);flex-wrap:wrap;margin-bottom:var(--e-4)}
.entete-compte{font-weight:600;color:var(--texte-fort);margin-right:auto}
/* Un titre dans l'entête pousse l'action au bord droit — la rangée « ce qu'on regarde à gauche,
   ce qu'on peut faire à droite » que le vocabulaire de composants promet. */
.entete h2{margin-right:auto}
/* Un repli EN TÊTE — « Comment marchent les rôles » — prend la place du titre, le geste à droite. */
.entete>details{margin-right:auto}

/* ---- Colonne principale ---- */
.principal{flex:1;display:flex;flex-direction:column;min-width:0}
/* `flex-wrap` : sans lui, le titre et le sélecteur d'organisation restent sur une ligne et
   débordent sous 880px — la page se met alors à défiler en largeur, ce que la feuille interdit
   explicitement plus bas. Le formulaire passe à la ligne plutôt que de pousser le contenu hors
   cadre. La hauteur, elle, vient du jeton `--h-barre` de la ligne « paramètres » : une valeur
   écrite deux fois finit par diverger. */
.barre{background:var(--surface);border-bottom:1px solid var(--ligne);padding:0 var(--e-6);min-height:var(--h-barre);display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-4)}
.barre-titre{font-size:var(--fs-lg);font-weight:700;margin:0}
/* Le sélecteur d'organisation, poussé à droite. Aucune couleur littérale : tout vient de
   tokens.css, et HabillageTest échoue si une valeur y réapparaît.

   Pas de règle de focus ici : `base.css` en pose une pour tout élément focalisable, avec le
   jeton `--focus` que certaines surfaces redéfinissent pour que l'anneau les suive. En écrire
   une seconde figerait la couleur hors de ce mécanisme.

   `min-width:0` : sans lui, un `<select>` refuse de se comprimer sous la largeur de sa plus
   longue option et pousse la barre hors cadre. */
.barre-organisation{display:flex;align-items:center;gap:var(--e-2);margin-left:auto}
/* `nowrap` : l'étiquette dit « Vous travaillez dans » depuis le vocabulaire du 2026-09-14, trois
   mots là où « Organisation » n'en faisait qu'un. Comprimée, elle passait à la ligne DANS son
   span à 390 px, à côté d'un nom resté sur une ligne ; c'est le NOM qui doit céder. */
.barre-organisation-etiquette{font-size:var(--fs-sm);color:var(--texte);white-space:nowrap}
.barre-organisation-active{font-size:var(--fs-sm);font-weight:600;color:var(--texte-fort)}
/* Ce qui vit SOUS la société, en secondaire : le chemin reste entier, mais la société se lit
   d'abord. Aucune abréviation — la barre porte `flex-wrap`, un chemin long passe à la ligne au
   lieu de déborder, et couper le milieu reviendrait à décider pour un client qu'on ne connaît
   pas que ce segment est du remplissage. Voir `OrganisationExtension::cheminEnDeux()`. */
.barre-organisation-reste{font-size:var(--fs-sm);color:var(--texte)}
/* LE MENU DÉROULANT — un composant de la vitrine (`menu`). Un `<details>` natif : le résumé se
   présente comme un bouton — la même forme que `.edition>summary` —, et le panneau se déroule
   par-dessus la page, ancré à droite du résumé (`.a-gauche` pour l'ancrer à gauche). Les
   entrées sont des boutons d'envoi ou des liens : pleine largeur, alignés à gauche, l'entrée
   courante en gras et cochée par `aria-current`. Rien ici ne dépend d'un script — menu-deroulant.js
   n'ajoute que la fermeture au clic à côté et sur Échap. Le sélecteur d'organisation de la
   barre en est une instance : `.barre-organisation` ne règle que sa place dans la barre. */
.menu-deroulant{position:relative;display:inline-block}
.menu-deroulant>summary{display:inline-flex;align-items:center;gap:var(--e-2);
  min-height:var(--h-controle-sm);padding:0 var(--e-3);
  border:1px solid var(--bord);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--texte-fort);
  font:var(--fs-sm)/1.2 var(--font);cursor:pointer;list-style:none}
.menu-deroulant>summary::-webkit-details-marker{display:none}
.menu-deroulant>summary::after{content:"\203A";content:"\203A" / "";line-height:1;color:var(--texte);
  transform:rotate(90deg);transition:transform var(--duree)}
.menu-deroulant[open]>summary::after{transform:rotate(-90deg)}
.menu-deroulant>summary:hover{border-color:var(--marque-encre)}
/* `.grand` : la taille d'un bouton ORDINAIRE (`.btn`) — pour un menu posé à côté de boutons
   ordinaires, dans le coin d'un bandeau. Le résumé, par défaut, a la taille d'un `.btn.petit` : sur
   la fiche d'un utilisateur, « Plus » paraissait plus petit qu'« Ajouter une exception » (le user,
   2026-09-29). Même règle que les boutons : la taille se choisit, elle ne se devine pas. */
.menu-deroulant.grand>summary{min-height:var(--h-controle);padding:0 var(--e-4);font:var(--gras-etiquette) var(--fs-base)/1.2 var(--font)}
/* `.sans-libelle` : le résumé n'est qu'un SIGNE — « ⋯ » —, carré et sans chevron, et son nom vit hors
   écran (« Gestes pour … »). Pour les gestes d'une LIGNE de tableau : un mot répété sur chaque ligne
   se lit comme une colonne de plus (fiche d'une société, le user, 2026-09-30). Carré de la hauteur
   d'un `.btn.petit`, au-delà des 24 px du SC 2.5.8. */
.menu-deroulant.sans-libelle>summary{justify-content:center;min-width:var(--h-controle-sm);padding:0;font-size:var(--fs-base);font-weight:var(--gras-etiquette)}
.menu-deroulant.sans-libelle>summary::after{content:none}
/* Au-dessus des en-têtes FIGÉS du tableau (z-index 2, 3 pour la case d'angle) : le panneau reste
   dans l'empilement de l'enveloppe (`isolation`), et retourné vers le haut il passait SOUS l'en-tête
   collant — mesuré le 2026-09-30, l'en-tête couvrait « Régler ses rôles ici ». */
.menu-deroulant.sans-libelle>.menu-deroulant-panneau{z-index:4}
/* Dans un tableau, le panneau d'un « ⋯ » vivrait DANS la zone qui défile (`.table-enveloppe`) : sur
   les dernières lignes il serait rogné, ou ferait défiler la liste pour se montrer. Il en SORT : en
   position fixe, ancré à son résumé (CSS Anchor Positioning), sous lui et aligné à sa droite, et
   retourné vers le haut quand la fenêtre manque dessous. `anchor-scope` borne le nom au menu —
   chaque ligne trouve SON résumé, sans identifiant à écrire. Et il se cache quand son résumé sort de
   la zone en défilant, plutôt que de flotter sur une autre ligne. Sans ancrage, il reste en absolu :
   entier ailleurs, rogné seulement au bas d'une zone qui défile. */
@supports (anchor-scope:all) and (position-try-fallbacks:flip-block){
  .menu-deroulant.sans-libelle{anchor-scope:--menu-ligne}
  .menu-deroulant.sans-libelle>summary{anchor-name:--menu-ligne}
  .menu-deroulant.sans-libelle>.menu-deroulant-panneau{position:fixed;position-anchor:--menu-ligne;inset:auto;
    position-area:block-end span-inline-start;margin-block:var(--e-1);position-try-fallbacks:flip-block;
    position-visibility:anchors-visible}
}
.menu-deroulant-panneau{position:absolute;right:0;top:calc(100% + var(--e-1));z-index:1;
  min-width:var(--l-selecteur-organisation);max-width:var(--l-boite-formulaire);
  padding:var(--e-2);background:var(--surface);border:1px solid var(--ligne);
  border-radius:var(--radius);box-shadow:var(--shadow)}
.menu-deroulant.a-gauche>.menu-deroulant-panneau{left:0;right:auto}
.menu-deroulant-panneau ul{list-style:none;margin:0;padding:0}
.menu-deroulant-panneau button,.menu-deroulant-panneau a{display:block;width:100%;text-align:left;white-space:nowrap;
  min-height:var(--h-controle-sm);padding:0 var(--e-3);border:0;border-radius:var(--radius-sm);
  background:none;color:var(--texte-fort);font:var(--fs-sm)/1.4 var(--font);cursor:pointer;text-decoration:none;
  line-height:var(--h-controle-sm)}
.menu-deroulant-panneau button:hover,.menu-deroulant-panneau a:hover,
.menu-deroulant-panneau button:focus-visible,.menu-deroulant-panneau a:focus-visible{background:var(--survol)}
.menu-deroulant-panneau [aria-current="true"]{font-weight:var(--gras-etiquette)}
.menu-deroulant-panneau [aria-current="true"]::before{content:"\2713\00A0";color:var(--marque-encre)}
/* 36×36 : au-delà des 24×24 du SC 2.5.8. Le bouton est POSÉ PAR JAVASCRIPT — sans
   lui, il n'existe pas plutôt que d'exister sans effet. */
.barre-repli{display:flex;align-items:center;justify-content:center;width:var(--h-icone);height:var(--h-icone);flex-shrink:0;background:none;border:1px solid var(--bord);border-radius:var(--radius-sm);color:var(--texte);cursor:pointer}
.barre-repli:hover{border-color:var(--marque-encre);color:var(--marque-encre)}
.contenu{flex:1;padding:var(--gouttiere-contenu);min-width:0}

/* Sous 880px le menu déployé prendrait les deux tiers d'un téléphone : il passe
   d'office en icônes. Pas de tiroir en surimpression — il faudrait y piéger le
   focus, et le socle n'a que quelques écrans. */
@media (max-width:879px){
  .menu{width:var(--l-menu-reduit);min-width:var(--l-menu-reduit)}
  .menu .menu-libelle,.menu .menu-marque,.menu .menu-qui-texte{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
  .menu .menu-item{justify-content:center;padding:var(--e-3) 0}
  .menu .menu-tete{justify-content:center;padding:var(--e-4) var(--e-2)}
  .menu .menu-section{height:0;padding:0;margin:var(--e-2) var(--e-2);border-top:1px solid var(--nav-survol);overflow:hidden}
  /* Sans ceci le pied garde son rembourrage de pleine largeur et déborde du rail,
     que `overflow:hidden` coupe alors en silence. */
  .menu .menu-pied{flex-direction:column;gap:var(--e-1);padding:var(--e-2)}
  .menu .menu-pied .btn{padding:var(--e-2)}
  .menu .menu-qui{justify-content:center;padding:var(--e-1)}
  /* Un peu de hauteur : la barre porte le sélecteur d'organisation, qui passe à la ligne ici. */
  .barre{padding:var(--e-2) var(--e-4)}
  /* La gouttière rétrécit — et le pied collant suit, puisqu'il lit le même token. */
  :root{--gouttiere-contenu:var(--e-4)}
  .barre-repli{display:none}
  /* Le sélecteur prend sa propre ligne : sur 320px, le titre et lui ne tiennent pas côte à côte.
     Le menu déroulé s'aligne alors à gauche et prend la largeur disponible. */
  .barre-organisation{margin-left:0;width:100%;flex-wrap:wrap}
  .barre-organisation>summary{flex-wrap:wrap}
  .barre-organisation>.menu-deroulant-panneau{left:0;right:auto;max-width:100%}
  .barre-organisation .menu-deroulant-panneau button{white-space:normal;line-height:1.4;padding-top:var(--e-2);padding-bottom:var(--e-2)}
}

.carte{background:var(--surface);border:1px solid var(--ligne);border-radius:var(--radius);box-shadow:var(--shadow);padding:var(--e-6);margin-bottom:var(--e-4)}
/* Le titre d'une carte touchait son paragraphe : `base.css` met `margin:0` sur `h2` ET sur
   `p`, et rien ne rattrapait. Un titre collé à son texte ne se lit pas « autre charte », il
   se lit « pas fini ». */
.carte>h2{font-size:var(--fs-md);font-weight:var(--gras-titre);margin-bottom:var(--e-2)}
.carte>h2+p{margin-bottom:var(--e-4);color:var(--texte)}

/* Bande de tête : le titre à gauche, les actions à droite, un filet en dessous. C'est le
   motif de la base fournie, et il résout un vrai problème — sans lui, l'action d'une carte
   n'a pas de place et finit soit au-dessus (elle flotte), soit en bas (on la cherche).
   Elle sort du rembourrage de la carte par des marges négatives : le filet doit aller d'un
   bord à l'autre, sinon il a l'air d'un trait tiré au milieu. */
.carte-tete{display:flex;align-items:center;gap:var(--e-3);flex-wrap:wrap;
  margin:calc(var(--e-6) * -1) calc(var(--e-6) * -1) var(--e-4);
  padding:var(--e-3) var(--e-6);border-bottom:1px solid var(--ligne)}
.carte-tete>h2{margin:0 auto 0 0}
/* Le titre garde sa facture quand son aide l'accompagne (`.aide-titre`, composant « aide »). */
.carte-tete>h2,.carte-tete>.aide-titre>h2{font-size:var(--fs-base);font-weight:var(--gras-titre)}
/* Le paragraphe qui présente la carte, sous sa bande de tête : la marge de `.carte>h2+p`, pour le
   même rôle. Sans elle, sur la fiche d'une société, « 5 personnes rattachées… » collait aux
   étiquettes des filtres (2026-09-28). */
.carte>.carte-tete+p{margin-bottom:var(--e-4)}

/* Tableau du journal. `overflow-x` sur le conteneur : la page elle-même ne
   défile jamais horizontalement, c'est le tableau qui le fait. */
/* L'ombre n'est pas un oubli qu'on rattrape : c'est la RÈGLE de la charte fournie — tout ce
   qui est une surface posée sur le fond de page flotte. Le socle ne l'appliquait qu'à la
   carte, si bien que le tableau avait l'air collé au fond à côté d'une carte qui décollait.

   `tabindex="0"` est posé dans les GABARITS et non ici : une zone qui défile sans pouvoir
   recevoir le focus enferme son contenu hors d'atteinte au clavier (SC 2.1.1). Chrome et
   Firefox rendent les conteneurs défilants focalisables d'office, Safari non.

   La marge basse suit la même logique de surface : hors carte, l'enveloppe est posée sur le
   fond au même titre qu'une carte, et sans elle le tableau des utilisateurs TOUCHAIT la carte
   qui le suit — les cartes-formulaires entre les deux sont retirées du flux par
   `carte-en-boite.js`. Dans une carte, `.carte .table-enveloppe` récrit `margin` en raccourci
   et l'annule : la carte est déjà la surface, sa marge fait le travail.

   POSITIONNÉE, et ce n'est pas un réglage de style : c'est ce qui garde le texte hors écran DANS
   la zone qui défile. `.hors-ecran` est en `position:absolute` sans coordonnées — sa boîte reste
   là où est le texte, mais son bloc contenant est le premier ancêtre POSITIONNÉ. Sans
   `position:relative` ici, les libellés cachés d'une cellule (« Gestes », « Retirer Paul de… »)
   prenaient le corps de la page pour bloc contenant, sortaient de la découpe de l'enveloppe et
   allongeaient le document : c'est la PAGE qui défilait en largeur, plus le tableau. Mesuré le
   2026-09-13 à 443 px de fenêtre : 608 px de document sur l'écran de rattachement, et neuf écrans
   du socle touchés, de 84 à 658 px de trop selon leur contenu (l'annuaire en tête) ; zéro sur les
   neuf avec la règle, chaque tableau défilant toujours dans son enveloppe.

   Deux contreparties, mesurées elles aussi. Ce qu'une cellule porterait en absolu est désormais
   découpé par l'enveloppe — c'était déjà vrai de tout ce qui s'ancre dans la cellule, et c'est
   pourquoi le panneau d'édition y reste dans le flux (plus bas). Et un élément positionné se peint
   APRÈS les blocs du flux, donc par-dessus ce qui glisserait sous lui : d'où la marge négative
   réservée au tableau qui ferme sa carte (`.carte .table-enveloppe:last-child`). */
.table-enveloppe{position:relative;overflow-x:auto;border:1px solid var(--ligne);border-radius:var(--radius);background:var(--surface);box-shadow:var(--shadow);margin-bottom:var(--e-4)}
table{border-collapse:collapse;width:100%;font-size:var(--fs-sm)}
th,td{padding:var(--e-3) var(--e-4);text-align:left;border-bottom:1px solid var(--ligne)}
/* L'en-tête de colonne est une ÉTIQUETTE, pas une donnée : plus petit, plus gras, en
   capitales espacées. À 13 px bas de casse il pesait autant que le contenu et la table ne se
   lisait pas d'un coup d'œil.
   Les capitales viennent d'un token — une charte qui les refuse pose `none` — et ne
   s'appliquent qu'ICI : sur un libellé de bouton ou de lien, elles deviennent un nom
   accessible que certains lecteurs d'écran restituent comme un sigle. Sur du contenu de
   tableau, le symptôme ne se produit pas. */
/* Les en-têtes PEUVENT passer à la ligne, et c'est ce qui fait tenir la table. En capitales
   espacées, « DERNIÈRE CONNEXION » mesure plus que « aujourd'hui » : interdire le retour à la
   ligne faisait réserver 180 px de colonne pour afficher 80 px de contenu. Six en-têtes ainsi
   dimensionnés consommaient la largeur que la colonne « Rattaché à » réclamait — mesuré, 47 px
   de débordement à 1280. Un en-tête sur deux lignes ne coûte qu'une fois, en haut du tableau ;
   une colonne surdimensionnée coûte à chaque ligne. */
th{background:var(--entete-bg);font-size:var(--fs-xs);font-weight:var(--gras-titre);color:var(--texte);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
/* Les en-têtes de LIGNE restent du contenu : ni capitales, ni fond. */
tbody th{background:none;font-size:inherit;font-weight:var(--gras-etiquette);color:var(--texte-fort);
  text-transform:none;letter-spacing:normal;white-space:normal}
/* Le tableau répond à la souris. Une ligne de CSS, et une liste cesse d'être une image. */
tbody tr:hover{background:var(--survol)}
/* Une ligne CLIQUABLE — l'option `data-lien-de-ligne` du tableau, que ligne-cliquable.js pose — le
   dit au curseur, et souligne son lien : le survol montre OÙ mène le clic. L'attribut n'existe
   qu'avec le script : sans lui, rien ne promet un clic que rien ne tiendrait. */
tr[data-ligne-cliquable]{cursor:pointer}
tr[data-ligne-cliquable]:hover a[data-lien-de-ligne]{text-decoration:underline}
/* La dernière rangée du CORPS perd son trait du bas : le bord de l'enveloppe ferme déjà le
   tableau, et deux traits l'un sur l'autre en font un épais. Du corps SEULEMENT : écrite
   `tr:last-child th`, la règle frappait aussi l'en-tête, dernière — et seule — rangée de son
   `thead` : du 25/08 au 27/09/2026, seul l'en-tête figé, qui le dessine par une ombre, a gardé un
   trait sous ses en-têtes. Le tableau des droits, dont la rangée d'un module a le même fond que
   l'en-tête, n'avait plus rien pour les séparer — relevé par le user contre la planche, qui trace
   ce trait sur chaque tableau. Et du DERNIER corps seulement : le tableau des droits à cocher
   range chaque module dans son `<tbody>`, et `tbody tr:last-child` effaçait le trait au-dessus de
   chaque rangée grise de module (relevé par le user le 2026-09-28). */
tbody:last-of-type tr:last-child td,tbody:last-of-type tr:last-child th{border-bottom:none}

/* Le conteneur de résultats reçoit le focus par PROGRAMME après un changement de page ou de
   tri, pour reposer le point de reprise de tabulation que le lien de fragment offrait avant.
   Sans anneau : personne n'a tabulé jusqu'ici, et cerner toute la zone de résultats d'un trait
   à chaque clic de pagination serait un signal pour un geste qui n'a pas eu lieu. Ce qui doit
   informer, c'est la région live — et elle le fait. MAIS pas après une activation au CLAVIER :
   Entrée sur « Page suivante » déplace le focus par programme, et la personne qui navigue au
   clavier doit voir où il est parti (SC 2.4.7) — la première écriture le masquait dans tous les
   cas, la relecture externe l'a relevé. `:not(:focus-visible)` laisse le navigateur trancher avec
   son heuristique : un `focus()` qui suit une frappe rend `:focus-visible` vrai, celui qui suit un
   clic de souris non. Par PRÉFIXE d'id et non `#resultats` seul : les listes nommées
   (`#resultats-personnes`) et l'aperçu de la vitrine (`#apercu-<motif>`) reçoivent le même focus
   par programme depuis que fragment-vif.js rejoint le nœud posé — un id fixe cernait les unes et
   pas l'autre. */
[id^="resultats"][tabindex="-1"]:focus:not(:focus-visible),[id^="apercu-"][tabindex="-1"]:focus:not(:focus-visible){outline:none}
/* …et, quel que soit son nom, la région recentrée après un POINTEUR : fragment-vif.js la marque
   lui-même, parce que le navigateur a jugé « visible » un focus posé par script après un clic —
   un cadre autour de tout le tableau des droits, relevé par le user le 2026-09-28. */
[data-recentre-sans-anneau]:focus{outline:none}

/* La ligne cochée porte un filet à gauche, et le sélecteur est MOT POUR MOT celui de
   selection.js — `VitrineTest::testLaCaseDeSelectionPorteUnIdentifiantEtNonUnRang` dérive
   celui-ci de celui-là et rougit s'ils divergent. La case d'une ligne se reconnaît à son crochet
   `data-ligne`, pas à sa place dans le balisage. Deux formes ont été essayées avant — « toute
   case du tbody », qui ramassait celles d'un panneau « Gérer » déplié dans la rangée, puis
   « enfant direct du td », qui les excluait mais interdisait d'envelopper la case dans un
   `label`. Le crochet ne pose ni l'une ni l'autre question. La PORTÉE compte autant que le
   prédicat : `.ecran-liste[data-actions-groupees]` est exactement l'élément sur lequel le script
   s'installe, sans quoi la feuille surlignerait des lignes que personne ne compte. Le script,
   lui, ne filtre PAS par `[form=…]` : une feuille ne sait pas comparer deux attributs, et deux
   prédicats qui doivent s'accorder sont deux occasions de diverger — d'où la règle « un seul
   formulaire de gestes groupés par écran », tenue par HabillageTest.
   `:not(:disabled)` : une case désactivée ne part pas au serveur, elle n'a rien à signaler.
   `:has()` n'est pas gardé : là où il manque, la case cochée porte seule l'information, ce qui
   reste juste. */
.ecran-liste[data-actions-groupees] tbody tr:has(input[type=checkbox][data-ligne]:checked:not(:disabled)){box-shadow:inset 3px 0 0 var(--selection-marque)}

/* ---- Écran de liste : en-tête qui DEVIENT contextuel, colonnes collantes, densité, bandeau ----
   `.ecran-liste` enveloppe l'en-tête (_liste-tete.html.twig), le tableau et le bandeau. Le motif
   de Material pour la sélection : quand des lignes sont cochées, la barre de titre ne s'empile
   pas d'un bandeau de plus, elle CHANGE — le compte et les gestes groupés prennent la place du
   titre et des outils. L'état vit dans `data-selection`, posé par selection.js à partir des
   cases ; sans script, les cases restent des cases et le formulaire les envoie. Le titre n'est
   retiré que de l'œil, jamais du document : le plan de page le garde. Ce n'est PAS `.liste`,
   qui est la liste à filets de la vue d'ensemble. */
.liste-tete{display:flex;align-items:center;gap:var(--e-4);flex-wrap:wrap;margin-bottom:var(--e-3);min-height:var(--h-controle)}
.liste-tete h2{margin:0}
.liste-compte{font-weight:400;font-size:var(--fs-sm);color:var(--texte);margin-left:var(--e-2)}
.liste-outils{margin-left:auto;display:flex;gap:var(--e-3);align-items:center;flex-wrap:wrap}
.liste-selection{display:flex;align-items:center;gap:var(--e-3);flex:1;min-height:var(--h-controle)}
.liste-selection b{color:var(--texte-fort)}
.liste-selection .btn-lien{margin-left:auto}
/* La barre est VISIBLE par défaut, et c'est le script qui la replie — par `data-selection-possible`,
   qu'il pose quand il a TROUVÉ des cases à compter — tant que rien n'est coché. La condition est
   « le script est là ET il peut compter », pas « le script est là » : sous le marqueur de
   l'idiome (`data-socle-selection`), une liste dont les cases n'ont pas le crochet `data-ligne`
   repliait sa barre pour toujours, et ses gestes groupés devenaient inatteignables alors que les
   cases partaient quand même au serveur. Le nom n'est pas libre non plus : c'est celui que
   selection.js écrit, et `VitrineTest::testLaFeuilleReplieLaBarreSurLAttributQueLeScriptPose`
   tient les deux bouts — la règle a déjà lu `data-selection-posee`, que plus personne ne posait,
   et la barre restait visible en permanence par-dessus le titre et les outils.
   Sans script, les boutons des gestes restent atteignables et envoient le formulaire
   (méthode-de-travail, § 3.4 : jamais un contrôle inatteignable) ; ce qui n'existe que par le
   script — le compte, « Tout décocher », la case « tout » — est `hidden` dans le gabarit et
   révélé par lui. La première écriture faisait l'inverse : barre masquée par défaut, case
   « tout » visible et inerte — sans script, rien n'envoyait les cases. */
.ecran-liste[data-selection-possible]:not([data-selection]) .liste-selection{display:none}
.ecran-liste[data-selection] .liste-outils{display:none}
.ecran-liste[data-selection] .liste-tete h2{position:absolute;clip-path:inset(50%)}
/* Normale | Dense, et le nombre par page : des LIENS qui portent l'état dans l'adresse, en
   pilules — le motif des filtres du socle, pas un interrupteur de script.
   `flex-wrap` : sans lui, quand la place manque, seule l'étiquette rétrécit ; une pilule garde sa
   largeur et la dernière sort du cadre. Mesuré le 2026-09-15 sur la barre des variantes de la
   visionneuse, six valeurs : 46 px de page en trop à 1024 px de fenêtre, 308 à 320 px. Le prix, dit :
   quand il ne manque que quelques pixels — de 180 à 203 px pour « Par page » et trois nombres —,
   l'étiquette ne se replie plus sur deux lignes ; elle reste entière, et la dernière pilule passe
   dessous. Partout où la barre tient, rien ne bouge. */
.densite{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2);font-size:var(--fs-sm);color:var(--texte)}
/* La barre de recherche d'une liste : sous le bandeau, à gauche — la rangée `.filtres` (champ et
   bouton alignés par le bas, le bouton se range quand fragment-vif.js est là) puis l'aide. Le
   champ garde la largeur d'une donnée : une recherche n'est pas une phrase. `<search>` est un
   élément sans style par défaut : on le déclare en bloc. */
.liste-recherche{display:block;margin:0 0 var(--e-4)}
.liste-recherche .filtres{margin-bottom:var(--e-1)}
.liste-recherche .champ{width:100%;max-width:var(--l-donnee)}
.liste-recherche .aide{display:block;margin:0}
/* La densité est deux tokens, pas une seconde feuille : le même tableau, resserré. */
.ecran-liste.dense{--fs-sm:var(--fs-dense);--h-controle-sm:var(--h-controle-dense)}
.ecran-liste.dense th,.ecran-liste.dense td{padding-block:var(--e-1)}
.ecran-liste.dense .avatar{width:var(--h-avatar-petit);height:var(--h-avatar-petit);min-width:var(--h-avatar-petit);font-size:var(--fs-xs)}
/* Le bandeau qui COMPTE (Carbon) : plage, total, page, lignes par page — sur les deux liens de
   _lien-page.html.twig, inchangés. Le journal, qui ne compte pas exprès, n'affiche que la page. */
.pagination-bandeau{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-4);padding:var(--e-3) 0;font-size:var(--fs-sm);color:var(--texte)}
.pagination-bandeau nav{display:flex;align-items:center;gap:var(--e-2)}
.pagination-bandeau nav[aria-label="Pages"]{margin-left:auto}
.pagination-bandeau b{color:var(--texte-fort)}

/* En-tête TRIABLE. Le motif « Sortable Table » de l'ARIA APG met un `button` dans le `th` ; le
   socle met un LIEN, et la différence est de fond : là-bas le tri est calculé dans la page, ici
   il change l'URL. Un lien dit ce qui se passe — l'adresse se partage, se met en signet, et le
   bouton retour la retrouve. Il fonctionne aussi sans JavaScript : le clic recharge la page
   triée, et le rafraîchissement partiel n'est qu'une amélioration posée par-dessus.
   Le lien hérite des capitales de son `th`, y compris sur les libellés courts que la remarque
   d'en-tête ci-dessus signale. Ce n'est pas un oubli : la chaîne annoncée est la même dans les
   deux cas (« Rôle » reste « Rôle » dans le DOM), donc envelopper le libellé n'ajoute aucun
   risque qui ne soit déjà livré. Le retirer ici, et là seulement, rendrait deux en-têtes voisins
   typographiquement différents selon qu'ils trient ou non. */
th>a.tri{display:flex;align-items:center;gap:var(--e-1);min-height:var(--e-6);min-width:var(--e-6);
  color:inherit;text-decoration:none;font:inherit;
  text-transform:inherit;letter-spacing:inherit}
/* 24 px de haut ET de large au minimum (SC 2.5.8, Target Size Minimum, les deux axes) : le texte
   d'en-tête fait 12 px sur une interligne de 1,55, soit 18,6 px, un libellé court (« N° ») moins
   de 24 px de large, et le rembourrage du `th` n'appartient pas au lien. `display:flex` garde au
   lien toute la largeur de la cellule (la zone cliquable la plus grande), `min-width` garantit
   les 24 px quand la colonne est plus étroite que ça — la première écriture ne tenait que la
   hauteur, la relecture externe l'a relevé. Le
   critère admet l'exception d'espacement — un cercle de 24 px sans chevauchement —, mais base.css
   la refuse pour le socle : « une cible qui dépend de ce qui l'entoure cesse d'être conforme le
   jour où l'on resserre une grille » — et `.dense` la resserre. Même raison pour `.case-cellule`,
   l'enveloppe des cases de sélection écrite par `_tableau.html.twig` : une case nue mesure 13 px. */
.case-cellule{display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--e-6);min-height:var(--e-6);margin:calc(-1 * var(--e-1)) 0;vertical-align:middle}
.case-cellule input{width:var(--h-case);height:var(--h-case);margin:0;accent-color:var(--marque)}
th>a.tri:hover{color:var(--texte-fort);text-decoration:underline}
/* La flèche est DÉCORATIVE : c'est `aria-sort`, sur le `th`, qui porte l'information — une
   flèche seule serait de la présentation, et SC 1.3.1 veut que la relation soit lisible par
   programme. D'où `aria-hidden` sur l'icône dans le gabarit.

   TROIS FORMES, et la troisième est ce qui rendait le premier clic muet. L'indice de survol
   pointait vers le BAS, comme l'état « trié décroissant » — or une colonne neuve ouvre
   justement en décroissant. Le premier clic ne changeait donc que l'opacité et la teinte du
   MÊME glyphe : mesuré, 2,26:1 en clair et 2,23:1 en sombre entre les deux rendus, sous le 3:1
   qui ferait de l'écart une distinction visuelle recevable (Understanding de SC 1.4.1) — et
   l'indice à .55 tenait 2,26:1 sur le fond d'en-tête en clair, sous le 3:1 de SC 1.4.11.
   Un utilisateur l'a dit en une phrase : « ça ne change pas d'orientation ».

   L'indice non trié porte donc `⇅`, une forme que ni `▲` ni `▼` n'ont — c'est la règle que
   l'ARIA APG écrit pour ce motif (« l'icône non triée doit différer par plus que la couleur et
   la taille »), et ce que font MOJ, USWDS et Carbon. Primer et Angular Material ne le font pas
   et portent exactement ce défaut ; la première écriture d'ici était celle de Material au
   chiffre près (0 / .54 / 1 plus une rotation).
   Plus d'opacité intermédiaire : l'indice prend `--texte` (6,31:1 sur l'en-tête en clair,
   7,16:1 en sombre) et l'état trié `--marque-encre` (5,10:1 et 6,94:1). Les deux tiennent le
   3:1 de SC 1.4.11 SUR LE FOND, ce qui est le seuil qui compte — l'écart entre les deux états
   n'a plus à porter l'information, la forme s'en charge.
   `:focus-visible` autant que `:hover` : au clavier, on ne survole pas.

   LES RÈGLES D'ÉTAT PORTENT `>a.tri`, ET C'EST CE QUI LES FAIT EXISTER. Écrites
   `th[aria-sort=ascending] .fleche` — (0,2,1) —, elles PERDAIENT contre la règle de repos
   `th>a.tri .fleche` — (0,2,2) —, et `…::before{content:"▲"}` (0,2,2) contre le `::before` de
   repos (0,2,3) : l'état trié ne s'est JAMAIS rendu, ni ▲ ni couleur ni opacité, depuis la
   première écriture. Le symptôme signalé — « la flèche ne change pas » — venait de LÀ, pas du
   glyphe ; la correction des trois formes a d'abord remplacé des caractères dans des règles
   mortes, et ses contrastes décrivaient un rendu inexistant. Relevé par une mesure des styles
   CALCULÉS, quand la garde de texte et la capture d'écran (faite sur l'ancienne feuille)
   disaient toutes deux « bon ». Selectors Level 4 § 17.

   Les glyphes sont ÉCHAPPÉS (`\21C5`) et non littéraux : la feuille n'a pas de `@charset`, et
   c'est la seule chaîne du fichier qu'un mauvais décodage rendrait visible. Ils ont leur propre
   pile de polices parce qu'AUCUNE police du socle ne les porte (table `cmap` de Poppins lue :
   217 points de code, rien au-delà du latin) : sans pile, Windows tirait ▲▼ de Segoe UI et ⇅ de
   Segoe UI Symbol en gras synthétique — deux dessins. Et la boîte est FIGÉE (`min-width`,
   `inline-block`) : ⇅ est plus large que ▲ de 4 px, la colonne bougeait au tri. */
th>a.tri .fleche{display:inline-block;min-width:var(--l-repere-tri);text-align:center;line-height:1;opacity:0;color:var(--texte);font-family:"Segoe UI Symbol",system-ui,"DejaVu Sans",sans-serif;font-weight:400}
th>a.tri .fleche::before{content:"\21C5"}
th>a.tri:hover .fleche,th>a.tri:focus-visible .fleche{opacity:1}
th[aria-sort=ascending]>a.tri .fleche,th[aria-sort=descending]>a.tri .fleche{opacity:1;color:var(--marque-encre)}
th[aria-sort=ascending]>a.tri .fleche::before{content:"\25B2"}
th[aria-sort=descending]>a.tri .fleche::before{content:"\25BC"}

.filtres{display:flex;flex-wrap:wrap;gap:var(--e-3);align-items:flex-end;margin-bottom:var(--e-4)}
.filtres .champ{margin-bottom:0}
/* Un filtre POSÉ se voit sans relire chaque liste : hors de son option vide (« Tous »), une liste
   déroulante prend la bordure de marque et le gras. Le MOT de l'option porte l'information, la
   bordure la redit (SC 1.4.1). `:has()` et non une classe posée par le serveur : la liste d'un écran
   vif dont htmx ne remplace que les options (l'annuaire) suit sans rien réécrire, sans script aussi.
   Pas d'ombre : elle écraserait le halo du focus, qui en est une. Sans `:has()`, rien ne change. */
.filtres select:not(:has(option[value=""]:checked)){border-color:var(--marque-encre);font-weight:var(--gras-etiquette)}

/* État vide. Sur un socle NEUF, toutes les listes sont vides : c'est littéralement le premier
   écran de la recette, et c'était une ligne de texte gris dans une cellule.

   Bord tireté et non plein : il dit « il y aura quelque chose ici », là où un bord plein dit
   « voici un bloc ». Le motif porte un titre et une invitation à agir — un état vide est une
   invitation, pas un constat d'échec. */
.vide{padding:var(--e-8) var(--e-4);text-align:center;color:var(--texte)}
.vide-motif{display:flex;flex-direction:column;align-items:center;gap:var(--e-3);
  padding:var(--e-12) var(--e-6);border:1.5px dashed var(--bord);border-radius:var(--radius);
  background:var(--surface);text-align:center}
.vide-motif svg{color:var(--marque-encre)}
.vide-motif h2{font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort)}
.vide-motif p{max-width:var(--l-mesure);color:var(--texte)}
.liste li{padding:var(--e-3) var(--e-4);border-bottom:1px solid var(--ligne)}
.liste li:last-child{border-bottom:none}

/* Sur le fond du menu, l'anneau de focus passe à --marque : --marque-encre n'y vaut que
   2,07:1, sous le seuil de 3:1 qu'un indicateur de focus doit tenir. --marque y vaut 5,34:1,
   et l'ancrage de --nav garantit ce chiffre dans les DEUX lots. */
.menu{--focus:var(--marque)}
/* L'arborescence en tableau — le composant « arbre », motif « lire en colonnes, éditer derrière
   Gérer » de l'annuaire. La cellule de nom porte ses FILETS, l'icône de sa nature, puis le nom et,
   dessous, ce sous quoi il est rangé. La profondeur et les filets arrivent du gabarit en NOMBRES
   sans unité (`--profondeur`, `--suite-N`, `--fin`, `--enfants`) ; les longueurs restent ici —
   HabillageTest refuse une longueur écrite dans un gabarit. Le retrait n'est honnête que parce que
   `sousArbreDe()` trie par chemin : un parent précède toujours ce qui est rangé dessous.

   **L'aplat est parti, et le cran est passé de --e-4 à --e-6** — la piste B, choisie par le user
   le 2026-09-15 parmi trois (artefact « Pistes pour la liste des sociétés »). Une teinte posée sur
   chaque société grisait huit lignes sur dix d'un groupe de sept sociétés et deux services, et
   faisait ressortir les services, l'inverse de l'intention. La nature se MONTRE par l'icône, la
   hiérarchie par le filet ; le cran de 24 px est ce qui laisse au coude la place d'aller de l'axe
   de l'icône parente à l'icône de l'enfant. La colonne « Type » écrit toujours la nature (SC 1.4.1). */
.arbre-nom{--cran-arbre:var(--e-6);--icone-arbre:var(--e-4);
  display:flex;align-items:center;gap:var(--e-3);min-width:0;
  padding-left:calc(var(--profondeur,0) * var(--cran-arbre))}
.arbre-nom>svg{flex:none;width:var(--icone-arbre);height:var(--icone-arbre);color:var(--texte)}
.arbre-texte{display:block;min-width:0}
.arbre-nom b{display:block;font-weight:var(--gras-etiquette);color:var(--texte-fort)}
/* Ce qui est RANGÉ dans une nature plus forte — un service parmi les sociétés — en graisse normale :
   le semi-gras reste à ce qui contient. L'icône le dit déjà ; la graisse n'est qu'un renfort. */
.arbre-nom-leger b{font-weight:400}
/* La ligne sous le nom — sous quoi il est rangé — en graisse NORMALE : elle héritait du gras de
   l'en-tête de ligne (`tbody th`, 600) et se lisait à égalité avec le nom, relevé par le user le
   2026-09-15. La maquette la pose en 12 px, gris, sans graisse. Un écran la passe hors écran quand
   l'arbre est entier : le retrait la montre déjà. */
.arbre-nom small{display:block;font-size:var(--fs-xs);font-weight:400;color:var(--texte)}
.arbre-nom .badge{margin-left:var(--e-2)}
/* LES FILETS — des traits d'un pixel, dessinés en fonds sur un élément décoratif (`.arbre-branches`,
   `aria-hidden`) posé en tête du nom et étiré sur toute la hauteur de la cellule, filet de ligne
   compris : la ligne voisine prend le relais là où la cellule s'arrête. SAUF la dernière rangée, qui
   n'a pas de trait à franchir : ce pixel-là débordait de la zone qui défile — 613 px de contenu pour
   612 de haut, et une barre de défilement vide chez qui les affiche toujours, relevée par le user le
   2026-09-15 sur « Sociétés et services ». Sa marge négative le cale
   sur l'origine de l'arbre, la profondeur zéro ; chaque trait est allumé par un nombre de la ligne —
   `--suite-N` pour le filet d'un niveau supérieur qui continue plus bas, le coude de la ligne
   (vertical jusqu'à mi-hauteur quand elle ferme sa branche, horizontal jusqu'à son icône), et le
   trait qui descend vers ce qui est rangé dessous. Cinq niveaux de suite couvrent la profondeur que
   le socle borne à six. La teinte des traits dérive du bord et de la surface : elle suit le thème.
   Il faut `:has()` pour positionner la cellule — ou la PROPOSITION, quand l'arbre se choisit (« Où
   le ranger ? », composant « choisir avec aperçu ») : le radio garde sa colonne, le nom porte le
   retrait et les filets ; sans `:has()`, pas de filet — l'icône et le retrait disent encore la
   hiérarchie. */
.arbre-branches{display:none}
@supports selector(:has(*)){
  tbody th:has(> .arbre-nom > .arbre-branches),.proposition:has(> .proposition-corps > .arbre-nom > .arbre-branches){position:relative}
  .arbre-branches{--ligne-arbre:color-mix(in srgb, var(--bord) 40%, var(--surface));--axe:calc(var(--icone-arbre) / 2);
    display:block;position:absolute;top:0;bottom:-1px;pointer-events:none;
    width:calc((var(--profondeur,0) + 1) * var(--cran-arbre));
    margin-left:calc(-1 * var(--profondeur,0) * var(--cran-arbre));
    background-image:
      linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),
      linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),
      linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),
      linear-gradient(var(--ligne-arbre),var(--ligne-arbre)),linear-gradient(var(--ligne-arbre),var(--ligne-arbre));
    background-repeat:no-repeat;
    background-position:
      var(--axe) 0,calc(var(--cran-arbre) + var(--axe)) 0,calc(2 * var(--cran-arbre) + var(--axe)) 0,
      calc(3 * var(--cran-arbre) + var(--axe)) 0,calc(4 * var(--cran-arbre) + var(--axe)) 0,
      calc((var(--profondeur,0) - 1) * var(--cran-arbre) + var(--axe)) 0,
      calc((var(--profondeur,0) - 1) * var(--cran-arbre) + var(--axe)) 50%,
      calc(var(--profondeur,0) * var(--cran-arbre) + var(--axe)) 100%;
    background-size:
      calc(var(--suite-1,0) * 1px) 100%,calc(var(--suite-2,0) * 1px) 100%,calc(var(--suite-3,0) * 1px) 100%,
      calc(var(--suite-4,0) * 1px) 100%,calc(var(--suite-5,0) * 1px) 100%,
      calc(min(var(--profondeur,0), 1) * 1px) calc(100% - var(--fin,0) * 50%),
      calc(min(var(--profondeur,0), 1) * (var(--cran-arbre) - var(--axe) - var(--e-1))) 1px,
      calc(var(--enfants,0) * 1px) 50%}
  tbody tr:last-child>th>.arbre-nom>.arbre-branches,.proposition:last-child>.proposition-corps>.arbre-nom>.arbre-branches{bottom:0}
}

/* La pilule COURANTE d'un groupe de filtres : l'état se déclenche sur `aria-current`, jamais
   sur une classe — même règle que le menu et les onglets, on ne peut pas styler l'état sans
   l'annoncer. Les couleurs sont celles du bouton plein : c'est le même « vous êtes ici ». */
/* Quelle que soit la VALEUR : le jeton dit la nature de l'élément courant — `true` pour un réglage
   (Normale | Dense, 20 par page, Toutes | Actives), `page` pour une page —, la CSS le suit ; une
   règle sur la seule valeur `"true"` dictait le jeton au gabarit, et `"page"` s'annonçait sans
   se voir. `"false"` est la seule valeur exclue, et c'est la seule qui le mérite : elle DIT que
   l'élément n'est pas le courant — la mettre en avant afficherait le contraire de ce qu'elle
   annonce. */
.pilule[aria-current]:not([aria-current="false"]){background:var(--action);border-color:var(--action);color:var(--sur-action)}
.pilule[aria-current]:not([aria-current="false"]):hover{border-color:var(--action);color:var(--sur-action)}

/* Sur le charbon du menu, l'anneau de focus passe à --marque : --focus n'y vaut que 2,07:1,
   sous le seuil de 3:1 qu'un indicateur de focus doit tenir. --marque y vaut 5,34:1, et l'aplat
   de marque ne bascule pas d'un lot à l'autre — le chiffre tient dans les DEUX.
   Cette ligne a désigné `--orange`, un jeton que rien ne définissait plus : un var() sans repli
   ne vaut rien, le menu gardait l'anneau des fonds clairs, et aucun test ne le voyait.
   `testChaqueJetonEmployeExisteDansLaCharte` le voit désormais. */
.menu{--focus:var(--marque)}

/* Enrôlement du second facteur. Ces deux classes vivaient dans auth.css, que leur écran ne
   charge pas : il étend base.html.twig pour garder la navigation. Le QR s'affichait donc
   sans cadre et la clé sans retour à la ligne. */
.qr{display:block;margin:var(--e-4) auto;background:var(--surface);padding:var(--e-3);border:1px solid var(--ligne);border-radius:var(--radius)}
.secret{display:block;font-family:var(--font-mono);font-size:var(--fs-sm);word-break:break-all;background:var(--surface);border:1px solid var(--ligne);border-radius:var(--radius-sm);padding:var(--e-3);margin-bottom:var(--e-4)}

/* ---- Écran des comptes ----
   Aucune couleur en dur : tout passe par les tokens, donc une autre charte suit sans
   qu'on revienne ici. */

/* Fil d'Ariane du rattachement. Le séparateur est POSÉ EN CSS et non écrit dans le
   gabarit : un « / » textuel serait lu à voix haute entre chaque nom. */
.chemin{margin-bottom:var(--e-4);font-size:var(--fs-sm);color:var(--texte)}
.chemin ol{display:flex;flex-wrap:wrap;gap:var(--e-2);list-style:none;padding:0;margin:0}
.chemin li+li::before{content:"›";margin-right:var(--e-2);color:var(--bord)}
.chemin [aria-current]{color:var(--texte-fort);font-weight:var(--gras-etiquette)}

/* Rangée de commandes. `flex-wrap` : sur un écran étroit les boutons descendent au lieu
   de déborder — un bouton hors du cadre est un bouton qui n'existe pas. */
.actions{display:flex;flex-wrap:wrap;gap:var(--e-3);align-items:center;margin:var(--e-4) 0}
/* Un geste INTERDIT du faux module de DÉMONSTRATION : visible et grisé, avec sa raison dessous.
   Le produit, lui, n'affiche jamais ce qui n'aboutit pas — c'est une divergence assumée, décidée
   pour qu'on voie d'un coup d'œil ce qui manque à quelqu'un au lieu de connecter deux comptes.
   `aria-disabled` et jamais `disabled` : un bouton désactivé sort de l'ordre de tabulation, donc
   la raison qui l'accompagne n'est jamais lue au clavier. Ces classes sont inscrites dans
   `VitrineTest::HORS_VITRINE` avec cette raison — elles n'ont pas à entrer dans la vitrine, aucun
   module du client ne les recopiera.

   PAS d'`opacity`, et c'est une mesure et non un goût : à `opacity:.7`, le texte du bouton
   tombait à 3,0:1 sur le fond de page — sous le 4,5:1 qu'exige WCAG 2.2 AA. L'exemption « composant
   d'interface inactif » du critère 1.4.3 ne couvre pas ce cas : le bouton reste focalisable, c'est
   tout l'objet d'`aria-disabled`, et la démonstration ne vaut que si le client le LIT. Le fond, la
   bordure et le curseur suffisent à le distinguer, et le contraste remonte à 5,8:1. */
.geste{display:flex;flex-direction:column;gap:var(--e-1);align-items:flex-start}
.geste .aide{max-width:var(--l-mesure)}
.geste-refuse{background:var(--neutre-bg);color:var(--texte);border-color:var(--bord);cursor:not-allowed}
/* Deux contrôles côte à côte DANS une cellule : le formulaire est un élément de bloc, il
   passerait sous son voisin.
   Nom distinct de `.cellule-actions`, qui désigne la COLONNE et se pose sur le `<td>` : une
   règle nue `.cellule-actions{display:flex}` se serait appliquée à ces cellules-là aussi, et
   leur `width:1%` aurait cessé d'opérer — la collision silencieuse contre laquelle le
   commentaire de cette classe met déjà en garde.
   Pas non plus `.actions`, qui porte une marge verticale faite pour une barre d'écran. */
.actions-en-ligne{display:flex;flex-wrap:nowrap;gap:var(--e-2);align-items:center;justify-content:flex-end}

/* Fiche en paires terme/définition. `grid` plutôt qu'un tableau : ce sont des propriétés
   d'un seul objet, pas des lignes comparables entre elles. */
/* L'étiquette AU-DESSUS de la valeur, dans le traitement typographique du `th` de la liste :
   une fiche de détail est un tableau vu de profil, et ses en-têtes de colonne sont ses
   étiquettes. La gouttière fixe de 12rem a disparu — taillée sur la pire étiquette, gaspillée
   sur toutes les autres, elle laissait 836 px à une adresse de 130.

   `min(…, 100%)` n'est pas une coquetterie : sans lui, `minmax(22rem, 1fr)` DÉBORDE dès que la
   carte descend sous 384 px, et le SC 1.4.10 Reflow (niveau AA) demande de tenir 320 px de
   fenêtre sans défilement à deux dimensions. */
/* ---- Ligne d'option ----
   Ce dont il s'agit à GAUCHE, ce qu'on peut en faire à DROITE, un filet entre deux. C'est le
   motif de la base fournie pour les réglages d'un compte : chaque ligne est un sujet, et l'œil
   descend la colonne de gauche sans lire les actions.

   Elle remplace une liste de définitions (`<dl class="fiche">`) là où chaque entrée porte une
   ACTION. Une `<dl>` décrit — terme, définition —, elle ne prévoit pas de troisième colonne, si
   bien que les boutons se rangeaient sous leur texte et la carte se lisait comme un formulaire.

   Le `<b>` et le `<small>` sont le contrat : un titre court, puis ce qu'il faut en savoir. Les
   deux en blocs, pour que la ligne tienne debout quand le libellé est long. */
.ligne-option{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-3);
              padding:var(--e-4) 0;border-bottom:1px solid var(--ligne)}
.ligne-option:first-child{padding-top:0}
.ligne-option:last-child{padding-bottom:0;border-bottom:none}
/* `flex:1 1 0` et surtout PAS `auto`, mesuré au navigateur. Avec une base `auto`, la base du
   sujet vaut la largeur de son propre texte : dans une carte de demi-largeur elle occupait les
   433 px de la ligne, et le conteneur — qui enveloppe — poussait l'action DESSOUS. C'est
   exactement ce que ce motif existe pour éviter. Base zéro, le sujet grandit ensuite dans ce qui
   reste. `min-width:0` sans quoi un mot long refuse de se couper et déborde la carte. */
.ligne-option>.ligne-option-sujet{flex:1 1 0;min-width:0}
.ligne-option b{display:block;font-weight:var(--gras-titre)}
.ligne-option small{display:block;margin-top:var(--e-1);font-size:var(--fs-sm);line-height:1.4}
/* Rien ici pour le panneau déplié : `.edition[open]{flex-basis:100%}` le fait déjà, et deux
   règles pour un seul comportement divergent le jour où l'une des deux change. */

/* LA VALEUR D'UN RÉGLAGE, DANS SA COLONNE — entre le sujet et le geste : ce qui vaut aujourd'hui en
   gras, ce qui en découle dessous (maquette A3 de « Sécurité », retenue par le user le 2026-10-03).
   La première écriture la posait en pastille grise à côté du sujet, et le user ne l'a pas reconnue :
   une pastille se lit comme un état parmi d'autres, pas comme la réponse à la question de la ligne.
   Valeur et geste ont une largeur FIXE, pour que les valeurs de deux lignes s'alignent et que la
   carte se lise en colonnes. Quand la ligne ne tient plus — un téléphone —, le sujet garde sa base
   (`--l-option-sujet`, au lieu de la base nulle d'une ligne sans valeur), la valeur passe dessous et
   le geste reste à droite. La valeur peut RÉTRÉCIR (`flex-shrink:1`) : seule sur sa ligne, sur un
   téléphone, ses 18rem dépassaient la carte de 9 px (mesuré à 390 px) ; tant que la ligne la tient, rien
   ne la rétrécit, le retour à la ligne passant avant. */
.ligne-option:has(>.ligne-option-valeur)>.ligne-option-sujet{flex-basis:var(--l-option-sujet)}
.ligne-option>.ligne-option-valeur{flex:0 1 var(--l-option-valeur);min-width:0;margin:0;font-size:var(--fs-sm);color:var(--texte-fort)}
/* Dans une boîte, un sujet plus étroit : le libellé reste À GAUCHE de sa valeur, comme sur une page. */
.carte-boite .ligne-option:has(>.ligne-option-valeur)>.ligne-option-sujet{flex-basis:var(--l-option-sujet-boite)}
.ligne-option-valeur>b{font-weight:var(--gras-etiquette)}
.ligne-option-valeur>small{margin-top:0;color:var(--texte)}
.ligne-option>.ligne-option-geste{flex:0 0 var(--l-colonne-etroite);display:flex;justify-content:flex-end;margin-left:auto}

/* LA LIGNE OUVERTE — « Modifier » la remplace SUR PLACE : la ligne qu'on règle n'est plus lue, elle
   est réglée. Les choix sur la ligne du titre, puis ce que le choix fera et les gestes ; le fond de
   survol et le filet de marque la détachent de ses voisines, dont le « Modifier » se grise tant
   qu'elle est ouverte. Jamais la valeur ET le formulaire : la valeur en cours est le choix coché.
   C'est la règle du bandeau de fiche — l'état est une ADRESSE (`?modifier=<réglage>`), « Annuler »
   un lien vers la lecture —, si bien que tout marche sans script ; avec htmx, seule la carte change.
   La ligne porte AUSSI `.ligne-option` (son filet, sa place) : ses deux règles de remplissage
   viennent APRÈS celles de `.ligne-option`, à spécificité égale, et c'est voulu.
   Un flex qui S'ENROULE, pas une grille : la première écriture, en `minmax(0,1fr) auto`, gardait les
   choix sur la ligne du titre jusqu'à 390 px — le titre écrasé sous la légende, la page défilant de
   9 px de côté (mesuré). Ici le titre garde une base, et les choix passent dessous quand ils ne tiennent
   plus à côté. */
.ligne-option.ligne-option-ouverte{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--e-3) var(--e-6);
  margin:0 calc(var(--e-6) * -1);padding:var(--e-4) var(--e-6);background:var(--survol);box-shadow:inset 3px 0 0 var(--marque)}
/* Le titre : un `b`, ou son `.aide-titre` quand une aide l'accompagne — jamais `:first-child`, qu'un champ
   caché du formulaire occupe sur la ligne du délai. */
.ligne-option-ouverte>:is(b,.aide-titre){flex:1 1 var(--l-option-titre);min-width:0}
.ligne-option.ligne-option-ouverte:first-child{padding-top:var(--e-4)}
.ligne-option-reglage{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--e-2) var(--e-4);margin:0;min-width:0;max-width:100%}
/* La question de chaque groupe À GAUCHE de ses choix, sur la même ligne. La légende flotte : une
   légende flottante n'est plus celle que le navigateur pose sur le cadre du `fieldset`, elle devient
   un enfant ordinaire — et le `fieldset` garde ce qu'il donne au lecteur d'écran, le nom du groupe. */
.ligne-option-reglage>fieldset,.ligne-option-reglage>.champ{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2);min-width:0;max-width:100%;margin:0;padding:0;border:0}
.ligne-option-reglage>fieldset>legend,.ligne-option-reglage>.champ>label{float:left;margin:0;padding:0;font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.ligne-option-reglage>.champ input:not([type=checkbox]):not([type=radio]){min-height:var(--h-controle-sm)}
/* Un nombre de jours (`.champ.court`, composant « champs ») : l'étiquette à GAUCHE, comme « Exigée pour » et
   « Délai » sur les autres lignes ouvertes, et la saisie dans une colonne de `--l-champ-court`. La largeur se
   pose sur le BLOC, par sa grille, jamais sur la saisie — `HabillageTest`. Bornée par `max-width`, l'étiquette
   passait au-dessus (mesuré, 2026-10-04). */
.ligne-option-reglage>.champ.court{display:grid;grid-template-columns:auto var(--l-champ-court);max-width:none}
.ligne-option-suite{flex:1 1 100%;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--e-3) var(--e-6)}
/* Toutes les phrases, et pas la seule première : une phrase par choix est rendue d'avance, une seule se
   montre (`apercu-sur-place.js`), et un refus s'y ajoute en tête. */
.ligne-option-suite>p:not(.actions-en-ligne){flex:1 1 var(--l-option-sujet);margin:0;font-size:var(--fs-sm);line-height:1.5;color:var(--texte-fort)}
.ligne-option-suite>p:not(.actions-en-ligne)>b{display:inline}
.ligne-option-suite>.actions-en-ligne{margin:0 0 0 auto}

/* Les deux mesures du `gap` sont écrites séparément, et ce n'est pas de la coquetterie :
   32 px entre les COLONNES — la gouttière de `.form-grille`, dont le commentaire dit pourquoi —
   et 16 px entre les LIGNES. Un `gap` unique à 32 aurait aéré la verticale d'autant, et une
   liste de paires terme/valeur n'en a aucun besoin : elle se lit en colonne, serrée. */
.fiche{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(var(--l-donnee),100%),1fr));
  gap:var(--e-4) var(--e-8);align-items:start;margin:0}
.fiche>div{min-width:0}
.fiche dt{font-size:var(--fs-xs);font-weight:var(--gras-titre);line-height:1.4;color:var(--texte);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.fiche dd{margin:var(--e-1) 0 0;line-height:1.4}
.fiche-valeur{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2)}

/* L'outil d'édition vit DANS le `dd` de la valeur qu'il change — la distance entre une donnée
   et son formulaire passe d'une carte entière à zéro. `<details>` est natif : aucune
   dépendance, aucun script, et aucun `tabindex` écrit à la main, `<summary>` étant focalisable
   de naissance et annoncé comme bouton avec son état déplié (SC 4.1.2, niveau A).

   Rien d'utile n'est masqué : la valeur courante reste affichée à côté du résumé. On ne replie
   pas un choix, on range un outil. */
.edition{min-width:0}
.edition[open]{flex-basis:100%}
.edition>summary{display:inline-flex;align-items:center;gap:var(--e-2);
  min-height:var(--h-controle-sm);padding:0 var(--e-3);
  border:1px solid var(--bord);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--texte-fort);
  font:var(--gras-etiquette) var(--fs-sm)/1.2 var(--font);cursor:pointer;list-style:none}
/* `inline-flex` retire déjà le marqueur natif sur Chrome ; Safari veut sa règle à lui. */
.edition>summary::-webkit-details-marker{display:none}
.edition>summary::after{content:"\203A";content:"\203A" / "";line-height:1;transform:rotate(90deg);
  transition:transform var(--duree)}
.edition[open]>summary::after{transform:rotate(-90deg)}
.edition>summary:hover{border-color:var(--marque-encre);color:var(--marque-encre)}
.edition-panneau{padding-top:var(--e-3)}
.edition-panneau p{margin-bottom:var(--e-3);font-size:var(--fs-sm);color:var(--texte)}
.edition-panneau .champ,.edition-panneau fieldset.champ{margin-bottom:var(--e-3)}
/* Un champ borné à 120 caractères n'ATTEND pas 120 caractères : c'est un plafond, tenu par
   `maxlength`, et la boîte n'a pas à l'annoncer. Mesuré : 1009 px avant, 387 après. Ce n'est
   pas une clause d'accessibilité — aucun critère ne traite de la largeur d'un champ — c'est de
   l'affordance : la taille d'une zone de saisie annonce ce qu'on y attend.

   LA BRIDE PORTE SUR LE BLOC `.champ`, JAMAIS SUR LA SAISIE, et cette ligne-là a été écrite
   deux fois. La première visait `.champ input` — la saisie rétrécissait bien, mais le bouton
   d'affichage du mot de passe s'ancre sur `.champ-secret` (base.css), l'enveloppe que le script
   glisse AUTOUR de la saisie. Enveloppe restée pleine largeur, saisie à 44ch : l'œil se posait
   au bord du panneau, à plus de deux cents pixels du champ qu'il découvre. Vu à l'écran, pas
   déduit. Brider le BLOC fait suivre l'enveloppe, donc l'œil, et referme la famille entière :
   toute largeur future se pose ici sans avoir à connaître l'existence de l'enveloppe. */
.edition-panneau .champ{max-width:var(--l-mesure)}

/* UN PANNEAU D'ÉDITION DANS UNE CELLULE DE TABLEAU s'accommode de sa colonne au lieu de la
   forcer, et ses contrôles s'empilent sur toute sa largeur.

   La version d'avant lui imposait un plancher de `--l-surgissant`. Mesuré : le tableau
   s'élargissait au-delà de son enveloppe, la barre de défilement horizontale apparaissait, et le
   panneau s'ouvrait EN PARTIE HORS DU CADRE — « Enregistrer les droits » n'était atteignable
   qu'en faisant défiler un tableau dont rien n'annonçait qu'il avait bougé. Entre un panneau
   large à moitié hors champ et un panneau étroit entièrement visible, c'est le second qui rend
   service.

   Aucun plancher de largeur non plus : essayé à 13rem puis à --l-surgissant, mesuré les deux
   fois, le tableau dépassait son enveloppe et le panneau s'ouvrait à cheval sur le bord. La
   colonne prend ce que les autres lui laissent — sur un écran de travail réel elle dépasse deux
   cents pixels et les libellés tiennent sur une ligne ; sur un écran étroit ils se replient, ce
   qui reste préférable à un panneau qu'il faut aller chercher en faisant défiler.

   Les boutons prennent donc la largeur disponible et s'empilent. Un libellé qui se replie sur
   deux lignes dans une colonne étroite ressemble à un accident ; le même, posé en bloc plein,
   se lit comme une liste de gestes — et les libellés ne sont pas négociables, « Retirer de
   Holding » et « Désactiver le compte » nomment deux gestes qu'on ne doit pas confondre.

   Le panneau reste dans le FLUX, jamais en absolu comme celui de la photo de profil : il pousse
   la rangée au lieu de surgir par-dessus. Ce n'est pas une question de goût — `.table-enveloppe`
   porte `overflow-x:auto`, et la spécification force alors `overflow-y` à `auto` lui aussi : un
   panneau absolu plus haut que le tableau y serait DÉCOUPÉ, ses derniers boutons devenant
   inatteignables. */
.table-enveloppe .edition-panneau .btn,
.table-enveloppe .edition-panneau .btn-primaire{display:flex;width:100%}
.table-enveloppe .edition-panneau form{margin-bottom:var(--e-2)}
.table-enveloppe .edition-panneau .form-pied{justify-content:stretch}

@media (max-width: 40rem){
  /* En colonne unique sous 640px : deux colonnes y coupent les adresses en plein milieu. */
  .fiche{grid-template-columns:1fr;gap:var(--e-1)}
  .fiche dd{margin-bottom:var(--e-3)}
}

/* Colonne d'actions : collée à droite, et ne s'étire pas.
   Nommée `cellule-actions` et non `droit` : la base fournie emploie `.droit` pour « une
   permission de la matrice », et porter sa matrice telle quelle aurait produit une collision
   silencieuse entre deux sens du même nom. */
td.cellule-actions,th.cellule-actions{text-align:right;white-space:nowrap;width:1%}

/* ---- Matrice des droits ----
   La « permission de la matrice » que le commentaire du dessus réserve : reprise de la base
   fournie. Un mot en pastille se LIT ; une matrice se BALAIE en colonnes, et le mot répété à
   chaque ligne pesait plus que l'information qu'il porte — une lettre dans un carré rend la
   colonne lisible d'un regard. Le mot n'a pas disparu pour autant : il reste dans la cellule,
   hors écran, et le gabarit (`parametres/roles.html.twig`) porte les trois garde-fous.
   Le carré est FIXE (largeur = hauteur) : « O » et « – » n'ont pas la même chasse, et des
   pastilles moulées sur leur contenu feraient des colonnes aux carrés inégaux.
   Les colonnes de signes se centrent, en-tête compris — le carré se lit sous son rôle comme
   une coche sous sa case ; la première colonne reste un libellé, alignée comme du texte. */
/* ---- Matrice ----
   Un tableau qui se BALAIE en colonnes : une chose par ligne (un écran, une notification), une
   catégorie par colonne (un rôle, un canal), et dans chaque cellule un signe centré — une
   lettre dans un carré, un interrupteur, un tiret. Deux tableaux du socle ont porté ce dessin
   sous deux noms, `.matrice-droits` et `.notif-table`, le second réécrivant en prime les règles
   de base des tableaux avec d'autres rembourrages ; il n'en reste qu'un, dans `.table-enveloppe`
   comme tous les autres. Les colonnes de signes ne prennent que ce qu'il leur faut (1 %) :
   c'est le libellé de la ligne qui doit disposer de la mesure. Pas de `white-space:nowrap` avec
   — essayé, mesuré sur la matrice des rôles : sept en-têtes qui ne peuvent plus se couper
   poussaient le tableau hors de son enveloppe, là où « Gestion sonde » sur deux lignes tient.
   L'en-tête de ligne est une étiquette —
   graisse d'étiquette, encre forte — et son aide se range dessous, en maigre. */
.matrice th:not(:first-child),.matrice td:not(:first-child){text-align:center;width:1%}
.matrice tbody th{font-weight:var(--gras-etiquette);color:var(--texte-fort);line-height:1.4}
.matrice tbody th .aide{display:block;margin-top:var(--e-1);font-weight:400}
.droit{display:inline-flex;align-items:center;justify-content:center;
  width:var(--e-6);height:var(--e-6);border-radius:var(--radius-sm);
  font-size:var(--fs-xs);font-weight:var(--gras-titre);line-height:1}
.droit-ouvert{background:var(--ok-bg);color:var(--ok)}       /* 4,60:1 clair, 7,22:1 sombre — tokens.css */
.droit-ferme{background:var(--neutre-bg);color:var(--texte)} /* mesuré : 5,64:1 clair, 6,23:1 sombre */
/* Le troisième état de la matrice des FORMULAIRES — facultatif, entre l'exigé et l'absent.
   La famille d'avertissement, déjà contrastée par tokens.css pour porter du texte. */
.droit-facultatif{background:var(--warn-bg);color:var(--warn)}
/* La clef du code, SOUS la carte comme dans la base fournie : le tableau garde ainsi son
   dernier rang contre le bord arrondi. `.carte` porte déjà la marge basse ; la légende n'ajoute
   qu'un léger retrait, pour se détacher de l'angle arrondi sans prétendre s'aligner sur le
   contenu de la carte. */
.droits-legende{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2) var(--e-6);
  margin:0 0 var(--e-4);padding:0 var(--e-2);font-size:var(--fs-sm);color:var(--texte)}
.droits-legende>span{display:inline-flex;align-items:center;gap:var(--e-2)}

/* ---- Tableau figé ----
   `.colonne-figee` sur l'enveloppe garde la colonne qui NOMME la ligne quand le tableau défile en
   largeur ; `.entete-figee` garde les en-têtes de colonnes quand les lignes défilent. Demandé par
   le user le 2026-09-15 sur la matrice des droits : à la onzième colonne de rôles, la ligne lue
   n'avait plus de nom. Une matrice pose `.colonne-figee` d'office — elle se balaie en colonnes —,
   un tableau de liste la demande à `_tableau.html.twig` (`colonne_figee`, `entete_figee`).

   Quatre choses, et chacune évite un défaut qu'on voit :
   - les cellules figées ont un FOND, celui de la surface ou du survol de leur rangée : sans lui, ce
     qui glisse dessous se lit à travers. Le repère d'une rangée cochée, un `box-shadow` du `<tr>`,
     est recouvert par ce fond : la cellule le reporte ;
   - avec une colonne de cases, la case ET la cellule qui nomme restent : figer la case seule
     garderait une colonne muette. La case a une largeur CONNUE (`--l-cellule-case` : son
     rembourrage, plus la cible de 24 px de `.case-cellule`), et la cellule suivante colle juste
     après ;
   - le filet qui sépare la colonne figée de ce qui glisse n'apparaît que si la zone déborde
     vraiment : `role="region"` est posé par tableau-defilant.js dans ce cas seul, et c'est lui que
     la règle lit. Pour l'en-tête, le trait du bas passe du bord du `th` à une ombre intérieure : un
     bord de tableau fusionné (`border-collapse`) reste où il était pendant que la cellule colle ;
   - l'en-tête ne colle que dans une zone BORNÉE (`--h-liste`) : une zone qui défile en largeur
     défile aussi en hauteur, et sans borne elle ne défile jamais.

   ET TOUT SE DÉCROCHE AU FOCUS CLAVIER, comme le pied collant plus bas, pour la même raison
   mesurée : un élément collant recouvre ce que le clavier atteint dessous, et le navigateur ne
   défile pas pour une cible qu'il croit déjà visible — l'échec F110 du SC 2.4.11. La colonne se
   décroche quand le focus est dans une cellule qu'elle peut couvrir (un `td` qui n'est pas la case),
   l'en-tête quand il est dans les lignes. Se décrocher, c'est rendre `auto` au SEUL côté qui colle
   (`left`, `top`) et non passer en `static` : la case d'angle, qui colle des deux côtés, garde ainsi
   le côté qui ne se décroche pas — un `static` l'emportait avec l'en-tête pendant que le reste de
   sa colonne restait. Le focus sur la zone elle-même — les flèches font défiler — ne décroche rien :
   `:has()` ne regarde que les descendants. Là où `:has()` manque, la borne `@supports` laisse tout
   STATIQUE plutôt que collant sans décrochage. */
.table-enveloppe{--l-cellule-case:calc(var(--e-4) * 2 + var(--e-6))}
.carte .table-enveloppe{--l-cellule-case:calc(var(--e-6) * 2 + var(--e-4))}
@supports selector(:has(*)){
  /* Un contexte d'empilement PROPRE à la zone : les `z-index` de ses cellules collantes (1 à 3)
     ne se comparent plus qu'entre elles. Sans lui, ils rejoignaient ceux de la page, et la case
     d'angle passait au-dessus du panneau d'un menu déroulant ouvert plus haut (`z-index:1`). */
  .colonne-figee,.entete-figee{isolation:isolate}
  .colonne-figee>table>*>tr>:first-child,
  .colonne-figee>table>*>tr>:first-child:has(>.case-cellule)+*{position:sticky;left:0;z-index:1}
  .colonne-figee>table>*>tr>:first-child:has(>.case-cellule){box-sizing:border-box;width:var(--l-cellule-case);min-width:var(--l-cellule-case)}
  .colonne-figee>table>*>tr>:first-child:has(>.case-cellule)+*{left:var(--l-cellule-case)}
  .colonne-figee>table>tbody>tr>:first-child,
  .colonne-figee>table>tbody>tr>:first-child:has(>.case-cellule)+*{background:var(--surface)}
  .colonne-figee>table>tbody>tr:hover>:first-child,
  .colonne-figee>table>tbody>tr:hover>:first-child:has(>.case-cellule)+*{background:var(--survol)}
  .colonne-figee[role=region]>table>*>tr>:first-child:not(:has(>.case-cellule)),
  .colonne-figee[role=region]>table>*>tr>:first-child:has(>.case-cellule)+*{box-shadow:inset -1px 0 0 var(--ligne)}
  /* LE TRAIT SOUS L'EN-TÊTE, PAR UNE OMBRE — comme sous l'en-tête figé, plus bas. Mesuré le
     2026-09-28 (bordure passée en rouge, aucun rouge à l'écran) : dans le contexte `isolation:isolate`
     posé plus haut, Chrome ne peint pas la bordure fusionnée entre l'en-tête et le corps, et le
     tableau des droits à cocher n'avait plus rien entre ses en-têtes et la rangée grise du premier
     module. L'isolation reste, elle garde les menus au-dessus. La bordure devient transparente :
     un moteur qui la peint en tracerait deux. La case d'angle garde ses deux traits. */
  .colonne-figee>table>thead>tr>th{border-bottom-color:transparent;box-shadow:inset 0 -1px 0 var(--ligne)}
  .colonne-figee[role=region]>table>thead>tr>:first-child:not(:has(>.case-cellule)),
  .colonne-figee[role=region]>table>thead>tr>:first-child:has(>.case-cellule)+*{box-shadow:inset -1px 0 0 var(--ligne),inset 0 -1px 0 var(--ligne)}
  .ecran-liste[data-actions-groupees] .colonne-figee>table>tbody>tr:has(input[type=checkbox][data-ligne]:checked:not(:disabled))>:first-child{box-shadow:inset 3px 0 0 var(--selection-marque)}
  .colonne-figee:has(>table>tbody>tr>td:not(:first-child) :focus-visible)>table>*>tr>*{left:auto}

  /* Bornée à `--h-liste` — les 3/4 de l'écran, toute la zone qui défile sur un téléphone —, JAMAIS sous le
     plancher `--h-liste-min`, l'en-tête et cinq lignes. Le user, 2026-10-06 : « une hauteur minimale avec
     le header en sticky, pour couvrir les écrans réduits ou le mode mobile ». À 60 % d'une fenêtre basse,
     on ne voyait que deux lignes ; c'est la page qui défile pour atteindre le tableau, et le tableau qui
     défile sous son en-tête. */
  .entete-figee{max-height:max(var(--h-liste),var(--h-liste-min));overflow-y:auto}
  @media (max-width:40rem){:root{--h-liste:var(--h-liste-telephone)}}
  .entete-figee>table>thead>tr>th{position:sticky;top:0;z-index:2;border-bottom-color:transparent;box-shadow:inset 0 -1px 0 var(--ligne)}
  .colonne-figee.entete-figee>table>thead>tr>:first-child,
  .colonne-figee.entete-figee>table>thead>tr>:first-child:has(>.case-cellule)+*{z-index:3}
  .colonne-figee.entete-figee[role=region]>table>thead>tr>:first-child:not(:has(>.case-cellule)),
  .colonne-figee.entete-figee[role=region]>table>thead>tr>:first-child:has(>.case-cellule)+*{box-shadow:inset -1px 0 0 var(--ligne),inset 0 -1px 0 var(--ligne)}
  .entete-figee:has(>table>tbody :focus-visible)>table>thead>tr>th{top:auto}

  /* LA LISTE QUI REMPLIT LE CADRE (`pleine_hauteur`, le user, 2026-09-30 : « à la taille du cadre,
     avec une hauteur mini au cas où »). Une hauteur « jusqu'au bas de la fenêtre » ne s'écrit pas en
     CSS pour un élément dont on ignore où il commence : c'est donc la PAGE qui tient dans la fenêtre,
     son contenu qui devient la zone qui défile, et chaque boîte entre ce contenu et le tableau qui
     s'étire en colonne pour lui passer la hauteur restante. Ce qui précède la liste — un bandeau, un
     titre — garde sa taille (`flex-shrink:0`). Le tableau ne descend pas sous `--h-liste` : les 3/4 de
     l'écran, et sur un téléphone toute la zone qui défile — on fait défiler jusqu'à ce que l'en-tête du
     tableau arrive sous les onglets, qui restent à l'écran, et le tableau défile sur ce qui reste (le
     user, 2026-10-06). Le contenu est un CONTENEUR (`container-type:size`) pour que `100cqh` mesure cette
     zone et rien d'autre. Mesuré avant de s'y fier : un élément `position:fixed` qu'il contient reste
     placé par rapport à l'écran (Chrome) — le conteneur ne change pas son repère.

     Une liste COURTE n'entre pas ici : le composant ne pose `.pleine-hauteur` qu'à partir de dix lignes
     (le user, 2026-10-03 : quatre utilisateurs, et la carte étirée jusqu'au bas de l'écran). Ces règles ne
     savent pas dire « jusqu'au bas de la fenêtre, jamais plus que le contenu » : mesuré au navigateur, six
     variantes — `flex:0 1 auto` laisse la page défiler sous une liste longue, `min-height:0` fait sortir la
     liste de sa carte en fenêtre basse, `max-height:max-content` la tient à son minimum. Une boîte flexible
     imbriquée tire sa hauteur minimale de la base de la liste, et il faudrait deux bases à la fois.

     Le cadre est la PAGE par défaut ; un `.cadre-pleine-hauteur` en tient lieu — une boîte de hauteur
     fixe, dont le contenu défile pareil. La vitrine s'en sert pour montrer l'option : sans lui, la
     chaîne changeait en colonne sa grille à trois colonnes, et la page de la vitrine défilait sur
     dix-neuf mille pixels (mesuré le 2026-09-30). Un cadre dans la page, et la page n'est plus le cadre. */
  .principal:has(.pleine-hauteur):not(:has(.cadre-pleine-hauteur)){height:100dvh}
  .principal:has(.pleine-hauteur):not(:has(.cadre-pleine-hauteur))>.contenu,
  .cadre-pleine-hauteur{display:flex;flex-direction:column;min-height:0;overflow-y:auto;container-type:size}
  .principal:has(.pleine-hauteur):not(:has(.cadre-pleine-hauteur))>.contenu>*,
  .cadre-pleine-hauteur>*{flex-shrink:0}
  .principal:has(.pleine-hauteur):not(:has(.cadre-pleine-hauteur))>.contenu :has(.pleine-hauteur),
  .cadre-pleine-hauteur :has(.pleine-hauteur){display:flex;flex-direction:column;flex:1 1 0;min-height:auto}
  .cadre-pleine-hauteur{height:var(--h-cadre-liste)}
  .entete-figee.pleine-hauteur{flex:1 1 0;min-height:var(--h-liste);max-height:none}
}

/* ---- Onglets ----
   Portés de la base fournie. Le soulignement orange marque l'onglet courant ; il est DOUBLÉ
   par un changement de couleur et de graisse du texte, parce qu'un trait de couleur seul
   porterait l'information à lui tout seul (SC 1.4.1).

   Le repère visuel se déclenche sur `aria-current`, jamais sur une classe : on ne peut donc
   pas styler l'état sans l'annoncer. Même règle que pour le menu.

   La barre défile en LARGEUR quand les onglets ne tiennent pas, et `overflow-x:auto` force
   `overflow-y` à `auto` : tout ce qui dépasse en hauteur la fait défiler aussi. Le trait gris est
   donc une ombre INTÉRIEURE, que le soulignement de l'onglet recouvre en restant dans la barre. La
   première écriture posait une bordure basse et faisait descendre chaque onglet d'un pixel dessous
   (`margin-bottom:-1px`) : 32 px de contenu pour 31 de haut, et une barre de défilement verticale
   vide chez qui les affiche toujours — relevée par le user le 2026-09-15, mesurée au navigateur.

   Douze pixels de part et d'autre d'un libellé, et non seize, depuis le 2026-10-01 : « Rôles
   temporaires » a remplacé « Exceptions », et la barre des paramètres débordait de 40 px à 1440 px de
   large — « Journal des actions » rogné, une barre de défilement sous les onglets. Mesuré : 1244 px de
   contenu pour 1204 de place ; 1172 après. Sous ~1400 px, elle défile encore, comme avant. */
.onglets{display:flex;gap:var(--e-1);padding:0 var(--e-6);background:var(--surface);box-shadow:inset 0 -1px 0 var(--ligne);overflow-x:auto}
.onglet{padding:var(--e-3);font-size:var(--fs-sm);font-weight:var(--gras-etiquette);color:var(--texte);text-decoration:none;white-space:nowrap;border-bottom:3px solid transparent}
.onglet:hover{color:var(--texte-fort);text-decoration:none}
.onglet[aria-current="page"]{color:var(--texte-fort);border-bottom-color:var(--marque)}
/* La NOTE d'un onglet — « aucun droit » sur celui que la démonstration montre fermé (planche CRM
   1a). En petit et au poids courant : elle précise le libellé, elle ne le concurrence pas. */
.onglet small{margin-left:var(--e-1);font-size:var(--fs-xs);font-weight:var(--gras-menu);color:var(--texte)}

@media (max-width:879px){
  .onglets{padding:0 var(--e-4)}
}

/* ---- L'attente visible ----
   Pendant un échange htmx, fragment-vif.js pose `aria-busy="true"` sur la zone visée, pour les
   lecteurs d'écran. Rien ne le montrait aux yeux : relevé par le user le 2026-09-28 sur « Déplacer
   une organisation », un choix, puis un aperçu qui ne bougeait pas pendant qu'il voyageait. La zone
   s'estompe donc, et le curseur dit qu'on attend — APRÈS 300 ms : une réponse rapide ne fait rien
   clignoter, et c'est le délai, plus que l'atténuation, qui rend la règle supportable. Sous
   « réduire les animations », le même délai sans fondu. Aucune roue qui tourne : une zone estompée
   dit ce qui va changer, un indicateur à part ne dirait que « quelque chose ». */
[aria-busy="true"]{cursor:progress;opacity:.55;transition:opacity var(--duree) ease 300ms}
@media (prefers-reduced-motion:reduce){
  [aria-busy="true"]{transition:opacity 0s 300ms}
}

/* ---- Période ----
   Sans script, deux champs date natifs (`.periode-champs`), en grille. Avec `periode.js`, un BOUTON à
   l'allure d'un champ dit la période et sa durée, et ouvre sous lui un calendrier de deux mois (le
   user, 2026-10-01, maquette « Choisir une période »). Le premier et le dernier jour sont des disques
   de la marque, la plage entre eux un ruban clair, aujourd'hui un cercle ; un jour hors des bornes est
   barré ET inerte — jamais la couleur seule. */
.periode{position:relative;margin-bottom:var(--e-4)}
.periode-champs{margin-bottom:0}
.periode-tete{display:flex;flex-direction:column;gap:var(--e-2);max-width:var(--l-boite-formulaire)}
.periode-etiquette{font-size:var(--fs-sm);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
/* La borne dite SOUS le bouton (« Jour inclus. Au plus un an : jusqu'au … ») : elle y reste avec le script,
   le calendrier barrant déjà les jours qu'elle exclut. */
.periode-borne{margin:var(--e-1) 0 0}
.periode-bouton{display:flex;align-items:center;gap:var(--e-2);min-height:var(--h-controle);padding:0 var(--e-3);
  border:1px solid var(--bord);border-radius:var(--radius);background:var(--bg);color:var(--texte-fort);
  font:var(--fs-base)/1.4 var(--font);text-align:left;cursor:pointer}
.periode-bouton[aria-expanded="true"]{background:var(--surface);border-color:var(--marque-encre);box-shadow:0 0 0 3px var(--halo)}
.periode-bouton:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.periode-texte{flex:1 1 auto}
.periode-duree{padding:0 var(--e-2);border-radius:var(--radius-pastille);background:var(--accent-bg);
  color:var(--marque-encre);font-size:var(--fs-xs);font-weight:var(--gras-etiquette);white-space:nowrap}
/* Le calendrier passe AU-DESSUS d'un pied collant (`z-index:5`) : plus large que la colonne des réglages
   de « Donner des droits temporaires », il filait sous « Ce qui change » et ses boutons, sa dernière rangée
   de jours coupée (relevé par le user le 2026-10-02). À valeur égale, le dernier de la page peint
   par-dessus — et le pied vient après. Sous les notifications (40), qui doivent rester lisibles. */
.periode-calendrier{position:absolute;left:0;top:calc(100% + var(--e-1));z-index:10;display:flex;flex-direction:column;gap:var(--e-3);
  padding:var(--e-4);border:1px solid var(--ligne);border-radius:var(--radius);background:var(--surface);box-shadow:var(--shadow)}
.periode-calendrier[hidden]{display:none}
.periode-raccourcis{margin:0}
.periode-mois-deux{display:grid;grid-template-columns:repeat(2,auto);gap:var(--e-6)}
.periode-mois-deux:not(:has(>.periode-mois+.periode-mois)){grid-template-columns:auto}
/* DANS UNE BOÎTE, le calendrier passe dans le flux : le corps d'une boîte défile (`overflow:auto`),
   et un calendrier posé en absolu y serait rogné au lieu de s'ouvrir. */
.carte-boite .periode-calendrier{position:static;box-shadow:none;margin-top:var(--e-2)}
.periode-mois-tete{display:flex;align-items:center;justify-content:space-between;gap:var(--e-2);min-height:var(--h-jour);margin-bottom:var(--e-2)}
.periode-mois-tete h3{flex:1 1 auto;margin:0;text-align:center;font-size:var(--fs-sm);font-weight:var(--gras-titre);color:var(--texte-fort);text-transform:capitalize}
.periode-nav{width:var(--h-jour);height:var(--h-jour);border:1px solid var(--ligne);border-radius:var(--radius-sm);background:var(--surface);
  color:var(--texte-fort);font:inherit;cursor:pointer}
/* `separate` et quatre pixels entre les semaines : le ruban d'une semaine ne colle pas à celui de la suivante
   — collés, deux semaines se lisaient comme un bloc. Pas d'écart entre les jours d'une semaine : le ruban y
   est continu. */
.periode-grille{border-collapse:separate;border-spacing:0 var(--e-1);-webkit-user-select:none;user-select:none}
/* Les règles des tableaux de liste (filets, fond d'en-tête) ne valent pas pour une grille de jours. */
.periode-grille :is(th,td){border:0;background:none}
/* Une semaine n'est pas une ligne de tableau : le survol générique (`tbody tr:hover`) la surlignait
   d'une bande, qu'on lisait comme une période (capture du user, 2026-10-01). Seul le jour se survole. */
.periode-grille tbody tr:hover{background:none}
.periode-grille th{width:var(--h-jour);padding-bottom:var(--e-1);font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte);text-align:center}
.periode-grille td{padding:0;text-align:center}
.periode-jour{width:var(--h-jour);height:var(--h-jour);border:0;border-radius:50%;background:none;color:var(--texte-fort);
  font:var(--fs-sm)/1 var(--font);font-variant-numeric:tabular-nums;cursor:pointer}
.periode-jour:hover:not(:disabled){background:var(--survol)}
.periode-jour:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.periode-jour[aria-current="date"]{box-shadow:inset 0 0 0 1.5px var(--texte-fort);font-weight:var(--gras-titre)}
/* LA PLAGE EN RUBAN (option A de la toile F6Ka, retenue par le user le 2026-10-04 — c'était déjà le dessin de
   la maquette « Période » validée, DP-1). Le fond pâle se posait sur le JOUR, un disque de 36 px dans une case
   de 43,6 : il restait 7,6 px de blanc entre deux jours (mesuré), et la période se lisait en carrés séparés. Il
   se pose désormais sur la CASE, et chaque case tire sa forme de ses VOISINES : un jour du milieu prend toute
   la case, arrondie au bord d'une semaine ou d'un mois ; une borne — le premier ou le dernier jour, ou le jour
   visé pendant le choix — ne prend que la moitié tournée vers la plage, si bien que le ruban part du centre
   de son disque. Lues par `:has()` et `+`, les voisines valent dans les deux sens, en glissant vers l'arrière
   compris, sans que le script ait à dire où le ruban commence. Une case vide précède le premier du mois. */
.periode-grille td:has(>:is(.periode-dans,.periode-apercu):not(.periode-vise)){background:var(--accent-bg)}
.periode-grille td:first-child:has(>:is(.periode-dans,.periode-apercu):not(.periode-vise)),
.periode-grille td:empty+td:has(>:is(.periode-dans,.periode-apercu):not(.periode-vise)){border-top-left-radius:var(--h-jour);border-bottom-left-radius:var(--h-jour)}
.periode-grille td:last-child:has(>:is(.periode-dans,.periode-apercu):not(.periode-vise)){border-top-right-radius:var(--h-jour);border-bottom-right-radius:var(--h-jour)}
.periode-grille td:has(>:is([aria-pressed="true"],.periode-vise)):has(+td>:is(.periode-dans,.periode-apercu,[aria-pressed="true"])){background:linear-gradient(to right,transparent 50%,var(--accent-bg) 50%)}
.periode-grille td:has(>:is(.periode-dans,.periode-apercu,[aria-pressed="true"]))+td:has(>:is([aria-pressed="true"],.periode-vise)){background:linear-gradient(to left,transparent 50%,var(--accent-bg) 50%)}
.periode-grille td:has(>:is(.periode-dans,.periode-apercu,[aria-pressed="true"]))+td:has(>:is([aria-pressed="true"],.periode-vise)):has(+td>:is(.periode-dans,.periode-apercu,[aria-pressed="true"])){background:var(--accent-bg)}
/* Le jour VISÉ pendant le choix du dernier : cerclé en pointillé tant qu'il n'est pas choisi. */
.periode-jour.periode-vise{border:1.5px dashed var(--marque-encre);background:var(--surface);font-weight:var(--gras-titre)}
.periode-jour[aria-pressed="true"]{background:var(--marque);color:var(--texte-fort);box-shadow:inset 0 0 0 1.5px var(--marque-encre);font-weight:var(--gras-titre)}
.periode-jour:disabled{color:var(--texte);opacity:.45;text-decoration:line-through;cursor:not-allowed}
.periode-pied{display:flex;align-items:center;justify-content:flex-end;gap:var(--e-3);padding-top:var(--e-3);border-top:1px solid var(--ligne)}
.periode-phrase{flex:1 1 auto;margin:0;font-size:var(--fs-sm);color:var(--texte-fort)}
/* LA BULLE au-dessus du jour visé : le nombre de jours là où l'œil est pendant le geste. Encre et fond
   inversés, pour qu'elle se détache de la grille ; elle ne prend aucun clic (le jour dessous reste
   visable). Sa flèche pointe vers le jour ; dessous, elle s'inverse. */
.periode-bulle{position:absolute;z-index:2;padding:var(--e-2) var(--e-3);border-radius:var(--radius);background:var(--texte-fort);color:var(--surface);text-align:center;white-space:nowrap;pointer-events:none;box-shadow:var(--shadow)}
.periode-bulle[hidden]{display:none}
.periode-bulle b{display:block;font-size:var(--fs-md);font-variant-numeric:tabular-nums}
.periode-bulle small{display:block;font-size:var(--fs-xs)}
.periode-bulle::after{content:'';position:absolute;left:50%;top:100%;margin-left:calc(var(--e-1) * -1.5);border:calc(var(--e-1) * 1.5) solid transparent;border-bottom:0;border-top-color:var(--texte-fort)}
.periode-bulle-dessous::after{top:auto;bottom:100%;border-top:0;border-bottom:calc(var(--e-1) * 1.5) solid var(--texte-fort)}
/* Étroit : les deux mois l'un sous l'autre — la flèche « mois suivant » vit dans l'en-tête du second. */
@media (max-width:879px){
  .periode-mois-deux{grid-template-columns:auto}
}

/* ---- Rechercher une entreprise ----
   Le champ de recherche dans l'annuaire des entreprises de l'État et son MENU, qui s'ouvre sous lui au fil
   de la frappe (Thierry, 2026-10-24 : « un menu qui s'affiche qui propose le nom des entreprises, SIRET et
   adresse […] il faut que je clique dessus pour valider »). Le menu est ACCROCHÉ au champ
   (`.recherche-entreprise-saisie`, la référence de position) et se pose PAR-DESSUS ce qui suit : il ne
   pousse pas le formulaire, comme le panneau d'un menu déroulant, dont il reprend le cadre. Il n'est
   visible que s'il a quelque chose à dire — une phrase, des options, l'attente — ; vide, il disparaît.
   Les options ont le dessin de « Choisir un utilisateur » : un filet entre les lignes, la marque à gauche
   de l'option survolée ou active (`aria-selected`). Dans une grille de champs, le bloc prend toute la
   largeur : il remplit les champs qui le suivent, il n'en est pas un. */
.form-grille>.recherche-entreprise{grid-column:1/-1}
.recherche-entreprise-saisie{position:relative;max-width:var(--l-boite-formulaire-large)}
.recherche-entreprise-menu{position:absolute;left:0;right:0;top:calc(100% + var(--e-1));z-index:4;display:none;
  max-height:var(--l-boite-formulaire);overflow:auto;padding:var(--e-2);
  background:var(--surface);border:1px solid var(--ligne);border-radius:var(--radius);box-shadow:var(--shadow)}
.recherche-entreprise-menu:has(.recherche-entreprise-resultats:not(:empty)){display:block}
.recherche-entreprise-compte{margin:0 0 var(--e-2);font-size:var(--fs-sm);color:var(--texte)}
.recherche-entreprise-resultats>.recherche-entreprise-compte:last-child{margin-bottom:0}
.recherche-entreprise-liste{list-style:none;margin:0;padding:0;border:1px solid var(--ligne);border-radius:var(--radius);overflow:hidden}
.recherche-entreprise-liste>li+li{border-top:1px solid var(--ligne)}
.recherche-entreprise-choix{display:flex;flex-direction:column;align-items:flex-start;gap:2px;min-height:var(--h-controle);padding:var(--e-2) var(--e-3);cursor:pointer}
.recherche-entreprise-choix:hover,.recherche-entreprise-choix[aria-selected="true"]{background:var(--survol);box-shadow:inset 3px 0 0 var(--marque)}
.recherche-entreprise-choix:hover b,.recherche-entreprise-choix[aria-selected="true"] b{color:var(--marque-encre)}
.recherche-entreprise-choix small{font-size:var(--fs-sm);color:var(--texte)}
/* L'ATTENTE de la recherche (le user, 2026-10-24 : « un loader serait le bienvenu »). « L'attente
   visible » estompe la zone qui se recharge ; ici, à la première recherche, la liste est VIDE — rien à
   estomper —, et l'annuaire de l'État met parfois plusieurs secondes. Une ligne dit donc qu'on cherche,
   avec un anneau qui tourne, pendant que la liste porte `aria-busy` (posé par fragment-vif.js) : en tête
   du menu, qu'elle ouvre, au-dessus d'une liste qui s'estompe. Visible passé 300 ms, comme l'estompe :
   une réponse rapide ne fait rien clignoter. Sous « réduire les animations », l'anneau reste immobile. */
.recherche-entreprise-attente{display:none;align-items:center;gap:var(--e-2);margin:0 0 var(--e-2);font-size:var(--fs-sm);color:var(--texte)}
.recherche-entreprise-menu:has(.recherche-entreprise-resultats[aria-busy="true"]){display:block}
/* Vide, le menu ne s'ouvre pour l'attente qu'avec elle, passé 300 ms : sinon un cadre vide clignoterait. */
.recherche-entreprise-menu:has(.recherche-entreprise-resultats[aria-busy="true"]:empty){animation:recherche-entreprise-attente 0s 300ms both}
.recherche-entreprise-menu:has(.recherche-entreprise-resultats[aria-busy="true"]) .recherche-entreprise-attente{display:flex;animation:recherche-entreprise-attente 0s 300ms both}
.recherche-entreprise-attente::before{content:'';flex:none;width:var(--e-4);height:var(--e-4);border:2px solid var(--ligne);border-top-color:var(--marque);border-radius:50%;animation:recherche-entreprise-tourne .8s linear infinite}
@keyframes recherche-entreprise-attente{from{visibility:hidden}to{visibility:visible}}
@keyframes recherche-entreprise-tourne{to{transform:rotate(1turn)}}
@media (prefers-reduced-motion:reduce){
  .recherche-entreprise-attente::before{animation:none}
}

/* ---- Choisir un utilisateur ----
   La recherche et le filtre par société, en GET, puis les premiers qui correspondent — chacun un LIEN
   qui le choisit (le user, 2026-10-01, maquette « Choisir un utilisateur »). La liste est une carte
   légère : un filet entre les lignes, le survol de la marque comme « choisir avec aperçu », l'anneau
   de focus DANS la ligne pour ne pas déborder du cadre arrondi. */
.choix-utilisateur{margin-bottom:var(--e-4)}
.choix-utilisateur-barre .champ:first-of-type{flex:0 1 var(--l-donnee)}
.choix-utilisateur-resultats{max-width:var(--l-boite-formulaire-large)}
.choix-utilisateur-compte{margin:0 0 var(--e-2);font-size:var(--fs-sm);color:var(--texte)}
.choix-utilisateur-liste{list-style:none;margin:0;padding:0;border:1px solid var(--ligne);border-radius:var(--radius);background:var(--surface);overflow:hidden}
.choix-utilisateur-liste>li+li{border-top:1px solid var(--ligne)}
.choix-utilisateur-liste :is(a,button){display:flex;align-items:center;gap:var(--e-3);width:100%;min-height:var(--h-controle);padding:var(--e-2) var(--e-3);border:0;background:none;color:inherit;font:inherit;text-align:left;text-decoration:none;cursor:pointer}
.choix-utilisateur-liste :is(a,button):hover{background:var(--survol);box-shadow:inset 3px 0 0 var(--marque)}
.choix-utilisateur-liste :is(a,button):hover .qui-texte b{color:var(--marque-encre)}
.choix-utilisateur-liste :is(a,button):focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.choix-utilisateur-liste button[aria-current="true"]{background:var(--accent-bg);box-shadow:inset 3px 0 0 var(--marque)}
.choix-utilisateur-liste .qui-texte small{display:block}
/* DANS UNE LIGNE (`choix-en-boite.js`) : le bouton prend le dessin d'un champ — la liste qu'il
   remplace en était un —, avec la ligne du collègue choisi ; la fenêtre reprend la barre et la liste du
   composant. La liste de la fenêtre défile seule, la recherche reste sous les yeux. */
.choix-en-boite-bouton{display:flex;align-items:center;gap:var(--e-2);width:100%;min-height:var(--h-controle);padding:var(--e-1) var(--e-3);border:1px solid var(--bord);border-radius:var(--radius);background:var(--bg);color:var(--texte-fort);font:var(--fs-base)/1.4 var(--font);text-align:left;cursor:pointer}
.choix-en-boite-bouton>.qui-texte{flex:1 1 auto;min-width:0}
.choix-en-boite-bouton small{display:block;font-family:var(--font);font-size:var(--fs-xs);color:var(--texte)}
.choix-en-boite-bouton:focus-visible{outline:none;background:var(--surface);border-color:var(--marque-encre);box-shadow:0 0 0 3px var(--halo)}
.champ.en-erreur .choix-en-boite-bouton,.choix-en-boite-bouton[aria-invalid="true"]{border-color:var(--err)}
.choix-en-boite[open]{width:min(var(--l-boite-formulaire-large),100%);max-height:var(--h-boite-pleine);padding:var(--e-6);gap:var(--e-3)}
.choix-en-boite form{display:flex;flex-direction:column;gap:var(--e-3);min-height:0}
.choix-en-boite-tete{padding-right:var(--e-8)}
.choix-en-boite-tete h2{margin:0;font-size:var(--fs-lg);color:var(--texte-fort)}
.choix-en-boite p{margin:0}
.choix-en-boite .choix-utilisateur-liste{overflow:auto;min-height:0}
.choix-en-boite .actions{display:flex;justify-content:flex-end}
/* Dans un formulaire : l'invite « Choisir un utilisateur… » a un avatar gris — rien n'est encore choisi —,
   et l'email d'un compte hors de la liste ferme la fenêtre, séparé de la liste par un filet. */
.avatar.choix-en-boite-invite{background:var(--neutre-bg);color:var(--texte-fort)}
/* Le poste — les rôles — sous le nom, dans la police du texte ; et les trois filtres de la fenêtre sur une
   ligne quand la place le permet : « Rôle » passait seul dessous. */
.choix-utilisateur-poste{display:block;font-size:var(--fs-xs);color:var(--texte-fort)}
.choix-en-boite .choix-utilisateur-barre{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,calc(var(--l-donnee) / 2)),1fr));gap:var(--e-3)}
.choix-en-boite .choix-utilisateur-barre .champ{margin:0}
.choix-utilisateur-liste .qui-texte{flex:1 1 auto}
.choix-utilisateur-lieux{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--e-1)}
.choix-utilisateur-lieux .badge{margin:0}
.choix-utilisateur-question{margin:0 0 var(--e-2);font-size:var(--fs-sm);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.choix-utilisateur>.qui{max-width:var(--l-boite-formulaire-large);padding:var(--e-2) var(--e-3);border:1px solid var(--ligne);border-radius:var(--radius);background:var(--surface)}
.choix-utilisateur>.qui>.qui-texte{flex:1 1 auto}

/* ---- Pilules de filtre actif ----
   Elles disent ce qui est POSÉ, après un rechargement, sans qu'on ait à relire cinq champs.
   Chaque pilule est un LIEN qui retire son propre filtre en conservant les autres : retirer
   une condition ne doit pas tout remettre à zéro.

   Le « × » est décoratif (`aria-hidden`) et doublé d'un libellé hors écran : seul, il serait
   annoncé « fois » ou pas du tout selon le lecteur d'écran. */
.pilules{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2);margin-bottom:var(--e-4)}
.pilule{display:inline-flex;align-items:center;gap:var(--e-2);min-height:var(--e-6);
  padding:var(--e-1) var(--e-3);border:1px solid var(--bord);border-radius:var(--radius-pastille);
  background:var(--surface);color:var(--texte-fort);font-size:var(--fs-xs);
  font-weight:var(--gras-etiquette);text-decoration:none}
.pilule:hover{border-color:var(--marque-encre);color:var(--marque-encre);text-decoration:none}

/* Une pilule peut aussi AGIR — un `<button>` de bascule dans un formulaire qui porte le jeton :
   c'est la forme de « Vos organisations », sur l'écran des organisations. Le navigateur ne fait
   hériter à un bouton ni la police ni l'interligne de la page ; sans ces deux déclarations, la
   barre s'affichait dans la police système à côté de pilules-liens par ailleurs identiques.
   `cursor` est qualifié par l'ÉLÉMENT et non posé sur la classe : un lien l'a déjà, et la forme
   non actionnable — un `<span class="pilule">` — ne doit pas promettre un clic. */
button.pilule{font-family:inherit;line-height:inherit;cursor:pointer}
/* Et la suite d'un chemin, en secondaire DANS la pilule, reprend l'échelle de la pilule.
   `.discret` porte une taille ABSOLUE (--fs-sm, 13 px) : dans une pilule qui écrit en 12 px,
   la suite du chemin se retrouvait plus GRANDE que la société qu'elle seconde, et la pilule
   1,55 px plus haute que ses voisines — mesuré au navigateur sur la vitrine, 30,14 px contre
   28,59. Seule la couleur de `.discret` est voulue ici ; sa taille est celle du contenant.
   Même correction scopée que `.vitrine-extrait > .discret`, pour la même raison. */
.pilule .discret{font-size:inherit;line-height:inherit}
/* Des pilules À COCHER : une VALEUR de formulaire — ni une adresse (le lien), ni un geste (le bouton).
   Nées sur « Donner une exception » (le user, 2026-09-30), pour la durée : un, trois, six ou douze
   mois. Un VRAI radio dans l'étiquette, masqué : les flèches passent d'une pilule à l'autre, le
   choix part avec le formulaire, sans script. La cochée se voit comme la courante — fond ET
   contour, jamais la couleur seule —, et l'anneau de focus se pose sur la pilule, le radio étant
   invisible. Le groupe se nomme par la légende de son `fieldset`. */
label.pilule{cursor:pointer;position:relative}
.pilule>input[type=radio]{position:absolute;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
.pilule:has(>input:checked){background:var(--action);border-color:var(--action);color:var(--sur-action)}
.pilule:has(>input:focus-visible){outline:2px solid var(--focus);outline-offset:2px}
.pilule:has(>input:disabled){opacity:.5;cursor:not-allowed}
.champ>.pilules{margin-bottom:0}
/* DES PILULES JOINTES — un contrôle segmenté : les choix d'UNE question collés en une seule pièce, le
   coché en plein. Pour deux à six réponses posées DANS une ligne, où des pilules espacées se liraient
   comme autant de filtres indépendants (la ligne ouverte de « Sécurité », maquette A3, 2026-10-03).
   Un nombre dans une pilule (`small`) dit ce que le choix donnerait. L'anneau de focus passe DEDANS :
   le conteneur coupe ce qui dépasse, pour garder ses coins arrondis.
   Trop étroites pour une ligne — un téléphone —, elles passent à la ligne au lieu de déborder : les
   séparations sont des ombres à GAUCHE et AU-DESSUS de chaque pilule, que le conteneur coupe sur ses
   bords, si bien qu'une seconde rangée garde ses filets. Un `border-left` n'en dessinait aucun. */
.pilules.pilules-jointes{display:inline-flex;flex-wrap:wrap;gap:0;max-width:100%;margin:0;border:1px solid var(--bord);border-radius:var(--radius-sm);overflow:hidden;background:var(--surface)}
.pilules-jointes>.pilule{flex:1 0 auto;justify-content:center;min-height:var(--h-controle-sm);padding:0 var(--e-3);border:0;border-radius:0;font-size:var(--fs-sm);white-space:nowrap;
  box-shadow:-1px 0 0 var(--ligne),0 -1px 0 var(--ligne)}
.pilules-jointes>.pilule>small{font-size:var(--fs-xs);font-weight:normal;opacity:.8}
.pilules-jointes>.pilule:has(>input:focus-visible){outline-offset:-3px}
/* « AUTRE » RÉVÈLE SA PRÉCISION — le groupe `.avec-precision`, la pilule `.pilule-precisee`, le champ
   `.precision` juste après les pilules. Le champ libre n'est là que quand la liste fermée n'a pas
   suffi (le user, 2026-10-01 : « n'affiche l'input pour autre que s'il est sélectionné »). En CSS
   pur ; sans `:has()`, il reste affiché, jamais un champ qu'on ne peut plus atteindre. Un champ à
   l'intérieur d'un `fieldset.champ` reprend l'écart d'un champ, la légende ne le colle pas. */
@supports selector(:has(*)){
  .avec-precision:not(:has(.pilule-precisee>input:checked))>.precision{display:none}
}
/* Un ENCART sous les pilules (maquette B, 2026-10-02) : sans lui, « Précisez » se lisait comme un champ de
   plus, détaché de « Autre », qui seul le fait apparaître. */
.avec-precision>.precision{margin:var(--e-3) 0 0;background:var(--entete-bg);padding:var(--e-3);
  border:1px solid var(--ligne);border-radius:var(--radius-sm)}


/* La divergence saisie/appliqué du journal : une date illisible n'a PAS filtré, et ça se dit.
   L'encre d'avertissement, hors de son fond : tokens.css ne la mesure que sur `--warn-bg` ;
   ici elle se pose sur le fond de page ou la surface — 5,90:1 et 6,38:1 en clair, 9,10:1 et
   8,21:1 en sombre. Le MOT porte l'information, jamais la couleur seule (SC 1.4.1). */
.filtre-ignore{font-size:var(--fs-sm);font-weight:var(--gras-etiquette);color:var(--warn);margin-bottom:var(--e-2)}

/* Champ de filtre effaçable. L'enveloppe et la croix sont POSÉES PAR JAVASCRIPT
   (fragment-vif) : sans script, le champ reste un champ ordinaire — le motif du champ de mot
   de passe, jusque dans les cotes (36×36, au-delà des 24×24 du SC 2.5.8). La croix d'un champ
   de DATE se décale d'un cran : à droite vit déjà le sélecteur natif du navigateur, et deux
   commandes empilées au même endroit se volent les clics. */
.champ-effacable{position:relative;display:block}
.champ-effacable input{padding-right:var(--e-12)}
.effaceur{position:absolute;right:var(--e-1);top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:var(--h-icone);height:var(--h-icone);padding:0;border:none;background:none;color:var(--texte);cursor:pointer;border-radius:var(--radius-sm);font-size:var(--fs-md);line-height:1}
.effaceur:hover{color:var(--texte-fort)}
.champ-effacable input[type=date]{padding-right:var(--e-12)}
.champ-effacable input[type=date]~.effaceur{right:var(--e-8)}

/* CHOISIR AVEC APERÇU — composant `choix-apercu` de la vitrine. La liste de propositions à
   gauche, l'effet du choix à droite, sur UNE page : on choisit d'abord, l'aperçu suit. La
   colonne de choix est collante et bornée en hauteur, la liste défile — à vingt-quatre
   propositions, une liste qui pousse l'aperçu hors de l'écran défait exactement ce que ce
   composant est venu régler. Sous 860 px les deux colonnes s'empilent, l'aperçu dessous.
   Né sur l'écran « Déplacer une organisation », qui en est la première instance. */
/* Flex et retour à la ligne, pas une grille à point de rupture : c'est la PLACE DISPONIBLE qui
   décide — dans la vitrine, dont l'aperçu est plus étroit que l'écran, comme sur une page
   entière. La colonne de choix garde sa largeur de token ; l'aperçu prend tout le reste, et
   passe dessous quand la ligne ne tient plus les deux. */
.choix-apercu{display:flex;flex-wrap:wrap;gap:var(--e-4);align-items:flex-start}
.choix-apercu-liste{flex:1 1 var(--l-colonne-propositions);max-width:100%;position:sticky;top:var(--e-4)}
/* Le titre de la liste garde le rang d'un titre de carte quand un fragment l'enveloppe. Sur
   « Ajouter une société ou un service », `#ajout-arbre` — la région que la nature réécrit — le
   sépare de sa carte, et `.carte>h2` ne le voyait plus : « Où le ranger ? » en 18 px et 600 sous
   « Que voulez-vous ajouter ? » en 16 px et 700, deux questions de même rang écrites à deux rangs
   (mesuré le 2026-09-15). La maquette 3c les écrit au même. Les autres instances posent leur
   titre en enfant direct de la carte : rien n'y change. */
.choix-apercu-liste h2{font-size:var(--fs-md);font-weight:var(--gras-titre)}
/* « L'autre enfant », quel qu'il soit : l'aperçu lui-même dans la recette, ou l'enveloppe qu'un
   écran pose autour de `#apercu` pour que htmx le remplace en place. */
.choix-apercu>:not(.choix-apercu-liste){flex:999 1 var(--l-donnee);min-width:0}
/* Sur un petit écran, une colonne collante de vingt-six rem cacherait l'aperçu passé dessous. */
@media (max-width:860px){.choix-apercu-liste{position:static}}
.propositions{max-height:var(--h-liste-propositions);overflow-y:auto;margin:0 calc(-1 * var(--e-4));
  border-top:1px solid var(--ligne);border-bottom:1px solid var(--ligne)}
.propositions-compte{margin:0;padding:var(--e-2) var(--e-4);background:var(--entete-bg);
  border-bottom:1px solid var(--ligne);font-size:var(--fs-xs);color:var(--texte)}

/* Une PROPOSITION : la case, le chemin en gris, le dernier segment en gras. Le chemin entier
   serait illisible répété vingt fois — c'est le dernier segment qu'on cherche des yeux. */
.proposition{display:flex;align-items:center;gap:var(--e-3);min-height:var(--h-controle);
  padding:var(--e-2) var(--e-4);border-bottom:1px solid var(--ligne);cursor:pointer}
.proposition:last-child{border-bottom:0}
.proposition:hover{background:var(--survol)}
.proposition:has(input:checked){background:var(--survol);box-shadow:inset 3px 0 0 var(--marque)}
/* UNE PROPOSITION QUI PORTE UN GESTE : la case et son texte forment un `<label>` interne, le
   geste vit à côté. Sans ce sous-label, un lien placé dans le `<label>` de la ligne basculerait
   la case en plus de suivre son ancre — c'est déjà pourquoi `.proposition-deja` est un `div`.
   Première instance : l'écran d'invitation, dont chaque ligne cochée porte « Régler ses rôles ». */
.proposition-case{display:flex;align-items:flex-start;gap:var(--e-3);flex:1;min-width:0;cursor:pointer}
/* LA CASE D'UNE PROPOSITION a la taille et la teinte d'une case du composant « cases ».
   Sans cette règle, elle gardait le rendu du NAVIGATEUR : mesuré, 13×13 px en bleu système à
   gauche, contre 18×18 px en orange de la marque à droite, sur le même écran — deux sortes de
   cases pour un seul geste. `.case input` (base.css) et `.case-cellule input` le posaient déjà ;
   `.proposition` avait été oublié. Vaut aussi pour les radios de « rattacher » et de « déplacer
   une organisation », qui passent de 13 à 18 px. */
.proposition input[type=checkbox],.proposition input[type=radio]{width:var(--h-case);height:var(--h-case);
  margin:0;flex:none;accent-color:var(--marque)}
.proposition-corps{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.proposition-chemin{font-size:var(--fs-sm);color:var(--texte)}
.proposition-chemin b{font-size:var(--fs-base);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
/* Une proposition refusée est ANNONCÉE, pas retirée : une entrée absente sans explication se
   cherche, et l'on finit par croire que le socle interdit ce choix-là. L'état NEUTRE dit un
   fait sans alerte — « position actuelle ». */
.proposition-etat{font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--err)}
.proposition-etat-neutre{color:var(--texte);font-weight:400}
/* L'ÉCHO des choix faits dans l'autre colonne, en PASTILLES et non en texte gris. Le client
   l'a dit : « on les voit apparaître sur le volet de gauche mais c'est assez léger ». Une
   pastille se lit comme un objet posé ; une énumération grise se lit comme une note. */
.proposition-roles{display:flex;flex-wrap:wrap;gap:var(--e-1);margin-top:2px}
.proposition-roles:empty{display:none}
/* Le filtre de la liste, POSÉ PAR LE SCRIPT (inviter.js) au-delà du seuil que le gabarit
   annonce — jamais rendu par le serveur, qui en ferait un contrôle inerte sans script. */
.filtre-propositions{width:100%;height:var(--h-controle);padding:0 var(--e-3);
  border:1px solid var(--bord);border-radius:var(--radius-sm);background:var(--bg);
  color:var(--texte-fort);font:var(--fs-sm)/1.4 var(--font);margin:0 0 var(--e-3)}
.proposition-actuelle{background:var(--entete-bg)}
/* La ligne qui RÉPOND à la frappe — « cette personne est déjà là » —, à distinguer du gris de
   `.proposition-actuelle`, qui dit « rien à faire ici ». Elle porte un geste, donc elle se
   remarque ; et `align-items:flex-start` parce qu'elle a trois lignes de texte à côté d'un
   bouton d'une seule. */
.proposition-deja{background:var(--accent-bg);align-items:flex-start;cursor:default}
.proposition-deja:hover{background:var(--accent-bg)}
/* Ce qui est CHERCHÉ, dans une liste filtrée. Un fond, jamais une couleur de texte seule, qui
   ne porterait rien (SC 1.4.1) — et un fond TRANSPARENT, qui fonce ce qu'il recouvre au lieu de
   le remplacer.

   La première écriture posait `var(--accent-bg)` opaque, la teinte même de `.proposition-deja` :
   mesuré au navigateur, le fond de la marque et celui de sa ligne rendaient tous deux
   `rgb(253,240,221)` — deux marques sur quatre étaient invisibles, précisément sur la ligne que
   la maquette met en avant. Le commentaire annonçait ce piège au-dessus du code qui y tombait. */
mark{background:color-mix(in srgb, var(--marque) 42%, transparent);color:var(--texte-fort);
  border-radius:3px;padding:0 2px}
/* Refusée : choisissable — l'aperçu dit pourquoi et la refuse pour de bon —, mais le dernier segment
   perd son gras : l'œil passe d'abord sur ce qui est possible. */
.proposition-refusee .proposition-chemin b,.proposition-refusee .arbre-nom b{font-weight:400;color:var(--texte)}
/* Une ligne dont le radio est INERTE — la position actuelle, une place que la règle interdit —
   ne promet pas le clic que le pointeur annonçait. */
.proposition:has(input:disabled){cursor:default}
/* LA FORME EN ARBRE, en deux écritures. L'arbre ENTIER — « Ajouter une société ou un service » —
   pose une ligne du composant « Arbre » dans le corps de chaque proposition : le nom porte le
   retrait et les filets (section Arbre, plus haut), la ligne ne reçoit aucune profondeur, et le
   radio reste dans sa colonne. L'arbre sous un FILTRE — l'écran d'invitation — décale la ligne
   elle-même et garde le chemin écrit sous chaque nom : un filtre qui retire les parents ferait
   mentir des filets, et c'est alors le chemin qui porte la hiérarchie. La profondeur arrive du
   gabarit en NOMBRE sans unité (`--profondeur`), la longueur d'un cran reste ici — HabillageTest
   refuse une longueur écrite dans un gabarit —, et le décalage porte sur le CONTENU, pas sur la
   ligne : le filet et le fond de la ligne choisie restent pleine largeur, l'œil suit la colonne. */
.propositions-arbre .proposition{padding-left:calc(var(--e-4) + var(--profondeur,0) * var(--e-4))}
/* LA LISTE ENTIÈRE, l'aperçu collant — `.choix-apercu-entier`, l'inverse du comportement par
   défaut, sur le conteneur. Pour un arbre qu'on lit pour choisir où ranger : une place n'a de sens
   qu'avec ses branches, et une boîte bornée coupe la hiérarchie en tranches. Mesuré le 2026-09-14
   à 1440 px sur « Ajouter une société ou un service » : la boîte de 26rem montrait cinq places et
   demie sur neuf, dans une colonne de 344 px où les chemins passaient à la ligne. La colonne de la
   liste s'élargit donc, cesse d'être collante et de défiler ; l'autre colle à sa place, et le
   récapitulatif comme son bouton suivent la lecture. Empilées, rien ne colle : l'aperçu est le
   dernier enfant, il n'a plus de place où glisser. Au-delà de quelques dizaines de places, c'est le
   FILTRE de l'écran de déplacement qu'il faudra, jamais une boîte qui couperait les branches.

   UN MODIFICATEUR, et pas `:has(.propositions-arbre)` — la première écriture. La forme en arbre ne
   dit pas à elle seule qu'il faut tout montrer : l'écran d'invitation liste aussi un arbre, garde
   sa liste bornée, et empile à droite un panneau de rôles par organisation, plus haut que la
   fenêtre — une colonne collante l'y aurait coupé. Relevé par la session qui porte cet écran,
   avant la fusion des deux branches. Et l'aperçu ne doit coller que s'il tient dans la fenêtre. */
.choix-apercu-entier>.choix-apercu-liste{flex:1 1 var(--l-colonne-arbre);position:static}
.choix-apercu-entier>:not(.choix-apercu-liste){flex:1 1 var(--l-donnee);position:sticky;top:var(--e-4)}
.choix-apercu-entier .propositions{max-height:none;overflow-y:visible}

/* L'APERÇU : une colonne de cartes, chacune un effet du choix. */
.apercu{display:flex;flex-direction:column;gap:var(--e-4)}
/* Une personne nommée, en gélule : à quatorze noms, une énumération séparée par des virgules ne
   se parcourt pas — on cherche UN nom, pas la liste. */
.personne-visible{display:inline-block;padding:2px var(--e-3);margin:0 var(--e-2) var(--e-2) 0;
  border-radius:var(--radius-gelule);background:var(--neutre-bg);border:1px solid var(--ligne);
  font-size:var(--fs-sm);color:var(--texte-fort)}

/* LE DÉCOMPTE D'UN GESTE — composant `decompte` de la vitrine : les chiffres nets AVANT ce qui
   nomme. Le signe est DÉCORATIF (`aria-hidden`) et redondant avec le verbe — « perd »,
   « obtient », « inchangées » : la couleur et le glyphe ne portent donc jamais seuls
   l'information, ce que le critère 1.4.1 exige et qu'un daltonien vérifie sans y penser. Le
   signe ne prend sa COULEUR que lorsqu'il y a quelque chose à signaler : à zéro, il tient la
   place et nomme la catégorie, en gris. */
.decompte{display:flex;flex-wrap:wrap;gap:var(--e-2) var(--e-6);align-items:baseline;
  margin:0 0 var(--e-4);font-size:var(--fs-sm);color:var(--texte)}
.decompte b{font-size:var(--fs-lg);font-weight:var(--gras-titre);color:var(--texte-fort);
  font-variant-numeric:tabular-nums;margin-right:2px}
.decompte-part{display:inline-flex;align-items:baseline;gap:var(--e-2)}
.decompte-signe{display:inline-flex;align-items:center;justify-content:center;
  width:var(--h-signe);height:var(--h-signe);flex:0 0 var(--h-signe);border-radius:var(--radius-gelule);
  background:var(--neutre-bg);border:1px solid var(--ligne);
  font-size:var(--fs-sm);font-weight:var(--gras-titre);color:var(--texte);align-self:center}
.decompte-perd .decompte-signe{background:var(--err-bg);border-color:var(--err-bg);color:var(--err)}
.decompte-gagne .decompte-signe{background:var(--ok-bg);border-color:var(--ok-bg);color:var(--ok)}

/* CASES À COCHER FILTRABLES — composant `cases` de la vitrine : un choix MULTIPLE dont la
   liste peut être longue. Sous huit entrées, des cases et rien de plus ; au-delà, le bloc se
   borne en hauteur, un filtre au-dessus MASQUE des lignes sans les réécrire — la case cochée
   reste cochée —, et la rangée des choix reste visible hors du défilement (cases.js). Deux
   colonnes tant que la place le permet. Né sur les rôles du rattachement, première instance. */
.cases{border:1px solid var(--ligne);border-radius:var(--radius-sm);padding:0;margin:0;min-width:0}
.cases-tete{display:flex;align-items:center;justify-content:space-between;gap:var(--e-3);flex-wrap:wrap;
  padding:var(--e-2) var(--e-4);border-bottom:1px solid var(--ligne);background:var(--entete-bg);
  border-radius:var(--radius-sm) var(--radius-sm) 0 0;font-size:var(--fs-sm);color:var(--texte)}
.cases-tete strong{font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.cases-filtre{height:var(--h-controle-sm);padding:0 var(--e-3);border:1px solid var(--bord);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--texte-fort);font:var(--fs-sm)/1.4 var(--font);min-width:0;flex:1 1 var(--l-champ-grille)}
.cases[data-cases] .cases-corps{max-height:var(--h-liste-cases);overflow-y:auto}
.cases-liste{columns:2;column-gap:var(--e-6);padding:var(--e-3) var(--e-4)}
.cases-liste .case-ligne{break-inside:avoid}
/* Un bloc de champ qui SUIT une liste de cases s'en écarte comme de tout autre champ : la liste n'a
   pas de marge basse, et « Pourquoi » touchait la dernière carte (« Donner une exception »,
   2026-09-30). Posée sur la paire et non sur `.cases` : les autres écrans rangent la liste dans des
   panneaux qui l'espacent déjà — aucun n'y fait suivre un `.champ`. */
.cases+.champ{margin-top:var(--e-4)}
@media (max-width:640px){.cases-liste{columns:1}}

/* LA FORME « EN CARTES » (`.cases-cartes`, variante « Forme » de la vitrine) — quand chaque entrée
   a une seconde ligne à dire : les modules qu'un rôle touche. Deux planches la dessinent pareil,
   « Fiche d'une personne » (état 8) et « Rattacher quelqu'un » : pas de cadre, le panneau qui la
   porte en tient lieu ; les cochées ÉPINGLÉES en tête (`.cases-epingles`), sur le fond de survol,
   hors du défilement et hors de portée du filtre — à quarante rôles, on ne perd jamais de vue ce
   qu'on a choisi ; les autres dessous, derrière un filet, en grille — trois colonnes à la largeur
   d'une fiche. Une carte fait 52 px de haut sur sa planche, 6 et 10 px de marge intérieure : le nom,
   les modules dessous, et la carte ENTIÈRE est la cible de la case.

   `min()` dans la grille : une colonne de `--l-role` ne tient pas dans un écran de 320 px moins ses
   gouttières, et la grille débordait la page plutôt que de rétrécir. */
.cases-cartes{border:0;display:flex;flex-direction:column;gap:var(--e-2)}
.cases-cartes .cases-tete{padding:0;border:0;border-radius:0;background:transparent;gap:var(--e-4)}
.cases-cartes .cases-tete:empty{display:none}
.cases-epingles,.cases-cartes .cases-liste{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--l-role),100%),1fr));
  gap:var(--e-1) var(--e-4);align-content:start}
.cases-cartes .cases-corps{border-top:1px solid var(--ligne)}
.cases-cartes[data-cases] .cases-corps{max-height:var(--h-liste-cartes)}
.cases-cartes .cases-liste{columns:auto;padding:var(--e-2) 0 0}
.cases-cartes .case-ligne{margin:0}
.cases-cartes .case{align-items:flex-start;gap:calc(var(--e-1) * 2.5);min-height:calc(var(--e-12) + var(--e-1));
  padding:calc(var(--e-1) * 1.5) calc(var(--e-1) * 2.5);border-radius:var(--radius-sm);box-sizing:border-box;
  font-size:var(--fs-base);color:var(--texte-fort)}
.cases-cartes .case input{flex:none;margin:2px 0 0}
.cases-cartes .case>span{display:flex;flex-direction:column;min-width:0}
.cases-cartes .case small{font-size:var(--fs-xs);color:var(--texte);line-height:1.3}
.cases-epingles .case{background:var(--survol)}
/* Une carte COCHÉE prend le fond des épinglées, où qu'elle soit : sans script, ou dans un groupe qui
   ne s'épingle pas (« Ses rôles dans ses autres sociétés », fiche d'une personne). */
.cases-cartes .case:has(>input:checked){background:var(--survol)}
/* LE FILTRE ÉTIQUETÉ (`data-cases-etiquette`) : cases.js enveloppe le champ dans un `label` qui
   porte le texte VISIBLE — « Filtrer les rôles » reste lisible pendant qu'on tape, là où un texte
   d'attente s'efface à la première lettre. À côté d'un titre, le champ garde sa largeur de planche ;
   seul sur sa ligne (« Rattacher quelqu'un »), il la prend toute. */
.cases-filtre-etiquette{display:flex;flex:none;align-items:center;gap:var(--e-2);white-space:nowrap;
  font-size:var(--fs-sm);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.cases-filtre-etiquette .cases-filtre{flex:none;width:var(--l-filtre-cases);font-weight:normal}
.cases-tete>.cases-filtre-etiquette:only-child,
.cases-tete>.cases-filtre-etiquette:only-child .cases-filtre{flex:1;width:auto}

/* Une ligne de changement dans la colonne « Ce qui a changé » du journal : une par champ,
   en petit — c'est un détail, pas le contenu. La règle qui interdit aux valeurs longues d'y
   entrer vit dans JournalExtension ; la feuille ne fait que composer les lignes. */
.changement{display:block;font-size:var(--fs-xs);color:var(--texte)}
/* Le dépliant des lignes repliées est `.depliant-discret`, le même que dans un encart —
   sa règle vit avec l'encart, plus bas. */

/* ---- Le panneau de rôles d'une organisation, dans l'aperçu ----
   UNE carte, une section par organisation cochée. La forme d'avant empilait un `<details>` par
   organisation À MÊME LE FOND DE PAGE : le composant « dépliant d'une rangée » (`.edition`) sorti
   de son contexte, dont le `<summary>` est en `inline-flex` bordé parce qu'il est fait pour vivre
   DANS une ligne. Six barres de largeurs inégales flottaient, sans lien visuel avec la colonne
   qui les commandait.

   La section est focalisable par script (`tabindex="-1"`) : cocher une organisation, ou suivre
   « Régler ses rôles », y pose le focus — le nom de l'organisation est alors annoncé avant ses
   rôles. L'anneau n'apparaît que si le navigateur juge le focus visible, c'est-à-dire après une
   activation au CLAVIER (SC 2.4.7) ; à la souris, rien ne clignote. */
.panneau-role{border-top:1px solid var(--ligne);padding:var(--e-4) 0}
.panneau-role:first-of-type{border-top:0;padding-top:0}
.panneau-role:last-of-type{padding-bottom:0}
.panneau-role>h3{font-size:var(--fs-base);font-weight:var(--gras-titre);color:var(--texte-fort);margin:0 0 var(--e-3)}
.panneau-role>h3 small{display:block;font-size:var(--fs-xs);font-weight:400;color:var(--texte)}
/* PAS D'ANNEAU sur la section, jamais — c'est le MARQUEUR (`.panneau-role-vise`, ci-dessous)
   qui dit où le focus est allé.

   La première écriture posait un anneau sous `:focus-visible`, en comptant sur le navigateur
   pour ne le dessiner qu'au clavier. Mesuré dans le volet de l'application : après un vrai clic
   de souris, `:focus-visible` était faux, pas d'anneau. Et pourtant le client le voyait, autour
   de toute la section, en cochant à la souris. Les deux sont vrais : la SPÉCIFICATION laisse au
   navigateur le soin de décider si un focus posé PAR SCRIPT est « visible », et tous ne
   tranchent pas pareil. Une règle qui dépend de cette heuristique rend un écran différent d'un
   navigateur à l'autre — ce n'est pas une règle.

   L'accessibilité n'y perd rien. La section n'est pas dans l'ordre de tabulation
   (`tabindex="-1"`) : on n'y arrive qu'au moment où `viser()` y pose le focus, et ce même geste
   pose le marqueur. Le focus est donc toujours visible là où il est (SC 2.4.7), par un signe
   que tous les navigateurs dessinent pareil. Et la tabulation suivante entre dans les cases,
   qui ont leur propre anneau. */
/* Et l'ARRONDI avec l'anneau, pas l'anneau seul. La règle globale de base.css pose sur tout
   `:focus-visible` un contour ET un `border-radius:var(--radius-sm)`. La première correction ne
   retirait que le contour : là où le navigateur juge le focus visible, la section prenait 8 px
   d'arrondi, et le filet orange — une ombre intérieure, qui épouse l'arrondi — se courbait à ses
   deux bouts. Invisible dans le volet de l'application, où ce focus n'est pas jugé visible ;
   reproduit en passant ce navigateur au clavier, puis mesuré : `border-radius: 8px`. */
.panneau-role:focus,.panneau-role:focus-visible{outline:none;border-radius:0}
/* LA SECTION VISÉE — celle qu'on vient de cocher, ou dont on a suivi « Régler ses rôles ».
   Un filet à gauche, l'idiome de `.proposition:has(input:checked)` dans la colonne d'en face :
   les deux colonnes se répondent par le même signe.

   Sans lui, le seul retour visuel était l'anneau de FOCUS — qui ne paraît qu'au clavier
   (mesuré : à la souris, `:focus-visible` est faux et le contour vaut `none`). À la souris, on
   cochait donc une organisation sans qu'aucun signe ne dise laquelle des sections lui
   correspond ; au clavier, un anneau de 2 px autour d'un bloc haut faisait tout le travail à
   lui seul, et le pesait. Le marqueur porte le SENS — « c'est celle-ci » —, l'anneau porte le
   FOCUS (SC 2.4.7) : deux choses, deux signes. */
.panneau-role-vise{box-shadow:inset 3px 0 0 var(--marque);
  padding-left:var(--e-3);margin-left:calc(-1 * var(--e-3))}

/* CE QU'ELLE POURRA FAIRE, sous les rôles d'un panneau — le tableau des droits de la fiche d'une
   personne (`personnes/_apercu-invitation.html.twig`), sous un filet, et qui RESTE dans le panneau.

   Relevé par le user le 2026-09-28, capture à l'appui : le tableau sortait du panneau, passait
   sous sa barre de gauche et touchait les bords de la carte. C'est `.carte .table-enveloppe` qui
   l'y tirait — marges négatives et premières cellules rembourrées, faites pour le tableau qui EST
   la carte, pas pour celui qui en est une pièce entre des cases (l'argument de `.fiche-panneau`).
   Chaque règle ci-dessous défait l'une des siennes ; le préfixe `.carte .panneau-role` leur donne
   le poids de passer devant elles quel que soit l'ordre de la feuille. */
.panneau-role-apercu{display:flex;flex-direction:column;gap:var(--e-3);margin-top:var(--e-4);padding-top:var(--e-4);
  border-top:1px solid var(--ligne)}
.panneau-role-apercu h4{flex-grow:1;margin:0;font-size:var(--fs-base);font-weight:var(--gras-titre);color:var(--texte-fort)}
.panneau-role-apercu h4 .discret{margin-left:var(--e-2);font-weight:normal}
.panneau-role-apercu p{margin:0}
/* Le cadre et les rembourrages : ceux du composant dans une carte (plus bas, « posé dans une carte »).
   Reste ici ce qui est propre à l'aperçu : le dernier en-tête d'action, serré. */
.carte .panneau-role .panneau-role-apercu .droits-tableau thead .droits-colonne:last-child{padding-right:var(--e-1)}
/* ET IL DÉFILE PLUTÔT QUE DE SE TASSER. La colonne des rôles n'a pas la largeur de la fiche : à
   100 % et en disposition fixe, les neuf actions s'y serraient jusqu'à ce que leurs titres se
   chevauchent (« ConsulterCréerModifier », mesuré à 1440 px). La largeur plancher du composant
   (`.droits-tableau`) fait défiler l'enveloppe, et la colonne des onglets reste figée ici
   pour qu'on sache toujours quelle ligne on lit. Elle ne couvre aucun contrôle : les seuls liens du
   tableau sont les siens (déplier un module), si bien que le décrochage au focus du tableau figé
   (SC 2.4.11) n'a rien à protéger ici. `isolation` garde ses `z-index` entre ses cellules. */
.carte .panneau-role .panneau-role-apercu .table-enveloppe{isolation:isolate}
.carte .panneau-role .panneau-role-apercu .droits-tableau thead th:last-child:not(.droits-colonne){width:calc(var(--l-colonne-coche) * 2)}
.carte .panneau-role .panneau-role-apercu .droits-tableau tr>:first-child{position:sticky;left:0;z-index:1;background:var(--surface);
  box-shadow:inset -1px 0 0 var(--ligne)}
.carte .panneau-role .panneau-role-apercu .droits-tableau thead tr>:first-child,
.carte .panneau-role .panneau-role-apercu .droits-tableau .droits-module>:first-child{background:var(--entete-bg)}

/* LE TABLEAU DES DROITS POSÉ DANS UNE CARTE A SON PROPRE CADRE — une règle du COMPOSANT, pour toute
   carte. `.carte .table-enveloppe` tire un tableau jusqu'aux bords de sa carte, par des marges
   négatives et des premières cellules rembourrées : voulu pour le tableau qui EST la carte (une
   liste), faux pour le tableau des droits, qui en est une pièce entre des cases et des titres. Le
   user l'a relevé trois fois le 2026-09-28 — l'aperçu de l'invitation, l'éditeur de rôle, puis
   « Rattacher », oublié parce que les deux premiers avaient reçu chacun LEUR copie du correctif (« tu
   as bâclé l'intégration du composant »). Chaque règle défait l'une des siennes, au poids qu'il faut
   pour passer devant elles ; `HabillageTest` refuse le retour d'une copie par écran. */
.carte .table-enveloppe.droits-enveloppe{margin:0;width:auto;border:1px solid var(--ligne);border-radius:var(--radius);box-shadow:none}
.carte .table-enveloppe.droits-enveloppe:last-child{margin-bottom:0}
.carte .droits-enveloppe .droits-tableau thead th:first-child{padding-left:var(--e-3)}
/* Zéro à gauche pour le nom d'un module dont le LIEN porte son propre retrait (`.droits-deplier`,
   douze pixels) — jamais pour le dessin de la fiche (`.droits-fiche`), dont le lien n'en a aucun :
   la flèche touchait alors le bord du cadre dans « Créer un rôle », à un pixel contre dix-sept sur
   la fiche d'un utilisateur (relevé par le user le 2026-09-29, mesuré). */
.carte .droits-enveloppe:not(.droits-fiche) .droits-tableau .droits-module>th:first-child{padding-left:0}
.carte .droits-enveloppe .droits-tableau tbody .droits-onglet{padding-left:calc(var(--e-6) + var(--e-2))}
.carte .droits-enveloppe .droits-tableau thead th:last-child{padding-right:var(--e-3)}
.carte .droits-enveloppe .droits-tableau .droits-case:last-child{padding-right:0}
.carte .droits-enveloppe .droits-tableau .droits-autres-cellule:last-child{padding-right:var(--e-2)}
/* Les droits d'un rôle, À COCHER : « Autres droits » a la largeur de « Voir tout le portefeuille » sur une ligne ;
   l'administration, dessous, s'en détache comme sur le catalogue — collée au cadre, elle se lisait
   comme une ligne de plus du tableau (le user, 2026-09-29). */
.droits-a-cocher+fieldset.champ{margin-top:var(--e-6)}
.carte .droits-a-cocher .droits-tableau thead th:last-child{width:calc(var(--l-colonne-coche) * 3)}
/* Le nom d'un module est un BOUTON qui replie son groupe (`droits-a-cocher.js`) : il prend le dessin
   du lien « déplier » des autres tableaux de droits, sans l'habit d'un bouton. */
.droits-a-cocher button.droits-deplier{width:100%;border:0;background:none;font:inherit;font-weight:var(--gras-titre);
  color:var(--texte-fort);text-align:left;cursor:pointer}
.droits-a-cocher button.droits-deplier .discret{font-weight:normal}
/* Le RÉSUMÉ d'un module replié : chaque dessin est rendu d'avance dans son enveloppe, que le script
   montre ou cache. L'enveloppe ne compte pas dans la mise en page — le demi-disque et son compte se
   rangent côte à côte, comme dans le tableau des droits ; `[hidden]` l'emporte (base.css). */
.droits-a-cocher .droits-signe>[data-resume-genre]{display:contents}
/* La ligne d'un module garde son fond d'en-tête jusque dans la colonne FIGÉE : la règle du tableau figé
   repeint la première cellule de tout le corps en `--surface`, et le nom du module sortait blanc sur
   une ligne grise (relevé par le user le 2026-09-28). */
.droits-a-cocher.colonne-figee>table>tbody>tr.droits-module>:first-child{background:var(--entete-bg)}
/* « Enregistrer ces droits … sous le nom » : la case et son champ sur une ligne, dans le pied. */
.rt-enregistrer{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2)}
.rt-enregistrer>.champ{margin:0;flex:1 1 auto}
/* ---- Réglages à côté — le composant « Réglages » de la vitrine ----
   Les réglages d'un geste À CÔTÉ de ce qui en découle : à gauche une carte de réglages en blocs, à droite
   la carte de ce que ces réglages produisent, le geste dessous. « Donner des droits temporaires » en est la
   première instance (maquette C4, le user, 2026-10-01), « Modifier le remplacement » la seconde (maquette
   B, 2026-10-02) — c'est la seconde qui l'a fait entrer dans la vitrine : deux écrans, une forme.

   **Côte à côte seulement quand la suite y tient ENTIÈRE** — et c'est le contenu qui le décide, pas un
   point de rupture. Mesuré à 1440 px, menu latéral ouvert : la grille des droits demande 824 px (222 pour
   l'onglet, sept actions à 65, 144 pour « Autres droits » — toutes à leur minimum) et n'en avait que 665 à
   côté d'une colonne de 400 ; elle défilait de côté, « Imprimer » coupé. Menu réduit, ou sans menu, la
   même fenêtre a la place. Un point de rupture sur la fenêtre ne voit pas le menu ; un `flex-wrap` voit la
   place réelle : les deux cartes tiennent sur une ligne quand leurs bases y tiennent, sinon les réglages
   passent au-dessus. La suite prend presque tout le surplus (`999`). */
.colonnes-reglages{display:flex;flex-wrap:wrap;gap:var(--e-6);align-items:flex-start}
.colonnes-reglages>.carte{margin-bottom:0;min-width:0}
.reglages{flex:1 1 var(--l-colonne-reglages);display:flex;flex-direction:column;padding:0}
/* Les réglages en QUESTIONS — Qui, Où, Quand, Pourquoi —, un bloc chacune, séparés par un filet (maquette B,
   le user, 2026-10-02 : « plus espacé et clair »). Le titre d'un bloc est l'ÉTIQUETTE de son champ, sous
   cinq formes : un titre écrit (`.reglages-titre`, quand il n'y a rien à choisir — l'absent d'un
   remplacement qu'on modifie), l'étiquette d'une liste, la légende d'un groupe, la question du choix d'un
   utilisateur, l'étiquette de la période. Elles prennent ici la casse et l'interlettrage des étiquettes de
   section (`--casse-etiquette`) : la typographie seule change, chacune garde ses marges.
   Le filet est une BORDURE du bloc suivant, pas une ombre : il reste dans la carte, et ne déborde pas de ses
   coins arrondis. */
.reglages-groupe{display:flex;flex-direction:column;gap:var(--e-2);padding:var(--e-4) var(--e-6)}
.reglages-groupe+.reglages-groupe{border-top:1px solid var(--ligne)}
.reglages-groupe>*,.reglages-groupe>.champ,.reglages-groupe>fieldset.champ,.reglages-groupe .periode{margin:0}
.reglages-groupe .reglages-titre,.reglages-groupe fieldset.champ>legend,.reglages-groupe .periode-etiquette,.reglages-groupe .choix-utilisateur-question{
  font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.reglages-suite{flex:999 1 var(--l-reglages-suite)}
/* Un groupe de réglages, ou des pilules, qu'on cache restent cachés : leur `display` l'emportait sur
   l'attribut `hidden`, et « Ajouter un utilisateur » montrait sous « Qui ? » un grand vide — le bloc
   « Son compte » masqué, toujours dessiné (relevé par le user le 2026-10-05). Et dans une carte de
   réglages, un seul panneau de rôles se montre à la fois : sans filet au-dessus. */
.reglages-groupe[hidden],.pilules[hidden]{display:none}
.reglages .panneau-role{border-top:0;padding:0}
/* Le pied BORD À BORD de la carte de la suite, sur le fond d'en-tête de la maquette : il ferme la carte au
   repos et, collé au bas de l'écran pendant que la suite défile, il en garde la largeur — la colonne des
   réglages reste libre à côté. Les marges négatives rendent le padding de la carte, qu'il reprend. */
.reglages-suite>.form-pied-colle{margin:var(--e-4) calc(-1 * var(--e-6)) calc(-1 * var(--e-6));padding-inline:var(--e-6);
  background:var(--entete-bg);border-radius:0 0 var(--radius) var(--radius)}

/* ---- Repli ----
   Un contenu SECONDAIRE qui ne doit pas occuper la place de ce que l'écran montre : une liste de
   plus (« Rôles retirés »), les modèles d'un plan d'import. Ouvert en permanence il se survole
   cent fois sans être lu ; replié, il reste disponible pour qui le cherche. Mesuré sur l'écran de
   maintenance : 64 mots visibles contre 77 repliés.

   Le texte qui EXPLIQUE n'est plus un repli depuis le 2026-09-29 : il a son composant, `.aide-ancre`,
   accolé au bouton ou au bloc qu'il explique (plus bas).

   `<details>` NATIF et non un composant piloté par un script : la page reste entière sans
   JavaScript, et le clavier fonctionne sans qu'on écrive une ligne pour lui. Même chevron que
   `.changements-plies` — un seul signe pour un seul geste dans toute l'interface.

   Le libellé du `summary` annonce ce qu'on trouve dedans, jamais « En savoir plus » : un libellé
   creux ne se clique pas. C'est une règle de rédaction, elle ne se tient pas en CSS. */
/* `margin-top` et pas seulement le filet : collé au tableau qui le précède, le premier repli
   se lisait comme une TROISIÈME ligne du tableau — mesuré à l'écran, 13 px contre 28 entre les
   deux replis. Un écart inégal fait chercher une différence qui n'existe pas. */
.repli{border-top:1px solid var(--ligne);margin-top:var(--e-2)}
.repli summary{cursor:pointer;color:var(--marque-encre);font-size:var(--fs-sm);
  font-weight:var(--gras-etiquette);list-style:none;padding:var(--e-3) 0;min-height:var(--h-controle-sm);
  display:flex;align-items:center}
.repli summary::-webkit-details-marker{display:none}
.repli summary::after{content:"\203A";margin-left:var(--e-2);display:inline-block;
  transform:rotate(90deg);transition:transform var(--duree)}
.repli[open]>summary::after{transform:rotate(-90deg)}
.repli>div{padding-bottom:var(--e-4)}
.repli>div p:last-child{margin-bottom:0}

/* ---- Aide ----
   Un « ? » accolé à ce qu'il explique — UN bouton ou UN bloc —, et une bulle qui s'ouvre dessous,
   par-dessus l'écran (`_aide.html.twig`). À ne pas confondre avec `.aide`, le texte sous un champ. Retenu par le user le 2026-09-29 : le dépliant d'aide
   vivait où restait de la place, loin de son bouton, et doublait d'un trait celui de l'en-tête.
   Ouvrir la bulle ne déplace rien ; c'est ce qui la distingue d'un repli.

   La bulle est un `popover` NATIF : ouvrir, fermer, Échap, clic à côté, sans script. Elle vit dans
   la couche supérieure, hors du flux, et s'ANCRE au « ? » par son nom (`--aide-nom`, posé par le
   gabarit sur `.aide-ancre` et hérité par les deux). Sans l'ancrage, le navigateur la centrerait à
   l'écran : `aide.js` la place alors sous le « ? ». */
.aide-ancre{display:inline-flex;align-items:center;flex:none;vertical-align:middle}
/* Le « ? » : 32 px, une cible conforme d'elle-même (SC 2.5.8), à l'encre de la marque comme le
   picto d'aide de toute l'interface. */
.aide-bouton{display:inline-grid;place-items:center;flex:none;width:var(--e-8);height:var(--e-8);padding:0;
  border:1px solid var(--ligne);border-radius:50%;background:var(--surface);color:var(--marque-encre);cursor:pointer;
  anchor-name:var(--aide-nom,--aide);transition:background var(--duree),border-color var(--duree)}
/* Le « ? » occupe le bouton — 20 px sur 32 : à la taille du texte, il était trop discret pour qu'on
   le cherche (le user, 2026-09-29, « grossis le picto partout »). */
.aide-bouton svg{width:calc(var(--e-4) + var(--e-1));height:calc(var(--e-4) + var(--e-1))}
.aide-bouton:hover,.aide-bouton:has(+.aide-bulle:popover-open){background:var(--accent-bg);border-color:var(--marque)}
/* La bulle remet à zéro ce que son hôte pourrait lui léguer : posée dans une légende de tableau,
   elle héritait des capitales et de l'interlettrage de l'étiquette. */
.aide-bulle{width:min(100% - var(--e-8),var(--l-surgissant));
  padding:var(--e-4);background:var(--surface);color:var(--texte);border:1px solid var(--ligne);border-radius:var(--radius);
  box-shadow:var(--shadow);font:normal var(--fs-sm)/1.5 var(--font);text-align:left;text-transform:none;letter-spacing:normal;white-space:normal}
.aide-bulle-titre{margin:0 0 var(--e-2);font-weight:var(--gras-titre);color:var(--texte-fort)}
.aide-bulle p{margin:0 0 var(--e-2)}
.aide-bulle>.btn-lien{margin-top:var(--e-1)}
/* L'ANCRAGE — sous le « ? », son bord droit sur le sien (la bulle s'étend vers la gauche, pour un
   « ? » dans le coin d'un en-tête), ou son bord gauche sur le sien (`.aide-vers-droite`, pour un
   « ? » après un titre). Sans place en dessous, elle passe au-dessus ; sans place sur un côté, de
   l'autre. Sous 40rem, elle prend la largeur de l'écran, gouttières comprises. */
@supports (anchor-name:--aide){
  .aide-bulle{position-anchor:var(--aide-nom,--aide);inset:auto;top:anchor(bottom);right:anchor(right);
    margin:var(--e-2) 0 0;position-try-fallbacks:flip-block,flip-inline}
  .aide-bulle.aide-vers-droite{right:auto;left:anchor(left)}
  @media (max-width:40rem){
    .aide-bulle,.aide-bulle.aide-vers-droite{left:var(--e-4);right:var(--e-4);width:auto}
  }
}
/* Le TITRE D'UN BLOC et son aide, côte à côte : le titre ne s'étire plus jusqu'au bord — le « ? »
   le suit —, et c'est l'ensemble qui prend la place que le titre prenait dans son en-tête. */
.aide-titre{display:flex;align-items:center;gap:var(--e-2);flex:1 1 auto;min-width:0}
.aide-titre>:is(h1,h2,h3,h4){margin:0;flex:0 1 auto;min-width:0}
/* Posé DIRECTEMENT dans une carte (sans `.carte-tete`), le titre et son « ? » reprennent ce que `.carte>h2`
   donne au titre seul — sa taille et l'écart sous lui. Sans cela, la marge du `h2` remise à zéro juste
   au-dessus ne passait à personne : « Modèles ? » touchait l'en-tête du tableau (capture du user,
   2026-10-04). L'écart est celui d'une bande de tête (`.carte-tete`), parce que le « ? » de 26 px fait
   la rangée plus haute qu'un titre seul. */
.carte>.aide-titre{margin-bottom:var(--e-4)}
.carte>.aide-titre>h2{font-size:var(--fs-md);font-weight:var(--gras-titre)}
/* L'ÉTIQUETTE D'UN CHAMP et son aide (« Au (jour inclus) ? », « Partir de ? ») : l'écart sous
   l'étiquette passe à la rangée, sans quoi le « ? » se centrait sur une étiquette décalée vers le haut. */
.champ>.aide-titre{margin-bottom:var(--e-2)}
.champ>.aide-titre>label{margin:0}
/* Et le « ? » de 32 px ne doit pas grandir la rangée d'une étiquette de 20 : il déborde de part et
   d'autre, sans quoi le champ dessous descendait de 12 px sous ses voisins de grille (mesuré). */
.champ>.aide-titre>.aide-ancre{margin-block:calc(var(--e-1) * -1.5)}

/* ---- Confirmation ----
   `<dialog>` natif : le navigateur pose le piège de focus, ferme sur Échap et rend
   l'arrière-plan inerte. `::backdrop` est le voile qu'il fournit — le styler évite d'en
   empiler un second en `position:fixed`.
   `position:fixed`, JAMAIS une autre valeur — vaut pour `.carte-boite` aussi. Une boîte modale vit
   dans la couche supérieure, où toute autre position est calculée `absolute` contre le haut du
   DOCUMENT : la boîte suit alors le défilement de la page. Les deux boîtes ont porté `relative`
   pour loger leur croix en absolu, ce que `fixed` fait aussi ; mesuré le 2026-10-01 (Chrome,
   Firefox), ouvrir une boîte depuis une page défilée la ramenait en haut, la feuille du bas
   flottait au milieu de l'écran, et la visionneuse sortait son en-tête de l'écran en changeant
   de page. HabillageTest::testUneBoiteModaleNeSuitPasLeDefilementDeLaPage le tient. */
.confirmation{position:fixed;border:1px solid var(--ligne);border-radius:var(--radius);box-shadow:var(--shadow);
  background:var(--surface);color:var(--texte);padding:0;width:min(100% - var(--e-8),var(--l-boite-formulaire))}
.confirmation::backdrop{background:var(--voile)}
.confirmation h2{font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort);margin:0}
/* L'en-tête à TROIS temps, posé par confirmation.js : le contexte (qui, où — la ligne de
   Linear), la question, la description (ce qui suit — la ligne de Primer). La question seule
   devait tout porter et s'allongeait jusqu'à ne plus se lire d'un coup ; l'annuaire en avait
   une de trois lignes. Le rembourrage droit laisse la place à la croix, absolue en haut à
   droite — le même bouton `.carte-boite-fermer` que la carte en boîte, un motif et non deux.
   L'icône d'APPARENCE (Atlassian) dit le danger avant qu'on lise ; elle est décorative, le
   mot du bouton et la question portent l'information (SC 1.4.1). */
.confirmation-tete{display:flex;gap:var(--e-3);align-items:flex-start;padding:var(--e-6) var(--e-12) 0 var(--e-6)}
.confirmation-texte{min-width:0;flex:1}
.confirmation-contexte{font-size:var(--fs-xs);color:var(--texte);margin:0 0 var(--e-1)}
.confirmation-description{color:var(--texte);margin:var(--e-2) 0 0;max-width:var(--l-mesure)}
.apparence{flex:none;width:var(--e-6);height:var(--e-6);border-radius:var(--radius-gelule);display:inline-grid;place-items:center;
  font-weight:var(--gras-titre);font-size:var(--fs-sm)}
.apparence-danger{background:var(--err-bg);color:var(--err)}
.confirmation .actions{margin:0;padding:var(--e-6);justify-content:flex-end}
/* Le destructif PLEIN n'existe que dans la boîte, là où le geste se confirme — dans une liste,
   il reste en contour : un rouge plein par ligne ferait de l'annuaire un mur d'alertes.
   `--sur-action` bascule avec le lot : blanc sur `--err` clair 6,54:1, encre sombre sur
   `--err` du lot sombre 7,12:1 — mesurés sur cette paire-là (une première écriture citait les
   ratios de `--err` sur `--err-bg`, ceux d'un autre couple). */
.btn.destructif.plein{background:var(--err);border-color:var(--err);color:var(--sur-action)}
/* Sous 880 px, une FEUILLE ancrée en bas (Primer) : le pouce l'atteint, la page reste visible
   au-dessus. `margin:auto 0 0` pousse la boîte au bord inférieur de sa zone fixe. */
@media (max-width:879px){
  .confirmation{width:100%;max-width:none;margin:auto 0 0;border-radius:var(--radius) var(--radius) 0 0;border-bottom:none}
}
/* Entrée et sortie en fondu-glissé, sous préférence de mouvement seulement ; sans elle rien ne
   bouge. `overlay` et `display` en transition discrète : la sortie s'anime avant que la boîte
   ne disparaisse — sans eux, seule l'entrée s'anime et la fermeture claque. */
@media (prefers-reduced-motion:no-preference){
  .confirmation{transition:opacity var(--duree),transform var(--duree),overlay var(--duree) allow-discrete,display var(--duree) allow-discrete}
  .confirmation:not([open]){opacity:0;transform:translateY(var(--e-3))}
  @starting-style{.confirmation[open]{opacity:0;transform:translateY(var(--e-3))}}
}

/* ---- Carte en boîte ----
   La surimpression de la maquette : `carte-en-boite.js` DÉPLACE une carte de la page dans ce
   <dialog>. La carte garde ses règles à elle ; la boîte lui retire le cadre qu'elle porterait
   en DOUBLE — bordure, ombre, marge — parce que c'est la boîte qui borde, comme la carte cède
   déjà son enveloppe au tableau (`.carte .table-enveloppe`).
   Plus large que `.confirmation` : elle reçoit un formulaire, pas une question — la largeur
   vit en token, bornée par l'écran. `overflow:auto` : le navigateur plafonne un <dialog> à la
   fenêtre, un formulaire plus haut qu'elle doit défiler dans la boîte, jamais déborder.
   `position:fixed` : la raison est sous « Confirmation », plus haut. */
.carte-boite{position:fixed;padding:0;border:1px solid var(--ligne);border-radius:var(--radius);
  box-shadow:var(--shadow);background:var(--surface);color:var(--texte);
  width:min(var(--l-boite-formulaire),100%);overflow:auto}
/* Le flex N'EXISTE qu'à l'état ouvert. Posé sans `[open]`, il écrasait le `display:none` que
   le navigateur donne aux <dialog> fermés : les boîtes en attente se rangeaient en enfants
   flex de la coquille et réduisaient la colonne de contenu à zéro. Mesuré au navigateur —
   `.principal` à 0px, trois boîtes fermées posées à côté du menu. */
.carte-boite[open]{display:flex;flex-direction:column}
.carte-boite-large{width:min(var(--l-boite-formulaire-large),100%)}
.carte-boite::backdrop{background:var(--voile)}
/* La boîte PLEINE HAUTEUR (`plein`, que la carte déclare par `data-boite-format` ou que le lien
   propose par `data-ouvre-en-boite`) : un document se lit de haut en bas, et
   une boîte à hauteur de contenu obligerait à zoomer, ou à défiler la page derrière elle. La
   carte s'étire, et seul son corps défile — l'en-tête et le pied restent sous les yeux.
   Sauf quand le corps n'a plus que le MESSAGE d'une visionneuse sans page : visionneuse.js l'y pose
   à la place d'une page seule qui ne s'est pas rendue, après que la carte a demandé la pleine
   hauteur — `data-boite-format` vaut `plein` dès qu'une page est annoncée. Une phrase au milieu
   d'une boîte pleine hauteur se lit comme un chargement raté ; la boîte retombe donc sur
   `.carte-boite`, par construction, et la feuille vaut quel que soit l'ordre — page en échec avant
   l'ouverture ou après, boîte rouverte. Écrire `height:auto` dans une règle à part ne la rendait
   PAS ordinaire, et c'est mesuré : 719 px sur 768. La boîte ordinaire tient sa hauteur du
   `height:fit-content` que le navigateur donne au `<dialog>` ; `auto` l'écrase, et une boîte
   modale, posée en haut ET en bas, s'étire alors jusqu'à son `max-height`. */
.carte-boite-plein:not(:has(.visionneuse-corps>.visionneuse-absente:only-child)){width:min(var(--l-boite-visionneuse),100%);height:var(--h-boite-pleine)}
.carte-boite-plein>.carte{flex:1}
.carte-boite>.carte{margin:0;border:0;box-shadow:none;display:flex;flex-direction:column;min-height:0}
/* Une carte prise en charge par carte-en-boite.js SORT du flux de la page : au repos, l'écran
   redevient celui de la maquette — le tableau et ses gestes, aucun formulaire déplié. Sans
   script, l'attribut n'est jamais posé et les cartes restent visibles : le repli. */
[data-en-boite-geree]{display:none}
.carte-boite>[data-en-boite-geree]{display:flex}

/* ---- Boîte-formulaire : corps défilant entre un titre et un pied posés ----
   En PAGE, ces classes ne font qu'empiler ; en BOÎTE, la hauteur plafonnée par le navigateur
   descend jusqu'au corps, qui devient la seule zone à défiler — le titre et le bouton d'envoi
   restent sous les yeux, comme la maquette. */
.boite-formulaire{display:flex;flex-direction:column;gap:var(--e-4);min-height:0}
.carte-boite .boite-formulaire{flex:1}
.boite-corps{display:flex;flex-direction:column;gap:var(--e-4);min-height:0}
.carte-boite .boite-corps{overflow:auto}
/* Le pied : la conséquence à gauche, l'action à droite. En boîte il prend le bandeau teinté
   de la maquette, à fond perdu — mêmes marges négatives que le tableau dans sa carte. */
.boite-pied{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:var(--e-3);border-top:1px solid var(--ligne);padding-top:var(--e-3)}
.carte-boite .boite-pied{background:var(--entete-bg);
  margin:0 calc(var(--e-6) * -1) calc(var(--e-6) * -1);padding:var(--e-3) var(--e-6)}

/* ---- Visionneuse d'un fichier ----
   Ses pages en images, sur le fond de page, à fond perdu dans la boîte — le document se détache
   de ce qui l'entoure, comme une feuille posée. En page entière, les mêmes classes empilent
   simplement : la visionneuse est aussi le repli sans script de la vignette.
   La place de chaque page est réservée par ses attributs `width`/`height` : `height:auto` garde
   le rapport, et la lecture ne saute pas quand une page arrive. */
/* Le `display` ne se pose JAMAIS sur la carte nue : `[data-en-boite-geree]{display:none}` a la même
   spécificité, et une règle écrite après lui l'emportait — la carte que carte-en-boite.js venait
   de retirer de la page y restait affichée. Vu à l'écran, qu'aucun test ne rend. D'où la carte
   PAS prise en charge (le repli sans script, la page entière) et la carte DANS sa boîte. */
.visionneuse:not([data-en-boite-geree]),.carte-boite>.visionneuse{display:flex;flex-direction:column;gap:var(--e-4)}
/* La place de la CROIX, que carte-en-boite.js pose en absolu en haut à droite : sans elle, un nom
   de fichier long passait dessous — vu à 375 px, « rapport-annuel-2026.pd » coupé par le ×. Le
   titre s'arrête avant, et ses points de suspension disent le reste. */
.carte-boite>.visionneuse .boite-entete{padding-right:var(--e-8)}
.visionneuse-corps{align-items:center;background:var(--bg);border-radius:var(--radius-sm);padding:var(--e-4)}
.carte-boite .visionneuse-corps{flex:1;border-radius:0;margin:0 calc(var(--e-6) * -1);padding:var(--e-4) var(--e-6)}
.visionneuse-page{display:block;width:100%;height:auto;border:1px solid var(--ligne);border-radius:var(--radius-sm)}
/* Entre deux pages, un vrai blanc : là où l'une s'arrête et où l'autre commence doit se voir sans
   chercher — l'écart du corps de boîte y suffisait à peine. */
.visionneuse-corps:has(.visionneuse-page,.visionneuse-page-absente){gap:var(--e-8)}
/* La barre de pages, sous l'en-tête, au centre : « 1 / 3 » entre ses deux flèches. Le compteur
   garde sa largeur quand le numéro change, pour que les flèches ne bougent pas sous le pointeur. */
.visionneuse-outils{display:flex;align-items:center;justify-content:center;gap:var(--e-2)}
.visionneuse-compteur{min-width:var(--l-compteur-pages);text-align:center;font-variant-numeric:tabular-nums;
  font-size:var(--fs-sm);color:var(--texte-fort)}
.visionneuse-absente{display:grid;justify-items:center;gap:var(--e-2);text-align:center;margin:auto;
  padding:var(--e-8) var(--e-4);max-width:var(--l-mesure)}
.visionneuse-absente p{margin:0}
.visionneuse-absente-pastille{width:var(--h-controle);height:var(--h-controle)}
.visionneuse-absente-titre{font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.visionneuse-limite{margin:0}
/* UNE PAGE QUI NE SE REND PAS, quand elle était SEULE : visionneuse.js pose à sa place le message
   d'une visionneuse sans page, seul enfant du corps. La boîte redevient ordinaire (`.carte-boite-plein`,
   plus haut), et le pied ne dit plus ce qu'une image de page ne permet pas, sous une page qui ne
   s'affiche pas. */
.visionneuse:has(.visionneuse-corps>.visionneuse-absente:only-child) .visionneuse-limite{display:none}
/* Une page PARMI D'AUTRES qui ne se rend pas : le cadre d'une page — même largeur, même bordure,
   le rapport de la place réservée, que visionneuse.js lui reporte —, et la phrase EN HAUT, pour
   qu'elle se lise dès que le bord de la page entre à l'écran. */
.visionneuse-page-absente{display:grid;align-content:start;justify-items:center;gap:var(--e-2);width:100%;
  padding:var(--e-8) var(--e-4);text-align:center;background:var(--surface);
  border:1px solid var(--ligne);border-radius:var(--radius-sm)}
.visionneuse-page-absente p{margin:0}
/* Le TEXTE d'un fichier — un Markdown, des notes — tel qu'il est écrit : chasse fixe, retours à la
   ligne gardés, et une ligne trop longue repliée plutôt qu'un défilement horizontal, qui ferait
   perdre la ligne à chaque retour. Sur la surface, comme une feuille posée ; il prend TOUTE la
   largeur du corps, qui centre ses enfants pour les pages d'un document. */
.visionneuse-texte{align-self:stretch;margin:0;padding:var(--e-4);white-space:pre-wrap;overflow-wrap:anywhere;
  font:var(--fs-sm)/1.6 var(--font-mono);color:var(--texte-fort);background:var(--surface);
  border:1px solid var(--ligne);border-radius:var(--radius-sm)}
/* Le MARKDOWN d'un fichier, mis en forme — une page de texte courant, sur la surface comme le texte
   brut. La charte remet à zéro marges et puces pour ses écrans ; un document en a besoin, et elles
   lui sont rendues ICI, dans ce seul conteneur. Ses titres commencent au niveau 3, sous le nom du
   fichier, et gardent une taille de document plutôt que de page. Un tableau ou un bloc de code trop
   large défile dans sa propre largeur : la boîte, elle, ne défile jamais de côté. */
.visionneuse-markdown{align-self:stretch;padding:var(--e-4) var(--e-6);background:var(--surface);
  border:1px solid var(--ligne);border-radius:var(--radius-sm);color:var(--texte-fort);line-height:1.6;overflow-wrap:anywhere}
.visionneuse-markdown>*+*{margin-top:var(--e-3)}
.visionneuse-markdown :is(h3,h4,h5,h6){margin:var(--e-6) 0 0;line-height:1.3;font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.visionneuse-markdown :is(h3,h4,h5,h6):first-child{margin-top:0}
.visionneuse-markdown h3{font-size:var(--fs-lg)}
.visionneuse-markdown h4{font-size:var(--fs-md)}
.visionneuse-markdown :is(h5,h6){font-size:var(--fs-base)}
.visionneuse-markdown :is(ul,ol){padding-left:var(--e-6)}
.visionneuse-markdown ul{list-style:disc}
.visionneuse-markdown li:has(>input[type=checkbox]){list-style:none}
.visionneuse-markdown li+li{margin-top:var(--e-1)}
.visionneuse-markdown blockquote{margin:0;padding-left:var(--e-4);border-left:3px solid var(--ligne);color:var(--texte)}
.visionneuse-markdown pre{margin:0;padding:var(--e-3);overflow-x:auto;background:var(--bg);border-radius:var(--radius-sm)}
.visionneuse-markdown :not(pre)>code{padding:0 var(--e-1);background:var(--neutre-bg);border-radius:var(--radius-sm)}
.visionneuse-markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse}
.visionneuse-markdown :is(th,td){padding:var(--e-1) var(--e-3);border:1px solid var(--ligne);text-align:left}
.visionneuse-markdown hr{border:0;border-top:1px solid var(--ligne)}
.visionneuse-markdown a{text-decoration:underline}

/* ---- Le sélecteur de rôle des gestes directs de l'écran des utilisateurs ----
   Ce qui reste d'un bloc de sept classes : la boîte d'invitation posait UNE LIGNE par
   organisation — case, nom et chemin, sélecteur — et six de ces classes ne servaient qu'à elle.
   L'invitation a sa page depuis le 2026-09-08 (`personnes/inviter.html.twig`, composants
   « choisir avec aperçu » et « cases »), et ces six-là ne se posaient plus nulle part.
   Retirées avec l'écran qui les employait : une classe orpheline dans la charte est ce qu'un
   junior recopie en croyant employer un composant. Le sélecteur, lui, sert encore aux deux
   gestes directs de « Faire entrer quelqu'un autrement ». */
.ligne-organisation-role{width:min(var(--l-affectation-role),100%);min-height:var(--h-controle-sm);
  padding:var(--e-1) var(--e-2);border:1px solid var(--bord);border-radius:var(--radius-sm);
  background:var(--bg);color:var(--texte-fort);font:inherit;font-size:var(--fs-sm)}


/* ---- Carte de gestion d'une personne ----
   L'en-tête à la maquette : l'avatar À CÔTÉ de la colonne nom + adresse. L'avatar dans le flux
   du h2 passait à la ligne dès que le nom manquait de place — mesuré : la boîte s'ouvrait sur
   un rond seul, le nom dessous. Les marges des enfants tombent, la rangée porte l'espacement. */
.boite-entete{display:flex;align-items:center;gap:var(--e-3)}
.boite-entete-texte{min-width:0}
.boite-entete h2{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.boite-entete .sous{margin:0;font-family:var(--font-mono);font-size:var(--fs-xs)}
/* Le complément inline d'un label — « le repli que l'annuaire affiche » à côté du nom du
   champ, comme la maquette : une étiquette seule oblige à chercher l'aide sous le champ. */
.etiquette-aide{font-weight:400;font-size:var(--fs-xs);color:var(--texte)}
/* L'aperçu montre CE QUE l'annuaire affiche et NOMME sa source — la préséance des noms rendue
   visible à l'endroit exact où l'on écrit le repli. Fond d'accent doux : c'est une information
   qui rassure, pas une alerte. Une seule rangée, la source à droite — la maquette. */
.apercu-annuaire{display:flex;justify-content:space-between;align-items:baseline;gap:var(--e-3);
  flex-wrap:wrap;margin-top:var(--e-2);padding:var(--e-2) var(--e-3);
  border:1px solid var(--ligne);border-radius:var(--radius-sm);background:var(--accent-bg);
  font-size:var(--fs-sm);color:var(--texte-fort)}
.apercu-etiquette{color:var(--marque-encre);font-weight:var(--gras-etiquette);font-size:var(--fs-xs)}
/* L'encart d'explication : un cadre calme qui raconte les deux champs — jamais une alerte. */
.encart-explication{border:1px solid var(--ligne);border-radius:var(--radius-sm);margin-block:var(--e-3);
  padding:var(--e-3) var(--e-4);display:flex;flex-direction:column;gap:var(--e-2);
  font-size:var(--fs-sm);color:var(--texte)}
.encart-titre{font-weight:var(--gras-etiquette);color:var(--texte-fort);font-size:var(--fs-xs);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.encart-liste{margin:0;padding-left:var(--e-4);display:flex;flex-direction:column;gap:var(--e-1);
  font-size:var(--fs-sm);color:var(--texte)}
/* Les chevrons `::after` des dépliants sont écrits DEUX fois : `content:"\203A" / ""` donne au
   glyphe un texte alternatif vide — sans lui, le contenu généré entre dans le nom accessible
   (accname, étape 2F) et « Gérer » devient « Gérer › » — et la forme sans `/ ""` reste devant
   pour les navigateurs qui ne lisent pas encore cette syntaxe et rejetteraient la seconde.
   Le dépliant discret : un résumé qui se lit comme un lien d'action discret, sans le cadre de
   bouton d'`.edition` — dans un encart ou une cellule déjà dense, un bouton par ligne pèserait
   plus que l'information. `<summary>` reste focalisable et annoncé nativement ; le chevron
   tourne à l'ouverture. Aucune taille de police ici : il prend celle de son contexte, celle de
   l'encart ou celle de la cellule. Le journal en avait sa propre copie (`.changements-plies`),
   réglée à un cran de moins ; une seule règle, un seul dessin. */
.depliant-discret summary{cursor:pointer;color:var(--marque-encre);font-weight:var(--gras-etiquette);
  width:fit-content;list-style:none}
.depliant-discret summary::-webkit-details-marker{display:none}
.depliant-discret summary::after{content:"\203A";content:"\203A" / "";margin-left:var(--e-1);display:inline-block;
  transform:rotate(90deg);transition:transform var(--duree)}
.depliant-discret summary:hover{text-decoration:underline}
.depliant-discret[open]>summary::after{transform:rotate(-90deg)}
.depliant-discret[open]>summary{margin-bottom:var(--e-2)}
/* ---- Gestes risqués ----
   Ce qui ne se répare pas d'un clic — retirer un accès, désactiver, mettre à la corbeille —
   vit à PART des boutons d'enregistrement : l'œil qui cherche « Enregistrer » ne doit pas
   frôler « Désactiver ». Un filet au-dessus dit où l'édition s'arrête, un titre nomme la zone,
   puis des `.ligne-option` en volets côte à côte — la même anatomie qu'une rangée de réglage,
   le sujet à gauche, l'action à droite —, chacun dans son cadre parce que chacun est un geste
   distinct, avec sa propre conséquence. Trois classes ont porté cela (`.section-retrait`,
   `.geste-risque`, `.geste-risque-texte`) pour ce que `.ligne-option` savait déjà faire.
   `flex-wrap:nowrap` sur le volet : le bouton reste à droite de sa phrase, et la colonne texte
   rétrécit (le sujet porte min-width:0) sans le pousser hors du cadre. Le cadre bat les règles
   `:first-child`/`:last-child` de `.ligne-option` à spécificité égale parce qu'il vient après. */
.gestes-risques{border-top:1px solid var(--ligne);padding-top:var(--e-3);
  display:flex;flex-wrap:wrap;gap:var(--e-3)}
.gestes-risques>h3{flex-basis:100%;margin:0;font-size:var(--fs-sm);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.gestes-risques>.ligne-option{flex:1 1 var(--l-champ-grille);flex-wrap:nowrap;
  border:1px solid var(--ligne);border-radius:var(--radius-sm);padding:var(--e-3) var(--e-4)}
.gestes-risques>.ligne-option b{font-size:var(--fs-sm)}
.gestes-risques>.ligne-option small{font-size:var(--fs-xs)}
.gestes-risques form{flex-shrink:0}
/* Le duo du pied — l'« Annuler » caché y attend le script qui le révèle ; c'est la garde
   globale `[hidden]{…!important}` de base.css qui le tient masqué malgré le `display` de
   `.btn`, pas cette règle-ci. */
.boite-pied-boutons{display:flex;gap:var(--e-2);align-items:center;margin-left:auto}
/* Le bouton qui ferme, posé PAR-DESSUS le rembourrage de la carte — d'où l'absolu, logé par le
   `position:fixed` de la boîte : une boîte fixe est déjà un bloc contenant, et y remettre
   `relative` la ferait défiler avec la page (« Confirmation » dit pourquoi). Carré de
   --h-icone : un bouton à glyphe seul ne suit pas la densité du texte, il n'en contient pas. Son nom accessible vient d'`aria-label`, posé
   par le script : le glyphe seul serait annoncé « multiplication » — ou rien. */
.carte-boite-fermer{position:absolute;top:var(--e-2);right:var(--e-2);
  width:var(--h-icone);height:var(--h-icone);display:inline-flex;align-items:center;
  justify-content:center;border:1px solid var(--ligne);background:var(--surface);
  color:var(--texte);font-size:var(--fs-lg);line-height:1;cursor:pointer;
  border-radius:var(--radius-sm)}
.carte-boite-fermer:hover{background:color-mix(in srgb, var(--texte) 4%, var(--surface))}
.carte-boite-fermer:hover{background:var(--neutre-bg);color:var(--texte-fort)}

/* Un tableau DANS une carte n'a pas besoin de sa propre enveloppe : la carte est déjà la
   surface, et deux bordures concentriques avec deux ombres font un cadre dans un cadre.
   Il garde son défilement — c'est sa raison d'être — et le rembourrage de la carte lui est
   retiré latéralement, pour que ses filets aillent d'un bord à l'autre. */
.carte .table-enveloppe{border:0;border-radius:0;box-shadow:none;
  margin:0 calc(var(--e-6) * -1);width:auto}
/* Le rembourrage du BAS ne se mange que si le tableau FERME la carte — le pendant du `:first-child`
   ci-dessous, qui mange celui du haut.

   Posée sur toute enveloppe de carte, la marge négative tirait vers le haut ce qui SUIT le
   tableau. La note de l'écran Sécurité remontait de 12 px dans la dernière rangée : sa marge de
   `--e-3` fusionne avec les `--e-6` négatifs, si bien que `.carte>.table-enveloppe+.aide`, écrite
   pour la détacher du dernier rang, ne l'a jamais fait. Un repli y remontait de 16 px. Tant que
   l'enveloppe restait dans le flux, cette suite se peignait par-dessus la rangée ; positionnée
   (plus haut), l'enveloppe se peint après elle, et son fond coupait en deux la première ligne de la
   note — mesuré au navigateur, avec et sans la règle. Et avant même ce changement, le haut d'un
   repli tombait parfois SOUS le tableau — l'historique d'un rôle à 443 comme à 1280 px, la
   maintenance à 443 : le point cliqué sur son résumé rendait le tableau.

   `:last-child` ne regarde que les ÉLÉMENTS : un commentaire Twig ou des blancs après le tableau ne
   comptent pas, un `<div>` vide, si. */
.carte .table-enveloppe:last-child{margin-bottom:calc(var(--e-6) * -1)}
/* Quand le tableau OUVRE la carte, il mange aussi le rembourrage du HAUT. La marge négative
   ci-dessus ne couvrait que trois côtés parce qu'un titre occupait toujours le quatrième —
   depuis que les titres de section vivent HORS des cartes (l'écran des rôles, comme la
   maquette), le rembourrage haut restait à nu : une bande blanche de --e-6 au-dessus de la
   bande d'en-tête. Les rayons remettent les coins du bandeau teinté dans ceux de la carte,
   que rien ne rogne — la carte n'a pas d'overflow, c'est l'enveloppe qui clippe. */
.carte>.table-enveloppe:first-child{margin-top:calc(var(--e-6) * -1);
  border-radius:var(--radius) var(--radius) 0 0}
/* Un tableau à colonnes FIXES (`_tableau`, `colonnes_fixes`) : d'un filtre à l'autre, les colonnes
   ne se redimensionnent plus d'après ce qu'elles contiennent — relevé par le user sur l'annuaire le
   2026-09-28, la colonne « Deux étapes » sautait à chaque choix et l'on perdait la lecture en colonne.
   La colonne sans largeur prend le reste ; sous la largeur minimale, la zone défile au lieu de
   l'écraser (`tableau-defilant.js` la rend alors focalisable). */
.colonnes-fixes{table-layout:fixed;min-width:var(--l-tableau-colonnes-fixes)}
.colonnes-fixes th.colonne-identite{width:var(--l-colonne-identite)}
.colonnes-fixes th.colonne-etroite{width:var(--l-colonne-etroite)}
.colonnes-fixes th.colonne-signe{width:var(--l-colonne-signe)}
.carte .table-enveloppe th:first-child,.carte .table-enveloppe td:first-child{padding-left:var(--e-6)}
.carte .table-enveloppe th:last-child,.carte .table-enveloppe td:last-child{padding-right:var(--e-6)}

/* ---- En-tête d'identité d'une fiche ----
   Le rôle à côté du nom dans le bandeau `.profil-entete` : l'encre de marque le distingue du
   nom sans en faire un lien. Le reste de l'ancien en-tête (`.fiche-identite`) est parti avec le
   dernier gabarit qui l'écrivait. */
.fiche-role{margin-left:var(--e-2);font-weight:var(--gras-etiquette);font-size:var(--fs-sm);
  color:var(--marque-encre)}
.avatar.grand{width:var(--h-avatar-grand);height:var(--h-avatar-grand);min-width:var(--h-avatar-grand);font-size:var(--fs-lg)}

/* Aucune indentation, aucun coude : la filiation se lit dans la colonne « Rattaché à », en
   toutes lettres. Le retrait coûtait 24 px par niveau — le seul coût de cet écran qui croissait
   sans borne, pris sur les cinq autres colonnes jusqu'au débordement horizontal. Et le coude
   qui l'accompagnait affirmait une filiation fausse 9 974 fois sur 9 999, mesuré sur 10 000
   comptes : le dépôt trie par NIVEAUX, donc la ligne du dessus n'est presque jamais le parent.

   Réparer le tri aurait coûté une migration irréversible chez le client, un index impossible
   dès la profondeur 5, et le renommage — le bouton le plus banal de l'écran — serait passé
   d'une ligne à dix mille. Pour un trait décoratif. */

/* ---- « Mon compte » : bandeau d'identité et cartes titrées ----
   Les onglets, eux, ne sont plus stylés ici : ils vivent dans le bloc `onglets` de la charpente,
   sous la barre, exactement comme ceux des paramètres. La première version les rangeait DANS la
   carte — ils avaient l'air d'appartenir au formulaire, et l'écran ne ressemblait plus à la base
   fournie. */

/* Le bandeau d'identité, hors carte, posé sur le fond de page : c'est le contexte de l'écran,
   pas une donnée de l'écran. L'avatar grand format et le nom en gras — on identifie quelqu'un. */
/* `.fiche-tete` est l'ANCIEN nom de ce bandeau, promis par docs/habillage.md pendant une
   semaine après son renommage, dépôt livré entre-temps. Il reste servi ici en alias jusqu'à la
   prochaine version majeure — table « Classes dépréciées » du guide, et
   HabillageTest::testChaqueClasseDeprecieeResteServieJusquAuRetrait. Le retirer avant
   l'échéance déshabille en silence un module client écrit sur l'ancien guide. */
.profil-entete,.fiche-tete{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-4);margin-bottom:var(--e-4)}
.profil-entete h2,.fiche-tete h2{font-size:var(--fs-lg);font-weight:var(--gras-titre);line-height:1.2;
  color:var(--texte-fort);margin:0;overflow-wrap:anywhere}
.profil-entete p,.fiche-tete p{margin:var(--e-1) 0 0;font-size:var(--fs-sm);color:var(--texte)}
/* `.fiche-role` pousse d'ordinaire à distance d'un nom sur la même ligne ; ici il OUVRE la
   ligne du dessous, la marge n'a rien à écarter. */
.profil-entete .fiche-role,.fiche-tete .fiche-role{margin-left:0}
/* Une image dans le rond de l'avatar : cadrée, jamais étirée. */
img.avatar{object-fit:cover}
/* L'outil de photo se range contre le bord droit du bandeau, comme la base fournie. Son
   panneau SURGIT sous le bouton au lieu de pousser la page : un formulaire qui déforme le
   bandeau à l'ouverture donne l'impression d'un écran cassé — c'est le reproche exact qui a
   motivé cette règle. */
/* La colonne de texte du bandeau, à droite de l'avatar. Elle était posée dans
   `compte/_entete.html.twig` et définie dans aucune feuille — le même point d'accroche mort que
   `case-ligne`, trouvé par le même test.

   Trois déclarations, et chacune répond à une panne DIFFÉRENTE de la même ligne. `min-width:0`
   lève le refus d'un élément flex de descendre sous la largeur de son contenu. Il ne suffit
   pas : une adresse email n'a aucun espace où se couper, donc réduite, elle DÉBORDE au lieu de
   se replier — mesuré au navigateur à 375 px, « Changer la photo » recouvrait le nom, et le
   commentaire qui vivait ici annonçait une troncature que rien dans cette feuille ne produit.
   D'où `overflow-wrap:anywhere` sur le `h2`, qui autorise la coupure hors d'un espace. Et la
   base `12rem` fait passer l'outil de photo À LA LIGNE quand il ne reste plus de quoi lire un
   nom, plutôt que de le comprimer contre lui : sous cette largeur, `flex-wrap` prend le relais.
   Avec `flex:1` — c'est-à-dire une base nulle — la ligne ne se serait jamais rompue, la colonne
   se laissant écraser jusqu'à quelques pixels sans jamais déclencher le repli. */
.profil-identite{min-width:0;flex:1 1 var(--l-identite)}
.profil-photo{position:relative;margin-left:auto}
/* `.edition[open]` prend toute la rangée — voulu DANS une fiche, où le panneau s'étale sous la
   valeur. Ici le panneau SURGIT en absolu : laisser la règle générique s'appliquer faisait
   grossir le déplieur à toute la largeur du bandeau, et l'identité se repliait sur trois
   lignes à l'ouverture. */
.profil-photo[open]{flex-basis:auto}
.profil-photo summary{white-space:nowrap}
/* La largeur du panneau, et la borne qui a menti : `min(var(--l-surgissant), 100%)` — le
   100 % d'un élément ABSOLU se résout contre son ancre positionnée, c'est-à-dire le bouton
   (mesuré : 154 px), jamais contre l'écran. Le garde-fou mobile choisissait donc toujours la
   mauvaise borne, et le panneau se lisait en colonne d'un mot. La borne juste est la FENÊTRE,
   moins une marge — même famille d'unité dynamique que le rail du menu. */
.profil-photo .edition-panneau{position:absolute;right:0;top:calc(100% + var(--e-2));z-index:30;
  width:var(--l-surgissant);max-width:calc(100dvw - var(--e-8));background:var(--surface);border:1px solid var(--ligne);
  border-radius:var(--radius);box-shadow:var(--shadow);padding:var(--e-4)}
/* L'état actuel en tête de panneau : la photo (ou les initiales), et « Retirer » contre ce
   qu'il retire. */
.photo-actuelle{display:flex;align-items:center;gap:var(--e-3);
  margin-bottom:var(--e-4);padding-bottom:var(--e-4);border-bottom:1px solid var(--ligne)}
.photo-actuelle form{margin-left:auto}
.photo-actuelle-texte{font-size:var(--fs-sm);color:var(--texte)}

/* ---- Bandeau de fiche ----
   L'en-tête d'UNE fiche, à fond perdu sous les onglets : le chemin, le nom et sa nature, puis
   les informations — ou, à leur place, le formulaire qui les modifie. Né de la maquette 2c de la
   fiche d'une organisation (2026-09-13), dont le parti pris tient en une phrase : « les
   informations ne sont pas une carte mais un bandeau ». La première fiche les avait posées dans
   une carte titrée, sous un en-tête resté sur le fond de page : l'écran ne ressemblait plus à
   la proposition retenue, et le user l'a relevé, capture contre maquette.

   Ce n'est pas `.profil-entete` : celui-là identifie une PERSONNE sur le fond de page (avatar,
   nom, rôle) ; celui-ci porte les données d'un objet et leur modification. */
.bandeau-fiche{display:flex;flex-direction:column;gap:var(--e-4);margin-bottom:var(--e-6);
  padding:var(--e-6);background:var(--surface);border-bottom:1px solid var(--ligne)}
/* Le fond perdu ne vaut que pour le bandeau posé EN TÊTE du contenu : la marge négative annule le
   rembourrage de `.contenu`, même valeur aux mêmes largeurs. Posé ailleurs — dans l'aperçu de la
   vitrine —, c'est une bande blanche ordinaire, et rien ne déborde de son cadre. */
.contenu>.bandeau-fiche{margin-inline:calc(var(--e-6) * -1)}
/* Il remonte contre les onglets quand aucun message ne le précède DANS LE FLUX : quand la zone
   des messages est ancrée par-dessus la page (section « Notifications »), ou quand elle est vide.
   La première condition est EXACTEMENT celle de l'ancrage — navigateur qui ancre, script, page
   qui porte un emplacement — : sans elle, la zone reste dans la page, et un bandeau remonté
   par-dessus cacherait « Informations enregistrées », la seule confirmation du geste. Sans
   `:has()`, le cas « zone vide » garde l'écart du rembourrage — le repli sûr. */
@supports (position-visibility: always) and (justify-self: anchor-center){
  :root:has(.emplacement-notifications) .contenu>[data-notifications-actives]+.bandeau-fiche{margin-top:calc(var(--e-6) * -1)}
}
@supports selector(:has(*)){
  .contenu>#messages-page:not(:has(.message))+.bandeau-fiche{margin-top:calc(var(--e-6) * -1)}
}
.bandeau-fiche>.chemin{margin:0}
/* Le bouton de retour et le chemin sur UNE ligne, séparés par un filet — seulement quand le retour
   est là : sans lui, le chemin reste seul, sans filet devant. Sous la largeur, le chemin passe dessous. */
.bandeau-fiche-provenance{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-3) var(--e-4)}
.bandeau-fiche-provenance>.chemin{margin:0}
.bandeau-fiche-provenance>.btn-retour+.chemin{padding-left:var(--e-4);border-left:1px solid var(--ligne)}
/* Le nom, sa nature, l'action. La nature est une pastille HORS du `h2` : dedans, un lecteur
   d'écran annoncerait « Compta Service » pour titre. L'action se range à droite, et passe à la
   ligne plutôt que d'écraser le nom. */
.bandeau-fiche-titre{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-3)}
.bandeau-fiche-titre>h2,.bandeau-fiche-titre>.aide-titre>h2{margin:0;font-size:var(--fs-xl);font-weight:var(--gras-titre);line-height:1.2;
  color:var(--texte-fort);overflow-wrap:anywhere}
.bandeau-fiche-titre>.btn{margin-left:auto}
/* Plusieurs gestes dans le coin : seul le PREMIER pousse vers la droite. Chacun portant sa marge
   automatique, l'espace libre se partageait entre eux, et « Modifier les informations » s'arrêtait au
   milieu du bandeau dès que « Rattacher » l'y rejoignait (fiche d'une société, 2026-09-30). */
.bandeau-fiche-titre>:is(.btn,.btn-primaire)~:is(.btn,.btn-primaire){margin-left:0}
/* En lecture, les informations tiennent sur UNE ligne — « cinq clés-valeurs sur une ligne », dit
   la maquette. La grille de `.fiche` en faisait trois colonnes sur deux rangs, et le bandeau
   doublait de hauteur au-dessus des personnes (mesuré à 1440 px). Chaque paire reste bornée :
   une adresse longue passe à la ligne dans sa colonne au lieu de pousser les autres dehors. */
.bandeau-fiche>.fiche{display:flex;flex-wrap:wrap;gap:var(--e-3) var(--e-8)}
.bandeau-fiche>.fiche>div{max-width:var(--l-donnee)}
.bandeau-fiche>.fiche dd{overflow-wrap:anywhere}
/* Des informations NOMBREUSES se rangent en GROUPES titrés, côte à côte — Identité, Siège, Contact sur
   la fiche d'une société. Thierry, le 2026-10-24, devant neuf paires sur une ligne : « manque un peu de
   clarté ». Le titre d'un groupe a le dessin d'un terme (petites capitales), et chaque ligne aligne le
   terme, discret, et sa valeur, en deux colonnes : l'œil descend la colonne des valeurs sans relire les
   termes. Sous la largeur d'un groupe, ils passent l'un sous l'autre. */
.fiche-rubriques{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(var(--l-donnee),100%),1fr));gap:var(--e-4) var(--e-8)}
.fiche-rubrique{min-width:0}
.fiche-rubrique>h3{margin:0 0 var(--e-2);font-size:var(--fs-xs);font-weight:var(--gras-titre);line-height:1.4;color:var(--texte);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.fiche-lignes{display:grid;grid-template-columns:auto 1fr;gap:var(--e-1) var(--e-4);margin:0}
.fiche-lignes>div{display:contents}
.fiche-lignes dt{color:var(--texte)}
.fiche-lignes dd{margin:0;min-width:0;color:var(--texte-fort);overflow-wrap:anywhere}
.fiche-adresse{margin:0;color:var(--texte-fort);line-height:1.5}
/* La modification s'ouvre DANS le bandeau, à la place des informations — jamais en plus. Le
   cadre est un filet et non une carte : le bandeau n'en est pas une, et deux surfaces ombrées
   l'une dans l'autre annonceraient deux objets. Le pied reprend l'anatomie de la boîte
   (`.boite-pied` : la conséquence à gauche, les gestes à droite) et son bandeau teinté, à fond
   perdu dans le cadre — mêmes marges négatives que dans `.carte-boite`. */
.bandeau-fiche-edition{border:1px solid var(--ligne);border-radius:var(--radius);
  padding:var(--e-4) var(--e-6) 0;overflow:hidden}
.bandeau-fiche-edition>h3{margin:0;font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort)}
.bandeau-fiche-edition>.sous{margin:var(--e-1) 0 var(--e-4)}
.bandeau-fiche-edition .boite-pied{background:var(--entete-bg);margin-inline:calc(var(--e-6) * -1);
  padding:var(--e-3) var(--e-6)}
@media (max-width:879px){
  .contenu>.bandeau-fiche{margin-inline:calc(var(--e-4) * -1);padding:var(--e-4)}
  .bandeau-fiche-edition{padding:var(--e-4) var(--e-4) 0}
  .bandeau-fiche-edition .boite-pied{margin-inline:calc(var(--e-4) * -1);padding-inline:var(--e-4)}
}
@media (max-width:879px){
  @supports (position-visibility: always) and (justify-self: anchor-center){
    :root:has(.emplacement-notifications) .contenu>[data-notifications-actives]+.bandeau-fiche{margin-top:calc(var(--e-4) * -1)}
  }
  @supports selector(:has(*)){
    .contenu>#messages-page:not(:has(.message))+.bandeau-fiche{margin-top:calc(var(--e-4) * -1)}
  }
}

/* ---- En-tête de page ----
   Le bandeau blanc sous les onglets, le même sur chaque page d'onglet (`_entete-page.html.twig`) :
   les CHIFFRES utiles à gauche, les GESTES à droite. Retenu par le user le 2026-09-29 (proposition A) :
   le bandeau de « Rôles et droits » ne portait plus qu'un bouton, et l'export vivait en bas de page.
   Il reprend le bandeau de fiche — son fond perdu, son remontage contre les onglets — sans titre. */
.chiffres{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2);margin:0;padding:0;list-style:none;flex:1 1 auto;min-width:0}
/* Une pastille : le nombre en gras, son mot à côté. Lien, elle applique le filtre de la page.
   L'arrondi est celui des BOUTONS du même bandeau, pas une gélule : seule forme toute ronde du bandeau
   blanc, elle détonnait à côté de « Donner des droits temporaires » — relevé par le client en réunion
   le 2026-10-05 (« partout ailleurs il y a cet arrondi-là »). Les badges des tableaux, eux, gardent
   `--radius-pastille` : le user n'a retenu que le bandeau. */
.chiffre{display:inline-flex;align-items:center;gap:calc(var(--e-1) * 1.5);min-height:var(--h-controle-sm);padding:0 var(--e-3);
  border:1px solid var(--ligne);border-radius:var(--radius-sm);background:var(--entete-bg);font-size:var(--fs-sm);color:var(--texte);text-decoration:none}
.chiffre b{font-size:var(--fs-base);font-weight:var(--gras-titre);color:var(--texte-fort);font-variant-numeric:tabular-nums}
a.chiffre:hover{border-color:var(--marque-encre);background:var(--survol);color:var(--texte-fort)}
/* À VOIR : la teinte d'avertissement des badges, et le mot porte le sens (SC 1.4.1). */
.chiffre-a-voir,.chiffre-a-voir b{background:var(--warn-bg);color:var(--warn)}
.chiffre-a-voir{border-color:transparent}
/* Le filtre POSÉ : la pastille est cerclée de la marque et porte la CROIX qui le retire — sans elle,
   rien ne disait qu'un second clic ramène la liste entière (le user, 2026-09-29). */
a.chiffre[aria-current="true"]{border-color:var(--marque);box-shadow:inset 0 0 0 1px var(--marque)}
.chiffre-retirer{display:inline-flex;margin-right:calc(var(--e-1) * -1)}
.chiffre-retirer svg{width:var(--t-picto-texte);height:var(--t-picto-texte)}
/* Passés à la ligne, les chiffres et les gestes restent deux GROUPES : plus d'écart entre eux (16 px)
   qu'entre deux pastilles ou deux boutons d'un même groupe (8 px) — la proximité dit ce qui va ensemble. */
.entete-page>.bandeau-fiche-titre{row-gap:var(--e-4)}
.entete-page-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2);margin-left:auto}
.entete-page-actions form{margin:0}

/* ---- Notifications ----
   La zone des messages `#messages-page` reste UN nœud en tête de `main` : elle reçoit les flashs et
   le message hors bande d'un geste. Où elle s'AFFICHE, le gabarit le dit en posant un emplacement
   (`_emplacement-notifications.html.twig`), et la feuille l'y ANCRE — CSS Anchor Positioning, sans
   aucune mesure. Le client a refusé la version d'avant, qui mesurait la place libre de la barre et
   repliait la pile sous les onglets quand elle manquait : l'endroit est une décision du
   développeur, pas un calcul.

   L'ancrage n'a lieu que si trois conditions tiennent ensemble :
   - le navigateur ancre (`@supports`), et connaît `position-visibility` — que Safari 26.0 et 26.1
     n'ont pas — et `anchor-center` — dont Chrome 125 à 128 n'avait que l'ancien nom ;
   - le script a marqué la zone (`data-notifications-actives`) : une pile posée par-dessus la page
     sans bouton « Fermer » serait un piège ;
   - la page porte un emplacement (`:root:has(.emplacement-notifications)`).
   Faute de l'une, la zone reste dans le flux en tête de page : le repli, le même que sans script.

   Plusieurs emplacements portant le nom : le DERNIER du document l'emporte (« the last element in
   tree order »), qu'il précède la zone ou qu'il la suive — d'où un seul de chaque sorte par page.

   `position:absolute` au repos : la pile est posée à son emplacement et le suit. Mais quand
   l'emplacement sort de l'écran, elle se COLLE en haut de l'écran (règle plus bas) : la première
   écriture la laissait partir avec la barre, et le user a relevé qu'une notification arrivée plus
   bas dans la page se perdait hors de l'écran. `fixed` n'est posé que dans cet état-là — un élément
   fixe ancré tremble au défilement sous Firefox (bug 2004003, ouvert), et ce cas n'y a pas été
   mesuré : aucun Firefox ici. `position-visibility: always` est
   écrit parce que sa valeur initiale masque la pile quand l'emplacement sort de la vue, et que les
   moteurs ne s'accordent pas sur ce qu'« hors de la vue » veut dire. Le bloc conteneur est la page :
   un ancêtre qui recevrait `transform`, `filter`, `contain` ou `will-change` en ferait un autre,
   l'ancre ne serait plus retenue, et la pile retomberait à sa place dans le flux. */
@supports (position-visibility: always) and (justify-self: anchor-center){
  .emplacement-notifications:not([data-sous]){anchor-name:--notifications}
  :root:has(.emplacement-notifications) [data-notifications-actives]{position:absolute;z-index:40;
    position-anchor:--notifications;position-visibility:always;top:anchor(top);margin-block-start:var(--e-2);
    justify-self:anchor-center;width:min(var(--l-surgissant),anchor-size(width));
    display:flex;flex-direction:column;gap:var(--e-2)}
  /* Par-dessus la page, une notification se détache : surface opaque et ombre. Dans le flux, elle
     garde l'allure d'un message ordinaire. */
  :root:has(.emplacement-notifications) [data-notifications-actives]>.notification{background:var(--surface);
    border-radius:var(--radius-sm);box-shadow:var(--shadow)}
  :root:has(.emplacement-notifications) [data-notifications-actives]>.notification>.message{margin:0}
  /* L'emplacement est sorti de l'écran — la page a défilé : la pile se colle en haut de l'écran,
     toujours alignée sur lui (`justify-self: anchor-center` demeure), pour qu'une notification qui
     arrive plus bas dans la page soit vue. `notifications.js` le dit en observant l'emplacement. */
  :root:has(.emplacement-notifications) [data-notifications-actives][data-emplacement-hors-vue]{position:fixed;top:0}
  /* Le RELAIS : sous son point de rupture, l'emplacement qui porte `data-sous` prend le nom de
     l'ancre et le retire aux autres — quand la page en a un, et seulement alors. UN élément nommé à
     la fois, parce que de deux ancres de même nom le navigateur retient la dernière du document,
     sans le dire. Les seuils sont ceux de la charte, écrits ici une fois : le gabarit ne passe
     qu'un nom. Le relais `telephone` l'emporte sur `etroit` sous 40rem : même poids de sélecteur,
     écrit après. */
  @media (max-width:879px){
    :root:has(.emplacement-notifications[data-sous="etroit"]) .emplacement-notifications:not([data-sous="etroit"]){anchor-name:none}
    :root:has(.emplacement-notifications[data-sous="etroit"]) .emplacement-notifications[data-sous="etroit"]{anchor-name:--notifications}
  }
  @media (max-width:40rem){
    :root:has(.emplacement-notifications[data-sous="telephone"]) .emplacement-notifications:not([data-sous="telephone"]){anchor-name:none}
    :root:has(.emplacement-notifications[data-sous="telephone"]) .emplacement-notifications[data-sous="telephone"]{anchor-name:--notifications}
  }
}
/* L'emplacement principal de la barre occupe l'espace libre entre le titre et le sélecteur, sur
   toute la hauteur de la barre : la pile s'y centre et s'y pose en haut. Sans ancrage, c'est un
   élément vide qui prend la place que la marge automatique du sélecteur laissait déjà vide. */
.barre>.emplacement-notifications{flex:1 1 0;min-width:0;align-self:stretch}
/* L'enveloppe d'une notification, écrite par le gabarit : le bouton « Fermer » en est l'enfant, À
   CÔTÉ du message et jamais dedans (un `role="status"` annoncerait le bouton inséré) ; il se pose
   par-dessus, dans la marge que le message lui réserve à droite. */
.notification{position:relative;flex-shrink:0}
.notification>.message{padding-right:calc(var(--h-icone) + var(--e-2))}
.message-fermer{position:absolute;top:var(--e-1);right:var(--e-1);display:flex;align-items:center;justify-content:center;
  width:var(--h-icone);height:var(--h-icone);border:0;border-radius:var(--radius-sm);background:none;
  color:var(--texte);font:inherit;font-size:var(--fs-lg);line-height:1;cursor:pointer}
.message-fermer:hover{background:var(--neutre-bg);color:var(--texte-fort)}
.message-fermer:focus-visible{outline:2px solid var(--action);outline-offset:-2px}
/* L'arrivée glisse et se fond, sous préférence de mouvement seulement ; sans elle rien ne bouge. */
@media (prefers-reduced-motion:no-preference){
  .notification{transition:opacity var(--duree),transform var(--duree)}
  @starting-style{.notification{opacity:0;transform:translateY(calc(var(--e-2) * -1))}}
}

/* Le sélecteur de fichier, habillé en zone : cliquer n'importe où dedans ouvre le sélecteur
   (le label enveloppe le champ), déposer un fichier sur le champ le choisit — natif des deux
   côtés. Le trait POINTILLÉ dit « déposez ici » sans un mot ; le champ reste visible parce que
   c'est lui qui confirme le fichier choisi. */
/* UN pixel, pas deux : Carbon et Ant Design sont à 1px, Polaris à 0,66 — deux pixels sont
   la graisse d'avant, et c'est elle qui datait, pas le pointillé. Le pointillé reste : il dit
   « déposez ici » sans un mot, et sept systèmes sur sept l'emploient au repos. */
/* `width:100%` et pas seulement `display:block` : un `<button>` ne s'étire pas à son
   conteneur comme le fait un `<label>`, et la zone de dépôt du champ par morceaux se
   retrouvait large comme son texte — mesuré au navigateur, jamais vu autrement. */
.champ-fichier{display:block;width:100%;padding:var(--e-4);border:1px dashed var(--bord);
  border-radius:var(--radius);background:var(--bg);text-align:center;cursor:pointer;
  transition:border-color var(--duree),background-color var(--duree)}
.champ-fichier:hover,.champ-fichier:focus-within{border-color:var(--marque-encre);background:var(--survol)}
/* L'état SURVOLÉ PAR UN GLISSER, posé par zone-de-depot.js : sans le script, déposer ne marche
   que pile sur l'input natif — le script étend la cible à toute la zone, et cet état le dit. */
/* Le trait devient PLEIN, il ne change pas seulement de couleur : le pointillé dit « rien
   ici pour l'instant », le plein dit « armé, lâchez ». Spectrum, Polaris et GOV.UK basculent
   tous les trois ainsi — trois éditeurs indépendants, même règle. */
.champ-fichier-survolee{border-style:solid;border-color:var(--marque-encre);background:var(--survol)}
/* EN FAUTE, la zone prend le trait d'erreur de toute saisie `.champ.en-erreur` : la règle de la
   base ne vise que les `input`, et ceux du dépôt sont hors écran — le refus s'écrirait sous un
   cadre resté gris. Plus spécifique que le survol, et c'est voulu : un refus ne s'efface pas
   parce que le pointeur passe dessus. */
.champ.en-erreur .champ-fichier{border-color:var(--err)}
.champ-fichier-invite{display:block;margin-bottom:var(--e-3);font-size:var(--fs-sm);color:var(--texte-fort)}
/* La forme BOUTON — le dépôt par morceaux — porte son titre et son aide dans le cadre, alignés à
   gauche comme la maquette validée ; la forme étiquette de la photo de profil reste centrée,
   son champ natif visible dessous. Le titre ne garde qu'un souffle avant l'aide qu'il annonce. */
/* `font:inherit` et une couleur posée : un `<button>` n'hérite PAS de la police de la page — la
   feuille du navigateur lui impose la sienne, et la charte n'a aucune règle `button{font:inherit}`.
   Mesuré au navigateur : le titre et l'aide sortaient dans la police système, l'aide en noir. La
   forme étiquette n'avait pas ce défaut, un `<label>` héritant comme tout texte. */
button.champ-fichier{text-align:left;font:inherit;color:var(--texte)}
button.champ-fichier .champ-fichier-invite{margin-bottom:var(--e-1);font-weight:var(--gras-etiquette)}
.champ-fichier input{width:100%;font-size:var(--fs-xs);color:var(--texte);cursor:pointer}
/* Le bouton natif du champ, aligné sur `.btn` : sans lui, le navigateur pose son gris système
   au milieu de la charte. */
.champ-fichier input::file-selector-button{appearance:none;margin-right:var(--e-3);
  padding:var(--e-2) var(--e-3);border:1px solid var(--bord);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--texte-fort);
  font:var(--gras-etiquette) var(--fs-sm)/1.2 var(--font);cursor:pointer}
.champ-fichier input::file-selector-button:hover{border-color:var(--marque-encre);color:var(--marque-encre)}

/* ─────────────────────────────────────────────────────────────────────────────
   LE DÉPÔT PAR MORCEAUX — la ligne d'un fichier qui monte.

   Trois pièces occupent LE MÊME gabarit `--h-piece` à gauche de la ligne, et se succèdent :
   l'anneau pendant l'envoi, la coche à l'instant où il finit, la vignette ensuite. Comme
   elles font toutes la même taille, la ligne ne bouge pas d'un pixel entre les états — c'est
   toute la raison du gabarit commun, et le remède au défaut qu'avait l'écran de démonstration,
   où le bouton d'annulation apparaissait sans place réservée et faisait sauter la page.

   Et l'anneau est un BOUTON, pas un décor : son glyphe dit le geste. Uppy — l'implémentation
   de référence du protocole que ce socle parle — y loge pause, reprise et annulation, et c'est
   la seule anatomie où « mettre en pause » est le geste de premier plan plutôt qu'« annuler ».
   Un envoi mis en pause garde ses octets ; annuler les jette.
   ───────────────────────────────────────────────────────────────────────────── */
.depot{display:grid;gap:var(--e-2);margin-top:var(--e-3)}
/* Une liste VIDE ne réserve rien : sous le champ de fichier d'un formulaire, elle attend le fichier
   choisi, et son écart poussait le bouton d'envoi pour rien. */
.depot:empty{margin-top:0}
.depot-ligne{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:var(--e-3);
  align-items:center;margin:0;padding:var(--e-2) var(--e-3);
  border:1px solid var(--ligne);border-radius:var(--radius-sm);background:var(--surface)}
.depot-corps{min-width:0}
/* Le nom ne se coupe jamais sur deux lignes : la ligne garderait alors une hauteur variable,
   et tout le dispositif du gabarit commun ne servirait plus à rien. */
.depot-nom{display:block;color:var(--texte-fort);font-weight:var(--gras-etiquette);
  font-size:var(--fs-sm);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Des chiffres de largeur constante : « 3,4 Mo sur 10,1 Mo » se réécrit vingt fois par seconde,
   et sans `tabular-nums` la ligne tremble à chaque rafraîchissement. */
.depot-mesure{display:block;font-size:var(--fs-xs);color:var(--texte);
  font-variant-numeric:tabular-nums}

/* L'ANNEAU. `--part` porte l'avancement, écrit par le script ; le disque intérieur est un
   `::after`, donc peint APRÈS le contenu — d'où le `z-index` sur le glyphe, sans lequel le
   masque le recouvre et l'anneau paraît vide. Mesuré au navigateur, pas déduit. */
.depot-anneau{width:var(--h-piece);height:var(--h-piece);flex:none;border:0;padding:0;
  border-radius:50%;position:relative;display:grid;place-items:center;cursor:pointer;
  background:conic-gradient(var(--marque-encre) var(--part,0%),var(--neutre-bg) 0);
  transition:background-color var(--duree)}
.depot-anneau::after{content:"";position:absolute;inset:3px;border-radius:50%;
  background:var(--surface);transition:inset var(--duree)}
.depot-anneau>span{position:relative;z-index:1;display:grid;place-items:center;line-height:0;
  color:var(--texte)}
.depot-anneau:hover>span{color:var(--marque-encre)}
/* L'achèvement : l'anneau se remplit de la couleur du succès et porte une coche. Il ne RESTE
   pas — le script le remplace par la vignette après un temps court. Une coche permanente
   occuperait la place pour ne rien dire de plus que le libellé « déposé » déjà écrit. */
.depot-anneau.est-fini{background:var(--ok);cursor:default}
.depot-anneau.est-fini>span{color:var(--ok)}

/* LA VIGNETTE prend la place de l'anneau, au même gabarit. Ni curseur ni survol tant qu'elle n'est
   qu'une image : ce qui a l'air cliquable doit l'être. Quand un aperçu existe, elle devient le LIEN
   de la visionneuse (`a.depot-vignette`, ci-dessous). Ce qu'elle montre n'est JAMAIS le
   fichier déposé : c'est une image que le socle a lui-même produite (voir `TypeDeFichier`,
   qui explique pourquoi il n'y a qu'un mode de service). Faute de vignette possible, c'est la
   pastille ci-dessous — le lien de la visionneuse, elle aussi, dès que le fichier est scellé. */
.depot-vignette{width:var(--h-piece);height:var(--h-piece);flex:none;
  border-radius:var(--radius-sm);overflow:hidden;background:var(--neutre-bg);display:block}
.depot-vignette img{width:100%;height:100%;object-fit:cover;display:block}
/* La vignette qui OUVRE l'aperçu : la loupe au pointeur et l'image qui s'éclaircit au survol disent
   qu'elle s'ouvre ; au clavier, l'anneau de focus de la charte. Un `<a>` sans adresse — le gabarit
   avant l'annonce du serveur — ne prend ni l'un ni l'autre. */
a.depot-vignette[href]{cursor:zoom-in}
a.depot-vignette[href]:hover img{opacity:.75}
/* Le conteneur où htmx pose la visionneuse, sous la ligne. Vide la plupart du temps ; sans le script
   de boîte, la carte s'y affiche et reprend l'écart d'une carte. */
.depot-apercu:not(:empty){margin-top:var(--e-3)}
.depot-pastille{width:var(--h-piece);height:var(--h-piece);flex:none;display:grid;
  place-items:center;border-radius:var(--radius-sm);background:var(--neutre-bg);
  font:var(--gras-etiquette) var(--fs-xs)/1 var(--font-mono);color:var(--texte);
  text-transform:uppercase}
/* La PASTILLE qui ouvre la visionneuse — un classeur, une photo HEIC, une vignette qui ne s'est pas
   chargée : la même loupe au pointeur que la vignette, et le fond qui s'éclaircit au survol, faute
   d'image à éclaircir. Un `<a>` sans adresse — le gabarit avant l'annonce — ne prend ni l'un ni
   l'autre. JAMAIS soulignée, au repos comme au survol : c'est une pièce, pas un mot du texte — et la
   ligne est un `<p>`, que `p a` de la base souligne. Mesuré au navigateur : « XLSX » soulignée dans
   son carré, invisible jusque-là parce que la vignette, seul lien de la ligne, n'a pas de texte. */
a.depot-pastille,a.depot-pastille:hover{text-decoration:none}
a.depot-pastille[href]{cursor:zoom-in}
a.depot-pastille[href]:hover{background:var(--survol)}

/* Le refus porte sur la LIGNE, et le message dit le remède — pas seulement le problème. */
.depot-ligne.en-erreur{border-color:var(--err)}
.depot-mesure>.badge{margin-right:var(--e-1)}

/* LE BOUTON DE LA LIGNE — annuler un envoi, retirer un fichier, écarter un refus. Un carré au
   gabarit `--h-piece`, comme les pièces de gauche : la ligne est symétrique et ne bouge pas.
   Son nom est dans `aria-label` et nomme le FICHIER. Le bord reste `--bord` même en destructif :
   c'est lui qui délimite la cible (SC 1.4.11, 3:1), et le filet pâle de la maquette ne tenait
   pas ce seuil — la contrainte change le moyen, la couleur du glyphe garde le sens. */
.depot-action{width:var(--h-piece);height:var(--h-piece);flex:none;display:grid;place-items:center;
  padding:0;border:1px solid var(--bord);border-radius:var(--radius-sm);background:var(--surface);
  color:var(--texte-fort);cursor:pointer;transition:border-color var(--duree),color var(--duree)}
.depot-action:hover{border-color:var(--marque-encre);color:var(--marque-encre)}
.depot-action.destructif{color:var(--err)}
.depot-action.destructif:hover{border-color:var(--err);color:var(--err)}

/* Deux cartes côte à côte qui redescendent à une seule sans media query — `auto-fit` s'en
   charge, et la largeur de bascule est celle d'une donnée lisible, pas une taille d'écran
   devinée. `align-items:start` : deux cartes voisines n'ont aucune raison de mentir sur leur
   hauteur en s'étirant l'une sur l'autre. */
.cartes-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(var(--l-donnee),100%),1fr));
  gap:var(--e-4);align-items:start;margin-bottom:var(--e-4)}
.cartes-2>.carte{margin-bottom:0}
/* Une note posée sous un tableau se détache du dernier rang — collée, elle se lit comme une
   ligne de plus. */
.carte>.table-enveloppe+.aide{display:block;margin-top:var(--e-3)}
/* Un formulaire posé sous un tableau, dans la même carte, s'en détache aussi — son titre collé
   au dernier filet se lisait comme un en-tête de ligne. « Qui a accès » : les partages en cours,
   puis « Partager cet enregistrement ». L'écart venait jusqu'ici d'une SECONDE carte autour du
   tableau, que `carte: false` aurait dû retirer et ne retirait pas (_tableau.html.twig) : mesuré
   le 2026-09-25, 17 px avec elle, 0 sans, 16 avec cette règle. */
.carte>.table-enveloppe+form{margin-top:var(--e-4)}

/* Deux colonnes de champs, même mécanique et même mesure que `.fiche` : deux grilles réglées
   sur la même largeur restent alignées d'une carte à l'autre.

   La GOUTTIÈRE vaut 32 px (`--e-8`) depuis le 2026-09-10, contre 16 auparavant. À 16, sur
   l'écran de rattachement, la liste défilante de gauche et le cadre des rôles se touchaient
   presque : l'ascenseur de la liste venait se coller au bord du `fieldset`, et c'est ce CONTACT
   — plus que la distance — qui étouffait la carte. Regardé sur maquette, aux trois valeurs de
   l'échelle (24, 32, 48), avant d'être posé.

   Elle a bougé EN MÊME TEMPS que celle de `.fiche`, et la changer ici seule est le piège :
   « Mon compte » porte les deux grilles, l'une sous l'autre, et deux gouttières différentes y
   désalignent les colonnes d'une carte à l'autre — ce que la phrase ci-dessus promet. */
.form-grille{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(var(--l-donnee),100%),1fr));
  gap:0 var(--e-8)}
.form-grille>.champ{min-width:0}
/* La grille RESSERRÉE : des champs courts — prénom, nom, code — dans une boîte de 40rem
   n'obtiendraient qu'une colonne avec la mesure d'une donnée ; `--l-champ-grille` en donne deux
   ou trois. Une seule classe de grille et un modificateur, là où `.champs-grille` faisait une
   seconde grille avec une autre mesure. */
.form-grille.dense{grid-template-columns:repeat(auto-fit,minmax(min(var(--l-champ-grille),100%),1fr));gap:var(--e-3)}
/* Le pied du formulaire est séparé du contenu par un filet, et ses boutons vont à DROITE —
   c'est la base fournie, et c'est le sens de lecture d'un formulaire : on finit en bas à
   droite. */
.form-pied{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--e-2);
  margin:var(--e-3) 0 0;padding-top:var(--e-3);border-top:1px solid var(--ligne)}
/* La variante posée sur le fond de page, sous une suite de cartes : le filet appartient aux
   cartes, pas au fond. */
.form-pied-page{border-top:0;padding-top:0}

/* ---- Le pied de formulaire COLLANT — le composant « pied collant » de la vitrine ----
   Il colle au bas de la fenêtre et se DÉCROCHE dès qu'un contrôle du formulaire, hors de lui,
   porte le focus clavier. À pleine page — le formulaire enfant direct de `.contenu` — il va
   d'un bord à l'autre de la zone principale et reste en bas même quand la page est courte ;
   ailleurs, il colle dans son formulaire, à sa largeur.

   **ÉCRIT ICI, APRÈS `.form-pied`, et c'est ce qui le fait fonctionner.** La première version
   vivait six cents lignes plus haut : `.form-pied` déclare `margin:` en RACCOURCI, ce qui remet
   `margin-inline` à zéro, et à spécificité égale c'est la règle la plus BASSE dans le fichier
   qui gagne. Mesuré au navigateur : `marginLeft` valait `0px`, et la barre restait en retrait de
   vingt-quatre pixels de chaque côté au lieu de toucher les bords. Le code paraissait juste, la
   cascade décidait autrement.

   **Le padding BAS, et le centrage, sont ceux de la maquette validée — et ils avaient sauté.**
   `.form-pied` ne pose qu'un `padding-top` : dans une carte, l'espace sous les boutons est celui
   de la carte. Collé au bas de la fenêtre, il n'y a plus rien dessous — mesuré le 2026-09-14,
   0 px entre le bouton et le bord, et le décompte calé en haut d'une rangée étirée. D'où
   `padding-block` et `align-items:center`, posés hors de la borne `@supports` : le décompte
   se centre aussi sur un pied resté statique.

   **La gouttière vient d'un token** (`--gouttiere-contenu`), le même que `.contenu` pose en
   padding : la barre ressort exactement de ce que le contenu rentre, à tous les points de
   rupture. Deux valeurs écrites séparément se seraient désynchronisées au premier changement.

   **Le décrochage au focus n'est pas un raffinement.** Mesuré : une barre de 63 px épinglée en
   bas recouvre ENTIÈREMENT 11 cibles sur 12 — les lignes de la liste font 18 px, les résumés 32
   —, ce qui est l'échec F110 du critère WCAG 2.2 SC 2.4.11 (AA), la cible du socle. Et
   `scroll-padding` NE LE RATTRAPE PAS : il n'agit que quand le navigateur défile, or une cible
   déjà « visible » sous la barre ne déclenche aucun défilement. Avec la règle ci-dessous :
   0 cible masquée sur 20, mesuré au vrai appui sur Tab.

   `:focus-visible` et non `:focus` — un clic de souris ne doit pas faire sauter la barre.
   `vitrine.css` refuse les bandeaux collants pour cette raison exacte ; ici la raison est levée,
   pas ignorée, et c'est ce qui permet de garder la barre. `VitrineTest` tient ce décrochage par
   une garde de texte : un pied collant sans lui réintroduit l'échec F110.

   `:has()` est déjà employé par cette feuille ; là où il manque, la borne `@supports` laisse le
   pied STATIQUE plutôt que collant — du bon côté, et pas à moitié conforme. */
.form-pied-colle{align-items:center;gap:var(--e-3);padding-block:var(--e-3)}
.form-pied-compte{font-size:var(--fs-sm);color:var(--texte);margin-right:auto}
/* Une phrase, puis sa précision dessous : « Hervé Lambert · « Responsable commercial » · … », et
   « La personne en sera prévenue par email. » (planche « Rattacher » D2). Sans `b` ni `small`, le
   compte reste une ligne, comme ailleurs. */
.form-pied-compte>b,.form-pied-compte>small{display:block}
.form-pied-compte>b{color:var(--texte-fort)}
@supports selector(:has(*)){
  .form-pied-colle{position:sticky;bottom:0;z-index:5;background:var(--surface);box-shadow:var(--ombre-haute)}
  /* TOUJOURS EN BAS DE LA FENÊTRE — que la page soit plus longue qu'elle ou plus courte.
     `sticky` ne colle QUE tant que son conteneur dépasse la fenêtre : sur une page courte, la barre
     restait à la fin de son formulaire. Mesuré dans une fenêtre de 1300 px : 444 px de vide SOUS la
     barre. `.contenu` s'étirait bien jusqu'en bas, pas le formulaire qu'il contient.

     D'où la chaîne : le contenu en colonne, le formulaire qui prend la place restante, et la barre
     poussée en bas par la marge haute `auto`. Page courte, le vide passe AU-DESSUS de la barre ;
     page longue, rien ne change — la barre colle au bas de la fenêtre pendant qu'on défile. Et la
     marge basse négative avale la gouttière du contenu, sans quoi la barre flottait à 24 px du bord.

     Borné à la PLEINE PAGE, jamais tout `.contenu` ni tout formulaire : passer un conteneur en
     colonne flexible change la mise en page de TOUS ses enfants, et les marges négatives d'un pied
     posé dans une carte le feraient déborder de la carte. */
  .contenu:has(> form > .form-pied-colle){display:flex;flex-direction:column}
  .contenu > form:has(> .form-pied-colle){flex:1 0 auto;display:flex;flex-direction:column}
  .contenu > form > .form-pied-colle{
    margin:auto calc(-1 * var(--gouttiere-contenu)) calc(-1 * var(--gouttiere-contenu));
    padding-inline:var(--gouttiere-contenu)}
  /* Le formulaire ENTIER est le sujet : le focus peut être n'importe où au-dessus du pied, et il
     doit lâcher. HORS du pied seulement — décroché pendant qu'on tabule sur ses propres boutons,
     il partirait à la fin du formulaire, peut-être sous la fenêtre, le bouton au focus avec lui. */
  form:has(:focus-visible:not(.form-pied-colle *)) .form-pied-colle{position:static;box-shadow:none}
}



/* Un champ en lecture seule se DISTINGUE d'un champ éditable : même fond neutre que les
   pastilles, curseur normal. `readonly` et non `disabled` — il reste focalisable et annoncé.

   Le sélecteur répète les deux `:not()` de la règle générale de base.css, et ce n'est pas du
   bruit : chaque `:not([…])` pèse un attribut, si bien que `.champ input:not(…):not(…)` pèse
   (0,3,1) quand `.champ input[readonly]` ne pesait que (0,2,1). La règle ne s'appliquait
   JAMAIS : mesuré au navigateur le 2026-09-13, le nom en lecture seule de la fiche d'une
   organisation avait le fond de ses voisins modifiables, au pixel près. Elle pèse désormais
   (0,4,1). */
.champ input[readonly]:not([type=checkbox]):not([type=radio]){background:var(--neutre-bg);cursor:default}

/* ── Choisir d'abord : le choix, et les panneaux qui le suivent ──
   De vrais radios dans le formulaire : l'option cochée part avec lui, et la route qui écrit la
   relit et rejoue ses règles. La bascule d'affichage des panneaux est en CSS pur, gardée par
   @supports : un navigateur sans `:has()` montre les panneaux l'un sous l'autre, la page reste
   entièrement utilisable — le même contrat que le repli sans script. (Ce bloc a d'abord décrit
   deux radios « HORS des formulaires », qui ne décidaient de rien : c'était la boîte de création
   du 2026-09-01, partie avec elle.) */
/* ---- Choix : des options qui se LISENT, posées AVANT ce qui en dépend ----
   Né comme « choix de nature » dans la création d'organisation ; c'est le même objet partout où
   un écran demande de choisir d'abord — d'où `.choix`, sans le mot nature. Un `fieldset` : les
   options sont un GROUPE de radios et la légende le nomme ; le cadre gravé du navigateur est
   retiré, comme sur fieldset.champ.

   **Des cartes d'options sous une légende de titre, et plus une bande.** Le composant est né
   dans la boîte de création, dont la maquette posait les options sur une bande sourde, à fond
   perdu entre un en-tête et le formulaire — des marges négatives, des filets haut et bas. Sur la
   page « Ajouter une société ou un service », le choix OUVRE sa carte : rien au-dessus, si bien
   que la bande laissait une marge blanche vide, sa légende à cheval sur son filet haut — un
   `fieldset` pose sa légende SUR sa bordure haute. Relevé par le user le 2026-09-15, capture à
   l'appui. La maquette 3c pose les options en cartes sur la surface, sous une légende au rang
   d'un titre de carte : c'est la forme du composant, et elle ne dépend plus de ce qui l'entoure. */
.choix{display:flex;flex-direction:column;gap:var(--e-2);margin:0 0 var(--e-6);padding:0;border:0;min-width:0}
.choix legend{padding:0;margin-bottom:var(--e-2);font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort)}
.choix-option{display:flex;gap:var(--e-3);align-items:flex-start;cursor:pointer;background:var(--surface);
  border:1px solid var(--ligne);border-radius:var(--radius-sm);padding:var(--e-4)}
.choix-option:hover{background:var(--survol)}
/* Cochée : bordure de texte fort ET fond de survol, les deux de la maquette. Le fond seul ne
   porterait rien — 1,07:1 contre la surface — ; la bordure tient 11:1, et la pastille du radio
   redit l'état : la couleur n'est jamais seule (SC 1.4.1). */
.choix-option:has(input:checked){border-color:var(--texte-fort);background:var(--survol)}
.choix-option b{display:block;margin-bottom:2px;font-size:var(--fs-base);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.choix-option small{display:block;font-size:var(--fs-sm);line-height:1.6;color:var(--texte)}
/* Le radio, dessiné — à la taille des cases du socle (`--h-case`), et coché comme un radio natif :
   un anneau et un point d'encre de marque, séparés par un liseré de surface (le point est le fond,
   le liseré une ombre interne). La première écriture dessinait un anneau épais sans point, là où
   la maquette dessine un radio natif. Le focus clavier vient
   du :focus-visible global. Un radio en `appearance:none` est un dessin d'auteur, et l'état coché
   doit tenir 3:1 contre la surface (SC 1.4.11, l'exception « apparence de l'agent utilisateur » ne
   s'applique plus) : `--marque` n'y vaut que 2,07:1 — tokens.css l'interdit d'ailleurs à tout ce
   qui porte du sens. `--marque-encre` : 5,32:1 clair, 7,30:1 sombre ; `--bord` pour l'anneau au
   repos : 3,63:1 clair, 3,43:1 sombre — la même paire que les champs et l'interrupteur. */
.choix-option input{appearance:none;flex:none;width:var(--h-case);height:var(--h-case);
  margin:2px 0 0;border:1px solid var(--bord);border-radius:var(--radius-gelule);
  background:var(--surface)}
.choix-option input:checked{border:2px solid var(--marque-encre);background:var(--marque-encre);
  box-shadow:inset 0 0 0 3px var(--surface)}

/* ---- Récapitulatif — « ce qui va se passer », dit AVANT le geste ----
   UN seul bloc pour les écrans qui l'emploient : la création d'organisation (« Ce qui va se
   passer »), et la boîte d'invitation jusqu'au 2026-09-08 — celle-ci le remplissait par script
   sous `data-recap`, et sa page de remplacement dit la même chose en clair, sans script, dans
   la phrase au-dessus des cases. Ils étaient deux — `.recap-invitation`, `.recap-creation` — avec cinq écarts
   pour un seul objet, dont trois littéraux (.72em, 600, .1em) là où les tokens d'étiquette
   existent ; la vitrine les a montrés côte à côte. C'est le modèle de la MAQUETTE qui reste,
   accentué dans tous les cas : annoncer les conséquences avant qu'elles aient lieu ne dépend
   ni de l'écran ni de la nature choisie — réserver la teinte à la société laissait croire que
   le service n'avait pas de conséquences, or il en a quatre.
   Teintes dérivées de la marque par color-mix, jamais posées en dur : elles suivent la marque
   du client et le lot sombre — et c'est ce qui les rend DÉPENDANTES d'elle : sur le fond à 10 %
   de la marque livrée, `--marque-encre` tient 4,97:1 en clair (6,02:1 en sombre) et `--texte`
   6,15:1 (6,21:1). Une marque plus sombre fait tomber le titre sous 4,5:1 sans qu'aucun test
   le voie : qui change la marque re-mesure ce bloc. Le titre est une ÉTIQUETTE, au même réglage que les en-têtes de
   colonne — 12 px, là où la maquette le posait à .72em, soit 10 px dans la coquille, sous
   l'échelle sans demi-pixel de tokens.css. */
.recapitulatif{border:1px solid color-mix(in srgb, var(--marque) 45%, var(--surface));
  border-radius:var(--radius-sm);padding:var(--e-3) var(--e-4);margin-block:var(--e-3);
  background:color-mix(in srgb, var(--marque) 10%, var(--surface))}
.recapitulatif-titre{font-size:var(--fs-xs);font-weight:var(--gras-etiquette);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette);
  color:var(--marque-encre);margin:0 0 var(--e-2)}
/* `base.css` retire le marqueur de TOUTE liste (`ul{list-style:none}`), et WebKit retire alors
   le rôle `list` : VoiceOver n'annonce plus « liste, 3 éléments ». Les listes qui portent du
   CONTENU le réclament par `role="list"` dans le gabarit — la vitrine promet ce décompte, il
   faut donc le tenir. Ici la puce est redessinée, mais le rôle ne revient pas avec elle. */
.recapitulatif ul{margin:0;padding:0;list-style:none}
.recapitulatif li{margin-block:var(--e-1);position:relative;padding-left:var(--e-4)}
.recapitulatif li::before{content:'';position:absolute;left:0;top:.45em;
  width:var(--l-puce);height:var(--l-puce);border-radius:var(--radius-gelule);
  background:var(--marque)}
/* Un TABLEAU dans un récapitulatif en est une pièce — une ligne par société et son choix —, pas la
   carte : il garde son cadre et reste dans la teinte. `.carte .table-enveloppe` le tirait jusqu'aux
   bords de la CARTE par des marges négatives, si bien qu'il débordait du récapitulatif de 7 px de
   chaque côté (mesuré, suppression d'un compte, 2026-10-01). Même remède, au même poids, que le
   tableau des droits posé dans une carte. */
.carte .recapitulatif .table-enveloppe{margin:0;width:auto;border:1px solid var(--ligne);
  border-radius:var(--radius-sm);box-shadow:none}
.carte .recapitulatif .table-enveloppe:last-child{margin-bottom:0}
.carte .recapitulatif .table-enveloppe :is(th,td):first-child{padding-left:var(--e-3)}
/* Et ce qui le suit, ou le précède, respire : la phrase avant le premier champ, l'aide après le
   tableau collaient à 4 px. */
.recapitulatif>p+.champ{margin-top:var(--e-3)}
/* Le titre et son aide « ? » sur une ligne (`.aide-titre`) : la marge passe du titre à la ligne, sinon
   elle décalait le titre de 4 px sous le « ? » et laissait le tableau coller à la ligne (mesuré, 0 px). */
.recapitulatif>.aide-titre{margin-bottom:var(--e-2)}
.recapitulatif>.aide-titre>.recapitulatif-titre{margin:0}
.recapitulatif>.table-enveloppe+.aide{margin-top:var(--e-2)}

/* LA FRISE — le récapitulatif quand ce qui va se passer arrive en plusieurs TEMPS : aujourd'hui,
   jusqu'à une date, ensuite. Retenue par le user le 2026-10-01 sur la suppression d'un compte, à la
   place de quatre cadres empilés qu'il trouvait trop denses : côte à côte, un filet entre deux
   temps, et le titre de chaque temps en étiquette — le premier marqué d'un point, c'est celui qui
   arrive au clic. Pas de fond ni de cadre : la frise informe, la zone où l'on agit (un
   `.recapitulatif`, en dessous) garde seule la teinte. Sous 40rem les temps s'empilent, et le filet
   passe au-dessus ; un filet vertical entre deux blocs empilés ne sépare plus rien. */
.frise{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);margin-block:var(--e-4)}
.frise-temps{display:flex;flex-direction:column;gap:var(--e-2);padding-inline:var(--e-4)}
.frise-temps:first-child{padding-left:0}
.frise-temps:last-child{padding-right:0}
.frise-temps+.frise-temps{border-left:1px solid var(--ligne)}
.frise-temps>h3{display:flex;align-items:center;gap:var(--e-2);margin:0;font-size:var(--fs-xs);
  font-weight:var(--gras-etiquette);text-transform:var(--casse-etiquette);
  letter-spacing:var(--interlettrage-etiquette);color:var(--marque-encre)}
.frise-temps:first-child>h3::before{content:'';flex:none;width:var(--l-puce);height:var(--l-puce);
  border-radius:var(--radius-gelule);background:var(--marque)}
.frise-temps>p{margin:0}
@media (max-width:40rem){
  .frise{grid-auto-flow:row;gap:var(--e-3)}
  .frise-temps{padding-inline:0}
  .frise-temps+.frise-temps{border-left:0;border-top:1px solid var(--ligne);padding-top:var(--e-3)}
}

/* UN CHOIX QUI RÉVÈLE SON PANNEAU — l'extension du composant `choix` : dans `.choix-panneaux`,
   le N-ième `.panneau` ne s'affiche que si la N-ième option du choix est cochée. POSITIONNEL,
   pour rester générique : aucun identifiant à connaître, l'ordre des panneaux suit celui des
   options, jusqu'à quatre (au-delà, le choix lui-même n'est plus le bon composant). En CSS pur
   par `:has()` ; sans lui, les panneaux s'affichent l'un sous l'autre, entièrement utilisables.
   Né sur la création d'organisation — un service, une société —, qui en est la première instance. */
@supports selector(:has(*)){
  .choix-panneaux .panneau{display:none}
  .choix-panneaux:has(.choix-option:nth-of-type(1) input:checked) .panneau:nth-of-type(1){display:block}
  .choix-panneaux:has(.choix-option:nth-of-type(2) input:checked) .panneau:nth-of-type(2){display:block}
  .choix-panneaux:has(.choix-option:nth-of-type(3) input:checked) .panneau:nth-of-type(3){display:block}
  .choix-panneaux:has(.choix-option:nth-of-type(4) input:checked) .panneau:nth-of-type(4){display:block}
}
/* La saisie d'un panneau est la QUESTION SUIVANTE du choix — « Raison sociale » après « Une
   société » —, et son étiquette en prend le rang : celui de la légende du choix, un titre de
   carte. En étiquette ordinaire (13 px, 600), elle se lisait comme un détail de formulaire sous
   deux questions en 16 px et 700 ; le user l'a voulue de la taille et du style de « Où le
   ranger ? », le 2026-09-15 — un écart assumé à la maquette 3c, qui la gardait en étiquette.
   Hors du `@supports` : sans `:has()`, les panneaux s'affichent tous, chacun avec sa question. */
.choix-panneaux .panneau>.champ>label{font-size:var(--fs-md);font-weight:var(--gras-titre)}

/* Le bandeau d'emprunt d'identité — pleine largeur, en tête de page, sur toutes les pages.
   Sombre et non coloré par un état : ce n'est ni une erreur ni un succès, c'est un CONTEXTE qui
   dure. Il emprunte les jetons de la navigation, seuls du socle à porter du blanc sur sombre. */
.bandeau-emprunt {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  flex-wrap: wrap;
  padding: var(--e-3) var(--e-6);
  background: var(--nav);
  color: var(--sur-nav);
  font-size: var(--fs-base);
}

.bandeau-emprunt p { margin: 0; flex: 1 1 auto; }

.bandeau-emprunt a {
  color: var(--sur-nav);
  border: 1px solid var(--sur-nav);
  border-radius: var(--radius-sm);
  padding: 0 var(--e-4);
  min-height: var(--h-controle);
  display: inline-flex;
  align-items: center;
  font-weight: 600;
  text-decoration: none;
}

.bandeau-emprunt a:hover { background: var(--sur-nav); color: var(--nav); }

/* ---- Le tableau des droits — le catalogue d'un rôle, les droits d'une personne ---------------
   Les deux planches validées le 2026-09-24 (`Catalogue`, `Main`) dessinent le même tableau : une
   ligne par module, qui se replie, une ligne par onglet, sept colonnes d'actions fixes et « Autres
   droits » qui grandit vers le BAS. Les colonnes d'action ont une largeur fixe (`table-layout`) :
   la même action tombe à la même place d'un module à l'autre, c'est ce qui fait qu'on balaie une
   colonne plutôt qu'on la cherche.

   Le signe est une COCHE ronde, et le genre change la FORME autant que la couleur (SC 1.4.1) :
   pleine, en pointillé et numérotée, à moitié et suivie d'un compte, un tiret. La case vide n'a
   rien — elle dit que l'action n'existe pas dans l'onglet, pas qu'elle est refusée.

   Les sélecteurs portent `.droits-enveloppe` : posé dans une `.carte`, le tableau recevrait sinon
   le retrait de première colonne des tableaux de carte, qui décale la ligne d'onglet sous celle
   du module. */
.droits-enveloppe{margin-bottom:0}
/* UNE LARGEUR PLANCHER, et le cadre défile en dessous. En disposition fixe à 100 %, les colonnes se
   partageaient la largeur disponible si petite soit-elle : sur une fenêtre étroite, « Consulter »,
   « Créer » et « Supprimer » se chevauchaient (le user, 2026-09-28). Le gabarit dit combien de colonnes
   il pose ; au-delà du plancher, la disposition fixe garde des colonnes égales. */
.droits-tableau{table-layout:fixed;min-width:calc(var(--l-colonne-onglet) + var(--colonnes-droits,7) * var(--l-colonne-coche) + var(--avec-autres,0) * var(--l-colonne-coche) * 2)}
/* La légende en bandeau, quand l'écran la montre (`legende_visible`, le catalogue) — hors écran
   sinon, `.hors-ecran` l'emportant par son `!important`. */
.droits-tableau caption{text-align:left;padding:var(--e-2) var(--e-3);background:var(--entete-bg);border-bottom:1px solid var(--ligne);
  font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.droits-enveloppe .droits-tableau th,.droits-enveloppe .droits-tableau td{padding:0;vertical-align:middle}
.droits-enveloppe .droits-tableau thead th{padding:var(--e-2) var(--e-3);vertical-align:bottom;
  text-transform:none;letter-spacing:normal;font-weight:var(--gras-etiquette)}
.droits-enveloppe .droits-tableau thead th:first-child{width:var(--l-colonne-onglet)}
/* Les colonnes d'ACTION se PARTAGENT la largeur, « Autres droits » a la sienne. Fixées à la largeur
   d'une coche, elles laissaient à « Autres droits » tout le reste : sur le catalogue, un tableau qui
   paraissait vide à droite (le user, 2026-09-29). La disposition fixe partage à parts égales ce que
   les colonnes à largeur donnée laissent ; le plancher de `.droits-tableau` tient toujours. */
.droits-enveloppe .droits-tableau thead .droits-colonne{width:auto;padding:var(--e-2) var(--e-1);text-align:center;color:var(--texte-fort)}
.droits-enveloppe .droits-tableau thead th:last-child:not(.droits-colonne){width:calc(var(--l-colonne-coche) * 2)}
.droits-colonne,.droits-case,.droits-autres-cellule,.droits-tableau thead th:last-child{border-left:1px solid var(--ligne)}
.droits-trouve{display:block;color:var(--marque-encre);font-size:var(--fs-xs)}

.droits-module{background:var(--entete-bg)}
.droits-deplier{display:flex;align-items:center;gap:var(--e-2);min-height:var(--h-controle);padding:var(--e-2) var(--e-3);
  color:var(--texte-fort);font-weight:var(--gras-titre);text-decoration:none}
.droits-deplier::before{content:"\25B8";color:var(--texte);font-size:var(--fs-xs)}
.droits-deplier[aria-expanded="true"]::before{content:"\25BE"}
.droits-deplier:hover{background:var(--survol);color:var(--texte-fort)}
.droits-enveloppe .droits-tableau tbody .droits-onglet{padding:var(--e-2) var(--e-3) var(--e-2) calc(var(--e-6) + var(--e-2));
  color:var(--texte-fort);font-weight:var(--gras-etiquette)}

.droits-signe{display:flex;align-items:center;justify-content:center;gap:var(--e-1);min-height:var(--h-controle-sm);
  padding:var(--e-1);color:var(--texte-fort);text-decoration:none}
a.droits-signe:hover,a.droits-autre:hover{background:var(--survol)}
/* TOUTE LA CASE EST LE LIEN (le user, 2026-09-30 : « la zone cliquable doit être toute la case, pas
   juste la police »). Le lien garde sa taille — le signe centré, sa phrase hors écran — et un calque
   posé par-dessus la case entière reçoit le clic : un lien étiré sur une case de tableau par
   `height:100%` ne tient pas, la hauteur d'une cellule n'est pas une hauteur de référence. Le survol
   et le focus se voient donc sur la CASE : le lien seul ne couvre plus ce qu'on vise.

   Et ce calque est une TUILE, en retrait de 4 px et arrondie (le user, même jour : « que la zone soit
   presque la totalité, pour montrer qu'il y a des zones séparées ») : au survol elle prend TOUTE la
   couleur de la case choisie, l'orange pâle cerclé de marque. Blanche et bordée d'abord, elle ne
   disait pas ce que le clic allait ouvrir (« le fond ne repasse pas sur toute la couleur », même jour).
   La ligne survolée garde sa teinte, dont la tuile se détache. Elle passe SOUS le signe (`z-index:-1`,
   dans la case isolée par `isolation`) : devant, elle le cacherait. */
.droits-tableau td.droits-case:has(>a.droits-signe){position:relative;isolation:isolate}
.droits-tableau td.droits-case>a.droits-signe::after{content:"";position:absolute;inset:var(--e-1);border-radius:var(--radius-sm);z-index:-1}
.droits-tableau td.droits-case>a.droits-signe:hover::after{background:var(--accent-bg);box-shadow:inset 0 0 0 1px var(--marque)}
/* Le lien ne peint rien au survol : la tuile est son fond. Le fond de survol commun des liens
   (`a.droits-signe:hover`, plus haut) couvrait la tuile d'une bande presque blanche, à la hauteur
   du signe — relevé par le user sur la recette, même jour. */
.droits-tableau td.droits-case>a.droits-signe:hover{background:transparent}
.droits-tableau td.droits-case>a.droits-signe:focus-visible{outline:none}
.droits-tableau td.droits-case>a.droits-signe:focus-visible::after{outline:2px solid var(--focus);outline-offset:0}
.droits-signe[aria-current="true"],.droits-autre[aria-current="true"]{background:var(--survol);box-shadow:inset 0 0 0 2px var(--marque)}
/* LA CASE CHOISIE EST L'ONGLET DE SA RÉPONSE (le user, 2026-09-30) : sa tuile prend le fond de la
   réponse qui s'ouvre dessous, filet de marque EN HAUT comme un onglet, et descend jusqu'à elle —
   le trait qui les séparait tombe. Un cadre orange autour de la coche, au-dessus d'une carte, se
   lisait comme deux choses. Le fond est l'orange PÂLE de la réponse (`--accent-bg`), jamais l'orange
   plein : la coche d'un droit ouvert EST orange, elle y disparaîtrait. Et plus `--survol` : c'est la
   teinte d'une ligne survolée, et la case choisie s'y confondait (capture du user, même jour). */
.droits-tableau td.droits-case:has(>a.droits-signe[aria-current="true"]){border-bottom-color:transparent}
.droits-tableau td.droits-case>a.droits-signe[aria-current="true"]{background:transparent;box-shadow:none}
.droits-tableau td.droits-case>a.droits-signe[aria-current="true"]::after{inset:var(--e-1) var(--e-1) 0;border-radius:var(--radius-sm) var(--radius-sm) 0 0;
  background:var(--accent-bg);box-shadow:inset 0 3px 0 var(--marque)}
.droits-case-attenuee{background:var(--entete-bg)}

.coche{display:inline-flex;align-items:center;justify-content:center;flex:none;box-sizing:border-box;
  width:var(--h-case);height:var(--h-case);border-radius:var(--radius-gelule);
  font-size:var(--fs-xs);font-weight:var(--gras-titre);line-height:1}
/* L'ORANGE DU THÈME pour ce qui est ouvert (le user, 2026-09-30, « Après 1 » de l'artefact) — mais
   jamais seul : #F6A23E sur blanc ne vaut que 2,07:1, sous le 3:1 d'un symbole (WCAG 1.4.11). C'est
   le CERCLE d'encre de marque (5,32:1) qui porte la forme, et il suffit à distinguer l'ouvert du
   trait gris du « fermé » ; la coche blanche n'y ajoute que le mot « oui », que la phrase hors écran
   dit déjà. Elle a été cernée de foncé une heure : « moche au final » (le user, le même jour). */
.coche-oui{background:var(--marque);color:var(--sur-marque-clair);box-shadow:inset 0 0 0 1.5px var(--marque-encre)}
.coche-temporaire{background:var(--surface);color:var(--marque-encre);border:1.5px dashed var(--marque-encre)}
.coche-partielle{border:1.5px solid var(--marque-encre);background:linear-gradient(to right,var(--marque) 50%,var(--surface) 50%)}
.coche-non{color:var(--texte);font-size:var(--fs-sm);font-weight:normal}
.coche-compte{font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte);line-height:1}
.coche-note{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;
  min-width:var(--h-case);height:var(--h-case);padding:0 var(--e-1);margin-left:var(--e-1);
  border:1px solid var(--marque-encre);border-radius:var(--radius-gelule);color:var(--marque-encre);
  font-size:var(--fs-xs);font-weight:var(--gras-titre);line-height:1}

.droits-enveloppe .droits-tableau .droits-autres-cellule{padding:var(--e-1) var(--e-2)}
.droits-autres{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--e-1)}
.droits-autres-en-ligne{flex-direction:row;flex-wrap:wrap;gap:var(--e-1) var(--e-6)}
.droits-autre{display:flex;align-items:flex-start;gap:var(--e-2);min-height:var(--e-6);padding:var(--e-1);border-radius:var(--radius-sm);
  font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte-fort);text-decoration:none;line-height:1.35}
.droits-autre:has(.coche-non){color:var(--texte);font-weight:normal}

/* ---- La forme « fiche » du tableau (`forme: 'fiche'`) ----------------------------------------
   Le catalogue et la fiche rangent les MÊMES lignes ; leurs planches ne les dessinent pas pareil.
   Celle de la fiche (`Main.dc.html`) : aucun filet vertical — un onglet se lit d'un bout à l'autre
   de sa ligne —, des coches DESSINÉES de 24 px, un disque et une coche au trait, un trait court
   pour « non », le nom d'un module précédé d'un chevron qui pivote quand il s'ouvre, l'intitulé
   de la première colonne tu à l'écran. Une case d'onglet fait 48 px, la ligne d'un module 44. */
.droits-fiche .droits-colonne,.droits-fiche .droits-case,.droits-fiche .droits-autres-cellule,
.droits-fiche .droits-tableau thead th:last-child{border-left:0}
/* Sans ombre : la planche borde le tableau d'un filet, et c'est tout — l'ombre de l'enveloppe en
   faisait une carte posée sur la page, et une seconde carte dans le panneau de l'aperçu. */
.droits-enveloppe.droits-fiche{box-shadow:none}
.droits-enveloppe.droits-fiche .droits-tableau thead th{padding:var(--e-3) 2px;line-height:1.25;font-size:var(--fs-xs);color:var(--texte-fort)}
.droits-enveloppe.droits-fiche .droits-tableau thead th:first-child{width:var(--l-colonne-intitule);padding:var(--e-3) var(--e-4)}
.droits-fiche .droits-case{text-align:center}
.droits-fiche tr:not(.droits-module)>.droits-case{height:var(--e-12)}
.droits-fiche .droits-module:has(.droits-deplier[aria-expanded="false"])>*{height:calc(var(--e-12) - var(--e-1))}
.droits-enveloppe.droits-fiche .droits-tableau .droits-module th{padding:0 var(--e-4)}
.droits-fiche .droits-deplier{min-height:var(--h-piece);padding:0;font-size:var(--fs-sm)}
.droits-fiche .droits-deplier::before{content:none}
.droits-fiche .droits-deplier:hover{background:transparent;text-decoration:underline}
.droits-enveloppe.droits-fiche .droits-tableau tbody .droits-onglet{padding:0 var(--e-4) 0 calc(var(--e-8) + var(--e-2));
  font-size:var(--fs-base);font-weight:var(--gras-menu)}
.droits-fiche .droits-signe{min-height:0;padding:0;gap:3px}
.droits-fiche .coche-note{margin-left:0}
.droits-chevron{flex:none;width:var(--e-3);height:var(--e-3);fill:none;stroke:var(--texte-fort);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.droits-deplier[aria-expanded="true"] .droits-chevron{transform:rotate(90deg)}
/* LA FORME « APERÇU » (`forme: 'apercu'`) : le dessin de la fiche, RESSERRÉ comme sur la planche 8
   — en-têtes à 10 px, onglets de 40 px en 13 px —, parce qu'il vit sous les cases qu'on coche et doit
   tenir avec elles dans l'écran. Les deux sélecteurs d'en-tête : celui de la première colonne pèse
   plus lourd dans la forme « fiche », et c'est l'ordre qui le départage ici. */
.droits-enveloppe.droits-apercu .droits-tableau thead th,
.droits-enveloppe.droits-apercu .droits-tableau thead th:first-child{padding-top:calc(var(--e-1) * 2.5);padding-bottom:calc(var(--e-1) * 2.5)}
.droits-apercu tr:not(.droits-module)>.droits-case{height:calc(var(--e-8) + var(--e-2))}
.droits-enveloppe.droits-apercu .droits-tableau tbody .droits-onglet{font-size:var(--fs-sm)}
.coche-dessin{display:block;flex:none;width:var(--e-6);height:var(--e-6)}
.coche-dessin path{fill:none;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.coche-dessin-oui circle{fill:var(--marque);stroke:var(--marque-encre);stroke-width:1.6}
.coche-dessin-oui path{stroke:var(--sur-marque-clair)}
.coche-dessin-temporaire circle{fill:var(--surface);stroke:var(--marque-encre);stroke-width:1.6;stroke-dasharray:3 2.4}
.coche-dessin-temporaire path{stroke:var(--marque-encre)}
.coche-dessin-partielle circle{fill:var(--surface);stroke:var(--marque-encre);stroke-width:1.6}
.coche-dessin-partielle path{fill:var(--marque);stroke:none}
.coche-trait{display:block;flex:none;width:var(--e-3);height:2px;border-radius:2px;background:var(--bord)}
.coche-case-vide{display:block;width:var(--e-6);height:var(--e-6);box-sizing:border-box;border:1px dashed var(--ligne);border-radius:var(--e-1)}
.droits-note .coche-note{min-width:var(--h-signe);height:var(--h-signe)}

.droits-administration{border-top:1px solid var(--ligne);padding:var(--e-3) var(--e-4);display:flex;flex-direction:column;gap:var(--e-2)}
.droits-administration h3{margin:0;font-size:var(--fs-sm);font-weight:var(--gras-titre);color:var(--texte-fort)}
.droits-administration .droits-autre{font-size:var(--fs-sm)}

/* La réponse à « Qui peut ? » s'ouvre SOUS la ligne cliquée, sur toute la largeur : la question
   reste à côté de ce qui l'a posée. Pour un droit d'administration, qui n'a pas de ligne, sous le
   tableau. Le filet de marque à gauche la rattache à la case choisie, cerclée du même ton. */
.droits-enveloppe .droits-tableau .droits-reponse>td{padding:0;background:var(--accent-bg)}
section.droits-reponse{margin-top:var(--e-4);background:var(--accent-bg);border:1px solid var(--ligne);border-radius:var(--radius);overflow:hidden}
.droits-reponse-corps{display:flex;flex-direction:column;gap:var(--e-2);padding:var(--e-3) var(--e-6);border-left:3px solid var(--marque)}
.droits-reponse-tete{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2) var(--e-4)}
.droits-reponse-tete h3{margin:0;font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort)}
/* Le droit demandé, au-dessus de « Qui a ce droit ? » : l'étiquette de la charte, à l'encre de la marque. */
.droits-reponse-droit{display:block;margin-bottom:var(--e-1);font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--accent);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.droits-reponse-tete .btn{margin-left:auto}
/* Sans filet sous chaque entrée : dans une grille de plusieurs colonnes, le filet de la dernière
   rangée soulignait le vide (relevé par le user le 2026-09-29 sur « Qui a ce droit ? »). Les rangées
   se séparent par l'espace. */
.droits-reponse-liste{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--l-donnee)),1fr));gap:var(--e-2) var(--e-8)}
.droits-reponse-liste li{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2);min-height:var(--h-controle-sm);
  font-size:var(--fs-sm);color:var(--texte-fort)}
.droits-reponse-liste a.badge{text-decoration:none;color:var(--texte-fort)}
.droits-reponse-liste a.badge:hover{background:var(--ligne)}
.droits-temporaire{border:1.5px dashed var(--texte-fort);border-radius:var(--radius-gelule);padding:0 var(--e-2);
  font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.droits-alerte{flex-basis:100%;font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--warn)}

/* « Comprendre le tableau » : la clef des signes, dans la bulle de son aide (`_legende-des-droits`)
   — un signe, sa phrase. Elle était un cadre replié au-dessus du tableau, et sur la fiche un second
   dépliant sous lui : une seule clef depuis le 2026-09-29, accrochée au titre du tableau. */
.coches-legende{display:grid;grid-template-columns:calc(var(--e-12) + var(--e-2)) minmax(0,1fr);gap:var(--e-2) var(--e-3);margin:0 0 var(--e-2)}
.coches-legende>div{display:contents}
.coches-legende dt{display:flex;align-items:center;gap:2px;font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.coches-legende dd{margin:0}
.coches-legende .coche-trait{margin-left:calc(var(--e-1) * 1.5)}

/* ---- « Rôles et droits » (Paramètres) — la page, pas un composant ----------------------------
   Les rôles dans une colonne étroite, ce qu'ouvre celui qu'on regarde dans le reste — la planche
   « Catalogue ». Chaque rôle est un LIEN (`aria-current` sur celui qu'on regarde) : l'adresse dit
   quel rôle on lit, et se partage. Sous le point de rupture, la liste passe au-dessus. */
.roles-et-droits{display:flex;gap:var(--e-3);align-items:flex-start}
.roles-liste{flex:0 0 var(--l-colonne-roles);padding:0;overflow:hidden;margin:0}
/* Le panneau du rôle est une carte SANS rembourrage : sa tête a le sien, et le tableau va d'un bord à
   l'autre, comme sur la planche. `.carte` n'est pas posée : ses règles de tableau tireraient
   l'enveloppe au-delà des bords, faites pour une carte rembourrée. */
.roles-panneau{flex:1;min-width:0;background:var(--surface);border:1px solid var(--ligne);border-radius:var(--radius);
  box-shadow:var(--shadow);overflow:hidden}
/* L'HISTORIQUE D'UN RÔLE (`parametres/_historique-versions`) : une carte par version, l'une sous
   l'autre ; dans chacune, ce qui a changé rangé par onglet — le groupe à gauche, ses droits en
   pastilles à droite. Sans fil vertical à gauche : « ça prend de la place pour rien » (le user,
   2026-09-30). */
.historique{display:flex;flex-direction:column;gap:var(--e-3);margin:0;padding:0;list-style:none}
/* Dans une carte, chaque bloc — la date, un retour, un renommage, le détail — à la même distance du
   suivant : la pastille « Retour à la version 3 » collait au détail qu'elle annonce (mesuré, 0 px). */
.historique>.carte{display:flex;flex-direction:column;gap:var(--e-2)}
.historique>.carte>p{margin:0}
/* Le titre, puis quand, qui et combien, sur SA ligne ; le bouton « Rétablir » reste dans le coin. */
.carte-tete>.historique-tete{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2) var(--e-3);margin-right:auto}
.carte-tete>.historique-tete>h2{margin:0;font-size:var(--fs-base);font-weight:var(--gras-titre)}
.historique-changements{display:grid;grid-template-columns:minmax(0,var(--l-colonne-intitule)) minmax(0,1fr);gap:var(--e-2) var(--e-4);margin:0}
.historique-changements dt{color:var(--texte-fort);font-weight:var(--gras-etiquette)}
.historique-changements dd{display:flex;flex-wrap:wrap;gap:var(--e-1);margin:0}
@media (max-width:40rem){.historique-changements{grid-template-columns:1fr;gap:var(--e-1)}.historique-changements dd{margin-bottom:var(--e-2)}}
.roles-panneau-tete{display:flex;flex-direction:column;gap:var(--e-3);padding:var(--e-4);border-bottom:1px solid var(--ligne);background:var(--entete-bg)}
.roles-liste-corps{max-height:var(--h-liste-roles);overflow-y:auto}
.roles-liste-tete .champ label,.roles-filtres .champ label{font-size:var(--fs-xs);margin-bottom:var(--e-1)}
.roles-liste-tete .champ input,.roles-filtres .champ input{min-height:var(--h-controle-sm);background:var(--surface);
  border-radius:var(--radius-sm);font-size:var(--fs-sm)}
.roles-filtres{display:flex;flex-direction:column;gap:var(--e-3);margin:0;padding:var(--e-4) var(--e-4) 0}
/* LA CONSIGNE D'UN CHAMP, lue au focus seulement (`.aide-au-focus`, motif « filtres »), posée SOUS
   le champ hors du flux : les champs d'une rangée de filtres s'alignent par le bas, et une ligne de
   plus dans l'un le remonterait au-dessus de ses voisins ; dans le flux, la rangée grandirait à chaque
   clic et le tableau dessous sauterait. Hors du focus elle est invisible ; `aria-describedby` la lit
   dans les deux cas — un texte caché référencé entre dans la description (accname 1.2). */
.champ:has(>.aide-au-focus){position:relative}
.aide-au-focus{position:absolute;top:100%;left:0;margin-top:var(--e-1);white-space:nowrap}
.champ:not(:focus-within)>.aide-au-focus{visibility:hidden}
/* Sous le plancher, la consigne se lit dans l'encre de la marque, un cran plus appuyée — la maquette
   retenue par le user le 2026-09-28 ; et la rangée lui garde sa ligne, sans quoi elle mordait sur le
   haut du tableau (relevé par le user le même jour, capture à l'appui). */
.aide-au-focus[data-plancher-court]{color:var(--accent);font-weight:var(--gras-etiquette)}
.filtres:has(.aide-au-focus){padding-bottom:var(--e-6)}
.roles-trouves{margin:var(--e-3) var(--e-4) 0;font-size:var(--fs-sm);color:var(--texte-fort)}
/* Dans le panneau, le tableau a son CADRE et de l'air autour, comme sur la fiche d'une personne —
   sans ombre : le panneau est la surface, une ombre de plus ferait une carte dans la carte. Il était
   À FLEUR, comme sur la planche ; le user l'a trouvé « collé en bout de bloc » (2026-09-28). */
.roles-panneau .droits-enveloppe{margin:var(--e-4);border:1px solid var(--ligne);border-radius:var(--radius);box-shadow:none}
/* Un panneau suivi d'une carte (la page d'un modèle : ses droits, puis « Qui a reçu ces droits ») garde
   l'écart de deux cartes. */
.roles-panneau+.carte{margin-top:var(--e-4)}
.roles-liste-tete{display:flex;flex-direction:column;gap:var(--e-2);padding:var(--e-3);border-bottom:1px solid var(--ligne)}
.roles-liste-tete h2{margin:0;font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette)}
.roles-liste-tete .champ{margin-bottom:0}
.roles-liste ul{list-style:none;margin:0;padding:0}
.roles-liste-groupe{margin:0;padding:var(--e-2) var(--e-3);background:var(--entete-bg);border-bottom:1px solid var(--ligne);
  font-size:var(--fs-xs);font-weight:var(--gras-etiquette);color:var(--texte)}
.roles-liste-lien{display:flex;flex-direction:column;gap:2px;min-height:var(--h-controle);padding:var(--e-2) var(--e-3);
  border-bottom:1px solid var(--ligne);color:var(--texte-fort);text-decoration:none}
.roles-liste-lien b{font-size:var(--fs-sm);font-weight:var(--gras-etiquette)}
.roles-liste-lien small{font-size:var(--fs-xs);color:var(--texte)}
.roles-liste-lien:hover{background:var(--survol);color:var(--texte-fort)}
.roles-liste-lien[aria-current="true"]{background:var(--survol);box-shadow:inset 3px 0 0 var(--marque)}
.roles-liste-lien[aria-current="true"] b{font-weight:var(--gras-titre)}
/* Un rôle RETIRÉ dans la liste : grisé, sous « Retirés » — il se lit, il ne s'attribue plus. */
.roles-liste-retire b{color:var(--texte);font-weight:var(--gras-menu)}
.roles-panneau-titre{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2)}
/* L'en-tête de l'écran vit dans le bandeau : le bouton va à droite. (« Comment marchent les rôles »
   y était un repli jusqu'au 2026-09-29 ; c'est l'aide du titre « Les rôles du groupe ». ) */
.bandeau-fiche>.message{margin:0}
.bandeau-fiche-titre>.btn-primaire{margin-left:auto}
.roles-panneau-titre h2{margin:0 auto 0 0;min-width:0;font-size:var(--fs-xl);font-weight:var(--gras-titre);line-height:1.2;color:var(--texte-fort)}
/* Un badge collé au titre (« Retiré ») : c'est LUI qui pousse les gestes à droite, sinon il partait
   avec eux, loin du nom qu'il qualifie. */
.roles-panneau-titre h2:has(+.badge){margin-right:0}
.roles-panneau-titre h2+.badge{margin-right:auto}
/* « À QUOI IL SERT » EN SOUS-TITRE (le user, 2026-09-30, variante 2 de l'artefact « Description ») :
   plus grand et plus foncé que ce qui suit, collé au nom — le rôle se présente comme on le dirait,
   son nom puis ce qu'il fait. Même corps et même couleur que la phrase de l'effectif, les deux se
   lisaient comme une seule phrase. Un filet la sépare de l'effectif, qui passe plus discret ; sans
   description, ni filet ni sous-titre : l'effectif suit le nom. */
.roles-panneau-description{margin:calc(var(--e-1) * -1) 0 0;font-size:var(--fs-md);line-height:1.45;color:var(--texte-fort)}
.roles-panneau-description+.roles-panneau-effectif{padding-top:var(--e-3);border-top:1px solid var(--ligne);font-size:var(--fs-sm)}
/* Combien l'ont, et où : le total en lien, puis une pastille par société, rangées par nom — des
   étiquettes, pas des liens (le user, 2026-09-30 : « cela reste informatif »). */
.roles-panneau-effectif{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2)}
.roles-panneau-effectif>a{font-weight:var(--gras-titre)}
.roles-panneau-effectif>p{margin:0}
.roles-panneau-effectif>ul{display:flex;flex-wrap:wrap;gap:var(--e-2);margin:0;padding:0;list-style:none}
.roles-panneau-effectif .badge{margin:0}
@media (max-width:879px){
  .roles-et-droits{flex-direction:column;align-items:stretch}
  .roles-liste{flex-basis:auto}
}

/* Les notes sous le tableau des droits : un rôle temporaire, un remplacement — ce que dit le numéro
   d'une coche en pointillé. Chaque note est un bloc, le numéro d'abord, le lien à droite. */
.droits-notes{list-style:none;margin:var(--e-3) 0 0;padding:0;display:flex;flex-direction:column;gap:var(--e-2)}
.droits-note{display:flex;gap:var(--e-3);align-items:flex-start;padding:var(--e-3) var(--e-4);background:var(--surface);
  border:1px solid var(--ligne);border-radius:var(--radius)}
.droits-note .coche-note{margin:0;flex:none}
.droits-note>div{flex:1;display:flex;flex-direction:column;gap:var(--e-1)}
.droits-note p{margin:0}
.droits-note .badge{align-self:flex-start}
.droits-note>a{font-size:var(--fs-sm);font-weight:var(--gras-etiquette);white-space:nowrap}

/* ---- La fiche d'une personne — la page, pas un composant -----------------------------------
   La planche « Fiche d'une personne » (`Main.dc.html`) fait foi, cote à cote, à l'échelle de la
   coque près : 14 px et contrôles de 38 px, ceux de la base fournie, là où la planche, dessinée
   hors de la coque, écrit 15 et 44. Le nom garde ses 25 px — la coque ne réduit pas cette taille.

   Ses sociétés en CARTES : la tête d'abord, au TIERS d'une rangée, puis ce qui est rangé dessous,
   en retrait derrière un filet, trois par rangée. Une carte en POINTILLÉ est une société atteinte
   par le haut, sans rattachement : la bordure change de forme, pas seulement de couleur, et le
   lecteur d'écran lit « atteinte par ». Une carte VIDE est la tête où la personne n'a aucun rôle. */
.fiche-personne-tete .avatar{background:var(--neutre-bg);color:var(--texte-fort);font-size:var(--fs-lg)}
.fiche-personne-identite{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.fiche-personne-identite h2{margin:0;font-size:var(--fs-xl);font-weight:var(--gras-titre);line-height:1.2;color:var(--texte-fort)}
.fiche-personne-identite p{margin:0;display:flex;flex-wrap:wrap;gap:0 calc(var(--e-4) + var(--e-1))}
.fiche-personne-fonction{color:var(--texte-fort);font-weight:var(--gras-menu)}
.fiche-personne-section{display:flex;flex-direction:column;gap:var(--e-4);margin-top:var(--e-8)}
.fiche-personne-section+.fiche-personne-section{margin-top:calc(var(--e-8) + var(--e-2))}
.fiche-personne-section>h2,.droits-tete :is(h2,h3){margin:0;font-size:var(--fs-lg);font-weight:var(--gras-titre);color:var(--texte-fort)}
.societes{display:flex;flex-direction:column;gap:var(--e-3)}
.societe-carte{display:flex;align-items:flex-start;gap:var(--e-3);box-sizing:border-box;min-height:calc(var(--e-12) + var(--e-1));
  padding:var(--e-3) var(--e-3) var(--e-3) var(--e-4);background:var(--surface);border:1px solid var(--ligne);border-radius:var(--radius);
  color:var(--texte-fort);list-style:none;min-width:0}
.societe-carte-corps{flex:1;min-width:0;display:flex;flex-direction:column;gap:calc(var(--e-1) * 1.5)}
.societe-carte-corps b{font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.societe-carte-corps p{margin:0;display:flex;flex-wrap:wrap;gap:calc(var(--e-1) * 1.5)}
.societe-carte-tete{width:calc((100% - 2 * var(--e-3)) / 3)}
.societe-carte-vide{background:transparent;align-items:center}
.societe-carte-vide b{color:var(--texte);font-weight:var(--gras-menu)}
.societe-carte-heritee{border-style:dashed;border-color:var(--bord)}
/* « Convertir » : une société décochée se voit avant qu'on confirme — le fond d'accent, le bord de
   l'erreur, comme la carte de la maquette validée. */
.societe-carte-heritee:has(>input[type=checkbox]:not(:checked)){border-style:solid;border-color:var(--err);background:var(--accent-bg)}
/* La case de « Convertir » est posée seule sur la carte, hors de `.case` : sans cette règle, AUCUNE ne la
   dessinait — 13 px, bleue, au défaut du navigateur, là où toutes les cases du socle font 18 px, orange
   (relevé par le user le 2026-09-28, planche et écran côte à côte). */
.societe-carte>input[type=checkbox]{flex:none;width:var(--h-case);height:var(--h-case);margin:0;accent-color:var(--marque)}
/* Une organisation où elle n'a PAS accès : sur le fond de la page, sans rôle, case vide ; cochée, elle
   prend la couleur du geste qu'elle ouvre (« Donner l'accès »), comme une société décochée prend
   celle du retrait. */
.societe-carte-sans-acces{background:transparent}
.societe-carte-sans-acces:has(>input[type=checkbox]:checked){border-color:var(--marque);background:var(--accent-bg)}
/* « Donner l'accès » : où elle porte déjà ce rôle, dans l'encre de la marque — c'est ce qui décide. */
.cases-cartes .case small.fiche-don-ou{color:var(--marque-encre);font-weight:var(--gras-etiquette)}
/* Ce que le rattachement à la tête ouvre : la conséquence de la carte, dans l'encre de la marque. */
.societe-carte-corps p.societe-carte-perimetre{align-items:center;gap:var(--e-1);color:var(--marque-encre);font-weight:var(--gras-etiquette)}
/* « Gérer » en graisse d'étiquette, comme les autres boutons de la carte sur la planche : le menu
   de la vitrine l'écrit au poids du texte, pour le sélecteur d'organisation de la barre. */
.societe-carte .menu-deroulant>summary{font-weight:var(--gras-etiquette)}
/* Les gélules de rôle de la planche, plus fines que le badge du socle : graisse 500, 2 × 10 px,
   arrondi entier. Mesuré sur la planche : 21 px de haut dans une carte. */
.societe-carte .badge{padding:2px calc(var(--e-1) * 2.5);border-radius:var(--radius-gelule);font-weight:var(--gras-menu)}
.societes-dessous{display:flex;flex-direction:column;gap:var(--e-2);margin-left:calc(var(--e-4) + var(--e-1));
  padding-left:calc(var(--e-4) + var(--e-1));border-left:2px solid var(--ligne)}
.societes-dessous>ul{margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--e-3)}
@media (max-width:879px){
  .societes-dessous>ul{grid-template-columns:minmax(0,1fr)}
  .societe-carte-tete{width:auto}
}
/* LA TÊTE DU TABLEAU DES DROITS (composant « droits ») : le titre prend la place, les deux réglages
   — « Tout déplier », « Seulement… » — se rangent à droite, sur sa ligne. Née sur la fiche d'un
   utilisateur, reprise par l'aperçu de l'invitation puis par « Rôles et droits » (le user, 2026-09-30 :
   « pas aligné », la recherche mêlée aux réglages) : trois écrans, une règle. La recherche, quand
   l'écran en a une, est COMPACTE et devant les réglages (`.droits-recherche`, le user, 2026-10-02 : seule
   sur sa ligne, elle prenait toute la largeur pour presque rien) ; son étiquette est hors écran — visible,
   au-dessus du champ, elle désalignait toute la rangée —, et la loupe dit ce qu'est le champ. */
.droits-tete{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2) var(--e-4);flex:1 1 100%}
.droits-tete form{display:flex;align-items:center;gap:var(--e-2);margin:0}
.droits-tete .case{font-size:var(--fs-sm);color:var(--texte-fort)}
.droits-recherche{margin:0;flex:0 1 var(--l-recherche-droit);position:relative}
.droits-recherche>svg{position:absolute;left:var(--e-3);top:50%;transform:translateY(-50%);width:var(--h-picto-champ);height:var(--h-picto-champ);color:var(--texte);pointer-events:none}
.droits-tete .droits-recherche input:not([type=checkbox]):not([type=radio]){min-height:var(--h-controle-sm);padding-left:calc(var(--e-3) + var(--h-picto-champ) + var(--e-2))}
/* Quand le tableau suit la tête sans rien entre les deux (« Ce qu'il ouvre », le formulaire d'un rôle),
   de l'air entre eux : le titre et sa bulle collaient au tableau (le user, 2026-09-30). Trois classes,
   pas deux : `.carte .table-enveloppe.droits-enveloppe{margin:0}` l'emportait, et l'écart mesuré au
   navigateur valait 0 px sous une règle pourtant présente. */
.droits-tete+.table-enveloppe.droits-enveloppe{margin-top:var(--e-4)}
.droits-recherche input{width:100%}
.fiche-droits-contenu{display:flex;flex-direction:column;gap:var(--e-4)}
.fiche-droits-contenu .droits-notes{margin-top:0}
.fiche-groupes{margin:0}
.fiche-groupes+.fiche-groupe-noms{margin-top:calc(-1 * var(--e-1))}
.fiche-groupes .pilule{min-height:var(--h-controle-sm);padding:0 var(--e-3);border-radius:var(--radius-gelule);font-size:var(--fs-sm)}
.fiche-groupes .coche-note{margin-left:0}
.fiche-groupes .pilule[aria-current="true"] .coche-note{border-color:var(--sur-action);color:var(--sur-action)}
.fiche-groupe-noms{margin:0;font-size:var(--fs-sm);color:var(--texte)}

/* L'APERÇU d'un changement de rôles : ce que le geste donnerait, ce qu'il reprendrait — avant de
   l'enregistrer. La case gagnée garde la coche et prend un « + », la case perdue un « − » ; le fond
   n'est qu'un renfort, le signe et la phrase portent l'information (SC 1.4.1). En VERT et en rouge
   depuis le 2026-10-01 (le user : « ajouter ou retirer des droits en vert et en rouge ») — l'ajout
   était ambré —, et le même dessin sert à « Donner des droits temporaires ». */
.droits-case-ajout{background:var(--ok-bg)}
.droits-case-retrait{background:var(--err-bg)}
.coche-plus{font-size:var(--fs-sm);font-weight:var(--gras-titre);color:var(--ok);line-height:1}
.coche-moins{font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--err);line-height:1}
/* Les gestes de la fiche s'ouvrent en PANNEAU dans la page, sous les sociétés — jamais une fenêtre :
   la planche le veut, et l'adresse dit quel panneau est ouvert. Le retrait est bordé de rouge.

   Un panneau n'est PAS une `.carte` : sa planche le dessine sans ombre, à 20 et 24 px de marge, et
   l'aperçu qu'il porte GARDE le cadre de son tableau — `.carte .table-enveloppe` le lui retirait
   pour le coller aux bords, ce qui vaut quand le tableau EST la carte, pas quand il est l'une de
   ses pièces entre des cases et des boutons. */
.fiche-panneau{margin:0;display:flex;flex-direction:column;gap:var(--e-4);background:var(--surface);
  border:1px solid var(--ligne);border-radius:var(--radius);padding:calc(var(--e-1) * 5) var(--e-6)}
.fiche-panneau h3{margin:0;font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort)}
.fiche-panneau h4{margin:0 auto 0 0;font-size:var(--fs-base);font-weight:var(--gras-etiquette);color:var(--texte-fort)}
.fiche-panneau .entete{margin:0;gap:var(--e-2)}
.fiche-panneau p{margin:0}
.fiche-panneau-risque{border-color:var(--err);max-width:var(--l-lecture);gap:var(--e-3)}
.fiche-panneau .cases-cartes{gap:var(--e-4)}
.fiche-panneau-gestes{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-3);margin:0}
/* L'aperçu, sous un filet : sa tête, son tableau, sa note à 10 px les uns des autres, puis les gestes
   à 16 — les écarts de la planche. Les gestes vivent DANS l'aperçu parce qu'ils envoient les rôles
   que l'aperçu a montrés, et qu'il les remplace avec lui quand on coche. */
.fiche-panneau-apercu{display:flex;flex-direction:column;gap:calc(var(--e-1) * 2.5);padding-top:var(--e-4);
  border-top:1px solid var(--ligne)}
.fiche-panneau-apercu>form{margin-top:calc(var(--e-1) * 1.5)}

/* ---- « Rattacher quelqu'un » — la disposition D (planches « Rattacher » D1 à D6) ----
   Une PHRASE à trous en tête de carte ; chaque trou est un lien qui ouvre son panneau sous la
   phrase, séparé d'elle par un filet — les panneaux sont dans la carte, jamais une carte dans la
   carte. Un trou VIDE est en pointillé et dans la teinte d'accent, un trou rempli en trait plein :
   la forme dit l'état, pas seulement la couleur (SC 1.4.1). Écran du socle : ses classes sont dans
   `VitrineTest::HORS_VITRINE`, avec leur raison. */
.rattacher-carte{display:flex;flex-direction:column;gap:var(--e-4)}
.rattacher-carte>p{margin:0}
.rattacher-phrase{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2) var(--e-3);
  font-size:var(--fs-lg);font-weight:var(--gras-etiquette);color:var(--texte-fort);line-height:1.6}
.trou{display:inline-flex;align-items:center;min-height:var(--h-controle-sm);padding:0 var(--e-4);
  border:1px solid var(--texte-fort);border-radius:var(--radius-gelule);background:var(--surface);
  color:var(--texte-fort);font-size:var(--fs-md);text-decoration:none}
.trou>span{margin-left:var(--e-1)}
.trou:hover{background:var(--survol)}
.trou-vide{border-style:dashed;border-color:var(--bord);background:var(--entete-bg);color:var(--accent)}
.trou[aria-expanded="true"]{box-shadow:0 0 0 3px var(--accent-bg)}
.rattacher-panneau{display:flex;flex-direction:column;gap:var(--e-3);padding-top:var(--e-4);border-top:1px solid var(--ligne)}
.rattacher-panneau p{margin:0}
.rattacher-panneau .champ{margin:0}
.rattacher-panneau .champ .actions-en-ligne input{flex:1;min-width:0}
.rattacher-panneau-titre{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--e-2)}
.rattacher-panneau-titre h2,.rattacher-panneau-titre h3{margin:0;font-size:var(--fs-md);font-weight:var(--gras-titre);color:var(--texte-fort)}
.rattacher-panneau-titre .actions-en-ligne{margin-left:auto}
.rattacher-personnes{display:flex;flex-direction:column;gap:var(--e-2)}
.rattacher-compte{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--e-2);font-size:var(--fs-xs);color:var(--texte)}
.rattacher-compte a{margin-left:auto}
.rattacher-deja{display:flex;align-items:center;flex-wrap:wrap;gap:var(--e-2) var(--e-3);padding:var(--e-3);
  border:1px solid var(--ligne);border-radius:var(--radius-sm);background:var(--entete-bg)}
.rattacher-deja a{margin-left:auto;font-size:var(--fs-sm);font-weight:var(--gras-etiquette)}
.rattacher-personnes ul{list-style:none;margin:0;padding:0;max-height:var(--h-liste-personnes);overflow-y:auto;
  border:1px solid var(--ligne);border-radius:var(--radius-sm);
  display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--l-personne),1fr))}
/* La case s'étire à la hauteur de sa rangée ; le lien la REMPLIT, pour que le fond de la personne
   choisie couvre toute la carte — il s'arrêtait à la hauteur du texte quand une voisine, sur trois
   lignes, faisait la rangée plus haute (relevé par le user le 2026-09-28). */
.rattacher-personnes li{display:flex;border-bottom:1px solid var(--ligne)}
.rattacher-personnes li a{flex:1;display:flex;flex-direction:column;justify-content:center;gap:1px;min-height:var(--h-controle);
  padding:var(--e-2) var(--e-3);color:var(--texte-fort);text-decoration:none}
.rattacher-personnes li a b{font-size:var(--fs-sm);font-weight:var(--gras-etiquette)}
.rattacher-personnes li a small{font-size:var(--fs-xs);color:var(--texte)}
.rattacher-personnes li a:hover{background:var(--survol)}
/* La personne choisie reste dans la liste, MARQUÉE : un filet de marque à gauche en plus du fond,
   pour que la marque ne tienne pas à la seule teinte. */
.rattacher-personnes li a[aria-current="true"]{background:var(--survol);box-shadow:inset 3px 0 0 var(--marque)}
/* Les rôles : le composant « cases » en cartes (sa forme « Des cartes ») — les cochés épinglés en
   tête, le filtre étiqueté, les autres dessous. Sa planche borne la grille à 200 px, trois rangées et
   un bout de la quatrième, là où la fiche en montre cinq : la page porte d'autres panneaux sous
   celui-ci. */
.rattacher-panneau .cases-cartes[data-cases] .cases-corps{max-height:calc(var(--e-12) * 4 + var(--e-2))}
.rattacher-neuf>th,.rattacher-neuf>td{background:var(--survol)}

/* ---- La page des cas de la démonstration (planche « Cas 1a ») ----
   Les douze cas en trois familles : l'intitulé de famille en bandeau d'en-tête, la phrase à
   observer au poids courant sous le titre du cas — l'en-tête de ligne la mettrait en gras, et
   c'est elle qu'on lit en parlant. Écran de démonstration : sa classe est dans HORS_VITRINE. */
.cas-table th[scope="colgroup"]{background:var(--entete-bg);color:var(--texte);font-size:var(--fs-xs);font-weight:var(--gras-etiquette);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette);text-align:left}
.cas-table th[scope="row"]{text-align:left}
.cas-table th[scope="row"] p{margin:var(--e-1) 0 0;font-weight:var(--gras-menu)}

/* ---- « Voir en tant que » (planche CRM 1c), au seul compte de démonstration ----
   Le cadre pointillé dit « ceci n'est pas l'écran du client » : c'est celui des zones de dépôt et
   des états hors produit de la maquette. Les personnes sont des liens à deux lignes — le nom, le
   rôle —, pleines pour celle dont on porte les droits, à la hauteur d'un contrôle (SC 2.5.8).
   Sous le point de rupture étroit, la planche les fait passer dans une liste déroulante : c'est
   le menu de liens de la vitrine, et l'un OU l'autre s'affiche — `display:none` retire l'autre de
   l'arbre d'accessibilité, les trois liens ne sont jamais annoncés deux fois. Écran de
   démonstration : ses classes sont dans HORS_VITRINE. */
.voir-en-tant-que{display:flex;flex-direction:column;gap:var(--e-2);margin-bottom:var(--e-4);
  padding:var(--e-3) var(--e-4);border:1px dashed var(--bord);border-radius:var(--radius);background:var(--entete-bg)}
.voir-en-tant-que-ligne{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e-2)}
.voir-en-tant-que-titre{margin-right:var(--e-2);font-size:var(--fs-xs);font-weight:var(--gras-etiquette);
  text-transform:var(--casse-etiquette);letter-spacing:var(--interlettrage-etiquette);color:var(--texte)}
.voir-en-tant-que-personne{display:inline-flex;flex-direction:column;align-items:flex-start;justify-content:center;
  min-height:var(--h-controle);padding:var(--e-1) var(--e-4);border:1px solid var(--bord);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--texte-fort);text-decoration:none}
.voir-en-tant-que-personne:hover{background:var(--survol);color:var(--texte-fort);text-decoration:none}
.voir-en-tant-que-personne b{font-size:var(--fs-sm)}
.voir-en-tant-que-personne small{font-size:var(--fs-xs)}
.voir-en-tant-que-personne[aria-current="true"],
.voir-en-tant-que-personne[aria-current="true"]:hover{background:var(--action);border-color:var(--action);color:var(--sur-action)}
.voir-en-tant-que-menu{display:none}
/* Le rôle SOUS le nom, comme dans les liens de la version large : sur une ligne, « Hervé Lambert
   Responsable commercial » élargissait le panneau à 298 px, qui débordait l'écran de 11 px à
   390 px de large (mesuré). */
.voir-en-tant-que-menu .menu-deroulant-panneau a{line-height:1.3;padding-block:var(--e-1)}
.voir-en-tant-que-menu small{display:block;font-size:var(--fs-xs)}
.voir-en-tant-que-difference{margin:0;font-size:var(--fs-sm);color:var(--texte-fort)}
@media (max-width:879px){
  .voir-en-tant-que-personne{display:none}
  .voir-en-tant-que-menu{display:inline-block}
}
/* Et sous un geste refusé, le lien vers quelqu'un qui a le droit : à la hauteur d'une cible, en
   gras comme sur la planche, parce qu'il se lit seul sous la raison et non dans une phrase. */
.geste .aide a{display:inline-flex;align-items:center;min-height:var(--e-6);font-weight:var(--gras-etiquette)}
