:root {
  /* Encre ardoise plutot que noir pur : plus douce a l'oeil sur de longues
     sessions de lecture de tableaux, sans perte de contraste. */
  --black: #0e1216;
/* Le cyan plein ne sert plus d'encre. Mesure le 31 aout 2026 : #00AEEF donne
     2,53:1 sur blanc, 2,39:1 sur --cyan-pale et 2,23:1 sur --cyan-light, quand il
     faut 4,5:1 pour du texte courant et 3:1 pour une icone ou un trait
     d'interface -- il echouait donc aux deux, sur tous les fonds du produit.

     La feuille etait deja coupee en deux sur ce point sans que personne l'ait
     decide : trente-sept regles peignaient ce role en --cyan-dark, vingt-huit au
     cyan plein, et .m-chip.active de mobile.css ecrivait deja de sa main le bon
     partage -- bordure au cyan, encre au barreau du dessous. Ces vingt-huit
     rejoignent donc le barreau voisin, qui remonte a 3,18-3,60:1 et franchit
     partout la barre graphique. C'est un pas, pas une mise en conformite :
     4,5:1 demanderait un barreau plus sombre que la rampe n'a pas, donc un
     arbitrage de marque -- et --blue, seul jeton existant qui passe, dit autre
     chose dans ce produit (les repertoires).

     Le cyan reste la marque : il garde les fonds, les surfaces pleines, les
     etats selectionnes et ses soixante bordures -- anneaux de survol, de focus
     et de selection, ou rien ne se lit dans le trait lui-meme. Ce qui change est
     l'encre, la ou le cyan devait se lire lui-meme. */
    --cyan: #00AEEF;
  --cyan-dark: #0090c9;
  --cyan-pale: #F0FAFF;
  --cyan-light: #E0F4FD;
  /* Un cran au-dessous de `--cyan-light` : le fond d'un total, dans un
     document de synthese. C'est ce que la page doit donner en premier -- le
     chiffre qui conclut un bloc, pas l'intitule qui l'ouvre (demande du
     26 aout 2026, « inverser les deux nuances de bleu »). Il vivait jusqu'ici
     dans le seul export PDF (`_TOTAL_FILL`) parce que l'annexe a l'ecran
     n'etait pas encore l'apercu de sa page ; elle l'est depuis le 6 septembre
     2026, et les deux lectures du meme document se peignent pareil. */
  --cyan-total: #C6EAF9;
  /* Rampe de gris legerement teintee ardoise (froide) plutot que neutre pur :
     donne un rendu plus "produit" tout en conservant la luminance d'origine
     (donc les memes rapports de contraste). */
  --gray-1: #f6f8fa;
  --gray-2: #eceff3;
  --gray-3: #dde2e8;
  --gray-4: #9aa3af;
  --gray-5: #5c6470;
  --gray-6: #3a414b;
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  /* La chasse fixe, pour tout ce qui se lit caractere par caractere : une
     forme de nom de fichier, un numero de compte, un exemple de renommage.
     `2026-06-30 AGO STRUCTURE CONVOCATION` et la meme chaine a deux espaces
     ne se distinguent pas en Inter. Aucune fonte n'est chargee -- ce sont
     celles du systeme, dans l'ordre ou chaque plateforme a la sienne. */
  --mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
  --red: #d64545;
  --red-pale: #fdecec;
  /* Le barreau sombre du rouge, sur la meme pente que --blue-dark : il ne sert
     qu'au survol du bouton de suppression plein, qui l'ecrivait en clair au
     milieu de la feuille. Une teinte choisie a l'oeil dans une regle est
     exactement ce qui fait deriver une palette. */
  --red-dark: #b93838;
  --orange: #FF8A3D;
  --orange-pale: #fff3e9;
  --green: #2e9e5b;
  --green-pale: #eafaf0;
  --purple: #7c5cbf;
  --purple-pale: #f2eefa;
  --blue: #3b6fd6;
  --blue-pale: #eef3fd;
  /* Le barreau sombre du bleu, sur la meme pente que --green-dark et
     --orange-dark (environ trois quarts de la luminance). Il teinte les deux
     repertoires qui ne sont pas des chemises ordinaires -- le dossier permanent
     juridique et le fonds d'archives : le bleu plein s'y confondait avec le
     bleu de survol et de cible de depot. */
  --blue-dark: #2c53a1;
  --yellow: #c9971f;
  --yellow-pale: #fdf6e3;
  /* LES COULEURS DES MARQUES, QUI NE SONT PAS DE LA PALETTE.
     « Utilise les bonnes couleurs et fais pareil pour les autres services »
     (suivi du ticket du 17 septembre 2026, apres le vrai logo de Claude).

     Ce ne sont pas des teintes du produit et elles ne se choisissent pas : ce
     sont celles que chaque marque publie, relevees dans Simple Icons, la meme
     source que les traces de `_icons.html`. Elles ne servent qu'a UNE chose,
     le carre qui porte le logo d'un fournisseur au tableau de bord, et elles
     n'ont donc ni barreau pale ni barreau sombre : une couleur de marque ne se
     decline pas, elle se recopie.

     Le noir de Vercel est un noir pur, et c'est le seul du site : la charte
     n'en a pas, son encre est --black, une ardoise. Mais la marque de Vercel
     EST un triangle blanc sur noir, et la repeindre en ardoise en ferait une
     approximation, exactement ce que le ticket precedent reprochait a l'etoile
     dessinee a vue.

     OpenAI est le noir, et il a fallu sortir de Simple Icons pour le savoir :
     la bibliotheque publie bien son trace, identique a celui d'`_icons.html`,
     mais plus sa fiche de couleur, donc son hexadecimal ne se relevait pas
     comme les six autres. Sa tuile a garde le cyan du produit jusqu'au
     21 septembre 2026 -- « OpenAI, je pense pas que la couleur officielle
     c'est le bleu : update le logo et la couleur contrastante ». C'est exact,
     et le cyan n'etait meme pas une couleur choisie : c'est la teinte de repli
     de la mosaique, celle que prend toute tuile qui n'en declare pas.

     La source est alors la charte d'OpenAI elle-meme (openai.com/brand), qui
     n'admet son logo qu'en noir ou en blanc : sa palette est le noir et le
     blanc, sans couleur d'identite. Le vert #10a37f existe chez elle, mais
     c'est l'accent d'action de ChatGPT, le bouton d'envoi, pas la couleur de
     la marque, et il serait entre en collision avec le vert de Supabase, qui,
     lui, en est une. Le noir a donc ete pris, comme pour Vercel et GitHub :
     trois carres noirs dans la rangee, ce qui est assume pour la raison ecrite
     plus bas, ce sont le nom et le logo qui distinguent les tuiles, jamais la
     couleur seule. */
  --marque-openai: #000000;
  --marque-claude: #d97757;
  --marque-mistral: #fa520f;
  --marque-supabase: #3fcf8e;
  --marque-vercel: #000000;
  --marque-github: #181717;
  --marque-google: #4285f4;
  /* Six tailles d'icone, une echelle reguliere de 2 px. Il y en avait onze
     (11, 13, 14, 15, 16, 17, 18, 20, 24 px) : deux boutons cote a cote
     portaient des icones de tailles differentes a un pixel pres, ce qui se
     voit sans qu'on sache dire pourquoi. */
  --icon-xs: 12px;
  --icon-sm: 14px;
  --icon: 16px;
  --icon-md: 18px;
  --icon-lg: 20px;
  --icon-xl: 24px;
  /* La hauteur d'un petit controle. Le barreau existait deja, ecrit a la main
     en 28px sur les carres d'un rang (.avancement-seg, .type-seg et leurs
     voisins) et sur la corbeille ronde d'un intervenant ; il n'avait pas de
     nom, donc tout ce qui n'etait pas un de ces carres se calait sur son seul
     remplissage. Le panneau Mandat d'un client, ou dix rangees alignent ces
     boutons cote a cote, en comptait cinq hauteurs : 26 px pour un
     bouton-lien, 27 s'il porte une icone ou si c'est une tuile de cabinet, 29
     pour le meme reduit a son icone, 30 quand la hauteur de ligne du parent
     deteignait dessus. Cinq hauteurs sur une meme rangee se lisent comme un
     desalignement sans qu'on sache dire lequel des cinq a tort. */
  --h-sm: 28px;
  /* La hauteur d'un champ de saisie, soeur de la precedente et posee pour la
     meme raison, un cran plus bas dans le panneau Mandat. Les rangees de
     boutons y comptaient cinq hauteurs ; les rangees de cases en comptaient
     trois. Mesure au navigateur le 27 aout 2026 : cinquante-six champs a
     31,78 px, quatre a 33,78 -- les dates --, et la reponse deduite de la
     duree du mandat a 34,39.

     La ligne « References et dates » aligne les trois : « N° de mandat CNCC »,
     « N° interne », « Date de derniere nomination », « S'agit-il d'un
     renouvellement ? », « Cloture du 1er exercice a controler », « Duree du
     mandat ». Six cases cote a cote dont la troisieme et la cinquieme
     depassent d'un pixel en haut et d'un pixel en bas, et la sixieme d'un peu
     plus. Rien qui se nomme, tout qui se voit.

     Le surplus des dates n'est pas un remplissage : le contenu interne d'un
     `input[type="date"]` a son propre plancher sous Chromium, que ni la
     hauteur de ligne ni le remplissage ne font descendre (quatre correctifs
     essayes, le meilleur regagnait six dixiemes de pixel). Il faut donc dire
     la hauteur. 32 px, la ou cinquante-six champs sur soixante et un se
     tenaient deja a deux dixiemes pres. */
  --h-champ: 32px;
  /* Le logo donne sa hauteur a la barre du haut : c'est le plus grand des blocs
     qu'on y pose, et c'est desormais voulu. Les entrees de la barre sont des
     commandes et tiennent dans la hauteur d'un champ ; avant, celle des
     reglages depassait le logo de quatre pixels et decidait de la barre. */
  --h-logo: 36px;
  /* La hauteur de la barre du haut n'est pas un choix mais une somme : le logo,
     le rembourrage vertical de .app-header-inner de part et d'autre, et son
     liseré du bas. Elle est nommee ici parce qu'une barre collante doit
     s'accrocher juste dessous sans avoir aucun moyen de la mesurer.
     .tuile-collante la recopiait a la main -- « 70 px = hauteur mesuree de
     .app-header » -- et cette copie avait deja vieilli de trois pixels et demi
     avant qu'on y touche : le liseré transparent que son commentaire disait
     vouloir eviter etait la depuis. */
  --h-entete: calc(var(--h-logo) + var(--espace) * 2 + 1px);
  /* Douze tailles de texte. Les deux feuilles en comptaient quarante-deux, dont
     neuf tenaient dans une bande de deux pixels (.74, .75, .76, .78, .79, .80,
     .82, .84, .85 rem) : deux libelles voisins n'avaient pas la meme taille
     sans qu'aucune intention ne le justifie, et c'est exactement ce qui donne
     au site son air de flotter. Chaque valeur a ete ramenee sur le barreau le
     plus proche ; le plus grand deplacement est de 1,4 px, tous les autres
     sont sous le pixel. Les initiales d'une pastille de profil ne sont pas
     du texte a lire et ne prennent aucun de ces barreaux : elles se calent
     sur le diametre de leur rond, voir --avatar-initiales. */
  --fs-3xs: .6rem;
  --fs-2xs: .68rem;
  --fs-xs: .75rem;
  --fs-sm: .8rem;
  --fs: .85rem;
  --fs-md: .9rem;
  --fs-lg: .95rem;
  --fs-xl: 1rem;
  --fs-h3: 1.15rem;
  --fs-h2: 1.3rem;
  --fs-h1: 1.4rem;
  --fs-hero: 1.75rem;
  /* Quatre arrondis, et rien d'autre. La feuille en comptait neuf (2, 3, 4, 6,
     7, 10, 12, 16, 18) : deux pastilles voisines n'avaient pas la meme forme
     sans qu'aucune raison ne le justifie. L'echelle va de la petite tuile a la
     grande surface flottante ; ce qui doit etre completement rond prend 999px,
     pas une valeur intermediaire. */
  --radius-xs: 4px;
  --radius-sm: 7px;
  --radius: 10px;
  --radius-lg: 16px;
  /* Ombres multi-couches teintees ardoise : profondeur plus realiste et plus
     douce qu'une ombre unique grise. */
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .05), 0 1px 1px rgba(15, 23, 42, .04);
  --shadow-md: 0 6px 20px rgba(15, 23, 42, .07), 0 2px 6px rgba(15, 23, 42, .05);
  --shadow-lg: 0 20px 48px rgba(15, 23, 42, .13), 0 6px 16px rgba(15, 23, 42, .07);
  /* Le voile d'une fenetre. Neuf surfaces du produit assombrissent ce qu'elles
     recouvrent, et elles le faisaient dans trois noirs : l'encre de la maison
     pour la fenetre modale, la feuille du telephone et la fenetre du Journal ;
     le noir pur pour les quatre `::backdrop` des dialogues natifs ; et, pour
     l'historique d'une piece, le bleu ardoise des ombres portees, recopie de
     --shadow-lg sur une surface qui n'est pas une ombre.

     Le depot tenait deja les deux moities de la reponse, et elles se
     contredisaient. Ici, le commentaire de .modal-overlay disait pourquoi un
     voile neutre est un defaut : « le noir n'est pas noir » (--black, #0e1216,
     encre ardoise) est un choix tenu partout, jusque dans les gris legerement
     froids, et un voile neutre pose par-dessus les eteint tous d'un demi-ton
     -- la fenetre parait posee sur une autre interface que celle qu'on vient
     de quitter. C'est pour cela que .modal-overlay etait passee du 10 10 10
     neutre a l'encre. En face, parite.json donnait aux quatre ::backdrop la
     raison inverse : un voile n'est pas une teinte, donc le noir pur y est
     permis. Une seule des deux pouvait etre la bonne, et c'est la premiere :
     un voile ne se regarde jamais seul, il se regarde en meme temps que
     l'interface qu'il eteint.

     Deux barreaux, parce qu'un flou separe deja. Une surface qui pose un
     `backdrop-filter` n'a pas besoin d'assombrir autant qu'une surface posee a
     plat : c'est le seul ecart qui restait a expliquer entre .42 et .55, et il
     s'explique.

     Un jeton plutot que le triplet recopie huit fois, pour la raison que
     --anneau-champ donne plus bas : un geste qu'on recopie est un geste qu'on
     finit par recopier de travers. Le triplet reste ecrit ici plutot qu'appele
     par `color-mix` sur --black -- la feuille ne l'emploie nulle part, et un
     voile que le navigateur ne comprend pas disparait en entier, ce qui est
     pire que la teinte qu'il corrige. Ce sont donc les memes chiffres que
     --black, et `teintes_recopiees`, dans parite.json, est ce qui les y
     rattache desormais. */
  --voile: rgba(14, 18, 22, .55);
  --voile-flou: rgba(14, 18, 22, .42);
  /* L'anneau d'un champ qui a le curseur. Ce n'est pas une ombre : c'est le
     signe, sur la seule surface du produit ou l'on ecrit, que la frappe ira
     la. La bordure du champ passe au cyan et trois pixels de cyan pale
     l'entourent.

     Il etait recopie a la main vingt-quatre fois, composant par composant, et
     quatre de ces copies avaient oublie le `outline: none` qui va avec :
     l'anneau du site venait alors s'ajouter par-dessus, et le champ portait
     deux anneaux au lieu d'un (constate sur /login et /compte le 28 aout
     2026). Un geste qu'on recopie est un geste qu'on finit par recopier de
     travers ; il a maintenant un nom. */
  --anneau-champ: 0 0 0 3px var(--cyan-light);
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-spring: cubic-bezier(.34, 1.4, .5, 1);
  /* Le rapport entre le diametre d'un rond de profil et les initiales qu'il
     porte. Un rapport, pas une taille : le diametre change d'un emplacement a
     l'autre (--avatar-d), les initiales le suivent toutes seules.
     Les onze emplacements qui portent un rond de profil ecrivaient chacun leur
     taille a la main, et le rapport allait de .33 dans l'apercu du compte a
     .49 dans la pastille de l'en-tete : les memes deux lettres paraissaient
     tantot perdues au milieu de leur rond, tantot a l'etroit contre le bord.
     .4 est la valeur que l'app tient deja (PastilleCollaborateur). */
  --avatar-initiales: .4;
  /* Et le meme rapport pour un rond qui porte une icone plutot que deux
     lettres : un fil de conversation qui n'a le visage de personne -- la place
     du cabinet, un mandat sans logo. Une icone est un carre plein la ou deux
     lettres sont une ligne, d'ou un rapport plus grand que --avatar-initiales ;
     sur le rond ordinaire de vingt-huit pixels, il tombe exactement sur
     --icon-sm, le barreau des icones voisines. */
  --avatar-icone: .5;
  /* Le relief d'un rond de profil : une lumiere rasante et un liseré interieur
     clair. « Le style de la pastille, pour la rendre un peu plus moderne, facon
     Revolut » (demande du 24 aout 2026) -- une rondelle de couleur plate,
     posee a l'identique depuis l'origine, est ce qui date le plus vite une
     interface.
     Deux jetons et non deux valeurs recopiees : quatre emplacements portent un
     rond (--avatar-d les dimensionne deja), et une valeur ecrite quatre fois
     finit par ne plus suivre.
     Ni l'une ni l'autre ne connait la couleur du collaborateur : elles se
     posent par-dessus, en blanc et en encre translucides, donc les seize
     teintes de pastille les prennent sans exception -- et aucune couleur
     nouvelle n'entre dans la palette. */
  --avatar-lumiere: linear-gradient(145deg, rgba(255, 255, 255, .28), rgba(255, 255, 255, 0) 52%, rgba(14, 18, 22, .16));
  --avatar-relief: inset 0 0 0 1px rgba(255, 255, 255, .35), 0 1px 2px rgba(14, 18, 22, .16);
  /* La case d'une valeur qui tient en deux ou trois caracteres -- un jour, un
     mois. Elle est un jeton et non une valeur ecrite dans sa regle parce que
     deux endroits doivent rester d'accord : la case elle-meme, et la case du
     SIREN juste au-dessus, calculee pour que les deux boutons « Enregistrer »
     se suivent a la verticale. Ecrite deux fois, la deuxieme aurait fini par
     ne plus suivre la premiere, et le decalage ne se serait signale nulle
     part. En `em` : la case suit la taille du texte qu'elle porte. */
  --champ-court: 4.5em;
  /* Teintes d'etat de controle d'audit (vert = valide, orange = probleme). */
  --green-dark: #1f7a44;
  --orange-dark: #c96a1f;
  --controle-valide-bg: rgba(46, 158, 91, .12);
  --controle-valide-bg-hover: rgba(46, 158, 91, .22);
  --controle-probleme-bg: rgba(255, 138, 61, .14);
  --controle-probleme-bg-hover: rgba(255, 138, 61, .26);
  /* Dix pas d'espacement, et rien entre eux. La feuille en comptait quarante
     valeurs distinctes pour poser un `padding`, une `margin` ou un `gap`, dont
     quatorze entre .25rem et .9rem -- c'est-a-dire quatorze barreaux dans une
     bande de dix pixels. Deux cartes voisines n'avaient donc pas la meme
     respiration sans qu'aucune intention ne le justifie, et c'est la premiere
     cause de l'air « mal espace » du produit : l'oeil ne lit pas une valeur,
     il lit un rythme, et un rythme a quarante temps n'en est pas un.
     L'echelle progresse d'environ un tiers a chaque barreau, ce qui est le
     minimum pour que deux barreaux voisins se distinguent. Les valeurs
     existantes ont ete ramenees sur le barreau le plus proche : le plus grand
     deplacement est de 1,6 px. */
  --espace-3xs: .15rem;
  --espace-2xs: .25rem;
  --espace-xs: .4rem;
  --espace-sm: .6rem;
  --espace: .8rem;
  --espace-md: 1rem;
  --espace-lg: 1.25rem;
  --espace-xl: 1.5rem;
  --espace-2xl: 2rem;
  --espace-3xl: 2.5rem;
  /* LES COTES D'UNE FEUILLE, ET NON UN BARREAU DE L'ECHELLE CI-DESSUS.

     « Dans l'annexe, l'affichage doit etre le plus proche possible du rendu
     final en PDF, selon le principe WYSIWYG » (ticket du 6 septembre 2026).
     Cet ecran-la n'est pas une vue du document : c'est le document, avant
     d'etre imprime. Il se mesure donc en millimetres de papier et en points de
     plomb, repris un a un de `app/export_pdf.py`, la ou toute autre surface du
     produit se mesure en `rem`. Les couleurs, elles, restent celles de la
     maison : c'est le meme document des deux cotes, il n'a aucune raison de
     changer de teintes en passant a l'ecran.

     Groupees ici et non ecrites dans les regles parce que c'est une echelle,
     celle du PDF : une taille retouchee dans `export_pdf` se retouche ici. */
  --annexe-page: 210mm;         /* A4 portrait */
  --annexe-marge-h: 10mm;       /* pdf.set_margins(10, 12, 10) */
  --annexe-marge-v: 12mm;
  --annexe-fs-section: 10.5pt;  /* _ANNEXE_TAILLE_SECTION */
  --annexe-fs-note: 9pt;        /* _ANNEXE_TAILLE_NOTE */
  --annexe-fs-texte: 8.5pt;     /* _ANNEXE_TAILLE_TEXTE */
  --annexe-fs-tableau: 8pt;     /* _ANNEXE_TAILLE_TABLEAU */
  --annexe-ligne: 4.6mm;        /* la hauteur d'une ligne de texte */
  --annexe-rangee: 5mm;         /* _ROW_H : la hauteur d'une rangee */
  --annexe-gouttiere: 1mm;      /* ce qui separe une cellule de son filet */
  /* Un cran d'imbrication : ce qui separe une ligne de sa ligne mere, dans un
     arbre de comptes comme dans une liste de repertoires. Ce n'est pas un
     barreau de l'echelle au-dessus et ne peut pas l'etre : un retrait se
     mesure sur le texte de la ligne, pas sur la page. Ecrit en `em`, il vaut
     14 px dans une table a 12,8 et 15 px dans une table a 13,6, si bien
     qu'une table dense et une table aeree gardent la meme profondeur optique.
     Un `em` pose dans `:root` se resout sur l'element qui s'en sert, pas ici
     (verifie au navigateur le 29 aout 2026).

     1,1 est deja ce qu'ecrivaient les six endroits qui posaient le cran en
     toutes lettres -- deux dans l'arbre d'analyse, deux dans l'arborescence
     juridique, un dans le mapping du bilan, un en CSS (.row-leaf-label) --,
     et aucun ne le nommait. Trois autres l'approchaient de memoire, en rem :
     1.6rem deux fois, 2.1rem une fois, soit jusqu'a 6,7 px d'ecart avec ce
     que leur propre commentaire annoncait. Desormais un retrait s'ecrit
     partout pareil :

         padding-left: calc(<creux de la cellule> + N * var(--retrait-pas))

     Le creux vient en premier parce qu'un niveau 0 doit retomber exactement
     ou se pose une ligne non indentee. Trois des cinq endroits ecrits en
     JavaScript l'ecrivaient a la main, correctement mais sans le dire ; les
     deux autres l'avaient perdu -- .5rem au lieu de .6 dans la fenetre
     « Deplacer », rien du tout au niveau 0 du mapping du bilan, ou les
     rubriques touchaient donc le bord de leur cellule.

     Deux des quatre endroits ecrits en CSS, eux, n'avaient jamais rien decale
     du tout : un retrait ecrit pour une classe seule (0,1,0) perd contre la
     regle qui pose le creux de la table (`.tree-table td`,
     `.mapping-table-compacte td`, toutes deux en 0,1,1). Le retrait d'un
     compte deplie sous un poste du bilan reglementaire et celui des soixante
     postes du mapping etaient ecrits, commentes, et sans effet. Un retrait
     pose sur une cellule s'ecrit donc `td.<classe>`, jamais `.<classe>`
     seule. */
  --retrait-pas: 1.1em;
  /* Trois interlettrages, pour le seul role qui en demande un : des capitales.
     Il y en avait neuf (.02, .03, .04, .05, .06, .1 em, plus trois negatifs)
     pour le meme geste -- espacer des petites capitales afin qu'elles se
     lisent -- si bien que deux en-tetes de colonne voisins, l'un a .04 et
     l'autre a .05, n'avaient pas la meme couleur de gris a l'oeil.
     Le barreau se choisit sur la taille du texte, pas sur la page : plus le
     texte est petit, plus il lui faut d'air entre les lettres. */
  --suivi-titre: .06em;
  --suivi-entete: .04em;
  --suivi-serre: .02em;
  /* Et un negatif, pour le role inverse : un grand titre se resserre, sinon
     ses lettres paraissent se detacher les unes des autres. Un seul barreau
     pour les deux tailles concernees -- il y en avait deux (-.01 et -.02 em),
     soit deux dixiemes de pixel d'ecart, ce qui ne se voit pas mais se
     recopie. */
  --suivi-grand: -.02em;
  /* Les largeurs. Elles etaient ecrites dans la regle de chaque page et avaient
     donc derive : cinq largeurs de bloc de texte (44, 46, 52, 60 rem), trois
     largeurs de grande surface flottante (1000, 1100, 1180 px), deux largeurs
     de colonne de formulaire (400 et 440 px). Passer d'une page a la suivante
     faisait sauter le contenu d'un bord a l'autre de l'ecran, alors que les
     deux pages font la meme chose.

     Il y en avait une cinquieme, `--largeur-page`, qui valait 1400 px et
     bornait la coquille entiere : l'en-tete, le corps de chaque page, le
     journal. Elle est partie le 9 septembre 2026. Sur un ecran de 1512 elle
     laissait 88 px de blanc mort de chaque cote, sur un 1920 elle en laissait
     260, sur un 2560 elle en laissait 580 -- 48 % de la fenetre a ne rien
     porter, pendant qu'un tableau de mandats se serrait au milieu. « Il
     faudrait que toujours tout l'espace de la fenetre du navigateur soit
     pris. » La coquille prend donc la fenetre, quelle qu'elle soit ; ce qui
     reste borne est ce qui a une raison propre de l'etre, et ces raisons sont
     les quatre ci-dessous.

     Quatre largeurs, une par forme de contenu :
     -- `--largeur-fenetre` : une grande surface flottante -- fenetre de
        dialogue, visionneuse, atelier ;
     -- `--largeur-bloc` : un bloc autonome pose dans une page large ;
     -- `--largeur-lecture` : du texte suivi, borne a la longueur de ligne
        au-dela de laquelle l'oeil perd le debut de la ligne suivante ;
     -- `--largeur-colonne` : une page qui ne porte qu'un formulaire.
     `--gouttiere` est la marge laterale d'une page, la meme dans l'en-tete et
     dans le corps pour que le titre et la premiere colonne s'alignent. */
  --largeur-fenetre: 1100px;
  /* LES TROIS MESURES DU BILAN COTE A COTE, AVANT MESURE.

     `alignerLesDeuxCotes` (synthese-groupe.js) les reecrit sur le bloc du
     bilan des que le document est dessine : la taille des lettres, la largeur
     d'une colonne d'intitules, celle d'une colonne de chiffres. Les valeurs
     posees ici sont celles du premier rendu, le temps d'un cadre -- et la
     reponse a « defini nulle part » du verificateur : un jeton qu'aucun :root
     ne declare retombe en silence sur la valeur par defaut de la propriete,
     et une largeur de colonne `auto` ne se voit pas. */
  --etats-fs: var(--fs-sm);
  --etats-col-libelle: 45%;
  --etats-col-chiffre: auto;
  --largeur-bloc: 52rem;
  --largeur-lecture: 46rem;
  --largeur-colonne: 440px;
  --gouttiere: 2rem;
  /* Le pas des rangees d'une grille tassee (grille-tassee.js). Une tuile y
     prend autant de rangees qu'il en faut pour sa hauteur et l'ecart qui la
     suit, arrondi au pas superieur : l'ecart vertical entre deux tuiles tombe
     entre 16 et 18 px quand l'horizontal en fait 16. Un pixel l'aurait rendu
     exact, mais Firefox ne compte pas plus de dix mille lignes par grille : au
     pixel, une colonne de plus de 10 000 px empilerait ses dernieres tuiles
     sur la ligne limite. A deux, la limite recule a 20 000. */
  --pas-tassement: 2px;
  /* Les trois colonnes de fin de ligne sur /dossiers -- exercice,
     collaborateurs, signataire. Elles sont a largeur fixe pour qu'une ligne
     plus chargee que sa voisine ne decale pas les colonnes du reste de la
     liste, et l'en-tete de tri doit tomber exactement dessus : la mesure se lit
     donc ici, et non recopiee dans les cinq regles qui la demandent -- c'est
     par la que les largeurs de bloc avaient derive juste au-dessus.
     Recopiees, celles-ci avaient derive de la meme facon : la bulle d'un
     collaborateur est passee de 15 px a 22 sans que sa colonne bouge de 32, si
     bien que la seconde bulle sortait de 3 px sur les 6,4 qui la separent du
     signataire, et la cloture la plus longue de 2,5 px sur les memes 6,4 avant
     les collaborateurs. Vingt-huit lignes sur 374 se lisaient donc plus
     serrees que les autres, a l'endroit precis ou la ligne est la plus
     chargee (27 aout 2026). */
  /* Le badge d'etat : voir .dossier-statut-slot. Cette colonne n'a pas de
     largeur propre, elle reprend celle du rang de trois carres qui dit le
     meme etat une fois la ligne depliee. Ecrite 96px a la main, elle avait
     cesse de l'egaler le 28 aout 2026, l'ecart du rang etant passe de six au
     barreau de 6,4 sans qu'elle suive. */
  --col-statut: calc(3 * var(--h-sm) + 2 * var(--espace-xs));
  /* Le compteur d'emission de notre rapport, en tete du groupe (ticket du
     6 septembre 2026). Sa largeur est celle du plus long des reperes : « J+199 »
     tient sur un seul volet, « J-19 » sur quatre volets de .72em a --fs-sm plus
     leurs charnieres et le rembourrage du tableau. Fixe comme ses trois
     voisines, et pour la meme raison : une ligne sur deux porte un compteur, et
     sans colonne l'etat et les avatars tomberaient a une abscisse differente
     d'une ligne a l'autre. */
  /* Douze pixels de plus depuis le 8 septembre 2026 : le compte de la cloture
     porte un cadenas devant ses volets (« un cadenas tres visible »), et
     « J-60 » avec sa serrure ne tenait pas dans cinquante. Elargie plutot que
     le cadenas mis au-dessus : un bandeau de plus aurait rehausse les trois
     cent quatre-vingts lignes de la liste pour la dizaine qui le porte.
     Soixante-six et non soixante-deux : le tableau mesure soixante-deux avec
     sa serrure, et une colonne a sa taille exacte le collerait a ses
     voisines. */
  --col-echeance: 66px;
  --col-exercice: 71px;        /* « 2026-06-30 », la cloture la plus longue */
  --col-collaborateurs: 35px;  /* deux bulles de 22 px decalees de 13 */
  --col-signataire: 24px;
  /* La tuile du titulaire ferme la rangee. Elle etait la seule des quatre a
     s'ecrire en chiffres, et deux fois : dans sa voie et dans son en-tete de
     tri. C'est exactement ce que le paragraphe du dessus dit de ne pas faire,
     et la raison est la meme -- deux copies d'une mesure ne restent egales que
     tant que personne n'en bouge une. */
  --col-titulaire: 42px;
}

/* Une page succede a l'autre, sans le blanc entre les deux.
 *
 * « Il y a certaines zones ou vraiment ca refresh completement le lien.
 * Essayez que ce soit plus smooth, sans qu'il y ait forcement un hard refresh
 * du site, mais que ca passe de facon plus smooth de page en page » (demande
 * du 26 aout 2026, reprise le 28 : « il faut que ca soit focus sur tout
 * l'ensemble du logiciel et du site »).
 *
 * Une navigation ordinaire efface le document avant de peindre le suivant : un
 * blanc, puis la page. C'est ce blanc que l'on prend pour un rechargement, et
 * il est d'autant plus visible que la page qui arrive ressemble a celle qui
 * part -- meme en-tete, meme colonne, meme fond. Le fondu croise le supprime :
 * les elements communs restent en place, seul change ce qui change.
 *
 * Une regle, pas un script : la feuille est chargee par toutes les pages, donc
 * toutes s'y inscrivent d'un coup -- c'est ce que la demande reclame, et une
 * couche de navigation maison aurait coute la fragilite que le prechargement
 * (static/js/prechargement.js) evite justement. Les navigateurs qui ne
 * connaissent pas la regle l'ignorent et naviguent comme avant. */
@view-transition { navigation: auto; }

/* Ce qui s'anime peut se refuser. Le fondu est court, mais c'est un mouvement
   de page entiere, exactement le genre que ce reglage vise. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

* { box-sizing: border-box; }

/* Un element porteur de l'attribut `hidden` ne s'affiche pas. Cela devrait
   aller de soi : le navigateur pose bien `[hidden] { display: none }`, mais
   dans sa feuille par defaut -- donc la moindre regle de classe qui ecrit
   `display: flex` l'emporte, et l'element reste visible sans que rien ne le
   signale.
   La feuille rattrapait le coup au cas par cas : soixante-cinq regles
   `.machin[hidden] { display: none }` ecrites une par une, a chaque fois qu'on
   s'apercevait qu'une chose cachee ne l'etait pas. Il en manquait -- l'en-tete
   du fil de Messages, par exemple, montrait un rond de profil vide en haut du
   panneau tant qu'aucune conversation n'etait ouverte.
   Une regle ici, et la question ne se repose plus. Le `!important` est ce qui
   la rend fiable : sans lui elle perdrait contre n'importe quel selecteur de
   classe, ce qui est exactement le probleme qu'elle resout. Aucun script du
   site n'ecrit `style.display`, donc rien ne peut entrer en conflit.

   Une chose cachee dans une colonne fait exception, et doit le dire : elle garde
   sa case et n'efface que son trace, faute de quoi les cases suivantes glissent
   toutes d'un cran. Trois regles le font -- la croix du signataire, la fleche de
   presence en ligne et le voyant d'enregistrement d'un cabinet --, chacune en
   reecrivant `display` avec son propre `!important`. Les deux premieres etaient
   ecrites sans, donc mortes, et le glissement qu'elles annoncaient etait sous
   les yeux (26 aout 2026). Ecrire `display: none` ici sans `!important` reste
   sans effet ; c'est bien un filet, et il ne se perce que volontairement. */
[hidden] { display: none !important; }

/* Le sol de la page. Il etait blanc, et les tuiles aussi : releve au
   navigateur le 31 aout 2026, `body` et `.tuile` rendaient l'un comme l'autre
   `rgb(255, 255, 255)`. Une tuile ne se detachait donc de sa page par rien
   d'autre qu'un filet d'un pixel -- sur quinze pages, tout le decoupage en
   zones reposait sur une bordure --gray-3.

   Demande du 30 aout 2026 : « essaye de mieux separer les espaces [...] plus
   de separation entre les sous-zones [...] pour eviter que ca fasse parfois
   l'effet zone de texte un peu fouillee avec plein de boutons [...] que ca
   fasse plus moderne, plus type Dashboard ». Une carte blanche posee sur un
   sol teinte se separe de ce qui l'entoure par toute sa surface, et non par
   son contour.

   Ce gris n'est pas invente ici. C'est deja le sol des pages
   d'authentification (`.login-body`, plus bas), et c'est surtout celui de
   l'app : `Palette.gris1` est le fond d'ecran de VueTickets, VueMessages,
   VueConversations, VueFilConversation, VueDetailTicket et VueAnnexe. Le site
   flottait ses cartes sur du blanc pendant que l'app flottait les siennes sur
   du gris, depuis l'ecriture de l'app -- un ecart qu'aucune route, aucun
   appariement de couleur et aucune regle d'affichage ne pouvait voir, parce
   qu'il ne porte sur aucun des trois. Les deux surfaces se rejoignent ici.

   Cinq surfaces s'appuyaient sur le blanc du corps sans le declarer. Chacune
   le dit desormais chez elle : `.tree-table-wrap` et `.frise-mandat` ici,
   `.dossier-list`, `.dossier-tabs` et `.dossier-list-header` dans mobile.css.
   L'export PDF, lui, garde le blanc -- voir le bloc `@media print`. */
body {
  font-family: var(--sans);
  color: var(--black);
  background: var(--gray-1);
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
  margin: 0;
  /* La page occupe la fenetre, du haut jusqu'en bas. C'etait la regle de la
     seule page de connexion, qui devait y centrer sa carte ; c'est celle de
     toute la coquille depuis le 9 septembre 2026, en meme temps que la
     largeur. Sans elle le corps s'arrete a sa derniere ligne : l'ecran du
     cabinet, qui tient en trois rangees, se terminait au quart de la fenetre
     et les trois quarts du bas n'etaient plus une page, juste le fond.
     `.app-main` prend ce que l'en-tete laisse (`flex: 1`), et une section qui
     doit descendre jusqu'en bas a enfin une hauteur a laquelle se raccrocher.
     `100dvh` et non `100vh` : la hauteur visible, et non celle que le
     telephone annonce barre d'adresse repliee -- sans elle la carte de
     connexion se centrerait dans une boite plus haute que l'ecran, donc trop
     bas. Les deux se suivent, la seconde pour qui la connait. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  /* Le filet contre le mot insecable. Ce produit ecrit des noms de pieces
     juridiques en clair, au milieu de la prose : « Feuille_de_presence_
     ASSEMBLEE_GENERALE_ORDINAIRE_ANNUELLE_du_30-06-2025.pdf » fait 471 px d'un
     seul tenant et pousse la page entiere vers la droite, sur telephone comme
     ailleurs. `break-word` -- et non `anywhere` -- parce qu'il ne coupe que
     lorsque le mot deborderait vraiment, et n'entre pas dans le calcul de la
     largeur minimale : il ne peut donc pas retrecir une mise en page qui tient
     deja. Ce qui doit rester d'un seul tenant le dit ailleurs, par
     `white-space: nowrap`, et n'est pas touche. */
  overflow-wrap: break-word;
}

.icon {
  width: var(--icon);
  height: var(--icon);
  flex: none;
  fill: none;
  stroke: currentColor;
}

/* ---------------------------------------------------------------------------
   La graisse des titres, posee a la base comme les controles juste en dessous.

   `_base.html` charge Inter avec quatre graisses et pas une de plus :
   `wght@400;500;600;700`. Ce sont quatre instances statiques, pas une fonte
   variable. Tout ce que la feuille demande en dehors de ces quatre-la, le
   navigateur l'apparie lui-meme et sans rien dire. Mesure du 7 septembre 2026,
   meme texte a 16 px : 650 rend 271,95 px, 700 rend 271,95 px. Les quatre
   `font-weight: 650` du journal des modifications demandaient donc une graisse
   absente et recevaient `bold`. Ils ecrivent 700 depuis : rien n'a bouge a
   l'ecran, la feuille dit ce qui se passe.

   L'autre bout du meme defaut : un titre a qui aucune regle ne dit sa graisse
   est dessine par le navigateur, en `bold`. Mesure du 7 septembre 2026, les
   deux feuilles echangees seules sous les vingt-cinq pages du banc : 38 titres
   passent de 700 a 600 -- la graisse de la maison, celle de `.tuile-titre` --
   et pas un n'avait ete ecrit. Dix-huit sont la prose publique d'assistance et
   de confidentialite, sept la consolidation d'un dossier, six la plaque de
   titre d'un ticket, quatre le journal, deux les pages d'erreur, un le
   sous-titre de la consommation. Aucune de leurs regles n'ecrit
   `font-weight` : elles posent une taille, une couleur, et laissent le reste
   au navigateur. Apres, il ne reste sur tout le produit que quatre titres hors
   de 600, et les quatre sont ecrits : les trois `.m-sheet-title`, qui
   demandent `bold` dans `mobile.css`, et `.jm-aside-titre`.

   `font-size: inherit` pour la meme raison, et il n'attrape que deux familles :
   le `h3` qui porte la plaque d'un ticket et le sous-titre de la consommation,
   seuls du produit a garder les 18,72 px du navigateur -- une taille que
   l'echelle a douze barreaux ne contient pas, sur des elements dont le contenu
   est compose plus petit qu'eux. Un titre nu ne se contente pas de mal
   paraitre, il reserve une boite de ligne dimensionnee par une fonte que
   personne n'a choisie : la plaque d'un ticket en rendait quatre pixels de
   hauteur de page. Les familles qui posent leur taille -- `.app-titre`,
   `.tuile-titre`, les cartes d'authentification, `.doc-wrap`, `.jm-*` -- la
   gardent : une regle de classe l'emporte sur une regle
   d'element.

   Portees par l'element et non par une classe, pour la raison ecrite juste
   dessous a propos des cases a cocher : ce qui doit valoir partout ne peut pas
   dependre de ce que chaque page pense a demander. Une regle qui veut autre
   chose le dit et l'emporte : `.m-sheet-title` ecrit 700 et le garde.
   --------------------------------------------------------------------------- */
h1, h2, h3, h4, h5, h6,
legend {
  font-size: inherit;
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Les controles de formulaire, poses a la base comme le lien juste en dessous.

   Case a cocher, bouton radio, liste deroulante, champ numerique : laisses nus,
   ils prennent l'apparence du systeme -- carre gris, coche bleue, fleche et
   fleches de reglage dessinees par macOS ou par Windows. Aucune de ces formes
   n'appartient au site, et elles changent d'une machine a l'autre.

   La case a cocher avait deja ete rhabillee, mais sous une classe
   (`.filter-checkbox`) : les trois cases de la fenetre de ticket, celles du
   mapping et celle d'une ligne selectionnee etaient restees au navigateur, et
   la prochaine case ecrite l'aurait ete de meme. Les regles sont donc portees
   par l'element et non par la classe -- ce qui doit valoir partout ne peut pas
   dependre de ce que chaque page pense a demander. Les classes ne servent plus
   qu'a ce qui differe vraiment : une taille, une couleur.
   --------------------------------------------------------------------------- */

/* La fonte, avant toute forme. Un controle de formulaire n'herite pas de celle
   de la page : la feuille du navigateur lui en impose une, et ce n'est pas
   celle du site. Rien ne le signale -- la regle est ailleurs, elle ne figure
   dans aucune de nos declarations --, et l'ecart ne se voit qu'en posant les
   deux textes cote a cote.

   Mesure du 28 aout 2026, sur huit pages : 3 103 controles visibles sur 6 911
   etaient composes dans la fonte du navigateur. La plupart ne portent pas de
   texte et n'en montraient donc rien -- une case a cocher, un selecteur de
   couleur. Ceux qui le montraient sont ceux que l'on lit : « Nouveau »,
   « En cours », « Termine » de la barre de statut d'un ticket, les segments de
   cabinet et de type d'un mandat, les depliants de cycle, le champ des
   etiquettes, celui du bandeau d'alerte. Un bouton du produit n'etait pas ecrit
   dans la fonte du produit, a cote d'un intitule qui l'etait.

   `inherit` plutot que `var(--sans)` : le controle prend alors la fonte de ce
   qui l'entoure -- donc `--sans` par le corps de page, et la chasse fixe s'il
   est un jour pose dans un bloc qui en demande une. Une valeur ecrite ici
   aurait fige la premiere en ignorant la seconde.

   Elle passe avant la regle de `select`, qui ecrit deja `--sans` : entre deux
   selecteurs d'element c'est l'ordre qui tranche, et un filet se pose sous ce
   qui est explicite, pas par-dessus.

   Le corps ne suit pas : `font-size` reste ou il est, regle par regle. Changer
   la fonte ne deplace rien -- le plus grand ecart mesure est de 1,4 px sur un
   segment de statut, et aucune page ne deborde --, changer le corps
   redimensionnerait chaque bouton du produit. C'est une autre question, et
   elle se pose ailleurs. */
button,
input,
select,
textarea {
  font-family: inherit;
}

/* Une zone de texte est un bloc. Laissee `inline-block` par le navigateur, elle
   reserve sous elle la place des jambages de la ligne qui la porte : six pixels
   sous la note commune d'un groupe, qui est seule dans sa tuile -- 22 px de
   creux en bas pour 16 en haut, et rien dans la feuille pour le dire. Les
   quatre zones de texte du produit sont des champs de formulaire ; aucune n'est
   posee au fil d'une phrase. */
textarea {
  display: block;
}

input[type="checkbox"],
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  margin: 0;
  flex: none;
  border: 1.5px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff center no-repeat;
  background-size: 72%;
  cursor: pointer;
  transition: background-color .15s var(--ease), border-color .15s var(--ease);
}

/* Un radio est rond : c'est ce qui dit « un seul de ces choix », la ou une
   case carree dit « autant que vous voulez ».

   999px, et non 50%, ici comme aux quatorze autres endroits ronds de la
   feuille. L'echelle d'arrondis le dit depuis :root -- « ce qui doit etre
   completement rond prend 999px, pas une valeur intermediaire » -- mais la
   feuille ecrivait encore 50% partout. Sur une boite carree les deux donnent
   exactement le meme dessin, et c'est bien le probleme : la difference ne se
   voit que le jour ou la boite cesse d'etre carree. 50% suit alors les deux
   cotes et peint une ellipse ; 999px bute sur la moitie du petit cote et rend
   une pastille a bouts ronds, qui est la forme voulue. Aucune des quinze
   n'est carree par construction : chacune l'est parce qu'une largeur et une
   hauteur ecrites a la main se trouvent egales. Un compteur « +12 » un peu
   plus large, une pastille etiree par son conteneur en flex, et l'ovale
   arrive sans que rien ne le signale. */
input[type="radio"] { border-radius: 999px; background-size: 52%; }

input[type="checkbox"]:hover,
input[type="radio"]:hover { border-color: var(--gray-4); }

/* La coche est une image de fond et non un pseudo-element : un fond suit la
   case quand sa taille change (mobile.css la passe a 20 px pour le doigt), un
   chevron trace en bordures pivotees, non. */
input[type="checkbox"]:checked {
  background-color: var(--cyan);
  border-color: var(--cyan);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}

input[type="radio"]:checked {
  background-color: var(--cyan);
  border-color: var(--cyan);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='12' fill='%23fff'/%3E%3C/svg%3E");
}

input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

input[type="checkbox"]:disabled,
input[type="radio"]:disabled { opacity: .5; cursor: default; }

/* La voie du chevron. Une liste deroulante dessine sa fleche en fond, dans sa
   marge droite : ce n'est pas un rembourrage, c'est une place reservee, et
   elle vaut le retrait du glyphe, plus le glyphe, plus l'air entre lui et le
   texte. Elle etait ecrite a la main quatre fois -- 1.8rem sur `select`, sur
   .choix-fichier-ou-bouton, sur .dossier-assigne-select et sur les trois
   selecteurs rhabilles du volet Mandat --, et le retrait du glyphe trois fois,
   dont deux a .5rem : les huit pixels que l'echelle des espaces refuse, parce
   qu'ils tombent pile entre 6,4 et 9,6. Ils ont tenu tout ce temps parce qu'un
   recensement de rembourrages ne lit pas `background-position`.

   Ecrite ainsi, la voie dit de quoi elle est faite, et le seul endroit qui en
   demandait une autre n'a plus qu'un terme a changer : le selecteur d'un
   formulaire de mandat, plus grand, retire son chevron de --espace-sm au lieu
   de --espace-xs, et sa voie vaut alors exactement --espace-2xl -- les 32 px
   qu'il ecrivait deja, sans dire d'ou ils venaient. Meme calcul que
   --mic-reserve, plus bas, et pour la meme raison : une reserve qui ne dit pas
   ce qu'elle contient ne suit pas ce qu'elle contient quand il bouge.

   Declaree ici et non dans :root : ce n'est pas une echelle mais une mesure
   tiree de deux d'entre elles, et trois familles seulement rangent un glyphe
   dans leur marge droite : la liste deroulante et le bouton de choix de
   fichier, qui y posent un chevron, et le champ de date, qui y pose le bouton
   de son calendrier. Le nom dit chevron parce que les deux premiers en portent
   un ; la mesure, elle, ne depend pas du dessin, et c'est elle qui met la
   fleche d'une liste et l'icone d'une date a la meme distance du bord quand
   elles se suivent sur une rangee de reglages -- ce qui est exactement le cas
   de « Quelle declaration », dans l'onglet Declaration d'un mandat.
   Le plancher de largeur des cases de choix (2.6rem, plus bas) compte cette
   voie et un peu de marge autour ; il a ete regle a l'oeil sur du texte, il
   reste tel quel. */
select,
.choix-fichier-ou-bouton,
.chatbot-choix-bouton,
.date-champ {
  --chevron-taille: var(--icon);
  --chevron-retrait: var(--espace-xs);
  --chevron-reserve: calc(var(--chevron-retrait) + var(--chevron-taille) + var(--espace-xs));
}

/* La liste deroulante : la fleche du systeme remplacee par celle de la banque
   d'icones, et la meme bordure que les champs voisins. Le menu qui s'ouvre est
   le notre depuis le 9 septembre 2026 -- voir `.liste-deroulante-menu` plus
   bas, et `liste-deroulante.js` qui le dessine. */
select {
  appearance: none;
  -webkit-appearance: none;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  padding: var(--espace-xs) var(--chevron-reserve) var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background-color: #fff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--chevron-retrait) center;
  background-size: var(--chevron-taille);
  cursor: pointer;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
  /* Une liste deroulante se dimensionne sur sa plus longue option, sans regarder
     ce qui la tient : « sur et probable -- ce qui a ete applique au fil de
     l'eau » faisait 494 px dans un telephone de 390, et poussait la page
     entiere. Elle est donc bornee a son contenant, et l'option choisie se coupe
     proprement plutot que de deborder. Le menu qui s'ouvre, lui, garde ses
     libelles entiers : il se dimensionne sur eux, borne a la fenetre. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* LE MENU D'UNE LISTE DEROULANTE, DESSINE PAR NOUS.
   « Les panneaux déroulants du site doivent être avec notre code, jamais avec
   celui du navigateur » (ticket du 9 septembre 2026). Le contrôle était habillé
   depuis longtemps ; le panneau qu'il ouvrait restait celui de macOS ou de
   Windows, police du système et coins carrés au milieu d'une interface qui n'en
   a pas.

   Une surface flottante de la famille des autres -- fond blanc, bordure
   `--gray-3`, ombre portée -- mais au rayon du contrôle qui l'ouvre et non à
   celui des grandes surfaces : un menu est attaché à sa liste, il en prolonge
   le dessin. Ses entrées reprennent celles du menu de portée de l'Assistant,
   qui est le premier menu maison du produit. */
.liste-deroulante-menu {
  position: fixed;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  max-width: calc(100vw - var(--espace-md));
  padding: var(--espace-3xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.liste-deroulante-liste {
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

/* Le libellé d'un `<optgroup>` : un repère, pas un titre -- même dessin que
   « Récents » dans le menu de portée. */
.liste-deroulante-groupe {
  padding: var(--espace-sm) var(--espace-2xs) var(--espace-2xs);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-4);
}

.liste-deroulante-groupe:first-child { padding-top: var(--espace-2xs); }

.liste-deroulante-item {
  display: block;
  width: 100%;
  padding: var(--espace-xs) var(--espace-sm);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  text-align: left;
  white-space: nowrap;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  cursor: pointer;
}

/* Un seul état de survol, celui que le clavier pose aussi : la souris et les
   flèches désignent la même chose, donc elles se voient pareil. */
/* La seconde ligne d'une entree de menu : ce que le libelle court abrege. Un
   cran plus petit et plus gris, sous le texte et non a cote, pour que la
   colonne des libelles reste alignee. */
.liste-deroulante-aide {
  display: block;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  font-weight: 400;
}

.liste-deroulante-item:hover,
.liste-deroulante-item.est-vise { background: var(--gray-2); }
.liste-deroulante-item.est-choisie { background: var(--cyan-light); font-weight: 600; }
.liste-deroulante-item[disabled] {
  color: var(--gray-4);
  cursor: default;
  background: none;
}

select:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Les deux fleches de reglage d'un champ numerique : dessinees par le systeme,
   minuscules, et inutiles la ou l'on tape un jour ou un mois. */
input[type="number"] { appearance: textfield; -moz-appearance: textfield; }

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Le choix d'une couleur. Le cadre etait bien arrondi -- c'est la pastille de
   couleur *a l'interieur* qui ne l'etait pas : le navigateur la dessine dans
   un pseudo-element a lui, qui n'herite ni de l'arrondi ni du rembourrage de
   la case. On voyait donc, dans une interface entierement arrondie, un
   rectangle a angle droit pose au milieu d'une case arrondie -- sur la ligne
   d'un cabinet comme sur celle de la pastille de « Mon compte ».

   Meme raison que la case a cocher et la liste deroulante : la regle se pose
   sur l'element et non sur une classe, sinon la prochaine roue posee ailleurs
   repartira nue. */
input[type="color"] {
  appearance: none;
  -webkit-appearance: none;
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: none;
  cursor: pointer;
  overflow: hidden;
}

input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }

input[type="color"]::-webkit-color-swatch {
  border: none;
  /* Un cran en dessous du cadre : deux arrondis concentriques separes par un
     pixel de bordure, comme partout ailleurs dans la feuille. */
  border-radius: var(--radius-xs);
}

input[type="color"]::-moz-color-swatch {
  border: none;
  border-radius: var(--radius-xs);
}

input[type="color"]:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* ---------- Le champ de date ---------- */

/* « Le selecteur de date utilise celui du navigateur, donc il faut que tu
   implementes ton propre selecteur de date. Et que tu l'implementes partout »
   (demande du 30 aout 2026). Le calendrier maison est parti ce jour-la --
   app/static/js/selecteur-date.js -- mais sans une ligne de feuille de style :
   aucune des dix-huit classes qu'il pose n'avait de regle nulle part, ni ici,
   ni dans mobile.css, ni sur la feuille servie en production.

   Ce que ca donnait, mesure au navigateur sur l'onglet Declaration d'un mandat
   le 31 aout 2026 : les deux champs se voyaient en meme temps. Celui d'origine
   gardait son texte segmente « mm/dd/yyyy » et l'icone de calendrier du
   systeme ; le notre s'ajoutait a cote, nu, a la largeur par defaut d'un
   `<input type="text">`. Dans le volet CNCC ils s'empilaient -- 32 px de haut,
   puis 22 -- ; sur la rangee « Quelle declaration » ils se posaient cote a
   cote, 176 px puis 260. Et le calendrier, faute de `position`, s'ouvrait dans
   le flux et poussait tout ce qui le suit. Un selecteur ecrit pour retirer le
   controle du navigateur le laissait donc en place et lui en ajoutait un
   second.

   Le partage que le fichier JavaScript annonce lui-meme est celui-ci :
   l'element d'origine reste -- il garde son `type="date"`, son identifiant,
   ses classes et sa valeur ISO, donc son cadre, sa hauteur et son anneau de
   mise au point continuent de venir de `.aglae-input` --, et ce qui est
   remplace est ce qu'on voit et ce qu'on touche. La feuille ne fait donc que
   trois choses : effacer le texte natif et son icone, poser le champ francais
   exactement par-dessus, et donner au calendrier la forme des autres surfaces
   flottantes du site. */
.date-champ {
  position: relative;
  display: block;
}

/* Les quatre boutons du selecteur -- l'icone du champ, les deux fleches de
   mois, les jours du calendrier, les deux raccourcis du pied -- partent du
   meme etat. La feuille n'a pas de remise a zero de `button` : seule la fonte
   est heritee a la base, et chacun repartirait sinon avec le cadre gris et le
   fond bombe du systeme. Ecrit une fois pour les quatre, parce que ce qui les
   separe ensuite est leur taille et leur couleur, pas leur remise a zero. */
.date-champ-bouton,
.date-fleche,
.date-case,
.date-raccourci {
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  padding: 0;
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}

/* Le champ d'origine : son texte s'efface, son icone se retire, il ne recoit
   plus le clic -- mais il reste la, avec son cadre et sa hauteur. C'est lui
   qu'on voit encore, et c'est lui que `for=` designe : un clic sur l'intitule
   lui donne le curseur, et le JavaScript le passe au champ francais.

   Le selecteur est lourd pour la meme raison que celui du champ francais plus
   bas, et le meme oubli s'y payait : ecrit `.date-champ-source` seul, il perd
   contre TOUTE regle de page qui pose une couleur sur ses champs -- meme poids,
   et la regle de page vient plus loin dans la feuille. Le texte segmente du
   navigateur redevient alors visible SOUS le champ francais, et la date
   s'affiche en double, decalee de deux ou trois pixels. Constate le 7 septembre
   2026 dans les outils OCCE (« bug d'affichage »), ou `.annexe-cellule-champ`
   repeint ses cases en `--gray-6` : les dates du Livret A s'y lisaient
   « 001/011/20226 ». Deux classes, un element et un attribut mettent la regle
   hors d'atteinte d'une classe de page, partout ou une date sera posee. */
.date-champ > input[type="date"].date-champ-source {
  color: transparent;
  pointer-events: none;
}

/* Le bouton de calendrier du systeme, et les deux commandes que certains
   navigateurs ajoutent a cote de lui. Meme geste que sur `input[type="number"]`
   plus haut : ce que le systeme dessine dans un champ n'est pas habillable, il
   se retire. */
.date-champ-source::-webkit-calendar-picker-indicator,
.date-champ-source::-webkit-clear-button,
.date-champ-source::-webkit-inner-spin-button {
  display: none;
}

/* Le champ francais, pose exactement sur le cadre de l'autre. Meme rembourrage
   que `.aglae-input`, plus la voie du glyphe a droite.

   Le selecteur est plus lourd que tous les autres de cette section, et c'est
   deliberé : ce champ porte `type="text"` par mecanique, pas par nature. Il
   est le visage d'une date, et toute regle de page qui habille les champs de
   texte qu'elle contient -- `.reglages-row input[type="text"]`,
   `.mapping-table input[type="text"]`, `.dossier-form input[type="text"]`,
   et les mêmes dans la feuille du telephone -- le prend au passage avec deux
   classes et un element, soit plus que son propre nom. Mesure au navigateur le
   31 aout 2026 sur la rangee « Quelle declaration » : le champ visible sortait
   de son cadre de 84 px, parce que `.reglages-row input[type="text"]` lui
   posait un plancher de 260 px, et il en reprenait aussi le rembourrage, la
   bordure grise et l'anneau de mise au point. Une classe, une classe et un
   attribut : la voie du glyphe et le cadre transparent tiennent desormais
   partout ou une date sera posee, y compris dans un tableau.

   `min-width: 0` rend donc ce plancher a la page, et les deux bords retrouvent
   la mesure du cadre qu'ils recouvrent.

   La bordure transparente n'est pas un ornement non plus : sans elle, son texte
   commencerait un pixel plus a gauche que celui du champ de texte pose a cote
   sur la meme rangee -- le cadre de l'un compte dans son rembourrage, pas
   celui de l'autre. */
.date-champ > .date-champ-saisie[type="text"] {
  position: absolute;
  inset: 0;
  min-width: 0;
  padding: var(--espace-xs) var(--chevron-reserve) var(--espace-xs) var(--espace-sm);
  border: 1px solid transparent;
  background: none;
  font-size: var(--fs-md);
  color: var(--black);
}

.date-champ > .date-champ-saisie[type="text"]:focus { outline: none; }

/* L'anneau de mise au point revient au champ d'origine, qui est celui qui
   porte le cadre. Les deux etats dans la meme regle : le curseur dans le champ
   francais, et le calendrier ouvert -- on ne peut pas etre dans les deux a la
   fois, et le cadre doit rester allume dans l'un comme dans l'autre. Recette
   reprise a la lettre de `.aglae-input:not([type="checkbox"]):focus`. */
.date-champ:focus-within > .date-champ-source,
.date-champ-ouvert > .date-champ-source {
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.date-champ-bouton {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--chevron-reserve);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-4);
}

.date-champ-bouton:hover { color: var(--cyan-dark); }

/* Le calendrier est une surface flottante, donc il en a la forme : --radius-lg,
   fond blanc, filet --gray-3, ombre portee.

   `width: max-content` n'est pas un ornement non plus. Une boite absolue se
   mesure sur son contenant quand rien ne la dimensionne, et ce contenant est
   ici le champ -- 176 px sur la rangee « Quelle declaration ». Le calendrier
   en demande 230 : sans cette ligne, il serait rentre de force et ses colonnes
   auraient ete comprimees.

   Pas de `display` ici, volontairement : le JavaScript ouvre et ferme le
   panneau par l'attribut `hidden`, et une regle de `display` dans la feuille
   l'emporterait sur celle du navigateur -- le panneau resterait affiche en
   permanence, comme cela avait failli arriver a la fenetre de reglages.

   Le niveau 40 est celui du resume des FEC : au-dessus des barres collantes de
   la page (15) et des en-tetes de tableau (14), en dessous des fenetres
   modales (100). */
.date-panneau {
  --date-case: var(--h-sm);
  position: absolute;
  z-index: 40;
  top: calc(100% + var(--espace-2xs));
  left: 0;
  width: max-content;
  padding: var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  background: #fff;
  box-shadow: var(--shadow-lg);
}

/* Un champ pose pres du bord droit -- une case de la derniere colonne du volet
   CNCC -- pousserait son calendrier hors de l'ecran. Le JavaScript mesure et
   pose cette classe ; c'est ici qu'elle s'aligne sur l'autre bord. */
.date-panneau-gauche {
  left: auto;
  right: 0;
}

/* Et le meme geste vers le haut. Depuis que l'espace de travail d'un mandat
   se tient a la fenetre, l'onglet ouvert est une boite de defilement : un
   calendrier pose sous un champ du bas s'y coupait au milieu du mois -- 212
   pixels manquants, mesures a 1280x800 sur l'assistant. Le JavaScript
   mesure le premier ancetre qui rogne ; c'est ici que le panneau passe
   au-dessus du champ. */
.date-panneau-dessus {
  top: auto;
  bottom: calc(100% + var(--espace-2xs));
}

.date-panneau-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--espace-sm);
}

/* « aout 2026 » est un titre, pas une phrase : la capitale se pose ici plutot
   que dans la liste des mois, qui sert aussi ailleurs.

   Depuis le 31 aout 2026 il porte deux boutons -- le mois, l'annee -- par
   lesquels on entre dans les grilles de raccourci. Ils heritent d'ici leur
   graisse et leur taille : ce qu'ils disent d'abord est ou l'on est, et un
   titre qui se mettrait a ressembler a une barre d'onglets pour signaler qu'il
   est cliquable aurait perdu au change. */
.date-panneau-titre {
  display: flex;
  align-items: center;
  gap: var(--espace-3xs);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--black);
  text-transform: capitalize;
}

/* Ce qui les signale est le survol, comme partout ailleurs dans ce panneau. */
.date-titre-part {
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  padding: var(--espace-3xs) var(--espace-2xs);
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}

.date-titre-part:hover { background: var(--gray-1); }

.date-fleche {
  width: var(--date-case);
  height: var(--date-case);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-5);
}

/* Les deux rangees ne font qu'une grille : les initiales des jours doivent
   tomber sur les colonnes des dates, et deux gabarits ecrits separement
   auraient fini par diverger.
   `minmax(0, ...)` et non la case seule : la largeur du panneau est plafonnee
   sur le telephone, et des colonnes fixes auraient deborde par-dessous plutot
   que de se resserrer. */
.date-semaine,
.date-grille {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, var(--date-case)));
  gap: var(--espace-3xs);
}

/* Les grilles de raccourci -- douze mois, douze annees -- sur trois colonnes.

   Leur largeur est celle de la grille des jours, ecrite en toutes lettres :
   sept cases et six gouttieres. Sans cela le panneau, qui se dimensionne sur
   son contenu, se serait retreci en passant aux mois puis elargi en revenant
   aux jours -- un panneau qui change de taille sous le curseur donne
   l'impression d'avoir clique a cote.

   `max-width` le rend a la page sur un telephone, ou le panneau est deja
   plafonne (voir mobile.css) : les colonnes se resserrent alors d'elles-memes,
   pour la meme raison que celles des jours. */
.date-grille-large {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  width: calc(var(--date-case) * 7 + var(--espace-3xs) * 6);
  max-width: 100%;
}

.date-semaine {
  margin-bottom: var(--espace-2xs);
}

.date-semaine span {
  text-align: center;
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  letter-spacing: var(--suivi-entete);
}

.date-case {
  height: var(--date-case);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-6);
  font-variant-numeric: tabular-nums;
}

/* Les cases qui precedent le premier du mois sont vides : rien a survoler,
   rien a viser. */
.date-case-vide { pointer-events: none; }

/* Les deux commandes du panneau s'assombrissent au survol ; une case du
   calendrier ne prend que le fond. Elle porte deja sa propre couleur -- cyan
   pour aujourd'hui, blanc pour le jour choisi -- et un survol qui ecrirait
   `color` la lui prendrait : `.date-case:hover` compte deux classes,
   `.date-case-aujourdhui` une seule. */
.date-fleche:hover,
.date-raccourci:hover {
  background: var(--gray-1);
  color: var(--black);
}

.date-case:hover { background: var(--gray-1); }

.date-case-aujourdhui {
  color: var(--cyan-dark);
  font-weight: 600;
}

/* Le jour choisi, et son survol ecrit a part pour la meme raison de compte :
   sans cette seconde regle, passer la souris sur le jour deja retenu le
   repeindrait en gris. */
.date-case-choisie {
  background: var(--cyan);
  color: #fff;
  font-weight: 600;
}

.date-case-choisie:hover { background: var(--cyan-dark); }

.date-panneau-pied {
  display: flex;
  justify-content: space-between;
  margin-top: var(--espace-sm);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
}

.date-raccourci {
  padding: var(--espace-3xs) var(--espace-xs);
  color: var(--gray-5);
}

/* Un seul lien de texte pour tout le site. Il y en avait trois : le bleu
   souligne du navigateur sur les pages de connexion, qu'aucune regle ne
   couvrait ; le bleu de la palette sur les pages publiques ; la couleur du
   texte courant sur les cartes de ticket. Le lien est ici pose a la base,
   donc plus rien ne peut retomber sur le bleu du navigateur. Les liens qui
   sont en realite des boutons (.icon-btn, .dossier-link, .mfa-mac-btn)
   posent leur propre couleur plus loin et l'emportent sur cette regle. */
a {
  color: var(--blue);
  text-underline-offset: .2em;
  text-decoration-thickness: 1px;
}

a:hover { color: var(--black); }

:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

.app-header {
  border-bottom: 1px solid var(--gray-3);
  background: rgba(255, 255, 255, .72);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  position: sticky;
  top: 0;
  z-index: 20;
}

/* La barre se replie plutot que de deborder. Elle ne le faisait pas : ses six
   blocs demandent environ 1210 px sur le detail d'un mandat, et en dessous ils
   sortaient simplement de la fenetre -- a 1024 px, « Tickets » etait coupe en
   deux et le menu « Reglages » entierement hors ecran, atteignable seulement en
   faisant defiler la page de cote. La feuille mobile ne reprend la main qu'a
   820 px : toute la plage des portables et des tablettes en paysage etait donc
   dans ce cas.
   Le titre se coupe en premier (il a deja son `text-overflow`), et si cela ne
   suffit pas le groupe de droite passe a la ligne, toujours cale a droite par
   son `margin-left: auto`. */
.app-header-inner {
  padding: var(--espace) var(--gouttiere);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-sm) var(--espace-lg);
}

.app-logo-link {
  display: inline-flex;
  line-height: 0;
  flex-shrink: 0;
}

/* Le mot-symbole porte un jambage, le `p` d'Alpboard, qui occupe le cinquieme
   bas du fichier. Cale sur sa boite entiere, il rendait des capitales de 29 px
   la ou l'ancienne marque, sans jambage, en donnait 36 : la barre paraissait
   vide. Le logo est donc agrandi jusqu'a ce que ses capitales retrouvent leur
   taille, et le jambage empiete sur le creux du bas, que la marge negative rend
   a la mise en page. L'en-tete garde ainsi la hauteur qu'annonce --h-entete,
   dont depend tout ce qui colle dessous. */
.app-logo { height: calc(var(--h-logo) + 8px); margin-bottom: -8px; }

.app-version {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-family: var(--sans);
  background: var(--gray-1);
  border-radius: 999px;
  padding: var(--espace-3xs) var(--espace-sm);
}

/* La barre de titre a trois zones, dans cet ordre sur toutes les pages :
   `.app-nav` (le retour), `.app-titre` (le nom de la page), `.app-nav-fin`
   (les actions puis les destinations). Voir `templates/_base.html`. */
.app-nav { display: flex; align-items: center; gap: var(--espace-xs); }

.app-nav-fin {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--espace-xs);
  margin-left: auto;
}

/* Ancien nom, pose directement sur un lien plutot que sur un conteneur.
   Conserve le temps qu'il ne reste plus rien qui l'emploie. */
.app-nav-end { margin-left: auto; }

.dossier-detail-badges {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  flex: none;
}

/* `.dossier-detail-titre` nommait le titre du detail d'un mandat, puis a servi
   de titre generique sur Mapping, Tickets et Messages. Le nom honnete est
   `.app-titre` ; l'ancien reste accepte, `mobile.js` fabrique encore le sien. */
.app-titre,
.dossier-detail-titre {
  font-size: var(--fs-xl);
  font-weight: 600;
  color: var(--black);
  margin: 0;
  flex: 1 1 auto;
  min-width: 80px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* La meme zone que `.app-nav-fin`, mais elle porte six groupes la ou les
   autres pages en portent quatre : le selecteur d'exercice, les pastilles de
   l'etat, la tuile du cabinet, puis les destinations communes. Sa gouttiere
   valait .75rem -- 12 px, aucun barreau --, et la feuille du telephone la
   ramenait a .4rem, ce qui disait deja que 12 n'etait pas la bonne mesure.

   Elle prend --espace-sm, le barreau qui separe deux choses distinctes ; six
   groupes a --espace-xs, essaye au navigateur, collent le selecteur d'exercice
   a la premiere pastille et la tuile du cabinet au mot « Messages ». Le
   telephone garde --espace-xs : sa barre ne montre ni les destinations ni les
   reglages, il n'y reste pas six groupes a separer. */
.dossier-header-right {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

.dossier-signataire {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

/* L'ecart entre une icone et son propre libelle, mesure au navigateur sur neuf
   pages le 28 aout 2026 : trois valeurs pour une seule relation. 6,4 px dans
   .btn-link (le barreau --espace-xs), 7,2 dans le declencheur des reglages,
   8 partout ailleurs. Les deux dernieres se cotoient dans l'en-tete de chaque
   page : « Messages » et « Tickets » portent leur icone a 8 px, « Reglages »
   la sienne a 7,2, sur la meme rangee et a trois centimetres d'ecart.

   Une icone et son libelle ne sont pas deux choses posees l'une a cote de
   l'autre, c'est un seul mot : l'ecart qui les separe doit etre plus serre que
   celui qui separe deux boutons. C'est deja ce qu'ecrit .btn-link, et c'est le
   barreau qu'on prend -- pas un jeton de 8 px, qui casserait une echelle
   resserree une fois pour la valeur la plus recopiee de la feuille.

   Reste que cette valeur etait bien la, 31 fois, dans les deux feuilles. Elle
   est rangee, le meme jour, sur l'un ou l'autre des barreaux voisins selon ce
   que le blanc separe : 6,4 quand il tient deux choses qui n'en font qu'une --
   une case et son etiquette, un rond et le nom de la personne, un intitule et
   son menu --, 9,6 quand il en separe deux, ou qu'il empile deux blocs. Ni
   l'un ni l'autre n'est le 8 de depart, et c'est precisement le point : une
   seule valeur posee partout ne disait rien de ce qu'elle separait, pendant
   que la meme relation s'ecrivait 6,4 trois regles plus haut.

   Un cas resume le reste. .toolbar-group, un seul et meme groupe de boutons,
   prenait 9,6 au navigateur et 8 sous 820 pixels. Ce n'etait pas une
   adaptation au petit ecran -- un ecran plus etroit ne demande pas 1,6 pixel
   de moins entre deux boutons --, c'etaient deux mains sur la meme barre a
   deux moments differents. Les deux prennent --espace-sm.

   Le remplissage de ce bouton-ci etait la derniere de ces deux mains, et la
   plus recopiee : `.5rem .75rem`, deux valeurs qu'aucun barreau ne porte,
   alors que ses trois seules exceptions -- la barre d'outils, l'en-tete, les
   lignes de reglage -- ecrivaient toutes les trois `--espace-2xs
   --espace-sm`. La base disait une chose, ses exceptions une autre, et
   c'etaient les exceptions qui avaient raison. Elles sont maintenant vides,
   sauf du plancher propre a l'en-tete.

   Restait ce que ce remplissage laissait decider au parent. Un bouton dont la
   hauteur vient de son contenu mesure ce que mesure la ligne du bloc qui le
   contient : sur « Mon compte », « Cabinets et equipe » faisait 37,2 px et
   « Se deconnecter », juste dessous, 34 -- meme classe, meme remplissage, deux
   hauteurs, quand les cent deux autres boutons du produit se tiennent a 28 ou
   32. Le meme defaut avait ete constate le 28 aout 2026 dans la carte d'un
   ticket, et repare la, sur huit classes ; la cause, elle, etait restee ici.

   .icon-btn prend donc la recette que .btn-link porte depuis toujours et que
   la carte de ticket a recopiee : hauteur de ligne fixe, plancher a --h-sm,
   remplissage vertical passe sous le plancher pour que ce soit lui qui decide.
   « Une hauteur de bouton ne se decide pas dans le parent. » */
.icon-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-5);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  min-height: var(--h-sm);
  line-height: 1.3;
  padding: var(--espace-2xs) var(--espace-sm);
  cursor: pointer;
  text-decoration: none;
  /* Un libelle de bouton ne se coupe jamais en deux lignes. Sans cela « Mon
     compte » passait a la ligne des que l'en-tete etait charge, et la barre du
     mandat devenait plus haute de 22 px que celle des autres pages : c'est la
     cause principale de l'impression que les pages ne sont pas alignees. */
  white-space: nowrap;
  transition: background .15s var(--ease), color .15s var(--ease);
}

/* `display: inline-flex` ci-dessus l'emporte sur la regle `[hidden]` du
   navigateur, qui n'est qu'un `display: none` d'agent utilisateur. Sans cette
   ligne, poser `hidden` sur un bouton d'icone ne le cache pas -- il ne fait
   plus que mentir aux lecteurs d'ecran. La liste plus bas montre que le cas
   se represente a chaque composant qui redeclare son `display`. */
.icon-btn[hidden] { display: none; }

.icon-btn:hover {
  background: var(--gray-1);
  color: var(--black);
}

/* La destination ou l'on se trouve deja. Aucune page ne l'indiquait : sur
   Mapping, le lien « Mapping » de l'en-tete etait rigoureusement identique aux
   trois autres. Meme marquage que la barre d'onglets du telephone, en plus
   discret : on assombrit le texte plutot que d'ajouter une couleur. */
.icon-btn.actif {
  color: var(--black);
  background: var(--gray-1);
}

/* Quatre boutons de la meme barre, tous `.icon-btn`, tous cernes du meme
   rembourrage, ne faisaient pas la meme hauteur : trois a 37,2 px, celui des
   reglages a 40. C'est le contenu qui decidait -- une ligne de texte de 19,2 px
   d'un cote, la pastille du collaborateur de 22 px de l'autre.

   Tant qu'aucun fond n'est peint, la difference ne se voit pas. Mais
   `.icon-btn.actif` en peint un, et le survol aussi : sur chaque page du
   produit, la plaque grise de la page ou l'on se trouve est plus courte de
   trois pixels que celle des reglages posee juste a cote, et son bord haut est
   un pixel et demi plus bas. Deux plaques voisines de la meme barre, jamais
   alignees.

   La hauteur cesse donc de venir du contenu : plancher a --h-champ, la hauteur
   d'un champ du produit, et rembourrage vertical passe sous ce plancher pour
   que ce soit lui qui decide. La pastille de 22 px y tient exactement. */
.app-header .icon-btn { min-height: var(--h-champ); }

/* Les trois destinations de la barre -- Notifications, Messages, Tickets --
   reduites a leur icone, leur nom sous elles au survol.

   « Notifications, Messages, Tickets dans le header se simplifie juste en leur
   icône, c'est en les survolant que le nom complet s'affiche » (ticket du
   7 septembre 2026). Trois mots pour trois dessins qu'on reconnaît -- une
   cloche, une enveloppe, un billet -- et qui reviennent sur chacune des pages
   du produit : on cesse de les lire au bout de deux jours, mais ils occupent la
   barre à chaque page.

   Le nom est DÉPLACÉ, pas supprimé : c'est le même élément qui se lit au survol
   et qui nomme le lien pour un lecteur d'écran. `opacity` et non `display`,
   pour cette raison précisément -- une infobulle en `display: none` sort de
   l'arbre d'accessibilité, et le lien n'aurait plus de nom du tout.

   Les pastilles restent à côté de l'icône : elles ne sont pas un nom, ce sont
   des chiffres qu'on vient lire d'un coup d'oeil, et les cacher au survol
   aurait retiré la seule chose que cette barre dit vraiment.

   Une bulle sombre, comme celles du système : c'est la seule surface du produit
   qui se pose PAR-DESSUS le contenu sans être une fenêtre, et le contraste la
   distingue d'un panneau qu'on pourrait cliquer. */
.app-header .app-destination { position: relative; }

.app-header .app-destination-nom {
  position: absolute;
  top: calc(100% + var(--espace-3xs));
  left: 50%;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--black);
  color: #fff;
  font-size: var(--fs-2xs);
  font-weight: 500;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -.2rem);
  pointer-events: none;
  transition: opacity .15s var(--ease), transform .15s var(--ease);
}

.app-header .app-destination:hover .app-destination-nom,
.app-header .app-destination:focus-visible .app-destination-nom {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* La barre du téléphone n'a pas de survol, et son nom est écrit en toutes
   lettres sous chaque onglet (voir mobile.js) : la bulle n'y aurait aucune
   façon de s'ouvrir, et elle se poserait sous une barre repliée. */
@media (hover: none) {
  .app-header .app-destination-nom { display: none; }
}

/* La fenetre de reglages : « Mon compte » et « Mapping », ranges derriere une
   seule entree de la barre (voir la macro `reglages` de _base.html).

   Le conteneur reste en position relative et le panneau se pose dessous, cale
   a droite : il deborde de l'en-tete, qui est `sticky` avec un z-index de 20,
   d'ou le 30 ici, faute de quoi le panneau passerait sous le contenu de la
   page. */
.app-reglages {
  position: relative;
  display: inline-flex;
}

/* La pastille du collaborateur, telle qu'elle apparait deja sur une ligne de
   mandat : c'est elle qui dit « ce menu parle de vous ». */
.app-reglages-pastille {
  --avatar-d: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--avatar-d);
  height: var(--avatar-d);
  border-radius: 999px;
  color: #fff;
  font-size: calc(var(--avatar-d) * var(--avatar-initiales));
  font-weight: 600;
  line-height: 1;
  flex: none;
}

.app-reglages-pastille-grande {
  --avatar-d: 34px;
}

/* Le rond du compte connecte, a cote de l'engrenage dans la barre (« garde la
   photo du profil connecte en plus », suivi du 7 septembre 2026).

   Un cran sous celui du panneau : il voisine des icones de 18 pixels, et un
   rond de 22 y pesait plus que l'engrenage qu'il accompagne. L'ecart entre les
   deux est celui d'une icone a son etiquette, pas celui de deux entrees de la
   barre, d'ou --espace-2xs et non le --espace-xs du bouton. */
.app-reglages-pastille-barre { --avatar-d: 20px; }

.app-reglages-declencheur { gap: var(--espace-2xs); }

/* L'engrenage des réglages est la DERNIÈRE entrée de la barre : sa bulle se cale
   à droite au lieu de se centrer sous lui, faute de quoi elle sort du bord de
   la fenêtre et se lit tronquée.

   Et elle s'efface dès que le panneau s'ouvre -- c'est-à-dire au survol, ce
   panneau s'ouvrant sans clic : la bulle se pose juste sous le bouton,
   c'est-à-dire par-dessus le haut du panneau, et elle y répéterait un mot que
   le panneau ouvert dit déjà. Le nom reste là où il est, et c'est tout ce
   qu'on lui demande : c'est lui qui nomme le bouton pour un lecteur d'écran. */
.app-header .app-reglages .app-destination-nom {
  left: auto;
  right: 0;
  transform: translate(0, -.2rem);
}

.app-header .app-reglages .app-destination:hover .app-destination-nom,
.app-header .app-reglages .app-destination:focus-visible .app-destination-nom {
  transform: translate(0, 0);
}

.app-header .app-reglages[data-ouvert] .app-destination-nom { opacity: 0; }

.app-reglages-panneau {
  position: absolute;
  top: calc(100% + .4rem);
  right: 0;
  z-index: 30;
  min-width: 250px;
  padding: var(--espace-xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

/* `display: flex` ci-dessus l'emporte sur la regle `[hidden]` du navigateur,
   qui n'est qu'un `display: none` d'agent utilisateur : sans cette ligne, le
   panneau reste affiche en permanence et l'attribut `hidden` ne fait plus que
   mentir aux lecteurs d'ecran. */
.app-reglages-panneau[hidden] { display: none; }

/* Le survol ne doit pas se rompre entre le bouton et le panneau : sans ce
   pont, descendre la souris de l'un vers l'autre traverse quatre pixels de
   vide et referme la fenetre avant qu'on l'atteigne. */
.app-reglages-panneau::before {
  content: "";
  position: absolute;
  top: -.4rem;
  left: 0;
  right: 0;
  height: .4rem;
}

.app-reglages-identite {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-sm);
  border-bottom: 1px solid var(--gray-2);
  margin-bottom: var(--espace-2xs);
}

.app-reglages-identite-texte {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.app-reglages-nom {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--black);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-reglages-email {
  font-size: var(--fs-xs);
  color: var(--gray-4);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-reglages-lien {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  width: 100%;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-5);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  padding: var(--espace-sm);
  cursor: pointer;
  text-decoration: none;
  text-align: left;
  white-space: nowrap;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.app-reglages-lien:hover { background: var(--gray-1); color: var(--black); }

.app-reglages-lien.actif { background: var(--gray-1); color: var(--black); }

/* « Se deconnecter en rouge » (ticket du 7 septembre 2026). Le site alignait
   la seule entree qui ferme la session sur les cinq qui ouvrent une page : on
   la cherchait par sa position, jamais par sa couleur, et on la trouvait en
   lisant les six.

   Ce n'est pas une nouveaute du produit, c'est le site qui rattrape l'app :
   la deconnexion y est un bouton `role: .destructive` depuis toujours, et
   iOS peint le destructif en rouge. Les deux surfaces disent enfin la meme
   chose de la meme action.

   `--red-dark` et non `--red` pour l'encre : c'est le barreau que la feuille
   emploie deja partout ou du rouge se lit en petits caracteres sur du blanc
   (.tuile-danger .tuile-titre), et le seul des deux qui tienne le contraste
   d'un libelle de 13 pixels. */
.app-reglages-deconnexion {
  margin: var(--espace-2xs) 0 0;
  padding-top: var(--espace-2xs);
  border-top: 1px solid var(--gray-2);
}

.app-reglages-deconnexion .app-reglages-lien { color: var(--red-dark); }

.app-reglages-deconnexion .app-reglages-lien:hover {
  background: var(--red-pale);
  color: var(--red-dark);
}

.icon-btn-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  padding: 0 var(--espace-2xs);
  border-radius: 999px;
  background: var(--cyan);
  color: #fff;
  font-size: var(--fs-2xs);
  font-weight: 600;
  line-height: 1;
}

/* La seconde pastille d'une destination : ce qui attend un geste, pas ce qui
   reste ouvert. Orange, comme l'etat « À valider » d'un ticket partout
   ailleurs (.ticket-statut-seg, la pastille de statut, Ticket.swift cote app)
   -- deux teintes pour le meme etat obligeraient a apprendre laquelle veut
   dire quoi. */
.icon-btn-badge-action { background: var(--orange); }

/* Le rembourrage du bas n'est pas celui du haut : le bouton flottant de
   signalement (`.ticket-widget`, 52 px de rond a 1.5rem des deux bords) est
   pose par-dessus la fenetre, et la derniere ligne d'une page qui descend
   jusqu'en bas passait dessous -- la derniere ligne de l'equipe du cabinet
   etait a moitie recouverte. La page se reserve donc sa hauteur en pied. */
.app-main {
  /* La page prend ce que l'en-tete laisse : voir le corps, plus haut. */
  flex: 1;
  padding: var(--espace-2xl) var(--gouttiere) calc(52px + var(--espace-xl) * 2);
}

/* Un corps de page tenu par la fenetre, et non par son contenu.

   Depuis l'etape precedente la coquille descend jusqu'en bas de l'ecran, mais
   un corps de page reste une pile de blocs : la hauteur qu'elle gagne n'est a
   personne, et le dernier bloc s'arrete ou son contenu s'arrete. Cette classe
   la donne -- le corps devient une colonne, et la section qui porte `flex: 1`
   descend jusqu'au pied de la fenetre.

   Elle ne va qu'aux pages ou l'on defile a l'interieur d'un panneau et non
   dans la page : une messagerie d'abord, ou la barre d'ecriture doit rester
   sous la main pendant que le fil bouge. Une page qui se lit de haut en bas
   n'en a pas besoin et ne doit pas la prendre.

   Deux declarations la tiennent, et il faut les deux -- mesure faite. `body`
   n'a qu'un `min-height` : sa hauteur reste donc celle de son contenu, et une
   hauteur qui n'est jamais definie ne se transmet a personne. La grille du fil
   se taillait alors sur la conversation entiere, et le panneau avec elle : mille
   soixante-onze pixels dans une fenetre de huit cent quarante sur le telephone,
   quatre cent trente-huit a faire defiler pour atteindre la barre d'ecriture.

   `height: 100dvh` rend la hauteur definie ; `min-height: 0` laisse ensuite le
   corps descendre sous le minimum automatique que son contenu lui imposait. Le
   plancher n'est pas perdu, il a change de place : il est sur le panneau, plus
   bas. Une fenetre trop courte fait donc defiler la page au lieu d'ecraser le
   fil -- verifie a 1280x400, ou le panneau garde ses 352 px et la page rend
   soixante-trois pixels de defilement. */
body:has(.app-main-pleine) {
  height: 100vh;
  height: 100dvh;
}

.app-main-pleine {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* Un onglet tenu par la fenetre : le panneau ouvert prend ce que la barre
   d'onglets laisse, et c'est lui qui defile.

   Le mapping en donne la mesure. Quatre tuiles empilees, dont une table de
   six cent une racines : 37 194 px de page. Ce qui partait au premier tour de
   molette n'etait donc pas seulement le contenu, c'etait la coquille -- la
   barre d'onglets d'abord, puis les titres de colonnes --, et arrive a la
   trois-centieme racine plus rien ne disait laquelle des six cases a cocher
   etait « Applicable (association) ». C'est la difference entre une page qu'on
   lit et un espace ou l'on travaille : dans le second, ce qui nomme ne bouge
   pas.

   `min-height: 0` est indispensable : le plancher automatique d'un element
   flexible est la hauteur de son contenu, et un panneau de 36 952 px ne se
   laisse pas comprimer sans qu'on le lui dise. Les panneaux fermes ne sont pas
   vises -- ils sont en `display: none` et ne prennent rien. */
.app-main-pleine > .tab-panel {
  flex: 1;
  min-height: 0;
  overflow: auto;
  /* Le creux du pied descend dans la zone qui defile -- meme raison que
     pour `.app-main-pleine > .panel` plus bas : laisse sur la page, il
     retirait cent pixels au bas de la fenetre en permanence, et l'onglet
     s'arretait a treize cent quarante d'une fenetre de mille quatre cent
     quarante. Pose ici, il ne se voit qu'une fois arrive au bout. */
  padding-bottom: calc(52px + var(--espace-xl) * 2);
}

/* Sur un telephone, trois bandes de l'analyse sortent de la gouttiere pour
   toucher les deux bords de l'ecran -- l'index des cycles, la barre de
   commandes, et chaque cycle (voir `.cycle-section` dans mobile.css). Le
   procede suppose que la gouttiere est celle de la boite qui defile ; elle
   etait restee sur le `<main>` pendant que l'onglet ouvert se mettait a
   defiler pour son compte, et la sortie de droite devenait 14 px de
   defilement lateral -- une page de telephone qui glisse de cote sans que
   rien ne s'y trouve.

   La gouttiere descend donc dans la zone qui defile : la sortie retombe
   pile sur le bord de sa boite, donc ne deborde plus, et le contenu
   ordinaire reste ou il etait, puisque ce que la marge retire le creux le
   rend. Vise le panneau d'onglet seul : c'est la seule des trois zones
   tenues par la fenetre qui soit nue -- une tuile de liste, elle, a un
   cadre, et un cadre pose a cheval sur le bord de la vue ne se ferme
   nulle part. */
@media (max-width: 820px) {
  .app-main-pleine > .tab-panel {
    margin-left: calc(var(--gouttiere) * -1);
    margin-right: calc(var(--gouttiere) * -1);
    padding-left: var(--gouttiere);
    padding-right: var(--gouttiere);
  }
}

/* Deuxieme forme : la page elle-meme est la boite qui defile.

   Les trois regles au-dessus tiennent la fenetre avec une colonne flexible
   dont un enfant prend la hauteur restante : il faut donc qu'il y ait un
   enfant, un seul, et qu'il sache defiler. L'acceptation n'a pas cette forme
   -- dix tuiles a la file, dont cinq dans une grille --, et deux choses s'y
   cassaient.

   La premiere : une colonne flexible plus haute que sa boite comprime ses
   items, et celui dont le debordement n'est pas `visible` perd meme son
   plancher automatique. Mesure a 2 560 : la frise, qui defile chez elle,
   tombait de 60 px a 32, l'en-tete de 328 a 118, la decision de 327 a 118 --
   phrases coupees au milieu, frise reduite a rien. Une boite qui defile n'a
   pas besoin d'etre flexible ; il lui suffit d'avoir une hauteur, et
   `.app-main-pleine` la lui donne deja.

   La seconde : les deux regles suivantes visent le panneau unique. Posees sur
   dix tuiles, elles donnaient a chacune cent pixels de creux au pied et son
   propre debordement -- l'en-tete, la decision et la tracabilite portaient
   `padding-bottom: 100px` pour un contenu qui s'arretait bien avant. D'ou le
   `:not(.defile-page)` qui les borne, et la reserve du bouton flottant qui
   reste ou elle etait : sur la page, c'est-a-dire dans la boite qui defile. */
.app-main-pleine.defile-page {
  display: block;
  overflow: auto;
}

/* Meme geste pour une page qui n'a qu'un panneau, sans onglets ni tuile de
   liste : les deux pages de tickets, ou l'on descend le plus loin dans le
   produit -- 2 289 px a 2 560 de large, 5 057 a 1 280, pour cinquante cartes.

   C'est le panneau qui defile, jamais la liste qu'il contient : `.tickets-list`
   coule en colonnes de journal, et une boite en colonnes a qui l'on donne une
   hauteur ferme et un debordement cesse de couler vers le bas pour couler vers
   la droite. Essaye : six colonnes a 2 560, vingt-deux a 1 280, et vingt mille
   pixels de defilement lateral. La liste garde donc sa hauteur libre, et c'est
   son parent qui borne.

   Le creux du pied passe de la page au panneau. La reserve du bouton flottant
   (voir `.app-main`) laissee sur la page aurait fait une bande morte de cent
   pixels au bas de la fenetre, sur toute la largeur, en permanence. Posee dans
   la zone qui defile, elle ne coute rien tant qu'on n'est pas au bout.

   IL EN RESTE SEIZE PIXELS, et pas zero (« la tu as colle, laisse un petit
   espace esthetique », suivi du 9 septembre 2026). A zero, la bordure du
   panneau tombe exactement sur le bord de la fenetre et s'y coupe : la tuile
   n'a plus l'air de descendre jusqu'en bas, elle a l'air d'etre tranchee. Le
   creux qui separe deux tuiles empilees, repris ici entre la derniere et le
   bord : c'est le meme blanc, donc la meme famille. Seize pixels et non les
   trente-deux du haut : ce qu'on rend au bas de la fenetre est repris sur la
   liste, et la demande d'avant celle-ci etait precisement de descendre plus
   bas. */
.app-main-pleine:not(.defile-page):has(> .panel),
.app-main-pleine:not(.defile-page):has(> .tab-panel) {
  padding-bottom: var(--espace-md);
}

.app-main-pleine:not(.defile-page) > .panel {
  flex: 1;
  min-height: 0;
  overflow: auto;
  margin-bottom: 0;
  padding-bottom: calc(52px + var(--espace-xl) * 2);
}

/* Et la barre d'outils se cale sur ce panneau, non plus sur la fenetre.
   `position: sticky` se mesure depuis le premier ancetre qui defile : le
   decalage qui la posait juste sous l'en-tete du produit la descendrait ici de
   soixante-trois pixels a l'interieur du panneau, et les cartes passeraient
   dans ce vide avant de disparaitre sous elle. */
.app-main-pleine .tuile-collante {
  top: 0;
}

/* Meme geste pour une page qui n'a pas d'onglets mais une liste : c'est la
   tuile de celle-ci qui prend la hauteur restante et qui defile. /dossiers
   mesurait 13 145 px, trois cent soixante-dix-neuf mandats a la file.

   La tuile defile en entier, sa rangee de tri comprise, et non la seule liste :
   une barre de defilement retire quinze pixels a ce qu'elle borde, et si la
   rangee restait dehors, ses cinq intitules ne tomberaient plus sur les
   colonnes qu'ils annoncent. Le meme creux pour les deux, ou aucun.

   Le creux du haut passe a la rangee de tri, qui devient collante : pose sur
   la tuile, il aurait fait glisser les lignes dans les seize pixels de blanc
   qui separent la rangee du bord.

   ET LE CREUX DU BAS PASSE DANS LA TUILE, comme il est passe dans le panneau
   juste au-dessus. « La liste n'est pas deployee jusqu'en bas, le bas est
   bloque un peu au-dessus du bas de la fenetre, un peu au-dessus du bouton
   pour ouvrir l'interface ticket assistant » (ticket du 9 septembre 2026) :
   c'etait exact, et mesure a cent pixels sur une fenetre de neuf cents. La
   reserve du bouton flottant (voir `.app-main`) restait sur la page, donc
   DEHORS de la boite qui defile : une bande morte au bas de la fenetre, en
   permanence, sur toute la largeur, alors que la liste avait treize mille
   pixels a montrer. La regle jumelle existait deja pour `.panel` et
   `.tab-panel` ; la tuile de liste n'y avait pas ete ajoutee, et c'est tout ce
   qui manquait. Posee ici, la reserve ne coute rien tant qu'on n'est pas au
   bout de la liste.

   Les seize pixels du pied sont ceux du panneau juste au-dessus, et pour la
   meme raison : a zero, la bordure de la tuile se coupe sur le bord de la
   fenetre au lieu de s'y arreter. Les deux regles se lisent ensemble, elles
   changent ensemble.

   ET LE CREUX DU HAUT EST LE MEME QUE LES DEUX AUTRES depuis le suivi du
   9 septembre 2026 (« compacte un peu plus la tuile des filtres avec le
   header »). Une page ordinaire s'ouvre a trente-deux pixels sous l'en-tete,
   et c'est juste : elle commence par un titre, qui a besoin d'air. Celle-ci
   commence par une barre d'outils -- le compte, la recherche, les exports, les
   pastilles de filtre --, qui se lit comme le prolongement de l'en-tete plutot
   que comme le debut d'une page. Trente-deux pixels l'en detachaient deux fois
   plus que les seize qui la separent de la liste, alors qu'elle appartient au
   haut de l'ecran. Les trois creux sont donc egaux : sous l'en-tete, entre les
   deux tuiles, sous la derniere. Et les seize pixels rendus passent a la
   liste, qui les prend comme elle a pris ceux du bas.

   Cette page-la seulement : la regle se ferme sur `> .tuile-liste`, que seule
   la liste des clients porte sous une page tenue a la fenetre. Le reste du
   site garde son ouverture de trente-deux. */
.app-main-pleine:not(.defile-page):has(> .tuile-liste) {
  padding-top: var(--espace-md);
  padding-bottom: var(--espace-md);
}

.app-main-pleine > .tuile-liste {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding-top: 0;
  padding-bottom: calc(52px + var(--espace-xl) * 2);
}

/* Et les titres de colonnes se collent en haut de cet espace.

   `position: sticky` se cale sur le premier ancetre qui defile, et se laisse
   pousser dehors par le bas de son propre tableau : chaque en-tete tient donc
   tant que sa table est a l'ecran et s'en va avec elle. Trois tables qui se
   suivent ne se disputent rien, et aucune ne coiffe la voisine.

   Le trait du bas se refait a l'ombre. `border-collapse: collapse` donne les
   bordures a la table et non aux cellules : une ligne d'en-tete qui se detache
   les laisse derriere elle, et l'en-tete colle flotte alors au-dessus des
   donnees sans rien qui l'en separe. Un `inset` d'un pixel le rend, du meme
   --gray-3 que la regle d'origine -- et le trait de groupe de colonnes avec
   lui, qui se perd de la meme facon. Le fond blanc est ce qui empeche les
   racines de se lire au travers.

   `z-index: 1` place l'en-tete au-dessus des rangees sans le mettre au-dessus
   de tout : le catalogue d'icones d'un cycle est a 20 et s'ouvre donc bien
   par-dessus. */
.app-main-pleine .sources-table thead,
.app-main-pleine .tree-table thead {
  position: sticky;
  top: 0;
  z-index: 1;
}

/* Le trait refait a l'ombre remplace celui de la regle d'origine, il ne s'y
   ajoute pas. Sans cette ligne, les deux coexistent des que l'en-tete n'est
   pas detache -- c'est-a-dire au premier coup d'oeil, avant tout defilement --
   et la rangee de titres se lit soulignee deux fois, a un pixel d'intervalle :
   celui du `border-bottom` de .sources-table th, pose hors de la cellule, et
   celui de l'ombre, pose dedans. Signale le 13 septembre 2026 sur l'onglet
   Comptable d'un mandat, capture a l'appui. */
.app-main-pleine .sources-table thead th,
.app-main-pleine .tree-table thead th {
  background: #fff;
  border-bottom: 0;
  box-shadow: inset 0 -1px 0 var(--gray-3);
}

.app-main-pleine .mapping-table thead th.mapping-groupe-debut {
  box-shadow: inset 1px 0 0 var(--gray-3), inset 0 -1px 0 var(--gray-3);
}

.panel { margin-bottom: var(--espace-2xl); }

/* Les sous-onglets de la Conso restent en tete quand la page defile
   (« les sous-onglets Perimetre etc. doivent rester figes lorsqu'on defile
   vers le bas », ticket du 15 septembre 2026).

   Les huit vues de la Conso se lisent en descendant -- un perimetre de
   quarante entites, des etats consolides, une liste d'ecritures --, et la
   rangee qui dit ou l'on est sortait de l'ecran a la premiere molette : pour
   passer d'une vue a l'autre il fallait remonter tout le tableau.

   `top: 0` et non `--h-entete` comme `.tuile-collante` : ce qui defile ici
   n'est pas la page mais le panneau lui-meme (voir `.app-main-pleine >
   .tab-panel`), et `position: sticky` se mesure depuis le premier ancetre qui
   defile. Accrochee a la hauteur de l'en-tete, la rangee se serait arretee
   soixante pixels trop bas, laissant defiler au-dessus d'elle une bande du
   tableau qu'elle coiffe.

   Opaque, sans quoi les lignes du tableau se liraient au travers ; le creux
   vertical est ce qui empeche une ligne d'affleurer le bord des boutons avant
   de passer dessous. Le z-index est celui des barres collantes du produit : au
   dessus de ce qui defile, sous l'en-tete de l'application, qui est a 20.

   Sur cet onglet seulement : toutes les autres barres du produit gardent leur
   comportement. */
#tab-panel-conso > .panel > .toolbar {
  position: sticky;
  top: 0;
  z-index: 15;
  background: #fff;
  padding-block: var(--espace-sm);
  margin-bottom: 0;
}

/* La tuile : une zone qui porte un nom, dans un cadre a elle.

   Demande du 30 aout 2026 : « il y a certains menus, par exemple le menu
   mandat, ou il y a une telle liste de choses que ca fait un peu brouillon, un
   peu fouillis [...] essaye de faire plus de tuiles possible, plus de
   separation entre les sous-zones [...] pour eviter que ca fasse parfois
   l'effet zone de texte un peu fouillee avec plein de boutons ».

   Ce que la demande decrit se mesure : l'onglet Mandat faisait 3573 px d'une
   seule colonne, vingt-quatre sections au meme rang, et rien entre deux
   voisines qu'un filet d'un pixel. Le filet avait ete pose la le 26 aout,
   contre un blanc qui ne disait rien -- et la regle qui l'installe (plus bas,
   `.reglages-group + .reglages-group`) ecartait explicitement la carte :
   « vingt-trois cartes empilees pesaient plus lourd que le mur qu'elles
   corrigent ». C'etait un arbitrage, il a ete tranche dans l'autre sens par
   celui qui lit la page. Le filet reste, mais d'un cran plus bas : il ne
   separe plus des sections, il separe des rangees a l'interieur d'une tuile.

   Deux niveaux, donc, la ou il n'y en avait qu'un :

     tuile              une zone nommee -- Identite, Marque du client...
       reglages-group   une rangee de reglages, filet entre deux

   Le fond est blanc et non `--gray-1` comme celui de la frise, et les deux ont
   ete regardes cote a cote : le panneau contient des cartes grises (une ligne
   d'intervenant, une ligne d'equipe, un apercu de charte), et une tuile grise
   les avale -- les deux niveaux se remettent a plat, ce que la tuile existe
   justement pour eviter. Sur blanc, la carte grise interieure se lit comme
   contenue. C'est le bord `--gray-3` qui dit la tuile, pas son fond.

   Le creux est celui des cartes de la maison (`--espace-md --espace-lg`), et
   l'ecart entre deux tuiles vaut `--espace-md` : c'est deja la marge basse de
   la frise, qui ouvre la colonne. Une seule cadence du haut en bas de l'onglet.

   Et dans l'app : elle le fait deja. `VueReglagesMandat.swift` rend ce meme
   ecran en un `Form` de onze `Section` -- « Identite », « Classement »,
   « Exercices d'audit », « Equipe », « Intervenants du client », « Presence en
   ligne », « Exercice », « Exporter » --, et une section de `Form` groupe est
   une tuile encartee. Le telephone tuilait cet ecran depuis son ecriture ;
   c'est le navigateur qui avait diverge. */
.tuile {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  padding: var(--espace-md) var(--espace-lg);
}

/* Une cadence unique pour toute la colonne, quel que soit le porteur.

   `.aglae-bloc` n'est pas une zone : c'est le sac ou la macro des champs Aglae
   pose les siennes, et il ne se voit pas. Les quatre selecteurs disent donc la
   meme chose -- deux zones voisines s'ecartent de `--espace-md` -- une fois
   pour deux tuiles du gabarit, une fois pour le sac qui suit une tuile, une
   fois pour la tuile qui suit le sac (la zone dangereuse), une fois pour deux
   tuiles a l'interieur du sac. Sans le troisieme, la zone dangereuse touchait
   la derniere tuile Aglae, bord contre bord.

   `display: contents` sur le sac dirait tout cela en une ligne, mais il en
   ferait un element sans boite : `.declaration-exercice` est un `.aglae-bloc`
   que le JS montre et cache exercice par exercice, et un mode d'affichage
   change sous un element qu'on montre et cache est exactement ce qu'on ne voit
   pas venir. Quatre selecteurs nommes coutent moins cher. */
.tuile + .tuile,
.tuile + .aglae-bloc,
.aglae-bloc + .tuile,
.aglae-bloc > .tuile + .tuile {
  margin-top: var(--espace-md);
}

/* Le meme geste pour un sac que le navigateur remplit.

   Trois zones du Mapping ne sont pas ecrites dans le gabarit : les sections du
   bilan et du compte de resultat, que `mapping-pcg.js` compose modele par
   modele, et la convention de nommage, que `mapping-nommage.js` devoile. Chacune
   est posee dans un conteneur sans cadre -- meme cas que `.aglae-bloc` --, et la
   premiere tuile qu'il porte n'a donc pas de tuile pour voisine : elle a le bord
   du sac, qui ne se voit pas. Sans cette ligne, elle touchait la tuile d'en-tete
   de son onglet.

   Un seul selecteur la ou `.aglae-bloc` en demande quatre : ces trois sacs
   ferment leur onglet, rien ne les suit. */
.tuile + .pile-de-tuiles { margin-top: var(--espace-md); }

/* Et le meme geste pour une liste de cartes, qui est une pile de tuiles sans
   en porter le nom : une `.ticket-card` a deja le cadre de premier rang --
   trait --gray-3, --radius, ombre portee. Une barre de tete en tuile suivie de
   ses cartes, c'est donc deux tuiles l'une sous l'autre, et il leur faut le
   cran qu'elles ont partout ailleurs.

   /tickets tenait cet ecart par la marge basse de `.tuile-collante`, qui ne
   vaut que sur cette page-la ; les deux marges se rabattent l'une sur l'autre
   et rien n'y bouge. La zone Messages n'avait rien : sa barre de tete touchait
   la premiere carte des qu'elle recevait son cadre. */
.tuile + .tickets-list { margin-top: var(--espace-md); }

/* Deux tuiles par rangee tant que la place existe -- « essaye de mieux separer
   les espaces, de creer peut-etre du systeme de tuiles [...] plus de separation
   entre les sous-zones [...] que ca fasse plus moderne, plus type Dashboard »
   (demande du 30 aout 2026).

   Les tuiles disaient deja ou une sous-zone commence et ou elle finit ; ce qui
   manquait etait ailleurs. L'onglet Mandat en aligne seize, toutes larges de
   1336 px, sur 4177 px d'une seule colonne. Une tuile de 1336 px qui porte
   deux champs courts et trois boutons, c'est neuf cents pixels de blanc a
   droite de chaque controle -- l'« effet zone de texte » que la demande nomme,
   et il ne vient pas du cadre qui manque mais de la largeur qui reste. Rangees
   deux par deux, les memes seize tuiles tiennent en 3722 px et se parcourent
   comme un tableau de bord.

   `--largeur-colonne` (440 px, « une page qui ne porte qu'un formulaire ») est
   le barreau qui mesure deja exactement cela : sous cette largeur, une tuile
   ne porte plus une ligne de formulaire. A 1336 px de panneau il donne deux
   colonnes de 660, et une seule des que le panneau passe sous 896 -- la
   feuille mobile n'a donc rien a defaire, la grille s'y replie d'elle-meme.

   Le `min(..., 100%)` n'est pas une precaution : sans lui le plancher de
   `minmax` l'emporte sur la largeur qui reste, et l'unique colonne mesure ses
   440 px sur un ecran qui en fait 390. Constate au telephone -- 64 px de
   debord horizontal sur toute la page. C'est l'idiome que la feuille emploie
   deja pour la meme raison (`minmax(min(300px, 100%), 1fr)`). */

/* `/compte` faisait exception a cette grille tant que son panneau etait
   borne a `--largeur-bloc` : sous 832 px, un plancher de 440 l'aurait replie
   sur une colonne et aurait defait ce qu'il avait gagne. Le plafond est parti
   avec celui de la coquille, le panneau prend la fenetre, et l'exception s'en
   va avec son motif -- la page y range desormais ses huit blocs, comme les
   trois autres.

   `align-items` place une tuile dans sa rangee ; `align-content` place les
   rangees dans la grille. Tant que la grille mesurait sa propre hauteur, le
   second n'avait rien a repartir et son defaut ne se voyait pas. Le jour ou
   elle devient la boite qui defile d'une page tenue par la fenetre, sa hauteur
   est celle de la fenetre : `stretch` -- ce defaut -- etale alors les rangees
   sur toute la place, et les tuiles, calees en haut de la leur, laissent le
   creux entre elles. Mesure sur `/compte` a 2560 : deux rangees de 693 et
   535 px pour des tuiles de 363 et 240, cinq tuiles en tete de page et trois a
   804 px, trois cents pixels de blanc entre les deux. Les rangees gardent donc
   la hauteur de ce qu'elles portent, et la place qui reste reste en bas. */
.grille-de-tuiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--largeur-colonne), 100%), 1fr));
  gap: var(--espace-md);
  align-items: start;
  align-content: start;
}

/* Dans la grille, la cadence est l'ecart de la grille et non la marge -- meme
   argument que `.compte-form`, et les quatre selecteurs qui posent
   `.tuile + .tuile` se neutralisent un a un. */
.grille-de-tuiles > .tuile + .tuile,
.grille-de-tuiles > .tuile + .aglae-bloc,
.grille-de-tuiles > .aglae-bloc + .tuile,
.grille-de-tuiles > .aglae-bloc > .tuile + .tuile { margin-top: 0; }

/* Ce qui ne se met pas en paire, et que seul le gabarit peut dire : une frise
   qui se lit d'un bord a l'autre, une liste dont chaque ligne porte un nom, un
   role et ses controles. Une liste tient la largeur, un formulaire de champs
   courts non. */
.grille-de-tuiles > .pleine-largeur { grid-column: 1 / -1; }

/* Une tuile qui est aussi un panneau rend sa marge basse a la grille. `.panel`
   porte 2rem sous lui : dans une colonne c'est la cadence de la page, dans une
   grille cela s'ajoute a l'ecart et la rangee suivante tombe a 48 px de la
   precedente pendant que les deux tuiles d'une meme rangee sont a 16. Un
   tableau de bord dont les ecarts horizontaux et verticaux ne sont pas les
   memes ne se lit plus comme une grille. */
.grille-de-tuiles > .panel { margin-bottom: 0; }

/* Le sac de champs s'efface pour que ses sept groupes soient des tuiles de la
   grille au meme titre que celles du gabarit. Sans cela ils formeraient une
   grille dans la grille : le sac prendrait une rangee pleine, et la tuile qui
   le precede resterait seule a cote de 660 px de blanc.

   Sur l'identifiant et non sur `.aglae-bloc` : la classe porte aussi
   `.declaration-exercice`, que le JS montre et cache exercice par exercice, et
   un mode d'affichage qui change sous un element qu'on montre et cache est
   exactement ce qu'on ne voit pas venir (c'est l'argument ecrit plus haut, et
   il tient toujours). Celui-ci n'est ni montre ni cache : `dossier-aglae.js`
   ne fait que parcourir les sacs pour cabler leurs champs. */
.grille-de-tuiles > #aglae-mandat { display: contents; }

/* La declaration fait desormais le meme geste : son sac s'efface, et ses
   groupes sont des tuiles de la grille du panneau, a cote de celle des
   honoraires (« en enlevant les espaces vides », demande du 13 septembre
   2026). Le sac portait sa propre grille, sous deux tuiles pleine largeur :
   le choix de la cloture, trois controles sur 2496 px, et les honoraires, une
   liste de noms sur 2496 px elle aussi. 49 % de blanc dans la grille, et deux
   bandes presque vides au-dessus.

   `:not([hidden])` est ce qui rend `display: contents` inoffensif sur ce
   sac-la, que l'argument ecrit plus haut ecartait : le sac passe de `contents`
   a `none` et retour, et ni l'un ni l'autre n'est une boite. Ce qu'on ne
   voyait pas venir, c'etait une boite qui reapparait ; il n'y en a plus
   aucune. */
.grille-de-tuiles > .declaration-exercice:not([hidden]) { display: contents; }

/* Une grille tassee (grille-tassee.js) : des rangees au pas de
   `--pas-tassement`, et plus d'ecart entre elles, puisque c'est le script qui
   laisse l'ecart sous chaque tuile en le comptant dans les rangees qu'elle
   prend. La classe ne se pose que sur une grille d'au moins deux colonnes :
   sur une seule, les rangees ordinaires font deja une pile sans trou. */
.grille-de-tuiles.est-tassee {
  grid-auto-rows: var(--pas-tassement);
  row-gap: 0;
}

/* La frise du mandat garde sa marge basse hors d'une grille ; dans une
   grille, l'ecart des tuiles la separe deja, et les deux s'ajoutaient :
   34 px sous la frise, 17 entre deux tuiles. */
.grille-de-tuiles > .frise-mandat { margin-bottom: 0; }

/* Le nom de la tuile. Plus grand et plus noir que l'intitule d'une rangee
   (`.toolbar-label`, petites capitales grises) : c'est ce qui doit se lire en
   parcourant la colonne du regard sans s'arreter, et deux titres de meme
   graisse a deux rangs differents ne se distinguent pas.

   `display: block` parce que ce titre est tantot un `<h3>` (les tuiles ecrites
   dans le gabarit), tantot un `<span>` (celles que la macro des champs Aglae
   pose, ou l'intitule porte parfois une explication au survol) : une marge sur
   une boite en ligne ne fait rien. */
.tuile-titre {
  display: block;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--black);
  margin: 0 0 var(--espace-md);
}

/* La marque du cabinet au fil d'un nom de tuile -- « Commissaires aux
   comptes ». Meme regle que sur un intitule de rangee, plus bas dans la
   feuille : c'est la meme marque au fil du meme genre de titre, et deux
   ecritures pour un seul geste finissent par diverger d'un pixel. */
.tuile-titre.toolbar-label-marque {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

/* Le titre pose dans une barre d'outils -- les douze du Mapping, ou le nom de
   la zone est a gauche et ses commandes a droite. La barre pose deja son propre
   ecart avec ce qu'elle coiffe (`.toolbar`, --espace-sm) ; la marge basse du
   titre, elle, entre dans la hauteur de la rangee, et l'ancre `center` de la
   barre descendait alors les commandes d'en face de la moitie de cette marge.
   Le titre rend donc sa marge des qu'une barre le tient. */
.toolbar-group > .tuile-titre { margin-bottom: 0; }

/* Le creux bas d'une tuile est celui de la tuile : aucun enfant ne l'allonge.
   Une marge basse posee sous le dernier enfant s'ajoute au creux au lieu de s'y
   fondre -- un creux n'est pas une marge, les deux ne se recouvrent pas --, et
   la tuile devient plus profonde en bas qu'en haut.

   La regle avait ete ecrite trois fois : pour la derniere rangee de reglages
   (16 px de creux plus 12,8), pour un paragraphe `.disclaimer` (16 plus 9,6),
   pour le resume de l'assistant. La quatrieme, trouvee le 30 aout 2026, etait
   le pied du registre des arbitrages du Mapping (16 plus 16). Trois exemples
   d'une meme regle sont une regle, et c'est elle qui est ecrite ici.

   Rien ne se perd a la generaliser : sous le dernier enfant d'une boite a
   creux, une marge basse ne peut, par construction, que doubler ce creux.

   Elle ne peut pas tout, en revanche. Une regle de page de meme specificite
   ecrite plus bas dans la feuille l'emporte sur elle, et une marge qui remonte
   d'un enfant par effondrement lui echappe : les deux cas se corrigent la ou
   la marge est ecrite, cf. `.compte-form .input-icon-group` et la derniere
   carte de `table.m-cards`.

   « Dernier » veut dire dernier visible. Une tuile finit souvent par une zone
   que le script devoile -- un formulaire, un message d'erreur, une liste vide
   --, et tant qu'elle est `hidden` c'est celle d'avant qui touche le fond de
   la tuile sans etre la derniere au sens de CSS : la barre de commandes des
   Clients rendait 25,6 px de creux en bas pour 16 en haut, a cause des deux
   zones repliees qui la suivaient. Le second selecteur se lit « un enfant
   visible qu'aucun enfant visible ne suit », et il se refait tout seul quand
   le script ouvre ou ferme l'une d'elles. */
.tuile > :last-child,
.tuile > :not([hidden]):not(:has(~ :not([hidden]))) { margin-bottom: 0; }

/* Et au-dessus du premier enfant, symetriquement. Une marge haute s'ajoute au
   creux au lieu de s'y fondre, pour la meme raison que celle du dessous : un
   creux n'est pas une marge, les deux ne se recouvrent pas.

   Elle etait ecrite ici pour un seul cas -- `.reglages-hint:only-child`, qui
   s'ecarte d'ordinaire d'un cran parce qu'elle suit un champ, et qui ne suit
   rien quand elle est seule : la tuile se lisait de travers, 20 px de creux en
   haut pour 16 en bas.

   Le meme defaut, en bien plus grand, sur les seize sections d'Assistance et de
   Confidentialite (31 aout 2026) : leur titre est un titre de document
   (`.doc-wrap h2`) et porte --espace-2xl au-dessus de lui pour ecarter deux
   sections d'un texte qui coule. Ces sections sont devenues des tuiles, et
   c'est le cadre qui les separe desormais ; l'air d'avant est reste. Les deux
   se cumulaient : 49 px de creux en haut pour 17 en bas, sur des pages qui ne
   sont faites que de cela.

   Rien ne se perd a generaliser, comme pour la marge basse : au-dessus du
   premier enfant d'une boite a creux, une marge haute ne peut, par
   construction, que doubler ce creux. Verifie le 31 aout 2026 sur les dix-sept
   surfaces du produit -- aucune tuile n'ouvre sur une marge haute negative,
   qui serait la seule a y perdre quelque chose. */
.tuile > :first-child { margin-top: 0; }

/* Le glisser-deposer ne retaille pas la tuile. `.depot-cible.dragover` arrondit
   a `--radius-sm` ce qu'il souligne, parce qu'il se pose d'ordinaire sur une
   zone qui n'a pas d'arrondi a elle. Une tuile en a un : « Papier a en-tete du
   client » est devenue une tuile le 30 aout 2026, et son coin serait passe de
   10 a 7 pendant qu'on tient un fichier au-dessus -- un tressaut, la ou le
   trait en pointille doit etre le seul changement visible. */
.tuile.depot-cible.dragover { border-radius: var(--radius); }

/* L'encart : une sous-zone a l'interieur d'une tuile.

   Une tuile nomme une zone. Ce qu'elle contient n'est pas toujours une suite
   de rangees : /cabinet y range des lignes qui sont chacune un formulaire a
   deux etages -- une ligne de cases, puis un repli separe par un filet. Ces
   lignes ont besoin d'un cadre a elles, sinon leur filet interieur et le filet
   qui les separerait de la voisine auraient le meme poids, et la colonne
   deviendrait une echelle de traits sans hierarchie.

   D'ou deux rangs de cadre, et ils se distinguent par leur dessin : la tuile
   prend `--radius` et `--gray-3`, l'encart le barreau en dessous -- 7 px et
   `--gray-2`. Le fond reste blanc des deux cotes : `--gray-1` ferait
   disparaitre les mentions que porte une carte de collaborateur, qui sont
   elles-memes des pastilles `--gray-1`.

   Ce que l'encart ne dit pas, c'est la densite. La ligne d'un cabinet et la
   carte d'un collaborateur ont ete reglees separement et en sens contraire --
   « reduis la hauteur des lignes de gestion de cabinet et gestion de l'equipe »
   les 25 et 26 aout 2026, puis « collaborateur mieux developpe » le 27, qui a
   rouvert la seconde. Un cadre commun qui imposerait un rembourrage commun
   defferait l'un des deux arbitrages sans le dire. L'encart est donc une
   forme, pas une mesure : chaque porteur garde son creux. */
.tuile-encart {
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* Ce qui suit autre chose dans une tuile s'en ecarte d'un cran.

   Un seul selecteur, et volontairement pas de `.tuile-encart +
   .tuile-encart` : les encarts empiles le sont a l'interieur d'un conteneur
   souple qui porte deja son `gap` (`.cabinet-gestion-list`), et une marge
   ajoutee a un `gap` ne s'y annule pas comme deux marges voisines -- elle s'y
   ajoute. La regle ne vise donc que l'encart pose directement dans la tuile,
   apres la liste : la ligne d'ajout d'un cabinet, celle d'invitation d'un
   collaborateur. */
.tuile > * + .tuile-encart {
  margin-top: var(--espace-sm);
}

/* La suppression du mandat, dans sa tuile a elle. Elle avait deja son signe
   propre avant les tuiles -- un filet plus haut et plus d'air que les autres,
   parce que c'est une coupure plus forte. Une tuile bordee de rouge pale dit
   la meme chose et le dit mieux : le geste est enferme, il ne borde plus le
   reglage d'a cote.

   `--red-pale` en fond et `--red` en bord auraient fait une alerte ; ce n'en
   est pas une, rien n'est en faute tant qu'on n'a pas clique. Le fond reste
   donc blanc comme celui des autres tuiles, et seul le bord change de teinte
   -- assez pour qu'on ne s'y trompe pas en parcourant la colonne, pas assez
   pour appeler le regard depuis le haut de la page. */
.tuile-danger {
  border-color: var(--red);
}

.tuile-danger .tuile-titre { color: var(--red-dark); }

/* Quatre bandeaux se suivent avant la premiere ligne de contenu : les onglets,
   la barre d'outils, le fil d'Ariane, l'en-tete du tableau. Ils prenaient 178
   px a eux quatre -- presque sept lignes de fichier, dans une liste dont les
   lignes ne font que 27 px -- et l'ecran ouvrait donc sur son propre chassis.
   Chacun a ete resserre a la hauteur qu'il lui faut pour se lire (demande du
   14 aout 2026) ; aucun n'a perdu sa taille de texte, seulement l'air autour. */
/* La rangee defile chez elle au lieu de pousser la page.

   Neuf onglets font 985 px de large. L'acceptation les posait dans une page
   bornee a 1040 px, soit 976 px de contenu -- plafond tombe depuis, la page
   prend la fenetre : la frise n'y tenait a aucune largeur, et c'est son dernier item qui debordait --
   « Acceptation », celui qui dit ou l'on est, et dont le gabarit ecrit qu'il
   est la « sans quoi la frise dirait ou aller sans dire d'ou l'on vient ».
   Il etait hors de vue a sept largeurs sur huit, 1440 px comprise. A 900 px,
   la rangee poussait en plus le document de 117 px : la page entiere partait
   de travers, et l'onglet ouvert etait celui qu'on ne voyait pas.

   `overflow-x: auto` est ce que le produit fait deja partout ailleurs pour une
   rangee horizontale -- la barre d'outils, les cycles, la piste des exercices,
   et cette meme barre sous 820 px, ou le commentaire de mobile.css appelle
   cette ligne « la piece qui manquait ». Elle manquait des deux cotes.

   Le filet passe de `border-bottom` a une ombre interne pour une raison
   precise : une bordure se peint hors de la boite a defilement, si bien que le
   soulignement de l'onglet actif ne pouvait plus la recouvrir sans deborder
   verticalement -- et l'onglet cessait alors de se raccorder a son panneau.
   Peint dans la boite, le filet ne defile pas avec la rangee et se laisse
   recouvrir par les 2 px de l'onglet actif, exactement comme avant : la barre
   garde ses 36,4 px et son dessin, elle ne change que de comportement.

   Amener l'onglet actif dans la vue est l'autre moitie du geste, et elle est
   dans `onglets-cales.js`. */
.dossier-tabs {
  display: flex;
  gap: var(--espace-xs);
  margin-bottom: var(--espace-md);
  overflow-x: auto;
  box-shadow: inset 0 -1px 0 var(--gray-3);
  scrollbar-width: none;
}

.dossier-tabs::-webkit-scrollbar { display: none; }

.dossier-tab-btn {
  border: none;
  background: none;
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 600;
  /* .45rem plutot que .7rem : l'onglet reste plus haut que son texte et garde
     une cible de clic confortable, sans faire de la rangee d'onglets le plus
     grand objet de la page. */
  padding: var(--espace-xs) var(--espace-lg);
  cursor: pointer;
  color: var(--gray-5);
  border-bottom: 2px solid transparent;
  /* Le `margin-bottom: -1px` qui tirait l'onglet sur la bordure de la rangee
     n'a plus lieu d'etre : le filet est maintenant peint dans la boite (voir
     ci-dessus), et le soulignement le recouvre sans avoir a en sortir. */
  transition: color .15s var(--ease), border-color .15s var(--ease);
}

.dossier-tab-btn:hover { color: var(--gray-6); }

.dossier-tab-btn.active {
  color: var(--cyan-dark);
  border-bottom-color: var(--cyan-dark);
}

/* Le temple barre porte par l'onglet Juridique : cale sur la ligne de base du
   libelle, a la distance du point de statut de l'onglet Source. */
.dossier-tab-juridique-vide {
  margin-left: var(--espace-xs);
  vertical-align: middle;
}

.dossier-tab-statut-dot {
  display: inline-block;
  width: .45rem;
  height: .45rem;
  border-radius: 999px;
  margin-left: var(--espace-xs);
  vertical-align: middle;
}

.dossier-tab-statut-dot-traite { background: var(--green); }
.dossier-tab-statut-dot-erreur { background: var(--red); }
.dossier-tab-statut-dot-en_attente { background: var(--cyan); }

.dossier-tab-btn.dossier-tab-btn-statut-traite.active { color: var(--green); border-bottom-color: var(--green); }
.dossier-tab-btn.dossier-tab-btn-statut-erreur.active { color: var(--red); border-bottom-color: var(--red); }
.dossier-tab-btn.dossier-tab-btn-statut-en_attente.active { color: var(--cyan-dark); border-bottom-color: var(--cyan-dark); }

/* La pastille de l'onglet Assistant : combien de constats, et de quelle nature
   est le plus grave d'entre eux. Un nombre plutot qu'un point -- « il y a
   quelque chose » n'engage a rien, « il y en a onze » se decide d'un coup
   d'oeil --, et la teinte dit lequel des trois registres domine.

   Aucune couleur nouvelle : les trois teintes sont celles que la palette
   emploie deja pour dire la meme chose ailleurs (le rouge d'une erreur,
   l'orange d'une echeance, le gris d'une mention). */
.dossier-tab-pastille {
  display: inline-block;
  min-width: 1.15rem;
  padding: 0 var(--espace-2xs);
  margin-left: var(--espace-xs);
  border-radius: 999px;
  font-size: var(--fs-2xs);
  font-weight: 700;
  line-height: 1.15rem;
  text-align: center;
  vertical-align: middle;
  color: var(--gray-5);
  background: var(--gray-2);
}

.dossier-tab-pastille[data-gravite="incoherence"] { color: var(--red); background: var(--red-pale); }
.dossier-tab-pastille[data-gravite="manque"] { color: var(--orange); background: var(--orange-pale); }

/* La seconde pastille de l'onglet Assistant : les publications non lues
   (demande du 30 août 2026). Elle porte une autre couleur que la première, et
   ce n'est pas un ornement : les deux nombres ne répondent pas à la même
   question. Le gris et l'orange de l'autre disent une gravité, qui ne baisse
   qu'en corrigeant le mandat ; le bleu dit « il y a du nouveau à lire », ce qui
   se solde en ouvrant. Deux pastilles de la même couleur côte à côte se
   liraient comme un seul compteur coupé en deux. */
.dossier-tab-pastille-veille {
  margin-left: var(--espace-2xs);
  color: var(--blue);
  background: var(--blue-pale);
}

.tab-panel[hidden] { display: none; }

/* Les onglets de la zone Messages sont des liens, pas des boutons : le fil
   choisi voyage dans l'URL, pour qu'il se partage et qu'un formulaire poste
   revienne au bon endroit. Il leur manque donc ce qu'un bouton a d'office. */
a.dossier-tab-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  text-decoration: none;
}

/* Le nombre de messages recus, dans l'onglet qui les porte. Discret : c'est
   un reperage, pas une alerte -- la pastille bleue de l'en-tete dit deja
   combien ne sont pas lus. */
.dossier-tab-compte {
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--gray-5);
  background: var(--gray-1);
  border-radius: 999px;
  padding: var(--espace-3xs) var(--espace-xs);
}

.drop-zone {
  border: 2px dashed var(--gray-3);
  border-radius: var(--radius);
  background: var(--cyan-pale);
  padding: 3rem var(--espace-2xl);
  text-align: center;
  cursor: pointer;
  transition: all .2s var(--ease);
}

.drop-zone:hover, .drop-zone.dragover {
  border-color: var(--cyan);
  background: var(--cyan-light);
}

/* Hors echelle, et volontairement : ce n'est plus une icone de commande mais
   l'illustration de la zone de depot, comme la pastille ronde de connexion.

   `display: block` n'est pas une preference de mise en page, c'est ce qui rend
   la marge d'en dessous egale a ce qui est ecrit. Un `<svg>` est en ligne par
   defaut : il se pose sur une ligne de texte, son bas s'aligne sur la ligne
   d'ecriture, et le jambage de la fonte continue en dessous de lui. Les 12,8
   demandes ici s'affichaient donc 18,8 -- six pixels que personne n'avait
   choisis, sur aucun barreau, entre --espace-md et --espace-lg. Mesure sur les
   trois onglets qui portent une zone de depot, le 30 aout 2026.

   Sortie de la ligne, l'icone ne recevrait plus le `text-align: center` de la
   zone : c'est `margin-inline: auto` qui la recentre, et le releve la retrouve
   au pixel sur l'axe. */
.drop-zone-icon {
  display: block;
  width: 34px;
  height: 34px;
  color: var(--cyan-dark);
  margin-inline: auto;
  margin-bottom: var(--espace);
  stroke-width: 1.5;
}

.drop-zone-title {
  font-family: var(--sans);
  font-size: var(--fs-h3);
  font-weight: 600;
  margin: 0 0 var(--espace-xs);
  color: var(--black);
}

.drop-zone-sub {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  margin: 0;
}

.file-list {
  list-style: none;
  padding: 0;
  margin: var(--espace-md) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
}

.file-list li {
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--espace-sm);
  font-size: var(--fs-sm);
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

.file-list .icon { color: var(--gray-4); }

.file-list .file-remove {
  cursor: pointer;
  color: var(--gray-5);
  font-weight: 700;
}

.upload-status {
  margin-top: var(--espace-md);
  font-size: var(--fs);
}

.upload-status.error { color: var(--red); }
.upload-status.loading { color: var(--gray-5); }
.upload-status.success { color: var(--green); }

/* Vides, ces deux-la ne montrent rien et poussent quand meme : chacune porte
   16 px de marge haute, qui se rejoignent en une bande blanche de 16 px sous
   la zone de depot de la Source -- mesuree au navigateur le 30 aout 2026, et
   demandee par personne. Meme geste que `.fil-ariane:empty`, quelques regles
   plus bas. */
.file-list:empty,
.upload-status:empty { display: none; }

.progress-container {
  position: relative;
  margin-top: var(--espace-sm);
  height: 4px;
  background: var(--gray-2);
  border-radius: 999px;
  overflow: hidden;
}

.progress-bar {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 0%;
  background: var(--cyan);
  border-radius: 999px;
  transition: width .2s ease;
}

.progress-bar.indeterminate {
  width: 30%;
  transition: none;
  animation: progress-indeterminate 1.1s ease-in-out infinite;
}

@keyframes progress-indeterminate {
  0% { left: -30%; }
  100% { left: 100%; }
}

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--espace-sm);
  flex-wrap: wrap;
  gap: var(--espace-md);
}

/* La barre reste en tete quand la liste defile (demande du 24 aout 2026,
   /tickets et /tickets/archives). L'en-tete de l'application est deja
   `sticky` avec `top: 0` et un z-index de 20 : on l'accroche juste dessous,
   au-dessus des cartes qui defilent -- sans quoi une carte peut la traverser
   par le haut, et le filtre devient illisible. Elle est opaque : les cartes
   passent dessous et non a travers.

   Elle etait, jusqu'au 30 aout 2026, une bande grise qui sortait de la
   gouttiere pour aller d'un bord a l'autre de la vue. C'etait la seule zone
   du produit dessinee ainsi, et la page s'ouvrait donc sur un fond que rien
   d'autre ne reprenait. C'est maintenant une tuile comme celles des autres
   pages : la classe ne porte plus que l'accrochage, le cadre vient de
   `.tuile`, et le creux vient des memes jetons que partout ailleurs.

   Reserve aux pages qui la posent sur la tuile de tete : toutes les autres
   barres du produit gardent leur comportement. */
.tuile-collante {
  position: sticky;
  /* Juste sous l'en-tete, au pixel : un cran plus bas laisse un liseré
     transparent par ou un fragment de carte passe, un cran plus haut engage la
     barre sous l'en-tete flou. Le nombre n'est plus recopie a la main, il se
     deduit de ce qui fait la hauteur de l'en-tete -- voir --h-entete. */
  top: var(--h-entete);
  z-index: 15;
  /* Ce qui la suit n'est pas une tuile mais la liste des cartes : le cran qui
     separe deux tuiles ne peut donc pas venir de `.tuile + .tuile`. */
  margin-bottom: var(--espace-md);
}

/* La hauteur d'une barre d'outils est celle de ce qu'on y pose : un bouton et,
   sur certaines pages, un champ de recherche. Les deux sont resserres ensemble
   et de la meme quantite, sans quoi la barre se remettrait a la hauteur du plus
   grand des deux et le resserrement ne se verrait nulle part. Ici seulement :
   le meme bouton dans l'en-tete de page garde sa taille, c'est la premiere
   ligne de l'ecran et elle n'etait pas en cause. */
/* Les deux resserrements descendent ensemble d'un dixieme de barreau, comme le
   veut la note ci-dessus : 4 px au lieu de 4,8. Le bouton ne bouge pas -- il
   est deja au plancher de --h-sm --, le champ passe de 30,59 a 29,79, et la
   rangee resserre de deux virgule six pixels d'ecart a moins d'un. */
.toolbar .toolbar-search { padding: var(--espace-2xs) var(--espace); }

.toolbar-group {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

.toolbar-group[hidden] {
  display: none;
}

/* La barre de l'analyse d'un mandat : « ces nouveaux menus changent de place,
   il faudrait qu'ils soient alignes (au niveau du bouton) sur les autres
   boutons deja existants » (suivi du 2 septembre 2026). Deux deplacements, et
   deux causes distinctes -- mesurees au navigateur en passant d'une vue a
   l'autre.

   **En hauteur**, neuf pixels. Les deux blocs de comptes annuels sont les
   seuls groupes coiffes d'un nom, donc les seuls plus hauts que les autres ;
   centres comme le reste de la barre, leur rangee de boutons tombait sous
   celle de Cycles / Balances / Outils. Les groupes se rangent donc par le bas :
   toutes les rangees de boutons retombent sur la meme ligne, et le nom prend
   sa place au-dessus, en poussant la tuile et non ses propres boutons.

   **En largeur**, cinq pixels. `space-between` va bien a une barre dont le
   contenu ne bouge pas ; celle-ci voit la moitie de ses groupes paraitre et
   disparaitre avec la vue, et l'espace libre etant reparti entre tous, le
   moindre groupe qui parait le reprend a chacun. Les groupes se serrent donc a
   gauche, a ecart fixe, et l'espace libre est pris tout entier devant le
   selecteur d'unite : la fin de la barre reste a droite comme avant, et le
   debut ne bouge plus d'une vue a l'autre. */
.toolbar-analyse {
  justify-content: flex-start;
  align-items: flex-end;
}

.toolbar-analyse .toolbar-group-unite {
  margin-left: auto;
}

/* LA DATE D'ARRÊT DES TROIS LECTURES DE L'ANALYSE.

   « Ajoute un sélecteur de date discret, par exemple un curseur accompagné
   d'un champ date, permettant de modifier la date de fin de période affichée,
   sans changer la présentation existante » (ticket du 13 septembre 2026), puis
   « sors cette barre de la barre de filtre classique mais met la au dessus hors
   de la tuile crée un nouveau bouton qui montre que c'es un choix d'ordre
   supérieur » (suivi du 14 septembre 2026).

   Discret, elle l'était au point de passer pour un filtre de plus : sixième
   groupe d'une barre qui en porte six, mêmes gris, même hauteur. Or les cinq
   autres choisissent ce qu'on regarde des mêmes chiffres -- une vue, une unité,
   un sens, des exercices, un plein écran --, celle-ci choisit LES CHIFFRES.
   Elle passe donc au-dessus de la tuile, libre comme la barre des cycles l'est
   devenue le 9 septembre 2026, et le rang se voit à trois choses :

   - elle est seule sur sa ligne, hors du cadre blanc ;
   - son bouton de portée est un rond complet quand ceux de la tuile sont des
     segments a angles courts, et il porte une icône quand aucun d'eux n'en
     porte ;
   - le cyan y prend le fond dès que la date s'écarte de la clôture, la où le
     même écart ne teintait qu'un mot.

   Le champ de date est celui de tout le site : `selecteur-date.js` l'habille
   au chargement comme les autres, il n'a donc rien à recevoir ici qu'une
   largeur -- une date française tient en dix caractères. */
.analyse-portee {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  /* Le cran qui la sépare de la tuile, et le seul : c'est la tuile qui porte
     l'écart avec ce qui la suit. */
  margin-bottom: var(--espace-sm);
}

.analyse-portee[hidden] { display: none; }

/* LA BANDE PORTE LE SÉLECTEUR DE LECTURE, PAS LA DATE (suivi du 15 septembre
   2026 : « remets la date d'arrêt là où elle était, c'est le sélecteur [...]
   qui doit être séparé »).

   Le groupe qu'il contenait posait une largeur minimale pour que la barre ne se
   réorganise pas à chaque changement de vue ; hors de la barre, il n'a plus
   personne à ne pas bousculer. */
.analyse-portee-vues { min-width: 0; }

/* ET LE RANG SE VOIT, PAS SEULEMENT LA PLACE : « change le style pour montrer
   que c'est un échelon supérieur » (suivi du 15 septembre 2026).

   Sortir le sélecteur de la tuile ne suffisait pas. Il en gardait le dessin --
   même piste grise, même petite encre, même hauteur que les segments restés
   dedans --, et l'oeil range par le dessin avant de ranger par la place : posé
   trente pixels au-dessus de « Sens naturel », de « €/K€ » et des exercices,
   il se lisait comme le premier d'entre eux, une rangée de filtres montée d'un
   cran. Or il ne filtre rien : il choisit le DOCUMENT que la tuile règle
   ensuite.

   Trois écarts le disent, et aucun n'est un jeton nouveau -- chacun est le
   barreau voisin de celui des segments de la tuile :

   - LA PISTE TOMBE. C'est la marque la plus nette, parce que c'est elle qui
     fait le segment : ce qui est enfermé dans une gouttière grise est un choix
     parmi des réglages, ce qui pose ses pastilles à même la page est au-dessus
     d'eux. Les toggles de la tuile gardent la leur, et la différence se lit
     sans qu'on ait à comparer.
   - L'ENCRE MONTE d'un barreau (--fs-xs vers --fs-sm) et passe en demi-gras.
     Un niveau au-dessus se lit plus gros que celui qu'il commande, et reste
     sous les onglets du mandat, qui tiennent le --fs-md.
   - LA HAUTEUR MONTE aussi d'un barreau, --h-sm vers --h-champ, et la pastille
     active devient un rond complet. `999px` et non un arrondi intermédiaire :
     c'est la règle de la feuille pour ce qui doit être entièrement rond, et
     c'est ce qui achève de séparer ces pastilles des segments à angles courts
     restés dans le cadre.

   Le cyan de l'onglet actif ne bouge pas : c'est la couleur de « ce que vous
   regardez » dans tout le produit, et la changer ici ferait croire à un autre
   objet. Ce qui change est tout ce qui l'entoure. */
.analyse-portee-vues .unit-toggle {
  gap: var(--espace-2xs);
  min-height: var(--h-champ);
  padding: 0;
  background: none;
  border-radius: 999px;
}

.analyse-portee-vues .unit-btn {
  border-radius: 999px;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: var(--espace-xs) var(--espace-md);
}

/* Le survol prend un fond et non plus la seule encre : sans piste derrière
   eux, les boutons inactifs n'ont plus aucune surface, et un simple
   assombrissement du texte ne dit pas où finit la cible. La pastille grise est
   celle que la piste portait -- la teinte n'est pas perdue, elle a changé de
   rôle. */
.analyse-portee-vues .unit-btn:not(.active):hover {
  background: var(--gray-2);
  color: var(--gray-6);
}

/* LE BOUTON DE PORTÉE A ÉTÉ RETIRÉ LE 15 SEPTEMBRE 2026, avec la rangée qu'il
   ouvrait. « Remets la date d'arrêt là où elle était : c'est le sélecteur [...]
   qui doit être séparé » -- la date est redescendue dans la barre, où le champ
   s'ouvre d'un clic comme partout ailleurs, et le sélecteur de lecture a pris
   la bande. Il ne restait de ce bouton qu'un dessin que plus aucun élément ne
   portait.

   L'écart à la clôture, lui, se marque toujours : c'est l'étiquette du groupe
   qui prend le cyan, quelques règles plus bas. */

/* L'ÉCART À LA CLÔTURE, la seule chose qui mérite d'être vue ici. Un groupe de
   barre n'a pas de pastille à teindre : c'est son étiquette qui prend le cyan,
   et c'est assez -- « Arrêté au » se lit déjà autrement que « Arrêté à la
   clôture du », et la couleur ne fait que le confirmer du coin de l'oeil. */
#arret-date-group.est-arrete .toolbar-label {
  color: var(--cyan-dark);
  font-weight: 700;
}

/* Le champ et le cadre qui le recouvre font la même largeur : le sélecteur
   maison pose son glyphe au bord du conteneur, et un conteneur plus large que
   le champ le laisserait hors du cadre. */
#arret-date-group .date-champ,
#arret-date-group input[type="date"] { width: 8.5rem; }

/* Le curseur : la piste et le pouce du produit, écrits pseudo-élément par
   pseudo-élément comme `.year-range-slider`, qui en est le modèle. Un
   `input[type="range"]` laissé nu prend le dessin du système et change d'une
   machine à l'autre.

   `.curseur` est le dessin, `.arret-curseur` n'est plus que sa largeur dans la
   barre de l'arrêté. La séparation date du 17 septembre 2026, quand « Mon
   compte » a reçu le sien pour régler la taille de la signature : recopier
   quatre pseudo-éléments pour un second curseur, c'était écrire deux fois le
   même dessin et le corriger une fois sur deux le jour où il bougerait. */
.curseur {
  height: 22px;
  margin: 0;
  padding: 0;
  background: none;
  appearance: none;
  cursor: pointer;
}

.arret-curseur { width: 7rem; }

.curseur::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--gray-3);
  border-radius: 999px;
}

.curseur::-moz-range-track {
  height: 4px;
  background: var(--gray-3);
  border: none;
  border-radius: 999px;
}

.curseur::-webkit-slider-thumb {
  appearance: none;
  width: 15px;
  height: 15px;
  margin-top: -5.5px;
  border: 2px solid #fff;
  border-radius: 999px;
  background: var(--cyan);
  box-shadow: 0 0 0 1px var(--cyan);
  cursor: pointer;
}

.curseur::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border: 2px solid #fff;
  border-radius: 999px;
  background: var(--cyan);
  box-shadow: 0 0 0 1px var(--cyan);
  cursor: pointer;
}

/* Un trait entre les zones d'une barre d'outils.

   Le gabarit de l'analyse d'un mandat le disait deja de sa propre barre :
   « quatorze commandes en six groupes, posees a nu, se lisaient comme une
   seule rangee de boutons sans debut ni fin ». La tuile lui a donne un
   dehors, jamais un dedans, et la barre de la liste des mandats aligne,
   elle aussi, quatorze commandes que rien ne separait entre elles.

   Le trait ne se pose que sur les barres qui portent un champ de recherche
   (`/dossiers`, `/tickets`, `/tickets/archives`). La raison est mesurable :
   la recherche est elastique, elle absorbe toute la place libre, donc
   `space-between` n'a plus rien a distribuer et l'ecart entre deux groupes
   vaut partout `--espace-md`. Le trait tient au milieu de cet ecart, a huit
   pixels d'encre de chaque cote. Sur les barres sans recherche, le meme
   `space-between` laisse de soixante a neuf cents pixels entre deux groupes :
   un trait y flotterait, rattache a rien.

   Un pseudo-element plutot qu'un `border-left` : il ne prend pas de place,
   donc il ne decale aucun groupe, et il suit `.toolbar-group[hidden]` sans
   qu'on ait a y penser, la moitie de ces groupes s'affichent et se cachent
   au fil des filtres. */
.toolbar:has(.toolbar-search-group) > .toolbar-group + .toolbar-group {
  position: relative;
}

.toolbar:has(.toolbar-search-group) > .toolbar-group + .toolbar-group::before {
  content: "";
  position: absolute;
  left: calc(var(--espace-md) / -2);
  top: 50%;
  margin-top: calc(var(--h-sm) / -2);
  width: 1px;
  height: var(--h-sm);
  background: var(--gray-3);
}

/* L'anneau de selection d'un rond de filtre deborde de quatre pixels hors de
   sa boite (`box-shadow`, invisible a la mise en page). Sans ce retrait, le
   trait qui precede les ronds tombait a quatre pixels de l'anneau la ou tous
   les autres sont a huit. `--tuile-anneau` est declare sur `.filtre-tuiles`,
   avec la raison de son existence. */
.toolbar .filtre-tuiles {
  padding-left: var(--tuile-anneau);
}

.toolbar-label,
.ronde-sous-titre {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  color: var(--gray-5);
}

.toolbar-count {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.toolbar-search-group { flex: 1; min-width: 200px; }

.toolbar-search {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  max-width: 320px;
  padding: var(--espace-sm) var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.toolbar-search:focus-within {
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.toolbar-search .icon {
  color: var(--gray-5);
  flex-shrink: 0;
}

.toolbar-search input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font-family: var(--sans);
  font-size: var(--fs-md);
}

.toolbar-search-clear {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--gray-5);
  cursor: pointer;
}

.toolbar-search-clear:hover { color: var(--gray-6); }
.toolbar-search-clear[hidden] { display: none; }

/* Une gouttiere teintee ou glisse une pastille, et non plus un cadre blanc
   cloisonne : « ce panneau n'est pas esthetique, il faut que tu le rendes plus
   moderne » (ticket du 13 septembre 2026, capture du segment des tickets).

   Ce qui datait tenait a trois choses, et elles allaient ensemble : les
   boutons etaient blancs sur fond blanc, donc seul un trait gris disait ou
   commencait la bande ; l'onglet actif etait un pave cyan colle aux bords,
   avec deux angles droits au milieu du rang des que ce n'etait ni le premier
   ni le dernier ; et rien ne bougeait au survol. C'est le dessin d'un groupe
   de boutons, pas d'un segment.

   Le dessin retenu est celui que la bascule de la fenetre de ticket portait
   deja (`.ticket-widget-bascule`, 7 septembre 2026) et que l'app rend
   nativement sur le meme filtre (`Picker` en `.segmented`, VueTickets) : un
   fond `--gray-2` qui dessine la piste, un remplissage et une gouttiere de
   `--espace-3xs`, et l'onglet actif en pastille detachee des bords. Trois
   surfaces pour un seul objet, desormais du meme cote.

   Le rognage vient de la bordure arrondie : sans lui, les angles droits du
   premier et du dernier bouton depassent de la pastille. Mais `overflow:
   hidden` rognait aussi ce qui ne tenait pas en largeur, sans rien pour aller
   le chercher -- et la bande a grossi (« Compte de resultat » le 25 aout 2026,
   « Annexe » le 26). A 390 px, elle demandait 415 px pour 360 disponibles :
   « Bilan fonctionnel » etait coupe en plein mot et injoignable.

   `overflow-x: auto` rend la fin atteignable et garde le rognage des angles --
   toute valeur autre que `visible` l'obtient. La barre de defilement reste
   cachee : dans une pastille de 30 px elle la deforme, et aux largeurs ou la
   bande deborde le geste est tactile. */
.unit-toggle {
  display: inline-flex;
  gap: var(--espace-3xs);
  min-height: var(--h-sm);
  padding: var(--espace-3xs);
  background: var(--gray-2);
  border-radius: var(--radius);
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}

.unit-toggle::-webkit-scrollbar { display: none; }

/* `white-space: nowrap` parce qu'un onglet est une etiquette, pas un
   paragraphe : sans lui, « Compte de resultat » se cassait en trois lignes et
   portait toute la bande a 60 px de haut pendant que ses voisins tenaient sur
   une. `flex: none` pour que le debordement parte au defilement plutot que
   d'ecraser les boutons les uns contre les autres. */
/* Le remplissage passe sous le plancher pose juste au-dessus, et c'est lui
   qui decide : le bouton se laisse etirer par le cadre plutot que de le
   pousser. Il vaut 4 px et non 6,4 pour cette seule raison -- a 6,4 la bande
   redemandait ses 29,78, le plancher ne servait a rien, et le rang retombait a
   deux hauteurs. Ce que le bouton perd en remplissage, le cadre le lui rend en
   etirement : la pastille cyan de l'onglet actif occupe toujours toute la
   hauteur de la piste, moins le filet de gouttiere qui la detache. */
.unit-btn {
  flex: none;
  white-space: nowrap;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs-xs);
  padding: var(--espace-2xs) var(--espace);
  cursor: pointer;
  color: var(--gray-5);
  transition: background .15s var(--ease), color .15s var(--ease);
}

/* `:not(.active)` et non l'ordre des regles : les deux selecteurs pesent le
   meme poids, et un survol qui reprend la main sur l'onglet actif lui rend
   l'encre grise sur le plein cyan. */
.unit-btn:not(.active):hover { color: var(--gray-6); }

.unit-btn.active {
  background: var(--cyan);
  color: #fff;
  box-shadow: var(--shadow-sm);
}

/* Selecteur d'annees : multi-selection, et deux annees adjacentes
   selectionnees doivent rester distinctes. Un trait gris entre les boutons
   s'en chargeait quand ils etaient jointifs ; la gouttiere de la piste le fait
   desormais toute seule, et le trait traverserait la pastille. */
.annees-toggle .unit-btn.active { font-weight: 600; }

/* `line-height` fixe et non heritee : deux boutons-liens identiques mesuraient
   26 et 30 px selon la hauteur de ligne du bloc qui les contenait -- celui du
   justificatif de nomination heritait du 1.5 de la page, ses voisins de la
   meme rangee tombaient sur `normal`. Une hauteur de bouton ne se decide pas
   dans le parent. */
.btn-link {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  min-height: var(--h-sm);
  line-height: 1.3;
  border: none;
  background: none;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--cyan-dark);
  cursor: pointer;
  text-decoration: none;
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  transition: background .15s var(--ease);
}

/* `display: inline-flex` ci-dessus l'emporte sur la regle `[hidden]` du
   navigateur : sans cette ligne, un bouton-lien pose masque dans le gabarit
   s'affiche quand meme. */
.btn-link[hidden] { display: none; }

.btn-link:hover { background: var(--cyan-pale); }

/* Un bouton-lien qui bascule -- « Rubriques vides » sur les deux documents de
   synthese -- doit dire s'il est enfonce : sans quoi rien ne distingue
   « je viens de l'activer » de « je viens de le desactiver », et on l'essaie
   deux fois. Le fond retenu, pas une couleur de plus : c'est celui du survol,
   qui dit deja « ce bouton-ci » dans cette barre. */
.btn-link.active {
  background: var(--cyan-pale);
  font-weight: 600;
}

.btn-link.btn-danger:hover { background: var(--red-pale); }

.btn-link:disabled {
  opacity: .6;
  cursor: default;
  background: none;
}

/* La boite qui defile a la place de la page. Meme geste que .tree-table-wrap,
   sans son cadre : la table qu'elle enveloppe est deja posee dans une tuile,
   et deux bordures concentriques a un pixel l'une de l'autre se voient. Une
   table large est large ; ce qui n'est pas acceptable, c'est qu'elle emmene la
   barre de navigation avec elle. */
.table-defilante { overflow-x: auto; }

/* Sauf dans un espace de travail tenu par la fenetre, ou la page ne defile
   plus : ce qui defile est le panneau, dans les deux sens, et il le fait sans
   emmener la barre d'onglets -- elle est au-dessus de lui, pas dedans. La
   boite intermediaire n'a donc plus rien a porter, et elle couterait cher :
   une table posee dans une boite qui defile colle son en-tete a cette boite,
   laquelle est aussi haute que la table. L'en-tete se collerait a rien.

   Sur telephone elle reprend son role. La table du bilan y fait 595 px pour
   375 d'ecran, sa premiere colonne est figee sur cette enveloppe (voir
   mobile.css, section 8), et faire glisser l'espace de travail entier de cote
   pour lire une colonne emmenerait les trois autres tables avec elle. */
.app-main-pleine .table-defilante { overflow: visible; }

@media (max-width: 720px) {
  .app-main-pleine .table-defilante { overflow-x: auto; }
}

.sources-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs);
}

.sources-table th {
  text-align: left;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
  /* L'en-tete etait plus haut de six pixels que les lignes qu'il coiffe, alors
     qu'il porte le plus petit texte du tableau. Il se cale desormais sur leur
     hauteur : une ligne de titres n'a pas a peser plus qu'une ligne de donnees. */
  padding: var(--espace-2xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
}

/* Un en-tete de colonne chiffree se cale a droite comme les chiffres qu'il
   coiffe. C'est le bord droit qu'on suit du regard dans une colonne de
   nombres ; un titre reste a gauche pendant que ses valeurs filent a droite
   n'annonce plus rien -- sur la liste des sources, « RÉSULTAT » se lisait a
   577 px au-dessus d'un montant qui finissait a 682, et « TAILLE » a 1223
   au-dessus d'une valeur finissant a 1279. La regle existait, les deux
   en-tetes n'avaient simplement pas la classe.

   Quand un tel en-tete porte un bouton de tri, le chevron passe devant le
   libelle : sinon c'est lui, et non le mot, qui vient se poser sur le bord
   des chiffres, le libelle restant en retrait des seize pixels que l'icone
   occupe -- invisible tant qu'aucun tri n'est actif, encombrante quand meme.
   Aucun autre `th.num` du produit ne contient de bouton : la regle ne
   s'applique aujourd'hui qu'a la colonne « Taille » des zones de fichiers. */
.sources-table th.num, .sources-table td.num { text-align: right; }
.sources-table th.num .sources-sort-btn { flex-direction: row-reverse; }

.sources-sort-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: inherit;
  cursor: pointer;
}

.sources-sort-btn:hover, .sources-sort-btn.active { color: var(--gray-6); }
.sources-sort-btn.active .dossier-sort-icon { opacity: 1; }
.sources-sort-btn[data-dir="desc"] .dossier-sort-icon { transform: rotate(90deg); }

/* Le tri de la colonne de qualification : une icone au lieu d'un mot, dans une
   colonne calibree sur une pastille (ticket du 10 septembre 2026). L'ecart
   entre les deux dessins se resserre, sans quoi les 52 px de la colonne ne
   tiennent pas les deux. */
.controle-col .sources-sort-btn {
  gap: var(--espace-3xs);
  justify-content: center;
  width: 100%;
}

/* Deux tris dans un meme en-tete : le classement du Comptable partage la
   colonne du nom (ticket du 10 septembre 2026). L'ecart les separe assez pour
   qu'on vise l'un ou l'autre sans hesiter. */
.th-tris {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

.sources-table td {
  padding: var(--espace-sm);
  border-bottom: 1px solid var(--gray-2);
  vertical-align: middle;
}

/* Ces deux-la sont posees directement sur des <td> (voir app.js), et elles
   etaient en `display: flex`. Un <td> en flex n'est plus une cellule de
   tableau : il quitte le calcul de hauteur de la ligne et sa bordure basse ne
   tombe plus a la meme hauteur que celle de ses voisines. C'est de la que
   venaient les traits horizontaux interrompus -- decroches sous la premiere
   colonne, absents sous la derniere -- dans la liste des sources comme dans
   celle du juridique, qui partagent cette feuille.

   Elles redeviennent donc des cellules. L'alignement vertical se fait par
   `vertical-align`, qui est ce que les cellules savent faire, et l'espacement
   par des marges plutot que par `gap`. */
.sources-actions-cell {
  text-align: right;
  white-space: nowrap;
}

.sources-actions-cell > * { vertical-align: middle; }
.sources-actions-cell > * + * { margin-left: var(--espace-2xs); }

.sources-nom-cell { white-space: nowrap; }

/* La corbeille se detache du reste de la rangee.

   Six icones nues a 4 px l'une de l'autre -- renommer, telecharger, marquer
   maison, associer, deplacer, supprimer --, toutes de 20,8 px, se lisent comme
   une file de dessins ou l'on ne voit pas ou finit l'un et ou commence l'autre.
   La derniere efface la piece, et elle etait a 4 px de celle qui ne fait que la
   ranger ailleurs. Mesure au navigateur le 31 aout 2026 sur le Juridique
   d'ACBB : vingt-deux rangees de six boutons, ecarts 4 / 4 / 4 / 3,9 / 4.

   Les rangees de fichiers, elles, n'ont plus de file du tout depuis le
   2 septembre 2026 : leurs six boutons sont entres dans le menu des trois
   points, ou c'est un trait qui detache la suppression (`.fichier-menu-trait`).
   La regle reste pour la table des sources comptables, qui garde ses icones --
   relancer l'analyse, visualiser, controle du FEC, telecharger, supprimer --
   parce qu'elles ne sont pas les gestes d'un fichier mais ceux d'une analyse.

   Le remede est celui que cette feuille a deja arbitre pour cette forme-la. La
   regle qui cerne les boutons d'une ligne de reglages dit pourquoi elle ne le
   fait pas partout : « dans une barre d'outils l'icone nue est la bonne forme,
   c'est la barre et ses separateurs qui la delimitent ». Une cellule d'actions
   est cette barre-la ; elle prend donc le separateur, pas le cadre.

   Le filet est celui de la maison -- 1 px de --gray-3 --, mais pose en
   pseudo-element plutot qu'en bordure gauche : les boutons sont arrondis a
   --radius-sm, et une bordure sur une boite de 20,8 px de haut se dessinerait
   en crochet, ses deux coupes de coin comprises.

   Il se centre dans la marge qu'il occupe. C'est ce qui le laisse a egale
   distance des deux dessins qu'il separe quel que soit le remplissage des
   boutons -- --espace-3xs dans les deux tables de zone, qui serrent leurs
   lignes, --espace-2xs partout ailleurs.

   Sa hauteur est celle du dessin, pas celle du bouton. Le bouton en fait 20,8
   sur ordinateur mais 44 sur telephone, ou il porte la cible tactile : un
   filet retire de la boite y serait devenu une barre de 39 px a cote d'une
   icone de 16, et le separateur aurait pese plus lourd que ce qu'il separe.
   --icon le tient a la taille du glyphe aux deux largeurs.

   `:not(:first-child)` : les trois fabriques posent leurs boutons a la
   condition, et un repertoire du systeme n'en recoit aucun. Une rangee reduite
   a sa seule corbeille porterait sinon un filet qui ne separe rien. */
.sources-actions-cell > .btn-danger:not(:first-child) {
  position: relative;
  margin-left: var(--espace-sm);
}

.sources-actions-cell > .btn-danger:not(:first-child)::before {
  content: "";
  position: absolute;
  top: 50%;
  left: calc(var(--espace-sm) / -2);
  width: 1px;
  height: var(--icon);
  transform: translateY(-50%);
  background: var(--gray-3);
}

/* Renommer sur place : le champ prend la place du nom, dans la ligne meme.
   La meme forme que le champ du titre de la visionneuse (.visionneuse-titre-champ)
   parce que c'est le meme geste -- on corrige un nom la ou on le lit, sans
   qu'une boite s'ouvre par-dessus la liste qu'on est en train de parcourir.

   `font: inherit` et non une taille a soi : le champ doit peser exactement ce
   que pesait le nom qu'il remplace, sans quoi la ligne change de hauteur au
   moment ou l'on commence a ecrire et la liste sursaute sous les yeux. La
   largeur, elle, ne suit pas le nom : un fichier appele « CR.pdf » se renomme
   souvent en quelque chose de bien plus long, et un champ a la taille de
   l'ancien nom obligerait a ecrire dans une fente. */
.ligne-nom-champ {
  font: inherit;
  width: min(32rem, 50vw);
  max-width: 100%;
  padding: 0 var(--espace-3xs);
  color: var(--black);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.ligne-nom-champ:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Le chevron d'un repertoire juridique : le meme que celui de l'arbre
   d'analyse (.row-toggle / .arrow), pose ici dans une cellule de tableau. Le
   creux qui le remplace sur la ligne d'un fichier tient exactement sa place,
   pour que les noms tombent sous les noms. */
.juridique-toggle,
.juridique-toggle-creux {
  display: inline-block;
  width: 18px;
  margin-right: var(--espace-2xs);
  vertical-align: middle;
}

.juridique-toggle-creux { height: 1px; }

/* Le nom d'un repertoire ouvre ce repertoire : le curseur le dit avant le
   clic, et le survol le confirme. Le chevron, lui, se contente de le
   deplier -- deux gestes voisins pour deux intentions differentes. */
.juridique-nom {
  cursor: pointer;
  vertical-align: middle;
  color: inherit;
  text-decoration: none;
}

.juridique-nom:hover { text-decoration: underline; }

.sources-nom-cell > * { vertical-align: middle; }

.sources-nom-cell .icon {
  color: var(--gray-4);
  margin-right: var(--espace-xs);
}

.sources-empty {
  font-size: var(--fs);
  color: var(--gray-5);
  padding: var(--espace) 0;
}

.fil-ariane {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-2xs);
  font-size: var(--fs-sm);
  /* Une seule ligne de texte, sans fond ni bordure : sa hauteur est celle de
     son interligne, et tout ce qui restait a reprendre etait l'ecart avec le
     tableau. */
  line-height: 1.35;
  /* Le quatrieme terme rend au fil le creux de son premier maillon. Un maillon
     porte un remplissage et une bordure transparente -- les deux sont voulus et
     dits plus bas : il est une cible de depot, et la bordure reserve la place de
     celle qui s'allume au survol. Mais rien ne peint cette boite au repos, si
     bien que le fil commencait son encre 7,4 px a l'interieur de la colonne,
     seul de la page a la quitter : l'intitule de la barre au-dessus et le filet
     du tableau au-dessous tiennent tous deux le bord. On tire donc le fil de son
     propre creux -- ecrit comme la somme de ses termes pour qu'il suive si
     l'echelle bouge --, et la cible de depot garde sa surface en debordant dans
     le creux gauche de la tuile qui porte la liste. */
  margin: 0 0 0 calc(-1 * (var(--espace-xs) + 1px));
}

.fil-ariane:empty { display: none; }

/* Les deux blocs de comptes annuels du reseau OCCE : « un premier bloc Siège
   [...] puis un 2nd bloc comptes agrégés » (suivi du 2 septembre 2026). Chacun
   est une rangee de boutons coiffee de son nom.

   Le nom est au-dessus de la rangee et non a cote, et c'est la barre qui
   rattrape la difference de hauteur : voir `.toolbar-analyse`, qui range ses
   groupes par le bas. Centres, ils ne pouvaient pas s'aligner -- « ces
   nouveaux menus changent de place, il faudrait qu'ils soient alignes (au
   niveau du bouton) sur les autres boutons deja existants » (suivi du
   2 septembre 2026) : mesure au navigateur, la rangee coiffee d'un nom tombait
   neuf pixels plus bas que Cycles / Balances / Outils. */
.jeu-comptes-bloc {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

.jeu-comptes-titre {
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-5);
  padding-left: var(--espace-2xs);
}

/* Le fil d'Ariane et la barre de selection sur une seule ligne.
   `.barre-selection[hidden]` garde sa boite pour que la liste ne bouge jamais
   sous le pointeur ; sur sa propre ligne, cette boite reservee valait 53 px
   d'air permanent entre l'intitule de la zone et l'en-tete du tableau. Cote a
   cote, la reserve se confond avec la ligne du fil : la liste ne bouge toujours
   pas, et la bande vide tombe a la hauteur d'une barre.
   Le fil prend la place restante et la barre se serre a droite ; sur une
   fenetre etroite, la barre passe a la ligne -- et elle y passe qu'elle soit
   visible ou non, puisqu'elle occupe la meme boite dans les deux cas. */
.ligne-fil-selection {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--espace-xs);
  margin-bottom: var(--espace-xs);
}

.ligne-fil-selection > .fil-ariane { flex: 1 1 auto; min-width: 0; }
.ligne-fil-selection > .barre-selection { flex: 0 1 auto; }

/* Un maillon est aussi une cible de depot : c'est par lui qu'une piece sort
   d'un repertoire, et notamment qu'elle revient a la racine. Il lui faut donc
   la surface d'une cible et pas celle d'un mot -- a `padding: 0`, il fallait
   viser une bande de treize pixels de haut, ce qu'aucune souris tenant un
   paquet ne fait. La bordure transparente reserve la place de celle qui se
   pose des le depart d'un glisser : sans elle, le fil se decalerait au
   passage. */
.fil-ariane-item {
  background: none;
  border: 1px solid transparent;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  color: var(--blue);
  cursor: pointer;
  font: inherit;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

/* Un maillon qui mene quelque part le dit quand on le vise. Il ne le disait
   pas : au survol, il etait au pixel pres ce qu'il est au repos -- pas de
   fond, pas de bordure, la meme couleur --, seul des boutons de texte du site
   a ne rien repondre, alors que sa regle transitionne depuis toujours le fond
   et la bordure pour cela. Il prend donc le pale de sa propre teinte, comme
   `.btn-link` prend le sien. Le maillon du niveau ouvert en est exclu : il
   porte `cursor: default` et son clic ne mene nulle part, donc un survol qui
   s'y allumerait promettrait un voyage qui n'a pas lieu.

   Ce fond deborde de 7,4 px a gauche sur le premier maillon, la ou le fil est
   tire hors de son propre creux pour que son texte tienne le bord de colonne
   (voir `.fil-ariane` plus haut). C'est voulu et ce n'est pas le meme sujet :
   ce qui doit tenir le bord, c'est l'encre au repos, celle qu'on lit en
   descendant une page immobile. Un fond qui n'existe que sous le pointeur
   montre la surface reelle de la cible, et c'est ce que fait `.btn-link`
   partout ailleurs. */
.fil-ariane-item:not(.fil-ariane-courant):hover { background: var(--blue-pale); }

/* Le niveau ouvert. Il ne mene nulle part -- on y est -- mais il n'est pas
   `disabled` pour autant : un bouton desactive ne voit passer aucun glisser,
   et c'est precisement sur lui qu'on lache une piece pour la faire remonter
   depuis un repertoire deplie. */
.fil-ariane-item.fil-ariane-courant {
  color: var(--gray-5);
  font-weight: 600;
  cursor: default;
}

.fil-ariane-sep { color: var(--gray-4); }

/* Les zones de fichiers listent des dizaines de pieces, et leurs lignes ne
   portent qu'un nom : elles prenaient 49 px de haut comme celles de la
   liste des sources, qui empilent une taille, un resultat, une cloture et
   deux dates. Un repertoire importe tenait donc sur deux ecrans la ou il
   tient sur un, et le fil d'Ariane sortait du champ des qu'on descendait.

   L'air est repris aux deux endroits qui le prenaient : la cellule et les
   boutons d'action, dont le rembourrage porte plus de hauteur que le texte
   lui-meme. Borne aux tableaux de zone : la liste des sources garde la
   sienne, ses lignes ayant vraiment de quoi la remplir.

   Repris d'un cran le 12 aout 2026 (« reduis encore l'epaisseur des lignes »)
   : 36 px deviennent 28. Ce qui fixe le plancher n'est plus le rembourrage
   mais l'icone du bouton d'action, qui mesure 16 px a elle seule -- descendre
   plus bas demanderait de la rapetisser, et une cible de 16 px sans marge se
   rate.

   Ecrit sur la CLASSE que le gabarit `zone_fichiers` pose, et non sur les
   identifiants des deux premieres zones. C'etait `#juridique-table` et
   `#permanent-table` : le Cabinet et la Conso, ouverts ensuite par le meme
   gabarit, gardaient donc les lignes hautes de la liste des sources -- 48 px
   contre 26 --, alors que tout le reste de la fenetre etait deja le meme code
   (ticket du 9 septembre 2026 : « il faut que ce soit exactement le meme code
   que juridique et comptable [...] la, ca a des tailles differentes »). Une
   zone qui s'ajoutera demain heritera de la densite sans qu'on y pense, ce
   qui est ce que le gabarit promettait. */
.sources-table.zone-fichiers-table td {
  padding-top: var(--espace-3xs);
  padding-bottom: var(--espace-3xs);
}

/* Le bouton d'action de ces tableaux reste dense, pour la meme raison : la
   hauteur commune des petits controles ferait grandir chaque ligne de sept
   pixels dans des tableaux ecrits pour en tenir le plus possible a l'ecran, et
   le bouton n'y voisine que ses semblables -- il n'y a personne a cote de qui
   s'aligner. */
.zone-fichiers-table .btn-link.btn-icon-only {
  padding: var(--espace-3xs);
  min-width: 0;
  min-height: 0;
}

.juridique-row-dossier .sources-nom-cell {
  cursor: pointer;
}

.juridique-row-dossier .sources-nom-cell:hover { color: var(--blue); }

.juridique-row-dossier .sources-nom-cell .icon { color: var(--yellow); }

/* Les deux repertoires qui n'en sont pas tout a fait : le dossier permanent
   juridique, qu'on ouvre en premier et qui porte les statuts, et le fonds
   d'archives, ou l'on ne depose plus rien. Ils portaient deja leur marque --
   le fronton a colonnes, la boite -- mais dans le jaune de chemise de tous les
   autres, si bien que la marque se lisait apres la couleur. Le bleu fonce les
   sort de la rangee de chemises sans rien dire d'un etat : aucune ligne de
   cette liste n'est bleue par ailleurs (demande du 14 aout 2026).
   Meme specificite que la regle ci-dessus : c'est l'ordre qui tranche, donc ces
   deux regles doivent rester apres elle. */
.juridique-row-epingle .sources-nom-cell .icon { color: var(--blue-dark); }
.juridique-row-archives .sources-nom-cell .icon { color: var(--blue-dark); }
/* Le dossier permanent comptable ouvre l'onglet « Comptable » comme le
   juridique ouvre le sien : meme fronton, meme place en tete. Le vert plutot
   que le bleu fonce parce que deux frontons de la meme teinte sous deux onglets
   voisins se confondraient, et que c'est justement d'un onglet a l'autre qu'on
   passe (demande du 14 aout 2026). Apres la regle de l'epingle, qu'il porte
   aussi : c'est l'ordre qui tranche, a specificite egale. */
.juridique-row-comptable .sources-nom-cell .icon { color: var(--green); }
/* Le fonds d'archives du Comptable porte la meme boite que celui du Juridique,
   mais dans le vert de sa zone : le bleu fonce est la teinte de l'onglet d'a
   cote, et deux boites de la meme couleur sous deux onglets voisins se
   confondraient (demande du 15 aout 2026). Meme arbitrage que pour les deux
   dossiers permanents, et meme place dans la feuille : apres la regle des
   archives, qu'un tel repertoire porte aussi. */
.juridique-row-archives-comptable .sources-nom-cell .icon { color: var(--green); }
.juridique-row-archives-cabinet .sources-nom-cell .icon { color: var(--purple); }
/* La troisieme zone, la Conso, et sa paire de tete : le meme fronton, la meme
   boite, en jaune (demande du 24 aout 2026, « cree deux dossiers jaunes »).
   C'est la teinte de la case qui ouvre la zone et de la pastille qui la signale
   sur la liste des clients ; le bleu fonce et le vert sont pris par les deux
   onglets voisins, et c'est justement d'un onglet a l'autre qu'on passe. Le
   jaune est aussi celui des chemises ordinaires : ici, ce sont les glyphes --
   le fronton, la boite -- et le nom appuye qui separent la paire de tete du
   reste, comme partout ailleurs dans cette liste.
   Apres les regles de l'epingle et des archives, que ces deux repertoires
   portent aussi : a specificite egale, c'est l'ordre qui tranche. */
.juridique-row-conso .sources-nom-cell .icon { color: var(--yellow); }
.juridique-row-archives-conso .sources-nom-cell .icon { color: var(--yellow); }
/* LE DEPOT DES COMPTES SOCIAUX DES FILIALES, troisieme place de tete de la
   Conso : « lui attribuer une couleur specifique, une icone / un logo
   specifique permettant de l'identifier immediatement » (ticket AMBISTRATE du
   17 septembre 2026). Le cyan, qui est la teinte du produit et la seule qu'un
   onglet voisin n'ait pas prise : ses deux voisins de tete sont jaunes, et
   c'est precisement d'eux qu'il faut le distinguer. Le glyphe suit la meme
   demande : une chemise a fleche entrante et non une chemise, parce que c'est
   le seul repertoire ou l'on depose pour faire ENTRER une structure dans un
   jeu de comptes. */
.juridique-row-comptes-sociaux .sources-nom-cell .icon { color: var(--cyan); }
/* L'EXERCICE CLOS : cadenas rouge (« le cadenas, tu le mets en rouge, et avec
   aussi la date », ticket du 8 septembre 2026). Le rouge ne signale pas une
   erreur ici : c'est, dans tout ce produit, la teinte de ce a quoi on ne
   touche plus. Un exercice archive s'ouvre encore -- les pieces sont dedans,
   et c'est bien pour cela qu'on l'ouvre --, mais il ne recoit plus rien.
   Apres les regles des archives, que son parent porte et non lui. */
.juridique-row-annee-archivee .sources-nom-cell .icon { color: var(--red); }

/* Glisser un fichier sur la ligne d'un repertoire l'y range. La ligne le dit
   pendant le survol -- fond bleu, liseré, dossier qui grossit -- puis accuse
   reception d'un vert qui s'efface. Sans ces deux signes, on lache un fichier
   au-dessus d'une ligne sans savoir si elle le prend, et on ne sait pas
   davantage ou il est parti : le repertoire vise n'est pas celui qu'on
   regarde, donc rien n'apparait a l'ecran. */
.juridique-dossier-icone { transition: transform .12s var(--ease-spring); }

/* Le dossier permanent juridique, epingle en tete de son niveau : son nom est
   appuye pour qu'il se detache de la liste qu'il ouvre. */
.juridique-row-epingle .juridique-nom { font-weight: 600; }

/* UNE PIECE QUI NOMME UN AUTRE MANDAT.

   « Tu le mets en rouge, faut que la police soit en rouge, mais tu ne le
   renommes pas, surtout pas » (suivi du 9 septembre 2026). Le nom garde donc
   son texte au caractere pres ; seule son encre change, et une phrase parait
   dessous avec le geste qui la resout.

   Le rouge et non l'orange : l'orange dit « a verifier » dans tout le produit,
   et c'est ce que porte deja la pastille de pointage a deux colonnes de la.
   Une piece rangee sous le mauvais mandat n'est pas a verifier, elle est a
   deplacer.

   La phrase est rare par construction (voir `mandat_suspect`) : neuf pieces
   sur les 38 607 du fonds juridique. C'est ce qui lui permet de prendre une
   seconde ligne dans une liste ecrite pour etre dense. */
.juridique-nom.juridique-nom-autre-mandat { color: var(--red); }

.juridique-autre-mandat {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--red);
}

.juridique-autre-mandat-action {
  margin-left: var(--espace-2xs);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--red);
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.juridique-autre-mandat-action:hover { color: var(--red-dark); }

/* Le nom suit la marque, pour ces deux repertoires-la seulement.
   L'icone etait passee au bleu fonce le 14 aout 2026 pendant que le nom restait
   a l'encre : la ligne se lisait donc en deux temps, une marque coloree suivie
   d'un nom comme les autres. Les deux teintes se rejoignent (demande du meme
   jour) -- ce n'est pas un etat de plus dans une liste deja pointee en vert et
   en orange, c'est la meme marque, portee jusqu'au bout de la ligne.

   L'encre est ecrite pour la chemise ordinaire plutot que laissee a l'heritage :
   les trois cas sont alors lisibles ensemble, ici comme dans MarqueRepertoire
   cote app, et le verificateur peut les comparer un a un (regles_affichage). */
.juridique-row-dossier .juridique-nom { color: var(--black); }
/* Une regle par etat plutot qu'un selecteur groupe : c'est ainsi que le
   verificateur lit la teinte de chacun (regles_affichage), etat par etat. */
.juridique-row-epingle .juridique-nom { color: var(--blue-dark); }
.juridique-row-archives .juridique-nom { color: var(--blue-dark); }
.juridique-row-comptable .juridique-nom { color: var(--green); }
.juridique-row-archives-comptable .juridique-nom { color: var(--green); }
.juridique-row-conso .juridique-nom { color: var(--yellow); }
.juridique-row-archives-conso .juridique-nom { color: var(--yellow); }
/* Le fonds d'archives du Cabinet, quatrieme zone : violet. Le bleu fonce, le
   vert et le jaune sont pris par les trois onglets voisins. */
.juridique-row-archives-cabinet .juridique-nom { color: var(--purple); }
/* Le depot des comptes sociaux des filiales : son nom suit sa marque, comme
   celui de ses deux voisins de tete. */
.juridique-row-comptes-sociaux .juridique-nom { color: var(--cyan); }
/* LE COMPTEUR DE FILIALES, a droite du nom. Il ne compte pas des fichiers :
   « il doit indiquer le nombre de filiales / structures distinctes pour
   lesquelles au moins un document a ete depose » (meme ticket). D'ou la
   pastille plutot qu'un nombre nu : un chiffre pose a cote d'un nom de
   repertoire se lit comme un nombre de pieces, et c'est justement ce qu'il
   n'est pas. Son infobulle le dit en toutes lettres. */
.juridique-filiales {
  margin-left: var(--espace-xs);
  padding: 0 var(--espace-xs);
  border-radius: var(--radius-sm);
  background: var(--cyan-light);
  color: var(--cyan-dark);
  font-size: var(--fs-2xs);
  font-weight: 600;
  line-height: 1.6;
  flex: none;
}
/* Le millesime d'un exercice scelle vit DANS la cartouche, sur son rouge
   plein : il s'ecrit donc en blanc, comme le nom court a cote de lui. */
.juridique-row-annee-archivee .juridique-nom { color: #fff; }

/* LE SCEAU D'UN EXERCICE CLOS : la cartouche, retenue sur la planche des six
   compositions (« je choisis le 1, la cartouche », suivi du 8 septembre 2026).

   Elle remplace la chemise -- « aucun dossier ni fichier ne doit apparaitre
   derriere » -- et porte la date DEDANS, sur une seule ligne. C'est ce qui l'a
   fait choisir : dix caracteres en chasse fixe demandent quatre-vingt-quatre
   pixels de large, mesures, et les formes presque carrees devaient couper
   « 2025-10-29 » en deux etages pour tenir, ce qui faisait grandir la ligne de
   moitie.

   Rouge plein et non un contour : c'est la teinte de ce a quoi on ne touche
   plus, et une tache pleine se voit d'un bout a l'autre d'une arborescence de
   trois cents pieces.

   ELLE ENGLOBE LE MILLESIME ET LE NOM COURT DEPUIS LE 9 SEPTEMBRE 2026.

   « Mets également le nom court du dossier en rouge, puisqu'il fait partie de
   la cartouche. [...] La cartouche doit englober le millésime et le nom court
   afin qu'ils forment visuellement un seul bloc » (suivi du 9 septembre 2026).
   Trois objets se suivaient a trois distances -- le sceau, « 2023 » rouge,
   « ADP94 » gris -- pour dire une seule chose.

   L'ETIQUETTE, RETENUE LE 9 SEPTEMBRE 2026 SUR LA PLANCHE DES SIX
   CARTOUCHES ENGLOBANTES (« choisie la sixieme, la cartouche etiquette »).

   Elle renverse le partage du rouge de la premiere composition, « Deux
   corps », posee le matin meme : le rouge plein passe au millesime et au
   client, et la date se refugie dans une pastille blanche a gauche. Ce qui
   change n'est pas la teinte mais ce qu'elle met en avant : DE QUI est
   l'exercice, plutot que QUAND il a ete scelle. Dans une liste ou six annees
   se suivent sous le meme fonds, c'est le millesime qu'on cherche ; la date
   d'archivage, on la lit une fois.

   La pastille blanche garde a la date sa tache a elle, et au cadenas le
   contraste qu'il perdrait en blanc sur rouge : les deux se lisent en rouge
   sur blanc, cernes par le rouge plein de la cartouche. */
.sceau-cloture {
  display: inline-flex;
  align-items: center;
  flex: none;
  /* L'ecart que la chemise laissait avant le nom : la cartouche prend sa
     place, elle doit prendre sa marge, sans quoi la ligne suivante s'y colle. */
  margin-right: var(--espace-xs);
  border-radius: var(--radius-xs);
  /* Le liseré rouge autour de la pastille : un pixel a gauche et en haut et en
     bas, l'ecart ordinaire a droite. C'est lui qui fait tenir la pastille DANS
     la cartouche au lieu de la poser a cote. */
  padding: 1px var(--espace-2xs) 1px 1px;
  gap: var(--espace-2xs);
  background: var(--red);
}

/* Le scelle : la pastille blanche, a gauche, ou vivent le cadenas et la date. */
.sceau-cloture-scelle {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-3xs);
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: #fff;
  color: var(--red);
}

/* L'identite : le millesime et le client, en blanc sur le rouge plein. */
.sceau-cloture-identite {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  color: #fff;
}

/* Le cadenas rouge sur la pastille blanche, et non le rouge que la ligne donne
   a tout ce qu'elle porte : c'est le meme rouge, mais il vaut mieux le dire
   ici, ou l'on voit sur quoi il se pose. Selecteur assez precis pour passer
   devant celui de la ligne, ecrit plus haut. */
.juridique-row-annee-archivee .sources-nom-cell .sceau-cloture .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--red);
}

/* La date, dans la chasse fixe des dates et au plus petit corps de l'echelle :
   elle tient dans un sceau haut comme une ligne de liste. */
.sceau-cloture-date {
  font-family: var(--mono);
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.6;
}

/* LE SCEAU HÉRITÉ : ce qui vit SOUS un exercice clos.

   « Il faut appliquer la même logique aux fichiers et dossiers présents dans
   l'arborescence sous le dossier clôturé, mais sans modifier leur nom. Il
   s'agit uniquement d'ajouter le cadenas de clôture, avec la même date de
   clôture » (suivi du 9 septembre 2026).

   La moitié gauche de la cartouche, et elle seule : le cadenas et la date. En
   rouge sur rouge pâle, là où le millésime est en blanc sur rouge plein -- la
   cartouche doit rester la seule tache pleine de sa branche, sinon quarante
   pièces la couvrent. C'est la même famille, un cran plus bas, et l'icône
   garde la mesure de celle de la cartouche. */
   ELLE ENGLOBE LA PIÈCE ENTIÈRE DEPUIS LE 9 SEPTEMBRE 2026.

   « Il faut que la cartouche englobe l'ensemble du fichier ou du sous-dossier,
   afin que chaque élément soit clairement identifié comme un seul bloc.
   Inspire-toi de ce qui a été fait dans le dossier "Clôturé" [...] tout en
   conservant une distinction visuelle entre les fichiers et les sous-dossiers.
   Tu peux notamment utiliser un effet bicolore ou un effet "étiquette" »
   (suivi du 9 septembre 2026).

   La marque se posait devant le nom et s'arrêtait là : trois objets à trois
   distances -- le cadenas daté, l'icône, le nom -- pour dire une seule chose,
   exactement ce que la cartouche du millésime avait corrigé la veille d'un
   cran plus haut. L'étiquette reprend donc sa composition, un ton plus bas :
   une pastille claire à gauche pour la date, puis l'icône et le nom sur le
   même fond, sans écart entre eux.

   PAS D'ÉLÉMENT ENVELOPPANT, ET C'EST VOULU. La cellule du nom porte aussi le
   retrait de l'arborescence, la marque du CAC, celle du cycle et la saisie du
   nom en place, qui remplace le lien dans son parent. Un `<span>` autour des
   trois aurait déplacé tout cela. Ce sont donc les trois pièces elles-mêmes
   qui se peignent et se collent : le bloc est le même à l'œil, et rien
   au-dessus n'a bougé.

   LA DISTINCTION FICHIER / SOUS-DOSSIER tient au liseré. Un sous-dossier porte
   une tranche rouge pleine à gauche de son étiquette -- il en contient
   d'autres, il ouvre une branche ; un fichier est une feuille et n'en a pas.
   C'est la même grammaire que le reste du produit, où une tranche pleine dit
   « il y a quelque chose derrière ». */
.sceau-herite {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: var(--espace-3xs);
  /* Collée à ce qui suit : c'est ce qui fait l'étiquette d'un seul tenant. */
  margin-right: 0;
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs) 0 0 var(--radius-xs);
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--red-pale);
  color: var(--red);
}
.sceau-herite .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--red);
}

/* Le corps de l'étiquette : l'icône du fichier ou de la chemise, puis le nom,
   sur le rouge pâle que la pastille borde. Le nom ferme le bloc à droite. */
.sceau-herite ~ .icon,
.sceau-herite ~ .juridique-nom {
  background: var(--red-pale);
}
/* L'écart que l'icône laisse d'ordinaire avant le nom (`.sources-nom-cell
   .icon`) passe dans son propre remplissage : une marge aurait coupé
   l'étiquette en deux au milieu, là où un remplissage la garde d'un tenant. */
.sceau-herite ~ .icon {
  margin-right: 0;
  padding: var(--espace-3xs) var(--espace-xs) var(--espace-3xs) var(--espace-2xs);
  box-sizing: content-box;
}
.sceau-herite ~ .juridique-nom {
  padding: var(--espace-3xs) var(--espace-2xs) var(--espace-3xs) 0;
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
}

/* Un sous-dossier ouvre une branche : sa tranche gauche est pleine. */
.juridique-row-dossier .sceau-herite {
  border-left: 3px solid var(--red);
  border-radius: 0 0 0 0;
}

/* Le nom court du mandat, apres le millesime scelle : « ajoute le nom court du
   dossier afin d'identifier clairement le client concerné » (suivi du
   8 septembre 2026).

   EN BLANC SUR LE ROUGE PLEIN depuis l'etiquette du 9 septembre 2026. Il
   avait ete demande « en rouge, puisqu'il fait partie de la cartouche », et
   c'est cette demande-la qui est tenue : le gris des mentions disait un
   voisin, la cartouche en a fait une moitie. Le rouge est passe du texte au
   fond, et le nom court prend le blanc qui se lit dessus -- le sortir en rouge
   sur rouge l'aurait efface.

   L'ecart d'avec le millesime est celui de la cartouche (`gap`) et non une
   marge a soi : deux ecarts sur la meme ligne s'additionnaient. */
.juridique-annee-client {
  font-size: var(--fs-2xs);
  color: #fff;
}

/* Le survol l'emporte sur les trois : il dit que la ligne s'ouvre, et une
   couleur de nom posee sur le span rendait sourd le bleu que la cellule prend
   au passage du pointeur. */
.juridique-row-dossier .sources-nom-cell:hover .juridique-nom { color: var(--blue); }
/* Sauf dans la cartouche : le millesime y est pose sur le rouge plein, et le
   bleu du survol l'y rendrait illisible. La ligne s'ouvre quand meme, et c'est
   le fond de ligne qui le dit. */
.juridique-row-annee-archivee .sources-nom-cell:hover .juridique-nom { color: #fff; }

.juridique-row-dossier.juridique-cible-depot > td { background: var(--blue-pale); }
.juridique-row-dossier.juridique-cible-depot > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue);
}
.juridique-row-dossier.juridique-cible-depot .sources-nom-cell { color: var(--blue); }
.juridique-row-dossier.juridique-cible-depot .juridique-dossier-icone {
  transform: scale(1.25);
}

@keyframes juridique-depot-recu {
  0%   { background: var(--green-pale); }
  70%  { background: var(--green-pale); }
  100% { background: transparent; }
}
.juridique-row-dossier.juridique-depot-recu > td {
  animation: juridique-depot-recu .9s var(--ease) both;
}

@media (prefers-reduced-motion: reduce) {
  .juridique-dossier-icone { transition: none; }
  .juridique-row-dossier.juridique-cible-depot .juridique-dossier-icone { transform: none; }
  .juridique-row-dossier.juridique-depot-recu > td { animation: none; }
}

/* Selectionner en balayant, comme dans une fenetre du Finder.

   La zone qui porte la liste sert de repere de position au rectangle et
   reserve, sous la derniere ligne, la bande vide d'ou le balayage part : un
   repertoire de trois pieces n'offrait sinon aucun endroit ou poser le
   pointeur, la table s'arretant a sa derniere ligne. */
.juridique-liste {
  position: relative;
  /* Deux reserves, et non une : la hauteur minimale tient l'air d'un
     repertoire presque vide, la marge basse garantit qu'il reste toujours une
     bande libre sous la derniere ligne -- y compris quand le repertoire en
     compte cinquante et que la table descend plus bas que l'ecran. Sans elle,
     une liste pleine n'offrait aucun endroit d'ou partir.

     Les deux ont ete reprises le 14 aout 2026 : la bande faisait 80 px, soit
     trois lignes de fichier, et la zone de depot tombait a 112 px sous la
     derniere piece -- l'oeil traversait un vide plus haut que ce qu'il
     quittait. 24 px suffisent a poser le pointeur (une ligne fait 27 px) et
     la hauteur minimale n'a plus a tenir que le message « dossier vide ». */
  min-height: 8rem;
  padding-bottom: var(--espace-xl);
}

/* La liste des pieces d'un mandat -- Source, Juridique, Comptable, Conso --
   se lit dans une tuile. Elle etait posee a nu sur la page : un intitule en
   petites capitales, deux boutons au bout de la ligne, un fil d'Ariane, puis
   une table qui commencait sans que rien ne dise ou. Quatre onglets sur huit
   se lisaient comme une feuille de texte, la ou le reste du produit range
   chaque zone dans son cadre.

   Le creux sous la liste vaut 16 px sur les quatre. Il en valait 16 sur le
   Juridique et le Comptable et 32 sur la Source et la Conso : la regle qui le
   posait nommait deux sections par leur identifiant, et les deux autres n'y
   figuraient pas -- la Conso parce qu'elle est nee apres, la Source parce
   qu'elle n'est pas rendue par le meme gabarit. Un nom de classe ne peut pas
   les oublier.

   Le selecteur porte les deux classes parce que `mobile.css` redonne plus bas
   au panneau son propre creux : a specificite egale c'est le dernier lu qui
   gagne, et la liste aurait repris 20 px sur telephone sans que rien ne le
   dise. */
.panel.tuile-fichiers { margin-bottom: var(--espace-md); }

/* La barre de tete se separe de ce qu'elle coiffe par un filet, comme l'en-tete
   d'une carte de ticket. Le creux au-dessus du filet vaut celui d'en dessous, et
   les deux sont ecrits ici sur le meme barreau : la marge basse d'une barre vaut
   9,6 px sur ordinateur mais 12,8 sur telephone, si bien que le filet aurait
   flotte de 3,2 px d'un cote ou de l'autre selon la largeur. Dans une tuile, le
   rythme des bandes est celui de la tuile, pas celui de la page. */
.tuile-fichiers > .toolbar {
  margin-bottom: var(--espace-sm);
  padding-bottom: var(--espace-sm);
  border-bottom: 1px solid var(--gray-2);
}

/* Le creux bas de la tuile est celui de la liste quand elle en a un. Les 24 px
   sous la derniere ligne ne sont pas de l'air : c'est la bande d'ou part un
   balayage, et le creux d'une tuile n'appartient pas a la liste -- on ne peut
   pas y poser le pointeur. Additionnes, ils faisaient 40 px de vide sous la
   derniere piece. La Source n'a pas de balayage, donc pas de bande : elle garde
   le creux ordinaire. */
.tuile-fichiers:has(> .juridique-liste) { padding-bottom: 0; }

/* Le rectangle lui-meme : le bleu de la selection, pose par-dessus les lignes
   sans jamais les intercepter -- il suit le pointeur, il ne le recoit pas. */
.juridique-bande {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  background: rgba(59, 111, 214, .12);
  border: 1px solid var(--blue);
  border-radius: var(--radius-xs);
}

/* Une ligne retenue porte la meme marque que dans le detail d'un compte :
   meme fond bleu, meme lisere gauche. Deux dessins differents pour une meme
   idee auraient demande de reapprendre a lire la selection en changeant
   d'onglet.

   Ecrit sur `.juridique-liste` et non sur deux identifiants de tableau : le
   gabarit `_zone_fichiers.html` est appele trois fois (Juridique, Comptable,
   Imports), et la troisieme zone n'avait donc aucune marque de selection --
   exactement le genre d'ecart que ce gabarit unique existe pour empecher. */
.juridique-liste .sources-table tr.ligne-selectionnee > td,
.juridique-liste .sources-table tr.ligne-selectionnee:hover > td {
  background: rgba(59, 111, 214, .16);
}
.juridique-liste .sources-table tr.ligne-selectionnee > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue);
}

/* La ligne que l'Assistant vient de designer.
   Le meme bleu que la selection, et pour la meme raison : c'est ce que le
   produit emploie deja pour dire « celle-ci ». Elle s'efface d'elle-meme au
   bout de quelques secondes -- une ligne qui resterait peinte se lirait comme
   un etat du dossier, alors qu'elle ne dit qu'une chose : on vient de vous la
   montrer. */
tr.ligne-montree > td {
  background: rgba(59, 111, 214, .16);
  transition: background .5s ease;
}
tr.ligne-montree > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue);
}

/* Le bleu de la selection se pose SUR la teinte de controle au lieu de la
   remplacer, comme dans le detail d'un compte (voir plus bas
   `.modal-table tr.ligne-selectionnee[data-controle]`) et pour la meme raison :
   un fichier retenu doit continuer de dire s'il est valide.

   Il ne le disait pas. Le bleu de la selection est monte d'un cran de
   specificite -- un identifiant de tableau -- et effacait la teinte verte pour
   toute la duree de la selection ; or on retient un fichier avant de le
   pointer, et c'est justement a ce moment-la qu'on regarde s'il a change de
   couleur. « Le fichier ne s'affiche pas en vert lorsqu'il est valide »
   (ticket du 4 septembre 2026).

   Deux couches de fond plutot qu'une couleur melangee : la premiere valeur de
   `background` est peinte au-dessus des suivantes. */
.juridique-liste .sources-table tr.ligne-selectionnee[data-controle="valide"] > td,
.juridique-liste .sources-table tr.ligne-selectionnee[data-controle="valide"]:hover > td {
  background:
    linear-gradient(rgba(59, 111, 214, .16), rgba(59, 111, 214, .16)),
    var(--controle-valide-bg-hover);
}
.juridique-liste .sources-table tr.ligne-selectionnee[data-controle="probleme"] > td,
.juridique-liste .sources-table tr.ligne-selectionnee[data-controle="probleme"]:hover > td {
  background:
    linear-gradient(rgba(59, 111, 214, .16), rgba(59, 111, 214, .16)),
    var(--controle-probleme-bg-hover);
}
/* Le lisere gauche dit la meme chose en plus franc : bleu sur les quatre
   premiers pixels, la couleur de l'etat sur les quatre suivants. */
.juridique-liste .sources-table tr.ligne-selectionnee[data-controle="valide"] > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue), inset 8px 0 0 var(--green);
}
.juridique-liste .sources-table tr.ligne-selectionnee[data-controle="probleme"] > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue), inset 8px 0 0 var(--orange);
}

/* Pendant le balayage, le pointeur traverse des noms de fichiers : sans cela
   le navigateur selectionne le texte au lieu des lignes, et lache un surlignage
   bleu systeme par-dessus le rectangle. */
.juridique-liste.balayage-en-cours {
  user-select: none;
  -webkit-user-select: none;
}

/* Le paquet qu'on tire : le nombre de pieces, pose sous le pointeur a la
   place de l'image d'une seule ligne. C'est ce qui distingue « je deplace
   cette ligne » de « je deplace les onze que je viens de balayer », le reste
   de la liste etant identique dans les deux cas. */
.juridique-fantome {
  position: fixed;
  top: -1000px;
  left: -1000px;
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-xs) var(--espace-sm);
  font: 500 var(--fs) var(--sans);
  color: #fff;
  background: var(--blue);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}

/* Ranger ailleurs : les memes cibles que le depot d'un fichier du bureau --
   la ligne d'un repertoire s'allume pareil, c'est le meme geste -- plus le
   fil d'Ariane, par ou une piece remonte d'un cran ou revient a la racine.

   La ligne qu'on tient s'efface a moitie : c'est ce qui distingue « je
   deplace ceci » de « je survole cela », les deux etant a l'ecran en meme
   temps. */
.juridique-en-deplacement > td { opacity: .45; }

.fil-ariane-item.fil-ariane-cible {
  background: var(--blue-pale);
  border-color: var(--blue);
  color: var(--blue);
}

/* Tant qu'on tient quelque chose, la zone montre ou l'on peut le poser.

   Une cible qui ne s'allume qu'une fois survolee demande de deviner qu'elle
   existe, et c'est ce qui a fait conclure qu'on « ne peut pas les deplacer
   directement sur la racine » : le fil d'Ariane recevait deja, il ne le disait
   a personne. Les maillons se cernent donc des le depart du glisser -- en
   pointille, qui dit « destination possible » la ou le trait plein dira
   « c'est ici que ca tombe ».

   Le maillon vise est exclu de cette regle, et il faut l'ecrire : sans le
   `:not`, elle repeignait aussi sa bordure en gris. Les deux selecteurs
   pesaient le meme poids -- `.fil-ariane-item.fil-ariane-cible` et
   `.juridique-glisser-en-cours .fil-ariane-item`, deux classes chacun --, et
   a poids egal c'est le dernier ecrit qui l'emporte : le bleu pose vingt
   lignes plus haut n'atteignait jamais l'ecran. La cible tombait en trait
   plein gris, de la couleur des destinations possibles, quand tout ce qui
   precede dit qu'elle doit s'en distinguer. */
.juridique-glisser-en-cours .fil-ariane-item:not(.fil-ariane-cible) {
  border-style: dashed;
  border-color: var(--gray-3);
  color: var(--blue);
}
.juridique-glisser-en-cours .fil-ariane-item.fil-ariane-cible {
  border-style: solid;
}

/* Le vide sous la liste : le fond de la fenetre, qui range dans le repertoire
   ouvert. Il ne se cerne pas au repos -- ce serait un cadre permanent autour
   de chaque liste --, seulement quand on tient quelque chose. */
.juridique-glisser-en-cours .juridique-liste {
  outline: 1px dashed var(--gray-3);
  outline-offset: -1px;
  border-radius: var(--radius-xs);
}
.juridique-liste.juridique-vide-cible {
  outline: 1px solid var(--blue);
  background: var(--blue-pale);
}

/* Une ligne de fichier vaut pour le repertoire qui la contient : rien n'entre
   dans un fichier, mais lacher dessus range a son niveau -- « il faut pouvoir
   le faire sur des fichiers egalement » (demande du 17 aout 2026).

   Elle s'allume donc autrement qu'un repertoire, qui, lui, s'ouvre pour
   recevoir : un liseré posé sur les deux bords horizontaux, entre les lignes,
   comme un curseur d'insertion -- et non le fond bleu franc, qui dirait « ceci
   recoit ». */
.juridique-cible-niveau > td {
  background: var(--blue-pale);
  box-shadow: inset 0 1px 0 var(--blue), inset 0 -1px 0 var(--blue);
}

/* Un PDF tire sur un PDF ne se range pas : il fusionne. Tant qu'on en tient
   un seul, les autres se cernent en pointille -- meme langage que le fil
   d'Ariane, qui s'annonce de la meme facon --, et celui qu'on survole passe au
   trait plein. Sans ce premier signe, la cible ne se decouvrait qu'en passant
   dessus, c'est-a-dire par hasard (demande du 17 aout 2026).

   La ligne qu'on tire est exclue : elle ne s'absorbe pas elle-meme. */
.juridique-glisser-pdf tr[data-famille="pdf"]:not(.juridique-en-deplacement) .sources-nom-cell {
  outline: 1px dashed var(--gray-3);
  outline-offset: -2px;
  border-radius: var(--radius-xs);
}
.juridique-cible-fusion > td { background: var(--blue-pale); }
/* Aussi specifique que la regle en pointille ci-dessus, et posee apres elle :
   sans quoi la cible survolee garderait le pointille des candidates. */
.juridique-glisser-pdf tr[data-famille="pdf"].juridique-cible-fusion .sources-nom-cell {
  outline: 1px solid var(--blue);
  color: var(--blue);
}
/* La piece qui va absorber l'autre grossit sous le pointeur, comme la chemise
   d'un repertoire qui s'ouvre pour recevoir. */
.juridique-icone { transition: transform .12s var(--ease-spring); }
.juridique-cible-fusion .juridique-icone { transform: scale(1.25); }
@media (prefers-reduced-motion: reduce) {
  .juridique-icone { transition: none; }
  .juridique-cible-fusion .juridique-icone { transform: none; }
}

/* La boite « Deplacer » : tout l'arbre de la zone, un bouton par destination.
   Meme famille de surface flottante que les autres fenetres du site -- sa
   forme est posee plus haut, avec .dialogue. L'arbre defile : une zone
   importee de Dropbox compte parfois trente repertoires, et la fenetre ne
   doit pas depasser l'ecran. */
.dialogue-deplacer::backdrop { background: var(--voile); }
.dialogue-deplacer-form { display: flex; flex-direction: column; gap: var(--espace); }
.dialogue-deplacer-titre { margin: 0; font-weight: 600; }
.dialogue-deplacer-aide { margin: 0; font-size: var(--fs-xs); color: var(--gray-5); }
.dialogue-deplacer-arbre {
  display: flex;
  flex-direction: column;
  max-height: 50vh;
  overflow-y: auto;
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  padding: var(--espace-2xs);
}
.dialogue-deplacer-item {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-2xs) var(--espace-sm);
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  font: inherit;
  color: var(--black);
  text-align: left;
  cursor: pointer;
}
.dialogue-deplacer-item .icon { color: var(--yellow); flex: none; }
/* Les deux repertoires qui n'en sont pas tout a fait portent ici la marque et
   la teinte qu'ils portent dans la liste : le fronton bleu fonce du dossier
   permanent, la boite du fonds d'archives, vertes toutes deux sous l'onglet
   Comptable. Une liste de destinations tout en chemises jaunes se lisait nom
   par nom (demande du 17 aout 2026). Apres la regle jaune ci-dessus : a
   specificite egale, c'est l'ordre qui tranche. */
.dialogue-deplacer-item.marque-permanent .icon { color: var(--blue-dark); }
.dialogue-deplacer-item.marque-archives .icon { color: var(--blue-dark); }
.dialogue-deplacer-item.marque-permanent-comptable .icon { color: var(--green); }
.dialogue-deplacer-item.marque-archives-comptable .icon { color: var(--green); }
.dialogue-deplacer-item.marque-permanent-conso .icon { color: var(--yellow); }
.dialogue-deplacer-item.marque-archives-conso .icon { color: var(--yellow); }
.dialogue-deplacer-item.marque-archives-cabinet .icon { color: var(--purple); }
.dialogue-deplacer-item.marque-comptes-sociaux .icon { color: var(--cyan); }
.dialogue-deplacer-item:hover:not(:disabled) { background: var(--gray-1); }
.dialogue-deplacer-item:disabled { color: var(--gray-4); cursor: default; }
.dialogue-deplacer-item:disabled .icon { color: var(--gray-3); }
/* La destination designee, en attente de validation. Le meme bleu que la
   selection d'une ligne : c'est la meme idee -- « voici ce que vise le
   prochain geste » -- et deux dessins pour une idee se reapprennent. */
.dialogue-deplacer-item.choisie,
.dialogue-deplacer-item.choisie:hover:not(:disabled) {
  background: rgba(59, 111, 214, .16);
  color: var(--blue);
  font-weight: 500;
}
.dialogue-deplacer-separateur {
  margin: var(--espace-sm) 0 var(--espace-2xs);
  padding-left: var(--espace-sm);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-4);
  border-top: 1px solid var(--gray-2);
  padding-top: var(--espace-sm);
}
/* Le premier intitule ouvre la liste : il n'a rien au-dessus dont il faudrait
   le separer, et un filet pose sur le bord interieur de la boite se lit comme
   une ligne oubliee. */
.dialogue-deplacer-separateur:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.dialogue-deplacer-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--espace-sm);
}

/* La boite « Fusionner » : deux decisions et rien d'autre -- lequel des deux
   PDF absorbe l'autre, et a quelle page l'autre entre. Elle reprend la forme
   de la boite « Deplacer », dont elle porte la classe : meme famille de
   surface flottante, meme rangee d'actions en bas, meme facon de designer un
   choix avant de valider. */
.dialogue-fusion-sens { display: flex; flex-direction: column; gap: var(--espace-3xs); }
.dialogue-fusion-sens .dialogue-deplacer-item .icon { color: var(--red); }
.dialogue-fusion-rang {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
  font-size: var(--fs);
}
.dialogue-fusion-page { width: 5rem; text-align: right; }
.dialogue-fusion-aide-rang {
  margin: -.5rem 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.dialogue-fusion-supprimer {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  font-size: var(--fs);
  cursor: pointer;
}
/* L'echec reste dans la boite plutot que d'ouvrir une fenetre par-dessus : ce
   qui a rate se corrige ici meme -- un rang hors du document, un PDF protege
   par mot de passe -- et refermer pour recommencer perdrait les deux choix
   deja faits. */
.dialogue-fusion-erreur {
  margin: 0;
  padding: var(--espace-xs) var(--espace-sm);
  font-size: var(--fs-xs);
  color: var(--red);
  background: var(--red-pale);
  border-radius: var(--radius-xs);
}

/* La boite « Choisir dans un mandat » : les images deja deposees dans le
   Juridique et le Comptable, pour les reposer en logo, en tampon ou en
   signature sans passer par le disque (demande du 17 aout 2026).

   Meme famille que « Deplacer » et « Fusionner », dont elle porte la classe :
   on designe, puis on valide. La liste et l'apercu cote a cote -- deux
   « signature.png » ne se distinguent qu'a l'oeil, et le nom seul ne dit pas
   laquelle est la bonne. */
/* Une largeur posee et non seulement plafonnee : la liste et l'apercu se
   partagent la place, et une boite qui se serre sur son contenu reduisait les
   chemins a « Juridique … » des le premier sous-repertoire.

   Ecrite sur `dialog.` : la largeur des autres boites de cette famille est
   posee plus bas dans la feuille, et une simple classe s'y ferait reprendre. */
dialog.dialogue-choix-fichier { width: min(46rem, calc(100vw - 2rem)); max-width: none; }
.choix-fichier-mandat { display: flex; align-items: center; gap: var(--espace-xs); font-size: var(--fs-sm); }
/* `hidden` seul ne cache pas un element qu'une regle met en `flex` : la boite
   proposait un choix de mandat depuis l'onglet Mandat, ou il n'y en a qu'un. */
.choix-fichier-mandat[hidden] { display: none; }
.choix-fichier-mandat select { flex: 1; min-width: 0; }
/* Ou chercher, et quoi chercher : le repertoire puis le nom (demande du
   27 aout 2026). On ne cherche pas une piece dans une liste de mille : on sait
   dans quel repertoire elle dort, et on y va. Le champ reprend la forme des
   barres de recherche du produit -- l'icone dedans, le champ sans cadre. */
/* « Ou chercher » : le seul menu deroulant du produit qui ne soit pas celui du
   systeme. Un <select> ne sait montrer que du texte, et ce qu'on choisit ici
   est un endroit -- le dossier permanent juridique, les archives comptables --
   qui se reconnait a son fronton ou a sa boite, et a sa teinte, avant de se
   lire (demande du 27 aout 2026). Le bouton pose dans la page garde exactement
   le dessin d'un <select>, fleche comprise : c'est le meme geste, il n'a pas a
   se presenter autrement. */
.choix-fichier-ou { position: relative; flex: 1; min-width: 0; }

.choix-fichier-ou-bouton {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  text-align: left;
  padding: var(--espace-xs) var(--chevron-reserve) var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background-color: #fff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--chevron-retrait) center;
  background-size: var(--chevron-taille);
  cursor: pointer;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.choix-fichier-ou-bouton:focus-visible {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.choix-fichier-ou-bouton .icon { width: var(--icon-sm); height: var(--icon-sm); flex: none; color: var(--yellow); }
.choix-fichier-ou-libelle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* La famille des surfaces flottantes, comme la fenetre de dialogue et la
   visionneuse : --radius-lg, fond blanc, bordure --gray-3, ombre portee. */
.choix-fichier-ou-menu {
  position: absolute;
  top: calc(100% + .25rem);
  left: 0;
  right: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  max-height: 18rem;
  overflow-y: auto;
  padding: var(--espace-2xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

/* Meme piege que les deux champs ci-dessus : `hidden` seul ne cache pas un
   element qu'une regle met en `flex`. */
.choix-fichier-ou-menu[hidden] { display: none; }

.choix-fichier-ou-item { font-size: var(--fs-sm); }
.choix-fichier-ou-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.choix-fichier-filtre {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

.choix-fichier-filtre:focus-within {
  background: #fff;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.choix-fichier-filtre .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
  flex: none;
}

.choix-fichier-filtre-champ {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.choix-fichier-filtre-champ:focus { outline: none; }

.choix-fichier-corps { display: flex; gap: var(--espace); align-items: stretch; }
.choix-fichier-liste { flex: 1; min-width: 0; min-height: 12rem; }
.choix-fichier-item { align-items: flex-start; }
.choix-fichier-texte { display: flex; flex-direction: column; min-width: 0; }
.choix-fichier-nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Le chemin de la piece, sous son nom : c'est lui qui separe deux fichiers de
   meme nom, mais on lit le nom d'abord. Il porte l'icone et la teinte de
   l'endroit d'ou vient la piece -- dans une liste qui melange les six zones,
   c'est ce qui dit laquelle a rendu cette ligne. */
.choix-fichier-chemin {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  min-width: 0;
  font-size: var(--fs-xs);
  color: var(--gray-4);
}

.choix-fichier-chemin .icon { width: var(--icon-xs); height: var(--icon-xs); flex: none; }
.choix-fichier-chemin > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* La teinte d'une zone, et elle se transmet a tout ce qui y est range : le
   juridique en bleu fonce, le comptable en vert, la conso en jaune. Ce sont
   les memes teintes que la liste des zones de fichiers (.juridique-row-*) et
   que la boite « Deplacer » (.dialogue-deplacer-item.marque-*). Apres les
   regles ci-dessus : a specificite egale, c'est l'ordre qui tranche. */
.choix-fichier-famille-juridique,
.choix-fichier-famille-juridique .icon { color: var(--blue-dark); }
.choix-fichier-famille-comptable,
.choix-fichier-famille-comptable .icon { color: var(--green); }
.choix-fichier-famille-conso,
.choix-fichier-famille-conso .icon { color: var(--yellow); }
.choix-fichier-famille-cabinet,
.choix-fichier-famille-cabinet .icon { color: var(--purple); }
/* Le « Documents » des missions exceptionnelles : la cinquieme zone, la
   cinquieme teinte. Appariee a `EspaceFichiers.teinte` dans app/parite.json
   (`famille_zone_piece`). */
.choix-fichier-famille-documents,
.choix-fichier-famille-documents .icon { color: var(--blue); }
/* Meme piege que le choix de mandat juste au-dessus : `hidden` seul ne cache
   pas un element qu'une regle met en `flex`. Le cadre d'apercu part quand la
   boite sert a choisir un document -- un .docx ne se peint pas, et le cadre
   vide n'aurait rien dit. */
.choix-fichier-apercu[hidden] { display: none; }
.choix-fichier-apercu {
  flex: none;
  width: 12rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  padding: var(--espace-sm);
}
.choix-fichier-apercu img { max-width: 100%; max-height: 11rem; object-fit: contain; }
.choix-fichier-apercu-vide { font-size: var(--fs-xs); color: var(--gray-4); text-align: center; }
.choix-fichier-etat { margin: 0; font-size: var(--fs-xs); color: var(--gray-5); }

/* La barre de selection : combien de pieces sont retenues, et ce qu'on peut
   en faire. Elle apparait des qu'il y en a une -- retenue au balayage ou a la
   pastille, c'est la meme selection -- et se pose sous le fil d'Ariane, la ou
   l'oeil revient apres avoir coche. En bas de zone, un repertoire de cinquante
   pieces l'aurait mise hors de l'ecran au moment meme ou elle sert. */
/* `display: flex` ecrase l'attribut `hidden`, dont la seule force est le
   `display: none` de la feuille du navigateur. Sans cette regle, la barre
   reste a l'ecran une fois la selection lachee, et y affiche un compte qui
   n'est plus vrai -- constate au navigateur le 17 aout 2026.

   Elle se cache en devenant invisible et non en disparaissant, et c'est tout
   sauf un detail : la barre s'affiche au PREMIER clic d'une ligne, et en
   apparaissant elle poussait la liste de cinquante-deux pixels vers le bas --
   deux lignes. Le second clic d'un double-clic tombait donc deux lignes plus
   haut que le premier, et l'on ouvrait un fichier qu'on n'avait pas vise.
   Mesure au navigateur le 31 aout 2026 : viser « RAPPORT DU TRESORIER.docx »
   et double-cliquer ouvrait « ATTESTATION HANDBALL.pdf », deux lignes
   au-dessus.

   C'est la panne que decrit le suivi du 31 aout 2026 -- « lorsque je clique
   dessus, cela ouvre le dossier au lieu de permettre de le renommer » : on vise
   le crayon d'une ligne, le premier clic la retient, tout descend d'un cran, et
   le clic suivant tombe sur une autre ligne, qui s'ouvre.

   `visibility` garde la boite. La bande reste donc reservee en permanence, et
   la liste ne bouge plus jamais -- ni a l'apparition de la barre, ni a sa
   disparition, ni quand son contenu passe a la ligne sur une fenetre etroite,
   ce qu'aucune hauteur ecrite a la main n'aurait su suivre.

   C'est l'exception que le filet du haut de la feuille prevoit et exige de
   dire : garder sa case et n'effacer que son trace demande de reecrire
   `display` avec son propre `!important`, sans quoi
   `[hidden] { display: none !important }` reprend la main et la boite s'en va
   avec le trace. */
.barre-selection[hidden] {
  display: flex !important;
  visibility: hidden;
  pointer-events: none;
}
.barre-selection {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace);
  flex-wrap: wrap;
  /* Le creux vertical est au plus petit barreau : ce sont les boutons qui
     donnent sa hauteur a la barre (leur plancher est --h-sm), et cette hauteur
     est celle de la reserve permanente au-dessus de la liste. Chaque pixel de
     creux y est donc paye en air, meme quand rien n'est retenu. */
  padding: var(--espace-3xs) var(--espace-sm);
  background: var(--blue-pale);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
}
.barre-selection-compte {
  font-size: var(--fs);
  font-weight: 600;
  color: var(--blue-dark);
}
.barre-selection-actions { display: flex; align-items: center; gap: var(--espace-2xs); }

.source-statut {
  font-size: var(--fs-2xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  color: var(--gray-5);
}

.source-statut-traite { background: var(--green-pale); color: var(--green); }
.source-statut-erreur { background: var(--red-pale); color: var(--red); }
.source-statut-en_attente { background: var(--cyan-light); color: var(--cyan-dark); }

/* La marque du cabinet a droite du statut : le resultat du FEC est celui que
   le rapport sur les comptes annuels ecrit (ticket ENCRES DUBUIT du
   16 septembre 2026). Meme rouge et meme gabarit que partout ailleurs ou
   cette marque parait -- la ligne d'un mandat, l'echeance, un document
   produit ici. */
.source-marque-cac {
  display: inline-flex;
  align-items: center;
  margin-left: var(--espace-3xs);
  color: var(--red);
  vertical-align: middle;
}
.source-marque-cac .icon { width: var(--icon-xs); height: var(--icon-xs); }

/* Colonne « Clôture » : le verdict de validation du FEC, lu dans ValidDate
   (voir etatCloture dans app.js). « Partiel » emprunte l'orange des signaux
   qui demandent un regard ; « Indéterminé » reste gris, parce qu'il ne dit
   rien de plus que « on ne sait pas ». */
.source-cloture-definitif { background: var(--green-pale); color: var(--green); }
.source-cloture-provisoire { background: var(--cyan-light); color: var(--cyan-dark); }
.source-cloture-partiel { background: var(--orange-pale); color: var(--orange); }
.source-cloture-indetermine { background: var(--gray-1); color: var(--gray-5); }

/* La colonne « Résultat » affiche desormais le resultat comptable du fichier,
   pas un verdict d'equilibre : plus de pastille verte/orange, un montant. Un
   fichier dont les debits et credits ne s'equilibrent pas rend ce chiffre
   suspect -- il est donc teinte, et l'infobulle dit pourquoi. */
/* Le resultat d'un fichier source, colore par son signe comme la ligne
   « Resultat de l'exercice » des cycles (.tree-table td.positive/.negative).
   La couleur est portee ici par un <span> et non par la cellule : la colonne
   est deja `num`, et seul le chiffre doit changer de teinte. */
.sources-table .positive { color: var(--green); }
.sources-table .negative { color: var(--red); }

/* Debits et credits qui ne s'equilibrent pas : un triangle orange apres le
   chiffre, plus la mise en gras. La teinte orange etait portee par le chiffre
   lui-meme, ce qui interdisait de le colorer par son signe -- or ce sont deux
   informations differentes, combien et fiable ou non. */
.source-resultat-ecart-valeur { font-weight: 600; }

.source-resultat-ecart-valeur::after {
  content: " ⚠";
  color: var(--orange);
}

/* Un FEC neutralise reste dans la liste (son fichier, ses actions restent
   accessibles) mais s'efface visuellement : il ne compte plus dans le
   calcul, la ligne le dit sans qu'il faille lire la colonne Statut. */
.source-row-neutralise { opacity: .5; }
.source-row-neutralise:hover { opacity: .8; }

/* Switch pris en compte / neutralise (colonne dediee de #sources-table) : un
   seul controle a deux etats visibles d'un coup d'oeil, plutot qu'un bouton
   icone dont il fallait deviner le sens. */
.switch-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  border: none;
  background: var(--gray-3);
  cursor: pointer;
  padding: 2px;
  flex: none;
  transition: background .15s var(--ease);
}

.switch-btn[aria-checked="true"] { background: var(--green); }

.switch-thumb {
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: transform .15s var(--ease);
}

.switch-btn[aria-checked="true"] .switch-thumb { transform: translateX(14px); }

.btn-danger { color: var(--red); }

/* Bouton reduit a son icone (ex. supprimer une source, ajouter un mandat) :
   carre, et de la hauteur commune aux petits controles. Son remplissage seul
   lui donnait 29 px, a cote des 26 d'un bouton-lien a libelle et des 28 d'un
   carre de rang -- trois voisins d'une meme rangee, trois hauteurs. */
.btn-link.btn-icon-only {
  padding: var(--espace-2xs);
  gap: 0;
  justify-content: center;
  min-width: var(--h-sm);
}

.btn-primary.btn-icon-only {
  padding: var(--espace-sm);
  gap: 0;
  justify-content: center;
}

/* Un bouton pose dans une ligne de reglages porte un cadre au repos, qu'il
   ait un libelle ou seulement une icone. Rien ne l'entourait : trois icones
   qui se suivent -- renommer, remplacer, supprimer le justificatif de
   nomination -- formaient une file de dessins gris ou l'on ne voyait pas ou
   finit l'un et ou commence l'autre, et un libelle cyan pose a plat ne se
   distinguait pas du texte de la ligne (« des boutons qui s'entrechoquent et
   qui ne sont pas bien delimites », 26 aout 2026).

   Le cadre est celui que la feuille donne deja au petit controle carre, celui
   de .type-seg : trait --gray-3, fond blanc, --radius-sm. Une ligne se lit
   alors comme un groupe -- un bouton plein pour l'action principale, des
   boutons cernes pour les autres -- au lieu d'une suite de dressages. La
   rangee du justificatif de nomination en compte six : « Remplacer » plein,
   « Choisir dans le mandat » et le nom du fichier a plat, puis trois icones.
   Depuis que les icones ont recu leur cadre, un dressage sur deux se voyait
   d'autant mieux.

   Porte sur les lignes de reglage, pas sur toute la feuille : dans une barre
   d'outils -- la visionneuse, l'atelier d'annotation, la barre collante de la
   liste des mandats, l'entete d'une colonne de conversations -- l'icone nue est
   la bonne forme, c'est la barre et ses separateurs qui la delimitent. Dans une
   ligne de reglage il n'y a pas de barre, seulement des cases cernees les unes a
   cote des autres, et une icone posee a plat au bout n'appartient a rien.

   Les deux listes de « Mon cabinet » sont exactement cette forme-la, et la
   regle ne les avait pas atteintes. Dans « Gestion des cabinets », la rangee
   aligne un nom, des initiales et une roue de couleur, tous cernes de
   --gray-3 sur fond blanc, puis une corbeille rouge nue a 1385 px. Dans
   « Gestion de l'equipe », la meme corbeille touche directement la liste
   deroulante du role, cernee elle aussi : la case s'arrete a 1367, l'icone
   commence a 1377 -- dix pixels entre un cadre et un dessin, sans rien qui
   dise ou l'un finit.

   `.reglages-piece` figure dans chacune de ces listes parce que le
   combinateur est direct : le nom d'une piece deposee et ses icones sont
   groupes dans un `span`, donc enfants du groupe et non de la rangee. Sans
   cette ligne, les trois icones du justificatif de nomination perdraient le
   cadre que cette regle vient de leur donner -- et le groupe qui les reunit
   les aurait deshabillees en les rassemblant.

   Le remplissage n'est plus repete ici. Cette regle abaissait le remplissage
   vertical d'un barreau parce que la bordure compte dans la hauteur et qu'un
   bouton-lien cerne passait a 30 px ; depuis que la base pose un plancher a
   --h-sm et laisse le remplissage passer dessous, c'est le plancher qui decide
   et la bordure ne le deplace plus. */
.reglages-row > .btn-link,
.reglages-piece > .btn-link,
.reglages-presence-row > .btn-link,
.cabinet-gestion-form > .btn-link,
.equipe-gestion-form > .btn-link {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.reglages-row > .btn-link.btn-icon-only,
.reglages-piece > .btn-link.btn-icon-only,
.reglages-presence-row > .btn-link.btn-icon-only,
.cabinet-gestion-form > .btn-link.btn-icon-only,
.equipe-gestion-form > .btn-link.btn-icon-only {
  width: var(--h-sm);
  height: var(--h-sm);
  padding: 0;
  flex: none;
}

/* Le survol repeint le trait de la couleur du geste, comme le carre retenu
   d'un rang : sans cette regle le fond blanc ci-dessus, plus specifique que
   `.btn-link:hover`, effacerait le survol au lieu de l'habiller. */
.reglages-row > .btn-link:hover,
.reglages-piece > .btn-link:hover,
.reglages-presence-row > .btn-link:hover,
.cabinet-gestion-form > .btn-link:hover,
.equipe-gestion-form > .btn-link:hover {
  background: var(--cyan-pale);
  border-color: var(--cyan);
}

.reglages-row > .btn-link.btn-danger:hover,
.reglages-piece > .btn-link.btn-danger:hover,
.reglages-presence-row > .btn-link.btn-danger:hover,
.cabinet-gestion-form > .btn-link.btn-danger:hover,
.equipe-gestion-form > .btn-link.btn-danger:hover {
  background: var(--red-pale);
  border-color: var(--red);
}

.dossier-form {
  display: flex;
  gap: var(--espace);
  margin-bottom: var(--espace-xl);
  flex-wrap: wrap;
}

.dossier-form[hidden] { display: none; }

/* L'onglet Mandat, et le bloc de signature de « Mon compte » qui reprend les
   memes classes.
   Resserre le 15 aout 2026 : quinze reglages y sont empiles, chacun avec son
   etiquette, sa ligne et souvent son paragraphe d'explication, et l'ensemble
   demandait un ecran et demi pour une page qu'on ouvre afin de changer une
   valeur et de ressortir. Ce sont les blancs qui ont ete repris, jamais la
   taille de ce qui se lit : etiquette collee a sa ligne, groupes plus
   rapproches, champs moins hauts. Rien ne disparait, tout remonte. */
.reglages-group {
  margin-bottom: var(--espace);
}

/* Le filet qui separe deux rangees a l'interieur d'une tuile.

   Il a ete pose le 26 aout 2026 pour separer des sections, quand le panneau
   n'en etait qu'une colonne : vingt-trois d'affilee, et rien entre deux
   voisines qu'un blanc de quatorze pixels, pas plus large que celui qui separe
   deja deux rangees de la meme section. Rien ne distinguait « la section
   suivante commence » de « la ligne suivante de la meme section ».

   Le filet a bien fait cette difference-la, mais il ne pouvait pas la faire
   vingt-trois fois : au-dela de quelques traits, une colonne de filets
   redevient un mur (demande du 30 aout 2026, voir `.tuile` en tete de
   feuille). Ce sont les tuiles qui separent les sections desormais, et le
   filet descend d'un rang -- il separe les rangees d'une meme tuile, ce pour
   quoi un trait suffit et convient : deux ou trois par tuile, jamais vingt.

   L'air vaut `--espace-sm` sous le filet, contre les douze pixels et huit de
   marge qui subsistent au-dessus (les marges voisines se rabattent l'une sur
   l'autre, c'est la plus grande qui reste ; c'est aussi pourquoi le
   `margin-top` ci-dessous ne s'applique jamais) : le filet appartient a la rangee
   qu'il ouvre. L'intitule qui le suit garde ses quatre pixels jusqu'a sa
   premiere ligne, soit le meme rapport de 2,4 qui fait deja lire un groupe
   dans une rangee de reglages.

   `.aglae-bloc` n'est plus nomme ici : les sept sections du volet CNCC qui
   vivent dedans sont devenues des tuiles, et la frontiere entre le mandat
   natif et ce qu'Aglae remplit -- celle qui compte le plus -- se voit comme
   toutes les autres, par le bord d'une tuile. */
.reglages-group + .reglages-group {
  margin-top: var(--espace-sm);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
}

/* La frise du mandat, en tete de l'onglet Mandat.

   Six paves poses cote a cote, un par exercice controle, du premier au
   dernier. Ce qui doit se voir sans etre lu : ou l'on en est, et quel est le
   dernier -- c'est apres celui-la qu'il faut avoir fait renouveler. D'ou trois
   teintes seulement, chacune disant un etat et pas une nuance : gris pour ce
   qui est passe, cyan pour l'exercice en cours, orange pour le dernier.

   L'orange plutot que le rouge : le rouge dit une faute, or un dernier
   exercice de mandat n'est pas une faute -- c'est une echeance. C'est la meme
   teinte que l'etat « urgent » d'un exercice (regles_affichage de
   parite.json), qui veut dire la meme chose : a traiter avant qu'il ne soit
   tard.

   Pas de regle d'affichage a declarer pour autant : l'app dit la meme frise en
   lignes de texte, sans teinte -- un ecran de telephone n'a qu'une colonne, et
   la brique employee (ligne_valeur) ne peint pas. Il n'y a donc aucun etat
   metier peint des deux cotes qui pourrait diverger. */
/* Le creux et l'ecart bas sont ceux d'une tuile (`.tuile`, en tete de
   feuille) : la frise ouvre la colonne des tuiles de l'onglet, et son texte
   doit partir du meme bord gauche que leurs titres. Ecrit `--espace` en
   horizontal, il en partait 7,2 px plus a gauche -- deux boites empilees dont
   les contenus ne s'alignent pas.

   Ce qui reste a elle : un fond gris. La frise n'est pas un reglage, ne se
   remplit pas, ne s'enregistre pas -- c'est l'etat du mandat, lu d'un coup
   d'oeil en haut de l'onglet. Le fond gris la sort de la pile blanche sans
   ajouter ni trait ni titre.

   Ce fond valait --gray-1 tant que la page etait blanche. Le sol a pris cette
   teinte le 31 aout 2026 (voir `body`), et la frise s'y serait fondue : seule
   surface de l'onglet a reculer dans la page pendant que les tuiles en
   sortent, soit exactement le contraire de ce qu'on lui demande. Elle descend
   donc d'un barreau. L'arbitrage ne bouge pas, c'est la teinte qui le servait
   qui a change de role sous lui. */
.frise-mandat {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: var(--gray-2);
  padding: var(--espace-md) var(--espace-lg);
  margin-bottom: var(--espace-md);
}

.frise-mandat[hidden] { display: none; }

.frise-mandat-entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--espace-xs) var(--espace-md);
  margin-bottom: var(--espace-sm);
}

.frise-mandat-titre {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
}

.frise-mandat-echeance {
  font-size: var(--fs);
  font-weight: 600;
  color: var(--orange-dark);
}

/* Un mandat deja expire ne s'annonce plus comme une echeance a venir : c'est
   un manquement en cours, et la seule fois ou le rouge est le bon mot. */
.frise-mandat-echeance-echu { color: var(--red); }

.frise-mandat-exercices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Les six paves se deploient sur toute la largeur de la page, et s'y
   redistribuent des qu'elle change (demande du 22 aout 2026 : « la frise des
   mandats, soit les 6 cases, doit se deployer sur la largeur de la page de
   facon dynamique »). Taillees au plus juste, elles laissaient la moitie de la
   ligne vide a droite du dernier exercice, et la frise, qui est la premiere
   chose de l'onglet, se lisait comme un reste.

   `1 1 auto` et non `1 1 0` : la base reste le contenu, et seul l'espace
   restant se partage a parts egales. C'est ce qui concilie cette demande avec
   celle de la veille (« fait que les cases s'ajustent automatiquement a la
   taille "2021 1/6", "2025 5/6 EN COURS", "2026 6/6 DERNIER" ») : un pave
   marque reste plus large qu'un pave nu -- c'est le contenu qui le dit --, mais
   plus aucun blanc ne traine en fin de ligne. Reparties a egalite (`1 1 0`),
   les six auraient retrouve la regle graduee qu'on venait de defaire.

   Le retrait (`1` et non `0` en second) suit : trop etroite pour les six, la
   rangee se replie comme avant, et les paves d'une rangee entamee se partagent
   ce qu'il reste sans jamais descendre sous leur texte (`white-space: nowrap`
   plus bas, qui les empeche de couper). */
.frise-mandat-exercice {
  flex: 1 1 auto;
  display: flex;
  align-items: baseline;
  /* L'espace gagne se pose de part et d'autre du texte, et non derriere lui :
     un pave elargi dont le contenu reste colle a gauche laisse un blanc qui se
     lit comme une case a moitie remplie. Centre, il se lit comme une case. */
  justify-content: center;
  gap: var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  padding: var(--espace-2xs) var(--espace-sm);
}

.frise-mandat-rang {
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--gray-4);
  letter-spacing: var(--suivi-serre);
  white-space: nowrap;
}

.frise-mandat-cloture {
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.15;
  color: var(--gray-6);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* La marque termine la ligne. Elle etait poussee a droite -- les six paves
   alignaient alors leurs « En cours » et « Dernier » sur un meme bord --, ce
   qui n'a plus d'objet depuis que chaque pave fait la largeur de son contenu :
   il n'y a plus de blanc a pousser, et le `margin-left: auto` ne servirait
   qu'a rouvrir celui qu'on vient de fermer. Elle suit donc le rang, a la
   distance ordinaire (le `gap` de la ligne). */
.frise-mandat-marque {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-4);
  white-space: nowrap;
}

.frise-mandat-echu {
  background: var(--gray-2);
  border-color: var(--gray-3);
}

.frise-mandat-echu .frise-mandat-cloture { color: var(--gray-4); }

.frise-mandat-courant {
  background: var(--cyan-pale);
  border-color: var(--cyan);
  box-shadow: var(--shadow-sm);
}

.frise-mandat-courant .frise-mandat-cloture,
.frise-mandat-courant .frise-mandat-marque,
.frise-mandat-courant .frise-mandat-rang { color: var(--cyan-dark); }

/* Le dernier exercice l'emporte sur son etat : qu'il soit a venir, en cours ou
   deja clos, c'est lui qu'on est venu voir. */
.frise-mandat-dernier {
  background: var(--orange-pale);
  border-color: var(--orange);
}

.frise-mandat-dernier .frise-mandat-cloture,
.frise-mandat-dernier .frise-mandat-marque,
.frise-mandat-dernier .frise-mandat-rang { color: var(--orange-dark); }

.reglages-group .toolbar-label {
  display: block;
  margin-bottom: var(--espace-2xs);
}

/* Un intitule qui porte une marque : « Titulaire » suivi du grand C, le titre
   du groupe des commissaires aux comptes suivi du meme. Une gelule « Cc » a
   qualifie le premier le 22 aout 2026, avant que la demande soit precisee --
   « prends la vignette rouge d'un petit c entoure d'un grand C, deja utilisee
   pour les rapports du commissaire aux comptes ». C'est donc le meme dessin aux
   deux endroits, et cette regle est ce qui le pose au fil d'un intitule.

   `flex` et non `inline-flex` : ces intitules restent des blocs, comme le veut
   la regle des groupes de reglages juste au-dessus. C'est l'ecart de la boite
   qui espace la marque, et non la marge que `.badge-maison` porte sur une ligne
   de document -- d'ou sa remise a zero.

   Le selecteur porte les deux classes, et il le faut : `.toolbar-label-marque`
   seul pese moins que `.reglages-group .toolbar-label` juste au-dessus, qui
   pose `display: block`. La mise en flex ne prenait donc pas, et un `gap` sur
   un bloc ne fait rien -- tandis que la remise a zero de la marge, elle,
   prenait. Les deux seules choses qui separaient la marque de l'intitule
   s'annulaient l'une l'autre : la vignette rouge se posait a zero pixel du
   « E » de « TITULAIRE » et du « S » de « COMMISSAIRES AUX COMPTES », lettre
   contre trace (releve le 26 aout 2026 sur le mandat ACBB).

   Meme taille pour les deux, et pour celles qui viendront : deux tailles d'une
   meme marque se verraient avant son sens. Cette regle-ci le disait tout en
   posant `--icon-md` a cet endroit seul, quand la marque d'une ligne de
   document valait 15 px et celle d'une case du catalogue 16 : trois tailles
   pour un meme dessin, dont deux hors des six barreaux de l'echelle. Un
   intitule de reglages est plus petit qu'un nom de fichier, et la marque y
   etait pourtant la plus grande. Plus aucune taille ne se pose donc ici : la
   base de la feuille habille toute icone en `--icon`, et la marque en est
   une. */
.toolbar-label.toolbar-label-marque {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

.toolbar-label-marque .badge-maison {
  margin-left: 0;
}

/* Une rangee de reglages qui manque de place se plie, elle ne deborde pas.

   Sans `flex-wrap`, une rangee de boutons trop large pour sa tuile a deux
   facons de mal finir, et elle les prenait toutes les deux : ce qui peut
   retrecir retrecit -- « Deduire de l'icone » se cassait sur trois lignes a
   l'interieur d'un bouton de soixante pixels --, et ce qui ne peut pas sortait
   du cadre. Mesure sur la charte du groupe a 1100 px : 71 px hors de la tuile.

   Le defaut dormait : les rangees tenaient tant qu'elles avaient toute la
   largeur de la page. Il s'est reveille des que l'ecran du groupe est passe en
   deux colonnes, et il attendait de la meme facon partout ailleurs. La reponse
   appartient donc a la rangee, pas a l'un de ses usages -- `gap` porte deja
   l'ecart entre deux lignes, il n'y a rien d'autre a poser. Elle rend inutile
   le `flex-wrap` que le choix de l'icone du groupe se posait a part.

   La bande tablette de `mobile.css` le posait deja, dans le triplet qui
   redresse la rangee apres l'avoir mise en colonne sous 600 px : la reponse
   avait donc ete trouvee une fois, a une largeur pres, et n'etait jamais
   remontee. Elle y reste, c'est une geometrie rendue entiere, pas un oubli.

   Releve au navigateur sur les quatre ecrans qui s'en servent : une seule
   rangee change ailleurs, celle du rapport a remplacer de l'onglet Mandat, qui
   passe de trois lignes serrees a deux lignes entieres. */
.reglages-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-sm);
}

/* La piece deposee et les gestes qui ne valent que sur elle : son nom, le
   crayon qui la renomme, la corbeille qui la retire -- et, quand elle
   s'annote, le stylo.

   Sans ce groupe, la rangee du justificatif de nomination alignait six
   controles a la meme distance les uns des autres : deux gestes de
   chargement, un nom de fichier, puis trois gestes qui ne portent que sur lui.
   Rien ne disait lesquels allaient ensemble, et le nom -- habille en
   `btn-link` parce qu'il se retelecharge -- ressemblait exactement au bouton
   d'a cote. Un nom et un verbe voisins, de meme apparence, a la meme distance.

   Le rapport est celui deja pose par la charte graphique deux groupes plus
   haut : `--espace-2xs` a l'interieur du groupe contre les .6rem de la rangee,
   soit deux fois et demie plus large dehors que dedans. C'est ce qui se lit,
   pas la valeur absolue.

   `flex-wrap` parce qu'un nom de fichier depose se mesure en dizaines de
   caracteres et qu'a 390 px de large la rangee passe a la ligne : le groupe
   plie avec elle plutot que de pousser ses icones hors du panneau. */
.reglages-piece {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  flex-wrap: wrap;
}

/* Tant qu'aucune piece n'est deposee, tout ce que le groupe contient est
   `hidden` -- mais le groupe, lui, reste un element de la rangee, et la rangee
   lui donne ses .6rem de chaque cote. Un couloir vide de neuf pixels devant le
   voyant d'etat, la ou il n'y avait rien avant : le groupe s'efface donc quand
   il n'a plus rien a montrer. */
.reglages-piece:not(:has(> :not([hidden]))) {
  display: none;
}

/* L'equipe du mandat : une ligne par personne -- son rond, son nom, le bouton
   qui la designe signataire, sa cadence de suivi des depots, et de quoi la
   retirer (suivi du 25 aout 2026 : « il faudrait regrouper Signataire,
   Collaborateur et Suivi des depots dans une meme logique »).

   Une grille et non des `flex` empiles : les cinq colonnes doivent s'aligner
   d'une ligne a l'autre, sinon les boutons et les listes ondulent avec la
   longueur des noms. */
/* La quatrieme colonne est la liste deroulante qui dit ce dont la personne est
   avertie. `max-content` ne sait pas se serrer : la rangee tenait ses cinq
   colonnes tant que la tuile faisait 1336 px, et debordait de sept pixels des
   qu'elle en fait 660. `minmax(0, max-content)` lui laisse sa largeur quand la
   place existe et l'autorise a la rendre quand elle manque -- un `<select>`
   coupe son texte tout seul, c'est la seule des cinq colonnes qui sache le
   faire sans rien perdre. */
.reglages-equipe {
  display: grid;
  grid-template-columns: auto auto max-content minmax(0, max-content) 1fr;
  align-items: center;
  gap: var(--espace-xs) var(--espace-sm);
}

/* La ligne etait un `display: contents` : elle disparaissait, ses cinq elements
   devenaient ceux de la grille, et il ne restait rien pour dire ou une personne
   finit et ou la suivante commence. Le panneau compte quatre listes ; les trois
   autres bornent leurs lignes -- une carte cernee pour les intervenants, un
   cadre pour les exercices, une rangee de champs pleine largeur pour la presence
   en ligne --, et sur un telephone l'equipe le fait aussi, avec un filet
   (mobile.css). L'ordinateur etait le seul endroit ou elle ne le faisait pas.

   `subgrid` la remet en boite sans lui rendre ses colonnes : elle reprend celles
   de la liste, donc les ronds, les noms, les etiquettes et les listes deroulantes
   restent alignes d'une personne a l'autre -- c'est l'argument ecrit au-dessus de
   la grille --, et elle gagne le filet et le rembourrage qu'un `contents` ne
   pouvait pas porter.

   La cinquieme colonne passe de `max-content` a `1fr` : la croix de retrait
   s'arretait a 755 px dans une rangee qui en fait 1336, seule au milieu du vide,
   pendant que la corbeille d'un intervenant, celle d'un exercice et la croix
   d'une adresse tombent toutes a 1393. Un seul geste, quatre listes, et une qui
   ne visait pas le meme bord. */
.reglages-equipe-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
  padding-bottom: var(--espace-xs);
  border-bottom: 1px solid var(--gray-2);
}

.reglages-equipe-row:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.reglages-equipe-nom {
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

/* Le role, lu comme une etiquette et non comme un formulaire : le mot passe en
   cyan des que le bouton est allume, ce qui suffit a dire qui signe sans qu'on
   ait a chercher le rond coche. */
.reglages-equipe-signataire {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--gray-4);
  cursor: pointer;
}

.reglages-equipe-signataire:has(input:checked) {
  color: var(--cyan-dark);
}

.reglages-equipe-signataire:has(input:disabled) {
  cursor: default;
  opacity: .6;
}

/* Le retrait, exactement celui des trois autres listes du panneau : meme
   geste, donc meme boite. C'est un carre cerne de 28 px, `--radius-sm` sur du
   blanc -- la forme que la corbeille d'un exercice et le crayon d'un
   intervenant ont prise le 26 aout 2026, chacun avec un commentaire se croyant
   « le dernier bouton nu du panneau Mandat ». Ils l'etaient chacun de son cote,
   et aucun des deux n'a vu les six croix restees rondes : trois a l'equipe,
   trois a la presence en ligne.

   Le rond venait d'un arbitrage anterieur qui le tenait de la croix des
   intervenants -- « meme geste, donc meme croix ». Cette croix-la n'existe plus
   depuis que la carte d'un intervenant porte un crayon et une corbeille, donc
   la raison ne tenait plus, et une ligne de presence en ligne le montrait a dix
   pixels pres : une fleche carree, puis une croix ronde, meme taille, meme
   filet, deux systemes. L'autre appui du rond etait la pastille d'initiales du
   titulaire ; un rond de profil et un bouton ne sont pas la meme famille.

   Le survol suit celui des voisines -- `--red-pale` sous un filet rouge --
   plutot que le rouge plein qu'il portait seul. */
.reglages-equipe-retirer {
  width: var(--h-sm);
  height: var(--h-sm);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
  padding: 0;
  justify-self: end;
}

/* La croix du signataire s'efface mais garde sa case : les lignes sont des
   `display: contents` dans une grille a cinq colonnes, et une case en moins
   ferait glisser toute la ligne suivante d'un cran.

   `!important` parce que la regle de securite en tete de feuille en porte un :
   `[hidden] { display: none !important }` gagnait ici, et le glissement que ce
   commentaire annonce se produisait depuis. Chaque rond de profil se retrouvait
   en cinquieme colonne de la ligne precedente -- a l'autre bout du panneau,
   au-dessus du nom d'une autre personne -- et l'etiquette « SIGNATAIRE » de la
   premiere ligne s'etirait sur la colonne des listes (releve le 26 aout 2026
   sur le mandat ACBB). C'est la seule facon de garder une case dans une grille
   sans sortir de l'attribut `hidden` que le script pose et retire. */
.reglages-equipe-retirer[hidden] {
  display: flex !important;
  visibility: hidden;
  pointer-events: none;
}

.reglages-equipe-retirer:hover {
  background: var(--red-pale);
  border-color: var(--red);
  color: var(--red);
}

.reglages-row input[type="text"],
.reglages-row input[type="number"] {
  font-family: var(--sans);
  font-size: var(--fs-md);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  min-width: 260px;
  min-height: var(--h-champ);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.reglages-row input[type="number"] {
  min-width: unset;
}

/* « Grow » disait de prendre la place, pas toute la place. Ces deux champs --
   la denomination et le nom court -- sont les seuls du panneau Mandat a etre
   seuls dans leur rangee : rien ne les arretait, et ils couraient donc sur les
   1336 px du panneau. Mesure au navigateur le 27 aout 2026 : sur les
   cinquante-huit champs de l'onglet, cinquante-six plafonnent a 642 px, et ces
   deux-la font 1336. « ACBB » s'ecrivait au bord gauche d'une case large comme
   l'ecran, et la meme denomination reparaissait quinze rubriques plus bas, dans
   « Entite controlee », sur 352 px.

   Deux natures, donc deux mesures, et deux barreaux qui existaient deja :

   -- la denomination est une ligne de texte -- « LA CONFEDERATION NATIONALE DES
      BURALISTES DE FRANCE », dit le gabarit --, donc --largeur-lecture, la
      longueur au-dela de laquelle l'oeil perd le debut de la ligne suivante ;
   -- le nom court est court par definition -- c'est tout son propos, et le
      gabarit l'ecrit : « celle qui ne tient nulle part » d'un cote, « ex :
      Buralistes de France » de l'autre. Il prend --largeur-colonne, la mesure
      d'un formulaire seul dans sa page, la plus etroite des cinq.

   Le plancher de 320 px ne bouge pas : sous 820 px la rangee devient une
   colonne et aucun des deux plafonds ne mord. */
.reglages-row .reglages-input-grow {
  flex: 1 1 auto;
  min-width: 320px;
  max-width: var(--largeur-lecture);
}

#reglages-nom-court-input { max-width: var(--largeur-colonne); }

/* Trois des cinq porteurs de `.reglages-input-grow` ne recevaient rien de la
   regle du dessus, pour la meme raison : elle ne nomme que ce qui est un
   `input` dans une `.reglages-row`.

   Les deux listes deroulantes -- le groupe et sa societe mere -- retombaient
   donc sur le `select` nu de la tete de feuille. Mesure au navigateur le 29
   aout 2026 : 29,8 px de haut et 12,8 px de texte, sous les deux cases de
   saisie qui portent la meme classe trois rangees plus haut, a 32 et 14,4.
   Meme classe, meme largeur de 736 px, l'une au-dessus de l'autre dans le
   meme panneau, et deux hauteurs. C'est le defaut que --h-champ a ete pose
   pour fermer le 27 aout : il avait ferme les cases et laisse les listes.

   Nomme par l'element et non par la rangee entiere : la troisieme liste de la
   rangee, `.dossier-assigne-select`, est une commande et non une case -- elle
   se tient a --h-sm, a cote du bouton qu'elle accompagne. */
.reglages-row select.reglages-input-grow {
  font-size: var(--fs-md);
  min-height: var(--h-champ);
}

/* La regle `.reglages-input-siren` vivait ici : elle calait la case SIREN des
   reglages sur la largeur des deux cases jour/mois de la date de cloture. Cette
   case a ete retiree le 22 aout 2026 -- elle faisait double emploi avec
   « Numero SIREN » du volet CNCC --, et la regle avec elle : une feuille de
   style qui garde ses morts finit par les faire revivre au hasard d'un nom de
   classe reutilise. Le champ survivant est une case du volet CNCC, largeur
   tenue par `aglae-champ` (`largeur="libelle"`, onze caracteres). */

.reglages-row input[type="text"]:focus,
.reglages-row input[type="number"]:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.reglages-hint {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

/* Une explication qui attend d'etre demandee.
 *
 * Le panneau de reglages s'ouvre pour changer un reglage en deux gestes, et
 * chaque paragraphe pose sous une case poussait tout ce qui suit vers le bas :
 * quatre lignes sur le repli de la date de cloture, trois sur les formats
 * d'image acceptes, trois encore sur ce qu'est un mandat ALPE. Ces phrases se
 * lisent une fois, la premiere ; elles restaient ensuite entre l'utilisateur
 * et le reglage suivant. Deux d'entre elles ont ete supprimees pour cette
 * raison (14 et 21 aout 2026) -- ce qui reglait l'encombrement en perdant
 * l'explication.
 *
 * Elle vit donc a cote de l'intitule, et se deplie au survol comme le resume
 * des FEC de la liste des clients : meme famille de surface flottante, donc
 * meme forme.
 *
 * Ce qui la demande a change le 4 septembre 2026. C'etait l'intitule lui-meme,
 * souligne en pointille pour se signaler : « remplace le soulignage par petits
 * points, a droite du texte un bouton pour l'interrogation, et c'est ce
 * bouton-la qui affichera le message au survol ». Le pointille disait qu'il y
 * avait quelque chose a lire, mais pas ou viser : la cible etait le mot entier,
 * donc la phrase se depliait des qu'on traversait l'intitule en allant
 * ailleurs, et une page de reglages en compte une dizaine. Un rond de la taille
 * d'une icone, pose a droite du texte et hors de son chemin, se vise quand on
 * le veut et ne se declenche pas quand on ne le veut pas.
 *
 * Le porteur garde `position: relative` : c'est lui qui ancre le panneau, pas
 * le bouton. Ancre sur un rond de seize pixels, une phrase de vingt-huit rem
 * partirait par la droite des que l'intitule est un peu long. */
.libelle-explique {
  position: relative;
}

/* Le point d'interrogation qui appelle l'explication. Pas d'icone du jeu :
   le glyphe est le dessin, et il porte deja son sens a cette taille. */
.explication-appel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon);
  height: var(--icon);
  /* Un demi-espace mot : le rond suit le texte sans s'en decoller. */
  margin-left: .35em;
  padding: 0;
  /* Sur la bande des capitales, et non sur `vertical-align: middle`.
     « Le rond est place trop bas » (suivi du 4 septembre 2026) : `middle`
     centre la boite sur la base plus la moitie de la hauteur d'x, alors que
     l'oeil, devant un intitule tout en capitales comme le sont ceux du panneau
     Mandat, prend pour milieu la moitie de la hauteur des capitales. L'ecart
     vaut la moitie de ce qui separe les deux hauteurs, un pixel mesure sur les
     trois tailles d'intitule qui portent un rond, et il tombe toujours du meme
     cote : vers le bas.
     Une longueur, donc, et non un mot-cle : elle remonte la base du rond
     d'autant au-dessus de celle du texte. Elle se compte dans la police du
     rond, qui est la meme partout (`--fs-3xs`) comme le rond lui-meme est
     partout `--icon` : un objet de taille fixe se recale d'une valeur fixe. */
  vertical-align: .14em;
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  /* Completement rond, donc 999px et pas un barreau de l'echelle. */
  border-radius: 999px;
  /* L'intitule est souvent en petites capitales espacees : le glyphe se lit
     comme un point d'interrogation, pas comme la suite de l'intitule. */
  font-family: inherit;
  font-size: var(--fs-3xs);
  font-weight: 700;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  color: var(--gray-5);
  cursor: help;
  transition: background .15s var(--ease), border-color .15s var(--ease),
              color .15s var(--ease);
}

.explication-appel:hover,
.explication-appel:focus-visible {
  background: var(--cyan-pale);
  border-color: var(--cyan);
  color: var(--cyan-dark);
}

.explication {
  position: absolute;
  top: calc(100% + .4rem);
  left: 0;
  z-index: 60;
  display: none;
  width: max-content;
  /* Jamais plus large que l'ecran : sur un telephone, une phrase de quatre
     lignes posee a 28rem sortait par la droite et se lisait a moitie. */
  max-width: min(28rem, calc(100vw - 2rem));
  padding: var(--espace-sm) var(--espace);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  /* L'intitule est en petites capitales espacees ; l'explication est une
     phrase et se lit comme telle. */
  font-size: var(--fs-sm);
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  line-height: 1.45;
  color: var(--gray-6);
  text-align: left;
  cursor: default;
  /* Le panneau ne se survole pas lui-meme : il flotte au-dessus des cases
     voisines, et laisser la souris le traverser ferait clignoter l'intitule
     qui est dessous. On le lit, on ne le manipule pas. */
  pointer-events: none;
}

/* `:focus` et non `:focus-visible` : sur un ecran tactile il n'y a pas de
   survol, et c'est la mise au point posee par le doigt qui deplie la phrase.
   `:focus-visible` ne se declenche pas la. */
.explication-appel:hover .explication,
.explication-appel:focus .explication { display: block; }

/* L'explication qui n'est pas une phrase (suivi du 5 septembre 2026, rubrique
   « Type de mission ») : « presenter de maniere claire et structuree les
   differentes missions, les normes d'exercice professionnel applicables et
   leurs consequences techniques, tout en restant simple a comprendre ».

   Une entree par mission, toutes du meme gabarit : la designation et sa norme
   en tete, ce que la mission est et ce qu'elle produit dessous. C'est ce
   gabarit repete qui rend la liste lisible, bien plus que la matiere elle-meme :
   on ouvre le panneau pour UNE mission, et la meme forme a chaque entree dit ou
   regarder sans avoir a lire les quatre autres.

   Des `<span>` mis en blocs plutot qu'une liste de definitions : le panneau vit
   dans un `<button>`, dont le contenu ne peut etre que du contenu de phrase.
   La forme est ici, le sens dans le gabarit. */
.explication-intro,
.explication-mission,
.explication-mission-titre,
.explication-mission-texte {
  display: block;
}

/* L'entree se decolle de la precedente, pas de l'intitule qui l'annonce : la
   premiere n'a donc pas de marge haute, et le panneau ne s'ouvre pas sur un
   blanc. */
.explication-mission + .explication-mission,
.explication-intro + .explication-mission {
  margin-top: var(--espace-xs);
}

.explication-mission-titre {
  font-weight: 600;
  color: var(--black);
}

/* Le texte s'efface d'un cran sous son titre : c'est la designation qu'on
   cherche en parcourant, la definition qu'on lit une fois arrive. */
.explication-mission-texte {
  color: var(--gray-5);
}

.reglages-hint-inline {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  font-style: italic;
}

.reglages-hint-erreur { color: var(--red); font-style: normal; }

/* Le voyant d'enregistrement, la ou un bouton « Enregistrer » se tenait
   jusqu'au 27 aout 2026 (« a chaque fois que je modifie un texte, ca soit
   enregistre tout seul »).

   Il occupe la meme place que le bouton et dit exactement ce que le bouton
   garantissait : ce qui part, ce qui est arrive, ce qui a echoue. Discret tant
   que tout va bien -- gris, en italique, efface au bout de deux secondes --,
   rouge et permanent quand le serveur n'a pas pris la modification : c'est le
   seul moment ou l'ecran doit contredire ce qu'on y voit ecrit.

   `[data-etat]` plutot qu'une classe : c'est le module qui l'ecrit, et un
   voyant sans etat est un voyant qui n'a rien a dire. */
.champ-etat,
.reglages-hint-inline[data-etat] {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  font-style: italic;
  align-self: center;
}

.champ-etat[data-etat="ok"],
.reglages-hint-inline[data-etat="ok"] { color: var(--green); }

.champ-etat[data-etat="erreur"],
.reglages-hint-inline[data-etat="erreur"] {
  color: var(--red);
  font-style: normal;
}

/* Une case a cocher sous un champ de reglages : meme retrait que le champ,
   ecrite comme une phrase entiere pour se lire d'une traite sans revenir au
   libelle en tete du bloc. */
.reglages-checkbox {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-top: var(--espace-xs);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  cursor: pointer;
}
.reglages-checkbox input[type="checkbox"] { flex: none; }

/* Le logo du client, dans l'onglet Mandat.
   Un cadre de taille fixe plutot qu'une image libre : les logos arrivent en
   bandeau, en carre ou en timbre, et une ligne de reglages qui change de
   hauteur selon le fichier depose se lit mal. `contain` garde les proportions
   et laisse le fond blanc autour -- un logo n'est pas une photographie qu'on
   recadre. */
.logo-client-cadre {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 140px;
  height: 56px;
  padding: var(--espace-2xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  flex: none;
}

/* Le cadre est une cible de depot, dans les cinq endroits ou il sert : logo
   et tampon d'un cabinet, logo du client, signature scannee, et l'icone d'un
   groupe depuis le 29 aout 2026. La regle vivait sous `.cabinet-image`, seule
   page a avoir recu le glisser-deposer le 15 aout 2026 ; elle porte desormais
   la classe du cadre, comme le geste porte sur la famille d'images et non sur
   la page (voir depot-fichier.js). Le cyan est celui de la grande zone de
   depot d'un mandat : un depot se signale partout de la meme couleur.

   L'apercu d'une icone de groupe s'y ajoute par son propre selecteur plutot
   qu'en prenant la classe du logo du client : son cadre n'a ni la meme taille
   ni le meme fond -- il est damie, pour dire ce qui est detoure --, et seul
   l'etat de depot leur est commun. */
.logo-client-cadre,
.reglages-groupe-apercu {
  cursor: pointer;
  transition: border-color .15s var(--ease), background-color .15s var(--ease);
}

.logo-client-cadre:hover,
.reglages-groupe-apercu:hover { border-color: var(--cyan); }

.logo-client-cadre.dragover,
.reglages-groupe-apercu.dragover {
  border-color: var(--cyan);
  background: var(--cyan-light);
}

/* La charte graphique du client, sous son logo (demande du 27 aout 2026).
   Deux roues de couleur, chacune sous son mot, et l'apercu de ce que le
   document en fera : les trois fonds cote a cote et le nom du client dans
   l'encre secondaire. Une charte se juge sur ses aplats, pas sur ses deux
   pastilles de depart -- un bleu franc et un bleu tres pale donnent la meme
   bande de titres, et c'est la bande qu'on imprime.
   La roue est celle du systeme, deja habillee a la base de la feuille
   (`input[type="color"]`) : il ne reste ici que l'etiquette au-dessus. */
.charte-couleur {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  flex: none;
}

/* Le mot passe a cote de sa roue et non plus au-dessus : empile, il donnait a
   la rangee trois hauteurs de lecture -- les deux mots en haut, les boutons au
   milieu, les roues qui descendaient plus bas qu'eux -- la ou tout le reste du
   panneau tient sur une seule ligne de 28 px. Trois lignes de base dans une
   rangee de six elements se lisent comme trois rangees mal empilees. */

/* La roue de cette rangee prend la mesure du site : 42 px de large, la largeur
   ecrite pour celle de « Mon compte » et d'un cabinet, et la hauteur de la
   rangee ou elle est posee. Nue, elle gardait les 50x27 du navigateur -- une
   troisieme roue chromatique dans le produit, a un pixel pres de la hauteur de
   ses voisines et huit pixels plus large qu'aucune autre. Le meme geste, ici
   comme sous « Mon compte », doit avoir le meme dessin.
   (`.cabinet-gestion-couleur` fait deja descendre la roue a la hauteur de sa
   ligne : c'est la meme regle, avec le barreau nomme depuis.) */
.charte-couleur input[type="color"] {
  width: 42px;
  height: var(--h-sm);
  flex: none;
}

/* L'apercu retombe sur le barreau de la rangee. Ecrit a la main, il en
   depassait de six pixels et faisait de la bande de couleurs le plancher de la
   ligne, alors que c'est elle qu'on regarde en dernier. */
.charte-apercu {
  display: inline-flex;
  align-items: stretch;
  height: var(--h-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: #fff;
  flex: none;
}

.charte-apercu-bande { width: 26px; }

.charte-apercu-encre {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--espace-sm);
  font-size: var(--fs-xs);
  font-weight: 600;
}

/* Un document n'a pas de cadre : rien ne s'affiche, c'est le nom du fichier
   qui en tient lieu. C'est donc le bloc du reglage qui s'allume au survol d'un
   fichier glisse -- meme cyan que le cadre d'une image, pour que le depot se
   signale partout pareil. La classe est posee par depot-fichier.js sur les
   seuls blocs qui acceptent vraiment un depot : peindre tous les reglages
   promettrait un geste que la plupart ne tiennent pas.

   Le selecteur ne nomme plus `.reglages-group` depuis le 24 aout 2026 : la
   photo de profil s'allume de la meme facon, et elle n'est pas un reglage de
   mandat. La classe seule suffit -- c'est deja depot-fichier.js qui decide ou
   elle est posee. */
.depot-cible.dragover {
  outline: 2px dashed var(--cyan);
  /* Le meme retrait que le lisere de la liste d'intervenants, qui est l'autre
     zone de depot du panneau. Il valait .3rem, soit quatre pixels et huit
     contre les quatre de l'autre : huit dixiemes d'ecart entre deux traits qui
     font le meme geste, et aucun barreau de l'echelle sous le premier. */
  outline-offset: var(--espace-2xs);
  border-radius: var(--radius-sm);
  background: var(--cyan-light);
}

.logo-client-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.logo-client-image[hidden] { display: none; }

.logo-client-vide {
  font-size: var(--fs-xs);
  color: var(--gray-4);
}

/* Le logo dans la barre de titre : cale sur la hauteur des tuiles voisines,
   large a discretion parce qu'un logo est plus souvent un bandeau qu'un
   carre. */
.dossier-detail-logo {
  height: 26px;
  max-width: 110px;
  object-fit: contain;
  flex: none;
}

.dossier-detail-logo[hidden] { display: none; }

.reglages-intervenants-liste { display: flex; flex-direction: column; gap: var(--espace-xs); }

/* La liste vide disparaît -- sauf pendant qu'on tient un fichier au-dessus
   d'elle : « il faut pouvoir déposer des fichiers Apple Contact (vcf) »
   (demande du 30 août 2026), et un mandat sans aucun intervenant est justement
   celui où l'on va déposer la première fiche. Une zone de dépôt qui n'existe
   pas tant qu'il n'y a rien dedans ne sert à rien. */
.reglages-intervenants-liste:empty { display: none; }

.reglages-intervenants-liste.depot-actif {
  display: flex;
  min-height: 3.5rem;
  outline: 2px dashed var(--cyan);
  outline-offset: var(--espace-2xs);
  border-radius: var(--radius-sm);
  background: var(--cyan-pale);
}

/* Le nom de famille se voit en majuscules pendant la frappe (demande du 24
   aout 2026), sans transformer la valeur : `text-transform` est un affichage,
   pas une reecriture. La reecriture reelle a lieu cote serveur, dans
   db.set_dossier_intervenants -- c'est elle qui garantit qu'un intervenant
   pose depuis l'API rangera le meme nom que celui saisi ici. */
.reglages-intervenant-row input.reglages-intervenant-nom {
  text-transform: uppercase;
}

.reglages-intervenant-row {
  display: grid;
  /* Six colonnes depuis le 26 aout 2026 : le telephone s'est intercale entre
     le courriel et le bouton. Le courriel garde la part la plus large -- c'est
     lui qui deborde --, le telephone en prend juste assez pour « 06 12 34 56
     78 » sans couper.

     Cinq depuis le 27 aout 2026 : la croix de suppression est sortie de la
     rangee pour devenir une poubelle posee sur la carte, hors de la saisie
     (suivi du 27 aout 2026).

     Six depuis le 28 aout 2026 : le cabinet de la personne s'est intercale
     entre son nom et ses adresses. Il ne parait qu'ici -- la carte refermee
     l'ignore --, et il ne prend donc de la place que pendant la saisie. La
     colonne la plus etroite des six : ce champ est vide chez presque tout le
     monde, et l'adresse reste celle qui deborde.

     Sept depuis le 31 aout 2026, et la premiere ne s'ecrit pas en fractions :
     le rond de l'image (« on doit pouvoir associer un logo ou une photo »)
     mesure 34 pixels et ne s'etire pas. `auto` le laisse a sa taille, les six
     champs se partagent le reste comme avant. */
  grid-template-columns: auto minmax(0, .8fr) minmax(0, .75fr) minmax(0, .75fr) minmax(0, .7fr) minmax(0, 1.2fr) minmax(0, .8fr);
  gap: var(--espace-sm);
  align-items: center;
}

.reglages-intervenant-row input[type="text"],
.reglages-intervenant-row input[type="email"],
.reglages-intervenant-row input[type="tel"],
.intervenant-complement input[type="text"],
.intervenant-complement input[type="url"],
.intervenant-complement textarea {
  font-family: var(--sans);
  font-size: var(--fs-md);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  min-width: 0;
  width: 100%;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.reglages-intervenant-row input[type="text"]:focus,
.reglages-intervenant-row input[type="email"]:focus,
.reglages-intervenant-row input[type="tel"]:focus,
.intervenant-complement input[type="text"]:focus,
.intervenant-complement input[type="url"]:focus,
.intervenant-complement textarea:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Une cellule qui tient plusieurs coordonnees (demande du 27 aout 2026) : les
   champs s'empilent, la principale en tete, et le bouton d'ajout ferme la
   pile. `min-width: 0` parce qu'une colonne de grille en `minmax(0, ...)` ne
   retient son contenu que si ses enfants acceptent de retrecir. */
.reglages-intervenant-multi {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  min-width: 0;
}

/* Discret par construction : il est sur chaque ligne, alors qu'on s'en sert
   deux fois par an. Un bouton plein a cet endroit ferait lire la ligne comme
   un formulaire d'ajout plutot que comme une fiche. */
.reglages-intervenant-plus {
  align-self: flex-start;
  border: none;
  background: none;
  padding: 0 var(--espace-2xs);
  color: var(--gray-4);
  font-family: var(--sans);
  font-size: var(--fs-xs);
  line-height: 1.3;
  cursor: pointer;
}

.reglages-intervenant-plus:hover { color: var(--cyan-dark); }

/* Meme boite qu'a l'equipe, et pour la meme raison. */
.reglages-intervenant-retirer {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--h-sm);
  height: var(--h-sm);
  flex: none;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.reglages-intervenant-retirer:hover {
  background: var(--red-pale);
  border-color: var(--red);
  color: var(--red);
}

/* La presence en ligne du client : meme rang de champs que les intervenants
   juste au-dessus, et volontairement -- ce sont les deux listes libres du
   panneau, et deux grilles qui se ressembleraient a peu pres se liraient comme
   une maladresse. Trois colonnes seulement ici : la nature du lien, une
   precision facultative, l'adresse -- qui prend la place qui reste, parce que
   c'est elle qu'on relit. Puis la fleche qui sort et la corbeille ronde, la
   meme classe que les intervenants. */
/* Les ecarts de ce panneau passent par l'echelle (27 aout 2026). Ils etaient
   cinq a s'en ecarter de un ou deux pixels, chacun ecrit a la main a un moment
   different, et c'est ce qui donnait aux rangees leur battement irregulier :
   une rangee de presence espacait ses cases de huit pixels, la rangee de
   reglages juste au-dessus de 9,6, le groupe de boutons d'un intervenant de
   6,4. Trois valeurs pour trois fois le meme geste, dont aucune paire
   n'appartenait au meme barreau -- assez proches pour qu'on ne sache pas dire
   pourquoi ca flotte, assez differentes pour que ca flotte.

   Le panneau a desormais deux ecarts et deux seulement, et ils se lisent :
   `--espace-sm` separe deux choses voisines, `--espace-2xs` colle ce qui n'en
   fait qu'une -- l'intitule et sa case, les deux teintes d'une charte, les
   trois outils d'une piece. Le rapport de 2,4 entre les deux est celui qui
   fait deja lire un groupe ailleurs dans la feuille. */
.reglages-presence-liste {
  display: flex;
  flex-direction: column;
  /* Deux liens du meme client se suivent de plus pres que deux rangees du
     panneau : c'est une liste, pas une succession de reglages. */
  gap: var(--espace-xs);
}
.reglages-presence-liste:empty { display: none; }

.reglages-presence-row {
  display: grid;
  /* Une colonne de plus en tete depuis le 30 aout 2026 : l'icone de la nature
     du lien (« leurs icones classiques avant leur nom pour que ca soit plus
     facilement identifiable »). Elle est fixe -- une icone ne se partage pas
     une fraction --, et les quatre autres colonnes gardent leurs rapports. */
  grid-template-columns: auto minmax(0, .8fr) minmax(0, .9fr) minmax(0, 1.8fr) auto auto;
  /* Le meme ecart que les dix-huit `.reglages-row` du panneau : cette rangee
     fait le meme travail qu'elles, elle n'a pas de raison de battre autrement. */
  gap: var(--espace-sm);
  align-items: center;
}

/* L'icone de la nature du lien. Elle n'est pas dans la liste deroulante -- le
   menu qu'un `select` ouvre appartient au systeme et ne prend pas de SVG --,
   elle est devant elle et elle suit le choix. Gris moyen : c'est un reperage,
   pas un etat, et six marques a leurs couleurs feraient de cette rangee une
   guirlande. */
.reglages-presence-icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-md);
  color: var(--gray-5);
  flex: none;
}

.reglages-presence-row input[type="text"],
.reglages-presence-row input[type="url"],
.reglages-presence-row select {
  font-family: var(--sans);
  font-size: var(--fs-md);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  min-width: 0;
  width: 100%;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
  min-height: var(--h-champ);
}

.reglages-presence-row input[type="text"]:focus,
.reglages-presence-row input[type="url"]:focus,
.reglages-presence-row select:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* La fleche s'efface plutot que de disparaitre quand la ligne n'a pas encore
   d'adresse : la retirer du flux deplacerait la corbeille d'un cran a chaque
   frappe. Elle garde sa place et cesse de repondre.

   `!important` pour la meme raison que la croix de l'equipe plus haut : sans
   lui, `[hidden] { display: none !important }` l'emportait et le deplacement
   annonce se produisait bel et bien. Sur une ligne sans adresse, la corbeille
   glissait en quatrieme colonne et les trois champs se partageaient les
   vingt-neuf pixels rendus -- ils s'elargissaient, puis se retrecissaient au
   moment ou l'adresse saisie devenait ouvrable. */
.reglages-presence-ouvrir[hidden] {
  display: inline-flex !important;
  visibility: hidden;
  pointer-events: none;
}

/* Ce que le repli a donne, exercice par exercice : une reponse deduite, posee
   sous les deux cases qui la produisent. Le panneau a deja son signe pour
   cela, ecrit plus bas sur la duree du mandat : « Il n'a pas de cadre -- il
   n'y a rien a y saisir --, et sans marque il se lisait comme une case qu'on
   aurait oublie de remplir. La demi-graisse et le fond pale disent ce qu'il
   est : une reponse, deduite de ce qui est repondu au-dessus. » Meme sens,
   donc meme signe : le fond pale de `.aglae-calcul`, la demi-graisse etant
   deja portee par l'annee.

   Le bloc n'en avait aucun. Son seul trait etait le filet qui separe deux
   exercices -- et `:last-child` le retire du dernier. Avec un seul exercice,
   qui est le cas courant, il ne restait donc rien du tout : une ligne de
   texte nu posee sur le fond de la page, a sept pixels des deux cases du
   dessus, moins que les 9,6 px qui separent deux controles d'une meme rangee
   du panneau. Elle ne se lisait pas comme la reponse a ce reglage mais comme
   un morceau tombe de la rangee, sans intitule et sans bord.

   Le filet part avec le defaut : sur un a-plat, l'ecart de la liste suffit a
   separer deux lignes, et un trait qui n'apparait qu'a partir du deuxieme
   exercice n'est pas une delimitation.

   L'a-plat epouse le texte (`max-content`) et non la largeur du panneau : mille
   trois cent trente-six pixels de fond pale pour une ligne de quatre cents
   serait pire que pas de fond du tout. */
.exercices-cloture-liste {
  margin-top: var(--espace-sm);
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  width: max-content;
  max-width: 100%;
  padding: var(--espace-xs) var(--espace-sm);
  background: var(--cyan-light);
  border-radius: var(--radius-sm);
}

.exercice-cloture-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace);
  font-size: var(--fs-sm);
}

.exercice-cloture-annee {
  font-weight: 600;
  min-width: 5rem;
}

.exercice-cloture-date { color: var(--gray-6); }

/* L'origine suit la date, elle ne part pas se ranger a droite du panneau : la
   ligne dit une seule chose -- tel exercice se clot tel jour, et voila d'ou la
   date vient -- et `margin-left: auto` en envoyait le dernier tiers a mille
   pixels des deux premiers sur un ecran large. Trois morceaux d'une meme
   phrase separes par un couloir vide se lisent comme trois colonnes d'un
   tableau qui n'existe pas. */
.exercice-cloture-source {
  color: var(--gray-5);
}

.dossier-form input[type="text"] {
  font-family: var(--sans);
  font-size: var(--fs-md);
  padding: var(--espace-sm) var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  flex: 1;
  min-width: 180px;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.dossier-form input[type="text"]:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* La liste deroulante maison est posee sur l'element, en tete de feuille : il
   ne reste ici que ce qui distingue celle d'un formulaire de mandat -- plus
   grande, plus aeree, comme les champs de texte a cote d'elle. */
.dossier-form select {
  font-size: var(--fs-md);
  --chevron-retrait: var(--espace-sm);
  padding: var(--espace-sm) var(--chevron-reserve) var(--espace-sm) var(--espace);
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  font-family: var(--sans);
  font-size: var(--fs);
  font-weight: 600;
  color: #fff;
  background: var(--cyan);
  border: none;
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--espace-lg);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background .15s var(--ease), box-shadow .2s var(--ease), transform .2s var(--ease-spring);
}

.btn-primary:hover { background: var(--cyan-dark); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.btn-primary:active { transform: translateY(0); }

.btn-primary[hidden] { display: none; }

/* Le bouton secondaire : la meme forme que `.btn-primary`, l'encre a la place
   du fond plein.

   Il n'avait aucune regle jusqu'au 5 septembre 2026, alors que la classe
   servait deja quatre fois -- « Consulter les registres publics » et
   « Refuser » sur l'ecran d'acceptation, « Fermer » dans une fenetre. Une
   classe sans regle ne fait rien : le navigateur peignait donc sa propre idee
   d'un bouton, un rectangle gris a bord biseaute de 13,3 px, qui n'a ni la
   forme ni la taille du reste et qui change d'une machine a l'autre. C'est
   exactement ce que la feuille evite partout ailleurs (voir les cases a cocher
   en tete de fichier), et cela se voyait sur l'ecran d'acceptation, ou deux
   boutons sur trois etaient au style du navigateur. Releve au navigateur le
   5 septembre 2026 en posant le depot de la piece d'identite, qui allait etre
   le troisieme.

   Le creux vertical est le meme litteral que `.btn-primary` et pour la raison
   qui l'y garde : les deux se posent cote a cote -- « Accepter le mandat » et
   « Refuser » --, et ils doivent avoir exactement la meme hauteur. */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  font-family: var(--sans);
  font-size: var(--fs);
  font-weight: 600;
  color: var(--gray-6);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--espace-lg);
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.btn-secondary:hover { background: var(--gray-1); border-color: var(--gray-4); }
.btn-secondary[hidden] { display: none; }

.btn-secondary.btn-sm {
  font-size: var(--fs-sm);
  min-height: var(--h-sm);
  line-height: 1.3;
  padding: var(--espace-2xs) var(--espace);
}

/* Refuser un mandat n'est pas detruire : le rouge se tient dans l'encre et
   dans le trait, pas dans un fond plein qui ferait du refus l'action
   principale de l'ecran. */
.btn-secondary.btn-danger { color: var(--red-dark); border-color: var(--red-pale); }
.btn-secondary.btn-danger:hover { background: var(--red-pale); border-color: var(--red); }

/* Un bouton eteint doit se voir eteint. La feuille n'avait aucune regle pour
   `:disabled` sur les trois boutons de base : un bouton refuse gardait son bleu
   plein et son ombre, et rien ne disait pourquoi le clic ne faisait rien --
   « Accepter le mandat » sur un dossier incomplet, « Deplacer » avant qu'une
   destination soit choisie. Constate le 2 septembre 2026 en posant l'ecran
   d'acceptation d'un mandat.

   Pose ici, sur les trois familles a la fois, plutot que sous une classe
   d'ecran : c'est une regle du systeme, pas une decoration locale. */
.btn-primary:disabled,
.btn-secondary:disabled,
.btn-link:disabled {
  opacity: .45;
  cursor: not-allowed;
  box-shadow: none;
}
.btn-primary:disabled:hover,
.btn-secondary:disabled:hover,
.btn-link:disabled:hover {
  transform: none;
  box-shadow: none;
  background: var(--cyan);
}
.btn-secondary:disabled:hover, .btn-link:disabled:hover { background: none; }

/* --h-sm est un plancher, pas une hauteur : le bouton s'y pose tant que son
   contenu tient dessous. Celui-ci n'y tenait qu'a moitie. Son texte, a 12,8 px
   d'un interligne laisse au navigateur, mesure 15,2 : avec 6,4 de creux de
   part et d'autre, cela fait exactement 28, le plancher au pixel pres. Mais
   une icone en fait 16, et 16 plus 12,8 font 28,8. Le meme bouton etait donc
   haut de 28 quand il portait un mot et de 28,8 quand il portait un dessin et
   un mot -- releve au navigateur le 29 aout 2026 sur /cabinet, ou « Ajouter »
   et « Generer un lien d'invitation » se suivent a un pixel pres dans la meme
   colonne.

   La recette est celle de `.btn-link`, le petit bouton qui, lui, tient son
   plancher depuis toujours : un interligne dit -- 1,3, soit 16,64 -- et un
   creux vertical d'un barreau plus bas. Le plus grand des deux contenus
   possibles, 16,64, plus 8, fait 24,64 : les deux cas retombent sous le
   plancher, et le bouton mesure 28 quoi qu'on lui mette dedans. Rien ne bouge
   a l'oeil, la hauteur cesse seulement de dependre de la fonte.

   Le creux horizontal ne change pas de valeur, seulement de nom : .8rem etait
   --espace ecrit en chiffres. Il reste plus large que celui de `.btn-link` --
   un bouton plein a besoin de plus d'air autour de son mot qu'un lien nu. */
.btn-primary.btn-sm {
  font-size: var(--fs-sm);
  min-height: var(--h-sm);
  line-height: 1.3;
  padding: var(--espace-2xs) var(--espace);
}

/* Meme cause, meme remede, et le meme carre que `.btn-link.btn-icon-only` :
   16 de dessin et 8 de creux tiennent dans les 28 que les deux planchers
   imposent deja. */
.btn-primary.btn-sm.btn-icon-only {
  padding: var(--espace-2xs);
  min-width: var(--h-sm);
}

.btn-primary.btn-danger {
  background: var(--red);
  color: #fff;
}

.btn-primary.btn-danger:hover { background: var(--red-dark); }

/* L'ecart se mesure entre ce qu'on voit, pas entre les boites. Une tuile
   retenue porte deux anneaux exterieurs -- `0 0 0 2px #fff, 0 0 0 4px` dans
   .filtre-tuile.selected --, et un `box-shadow` ne prend aucune place : le
   cercle occupe 34 px de rang et 42 px de regard. A huit pixels d'ecart, les
   deux anneaux gris se touchaient exactement ; a --espace-xs, ils se
   recouvraient de un virgule six. Quatre tuiles allumees ne formaient plus
   qu'une chaine.
   L'ecart est donc la somme de deux choses : le blanc qu'un rang de carres
   laisse voir -- --espace-xs, celui de .avancement-pill et de
   .programme-choix -- et les deux rayons d'anneau que la boite ne compte pas.
   Ecrit --espace-md, il en laissait huit et non six virgule quatre : ce
   rang-la respirait plus large que les autres sans que rien ne le demande, et
   son commentaire annoncait pourtant la meme mesure (29 aout 2026).
   Le rayon est nomme ici et relu par l'anneau, plus bas, pour qu'aucun des
   deux ne bouge sans l'autre ; l'anneau garde un repli, une tuile posee un
   jour hors du rang ne devant pas perdre son relief pour autant. */
.filtre-tuiles {
  --tuile-anneau: 4px;
  display: flex;
  align-items: center;
  gap: calc(var(--espace-xs) + 2 * var(--tuile-anneau));
}

.filtre-tuile {
  position: relative;
  --avatar-d: 34px;
  width: var(--avatar-d);
  height: var(--avatar-d);
  border: none;
  /* Un `<button>` porte un rembourrage par defaut, et la boite est bordee :
     la photographie qu'il peut desormais contenir (elle fait 100 % de la boite
     de contenu) serait rentree de six pixels et aurait laisse un anneau de
     couleur autour d'elle. Les initiales, centrees par le flex, ne le voyaient
     pas. */
  padding: 0;
  border-radius: 999px;
  color: #fff;
  font-size: calc(var(--avatar-d) * var(--avatar-initiales));
  font-weight: 700;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: .4;
  transition: opacity .1s, transform .1s;
}

/* La tuile de filtre quand le lecteur lit les noms plutôt que les ronds
   (demande du 9 septembre 2026). Même allongement que `.dossier-avatar-nom`,
   et pour la même raison : la hauteur, la couleur, l'anneau de sélection et le
   relief ne bougent pas, seule la largeur suit le nom. La coche de sélection
   reste posée au centre du bouton, où elle l'a toujours été.

   Ces tuiles-là étaient justement celles que le réglage avait oubliées la
   première fois (« Vérifie, le choix ne s'applique pas partout. Notamment pour
   les tickets », suivi du 25 août 2026) : elles ne sont pas des
   `.dossier-avatar`, et une règle écrite sur cette seule classe les aurait
   laissées de côté une deuxième fois. */
.filtre-tuile-nom {
  width: auto;
  max-width: calc(var(--avatar-d) * 5);
  padding: 0 calc(var(--avatar-d) * .25);
  font-size: var(--fs-3xs);
  white-space: nowrap;
  overflow: hidden;
}

.filtre-tuile:hover { transform: scale(1.08); }

/* Les deux anneaux de la tuile retenue s'ajoutent au relief, ils ne le
   remplacent pas. `box-shadow` est une propriete unique : la reecrire ici
   effacait le liseré interieur et l'ombre courte de --avatar-relief, et la
   seule pastille du site a rester plate etait celle qu'on venait de choisir --
   exactement celle qu'on regarde. Le meme piege que le raccourci `background`
   sur le compteur « +N » d'a cote.
   Le relief en tete : son liseré est interieur, les anneaux sont exterieurs,
   aucun des deux ne recouvre l'autre. */
.filtre-tuile.selected {
  opacity: 1;
  box-shadow: var(--avatar-relief), 0 0 0 2px #fff,
              0 0 0 var(--tuile-anneau, 4px) var(--gray-6);
}

/* La coche suit le rond, comme ses initiales au-dessus. `--avatar-d` ne vaut
   pas la meme chose partout : 34 px sur ordinateur, 38 au doigt dans la liste,
   44 dans la feuille de filtres. Une coche figee a 15 px pesait donc 44 % du
   rond ici et 34 % la-bas -- la meme tuile retenue, deux poids differents --,
   et son debord de 3 px, constant lui aussi, la faisait rentrer sous le liseré
   a mesure que le cercle grandissait : sur telephone elle ne chevauchait plus
   le bord, elle s'y cachait. Les deux mesures deviennent donc des fractions du
   diametre, dans le rapport qu'elles avaient sur ordinateur, ou elles etaient
   justes -- .44 du rond pour la coche, un cinquieme d'elle-meme pour le debord,
   soit exactement les 15 px et les 3 px d'avant sur les 34 px du bureau. */
.filtre-tuile-check {
  display: none;
  position: absolute;
  --coche-d: calc(var(--avatar-d) * .44);
  bottom: calc(var(--coche-d) * -.2);
  right: calc(var(--coche-d) * -.2);
  width: var(--coche-d);
  height: var(--coche-d);
  background: #fff;
  border-radius: 999px;
  color: var(--cyan-dark);
}

.filtre-tuile.selected .filtre-tuile-check { display: block; }

.filtre-etats {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin-left: var(--espace-sm);
  padding-left: var(--espace-sm);
  border-left: 1px solid var(--gray-3);
}

/* Le filtre d'etat : les memes carres que le selecteur d'un exercice, coches
   plutot que choisis. Forme, taille et couleurs sont posees avec lui, plus
   bas (voir « L'etat d'un exercice : trois carres, un seul allume »), un
   filtre qui montre l'etat autrement que la liste qu'il filtre oblige a
   apprendre deux fois la meme chose. */
.filtre-etat-tuile:hover { transform: scale(1.08); }

/* La rangee de tri coiffe la liste. Elle portait son propre filet en haut,
   qui fermait une zone sans cadre ; la tuile ferme desormais la liste, et ce
   filet se serait pose seize pixels sous le bord de la tuile, en travers du
   creux. Celui qui separe la rangee des lignes reste, il est ecrit sur la
   liste (`.dossier-list`).

   Le retrait lateral valait `.6rem` en chiffres, soit exactement --espace-sm :
   c'est le meme que celui d'une ligne (`.dossier-link`), et c'est ce qui aligne
   les intitules sur ce qu'ils annoncent. Une somme ecrite en chiffres d'un cote
   et au jeton de l'autre finit toujours par se defaire. */
.dossier-list-header {
  display: flex;
  align-items: center;
  padding: var(--espace-xs) var(--espace-sm);
}

/* Elle ne bouge plus des que la liste est tenue par la fenetre : c'est la tuile
   qui defile (voir `.app-main-pleine > .tuile-liste`), et la rangee s'y colle
   en haut. Sans elle, « Nom », « Échéance », « État », « Exercice » et
   « Titulaire » s'en allaient a la quatrieme ligne lue, et trois cent
   soixante-quinze lignes se lisaient sans que rien ne dise quelle colonne
   disait quoi.

   Elle porte le creux du haut que la tuile lui a rendu -- son propre creux plus
   celui de la tuile --, et un fond blanc : une bande transparente laisserait
   voir les lignes glisser dessous. `z-index: 1` la met au-dessus d'elles sans
   la mettre au-dessus du resume des FEC, qui vaut 40 et doit continuer a la
   recouvrir.

   Le filet du bas est celui de la liste (`.dossier-list`), qui s'en va avec la
   premiere ligne : sans lui, les lignes remontaient jusque sous les intitules
   sans que rien ne les separe. La rangee le refait sous elle, a l'ombre et sans
   flou, exactement sur le pixel ou passe celui de la liste -- les deux se
   superposent au repos, il n'en reste qu'un a l'oeil. */
.app-main-pleine .dossier-list-header {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #fff;
  padding-top: calc(var(--espace-md) + var(--espace-xs));
  box-shadow: 0 1px 0 var(--gray-3);
}

@media (max-width: 720px) {
  /* Ici la rangee n'est pas l'en-tete blanc d'un tableau mais une piste
     segmentee posee sur le sol gris, et la tuile qui la porte n'a deja plus de
     creux (voir mobile.css) : elle reprend donc son fond et son propre
     rembourrage, la seule chose qu'elle garde du dessus etant de rester en
     place. */
  .app-main-pleine .dossier-list-header {
    background: var(--gray-2);
    padding-top: var(--espace-3xs);
    box-shadow: none;
  }
}

.dossier-sort-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  background: none;
  border: none;
  padding: 0;
  font-family: var(--sans);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  color: var(--gray-5);
  cursor: pointer;
}

.dossier-sort-btn:hover { color: var(--gray-6); }
.dossier-sort-btn.active { color: var(--gray-6); }

/* « Titulaire » ferme la rangée depuis le 21 août 2026, la tuile du cabinet
   ayant rejoint la droite de la ligne. Même façon de faire que « Exercice » :
   la largeur est celle de la colonne (--col-titulaire), le libellé déborde de
   part et d'autre sur le vide de l'en-tête plutôt que d'élargir le bouton,
   ce qui pousserait « État » et « Exercice » hors de leurs colonnes. La marge
   est ce qui suit dans la ligne : l'écart de .dossier-link puis le chevron.

   Ce chevron comptait pour --icon. Il ne le vaut plus : il est passé à
   --icon-sm le jour où on a constaté qu'il était d'un pixel plus gros que sa
   jumelle sur les trois cent soixante-quatorze lignes de la liste (voir
   .dossier-chevron). La marge, elle, a gardé l'ancien chiffre, et réservait
   donc deux pixels de trop, ce qui tirait vers la gauche non pas ce seul
   libellé mais les trois, chacun poussant le précédent : « Titulaire » à
   1344 pour une colonne à 1346, « Exercice » à 1188 pour 1190, et « État »
   s'arrêtant à 1182 quand sa voie s'arrête à 1184. Une somme ne vaut que
   tant que ses termes disent encore la vérité. */
.dossier-list-header .dossier-sort-btn[data-sort="cabinet"] {
  width: var(--col-titulaire);
  flex: none;
  justify-content: center;
  white-space: nowrap;
  margin-right: calc(var(--espace) + var(--icon-sm));
}
/* L'en-tête « État » tombe pile sur l'emplacement du badge : la marge est la
   somme de ce qui le suit dans la ligne (exercice, collaborateurs, signataire,
   chevron) et des écarts entre eux, .4rem à l'intérieur de
   .dossier-statut-group, .75rem entre lui et le chevron. Une valeur ronde
   posée à l'œil ne tenait pas : elle laissait le titre au-dessus de la
   colonne d'à côté. */
/* « État » occupe desormais sa voie entiere, comme « Exercice » et
   « Titulaire » occupent les leurs. Il n'avait aucune largeur : son libelle
   faisait trente-quatre pixels quand sa colonne en fait quatre-vingt-seize, et
   la marge automatique le collait a droite de celle-ci. Tant qu'il ouvrait la
   partie droite de la rangee, cela ne se voyait pas -- rien ne le precedait.
   Depuis qu'« Échéance » le precede, cette difference de soixante pixels
   deviendrait le decalage de l'en-tete du compteur. Le libelle ne bouge pas :
   il reste cale a droite, ou le badge se pose. */
.dossier-list-header .dossier-sort-btn[data-sort="etat"] {
  width: var(--col-statut);
  flex: none;
  justify-content: flex-end;
  margin-right: var(--espace-xs);
}

/* « Échéance » ouvre desormais la partie droite de la rangee, et c'est lui qui
   porte la marge automatique qui l'y pousse : la colonne du compteur precede
   celle de l'etat dans la ligne, l'en-tete doit suivre le meme ordre. Sa
   largeur est celle de sa voie (--col-echeance) et son libelle deborde a
   gauche, sur le vide de l'en-tete, plutot que d'elargir le bouton -- comme
   « Exercice » et « Titulaire » debordent des leurs. */
.dossier-list-header .dossier-sort-btn[data-sort="echeance"] {
  margin-left: auto;
  width: var(--col-echeance);
  flex: none;
  justify-content: center;
  white-space: nowrap;
  margin-right: var(--espace-xs);
}

/* « Exercice » occupe exactement la largeur de .dossier-exercice-slot et rien
   de plus : son libelle est plus long que la colonne et deborde donc a droite,
   sur la zone vide de l'en-tete, plutot que d'elargir le bouton -- ce qui
   pousserait « État » hors de la colonne du badge. Le reste de la marge est ce
   qui suit dans .dossier-statut-group -- collaborateurs, signataire et leurs
   ecarts de .4rem -- plus le .75rem qui separe le groupe de la tuile du
   titulaire. Ce qui vient encore apres (la tuile elle-meme, puis le chevron)
   est porte par « Titulaire », qui suit ce bouton.
   Les trois mesures se lisent dans :root : ecrites ici en chiffres, elles ne
   suivaient plus les colonnes qu'elles visent. */
.dossier-list-header .dossier-sort-btn[data-sort="cloture"] {
  width: var(--col-exercice);
  flex: none;
  white-space: nowrap;
  margin-right: calc(var(--col-collaborateurs) + var(--col-signataire) + var(--espace-xs) * 2 + var(--espace));
}

.dossier-sort-icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  opacity: 0;
  transform: rotate(-90deg);
  transition: transform .15s var(--ease);
}

.dossier-sort-btn.active .dossier-sort-icon { opacity: 1; }
.dossier-sort-btn[data-dir="desc"] .dossier-sort-icon { transform: rotate(90deg); }

.dossier-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--gray-3);
}

/* La voie du nom d'un mandat : ce qui separe le bord gauche de la ligne du
   premier caractere de la raison sociale. Elle sert a une seule chose, mais
   celle-la ne peut pas s'ecrire en un nombre -- la liste depliee d'un mandat
   se range dessous, et doit commencer la ou commence le nom.

   Elle etait ecrite 4.2rem, soit 67,2 px, sous un commentaire qui promettait
   d'aligner les sous-lignes sur le nom. Le nom est a 114 px du bord : les
   exercices commencaient 47 px trop a gauche, sur rien -- ni le chevron, ni la
   case du logo, ni la pastille de type. Mesure le 29 aout 2026 ; personne ne
   pouvait le voir en relisant la regle, puisque la regle disait le contraire.

   Un nombre n'y suffisait pas, parce que la ligne a trois formes : avec logos,
   sans logos (l'oeil barre retire la colonne entiere), et en grille a deux
   rangees sous 820 px. La voie est donc la somme de ses termes, et chaque
   forme n'a qu'un terme a changer :

     le chevron de depliage   var(--espace-2xs) + var(--icon-sm) + var(--espace-3xs)
     l'ecart de la ligne      var(--espace-xs)
     le creux gauche du lien  var(--espace-sm)
     la case du logo          --dossier-voie-logo, mise a zero avec la colonne
     la pastille de type      var(--icon-md) + var(--espace)

   Soit 114 px ici, 80,8 dans la grille du telephone, ou la tuile du cabinet
   remplace le logo et la pastille (voir mobile.css). Les deux valeurs ont ete
   relevees au navigateur avant d'etre ecrites, pas deduites. */
.dossier-item {
  --dossier-logo-l: 34px;
  --dossier-voie-logo: calc(var(--dossier-logo-l) + var(--espace));
  --dossier-voie-nom: calc(
      var(--espace-2xs) + var(--icon-sm) + var(--espace-3xs)
    + var(--espace-xs)
    + var(--espace-sm)
    + var(--dossier-voie-logo)
    + var(--icon-md) + var(--espace));
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  border-bottom: 1px solid var(--gray-3);
}

.dossier-item[hidden] { display: none; }

/* La derniere ligne ne porte pas de filet. Il fermait la liste tant qu'elle
   courait jusqu'au bas de la page ; depuis qu'elle tient dans une tuile, il se
   posait seize pixels au-dessus du bord de celle-ci -- deux traits paralleles
   pour rien --, et sur telephone, ou la liste est une carte, exactement sur le
   bord : un fond de carte epais de deux pixels.

   « Derniere » veut dire derniere visible. Le filtre et la recherche replient
   les lignes avec `hidden`, et celle qui ferme la liste change donc a chaque
   frappe ; le selecteur se lit « une ligne visible qu'aucune ligne visible ne
   suit », et se refait tout seul. */
.dossier-item:not([hidden]):not(:has(~ .dossier-item:not([hidden]))) {
  border-bottom: 0;
}

/* Demande le 11 aout 2026 : des lignes moins hautes. Le respirateur vertical
   etait de .9rem de part et d'autre, soit 29 px de blanc pour 25 px de
   contenu -- une ligne sur deux etait du vide, et un cabinet de 175 mandats
   n'en voyait qu'une quinzaine par ecran. Ramene a .5rem : la ligne passait
   de 55 a 42 px.

   Redemande le 15 aout 2026, la liste etant toujours jugee trop aeree. Le
   blanc restant (8 px de part et d'autre) ne suffisait plus a lui seul : la
   ligne butait sur l'avatar du signataire, 28 px qui en fixaient le plancher.
   Les deux ensemble -- .3rem de respirateur, avatar a 24 px dans cette liste
   seulement (voir .dossier-signataire-slot) -- ramenent la ligne de 45 a
   35 px, soit vingt-et-un mandats par ecran au lieu de dix-sept sur un
   portable de 900 px de haut. On descend sous les 40 px que la note
   precedente se donnait pour limite : c'est assume, /dossiers est un tableau
   de bureau qu'on lit a la souris, ou 35 px reste une cible confortable --
   la regle des 44 px vise le doigt, et c'est l'app qui le sert. */
.dossier-link {
  display: flex;
  align-items: center;
  gap: var(--espace);
  padding: var(--espace-2xs) var(--espace-sm);
  text-decoration: none;
  color: var(--black);
  border-radius: var(--radius-sm);
  transition: background .15s var(--ease);
  flex: 1;
  min-width: 0;
}

/* Elle tient dans une rangee de 28 px -- le rond de profil, la croix de
   retrait, les segments du titulaire --, mais sa hauteur se deduisait d'un
   rembourrage de .35rem et tombait a 28,2 : deux dixiemes de plus que tout ce
   qui l'entoure, assez pour que la rangee n'ait pas de ligne de fond commune.
   Elle la prend donc au jeton, et le rembourrage revient sur l'echelle.

   A gauche, .5rem faisait commencer son texte 1,6 px avant celui de tous les
   champs du panneau, qui retirent --espace-sm ; a droite, 1.6rem laissait a son
   chevron moins de place que la voie que la regle de base reserve a toute
   liste deroulante -- la voisine de la presence en ligne, elle, l'avait. */
.dossier-assigne-select {
  color: var(--gray-5);
  background-color: var(--gray-1);
  min-height: var(--h-sm);
  padding: var(--espace-2xs) var(--chevron-reserve) var(--espace-2xs) var(--espace-sm);
  margin-right: var(--espace-sm);
}

/* Le style commun a tout rond de profil, quel que soit l'endroit ou il est
   pose : la lumiere rasante et le liseré interieur de --avatar-lumiere /
   --avatar-relief, et un texte d'un cran plus dense.

   Ecrit une fois pour les quatre familles qui en portent un, et non dans
   chacune : c'est exactement le defaut qui avait fait diverger la taille des
   initiales d'un emplacement a l'autre (voir --avatar-initiales). Un rond
   ecrit demain n'aura, lui aussi, que son diametre a declarer. */
.dossier-avatar,
.app-reglages-pastille,
.filtre-tuile,
.conso-pastille {
  background-image: var(--avatar-lumiere);
  box-shadow: var(--avatar-relief);
  letter-spacing: var(--suivi-serre);
  /* Sans quoi le degrade deborde du rond sur les navigateurs qui rendent le
     fond avant le rayon. */
  background-clip: padding-box;
}

/* Le rond de profil, dans tous ses emplacements. Un seul reglage le decrit :
   son diametre. Les initiales s'en deduisent (--avatar-initiales), donc une
   variante n'a plus qu'une ligne a ecrire -- et ne peut plus se tromper de
   taille de texte. */
.dossier-avatar {
  --avatar-d: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--avatar-d);
  height: var(--avatar-d);
  flex: none;
  border-radius: 999px;
  color: #fff;
  font-size: calc(var(--avatar-d) * var(--avatar-initiales));
  font-weight: 700;
  letter-spacing: var(--suivi-serre);
}

/* Le nom en toutes lettres, quand c'est lui que le lecteur a demandé à voir
   (demande du 9 septembre 2026). C'est la seule des trois propositions qui
   change la forme du rond : deux lettres tiennent dans un disque, un nom non.
   La pastille s'allonge donc en capsule -- même hauteur, même couleur, même
   relief, `999px` comme tout ce qui est complètement rond -- et le rang de
   collègues reste une file de pastilles au lieu de devenir une liste.

   Une largeur bornée et non libre : « Marie-Christine Delaunay-Berger » ne
   doit pas pousser l'état de l'exercice hors de la ligne des mandats. Au-delà,
   le nom se coupe et l'infobulle le donne entier -- elle est posée par le même
   macro, sur la même pastille, quelle que soit la proposition retenue.

   `inline-block` et non `inline-flex` : la coupure par points de suspension ne
   s'applique pas au texte nu d'un conteneur flex. La hauteur est alors tenue
   par `line-height`, ce qui centre le nom aussi exactement que le faisait
   `align-items`. */
.dossier-avatar-nom {
  display: inline-block;
  width: auto;
  min-width: var(--avatar-d);
  max-width: calc(var(--avatar-d) * 5);
  padding: 0 calc(var(--avatar-d) * .25);
  line-height: var(--avatar-d);
  font-size: var(--fs-3xs);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}

/* La photo dans le rond, quand elle remplace les initiales (demande du 24 août
   2026). Elle remplit le disque et se recadre au centre : un portrait est
   presque toujours plus haut que large, et le laisser tenir en entier
   laisserait deux bandes de couleur sur les côtés.

   Le rond garde sa couleur de fond sous l'image : c'est elle qu'on voit le
   temps que la photo arrive, et c'est elle qui sert de filtre dans la liste
   des clients. Rien ici ne touche à `--avatar-relief` ni à `--avatar-lumiere` :
   le relief du rond reste celui de tous les autres. */
.dossier-avatar-photo {
  width: 100%;
  height: 100%;
  border-radius: 999px;
  object-fit: cover;
  display: block;
}

/* Le logo d'un client dans le rond de son fil de conversation (demande du
   27 aout 2026). Il ne se recadre pas comme un portrait : un visage garde son
   essentiel au centre, une marque non -- un logo large coupe en disque n'en
   montrerait que le milieu. Il tient donc entier, sur le blanc qui est le fond
   ou toute marque est dessinee. Le relief du rond (`--avatar-relief`) n'est pas
   touche : c'est l'image qui prend ce fond, pas la pastille. */
.dossier-avatar-logo {
  object-fit: contain;
  padding: 2px;
  background-color: #fff;
}

/* L'icone dans le rond, quand le fil n'a le visage de personne : la place du
   cabinet, ou un mandat qui n'a ni logo ni initiales. Elle y etait dessinee par
   un emoji -- un batiment antique beige et brun, seul glyphe en couleur d'une
   colonne de pastilles plates, et d'un dessin que chaque systeme fait a sa
   facon : Apple le rend en relief, Windows a plat, et une machine sans police
   d'emoji ne rend qu'un rectangle vide. C'est le meme defaut que le triangle
   d'un `<summary>` : le systeme dessinait a la place de la feuille.

   Elle se deduit du diametre comme les initiales (--avatar-icone), donc un rond
   ecrit demain n'a toujours que son diametre a declarer. Le trait prend le blanc
   du texte qu'il remplace ; le relief du rond n'est pas touche. */
.dossier-avatar-icone {
  width: calc(var(--avatar-d) * var(--avatar-icone));
  height: calc(var(--avatar-d) * var(--avatar-icone));
  color: inherit;
}

/* Icones des collaborateurs additionnels (hors signataire) sur /dossiers :
   largeur fixe quel que soit leur nombre (0 a N+), pour ne jamais decaler
   le compteur FEC ni le pill d'avancement du reste de la liste. Empilees
   horizontalement en bulles qui se chevauchent legerement (max 2 visibles,
   "+N" au-dela), a la maniere d'un groupe d'avatars classique - plus lisible
   que l'empilement vertical precedent, dont les bulles (15px, bordure 2px)
   etaient trop petites pour rester nettes a cote de l'avatar du signataire. */
.dossier-collaborateurs-slot {
  width: var(--col-collaborateurs);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.dossier-collaborateurs-icones {
  position: relative;
  /* La largeur du rang est celle des bulles, pas une valeur posee a cote :
     deux bulles de --avatar-d decalees de leur recouvrement. */
  width: var(--col-collaborateurs);
  height: 22px;
}

.dossier-avatar-collaborateur {
  position: absolute;
  top: 0;
  --avatar-d: 22px;
  border: 1.5px solid #fff;
}

.dossier-avatar-collaborateur:nth-child(1) { left: 0; z-index: 2; }
.dossier-avatar-collaborateur:nth-child(2) { left: 13px; z-index: 1; }

/* Le compteur « +N » porte trois caracteres la ou une pastille en porte deux :
   il est le seul a s'ecarter du rapport commun, et du meme cran que l'app
   (RangDeCollaborateurs, 0.38). */
.dossier-avatar-collaborateur-plus {
  /* `background-color` et non le raccourci `background` : celui-ci remettrait
     a zero le degrade de --avatar-lumiere pose sur tous les ronds. */
  background-color: var(--gray-5);
  font-size: calc(var(--avatar-d) * .38);
}

.dossier-link:hover { background: var(--cyan-pale); }

/* Le logo du client, en tête de ligne (demande du 24 août 2026). Une colonne
   à largeur fixe, et non une image qui pousse ses voisines : sans elle, les
   marques de forme juridique ne seraient plus alignées d'une ligne à l'autre,
   un logo carré et un logo panoramique n'occupent pas la même place.

   La case reste posée sur les lignes sans logo, vide : c'est ce qui garde la
   colonne droite. `object-fit: contain` laisse à chaque marque ses
   proportions ; recadrer un logo, c'est le retoucher. */
.dossier-logo-cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--dossier-logo-l);
  height: 22px;
}

.dossier-logo {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Masquée : la colonne entière part, pas seulement les images, une colonne
   vide de 34 pixels sur toute la liste serait un décalage sans raison. */
.dossier-list-sans-logos .dossier-logo-cell { display: none; }
/* La colonne partie, l'ecart qui la suivait part avec : sans cela la voie
   du nom continuerait de compter 46,8 px de logo que plus rien ne dessine. */
.dossier-list-sans-logos .dossier-item { --dossier-voie-logo: 0px; }

/* La pastille du groupe part avec (« quand l'œil est barré il faut également
   masquer les pastilles des groupes : logo ou le nom des groupes », ticket du
   29 août 2026). L'œil barré ne demande pas « moins d'images » mais « les noms
   seuls » : masquer la marque du client et laisser celle de son groupe, c'est
   retirer une distraction et en garder une autre. Les deux formes de la
   pastille partent donc, celle qui montre une marque comme celle qui écrit le
   nom du groupe : c'est la même chose dite de deux façons, et le ticket les
   nomme toutes les deux. */
.dossier-list-sans-logos .dossier-groupe-chip { display: none; }

.dossier-icon { width: var(--icon-md); height: var(--icon-md); }
.dossier-icon-entreprise { color: var(--purple); }
.dossier-icon-association { color: var(--blue); }

.dossier-cabinet-slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--col-titulaire);
}

.dossier-cabinet-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 20px;
  padding: 0 5px;
  border-radius: var(--radius-xs);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: var(--suivi-serre);
  color: #fff;
}

.dossier-nom { font-weight: 600; }

/* L'audit contractuel, signalé sur la ligne du client. Le carré coché dans la
   rubrique « Type de mission » du mandat, rapporté ici : même icône, même
   violet, même coin arrondi que `.type-pill-audit`, pour qu'on reconnaisse
   sans y penser le choix qu'on a fait là-bas.

   Les deux lettres « AC » qu'il remplace disaient la même chose en obligeant à
   les lire, et à savoir ce qu'elles abrègent (demande du 24 août 2026). Même
   habillage et même gabarit que la consolidation d'à côté : les deux sont la
   reprise d'un bouton de la même rubrique, et un écart entre elles se verrait
   avant le sens.

   --icon-sm comme elle : « une taille légèrement réduite ». Le cadre et le
   fond donnent quelques pixels de plus que la marque du co-commissariat, qui
   n'en a pas ; au gabarit de celle-ci, ces deux-là pèseraient plus lourd
   qu'elle sur la ligne alors qu'elles en disent moins. */
.dossier-audit-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--purple);
  background: var(--purple-pale);
  border: 1px solid var(--purple);
  border-radius: var(--radius-sm);
  padding: var(--espace-3xs) var(--espace-2xs);
}

.dossier-audit-badge .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

/* La marque d'un co-commissariat : le grand C du logo du cabinet, et dedans
   un anneau jaune à la place du petit c rouge, le mandat est signé à
   plusieurs, la seconde signature est ce second cercle.

   Sans cadre ni fond, contrairement au carré de l'audit contractuel d'à côté
   et contrairement aux deux lettres qu'elle remplace : elle porte déjà ses
   deux teintes, et une
   pastille pâle par-dessous les ferait piétiner. C'est la règle du temple
   barré juste en dessous : une marque se lit à son dessin, un badge à son
   texte, et les deux ne s'habillent pas pareil. */
.dossier-cocac-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--red);
}

.dossier-cocac-badge .icon {
  width: var(--icon-md);
  height: var(--icon-md);
}

/* La consolidation, signalée sur la ligne du client (demande du 24 août
   2026). Le carré coché dans la rubrique « Type » du mandat, rapporté ici :
   même icône, même jaune, même coin arrondi que `.type-pill-conso`, pour
   qu'on reconnaisse sans y penser la case qu'on a cochée là-bas.

   Avec cadre et fond, contrairement à la marque du co-commissariat d'à côté :
   celle-ci est un dessin qui porte ses propres teintes, celle-là est la
   reprise d'un bouton, et c'est son cadre pâle qui dit qu'elle en vient.

   --icon-sm et non --icon-md : « un peu plus petite » (suivi du 24 août
   2026). Son cadre et son fond lui donnent quatre pixels de plus que la
   marque voisine, qui n'en a pas ; au gabarit de celle-ci, elle pesait donc
   plus lourd qu'elle sur la ligne alors qu'elle en dit moins. */
.dossier-conso-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--yellow);
  background: var(--yellow-pale);
  border: 1px solid var(--yellow);
  border-radius: var(--radius-sm);
  padding: var(--espace-3xs) var(--espace-2xs);
}

.dossier-conso-badge .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

/* Le temple barré : section juridique vide.
   Sans fond ni cadre, contrairement au carré de l'audit contractuel d'à côté.
   Celui-là nomme une nature de mission, qui appartient à la ligne ; celui-ci
   signale un manque, et un manque se remarque mieux par sa couleur seule que
   par une pastille de plus sur une ligne qui en porte déjà quatre. */
.dossier-juridique-vide {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--red);
}

/* `display: inline-flex` ci-dessus l'emporte sur la regle `[hidden]` du
   navigateur : sans cette ligne, le temple de l'onglet Juridique reste
   affiche sur un mandat dont la section est pleine. */
.dossier-juridique-vide[hidden] { display: none; }

/* Le temple garde la taille d'icone de la maison, --icon : il lui faut ces
   seize pixels pour que le couloir creuse par la barre du fronton reste
   visible plutot que de se refermer. C'est deja ce que la regle de base donne
   a toute `.icon`, et cette famille n'a aucune raison d'y deroger -- rien
   n'est donc ecrit ici. Ce qu'il ne faut pas y remettre, c'est le quinze
   d'avant, qui refermait le couloir. */

.dossier-fec-count {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-5);
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-3xs) var(--espace-xs);
  flex: none;
  margin-left: auto;
}

/* Meme valeur qu'avant au dixieme pres, mais dite par son barreau : cet
   ecart n'est pas libre, l'en-tete de la liste le rajoute a ses marges pour
   poser « Exercice » et « Titulaire » sur leurs colonnes. Ecrit en chiffres
   des deux cotes, il se serait desolidarise a la premiere retouche -- c'est
   exactement ce qui etait arrive aux trois largeurs de colonne, montees dans
   :root pour cette raison. */
.dossier-statut-group {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  flex: none;
}

.dossier-statut-slot {
  /* Largeur fixe, pour que le badge cadenas (plus etroit) n'y decale pas le
     compteur FEC qui le precede. Sa valeur, elle, n'a pas de raison propre :
     elle copie le rang de carres qui dit le meme etat une fois la ligne
     depliee (.avancement-pill). Une largeur copiee derive -- c'est ce qui
     etait arrive aux trois colonnes voisines, montees dans :root pour cette
     raison --, et celle-ci avait derive de huit dixiemes le 28 aout 2026,
     quand l'ecart du rang est passe de six a --espace-xs sans qu'elle suive.
     Elle se calcule donc des memes termes, dans :root avec les trois autres.
     Cale a droite comme les trois emplacements suivants : un emplacement fixe
     est plus large que ce qu'il contient, et l'espace qui reste doit tomber
     du meme cote partout, sinon le badge flottait au milieu d'un vide de
     37 px de chaque cote au lieu de se ranger sous son en-tete. */
  width: var(--col-statut);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex: none;
}

.dossier-fec-count .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* Le nom complet d'une personne, au survol de son rond.
   ---------------------------------------------------------------------------
   Meme famille que le resume des FEC juste en dessous -- surface flottante,
   fond blanc, bordure grise, ombre portee --, en plus petit : celui-la ouvre
   un tableau, celui-ci dit un nom. « Une petite fenetre legere, facon celle du
   compteur de FEC » (demande du 26 aout 2026).

   Posee dans le corps du document et non a cote du rond : un rond vit souvent
   dans une cellule de tableau au `overflow` ferme, qui aurait coupe la fenetre.
   C'est donc le code qui la place (avatar-nom.js), en coordonnees de page.

   `--radius` et non `--radius-lg` : a cette taille, le grand arrondi mangerait
   la moitie de la premiere lettre. */
.avatar-noms {
  position: absolute;
  z-index: 60;
  max-width: 320px;
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-md);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--gray-6);
  text-align: left;
  /* On la regarde, on ne la manipule pas : laisser la souris la traverser
     fermerait le survol du rond qui l'a ouverte. */
  pointer-events: none;
}

.avatar-noms-liste { margin: 0; padding: 0; list-style: none; }

/* Le rond survole, en evidence dans la liste du groupe : sans lui, on lit
   trois noms sans savoir lequel repond au rond qu'on vise. */
.avatar-noms-liste .vise { color: var(--black); font-weight: 600; }

/* Le resume des FEC importes, ouvert en posant la souris sur le compteur.
   ---------------------------------------------------------------------------
   Le compteur disait combien, jamais lesquels : pour savoir si le dernier
   exercice etait bien la, il fallait ouvrir le mandat, puis l'onglet Source.
   Le panneau repond sur place -- exercice, fichier, derniere ecriture,
   resultat -- et c'est tout : ce n'est pas une seconde liste des sources,
   c'est le coup d'oeil qui evite de l'ouvrir.

   Le compteur devient donc le point d'ancrage (position: relative) d'un
   panneau absolu, pose au-dessus de la ligne. Il est dans une ancre -- toute
   la ligne du mandat en est une -- d'ou le survol comme seule ouverture :
   un clic irait au mandat. */
.dossier-fec-count {
  position: relative;
  cursor: default;
}

.dossier-fec-resume {
  position: absolute;
  bottom: calc(100% + .5rem);
  right: -.5rem;
  z-index: 40;
  display: none;
  flex-direction: column;
  gap: var(--espace-sm);
  width: max-content;
  max-width: 620px;
  padding: var(--espace);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  font-weight: 400;
  color: var(--gray-6);
  text-align: left;
  cursor: default;
  /* Le panneau ne se survole pas lui-meme : il flotte au-dessus des lignes
     voisines, et laisser la souris le traverser ferait clignoter le mandat
     qui est dessous. On le regarde, on ne le manipule pas. */
  pointer-events: none;
}

.dossier-fec-count:hover .dossier-fec-resume,
.dossier-fec-count:focus-visible .dossier-fec-resume { display: flex; }

/* Le panneau s'ouvre vers le haut, ce qui ne coutait rien tant que la page
   entiere defilait : il debordait sur la barre d'outils, et se voyait.

   Depuis que la liste est tenue par la fenetre, ce qui defile est la tuile, et
   une boite au defilement ouvert coupe ce qui en sort : le resume de la
   premiere ligne perdait 113 px sur 155. C'est le meme obstacle que celui des
   ronds de profil, resolu la-bas en posant la fenetre dans le corps du document
   (avatar-nom.js) ; ici elle reste ou elle est et c'est sa direction qui
   change, `dossiers.js` posant la classe quand la place manque au-dessus. */
.dossier-fec-count-dessous .dossier-fec-resume {
  bottom: auto;
  top: calc(100% + .5rem);
}

.dossier-fec-resume-titre {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--black);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dossier-fec-resume-table {
  border-collapse: collapse;
  font-size: var(--fs-xs);
  font-weight: 400;
}

.dossier-fec-resume-table th {
  text-align: left;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
  font-weight: 600;
  padding: 0 var(--espace-sm) var(--espace-2xs) 0;
  border-bottom: 1px solid var(--gray-2);
}

.dossier-fec-resume-table td {
  padding: var(--espace-2xs) var(--espace-sm) var(--espace-2xs) 0;
  color: var(--gray-6);
  white-space: nowrap;
  vertical-align: middle;
}

.dossier-fec-resume-table th.num,
.dossier-fec-resume-table td.num { text-align: right; padding-right: 0; }

.dossier-fec-resume-table td.positive { color: var(--green); font-weight: 600; }
.dossier-fec-resume-table td.negative { color: var(--red); font-weight: 600; }

/* Le nom d'un FEC fait volontiers cinquante caracteres. Il est coupe plutot
   que d'etirer le panneau au-dela de la fenetre ; le nom entier reste dans
   l'infobulle de la cellule. */
.dossier-fec-resume-nom {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dossier-fec-resume-reste,
.dossier-fec-resume-vide,
.dossier-fec-resume-note {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

/* Fichier neutralise ou import inacheve : la ligne reste lisible, le chiffre
   perd le vert et le rouge qui annoncent un resultat retenu. Meme geste que
   .source-row-neutralise dans la liste des sources -- « c'est encore la, ca ne
   compte juste plus ». */
.dossier-fec-resume-table tr.dossier-fec-resume-hors td {
  color: var(--gray-4);
}

/* Le chevron de fin de ligne. C'est le meme dessin que celui qui deplie la
   ligne a l'autre bout -- #icon-chevron-right dans les deux cas -- et le meme
   gris, --gray-4. Il etait pourtant a 16 px quand celui de gauche est a 14 :
   faute de taille ecrite ici, `.icon` tout court le faisait retomber sur
   --icon. Deux fois la meme fleche, deux fois la meme couleur, deux tailles,
   aux deux extremites d'une ligne que l'oeil parcourt d'un bout a l'autre, et
   ce sur les trois cent soixante-quatorze lignes de la liste : c'est le defaut
   que l'echelle a six barreaux a ete ecrite pour empecher (« deux boutons cote
   a cote portaient des icones de tailles differentes a un pixel pres, ce qui se
   voit sans qu'on sache dire pourquoi »). Il prend donc le barreau de sa
   jumelle, --icon-sm, qui est aussi celui du compteur de FEC un peu avant lui
   dans la meme ligne. La marque de forme juridique reste a --icon-md : c'est un
   autre dessin, et deux barreaux d'ecart se lisent comme une intention. */
.dossier-chevron {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
}

/* ---- Choisir un etat : des carres, un seul allume --------------------------

   Le badge de la ligne repliee (.dossier-etat-badge) a fixe la forme de tout
   ce qui dit un etat sur ce site : un carre a coins arrondis, borde de la
   couleur de l'etat et rempli de sa teinte pale, ou le fond clair laisse
   deviner la ligne dessous. Ce carre est desormais la seule forme par
   laquelle on en choisit un, et les quatre endroits qui en demandent un le
   reprennent :

     .avancement-pill   l'etat d'un exercice, dans la liste et sur sa fiche ;
     .filtre-etat-tuile le filtre d'etat de la barre d'outils ;
     .type-pill         la nature du mandat : entreprise ou association ;
     .controle-pill     la marque posee sur les lignes cochees d'un compte.

   Ce qui disparait des quatre : la pilule grise a pouce blanc glissant. Elle
   jouait l'interrupteur, une position qui coulisse, pour ce qui est un
   choix entre des etats nommes, et elle donnait au site autant de
   vocabulaires que de selecteurs pour une information que le badge disait
   deja d'une seule facon.

   Le fonctionnement ne bouge dans aucun des quatre : un clic par etat, memes
   `data-value` et `data-etat`, memes branchements (dossier-avancement.js,
   dossier-type.js, app.js). Seule la forme change.

   Le rang d'avancement mesure trois carres de --h-sm espaces de --espace-xs,
   soit 96,8 px, et c'est la largeur que reprend --col-statut, la colonne du
   badge d'etat. Ecrite 96 px a la main, elle etait restee sur l'ecart de six
   qu'abandonne la regle juste dessous.
   --------------------------------------------------------------------------- */

/* Un rang de carres : le meme ecart partout, pour que deux selecteurs voisins
   ne se lisent pas comme deux objets differents. Ecrit 6px jusqu'au 28 aout
   2026, c'est-a-dire a cote de l'echelle : le barreau qui le porte vaut 6,4 px,
   quatre dixiemes plus loin, et c'est desormais lui qu'on lit ici et sur
   .cabinet-toggle, qui suit ce rang. */
.avancement-pill,
.type-pill,
.controle-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  flex: none;
}

/* La forme commune, celle de .dossier-etat-badge en plus grand : un carre
   qu'on vise du doigt ne peut pas faire 22px. */
.avancement-seg,
.avancement-lock-badge,
.filtre-etat-tuile,
.type-seg,
.selection-bar-seg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-sm);
  height: var(--h-sm);
  flex: none;
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* Un carre qui n'est pas retenu s'efface sans disparaitre : il doit rester
   assez visible pour qu'on sache qu'il se clique. */
.avancement-seg,
.filtre-etat-tuile,
.type-seg,
.selection-bar-seg {
  cursor: pointer;
  --seg-voile: .45;
  transition: background .15s var(--ease),
              border-color .15s var(--ease), transform .1s var(--ease);
}

/* Le voile porte sur ce qu'il y a dans le carre, pas sur le carre. Il etait
   pose sur le bouton lui-meme, donc il effacait aussi sa bordure : le
   --gray-3 d'un contour a 45 % vaut #f0f2f5 sur blanc, soit 1,06 de contraste
   -- un trait qu'on ne voit plus. Ces carres etaient les seuls boutons du
   panneau Mandat a ne pas montrer leur contour, au milieu de vingt-cinq
   autres qui le montrent : « des boutons qui ne sont pas bien delimites »,
   dit tel quel le 26 aout 2026.

   Ce que la regle voisine se donne pour intention -- « il doit rester assez
   visible pour qu'on sache qu'il se clique » -- se joue justement sur la
   bordure et le fond : ce sont eux qui disent qu'il y a un bouton la. Le
   glyphe, lui, ne dit que lequel ; c'est a lui de s'attenuer tant qu'il n'est
   pas choisi. Le voile a donc change de cible sans changer de valeur.

   Il passe par une variable plutot que par l'opacite directe pour que les
   quinze regles d'etat retenu continuent de le lever depuis le carre, sans
   avoir a redesigner chacune l'element qu'il contient -- un span pour les
   pastilles d'avancement, un svg pour les icones, une image pour le logo
   Francas. */
.avancement-seg > *,
.filtre-etat-tuile > *,
.type-seg > *,
.selection-bar-seg > * {
  opacity: var(--seg-voile, 1);
  transition: opacity .15s var(--ease);
}

.avancement-seg:hover,
.filtre-etat-tuile:hover,
.type-seg:hover { --seg-voile: .85; }

/* Le carre retenu prend les couleurs de son etat, exactement comme le badge
   de la ligne repliee : bordure pleine, fond pale. Selecteur et filtre le
   designent differemment : l'un par la valeur du groupe, l'autre par une
   classe posee sur chaque tuile, puisqu'on peut en cocher plusieurs. */
.avancement-pill[data-value="urgent"] .avancement-seg[data-value="urgent"],
.filtre-etat-tuile.selected[data-etat="urgent"] {
  --seg-voile: 1;
  border-color: var(--orange);
  background: var(--orange-pale);
}

.avancement-pill[data-value="en_cours"] .avancement-seg[data-value="en_cours"],
.filtre-etat-tuile.selected[data-etat="en_cours"] {
  --seg-voile: 1;
  border-color: var(--green);
  background: var(--green-pale);
}

/* Verrouille : volontairement le plus discret des trois, comme le badge de la
   ligne repliee, c'est du travail termine dont il n'y a plus rien a attendre. */
.avancement-pill[data-value="termine"] .avancement-seg[data-value="termine"],
.filtre-etat-tuile.selected[data-etat="termine"] {
  --seg-voile: 1;
  border-color: var(--gray-4);
  background: var(--gray-1);
}

/* Le point d'avancement n'a que deux tailles, et aucun contexte ne lui en
   donne une troisieme : neuf pixels partout, douze dans le carre retenu (plus
   bas). Il en a eu trois, dont deux cote a cote sur la meme ligne : dans
   l'en-tete d'un mandat, le point de l'onglet d'exercice etait a huit et celui
   de la pastille d'avancement, trente-six pixels a sa droite, a neuf. Un pixel
   d'ecart entre deux points voisins qui disent la meme chose ne se lit pas
   comme une nuance, il se lit comme un defaut d'impression. */
.avancement-dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  transition: width .15s var(--ease), height .15s var(--ease);
}

.avancement-dot-urgent { background: var(--orange); }
.avancement-dot-encours { background: var(--green); }

/* Le point du carre retenu grossit d'un cran, pas davantage : la bordure et
   le fond disent deja l'etat, le point n'a plus a le crier. */
.avancement-pill[data-value="urgent"] .avancement-seg[data-value="urgent"] .avancement-dot,
.avancement-pill[data-value="en_cours"] .avancement-seg[data-value="en_cours"] .avancement-dot,
.filtre-etat-tuile.selected .avancement-dot {
  width: 12px;
  height: 12px;
}

.avancement-lock-icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-5);
}

.avancement-pill[data-value="termine"] .avancement-lock-icon { color: var(--black); }

.avancement-lock-badge { background: var(--gray-1); }

.avancement-lock-badge .avancement-lock-icon { color: var(--black); }

/* La nature du mandat : deux carres, celui qui est retenu prend la couleur
   qui identifie deja le mandat partout ailleurs, le violet de l'entreprise,
   le bleu de l'association (.dossier-icon-entreprise, .dossier-icon-
   association). Forme et taille sont posees plus haut, avec l'avancement. */
.type-pill[data-value="entreprise"] .type-seg[data-value="entreprise"] {
  --seg-voile: 1;
  border-color: var(--purple);
  background: var(--purple-pale);
}

.type-pill[data-value="association"] .type-seg[data-value="association"] {
  --seg-voile: 1;
  border-color: var(--blue);
  background: var(--blue-pale);
}

/* La consolidation : le meme carre, mais coche a part. Elle ne choisit pas
   entre les deux natures de mandat, elle s'ajoute a celle qui est retenue --
   « conso, ca peut etre clique ou pas clique, mais c'est independant »
   (demande du 24 aout 2026). D'ou son propre groupe, separe par l'ecart de
   .reglages-row, et sa propre teinte : le jaune, demande avec le bouton, et
   qui n'est celle d'aucune des deux natures. */
.type-pill-conso[data-value="oui"] .type-seg[data-value="conso"] {
  --seg-voile: 1;
  border-color: var(--yellow);
  background: var(--yellow-pale);
}

/* La mission : la marque du cabinet pour l'audit légal, la page signée pour
   l'audit contractuel (demande du 24 août 2026). Deux carrés de la même
   famille que la forme juridique au-dessus, et non plus deux rectangles de
   texte : ce sont deux choix qui s'excluent, comme société et association, et
   ils se lisent mieux d'un coup d'œil que par leurs deux libellés, dont le
   premier mot était le même.

   Le rouge est celui de la marque, c'est-à-dire celui du cabinet qui signe ;
   le violet est celui du carré de la liste des clients, qui signale
   déjà l'audit contractuel : la ligne et le mandat disent donc la même chose
   de la même couleur. */
.type-pill-audit[data-value="legal"] .type-seg[data-value="legal"] {
  --seg-voile: 1;
  border-color: var(--red);
  background: var(--red-pale);
}

.type-pill-audit[data-value="contractuel"] .type-seg[data-value="contractuel"] {
  --seg-voile: 1;
  border-color: var(--purple);
  background: var(--purple-pale);
}

/* La norme PE (ticket du 30 aout 2026) : « ajoute un nouveau type de mission
   "Norme PE" [...] L'icone doit etre carree, verte et bien visible, dans le
   meme style que les autres. Affiche "Norme PE" en haut et un petit "Cc" rouge
   en dessous, pour rappeler le lien avec le commissariat aux comptes. »

   Coche a part comme la consolidation, et pour la meme raison : les deux
   carres du selecteur s'excluent, celui-ci s'ajoute a l'un ou a l'autre. Le
   vert n'est la teinte d'aucun des trois voisins -- rouge, violet, jaune --,
   et c'est ce qui permet a un quatrieme carre de se lire d'un coup d'oeil dans
   une rangee ou trois couleurs sont deja prises.

   Ce carre porte un mot la ou les autres portent un trace, et c'est ce que la
   demande veut : « PE » n'est pas un dessin qu'on reconnait, c'est un nom de
   norme qu'on lit -- un trace aurait demande d'apprendre ce qu'il veut dire.
   Le trace, ici, est derriere : la marque du commissaire aux comptes en
   filigrane, qui n'a rien a apprendre a personne puisqu'elle ne fait que
   rappeler un lien deja connu (voir `.normepe-marque`). */
.type-pill-normepe[data-value="oui"] .type-seg[data-value="norme_pe"] {
  --seg-voile: 1;
  border-color: var(--green);
  background: var(--green-pale);
}

/* Le carre revient a la taille de ses voisins (suivi du 30 aout 2026) :
   « garde une forme carree, de la meme taille que les autres icones, et
   conserve le vert pour "PE". Retire uniquement le mot "Norme". Place "CC"
   derriere "PE", en rouge et en transparence, en t'inspirant du graphisme de
   l'icone "Commissariat aux comptes". Le "PE" doit rester bien lisible. »

   La version precedente s'etait elargie parce qu'elle voulait tenir « Norme PE »
   sur une ligne. Retirer le mot supprime la contrainte d'un coup : « PE » tient
   dans 28 px sans descendre sous le plus petit barreau de l'echelle, et le
   carre redevient un carre -- donc `.type-seg-normepe` n'a plus rien a redire de
   sa largeur et la regle a disparu.

   Le graphisme est celui de la marque du commissaire aux comptes : un signe
   derriere un autre, comme le petit c dans le grand C. Le « CC » rouge passe
   donc DERRIERE, en filigrane, et « PE » se lit par-dessus. C'est le meme lien
   qu'avant -- meme rouge, celui du carre « Audit legal » deux places a gauche --
   dit par la superposition au lieu de l'empilement. */
.normepe-glyphe,
.alpe-glyphe {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  line-height: 1;
}

/* Le filigrane. Plus grand que « PE » -- c'est ce qui en fait un fond et non un
   voisin --, centre sur lui. Il ne prend pas de place : sorti du flux, il ne
   peut pas pousser le texte ni elargir le carre.

   Il a d'abord ete pose a 22 % de `--red`, et c'etait trop peu : « On ne voit
   pas assez. La marque Cc en rouge. Essaye de le foncer un peu plus. » (suivi
   du 31 aout 2026). Un filigrane qu'on ne voit pas ne dit pas le lien avec le
   commissariat aux comptes -- il ne laisse qu'un carre vert avec deux lettres.
   Il passe donc au rouge fonce (`--red-dark`, celui des titres d'alerte) a
   40 % : sur le blanc du carre au repos, le rose obtenu se lit franchement, et
   le vert de « PE » par-dessus garde tout son contraste puisque c'est le fond
   qui a fonce, pas le texte. Deux leviers, pas un : la teinte ET le voile --
   monter le seul voile aurait delave un rouge deja clair au lieu de le
   foncer.

   Et il a cesse d'etre deux lettres le meme jour : « pour le CC, la forme du
   CC, inspire-toi du logo » -- celui de la CNCC, joint au ticket : deux arcs
   ouverts a droite, un grand C et un petit c dedans. « CC » compose en
   caracteres etait le NOM de la marque ; ce qu'on reconnait d'elle est son
   TRACE.

   Ce trace existait deja, et c'est celui qui est repris : `#icon-marque-maison`,
   le glyphe du carre « Audit legal » a deux places de la -- lui-meme mesure sur
   le logo fourni (rayons 10,6 et 4,92, ouvertures de 80 et 68 degres). Le
   redessiner ici en aurait fait un second, et deux traces de la meme marque
   auraient diverge a la premiere retouche. Il n'y en a qu'un, et le voisin
   qu'on demandait de prendre pour modele EST le modele.

   Ce qui reste propre au filigrane : sa taille -- tout le carre, la ou un
   glyphe ordinaire en occupe le centre --, sa teinte et son voile. Deborder le
   « PE » est ce qui en fait un fond ; s'il tenait dans les memes 18 px que les
   icones voisines, il serait un dessin a cote d'un mot, pas derriere lui. */
.normepe-marque,
.alpe-marque {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  color: var(--red-dark);
  opacity: .4;
  pointer-events: none;
}

/* « PE », par-dessus, et c'est lui qu'on lit. Le vert de la demande, la graisse
   des deux autres carres a mots du rang. */
.normepe-titre {
  position: relative;
  font-size: var(--fs-2xs);
  font-weight: 700;
  color: var(--green);
  white-space: nowrap;
}

/* La mission ALPE, cinquieme carre du rang (suivi du 5 septembre 2026) :
   « revois la partie "Type de mission" et ajoute la mission ALPE, qui n'est pas
   encore prevue parmi les types de missions ».

   Cochee a part comme la norme PE et la consolidation, et pour la meme raison :
   les deux carres du selecteur s'excluent, celui-ci s'ajoute a l'audit legal.
   Le bleu n'est la teinte d'aucun de ses quatre voisins -- rouge, violet, vert,
   jaune --, et c'est ce qui permet a un cinquieme carre de se lire d'un coup
   d'oeil dans un rang ou quatre couleurs sont deja prises. */
.type-pill-alpe[data-value="oui"] .type-seg[data-value="alpe"] {
  --seg-voile: 1;
  border-color: var(--blue);
  background: var(--blue-pale);
}

/* Les deux carres subordonnes au fondement, eteints sur une mission
   contractuelle : « il faut d'abord distinguer la mission de commissariat aux
   comptes de la mission contractuelle. Une mission de commissariat aux comptes
   peut ENSUITE etre : une mission PE, une mission ALPE » (suivi du 5 septembre
   2026).

   Un retrait et non un masquage : la rubrique garde son rang de cinq carres,
   et les deux qui ne s'appliquent pas se lisent comme ce qu'ils sont -- des
   reponses possibles que le fondement choisi ne pose pas. Les faire disparaitre
   ferait sauter la rubrique d'une largeur a l'autre a chaque clic, et
   laisserait croire qu'ils n'existent pas.

   L'opacite est celle des autres commandes hors d'atteinte du produit
   (`.selection-bar-seg:disabled`) : une seule valeur pour une seule idee. */
.type-pill-inerte {
  opacity: .25;
}
.type-pill-inerte .type-seg:disabled {
  cursor: not-allowed;
}

/* Le glyphe du carre est celui de « PE », a la lettre pres : un mot par-dessus
   la marque du commissaire aux comptes en filigrane. C'est voulu, et c'est
   pourquoi `.alpe-glyphe` et `.alpe-marque` partagent les regles du carre
   voisin au lieu de les recopier (voir plus haut) : les deux disent la meme
   sorte de chose, sous quel referentiel la mission est conduite, et deux
   dessins recopies auraient diverge a la premiere retouche. Ce qui reste propre
   a celui-ci est dessous : la taille du mot, et sa couleur.

   « ALPE » d'un barreau plus petit que « PE » : quatre lettres au lieu de deux
   dans le meme carre de 28 px. Le bleu est celui du carre allume, pour que le
   mot et son cadre disent la meme chose. */
.alpe-titre {
  position: relative;
  font-size: var(--fs-3xs);
  font-weight: 700;
  /* Le barreau negatif de l'echelle, pris ici pour la raison inverse de celle
     qui l'a fait naitre : ce n'est pas un grand titre dont les lettres se
     detachent, c'est un mot de quatre lettres qui doit tenir dans un carre de
     28 px. Mesure au navigateur : 25,6 px de mot pour 26 px de place, quatre
     dixiemes de marge. Le barreau en rend pres d'un, et une police de repli
     un peu plus large ne fait plus deborder le carre. */
  letter-spacing: var(--suivi-grand);
  color: var(--blue);
  white-space: nowrap;
}

/* Le modele des etats financiers (demande du 25 aout 2026) : les deux memes
   carres que la forme juridique juste au-dessus, et les deux memes teintes.
   C'est voulu -- le modele societe et le modele association se lisent avec le
   meme oeil que l'entite qu'ils decrivent --, et ce sont les titres des deux
   rubriques qui disent laquelle repond a quelle question. */
/* Les deux systemes allument le meme carre depuis le 31 aout 2026 : « l'onglet
   mandat ne doit avoir plus qu'un bouton pour societes ». Le systeme abrege
   avait son carre a lui du 27 au 31 aout ; il n'en a plus besoin, parce qu'il
   ne dit pas la meme chose que ses voisins -- eux nomment la sorte d'entite qui
   presente ses comptes, lui la longueur du document. Ce choix-la se fait
   maintenant devant le document (#systeme-etats-toggle), et le carre du mandat
   redit ce qu'il a toujours dit : c'est une societe. */
.type-pill-etats[data-value="societe"] .type-seg[data-value="societe"],
.type-pill-etats[data-value="societe_abrege"] .type-seg[data-value="societe"] {
  --seg-voile: 1;
  border-color: var(--purple);
  background: var(--purple-pale);
}

.type-pill-etats[data-value="association"] .type-seg[data-value="association"] {
  --seg-voile: 1;
  border-color: var(--blue);
  background: var(--blue-pale);
}

/* Le modele Francas (27 aout 2026) : le jaune du reseau, qui est celui de sa
   bulle. Les trois autres carres disent une categorie et empruntent la teinte
   de l'entite ; celui-ci designe un reseau, et un reseau se reconnait a sa
   couleur autant qu'a sa marque. */
.type-pill-etats[data-value="francas"] .type-seg[data-value="francas"] {
  --seg-voile: 1;
  border-color: var(--yellow);
  background: var(--yellow-pale);
}

/* Le modele OCCE (28 aout 2026) : le vert du premier « o » de son sigle. Meme
   regle que le carre voisin -- un reseau se reconnait a sa couleur autant qu'a
   sa marque --, et il fallait qu'elle ne soit pas la sienne : deux carres de
   reseau cote a cote sous le meme jaune se seraient lus comme un seul choix a
   deux boutons. */
.type-pill-etats[data-value="occe"] .type-seg[data-value="occe"] {
  --seg-voile: 1;
  border-color: var(--green);
  background: var(--green-pale);
}

.type-seg-icon { width: var(--icon-sm); height: var(--icon-sm); }

/* Un logo a la place d'un trace, et c'est desormais le LOGO qui cede.

   « Le bouton OCCE doit etre uniformise sur les autres (carre) » (ticket du
   31 aout 2026). Il etait le seul rectangle d'un rang de carres : la regle
   d'avant tenait la hauteur du logo sur le barreau des icones voisines
   (--icon-sm) et laissait le carre s'elargir pour recevoir un sigle deux fois
   plus large que haut.

   Cet arbitrage venait du logotype des Francas, une bande de 72 sur 26 qu'on
   ne pouvait tenir qu'en largeur ; elle a ete remplacee le 30 aout par la
   bulle carree du reseau (voir .type-seg-marque), et il ne restait plus que
   l'OCCE a s'elargir. Un rang de tuiles egales vaut mieux qu'un pixel de
   hauteur de marque : on lit d'abord un rang.

   C'est donc la largeur qui est tenue, a --icon-xl -- le barreau le plus large
   de l'echelle d'icones, celui qui remplit le carre sans le toucher. La
   hauteur suit : douze pixels pour un sigle 2:1, soit --icon-xs, un cran sous
   ses voisines. Le sigle s'y lit encore, la ou une bulle ramenee a la meme
   largeur n'etait plus qu'une trainee. */
.type-seg-logo {
  width: var(--icon-xl);
  height: auto;
}

/* Une marque carree, elle, ne demande rien au carre (30 aout 2026) : « que la
   pastille ait la meme forme exterieure que les trois autres modeles a
   gauche ».

   L'arbitrage du dessus -- c'est le carre qui cede, pas le logo -- valait pour
   un logotype allonge, qu'on ne peut tenir qu'en largeur. Il ne vaut plus des
   que la marque est aussi haute que large : la bulle des Francas, prise a
   l'icone de leur groupe, tient dans le carre commun au meme barreau que les
   trois traces voisins. Le rang redevient un rang de carres egaux, et la
   regle du dessus ne sert plus qu'a l'OCCE, dont le sigle est deux fois plus
   large que haut.

   `max-width` sur la meme valeur que la hauteur, pour que la regle tienne
   aussi le jour ou la marque sera remplacee par une image un peu plus large :
   ce qui est promis ici est la forme du carre, pas la fidelite au fichier. */
.type-seg-marque {
  height: var(--icon-sm);
  width: auto;
  max-width: var(--icon-sm);
  object-fit: contain;
}
/* Le systeme abrege prend le violet du systeme de base : les deux disent la
   meme entite, une societe, et c'est sa taille qui les separe -- pas sa
   nature. Il etait reste au gris par defaut, seul carre eteint d'une rangee
   de quatre, ce qui le faisait lire comme indisponible plutot que comme la
   forme courte de son voisin. */
.type-seg[data-value="societe"] .type-seg-icon,
.type-seg[data-value="societe_abrege"] .type-seg-icon { color: var(--purple); }
.type-seg[data-value="entreprise"] .type-seg-icon { color: var(--purple); }
.type-seg[data-value="association"] .type-seg-icon { color: var(--blue); }
.type-seg[data-value="conso"] .type-seg-icon { color: var(--yellow); }
.type-seg[data-value="legal"] .type-seg-icon { color: var(--red); }
.type-seg[data-value="contractuel"] .type-seg-icon { color: var(--purple); }

/* L'ecart de tous les rangs de carres de la feuille (voir .avancement-pill) :
   au barreau du dessous, deux tuiles voisines se lisaient comme une seule --
   c'est la rangee qui donnait les cinq paires collees du panneau Mandat au
   telephone. */
.cabinet-toggle {
  display: inline-flex;
  gap: var(--espace-xs);
}

.cabinet-seg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--h-sm);
  border: 1px solid var(--gray-3);
  background: var(--gray-1);
  border-radius: var(--radius-sm);
  padding: var(--espace-2xs) var(--espace-sm);
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--gray-5);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
}

.cabinet-seg:hover { opacity: .8; }

.cabinet-seg.active {
  color: #fff;
  border-color: transparent;
  opacity: 1;
  background: var(--seg-couleur);
}

/* Un filet d'un pixel qui ne se laisse pas retirer un pixel. Les tuiles de la
   bande portent `flex: 1 0 auto` -- elles grandissent quand il reste de la
   place, ne se compriment jamais --, si bien que ce filet etait le seul
   element retractable de la rangee : il encaissait a lui seul tout le manque
   de largeur, et tombait a zero. Mesure au navigateur le 27 aout 2026, a 320
   et a 360 px, les deux largeurs de telephone ou la rangee deborde : la seule
   chose qui separait les trois cabinets des quatre personnes physiques
   disparaissait exactement la ou il fallait la voir, et la rangee se lisait
   comme sept boutons de meme rang. Le filet reparait, la bande defile d'un
   pixel de plus, ce qu'elle faisait deja. */
.cabinet-toggle-separateur {
  width: 1px;
  flex: none;
  margin: var(--espace-3xs) var(--espace-2xs);
  background: var(--gray-3);
}

/* Rond, mais pas un rond de profil : c'est une position d'un segmente, et sa
   taille de texte est celle de ses voisines (--fs-xs, les tuiles de cabinet).
   L'aligner sur --avatar-initiales rendrait ses initiales plus petites que
   celles du bouton d'a cote, ce qui est exactement le defaut qu'on corrige
   ailleurs. */
.cabinet-seg-personne {
  border-radius: 999px;
  width: var(--h-sm);
  height: var(--h-sm);
  flex: none;
  padding: 0;
}

.dossier-empty {
  padding: var(--espace-md) var(--espace-2xs);
  color: var(--gray-5);
  font-size: var(--fs-md);
}

/* « La recherche porte sur tous les clients ». Une note, pas une alerte :
   elle explique pourquoi la liste montre des mandats que les tuiles allumees
   excluraient, et disparait des qu'on efface le champ. */
.dossier-note-recherche {
  margin: 0;
  padding: var(--espace-xs) var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.controle-banner {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace-md);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  margin-bottom: var(--espace-md);
}

.controle-banner .icon { flex: none; }

/* Un bandeau muet ne prend pas de place. Il y en a deux au-dessus des
   tableaux -- l'origine des ecritures, l'ecart de controle -- et chacun est
   vide la plupart du temps : sans cette regle, leurs marges empilaient deux
   blancs entre la barre d'outils et le premier tableau. */
.controle-banner:empty {
  display: none;
}

.controle-banner.ok {
  background: var(--green-pale);
  color: var(--green);
}

.controle-banner.warn {
  background: var(--red-pale);
  color: var(--red);
}

/* Ni un controle passe ni une anomalie : un renseignement sur ce qu'on lit --
   « cette analyse repose sur un grand livre ». Le bleu le distingue des deux
   autres, qui portent un verdict. */
.controle-banner.info {
  background: var(--blue-pale);
  color: var(--blue-dark);
}

/* Ce qui suit la barre de commandes n'est pas toujours une tuile : les trois
   bandeaux de controle s'intercalent entre elle et la barre des cycles, et
   s'effacent des qu'ils n'ont rien a dire. Le cran qui separe deux tuiles ne
   peut donc pas venir de `.tuile + .tuile`, qui demande deux voisines dans le
   document ; la barre le porte elle-meme, comme la barre collante des
   tickets porte le sien. */
#results-section > .toolbar { margin-bottom: var(--espace-md); }

/* La barre des cycles : une rangée de vignettes, et rien autour.

   Elle a été une tuile jusqu'au 9 septembre 2026 : « sors-les de la tuile,
   laisse-les libres ». Ses vignettes sont déjà des pastilles cernées, arrondies
   et teintées ; les enfermer dans un cadre blanc arrondi faisait deux boîtes
   l'une dans l'autre pour une rangée d'icônes, et cette rangée-là pesait plus
   lourd à l'oeil que les tableaux qu'elle sert à atteindre.

   Ce qui reste de la tuile est ce qu'un accrochage impose : de quoi séparer
   les vignettes de ce qui passe dessous. Une barre collante nue laisse les
   tableaux défiler au travers, et les vignettes deviennent illisibles à la
   première ligne de chiffres qui passe.

   Ce fut le fond de la page, opaque, jusqu'au 13 septembre 2026 : « quand on
   défile il reste sur fond gris, il faut que ça soit en fond transparent
   progressivement flou ». Un aplat opaque coupe net, et la coupure se voit
   d'autant mieux qu'elle tombe au milieu d'un tableau. C'est donc le geste de
   l'en-tête de page qui s'applique ici, avec ce que la demande ajoute : le
   voile s'efface vers le bas au lieu de s'arrêter.

   Trois choses en découlent, et aucune n'est décorative :

   - le voile vit dans une couche à lui (`::before`) et non sur la barre. Un
     `backdrop-filter` posé sur la barre elle-même flouterait sur toute sa
     hauteur, d'un bord à l'autre, et ne saurait pas s'estomper ;
   - le masque et le dégradé de fond s'effacent au même endroit et à la même
     cadence. Deux cadences donneraient soit un liseré gris sous un flou déjà
     fini, soit l'inverse ;
   - la couche déborde par le bas de la hauteur du creux, pour que
     l'estompage ait où se faire : arrêté au ras des vignettes, il serait
     redevenu la coupure qu'on retire.

   Le fond est écrit en chiffres, et c'est --gray-1 à 82 %. Pour la raison
   donnée à --voile en tête de feuille, et déjà suivie par .app-header : un
   voile appelé par une fonction que le navigateur ne comprend pas disparaît
   en entier, ce qui est pire que la teinte recopiée qu'il corrige.

   L'accrochage vient toujours de `.tuile-collante` -- d'où l'absence, ici, de
   `position`, de `top` et de `z-index`, et il faut la lire comme une
   interdiction : un `position: relative` écrit ici pour caler la couche de
   voile écrase le `sticky` de la classe voisine, qui a la même spécificité et
   vient plus haut dans la feuille. La barre décroche alors et s'en va avec le
   tableau, ce qui ne se voit pas dans un diff. Elle n'en a pas besoin : un
   élément `sticky` est un élément positionné, et la couche se cale déjà
   dessus. Le creux latéral tombe à zéro avec le cadre : les vignettes partent
   maintenant du bord de la colonne, comme les tableaux qu'elles
   surplombent. */
.cycles-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-xs);
  padding: var(--espace-sm) 0;
}

.cycles-nav::before {
  content: "";
  position: absolute;
  inset: 0 0 calc(var(--espace-sm) * -1);
  /* Derrière les vignettes, devant la page : `.tuile-collante` porte déjà un
     z-index, donc un contexte d'empilement, et le -1 reste dedans. */
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(246, 248, 250, .82) 0%,
    rgba(246, 248, 250, .82) 55%,
    rgba(246, 248, 250, 0) 100%
  );
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%);
}

.cycles-nav[hidden] { display: none; }

/* Meme plancher que la barre d'outils qui le surplombe, pour la meme raison.
   Cet onglet mesurait 29,19 px : une icone de 16, deux fois 5,6 de
   remplissage, deux bordures. C'etait le seul 29 du site, et il ne se lisait
   pas seul -- il est pose cinquante pixels sous une rangee ou cinq
   boutons-liens tiennent le 28 de --h-sm et deux bandes d'unites tenaient
   29,78. Trois hauteurs de petit controle empilees dans le meme regard, ce
   qui est exactement ce que ce jeton a ete pose pour empecher un panneau plus
   bas.

   Le remplissage vertical passe donc sous le plancher, comme celui du bouton
   d'unite, et le plancher fait le reste. L'horizontal ne bouge pas : c'est
   deja --espace, et la largeur de la vignette repliee n'a pas a changer. */
.cycles-nav-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  min-height: var(--h-sm);
  border: 1px solid var(--gray-3);
  background: var(--gray-1);
  color: var(--gray-6);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  padding: var(--espace-2xs) var(--espace);
  border-radius: 999px;
  cursor: pointer;
  transition: background .12s var(--ease), border-color .12s var(--ease), color .12s var(--ease),
    box-shadow .15s var(--ease), transform .15s var(--ease-spring);
}

/* Barre d'onglets des cycles : par defaut on n'affiche que l'icone (compact) ;
   le nom du cycle n'apparait que sur l'onglet actif. */
.cycles-nav-btn .cycles-nav-label { display: none; }
.cycles-nav-btn.active .cycles-nav-label { display: inline; }
.cycles-nav-btn .icon { width: var(--icon); height: var(--icon); }

.cycles-nav-btn:hover {
  border-color: var(--cyan);
  transform: translateY(-1px);
}

.cycles-nav-btn.active {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #fff;
  box-shadow: 0 4px 12px rgba(0, 174, 239, .3);
}

/* Le Memo, au bout de la barre : « place a droite des icones correspondant aux
   cycles » (ticket RUGBY CLUB DE DRANCY du 17 septembre 2026). La marge
   automatique le pousse au bout de la rangee quel que soit le nombre de
   cycles, et son nom reste lisible meme quand il n'est pas actif -- un cycle
   se reconnait a son symbole, un memo n'en a pas. */
.cycles-nav-memo { margin-left: auto; }
.cycles-nav-btn .cycles-nav-memo-label { display: inline; }

/* Teinte l'onglet de cycle selon son etat de controle d'audit (memes couleurs
   que le cadre du cycle correspondant, voir .cycle-section[data-controle-cycle]).
   L'etat remplit la vignette, il ne la borde pas : replie, un onglet ne montre
   que son icone sur une pastille de la taille d'une icone, et un lisere d'un
   pixel sur fond gris ne se voit pas -- « il faut qu'on puisse le voir beaucoup
   plus [...] que le fond ne soit plus gris, mais qu'il soit soit vert, soit
   orange, meme quand on n'est pas sur cette zone-la » (demande du 27 aout 2026).
   C'est ce que disait la coche posee sous la vignette le matin meme, en
   ajoutant une marque ; le fond le dit sans rien ajouter, et il le dit aussi
   pour l'orange, qui n'avait pas de coche. */
.cycles-nav-btn[data-controle="valide"] {
  background: var(--green);
  border-color: var(--green);
  color: #fff;
}

.cycles-nav-btn[data-controle="probleme"] {
  background: var(--orange);
  border-color: var(--orange);
  color: #fff;
}

/* L'onglet actif de ce meme cycle : la teinte s'assombrit d'un cran pour rester
   distincte du plein des onglets replies, et garde son ombre portee. */
.cycles-nav-btn.active[data-controle="valide"] {
  background: var(--green-dark);
  border-color: var(--green-dark);
  color: #fff;
  box-shadow: 0 4px 12px rgba(46, 158, 91, .3);
}

.cycles-nav-btn.active[data-controle="probleme"] {
  background: var(--orange-dark);
  border-color: var(--orange-dark);
  color: #fff;
  box-shadow: 0 4px 12px rgba(255, 138, 61, .3);
}

/* Un cycle est une tuile : son titre, ses trois commandes, son tableau et son
   programme de travail dans un meme cadre. Le titre flottait au-dessus d'un
   tableau qui, lui, en avait un ; a l'oeil il fermait le cycle precedent
   autant qu'il ouvrait le sien, et dix titres de suite donnaient a la colonne
   l'air d'une liste de fragments plutot que de dix blocs.

   L'ecart entre deux cycles descend du meme coup a --espace-md : 24 etait
   l'ecart de deux blocs que rien n'encadrait, 16 est celui que la feuille pose
   entre deux tuiles partout ailleurs (`.tuile + .tuile`). */
.cycle-section {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  padding: var(--espace-md) var(--espace-lg);
  margin-bottom: var(--espace-md);
  scroll-margin-top: 100px;
}

/* Dans la tuile d'un cycle, le tableau et le programme de travail descendent
   d'un rang. Bordure --gray-3, arrondi --radius et ombre portee sont la
   signature d'une surface posee sur la page : repetee a l'interieur d'une
   tuile qui porte exactement ce cadre, elle donne deux cadres jumeaux
   emboites a vingt pixels l'un de l'autre. Le second rang de la feuille --
   --gray-2 et --radius-sm, celui de `.tuile-encart` -- les separe sans
   redessiner la tuile, et l'ombre tombe avec : une surface a l'interieur
   d'une autre ne flotte au-dessus de rien.

   La table de tete, elle, garde le premier rang : elle n'est dans aucune
   tuile, c'est elle la surface de tete de son bloc. */
.cycle-section > .tree-table-wrap,
.cycle-section > .programme-travail {
  border-color: var(--gray-2);
  border-radius: var(--radius-sm);
  box-shadow: none;
}

/* Huit pixels, releves dix fois sur la page : l'ecart entre l'icone et le
   titre, et l'air sous le titre avant son tableau. Ni l'un ni l'autre n'est un
   barreau, et les deux prennent --espace-sm -- celui que le bandeau de
   conclusion emploie deja pour la meme paire icone-titre, quelques milliers de
   lignes plus bas. */
.cycle-section-title {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  font-size: var(--fs-lg);
  font-weight: 700;
  margin: 0 0 var(--espace-sm);
  color: var(--gray-6);
}

.cycle-section-title .icon { width: var(--icon-md); height: var(--icon-md); color: var(--cyan-dark); }

/* Les trois memes commandes que la barre de la vue, quelques pixels plus haut
   -- tout deplier, tout deplier hors soldes, tout replier --, cette fois
   portees sur une seule section. Memes commandes, donc meme controle : le carre
   commun aux petits controles, l'icone de la maison, l'ecart de la barre
   au-dessus, et un creux ecrit.

   Elles etaient dessinees a la main : un carre de 24 pour une icone de 14, et
   le remplissage laisse par le navigateur (1px 6px), qui debordait de sa propre
   boite. Le meme chevron de depliage se lisait donc a 16 dans la barre et a 14
   sur le titre, trente-huit pixels plus bas, les deux rangs visibles ensemble.
   C'est le defaut que le commentaire de `.btn-link.btn-icon-only` a deja nomme
   ailleurs -- « trois voisins d'une meme rangee, trois hauteurs » --, et celui
   que la feuille du telephone a corrige de son cote en accordant les quatre
   commandes du titre a 38 px.

   La teinte, elle, ne bouge pas : ces trois-la sont posees sur un titre et non
   dans une barre d'actions, et le gris est le seul ecart qu'on garde. La bulle
   du commentaire garde aussi ses 20 px, pour la raison ecrite dans mobile.css :
   sur le bureau `margin-left: auto` la laisse contre le texte et met mille
   pixels entre elle et les bascules -- deux boutons qui ne se voient pas ne se
   comparent pas. */
.cycle-section-toggles {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-sm);
  margin-left: auto;
}

.cycle-section-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-sm);
  height: var(--h-sm);
  padding: 0;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--gray-5);
  transition: background .15s var(--ease), color .15s var(--ease);
}

.cycle-section-toggle-btn:hover { background: var(--gray-2); color: var(--gray-6); }

.cycle-section-toggle-btn .icon { width: var(--icon); height: var(--icon); color: inherit; }

/* La table de tete de l'onglet Analyse (« Resultat de l'exercice » en vue
   cycles, ou le bilan) porte le cadre de premier rang -- --gray-3, --radius,
   ombre portee --, celui que le commentaire de `.cycle-section` appelle « la
   signature d'une surface posee sur la page ». Elle n'avait pas de fond : elle
   empruntait le blanc du corps. Le sol etant passe au gris (voir `body`), il
   lui faut le sien, sans quoi son en-tete --gray-1 se confond avec la page et
   la surface de tete du bloc n'en est plus une. Le meme cadre place dans une
   tuile de cycle descend au second rang et n'a pas ce besoin : il est deja
   pose sur du blanc. */
.tree-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-sm);
}

/* Table de tete (Resultat de l'exercice en vue cycles, ou le bilan) : enfant
   direct du conteneur, donc ne beneficie pas de la marge des .cycle-section.
   On l'espace explicitement de la premiere section de cycle qui suit.

   Explicitement, oui, mais pas du meme creux : 32 ici, 24 partout ailleurs. Le
   commentaire disait deja ce qu'il fallait faire -- « on l'espace de la
   premiere section de cycle qui suit » --, et c'est precisement ce qui impose
   la meme valeur : ce qui separe la table de tete du premier cycle n'est pas
   d'une autre nature que ce qui separe deux cycles. La colonne s'ouvrait sur un
   ecart de 32, puis n'en montrait plus que de 24 sur toute sa hauteur ; le
   premier blanc etait le seul a ne ressembler a aucun autre.

   Et c'est encore cette egalite qui le fait passer a 16 : les cycles sont
   devenus des tuiles, l'ecart entre deux tuiles vaut --espace-md, et ce qui
   separe la table de tete de la premiere d'entre elles n'est toujours pas
   d'une autre nature. */
#tree-tables-container > .tree-table-wrap { margin-bottom: var(--espace-md); }

.tree-table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--fs-sm);
}

/* Alignement des colonnes entre cycles : chaque cycle est un <table> distinct.
   Sans largeurs fixes, chacun dimensionne ses colonnes selon son propre
   contenu et les colonnes 2025/2024/Variation ne s'alignent pas d'un cycle a
   l'autre. On fige donc les colonnes numeriques (identiques partout) ; la
   colonne Poste absorbe le reste, largeur elle aussi identique puisque toutes
   les tables occupent la meme largeur totale. Scope au conteneur d'analyse
   pour ne pas toucher la table de mapping (colonnes differentes). */
#tree-tables-container .tree-table { table-layout: fixed; }
#tree-tables-container .tree-table col.col-annee { width: 9rem; }
#tree-tables-container .tree-table col.col-variation { width: 10rem; }
#tree-tables-container .tree-table td.label-cell { overflow-wrap: anywhere; }
#tree-tables-container .tree-table .row-toggle { min-width: 0; }

.tree-table thead th {
  background: var(--gray-1);
  text-align: right;
  font-weight: 500;
  padding: var(--espace-sm) var(--espace);
  border-bottom: 1px solid var(--gray-3);
  white-space: nowrap;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
}

.tree-table thead th:first-child { text-align: left; }

/* Colonne de l'exercice audite en cours (voir classeAnneeActive dans app.js) :
   distinguee en gras, header et chiffres, tant que l'exercice reste ouvert.
   Bascule seule sur la colonne suivante a la cloture, sans logique en plus. */
.tree-table th.col-annee-active,
.tree-table td.col-annee-active { font-weight: 700; }

/* L'intitule d'un exercice dans un DOCUMENT -- le bilan, le compte de resultat,
   le tableau de flux --, et les trois sous-titres Brut / Amort. / Net qui le
   suivent. Tous du meme poids, l'exercice audite comme les autres.

   « Mets l'intitule de l'exercice N-1, 31 decembre 2024, en gras comme celui
   de l'exercice N, 31 decembre 2025 » (ticket du 6 septembre 2026). La regle
   juste au-dessus a du sens dans une table d'analyse, ou l'on parcourt cinq
   exercices en cherchant celui sur lequel porte la campagne. Un document n'en
   porte que deux, ne se travaille pas et s'imprime : son PDF ne distingue
   aucune annee, et l'ecran ne doit pas en distinguer une non plus. */
.tree-table thead th.th-exercice-document { font-weight: 700; }

/* L'en-tete d'un exercice qui couvre plusieurs colonnes -- l'exercice N de
   l'actif du bilan reglementaire, et ses trois colonnes Brut / Amort. et
   depreciations / Net. Centre sur ce qu'il couvre, et non aligne a droite
   comme une colonne de chiffres : « il faut que l'annee N ne fasse qu'une
   cellule fusionnee et centree, alignee sur les 3 rubriques Brut Amort et
   Depreciations et Net » (demande du 25 aout 2026). Aligne a droite, la date
   se lisait au-dessus de la seule colonne Net et passait pour son titre. */
.tree-table thead th.th-exercice-fusionne { text-align: center; }

/* Symbole Δ (delta) a la place du libelle "Variation" : centre plutot
   qu'aligne a droite comme les colonnes chiffrees, et a taille normale
   puisque ce n'est plus un mot a faire tenir. */
.tree-table thead th.th-variation {
  text-align: center;
  font-size: var(--fs);
  text-transform: none;
  cursor: help;
}

/* Tableau "Résultat de l'exercice" (renderHead appelé avec sansDelta) : la
   colonne Variation reste presente pour l'alignement mais son en-tete est
   vide, puisque cette ligne n'affiche jamais de variation -- pas de curseur
   d'aide sans rien a expliquer. */
.tree-table thead th.th-variation:empty {
  cursor: default;
}

.tree-table tbody tr:not(.row-verification):hover td { background: var(--gray-1); }

.tree-table td {
  padding: var(--espace-xs) var(--espace);
  border-bottom: 1px solid var(--gray-2);
  text-align: right;
  white-space: nowrap;
  transition: background .1s var(--ease);
}

.tree-table td.label-cell {
  text-align: left;
  white-space: normal;
}

.tree-table tr.level-total > td { font-weight: 700; }

/* Un sous-total pese sur toute sa ligne, chiffres et variation compris.
   L'intitule seul etait en gras : « pour chaque sous-total de cycle, toute la
   ligne doit etre en gras. Exemple pour la ligne Fonds propres, les chiffres
   et la variation doivent etre egalement en gras » (demande du 26 aout 2026).
   Un oeil qui parcourt la colonne des montants en diagonale ne voyait aucune
   marche : les chiffres d'un sous-total y avaient exactement le meme poids que
   ceux des comptes qu'il additionne.

   Six cents et non sept : la ligne de total du cycle garde sa marche
   au-dessus, sinon les deux niveaux se confondraient.

   La colonne de l'exercice audite est mise hors d'atteinte : sans le `:not`,
   cette regle-ci l'emporte sur `col-annee-active` -- meme selecteur, un cran
   de specificite en plus -- et le sous-total effacait sur sa propre ligne la
   marque qui dit sur quelle annee porte la campagne. */
.tree-table tr.level-0 > td:not(.col-annee-active) { font-weight: 600; }
.tree-table tr.level-0 > td.label-cell { font-family: var(--sans); font-size: var(--fs); }
.tree-table tr.row-compte > td:not(.variation-cell) { color: var(--blue); }

.row-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  cursor: pointer;
  user-select: none;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  padding: 0;
}

.row-toggle .arrow {
  display: inline-block;
  transition: transform .15s var(--ease);
  color: var(--gray-4);
  /* Meme valeur qu'avant, mais nommee : c'est le barreau que reprend le
     chevron de fin de ligne des mandats (.dossier-chevron), et un barreau
     ecrit a la main ne se laisse pas suivre. */
  width: var(--icon-sm);
  height: var(--icon-sm);
}

.row-toggle.open .arrow { transform: rotate(90deg); }

.row-label-text { cursor: pointer; user-select: none; }

/* Un compte pose sous son poste : un cran a partir du creux de `.tree-table
   td`. La regle etait ecrite `.row-leaf-label` (0,1,0) et perdait donc contre
   `.tree-table td` (0,1,1), qui repose le creux : elle n'a jamais rien
   decale. Dans l'arbre d'analyse cela ne se voyait pas -- app.js y pose le
   retrait en ligne --, mais dans le bilan et le compte de resultat
   reglementaires, ou personne ne le pose, un compte deplie s'alignait sur son
   poste (constate au navigateur le 29 aout 2026 : 104 comptes a 12,8 px,
   comme la ligne du dessus). Le `td.` la fait gagner. */
td.row-leaf-label {
  padding-left: calc(var(--espace) + var(--retrait-pas));
  color: var(--gray-5);
}

.row-account {
  cursor: pointer;
  color: var(--blue);
  border-radius: var(--radius-xs);
  transition: color .1s var(--ease);
}

.row-account:hover { text-decoration: underline; }

.row-account-montant { cursor: pointer; }
.row-account-montant:hover { text-decoration: underline; }

/* Une ligne de detail qui ne descend nulle part : l'apport des comptes rendus
   des cooperatives sous le jeu « Association » du reseau OCCE (ticket du
   2 septembre 2026, voir documents_pcg._comptes_du_poste). Elle compose le
   poste comme un compte, mais aucune ecriture ne dort dessous -- une
   cooperative ne tient pas de comptabilite. Elle prend donc l'encre grise des
   lignes qu'on lit et le curseur des lignes qu'on n'ouvre pas. */
.row-account-inerte { color: var(--gray-5); }
/* Une ligne de compte qui recoit la piece qu'on lui tire dessus (ticket du
   10 septembre 2026). Le meme liseré que les cibles de dépôt des zones de
   fichiers : on doit voir OU la piece va tomber avant de lacher. */
/* La cible que survole une piece tiree d'une zone de fichiers du mandat : une
   ligne de compte, une ligne d'ecriture, l'en-tete d'une fenetre d'ecriture
   (ticket du 12 septembre 2026 -- le compte seul recevait, depuis le 10). Le
   violet des justificatifs, comme le trombone. */
tr.depot-mandat-cible > td {
  background: var(--purple-pale) !important;
  box-shadow: inset 0 0 0 1px var(--purple);
}

/* Et quand la cible n'est pas une rangee de tableau : l'en-tete de la fenetre
   d'une ecriture, qui recoit la piece de l'ecriture entiere. */
.depot-mandat-cible:not(tr) {
  background: var(--purple-pale);
  box-shadow: inset 0 0 0 1px var(--purple);
}

.row-compte-inerte .row-account-montant { cursor: default; }
.row-compte-inerte .row-account-montant:hover { text-decoration: none; }

.row-ecriture-num {
  cursor: pointer;
  color: var(--cyan-dark);
  transition: color .1s var(--ease);
}

.row-ecriture-num:hover { color: var(--cyan-dark); text-decoration: underline; }

.variation-cell { color: var(--gray-5); font-size: var(--fs-xs); }

.tree-table td.positive { color: var(--green); }
.tree-table td.negative { color: var(--red); }

/* Un solde negatif dans des Cycles lus en sens usuel : « lorsque Sens usuel
   est choisi, si un solde est negatif alors il doit figurer en rouge » (ticket
   du 28 aout 2026).

   C'est ce que le sens usuel promet : chaque poste ecrit en positif du cote ou
   il se lit d'ordinaire. Un negatif y est donc un poste a l'envers -- un
   capital debiteur, une reserve negative --, et non un simple signe. Au sens
   naturel il n'a rien d'anormal, la moitie du bilan y etant negative par
   construction : la classe n'est alors pas posee (voir
   montantNegatifAsignaler). */
/* Un solde negatif lu en sens usuel : « lorsque Sens usuel est choisi, si un
   solde est negatif alors il doit figurer en rouge » (ticket du 28 aout 2026).

   Le second selecteur est la raison pour laquelle la regle ne s'appliquait pas
   sur une ligne de compte : « .tree-table tr.row-compte > td:not(.variation-cell) »
   peint les comptes en bleu et pese un cran de plus que « .tree-table
   td.solde-a-l-envers ». Un 102 negatif restait donc bleu, alors que la
   rubrique qui le porte virait au rouge -- « je viens de verifier dans le
   client ACBB et les comptes 102 negatifs ne sont pas en rouge » (suivi du
   meme jour). */
.tree-table td.solde-a-l-envers { color: var(--red); }

/* La meme regle, un cran plus haut, pour une ligne de compte : « .tree-table
   tr.row-compte > td:not(.variation-cell) » peint les comptes en bleu et pese
   un cran de plus que la regle ci-dessus. Un 102 negatif restait donc bleu,
   alors que la rubrique qui le porte virait au rouge -- « je viens de verifier
   dans le client ACBB et les comptes 102 negatifs ne sont pas en rouge alors
   qu'ils sont negatifs » (suivi du 28 aout 2026). */
.tree-table tr.row-compte > td.solde-a-l-envers:not(.variation-cell) {
  color: var(--red);
}

tr.child-row[hidden] { display: none; }

tr.row-verification > td {
  background: var(--cyan-pale);
  border-bottom: 2px solid var(--cyan);
  font-weight: 700;
}

tr.row-verification > td.label-cell { font-family: var(--sans); }

/* Le resultat de l'exercice, dans les deux documents de synthese du PCG
   (« mets la rubrique Resultat de l'exercice en evidence », demande du 25 aout
   2026). C'est le chiffre qu'on va chercher en premier, et il se perdait :
   dans le bilan, ligne ordinaire entre le report a nouveau et les subventions ;
   dans le compte de resultat, derniere ligne cyan d'une colonne de lignes cyan.

   Un bleu clair, et rien d'autre : « concernant le resultat de l'exercice,
   utilise un bleu clair mais fais une rubrique moins marquee qu'un sous total »
   (suivi du 25 aout 2026). Un jaune de surligneur avait tenu cette place le
   temps d'une version, avec le gras et le filet d'un total -- il criait plus
   fort que les lignes qui l'encadrent, ce qui n'est pas ce qu'on demande a une
   rubrique reperable. Le fond suffit a la retrouver ; le gras et le filet
   restent la marque des sous-totaux.

   La regle passe apres .row-verification pour la defaire sur la ligne du
   compte de resultat, qui en est un. */
tr.document-pcg-resultat > td {
  background: var(--blue-pale);
  border-bottom: 1px solid var(--gray-2);
  font-weight: 500;
}

tr.document-pcg-resultat > td.label-cell { font-family: var(--sans); }

/* Ce qu'un mandat ne tient pas : la phrase qui remplace le tableau quand la
   balance clients ou fournisseurs n'a aucun tiers a montrer (demande du
   25 aout 2026). Un tableau vide se lirait comme une panne. */
/* Le cycle d'ou vient un compte de la balance, pose devant son numero
   (demande du 25 aout 2026). En gris : c'est un reperage, pas une alerte --
   l'oeil balaie la colonne et s'arrete sur ce qui detonne. */
.row-cycle-icone {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
  margin-right: var(--espace-xs);
  vertical-align: -.15em;
}

/* Et l'absence de cycle, qui est le cas qu'on cherche : elle se nomme, en
   orange, plutot que de laisser un blanc qu'on prendrait pour un oubli
   d'affichage. */
.row-cycle-absente { color: var(--orange); }

/* La seconde rangee de titres d'une balance de tiers : Debit, Credit, Solde
   sous le millesime de chaque exercice (demande du 25 aout 2026). Plus petite
   et plus claire que la premiere -- elle nomme des colonnes, elle n'annonce pas
   une periode. */
.tree-table thead tr.th-mouvements th {
  font-size: var(--fs-3xs);
  font-weight: 600;
  color: var(--gray-4);
  text-transform: none;
  letter-spacing: 0;
  padding-top: 0;
}

/* Les trois titres qui trient la balance de tiers (demande du 25 aout 2026) :
   un clic les fait passer du plus grand au plus petit, puis l'inverse, puis
   plus rien. La colonne qui tient le tri porte une fleche et l'encre du
   produit ; les deux autres restent grises, comme un titre ordinaire. */
.tree-table thead tr.th-mouvements th.th-triable {
  cursor: pointer;
  user-select: none;
  transition: color .15s var(--ease);
}

.tree-table thead tr.th-mouvements th.th-triable:hover { color: var(--gray-6); }

.tree-table thead tr.th-mouvements th.th-tri-actif { color: var(--cyan-dark); }

.balance-aux-vide {
  color: var(--gray-5);
  font-size: var(--fs-sm);
  padding: var(--espace-xl);
  margin: 0;
  text-align: center;
}

/* Le filet d'air entre le resultat et le solde, en tete de la balance, a vecu
   le temps d'une version : les deux controles sont depuis dans deux tableaux
   distincts (« fais plutot deux blocs separes, un pour le resultat et un pour
   le solde », suivi du 25 aout 2026), et l'ecart entre deux blocs est celui de
   tous les autres. */

/* Le solde de la balance : meme ligne de controle que le resultat, mais elle
   passe au rouge quand elle ne solde pas a zero. Une balance qui ne solde pas
   n'est pas une nuance de plus dans un tableau -- c'est un FEC a reprendre, et
   ca doit se voir de l'autre bout de la page (demande du 25 aout 2026). */
tr.row-solde-balance.rompu > td {
  background: var(--red-pale);
  border-bottom: 2px solid var(--red);
  color: var(--red);
}

.modal-table tr.row-cloture > td {
  background: var(--cyan-pale);
  border-bottom: 2px solid var(--cyan);
  border-top: 2px solid var(--cyan);
  font-weight: 700;
  color: var(--cyan-dark);
}

/* L'ecart qu'un document ne verifie plus, dit sous le chiffre. Le triangle est
   celui du produit (`#icon-alert-triangle`) et non le caractere `⚠`, que la
   plupart des machines rendent avec leur police d'emoji : un panneau jaune et
   bombe pose au milieu d'une ligne rouge et plate, et redessine par chaque
   systeme a sa facon.

   Le triangle et la phrase sont un seul mot, d'ou --espace-xs entre eux ; il ne
   se comprime pas et se cale en haut, la phrase pouvant tenir sur deux lignes
   dans une cellule etroite. */
.resultat-ecart-warn {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-xs);
  font-weight: 400;
  font-size: var(--fs-2xs);
  color: var(--red);
  white-space: normal;
  margin-top: var(--espace-2xs);
}

.resultat-ecart-warn > .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  flex: none;
  /* Centre sur la premiere ligne de texte plutot que sur son haut. */
  margin-top: calc((1lh - var(--icon-xs)) / 2);
}

/* Un bilan dont l'actif ne vaut pas le passif, un compte de resultat dont le
   resultat n'est pas celui du FEC : deux documents qui ne se verifient plus, et
   ca doit se lire avant les chiffres, pas apres (demandes du 26 aout 2026). Le
   bandeau tient donc en tete du document, dans le rouge des anomalies, comme
   la ligne de solde rompue de la balance. */
.document-pcg-alertes {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-md);
}

.document-pcg-alerte {
  margin: 0;
  padding: var(--espace) var(--espace-md);
  border-radius: var(--radius);
  border: 1px solid var(--red);
  background: var(--red-pale);
  color: var(--red);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* Vingt paragraphes d'explication vivent sur /mapping -- un par tableau, pour
   dire d'ou viennent les rubriques, comment un prefixe capte un compte, ce
   qu'une bascule change. Ce sont les seuls usages de la classe, et le plus
   long fait mille trois cent soixante-dix caracteres.

   Ils n'avaient pas de plafond, donc ils prenaient les 1336 px du panneau :
   a 12 px, environ deux cent vingt caracteres par ligne. C'est le double de
   ce que l'oeil suit, et l'effet est celui d'un texte qu'on ne lit pas -- on
   voit un bloc gris et on passe. Le meme texte pose sur --largeur-lecture en
   fait des lignes de la longueur d'un paragraphe de /confidentialite, ou
   .doc-wrap porte deja ce plafond.

   Le plafond ne mord que sur du texte suivi : les deux compteurs remplis par
   le script (#bilan-pcg-compteur, #resultat-pcg-compteur) font trente
   caracteres et tiennent bien en deca.

   Il s'ecarte du meme cran en haut et en bas, et ne l'ecrivait qu'a moitie :
   il choisissait sa marge haute et laissait la basse au navigateur, qui pose un
   `1em` suivant la taille du texte. Mesure le 30 aout 2026 : 12 px sur ecran
   large, 10,9 a 390 -- la cadence changeait avec la largeur de la fenetre, sans
   que rien ne le dise.

   L'ecart s'est d'abord ecrit sous `.tuile > p.disclaimer`, parce que le Mapping
   posait ses vingt paragraphes hors de toute tuile et qu'il fallait leur laisser
   celui qu'on leur connaissait. Il les y pose depuis le 30 aout 2026, et le
   vingt-et-unieme -- l'alerte generale du cabinet -- y etait deja : plus un seul
   `.disclaimer` du produit ne vit hors d'une tuile, et cette portee ne protegeait
   plus rien. Ce qui reste vrai de la tuile est ecrit avec les regles de tuile,
   en tete de feuille : le dernier enfant d'une tuile, quel qu'il soit, rend sa
   marge basse au creux de la tuile.

   Restait sa teinte, la seule chose que ce commentaire n'avait jamais
   arbitree, et le seul texte du produit qui echouait au contraste : --gray-4
   sur blanc, 2,55 pour 1 la ou il en faut 4,5. --gray-4 est le gris des
   bordures et des icones, pas celui d'une encre -- les deux encres secondaires
   de la feuille sont --gray-5 et --gray-6, et le premier des deux mene ce
   paragraphe a 5,98.

   C'est le meme defaut que celui du dessus, par l'autre bout. Le plafond de
   largeur a ete pose parce qu'un texte trop long donne « l'effet d'un texte
   qu'on ne lit pas -- on voit un bloc gris et on passe » ; un texte trop pale
   le donne aussi, et vingt-trois paragraphes du produit l'avaient encore. */
.disclaimer {
  max-width: var(--largeur-lecture);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  margin: var(--espace-md) 0 var(--espace-sm);
  font-style: italic;
}

/* Le voile d'une fenetre modale, celui qu'on voit le plus. Le recensement des
   neuf surfaces qui assombrissent et la raison des deux barreaux sont ecrits
   avec --voile, en tete de feuille. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: var(--voile);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: var(--espace-2xl);
  animation: modal-fade-in .15s var(--ease);
}

.modal-overlay[hidden] { display: none; }

@keyframes modal-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes modal-pop-in {
  from { opacity: 0; transform: translateY(6px) scale(.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* Grande surface flottante, comme la feuille du telephone : meme arrondi. */
.modal {
  background: #fff;
  border-radius: var(--radius-lg);
  width: 100%;
  max-width: var(--largeur-fenetre);
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  animation: modal-pop-in .18s var(--ease);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: var(--espace-lg) var(--espace-xl);
  border-bottom: 1px solid var(--gray-3);
}

.modal-header h2 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--fs-h2);
  margin: 0;
}

.modal-compte-lib {
  color: var(--gray-5);
  font-size: var(--fs);
  margin: var(--espace-2xs) 0 0;
}

.modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: none;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  color: var(--red);
  transition: background .15s var(--ease), color .15s var(--ease);
}

.modal-close:hover { background: var(--red-pale); color: var(--red); }

/* La barre de filtres se lit sous l'en-tete de la fenetre, et les deux se
   suivent : memes creux sur les cotes, --espace-xl, pour que leur contenu tombe
   sur la meme verticale. Un barreau de moins en hauteur, parce que c'est la
   barre subordonnee. L'en-tete ecrivait ses 24 px a la main -- desormais tous
   deux passent par le meme jeton, donc ils bougeront ensemble. */
.modal-filters {
  display: flex;
  gap: var(--espace-lg);
  align-items: center;
  padding: var(--espace-md) var(--espace-xl);
  border-bottom: 1px solid var(--gray-2);
  font-size: var(--fs-sm);
  flex-wrap: wrap;
}

.modal-filters label {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

/* « Sélectionner » et « Non Lettrées » forment un bloc, calé à droite de la
   barre de filtres : les deux portent sur les mêmes lignes, et l'un se lit
   dans la foulée de l'autre. Le bouton était auparavant dans la barre de
   titre, deux étages plus haut, à côté du nom du compte -- où rien ne disait
   qu'il parlait de la liste. */
.modal-filters-actions {
  display: flex;
  align-items: center;
  gap: var(--espace);
  margin-left: auto;
}

.filter-checkbox {
  gap: var(--espace-xs);
  color: var(--gray-6);
  cursor: pointer;
  user-select: none;
}

/* La case a cocher maison est desormais posee sur l'element, en tete de
   feuille, et vaut donc pour toutes les cases du site. Il ne reste ici que le
   survol de l'etiquette : poser la souris sur le mot doit eclairer la case,
   ce que la regle de base ne peut pas savoir. */
.filter-checkbox:hover input[type="checkbox"] { border-color: var(--gray-4); }
.filter-checkbox:hover input[type="checkbox"]:checked { border-color: var(--cyan); }

.year-slider-group {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  flex: 1;
  min-width: 220px;
  max-width: 360px;
}

.year-slider-group label {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.year-slider-group #filter-year-label {
  color: var(--black);
  font-weight: 600;
}

.year-range-slider {
  position: relative;
  height: 22px;
  display: flex;
  align-items: center;
}

.year-range-track {
  position: absolute;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--gray-3);
  border-radius: 999px;
}

.year-range-fill {
  position: absolute;
  height: 4px;
  background: var(--cyan);
  border-radius: 999px;
}

.year-range-slider input[type="range"] {
  position: absolute;
  left: 0;
  right: 0;
  width: 100%;
  margin: 0;
  background: none;
  appearance: none;
  pointer-events: none;
}

.year-range-slider input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  background: transparent;
}

.year-range-slider input[type="range"]::-moz-range-track {
  height: 4px;
  background: transparent;
  border: none;
}

.year-range-slider input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  pointer-events: auto;
  width: 15px;
  height: 15px;
  border-radius: 999px;
  background: var(--cyan);
  cursor: pointer;
  margin-top: -5.5px;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--cyan);
}

.year-range-slider input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
  width: 15px;
  height: 15px;
  border-radius: 999px;
  background: var(--cyan);
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--cyan);
}

.modal-table-wrap {
  overflow: auto;
  padding: 0 var(--espace-xl) var(--espace-xl);
}

.modal-table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--fs-sm);
}

/* Colonnes Analytique / Lettrage masquees quand le compte ouvert n'en a
   aucune valeur (classes posees par renderTransactions). Les lignes de solde
   de cloture n'ont pas ces cellules (couvertes par un colspan) : la colonne se
   replie donc bien a 0 des lors que l'en-tete et les cellules sont masques. */
.modal-table.hide-analytique .col-analytique,
.modal-table.hide-lettrage .col-lettrage { display: none; }

/* Visualiseur de document source (FEC brut) : colonnes rarement renseignees
   masquees quand aucune ligne du document ne les utilise (classes posees par
   renderDocumentEcritures). */
.modal-table.hide-doc-aux .col-doc-aux,
.modal-table.hide-doc-piece-date .col-doc-piece-date,
.modal-table.hide-doc-lettrage .col-doc-lettrage,
.modal-table.hide-doc-devise .col-doc-devise { display: none; }

#tab-panel-document .toolbar-search { max-width: 360px; }

.modal-table th {
  position: sticky;
  top: 0;
  background: #fff;
  text-align: left;
  padding: var(--espace-xs) var(--espace-sm);
  border-bottom: 2px solid var(--gray-3);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
}

.modal-table th.num, .modal-table td.num { text-align: right; }

/* Les colonnes triables du grand livre : « dans cette vue, il faut pouvoir
   trier par n'importe quelle colonne (tri croissant ou décroissant) » (ticket
   du 15 septembre 2026).

   La flèche se pose en pseudo-élément et ne prend aucune place tant qu'aucun
   tri n'est actif : un chevron gris sur chacune des dix colonnes se lirait
   comme un menu déroulant, et l'en-tête est déjà serré. Au survol, la colonne
   annonce ce qu'un clic ferait. */
.modal-table th[data-tri] { cursor: pointer; user-select: none; }
.modal-table th[data-tri]:hover { color: var(--gray-6); }
.modal-table th[data-tri][aria-sort="ascending"]::after { content: " \2191"; }
.modal-table th[data-tri][aria-sort="descending"]::after { content: " \2193"; }
.modal-table th[data-tri][aria-sort="ascending"],
.modal-table th[data-tri][aria-sort="descending"] { color: var(--blue); }

.modal-table td {
  padding: var(--espace-xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-2);
  white-space: nowrap;
}

/* Detail de compte : meme panneau ancre que les autres onglets (pas de boite
   flottante par-dessus un fond assombri), la table suit le flux normal de la
   page au lieu d'etre limitee a une zone de defilement interne.

   Ses trois bandes -- le compte et sa navigation, les filtres, les ecritures
   -- se posaient a nu sur le blanc de la page, separees par deux filets : on
   lisait une colonne de texte et de boutons, pas trois zones. Elles font deux
   tuiles, les commandes d'un cote et la liste de l'autre.

   L'en-tete et les filtres partagent un seul cadre au lieu d'en avoir un
   chacun, parce que les deux se collent au haut de la fenetre au defilement
   (`position: sticky` plus bas) : un intervalle entre eux laisserait defiler
   les ecritures dans l'entrebaillement. Le cadre est donc coupe en deux
   moities -- haut et cotes ici, cotes et bas la -- et le filet qui les separe
   est celui de l'en-tete, descendu d'un rang (--gray-2) puisqu'il est
   desormais a l'interieur d'une surface. */
.compte-detail-panel .modal-header {
  padding-left: var(--espace-lg);
  padding-right: var(--espace-lg);
  border: 1px solid var(--gray-3);
  border-bottom-color: var(--gray-2);
  border-radius: var(--radius) var(--radius) 0 0;
  gap: var(--espace-md);
}

/* Les trois groupes de l'en-tete -- la navigation entre comptes, la marque de
   controle, la croix -- se touchaient : `.compte-nav` prend tout l'espace
   libre (flex: 1), donc le `margin-left: auto` de la marque ne recevait rien
   et « Valider le compte » venait buter contre le nom du compte suivant. Le
   creux est maintenant celui de l'en-tete, le meme entre les trois ; la marge
   propre a la marque, qui vaut pour la fenetre d'ecriture ou elle est seule de
   son cote, ferait ici 32 px d'un cote et 16 de l'autre. */
.compte-detail-panel .modal-header .ecriture-valider {
  margin-right: 0;
}

.compte-detail-panel .modal-filters {
  padding-left: var(--espace-lg);
  padding-right: var(--espace-lg);
  border: 1px solid var(--gray-3);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  margin-bottom: var(--espace-md);
}

.compte-detail-panel .modal-table-wrap {
  overflow: visible;
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

/* Le dernier filet du tableau tombait sur le bord de la tuile : deux traits
   colles, gris-2 puis gris-3, la ou le dessin n'en demande qu'un. La derniere
   rangee rend donc son trait au cadre -- sauf un solde de cloture, dont le
   filet cyan de 2 px n'est pas une separation entre deux lignes mais la
   fermeture d'un exercice. */
.compte-detail-panel .modal-table > tbody > tr:last-child:not(.row-cloture) > td {
  border-bottom: 0;
}

.compte-detail-panel .modal-table th {
  position: static;
}

/* Detail de compte : l'en-tete de compte, ses filtres et l'en-tete de
   tableau restent visibles au defilement de la page (voir
   syncCompteDetailOffsets, qui calcule le `top` de chacun sous le header
   sticky de l'app). */
#tab-panel-compte .modal-header,
#tab-panel-compte .modal-filters {
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 15;
}

/* En-tete de compte compact : numero et nom du compte sur la meme ligne
   plutot qu'empiles, pour occuper moins de place une fois fixe au
   defilement. */
#tab-panel-compte .modal-header {
  padding-top: var(--espace-sm);
  padding-bottom: var(--espace-sm);
}

.compte-nav {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--espace-md);
  flex: 1;
  min-width: 0;
}

/* Position explicite de chaque enfant : quand le bouton precedent est
   masque (hidden, donc retire du flux), l'auto-placement de la grille
   compacterait sinon le titre et le bouton suivant dans les colonnes 1 et 2
   au lieu de rester chacun dans sa colonne dediee. */
#compte-nav-prev { grid-column: 1; }
.modal-compte-titre { grid-column: 2; }
#compte-nav-next { grid-column: 3; }

.modal-compte-titre {
  display: flex;
  align-items: baseline;
  gap: var(--espace-xs);
  justify-self: center;
}

.modal-compte-titre #modal-compte-num {
  font-size: var(--fs-h3);
  color: var(--blue);
}

.modal-compte-titre .modal-compte-lib {
  margin: 0;
}

.compte-nav-btn {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  min-width: 0;
  max-width: 100%;
  background: none;
  border: none;
  padding: var(--espace-2xs) var(--espace-xs);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--gray-6);
  transition: background .15s var(--ease);
  justify-self: start;
}

.compte-nav-btn[hidden] {
  display: none;
}

.compte-nav-btn-suivant {
  justify-self: end;
}

.compte-nav-btn:hover {
  background: var(--gray-2);
}

.compte-nav-btn .icon {
  width: var(--icon);
  height: var(--icon);
  flex-shrink: 0;
  color: var(--gray-5);
}

.compte-nav-btn-texte {
  display: flex;
  gap: var(--espace-2xs);
  min-width: 0;
  font-size: var(--fs-xs);
  white-space: nowrap;
  overflow: hidden;
}

.compte-nav-btn-lib {
  overflow: hidden;
  text-overflow: ellipsis;
}

#tab-panel-compte .modal-table th {
  position: sticky;
  z-index: 14;
}

/* ---------- Connexion ---------- */

/* Les six pages d'authentification -- connexion, code a deux facteurs,
   inscription du second facteur, mot de passe oublie, reinitialisation,
   invitation -- sont une seule page a six contenus : le meme fond, la meme
   carte, le meme rond d'icone, le meme titre. Elles ne se ressemblaient
   pourtant pas d'une a l'autre, pour deux raisons.

   La carte pendait du haut. `margin: 4rem auto` la posait a 64 px sous
   l'entete quelle que soit sa taille, et les cartes n'ont pas la meme : la
   connexion laissait 359 px de vide en dessous d'elle, l'invitation 525. Meme
   cadre, meme page, et un equilibre different a chaque fois -- un cadre pose
   dans le tiers superieur d'un ecran par ailleurs vide. La carte se pose
   maintenant au milieu de ce qui reste sous l'entete : le corps devient une
   colonne, l'entete y garde sa hauteur, la carte prend le reste et s'y centre.
   Aucune des six pages n'a a connaitre la hauteur de l'entete, qui n'est
   d'ailleurs pas la meme sur un telephone (53 px) et sur un ecran large (63).

   Le rythme de la carte comptait cinq ecarts -- 5,6, 12,8, 16, 17,6 et 24 px
   --, dont deux seulement tombaient sur l'echelle. Il en reste trois, tous
   dessus, et chacun ne dit qu'une chose. --espace-xs tient ensemble ce qui
   forme un bloc : un titre et son sous-titre, un intitule et sa case.
   --espace-md est la coupure ordinaire : le rond au titre, une case au
   libelle suivant, la derniere case au bouton, le formulaire au lien de bas
   de carte. --espace-lg est la seule coupure large, celle qui ouvre le
   formulaire. Le meme ecart dit partout la meme chose, sur les six pages.

   La connexion, elle, n'a pas de sous-titre, et son titre recevait quand meme
   l'ecart serre : « Connexion » se lisait a cinq pixels et demi de « Email »,
   quand sur la page voisine le meme titre se lisait a cinq et demi de son
   sous-titre et a vingt-quatre du formulaire. Le titre prend donc la coupure
   des qu'il n'a pas de sous-titre a tenir -- les marges voisines se rabattent
   l'une sur l'autre, donc elle vaut --espace-lg et non la somme des deux. */

/* Ce bloc posait la hauteur de fenetre et la colonne flex : c'est le corps qui
   les pose pour toutes les pages depuis le 9 septembre 2026, et la connexion
   n'a plus a les redire. Le fond reste, alors qu'il repete celui du corps :
   c'est lui que l'app transcrit dans `VueConnexion`, et le verificateur de
   parite le lit ici -- ecrit ailleurs, plus rien ne compare les deux sols.
   Le reste est propre a la connexion : son en-tete est blanc et non
   translucide, faute d'une page a laisser voir dessous. */
.login-body { background: var(--gray-1); }
.login-body .app-header { background: #fff; }

.login-wrap {
  max-width: var(--largeur-colonne);
  /* La colonne prend ce que l'entete laisse et y centre la carte. `width` avec
     `margin: 0 auto` : des qu'une marge laterale est automatique, l'etirement
     transversal ne joue plus et la colonne se reduirait a son contenu. */
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: 0 auto;
  /* Le blanc vertical n'est plus une position, c'est une garde : une carte plus
     haute que la place disponible pousse la colonne au lieu d'etre rognee, et
     garde cet ecart avec l'entete et le bas de la fenetre. */
  padding: var(--espace-3xl) var(--espace-xl);
}

.login-card {
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  /* Le bas valait 36 px contre 32 en haut, sans que rien ne le demande. */
  padding: var(--espace-2xl);
}

.login-icon-badge {
  width: 44px;
  height: 44px;
  /* Completement rond : 999px, jamais un pourcentage. A 50 %, un rond qui
     cesserait d'etre carre deviendrait une ellipse sans que rien ne le dise. */
  border-radius: 999px;
  background: var(--cyan-pale);
  color: var(--cyan-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--espace-md);
}

.login-icon-badge .icon { width: var(--icon-lg); height: var(--icon-lg); }

.login-card h1 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--fs-h1);
  margin: 0 0 var(--espace-xs);
}

/* Le titre se detache de ce qui ouvre la carte quand il n'a pas de sous-titre
   a tenir. */
.login-card h1 + form,
.login-card h1 + .login-erreur { margin-top: var(--espace-lg); }

.login-sub {
  font-size: var(--fs);
  color: var(--gray-5);
  margin: 0 0 var(--espace-lg);
}

/* Le lien de bas de carte (« Mot de passe oublie ? », « Retour a la
   connexion »). Il etait pose en style en ligne, avec des valeurs qui ne
   concordaient pas d'une page a l'autre. */
.login-lien-bas {
  margin-top: var(--espace-md);
  margin-bottom: 0;
}

.login-card label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 500;
  margin-bottom: var(--espace-xs);
  color: var(--gray-5);
}

/* La voie de l'icone d'un champ. Meme forme que la voie du chevron, plus haut,
   et pour la meme raison : trois termes qui se suivent -- le retrait de
   l'icone, l'icone, l'air entre elle et la premiere lettre -- dont la somme
   est le creux gauche de la case.

   Elle etait ecrite en trois nombres sans rapport apparent, dans trois regles :
   `left: .75rem` sur l'icone -- 12 px, aucun barreau, et personne ne l'avait vu
   parce qu'un recensement d'espacements lit les rembourrages et les marges, pas
   `left` --, puis 2.35rem recopie a l'identique dans `.login-card input` et
   dans `.compte-form input`. 12 + 16 + 9,6 = 37,6 : le compte tombait juste,
   mais rien ne le disait, et changer la taille de l'icone aurait laisse les
   deux autres nombres ou ils etaient.

   Le retrait prend le barreau voisin (--espace, 12,8), donc la voie vaut
   12,8 + 16 + 9,6 = 38,4. Huit dixiemes de pixel de plus, et un calcul qui se
   refait tout seul.

   Les trois termes sont poses sur .input-icon-group et non sur la case :
   l'icone est la soeur de la case, pas sa fille, et le groupe est leur parent
   commun. Les sept gabarits qui s'en servent -- connexion, MFA, inscription au
   MFA, mot de passe oublie, reinitialisation, invitation, compte -- y mettent
   toutes leurs cases visibles ; les deux seules qui restent dehors sont des
   `input type="file"` masques, qui ne peignent rien. */
.input-icon-group {
  --champ-icone-taille: var(--icon);
  --champ-icone-retrait: var(--espace);
  --champ-icone-voie: calc(var(--champ-icone-retrait) + var(--champ-icone-taille) + var(--espace-sm));
  position: relative;
  margin-bottom: var(--espace-md);
}

.input-icon {
  position: absolute;
  left: var(--champ-icone-retrait);
  width: var(--champ-icone-taille);
  height: var(--champ-icone-taille);
  top: 50%;
  transform: translateY(-50%);
  color: var(--gray-4);
  pointer-events: none;
}

.login-card input {
  width: 100%;
  padding: var(--espace-sm) var(--espace) var(--espace-sm) var(--champ-icone-voie);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs-lg);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.login-card input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.login-card button {
  width: 100%;
  /* Le bouton fermait la carte a la meme distance que tout le reste. Les six
     pages d'authentification tiennent leur rythme de deux ecarts : --espace-xs
     entre un intitule et sa case, --espace-md entre deux groupes de saisie. Le
     bouton, dernier enfant du formulaire, n'avait pas de marge propre et
     heritait donc du second : il tombait a seize pixels sous le mot de passe,
     exactement l'ecart qui separe la case de l'email de l'intitule suivant.
     Trois rapports differents -- un intitule et sa case, deux groupes voisins,
     un formulaire et son action -- disaient la meme chose a la meme distance,
     et la carte se lisait comme une pile de rectangles de meme largeur plutot
     que comme une saisie suivie d'un geste.

     La marge posee ici s'ajoute aux --espace-md que le groupe de saisie porte
     deja sous lui : seize et seize, donc --espace-2xl en tout entre la derniere
     case et le bouton. Exactement le double de l'ecart entre deux groupes, ce
     qui est ce qui se lit -- pas la valeur absolue. Un cran de plus (--espace-lg,
     soit trente-six au total) ne tombe sur aucun barreau de l'echelle. */
  margin-top: var(--espace-md);
  padding: var(--espace);
  border: none;
  border-radius: var(--radius-sm);
  /* Cyan, comme toute action principale du produit (.btn-primary) et comme le
     bouton de connexion de l'app, qui prend la teinte d'accent du systeme. Il
     etait noir : la premiere page qu'on voit du produit annoncait donc une
     autre couleur d'action que toutes les suivantes. */
  background: var(--cyan);
  color: #fff;
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background .15s var(--ease), box-shadow .2s var(--ease), transform .2s var(--ease-spring);
}

.login-card button:hover { background: var(--cyan-dark); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.login-card button:active { transform: translateY(0); }

.login-erreur {
  color: var(--red);
  background: var(--red-pale);
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--espace);
  font-size: var(--fs-sm);
  margin-bottom: var(--espace-md);
}

/* ---------- Les cles d'acces ---------- */

/* Le « ou » entre les deux facons d'entrer. Un filet qui traverse la carte, le
   mot pose dessus sur le fond de la carte : deux boutons empiles sans lui se
   liraient comme une action et son repli, quand ce sont deux chemins de meme
   rang -- le mot de passe et la cle ouvrent la meme session. */
.login-separateur {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  margin: var(--espace-lg) 0 var(--espace-md);
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

.login-separateur::before,
.login-separateur::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--gray-3);
}

/* Le bouton de la cle d'acces. Sur le contour, quand celui du mot de passe est
   plein : ils font la meme chose, mais un seul peut etre celui qu'on prend par
   defaut, et deux aplats cyan l'un sous l'autre ne diraient plus lequel. */
.login-card button.login-passkey {
  margin-top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--espace-sm);
  background: #fff;
  color: var(--cyan-dark);
  border: 1px solid var(--gray-3);
  box-shadow: none;
}

.login-card button.login-passkey:hover {
  background: var(--cyan-pale);
  border-color: var(--cyan);
  box-shadow: var(--shadow-sm);
}

.login-card button.login-passkey .icon {
  width: var(--icon);
  height: var(--icon);
}

/* Le refus d'une cle se dit sous le bouton qui l'a demandee, pas en tete de
   carte ou l'erreur du mot de passe s'affiche : c'est l'autre chemin qui a
   echoue. */
.login-passkey-erreur {
  margin-top: var(--espace-sm);
  margin-bottom: 0;
}

/* La page qui propose la cle juste apres une connexion par mot de passe
   (/cles-acces/proposer). Elle emprunte la carte de la connexion : c'est la
   suite immediate du meme geste, et changer d'habillage entre les deux ferait
   croire qu'on a atterri ailleurs.

   Le texte d'explication porte plus de poids ici que sur les autres cartes :
   il est la seule chose qui dise ce qu'une cle d'acces est, a quelqu'un qui
   n'a rien demande. D'ou l'interligne, plus large que le --lh du produit. */
.cle-proposition .login-sub { line-height: 1.55; }

/* « Plus tard ». Un lien, pas un bouton : le refus ne se met pas au meme rang
   que l'acceptation, et un second rectangle pleine largeur sous le premier
   ferait hesiter entre deux actions alors qu'une seule fait quelque chose.
   Pleine largeur quand meme, pour rester cliquable au pouce. */
.btn-plus-tard {
  display: block;
  margin-top: var(--espace-md);
  padding: var(--espace-sm);
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-5);
  border-radius: var(--radius-sm);
  transition: background .15s var(--ease), color .15s var(--ease);
}

.btn-plus-tard:hover {
  background: var(--gray-1);
  color: var(--gray-6);
}

/* Ce que « Plus tard » engage vraiment : la proposition ne revient pas de
   sitot. Ecrit sous le lien, en plus petit, parce que c'est une precision et
   non un argument. Le filet la separe du geste sans en faire un pave. */
.cle-proposition-note {
  margin: var(--espace-md) 0 0;
  padding-top: var(--espace-md);
  border-top: 1px solid var(--gray-2);
  font-size: var(--fs-sm);
}

/* La liste des cles, dans « Mon compte ». Une ligne par cle : son nom tel que
   Supabase le tire du modele d'authentificateur (« iCloud Keychain »,
   « Windows Hello »), la derniere fois qu'elle a servi, et de quoi la retirer.
   La date compte autant que le nom : deux telephones donnent deux lignes du
   meme nom, et c'est l'usage qui dit lequel on retire. */
.passkey-liste {
  list-style: none;
  margin: var(--espace-md) 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
}

.passkey-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

.passkey-nom {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-6);
}

.passkey-date {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  /* Pousse le retrait au bord droit, et lui seul : le nom reste colle a ce
     qu'il nomme. */
  margin-right: auto;
}

.passkey-vide {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  font-style: italic;
}

.passkey-retirer { color: var(--red); }

/* L'echec d'un reglage, dit a cote du bouton qui l'a tente. La classe etait
   posee par le script depuis la liaison Telegram sans qu'aucune regle ne la
   lise : le message d'echec s'affichait dans le gris et l'italique du succes. */
.reglages-hint-inline.erreur { color: var(--red); font-style: normal; }

/* Les quatre groupes du profil se suivaient dans une colonne de 440 px, au
   milieu d'une page qui en fait 1400 : la page ouvrait sur un ruban de
   formulaire a gauche et neuf cents pixels de blanc a droite, quand la page
   voisine des reglages du cabinet, elle, occupe toute la largeur. Les memes
   groupes se rangent maintenant cote a cote tant que la place existe, et se
   remettent d'eux-memes en une seule colonne des qu'elle manque -- le
   formulaire poste exactement les memes champs, sous les memes noms.

   Le panneau gardait par-dessus un plafond a lui, `--largeur-bloc`, soit
   832 px. Il ne se voyait pas tant que la page en faisait 1400 ; le jour ou la
   coquille a pris la fenetre entiere, le profil est reste seul a deux colonnes
   avec mille pixels de blanc a sa droite -- le meme defaut que ci-dessus, d'un
   cran plus loin. Le plafond est parti avec celui de la coquille. C'est la
   grille qui decide desormais du nombre de colonnes, et elle en ajoute une
   chaque fois que la place d'un groupe entier apparait.

   Cette grille est maintenant celle du panneau, et non plus celle du
   formulaire. La page en portait deux, et donc deux cadences : les quatre
   groupes du profil sur une rangee de colonnes de 612 px, puis les cles
   d'acces, le retour sonore, Telegram et le pied de page en quatre barres de
   2 496 px, l'une sous l'autre -- une case a cocher seule sur toute la largeur
   de la fenetre, deux boutons seuls sur la suivante. Le sac s'efface donc, ses
   quatre groupes deviennent des tuiles de la grille du panneau comme les
   quatre autres, et les huit blocs se rangent d'une seule main : cinq de front
   a 2560, quatre a 1920, trois a 1512, deux a 1280, un au telephone.

   C'est le geste deja ecrit pour `#aglae-mandat`, et pour la meme raison : sans
   lui, une grille dans la grille, ou le sac prend une rangee pleine. Un
   element sans boite reste un element du document -- le formulaire poste les
   memes champs, sous les memes noms, vers la meme adresse. */
.compte-form { display: contents; }

/* Huit des neuf intitules de cette page etaient des `<label>` nus. Le neuvieme
   -- « Signature scannee » -- recevait, lui, l'habillage des intitules du
   produit, parce qu'un bloc ecrit plus tard le lui donnait sous son propre nom.
   La page portait donc deux traitements pour un meme role : sept noms de case
   en texte courant noir, colles a deux pixels de leur case parce qu'une boite
   en ligne est sourde a toute marge verticale, et un huitieme en petit gris a
   cinq et demi. On les lisait a dix centimetres l'un de l'autre, sous le meme
   panneau.

   C'est l'habillage du produit qui l'emporte, celui de `.login-card label` et
   du bloc de la signature : petit, gris, en propre ligne, avec l'ecart qui va
   avec. La page y perd meme de la hauteur -- l'intitule descend d'une echelle
   de texte pendant qu'il gagne trois pixels et demi de marge --, ce qui va dans
   le sens de la demande du 25 aout 2026 ecrite juste dessous.

   Les intitules qui portent une explication sont des `<span>` et non des
   `<label>` depuis le 4 septembre 2026, et c'est le point d'interrogation qui
   les y a forces : un `<label>` sans `for` prend pour cible le premier controle
   qu'il contient, et le navigateur reporte alors sur ce controle le survol de
   toute l'etiquette. Le rond etait donc tenu pour survole des qu'on passait sur
   le mot -- exactement ce que la demande voulait supprimer. Ces intitules ne
   designaient aucun champ ; ils ne perdent rien a redevenir du texte, et
   gardent ici leur habillage. */
.compte-form label,
.compte-form .libelle-explique {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 500;
  margin-bottom: var(--espace-xs);
  color: var(--gray-5);
}

/* Sauf l'intitule qui porte une explication : il ne prend que la largeur de
   son texte. C'etait, jusqu'au 4 septembre 2026, pour ne pas trainer un
   pointille en travers de la page ni deplier la phrase en posant la souris
   n'importe ou sur la ligne ; le point d'interrogation a repris cette charge,
   et le bloc etroit reste pour la seconde raison, celle de mise en page qui
   suit. C'est la raison deja ecrite plus bas pour la signature scannee, qui
   etait jusqu'ici le seul de ces intitules a etre habille.

   Il le fait en bloc etroit, et non plus en boite en ligne. Une boite en ligne,
   fut-elle `inline-block`, se pose sur une ligne de texte, et cette ligne-la
   n'est pas reglee par elle mais par le groupe qui l'entoure : 16 px de corps,
   24 d'interligne. Les quatre pixels de blanc que le groupe reserve au-dessus
   de sa ligne s'ajoutaient donc a la marge du bloc precedent, sans que rien ne
   l'ecrive nulle part -- 9,6 devenait 13,6 devant « Ce que je vois »,
   « Couleur » et « Signature scannee », 12,8 devenait 16,8 devant « Photo ».
   Quatre ecarts hors barreau dans un formulaire qui en compte dix.

   `width: fit-content` donne la meme largeur qu'`inline-block` -- celle du
   texte, rien de plus --, sans ligne de texte pour la porter : la marge du bloc
   precedent arrive alors telle qu'elle est ecrite, et l'explication se deplie
   au meme endroit, son ancrage n'ayant pas bouge. */
.compte-form .libelle-explique {
  display: block;
  width: fit-content;
}

/* « Réduis les hauteurs de ligne de mon compte » (demande du 25 août 2026).
   Les cases de cette page étaient réglées comme celles de la page de connexion,
   mêmes marges intérieures, même écart, alors qu'on n'y saisit pas la même
   chose : deux cases qu'on remplit à l'aveugle, en face de huit qu'on relit et
   dont on ne corrige qu'une. Le formulaire tenait sur un écran et demi, et le
   bouton « Enregistrer » sortait du cadre.

   Les cases de la connexion, elles, ne bougent pas : `.login-card input` porte
   les mêmes valeurs sous son propre nom, et c'est voulu, une page où l'on tape
   son mot de passe sans le voir gagne à être large. */
/* Un curseur n'est pas une case à écrire : il n'a ni bordure, ni rembourrage,
   ni largeur de champ, et cette règle-là les lui donnait tous les trois -- le
   réglage de taille de la signature sortait en barre pleine largeur encadrée
   comme un champ de texte. Il est donc exclu par sa famille (`.curseur`)
   plutôt que repris à coups de spécificité dans la règle qui le dessine. */
.compte-form input:not(.curseur) {
  width: 100%;
  padding: var(--espace-xs) var(--espace) var(--espace-xs) var(--champ-icone-voie);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs-lg);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.compte-form input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.compte-form input:disabled {
  background: var(--gray-1);
  color: var(--gray-5);
}

/* Les cinq zones de « Mon compte » sont des tuiles.

   Elles ne l'etaient pas, et le commentaire qui tenait ici disait pourquoi :
   « un cadre par groupe, dans un panneau qui en a deja un, ferait trois boites
   dans une boite ». Pour seule separation, un filet gris surmonte d'un petit
   mot en capitales. La demande du 30 aout 2026 tranche l'inverse, pour cette
   page comme pour l'onglet Mandat : « essaye de faire plus de tuiles possible,
   plus de separation entre les sous-zones [...] pour eviter que ca fasse
   parfois l'effet zone de texte un peu fouillee avec plein de boutons ». Cinq
   zones sans cadre, dont deux portent huit ronds de couleur, une photo, une
   roue chromatique et six boutons, faisaient exactement cet effet.

   La boite dans la boite n'en est pas une : le panneau est le fond de page, la
   tuile est ce qu'il range. C'est deja ce que fait l'ecran Compte de l'app,
   avec les memes noms de zones -- les `Section` « Identite », « Exercice
   professionnel », « Ma pastille » et « Les intervenants » de
   `VueCompte.swift`.

   Le cadre, l'arrondi, le fond et le creux viennent de `.tuile` : ce qui reste
   ici est ce qui en differe. `min-width: 0` parce qu'un `fieldset` ne sait pas
   retrecir sous la largeur minimale de son contenu et emporterait la grille
   avec lui ; la marge est celle de la grille et non la sienne. */
.compte-groupe {
  margin: 0;
  min-width: 0;
}

/* Dans la grille, la cadence est l'ecart de la grille et non la marge :
   `.tuile + .tuile` vise le voisin dans le document et non dans la page, et
   posait donc seize pixels de plus en tete de la deuxieme colonne, qui
   descendait d'autant sous la premiere. */
.compte-form > .tuile + .tuile { margin-top: 0; }

/* Les cles d'acces vivent hors du formulaire -- c'est un reglage de compte, la
   raison est dans le gabarit : leur voisin de dessus est un `<form>`, et aucune
   des regles de cadence de `.tuile` ne le voit. Il fallait donc le dire ici, et
   il faut maintenant le dedire : dans la grille, la cadence est l'ecart de la
   grille, et cette marge s'y ajoutait -- la premiere tuile de la deuxieme
   rangee descendait de seize pixels sous ses voisines. */
.compte-form + .tuile { margin-top: 0; }

/* L'écart entre deux cases, ici seulement : `.input-icon-group` sert aussi aux
   pages de connexion, d'invitation et de mot de passe oublié, qui n'ont que
   deux cases et rien à resserrer.

   C'est le premier des deux barreaux dont ce formulaire est fait, et il n'en
   veut pas d'autres : `--espace-sm` entre deux blocs, `--espace-xs` entre un
   intitule et sa case. Il en portait cinq -- 6,4, 9,6, 12,8, 13,6 et 16 --, et
   la moitie de ses ecarts tombait a cote. Deux causes, corrigees ensemble : les
   intitules a explication ajoutaient quatre pixels par la ligne de texte qui
   les portait (raison ecrite au-dessus), et quatre blocs ecrivaient leur marge
   basse un barreau trop haut -- la signature scannee a `--espace-md`, la file
   de propositions, la ligne de la photo et celle de la couleur a `--espace`.
   Les quatre prennent `--espace-sm` ci-dessous.

   « L'ecart entre deux cases » est a prendre au mot depuis le 30 aout 2026 :
   il s'ecrivait comme une marge basse, donc pose aussi sous la derniere case,
   la ou il n'y a plus de case en face. Il s'ajoutait au creux de la tuile, qui
   mesurait 25,6 px en bas pour 16 en haut. La regle de tuile qui rend cette
   marge au creux ne pouvait rien ici -- meme specificite, et ecrite plus haut
   dans la feuille --, alors l'ecart se corrige a sa source. */
.compte-form .input-icon-group:not(:last-child) { margin-bottom: var(--espace-sm); }

/* Le groupe « Retour sonore » est arrive apres le resserrage decrit au-dessus,
   et n'en a donc rien recu : il portait les deux seuls ecarts de la page qui
   ne soient d'aucun des deux barreaux.

   Seize pixels au-dessus de la case. Le filet donne son --espace-sm, et
   `.reglages-checkbox` ajoutait par-dessus le --espace-xs qui la colle au champ
   qu'elle qualifie -- sauf qu'ici elle ne qualifie rien, elle est le premier
   controle du groupe.

   Zero au-dessus de « Tester le son ». Une `.reglages-row` n'a pas de marge
   verticale : les deux autres de cette page tiennent la leur de l'enveloppe qui
   les porte, `.compte-signature` et `.compte-photo`. Celle-ci n'en a pas, et le
   bouton touchait donc la case.

   Chacun des deux selecteurs ne vise qu'un seul element : aucune autre rangee
   de la page n'est fille directe d'un `.compte-groupe`. */
.compte-groupe > .reglages-checkbox { margin-top: 0; }
.compte-groupe > .reglages-row { margin-top: var(--espace-sm); }

/* LA LIAISON TELEGRAM, EN UNE LIGNE D'ETAT ET NON EN DEUX PHRASES.

   « Ameliore le design pour plus moderne, moins de texte » (suivi du
   9 septembre 2026). La tuile disait tout en prose : « Relie a la conversation
   n° 1568010401, depuis le 2026-07-28 (depuis 6 semaines). Envoi direct a
   l'agent avec "!" : ouvert. » Quatre informations enfilees dans deux phrases,
   qu'il faut lire en entier pour trouver celle qu'on est venu chercher.

   Elles se rangent maintenant comme un etat se range partout ailleurs dans le
   produit : un point de couleur, la chose nommee, une etiquette pour ce qui est
   ouvert ou ferme, et le second rang pour la date. Rien n'est perdu -- la
   demande d'origine voulait le compte, la date et l'anciennete, les trois sont
   la -- mais on les trouve sans les lire.

   Le point est de --icon-xs mis en rond : c'est le plus petit barreau de
   l'echelle des icones, et un voyant d'etat n'est rien d'autre qu'une icone
   qui ne dessine rien. */
.compte-telegram-etat {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin: 0;
}

.compte-telegram-point {
  flex: none;
  width: var(--icon-xs);
  height: var(--icon-xs);
  border-radius: 999px;
  background: var(--green);
}

/* Gris et non rouge : aucun compte relie n'est pas une panne, c'est un reglage
   qu'on n'a pas encore pose. Le rouge de la feuille dit qu'une chose a echoue. */
.compte-telegram-point.absent { background: var(--gray-3); }

.compte-telegram-cible {
  font-weight: 600;
  color: var(--black);
}

/* L'etiquette de l'envoi direct. Les deux teintes de la feuille pour un etat
   acquis et un etat en attente, celles-la memes que portent les pastilles de
   statut : le vert dit que c'est ouvert, l'orange qu'il reste un geste. */
.compte-telegram-marque {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-sm);
  font-size: var(--fs-2xs);
  font-weight: 600;
}

.compte-telegram-marque.ouvert {
  background: var(--green-pale);
  color: var(--green-dark);
}

.compte-telegram-marque.attente {
  background: var(--orange-pale);
  color: var(--orange-dark);
}

/* Le second rang : la date de la liaison, qui se consulte et ne se surveille
   pas. Meme encre et meme taille que les autres indications de la page. */
.compte-telegram-detail {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Les deux gestes sur une rangee : chacun garde son compte rendu a cote de
   lui, et `wrap` les laisse se replier quand un code de liaison s'affiche. */
.compte-telegram-gestes { flex-wrap: wrap; }

/* Le nom de la tuile est ici une `legend`, et une `legend` est le seul element
   du web que son parent dessine autour d'elle : le navigateur ouvre la bordure
   haute du `fieldset` sur toute la largeur qu'elle occupe. Comme celle-ci fait
   100 %, la tuile n'aurait eu que trois cotes -- constate au navigateur avant
   d'ecrire ces trois lignes, pas devine.

   Une `legend` qui flotte n'est plus la legende rendue de son `fieldset`, et la
   bordure se referme. Un flottant ne pousse ensuite que les lignes de texte et
   non les blocs : ce qui le suit doit se degager lui-meme, d'ou le `clear`. Le
   reste de l'habillage -- taille, graisse, encre, ecart sous le titre -- vient
   de `.tuile-titre`, que la balise porte en classe comme les quinze titres de
   l'onglet Mandat. */
.compte-groupe > legend {
  float: left;
  width: 100%;
  padding: 0;
}
.compte-groupe > legend + * { clear: both; }

/* La roue chromatique et le voyant d'enregistrement partagent la derniere
   ligne du formulaire.

   Le bouton « Enregistrer » l'occupait avec elle depuis le 25 aout 2026. Il a
   quitte la page le 27, quand les cases ecrites se sont mises a partir seules,
   et le voyant a pris sa place. Huit regles ont continue de l'habiller : deux
   ici, deux dans le formulaire, trois sur telephone, et la marge basse que la
   roue portait pour se detacher de lui -- laquelle n'existait plus que pour
   etre annulee par ses deux seuls emplacements. Chacune avait son commentaire,
   et la feuille decrivait ainsi une derniere ligne, une largeur de bouton et
   une cible tactile que plus personne n'avait sous les yeux. Elles sont
   parties avec lui (28 aout 2026).

   Le voyant ferme la rangee, apres la roue. Contrairement a la ligne d'un
   cabinet, rien ne le precede qui puisse glisser quand il parle : il n'a donc
   pas de colonne a tenir, et se tait en ne prenant rien. */
.compte-couleur-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-sm);
}

.compte-avatar-preview {
  display: flex;
  /* Les deux propositions se replient l'une sous l'autre plutot que de sortir
     du panneau : leur largeur depend du nombre de collegues du cabinet, qui
     n'est pas une constante de la feuille. */
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--espace-xl);
  margin-bottom: var(--espace-sm);
}

.compte-avatar-preview .dossier-avatar {
  --avatar-d: 56px;
}

/* Les deux propositions du rond de profil : les initiales, ou la photo
   (demande du 24 août 2026). Deux boutons plutôt qu'une case à cocher : c'est
   un choix d'apparence, il se prend à l'œil, en regardant les deux.

   Celui qui est retenu porte l'anneau cyan de la mise au point du site ; celui
   qui ne l'est pas s'efface d'un cran, sans disparaître : il faut le voir pour
   pouvoir le choisir. */
.compte-avatar-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-xs);
  border: none;
  background: none;
  border-radius: var(--radius);
  cursor: pointer;
  opacity: .45;
  transition: opacity .15s var(--ease), box-shadow .15s var(--ease);
}

.compte-avatar-option:hover { opacity: .8; }

.compte-avatar-option.selected {
  opacity: 1;
  box-shadow: 0 0 0 2px var(--cyan);
}

.compte-avatar-option[hidden] { display: none; }

.compte-avatar-option-nom {
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--gray-5);
}

.compte-photo-ligne { margin-bottom: var(--espace-sm); }

/* IDENTITE ET PASTILLE DANS UNE SEULE TUILE (ticket du 18 septembre 2026 :
   « fusionne les sections "Identite" et "Ma pastille" [...] fais un affichage
   classique, compact et sobre »).

   La forme d'une fiche de compte ordinaire : l'image a gauche, les cases a
   droite. Aucun point de rupture ecrit -- c'est le `flex-wrap` qui replie la
   colonne des cases sous l'image quand la tuile devient etroite, a la largeur
   du contenu et non a celle d'un ecran suppose. La colonne de gauche ne
   s'etire pas (`flex: none`), celle de droite prend ce qui reste et peut
   retrecir (`min-width: 0`), sans quoi un champ large pousserait l'image
   dehors. */
.compte-identite-corps {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--espace-md) var(--espace-lg);
}

.compte-identite-image {
  flex: none;
  /* La largeur des deux ronds cote a cote, leurs noms compris : en deca, la
     rangee se replie et la tuile grandit pour rien. */
  min-width: 11rem;
}

.compte-identite-champs {
  flex: 1;
  min-width: 12rem;
}

/* Le premier libelle de chaque colonne touche le haut de la tuile : la marge
   qu'un libelle pose au-dessus de lui n'a plus de champ a separer. */
.compte-identite-champs > label:first-child { margin-top: 0; }

/* Les trois propositions d'affichage des intervenants : la meme rangee de
   boutons que le choix de pastille, mais chacun porte une file de ronds de
   collegues plutot qu'un rond unique. Ils se chevauchent legerement, comme les
   pastilles d'une ligne de mandat -- c'est la meme file, montree telle qu'elle
   sera (demande du 25 aout 2026). La troisieme, les noms, est venue le
   9 septembre 2026. */
.compte-intervenants-file {
  display: flex;
  align-items: center;
  padding-left: var(--espace-xs);
}

.compte-intervenants-file .dossier-avatar { margin-left: -.45rem; }

/* Les capsules nommees ne se chevauchent pas : le recouvrement cache deux
   lettres sur un rond, il cacherait la moitie d'un nom. Elles se suivent donc,
   separees comme deux mots. */
.compte-intervenants-file-noms .dossier-avatar {
  margin-left: 0;
  margin-right: var(--espace-2xs);
}

/* Le choix d'une couleur, partout le même : la roue du système, et rien
   d'autre.

   Les seize pastilles prédéfinies vivaient au-dessus, ici et sur la ligne
   d'un cabinet : « supprime les pastilles prédéfinies et conserve uniquement
   la roue chromatique » (demande du 24 août 2026). Elles étaient un
   raccourci vers un spectre que le serveur accepte en entier, et le cabinet
   n'avait qu'elles : sa couleur ne pouvait pas sortir de la rampe quand celle
   d'un profil le pouvait.

   Les trois écritures HEX, RVB et HSL les ont suivies le lendemain :
   « supprime entièrement le pavé contenant HEX, RVB et HSL ». Trois cases de
   texte posées à côté d'une roue qui dit déjà la même chose, et qui ne
   tenaient pas dans la ligne d'un cabinet : c'est pour les loger que cette
   ligne était passée à deux hauteurs. Ce qu'elles servaient, recopier
   exactement la teinte d'une charte, la fenêtre du système le fait, son
   hexadécimal compris ; c'est aussi ce que l'app a toujours eu, un
   `ColorPicker` seul. */
/* `flex` et non `inline-flex` : sous « Mon compte », le bloc suit un intitulé
   écrit, et une boîte en ligne serait venue se poser au bout de la phrase.

   La roue portait ici une marge basse de 11,2 px, pour se détacher du bouton
   « Enregistrer » qui la suivait. Elle n'a que deux emplacements dans le
   produit -- cette page et la ligne d'un cabinet --, et tous deux annulaient
   cette marge en toutes lettres : elle n'existait plus que pour être défaite
   deux fois. Les trois règles sont parties ensemble (28 août 2026). */
.choix-couleur {
  display: flex;
  align-items: center;
}

/* Le sélecteur natif : sans son cadre gris ni ses marges intérieures, qui le
   feraient passer pour un champ de saisie alors qu'il ouvre une fenêtre.

   Le sélecteur nomme son parent, et pas seulement la classe : « Mon compte »
   étire toutes les cases de son formulaire sur la colonne (`.compte-form
   input`), et la roue y devenait une longue barre de couleur. C'est ce qui la
   tenait quand elle portait un identifiant. */
.choix-couleur input.choix-couleur-roue {
  width: 42px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: none;
  cursor: pointer;
  flex: none;
}

/* La signature scannee, sous le formulaire de « Mon compte ».
   Le cadre est celui du logo d'un client, aux proportions d'un trait
   manuscrit : plus large que haut, et prenant toute la colonne, parce qu'une
   signature s'etale la ou un logo tient dans un timbre. La rangee se replie --
   le panneau ne fait que 440 px, ou le cadre, le bouton et le retrait ne
   tiennent pas de front. */
.compte-signature { margin-top: var(--espace-sm); }

.compte-signature label,
.compte-signature .libelle-explique {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 500;
  margin-bottom: var(--espace-xs);
  color: var(--gray-5);
}

/* L'intitule porte l'explication (voir `.libelle-explique`) : il ne prend donc
   que la largeur de son texte. Bloc etroit
   plutot que boite en ligne, pour la raison ecrite plus haut sur
   `.compte-form .libelle-explique` : une boite en ligne emporte avec elle
   le blanc de la ligne qui la porte. */
.compte-signature .libelle-explique {
  display: block;
  width: fit-content;
}

.compte-signature .reglages-row { flex-wrap: wrap; }

.signature-cadre {
  width: 100%;
  height: 88px;
}

/* A quelle taille la signature sort sur les rapports (ticket du 17 septembre
   2026). Le réglage est un curseur, et l'aperçu qui le suit est une règle : le
   cadre représente les sept centimètres du bloc de signature d'un rapport, la
   signature y occupe la part qu'elle occupera sur la page. C'est la seule
   façon de choisir une largeur sans imprimer pour voir -- un cadre à taille
   libre, comme celui du dépôt juste au-dessus, ne dit rien de la mesure.

   La graduation du milieu se pose en fond plutôt qu'en élément : c'est un
   repère, pas un contenu, et rien ne doit pouvoir passer devant la
   signature. */
.signature-taille { margin-top: var(--espace-md); }

.signature-taille-reglage { align-items: center; }

.signature-largeur-curseur { width: 12rem; flex: none; }

.signature-largeur-valeur {
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
}

.signature-regle {
  display: flex;
  align-items: center;
  min-height: 72px;
  margin-top: var(--espace-xs);
  padding: var(--espace-xs) var(--espace-xs) var(--espace-md);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  /* Une graduation par centimètre, posée au pied du cadre : en fond et non en
     élément, pour que rien ne puisse passer devant la signature, et sous le
     rembourrage pour que la signature ne passe pas devant elle. Un trait au
     milieu aurait disparu dès que l'image l'atteint -- un scan est opaque,
     c'est du papier blanc.

     Le nombre de crans est posé par le gabarit (`--regle-crans`), qui le tient
     du serveur : c'est la borne du curseur en centimètres, passée de 7 à 9 le
     17 septembre 2026. Une valeur écrite ici serait le troisième endroit à
     dire la même mesure, donc le premier à ne plus la dire. */
  background:
    repeating-linear-gradient(to right, var(--gray-3) 0 1px,
                              transparent 1px calc(100% / var(--regle-crans, 7)))
      left bottom / 100% 7px no-repeat,
    linear-gradient(var(--gray-2), var(--gray-2)) left bottom / 100% 1px no-repeat,
    #fff;
}

/* La largeur est posée par le curseur (compte.js), en pourcentage des sept
   centimètres du cadre : c'est elle qui porte la mesure, la hauteur suit.

   ET RIEN NE LA BORNE. Une hauteur maximale semblait prudente, elle rendait
   l'aperçu faux : passé sa limite, `contain` recalait l'image DANS le cadre et
   la signature cessait de grandir avec le curseur -- à 7 cm elle s'affichait
   comme à 4. Un aperçu à l'échelle qui plafonne n'est plus à l'échelle ; c'est
   au cadre de s'allonger, pas à la mesure de mentir. */
.signature-regle-image {
  width: 50%;
  height: auto;
}

.signature-regle-image[hidden] { display: none; }

.signature-regle-vide {
  font-size: var(--fs-xs);
  color: var(--gray-4);
}

.cabinet-gestion-list {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-md);
}

/* Un cabinet tient en deux etages dans le meme cadre : la ligne qui le designe
   (pastille, nom, initiales, couleur) et, repliee sous elle, l'identite qui
   l'ecrit en tete d'un rapport. Le cadre est donc porte par le bloc et non
   plus par la ligne, sinon le depliage sortirait de la bordure.

   « Réduis la hauteur des lignes de gestion de cabinet et gestion de l'équipe »
   (demande du 25 août 2026) : le rembourrage du cadre, l'écart entre les deux
   étages et celui des cases se resserrent d'un cran. Ces deux listes se
   relisent d'un coup d'œil (on y cherche un cabinet parmi cinq, pas on n'y
   rédige), et elles étaient réglées comme des formulaires.

   Un cran de plus le lendemain (« réduis encore la hauteur des lignes de
   gestion du cabinet et de gestion de l'équipe ») : le cadre, l'écart entre les
   étages et les cases se resserrent une seconde fois, et la roue chromatique
   descend à la hauteur des cases qui l'entourent, c'était elle le plancher de
   la ligne, un rectangle de 34 px au milieu de champs qui n'en font plus que
   26. */
/* Le cadre est celui de `.tuile-encart`, commun aux trois zones de la page.
   Ne reste ici que le creux, qui lui est propre : deux crans plus serre que
   celui d'une carte de collaborateur, et c'est voulu -- on parcourt cette
   liste, on n'y redige pas. */
.cabinet-gestion-bloc {
  padding: var(--espace-xs) var(--espace-sm);
}

.cabinet-gestion-form {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-2xs) var(--espace-sm);
}

/* Les deux lignes d'ajout de la page -- un cabinet, un collaborateur -- se
   marquent du meme trait : l'encart en pointille. Elles ne contiennent rien
   encore, et un cadre plein annoncerait une entree qui existe. */
.cabinet-gestion-ajout,
.equipe-gestion-ajout {
  border-style: dashed;
}

/* La colonne du voyant d'enregistrement.

   Le bouton « Enregistrer » a quitte cette rangee le 27 aout 2026 et le voyant
   a pris sa place -- mais un voyant qui n'a rien a dire est `hidden`, donc
   absent de la rangee, et la place n'etait plus tenue par personne. Le nom
   commercial est le seul element elastique de la ligne : c'est lui qui avale
   la colonne libre, et tout ce qui le suit glisse.

   Mesure au navigateur le 28 aout 2026, sur une seule saisie : « Enregistrement… »
   parait (103 px) et les initiales, la roue et la poubelle sautent de 111 px
   vers la gauche ; deux secondes plus tard « Enregistre » (61 px) les ramene de
   41 px ; l'effacement du voyant les remet 70 px plus loin. Trois sauts pour
   avoir tape une lettre.

   Le meme trou expliquait la rangee du nouveau cabinet, qui se lisait 103 px a
   gauche des trois du dessus : elle, elle est batie comme si le voyant etait
   toujours affiche. Le cale-place pose ici le 26 aout 2026 ne rendait que la
   poubelle -- 36 des 139 px manquants --, parce qu'a l'epoque les deux rangees
   portaient encore un bouton de meme largeur.

   La colonne est donc tenue en permanence, muette ou non, et le bouton de la
   rangee du nouveau cabinet prend exactement les deux cases qu'il remplace :
   le voyant, l'ecart, la poubelle. Les quatre rangees tombent alors sur les
   memes verticales, et plus rien ne bouge a la frappe. */
.cabinet-gestion-bloc { --cabinet-voyant: 7rem; }

/* La queue de la rangee -- le voyant puis la corbeille, le bouton « Ajouter »
   pour la derniere -- se cale au bord droit de la tuile, par la meme marge
   automatique que le groupe de droite de l'en-tete. Sans elle, la rangee se
   terminait a 1265 px dans une tuile qui en fait 1900 depuis que la page prend
   la fenetre : quatre cases serrees a gauche et six cents pixels de blanc a
   l'interieur du cadre, ce qui se voit bien plus qu'au dehors. Les quatre
   rangees tombent toujours sur les memes verticales -- le bouton d'ajout
   occupe exactement les deux cases qu'il remplace, et il recoit donc la meme
   marge. */
.cabinet-gestion-form .champ-etat {
  flex: none;
  min-width: var(--cabinet-voyant);
  margin-left: auto;
  text-align: right;
}

/* Tenir une colonne, c'est l'occuper meme sans rien dire : le voyant muet garde
   sa case et n'efface que son trace. Meme recette que la croix du signataire et
   la fleche de presence en ligne, et meme `!important` -- le filet en tete de
   feuille en porte un, sans quoi la regle serait morte. */
.cabinet-gestion-form .champ-etat[hidden] {
  display: block !important;
  visibility: hidden;
}

.cabinet-gestion-ajout .btn-primary {
  flex: none;
  margin-left: auto;
  width: calc(var(--cabinet-voyant) + var(--espace-sm) + var(--h-case));
}

.cabinet-gestion-apercu {
  flex: none;
  min-width: 32px;
}

/* Le plafond n'est pas un gout, c'est la mesure du champ : le nom commercial
   accepte cent caracteres (`maxlength`), et cent caracteres de --fs tiennent
   dans un bloc. Sans lui, ce champ etait le seul enfant elastique de la rangee
   et prenait tout ce que la fenetre offrait -- 1500 px de case a texte sur un
   ecran de 1920, 3000 sur un 3440, pour un nom de douze lettres. */
.cabinet-gestion-nom {
  flex: 1 1 180px;
  min-width: 140px;
  max-width: var(--largeur-bloc);
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs);
}

.cabinet-gestion-initiales {
  flex: none;
  width: 60px;
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs);
  text-align: center;
  text-transform: uppercase;
}

/* L'identite du cabinet : les mentions d'un papier a en-tete. Repliee, parce
   qu'on la renseigne une fois pour toutes et qu'on relit la ligne du dessus
   tous les jours -- douze champs deplies par cabinet auraient fait de cette
   page une pile de formulaires.

   Le filet respire pareil des deux cotes : il avait 5,6 px au-dessus et 4,8 en
   dessous, deux valeurs ecrites a la main que rien ne distinguait. */
.cabinet-identite {
  margin-top: var(--espace-2xs);
  border-top: 1px solid var(--gray-2);
  padding-top: var(--espace-2xs);
}

/* Les `<summary>` du produit qui partagent ce dessin : l'identite d'un
   etablissement et le compte rendu d'une ronde, tous deux dans /cabinet, et
   depuis le 20 septembre 2026 le detail d'un exercice de primes, dans /compte.
   Ils portaient le triangle que le navigateur dessine
   tout seul : plein, cale sur la ligne de base, et d'un dessin qui change
   entre macOS, Windows et Firefox. Partout ailleurs un repli se montre du
   meme chevron -- la ligne d'un repertoire du Juridique
   (`.row-toggle .arrow`), le bandeau d'un programme de travail
   (`.programme-chevron`), le bout d'une ligne de mandat (`.dossier-chevron`).
   Trois endroits, un seul dessin, une rotation de 90 degres a l'ouverture.
   Celui de l'identite etait le quatrieme et ne suivait pas ; celui du compte
   rendu, arrive le 30 aout 2026 avec le detail des rondes, etait le cinquieme
   et ne suivait pas non plus. Ce commentaire annoncait « le seul `<summary>`
   du produit » et disait vrai le jour ou il a ete ecrit : c'est la forme
   d'affirmation qui vieillit le plus vite dans une feuille de style.

   Le marqueur se retire des trois facons qu'il faut pour qu'il parte partout :
   `display: flex` suffit a Chromium, `list-style` est ce que lit Firefox, et
   Safari n'ecoute que son pseudo-element.

   Le chevron et son libelle sont un seul mot, d'ou `--espace-xs` entre eux et
   le survol qui les prend ensemble : le chevron garde le gris des deux autres
   -- c'est tout l'objet de la reprise -- mais suit le titre quand il passe au
   cyan, sans quoi la moitie du mot s'allumerait. */
.cabinet-identite-titre,
.compte-primes-detail > summary,
.controle-etats-detail > summary,
.ronde-detail > summary {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  list-style: none;
  font-size: var(--fs-sm);
  color: var(--gray-5);
  cursor: pointer;
  user-select: none;
}

.cabinet-identite-titre::-webkit-details-marker,
.compte-primes-detail > summary::-webkit-details-marker,
.controle-etats-detail > summary::-webkit-details-marker,
.ronde-detail > summary::-webkit-details-marker { display: none; }

.cabinet-identite-titre > .icon,
.compte-primes-detail > summary > .icon,
.controle-etats-detail > summary > .icon,
.ronde-detail > summary > .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
  transition: transform .15s var(--ease), color .15s var(--ease);
}

.cabinet-identite[open] > .cabinet-identite-titre > .icon,
.compte-primes-detail[open] > summary > .icon,
.controle-etats-detail[open] > summary > .icon,
.ronde-detail[open] > summary > .icon { transform: rotate(90deg); }

.cabinet-identite-titre:hover,
.compte-primes-detail > summary:hover,
.controle-etats-detail > summary:hover,
.ronde-detail > summary:hover { color: var(--cyan-dark); }
.cabinet-identite-titre:hover > .icon,
.compte-primes-detail > summary:hover > .icon,
.controle-etats-detail > summary:hover > .icon,
.ronde-detail > summary:hover > .icon { color: inherit; }

/* Flex-wrap et non une grille de colonnes egales : treize cases dont six ne
   portent qu'un identifiant de longueur connue -- un code APE fait cinq
   caracteres, un code postal cinq, un SIREN neuf -- et sept un texte libre.
   Toutes taillees pareil, un « 6920Z » s'affichait dans la case d'une raison
   sociale (demande du 22 aout 2026). Chaque case demande maintenant la largeur
   dont elle a besoin ; c'est la meme regle qu'au volet CNCC (.aglae-grille). */
.cabinet-identite-grille {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin-top: var(--espace);
  align-items: flex-start;
}

.cabinet-identite-champ {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  font-size: var(--fs-sm);
  color: var(--gray-5);
  /* La largeur d'avant, celle d'un texte libre : la case prend ce qui reste
     sur sa ligne sans descendre sous 190 pixels. */
  flex: 1 1 190px;
  min-width: 0;
}

/* L'adresse tient la ligne entiere : une voie ne se lit pas dans la meme
   largeur qu'un code postal. Apres la regle ci-dessus et non avant : les deux
   posent `flex` sur le meme element, a specificite egale, et c'est la derniere
   ecrite qui l'emporte -- placee avant, elle etait annulee et l'adresse
   partageait sa ligne (constate au navigateur le 22 aout 2026). */
.cabinet-identite-large { flex: 1 1 100%; }

/* Les six cases taillees sur ce qu'elles portent. `max-content` mesure le plus
   large des deux -- l'intitule, ou les `size` caracteres poses par le gabarit
   --, exactement comme au volet CNCC : « N° TVA intracommunautaire » est plus
   large que le numero qu'il annonce, et c'est alors lui qui decide. Plafonnee
   comme la-bas, pour qu'un intitule a rallonge ne rende pas la rangee
   bancale. */
.cabinet-identite-champ[data-largeur="libelle"] {
  flex: 0 0 auto;
  width: max-content;
  max-width: 22rem;
}

.cabinet-identite-champ input {
  width: 100%;
  min-width: 0;
  padding: var(--espace-sm) var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs);
  color: var(--black);
  min-width: 0;
}

.cabinet-gestion-nom:focus,
.cabinet-gestion-initiales:focus,
.cabinet-identite-champ input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Le logo et le tampon d'un cabinet, sous ses coordonnees.
   Deux blocs cote a cote tant que la colonne le permet, empiles ensuite : ce
   sont deux gestes de meme nature, et les eloigner l'un de l'autre les aurait
   fait passer pour deux reglages sans rapport. Le cadre est celui du logo d'un
   client, aux memes proportions -- un logo de cabinet arrive en bandeau comme
   celui d'un client, et un tampon tient dedans sans le deformer.

   `min(300px, 100%)` plutot que `300px` : les trois cents pixels sont le seuil
   a partir duquel deux colonnes valent mieux qu'une, pas une largeur due. Ecrits
   nus, ils sont aussi un plancher -- une piste de grille ne descend jamais sous
   son minimum -- et sous trois cents pixels de colonne la piste restait large de
   trois cents pendant que la boite, elle, se resserrait : le cadre du logo et sa
   rangee de boutons sortaient de vingt et un pixels a droite, hors de tout ce qui
   defile. Le `min()` rend le seuil a son role : il ne vaut que tant qu'il tient. */
.cabinet-images {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: var(--espace-md);
  margin-top: var(--espace-md);
  padding-top: var(--espace);
  border-top: 1px solid var(--gray-2);
}

/* `width: max-content` : l'intitule porte l'explication des formats acceptes
   (`.libelle-explique`), et le rond d'interrogation se pose au bout de son
   texte. Une boite large de toute la colonne laisserait la marge du bloc
   suivant se calculer sur une ligne qu'on ne voit pas. */
.cabinet-image-libelle {
  display: block;
  width: max-content;
  max-width: 100%;
  font-size: var(--fs-sm);
  font-weight: 500;
  margin-bottom: var(--espace-xs);
  color: var(--gray-5);
}

/* Le cadre recoit aussi un fichier glisse depuis le bureau, et se clique pour
   ouvrir le selecteur : devant un cadre vide dont le bouton dit « Déposer »,
   c'est le geste qu'on tente avant de chercher le bouton. Il s'allume comme la
   grande zone de depot d'un mandat -- meme cyan, meme fond pale -- pour dire
   qu'il attend le fichier ; le fond blanc revient ensuite, un logo se lisant
   sur du blanc. */
/* La rangee se replie : le cadre, le bouton et le retrait ne tiennent pas de
   front dans une colonne de trois cents pixels. */
.cabinet-image-ligne {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-sm);
}

/* La ligne d'un cabinet tient sur une seule hauteur : la pastille, le nom, les
   initiales, la roue, « Enregistrer » et la corbeille, dans cet ordre
   (demande du 25 août 2026, « place sur une seule ligne : AF, Audit France, la
   roue chromatique, le bouton Enregistrer et l'icône de poubelle »).

   Elle en avait pris deux la veille, puis trois : le choix de couleur portait
   trois cases de texte (HEX, RVB, HSL) qui ne tenaient pas à côté du nom, il
   passait donc sous lui sur toute la largeur en emmenant les deux boutons. Ces
   trois cases retirées, la roue seule se glisse entre les initiales et
   « Enregistrer », et le sous-étage n'a plus lieu d'être : c'est lui qui est
   parti, pas les boutons qui sont remontés. */
.cabinet-gestion-couleur {
  flex: none;
}

/* La roue était le plancher de la ligne : 34 px de haut au milieu de cases qui
   en font moins. Elle descend à leur hauteur : ici seulement, « Mon compte » la
   garde telle quelle, c'est là qu'on choisit sa couleur pour de bon. */
/* La hauteur d'une case de ces rangees. Elle n'etait ecrite nulle part et
   pourtant tout s'en reclamait : les deux champs la tiraient de leur
   rembourrage, la roue chromatique la recopiait en dur -- « height: 26px » --,
   et les deux boutons du bout ne la connaissaient pas du tout. Eux prenaient
   --h-sm, le barreau des boutons-icones du panneau Mandat, ou les cases
   voisines font 32 et ou 28 est donc un cran en dessous.

   Ici les cases n'en font que 26 : « Réduis la hauteur des lignes de gestion de
   cabinet et gestion de l'équipe », puis « réduis encore » le lendemain. Le
   carre de 28 depassait donc d'un pixel en haut et d'un pixel en bas, quatre
   rangees de suite, et le « + » de la derniere autant. Tant que l'icone etait
   nue cela ne se voyait pas ; le cadre pose le 26 aout le rend lisible, et
   c'est exactement ce qu'un cadre est cense faire.

   Nommee ici, la hauteur se dit une fois et tout la suit : les cases, la roue,
   la corbeille, le bouton d'ajout, et la largeur que ce dernier doit couvrir
   pour tomber sur la meme verticale que les corbeilles du dessus. */
.cabinet-gestion-bloc { --h-case: 26px; }

.cabinet-gestion-nom,
.cabinet-gestion-initiales,
.cabinet-gestion-couleur input.choix-couleur-roue { height: var(--h-case); }

/* --h-sm n'est pas seulement une hauteur posee sur ces boutons, c'est aussi un
   plancher : `.btn-link` porte `min-height` et `.btn-link.btn-icon-only`
   `min-width`. Une hauteur plus courte ecrite seule ne fait donc rien du tout
   -- le carre restait a 28 en annoncant 26. Les deux planchers descendent
   avec elle. */
.cabinet-gestion-form > .btn-link.btn-icon-only {
  width: var(--h-case);
  min-width: var(--h-case);
  height: var(--h-case);
  min-height: var(--h-case);
}

.cabinet-gestion-form > .btn-primary {
  height: var(--h-case);
  min-height: var(--h-case);
}

/* Une ligne d'équipe ne porte qu'un rond, un nom, un courriel et un rôle :
   elle se lit d'un coup d'œil, et son rembourrage vertical se resserre avec
   celui des cabinets (« réduis la hauteur des lignes de gestion de cabinet et
   gestion de l'équipe »). Le rembourrage horizontal, lui, ne bouge pas : c'est
   lui qui tient le rond à distance de la bordure. Le plancher de la ligne est
   désormais la liste déroulante des rôles, qui garde la hauteur qu'ont tous
   les contrôles du site, et c'est elle qui borne le second resserrement du
   lendemain (« réduis encore la hauteur des lignes »), le rembourrage vertical
   ne pouvant que s'approcher d'elle sans la faire descendre : un contrôle qui
   n'aurait pas la hauteur des autres se verrait d'un écran à l'autre. */
/* Une grille et non plus une rangee souple, parce que six lignes qui se suivent
   doivent tomber sur les memes colonnes. Elles n'y tombaient pas : la ligne
   « (vous) » ne porte pas de liste de roles -- elle affiche son role en toutes
   lettres -- ni de bouton de retrait, et ses quatre elements se repartissaient
   donc la largeur autrement que les cinq des autres lignes. Le nom y gagnait
   39 px, le courriel demarrait 39 px plus loin, et le role flottait 77 px a
   droite de tous les autres. Une colonne vide vaut mieux qu'une colonne qui
   bouge. */
/* Un collaborateur est une carte et non une ligne depuis le 27 aout 2026
   (« collaborateur mieux developpe ») : la rangee de tete -- rond, nom,
   adresse, role, corbeille -- et, sous elle, ce qu'il porte. Le cadre passe
   donc de la rangee a la carte, la rangee n'etant plus qu'une des deux. */
/* Le dessin de la carte a suivi le lendemain (« ameliore le design des cartes
   pour les rendre plus belles et modernes », 27 aout 2026). Trois choses, et
   elles se tiennent : le rond passe de 28 a 34 px, l'adresse descend sous le
   nom au lieu d'occuper une colonne a elle -- ces deux-la sont une seule
   identite, et les separer de dix rem laissait un blanc au milieu de chaque
   carte --, et ce que le collaborateur porte devient des pastilles posees sur
   un fond plutot que des mentions grises alignees. Le cadre s'ouvre en
   consequence : plus de rembourrage, l'arrondi du barreau au-dessus, une ombre
   basse et une bordure qui repond au survol. */
.equipe-gestion-carte,
.equipe-gestion-ajout {
  --equipe-rond: 34px;
  padding: var(--espace-sm) var(--espace-md);
}

/* L'ombre et le survol ont quitte la carte le 30 aout 2026, quand la zone a
   pris un cadre a elle. Une ombre portee dit « cette surface flotte au-dessus
   du fond » ; posee dans une tuile, elle disait que la carte flottait au-dessus
   d'une surface qui flotte deja, et les six cartes se lisaient comme six
   fenetres empilees. Le survol partait du meme malentendu : la carte n'est pas
   cliquable -- seuls le choix de role, la corbeille et « Personnalisation des
   acces » le sont --, et un cadre qui s'assombrit sous le curseur promet un
   geste qui n'existe pas. */
.equipe-gestion-carte {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
}

/* Sa propre carte, dans la pile de celles des autres : le fond pale du cyan,
   celui qui marque deja « moi » dans un fil de messages. */
.equipe-gestion-soi { background: var(--cyan-pale); border-color: var(--cyan-light); }

/* La derniere colonne mesure un bouton d'action, pas un dessin : elle valait
   1,9 rem -- 30,4 px --, une largeur taillee a l'oeil pour une corbeille nue,
   et le carre cerne s'y etirait a 30,4 sur 28 de haut. Seul bouton-icone du
   produit a n'etre pas carre. */
.equipe-gestion-form {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) 8.5rem var(--h-sm);
  align-items: center;
  gap: var(--espace-2xs) var(--espace-sm);
}

/* Le nom et l'adresse en pile : une seule identite, une seule colonne. */
.equipe-gestion-identite {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  min-width: 0;
}

/* La ligne d'invitation n'a que trois cases : elle garde sa propre grille
   plutot que d'aller se ranger sur des colonnes qui ne sont pas les siennes. */
.equipe-gestion-ajout {
  grid-template-columns: auto 1fr auto;
}

/* Ce que le collaborateur porte, sous son nom : des mentions et non des
   champs -- rien ne s'y modifie. Elles se lisent d'un coup d'oeil, alignees
   sur le nom au-dessus plutot que sur le bord de la carte : la premiere
   colonne de la rangee est le rond, et les mentions commencent apres lui. */
.equipe-gestion-details {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-2xs);
  padding-left: calc(var(--equipe-rond) + var(--espace-sm));
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Des pastilles et non des mentions : chacune est un renseignement entier --
   un numero, un nombre de mandats, une derniere venue -- et une rangee de
   textes gris de meme taille les faisait lire comme une phrase. Le fond les
   separe sans qu'il faille les separer d'un blanc. */
.equipe-gestion-detail {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  white-space: nowrap;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
}

.equipe-gestion-detail .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--gray-4);
}

/* LA PART DU CAPITAL, seule mention de la rangee qui se saisisse. Elle garde la
   boite et le gris des autres : c'est un renseignement de la meme famille, et
   lui donner l'allure d'un formulaire aurait coupe la rangee en deux. Ce qui
   dit qu'on peut y toucher est le cadre du champ, pas la pastille autour. */
.equipe-capital label { color: var(--gray-5); }

.equipe-capital-champ {
  width: 5.5em;
  padding: 0 var(--espace-2xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  color: var(--black);
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.equipe-capital-champ:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 1px;
}

/* Le total et la part, gris : « 3 050 » est le nombre qu'on vient changer, le
   reste est ce qui lui donne son sens. */
.equipe-capital-total { color: var(--gray-5); }

/* Les tickets qu'il porte encore sont la seule mention qui appelle un geste :
   elle prend l'orange des choses a traiter, comme la pastille de l'entete. */
.equipe-gestion-detail-tickets { color: var(--orange-dark); background: var(--orange-pale); }
.equipe-gestion-detail-tickets .icon { color: var(--orange); }

/* La page d'un accès refusé, et celle d'une adresse qui ne mène nulle part.
 *
 * Elle nomme ce qui est fermé et dit par qui ça s'ouvre : un refus qui
 * n'explique pas se lit comme une panne. Centrée et courte -- il n'y a rien à
 * y faire qu'en repartir.
 *
 * Deux porteurs depuis le 30 août 2026, et non deux formes : `.page-erreur`
 * (erreur.html) sert le 404 et le 500, qui n'avaient jusque-là aucune page du
 * tout -- Flask servait la sienne, nue et en anglais. Ce sont les mêmes
 * écrans : quelque chose n'est pas là, on dit quoi et par où repartir. Le
 * second nom existe parce qu'un 404 n'est pas un refus d'accès, pas parce que
 * le dessin diffère ; qu'ils partagent la règle est ce qui garantit qu'ils ne
 * divergeront pas. */
.acces-refuse,
.page-erreur {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-sm);
  max-width: var(--largeur-lecture);
  margin: var(--espace-xl) auto;
  padding: var(--espace-xl) var(--espace);
  text-align: center;
  color: var(--gray-5);
}

.acces-refuse > .icon,
.page-erreur > .icon {
  width: var(--icon-xl);
  height: var(--icon-xl);
  color: var(--gray-4);
}

.acces-refuse h2,
.page-erreur h2 {
  margin: 0;
  font-size: var(--fs-lg);
  color: var(--black);
}

.acces-refuse p,
.page-erreur p { margin: 0; font-size: var(--fs-sm); }
.acces-refuse-suite,
.page-erreur-suite { color: var(--gray-4); }
.acces-refuse .btn-primary,
.page-erreur .btn-primary { margin-top: var(--espace-sm); text-decoration: none; }

/* Les accès personnalisés d'un collaborateur : le bouton qui les règle, et le
   panneau qu'il déplie.
 *
 * « Je veux que chaque collaborateur ait un bouton Personnalisation des accès,
 * et puisse vraiment décider très précisément, avec des coches [...] exhaustif
 * mais organisé » (demande du 27 août 2026).
 *
 * Le bouton fut une pastille comme les autres -- même boîte, même gris que le
 * téléphone et le nombre de mandats --, et il n'annonçait ce qu'il ouvrait
 * qu'au survol. Rien ne le distinguait de ce qui ne se clique pas : « il est
 * mis à côté d'éléments non cliquables [...] on ne trouve pas l'endroit »
 * (suivi du 28 août 2026).
 *
 * Il a donc sa propre ligne, sous les mentions, et la forme d'un bouton à
 * l'arrêt : un cadre, le fond pâle de l'accent, son intitulé en toutes lettres
 * et un chevron qui dit qu'il déplie. Ce qu'il ouvrait au survol, il le dit
 * maintenant avant qu'on l'ait trouvé. */
/* Sous les mentions, donc sur leur colonne : ce que porte le collaborateur
   commence apres son rond, jamais au bord de la carte -- c'est ce qu'ecrit
   `.equipe-gestion-details` plus haut, et cette ligne, ajoutee un jour plus
   tard, ne l'avait pas repris. Son bouton pendait quarante-quatre pixels a
   gauche de l'adresse qu'il suit, seul element de la carte a ne pas partir du
   nom. */
.equipe-acces-barre {
  display: flex;
  padding-left: calc(var(--equipe-rond) + var(--espace-sm));
}

.equipe-acces-bouton {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  min-height: var(--h-sm);
  padding: var(--espace-3xs) var(--espace-sm);
  border: 1px solid var(--cyan-light);
  border-radius: var(--radius-sm);
  background: var(--cyan-pale);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--cyan-dark);
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.equipe-acces-bouton .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--cyan-dark);
}

.equipe-acces-bouton:hover,
.equipe-acces-bouton[aria-expanded="true"] { border-color: var(--cyan); }

/* Le chevron pointe vers la droite tant que rien n'est ouvert, vers le bas
   quand le panneau l'est : c'est le même geste que partout ailleurs sur le
   site, et il évite d'avoir à écrire « replier ». */
.equipe-acces-chevron { transition: transform .15s var(--ease); }
.equipe-acces-bouton[aria-expanded="true"] .equipe-acces-chevron { transform: rotate(90deg); }

/* La mention des accès dans la rangée du dessus prend l'accent dès qu'une part
   du produit est fermée : une personne restreinte se repère alors dans la pile
   sans ouvrir une seule carte. */
.equipe-gestion-detail-acces { color: var(--cyan-dark); background: var(--cyan-pale); }
.equipe-gestion-detail-acces .icon { color: var(--cyan-dark); }

.equipe-acces {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
  margin-top: var(--espace-sm);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
}

.equipe-acces-tete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  flex-wrap: wrap;
}

.equipe-acces-titre {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-6);
}

.equipe-acces-attente {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  font-style: italic;
}

/* Le panneau d'un administrateur : le catalogue s'y lit, il ne s'y règle pas.
   La phrase dit pourquoi les cases ne répondent pas -- sans elle, vingt-deux
   lignes cochées et sourdes se lisent comme une page en panne. */
.equipe-acces-note {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-2xs);
  padding: var(--espace-2xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--cyan-pale);
  font-size: var(--fs-2xs);
  color: var(--cyan-dark);
}

.equipe-acces-note .icon { flex: none; color: var(--cyan-dark); }

/* Les cases d'un administrateur sont cochées et sourdes. L'intitulé s'éteint
   avec elles : la case pâlit déjà d'elle-même (`input:disabled`), mais un
   « Voir » resté franc à côté d'une case éteinte se lit comme un réglage qu'on
   vient de poser, et on repart en croyant avoir fermé quelque chose. */
.equipe-acces-case:has(input:disabled) {
  cursor: default;
  color: var(--gray-4);
}

/* Un groupe du catalogue -- « Les mandats », « L'analyse ». C'est lui qui rend
   la liste tenable : vingt-deux domaines à plat se lisent comme un formulaire
   d'assurance, six groupes de trois ou quatre se parcourent. */
.equipe-acces-groupe {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

.equipe-acces-groupe-titre {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
}

.equipe-acces-groupe-note {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  margin-bottom: var(--espace-2xs);
}

/* L'écran de préparation d'un mandat : « fais un écran de chargement propre,
   mais qui se charge dès que tout est chargé. Il faut vraiment que ça soit pas
   plus lent, juste qu'on n'ait pas cet affichage en deux temps » (ticket du
   28 août 2026).

   Il tient la place des panneaux le temps que la liste des sources arrive :
   sans lui, la page ouvrait sur Source -- qu'on ne voulait pas -- puis
   basculait sur Analyse une fois la réponse là. */
.dossier-preparation {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--espace);
  min-height: 40vh;
  color: var(--gray-4);
  font-size: var(--fs-sm);
}

.dossier-preparation-rond {
  width: var(--icon-xl);
  height: var(--icon-xl);
  border: 2px solid var(--gray-3);
  border-top-color: var(--cyan);
  border-radius: 50%;
  animation: dossier-preparation-tourne .8s linear infinite;
}

@keyframes dossier-preparation-tourne {
  to { transform: rotate(360deg); }
}

/* Tant que le voile est là, les panneaux ne s'affichent pas -- y compris celui
   que le gabarit ouvre par défaut. Et aucun onglet ne se dit actif : souligner
   « Source » pendant la préparation pour souligner « Analyse » une seconde
   après serait le même deux temps, en plus petit. */
body.dossier-en-preparation .tab-panel { display: none; }

body.dossier-en-preparation .dossier-tab-btn.active {
  color: var(--gray-5);
  border-bottom-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  .dossier-preparation-rond { animation-duration: 2.4s; }
}

/* Le portefeuille : « tous les mandats », puis la liste quand on décoche
   (ticket du 28 août 2026). Elle est haute -- cent trente lignes chez ce
   cabinet --, donc elle défile dans sa propre boîte au lieu de repousser les
   six groupes de domaines hors de l'écran. */
.equipe-acces-mandats {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  max-height: 14rem;
  overflow-y: auto;
  margin-top: var(--espace-2xs);
  padding: var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

/* Une ligne de mandat porte depuis le 30 août 2026 ce que porte une ligne de la
   liste des clients : l'état, le nom, le groupe, le titulaire. « Il y a juste
   le nom, alors qu'en vrai, essaye d'afficher sur la liste toutes les
   informations, un peu comme ce qu'on a sur la liste des clients [...] pour une
   sélection, parfois c'est utile de lui passer que d'un seul cabinet. »

   Les trois marques sont exactement celles de la liste des clients, classes
   comprises (.dossier-etat-badge, .dossier-groupe-chip, .dossier-cabinet-tile
   pour le titulaire) : deux listes qui disent la même chose doivent la dire de
   la même façon, sinon il faut traduire de tête en passant de l'une à
   l'autre. */
/* Deux sélecteurs et non un : `.equipe-acces-case`, écrite plus bas dans la
   feuille, pose une largeur de colonne de 6,5 rem qui vaut pour les cases
   Voir/Modifier et qui gagnerait ici à égalité de poids. Une ligne de mandat
   prend toute la largeur de sa boîte -- c'est ce qui aligne les titulaires
   d'une ligne à l'autre, et ce qui laisse au nom la place de s'écrire. */
.equipe-acces-mandats .equipe-acces-mandat {
  width: auto;
  align-self: stretch;
  font-size: var(--fs-xs);
  gap: var(--espace-2xs);
}

/* Le nom prend la place qui reste : c'est lui qui pousse le groupe et le
   titulaire en fin de ligne, où ils s'alignent d'une ligne à l'autre.
   `min-width: 0` sans quoi un nom long refuse de se raccourcir : dans une
   boîte flexible, un élément ne descend pas sous sa largeur de contenu tant
   qu'on ne l'y autorise pas, et c'est la ligne entière qui déborderait. */
.equipe-acces-mandat-nom {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.equipe-acces-mandat-groupe {
  flex: none;
  padding: 0 var(--espace-2xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  font-size: var(--fs-3xs);
  color: var(--gray-5);
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 8rem;
}

/* Les deux personnes qui portent le mandat, à la fin de la ligne comme sur la
   liste des clients : le signataire puis le titulaire (« le titulaire, c'est
   super, mais mets aussi le signataire », suivi du 30 août 2026). Plus petites
   ici : la ligne fait un tiers de la largeur de celle de la liste.

   Un rond pour la personne, une tuile pour le titulaire -- qui est souvent un
   cabinet. Deux formes pour deux natures, comme partout ailleurs sur le site :
   ce qui est rond est quelqu'un. */
.equipe-acces-mandat-signataire {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--icon-lg);
  height: var(--icon-lg);
  border-radius: 999px;
  font-size: var(--fs-3xs);
  font-weight: 700;
  letter-spacing: var(--suivi-serre);
  color: #fff;
}

.equipe-acces-mandat-titulaire {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  min-width: var(--icon-xl);
  height: var(--icon-lg);
  padding: 0 var(--espace-3xs);
  border-radius: var(--radius-xs);
  font-size: var(--fs-3xs);
  font-weight: 700;
  letter-spacing: var(--suivi-serre);
  color: #fff;
}

/* « Tous les mandats (375) » sur une seule ligne : la case et son texte, sans
   la colonne des deux cases Voir/Modifier qui rend les autres lignes étroites. */
.equipe-acces-tous-mandats,
.equipe-acces-mandat {
  width: auto;
  align-self: flex-start;
  white-space: nowrap;
}

/* La barre au-dessus de la liste : les clés de tri à gauche, les deux boutons
   de sélection en masse à droite. « Faut que tu fasses une fonction tout
   désélectionner ou tout sélectionner » (suivi du 30 août 2026) -- décocher
   « Tous les mandats » cochait les trois cent soixante-quinze, et n'en garder
   que six demandait trois cent soixante-neuf clics. */
.equipe-acces-outils {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--espace-2xs);
  margin-top: var(--espace-2xs);
}

.equipe-acces-tris,
.equipe-acces-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-sm);
}

.equipe-acces-masse { font-size: var(--fs-2xs); }

.equipe-acces-filtre {
  margin-top: var(--espace-2xs);
  padding: var(--espace-2xs) var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  font-family: var(--sans);
}

/* Une ligne : ce que le domaine gouverne à gauche, les deux cases à droite,
   alignées d'une ligne à l'autre pour qu'on puisse descendre la colonne du
   regard au lieu de lire chaque ligne. */
.equipe-acces-ligne {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-sm);
  padding: var(--espace-2xs) var(--espace-xs);
  border-radius: var(--radius-xs);
}

.equipe-acces-ligne:hover { background: var(--gray-1); }

.equipe-acces-domaine {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  flex: 1;
  min-width: 0;
}

.equipe-acces-domaine-titre {
  font-size: var(--fs-xs);
  color: var(--gray-6);
}

.equipe-acces-domaine-note {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

.equipe-acces-case {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  flex: none;
  width: 6.5rem;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  cursor: pointer;
}

.equipe-gestion-apercu {
  --avatar-d: var(--equipe-rond);
  flex: none;
}

.equipe-gestion-nom {
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.equipe-gestion-email {
  min-width: 0;
  color: var(--gray-5);
  font-size: var(--fs-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Le champ d'invitation prend la recette exacte du controle du site -- celle de
   `select` : meme rembourrage vertical, meme corps, meme bordure. Il ne l'avait
   pas, et se trouvait 4 px plus court que la liste des roles posee juste
   au-dessus de lui dans la meme colonne. Le corps descend au passage a celui
   des courriels qu'il rejoint : cette case remplace la colonne des adresses,
   elle doit s'y lire a la meme taille. */
.equipe-gestion-email-input {
  min-width: 0;
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs-sm);
}

.equipe-gestion-email-input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.equipe-gestion-role { min-width: 0; }

/* Le role ecrit en toutes lettres tient la place exacte de la liste deroulante
   des autres lignes -- meme rembourrage, meme bordure (transparente) -- pour
   que les deux se lisent sur la meme verticale.

   Il ne la tenait pas tout a fait : un texte ordinaire herite de l'interligne
   du site (1.5), une liste deroulante garde celui du navigateur, et les deux
   font 4 px d'ecart. La ligne « (vous) » etait donc la seule des sept a etre
   plus haute que ses voisines, au milieu d'une pile ou toutes les autres
   tombent au meme pixel. L'interligne se remet ici sur celui du controle. */
.equipe-gestion-role-lecture {
  color: var(--gray-5);
  font-size: var(--fs-sm);
  line-height: normal;
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid transparent;
}

.equipe-lien-bloc {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

.equipe-lien-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  flex-wrap: wrap;
}

.equipe-lien {
  padding: var(--espace-xs) var(--espace-sm);
  background: var(--gray-1);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  word-break: break-all;
}

.compte-confirmation {
  color: var(--cyan-dark);
  background: var(--cyan-pale);
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--espace);
  font-size: var(--fs-sm);
  margin-bottom: var(--espace-md);
}

/* Le mot qui repond a un envoi traverse la grille : ce n'est pas une tuile de
   plus a ranger a cote des sept autres, c'est la reponse de la page au geste
   qu'on vient de faire, et elle se lit en tete. Sa marge basse retourne a
   l'ecart de la grille, qui la porte deja. Ecrit sous `.compte-panel` parce
   que la meme classe sert aussi en tete d'un panneau de `/cabinet`, ou elle
   n'est pas dans une grille. */
.compte-panel > .compte-confirmation {
  grid-column: 1 / -1;
  margin-bottom: 0;
}

.compte-erreur {
  color: var(--red);
  background: var(--red-pale);
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--espace);
  font-size: var(--fs-sm);
  margin-bottom: var(--espace-md);
}

/* Le renvoi vers la page Cabinet : ce qui a quitte « Mon compte » le 7 aout
   2026 doit rester trouvable depuis l'endroit ou on le cherchera encore. Il
   passe avant la deconnexion, qui garde sa place de dernier geste.

   Les deux tenaient sous la colonne sans rien autour d'eux : un lien et un
   bouton nus sous une pile de tuiles encadrees, separes du reste par un filet
   qui traversait toute la page -- et qui, depuis que ce qui precede est
   encadre, se lisait comme le bord casse d'une tuile de plus. On leur a donc
   donne une tuile a eux, pour que le filet puisse partir.

   C'etait une tuile de trop. Un cadre est fait pour tenir un ensemble, et deux
   boutons ne sont pas un ensemble : encadres, ils prenaient le poids d'une des
   huit rubriques de la page alors qu'ils n'en sont pas une, et la grille leur
   ouvrait une case entiere pour deux libelles. Le cadre se garde pour les
   grands ensembles ; a cette echelle il alourdit ce qu'il devait separer.

   Ils reprennent donc leur nudite, sans que le filet ait a revenir : tout ce
   qui precede est encadre, c'est desormais l'absence de cadre qui les
   distingue. Ils s'etendent sur toute la largeur de la grille pour se lire
   comme le pied de la page, et s'y rangent a gauche -- `space-between`
   jetterait « Se deconnecter » a deux mille cinq cents pixels de son voisin,
   ce qui est exactement la barre horizontale que la page vient de perdre.

   Sans titre, seul cas de la page : les deux libelles se nomment eux-memes, et
   un mot de plus au-dessus de « Cabinets et equipe » et « Se deconnecter »
   n'apprendrait rien a personne. */
.compte-pied {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--espace-xl);
}

.compte-logout { margin: 0; }

.compte-renvoi { margin: 0; }

/* Ces deux boutons sont les seuls de la colonne a n'avoir ni fond ni bordure
   visibles. Leur creux horizontal -- celui que `.icon-btn` porte pour que le
   rectangle de survol depasse du texte -- poussait donc leur encre dix pixels a
   l'interieur, sans que rien ne marque le bord qu'ils quittaient : ils pendaient
   sous rien. Tout le reste de la page tient ce bord, y compris « Tester le
   son », dont la bordure dessine sa boite dessus.

   On rend le creux au bouton en le tirant de sa propre valeur : l'encre revient
   sur le bord de la colonne, et le rectangle de survol garde son creux en
   debordant dans le rembourrage du panneau. Ecrit comme la somme de ses termes
   -- le creux de `.icon-btn` et sa bordure transparente -- pour qu'il suive si
   l'echelle bouge. */
.compte-renvoi .icon-btn,
.compte-logout .icon-btn {
  margin-left: calc(-1 * (var(--espace-sm) + 1px));
}

/* `.mfa-enroll-wrap` ne portait qu'une largeur, et cette largeur est
   desormais celle de `.login-wrap` : les six pages d'authentification font la
   meme chose et n'ont aucune raison d'avoir deux largeurs. */

/* ---------- L'enrolement de la double authentification ---------- */

/* La carte alignait huit blocs a la file -- pastille, titre, texte, code QR,
   cle, bouton Mac, precision, formulaire -- separes par sept ecarts differents
   (16, 6.4, 20, 12.8, 24, 6.4, 24), sans que rien ne dise qu'ils ne servent pas
   tous la meme chose. Il y a pourtant deux temps, et l'ordre compte : enregistrer
   le compte dans une application d'authentification, puis prouver qu'il y est.

   Le premier est cerne, le second reste a nu -- c'est celui qui se termine, il
   n'a pas besoin d'etre designe. L'air entre les deux vaut un barreau de plus
   que l'air a l'interieur du premier ; c'est tout ce qui separe une liste d'une
   zone. */
.mfa-ajout {
  margin: var(--espace-xl) 0;
  padding: var(--espace-md) var(--espace-lg);
}

/* La remise a zero d'abord, le rythme ensuite. Sans la premiere ligne, chaque
   bloc devrait porter son propre `margin: 0` -- et un `.mfa-secret { margin: 0 }`
   pese exactement autant que `.mfa-ajout > * + *`, donc l'emporte en etant ecrit
   plus bas : la cle se collait sous le carre. La zone tient son rythme, ses
   blocs ne portent plus que leur dessin. */
.mfa-ajout > * { margin: 0; }

.mfa-ajout > * + * { margin-top: var(--espace-md); }

/* La precision colle a son bouton : elle dit ce qu'il ouvre, elle n'est pas le
   troisieme moyen d'enregistrer le compte. */
.mfa-mac-btn + .mfa-mac-hint { margin-top: var(--espace-xs); }

/* Le carre ne porte plus de cadre : celui de la zone l'entoure desormais, et
   deux filets emboites autour d'un seul dessin font une boite dans une boite.
   Reste le centrage, qui n'operait pas : `mobile.css` bridait la largeur de la
   boite a 220 pixels, si bien que sous 820 le carre s'alignait a gauche pendant
   que le titre, la cle, le bouton et la precision etaient centres. La boite
   prend toute la largeur, et son contenu se centre dedans. */
.mfa-qr {
  display: flex;
  justify-content: center;
}

.mfa-qr svg { width: 180px; height: 180px; }

.mfa-secret {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  text-align: center;
}

/* Une cle TOTP fait trente-deux caracteres. Sur la meme ligne que son intitule,
   elle occupait la largeur de la carte, se coupait au milieu d'un groupe et
   posait son fond gris jusqu'au bord. Elle passe donc dessous, seule sur sa
   ligne, et en chasse fixe : c'est une cle qu'on recopie a la main, ou un 0 et
   un O, un 1 et un l doivent se distinguer. */
.mfa-secret code {
  display: block;
  margin-top: var(--espace-2xs);
  padding: var(--espace-xs) var(--espace-sm);
  background: var(--gray-1);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: var(--fs-sm);
  letter-spacing: var(--suivi-entete);
  color: var(--gray-6);
  word-break: break-all;
}

.mfa-mac-btn {
  display: block;
  text-align: center;
  font-family: var(--sans);
  font-size: var(--fs);
  font-weight: 600;
  color: var(--black);
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--espace-md);
  text-decoration: none;
  transition: background .15s var(--ease);
}

.mfa-mac-btn:hover { background: var(--gray-3); }

.mfa-mac-hint {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  text-align: center;
}

/* Ce champ est pose dans une barre d'outils, et une barre d'outils tient sur
   une seule hauteur. Celle de la barre du mapping etait deja arbitree juste
   au-dessus, sur .unit-toggle : plancher a --h-sm, et le remplissage de ses
   boutons ramene a 4 px pour que ce plancher decide vraiment -- « a 6,4 la
   bande redemandait ses 29,78, le plancher ne servait a rien, et le rang
   retombait a deux hauteurs ».

   Le rang y etait retombe quand meme, par l'autre bout : ce champ-ci n'a
   jamais suivi. Il gardait le remplissage d'origine, .5rem -- une valeur qui
   n'est meme pas un barreau de l'echelle --, ce qui le portait a 34 contre 28
   pour la bascule a sa gauche. Six pixels d'ecart et trois de decalage, dans
   une rangee de deux elements, sur les deux barres du mapping.

   Il ne suivait pas parce que le resserrement voisin est ecrit sous
   `.toolbar .toolbar-search` : il s'adresse a un nom de classe, pas a ce
   qu'est l'element. Un champ de filtre pose dans une barre est pourtant
   exactement la meme chose qu'un champ de recherche pose dans une barre. */
.mapping-filtre-input {
  font-family: var(--sans);
  font-size: var(--fs);
  height: var(--h-sm);
  padding: var(--espace-2xs) var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  min-width: 260px;
}

/* Seul champ du produit a n'avoir jamais eu d'anneau a lui : il recevait donc
   celui du site, un trait plein de deux pixels a deux pixels du bord, quand
   les vingt et un autres champs montrent le halo pale. Deux barres d'outils
   voisines, deux facons de dire « c'est ici que vous ecrivez ». */
.mapping-filtre-input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Le champ de saisie d'une ligne de mapping. Il se reecrivait ici de bout en
   bout -- arrondi, remplissage, bordure --, alors que la liste deroulante de
   la meme rangee prend, elle, l'habit que la base de cette feuille donne a
   l'element : « la meme bordure que les champs voisins », dit son
   commentaire. Les deux se retrouvaient cote a cote, la colonne SENS contre
   les colonnes CODE, sans rien avoir en commun -- quatre pixels d'arrondi
   contre sept, 26,6 px de haut contre 29,8, et donc pas meme un bord
   superieur partage.

   Il reprend donc le remplissage vertical de la liste deroulante et son
   arrondi : --espace-xs sur --espace-sm, ses deux barreaux, l'ecart
   horizontal en moins de la place que la fleche lui prend a droite. Les deux
   controles d'une rangee se posent alors sur la meme ligne et ont la meme
   forme. La rangee ne s'en trouve pas plus haute : ce sont les 9,6 px de
   marge du `td` qui la tiennent a 50 px, et c'etait deja la liste
   deroulante, la plus haute des deux, qui s'y logeait le plus juste. */
.mapping-table input[type="text"] {
  font-family: var(--sans);
  font-size: var(--fs-sm);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  width: 100%;
  min-width: 60px;
  box-sizing: border-box;
}

.mapping-table input[type="text"]:focus {
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
  outline: none;
}

/* La table des denominations en aligne 378, une par mandat. A la hauteur
   ordinaire d'une ligne de tableau -- .6rem de marge haute et basse autour
   d'un champ de saisie qui porte les siennes -- il en tient une quinzaine par
   ecran, et corriger deux noms courts eloignes demande de faire defiler tout
   le tableau. Les lignes se resserrent donc sur la hauteur de l'en-tete
   (.3rem .6rem, deja la valeur de `.sources-table th`), et le champ de saisie
   avec elles : sans lui, c'est le champ qui continue de tenir la hauteur et
   la ligne ne bouge pas. */
.mapping-table-compacte td { padding: var(--espace-2xs) var(--espace-sm); }

/* La colonne SIREN de la table des noms courts. Groupe par trois, le numero
   fait onze caracteres -- neuf chiffres et deux espaces --, et le calcul
   automatique du tableau lui en donnait 96 pixels : chaque numero de la liste
   se cassait en deux lignes (constate au navigateur le 21 aout 2026).
   `nowrap` interdit la coupure, `width: 1%` demande au tableau la place juste
   necessaire et pas davantage -- ce que la colonne prend, c'est la
   denomination, seule colonne extensible de la table, qui le rend. */
.mapping-siren-cell {
  white-space: nowrap;
  width: 1%;
}
/* La table serree garde son champ serre -- c'est tout l'objet du resserrement
   decrit au-dessus --, mais sur les barreaux plutot qu'en chiffres : le
   voisin le plus proche coute 1,6 px par rangee, soit une rangee de moins par
   ecran sur les trois cent soixante-dix-huit. L'arrondi, lui, vient
   maintenant de la regle commune : une table dense n'est pas une raison
   d'avoir des coins a soi. */
.mapping-table.mapping-table-compacte input[type="text"] {
  padding: var(--espace-3xs) var(--espace-xs);
}

/* Le dictionnaire des evenements : une denomination tient en un sigle, ses
   formes reconnues en une liste. Laissees libres, les deux colonnes se
   partagent la ligne a parts egales et le sigle nage dans un champ dix fois
   trop large pendant que la liste passe a la ligne. */
#evenements-table th:first-child,
#evenements-table td:first-child { width: 14rem; }
#evenements-table th:nth-child(3),
#evenements-table td:nth-child(3) { width: 6rem; }

/* Le mapping du bilan reglementaire. Sa table n'est pas un arbre -- le modele
   du PCG n'a que deux etages, la rubrique et le poste --, mais elle se lit
   comme tel : la rubrique annonce, les postes qui la suivent sont en retrait.
   Sans ce retrait, soixante lignes de meme graisse se suivent et on ne sait
   plus sous quelle rubrique on saisit. */
.bilan-pcg-mapping-rubrique > td {
  font-family: var(--sans);
  font-weight: 600;
  padding-top: var(--espace);
}

/* Ce retrait n'avait jamais eu lieu : la regle etait ecrite pour une classe
   seule (0,1,0) et perdait contre `.mapping-table-compacte td` (0,1,1), qui
   repose les .6rem de la table. Les soixante postes se suivaient donc a plat
   sous leurs rubriques -- exactement ce que le commentaire du dessus dit
   qu'il ne faut pas (constate au navigateur le 29 aout 2026 : rubrique et
   poste tous deux a 9,6 px). Le `td.` suffit a la faire gagner. */
td.bilan-pcg-mapping-poste { padding-left: calc(var(--espace-sm) + var(--retrait-pas)); }

/* Une ligne « dont » d'un document de synthese : elle detaille la ligne du
   dessus et n'entre dans aucun total -- son montant y est deja. En gris et en
   italique, decalee : elle informe, elle ne compte pas, et il ne faut pas
   l'additionner de l'oeil non plus (demande du 26 aout 2026). */
.bilan-pcg-informatif > td {
  color: var(--gray-5);
  font-style: italic;
}

.bilan-pcg-informatif > td.label-cell {
  padding-left: calc(var(--espace) + var(--retrait-pas));
}

/* La colonne des intitules porte des libelles entiers du PCG (« Concessions,
   brevets, licences, marques, procedes... ») ; les deux colonnes de prefixes
   ne portent que des racines de compte. Laissees libres, elles se partagent
   la ligne a parts egales et l'intitule se casse en trois lignes. */
#bilan-pcg-mapping-sections th:first-child,
#bilan-pcg-mapping-sections td:first-child { width: 45%; }

.mapping-table input.mapping-cycle-input { width: 3.5rem; min-width: 3.5rem; text-align: center; }
/* Le sens usuel d'une racine : trois entrees, donc aussi etroit qu'un code de
   cycle. La liste deroulante est deja habillee par l'element a la base de
   cette feuille -- il ne reste que la largeur, qui est propre a cette
   colonne. */
.mapping-table select.mapping-sens-input { width: 4.2rem; min-width: 4.2rem; text-align: center; }
.mapping-table input[type="checkbox"] { width: 1rem; height: 1rem; cursor: pointer; }

/* Le trait qui ouvre un groupe de colonnes. --gray-3, celui des separateurs
   de la maison (`.annotation-separateur`, `.cabinet-toggle-separateur`), et
   non le --gray-2 des filets de lignes qu'il croise : un trait de groupe qui
   pese le poids d'un trait de ligne se lit comme une ligne de plus.

   Il n'a pas besoin qu'on lui reserve de l'air : les cellules portent deja
   --espace-sm de creux de chaque cote, soit exactement l'ecart que le
   separateur de la maison se pose a lui-meme. */
.mapping-table .mapping-groupe-debut { border-left: 1px solid var(--gray-3); }
.mapping-table tr[hidden] { display: none; }
/* Un titre de colonne se pose au-dessus de ce qu'il annonce. Ces deux
   classes ne valaient que pour les `td` -- posees par le JS qui construit les
   rangees -- et les `th` correspondants, ecrits a la main dans le gabarit,
   n'en portaient aucune : une colonne de cases a cocher etait centree et son
   titre restait a gauche. Mesure : « Visible (entr.) » a 51 px de la case
   qu'il nomme, « Documents » a 53, « A renommer » a 55. Les en-tetes portent
   desormais la meme classe que leurs cellules (mapping.html). */
.mapping-table th.mapping-check-cell,
.mapping-table td.mapping-check-cell { text-align: center; }

/* Et la largeur juste, comme la colonne SIREN plus haut. Une colonne de case a
   cocher se voyait attribuer la largeur de son titre, pas celle de son contenu :
   « Visible (entr.) » reservait 213 px a une case de 16, deux fois dans la meme
   table des sous-totaux. Les deux colonnes de noms se partageaient ce qui
   restait -- 349 px chacune a 1512 de large --, et le plus long des sous-totaux,
   « Versements des fondateurs ou consommation de dotation », debordait de son
   champ meme sur un ecran entier (379 px de texte dans 328 px de boite).
   `width: 1%` rend le surplus aux colonnes extensibles ; le titre se replie sur
   deux lignes, ce qu'un en-tete sait faire et pas un nom de poste. */
.mapping-table th.mapping-check-cell { width: 1%; }

/* La colonne « Icone » des cycles porte le meme exces sans porter de case a
   cocher : le tableau lui donnait 407 px a 1512 de large, exactement autant
   qu'aux deux colonnes de noms a cote d'elle, pour un nom d'icone. Mais pas
   `width: 1%` ici -- ce que ces noms mesurent vraiment va de « id-card » a
   « square-arrow-right-enter », 168 px, et la place juste necessaire d'un
   controle est celle de son texte, pas celle de son minimum. 12rem tient le
   plus long d'entre eux ; le reste retourne aux deux colonnes de noms.
   (Le champ de saisie est devenu un selecteur le 30 aout 2026, mais il porte
   le meme nom d'icone et demande donc la meme largeur.) */
#cycles-table th.mapping-icone-cell { width: 12rem; }
.mapping-table th.mapping-actions-cell,
.mapping-table td.mapping-actions-cell { white-space: nowrap; text-align: right; }

/* La place de la poubelle, meme quand il n'y a rien a supprimer. Cette colonne
   porte deux boutons tires chacun a sa condition : l'ajout n'existe que sur un
   total, la suppression que sur un poste effacable. Colonne calee a droite, le
   bouton d'ajout d'une rangee qui n'a pas de poubelle glissait donc de 33,6 px
   -- sa propre largeur -- et venait se poser exactement la ou les rangees du
   dessus mettent leur poubelle : dans une colonne de croix, un plus au milieu.
   Le cale-place rend la place sans rendre le bouton, comme pour la rangee du
   nouveau cabinet. Sa largeur est celle d'un `.btn-link` a icone seule :
   l'icone et ses deux creux lateraux.

   Ces creux valaient .55rem quand la ligne a ete ecrite. `.btn-link` les prend
   depuis au barreau --espace-sm, qui en fait 9,6, et le cale-place a garde
   l'ancien chiffre : il reservait 33,6 px pour un bouton qui en occupe 35,2.
   Comme la rangee est calee a droite, ce pouce et demi manquant poussait vers
   la droite tout ce qui precede -- c'est-a-dire le plus lui-meme. Sur l'onglet
   Bilan du mapping, les trente-six croix tenaient une colonne parfaitement
   droite a 1376 pendant que les quatorze plus se partageaient entre 1340,8 et
   1342,4, selon qu'une croix ou ce cale-place les suivait. Une colonne qui
   n'est droite qu'une ligne sur trois se voit sans qu'on sache dire pourquoi.
   La somme se lit maintenant dans les memes jetons que le bouton qu'elle
   remplace, et bouge donc avec lui. */
.mapping-table td.mapping-actions-cell:has(.btn-link):not(:has(.btn-danger))::after {
  content: '';
  display: inline-block;
  width: calc(var(--icon) + var(--espace-sm) * 2);
}

/* Un mapping affiche du texte, pas des chiffres. `.tree-table` aligne ses
   colonnes a droite parce qu'elle sert d'abord aux etats financiers ; les
   donnees d'un mapping avaient ete ramenees a gauche, mais les titres etaient
   restes a droite -- « Type » et « Prefixes de comptes » se lisaient au bout
   d'une colonne ecrite a son debut. Les deux moities vont ensemble.
   Le `:not()` laisse passer les colonnes de cases et d'actions ci-dessus,
   qui ont leur propre alignement et le gardent ici aussi. */
.mapping-table.tree-table td:not(.mapping-check-cell):not(.mapping-actions-cell),
.mapping-table.tree-table thead th:not(.mapping-check-cell):not(.mapping-actions-cell) {
  text-align: left;
}
.mapping-table.tree-table td.label-cell input[type="text"] { font-weight: inherit; }

/* L'agent de nommage, en haut de l'onglet Nommage.
   -------------------------------------------------------------------------
   Trois reglages sur une ligne et un petit releve dessous. Rien de neuf en
   dessin : la pastille reprend la forme des marques d'etat du produit
   (`999px`, jamais un rayon intermediaire), les cases et le champ numerique
   sont laisses nus parce qu'ils sont deja habilles a la base de cette feuille
   -- les rhabiller ici est exactement ce qui avait laisse trois cases au
   navigateur pendant des mois.

   La table du releve n'a pas d'en-tete : deux colonnes, un libelle et une
   mesure. La mesure est alignee a gauche et non a droite -- deux des trois
   lignes sont des phrases, et une phrase alignee a droite se lit mal. Les
   chiffres tabulaires restent : la file change a chaque enregistrement, et un
   nombre qui se decale en changeant de valeur attire l'oeil pour rien. */
.agent-etat {
  font-family: var(--sans);
  font-size: var(--fs-2xs);
  font-weight: 600;
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: 999px;
  letter-spacing: var(--suivi-serre);
}

.agent-etat-marche { color: var(--green-dark); background: var(--green-pale); }
.agent-etat-arret { color: var(--gray-6); background: var(--gray-2); }

.agent-reglages {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xl);
  margin-bottom: var(--espace-md);
}

.agent-reglage {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  cursor: pointer;
  /* Sans ca, l'element de flex ne descend pas sous la largeur de son contenu et
     le `max-width: 100%` de la liste n'a rien a quoi se mesurer : les deux se
     renvoient la balle et la ligne reste large. */
  min-width: 0;
}

.agent-reglage-libelle { color: var(--gray-6); flex: none; }
.agent-reglage select { min-width: 0; }
.agent-reglage input[type="number"] { width: 4.5rem; text-align: center; }

.agent-table { max-width: var(--largeur-lecture); }
.agent-table td:first-child { width: 14rem; color: var(--gray-6); }
.agent-table td.mapping-valeur {
  text-align: left;
  font-variant-numeric: tabular-nums;
}

/* La convention de nommage, en bas de l'onglet Nommage.
   -------------------------------------------------------------------------
   Une forme de nom se lit caractere par caractere : `2026-06-30 AGO STRUCTURE
   CONVOCATION` et `2026-06-30 AGO STRUCTURE  CONVOCATION` ne different que par
   une espace, et en Inter la difference ne se voit pas. Tout ce qui est une
   forme, un exemple ou un nom de fichier passe donc en chasse fixe.

   La table de convention posait deja des <code> depuis le 20 aout 2026, sans
   qu'aucune regle ne les habille : ils tombaient sur la fonte monospace du
   navigateur, qui n'est ni la meme ni a la meme graisse sous macOS, Windows
   et iOS. */
#tab-panel-nommage code {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  white-space: nowrap;
}

/* L'editeur de la forme des noms.
   -------------------------------------------------------------------------
   Quatre gabarits, chacun une suite de blocs qu'on deplace. Une carte par
   gabarit et non un filet a gauche comme dans le document du bas : il y en a
   quatre, pas soixante, et chacune porte une ligne de controles -- sans
   surface qui les tienne, les blocs du troisieme gabarit se lisent comme la
   suite de ceux du deuxieme. */
.gabarits {
  display: flex;
  flex-direction: column;
  gap: var(--espace-lg);
}

.gabarit {
  background: var(--gray-1);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  padding: var(--espace-md);
}

.gabarit-entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace-md);
}

.gabarit-titre {
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
  margin: 0;
}

/* Un ordre deplace ne change rien tant qu'on n'a pas enregistre. Sans cette
   mention, on quitte la page en croyant avoir change la forme des noms. */
.gabarit-modifie {
  flex: none;
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--orange-dark);
  background: var(--orange-pale);
  border-radius: 999px;
  padding: var(--espace-3xs) var(--espace-xs);
}

.gabarit-quand {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
  margin: var(--espace-2xs) 0 0;
  max-width: var(--largeur-bloc);
}

.gabarit-blocs,
.gabarit-absents {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs);
  margin-top: var(--espace);
}

/* Le bloc lui-meme : son rang, son nom, et les trois gestes qui le deplacent.
   Les gestes sont dans la pastille et non dans une barre d'outils separee --
   sur sept blocs, une barre obligerait a designer d'abord lequel on deplace. */
.gabarit-bloc {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-2xs) var(--espace-2xs) var(--espace-2xs) var(--espace-xs);
}

.gabarit-bloc-rang {
  font-size: var(--fs-3xs);
  font-weight: 600;
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

.gabarit-bloc-nom {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
  white-space: nowrap;
}

.gabarit-bloc-gestes {
  display: inline-flex;
  align-items: center;
}

.gabarit-bloc-geste {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3rem;
  height: 1.3rem;
  padding: 0;
  border: none;
  background: none;
  border-radius: var(--radius-xs);
  color: var(--gray-4);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.gabarit-bloc-geste .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.gabarit-bloc-geste:hover:not(:disabled) {
  background: var(--gray-2);
  color: var(--gray-6);
}

.gabarit-bloc-geste:disabled {
  color: var(--gray-3);
  cursor: default;
}

/* Un bloc retire reste sous les yeux. Le faire disparaitre reviendrait a
   demander de connaitre le vocabulaire pour le retrouver, et ce vocabulaire
   ne s'invente pas depuis cet ecran : il est fige, c'est ce que composer()
   sait remplir. */
.gabarit-absents-libelle {
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--gray-4);
}

.gabarit-bloc-absent {
  font: inherit;
  border-style: dashed;
  background: none;
  color: var(--gray-4);
  padding: var(--espace-2xs) var(--espace-sm) var(--espace-2xs) var(--espace-xs);
  cursor: pointer;
  transition: border-color .15s var(--ease), color .15s var(--ease);
}

.gabarit-bloc-absent .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.gabarit-bloc-absent .gabarit-bloc-nom {
  font-weight: 500;
  color: inherit;
}

.gabarit-bloc-absent:hover {
  border-color: var(--cyan);
  color: var(--cyan-dark);
}

/* La forme, puis l'exemple compose avec elle. Les deux en chasse fixe et sur
   une ligne : une forme se lit caractere par caractere, et si elle passe a la
   ligne on ne voit plus ou tombe le bloc qu'on vient de deplacer. */
.gabarit-apercu {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  /* Le meme couple qu'a `.cabinet-images`, seul autre filet du produit dont
     l'ecart au-dessus differe de celui au-dessous : un barreau de plus avant
     le trait qu'apres. 14,4 / 11,2 dessinait le meme rapport hors de
     l'echelle. */
  margin-top: var(--espace-md);
  padding-top: var(--espace);
  border-top: 1px solid var(--gray-2);
  overflow-x: auto;
}

.gabarit-apercu-fleche {
  flex: none;
  color: var(--blue);
}

/* Le registre des arbitrages de la ronde.

   Une carte par decision, la ou les regles du bas prennent un simple filet a
   gauche : ces entrees-la ne sont pas de la documentation, ce sont des actes,
   ils sont peu nombreux, et on veut les compter d'un coup d'oeil. La liste des
   cinq options est numerotee par <ol> et non par des pastilles dessinees : le
   numero EST l'information -- « option 5 » est la facon dont ces arbitrages se
   nomment depuis le premier d'entre eux. */
.arbitrages {
  display: flex;
  flex-direction: column;
  gap: var(--espace-md);
}

/* Le pied du registre : le bouton qui deplie les decisions plus anciennes. Il
   etait tenu par un `<p>` sans regle, donc aux marges du navigateur -- un `1em`
   en haut comme en bas, seule mesure de la page a ne venir d'aucun barreau. Les
   16 px du bas s'ajoutaient au creux de la tuile, et ceux du haut ne tombaient
   juste que par accident. Un paragraphe qui ne contient qu'un bouton n'etait de
   toute facon pas un paragraphe. */
.arbitrages-suite {
  margin-top: var(--espace-md);
}

/* Une carte, comme le dit le commentaire au-dessus -- et les cartes de ce
   produit ont toutes le meme creux : --espace-md dedans, --espace-lg sur les
   cotes. .ticket-card l'ecrit, .doc-contact et .conso-verdict aussi. Celle-ci
   ecrivait `1rem 1.1rem` : la hauteur etait deja le bon barreau, seuls les
   cotes s'en ecartaient de 2,4 px, et 17,6 ne tombe sur aucun barreau.

   Le cadre, lui, a change de rang le 30 aout 2026, quand la liste qui la porte
   est devenue une tuile : la carte ecrivait le cadre de la tuile -- meme rayon,
   meme gris --, et les deux se lisaient concentriques a vingt pixels l'un de
   l'autre. Elle prend celui de l'encart. Le creux ne suit pas : un encart est
   une forme, pas une densite. */
.arbitrage {
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  padding: var(--espace-md) var(--espace-lg);
  max-width: var(--largeur-bloc);
}

.arbitrage-tete {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-sm);
}

.arbitrage-numero {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--cyan-dark);
  background: var(--cyan-pale);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
}

.arbitrage-titre {
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 700;
  margin: 0;
}

.arbitrage-meta {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  letter-spacing: var(--suivi-serre);
  margin-left: auto;
}

.arbitrage-question {
  font-size: var(--fs-md);
  color: var(--gray-6);
  line-height: 1.5;
  margin: 0 0 var(--espace-xs);
}

.arbitrage-constat {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  line-height: 1.5;
  margin: 0 0 var(--espace);
}

.arbitrage-options {
  margin: 0 0 var(--espace);
  padding-left: var(--espace-xl);
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
}

.arbitrage-option {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  line-height: 1.45;
}

/* La retenue se lit sans chercher : c'est la seule ligne encrée et graissée
   des cinq. Un fond colore ferait une bande dans la carte ; ce qu'on veut est
   un poids, pas une surface. */
.arbitrage-option.retenue { color: var(--black); font-weight: 600; }
.arbitrage-option.retenue::marker { color: var(--cyan-dark); font-weight: 700; }

.arbitrage-option-effet {
  color: var(--gray-4);
  font-weight: 400;
}

.arbitrage-option-effet::before { content: " : "; }

.arbitrage-pied {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--espace-2xs) var(--espace);
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.5;
}

.arbitrage-pied dt {
  font-family: var(--sans);
  font-weight: 600;
  color: var(--gray-4);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  padding-top: var(--espace-3xs);
}

.arbitrage-pied dd {
  margin: 0;
  color: var(--gray-6);
}

.arbitrage-exemples {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-xs);
  margin: var(--espace) 0 0;
  /* Un nom de piece juridique est un mot insecable de soixante caracteres et
     davantage. Sans point de coupe il ne deborde pas de sa carte : il pousse
     la page entiere vers la droite, et c'est le corps du document qui defile
     de travers. La coupe se fait donc n'importe ou -- une cesure au milieu
     d'un nom de fichier se lit tres bien, une barre de defilement horizontale
     sur toute la page, non. */
  min-width: 0;
}

/* L'identifiant de l'onglet dans le selecteur n'est pas une precaution : sans
   lui, `.arbitrage-exemples code` pese moins que `#tab-panel-nommage code` et
   le `white-space: normal` ci-dessous ne s'appliquait pas. La coupe decrite
   juste au-dessus n'a donc jamais eu lieu : au 26 aout 2026, l'onglet Nommage
   defilait de 721 px vers la droite sur un telephone, exactement le defaut que
   ce bloc devait empecher. */
#tab-panel-nommage .arbitrage-exemples code {
  /* Comme dans la table des types : le nowrap general des <code> defait la
     coupe, et max-width seul rognerait le nom au lieu de le replier. */
  white-space: normal;
  overflow-wrap: anywhere;
  max-width: 100%;
}

/* Meme raison dans la table des types, mais overflow-wrap n'y suffit pas :
   une cellule de tableau se dimensionne sur son contenu le plus large avant
   de regarder les points de coupe, et un motif comme
   (?<![a-z0-9])bpf(?![a-z0-9]) elargit la table jusqu'a pousser la page.
   break-all coupe partout, ce qu'on peut se permettre sur une expression
   reguliere -- elle se lit caractere par caractere de toute facon. */
/* La meme chose pour toutes les tables de la convention, et pas seulement pour
   celle des types : un <code> en nowrap dimensionne sa cellule, et la cellule
   la table. `AAAA-MM-JJ -> EVENEMENT -> STRUCTURE -> OBJET -> ...` tenait 486 px
   dans un telephone de 390. Une suite de blocs se lit aussi bien repliee sur
   deux lignes -- ce qui doit rester d'un seul tenant, c'est la forme de l'apercu
   des gabarits, et elle a sa propre boite qui defile. */
#tab-panel-nommage td code {
  white-space: normal;
  overflow-wrap: anywhere;
}

#types-table code {
  /* white-space: nowrap vient de la regle generale des <code> de la page et
     defait toute coupe : tant qu'il tient, ni word-break ni overflow-wrap
     n'ont d'effet. Il est leve ici, et seulement ici. */
  white-space: normal;
  word-break: break-all;
}

/* Une carte etroite ne peut pas tenir deux colonnes : les intitules passent
   au-dessus de leur valeur plutot que de couper les mots. */
@media (max-width: 560px) {
  .arbitrage-pied { grid-template-columns: 1fr; }
  .arbitrage-pied dd { margin-bottom: var(--espace-sm); }
  .arbitrage-meta { margin-left: 0; }
}

.regle-objectif {
  font-size: var(--fs-md);
  color: var(--gray-6);
  line-height: 1.55;
  max-width: var(--largeur-lecture);
  margin: 0 0 var(--espace-lg);
}

.regle-blocs {
  display: flex;
  flex-direction: column;
  gap: var(--espace-lg);
}

/* Les ecarts du moteur suivent immediatement la table des crans. Colles a son
   dernier filet, ils se lisaient comme une septieme ligne du tableau.

   L'ecart valait 22,4 px, qui ne tombe sur aucun barreau. Il vaut le cran
   voisin, celui-la meme que le groupe met entre ses propres blocs (`gap:
   --espace-lg`) : le rythme du groupe ne change pas a sa lisiere.

   Et il vaut dans les deux sens. La paire n'etait ecrite que dans un ordre,
   alors que la tuile « La date » range le groupe avant la table : les deux se
   touchaient sans un pixel entre eux. */
.mapping-table + .regle-blocs,
.regle-blocs + .mapping-table {
  margin-top: var(--espace-lg);
}

/* Un filet a gauche plutot qu'une carte : le document en compte une
   soixantaine, et soixante cartes bordees feraient un damier ou plus rien ne
   ressort. Le filet donne le rythme sans ajouter de surface. */
.regle-bloc {
  border-left: 2px solid var(--gray-3);
  padding-left: var(--espace);
  max-width: var(--largeur-bloc);
}

.regle-bloc-entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace-md);
}

.regle-bloc-titre {
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
  margin: 0;
}

/* D'ou vient la regle : le numero du point qui l'a tranchee, ou qui l'a
   tranchee. Une regle sans sa provenance est ce qui rendait les fichiers de
   configuration illisibles -- on lisait une decision sans savoir qui l'avait
   prise ni contre quoi. */
.regle-bloc-renvoi {
  flex: none;
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--gray-4);
}

.regle-bloc-chapo {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  line-height: 1.5;
  margin: var(--espace-2xs) 0 0;
}

.regle-bloc-texte {
  font-size: var(--fs);
  color: var(--gray-6);
  line-height: 1.6;
  margin: var(--espace-xs) 0 0;
}

.regle-bloc-mesure,
.regle-bloc-reserve {
  font-size: var(--fs-xs);
  line-height: 1.55;
  margin: var(--espace-xs) 0 0;
}

.regle-bloc-mesure { color: var(--gray-5); }

/* Ce que la regle ne couvre pas. C'est la seule chose de ce document qui
   doive accrocher l'oeil : une regle appliquee sans sa reserve est une regle
   appliquee a des fichiers qu'elle n'a jamais vus. */
.regle-bloc-reserve { color: var(--orange-dark); }

/* Un renommage reellement calcule sur le fonds, pas un exemple invente.
   Les deux lignes sont en chasse fixe et alignees a gauche sur la meme
   colonne : la fleche est dans un ::before de largeur fixe, sinon `apres`
   demarre un caractere plus loin que `avant` et l'oeil ne peut plus comparer
   les deux noms en descendant. */
.regle-paire {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  margin-top: var(--espace-sm);
  overflow-x: auto;
}

.regle-paire-avant,
.regle-paire-apres {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  line-height: 1.6;
  white-space: nowrap;
}

.regle-paire-avant::before,
.regle-paire-apres::before {
  display: inline-block;
  width: 1.2rem;
  font-family: var(--sans);
}

.regle-paire-avant { color: var(--gray-4); }
.regle-paire-avant::before { content: ""; }

.regle-paire-apres { color: var(--gray-6); }
.regle-paire-apres::before { content: "→"; color: var(--blue); }

.regle-colonnes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--espace-lg);
}

.regle-colonne-chapo {
  display: block;
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--gray-4);
}

/* Une liste, sans puce : les types s'alignent sur le chapo de leur axe, et une
   puce ne dirait rien de plus qu'un retour a la ligne. */
.regle-colonne-liste {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.7;
  margin: var(--espace-xs) 0 0;
  padding: 0;
  list-style: none;
}

.regle-colonne-type + .regle-colonne-type {
  border-top: 1px solid var(--gray-2);
}

/* Ce qui suit n'est pas la regle mais ce que le moteur en fait -- et les deux
   divergent aujourd'hui. Lire la seconde table en croyant lire la premiere
   ferait passer la convention pour appliquee. */
.regle-avertissement {
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.55;
  background: var(--orange-pale);
  border-left: 3px solid var(--orange);
  border-radius: var(--radius-xs);
  padding: var(--espace-sm) var(--espace-md);
  margin: 0 0 var(--espace-lg);
  max-width: var(--largeur-bloc);
}

.mapping-cycle-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
}

.mapping-cycle-icon {
  color: var(--gray-5);
  flex: none;
}

/* Le choix de l'icone d'un cycle (Mapping > Cycles). Un champ de texte ou il
   fallait ecrire « square-arrow-right-enter » de memoire jusqu'au 30 aout
   2026 ; le catalogue s'ouvre maintenant sous le bouton, en clair. */
.mapping-icone-choix {
  position: relative;
}

.mapping-icone-bouton {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  padding: var(--espace-xs) var(--espace-sm);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  color: var(--black);
  cursor: pointer;
  text-align: left;
  transition: border-color .15s var(--ease);
}

.mapping-icone-bouton:hover,
.mapping-icone-bouton[aria-expanded="true"] {
  border-color: var(--cyan);
}

.mapping-icone-nom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mapping-icone-nom-vide { color: var(--gray-4); }

/* Surface flottante : meme famille que les autres panneaux poses par-dessus
   la page -- fond blanc, bordure grise, grand arrondi, ombre portee. */
.mapping-icone-palette {
  position: absolute;
  z-index: 20;
  top: calc(100% + var(--espace-2xs));
  left: 0;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: var(--espace-3xs);
  width: max-content;
  max-height: 18rem;
  overflow-y: auto;
  padding: var(--espace-xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.mapping-icone-case {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--espace-2xl);
  height: var(--espace-2xl);
  padding: 0;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--gray-5);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background .15s var(--ease);
}

.mapping-icone-case:hover { background: var(--gray-2); }

.mapping-icone-case.active {
  background: var(--cyan-pale);
  border-color: var(--cyan);
  color: var(--cyan-dark);
}

/* « Aucune » occupe le rang entier : c'est un choix, pas une icone de plus a
   reconnaitre parmi les autres. */
.mapping-icone-case-aucune {
  grid-column: 1 / -1;
  width: auto;
  height: auto;
  padding: var(--espace-2xs);
  color: var(--gray-4);
}

/* ---------- Export PDF (impression navigateur) ---------- */

@media print {
  .app-header,
  .dossier-tabs,
  .toolbar,
  .cycles-nav,
  .disclaimer {
    display: none !important;
  }

  body, .app-main {
    margin: 0;
    padding: 0;
  }

  /* La coquille de l'ecran se cale sur la fenetre et empile ses blocs en flex.
     Une feuille n'a pas de fenetre, et un conteneur flex se coupe mal entre
     deux pages : le corps redevient un bloc ordinaire pour l'export. */
  body {
    display: block;
    min-height: 0;
  }

  /* Le sol teinte est celui de l'ecran. Une feuille de papier n'a pas de sol,
     et le navigateur ne peint pas les fonds sans « Graphiques d'arriere-plan »
     -- mais la case existe, et celui qui la coche pour garder les couleurs de
     ses tableaux teinterait du meme geste chaque page de l'export. */
  body { background: #fff; }

  .tree-table-wrap {
    overflow: visible;
  }

  .cycle-section {
    break-inside: avoid;
  }

  .tree-table {
    font-size: 9pt;
  }
}

/* ---------- Controle d'audit (3 etats, carrousel au clic) ---------- */
/* non controle (neutre, defaut) | valide (vert) | probleme (orange). Toute
   la zone cliquable (ligne, en-tete de cycle, en-tete "valider l'ecriture")
   fait avancer l'etat d'un cran a chaque clic. */

.controle-clickable { cursor: pointer; }

.modal-table tr.controle-clickable:hover > td { background: var(--gray-1); }

/* Compte dont le programme de travail a fait le tour : le meme vert que celui
   qu'on pose au clic, « comme quand on le valide quand on clique dessus »
   (ticket du 28 aout 2026). Pose par le frontend sur la ligne du compte quand
   toutes les questions qui le regardent sont realisees, sans objet ou non
   applicables (voir appliquerVertsDuProgramme).

   Ecrit AVANT les regles [data-controle] qui suivent, et c'est tout ce qui
   fait la hierarchie : a specificite egale, la derniere l'emporte. Un compte
   marque « probleme » a la main reste donc orange, meme quand ses controles
   sont tous repondus -- ce qu'on a pointe soi-meme a le dernier mot. */
.tree-table tr[data-controle-programme="valide"] > td { background: var(--controle-valide-bg); }
.tree-table tbody tr[data-controle-programme="valide"]:hover > td {
  background: var(--controle-valide-bg-hover);
}
.tree-table tr[data-controle-programme="valide"] > td:first-child {
  box-shadow: inset 4px 0 0 var(--green);
}

/* Ligne dont l'etat est pose : toute la ligne se teinte legerement (vert /
   orange) + un liseré plus marque a gauche, pour un reperage tres visuel. Le
   fond s'applique a chaque cellule (les tr n'acceptent pas background-color de
   maniere fiable derriere border-collapse) et prime sur le survol. */
.tree-table tr[data-controle="valide"] > td,
.sources-table tr[data-controle="valide"] > td,
.modal-table tr[data-controle="valide"] > td { background: var(--controle-valide-bg); }
.tree-table tr[data-controle="probleme"] > td,
.sources-table tr[data-controle="probleme"] > td,
.modal-table tr[data-controle="probleme"] > td { background: var(--controle-probleme-bg); }

.tree-table tbody tr[data-controle="valide"]:hover > td,
.sources-table tbody tr[data-controle="valide"]:hover > td,
.modal-table tr[data-controle="valide"]:hover > td { background: var(--controle-valide-bg-hover); }
.tree-table tbody tr[data-controle="probleme"]:hover > td,
.sources-table tbody tr[data-controle="probleme"]:hover > td,
.modal-table tr[data-controle="probleme"]:hover > td { background: var(--controle-probleme-bg-hover); }

/* Liseré gauche marque sur la premiere cellule de la ligne. */
.tree-table tr[data-controle="valide"] > td:first-child,
.sources-table tr[data-controle="valide"] > td:first-child,
.modal-table tr[data-controle="valide"] > td:first-child { box-shadow: inset 4px 0 0 var(--green); }
.tree-table tr[data-controle="probleme"] > td:first-child,
.sources-table tr[data-controle="probleme"] > td:first-child,
.modal-table tr[data-controle="probleme"] > td:first-child { box-shadow: inset 4px 0 0 var(--orange); }

/* Tableau d'un cycle entier valide / probleme : cadre + en-tete colores, sans
   toucher les lignes internes (qui gardent leur propre etat). Applique sur la
   .cycle-section via data-controle-cycle pose par le frontend.

   L'anneau reste -- c'est lui qui donne au cadre colore son epaisseur, et un
   etat de controle se voit de loin ou ne sert a rien. L'ombre portee, non :
   ce tableau est desormais dans la tuile de son cycle, et ce qui est dans une
   tuile ne flotte pas (voir `.cycle-section > .tree-table-wrap`). */
.cycle-section[data-controle-cycle="valide"] .tree-table-wrap {
  border-color: var(--green);
  box-shadow: 0 0 0 1px var(--green);
}
.cycle-section[data-controle-cycle="valide"] .tree-table thead th {
  background: var(--controle-valide-bg-hover);
  color: var(--green-dark);
}
.cycle-section[data-controle-cycle="valide"] .cycle-section-title .icon { color: var(--green); }

.cycle-section[data-controle-cycle="probleme"] .tree-table-wrap {
  border-color: var(--orange);
  box-shadow: 0 0 0 1px var(--orange);
}
.cycle-section[data-controle-cycle="probleme"] .tree-table thead th {
  background: var(--controle-probleme-bg-hover);
  color: var(--orange-dark);
}
.cycle-section[data-controle-cycle="probleme"] .cycle-section-title .icon { color: var(--orange); }

/* Colonne de controle dans les modales. */
.modal-table .controle-col,
.modal-table .controle-cell,
.sources-table .controle-col,
.sources-table .controle-cell {
  width: 52px;
  text-align: center;
  padding-left: var(--espace-2xs);
  padding-right: var(--espace-2xs);
  white-space: nowrap;
}

/* Le Juridique a eu 66 px ici, pour deux boutons : la pastille de pointage et
   le commentaire. Le second n'y est plus -- une ligne de zone de fichiers ne
   passe pas par `rendreClickableControle`, qui est le seul endroit qui pose ce
   bouton --, et la colonne restait large de quatorze pixels de plus que celle
   du Comptable, du Cabinet et de la Conso pour un bouton unique. Les quatre
   zones sont le meme gabarit : elles reprennent donc la largeur commune
   (ticket du 9 septembre 2026). Le jour ou le commentaire revient, la regle
   revient avec lui, et sur la classe de zone plutot que sur un identifiant. */

/* Colonne de selection multiple, detail d'un compte : une case a cocher par
   ligne, independante du controle individuel porte par controle-cell. */
.modal-table .selection-col,
.modal-table .selection-cell {
  width: 32px;
  text-align: center;
  padding-left: var(--espace-2xs);
  padding-right: 0;
}

.selection-checkbox {
  width: 16px;
  height: 16px;
  margin: 0;
  cursor: pointer;
  accent-color: var(--cyan);
}

/* Le bouton « Sélectionner » de l'en-tete du compte, et ce qu'il change.
   Retenu, il s'allume en bleu -- la meme teinte que la surbrillance qu'il
   pose sur les lignes, pour qu'on lise d'un coup ou va le prochain clic. */
/* Plus de `margin-left: auto` : c'est desormais .modal-filters-actions, le
   bloc qui le contient avec la case « Non Lettrées », qui se cale a droite. */
#compte-selection-mode { flex: none; }
#compte-selection-mode[aria-pressed="true"] {
  background: var(--blue);
  color: #fff;
}
#compte-selection-mode[aria-pressed="true"]:hover { background: var(--blue); }

/* Mode actif : la ligne entiere devient la cible, plus seulement les 16 px de
   la case a cocher. Le curseur le dit avant le clic. */
.modal-table.mode-selection tbody tr { cursor: pointer; }

/* Surbrillance bleue d'une ligne retenue. Elle se pose SUR la teinte de
   controle au lieu de la remplacer : pendant qu'on constitue une selection,
   il faut voir a la fois ce qu'on a pris et l'etat de ce qu'on a pris. Le
   bleu effacait la teinte, et une ligne selectionnee ne disait plus si elle
   etait validee ou en probleme -- or c'est justement ce qu'on va changer
   depuis la barre de selection.

   Deux couches de fond plutot qu'une seule couleur : la premiere valeur de
   `background` est peinte au-dessus des suivantes, donc le bleu se superpose
   a la teinte et les deux se lisent. Une couleur melangee a la main aurait
   fallu la recalculer pour chaque etat. */
.modal-table tr.ligne-selectionnee > td,
.modal-table tr.ligne-selectionnee:hover > td {
  /* Un cran plus soutenu que --blue-pale : les lignes de solde de cloture
     portent deja un fond pale, et une selection doit s'en distinguer sans
     qu'on ait a comparer deux teintes voisines. */
  background: rgba(59, 111, 214, .16);
}
.modal-table tr.ligne-selectionnee[data-controle="valide"] > td,
.modal-table tr.ligne-selectionnee[data-controle="valide"]:hover > td {
  background:
    linear-gradient(rgba(59, 111, 214, .16), rgba(59, 111, 214, .16)),
    var(--controle-valide-bg-hover);
}
.modal-table tr.ligne-selectionnee[data-controle="probleme"] > td,
.modal-table tr.ligne-selectionnee[data-controle="probleme"]:hover > td {
  background:
    linear-gradient(rgba(59, 111, 214, .16), rgba(59, 111, 214, .16)),
    var(--controle-probleme-bg-hover);
}

/* Le lisere gauche dit la meme chose en plus franc : bleu sur les quatre
   premiers pixels, puis la couleur de l'etat sur les quatre suivants. Deux
   ombres internes empilees -- la premiere est dessinee par-dessus la
   seconde, qui deborde donc de quatre pixels a sa droite. */
.modal-table tr.ligne-selectionnee > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue);
}
.modal-table tr.ligne-selectionnee[data-controle="valide"] > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue), inset 8px 0 0 var(--green);
}
.modal-table tr.ligne-selectionnee[data-controle="probleme"] > td:first-child {
  box-shadow: inset 4px 0 0 var(--blue), inset 8px 0 0 var(--orange);
}

/* Barre flottante recapitulant la selection en cours (nombre de lignes,
   moyenne et total du solde) avec un switch pour poser en un geste le meme
   controle (vert/orange/neutre) sur toutes les lignes cochees. */
.selection-bar {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  z-index: 950;
  display: flex;
  align-items: center;
  gap: var(--espace-xl);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--espace-sm) var(--espace-lg);
  max-width: calc(100vw - 2rem);
}

/* Sans cette regle, `display: flex` ci-dessus l'emporte sur le
   `[hidden] { display: none }` de la feuille du navigateur : la barre restait
   affichee apres avoir tout decoche, avec le dernier compte lu ("1 ligne
   selectionnee" alors que plus rien ne l'etait). */
.selection-bar[hidden] { display: none; }

.selection-bar-count {
  font-size: var(--fs);
  color: var(--gray-6);
  white-space: nowrap;
}

.selection-bar-stats {
  display: flex;
  gap: var(--espace-lg);
  padding-left: var(--espace-lg);
  border-left: 1px solid var(--gray-3);
}

.selection-bar-stat {
  display: flex;
  flex-direction: column;
  gap: 1px;
  white-space: nowrap;
}

.selection-bar-stat-label {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-serre);
  color: var(--gray-4);
}

.selection-bar-stat-value {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
  font-variant-numeric: tabular-nums;
}

.selection-bar-switch {
  padding-left: var(--espace-lg);
  border-left: 1px solid var(--gray-3);
  display: flex;
  align-items: center;
}

/* La marque posee sur les lignes cochees : neutre, valide, a verifier. Trois
   carres, comme l'avancement d'un exercice et le filtre d'etat : forme et
   taille sont posees avec eux, plus haut. Ce selecteur-ci a de particulier
   qu'il peut n'allumer aucun carre : une selection panachee (une ligne verte,
   une orange) n'a pas d'etat commun a designer, et en designer un mentirait
   sur ce qui est pointe. Le rang reste alors entierement eteint, ce qu'un
   pouce glissant ne savait pas montrer autrement qu'en disparaissant. */
/* Chaque carre porte la couleur de son etat en permanence, comme le point
   orange et le point vert du selecteur d'avancement : c'est la teinte, pas
   l'icone, qui dit d'un coup d'oeil lequel des trois pose le vert. Ils
   etaient tous gris jusqu'a etre choisis, si bien que le rang eteint --
   c'est-a-dire le cas normal, celui d'une selection panachee -- ne
   distinguait plus le valide du a-verifier. Le carre non retenu reste
   attenue par l'opacite .45 posee avec la forme commune. */
.selection-bar-seg[data-etat="non"] { color: var(--gray-5); }
.selection-bar-seg[data-etat="valide"] { color: var(--green); }
.selection-bar-seg[data-etat="probleme"] { color: var(--orange); }

/* Seul cas ou l'opacite reste posee sur le carre entier, bordure comprise :
   un bouton qu'on ne peut pas actionner n'a pas a se delimiter comme les
   autres, c'est meme ce qui doit le distinguer d'eux. */
.selection-bar-seg:disabled { opacity: .25; cursor: not-allowed; }

.selection-bar-seg .icon { width: var(--icon-sm); height: var(--icon-sm); }

.selection-bar-seg:not(:disabled):hover { --seg-voile: .85; }

.controle-pill[data-value="non"] .selection-bar-seg[data-etat="non"] {
  --seg-voile: 1;
  border-color: var(--gray-4);
  background: var(--gray-1);
}

.controle-pill[data-value="valide"] .selection-bar-seg[data-etat="valide"] {
  --seg-voile: 1;
  border-color: var(--green);
  background: var(--green-pale);
  color: var(--green-dark);
}

.controle-pill[data-value="probleme"] .selection-bar-seg[data-etat="probleme"] {
  --seg-voile: 1;
  border-color: var(--orange);
  background: var(--orange-pale);
  color: var(--orange-dark);
}

.selection-bar-seg[data-etat="valide"]:not(:disabled):hover { color: var(--green-dark); }
.selection-bar-seg[data-etat="probleme"]:not(:disabled):hover { color: var(--orange-dark); }

/* Bouton commentaire, porte par chaque cible de controle (cycle / sous-total
   / compte / ligne). Discret par defaut, ne se revele qu'au survol de la
   ligne/en-tete ou quand un commentaire est deja pose. */
.controle-commentaire-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: var(--espace-xs);
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--gray-4);
  cursor: pointer;
  vertical-align: middle;
  opacity: .35;
  flex: none;
}

.controle-cell .controle-commentaire-btn { margin-left: 0; }

/* La pastille de pointage d'un document juridique.
   Trois etats, comme un cycle ou un compte : rien (gris), validé (vert), à
   vérifier (orange). Le gris est le point du dispositif : un etat neutre
   invisible ne se distingue pas d'une absence d'etat, et c'est ce qui faisait
   croire que le juridique n'avait pas de pointage.

   Elle partage sa cellule avec le bouton de commentaire : meme boite de 20px,
   meme alignement vertical, meme fond au survol. Ecrite d'abord en
   inline-block a la taille du dessin, elle ne tombait pas sur la meme ligne
   de base que son voisin et les deux se touchaient dans une colonne trop
   etroite pour eux -- deux boutons cote a cote, dessines chacun a sa facon. */
.controle-pastille {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  vertical-align: middle;
  cursor: pointer;
  color: var(--gray-4);
  opacity: .55;
  flex: none;
  transition: opacity .12s var(--ease), background-color .12s var(--ease);
}
/* L'ecart avec le bouton de commentaire, quand les deux sont la. Le bouton
   seul (lignes d'ecriture, detail d'un compte) garde sa marge nulle. */
.controle-cell .controle-pastille + .controle-commentaire-btn { margin-left: var(--espace-2xs); }

.controle-pastille:hover { opacity: 1; background: var(--gray-1); }
.controle-pastille .icon { width: var(--icon); height: var(--icon); }
/* Sans marque : le contour vert n'a pas lieu d'etre, le triangle non plus. */
.controle-pastille .pastille-probleme { display: none; }

/* Comme le bouton de commentaire : survoler la ligne suffit a rendre les deux
   pleinement lisibles, sans avoir a viser. */
.controle-clickable:hover .controle-pastille { opacity: 1; }

tr[data-controle="valide"] .pastille-valide { color: var(--green); }
tr[data-controle="valide"] .controle-pastille { opacity: 1; }
tr[data-controle="probleme"] .pastille-probleme { color: var(--orange); display: inline-block; }
tr[data-controle="probleme"] .pastille-valide { display: none; }
tr[data-controle="probleme"] .controle-pastille { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .controle-pastille { transition: none; }
}

.controle-commentaire-btn .icon { width: var(--icon-sm); height: var(--icon-sm); }

.controle-clickable:hover .controle-commentaire-btn,
.controle-commentaire-btn:hover,
.controle-commentaire-btn.a-commentaire {
  opacity: 1;
}

.controle-commentaire-btn:hover { color: var(--cyan-dark); background: var(--cyan-pale); }

.controle-commentaire-btn.a-commentaire { color: var(--cyan-dark); }

/* Bouton justificatif (trombone), a cote du bouton commentaire et dessine
   comme lui -- meme boite, meme discretion, meme reveil au survol de la ligne.
   « Il faut pouvoir deposer un justificatif a une ligne d'ecriture et/ou une
   ecriture » (demande du 26 aout 2026) : deux gestes voisins sur la meme
   ligne, donc deux boutons de la meme famille. Ce qui les distingue est
   l'icone, et la teinte une fois quelque chose de pose : cyan pour un mot
   ecrit, violet pour une piece deposee. Le violet n'a pas de barreau sombre
   dans l'echelle, et n'en reclame pas ici : le trombone allume se lit deja
   sur le fond blanc d'une ligne de tableau. */
.controle-justificatif-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: var(--espace-2xs);
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--gray-4);
  cursor: pointer;
  vertical-align: middle;
  opacity: .35;
  flex: none;
}

.controle-justificatif-btn .icon { width: var(--icon-sm); height: var(--icon-sm); }

.controle-clickable:hover .controle-justificatif-btn,
.controle-justificatif-btn:hover,
.controle-justificatif-btn.a-justificatif {
  opacity: 1;
}

.controle-justificatif-btn:hover { color: var(--purple); background: var(--purple-pale); }

/* Une piece posee : la teinte, et le nombre ecrit a cote du trombone.
   « En ouvrant l'ecriture, je dois pouvoir voir que cette ligne a
   justificatif » (suivi du 26 aout 2026) : la teinte seule ne repondait pas --
   un trombone violet de 20 px parmi des trombones gris ne se remarque pas
   quand on cherche laquelle des six lignes porte la facture. Le bouton
   s'elargit alors juste ce qu'il faut ; la colonne de controle n'a pas de
   largeur imposee (table-layout auto), elle suit. */
.controle-justificatif-btn.a-justificatif {
  color: var(--purple);
  width: auto;
  min-width: 20px;
  padding: 0 var(--espace-2xs);
  gap: var(--espace-3xs);
}

.controle-justificatif-compte {
  font-size: var(--fs-3xs);
  font-weight: 700;
  line-height: 1;
}

/* Sauf sur un compte. « Que le trombone au niveau du compte ne soit pas en
   gras, puisque le compte peut etre justifie par plusieurs ecritures et
   plusieurs justificatifs » (suivi du 27 aout 2026).
   Une piece posee sur une ligne dit que cette ligne-la est justifiee : c'est
   un fait clos, et le violet plein le dit bien. Une piece posee sur un compte
   n'en couvre qu'une part -- les autres justificatifs du compte sont sur ses
   ecritures --, et le meme violet gras la faisait lire comme un compte
   entierement couvert. Le trombone reste donc dans le gris du texte et le
   nombre perd sa graisse : on voit qu'il y a quelque chose, on ne lit pas que
   tout est fait. Le geste, lui, ne bouge pas -- rattacher une piece a un
   compte reste possible. */
.controle-justificatif-btn[data-just-type="compte"].a-justificatif { color: var(--gray-5); }

.controle-justificatif-btn[data-just-type="compte"] .controle-justificatif-compte {
  font-weight: 500;
}

/* La couverture d'un compte, lue depuis la premiere page de l'Analyse : les
   pieces posees sur le compte, et le rapport de ses lignes justifiees (ticket
   du 10 septembre 2026, « l'affichage doit rester tres synthetique »).

   Derriere l'intitule du compte, en petit et en gris : la ligne se lit d'abord
   pour son numero et son solde, et ces deux nombres ne doivent pas la disputer.
   Le vert du complet est la seule chose qui accroche l'oeil, parce que c'est la
   seule qu'on cherche en parcourant deux cents comptes. */
.compte-couverture {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-left: var(--espace-sm);
  font-size: var(--fs-xs);
  color: var(--gray-4);
  white-space: nowrap;
}

.compte-couverture-item {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-3xs);
  font-variant-numeric: tabular-nums;
}

.compte-couverture-item > .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

/* Ce qui existe se teinte, ce qui manque reste gris : c'est la meme regle que
   les trois compteurs de l'en-tete, juste dessous. */
.compte-couverture-item[data-vide="0"] { color: var(--purple); font-weight: 600; }
.compte-couverture-item[data-complet="1"] { color: var(--green); }

/* Ouvrir toutes les pieces du compte a la suite (ticket du 10 septembre 2026).
   Au bout des deux nombres, a la taille de la ligne : c'est un geste offert au
   passage, pas une commande qui doit se voir de loin. */
.compte-liasse-btn .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

.compte-couverture .compte-liasse-btn { color: var(--gray-4); }
.compte-couverture .compte-liasse-btn:hover { color: var(--purple); }

/* Les trois compteurs de justificatifs de l'en-tete d'un compte analyse
   (ticket du 10 septembre 2026) : combien de pieces le compte porte, et a quel
   rang chacune est posee -- le compte entier, une ecriture, une seule ligne.

   Un bloc de lecture, pas un bouton : rien ne s'y clique, la piece se depose
   la ou elle se pose deja. D'ou le cadre gris et non la teinte des pieces, que
   les nombres gardent pour eux. */
.compte-justificatifs {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-right: var(--espace-md);
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  flex: none;
}

.compte-justificatifs > .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
  flex: none;
}

.compte-justificatifs-item {
  display: inline-flex;
  align-items: baseline;
  gap: var(--espace-3xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  white-space: nowrap;
}

/* Un filet entre deux rangs : trois nombres colles se lisent comme un seul. */
.compte-justificatifs-item + .compte-justificatifs-item {
  padding-left: var(--espace-xs);
  border-left: 1px solid var(--gray-3);
}

.compte-justificatifs-nombre {
  font-weight: 600;
  color: var(--purple);
}

/* Zero se lit -- « aucune piece » est une reponse --, mais ne se met pas en
   avant : la teinte des justificatifs est reservee a ce qui existe. */
.compte-justificatifs-item[data-vide="1"] .compte-justificatifs-nombre {
  font-weight: 500;
  color: var(--gray-4);
}

/* Le trombone de l'ecriture entiere, dans l'en-tete de sa fenetre : il n'est
   pas porte par une ligne, donc rien ne le revele au survol -- il se montre
   d'emblee, avec le mot qui dit ce qu'il fait. */
.ecriture-justificatif {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-left: auto;
  margin-right: var(--espace);
}

.ecriture-justificatif-label {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.ecriture-justificatif .controle-justificatif-btn { opacity: 1; }

/* Une piece dans le volet : son nom, et le trombone qui l'annonce. Le nom ouvre
   la meme fenetre de lecture que partout ailleurs.

   PLUS DE POIDS A COTE DU NOM (ticket du 12 septembre 2026) : « supprime [...]
   la taille du fichier ». Savoir qu'une facture pese 240 Ko n'a jamais aide a
   verifier une ecriture, et le nom qu'on cherche s'en trouvait repousse d'une
   parenthese. */
.justificatif-lien {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  /* Il prend la place qui reste sur la ligne, entre le cycle et les gestes :
     c'est lui qu'on lit, les deux autres se reconnaissent a leur dessin. */
  flex: 1;
  min-width: 0;
  font-size: var(--fs-sm);
  color: var(--cyan-dark);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.justificatif-lien:hover { text-decoration: underline; }

.justificatif-lien .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  flex: none;
}

/* La fleche qui passe une piece de la ligne a l'ecriture entiere, posee dans
   l'en-tete de la piece a cote de la corbeille et dessinee comme elle -- meme
   boite, meme discretion. Sa teinte au survol est celle des justificatifs, le
   violet : c'est un rattachement, pas un retrait.

   « Je devrais pouvoir mettre dans un deuxieme temps comme justificatif de
   l'ecriture » (suivi du 26 aout 2026). */
.justificatif-rattacher-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--gray-4);
  cursor: pointer;
}

.justificatif-rattacher-btn .icon { width: var(--icon-sm); height: var(--icon-sm); }
.justificatif-rattacher-btn:hover { color: var(--purple); background: var(--purple-pale); }

/* « Choisir dans le mandat », sous le bouton de depot du volet : un lien, pas
   un second bouton pleine largeur -- c'est la seconde provenance de la meme
   piece, pas un second geste de meme poids. */
.justificatif-du-mandat-btn { align-self: center; }

/* LE VOLET DES JUSTIFICATIFS TIENT EN UNE LIGNE PAR PIECE.

   « Quand deux justificatifs de compte sont ouverts, optimise l'affichage pour
   faire tenir les informations sur une seule ligne. Place "Choisir un mandat"
   et "Deposer un fichier" sur la meme ligne, et affiche l'icone de la poubelle
   en rouge » (ticket du 13 septembre 2026).

   Un nom rendu par la ronde de nommage fait facilement cinquante caracteres :
   avec `overflow-wrap: anywhere`, deux pieces prenaient six lignes, et le volet
   descendait sous le bord de l'ecran sur un compte charge. Le nom se coupe donc
   aux points de suspension, entier dans son infobulle. */
.justificatif-popover .justificatif-lien {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  overflow-wrap: normal;
  /* Le texte du lien deborde de son conteneur en flex sans cette ligne : c'est
     `display: block` qui fait travailler l'ellipse, l'icone passant en tete de
     ligne comme un puce. */
  display: block;
}

.justificatif-popover .justificatif-lien .icon { vertical-align: -.18em; }

/* Les deux gestes cote a cote, le bouton plein au bord. Le volet des
   commentaires, lui, garde sa colonne : son champ de saisie prend toute la
   largeur et son bouton se pose dessous. */
.justificatif-popover .justificatif-popover-form {
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-2xs);
}

.justificatif-popover .justificatif-popover-form .commentaire-add-btn {
  align-self: auto;
}

/* Et leurs libelles d'un seul tenant : « Deposer un fichier » plie en deux
   rendrait a la hauteur ce que la ligne commune vient de gagner. */
.justificatif-popover .justificatif-popover-form button { white-space: nowrap; }

/* La corbeille en rouge des le repos, et non au seul survol : « affiche l'icone
   de la poubelle en rouge ». Elle retire une piece d'un mandat, ce que le gris
   des gestes ordinaires ne disait pas. Le fond pale reste pour le survol. */
.justificatif-popover .commentaire-delete-btn { color: var(--red); }

/* CE QUE LA PIECE JUSTIFIE, POUR L'EN DETACHER (ticket du 13 septembre 2026).

   Le meme volet que celui du trombone -- meme boite, meme liste, meme
   corbeille --, range par cycle : un titre de cycle, ses accroches dessous. Le
   titre porte le logo du cycle et, quand il y a plus d'une accroche a retirer,
   le geste qui les retire toutes. */
.dissociation-groupe {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  padding: var(--espace-2xs) 0 var(--espace-3xs);
  border-top: 1px solid var(--gray-2);
}

/* Le premier titre ouvre la liste : un trait au-dessus de lui separerait le
   volet de son en-tete, qui porte deja le sien. */
.dissociation-groupe:first-child { border-top: none; padding-top: 0; }

.dissociation-groupe-nom {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--gray-5);
  text-transform: uppercase;
  letter-spacing: .04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dissociation-groupe-btn { flex: none; white-space: nowrap; }

/* Le nom de la cible sur une seule ligne, coupe aux points de suspension :
   « Compte 471 0000  Compte d'attente a ventiler » et le nom entier au survol.
   Meme regle que le nom d'une piece dans le volet d'a cote. */
.dissociation-cible {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Lacher un fichier sur une ligne, ou sur l'en-tete d'une fenetre d'ecriture.
   « Je dois pouvoir faire un simple glisser-deposer pour deposer un
   justificatif d'une ligne ou d'une ecriture et pas forcement aller dans le
   trombone » (demande du 27 aout 2026).

   `depot-cible` est pose par depot-fichier.js, et son dessin d'origine -- un
   liseré en pointille autour du bloc, decale de .3rem -- vaut pour un cadre
   d'image, pas pour une ligne de tableau : le decalage empiete sur les lignes
   voisines et le fond ne se voit pas, les cellules portant deja le leur (teinte
   de pointage, ligne de cloture). La ligne s'allume donc par ses cellules, et
   son liseré rentre a l'interieur. */
tr.depot-cible.dragover {
  outline-offset: -2px;
}

tr.depot-cible.dragover > td {
  background: var(--cyan-light);
}

/* L'en-tete d'une fenetre d'ecriture : la cible de l'ecriture entiere. Le
   liseré rentre aussi -- l'en-tete touche le bord arrondi de la fenetre. */
.modal-header.depot-cible.dragover {
  outline-offset: -3px;
}

/* Ce que fait la fleche, ecrit une fois sous la liste : une icone de 12 px
   dans un en-tete de piece ne dit pas d'elle-meme qu'elle la promeut. */
.justificatif-popover-note {
  margin: 0;
  padding: 0 var(--espace) var(--espace-sm);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Le cycle d'audit qu'une piece justifie, dans l'en-tete de la piece :
   « quand un justificatif a ete associe a une ligne ou une ecriture il doit
   avoir l'icone du cycle ou des cycles qu'il a justifie ainsi que sa couleur
   (orange, vert, ...) » (demande du 27 aout 2026). La teinte est celle du
   pointage de la cible -- verte quand elle est validee, orange quand elle
   porte un probleme, grise tant qu'elle n'est pas pointee : les memes trois
   etats que les lignes du tableau, avec les memes couleurs. */
.justificatif-cycles {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-3xs);
  color: var(--gray-4);
  flex: none;
}

.justificatif-cycles[data-controle="valide"] { color: var(--green); }
.justificatif-cycles[data-controle="probleme"] { color: var(--orange); }

/* La marque qui ouvre la liste de ce que la piece justifie, pour l'en detacher
   (ticket du 13 septembre 2026). C'est un vrai <button> -- le clavier le
   trouve, et la ligne de la zone laisse passer son clic --, donc il faut lui
   retirer l'habillage que le navigateur donne aux boutons. Sa teinte reste
   celle de la marque et de sa ligne : les regles qui la peignent sont plus
   specifiques, rien n'est repris ici. */
.justificatif-cycles-ouvrable {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.justificatif-cycles-ouvrable:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* La meme marque, devant le nom d'une piece dans une zone de fichiers : elle y
   prend la teinte de sa ligne plutot que la sienne. La ligne porte deja l'etat
   de revue du document, et il est tenu synchronise avec celui de la cible que
   la piece justifie (voir db.propager_controle_justificatifs) : un second
   attribut a mettre a jour aurait fini par dire autre chose que le premier. */
tr[data-controle="valide"] .sources-nom-cell .justificatif-cycles { color: var(--green); }
tr[data-controle="probleme"] .sources-nom-cell .justificatif-cycles { color: var(--orange); }
.sources-nom-cell .justificatif-cycles { margin-right: var(--espace-2xs); }

/* Et la meme marque dans le suivi de l'arrete, devant la pastille de pointage
   (ticket du 12 septembre 2026). Elle y prend la teinte de sa puce, pour la
   meme raison que dans une zone de fichiers : la puce porte deja l'etat de la
   piece, et deux attributs a tenir a jour finissent par se contredire. */
.arrete-cycles { margin-right: var(--espace-3xs); }
[data-controle="valide"] > .arrete-cycles { color: var(--green); }
[data-controle="probleme"] > .arrete-cycles { color: var(--orange); }

/* LA MARQUE « ETAT COMPTABLE » EST VERTE, ET ELLE NE PREND PAS LA TEINTE DE SA
   LIGNE.

   « L'icone "Etat comptable" doit etre verte, de la meme couleur que l'icone
   "Archive comptable" » (suivi du 10 septembre 2026). C'est le meme vert que la
   chemise d'ou ces pieces sortent (`.marque-archives-comptable`), et ce n'est
   pas une coincidence : elles disent la meme chose, l'une sur un rangement,
   l'autre sur la piece.

   Ecrite apres les trois regles ci-dessus, elle les couvre : la marque partage
   la boite des cycles, pas leur teinte. Un cycle change de couleur avec le
   pointage de ce qu'il justifie ; la nature d'une piece, non. */
.piece-etat-comptable,
tr[data-controle="valide"] .sources-nom-cell .piece-etat-comptable,
tr[data-controle="probleme"] .sources-nom-cell .piece-etat-comptable {
  /* PLUS VISIBLE, ET DANS LE MEME VERT.

     « La couleur verte doit egalement etre plus visible » (suivi du
     10 septembre 2026). Ce qui manquait n'etait pas la teinte : c'est celle de
     la chemise d'archives du Comptable, et le suivi precedent demandait
     justement qu'elles soient la meme. Ce qui manquait etait la SURFACE --
     quatorze pixels de trait fin, perdus entre l'icone de format et le nom du
     fichier sur une ligne de tableau.

     Le vert garde donc son barreau, et prend son pale derriere : la gelule se
     voit d'un coup d'oeil en parcourant la colonne, ce que le trait seul ne
     faisait pas. Le meme couple que partout ailleurs dans le produit, une
     teinte et son pale. */
  color: var(--green);
  background-color: var(--green-pale);
  border-radius: var(--radius-xs);
  padding: var(--espace-3xs);
}

/* LA MARQUE « COMPTES INTEGRES A LA CONSOLIDATION », SUR LES PIECES DU DEPOT
   DES FILIALES.

   « Mets un logo qui indique que les comptes de la filiale ont bien ete
   integres » (ticket AMBISTRATE du 21 septembre 2026). Meme gelule que la
   marque « Etat comptable » ci-dessus, pour la meme raison : quatorze pixels de
   trait fin se perdent entre l'icone de format et le nom du fichier, et c'est
   en parcourant la colonne qu'on veut la voir.

   En cyan, la teinte de la chemise ou ces pieces vivent : le vert dit deja une
   piece du Comptable, l'orange et le rouge disent un pointage de revue. Elle ne
   prend donc pas la teinte de sa ligne, comme la marque verte a cote : ce
   qu'elle dit est un fait de la consolidation, pas un etat de revue. */
.piece-filiale-integree,
tr[data-controle="valide"] .sources-nom-cell .piece-filiale-integree,
tr[data-controle="probleme"] .sources-nom-cell .piece-filiale-integree {
  display: inline-flex;
  align-items: center;
  flex: none;
  margin-right: var(--espace-2xs);
  color: var(--cyan-dark);
  background-color: var(--cyan-pale);
  border-radius: var(--radius-xs);
  padding: var(--espace-3xs);
}

/* Le meme cran de plus que le registre de la marque verte : l'organigramme
   porte trois cartouches et deux traits, illisibles a quatorze pixels. */
.piece-filiale-integree-icone {
  width: var(--icon-md);
  height: var(--icon-md);
}

/* Et le dessin d'un cran plus grand DANS la gelule : le registre ouvert porte
   deux pages reglees, qui a quatorze pixels se referment en un pate. */
.piece-etat-comptable .justificatif-cycle-icone {
  width: var(--icon-md);
  height: var(--icon-md);
}

.justificatif-cycle-icone {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

/* D'ou vient une piece que la ligne n'a pas recue elle-meme (demande du
   27 aout 2026) : elle est posee sur l'ecriture, et chacune de ses lignes la
   montre. Sans cette mention, on la croirait deposee ici -- et on chercherait
   le bouton qui la retire, lequel n'existe que sur l'ecriture. */
.justificatif-herite-mention {
  margin: var(--espace-3xs) 0 0;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  font-style: italic;
}

/* Popover de commentaires (plusieurs par cible, horodates, rattaches a leur
   auteur, supprimables individuellement) ouvert au clic sur le bouton
   commentaire. Positionne en absolu (top/left calcules en JS) sous le bouton. */
.commentaire-popover {
  position: absolute;
  z-index: 110;
  width: 320px;
  max-width: calc(100vw - 24px);
  background: #fff;
  /* --radius-md n'a jamais existe : la valeur de repli faisait tout le travail,
     et c'est elle -- dix pixels -- que la premiere reparation a nommee. Nommer
     un repli n'est pas le choisir : les deux autres regles tombees dans le meme
     piege, la fenetre de reglages et le resume des FEC, ont ete rendues a
     --radius-lg, la forme des surfaces flottantes de la feuille. Celle-ci en
     est une aussi -- 320 px de large, un en-tete avec son titre et sa croix, un
     champ, un bouton -- et elle restait seule a dix.

     L'objection ecrite sur `.avatar-noms` (« a cette taille, le grand arrondi
     mangerait la moitie de la premiere lettre ») ne la vise pas : cette
     fenetre-la fait trois cent vingt pixels et son texte commence sous
     l'en-tete, pas dans l'angle. */
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--gray-3);
  animation: modal-pop-in .15s var(--ease);
}

.commentaire-popover-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--espace-sm) var(--espace);
  border-bottom: 1px solid var(--gray-3);
  font-weight: 600;
  font-size: var(--fs);
}

.commentaire-popover-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 999px;
  background: none;
  color: var(--gray-5);
  cursor: pointer;
}

.commentaire-popover-close .icon { width: var(--icon-sm); height: var(--icon-sm); }
.commentaire-popover-close:hover { background: var(--gray-1); color: var(--gray-6); }

.commentaire-popover-list {
  max-height: 260px;
  overflow-y: auto;
  padding: var(--espace-sm) var(--espace);
}

.commentaire-popover-vide {
  color: var(--gray-5);
  font-size: var(--fs-sm);
  margin: var(--espace-2xs) 0;
}

.commentaire-item {
  padding: var(--espace-sm) 0;
  border-bottom: 1px solid var(--gray-2);
}

.commentaire-item:last-child { border-bottom: none; }

.commentaire-item-header {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

.commentaire-avatar {
  --avatar-d: 20px;
}

.commentaire-auteur-nom {
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.commentaire-date {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.commentaire-delete-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--gray-4);
  cursor: pointer;
}

.commentaire-delete-btn .icon { width: var(--icon-sm); height: var(--icon-sm); }
.commentaire-delete-btn:hover { color: var(--red); background: var(--red-pale); }

.commentaire-texte {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs);
  color: var(--black);
  white-space: pre-wrap;
  word-break: break-word;
}

.commentaire-popover-form {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
  padding: var(--espace-sm) var(--espace) var(--espace);
  border-top: 1px solid var(--gray-3);
}

/* La fenetre de commentaire reprend le champ d'un ticket, en plus court : elle
   flotte au-dessus de la page, et ce qu'on vient y lire est la liste des
   commentaires posee au-dessus du champ.

   Ce bloc reglait aussi la taille du micro, celle de son icone et les quatre
   cotes du padding. Aucune de ces neuf declarations n'a jamais rien fait :
   .ticket-widget-texte et .ticket-widget-mic ont exactement la meme
   specificite et sont ecrits cent-soixante lignes plus bas, donc ils
   gagnaient, en silence. Le champ demandait 44px de haut et en mesurait 104,
   le micro demandait 24px et en mesurait 28, l'icone demandait --icon-sm et
   rendait --icon. Une variante qui ne tient que par l'ordre des lignes n'est
   pas une variante : celle-ci s'accroche a son enveloppe, donc elle gagne ou
   qu'elle soit ecrite, et elle ne redit plus ce que la base dit deja. */
.commentaire-popover-champ-texte .ticket-widget-texte {
  min-height: var(--mic-place);
  max-height: 8rem;
}

.commentaire-popover-mic-statut {
  margin-top: 0;
  font-size: var(--fs-2xs);
}

.commentaire-popover-form .commentaire-add-btn {
  align-self: flex-end;
  font-size: var(--fs-sm);
  padding: var(--espace-xs) var(--espace);
}

/* Action "valider l'ecriture" dans l'en-tete du detail d'ecriture : toute la
   zone est cliquable (carrousel non -> valide -> probleme -> non) et se
   teinte selon l'etat commun des lignes de l'ecriture. */
.ecriture-valider {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-left: auto;
  margin-right: var(--espace-md);
  padding: var(--espace-xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background .12s var(--ease);
}

.ecriture-valider:hover { background: var(--gray-1); }

.ecriture-valider[data-controle="valide"] { background: var(--controle-valide-bg); }
.ecriture-valider[data-controle="valide"]:hover { background: var(--controle-valide-bg-hover); }
.ecriture-valider[data-controle="valide"] .ecriture-valider-label { color: var(--green-dark); }

.ecriture-valider[data-controle="probleme"] { background: var(--controle-probleme-bg); }
.ecriture-valider[data-controle="probleme"]:hover { background: var(--controle-probleme-bg-hover); }
.ecriture-valider[data-controle="probleme"] .ecriture-valider-label { color: var(--orange-dark); }

.ecriture-valider-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

/* Widget flottant de tickets (suggestion de modification), present sur
   toutes les pages authentifiees. */
.ticket-widget {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 1000;
}

.ticket-widget-toggle {
  width: 52px;
  height: 52px;
  border-radius: 999px;
  border: none;
  background: var(--cyan);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow-lg);
  transition: transform .1s, background .15s;
}

.ticket-widget-toggle:hover { background: var(--cyan-dark); transform: translateY(-2px); }
.ticket-widget-toggle .icon { width: var(--icon-xl); height: var(--icon-xl); }

.ticket-widget-panel {
  position: absolute;
  right: 0;
  bottom: 64px;
  width: 320px;
  background: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--gray-3);
  overflow: hidden;
}

.ticket-widget-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--espace) var(--espace-md);
  background: var(--gray-1);
  border-bottom: 1px solid var(--gray-3);
  font-weight: 600;
  font-size: var(--fs-md);
  color: var(--gray-6);
}

.ticket-widget-close {
  border: none;
  background: none;
  cursor: pointer;
  font-size: var(--fs-h2);
  line-height: 1;
  color: var(--gray-5);
}

/* Le corps etait une pile plate : le champ de texte, trois cases, la zone de
   depot, la liste des fichiers et un renvoi, separes par un seul et meme
   ecart de 9,59 px du haut en bas. Neuf elements au meme rythme, quatre
   natures differentes -- c'est ce que la demande du 30 aout 2026 appelle
   « l'effet zone de texte un peu fouillee avec plein de boutons ».

   Ils sont maintenant quatre sous-zones : ce qu'on dit, comment on veut que
   ce soit traite, ce qu'on joint, et ce que le site ajoute tout seul.
   L'ecart entre elles vaut 16 px, les ecarts a l'interieur 6,4 et 9,6 : la
   frontiere se lit plus fort que le contenu, comme les 17 px de la fenetre de
   lecture contre ses 4 px. */
.ticket-widget-body {
  padding: var(--espace-md);
  display: flex;
  flex-direction: column;
  gap: var(--espace-md);
}

/* Sur telephone le corps devient la partie qui defile d'une feuille (mobile.css
   lui donne flex: 1 1 auto et overflow-y: auto). Sans ce garde-fou ses enfants,
   devenus des elements flex, se laisseraient comprimer pour tenir dans la
   hauteur disponible au lieu de la faire defiler. */
.ticket-widget-body > * { flex: none; }

/* Les sous-zones du panneau, sans cadre. Elles n'existent que pour tenir
   ensemble un element et son satellite -- le champ et l'etat de la dictee, la
   case de depot et la liste des fichiers -- de sorte que l'ecart de 16 px
   tombe entre les sous-zones et jamais au milieu d'une. */
.ticket-widget-dire,
.ticket-widget-joindre {
  display: flex;
  flex-direction: column;
}

/* La troisieme sous-zone : trois cases qui disent comment traiter le ticket et
   non ce qu'il raconte, puis la ligne qui passe la main.

   Elle a porte un cadre d'encart -- --gray-2 et --radius-sm sous un panneau en
   --gray-3 et --radius-lg -- pour marquer cette difference de nature. Le cadre
   est parti : un cadre tient un ensemble, et trois cases a cocher dans un
   panneau de 320 px n'en sont pas un. Encadrees, elles pesaient autant que le
   panneau qui les contient, pour trois mots chacune.

   Ce qu'il disait ne se perd pas : les deux sous-zones au-dessus n'ont pas de
   cadre non plus, l'ecart de 16 px les separe deja, et celle-ci reste la
   derniere avant le bouton d'envoi -- sa place dit son role. Le creux part
   avec le cadre : sans trait a longer, il ne faisait plus que decaler les
   cases de la colonne de texte au-dessus d'elles. */
.ticket-widget-options {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* Passer la main ou travailler a plusieurs, des l'ecriture (ticket du
   4 septembre 2026). Quatrieme ligne de l'encart, sous les trois cases : elle
   dit elle aussi comment le ticket sera traite, et non ce qu'il raconte.

   Deroule dans le flux et non en surface flottante, contrairement au meme
   menu sur la carte d'un ticket : le panneau du widget fait 320 px et coupe ce
   qui deborde (`overflow: hidden`), ou un menu pose en absolu se ferait
   trancher. Les rangees, elles, sont exactement celles de la carte
   (`.ticket-card-collaborer-choix`) -- meme dessin, meme coche verte. */
.ticket-widget-personnes {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
}

.ticket-widget-personnes-btn {
  justify-content: flex-start;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
}

/* Les deux verbes tiennent sur une ligne : coupes en deux, ils se lisaient
   comme deux commandes empilees. C'est le resume qui cede la place, puisque
   c'est lui qui varie. */
.ticket-widget-personnes-btn > span:not(.ticket-widget-personnes-resume) {
  white-space: nowrap;
}

/* Ce que le bouton replie dit du choix fait : sans lui, un destinataire retenu
   puis la liste refermee ne se voit plus nulle part. Efface, donc, mais lisible
   -- c'est un rappel, pas une commande. */
.ticket-widget-personnes-resume {
  flex: 1 1 auto;
  min-width: 0;
  text-align: right;
  color: var(--gray-4);
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ticket-widget-personnes-listes {
  display: flex;
  flex-direction: column;
  padding: var(--espace-2xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
}

/* Le titre d'une des deux listes vient du menu de la carte ; en tete de boite,
   sa marge haute ferait un creux que le menu flottant, lui, n'a pas. */
.ticket-widget-personnes-listes > .ticket-card-transfert-menu-titre:first-child {
  margin-top: 0;
}

/* Vides, ces deux-la ne montrent rien et poussent quand meme : la ligne de
   dictee garde ses 6,4 px de marge haute et la liste des fichiers ses 9,6, ce
   qui faisait 19,19 px sous la zone de depot la ou tous les autres ecarts du
   panneau valaient 9,59. Mesure au navigateur le 31 aout 2026. Meme geste que
   `.file-list:empty` et `.upload-status:empty`.

   La regle existait deja, mais pour un seul des cinq porteurs de
   .ticket-widget-mic-statut (`.ticket-card-suivi-mic-statut:empty`, supprimee
   ici). Elle vaut pour les cinq, donc elle s'ecrit sur la classe de base --
   ce qui referme au passage les 19,17 px du meme ecart sur la carte de
   ticket. */
.ticket-widget-mic-statut:empty,
.ticket-widget-fichiers-liste:empty { display: none; }

/* Cinq champs de ce produit portent un bouton de dictee flottant dans leur
   coin bas-droit, et cinq fois la meme question a ete tranchee a l'oeil :
   combien de place reserver a droite pour que le texte ne passe pas sous le
   bouton ? Les reponses etaient 38.4, 41.6, 35.2, 38.4 et 38.4 px. Cinq
   nombres ecrits a la main, dont aucun ne disait qu'il contenait la taille du
   bouton et son retrait.

   Le jour ou mobile.css a porte les micros a --m-tap pour la cible tactile
   (« tout ce qui se clique fait au moins 44px de haut »), aucune des cinq
   reserves n'a suivi : elles ne savaient pas qu'elles en dependaient. Sur
   telephone, les quatre champs ecrivaient donc leur texte SOUS le micro, de 8
   a 13 pixels. C'est mesure au navigateur, pas suppose.

   La relation s'ecrit maintenant une seule fois, ici, sur l'enveloppe : le
   micro declare son diametre et son retrait, le champ en deduit la reserve
   qu'il doit garder a droite et la hauteur minimale qu'il doit tenir. Les deux
   moities ne peuvent plus diverger, parce qu'il n'y en a plus qu'une. Changer
   --mic-taille suffit, et tout suit -- c'est ce que fait mobile.css. */
.ticket-widget-champ-texte,
.ticket-card-suivi-champ {
  --mic-taille: var(--h-sm);
  --mic-retrait: var(--espace-xs);
  --mic-reserve: calc(var(--mic-retrait) + var(--mic-taille) + var(--espace-xs));
  --mic-place: calc(var(--mic-taille) + var(--mic-retrait) * 2);
}

.ticket-widget-champ-texte {
  position: relative;
}

.ticket-widget-texte {
  width: 100%;
  min-height: 6.5rem;
  max-height: 16rem;
  overflow-y: auto;
  resize: vertical;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-sm) var(--mic-reserve) var(--espace-sm) var(--espace-sm);
  font-family: inherit;
  font-size: var(--fs);
  line-height: 1.4;
  color: inherit;
}

.ticket-widget-texte:focus {
  outline: 2px solid var(--cyan-light);
  outline-offset: -1px;
}

.ticket-widget-texte:empty::before {
  content: attr(data-placeholder);
  color: var(--gray-4);
}

/* L'etiquette qui dit le raccourci, dans le coin du champ ou l'on vient de se
   placer. Translucide et sans prise au clic : elle se lit, elle ne se vise
   pas, et le texte qui arrive la fait disparaitre avant de l'atteindre (voir
   voice-dictation.js). Rien de neuf dans la palette -- les trois teintes sont
   celles des champs qu'elle borde. */
.dictee-raccourci {
  position: fixed;
  z-index: 1002;
  pointer-events: none;
  opacity: .45;
  font-family: inherit;
  font-size: var(--fs-xs);
  line-height: 1;
  padding: var(--espace-3xs) var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  color: var(--gray-5);
  white-space: nowrap;
}

.voice-dictation-provisoire {
  color: var(--gray-4);
}

.voice-dictation-traitement {
  opacity: .6;
}

.ticket-widget-mic {
  position: absolute;
  right: var(--mic-retrait);
  bottom: var(--mic-retrait);
  width: var(--mic-taille);
  height: var(--mic-taille);
  border-radius: 999px;
  border: none;
  background: var(--gray-2);
  color: var(--gray-6);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background .15s, color .15s;
}

.ticket-widget-mic .icon {
  width: var(--icon);
  height: var(--icon);
}

.ticket-widget-mic:hover {
  background: var(--gray-3);
}

.ticket-widget-mic-connexion {
  background: var(--gray-3);
  color: var(--gray-5);
}

.ticket-widget-mic-actif {
  background: var(--red);
  color: #fff;
  animation: ticket-widget-mic-pouls 1.4s ease-in-out infinite;
}

.ticket-widget-mic-traitement {
  background: var(--cyan);
  color: #fff;
}

/* Le halo bat au rythme du bouton d'ou il sort, et dans sa couleur. Le bouton
   est peint `var(--red)`, soit 214 69 69 ; l'onde, elle, partait sur un
   211 51 51 -- un rouge plus sourd, absent de la palette. Un halo se lit comme
   la continuation de ce qu'il entoure : deux rouges voisins a trois unites
   d'ecart ne se distinguent pas l'un de l'autre, ils salissent le premier.

   Le second temps ne teinte plus rien du tout -- une onde qui s'eteint est
   transparente, elle n'a pas de couleur --, ce qui retire au passage le seul
   endroit du produit ou une teinte etait ecrite a l'alpha zero. */
@keyframes ticket-widget-mic-pouls {
  0%, 100% { box-shadow: 0 0 0 0 rgba(214, 69, 69, .35); }
  50% { box-shadow: 0 0 0 6px transparent; }
}

.ticket-widget-mic-statut {
  display: block;
  margin-top: var(--espace-xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.ticket-widget-checkbox {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  cursor: pointer;
}

/* Des trois cases, c'est la seule qui change le sort du ticket, et elle ne le
   disait pas : la classe etait posee dans le gabarit sans qu'aucune regle ne
   la porte. Cochee, elle se colore ; decochee, elle reste une case comme les
   deux autres. La couleur seule, pas la graisse : changer la graisse
   recomposerait la ligne a chaque clic. */
.ticket-widget-checkbox-urgent:has(input:checked) {
  color: var(--red-dark);
}

.ticket-widget-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-xs);
  text-align: center;
  /* Le seul creux du produit plus haut que large, et il le reste : le contenu
     de cette case est centre, donc ses cotes ne poussent rien -- seule sa
     hauteur a jamais ete choisie. 14,4 ne tombait sur aucun barreau. */
  padding: var(--espace) var(--espace-sm);
  /* 2 px comme .drop-zone et .chat-depot : les trois cibles de depot du
     produit se dessinent pareil. 1,5 px etait la seule des trois a etre
     arrondie par le navigateur, qui la rendait a 1 px. */
  border: 2px dashed var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  color: var(--gray-5);
  font-size: var(--fs-xs);
  line-height: 1.35;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}

.ticket-widget-dropzone .icon {
  width: var(--icon-md);
  height: var(--icon-md);
  color: var(--gray-4);
}

.ticket-widget-dropzone:hover,
.ticket-widget-dropzone:focus-visible {
  border-color: var(--cyan);
  background: var(--cyan-pale);
}

.ticket-widget-dropzone-actif {
  border-color: var(--cyan);
  background: var(--cyan-light);
}

.ticket-widget-fichiers-liste {
  list-style: none;
  margin: var(--espace-sm) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
}

.ticket-widget-fichier-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  background: var(--gray-2);
  font-size: var(--fs-xs);
}

.ticket-widget-fichier-nom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ticket-widget-fichier-retirer {
  flex: none;
  border: none;
  background: none;
  color: var(--gray-5);
  font-size: var(--fs-xl);
  line-height: 1;
  cursor: pointer;
  padding: 0 var(--espace-2xs);
}

.ticket-widget-fichier-retirer:hover {
  color: var(--red);
}

.ticket-widget-hint {
  font-size: var(--fs-xs);
  color: var(--gray-4);
  margin: 0;
}

.ticket-widget-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
  padding: 0 var(--espace-md) var(--espace-md);
}

.ticket-widget-statut {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Page d'administration des tickets. */
/* UNE SEULE COLONNE, ET C'EST TRANCHE. « Je ne veux qu'une seule colonne dans
   ticket » (suivi du 9 septembre 2026).

   La liste s'ecoulait en colonnes de journal depuis le 9 septembre au matin :
   une carte descendait jusqu'au bas de la colonne, la suivante repartait en
   haut de la suivante, trois colonnes a 2560 et deux a 1920. La mesure disait
   qu'une carte de sept cents pixels ne serre rien et qu'il en tient deux la ou
   une seule laissait sept cents pixels de blanc a sa droite. Elle avait
   raison sur les pixels et tort sur la lecture : une liste de tickets se
   parcourt de haut en bas, et un colonnage impose de remonter en haut de
   l'ecran a chaque fin de colonne. La demande a ete faite deux fois, la
   seconde sans equivoque ; c'est elle qui tranche, pas la mesure.

   Reste de ce passage ce qui vaut toujours : le creux se pose sur la carte et
   non sur la liste, ce qui evite de le poser deux fois le jour ou l'on
   changerait d'avis. */
/* Le pied d'une carte de ticket : le pipeline de statut d'un côté, les
   téléchargements de l'autre, sur la même ligne. « Garde tout sur la même
   ligne » (ticket du 9 septembre 2026) -- ils étaient deux rangées, et une
   carte de colonne a la place des deux : 468 px pour le pipeline, 131 au plus
   pour les téléchargements, dans 696. Ce qui les séparait n'était pas la
   place, c'était qu'ils étaient deux blocs.

   Le creux entre les deux est le plus petit de l'échelle, et c'est mesuré :
   le pipeline fait 603 px et les téléchargements 165, soit 768 dans les 777
   d'une carte à 2560 -- un creux ordinaire de 16 px les faisait passer à 784
   et retomber l'un sous l'autre pour sept pixels.

   La carte prend depuis toute la largeur de la liste (voir `.tickets-list`) :
   la paire y tient partout, et le creux serré ne coûte donc plus rien. `wrap`
   reste pour les fenêtres étroites, où deux boîtes de 768 px ne tiennent
   toujours pas côte à côte. */
.ticket-card-pied {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--espace-2xs);
  margin-top: var(--espace-md);
  /* Le trait qui ouvre la bande des gestes, depuis que les deux cadres sont
     tombes : voir la regle qui suit. Il est ici parce qu'il borde la ligne
     entiere, alors qu'un cadre par bloc bordait chaque groupe de boutons. */
  padding-top: var(--espace);
  border-top: 1px solid var(--gray-2);
}

/* PLUS DE CADRE AUTOUR DES BOUTONS, un seul trait au-dessus d'eux (« faire des
   blocs pour ces boutons est inutile », ticket du 9 septembre 2026).

   Les deux cadres viennent du 30 aout : sept commandes posees a meme le fond
   blanc, sous une conversation qui, elle, a des bulles -- on ne voyait pas ou
   finit ce qu'on lit et ou commence ce qu'on fait. La boite repondait a cela,
   et elle y repondait tant qu'il n'y en avait qu'une, empilee. Depuis que la
   paire est passee sur une seule ligne, il y en a deux, cote a cote, chacune
   serree sur son contenu : elles n'encadrent plus une bande de gestes, elles
   entourent quatre boutons d'un cote et un bouton de l'autre. Un bouton porte
   deja sa propre forme -- le segmente a la sienne, « Synthese (.md) » est une
   pastille --, et l'encadrer une seconde fois ne dit rien de plus.

   Ce qui reste est le trait, porte par le pied lui-meme (voir la regle
   ci-dessus) et non par chacun des deux : il separe ce qu'on lit de ce qu'on
   fait, ce que la boite etait venue faire, sans rien entourer. */
.ticket-card-pied > .ticket-statut-pipeline,
.ticket-card-pied > .ticket-card-telechargements {
  margin-top: 0;
  padding: 0;
  border: 0;
}

.tickets-list {
  display: block;
}

.tickets-list > .ticket-card {
  margin-bottom: var(--espace-md);
}

/* `display: block` ci-dessus l'emporte sur la regle `[hidden]` du navigateur,
   qui ne pose qu'un `display: none` sans specificite. Sans cette ligne, la
   liste ordinaire restait dessinee sous les resultats de recherche : deux
   listes de tickets l'une au-dessus de l'autre, dont une qui ne repondait
   pas a ce qu'on venait de taper. */
.tickets-list[hidden] { display: none; }

.ticket-card {
  border: 1px solid var(--gray-3);
  border-left: 3px solid var(--gray-3);
  border-radius: var(--radius);
  padding: var(--espace-md) var(--espace-lg);
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: box-shadow .15s var(--ease), opacity .2s var(--ease), transform .2s var(--ease);
}

/* Le creux du bas est celui du haut, comme dans une tuile : une marge basse
   posee sur le dernier enfant s'ajoute au remplissage de la carte au lieu de
   s'y fondre.

   La carte finit tantot sur une rangee sans marge -- `.ticket-card-telechargements`,
   le segmente d'etat --, tantot sur une rangee qui en porte une :
   `.ticket-card-thread` sur 22 des 166 cartes des archives, et
   `.ticket-card-page` sur toutes celles de la zone Messages. Ces deux-la
   rendaient 29,8 px de creux en bas pour 17 en haut, au milieu de voisines a
   17 dans la meme liste.

   Le `:last-child` seul suffit ici, la ou une tuile demande en plus la forme
   « dernier visible » (cf. `.tuile > :last-child`) : aucune carte ne finit sur
   une suite d'enfants `hidden` -- verifie sur les 179 cartes des trois listes,
   toutes a `apres = 0`. */
.ticket-card > :last-child { margin-bottom: 0; }

.ticket-card-disparait {
  opacity: 0;
  transform: scale(.97);
  pointer-events: none;
}

.ticket-card:hover {
  box-shadow: var(--shadow-md);
}

.ticket-card[data-lu="false"] {
  border-left-color: var(--cyan);
}

.ticket-card[data-statut="nouveau"] { border-left-color: var(--cyan); }
.ticket-card[data-statut="envoye_a_claude"] { border-left-color: var(--blue); }
.ticket-card[data-statut="resolu"] { border-left-color: var(--green); }

/* Le liseré d'une carte urgente, orange depuis le 7 septembre 2026 comme la
   pastille et la plaque qu'elle porte : c'est le troisième endroit où la même
   carte peint le même état, et le rouge le faisait ici seul. Orange est
   d'ailleurs la couleur de l'urgence partout ailleurs dans le produit -- le
   point d'avancement d'un mandat, le badge d'état de la liste des mandats --,
   donc le rouge des tickets était l'exception, pas la règle. */
.ticket-card[data-urgent="true"] {
  border-color: var(--orange-pale);
  border-left-color: var(--orange);
  border-left-width: 4px;
}

/* La marque d'urgence. Sur /tickets c'est un bouton -- le même élément dit
   l'état et le change (demande du 30 août 2026) --, sur /tickets/archives une
   simple marque : l'urgence règle l'ordre de la file des tickets ouverts, et il
   n'y a pas de file dans les archives. La règle vaut pour les deux, et rien
   n'est réécrit sous une classe de bouton.

   ORANGE ET NON PLUS ROUGE depuis le 7 septembre 2026 : « urgent ? en orange ou
   un truc comme ça ». La plaque d'intitulé, deux lignes plus bas sur la même
   carte, peint déjà l'urgence en orange (`.ticket-card-titre`, demande du
   30 août 2026 : « la couleur orange signalera déjà l'urgence ») ; la pastille,
   elle, restait rouge depuis avant elle. Le même état portait donc deux
   couleurs sur la même page, selon que l'Agent avait ou non déjà donné un
   intitulé au ticket -- et c'est ce défaut-là, à l'échelle des deux surfaces,
   que `regles_affichage` existe pour attraper. Ce sont les teintes exactes de
   la plaque, et non un orange voisin : deux oranges se liraient comme deux
   états. */
.ticket-card-urgent-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  border: 1px solid transparent;
  border-radius: 999px;
  padding: var(--espace-2xs) var(--espace);
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  background: var(--orange-pale);
  color: var(--orange-dark);
  white-space: nowrap;
}

button.ticket-card-urgent-badge { cursor: pointer; }

/* Sans urgence : la question, écrite. « La fonction + pour rendre un ticket
   urgent n'est pas clair, il faut quelque chose de plus explicite, "urgent ?"
   en orange ou un truc comme ça » (ticket du 7 septembre 2026).

   Le mot était masqué ici, au motif qu'« une carte ordinaire n'a pas à porter
   "Urgent" pour dire qu'elle ne l'est pas » (30 août 2026). C'est vrai d'un
   ÉTAT et faux d'une question : il ne restait qu'un triangle pâle et un plus,
   deux signes sans un mot, sur le seul endroit où l'urgence se pose pour une
   carte sans intitulé. Le gabarit écrit donc « Urgent ? », et cette règle ne
   masque plus rien.

   Creuse là où l'état est plein, et dans la même teinte : c'est ce que la carte
   deviendra, montré sans l'affirmer. Un fond orange ici aurait fait passer pour
   urgente chaque carte qui ne l'est pas -- exactement l'inverse de ce qu'une
   marque d'urgence sert à faire. */
.ticket-card-urgent-badge.non-urgent {
  border-color: var(--orange);
  background: none;
  color: var(--orange-dark);
}

/* Rien sur une carte urgente QUI A un intitulé : « supprime l'icône "Urgent",
   puisque la couleur orange signalera déjà l'urgence » (30 août 2026). La
   plaque du titre est orange, la pastille répéterait le mot à dix centimètres.

   Elle reste sur une carte urgente SANS intitulé -- il n'y a pas de plaque pour
   le dire --, et sur toute carte qui n'est pas urgente, quelle qu'elle soit :
   là, ce n'est plus un état répété, c'est la question, et rien d'autre sur la
   carte ne la pose (ticket du 7 septembre 2026, « non je parle du + sur le
   titre sur un ticket existant »).

   La règle porte donc sur la carte et non sur la pastille : la bascule se fait
   sur place, et `data-urgent` change sous elle au clic. Rien à créer ni à
   détruire. */
.ticket-card[data-titre="true"][data-urgent="true"] .ticket-card-urgent-badge {
  display: none;
}

/* La croix qui annonce le clic (suivi du 30 août 2026). Plus petite que le
   triangle et à peine appuyée : elle dit « ceci s'enlève », elle ne demande pas
   qu'on l'enlève. Elle s'affirme au survol, au moment où l'on vise. */
.ticket-card-urgent-croix {
  width: var(--icon-xs);
  height: var(--icon-xs);
  margin-left: var(--espace-3xs);
  opacity: .55;
}

.ticket-card-urgent-badge:hover .ticket-card-urgent-croix { opacity: 1; }

/* Rien à enlever sur un ticket qui n'est pas urgent : il n'y reste que le
   triangle, et le clic pose la marque au lieu de la retirer. */
.ticket-card-urgent-badge.non-urgent .ticket-card-urgent-croix { display: none; }

/* Le plus, symétrique de la croix : « de la même manière on doit pouvoir rendre
   urgent un ticket actuel » (suivi du 30 août 2026). Le triangle gris se
   cliquait déjà, mais un triangle seul dans un rond est une marque et non un
   bouton -- le même reproche exactement que celui qui avait valu la croix à
   l'autre sens.

   Mêmes dimensions, même opacité, même affirmation au survol que la croix : le
   geste est le même dans les deux sens, il se lit donc pareil. Il n'apparaît
   que sur un ticket qui n'est pas urgent, comme la croix n'apparaît que sur un
   ticket qui l'est : sur chaque carte, le badge ne montre jamais que ce que le
   clic va faire. */
.ticket-card-urgent-plus {
  width: var(--icon-xs);
  height: var(--icon-xs);
  margin-left: var(--espace-3xs);
  opacity: .55;
}

.ticket-card-urgent-badge:not(.non-urgent) .ticket-card-urgent-plus { display: none; }

.ticket-card-urgent-badge.non-urgent:hover .ticket-card-urgent-plus { opacity: 1; }

/* Le survol remplit la pastille : c'est l'état qu'elle prendra, montré avant
   qu'on clique. La teinte ne change plus au survol depuis le 7 septembre 2026,
   c'est le FOND qui arrive -- creux et plein disent maintenant la question et
   l'état, et virer d'une couleur à l'autre en aurait fait un troisième. */
.ticket-card-urgent-badge.non-urgent:hover {
  background: var(--orange-pale);
}

/* Le rythme de la carte : un ecart entre deux rangees, double a l'unique
   endroit ou la carte cesse de decrire et se met a agir.

   Il y en avait sept -- 0, 8, 9,6, 14,4, 16, 25,6 et 28,8 px -- et aucun ne
   voulait dire quoi que ce soit : chacun etait la somme accidentelle des deux
   marges ecrites a la main que ses voisins portaient. La meme frontiere, celle
   qui suit les etiquettes, mesurait 9,6, 14,4 ou 25,6 px selon la rangee qui
   suivait ; le titre et l'origine du ticket, eux, se touchaient (0 px), parce
   que `.ticket-card-titre` n'avait pas de marge basse et `.ticket-card-page`
   pas de marge haute. Un blanc qui varie sans rien signifier ne separe pas :
   il donne seulement l'impression que la carte a ete assemblee piece par
   piece.

   Toutes les rangees prennent donc --espace, et la carte se lit en trois
   bandes separees par un filet --gray-2 : qui parle (l'en-tete), ce qui est
   dit (titre, texte, origine, etiquettes, fil), et ce qu'on peut faire (le
   segmente des statuts et la rangee de telechargement). Les deux filets sont
   poses par la bande du bas de chacune -- l'en-tete ferme la sienne, le
   segmente ouvre la troisieme -- et non par un conteneur : `tickets-page.js`
   accroche la rangee de telechargement directement sur la carte
   (`carte.appendChild`), une bande enveloppee la mettrait dehors.

   La frontiere avant les gestes valait deja deux crans avant le
   30 aout 2026, mais par accident : `.ticket-statut-pipeline` etait une boite
   en ligne (`inline-flex`), donc sa marge ne se rabattait pas sur celle de sa
   voisine en bloc et les deux --espace s'additionnaient. Ce qui separait les
   deux moities de la carte n'etait donc ecrit nulle part et disparaissait au
   premier passage en `flex`. Le segmente est aujourd'hui une boite en bloc
   qui porte le filet, un --espace au-dessus et un --espace en dessous : le
   meme blanc qu'avant, cette fois dit.

   Les trois bandes valent partout ou `.ticket-card` sert -- /tickets,
   /tickets/archives, /messages -- et se degradent seules : l'archive n'a pas
   de segmente, sa rangee de telechargement garde alors son propre filet ; un
   message n'a ni l'un ni l'autre et s'arrete a deux bandes. */
.ticket-card-header {
  display: flex;
  align-items: center;
  gap: var(--espace);
  padding-bottom: var(--espace);
  border-bottom: 1px solid var(--gray-2);
}

.ticket-card-meta {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--espace-3xs);
}

.ticket-card-date {
  font-size: var(--fs-xs);
  color: var(--gray-4);
}

/* D'ou vient un ticket qui a change de main (demande du 27 aout 2026) : sous
   le nom de celui qui le porte aujourd'hui, dans le meme gris que la date --
   c'est une mention de contexte, pas une information a lire avant le sujet. */
.ticket-card-transfert-trace {
  font-size: var(--fs-xs);
  color: var(--gray-4);
  font-style: italic;
}

/* L'intitulé d'un ticket, surligné. « Mets davantage en évidence l'intitulé des
   tickets [...] pour attirer immédiatement le regard. Inspire-toi du style
   utilisé pour la durée du mandat : un surlignement bleu par défaut, orange si
   le ticket est urgent » (demande du 30 août 2026).

   La recette est celle de `.aglae-calcul`, la plaque de la durée du mandat : la
   demi-graisse, un fond pâle, un arrondi court, et le texte qui respire d'un
   barreau de chaque côté. Ce qui change ici est la raison d'être : là-bas la
   plaque disait « ceci est déduit », ici elle dit « voici de quoi il s'agit »
   -- dans une pile de cartes, c'est la seule ligne qu'on lit avant de décider
   si on lit le reste.

   La plaque est en ligne et non en bloc : elle épouse l'intitulé. Un
   surlignement qui prendrait toute la largeur serait une bande, pas une marque.

   `h3` porte l'espacement, la plaque le reste : le titre reste un titre pour un
   lecteur d'écran, même quand le surlignement est un bouton. */
.ticket-card-titre-ligne {
  margin: var(--espace) 0;
}

.ticket-card-titre {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  border: 1px solid transparent;
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 600;
  text-align: left;
  /* Orange par défaut, parce que c'est la carte qui décide : la plaque naît
     urgente et `non-urgent` la ramène au bleu. L'ordre est celui du gabarit,
     qui pose la classe quand le ticket ne l'est pas -- comme la pastille
     qu'elle remplace. */
  background: var(--orange-pale);
  color: var(--orange-dark);
}

.ticket-card-titre.non-urgent {
  background: var(--cyan-light);
  color: var(--cyan-dark);
}

/* Sur /tickets, la plaque est le bouton qui pose et retire l'urgence : le même
   élément dit l'état et le change, comme la pastille « Urgent » qu'elle
   remplace. Sur /tickets/archives, c'est un span -- rien à basculer sur une
   archive. */
button.ticket-card-titre { cursor: pointer; }

button.ticket-card-titre:hover { border-color: var(--orange); }

button.ticket-card-titre.non-urgent:hover { border-color: var(--cyan); }

/* La croix et le plus, hérités de la pastille : ils disent ce que le clic va
   faire (« on peut pas savoir qu'en cliquant on va l'enlever », suivi du
   30 août 2026). Mêmes règles que sur la pastille, réécrites ici parce que la
   plaque n'est pas dans la même famille de sélecteurs. */
.ticket-card-titre .ticket-card-urgent-croix {
  width: var(--icon-xs);
  height: var(--icon-xs);
  opacity: 0;
  transition: opacity .15s var(--ease);
}

/* Rien à enlever sur une plaque qui n'est pas urgente. Le plus, lui, a quitté
   la plaque le 7 septembre 2026 : il n'apparaissait qu'au survol, et c'est la
   pastille « Urgent ? » en tête de carte qui pose la question désormais. */
.ticket-card-titre.non-urgent .ticket-card-urgent-croix { display: none; }

button.ticket-card-titre:hover .ticket-card-urgent-croix { opacity: 1; }

/* Une plaque de marque -- les archives -- n'annonce aucun geste. */
span.ticket-card-titre .ticket-card-urgent-croix { display: none; }

.ticket-card-statut-badge {
  border: 1px solid transparent;
  border-radius: 999px;
  padding: var(--espace-2xs) var(--espace);
  font-size: var(--fs-xs);
  font-weight: 600;
  background: var(--gray-2);
  color: var(--gray-5);
  white-space: nowrap;
}

.ticket-card[data-statut="nouveau"] .ticket-card-statut-badge { background: var(--cyan-light); color: var(--cyan-dark); }
.ticket-card[data-statut="envoye_a_claude"] .ticket-card-statut-badge { background: var(--blue-pale); color: var(--blue); }
.ticket-card[data-statut="repondu"] .ticket-card-statut-badge { background: var(--orange-pale); color: var(--orange-dark); }
.ticket-card[data-statut="resolu"] .ticket-card-statut-badge { background: var(--green-pale); color: var(--green); }

/* Le rang dans la file de l'Agent (ticket du 4 septembre 2026), a la place que
   la pastille de statut laisse libre sur un ticket envoye -- elle y est
   masquee, le pipeline disant deja « Envoyé à l'Agent ».

   Meme forme et meme teinte que cette pastille dans ce meme etat (--blue-pale
   sur --blue) : c'est la meme information, le mot en moins et le numero en
   plus. L'exposant du rang ne doit pas ecarter les lignes, d'ou la hauteur
   nulle -- une pastille qui grandit d'un pixel deplace la rangee entiere. */
.ticket-card-file {
  border-radius: 999px;
  padding: var(--espace-2xs) var(--espace);
  font-size: var(--fs-xs);
  font-weight: 600;
  background: var(--blue-pale);
  color: var(--blue);
  white-space: nowrap;
}

.ticket-card-file sup {
  font-size: var(--fs-3xs);
  line-height: 0;
  vertical-align: super;
}

/* La bande des gestes. Elle etait un filet et deux rangees flottantes : les
   quatre etats, « Confier ou collaborer » et la poubelle sur la premiere, la
   synthese et les pieces jointes sur la seconde -- sept commandes posees a
   meme le fond blanc de la carte, sous une conversation qui, elle, a des
   bulles. On ne voyait pas ou finit ce qu'on lit et ou commence ce qu'on
   fait ; c'est le « plein de boutons » du 30 aout 2026.

   Elle est devenue une boite le 30 aout, et ne l'est plus depuis le
   9 septembre : « faire des blocs pour ces boutons est inutile ». Ce qui
   ouvre la bande est de nouveau un filet, mais porte par le pied de la carte
   (`.ticket-card-pied`), qui tient la ligne entiere -- le raisonnement est
   ecrit la-bas. Il ne reste ici que la rangee elle-meme.

   Pas d'`overflow` ici : le menu de « Confier ou collaborer » remonte de 272 px
   au-dessus de la bande (`bottom: calc(100% + .35rem)`), et une boite qui
   rognerait le sien le couperait. */
.ticket-statut-pipeline {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin: var(--espace-md) 0 0;
}

.ticket-statut-pipeline-form { display: contents; }

/* La sortie, pas une position de plus : le bouton se detache du segmente d'un
   cran d'espace plutot que du gap de 4 px qui lie les quatre etats entre eux.
   Il garde la taille des segments -- c'est la meme rangee -- et prend le rouge
   des gestes qui ne se defont pas (.btn-danger). */
/* La poubelle seule, sans libelle (suivi du 24 aout 2026). Une case carree et
   non la boite d'un mot absent : le rembourrage lateral de `.icon-btn` laissait
   l'icone flotter au milieu d'un bouton deux fois trop large, et le survol
   rouge dessinait ce vide. La hauteur reste celle des positions du segmente a
   cote -- meme rembourrage vertical --, pour que les cinq boutons de la ligne
   posent sur la meme assise. */
/* Six familles de boutons dans une carte de ticket, six hauteurs. Mesure au
   navigateur le 28 aout 2026, sur les deux pages : 37,19 px pour « Ouvrir dans
   un nouvel onglet », 34 pour « Joindre un fichier » (cent vingt-neuf fois),
   31,19 pour les quatre segments du pipeline et les deux icones qui les
   suivent, 29,59 pour les pastilles de telechargement (cent trente-six fois),
   et 28 pour le bouton-lien -- le seul de la carte qui porte deja le plancher.
   Sur la page des archives, cent vingt-neuf rangees mettent « Joindre un
   fichier » a 34 px et « Annuler » a 28 aux deux bouts de la meme ligne.

   Deux de ces hauteurs viennent du meme remplissage declare -- `.5rem .75rem`,
   celui de .icon-btn -- rendu different par la hauteur de ligne du bloc qui
   contient le bouton : 1.5 heritee de la page pour le premier, `normal` pour le
   second. C'est mot pour mot ce que dit .btn-link quelques milliers de lignes
   plus haut, « une hauteur de bouton ne se decide pas dans le parent », et
   .btn-link est justement celui des six qui tombe juste.

   Les cinq autres prennent donc sa recette : hauteur de ligne fixe, plancher a
   --h-sm, remplissage vertical passe sous le plancher pour que ce soit lui qui
   decide. Le commentaire ci-dessous demandait deja cette assise commune, et
   l'obtenait en recopiant un remplissage d'un bouton a l'autre -- ce qui ne
   pouvait pas tenir, puisque le remplissage n'est pas ce qui fixait la hauteur.

   Le plancher est ecrit a une seule classe pour que la cible tactile de 44 px,
   posee plus loin dans mobile.css, continue de passer devant lui au telephone. */
.ticket-statut-seg,
.ticket-card-transfert-btn,
.ticket-card-supprimer,
.ticket-card-pdf,
.ticket-card-zip,
.ticket-card-fichier,
.ticket-card-suivi-joindre,
.ticket-card-verifier {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-sm);
  line-height: 1.3;
}

/* Le bouton reduit a son icone est un carre de --h-sm, comme les autres
   boutons-icones de la feuille : sans largeur minimale, le remplissage seul lui
   donnait 26 px pour 28 de haut.

   Ils etaient deux ; « Confier ou collaborer » a repris son mot le 30 aout 2026 et
   n'en est plus (voir le gabarit). Il garde le plancher de hauteur, pose
   au-dessus avec les six autres, et prend l'ecart entre l'icone et le mot. */
.ticket-card-supprimer {
  min-width: var(--h-sm);
  justify-content: center;
  padding: var(--espace-2xs);
}

.ticket-card-transfert-btn {
  gap: var(--espace-2xs);
  padding: var(--espace-2xs) var(--espace-xs);
}

.ticket-card-supprimer {
  margin-left: var(--espace-sm);
  font-size: var(--fs-xs);
  font-weight: 600;
}

.ticket-card-supprimer:hover { background: var(--red-pale); color: var(--red); }

/* Passer le ticket a un autre collaborateur (demande du 27 aout 2026), reduit
   a son icone au suivi du meme jour (« trop gros et moche, fait plus moderne et
   discret avec juste une icone transferer »). Il tenait une rangee entiere de
   la carte -- icone, liste deroulante pleine largeur, bouton « Transferer » --
   pour un geste qu'on fait une fois sur vingt ; il occupe maintenant la meme
   case carree que la poubelle, dans la meme rangee, et les noms n'apparaissent
   qu'au clic. Les deux se detachent ensemble du segmente : le decrochage de
   .6rem passe au premier des deux, le gap de 4 px les lie entre eux. */
.ticket-card-transfert {
  position: relative;
  display: inline-flex;
  margin-left: var(--espace-sm);
}

.ticket-card-transfert + .ticket-card-supprimer { margin-left: 0; }

.ticket-card-transfert-btn {
  font-size: var(--fs-xs);
}

.ticket-card-transfert-btn:hover,
.ticket-card-transfert-btn[aria-expanded="true"] {
  background: var(--cyan-light);
  color: var(--cyan-dark);
}

/* Le menu des noms : meme famille que les autres surfaces flottantes de la
   feuille (fond blanc, bordure --gray-3, ombre portee). Il s'ouvre vers le
   haut, la rangee du pipeline etant en bas de la carte.

   Il annoncait cette famille depuis le debut sans en prendre l'arrondi. Les
   deux autres menus de la feuille -- `.choix-fichier-ou-menu` et
   `.app-reglages-panneau` -- tiennent --radius-lg avec quatre et six pixels de
   marge interieure, moins que le rayon : un rang survole ne deborde pas dans
   l'angle pour autant, et celui-ci en a cinq. */
.ticket-card-transfert-menu {
  position: absolute;
  bottom: calc(100% + .35rem);
  left: 0;
  z-index: 110;
  min-width: 190px;
  padding: var(--espace-2xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: modal-pop-in .15s var(--ease);
}

.ticket-card-transfert-menu-titre {
  margin: var(--espace-2xs) var(--espace-sm) var(--espace-2xs);
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-4);
}

.ticket-card-transfert-choix {
  display: block;
  width: 100%;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--espace-sm);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-6);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.ticket-card-transfert-choix:hover { background: var(--cyan-light); color: var(--cyan-dark); }
.ticket-card-transfert-choix[disabled] { opacity: .5; cursor: default; }

/* « Collaborer avec », sous « Transferer a » dans le meme menu : les memes
   noms sous deux verbes (demande du 27 aout 2026). La difference se voit a la
   coche -- un nom coche suit deja le ticket, et se declique pour l'en retirer.
   Le transfert, lui, se fait une fois et ne se defait pas d'ici : sa liste n'a
   donc pas de coche. */
.ticket-card-collaborer-choix {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--espace-sm);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-6);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.ticket-card-collaborer-choix:hover { background: var(--cyan-light); color: var(--cyan-dark); }
.ticket-card-collaborer-choix[disabled] { opacity: .5; cursor: default; }

.ticket-card-collaborer-choix .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  flex: none;
  color: var(--gray-3);
}

.ticket-card-collaborer-choix.suit { color: var(--green-dark); }
.ticket-card-collaborer-choix.suit .icon { color: var(--green); }

/* Les ronds de ceux qui suivent le ticket a cote de son porteur, a la file
   comme les intervenants d'un mandat dans la liste des clients. */
/* Trois virgule deux pixels entre deux visages de 22 : le seul ecart de la
   carte qui ne soit pas un barreau. Il monte au premier, --espace-2xs -- moins
   d'un pixel de deplacement, et deux ronds voisins continuent de se lire comme
   deux personnes plutot que comme une chaine. */
.ticket-card-collaborateurs {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  flex: none;
}

.ticket-card-collaborateur-rond { --avatar-d: 22px; }

.ticket-statut-seg {
  border: 1px solid var(--gray-3);
  background: var(--gray-1);
  border-radius: var(--radius-sm);
  padding: var(--espace-2xs) var(--espace);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-5);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
}

.ticket-statut-seg:hover:not(.active) { opacity: .8; border-color: var(--seg-couleur); color: var(--seg-couleur); }

.ticket-statut-seg.active {
  color: #fff;
  border-color: transparent;
  background: var(--seg-couleur);
  cursor: default;
}

@keyframes ticket-statut-seg-pouls {
  0%, 100% { opacity: 1; }
  50% { opacity: .4; }
}

.ticket-statut-seg-envoi {
  animation: ticket-statut-seg-pouls .9s ease-in-out infinite;
}

/* Indicateur de position pose par l'Agent (statut repondu), pas par un
   clic humain : pas de curseur ni de survol qui suggereraient une action. */
/* `-verrouille` : « Envoyé à l'Agent » vu par un collaborateur, qui ne peut
   pas le cliquer (audit securite du 14 septembre 2026). Meme dessin que le
   palier pose par l'Agent, nom distinct parce que la cause differe. */
.ticket-statut-seg-fixe,
.ticket-statut-seg-verrouille { cursor: default; pointer-events: none; }

.ticket-card-texte {
  margin: var(--espace) 0;
  padding: var(--espace) var(--espace-md);
  background: var(--gray-1);
  border-radius: var(--radius-sm);
  white-space: pre-wrap;
  font-size: var(--fs);
  line-height: 1.55;
  color: var(--gray-6);
}

/* `align-items: flex-start` cale le bouton d'envoi a gauche -- et faisait du
   meme coup retrecir la case de texte a la largeur de ce qu'elle contient :
   d'une carte a l'autre, le meme champ faisait 180, 140 ou 470 px selon la
   phrase qu'on y avait ecrite, alors que son `width: 100%` disait le
   contraire. Le calage ne vaut que pour le bouton, pas pour la case. */
.ticket-card-texte-form {
  margin: var(--espace) 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--espace-xs);
}

.ticket-card-texte-form > .ticket-widget-champ-texte { align-self: stretch; }

.ticket-card-texte-edit {
  width: 100%;
  min-height: 5rem;
  max-height: 16rem;
  overflow-y: auto;
  white-space: pre-wrap;
  background: var(--gray-1);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: var(--espace) var(--mic-reserve) var(--espace) var(--espace-md);
  font-size: var(--fs);
  line-height: 1.55;
  color: var(--gray-6);
  font-family: inherit;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.ticket-card-texte-edit:hover { background: var(--gray-2); }

.ticket-card-texte-edit:focus {
  outline: none;
  background: #fff;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.ticket-card-texte-edit:empty::before {
  content: attr(data-placeholder);
  color: var(--gray-4);
}

.ticket-card-thread {
  margin: var(--espace) 0;
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

.ticket-card-thread[hidden] {
  display: none;
}

/* LA BULLE PREND LA CARTE, ET C'EST UN ARBITRAGE DEMANDE DEUX FOIS.

   Elle etait bornee a --largeur-lecture, comme les explications du mapping et
   les paragraphes de /confidentialite : une bulle est du texte suivi -- une
   demande, une reponse de l'Agent --, et l'oeil suit mal une ligne de cent
   quatre-vingt-six caracteres. C'est ce qui a ete repondu au passage en une
   colonne (« le fil garde sa largeur de lecture, d'ou le blanc a droite »), et
   la reponse a ete « super, laisse la discussion avec l'Agent s'elargir vers
   la droite » (suivi du 9 septembre 2026). La demande passe : ce blanc etait
   la moitie droite de chaque carte, et une conversation qu'on relit en
   diagonale n'est pas un article qu'on lit ligne a ligne.

   Le plafond part donc, et la bulle suit la carte -- 1292 px sur une fenetre
   de 1600, la largeur meme qui avait motive le plafond. C'est le seul endroit
   du produit dans ce cas : une bulle du chat prive reste bornee a 78 % de sa
   colonne, parce que les bulles y sont rangees des deux cotes et que ce qui
   les distingue est justement de ne pas se toucher.

   Les deux boites au-dessus gardaient deja toute la largeur, parce que ce sont
   des champs : on y saisit le texte du ticket et ses etiquettes, et le micro du
   premier est pose contre le bord de la carte -- le borner le laisserait
   seul a droite. Les trois blocs de la carte s'alignent donc enfin sur le meme
   bord droit.

   L'ecart du bourrelet reprend celui de la carte qui le porte, --espace-md
   contre --espace-lg, un barreau plus bas : --espace dedans, --espace-md sur
   les cotes. Le .9rem d'avant ne tombait sur aucun barreau. */
.ticket-card-thread-msg {
  padding: var(--espace) var(--espace-md);
  border-radius: var(--radius-sm);
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
}

.ticket-card-thread-msg-user {
  background: var(--gray-1);
}

.ticket-card-thread-msg-agent {
  background: var(--blue-pale);
}

.ticket-card-thread-msg-label {
  font-size: var(--fs-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
}

.ticket-card-thread-msg-agent .ticket-card-thread-msg-label {
  color: var(--blue);
}

.ticket-card-thread-msg-texte {
  white-space: pre-wrap;
  font-size: var(--fs);
  line-height: 1.5;
  color: var(--gray-6);
  margin: 0;
}

.ticket-card-reponse-attente {
  font-size: var(--fs-sm);
  font-style: italic;
  color: var(--gray-5);
  margin: 0;
}

/* « Ouvrir dans un nouvel onglet » : la page ou la reponse de l'Agent se
   constate. Il prend la teinte de la bulle de l'Agent juste au-dessus, parce
   qu'il appartient a cette reponse et non a la carte -- et `align-self` parce
   que le fil est une colonne flex, ou un lien s'etirerait sur toute la
   largeur et cesserait de se lire comme un bouton. */
/* Meme decrochage horizontal que les pastilles de telechargement, et pour la
   meme raison : un bouton qui porte une peau visible ecarte son contenu de ses
   bords d'un cran de plus qu'un bouton fantome. Les deux plaques de la carte
   -- celle-ci et « Synthese (.md) », l'une sous l'autre -- posent alors leur
   icone sur la meme verticale. */
.ticket-card-verifier {
  align-self: flex-start;
  padding: var(--espace-2xs) var(--espace);
  color: var(--blue);
  background: var(--blue-pale);
  border-color: transparent;
}

.ticket-card-verifier:hover {
  color: var(--blue);
  background: var(--blue-pale);
  border-color: var(--blue);
}

/* Aucune marge : le fil est une colonne flex qui pose son propre ecart
   (`gap: var(--espace-sm)`), et tous ses autres membres -- les bulles, la
   plaque « Ouvrir dans un nouvel onglet », « En attente de traitement... » --
   s'en remettent a lui. Ce formulaire etait le seul a ajouter un terme, et la
   somme tombait a cote : 9,6 + 4 = 13,6, sur aucun barreau. Releve du 30 aout
   2026 sur /tickets : vingt-trois ecarts a 9,6 dans les fils de la page, sept a
   13,6, tous les sept au-dessus de ce formulaire.

   Le terme avait un sens le 29 juillet, quand il a ete ecrit : le formulaire
   vivait alors dans `.ticket-card-reponse`, dont l'ecart etait de 4,8, et le
   doubler ecartait la demande de suivi de la reponse qu'elle commente. Le
   formulaire a depuis demenage dans le fil, dont l'ecart est de 9,6 -- le
   doubler ferait 19,2, qui n'est sur aucun barreau. L'intention d'origine
   n'est plus ecrivable, donc elle n'est plus l'intention : c'est la colonne
   qui parle. */
.ticket-card-suivi-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--espace-sm);
}

.ticket-card-suivi-champ {
  position: relative;
  flex: 1;
  min-width: 12rem;
}

/* Les pieces choisies pour une demande de suivi, et les deux boutons qui
   ferment le formulaire. La liste prend toute la largeur pour passer sous le
   champ, jamais a cote : un nom de fichier est long, et le champ de texte est
   ce qu'on regarde en ecrivant. */
.ticket-card-suivi-fichiers,
.ticket-card-suivi-actions {
  flex-basis: 100%;
}

.ticket-card-suivi-fichiers {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-2xs);
}

.ticket-card-suivi-fichiers:empty { display: none; }

.ticket-card-suivi-fichiers li {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  max-width: 100%;
  padding: var(--espace-3xs) var(--espace-2xs) var(--espace-3xs) var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  font-size: var(--fs-xs);
  color: var(--gray-6);
}

.ticket-card-suivi-fichier-nom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ticket-card-suivi-fichier-retirer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--gray-4);
  cursor: pointer;
  flex: none;
}

.ticket-card-suivi-fichier-retirer .icon { width: var(--icon-sm); height: var(--icon-sm); }
.ticket-card-suivi-fichier-retirer:hover { color: var(--red); background: var(--red-pale); }

.ticket-card-suivi-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
}

.ticket-card-suivi-joindre {
  font-size: var(--fs-xs);
  padding: var(--espace-2xs) var(--espace-sm);
}

.ticket-card-suivi-input {
  width: 100%;
  min-height: var(--mic-place);
  max-height: 12rem;
  overflow-y: auto;
  border: 1px solid var(--gray-3);
  background: #fff;
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--mic-reserve) var(--espace-xs) var(--espace-sm);
  font-size: var(--fs-sm);
  font-family: var(--sans);
  color: var(--gray-6);
  resize: vertical;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.ticket-card-suivi-input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.ticket-card-suivi-input:empty::before {
  content: attr(data-placeholder);
  color: var(--gray-4);
}

/* Le micro du suivi faisait 22px avec une icone de 14, celui juste au-dessus
   dans la meme carte 28 avec une icone de 16 : deux boutons identiques, a six
   pixels l'un de l'autre, dans le meme regard. « Deux icones voisines ne
   doivent pas differer d'un pixel. » Il n'y a plus qu'un micro, d'une seule
   taille ; le champ de suivi a grandi de quatre pixels pour le loger, ce que
   --mic-place fait tout seul. */

.ticket-card-suivi-mic-statut {
  flex: 1 0 100%;
  margin-top: 0;
}

.ticket-card-workflow {
  display: flex;
  justify-content: flex-end;
  margin-bottom: var(--espace);
}

.ticket-card-workflow .btn-primary.btn-sm {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
}

.ticket-card-workflow .icon { width: var(--icon); height: var(--icon); }

.ticket-card-page {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  font-size: var(--fs-sm);
  color: var(--gray-5);
  /* Marge haute autant que basse : sur les archives, l'origine du ticket
     suit directement l'en-tete quand il n'y a pas de titre, et les deux se
     touchaient. Les marges voisines se rabattent l'une sur l'autre, donc
     la rangee garde le meme ecart partout ou elle apparait. */
  margin: var(--espace) 0;
}

.ticket-card-page a { color: inherit; text-decoration: none; }
.ticket-card-page a:hover { color: var(--cyan-dark); text-decoration: underline; }

.ticket-card-dossier {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-5);
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-3xs) var(--espace-xs);
}

/* Les etiquettes deja posees, et rien quand il n'y en a pas.

   Le champ de saisie qui vivait ici a ete retire le 30 aout 2026 (« supprime le
   champ "Etiquettes separees par des virgules" ») : il prenait une ligne pleine
   sur chaque carte, meme vide, meme sur vingt cartes d'affilee ou personne n'en
   pose jamais. Ce qui reste ne coute rien a un ticket sans etiquette -- le bloc
   n'est pas rendu -- et donne a lire celles qui existent, posees depuis l'app.

   Des pastilles et non des mots separes par des virgules : elles ne se saisissent
   plus, et une liste qu'on ne peut pas modifier ne doit pas ressembler a un
   champ. */
.ticket-card-etiquettes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-2xs);
  margin-bottom: var(--espace);
}

.ticket-card-etiquette {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Les versions poussées pour le ticket : « affiche en attribut de chaque ticket
   les version push associées » (ticket du 7 septembre 2026).

   Un attribut, donc un nom et des valeurs : le mot dit de quoi il s'agit, les
   pastilles portent les numéros. Sans le mot, une rangée de « 17.91 » sous la
   page d'origine ne dirait pas si l'on lit une version, une heure ou un
   montant.

   La forme des étiquettes juste au-dessus, et pas une de plus : même rangée qui
   se replie, même pastille grise, même taille de texte. Ce sont deux attributs
   du même ticket, ils n'ont pas à se distinguer -- ce qui les distingue est
   déjà que l'un porte un mot devant lui. */
.ticket-card-versions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-2xs);
  margin-bottom: var(--espace);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

.ticket-card-version {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  color: var(--gray-5);
  /* Les chiffres à chasse fixe, seule différence avec une étiquette : trois
     numéros alignés se comparent d'un coup d'oeil, et « 17.9 » ne doit pas
     paraître plus court que « 17.91 » de la largeur d'un chiffre. */
  font-variant-numeric: tabular-nums;
}

.ticket-card-telechargements {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-sm);
  padding-top: var(--espace);
  border-top: 1px solid var(--gray-2);
}

/* Quand le segmente est la, il a deja ouvert la bande des gestes : la rangee
   de telechargement qui le suit appartient a la meme et ne repose pas un
   second filet un demi-cran plus bas -- ce filet est desormais celui du pied
   de la carte, et il est au-dessus des deux. Sur l'archive, ou il n'y a pas de
   segmente ni de pied, la regle ne s'applique pas et la rangee garde le sien :
   elle y est seule sous la conversation, et sans trait rien ne l'en separe. */
.ticket-statut-pipeline + .ticket-card-telechargements {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.ticket-card-pdf,
.ticket-card-zip,
.ticket-card-fichier {
  display: inline-flex;
  font-size: var(--fs-xs);
  background: var(--gray-1);
  border-radius: 999px;
  padding: var(--espace-2xs) var(--espace);
}

.ticket-card-pdf:hover,
.ticket-card-zip:hover,
.ticket-card-fichier:hover {
  background: var(--gray-2);
}

.ticket-card-zip {
  font-weight: 600;
}

.ticket-card-fichiers {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
}

/* Le bandeau rouge d'alerte, et le bloc qui sert a le publier juste en dessous.
   Cette famille entiere posait ses blancs a la main : 16, 9,6, 19,2, 3,2, 11,2,
   14,4, 10,4 -- sept valeurs pour six regles, dont quatre ne tombent sur aucun
   barreau de l'echelle. C'est le bandeau que l'on voit en premier en arrivant
   sur le site un jour de panne, et il n'avait pas la respiration du reste. */
.alerte-bandeau {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--espace-md);
  padding: var(--espace-sm) var(--espace-lg);
  background: var(--red);
  color: #fff;
  font-size: var(--fs);
  font-weight: 600;
  text-align: center;
}

.alerte-bandeau[hidden] {
  display: none;
}

.alerte-bandeau-texte {
  max-width: var(--largeur-bloc);
}

/* La croix : son blanc lateral passe de 3,2 a 4 px, le barreau voisin. C'est le
   sens qui agrandit la cible plutot que de la reduire -- une croix de fermeture
   se vise, et celle-ci n'a que la largeur de son signe. */
.alerte-bandeau-fermer {
  background: none;
  border: none;
  color: #fff;
  font-size: var(--fs-h2);
  line-height: 1;
  cursor: pointer;
  padding: 0 var(--espace-2xs);
  opacity: .85;
}

.alerte-bandeau-fermer:hover {
  opacity: 1;
}

/* Ce bloc a perdu son cadre gris le 30 aout 2026, quand la zone a pris le
   sien. Il ne contient qu'une ligne de saisie et un bouton : encadre dans une
   tuile, il faisait trois bordures emboitees pour un seul champ -- celle de la
   tuile, la sienne, celle du champ. Ce n'est pas une sous-zone, c'est le
   contenu de sa zone, et le creux de la tuile est le sien.

   Son ecart bas est parti avec : il repondait a l'empilement du panneau des
   tickets, d'ou ce bloc a demenage le 30 aout 2026, et il n'a plus rien en
   dessous de lui -- il ouvrait un fond de tuile deux fois trop profond. */
.alertes-bandeau-admin {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* L'alerte en cours, elle, est bien une sous-zone, et la seule de sa tuile :
   c'est un etat -- il y a en ce moment un message affiche a tout le monde --,
   et il se lit avant qu'on songe a en publier un autre. Le formulaire en
   dessous n'est pas un etat, c'est le geste ordinaire de la zone. */
.alertes-bandeau-admin-active {
  padding: var(--espace-sm) var(--espace-md);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-md);
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.alertes-bandeau-admin-form {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

.alertes-bandeau-admin-input {
  flex: 1;
  border: 1px solid var(--gray-3);
  background: #fff;
  border-radius: var(--radius-sm);
  /* 10,4 px sur les cotes : une valeur recopiee de champ en champ sans jamais
     avoir ete choisie -- on la retrouve a l'identique sur le champ des
     etiquettes d'un ticket. 9,6 est le barreau voisin, et c'est celui que tient
     la recette de champ du site.

     La hauteur, elle, bouge : ce champ et le bouton pose a sa droite sont les
     deux seules choses de la barre, et ils ne mesuraient pas pareil -- 29,78
     contre 28. Un pixel et trois quarts, c'est trop peu pour se lire comme un
     choix et bien assez pour se voir : les deux boites se manquaient en haut
     comme en bas. Releve au navigateur le 30 aout 2026.

     Le remede est celui qui est deja ecrit plus haut pour `.btn-primary.btn-sm`,
     et il vaut ici mot pour mot : un interligne dit plutot que laisse au
     navigateur, un creux vertical d'un barreau plus bas, et --h-sm redevenu le
     plancher qu'il est. 12,8 a 1,3 font 16,64 ; plus 8 de creux et 2 de bordure,
     26,64 -- sous le plancher, donc ce champ mesure 28 quoi qu'on lui mette
     dedans, exactement comme le bouton a cote de lui.

     29,78 n'est pas une faute partout : c'est la hauteur naturelle de la recette
     de champ, et les six autres champs qui la portent vivent dans des rangees
     denses ou ils s'alignent sur un `select` voisin. Celui-ci n'a pas de rangee,
     il a un bouton. */
  padding: var(--espace-2xs) var(--espace-sm);
  min-height: var(--h-sm);
  line-height: 1.3;
  font-size: var(--fs-sm);
  color: var(--gray-6);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.alertes-bandeau-admin-input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* ---------- Les comptes des registres publics ---------- */

/* Un registre public ferme derriere un compte n'est pas ferme : il est ouvert a
   qui s'est inscrit. Le panneau qui pose ce compte reprend la forme des deux
   autres de la page -- un encart par ligne, ses champs sur une rangee, le
   bouton au bout -- plutot que d'inventer une troisieme mise en page pour trois
   cases. */
.registres-comptes {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

.registre-compte {
  padding: var(--espace-sm) var(--espace-md);
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
}

.registre-compte-entete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

.registre-compte-nom {
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

/* L'etat en pastille et non en phrase : c'est ce qu'on vient verifier, et il se
   lit avant le nom du registre quand on rouvre la page six mois plus tard. */
.registre-compte-etat {
  border-radius: 999px;
  padding: 0 var(--espace-sm);
  font-size: var(--fs-2xs);
  line-height: 1.7;
  background: var(--gray-1);
  color: var(--gray-5);
}

.registre-compte-etat.actif {
  background: var(--green-pale);
  color: var(--green-dark);
}

.registre-compte-etat.refus {
  background: var(--red-pale);
  color: var(--red-dark);
}

.registre-compte-champs {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  flex-wrap: wrap;
  margin-top: var(--espace-2xs);
}

/* Meme recette de champ que la barre de l'alerte generale, juste au-dessus : ces
   deux cases-la ne vivent pas dans une rangee dense, elles vivent a cote d'un
   bouton, et c'est sur lui qu'elles s'alignent. */
.registre-compte-identifiant,
.registre-compte-motdepasse {
  border: 1px solid var(--gray-3);
  background: #fff;
  border-radius: var(--radius-sm);
  padding: var(--espace-2xs) var(--espace-sm);
  min-height: var(--h-sm);
  line-height: 1.3;
  font-size: var(--fs-sm);
  color: var(--gray-6);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.registre-compte-identifiant { flex: 1 1 16rem; }
.registre-compte-motdepasse { flex: 1 1 12rem; }

.registre-compte-identifiant:focus,
.registre-compte-motdepasse:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Jour et mois de cloture : deux champs a deux chiffres. La largeur etait
   posee en style en ligne, seul reste du site a le faire.

   Une classe ne pese pas ce que pesait ce style en ligne : `mobile.css` doit la
   redire sous `.reglages-row > input.reglages-champ-court`, sans quoi les deux
   champs y reprennent toute la largeur de la colonne. */
.reglages-champ-court { width: var(--champ-court); }

/* ---------- Pages publiques (assistance, confidentialite) ---------- */

/* Ces deux pages sont atteignables sans compte : App Store Connect l'exige, et
   le relecteur d'Apple les consulte avant d'ouvrir l'application. Elles ne
   chargent donc ni `mobile.css`, ni le manifeste, ni la banque d'icones.

   Leur mise en forme etait jusqu'ici recopiee dans un bloc <style> a l'interieur
   de chacune des deux : les copies avaient commence a diverger, et aucune de
   leurs couleurs (#6b7280, #334155, #2563eb, #e5e7eb) n'appartenait a la
   palette du site. Elles sont ici, une seule fois, sur les jetons communs. */

/* Les ecarts de ces deux pages etaient tous ecrits a la main, et aucun ne
   tombait sur un barreau de l'echelle : .35rem, 2.25rem, 5rem, 1.15rem, .5rem,
   .75rem, .55rem, 1.1rem. Huit valeurs inventees pour une page de texte, quand
   l'echelle en propose dix. Les couleurs de ce bloc avaient deja ete ramenees
   sur les jetons communs (cf. le commentaire ci-dessus) ; les espacements, eux,
   etaient restes tels quels.

   Chacun prend le barreau voisin. Le seul qui demandait un arbitrage est le
   blanc au-dessus d'un titre de section, 2.25rem, pose exactement entre
   --espace-2xl (32) et --espace-3xl (40) : c'est --espace-2xl qui est retenu,
   parce que le titre est deja separe de son propre texte par --espace-md (16),
   et que 32 fait le double de 16. Ce qui se lit est ce rapport -- un titre plus
   loin de la section d'avant qu'il ne l'est de la sienne -- pas la valeur.

   Le bas de page fait exception a la lettre de la regle sans y echapper :
   aucun barreau ne vaut 5rem, mais ce n'est pas un ecart entre deux elements,
   c'est le vide sous le dernier. Il s'ecrit comme deux fois le plus grand
   barreau, ce qui le rattache a l'echelle au lieu de flotter a cote. */

.doc-wrap {
  max-width: var(--largeur-lecture);
  margin: 0 auto;
  padding: var(--espace-3xl) var(--espace-lg) calc(var(--espace-3xl) * 2);
}

.doc-wrap h1 {
  font-size: var(--fs-hero);
  margin: 0 0 var(--espace-xs);
  letter-spacing: var(--suivi-grand);
}

.doc-wrap h2 {
  font-size: var(--fs-h3);
  margin: var(--espace-2xl) 0 var(--espace-sm);
  letter-spacing: var(--suivi-grand);
}

.doc-maj {
  color: var(--gray-5);
  font-size: var(--fs);
  margin: 0 0 var(--espace-3xl);
}

.doc-wrap p,
.doc-wrap li {
  line-height: 1.65;
  color: var(--gray-6);
}

.doc-wrap ul {
  padding-left: var(--espace-lg);
  margin: var(--espace-sm) 0;
}

.doc-wrap li { margin-bottom: var(--espace-xs); }

/* Sauf sous le dernier, ou elle ne separe plus rien. Une liste n'a ni creux ni
   bordure en bas : la marge de son dernier element remonte a travers elle et
   ressort dehors, la ou `.tuile > :last-child` ne peut plus l'atteindre -- le
   commentaire de cette regle-la prevoit le cas et renvoie l'effondrement a
   l'endroit ou la marge est ecrite, c'est-a-dire ici.

   Au milieu d'un document elle ne se voyait pas : la liste porte --espace-sm
   au-dessous d'elle et le paragraphe suivant 1em au-dessus, les trois
   s'effondrent ensemble et le plus grand gagne -- 16 px, mesures le 31 aout
   2026 sur les quatre listes de Confidentialite qui sont suivies d'un texte.
   Elle ne se voyait qu'au fond d'une tuile, ou la marge de la liste a ete
   ramenee a zero et ou celle du dernier element restait donc seule a pousser :
   23,4 px de creux en bas pour 17 en haut, sur les trois seules tuiles du
   produit qui finissent par une liste. */
.doc-wrap li:last-child { margin-bottom: 0; }

.doc-wrap table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--espace) 0;
  font-size: var(--fs-lg);
}

.doc-wrap th,
.doc-wrap td {
  text-align: left;
  vertical-align: top;
  padding: var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
}

.doc-wrap th {
  color: var(--gray-5);
  font-weight: 600;
}

/* Un tableau large defile dans son propre cadre : la page, elle, ne part
   jamais de travers. */
.doc-scroll { overflow-x: auto; }

/* Ce que le cadre defilant ne dit pas, c'est ou finit le texte. Le registre des
   donnees traitees garde ses trois colonnes -- Donnee, Pourquoi, Base legale --
   parce qu'elles portent le sens ; mais a 390 px il reclame 372 px pour les 350
   du cadre, et se faisait couper en plein milieu d'un mot : « Interet legitim »,
   sans rien qui dise qu'il y a une suite.

   Ce qui elargit la table, c'est le mot le plus long de chaque colonne --
   « professionnelle », « commissaire », « electronique ». Le
   `overflow-wrap: break-word` pose sur `body` n'y peut rien, et son propre
   commentaire dit pourquoi : il n'entre pas dans le calcul de la largeur
   minimale, donc il ne retrecit jamais une colonne. La cesure, si. Le document
   porte `lang="fr"`, elle sait donc ou couper, et un mot coupe par un trait
   d'union se lit -- un mot coupe par un bord, non.

   Reserve au telephone, au barreau que la feuille se donne deja pour « la carte
   trop etroite pour deux colonnes » : au-dessus, chaque colonne a la place de
   ses mots, et une cesure y serait une facon d'ecrire qu'aucune autre table du
   site n'a. Cette page ne chargeant pas `mobile.css` -- elle est publique et
   autonome, cf. `confidentialite.html` --, la regle vit ici. */
@media (max-width: 560px) {
  .doc-wrap th,
  .doc-wrap td { hyphens: auto; }
}

/* Le bloc de contact n'a plus de cadre du tout. Il en portait un d'encart,
   pose dans une tuile qui porte le sien : deux traits emboites pour un nom de
   cabinet et une adresse de courriel, sous un titre -- « Nous ecrire » -- qui
   dit deja ce que ces deux lignes sont. Un cadre tient un ensemble ; deux
   lignes n'en sont pas un, et la section qui les porte est deja l'ensemble.

   Le creux part avec : c'etait la seule mesure que l'encart laissait a son
   porteur, et sans trait a longer il n'ecartait plus l'adresse que du vide.
   Restent les marges entre les deux lignes, qui, elles, sont a elles.

   Ce qui suit tient l'histoire du cadre disparu, parce qu'elle explique
   pourquoi le rang d'encart existe -- et le meme raisonnement, pousse d'un
   cran, est ce qui l'a retire ici.

   Le bloc etait une sous-zone posee dans une tuile, et le gabarit le
   disait : `class="doc-contact tuile-encart"`. Sa propre regle redeclarait
   pourtant le cadre du rang au-dessus -- --radius et --gray-3, soit trait pour
   trait celui de la tuile qui le contient. Une sous-zone y pesait donc le
   poids de sa zone, ce que le commentaire de `.tuile-encart` annonce en toutes
   lettres quelques milliers de lignes plus haut : deux rangs de cadre au meme
   dessin, et « la colonne deviendrait une echelle de traits sans hierarchie ».

   Releve le 31 aout 2026 en mesurant, sur seize ecrans, chaque surface
   encadree contre celle qui la contient : c'etait le seul endroit du produit
   ou l'enfant ne se distinguait pas de son parent. Sur cette page meme, les
   quatre reperes de la rubrique voisine sont de vrais encarts -- deux dessins
   pour un role identique, a trois cents pixels l'un de l'autre.

   Le cadre revient donc a `.tuile-encart`, et l'ecart d'avec ce qui precede a
   la cadence de la maison. La marge ecrite ici etait de toute facon morte :
   `.tuile > * + .tuile-encart` pose --espace-sm avec deux classes contre une,
   et l'emportait deja -- 9,6 px sortaient a la place des 16 declares. La
   retirer ne deplace donc rien a l'ecran, elle enleve une declaration qui
   affichait une mesure que personne n'appliquait.

   Ne restait que le creux, la seule mesure que l'encart laissait deliberement
   a son porteur -- et il est parti avec l'encart. */
.doc-contact p { margin: 0 0 var(--espace-xs); }
.doc-contact p:last-child { margin-bottom: 0; }

.doc-retour { margin-top: var(--espace-3xl); }

/* ---------------------------------------------------------------------------
   Exercices d'audit : le decoupage annuel d'un mandat.

   La liste reste a une ligne par mandat. Les annees s'y montrent en pastilles
   compactes ; le detail de chacune se lit en depliant la ligne.
   --------------------------------------------------------------------------- */

/* La ligne accueille desormais un second bloc (la liste depliee) : on
   l'autorise a passer a la ligne plutot que de le poser a cote du lien. */
.dossier-item { flex-wrap: wrap; }

.dossier-etat-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}

.dossier-etat-lock { width: var(--icon-xs); height: var(--icon-xs); color: var(--gray-5); }

.dossier-etat-badge-urgent { border-color: var(--orange); background: var(--orange-pale); }
.dossier-etat-badge-en_cours { border-color: var(--green); background: var(--green-pale); }
/* Verrouille : volontairement le plus discret des trois, c'est du travail
   termine dont il n'y a plus rien a attendre. */
.dossier-etat-badge-termine { background: var(--gray-1); }

.dossier-etat-exercice {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  flex: none;
}

/* Largeur fixe : c'est ce qui tient les colonnes suivantes (signataire,
   chevron) et, par ricochet, le compteur de FEC et le badge d'état qui les
   precedent -- ces deux-la sont pousses vers la droite par `margin-left: auto`,
   donc toute variation de largeur en aval les deplace. « 2025 », « 2024-2025 »
   et « 2026-03-31 » n'ont pas la meme longueur : sans emplacement fixe, aucune
   ligne ne s'aligne sur la precedente. Le dimensionnement suit celui de
   .dossier-statut-slot, pose plus haut pour la meme raison.

   Contenu cale a gauche, et non centre ni cale a droite. Les trois autres
   emplacements ne contiennent qu'un objet de taille constante -- une pastille,
   un badge -- pour lequel les trois alignements reviennent au meme d'une ligne
   a l'autre. Celui-ci contient du texte de longueur variable, et c'est son
   PREMIER caractere qui doit tomber au meme endroit sur toutes les lignes :
   c'est par la gauche qu'on lit une colonne. Cale a droite, « 2025 » laissait
   42 px de vide a sa gauche la ou « 2026-03-31 » n'en laissait que 6 ; centre,
   les deux partageaient un axe median que l'oeil ne suit pas. Le bord gauche
   de l'emplacement reste a la meme distance du badge d'etat qu'avant (le
   `gap` de .dossier-statut-group), donc rien d'autre ne bouge. */
/* La colonne du compteur d'echeance, en tete du groupe. Largeur fixe pour la
   raison qui vaut pour ses trois voisines : une ligne sur deux porte un
   compteur, et sans colonne l'etat, les avatars et la tuile du titulaire
   tomberaient a une abscisse differente d'une ligne a l'autre. Contenu centre,
   comme le badge d'etat : c'est un objet de largeur presque constante, pas du
   texte qu'on lit par la gauche. */
.dossier-echeance-slot {
  width: var(--col-echeance);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Le tableau a rabats reduit a sa rangee de volets : « un style esthetique et
   immediatement comprehensible, inspire des tableaux d'aeroport » (ticket du
   6 septembre 2026). C'est la meme vignette que l'Assistant et que la liste
   commune de « Messages » -- meme fond d'encre, memes volets, memes teintes
   d'urgence --, privee de son bandeau de date : une ligne de liste n'a pas la
   hauteur d'une page de calendrier, et trois cent soixante-quatorze pages de
   calendrier empilees ne se liraient plus comme une liste. La date entiere
   reste dans l'infobulle, avec le nombre de jours en clair.

   Ni flottante ni margee, contrairement a la vignette du bloc de seance : elle
   est ici le contenu d'une cellule, c'est la colonne qui la place. */
/* Selecteur porte par la cellule : la vignette pose sa largeur de trois
   centimetres plus bas dans la feuille (`.arrete-rebours`), et a specificite
   egale c'est elle qui gagnait -- le tableau restait donc a 3,1 rem et rognait
   ce qui depassait. Ici il prend la largeur de ce qu'il porte, quatre volets ou
   un cadenas de plus, et c'est la colonne qui le centre. */
.dossier-echeance-slot .arrete-rebours.dossier-echeance {
  float: none;
  width: auto;
  margin: 0;
}

/* Les volets d'une ligne de liste : un cran sous ceux de la vignette, qui sont
   dimensionnes pour trois centimetres de large. --fs-sm est la taille que la
   vignette elle-meme prend deja a quatre volets. */
.dossier-echeance-slot .arrete-flap { font-size: var(--fs-sm); }

/* LE CADENAS DE LA CLOTURE, dans le tableau et avant les volets.

   « Dès leur signature, elle est remplacée par une nouvelle pastille "Clôture
   du dossier", avec un cadenas très visible et un compte à rebours de 60 jours »
   (ticket du 8 septembre 2026). Rouge sur l'encre du tableau : c'est la teinte
   de ce qui se ferme, la meme que le cadenas d'un exercice archive, et elle se
   voit d'un bout a l'autre de la liste sans rien ajouter a la hauteur d'une
   ligne -- c'est la largeur de la colonne qui lui fait sa place
   (--col-echeance), pas le rang.

   Dans la rangee des volets et non au-dessus : un bandeau de plus aurait
   rehausse toutes les lignes de la liste, y compris celles qui ne portent
   aucune echeance. */
.dossier-echeance-verrou {
  flex: none;
  align-self: center;
  width: var(--icon-xs);
  height: var(--icon-xs);
  margin-right: var(--espace-3xs);
  color: var(--red);
}

/* ET LA MARQUE DU CABINET SUR L'AUTRE ECHEANCE, A LA MEME PLACE.

   « Affiche le retard par rapport a cette date [...] avec le symbole CAC : le
   petit C rouge dans le grand C rouge » (ticket du 16 septembre 2026). Les deux
   echeances se succedent dans la meme pastille, et une seule des deux etait
   nommee : le cadenas disait la cloture, son absence ne disait rien, et un J+1
   nu ne disait pas de quoi il comptait le retard.

   Meme gabarit que le cadenas ci-dessus, au pixel pres, parce que c'est la meme
   case : deux reperes qui ne se croisent jamais mais qui occupent la meme
   place, et un ecart de taille entre eux se verrait en descendant la liste.
   Meme rouge, aussi -- c'est la marque telle qu'elle s'ecrit partout ailleurs
   dans le produit (`.dossier-cocac-badge`, la tuile de l'Assistant), et le
   ticket la demande rouge. Elle ne suit donc pas l'urgence des volets : la
   marque dit DE QUOI on compte les jours, les volets disent ou l'on en est. */
.dossier-echeance-marque {
  flex: none;
  align-self: center;
  width: var(--icon-xs);
  height: var(--icon-xs);
  margin-right: var(--espace-3xs);
  color: var(--red);
}

/* Et « Jour J », qui ne se decoupe pas, descend du meme cran : le mot entier
   doit tenir dans les cinquante pixels de la colonne. Selecteur porte par la
   cellule, sans quoi la regle de la vignette -- ecrite plus bas dans la feuille,
   a specificite egale -- reprendrait la main. */
.dossier-echeance-slot .arrete-rebours[data-volets="mot"] .arrete-flap {
  font-size: var(--fs-3xs);
}

/* Ce que le compteur cache : la date. « Quand je survole un J- ou J+ ça m'ouvre
   un menu qui me montre la date en question » (ticket du 14 septembre 2026).
   -------------------------------------------------------------------------
   Le geste, la boite et la mecanique sont ceux du resume des FEC, deux colonnes
   plus a gauche (`.dossier-fec-resume`) : meme survol, meme panneau blanc pose
   au-dessus de la ligne, meme retournement vers le bas quand la place manque
   (`dossiers.js`). Deux panneaux qui s'ouvrent du meme geste sur la meme ligne
   ne peuvent pas s'ouvrir de deux facons.

   L'ancre est une enveloppe autour de la vignette, et non la vignette : celle-ci
   porte `overflow: hidden` pour tenir ses volets dans son cadre, et un panneau
   absolu pose dedans serait coupe au premier pixel. */
.dossier-echeance-ancre {
  position: relative;
  display: flex;
  align-items: center;
  cursor: default;
}

.dossier-echeance-resume {
  position: absolute;
  bottom: calc(100% + .5rem);
  /* Centre sur la vignette : la colonne est au milieu de la ligne, il reste de
     la place des deux cotes, et un panneau de deux lignes cale a droite
     pointerait a cote de ce qu'on survole. */
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  display: none;
  flex-direction: column;
  gap: var(--espace-3xs);
  width: max-content;
  max-width: 320px;
  padding: var(--espace-sm) var(--espace);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  font-weight: 400;
  text-align: left;
  /* Meme raison que pour le resume des FEC : le panneau flotte au-dessus des
     lignes voisines, et laisser la souris le traverser ferait clignoter le
     mandat qui est dessous. On le regarde, on ne le manipule pas. */
  pointer-events: none;
}

.dossier-echeance-ancre:hover .dossier-echeance-resume,
.dossier-echeance-ancre:focus-visible .dossier-echeance-resume { display: flex; }

/* Retourne vers le bas quand la tuile qui defile couperait le panneau par le
   haut : la classe est posee par `dossiers.js`, qui mesure au survol. */
.dossier-echeance-ancre-dessous .dossier-echeance-resume {
  bottom: auto;
  top: calc(100% + .5rem);
}

/* Ce qu'on compte, en petit : c'est la ligne de service, pas la reponse. */
.dossier-echeance-resume-titre {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  color: var(--gray-5);
  white-space: nowrap;
}

/* Et la reponse, qui est la date : c'est elle qu'on est venu chercher. */
.dossier-echeance-resume-date {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--black);
  white-space: nowrap;
}

.dossier-exercice-slot {
  width: var(--col-exercice);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  white-space: nowrap;
}

.dossier-signataire-slot {
  width: var(--col-signataire);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

/* L'avatar du signataire est le plus haut de la ligne : tant qu'il fait 28 px,
   aucun rabotage du blanc ne descend la ligne sous 44. Reduit a 24 px ici
   seulement -- deux initiales y tiennent encore -- et nulle part ailleurs :
   .dossier-avatar sert aussi aux messages, au compte et a l'equipe du cabinet,
   ou rien ne demande de serrer. Selecteur porte par le creux et non par la
   liste, pour ne pas rattraper au passage les bulles de collaborateurs, qui
   ont leur propre taille. */
.dossier-signataire-slot .dossier-avatar {
  --avatar-d: 24px;
}

/* La voie du signataire s'élargit quand le lecteur a demandé à lire les noms
   (demande du 9 septembre 2026). Une capsule nommée fait jusqu'à cinq fois le
   diamètre d'un rond : laissée dans les 24 px prévus pour un disque, elle
   débordait par la gauche sur la pile des collaborateurs et par la droite sur
   la colonne de l'exercice.

   C'est le jeton qui est redéfini, pas la règle qui le lit : l'en-tête de tri
   calcule sa marge sur `--col-signataire`, et la colonne et son titre doivent
   bouger ensemble -- c'est exactement ce que dit le commentaire de `:root` sur
   les mesures écrites deux fois. Porté par `<html>`, où le serveur pose ce que
   le lecteur veut voir. */
html[data-intervenants="nom"] {
  --col-signataire: 120px;
}

/* Le chevron de depliage reprend .row-toggle / .arrow de l'arbre d'analyse
   (rotation, couleur, taille) : c'est le meme geste, il doit avoir la meme
   tete. Seul l'alignement dans la ligne est propre a la liste. */
.dossier-exercices-toggle {
  flex: none;
  padding: var(--espace-2xs) var(--espace-3xs) var(--espace-2xs) var(--espace-2xs);
}

.dossier-exercices {
  flex-basis: 100%;
  list-style: none;
  margin: 0;
  /* Aligne les sous-lignes sur le nom du mandat. La voie est calculee sur
     .dossier-item, terme par terme ; le creux droit rend au dernier bouton
     de la sous-ligne l'aplomb du chevron de la ligne du dessus. */
  padding: 0 var(--espace-sm) var(--espace-sm) var(--dossier-voie-nom);
  background: var(--gray-1);
}

.dossier-exercice {
  display: flex;
  align-items: center;
  gap: var(--espace);
  padding: var(--espace-xs) 0;
}

.dossier-exercice + .dossier-exercice { border-top: 1px solid var(--gray-3); }

.dossier-exercice-lien {
  text-decoration: none;
  color: var(--black);
  min-width: 8rem;
}

.dossier-exercice-lien:hover .dossier-exercice-titre { text-decoration: underline; }
.dossier-exercice-titre { font-size: var(--fs-sm); font-weight: 500; }

.dossier-exercice-cloture {
  display: block;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.dossier-exercice-etat { display: flex; align-items: center; }

/* Le retour d'un enregistrement de cloture : combien d'exercices ont suivi. */

/* Les fenetres du site (confirmation, message, saisie), qui remplacent celles
   du navigateur : meme typographie, memes couleurs, meme bouton primaire que
   le reste. Voir static/js/dialogue.js. */
.dialogue,
.dialogue-campagne,
.dialogue-lecteurs,
.dialogue-deplacer {
  border: 1px solid var(--gray-2);
  /* --radius-md n'existe pas dans l'echelle (xs, sm, base, lg) : la ligne ne
     posait donc aucun arrondi, et les deux fenetres sortaient a angles droits
     -- signale le 6 aout 2026. Une surface flottante prend le grand arrondi,
     comme la carte de connexion et la barre de selection. */
  border-radius: var(--radius-lg);
  padding: var(--espace-lg) var(--espace-xl);
  min-width: 320px;
  max-width: min(30rem, calc(100vw - 2rem));
  color: var(--black);
  box-shadow: var(--shadow-lg);
}
.dialogue::backdrop { background: var(--voile); }

/* Le cadrage d'une photo de profil (demande du 25 août 2026) : la photo dans
   un carré, un rond par-dessus qui montre ce qui sera gardé.

   Le carré vit à part de la scène qu'il contient : c'est lui qui coupe ce qui
   dépasse, et la photo à l'intérieur est posée en absolu autour de son centre,
   `cadrage-photo.js` ne pilote qu'une taille et une translation. */
.cadrage-scene {
  position: relative;
  width: 256px;
  height: 256px;
  max-width: 100%;
  margin: 0 auto;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--gray-2);
  cursor: grab;
  touch-action: none;
  user-select: none;
}

.cadrage-scene-tenue { cursor: grabbing; }

.cadrage-image {
  position: absolute;
  top: 50%;
  left: 50%;
  max-width: none;
  transform-origin: center;
  pointer-events: none;
}

/* Le rond : un simple voile qui assombrit tout ce qui n'y entre pas. Une
   ombre intérieure démesurée plutôt qu'un découpage : c'est la seule façon
   d'obtenir le trou sans poser un second élément par-dessus la photo, et elle
   laisse le geste de glisser passer dessous. */
.cadrage-masque {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  box-shadow: 0 0 0 9999px rgba(14, 18, 22, .45);
  pointer-events: none;
}

.cadrage-zoom { margin: 0 auto; width: 256px; max-width: 100%; }
.dialogue-form { display: flex; flex-direction: column; gap: var(--espace); }
.dialogue-titre { margin: 0; font-weight: 600; }
.dialogue-message { margin: 0; font-size: var(--fs-sm); color: var(--gray-5); white-space: pre-line; }
.dialogue-saisie {
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  font: inherit;
}
/* Plusieurs cases dans la meme fenetre : chacune son intitule au-dessus, comme
   partout ou le produit nomme une case ailleurs que dans son invite (le volet
   Mandat, « Mon compte »). Le champ lui-meme est un `.aglae-input`, donc le
   calendrier du site s'y pose sans une regle de plus. */
/* La feuille du navigateur pose `overflow: auto` sur tout `<dialog>`, ce qui
   rognait le calendrier au bord de la boite : il se deplie sous son champ,
   c'est-a-dire au-dela du bas de la fenetre quand le champ est le dernier.
   Posee par dialogue.js sur les seules fenetres a cases, pour que les autres
   gardent le reglage du navigateur. */
.dialogue-deborde { overflow: visible; }
.dialogue-champs { display: flex; flex-direction: column; gap: var(--espace-sm); }
.dialogue-champ { display: flex; flex-direction: column; gap: var(--espace-2xs); }
.dialogue-champ-libelle { font-size: var(--fs-sm); color: var(--gray-6); }

.dialogue-actions { display: flex; justify-content: flex-end; gap: var(--espace); align-items: center; }

/* Associer une piece du mandat a ce qu'elle justifie (demande du 27 aout
   2026) : le compte, la portee, puis l'ecriture. Trois listes deroulantes,
   deja habillees a la base de la feuille -- il ne reste ici que l'etiquette
   au-dessus de son champ, et la largeur : le libelle d'une ecriture porte sa
   date, son intitule et son montant, et se coupait a mi-mot dans les 30 rem
   d'une fenetre de confirmation. */
dialog.association-boite { width: min(38rem, calc(100vw - 2rem)); max-width: none; }

.association-champ {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.association-champ[hidden] { display: none; }

.association-champ select { width: 100%; }

.association-etat { margin: 0; font-size: var(--fs-xs); color: var(--gray-5); }

/* Boite « Ajouter une campagne » : la nature (exercice ou situation) et la
   date complete. Un <dialog> plutot qu'un window.prompt, qui ne savait
   demander qu'une seule ligne de texte -- c'est-a-dire l'annee seule. */
.dialogue-campagne::backdrop { background: var(--voile); }
.dialogue-campagne-form { display: flex; flex-direction: column; gap: var(--espace); }
.dialogue-campagne-titre { font-weight: 600; margin: 0; }
.dialogue-campagne-types { display: flex; gap: var(--espace-lg); font-size: var(--fs-sm); }
.dialogue-campagne-types label { display: flex; align-items: center; gap: var(--espace-xs); cursor: pointer; }
.dialogue-campagne-aide { margin: 0; font-size: var(--fs-xs); color: var(--gray-5); }
.dialogue-campagne-date { display: flex; gap: var(--espace); }
.dialogue-campagne-date label {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.dialogue-campagne-erreur { margin: 0; font-size: var(--fs-xs); color: var(--red); }
.dialogue-campagne-actions { display: flex; justify-content: flex-end; gap: var(--espace); align-items: center; }

/* Le compteur de FEC d'un exercice porte le meme panneau que celui de la ligne
   repliee (.dossier-fec-count plus haut), restreint aux fichiers de son annee.
   Il ne portait qu'un `title` disant « FEC clotures en 2025 » : deplier un
   client faisait donc perdre le resultat de l'exercice, qu'on lisait juste
   au-dessus (demande du 24 aout 2026). Meme ancrage, meme ouverture au survol
   et au clavier ; le panneau lui-meme est decrit une seule fois. */
.dossier-exercice-fec {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  position: relative;
  cursor: default;
}

.dossier-exercice-fec .icon { width: var(--icon-sm); height: var(--icon-sm); }

.dossier-exercice-fec:hover .dossier-fec-resume,
.dossier-exercice-fec:focus-visible .dossier-fec-resume { display: flex; }

/* Vers la droite, a l'inverse du panneau de la ligne repliee. Celui-ci pend
   sous un compteur cale a droite de l'ecran et s'ouvre donc vers la gauche ;
   le compteur d'un exercice, lui, se tient a un cran du bord gauche, et le
   meme ancrage faisait sortir le panneau de la fenetre -- moitie de tableau
   coupee, titre ampute. */
.dossier-exercice-fec .dossier-fec-resume {
  right: auto;
  left: -.5rem;
}

.dossier-exercice-verrou {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  margin-left: auto;
}

/* Rouge au repos comme toutes les corbeilles depuis le 6 septembre 2026 : voir
   .annexe-ligne-retirer, ou la regle est ecrite. */
.dossier-exercice-retirer {
  border: none;
  background: none;
  padding: var(--espace-2xs);
  cursor: pointer;
  color: var(--red);
  flex: none;
}

.dossier-exercice-retirer:hover { color: var(--red-dark); }
.dossier-exercice-retirer .icon { width: var(--icon-sm); height: var(--icon-sm); }
.dossier-exercice-ajout { padding-top: var(--espace-sm); }

/* ---- Selecteur d'exercice, en tete de la fiche mandat ---- */

.exercice-selecteur {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  padding: var(--espace-3xs);
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
}

.exercice-onglet {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: calc(var(--radius-sm) - 2px);
  text-decoration: none;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--gray-5);
  /* « 2025-2026 » est deux fois plus large que « 2025 » : sans cela l'onglet
     d'un exercice decale se coupait au trait d'union et tenait sur deux
     lignes, ce qui decalait toute la barre d'en-tete. */
  white-space: nowrap;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.exercice-onglet:hover { background: var(--cyan-pale); }

.exercice-onglet.active {
  background: #fff;
  color: var(--black);
  font-weight: 600;
  /* Le relief du barreau, pas une ombre a soi. Celle qui etait ecrite ici tirait
     au noir pur, la seule de la feuille avec celle de la feuille de commentaire :
     les gris du produit sont legerement froids, et un noir franc pose sur du blanc
     se voit d'autant mieux qu'il est petit. Meme geometrie qu'avant -- --shadow-sm
     commence par le meme `0 1px 2px` --, teintee ardoise et doublee du liseré court
     que porte toute surface posee du site. */
  box-shadow: var(--shadow-sm);
}

.exercice-onglet-lock { width: var(--icon-xs); height: var(--icon-xs); color: var(--gray-5); }

/* ---- Reglages : l'ouverture d'un exercice ferme ---- */

.reglages-exercices {
  display: flex;
  flex-direction: column;
  /* Le barreau de la liste des intervenants, deux groupes plus haut. Ce gap
     valait .35rem, soit huit dixiemes de pixel de moins : un ecart que
     personne ne voit et que rien ne justifiait. */
  gap: var(--espace-xs);
}

/* La ligne d'un exercice est une carte du panneau, comme celle d'un
   intervenant et celle d'une nature de rapport : la recette se lit juste
   au-dessus, cette regle-ci ne pose plus que la mise en page.

   Elle etait la seule liste du panneau que rien ne cernait. Les intervenants
   sont des cartes, la presence en ligne et l'equipe sont des rangees de
   controles habilles ; ici, trois mots poses sur le blanc du panneau, et une
   corbeille rouge encadree a cote d'eux. Le seul element delimite de la ligne
   etait donc le geste destructeur -- c'est lui qu'on voyait en premier, faute
   de quoi que ce soit d'autre a voir.

   Le commentaire de cette corbeille disait deja le probleme sans le corriger :
   « ici elle termine une ligne de texte dans une colonne ou tout le reste est
   cerne ». Le voisinage tranche, en effet ; il fallait encore que la ligne en
   fasse partie. */
/* ---------- La carte du panneau Mandat ---------- */

/* Le panneau range ce qu'il tient en cartes : une par exercice, une par
   intervenant, une par nature de rapport. Meme recette pour les trois --
   filet --gray-2, --radius, fond blanc, --shadow-sm, et le creux des cartes
   du panneau.

   Elle etait ecrite deux fois, a quatre mille trois cents lignes d'ecart, en
   dix declarations rigoureusement identiques ; le commentaire de la seconde
   disait « meme recette » sans que rien ne le garantisse. Une recette
   recopiee n'est pas une recette : elle est deux recettes qui se ressemblent
   aujourd'hui.

   Les pieces deposees dans « Rapports et attestations » la rejoignent. Elles
   etaient posees a nu, et c'etait la derniere liste du panneau que rien ne
   cernait -- le seul endroit ou l'on pouvait deposer un fichier sans voir sur
   quoi. La tuile ne range plus des natures mais des documents (suivi du 31
   aout 2026) ; ce que la carte cerne a change de contenu, pas de famille.

   Ce que la regle ne pose pas : la mise en page. Chacune des trois aligne son
   contenu a sa facon -- c'est leur affaire, pas celle de la carte. */
.intervenant-carte,
.reglages-exercice,
.rapport-cac {
  padding: var(--espace-sm) var(--espace-md);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-sm);
}

.reglages-exercice {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  font-size: var(--fs-sm);
}

.reglages-exercice-annee { font-variant-numeric: tabular-nums; min-width: 3.5rem; }

.reglages-exercice-etat {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  color: var(--gray-5);
}

.reglages-exercice-etat .avancement-lock-icon { width: var(--icon-sm); height: var(--icon-sm); }
.reglages-exercice-etat-ouvert { color: var(--green-dark); }

/* Le geste qui termine la carte se range a son bord droit, comme le crayon et
   la corbeille d'un intervenant deux listes plus haut.

   La carte d'un exercice a recu la recette de celle d'un intervenant -- filet,
   arrondi, ombre, remplissage -- sans en recevoir la mise en page : son
   contenu tient en trois mots, et la corbeille restait collee a eux, suivie de
   onze cents pixels de blanc jusqu'au bord. Une carte pleine largeur dont tout
   le contenu s'arrete au premier quart ne se lit pas comme une carte, mais
   comme une rangee qui n'a pas su se remplir -- exactement ce que la feuille
   du telephone dit deja d'un carre de 44 px laisse contre le bord gauche.

   « Rouvrir » suit la meme regle : il occupe la meme place sur une campagne
   verrouillee que la corbeille sur une campagne ouverte, et les deux formes de
   la carte gardent ainsi la meme silhouette. Cela le laisse aussi ou son
   commentaire le veut, loin du parcours courant. */
.reglages-exercice-retirer,
.reglages-exercice-rouvrir {
  margin-left: auto;
}

/* Discret a dessein : la reouverture existe, elle ne s'annonce pas. */
.reglages-exercice-rouvrir {
  border: none;
  background: none;
  padding: 0;
  font-family: var(--sans);
  font-size: var(--fs-xs);
  color: var(--gray-4);
  text-decoration: underline;
  cursor: pointer;
}

.reglages-exercice-rouvrir:hover { color: var(--gray-5); }

/* Une liste libre est suivie de sa rangee d'ajout. Le filet du dernier bloc
   est retire juste au-dessus (`:last-child`), et plus rien ne separait alors
   la derniere corbeille du « Ajouter... » qui suit : les deux boites se
   touchaient exactement, zero pixel entre elles, sur les listes du panneau
   Mandat.

   La marge est posee sous la liste et non sur la rangee qui suit : le modele
   de ligne de la presence en ligne est un `<template>`, qui ne s'affiche pas
   mais reste un frere -- un `+` sautait donc la rangee d'ajout de cette
   liste-la, la seule a en avoir un.

   L'equipe est la quatrieme de ces listes et n'y figurait pas : elle est une
   grille la ou les trois autres sont des colonnes flex, et c'est ce qui l'a
   fait manquer. Elle etait donc la seule du panneau a coller son « Ajouter
   quelqu'un... » contre sa derniere ligne -- et le pire des quatre cas, parce
   que ce menu et le « Ne pas suivre » de la ligne au-dessus sont le meme
   controle, la meme `.dossier-assigne-select` : sous 600 px ou la ligne se
   replie, deux listes deroulantes identiques se retrouvaient bord a bord, sans
   rien pour dire qu'elles ne font pas partie du meme reglage. */
.reglages-intervenants-liste,
.reglages-presence-liste,
.reglages-exercices,
.reglages-equipe {
  margin-bottom: var(--espace-sm);
}

/* La corbeille d'une mission porte le cadre de celle d'un intervenant et de
   celle du logo, dans le meme panneau : meme geste -- supprimer une entree
   d'une liste --, donc meme boite de 28 px, meme icone de 16 et meme rouge.
   Elle en portait un troisieme dessin, gris et de 14 px, sans cadre : le
   dernier bouton nu du panneau Mandat, et le seul geste destructeur a y peser
   moins lourd que le « + Ajouter une mission » pose juste dessous.

   Elle cesse donc de suivre la corbeille d'une ligne depliee de la liste des
   clients, dont elle etait la copie exacte. Celle-la est seule a l'extremite
   droite d'une bande grise, sans aucun controle autour d'elle : un cadre y
   serait une boite blanche posee sur rien. Ici elle termine une ligne de texte
   dans une colonne ou tout le reste est cerne. Le meme dessin ne dit pas la
   meme chose aux deux endroits ; c'est le voisinage qui tranche, pas la
   ressemblance des deux gestes. */
.reglages-exercice-retirer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-sm);
  height: var(--h-sm);
  flex: none;
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--red);
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.reglages-exercice-retirer:hover {
  background: var(--red-pale);
  border-color: var(--red);
}

/* Une section « Controle de l'import juridique » vivait ici : un bandeau de
   chiffres encadres, un tableau et des pastilles d'etat. Treize regles, aucun
   porteur -- ni gabarit, ni JS, ni Python, ni Swift -- et des commentaires qui
   parlaient encore de « ces trois tuiles » disparues. Retiree le 31 aout 2026,
   le jour ou les chiffres d'une ronde sont devenus des cases : la feuille
   portait deux recettes pour la meme idee, dont une morte. Ce qui reste vivant
   sous le prefixe « controle- » est le bandeau d'avertissement et les marques
   de tableau du mandat, qui n'ont rien a voir et n'ont pas bouge. */

/* ---------- Les types de fichier de la zone Juridique ---------- */
/* Une famille, une teinte. Les trente mille documents du juridique portaient
   tous la meme feuille grise : rien ne distinguait un tableau d'un statut sans
   lire le nom jusqu'a son extension. La couleur fait le tri avant la lecture,
   et l'icone dit la nature.

   Ces teintes sont appariees a celles de l'app (TypeFichier.swift) dans
   app/parite.json, section regles_affichage : un tableur vert dans le
   navigateur et orange sur le telephone serait pire que pas de couleur. */
/* Le selecteur passe par la cellule : `.sources-nom-cell .icon` pose deja le
   gris de la colonne, et une classe seule perdait contre lui. */
/* Le PDF en gris et non en rouge (demande du 14 aout 2026). C'est la famille
   la plus nombreuse -- neuf lignes sur dix dans le Juridique d'un mandat --, et
   le rouge y mettait une alerte que rien ne justifie : le rouge dit ailleurs
   qu'une source est en erreur ou qu'un mandat est urgent. Le gris fonce laisse
   la couleur aux familles rares, celles qu'on cherche justement du regard. */
.sources-nom-cell .juridique-icone-pdf { color: var(--gray-5); }
.sources-nom-cell .juridique-icone-texte { color: var(--blue); }
.sources-nom-cell .juridique-icone-tableur { color: var(--green); }
.sources-nom-cell .juridique-icone-presentation { color: var(--orange); }
.sources-nom-cell .juridique-icone-image { color: var(--purple); }
.sources-nom-cell .juridique-icone-courriel { color: var(--cyan-dark); }
.sources-nom-cell .juridique-icone-archive { color: var(--yellow); }
.sources-nom-cell .juridique-icone-code { color: var(--gray-5); }
.sources-nom-cell .juridique-icone-note { color: var(--gray-4); }
.sources-nom-cell .juridique-icone-lien { color: var(--gray-4); }
.sources-nom-cell .juridique-icone-inconnu { color: var(--gray-4); }

/* L'icone du format s'efface derriere celle du cycle : « quand un fichier est
   lie a un ou plusieurs cycles, l'icone, comme l'icone PDF, doit disparaitre et
   ne reapparaitre que s'il n'est plus lie a un cycle » (ticket du 28 aout
   2026). La regle est ecrite ici parce qu'un <svg> ne repond pas a la propriete
   `hidden` du DOM comme un element HTML : c'est l'attribut que la facade pose
   (voir poserMarqueDeCycleSurLaLigne), et c'est ce selecteur qui le lit. */
.sources-nom-cell .juridique-icone[hidden] { display: none; }

/* ---------- « Maison » : produit par le cabinet ---------- */
/* Une note d'Audit France et un statut recu du client se lisent de la meme
   facon dans une liste de fichiers. Le badge le dit sans qu'on ait a ouvrir :
   c'est ce qui distingue notre production de ce qu'on nous a remis, y compris
   devant le client. */
/* La marque du cabinet sur un document produit ici. Le logo remplace le mot
   « Maison » : il se reconnait sans se lire, et une ligne de fichier est deja
   pleine de texte. Sans chape ni fond -- le trace se pose sur la teinte de la
   ligne, quelle qu'elle soit, la ou un fond pale aurait fait une tache sur une
   ligne pointee. */
.badge-maison {
  display: inline-flex;
  align-items: center;
  margin-left: var(--espace-xs);
  color: var(--red);
  vertical-align: middle;
}

/* Le selecteur passe par la cellule, comme les icones de famille juste
   au-dessus : `.sources-nom-cell .icon` pose le gris de la colonne et gagnait
   contre la couleur posee sur le badge -- la marque sortait grise.

   La marge, elle, est redevenue celle des icones de famille le 5 septembre
   2026, quand la marque a pris leur place en tete de ligne : c'est le nom qui
   la suit maintenant, et il lui faut le meme ecart qu'a l'icone qu'elle
   remplace. Elle valait zero tant que la marque fermait la ligne, ou rien ne
   la suivait.

   Ce qui ne se redit pas ici, c'est la taille. Elle valait 15 px, hors echelle,
   sur une ligne qui en porte neuf autres a 16 : les icones de famille, la
   marque de controle, les cinq actions de fin de ligne -- et jusqu'au bouton
   qui pose cette marque-la, qui en dessine le trace a 16 sans jamais avoir eu
   besoin de le dire. Le meme dessin se montrait donc deux fois sur une meme
   ligne a un pixel d'ecart, et la marque posee retombait d'un demi-pixel sous
   le rang de ses voisines (releve le 29 aout 2026 sur le Juridique d'ACBB). */
.sources-nom-cell .badge-maison {
  margin-left: 0;
}

.sources-nom-cell .badge-maison .icon {
  margin-right: var(--espace-xs);
  color: var(--red);
}

/* `display: inline-flex` ci-dessus l'emporte sur la regle du navigateur pour
   l'attribut `hidden` : sans cette ligne, le badge reste visible sur TOUTES
   les lignes, y compris celles qui ne portent pas la marque. */
.badge-maison[hidden] { display: none; }

/* Le bouton qui posait la marque a disparu de la rangee le 2 septembre 2026 :
   « regroupe toutes les actions situees en fin de ligne dans un seul bouton
   "..." ». La marque se pose depuis ce menu ; ce qui reste ici est le badge
   ci-dessus, qui la montre. */

/* La ligne d'un document juridique repond au clic : c'est la marque de
   controle qui avance, comme sur une ligne de cycle. */
.sources-table tr.controle-clickable:hover > td { background: var(--gray-1); }

/* ---------------------------------------------------------------------------
   Consommation : un bloc par fournisseur, et rien qui traverse.

   Le bloc OpenAI ne se lit pas comme un tableau de depenses mais comme une
   reconciliation. D'ou la mise en page en trois cases de meme rang : le
   facture, l'ecart, le compte. L'ecart est au centre parce que c'est lui
   qu'on vient regarder ; il n'est pas plus petit que les deux autres, et il
   reste affiche meme quand il est nul.

   Le bloc Supabase ne se lit pas ainsi -- il n'y a la qu'une seule mesure et
   un bareme. Les deux blocs ne partagent donc que leur forme : une tete qui
   nomme le fournisseur, dit ce qu'il facture et porte son chiffre, puis ce qui
   lui est propre. Chacun porte sa teinte dans `--conso-teinte`, une seule fois
   et non a chaque regle : c'est ce jeton local que suivent le jeton d'en-tete
   et les jauges du bloc (demande du 24 aout 2026 : « separe strictement le
   cote OpenAI du cote Supabase »).

   Aucune couleur nouvelle : la palette de `:root` suffit, et le verificateur
   de parite compare `:root` a `Palette.swift` teinte par teinte.
   --------------------------------------------------------------------------- */

.conso-main { display: flex; flex-direction: column; gap: var(--espace-lg); }

/* Chaque fournisseur est une carte a lui, et non une bande de plus dans le
   flux : c'est la forme qui dit qu'on change de facture en passant de l'une a
   l'autre. `.panel` ne pose qu'une marge basse, remise a zero ici -- c'est le
   `gap` de `.conso-main` qui espace les deux cartes, sans quoi les deux
   s'additionneraient.

   Une carte, donc le creux des cartes : --espace-md dedans, --espace-lg sur
   les cotes, comme .arbitrage et .ticket-card. Elle portait trois valeurs
   differentes -- 17,6 en haut, 20 sur les cotes, 20,8 en bas -- dont deux hors
   echelle, et une asymetrie haut/bas de 3,2 px que rien ne demandait. */
.conso-bloc {
  --conso-teinte: var(--cyan);
  margin-bottom: 0;
  padding: var(--espace-md) var(--espace-lg);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-sm);
}

/* LA TEINTE D'UN FOURNISSEUR EST CELLE DE SA MARQUE, PRISE DANS LA PALETTE.
   « Les couleurs contrastantes, par exemple la, Supabase est en violet alors
   que c'est vert : fais des couleurs contrastantes adaptees a la couleur du
   service » (suivi du 18 septembre 2026).

   Ce que ce jeton peint est tout ce qui entoure le logo : le lavis du haut de
   la tuile, son trait quand elle est ouverte, l'esquisse de serie, le
   « Detail », et les titres du volet. Il etait choisi par elimination -- le
   cyan au fournisseur principal, le violet a l'infrastructure, le bleu au
   depot, chaque teinte prise ecartant la suivante --, si bien que la tuile de
   Supabase portait un carre vert dans un lavis violet. Le carre disait la
   marque, le reste disait autre chose, et c'est cet ecart-la qu'on voit.

   La teinte suit donc desormais la marque, dans la famille de sa couleur. Pas
   la couleur de marque elle-meme (`--marque-*`) : ces hexadecimaux sont faits
   pour un aplat de trente pixels portant un logo blanc, et le vert de Supabase
   ecrit en texte sur du blanc ne se lit plus. Le barreau de la palette dans la
   meme famille se lit, lui, et il existe des deux cotes -- l'app peint la meme
   tuile (`TeintesDashboard.tuile`), et une teinte qui n'existerait que sur le
   site rendrait Supabase vert dans le navigateur et violet sur le telephone.

   Deux consequences qu'il faut assumer plutot que contourner :

   - Le vert et l'orange disent un etat ailleurs sur cette page, et c'etait la
     raison de les ecarter d'ici. Elle ne tient plus des lors qu'une tuile porte
     sa pastille d'etat : c'est elle, et elle seule, qui affirme quelque chose.
     Le lavis dit de qui on parle, pas si ca va bien.
   - Vercel et le depot partagent le noir, parce que leurs deux marques sont
     noires. Ce n'est pas une collision a arbitrer : la couleur n'a jamais
     distingue les tuiles entre elles -- OpenAI, Tickets et Temps passe
     partagent le cyan depuis le premier jour --, ce sont le nom et le logo qui
     le font. */
.conso-bloc-mistral,
.conso-tuile-mistral { --conso-teinte: var(--orange); }

/* Claude prend le barreau sombre de l'orange : sa couleur de marque est une
   terre cuite, plus sourde que l'orange vif de Mistral, et les deux tuiles se
   suivent dans la rangee. Le meme orange pour les deux aurait dit qu'il s'agit
   de la meme facture, ce qui est vrai d'OpenAI et de Mistral -- une seule
   depense d'IA relevee sur deux factures -- et faux de Claude, qui ne sert
   qu'aux sessions de developpement de ce depot. */
.conso-bloc-claude,
.conso-tuile-claude { --conso-teinte: var(--orange-dark); }

/* Le vert pour Supabase, qui est la couleur de sa marque et le point de depart
   du ticket. */
.conso-bloc-supabase,
.conso-tuile-supabase { --conso-teinte: var(--green); }

/* Le noir pour le depot : sa tuile porte le logo de GitHub, dont la marque est
   noire. Le bleu qu'elle portait etait un reste de l'ancien choix par
   elimination. */
.conso-bloc-code,
.conso-tuile-code { --conso-teinte: var(--black); }

/* Le bleu pour Search Console : c'est le bleu de Google, celui du logo pose sur
   son carre. Le bleu sombre qu'elle portait ne servait qu'a la distinguer du
   depot, qui ne tient plus le bleu. */
.conso-bloc-gsc,
.conso-tuile-gsc { --conso-teinte: var(--blue); }

/* Le noir pour Vercel, inchange : la marque de Vercel est un triangle blanc sur
   noir, et c'est la seule teinte de cette liste qui etait deja celle de sa
   marque avant que la regle ne soit ecrite. */
.conso-bloc-vercel,
.conso-tuile-vercel { --conso-teinte: var(--black); }

/* Le noir pour OpenAI, ecrit le 21 septembre 2026. Sa tuile etait la derniere
   a n'avoir aucune regle ici, donc la derniere a heriter du cyan de repli de
   la mosaique : une teinte qui ne disait rien d'elle, et qu'on lisait pourtant
   comme une couleur de marque puisque les six voisines en portent une. La
   charte d'OpenAI n'admet son logo qu'en noir ou en blanc (voir
   --marque-openai) : c'est donc le meme noir que Vercel et le depot, a l'encre
   du produit, qui se lit en texte la ou le noir pur du carre ne le ferait
   pas. */
.conso-bloc-openai,
.conso-tuile-openai { --conso-teinte: var(--black); }

/* ---------------------------------------------------------------------------
   La mosaique du Dashboard systeme : six tuiles, un volet qui s'ouvre dans la
   rangee.

   « Que tous les morceaux du dashboard soient visibles sur une seule page et
   qu'ensuite on clique pour tout afficher », « les animations quand on clique
   dessus et du coup elle va s'ouvrir et pousser les autres, soient ultra
   smooth » (demande du 26 aout 2026).

   Une seule grille pour les tuiles et les volets, et non deux zones : c'est ce
   qui permet au volet de prendre toute la largeur juste sous la rangee de sa
   tuile et de pousser la suite vers le bas. Le volet est pose la par le script
   (static/js/dashboard-tuiles.js) parce que la rangee depend du nombre de
   colonnes, et que ce nombre-la est ici, dans le `repeat(auto-fit)`.

   Aucune couleur nouvelle : la palette de `:root` suffit, comme pour les blocs
   au-dessus. La teinte du fournisseur (`--conso-teinte`) porte le jeton, la
   trace et le liseré de la tuile ouverte ; seule la pastille d'etat prend le
   vert ou l'orange, parce que c'est la seule chose de la tuile qui affirme
   quelque chose.

   Le depliement se joue sur `grid-template-rows: 0fr -> 1fr` et non sur une
   hauteur en pixels : la hauteur du volet n'est pas connue d'avance -- le bloc
   OpenAI en fait cinq fois celle du bloc Supabase -- et une hauteur ecrite
   dans la feuille aurait coupe le contenu le jour ou il grandit.
   --------------------------------------------------------------------------- */

.conso-mosaique {
  /* La duree du depliement, ecrite une fois : la tuile, le volet et son
     contenu doivent finir ensemble, sinon le mouvement se dedouble. Le script
     la relit pour savoir quand reposer `hidden`. */
  --conso-duree: 420ms;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  column-gap: var(--espace-md);
  /* Aucun `row-gap` : un volet replie ne doit rien occuper, pas meme un
     interligne. L'espacement vertical est porte par les elements eux-memes. */
  row-gap: 0;

  /* La teinte de repli se pose ici, sur le conteneur, et non sur `.conso-tuile`
     ou elle etait d'abord ecrite. Les quatre teintes de fournisseur
     (`.conso-tuile-supabase` et les suivantes) sont declarees plus haut dans le
     fichier et ont la meme specificite qu'elle : `.conso-tuile` etant plus bas,
     c'est elle qui gagnait, et les six tuiles sortaient cyan -- jeton, jauge et
     courbe compris -- alors que le violet, le bleu, le bleu sombre et le noir
     etaient bien ecrits. Posee sur le parent, elle n'est plus qu'heritee, donc
     ecartee des qu'une tuile declare la sienne. */
  --conso-teinte: var(--cyan);
}

/* --- La tuile ------------------------------------------------------------ */

.conso-tuile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  margin: 0 0 var(--espace-md);
  padding: var(--espace-md) var(--espace-md) var(--espace);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-lg);
  background: #fff;
  box-shadow: var(--shadow-sm);
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: transform var(--conso-duree) var(--ease-spring),
              box-shadow var(--conso-duree) var(--ease),
              border-color var(--conso-duree) var(--ease);
}

/* La lumiere du haut, dans la teinte du fournisseur. Tres basse -- six pour
   cent -- parce qu'elle sert a distinguer cinq cartes d'un coup d'oeil, pas a
   les colorer : cinq aplats teintes cote a cote feraient un damier. */
.conso-tuile::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 96px;
  background: linear-gradient(180deg, var(--conso-teinte), transparent);
  opacity: .06;
  pointer-events: none;
  transition: opacity var(--conso-duree) var(--ease);
}

.conso-tuile:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.conso-tuile:hover::before { opacity: .1; }
.conso-tuile:active { transform: translateY(0) scale(.995); }

.conso-tuile:focus-visible {
  outline: 2px solid var(--conso-teinte);
  outline-offset: 2px;
}

/* La tuile ouverte reste levee et prend un lisere de sa teinte : c'est le seul
   repere qui dit quel volet on est en train de lire quand il est long. */
.conso-tuile.ouverte {
  transform: translateY(-2px);
  border-color: var(--conso-teinte);
  box-shadow: var(--shadow-md), inset 0 0 0 1px var(--conso-teinte);
}

.conso-tuile.ouverte::before { opacity: .14; }

.conso-tuile-tete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

.conso-tuile-jeton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: var(--radius-sm);
  background: var(--conso-teinte);
  color: #fff;
}

.conso-tuile-jeton .icon { width: var(--icon); height: var(--icon); }

/* LE CARRE DU LOGO PORTE LA COULEUR DE LA MARQUE, LE RESTE DE LA TUILE NON.
   « Utilise les bonnes couleurs et fais pareil pour les autres services »
   (suivi du ticket du 17 septembre 2026).

   Le jeton et lui seul : `--conso-teinte` peint aussi la courbe et le trait de
   la tuile, et une courbe verte ou noire dirait un etat -- c'est la raison
   deja ecrite plus haut pour ecarter le vert et l'orange de ces tuiles. Le
   logo, lui, ne dit rien d'autre que « c'est cette marque-la », et c'est
   exactement ce qu'une couleur de marque sert a dire.

   Les sept y sont depuis le 21 septembre 2026 : OpenAI a rejoint la liste avec
   le noir de sa charte, la seule des sept dont la couleur ne se releve pas
   dans Simple Icons (voir les jetons `--marque-*` de `:root`). */
.conso-tuile-openai .conso-tuile-jeton { background: var(--marque-openai); }
.conso-tuile-claude .conso-tuile-jeton { background: var(--marque-claude); }
.conso-tuile-mistral .conso-tuile-jeton { background: var(--marque-mistral); }
.conso-tuile-supabase .conso-tuile-jeton { background: var(--marque-supabase); }
.conso-tuile-vercel .conso-tuile-jeton { background: var(--marque-vercel); }
.conso-tuile-code .conso-tuile-jeton { background: var(--marque-github); }
.conso-tuile-gsc .conso-tuile-jeton { background: var(--marque-google); }

.conso-tuile-nom {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--black);
  min-width: 0;
  overflow-wrap: normal;
  word-break: normal;
}

/* La pastille d'etat : la seule chose de la tuile qui affirme quelque chose,
   donc la seule qui prenne une couleur d'etat. Le reste porte la teinte du
   fournisseur, qui ne dit rien d'autre que « c'est celui-la ». */
.conso-tuile-etat {
  align-self: flex-start;
  margin-top: var(--espace-sm);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: 999px;
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  white-space: nowrap;
  color: var(--gray-5);
  background: var(--gray-1);
}

.conso-tuile-sain .conso-tuile-etat { color: var(--green-dark); background: var(--green-pale); }
.conso-tuile-attention .conso-tuile-etat { color: var(--orange-dark); background: var(--orange-pale); }
.conso-tuile-indisponible .conso-tuile-etat { color: var(--gray-5); background: var(--gray-2); }

.conso-tuile-chiffre {
  margin-top: var(--espace-sm);
  font-size: var(--fs-hero);
  font-weight: 600;
  line-height: 1.1;
  color: var(--black);
  font-variant-numeric: tabular-nums;
}

.conso-tuile-borne {
  margin-top: var(--espace-3xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* La trace : la jauge du forfait quand il y en a un, l'esquisse de la serie
   sinon. Une hauteur fixe et non `auto` -- les tuiles d'une meme rangee
   doivent poser leur phrase a la meme ligne, sans quoi la rangee ondule. */
.conso-tuile-trace {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 44px;
  margin-top: var(--espace-sm);
}

.conso-tuile .conso-jauge {
  display: block;
  width: 100%;
  margin: 0 0 var(--espace-2xs);
}

.conso-tuile-legende {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.conso-tuile-courbe {
  display: block;
  width: 100%;
  height: 34px;
}

.conso-tuile-aire { fill: var(--conso-teinte); opacity: .12; }

/* `vector-effect` parce que le SVG est etire a la largeur de la tuile : sans
   lui, le trait serait epais sur une tuile large et fin sur une etroite. */
.conso-tuile-trait {
  fill: none;
  stroke: var(--conso-teinte);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.conso-tuile-mot {
  margin-top: var(--espace-sm);
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--gray-5);
}

.conso-tuile-ouvrir {
  display: flex;
  align-items: center;
  gap: var(--espace-3xs);
  margin-top: auto;
  padding-top: var(--espace-sm);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--conso-teinte);
  opacity: .7;
  transition: opacity var(--conso-duree) var(--ease);
}

.conso-tuile:hover .conso-tuile-ouvrir,
.conso-tuile.ouverte .conso-tuile-ouvrir { opacity: 1; }

.conso-tuile-ouvrir .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  transition: transform var(--conso-duree) var(--ease-spring);
}

.conso-tuile.ouverte .conso-tuile-ouvrir .icon { transform: rotate(90deg); }

/* --- Le volet ------------------------------------------------------------ */

/* `[hidden]` d'abord : un volet ferme sort de la grille, sans quoi il y
   occuperait une rangee vide et casserait la mosaique en cinq lignes d'une
   tuile. Le script ne le repose qu'une fois le repli termine. */
.conso-volet[hidden] { display: none; }

.conso-volet {
  grid-column: 1 / -1;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--conso-duree) var(--ease);
}

.conso-volet.ouvert { grid-template-rows: 1fr; }

.conso-volet-fenetre { min-height: 0; overflow: hidden; }

/* Le contenu ne se contente pas d'apparaitre avec son cadre : il descend et se
   revele un peu apres lui. C'est ce decalage de quatre-vingt-dix millisecondes
   qui fait la difference entre « un bloc a surgi » et « un tiroir s'ouvre ». */
.conso-volet .conso-bloc {
  margin-bottom: var(--espace-md);
  border-radius: var(--radius-lg);
  opacity: 0;
  transform: translateY(-10px);
  transition: opacity calc(var(--conso-duree) * .65) var(--ease) 90ms,
              transform calc(var(--conso-duree) * .65) var(--ease) 90ms;
}

.conso-volet.ouvert .conso-bloc { opacity: 1; transform: none; }

/* Ce que la tuile ne porte pas et que le volet garde : les bornes du cycle
   chez l'hebergeur, le nom de la propriete chez Google. */
.conso-volet-quoi {
  margin: 0 0 var(--espace-sm);
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

/* --- Le verdict ---------------------------------------------------------- */

.conso-verdict {
  --conso-teinte: var(--gray-4);
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--espace-md);
  padding: var(--espace-md) var(--espace-lg);
  border: 1px solid var(--gray-2);
  border-left: 4px solid var(--conso-teinte);
  border-radius: var(--radius-lg);
  background: #fff;
  box-shadow: var(--shadow-sm);
}

.conso-verdict-sain { --conso-teinte: var(--green); }
.conso-verdict-attention { --conso-teinte: var(--orange); }

.conso-verdict-jeton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  border-radius: var(--radius);
  background: var(--conso-teinte);
  color: #fff;
}

.conso-verdict-jeton .icon { width: var(--icon-md); height: var(--icon-md); }

.conso-verdict-dit { display: flex; flex-direction: column; gap: var(--espace-3xs); min-width: 0; }

.conso-verdict-titre { font-size: var(--fs-h3); font-weight: 600; color: var(--black); }

.conso-verdict-phrase { font-size: var(--fs-sm); color: var(--gray-5); line-height: 1.5; }

.conso-verdict-muettes {
  margin-top: var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
}

/* Le nom d'une source muette ouvre son volet : c'est la qu'est ecrit ce qui
   manque pour qu'elle parle. */
.conso-verdict-lien {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--blue);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.conso-verdict-lien:hover { color: var(--blue-dark); }

.conso-verdict-compte {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  flex: none;
}

.conso-verdict-compte strong {
  font-size: var(--fs-h2);
  font-weight: 600;
  color: var(--conso-teinte);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.conso-verdict-compte span { font-size: var(--fs-2xs); color: var(--gray-5); }

@media (max-width: 640px) {
  .conso-verdict { flex-wrap: wrap; }
  .conso-verdict-compte { margin-left: 0; align-items: flex-start; text-align: left; }
}

/* ---------------------------------------------------------------------------
   La page qui arrive par morceaux (demande du 14 septembre 2026).

   Une tuile en attente a deja son nom et sa marque, et seulement eux : ce qui
   se mesure est remplace par un trait qui luit doucement, a la place exacte
   ou le chiffre et la trace viendront. La tuile ne bouge donc pas quand sa
   source repond, elle se remplit. Pas de survol ni de curseur de main : il
   n'y a encore rien a ouvrir.
   --------------------------------------------------------------------------- */
.conso-tuile-attente { cursor: default; }
.conso-tuile-attente:hover { transform: none; box-shadow: var(--shadow-sm); }
.conso-tuile-attente .conso-tuile-etat { color: var(--gray-5); background: var(--gray-1); }

.conso-attente-trait {
  display: block;
  width: 45%;
  height: 1em;
  margin: .15em 0;
  border-radius: var(--radius);
  background: linear-gradient(90deg, var(--gray-1) 0%, var(--gray-2) 50%, var(--gray-1) 100%);
  background-size: 200% 100%;
  animation: conso-attente-lueur 1.4s ease-in-out infinite;
}

.conso-attente-large { width: 100%; height: 30px; }

/* Le même trait, dans une cellule de tableau ou au fil d'une phrase : en ligne
   et non en bloc, calé sur la hauteur du texte qui l'entoure. Les deux
   colonnes du Périmètre qui attendent leur lecture portaient des points de
   suspension, immobiles, pendant une minute : personne n'attend devant trois
   points, on les lit comme une case vide (ticket AMBISTRATE du 17 septembre
   2026). */
.conso-attente-cellule {
  display: inline-block;
  width: 4.5em;
  height: .85em;
  margin: 0;
  vertical-align: middle;
  border-radius: var(--radius-xs);
}

/* La phrase sous le tableau, pendant la lecture des deux colonnes : son trait
   devant elle, et le reste dans la glose grise des indications. */
.conso-couverture-attente .conso-attente-cellule {
  width: 2.5em;
  margin-right: var(--espace-2xs);
}

@keyframes conso-attente-lueur {
  from { background-position: 100% 0; }
  to { background-position: -100% 0; }
}

/* L'arrivee : un fondu court, pour que l'oeil voie ce qui vient de changer
   sans que la page ait l'air de sauter. */
.conso-tuile-arrivee,
.conso-verdict-arrivee { animation: conso-arrivee .32s var(--ease) both; }

@keyframes conso-arrivee {
  from { opacity: .35; }
  to { opacity: 1; }
}

/* Une source qui n'a pas abouti : la tuile le dit et se redemande d'un clic.
   Le mot « Reessayer » reste visible sans survol, il est la seule chose a
   faire ici. */
.conso-tuile-echec .conso-tuile-mot { color: var(--gray-5); }
.conso-tuile-echec .conso-tuile-ouvrir { opacity: 1; color: var(--blue); }

.conso-verdict-attente .conso-verdict-compte strong { color: var(--gray-5); }

.conso-noscript {
  margin: var(--espace-md) 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

/* Le mouvement est un agrement, pas une information : qui l'a refuse au
   systeme recoit la meme page, immediate. */
@media (prefers-reduced-motion: reduce) {
  .conso-mosaique { --conso-duree: 1ms; }
  .conso-attente-trait,
  .conso-tuile-arrivee,
  .conso-verdict-arrivee { animation: none; }
  .conso-tuile:hover,
  .conso-tuile:active,
  .conso-tuile.ouverte { transform: none; }
  .conso-volet .conso-bloc { transition-delay: 0ms; }
}

/* ---------------------------------------------------------------------------
   Les trois figures du volet Vercel.

   Le volet dessinait quatorze barres horizontales -- une piste pour le credit,
   une par projet, une pile pour les familles, une jauge par ligne de tableau.
   Toutes de la meme longueur a l'oeil, toutes decoupant le meme total. Trois
   figures les remplacent, d'autant de familles differentes.

   Tout est porte sous un parent `.vercel-*` : ces regles sont posees avant
   celles des `.conso-*` qu'elles precisent, et une classe seule y perdrait a
   specificite egale.
   --------------------------------------------------------------------------- */

/* 1. La course du credit. */
.vercel-course { margin: 0 0 var(--espace-lg); }

.vercel-course-cadre { position: relative; }

/* Etire a la largeur du bloc : ce qui doit garder sa forme -- un point, une
   etiquette -- est pose en HTML par-dessus, jamais dans le dessin. Meme
   hauteur que la courbe du depot, quelques lignes plus bas : deux courbes sous
   les yeux ne doivent pas differer d'un pixel. */
.vercel-course-svg {
  display: block;
  width: 100%;
  height: 180px;
  overflow: visible;
  border-bottom: 1px solid var(--gray-3);
}

.vercel-course-aire { fill: var(--gray-2); stroke: none; }
.vercel-course-aire.depasse { fill: var(--orange-pale); }

.vercel-course-trace {
  fill: none;
  stroke: var(--conso-teinte);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.vercel-course-trace.depasse { stroke: var(--orange); }

/* Le plafond du credit, en tirets : il n'est pas une mesure du cycle mais la
   limite contre laquelle on la lit, et un trait plein le ferait prendre pour
   une seconde courbe. */
.vercel-course-plafond {
  fill: none;
  stroke: var(--gray-4);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  vector-effect: non-scaling-stroke;
}

/* La projection prolonge la trace du jour au lieu de poser un repere ailleurs :
   c'est la meme mesure continuee, pas une mesure de plus. */
.vercel-course-suite {
  fill: none;
  stroke: var(--conso-teinte);
  stroke-width: 2;
  stroke-dasharray: 3 5;
  stroke-linecap: round;
  opacity: .38;
  vector-effect: non-scaling-stroke;
}

/* L'etiquette du plafond se pose a gauche, la ou le trace n'est pas encore
   monte : a droite elle rencontrait le point du bout des que la projection
   frolait le credit, et c'est justement le cas qui compte. */
.vercel-course-plafond-nom {
  position: absolute;
  left: 0;
  transform: translateY(-100%);
  padding-bottom: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  white-space: nowrap;
  pointer-events: none;
}

/* Le jour ou le credit est mange : une verticale et rien d'autre. La date est
   ecrite en toutes lettres sous la figure, et un cartouche pose ici couvrirait
   la trace a l'endroit precis qu'il designe. */
.vercel-course-seuil {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--orange);
  pointer-events: none;
}

.vercel-course-point,
.vercel-course-bout {
  position: absolute;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 999px;
  pointer-events: none;
}

.vercel-course-point { background: var(--conso-teinte); }
.vercel-course-point.depasse { background: var(--orange); }

/* Le bout de la projection est creux : plein, il aurait le poids d'une mesure
   prise, alors qu'il n'est que la ou l'on arrive si rien ne change. */
.vercel-course-bout {
  background: #fff;
  border: 2px solid var(--conso-teinte);
  opacity: .55;
}

.vercel-course-axe {
  display: flex;
  justify-content: space-between;
  margin-top: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

.vercel-course-note {
  margin-top: var(--espace-xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
}

.vercel-course-note strong { color: var(--orange-dark); font-weight: 600; }

/* 2. L'astre des services : les familles dedans, les postes dehors. */
.vercel-astre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xl);
  margin: 0 0 var(--espace-md);
}

/* Plus large que la couronne d'une passe : elle porte un anneau, l'astre en
   porte deux et un moyeu ecrit. */
.vercel-astre-dessin {
  position: relative;
  flex: none;
  width: 180px;
}

.vercel-astre-svg {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  overflow: visible;
}

/* Les pistes, sous les arcs : sans elles, des parts qui ne font pas tout a
   fait cent laisseraient un anneau flottant au lieu d'un anneau entame. */
.vercel-astre .vercel-astre-piste { fill: none; stroke: var(--gray-2); }
.vercel-astre .vercel-astre-famille { stroke-width: 13; }
.vercel-astre .vercel-astre-poste { stroke-width: 11; }

.vercel-astre .conso-legende {
  flex: 1 1 220px;
  min-width: 0;
  margin-top: 0;
}

/* Le moyeu couvre tout le dessin et non le seul disque du milieu : il
   intercepterait le pointeur avant les arcs, donc il ne recoit rien. Meme
   raison qu'au rond de profil des couronnes, plus bas. */
.vercel-astre-centre {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--espace-3xs);
  pointer-events: none;
}

.vercel-astre-total {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--black);
  font-variant-numeric: tabular-nums;
}

.vercel-astre-quoi { font-size: var(--fs-3xs); color: var(--gray-4); }

/* 3. Les projets en disques : la surface est la depense. */
.vercel-disques {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--espace-xl);
  margin: 0 0 var(--espace-md);
  /* Le plus gros disque, et la fraction que chacun en prend. Le rapport est
     ecrit case par case par le gabarit ; il est declare ici pour deux raisons :
     la feuille dit alors d'ou vient la taille, et le verificateur ne voit plus
     un jeton utilise que personne ne definit. */
  --vercel-disque-max: 108px;
  --cote: 1;
}

.vercel-disque {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-3xs);
  min-width: 0;
  text-align: center;
}

/* La place du disque garde la hauteur du plus gros, pour que les noms de tous
   les projets tombent sur une meme ligne quelle que soit leur part. */
.vercel-disque-place {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--vercel-disque-max);
  height: var(--vercel-disque-max);
  margin-bottom: var(--espace-2xs);
}

/* Le meme partage que l'aire de la course juste au-dessus : le creux en
   `--gray-2`, le contour dans la teinte du volet. Pleine, la teinte de
   celui-ci est l'encre du site, et un disque de cent pixels d'encre pese
   comme une rature -- alors que ce qu'on vient comparer ici, c'est une
   surface, pas une quantite de noir. */
.vercel-disque-rond {
  width: calc(var(--vercel-disque-max) * var(--cote));
  aspect-ratio: 1;
  border: 2px solid var(--conso-teinte);
  border-radius: 999px;
  background: var(--gray-2);
}

.vercel-disque-nb {
  font-size: var(--fs);
  font-weight: 600;
  color: var(--black);
  font-variant-numeric: tabular-nums;
}

.vercel-disque-nom {
  max-width: 132px;
  font-size: var(--fs-xs);
  color: var(--gray-6);
}

.vercel-disque-usd {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .vercel-course-svg { height: 140px; }
  .vercel-astre { gap: var(--espace-md); }
  .vercel-disques {
    gap: var(--espace-md);
    --vercel-disque-max: 84px;
  }
}

/* La courbe. Pas de grille ni de graduations : ce qu'on vient lire ici est une
   pente et deux bouts, que la legende sous le cadre donne en toutes lettres. */
.code-courbe {
  margin: var(--espace-md) 0 var(--espace-lg);
  padding: 0;
}

/* Le cadre du trace. Il existe pour le repere de survol, qui se pose dessus en
   coordonnees de page : le SVG etant etire, rien de ce qui doit garder sa
   forme -- un point rond, une etiquette lisible -- ne peut etre dessine
   dedans. */
.code-cadre { position: relative; }

.code-svg {
  display: block;
  width: 100%;
  height: 180px;
  overflow: visible;
  border-bottom: 1px solid var(--gray-3);
}

/* Le trait vertical du jour survole, du haut du cadre a la ligne de base. */
.code-repere {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--gray-4);
  pointer-events: none;
}

/* Le point sur la courbe. Cercle a 999px : ce qui doit etre completement rond
   ne prend pas une valeur intermediaire. */
.code-point {
  position: absolute;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border: 2px solid #fff;
  border-radius: 999px;
  background: var(--conso-teinte);
  pointer-events: none;
}

/* L'etiquette suit le jour survole sans jamais sortir du cadre : collee a
   droite, elle deborderait de la carte et couperait sa propre fin. C'est le
   code qui la retient (voir dashboard-code.js) ; ici, seulement sa forme --
   celle des autres surfaces flottantes du site, en plus petit. */
.code-infobulle {
  position: absolute;
  top: 0;
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-xs);
  color: var(--gray-6);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

.code-infobulle strong { color: var(--black); font-weight: 600; }

.code-infobulle .code-infobulle-delta { color: var(--conso-teinte); }

.code-trait {
  fill: none;
  stroke: var(--conso-teinte);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  /* Le trait s'etire avec le cadre : sans cela, l'echelle horizontale du
     viewBox epaissirait la ligne autant qu'elle etire la courbe. */
  vector-effect: non-scaling-stroke;
}

.code-aire {
  fill: var(--blue-pale);
  stroke: none;
}

.code-axe {
  display: flex;
  justify-content: space-between;
  margin-top: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

.code-resume {
  margin-top: var(--espace-xs);
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

/* Les sept derniers jours, sous la courbe -- le graphique que la page n'avait
   pas et que le mur du bureau montrait déjà (suivi du 30 août 2026). La courbe
   dit où l'on en est, ces barres-là disent à quel rythme on y va.

   Deux pistes par jour, comme sur le mur : les lignes ajoutées et les commits.
   Elles ont chacune leur échelle -- vingt mille lignes et trente commits ne se
   mesurent pas sur le même axe --, et c'est pourquoi chaque jour écrit ses deux
   chiffres plutôt que de laisser comparer les hauteurs entre pistes. */
.code-semaine { margin-top: var(--espace-lg); }

.code-semaine-tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace-md);
  flex-wrap: wrap;
}

.code-semaine-tete .conso-sous-titre { margin-top: 0; }

.code-legende {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-md);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

.code-legende i {
  display: inline-block;
  width: var(--espace-sm);
  height: var(--espace-sm);
  margin-right: var(--espace-2xs);
  border-radius: var(--radius-xs);
  vertical-align: middle;
}

.code-legende-lignes { background: var(--cyan); }
.code-legende-commits { background: var(--gray-3); }

.code-jours {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--espace-xs);
  margin-top: var(--espace-xs);
}

.code-jour {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-3xs);
  min-width: 0;
}

.code-jour-valeur {
  font-size: var(--fs-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--cyan-dark);
  white-space: nowrap;
}

/* Une journée qui retire du code n'est pas une journée creuse : elle se lit,
   et dans l'autre teinte. Une journée sans commit s'efface, sans disparaître --
   la case reste, sinon la semaine se resserrerait autour de ses trous. */
.code-jour.negatif .code-jour-valeur { color: var(--orange-dark); }
.code-jour.vide .code-jour-valeur { color: var(--gray-4); }

.code-jour-pistes {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: var(--espace-3xs);
  width: 100%;
  height: 6rem;
}

.code-jour-piste {
  display: flex;
  align-items: flex-end;
  flex: 1 1 0;
  max-width: 1.4rem;
  height: 100%;
}

.code-jour-barre {
  display: block;
  width: 100%;
  min-height: 2px;
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
}

.code-jour-barre-lignes { background: var(--cyan); }
.code-jour.negatif .code-jour-barre-lignes { background: var(--orange); }
.code-jour-barre-commits { background: var(--gray-3); }

.code-jour-nom,
.code-jour-commits {
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  white-space: nowrap;
}

/* --- La rose des jours ------------------------------------------------------
   Sept petales autour d'un moyeu, lundi en haut, la semaine dans le sens des
   aiguilles. Le rayon porte le nombre de commits ; les trois cercles de repere
   departagent deux petales voisins de longueur proche, ce qu'un cadran nu ne
   fait pas. Le trace se calcule dans `depot_code.rose_semaine`. */
.code-rose-cadre {
  display: flex;
  justify-content: center;
  margin-top: var(--espace-md);
}

.code-rose {
  display: block;
  width: 100%;
  max-width: 300px;
  height: auto;
  overflow: visible;
}

.code-rose-guide {
  fill: none;
  stroke: var(--gray-2);
  stroke-width: 1;
  pointer-events: none;
}

.code-petale {
  fill: var(--conso-teinte);
  fill-opacity: .9;
  transition: opacity .15s var(--ease);
}

/* Le samedi et le dimanche dans la meme teinte, diluee : la semaine de travail
   se lit alors sans qu'aucune legende n'ait a dire ou elle s'arrete. La
   dilution passe par `fill-opacity` et non par `opacity`, qui sert deja a
   l'extinction du survol juste dessous -- deux reglages sur la meme propriete
   s'annuleraient l'un l'autre. */
.code-petale.repos { fill-opacity: .42; }

/* Eteindre plutot que souligner, comme partout ailleurs sur la page : ce qu'on
   cherche est un jour parmi sept, et six teintes qui baissent le designent
   mieux qu'une qui monte. L'ordre des deux regles compte -- a specificite
   egale, c'est la derniere qui gagne. */
.code-rose:hover .code-petale { opacity: .3; }
.code-rose .code-petale:hover { opacity: 1; }

.code-rose-jour,
.code-rose-nb,
.code-rose-total,
.code-rose-total-nom { pointer-events: none; }

.code-rose-jour {
  font-size: var(--fs-2xs);
  font-weight: 600;
  fill: var(--gray-6);
}

.code-rose-nb { font-size: var(--fs-3xs); fill: var(--gray-4); }

.code-rose-total {
  font-size: var(--fs-h2);
  font-weight: 600;
  fill: var(--black);
}

.code-rose-total-nom { font-size: var(--fs-3xs); fill: var(--gray-4); }

/* --- La carte du depot ------------------------------------------------------
   L'aire est le nombre de lignes, la hauteur vive ce qui vient d'y etre ecrit.
   Le pavage est calcule dans `depot_code.carte` (Bruls, Huizing et van Wijk) :
   un decoupage naif donne des lanieres des que le premier langage pese la
   moitie du total, ce qui est exactement le cas ici. Le rapport de la boite est
   celui que ce calcul a suppose ; le changer sans le changer la-bas rendrait
   les lanieres. */
.code-carte {
  position: relative;
  aspect-ratio: 2.2 / 1;
  margin-top: var(--espace-md);
}

/* Le jeu entre deux tuiles est pris sur une bordure transparente et non sur une
   marge : les rectangles calcules pavent la carte sans trou ni chevauchement,
   et une boite absolue posee dedans se cale sur la boite de remplissage, donc
   a l'interieur du jeu. */
.code-tuile {
  position: absolute;
  border: var(--espace-3xs) solid transparent;
  border-radius: var(--radius-xs);
  overflow: hidden;
}

.code-tuile-fond { position: absolute; inset: 0; opacity: .18; }

/* Ce qui vient d'etre ecrit, pose au fond de la tuile : ca monte, comme un
   niveau. Vers le haut et non vers la droite -- la largeur est deja prise par
   la part du depot, et une deuxieme mesure sur le meme axe ne se lirait pas. */
.code-tuile-neuf {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: .55;
}

.code-tuile-nom,
.code-tuile-part {
  position: relative;
  display: block;
  overflow: hidden;
  padding: 0 var(--espace-2xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.code-tuile-nom {
  margin-top: var(--espace-2xs);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--black);
}

.code-tuile-part {
  font-size: var(--fs-3xs);
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
}

/* Sur un telephone la carte se redresse -- une bande de deux fois et demie de
   large y ferait des tuiles de douze pixels de haut -- et les parts quittent
   les tuiles : la legende juste dessous les porte deja. */
@media (max-width: 720px) {
  .code-carte { aspect-ratio: 1.4 / 1; }
  .code-tuile-part { display: none; }

  /* Sept colonnes de quarante pixels ne tiennent pas « mar 01/09 » ni
     « 30 commits » sur une ligne : les trois lignes de chaque jour mordaient
     sur le jour voisin. Elles se replient plutot que de deborder. */
  .code-jours { gap: var(--espace-3xs); }

  .code-jour-nom,
  .code-jour-commits {
    white-space: normal;
    text-align: center;
  }

  .code-jour-valeur { font-size: var(--fs-3xs); }
}

/* La courbe de Search Console. Meme cadre que celle du code, deux traces au
   lieu d'un -- et surtout deux echelles, une par trace (voir gsc_conso._courbe).
   Des classes a elle et non celles du code : les deux blocs n'ont ni le meme
   nombre de courbes ni le meme rapport au survol, et les faire partager un nom
   de classe ferait qu'un reglage de l'un deplacerait l'autre. */
.gsc-courbe { margin: var(--espace-md) 0 var(--espace-lg); padding: 0; }

.gsc-svg {
  display: block;
  width: 100%;
  height: 150px;
  overflow: visible;
  border-bottom: 1px solid var(--gray-3);
}

/* Les impressions : ce que Google a montre. En aire pleine et pale, parce que
   c'est le fond sur lequel se lit le reste -- une surface, pas un evenement. */
.gsc-aire { fill: var(--blue-pale); stroke: none; }

/* Les clics : ce qui a effectivement ete clique. En trait net par-dessus
   l'aire, et sur sa propre echelle : c'est le contraste entre les deux qu'on
   vient lire. */
.gsc-trait {
  fill: none;
  stroke: var(--conso-teinte);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* La grille : trois traits aux quarts de l'echelle utile, sous les traces. Une
   courbe sans grille se lit de forme et jamais de hauteur -- on voit qu'un jour
   est plus haut qu'un autre, jamais de combien. Le meme nombre de graduations
   que la courbe datee des autres volets, pour que les deux dessins se lisent de
   la meme facon. */
.gsc-grille {
  fill: none;
  stroke: var(--gray-2);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}

/* Un jour de la courbe : sa bande sensible, son guide, ses deux reperes.

   La courbe etait un dessin. On en voyait la forme, jamais le chiffre : trois
   pics et un creux, et rien pour dire lequel des vingt-huit jours valait quoi.
   Chaque jour porte donc ce qu'il vaut, et la page l'ecrit au survol comme elle
   l'ecrit au-dessus des barres du volet d'a cote.

   Rien de tout cela au repos, et c'est la raison de la bande transparente :
   trois cent soixante-cinq reperes sur la fenetre la plus large feraient de la
   courbe une texture. Ce qu'on vise est une colonne et non un point -- viser
   deux pixels a la souris est un exercice, au doigt c'est impossible.

   Des traits horizontaux et non des ronds : le cadre est etire
   (`preserveAspectRatio="none"`), un cercle y deviendrait une ellipse qui ment,
   large de un et un cinquieme pour haute de deux tiers. Un segment horizontal
   n'a pas de hauteur a deformer. */
.gsc-jour-bande {
  fill: var(--conso-teinte);
  opacity: 0;
  transition: opacity .15s var(--ease);
}

.gsc-jour-guide,
.gsc-jour-marque {
  opacity: 0;
  transition: opacity .15s var(--ease);
  /* Le pointeur revient a la bande : elle seule couvre toute la hauteur, et
     trois cibles dans un meme groupe feraient clignoter le releve au passage
     d'un repere a l'autre. */
  pointer-events: none;
}

.gsc-jour-guide {
  stroke: var(--gray-4);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}

.gsc-jour-marque {
  stroke-width: 3;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* Chacun de la couleur de sa trace : les deux echelles sont differentes, et un
   repere de la mauvaise couleur ferait lire une hauteur sur l'autre echelle. */
.gsc-jour-impressions { stroke: var(--blue); }
.gsc-jour-clics { stroke: var(--conso-teinte); }

/* `.conso-vise` double le survol pour le clavier : les fleches deplacent le
   jour vise sans qu'aucun pointeur ne soit sur la page. */
.gsc-jour:hover .gsc-jour-bande,
.gsc-jour.conso-vise .gsc-jour-bande { opacity: .07; }

.gsc-jour:hover .gsc-jour-guide,
.gsc-jour:hover .gsc-jour-marque,
.gsc-jour.conso-vise .gsc-jour-guide,
.gsc-jour.conso-vise .gsc-jour-marque { opacity: 1; }

/* Les traces ne recoivent pas le pointeur : elles sont peintes sous les bandes,
   et une trace qui l'attraperait la ou la bande est etroite ouvrirait un releve
   sans jour. */
.gsc-aire,
.gsc-trait { pointer-events: none; }

/* Les deux echelles, ecrites de part et d'autre du cadre : une echelle qu'on
   ne montre pas est une echelle qu'on ne peut pas contredire. */
.gsc-echelles,
.gsc-axe {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

.gsc-echelles { margin-bottom: var(--espace-2xs); }
.gsc-axe { margin-top: var(--espace-2xs); }

.gsc-echelle-clics { color: var(--conso-teinte); font-weight: 600; }

/* La requete elle-meme, en tete de ligne : c'est le texte tape par quelqu'un,
   et il se distingue de ce que nous en disons. */
.gsc-requete { font-weight: 500; color: var(--black); }

.gsc-chemin {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--gray-6);
  word-break: break-all;
}

/* Une ligne vue et jamais cliquee. Ni rouge ni orange -- ce n'est pas une
   panne : c'est le cas le plus frequent, et le rendre alarmant ferait d'un
   tableau entier une alerte. Un gris suffit a dire « rien ici ». */
.gsc-zero { color: var(--gray-4); }

/* La part d'impressions d'une ligne, posee sous son nombre. Les deux tableaux
   du volet etaient les seules surfaces ou la repartition par page de resultats
   ne se voyait pas : cinq colonnes de chiffres, et la couleur de la pile nulle
   part. La jauge la remet sous chaque ligne, teintee comme la part de pile qui
   compte cette ligne.

   Sous le nombre et non dans une colonne de plus : cinq colonnes tiennent sur
   un telephone, six non.

   Plus courte que la jauge ordinaire : la colonne des impressions n'a que
   quatre chiffres a porter, et une jauge de 4,5rem y pesait plus lourd que le
   nombre qu'elle illustre. */
.gsc-part {
  display: block;
  margin-top: var(--espace-3xs);
}

.gsc-part .conso-jauge {
  width: 3rem;
  margin-right: 0;
}

/* Les requetes puis les pages : deux tables, l'une sous l'autre. Collees, leurs
   bordures se rejoignent et l'en-tete « Page » se lit comme une ligne de plus
   dans la table des requetes. L'ecart dit qu'on a change de sujet. */
.conso-bloc-gsc .conso-table-cadre + .conso-table-cadre { margin-top: var(--espace-md); }

/* --------------------------------------------------------------------------
   La courbe datee d'un volet : un cadre, une grille, un ou deux traces.

   Une famille a elle, comme celle du depot et celle de Search Console, et pour
   la raison ecrite plus haut : ces blocs n'ont ni le meme nombre de courbes ni
   le meme rapport au survol, et leur faire partager un nom de classe ferait
   qu'un reglage de l'un deplacerait l'autre. Ce qu'ils partagent est ailleurs,
   dans `app/graphe.py` : la geometrie, pas l'habillage.
   -------------------------------------------------------------------------- */
.conso-graphe { margin: 0; }

.conso-graphe-tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace-sm);
  flex-wrap: wrap;
  margin-bottom: var(--espace-xs);
}

.conso-graphe-legende {
  display: flex;
  align-items: center;
  gap: var(--espace-md);
  flex-wrap: wrap;
}

.conso-graphe-entree {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Un trait et non une pastille, contrairement a la legende du depot : c'est un
   trait qu'il annonce dans le cadre, et un carre de couleur promettrait des
   barres. */
.conso-graphe-entree i {
  display: block;
  width: var(--espace-md);
  height: var(--espace-3xs);
  border-radius: 999px;
  background: var(--conso-teinte);
}

/* Pointille comme le trace qu'il annonce, et sur le meme rythme que son
   `stroke-dasharray` : un temoin plein pour une courbe en pointille laisse
   croire a deux traits pleins et fait chercher lequel est lequel. */
.conso-graphe-entree-maison i {
  background: repeating-linear-gradient(
    to right, var(--gray-5) 0 4px, transparent 4px 7px);
}

/* Le sommet ecrit en toutes lettres plutot que porte par un axe gradue : la
   meme decision que pour le bloc Search Console, et la meme raison. */
.conso-graphe-haut {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

/* `overflow: visible` : le jour le plus haut touche le bord du cadre, et un
   trait de deux pixels centre dessus serait coupe en deux sans cela. */
.conso-graphe-svg {
  display: block;
  width: 100%;
  height: 200px;
  overflow: visible;
  border-bottom: 1px solid var(--gray-3);
}

/* Trois traits aux quarts de l'echelle, et rien de plus : une grille plus
   dense se met a decorer, et une grille qui decore se lit comme une donnee. */
.conso-graphe-grille {
  fill: none;
  stroke: var(--gray-2);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.conso-graphe-aire { fill: var(--conso-teinte); opacity: .12; stroke: none; }
.conso-graphe-aire-maison { fill: var(--gray-4); }

/* `non-scaling-stroke` : le cadre est etire a la largeur du bloc sans garder
   ses proportions (`preserveAspectRatio="none"`), donc une epaisseur posee
   dans le repere du dessin s'etirerait avec lui. */
.conso-graphe-trait {
  fill: none;
  stroke: var(--conso-teinte);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* Notre compteur en pointille : deux traits pleins de meme epaisseur se
   confondraient partout ou les deux mesures concordent, c'est-a-dire la ou il
   n'y a justement rien a signaler. */
.conso-graphe-trait-maison {
  stroke: var(--gray-5);
  stroke-width: 1.5;
  stroke-dasharray: 4 3;
}

.conso-graphe-axe {
  display: flex;
  justify-content: space-between;
  margin-top: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

.conso-tete {
  display: flex;
  align-items: center;
  gap: var(--espace);
  padding-bottom: var(--espace);
  border-bottom: 1px solid var(--gray-2);
}

/* La tuile du fournisseur : le seul endroit de la page ou sa teinte est
   pleine. Elle sert de repere de bloc quand on fait defiler -- on ne relit pas
   le nom, on reconnait la case. */
.conso-tete-jeton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: var(--radius-sm);
  background: var(--conso-teinte);
  color: #fff;
}

.conso-tete-jeton .icon { width: var(--icon-md); height: var(--icon-md); }

.conso-tete-noms { display: flex; flex-direction: column; min-width: 0; }

.conso-tete-nom {
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--black);
  line-height: 1.2;
}

.conso-tete-quoi { font-size: var(--fs-sm); color: var(--gray-5); }

/* Le chiffre du fournisseur, aligne a droite : les deux blocs le posent au
   meme endroit, ce qui les rend comparables d'un coup d'oeil -- sans jamais
   les additionner, ils ne comptent pas la meme chose ni la meme periode. */
.conso-tete-chiffre {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
}

.conso-tete-chiffre strong {
  font-size: var(--fs-h2);
  font-weight: 600;
  color: var(--black);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.conso-tete-borne { font-size: var(--fs-2xs); color: var(--gray-5); }

.conso-toolbar { border-bottom: none; }
/* Une barre qui ne porte que « Rafraichir » : a droite, a sa place dans
   les volets qui ont aussi une periode. */
.conso-toolbar-seule { justify-content: flex-end; }

/* Le titre d'un tableau a l'interieur d'un bloc : plus discret qu'une tete de
   fournisseur, sinon les deux niveaux se disputeraient la lecture. */
.conso-sous-titre {
  display: flex;
  align-items: center;
  /* La note passe sous le titre plutot que de le serrer : sans quoi, sur un
     telephone, un titre de deux mots se casse en colonne pendant que sa note
     occupe le reste de la largeur. */
  flex-wrap: wrap;
  gap: var(--espace-xs);
  margin: var(--espace-xl) 0 var(--espace-sm);
}

.conso-sous-titre-texte {
  /* Le volet des tickets et celui du temps y posent des `h2` et des `h3` : la
     marge que le navigateur leur donne d'office jetterait la note a la ligne
     suivante, et le titre serait seul sur la sienne. */
  margin: 0;
  white-space: nowrap;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  font-weight: 600;
  color: var(--gray-6);
}

.conso-sous-titre-note {
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--gray-5);
}

/* --- Les onglets d'une carte, et d'un tableau de bord -----------------------

   « C'est pas mal mais trop long, fais des pages plus compactes avec des
   onglets qu'on peut ouvrir pour plus de detail » (demande du 7 septembre
   2026), puis « implemente a chaque fois pour tous les dashboards » (le 8).

   Un volet du Dashboard ouvert mesurait de 1122 a 3464 px de haut, soit trois
   ecrans et demi pour le plus long ; l'ecran du cabinet 2901 px pour huit
   tuiles, l'onglet Mandat d'un dossier 4943 pour seize. Ce sont les memes deux
   pages en une : des sections qui se suivent, dont on ne lit qu'une a la fois.
   Elles deviennent une rangee d'onglets et un seul panneau ouvert.

   Le Dashboard en est reparti des le lendemain, et c'est la premiere chose a
   savoir avant de poser cette rangee ailleurs : « je voulais voir toutes les
   cases [...] pas besoin de defiler par un menu ». La forme vaut pour des
   sections dont on fait une a la fois -- des formulaires, l'ecran du cabinet
   --, pas pour des mesures qu'on releve d'un coup d'oeil. Ce que le Dashboard
   a pris a la place est plus bas, `.conso-cases`.

   D'ou le nom sans prefixe. La rangee est la meme aux quatre endroits ou elle
   sert ; ce qui differe est la coupe -- un titre de section dans une carte du
   Dashboard, un attribut de gabarit sur une tuile --, et la coupe est du
   ressort de qui appelle. La mecanique commune est dans `onglets.js`.

   C'est la rangee d'onglets du site (`.dossier-tabs`, plus haut dans cette
   feuille) et non une seconde : un filet, un soulignement de deux pixels sous
   l'onglet ouvert, et la rangee qui defile plutot que de pousser la page. Elle
   en differe sur deux points, tous deux tenus par ce qu'elle nomme.

   Les libelles sont ceux des titres de section qu'ils remplacent, donc ils en
   gardent la casse, le corps et le suivi : ce sont les memes mots, ils ne
   changent pas de voix en changeant de place.

   Et le soulignement prend la teinte de la carte plutot que le cyan -- cinq
   volets sur huit ne sont pas cyan, et une barre cyan sous un bloc violet
   annoncerait une couleur que rien d'autre n'y porte. Hors du Dashboard,
   `--conso-teinte` n'est declaree nulle part : le repli ecrit le cyan du
   produit, qui est la teinte d'une page ordinaire. Le texte de l'onglet
   ouvert, lui, reste noir : la teinte vaut ce meme cyan dans trois volets, et
   du cyan en capitales de onze pixels sur blanc ne se lit pas. C'est deja la
   raison pour laquelle `.conso-periode-lien.actif` prend `--cyan-dark` et non
   `--cyan`.
   -------------------------------------------------------------------------- */

.onglets {
  display: flex;
  gap: var(--espace-2xs);
  margin: var(--espace-lg) 0 var(--espace-md);
  overflow-x: auto;
  /* Peint dans la boite : le filet ne defile pas avec la rangee, et il se
     laisse recouvrir par les deux pixels de l'onglet ouvert. */
  box-shadow: inset 0 -1px 0 var(--gray-2);
  scrollbar-width: none;
}

.onglets::-webkit-scrollbar { display: none; }

/* Le volet des tickets n'a pas de tete : ses huit sections commencent des le
   bord de la carte, qui a deja son creux. Un tableau de bord non plus, quand
   le gabarit nomme sa premiere tuile. */
.onglets:first-child { margin-top: 0; }

/* Deshabille par l'element, comme les fenetres de periode juste au-dessus : un
   bouton laisse nu prend l'apparence du systeme et change d'une machine a
   l'autre. Le creux vertical vaut --espace-sm et non --espace-xs : l'onglet
   fait alors 34 px de haut, la taille de ceux du dossier, quand son libelle en
   capitales de onze pixels en donnerait 28. */
.onglet {
  flex: none;
  padding: var(--espace-sm) var(--espace);
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  font-family: inherit;
  line-height: inherit;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  font-weight: 600;
  white-space: nowrap;
  color: var(--gray-4);
  cursor: pointer;
  transition: color .15s var(--ease), border-color .15s var(--ease);
}

.onglet:hover { color: var(--gray-6); }

.onglet[aria-selected="true"] {
  color: var(--black);
  border-bottom-color: var(--conso-teinte, var(--cyan));
}

.panneau[hidden] { display: none; }

/* Ce qui ouvre un panneau suit la rangee d'onglets, qui a deja son espace : la
   marge haute d'un titre de section creuserait un trou de vingt-quatre pixels
   sous le filet. Et ce qui le ferme ne pousse pas le bas de la page : les
   32 px que `.panel` porte sous lui sont la cadence d'une colonne, pas celle
   d'un onglet. */
.panneau > :first-child { margin-top: 0; }
.panneau > :last-child { margin-bottom: 0; }

/* Un tableau de bord qui prend des onglets cesse d'etre une grille : il empile
   sa tete, sa rangee et ses panneaux, et c'est le panneau qui redevient la
   grille (`onglets.js` lui pose la classe). Tout ce qui est ecrit plus haut
   pour `.grille-de-tuiles > ...` continue donc de valoir sur les tuiles, sans
   qu'une seule regle soit recopiee. */
.grille-de-tuiles.a-onglets { display: block; }

/* Ce qui precede la rangee -- une frise qui se lit d'un bord a l'autre quel
   que soit l'onglet ouvert -- n'est plus dans une grille : les tuiles y
   retrouvent la marge que la grille leur avait reprise. */
.grille-de-tuiles.a-onglets > .tuile + .tuile,
.grille-de-tuiles.a-onglets > .tuile + .aglae-bloc,
.grille-de-tuiles.a-onglets > .aglae-bloc + .tuile { margin-top: var(--espace-md); }

/* Le titre qu'un onglet reprend ne se lit pas deux fois a dix pixels d'ecart :
   celui de la tuile s'efface, l'onglet le porte. Deux regles voisines
   effacaient de meme le titre d'une section du Dashboard ; elles sont parties
   le 8 septembre 2026 avec ses onglets. Dans une case, le titre est reste ou
   il etait, et plus rien ne le reprend. */
.titre-repris { display: none; }

/* Le panneau qui s'ouvre monte de quelques pixels au lieu d'apparaitre d'un
   coup. Une animation et non une transition : le panneau passe de `display:
   none` a visible, etat entre lesquels une transition n'a rien a interpoler.
   Le navigateur rejoue l'animation a chaque reaffichage, ce qui est exactement
   le moment voulu et n'oblige a poser aucune classe. */
@keyframes panneau-entre {
  from { opacity: 0; transform: translateY(4px); }
}

.panneau { animation: panneau-entre calc(var(--conso-duree, 420ms) * .5) var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .panneau { animation: none; }
}

/* --- Les cases d'un tableau de bord -----------------------------------------

   « Je voulais voir toutes les cases, mais avec seulement les informations
   essentielles ou un raccourci, et chaque case pouvoir la deployer pour plus
   de details. Elles sont de base toutes la. Pas besoin de defiler par un
   menu » (demande du 8 septembre 2026).

   La rangee d'onglets ci-dessus avait pris la longueur au mot : elle range
   huit metriques dans huit tiroirs et n'en ouvre qu'un. Or ce qui etait long
   n'est pas le nombre de metriques -- c'est le detail de chacune. Un tableau
   de bord se lit d'un coup d'oeil ; ce qu'on veut replier est le releve ligne
   a ligne, pas la mesure.

   Donc toutes les sections a la fois, en deux colonnes la ou la largeur les
   porte, chacune coupee a la hauteur d'un apercu et rouverte sur place. Le
   volet le plus long du Dashboard passe de 3464 px a un millier, sans qu'une
   seule metrique ait a etre cherchee dans un menu.

   L'apercu vaut 340 px, et ce n'est pas une hauteur d'ecran : c'est celle du
   plus grand dessin de la page, la rose des langages du depot, 318 px avec son
   titre. Aucune figure n'est donc jamais coupee ; ce que la coupe rogne est ce
   qui est long par nature -- un tableau, une pile de rails, huit rangees de
   tickets. Un apercu plus court aurait mange une couronne ou une courbe, et une
   figure a moitie dessinee ne dit plus rien du tout. La valeur se declare sur
   la case et non dans `:root` : elle ne mesure pas un barreau d'echelle, elle
   mesure cette page-la, comme `--conso-duree` juste a cote.

   La case n'a pas de cadre. La carte du volet en est deja un (`.conso-bloc`)
   et huit cadres dans un cadre feraient une pile de traits -- c'est la raison
   deja ecrite pour `.tka-bloc`. Ce qui separe est un fond pale, la meme
   distinction qu'une `.tuile` sur une page ordinaire, et il tombe bien : les
   rails et les mesures qui s'y posent sont blancs, et se detachaient jusqu'ici
   sur leur seule bordure.

   La grille est celle de tout le produit (`.grille-de-tuiles`, plus haut) :
   `--largeur-colonne`, donc deux colonnes sur un ecran large et une seule des
   qu'on descend. Un tableau large ne reclame pas la pleine largeur en
   s'ouvrant -- il defile dans son cadre, comme partout ailleurs dans cette
   feuille. Une case qui changerait de colonne en s'ouvrant deplacerait toutes
   les suivantes sous la main qui vient de cliquer, et c'est exactement le
   defaut qu'on vient de corriger.
   -------------------------------------------------------------------------- */

.conso-cases {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--largeur-colonne), 100%), 1fr));
  gap: var(--espace-md);
  /* Les cases d'une meme rangee font la meme hauteur. L'inverse a ete essaye
     d'abord -- `align-items: start`, chaque case a sa hauteur propre -- et le
     navigateur l'a tranche : une section courte a cote d'une section coupee
     laissait un trou blanc de trois cents pixels au milieu de la page, sans
     rien pour dire si c'etait un vide voulu ou un morceau qui n'a pas charge.
     Etiree, la meme section courte est une tuile pale qui va jusqu'au bas de
     sa rangee : le vide appartient a la case, et se lit comme « rien de plus
     ici ». La contrepartie est assumee : la voisine d'une case ouverte s'etire
     avec elle et montre du fond nu sous son contenu. Ecrit, bien que ce soit
     la valeur par defaut : la ligne dit ce que la rangee fait. */
  align-items: stretch;
}

.conso-case {
  --conso-apercu: 340px;
  /* La hauteur reelle du contenu, que le script releve juste avant l'ouverture
     (voir `dashboard-gestes.js`). Declaree ici a `none` : c'est la valeur qui
     s'applique si le script n'a pas pu mesurer, et une case bloquee ouverte se
     lit, la ou une case bloquee fermee cache. Meme facon de faire que
     `--rang`, pose par le meme script un peu plus bas dans la feuille. */
  --conso-plein: none;
  padding: var(--espace) var(--espace-md);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

.conso-case-corps {
  position: relative;
  max-height: var(--conso-apercu);
  overflow: hidden;
  transition: max-height var(--conso-duree, 420ms) var(--ease);
}

/* Le titre d'une section porte une marge haute pour se detacher de la section
   precedente. Dans une case il n'y a plus de section precedente : il y a le
   bord de la case, qui a deja son creux. Et le bas ne pousse pas non plus --
   ce qui suit est le bouton, pas une autre section. */
.conso-case-corps > :first-child { margin-top: 0; }
.conso-case-corps > :last-child { margin-bottom: 0; }

/* Ce qui est coupe s'efface plutot que de finir net : une ligne de tableau
   tranchee au milieu se lit comme une ligne, un degrade se lit comme une
   suite. Peint dans la boite coupee -- `overflow: hidden` en fait le bloc
   conteneur, et le bas de ce bloc est exactement la ou la coupe tombe.

   LE VOILE NE PARAIT QUE SUR UNE CASE REELLEMENT COUPEE, c'est-a-dire sur
   celles qui portent un bouton « Plus de detail ». « Je pense qu'il faut
   implementer ce flou en bas uniquement s'il y a une section PLUS DE DETAIL,
   la on peut avoir un flou important ; s'il n'y en a pas, mets aucun flou »
   (suivi du 15 septembre 2026, apres la 23.16 et la 23.73).

   C'etait la vraie cause des deux plaintes precedentes, et ni la hauteur ni
   l'opacite ne pouvaient la corriger : la bande etait peinte sur TOUTES les
   cases, y compris celles qui tiennent entieres dans leur cadre. Sur
   celles-la, elle ne prevenait de rien -- il n'y a pas de suite -- et voilait
   quand meme la derniere ligne. On corrigeait donc le voile la ou il fallait
   le retirer, et chaque tour d'attenuation le rendait un peu moins lisible de
   part et d'autre : trop pale pour annoncer une coupe la ou il y en a une,
   encore trop present la ou il n'y en a pas.

   Separees, les deux cases se reglent chacune pour elle-meme. Celle qui n'est
   pas coupee ne porte plus rien, et sa derniere ligne se lit comme les autres.
   Celle qui l'est porte un degre franc -- jusqu'a --gray-1, le fond plein de
   la case, sur --espace-lg -- parce que ce qu'il couvre est de toute facon
   tranche, et qu'un voile qui n'ose pas ne dit plus qu'il y a une suite.

   C'est le script qui tranche, case par case et a chaque redimensionnement
   (`data-coupe` dans dashboard-gestes.js) : la meme mesure qui decide
   d'afficher le bouton, puisque c'est la meme question. Une case deployee
   n'est plus coupee et perd son voile par la regle qui suit. */
.conso-case[data-coupe="true"] > .conso-case-corps::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: var(--espace-lg);
  background: linear-gradient(to bottom, transparent, var(--gray-1));
  pointer-events: none;
}

.conso-case[data-deploye="true"] > .conso-case-corps { max-height: var(--conso-plein); }

.conso-case[data-deploye="true"] > .conso-case-corps::after { display: none; }

/* Le bouton qui deroule, sur toute la largeur de sa case : son libelle fait
   onze pixels de haut, et une cible a la taille de son texte se rate. Il
   n'apparait que si quelque chose est vraiment cache -- c'est le script qui
   le decide, case par case, et une section courte n'en a pas. */
.conso-case-plus {
  display: block;
  width: 100%;
  min-height: var(--h-champ);
  margin-top: var(--espace-xs);
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  font-weight: 600;
  text-align: left;
  color: var(--gray-5);
  cursor: pointer;
  transition: color .15s var(--ease);
}

.conso-case-plus:hover { color: var(--black); }

@media (prefers-reduced-motion: reduce) {
  .conso-case-corps { transition: none; }
}

/* Un tableau large ne pousse pas la page : il defile dans son cadre. La
   derniere ligne perd sa bordure basse -- celle du cadre la double, et deux
   traits a un pixel d'ecart se voient. */
.conso-table-cadre {
  overflow-x: auto;
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
}

.conso-table-cadre tr:last-child > td { border-bottom: none; }

/* Cinq fenetres de periode : elles se replient plutot que de pousser la page.
   Une rangee souple qui refuse de plier a une largeur minimale egale a la somme
   de ses cinq boutons -- 303 px ici -- et la barre d'outils qui la porte,
   posee en `flex: none`, la reportait telle quelle : la page de consommation
   depassait de 18 px a droite sur un telephone, et c'est la page entiere qui
   defilait lateralement. */
.conso-periodes { display: inline-flex; flex-wrap: wrap; gap: var(--espace-2xs); min-width: 0; }

.conso-periode-lien {
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: var(--radius-xs);
  font-size: var(--fs-sm);
  color: var(--gray-5);
  text-decoration: none;
  transition: background .15s var(--ease), color .15s var(--ease);
}

/* Les fenetres de la courbe du code sont des boutons, pas des liens : elles ne
   rechargent rien. Un bouton laisse nu prend l'apparence du systeme -- cadre
   gris, degrade, police de l'OS -- et change d'une machine a l'autre ; a cote
   des fenetres de periode d'OpenAI, qui sont des liens, les deux rangees ne se
   ressemblaient plus du tout (« completement inadapte au style du site »,
   demande du 26 aout 2026). Deshabille ici, par l'element : c'est la meme
   regle que pour les cases a cocher et les listes deroulantes a la base de
   cette feuille. */
button.conso-periode-lien {
  border: none;
  background: none;
  font-family: inherit;
  line-height: inherit;
  cursor: pointer;
}

.conso-periode-lien:hover { background: var(--gray-2); color: var(--gray-6); }

.conso-periode-lien.actif { background: var(--cyan-light); color: var(--cyan-dark); font-weight: 600; }

/* La fenetre retenue prend la teinte de sa carte. Le cyan de la regle
   ci-dessus est celui d'OpenAI ; pose dans la carte bleue du code, il y
   annoncait une couleur que rien d'autre dans le bloc ne porte. */
.conso-bloc-code .conso-periode-lien.actif {
  background: var(--blue-pale);
  color: var(--blue-dark);
}

.conso-bornes { font-size: var(--fs-sm); color: var(--gray-5); }

.conso-mesures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--espace-md);
  margin-top: var(--espace-md);
}

/* Filet gris, --radius, fond blanc : le creux des cartes, cf. .arbitrage. */
.conso-mesure {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  padding: var(--espace-md) var(--espace-lg);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
}

.conso-mesure-titre {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  color: var(--gray-5);
}

.conso-mesure-chiffre {
  font-size: var(--fs-hero);
  font-weight: 600;
  color: var(--black);
  font-variant-numeric: tabular-nums;
}

.conso-mesure-second { font-size: var(--fs-sm); color: var(--gray-6); }

/* Le chiffre et son ecart sur une meme ligne : l'ecart est une lecture du
   chiffre, pas un second chiffre. Aligne sur la ligne de base, pour que le
   petit ne flotte pas au milieu du grand. */
.conso-mesure-ligne {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--espace-xs);
}

/* L'ecart entre les deux moities de la fenetre. Vert a la hausse, gris a la
   baisse -- jamais rouge : une baisse d'impressions n'est pas une panne, et
   peindre en rouge ce que personne ne peut reparer transforme un tableau de
   bord en tableau d'alarmes. C'est la meme raison qui laisse `.gsc-zero` gris
   dans le tableau juste en dessous. */
.conso-delta {
  font-size: var(--fs-2xs);
  font-weight: 600;
  padding: 0 var(--espace-2xs);
  border-radius: 999px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.conso-delta.hausse { color: var(--green-dark); background: var(--green-pale); }
.conso-delta.baisse,
.conso-delta.plat { color: var(--gray-5); background: var(--gray-1); }

.conso-mesure-detail { font-size: var(--fs-xs); color: var(--gray-5); }

/* La marque « estime », a cote d'une duree deduite des tokens plutot que
   publiee par OpenAI. Discrete mais lisible : elle doit se voir sans qu'on la
   cherche, sinon on compare une estimation a une mesure sans le savoir. */
.conso-estime {
  font-size: var(--fs-3xs);
  color: var(--gray-5);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  padding: 0 .35em;
  margin-left: .35em;
  text-decoration: none;
  cursor: help;
  white-space: nowrap;
}

/* La case du facture porte la marque de la source de verite : c'est elle qui
   dit le total du cabinet, pas la somme de nos lignes. */
.conso-mesure-source { border-color: var(--cyan); background: var(--cyan-pale); }

/* L'ecart est orange par defaut : il appelle une explication tant qu'il n'a
   pas ete regarde. Vert quand les deux mesures concordent, gris quand il n'est
   pas mesurable -- surtout pas vert, qui laisserait croire a un accord. */
.conso-mesure-ecart { border-color: var(--orange); background: var(--orange-pale); }
.conso-mesure-ecart .conso-mesure-chiffre { color: var(--orange-dark); }
.conso-mesure-ecart.negligeable { border-color: var(--green); background: var(--green-pale); }
.conso-mesure-ecart.negligeable .conso-mesure-chiffre { color: var(--green-dark); }
.conso-mesure-ecart.inconnu { border-color: var(--gray-3); background: var(--gray-1); }
.conso-mesure-ecart.inconnu .conso-mesure-chiffre { color: var(--gray-4); }

/* Le « rien ici » du tableau de bord : un tiret, un mot gris dans une case.
   Pas `.conso-vide`, qui est le nom d'une vue vide entiere dans le second
   espace `.conso-*` de cette feuille, celui du controle FEC -- une carte a
   bordure pointillee, declaree plus bas et qui gagnait donc a specificite
   egale. Dix cases du tableau de bord s'affichaient en cadres pointilles. */
.conso-rien { color: var(--gray-4); font-weight: 400; }

/* Le prix a l'unite, sous la quantite. Sur sa propre ligne : c'est une autre
   mesure que la quantite, pas une precision de celle-ci, et les deux collees se
   liraient comme un seul nombre coupe en deux. */
.conso-prix-unite {
  display: block;
  white-space: nowrap;
}

/* La colonne d'une part : une barre, puis le chiffre.
   Des pourcentages empiles se relisent ligne a ligne ; des barres se comparent
   sans lecture. Les deux sont la, parce qu'une barre seule ne se cite pas dans
   un courriel. La barre prend la teinte de son bloc, sauf quand elle dit un
   depassement -- la, elle passe a l'orange, la meme couleur que l'ecart dit
   ailleurs sur cette page : ce qui appelle une explication. */
.conso-col-part {
  white-space: nowrap;
  min-width: 8.5rem;
}

.conso-jauge {
  display: inline-block;
  vertical-align: middle;
  width: 4.5rem;
  height: 6px;
  margin-right: var(--espace-xs);
  border-radius: 999px;
  background: var(--gray-2);
  overflow: hidden;
}

.conso-jauge-remplissage {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--conso-teinte);
}

.conso-jauge.depasse { background: var(--orange-pale); }
.conso-jauge.depasse .conso-jauge-remplissage { background: var(--orange); }

.conso-jauge-valeur {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

/* Les rails de plafond : la meme grandeur qu'une colonne « Part du forfait »,
   lue dans l'autre sens. Les trois postes du forfait Supabase les portent, et
   le credit inclus de Vercel depuis -- d'ou un nom qui ne dit plus de qui.

   Le tableau dit ce qui est consomme ; le rail dit ce qu'il reste, dans
   l'unite du poste, et ce que coutera l'unite suivante. Les trois postes y
   sont ranges du plus serre au plus large -- le premier est celui qui coutera
   en premier, ce qu'un ordre fixe ne dit jamais.

   Pleine largeur, la ou la jauge du tableau tient en 4,5 rem : trois postes se
   comparent d'un coup d'oeil sur une longue piste, pas sur trois moignons.

   Trois lignes dans deux colonnes : le nom et la part se font face, la piste
   et la marge tiennent toute la largeur. La marge est une phrase, elle se
   replie donc toute seule sur un telephone au lieu de disputer une colonne au
   nom du poste. */
.conso-rails {
  display: grid;
  gap: var(--espace-sm);
  margin-top: var(--espace-md);
}

.conso-rail {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: var(--espace-2xs) var(--espace-sm);
  padding: var(--espace-sm) var(--espace-md);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}

.conso-rail-nom {
  font-size: var(--fs);
  font-weight: 600;
  color: var(--black);
}

.conso-rail-part {
  font-size: var(--fs);
  font-weight: 600;
  color: var(--conso-teinte);
  font-variant-numeric: tabular-nums;
}

.conso-rail-piste {
  /* Le repere de la projection, qui se cale dessus. */
  position: relative;
  grid-column: 1 / -1;
  height: 10px;
  border-radius: 999px;
  background: var(--gray-2);
  overflow: hidden;
}

.conso-rail-trace {
  /* Elle passe au-dessus de la projection, qui la precede dans le gabarit. */
  position: relative;
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--conso-teinte);
}

/* La piste d'un rail decoupee en parts, dans le volet OpenAI. La longueur
   compare les modeles entre eux, la decoupe compare les natures a l'interieur
   d'un seul modele : deux echelles emboitees, la meme construction que
   `barre_pile` du volet Temps.

   Les segments sont des `.conso-pile-part` et non une classe a eux : ce sont
   les memes parts, aux memes teintes, que la pile des natures posee plus bas
   sur la page, et c'est par cette identite qu'un modele et cette pile
   s'allument ensemble. Le rayon et le rognage sont ici et non sur la piste :
   la pile est plus courte qu'elle, son bout droit resterait carre. */
.conso-rail-pile {
  display: flex;
  height: 100%;
  border-radius: 999px;
  overflow: hidden;
}

/* Un rail qui recule. La meme convention que les sept cases du volet Code,
   et pour la meme raison : orange et non rouge, une suppression n'est pas une
   panne -- c'est meme souvent la meilleure journee de la semaine. */
.conso-rail.negatif .conso-rail-part { color: var(--orange-dark); }
.conso-rail.negatif .conso-rail-trace { background: var(--orange); }

/* Un rail dont la mesure est un age. Sa trace prend sa teinte de la roue, par
   `data-teinte` ; la duree ecrite en bout de ligne la prend ici, dans la
   version foncee. La roue peint des fonds, et un orange de fond passe a
   2,4 pour 1 sur du blanc des qu'on en fait de l'encre -- c'est la meme raison
   qui fait ecrire `--orange-dark` sur la ligne au-dessus. */
.conso-rail[data-part="age-frais"] .conso-rail-part { color: var(--green-dark); }
.conso-rail[data-part="age-semaine"] .conso-rail-part { color: var(--yellow); }
.conso-rail[data-part="age-mois"] .conso-rail-part { color: var(--orange-dark); }
.conso-rail[data-part="age-vieux"] .conso-rail-part { color: var(--red-dark); }

/* La projection : la meme mesure prolongee jusqu'au bout du cycle si le rythme
   tient. Elle part de zero comme la trace du jour et passe dessous, de sorte
   que ce qui la depasse est exactement ce qui reste a venir.

   La meme teinte a un quart d'encre plutot qu'une couleur a elle : une seconde
   couleur ferait croire a une seconde mesure, alors qu'il n'y en a qu'une, lue
   deux fois. Un repere pose a un endroit de la piste, lui, se lirait comme une
   borne a ne pas franchir -- ce qu'une projection n'est pas. */
.conso-rail-projection {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  border-radius: 999px;
  background: var(--conso-teinte);
  opacity: .25;
}

.conso-rail-marge {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
}

.conso-rail-prix { color: var(--gray-6); font-weight: 500; white-space: nowrap; }

/* Un poste depasse passe a l'orange, la meme couleur que le depassement dit
   ailleurs sur cette page : ce qui appelle une explication. */
.conso-rail.depasse .conso-rail-part { color: var(--orange); }
.conso-rail.depasse .conso-rail-piste { background: var(--orange-pale); }
.conso-rail.depasse .conso-rail-trace { background: var(--orange); }

/* Deux familles de bandes pales, et elles ne prennent pas le meme creux.

   Un AVERTISSEMENT tient la largeur de la page : 9,6 x 16, comme
   `.classeur-avertissement` -- dont `.conso-alerte` est la jumelle a la
   declaration pres -- et comme `.alertes-bandeau-admin`.

   Un message d'ERREUR de formulaire vit dans une colonne de 440 px : 9,6 x
   12,8, comme `.login-erreur` et `.compte-erreur`. Seize pixels de chaque cote
   dans une colonne aussi etroite se lisent comme une marge, pas comme un
   creux.

   Les deux etaient a 11,2 x 14,4, entre les deux familles et sur aucune. */
.conso-alerte {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-xs);
  margin-top: var(--espace-md);
  padding: var(--espace-sm) var(--espace-md);
  border-radius: var(--radius-sm);
  background: var(--yellow-pale);
  color: var(--gray-6);
  font-size: var(--fs-sm);
  line-height: 1.5;
}

.conso-alerte .icon { flex: none; margin-top: var(--espace-3xs); color: var(--yellow); }

.conso-causes {
  margin-top: var(--espace-md);
  padding: var(--espace) var(--espace-md);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

.conso-causes-titre {
  display: block;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  color: var(--gray-5);
  margin-bottom: var(--espace-sm);
}

.conso-causes-liste {
  margin: 0;
  padding-left: var(--espace-lg);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.6;
}

.conso-table .num { font-variant-numeric: tabular-nums; }

.conso-total-cellule { font-weight: 600; color: var(--black); }

.conso-table tfoot td {
  font-weight: 600;
  border-top: 2px solid var(--gray-3);
  background: var(--gray-1);
}

/* L'ECART AVEC LE NOM N'APPARTIENT PAS AU ROND, IL APPARTIENT A LA PAIRE.

   « ronds pas centré » (ticket du 16 septembre 2026, capture des couronnes
   « Par collaborateur » a l'appui). Le rond portait `margin-right` pour se
   detacher du nom qui le suit dans le tableau ; au centre d'une couronne il n'a
   aucun nom a cote de lui, et le centrage en flexbox centre la boite MARGES
   COMPRISES. Les six ronds etaient donc decales de 3,2 px vers la gauche, la
   moitie de l'ecart, dans un anneau parfaitement centre. Mesure du jour : dx
   -3,2 px, dy 0.

   La marge passe donc au nom, qui est le seul a la vouloir et qui n'existe que
   la ou elle a un sens : une couronne n'a pas de `.conso-nom` dedans, elle ne
   recoit plus rien, et le rond reprend sa place sans qu'aucune regle n'ait a
   defaire ce qu'une autre a pose. */
.conso-pastille {
  --avatar-d: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--avatar-d);
  height: var(--avatar-d);
  border-radius: 999px;
  color: #fff;
  font-size: calc(var(--avatar-d) * var(--avatar-initiales));
  font-weight: 600;
  vertical-align: middle;
}

.conso-nom {
  margin-left: var(--espace-xs);
  vertical-align: middle;
}

.conso-note {
  margin: var(--espace) 0 0;
  max-width: 70ch;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
}

/* Quand la mesure a été prise. Elle se lit avant le tableau et non après --
   c'est la question qu'on se pose en ouvrant (« à quelle date les données qu'on
   est en train de lire ont été tirées ? », demande du 30 août 2026), pas celle
   qu'on se pose en le refermant. D'où la marge du dessus remise à zéro : elle
   suit la ligne du forfait, elle ne clôt pas un bloc.

   `conso-datation` et non `conso-mesure` : ce dernier nom est déjà celui des
   grands blocs de chiffres du volet OpenAI et de Search Console, et le
   reprendre ici leur aurait retiré leur marge du dessus. Deux choses
   différentes ne portent pas le même nom, même quand le mot est libre à
   l'oreille. */
.conso-datation { margin-top: 0; margin-bottom: var(--espace); }

/* L'etat des services Supabase, dans un bloc .conso-mesure. Une liste et non
   des pilules : ils se lisent l'un sous l'autre, et ce qu'on cherche est la
   ligne qui n'est pas verte.

   Les deux teintes sont celles que les tuiles de cette meme page emploient
   deja pour dire sain et attention (.conso-tuile-sain / -attention) : un etat
   de service n'est pas un etat nouveau, il ne merite donc pas une troisieme
   facon de peindre le vert. */
.conso-services {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  margin: var(--espace-3xs) 0 0;
  padding: 0;
  list-style: none;
}

.conso-service {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

/* Une pile : une seule piste decoupee en parts qui font un tout, la ou des
   barres classees juste au-dessus comparent des choses entre elles. Deux
   dessins parce que ce sont deux questions.

   Elle sert deux fois sur cette page -- aux natures de jeton d'OpenAI, a la
   composition du depot -- et sa legende avec. D'ou des noms qui ne parlent ni
   de jetons ni de langages, et un attribut de teinte qui dit seulement qu'il
   designe une part. */
.conso-pile {
  display: flex;
  height: 14px;
  margin-top: var(--espace-md);
  border-radius: 999px;
  overflow: hidden;
  background: var(--gray-2);
}

/* Un pixel au moins, comme la pile des tickets : une nature qui ne pese
   presque rien pese quand meme quelque chose, et un segment de largeur nulle
   dirait qu'elle n'existe pas. */
.conso-pile-part { min-width: 1px; }

/* Les couronnes. Une par personne, decoupee par passe, le rond de profil au
   centre.

   Une pile horizontale de plus aurait dit la meme chose que les barres du
   dessus et que le tableau du dessous : trois fois la meme forme sur un seul
   volet, et l'oeil ne distingue plus laquelle repond a quoi. L'anneau repond a
   une autre question. Il ne compare pas les gens entre eux -- il est de la
   meme taille pour tout le monde --, il dit de quoi la depense de chacun est
   faite. « Celui-ci ne fait que dicter, celui-la ne lit que des pieces » se
   voit d'un coup d'oeil, sans lire un chiffre.

   Le tour de l'anneau vaut cent, ce qui supprime tout calcul : le pourcentage
   se pose tel quel dans `stroke-dasharray`. C'est le rayon qui s'y plie
   (100 / 2pi = 15,9155) et non les nombres qui s'adaptent au rayon. */
.conso-couronnes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(146px, 1fr));
  gap: var(--espace-lg) var(--espace-md);
  margin-bottom: var(--espace-lg);
}

.conso-couronne {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-3xs);
  min-width: 0;
  text-align: center;
}

.conso-couronne-anneau {
  position: relative;
  width: 108px;
  max-width: 100%;
  aspect-ratio: 1;
}

.conso-couronne-svg { display: block; width: 100%; height: 100%; }

/* La piste, sous les arcs : sans elle, une personne qui n'a qu'une passe
   montre un trait suspendu au lieu d'un anneau entame. */
.conso-couronne-piste { fill: none; stroke: var(--gray-2); stroke-width: 3.6; }

.conso-arc { fill: none; stroke: currentColor; stroke-width: 3.6; }

/* Le rond de profil au centre. Un seul reglage le decrit, son diametre : le
   relief et les initiales s'en deduisent, et rien ici ne les reecrit.
   Sa boite couvre tout l'anneau et non le seul disque du milieu, donc elle
   intercepterait le pointeur avant les arcs : elle ne recoit rien. */
.conso-couronne-centre {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.conso-couronne-centre .conso-pastille { --avatar-d: 54px; }

.conso-couronne-nom {
  max-width: 100%;
  overflow: hidden;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--black);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.conso-couronne-chiffre { font-size: var(--fs-2xs); color: var(--gray-5); }

.conso-legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-2xs) var(--espace-md);
  margin-top: var(--espace-sm);
}

.conso-legende-entree {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
}

/* La meme pastille que les points de service plus bas dans la page : deux
   ronds de legende sous les yeux ne doivent pas differer d'un pixel. */
.conso-legende-pastille {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 999px;
}

.conso-legende-nom { color: var(--gray-6); }

.conso-legende-nb {
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

/* Les natures de jeton d'OpenAI. Trois nuances du cyan du bloc et non trois
   couleurs franches : ce sont trois parts d'une meme depense, pas trois choses
   differentes. La rampe va du plus fonce au plus clair dans l'ordre de
   lecture, l'entree en tete parce que c'est presque toujours elle qui pese. */
.conso-pile-part[data-part="entree"],
.conso-legende-pastille[data-part="entree"] { background: var(--cyan-dark); }
.conso-pile-part[data-part="sortie"],
.conso-legende-pastille[data-part="sortie"] { background: var(--cyan); }
.conso-pile-part[data-part="cache"],
.conso-legende-pastille[data-part="cache"] { background: var(--cyan-total); }
.conso-pile-part[data-part="autre"],
.conso-legende-pastille[data-part="autre"] { background: var(--gray-4); }

/* Les langages du depot. Sept teintes de la maison posees sur la convention
   que tout le monde reconnait : Python bleu, JavaScript jaune, Swift orange,
   CSS violet, HTML rouge. Elles distinguent sept parts, elles ne qualifient
   aucun etat -- aucune ne veut dire ici « attention » ni « tout va bien ». */
/* Ou sont les octets, dans le volet Supabase. La base prend la teinte du
   bloc, les fichiers le cyan de la maison : deux matieres differentes, donc
   deux couleurs et non deux nuances d'une meme -- la pile ne dit pas un degrade
   d'intensite, elle dit une frontiere. */
.conso-pile-part[data-part="base_octets"],
.conso-legende-pastille[data-part="base_octets"] { background: var(--purple); }
.conso-pile-part[data-part="stockage_octets"],
.conso-legende-pastille[data-part="stockage_octets"] { background: var(--cyan); }

/* La carte du depot prend la meme table que la legende : deux couches par
   tuile, le fond et la part vive, qui ne different que par leur opacite. C'est
   la pile qui a quitte la liste -- la carte l'a remplacee, et une regle qui ne
   peint plus rien est le debut d'une table qu'on n'ose plus toucher. */
.code-tuile-fond[data-part="python"],
.code-tuile-neuf[data-part="python"],
.conso-legende-pastille[data-part="python"] { background: var(--blue); }
.code-tuile-fond[data-part="javascript"],
.code-tuile-neuf[data-part="javascript"],
.conso-legende-pastille[data-part="javascript"] { background: var(--yellow); }
.code-tuile-fond[data-part="swift"],
.code-tuile-neuf[data-part="swift"],
.conso-legende-pastille[data-part="swift"] { background: var(--orange); }
.code-tuile-fond[data-part="css"],
.code-tuile-neuf[data-part="css"],
.conso-legende-pastille[data-part="css"] { background: var(--purple); }
.code-tuile-fond[data-part="html"],
.code-tuile-neuf[data-part="html"],
.conso-legende-pastille[data-part="html"] { background: var(--red); }
.code-tuile-fond[data-part="sql"],
.code-tuile-neuf[data-part="sql"],
.conso-legende-pastille[data-part="sql"] { background: var(--cyan); }
.code-tuile-fond[data-part="shell"],
.code-tuile-neuf[data-part="shell"],
.conso-legende-pastille[data-part="shell"] { background: var(--green); }

/* La roue des familles de service. Elle ne nomme rien : Vercel n'ouvre pas la
   liste de ses categories, et une famille qui apparaitrait demain sortirait
   sans couleur d'une table ecrite ici. La teinte marque donc le rang dans la
   depense, la legende dit le nom, et huit rangs suffisent -- les postes qui
   coutent se rangent en six familles.

   Ce sont les teintes de la maison, prises dans l'ordre ou elles se
   distinguent le mieux les unes des autres. Comme pour les langages du depot,
   aucune ne qualifie un etat : ni « attention », ni « tout va bien ».

   Six surfaces et non une : la part de pile, la pastille de legende, la
   trace d'un rail, celle d'une barre, le remplissage d'une jauge et l'arc
   d'une couronne. Search Console range ses requetes par page de resultats a
   quatre endroits a la fois -- la pile, les requetes muettes, le tableau des
   requetes, celui des pages -- et une couleur qui n'aurait suivi qu'a l'un
   d'eux aurait fait quatre dessins au lieu d'un.

   L'arc fait exception a la forme : un trait de SVG ne prend pas de fond. La
   roue pose donc la meme teinte deux fois, en fond et en encre, et l'arc lit
   l'encre (`stroke: currentColor`). Une seule table, deux facons de la
   prendre -- recopier la table en `stroke` aurait fait deux tables a tenir.

   Les passes du raisonnement s'en servent autrement : leur teinte ne marque
   pas un rang mais une identite, fixee une fois pour toutes dans `conso_ia`
   (`TEINTES_PASSES`). Les deux lectures cohabitent sans se gener -- la roue ne
   dit que « voici huit couleurs qui se distinguent », c'est celui qui l'emploie
   qui decide de ce que le cran veut dire. */
.conso-pile-part[data-teinte="1"],
.conso-rail-trace[data-teinte="1"],
.conso-jauge-remplissage[data-teinte="1"],
.tka-barre-trace[data-teinte="1"],
.conso-arc[data-teinte="1"],
.conso-legende-pastille[data-teinte="1"] { background: var(--blue); color: var(--blue); }
.conso-pile-part[data-teinte="2"],
.conso-rail-trace[data-teinte="2"],
.conso-jauge-remplissage[data-teinte="2"],
.tka-barre-trace[data-teinte="2"],
.conso-arc[data-teinte="2"],
.conso-legende-pastille[data-teinte="2"] { background: var(--cyan); color: var(--cyan); }
.conso-pile-part[data-teinte="3"],
.conso-rail-trace[data-teinte="3"],
.conso-jauge-remplissage[data-teinte="3"],
.tka-barre-trace[data-teinte="3"],
.conso-arc[data-teinte="3"],
.conso-legende-pastille[data-teinte="3"] { background: var(--purple); color: var(--purple); }
.conso-pile-part[data-teinte="4"],
.conso-rail-trace[data-teinte="4"],
.conso-jauge-remplissage[data-teinte="4"],
.tka-barre-trace[data-teinte="4"],
.conso-arc[data-teinte="4"],
.conso-legende-pastille[data-teinte="4"] { background: var(--orange); color: var(--orange); }
.conso-pile-part[data-teinte="5"],
.conso-rail-trace[data-teinte="5"],
.conso-jauge-remplissage[data-teinte="5"],
.tka-barre-trace[data-teinte="5"],
.conso-arc[data-teinte="5"],
.conso-legende-pastille[data-teinte="5"] { background: var(--green); color: var(--green); }
.conso-pile-part[data-teinte="6"],
.conso-rail-trace[data-teinte="6"],
.conso-jauge-remplissage[data-teinte="6"],
.tka-barre-trace[data-teinte="6"],
.conso-arc[data-teinte="6"],
.conso-legende-pastille[data-teinte="6"] { background: var(--yellow); color: var(--yellow); }
.conso-pile-part[data-teinte="7"],
.conso-rail-trace[data-teinte="7"],
.conso-jauge-remplissage[data-teinte="7"],
.tka-barre-trace[data-teinte="7"],
.conso-arc[data-teinte="7"],
.conso-legende-pastille[data-teinte="7"] { background: var(--red); color: var(--red); }
.conso-pile-part[data-teinte="8"],
.conso-rail-trace[data-teinte="8"],
.conso-jauge-remplissage[data-teinte="8"],
.tka-barre-trace[data-teinte="8"],
.conso-arc[data-teinte="8"],
.conso-legende-pastille[data-teinte="8"] { background: var(--gray-4); color: var(--gray-4); }

/* Un neuvieme cran, ajoute pour les passes du raisonnement : elles sont huit,
   plus celle qui n'a pas de nom, et huit crans ne suffisaient plus. Ce bleu
   profond est deja celui du bloc Search Console -- pas une couleur de plus,
   un jeton de plus dans la roue. */
.conso-pile-part[data-teinte="9"],
.conso-rail-trace[data-teinte="9"],
.conso-jauge-remplissage[data-teinte="9"],
.tka-barre-trace[data-teinte="9"],
.conso-arc[data-teinte="9"],
.conso-legende-pastille[data-teinte="9"] { background: var(--blue-dark); color: var(--blue-dark); }

/* La meme pastille sert de rappel dans le tableau, collee au nom de la
   famille. Elle y perd le contexte flexible de la legende, donc son rang de
   boite : sans `inline-block`, ses sept pixels ne s'appliquent a rien. */
.conso-sous-titre-note .conso-legende-pastille {
  display: inline-block;
  margin-right: var(--espace-3xs);
  vertical-align: middle;
}

.conso-service-point {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--green);
}

.conso-service.malade { color: var(--orange-dark); font-weight: 600; }
.conso-service.malade .conso-service-point { background: var(--orange); }

/* ---------------------------------------------------------------------------
   Les gestes du tableau de bord. `dashboard-gestes.js` dit pourquoi ; ici,
   comment.

   Tout ce qui touche au deploiement est sous `.gestes`, une classe que le
   script pose lui-meme quand il prend la main. La raison tient en une phrase :
   l'etat de repos d'une trace est ici « pas encore dessinee », donc invisible,
   et une feuille qui l'imposerait seule laisserait une page de graphiques
   vides le jour ou le script ne se charge pas.
   --------------------------------------------------------------------------- */

/* Le releve, qui remplace l'infobulle du systeme sur toutes les parts de la
   page. La meme surface que l'infobulle de la courbe du code, dont il
   generalise le geste. Pose sur le corps et non dans le volet : une rangee de
   colonnes defile, une pile est rognee, une jauge vit dans une cellule -- un
   releve rendu dans le graphique se ferait couper par le premier
   `overflow: hidden` venu. */
.conso-releve {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 950;
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  max-width: 20rem;
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  box-shadow: var(--shadow-md);
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  opacity: 0;
  transform: translateY(var(--espace-3xs));
  transition: opacity .15s var(--ease), transform .15s var(--ease);
}

.conso-releve.visible { opacity: 1; transform: none; }

/* La premiere ligne nomme, les suivantes chiffrent. */
.conso-releve-tete { color: var(--black); font-weight: 600; }

/* Les barres du releve, quand une part en porte le dessin (voir la macro
   `rythme_colonnes` et `dashboard-gestes.js`). Le survol d'un barreau de
   rythme donnait sept noms et sept durees a la file, en une phrase qui tenait
   sur quatre lignes : on y lisait qui etait la, jamais qui avait fait le plus.
   Les memes chiffres en barres repondent aux deux d'un coup d'oeil.

   Une grille de trois colonnes et non une ligne par personne : les lignes sont
   en `display: contents`, donc les noms s'alignent entre eux et les chiffres
   aussi. En drapeau, chaque barre serait partie d'un endroit different et il
   n'y aurait plus rien a comparer, ce qui etait tout le reproche fait au
   texte. */
/* Une largeur plancher, et c'est ce qui fait tenir les barres : le releve est
   pose en `position: fixed`, donc il se retrecit sur son contenu, et une piste
   en `1fr` n'aurait rien ou s'etendre. Dix-sept rem est la place qu'il faut
   pour un nom, une piste ou l'oeil compare, et une duree. */
.conso-releve-dessin { min-width: 17rem; max-width: 24rem; }

.conso-releve-barres {
  display: grid;
  grid-template-columns: auto minmax(2.5rem, 1fr) auto;
  align-items: center;
  gap: var(--espace-3xs) var(--espace-xs);
  margin-top: var(--espace-3xs);
}

.conso-releve-barre { display: contents; }

/* Un nom coupe plutot qu'une colonne qui s'etire : la piste est ce qu'on
   compare, elle ne doit pas se retrecir parce que quelqu'un a un nom long. */
.conso-releve-nom {
  max-width: 9rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.conso-releve-piste {
  height: var(--espace-xs);
  border-radius: 999px;
  background: var(--gray-2);
  overflow: hidden;
}

/* Pleine pour la plus grosse part du jour, les autres a l'echelle : c'est
   `rythme.py` qui pose la largeur, la teinte est celle de la personne dans la
   pile juste au-dessus. */
.conso-releve-trace {
  display: block;
  height: 100%;
  border-radius: inherit;
  min-width: 2px;
}

.conso-releve-nb {
  color: var(--black);
  font-weight: 600;
  white-space: nowrap;
}

/* Le lien entre une pile et sa legende. Eteindre plutot que souligner : ce
   qu'on cherche est de retrouver une part parmi sept, et six teintes qui
   baissent la designent mieux qu'une qui monte. */
.conso-part-pale { opacity: .3; }

.conso-pile-part,
.conso-legende-entree,
.conso-legende-pastille,
.conso-rail,
.code-tuile,
.conso-table tbody tr { transition: opacity .15s var(--ease), transform .15s var(--ease); }

/* La pastille de l'entree eclairee grossit un peu : la legende est loin de sa
   part, et l'oeil qui revient de la pile doit retrouver ou il en etait. */
.conso-legende-entree.conso-part-vive .conso-legende-pastille { transform: scale(1.4); }

/* Le deploiement. Les traces sont rognees au repos et se decouvrent a
   l'ouverture : un rideau et non un etirement. Une trace qu'on etire deforme
   ses bouts ronds et, le temps de l'animation, affiche une longueur qui n'est
   pas la mesure -- ce qui se voit surtout sur les barres courtes, celles
   justement qu'on regarde deux fois.

   Le rang vient du script, le decalage se calcule ici. Le rognage garde
   l'arrondi de la forme (`round`) partout ou aucun parent ne le redonne : sans
   lui, une pile en pilule finirait l'animation a angle droit. */
.conso-mosaique.gestes {
  /* Le pas entre deux traces voisines. Assez pour qu'on voie l'ordre, trop peu
     pour qu'on attende : quatorze rangs font trois cent huit millisecondes,
     soit a peu pres la duree du volet qui les porte. */
  --conso-pas: 22ms;
  /* Le rang lui-meme, ecrit case par case par le script. Il est declare ici
     pour deux raisons : la feuille dit alors d'ou vient le decalage, et le
     verificateur ne voit plus un jeton utilise que personne ne definit. */
  --rang: 0;
}

.conso-mosaique.gestes .conso-volet .tka-barre-trace,
.conso-mosaique.gestes .conso-volet .temps-pile,
.conso-mosaique.gestes .conso-volet .gsc-svg,
.conso-mosaique.gestes .conso-volet .conso-jauge-remplissage,
.conso-mosaique.gestes .conso-volet .vercel-course-cadre {
  clip-path: inset(0 100% 0 0);
  transition: clip-path calc(var(--conso-duree) * .8) var(--ease)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .tka-barre-trace,
.conso-mosaique.gestes .conso-volet.deploye .temps-pile,
.conso-mosaique.gestes .conso-volet.deploye .gsc-svg,
.conso-mosaique.gestes .conso-volet.deploye .conso-jauge-remplissage,
.conso-mosaique.gestes .conso-volet.deploye .vercel-course-cadre {
  clip-path: inset(0);
}

.conso-mosaique.gestes .conso-volet .tka-pile,
.conso-mosaique.gestes .conso-volet .tka-heure-trace,
.conso-mosaique.gestes .conso-volet .code-jour-barre {
  clip-path: inset(100% 0 0 0 round var(--radius-xs) var(--radius-xs) 0 0);
  transition: clip-path calc(var(--conso-duree) * .8) var(--ease)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .tka-pile,
.conso-mosaique.gestes .conso-volet.deploye .tka-heure-trace,
.conso-mosaique.gestes .conso-volet.deploye .code-jour-barre {
  clip-path: inset(0 round var(--radius-xs) var(--radius-xs) 0 0);
}

/* Les traces de rail se decouvrent comme les jauges, mais avec leurs bouts
   ronds : une piste de dix pixels de haut coupee au carre montre deux angles
   droits pendant tout le balayage. La projection part avec la trace du jour et
   non apres -- ce sont deux lectures d'une seule mesure, pas deux mesures. */
.conso-mosaique.gestes .conso-volet .conso-rail-pile,
.conso-mosaique.gestes .conso-volet .conso-rail-trace,
.conso-mosaique.gestes .conso-volet .conso-rail-projection {
  clip-path: inset(0 100% 0 0 round 999px);
  transition: clip-path calc(var(--conso-duree) * .8) var(--ease)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .conso-rail-pile,
.conso-mosaique.gestes .conso-volet.deploye .conso-rail-trace,
.conso-mosaique.gestes .conso-volet.deploye .conso-rail-projection {
  clip-path: inset(0 round 999px);
}

/* La pile se decouvre d'un seul balayage, sans decalage par part : c'est une
   piste unique et non une serie, et sept rideaux simultanes en feraient une
   texture. Un peu plus lente que les autres, pour la meme raison. */
.conso-mosaique.gestes .conso-volet .conso-pile {
  clip-path: inset(0 100% 0 0 round 999px);
  transition: clip-path calc(var(--conso-duree) * 1.1) var(--ease) 160ms;
}

.conso-mosaique.gestes .conso-volet.deploye .conso-pile {
  clip-path: inset(0 round 999px);
}

/* La rose se deploie en poussant : chaque petale part du moyeu et sort. Un
   rideau lateral ne veut rien dire sur une forme radiale -- il couperait les
   sept petales par une verticale qui n'est l'axe d'aucun d'eux.
   `transform-box: view-box` cale l'origine sur le repere du dessin et non sur
   la boite du chemin, sans quoi chaque petale tournerait autour de son propre
   milieu. L'opacite est reprise dans la meme declaration : sans elle, la
   transition d'extinction du survol serait ecrasee par celle-ci. */
.conso-mosaique.gestes .conso-volet .code-petale {
  transform-box: view-box;
  transform-origin: 50% 50%;
  transform: scale(.06);
  transition: opacity .15s var(--ease),
              transform calc(var(--conso-duree) * .9) var(--ease-spring)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .code-petale { transform: none; }

/* Les tuiles s'ouvrent en iris depuis leur centre. Un rideau lateral dirait une
   largeur, et la largeur d'une tuile EST une mesure : le temps du balayage, la
   carte afficherait des aires fausses. Meme raison qu'au-dessus pour l'opacite,
   qui fait ici le fondu de l'appariement. */
.conso-mosaique.gestes .conso-volet .code-tuile {
  clip-path: inset(50% round var(--radius-xs));
  transition: opacity .15s var(--ease),
              clip-path calc(var(--conso-duree) * .8) var(--ease)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .code-tuile {
  clip-path: inset(0 round var(--radius-xs));
}

/* L'astre s'ouvre depuis son moyeu, comme la rose du depot et pour la meme
   raison : un rideau lateral couperait ses deux anneaux par une verticale qui
   n'est l'axe d'aucun de leurs arcs. */
.conso-mosaique.gestes .conso-volet .vercel-astre-arc {
  transform-box: view-box;
  transform-origin: 50% 50%;
  transform: scale(.4);
  transition: opacity .15s var(--ease),
              transform calc(var(--conso-duree) * .9) var(--ease-spring)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .vercel-astre-arc { transform: none; }

/* Les disques s'ouvrent en iris, comme les tuiles de la carte du depot : leur
   diametre EST la mesure, et un balayage lateral en afficherait de fausses
   pendant toute la duree de l'animation. */
.conso-mosaique.gestes .conso-volet .vercel-disque-rond {
  clip-path: inset(50% round 999px);
  transition: opacity .15s var(--ease),
              clip-path calc(var(--conso-duree) * .8) var(--ease)
              calc(120ms + var(--rang, 0) * var(--conso-pas));
}

.conso-mosaique.gestes .conso-volet.deploye .vercel-disque-rond {
  clip-path: inset(0 round 999px);
}

/* Le mouvement est un agrement, pas une information -- la meme regle que la
   mosaique plus haut. Qui l'a refuse au systeme voit les traces a leur
   longueur des l'ouverture, et le releve arriver sans fondu. */
@media (prefers-reduced-motion: reduce) {
  .conso-releve { transition: none; }
  .conso-mosaique.gestes .conso-volet .tka-barre-trace,
  .conso-mosaique.gestes .conso-volet .temps-pile,
  .conso-mosaique.gestes .conso-volet .gsc-svg,
  .conso-mosaique.gestes .conso-volet .conso-jauge-remplissage,
  .conso-mosaique.gestes .conso-volet .tka-pile,
  .conso-mosaique.gestes .conso-volet .tka-heure-trace,
  .conso-mosaique.gestes .conso-volet .code-jour-barre,
  .conso-mosaique.gestes .conso-volet .conso-rail-pile,
  .conso-mosaique.gestes .conso-volet .conso-rail-trace,
  .conso-mosaique.gestes .conso-volet .conso-rail-projection,
  .conso-mosaique.gestes .conso-volet .conso-pile,
  .conso-mosaique.gestes .conso-volet .code-tuile,
  .conso-mosaique.gestes .conso-volet .conso-couronne-anneau,
  .conso-mosaique.gestes .conso-volet .vercel-course-cadre,
  .conso-mosaique.gestes .conso-volet .vercel-disque-rond {
    clip-path: none;
    transition: none;
  }

  /* La rose et l'astre ne se rognent pas, ils se mettent a l'echelle : c'est
     l'autre forme du deploiement, et elle s'annule autrement. */
  .conso-mosaique.gestes .conso-volet .code-petale,
  .conso-mosaique.gestes .conso-volet .vercel-astre-arc {
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   L'apercu du mur : /db encadre dans le Dashboard systeme.

   Le cadre est au format des televiseurs du bureau, et c'est tout ce qu'il
   fait. Le mur se regle sur la hauteur de son cadre (100svh) : lui donner le
   bon rapport suffit a ce qu'il tombe exactement comme sur l'ecran du couloir,
   sans qu'aucune regle d'ici n'ait a decrire sa mise en page. Aucune ne le
   fait, d'ailleurs -- ce qui est peint dedans est peint par mur.html, et une
   regle posee ici serait justement le debut de la divergence qu'on evite en
   encadrant plutot qu'en recopiant.

   Encore faut-il que le rapport soit celui du contenu et pas seulement celui
   de la boite. Ce paragraphe a decrit pendant trois semaines quelque chose qui
   n'arrivait pas : le gabarit ecrit `class="tv-cadre tuile"`, et le creux de
   la tuile tombe a l'interieur du 16/9. La boite etait au format, ce qu'elle
   encadrait ne l'etait pas -- 1174x650 pour 1216x684 sur un poste, 305x161
   pour 347x195 sur un telephone, quand 16/9 vaut 1,778. Le mur y tombait
   ecrase de un et demi a six pour cent selon la largeur de la fenetre, et
   personne ne pouvait le voir : le creux est peint du meme noir que lui.

   C'est le seul `... tuile` du depot dont le contenu doit aller bord a bord.
   La classe reste malgre tout : elle ne sert plus le cadre, elle sert la
   cadence -- `.tuile + .tuile` est ce qui separe l'apercu du reglage au-dessus
   et de la note en dessous. On lui retire donc son creux, pas son appartenance.
   --------------------------------------------------------------------------- */

.tv-cadre {
  aspect-ratio: 16 / 9;
  width: 100%;
  /* Voir ci-dessus : le creux de `.tuile` se compte dans le rapport. Il reste
     la bordure, qui vaut deux pixels sur mille deux cents -- 1,780 au lieu de
     1,778 -- et qui est ce qui dit la tuile. */
  padding: 0;
  /* Le mur n'a pas de coins ronds : ils sont poses par le cadre, qui doit donc
     couper ce qui deborde. */
  overflow: hidden;
  border-radius: var(--radius);
  border: 1px solid var(--gray-3);
  /* Le fond de nuit du mur, pour que le cadre ne clignote pas en blanc le
     temps que /db se charge. Une teinte de la page encadree et non du site :
     elle n'est donc pas dans `:root`, et n'a rien a faire dans la palette
     commune -- voir la meme couleur dans mur.html. */
  background: #05070a;
}

.tv-iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* L'adresse a taper sur la telecommande : elle se lit, elle ne se clique pas.
   Un lien la ferait ouvrir ici, ou elle ne sert a rien. */
.tv-adresse b {
  color: var(--gray-6);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   L'onglet « Privé » de la zone Messages : les conversations deux a deux.

   Deux colonnes, comme toutes les messageries : a qui l'on parle a gauche, ce
   qu'on se dit a droite. Rien ici n'invente de forme -- les bulles reprennent
   celles du fil du cabinet, que cet onglet a remplace, les avatars sont ceux de
   la liste des mandats, et les arrondis sortent de l'echelle (voir la skill
   design-aiudit).
   --------------------------------------------------------------------------- */

/* Le panneau ne se pose plus dans la page comme une tuile encadree : il la
   prend de bord a bord, sous la rangee d'onglets, comme la fenetre d'une
   messagerie. Le cadre gris et ses coins arrondis faisaient de la conversation
   une fenetre dans la fenetre ; la refonte du 14 septembre 2026 les retire. Un
   seul filet en haut, qui prend la suite de celui des onglets, et la gouttiere
   de la page rendue au panneau par une marge negative (`--gouttiere` vaut la
   gouttiere reelle aux deux surfaces : mobile.css la recale sur le telephone). */
.panel-chat {
  padding: 0;
  overflow: hidden;
  background: #fff;
  border: none;
  border-top: 1px solid var(--gray-2);
  border-radius: 0;
  margin-inline: calc(var(--gouttiere) * -1);
}

/* Le panneau prend toute la hauteur que la page lui laisse, et le `.panel`
   ordinaire lui poserait dessous une marge de bas qui ne separe plus rien.

   `min-height` est le plancher : la tete du fil, quatre bulles et la barre
   d'ecriture. Une fenetre plus courte que cela fait defiler la page plutot que
   d'ecraser la messagerie -- c'est ce plancher qui redonne au corps un minimum
   automatique, celui qu'il perdrait autrement en devenant flexible. */
.app-main-pleine > .panel-chat {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 22rem;
  margin-bottom: 0;
}

/* Le bas du panneau touche le bas de la fenetre. Deux creux s'y posaient : le
   bourrelet que .app-main-pleine garde sous un panneau, et la reserve du bouton
   de ticket que `.panel` prend pour qu'il ne couvre pas sa derniere ligne. Ici
   c'est la barre d'ecriture qui tient cette reserve, a sa droite (voir
   .chat-ecrire), et le fil defile au-dessus. */
.app-main-pleine:not(.defile-page) > .panel.panel-chat { padding-bottom: 0; }
.app-main-pleine:not(.defile-page):has(> .panel-chat:not([hidden])) { padding-bottom: 0; }

/* Le filet du panneau, a bord perdu, remplace celui de la rangee d'onglets ;
   l'onglet retenu garde son trait cyan, pose juste dessus. */
.app-main-pleine:has(> .panel-chat:not([hidden])) > .dossier-tabs {
  margin-bottom: 0;
  box-shadow: none;
}

.chat {
  display: grid;
  /* `minmax(0, 1fr)` et non `1fr` : une piste `1fr` ne descend pas sous la
     largeur minimale de ce qu'elle contient, et un apercu de conversation est
     ecrit en `nowrap` -- sa largeur minimale est donc sa phrase entiere. La
     colonne se dilatait jusqu'a 650 px, le panneau la coupait sans bruit
     (`overflow: hidden`), et l'heure du dernier message tombait hors de vue.
     Le plancher explicite a zero rend aux colonnes le droit de retrecir. */
  grid-template-columns: 280px minmax(0, 1fr);
  /* La hauteur vient du panneau, qui la tient de la fenetre : dans une
     messagerie, c'est le fil qui defile, pas la page -- la barre d'ecriture
     doit rester sous la main.

     Elle valait `min(72vh, 680px)` jusqu'au 9 septembre 2026. Le plafond de
     680 px avait ete choisi quand la coquille elle-meme s'arretait a sa
     derniere ligne ; une fois la fenetre prise de haut en bas, il laissait
     sept cents pixels de sol vide sous un panneau de messagerie, sur un ecran
     de 1440 de haut. La messagerie prend maintenant ce qui reste, et rien de
     plus. `min-height: 0` pour que mille messages fassent defiler le fil et
     non grandir le panneau. */
  flex: 1;
  min-height: 0;
}

.chat-colonne {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  border-right: 1px solid var(--gray-2);
  background: #fff;
}

.chat-colonne-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace) var(--espace-sm) var(--espace-md);
  border-bottom: 1px solid var(--gray-2);
}

/* Les deux tetes se font face de part et d'autre du filet vertical : a la meme
   hauteur, leurs filets du bas n'en font qu'un. Celle du fil porte le rond de la
   conversation au barreau du logo, et c'est lui qui fixe la mesure. */
.chat-colonne-tete,
.chat-fil-tete { min-height: calc(var(--h-logo) + var(--espace-sm) * 2 + 1px); }

#chat-fil-avatar { --avatar-d: var(--h-logo); }

.chat-annuaire {
  border-bottom: 1px solid var(--gray-2);
  max-height: 40%;
  overflow-y: auto;
  background: #fff;
}

.chat-annuaire[hidden] { display: none; }

.chat-annuaire-ligne,
.chat-conversation {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  width: 100%;
  padding: var(--espace-sm) var(--espace-md);
  border: none;
  background: none;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  text-align: left;
  cursor: pointer;
}

.chat-annuaire-ligne:hover,
.chat-conversation:hover { background: var(--cyan-pale); }

.chat-conversations { flex: 1; overflow-y: auto; min-height: 0; }

.chat-conversation.active { background: var(--cyan-light); }

/* Le nom et l'apercu sont deux lignes d'une meme conversation : le barreau le
   plus serre de l'echelle, et non 1,6 px qui n'en est pas un. */
.chat-conversation-corps { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--espace-3xs); }

.chat-conversation-tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  /* Le nom et l'heure sont deux choses, pas un mot et son icone : l'ecart
     minimal qui les separe prend le barreau le plus large des deux voisins. */
  gap: var(--espace-sm);
}

.chat-conversation-tete strong {
  color: var(--black);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chat-conversation-date { font-size: var(--fs-2xs); color: var(--gray-4); flex: none; }

.chat-conversation-apercu {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* La ligne reste, meme vide. Une conversation ouverte ou personne n'a
     encore ecrit n'a rien a montrer du dernier message -- il n'y en a pas --
     et la ligne s'effondrait a zero : la rangee perdait 3,6 px, son nom
     glissait au milieu de la hauteur pendant que celui des voisines est en
     haut, et la liste avait l'air mal empilee. `1lh` reserve exactement une
     ligne de ce texte-la, sans nombre ecrit a la main : si `--fs-xs` bouge,
     la reserve bouge avec. */
  min-height: 1lh;
}

/* Le compte des messages recus et pas lus. La meme pastille que les onglets,
   parce que c'est la meme information : ce qui attend. */
.chat-pastille {
  flex: none;
  min-width: 18px;
  padding: 0 var(--espace-2xs);
  border-radius: 999px;
  background: var(--cyan);
  color: #fff;
  font-size: var(--fs-2xs);
  font-weight: 700;
  text-align: center;
}

/* La colonne de droite porte le voile du glisser-deposer, qui se cale sur
   elle : c'est elle entiere qui accepte un fichier, et non le seul fil.

   Elle porte aussi le sol de la conversation. Les bulles s'y levent en blanc et
   la barre d'ecriture s'y pose sans bande a elle : un seul fond, du haut du fil
   au bas de la fenetre, comme dans toutes les messageries. L'app le transcrit
   (verifier_fil_conversation). */
.chat-fil-zone {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  position: relative;
  background: var(--gray-2);
}

.chat-depot {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--espace-xs);
  /* Le voile ne prend jamais le pointeur. S'il le prenait, il s'interposerait
     entre la main et la zone a l'instant meme ou il apparait : le navigateur
     enverrait un `dragleave`, le voile clignoterait et le lacher tomberait a
     cote. */
  pointer-events: none;
  border: 2px dashed var(--cyan);
  border-radius: var(--radius);
  background: var(--cyan-light);
  color: var(--cyan-dark);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.chat-depot[hidden] { display: none; }
.chat-depot .icon { width: var(--icon-xl); height: var(--icon-xl); }

/* Rien a recevoir tant qu'aucune conversation n'est ouverte : le voile le dit
   au lieu de promettre un envoi qui n'aurait pas de destinataire. */
.chat-depot-refus {
  border-color: var(--gray-3);
  background: var(--gray-1);
  color: var(--gray-5);
}

.chat-fil-tete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace-md);
  border-bottom: 1px solid var(--gray-2);
  background: #fff;
}

/* Les gestes du logo, au bout de la ligne : choisir l'image que porte le rond
   du fil, la retirer. Ils ne concernent que le fil du cabinet, et se poussent
   a droite pour ne pas s'interposer entre la pastille et le nom. */
.chat-fil-tete-fin {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}
.chat-fil-tete-fin[hidden] { display: none; }

/* La colonne du fil, bornee au bloc, et le creux lateral qui la centre.

   Une bulle est bornee a 78 % de sa colonne. C'est une proportion, pas une
   mesure : elle ne vaut que ce que vaut la colonne. Tant que le panneau
   s'arretait a 1400 px, 78 % faisaient 860 px de bulle et deux piles de
   messages distantes de mille pixels. Sur un ecran de 2560 pris en entier,
   elles font 1800 px de bulle et deux piles distantes de deux mille : la
   conversation ne se lit plus comme un echange mais comme deux colonnes sans
   rapport, l'une contre le bord gauche, l'autre contre le bord droit.

   Le fil garde donc toute sa largeur -- c'est lui qui defile, et une barre de
   defilement se prend au bord -- mais son contenu tient dans un bloc, centre
   par un creux lateral qui ne descend jamais sous le bourrelet ordinaire. Le
   fil d'un ticket resout la meme chose autrement, en bornant chaque message a
   --largeur-lecture : ici les bulles se rangent des deux cotes, et c'est la
   colonne qu'il faut tenir pour que les deux bords restent voisins. */
.chat-fil {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--espace-md);
  padding-inline: max(var(--espace-md), (100% - var(--largeur-bloc)) / 2);
  display: flex;
  flex-direction: column;
  /* Deux bulles d'une meme serie se touchent presque, --espace-3xs ; une
     nouvelle serie (un autre auteur, ou cinq minutes d'ecart) reprend de l'air
     par sa propre marge, voir .chat-message. C'est le rythme des messageries :
     le fil se lit par tours de parole et non ligne a ligne. */
  gap: var(--espace-3xs);
}

.chat-vide { color: var(--gray-4); font-size: var(--fs-sm); padding: var(--espace-md); margin: 0; }

/* Quand le fil ne contient que sa phrase d'accueil, celle-ci se pose au milieu
   du panneau et non dans son coin superieur gauche : elle etait seule en haut
   a gauche de six cents pixels de blanc, ce qui donnait a la zone l'air de
   n'avoir pas fini de charger. */
.chat-fil > .chat-vide:only-child {
  margin: auto;
  text-align: center;
  max-width: 26rem;
}

.chat-jour {
  align-self: center;
  margin-block: var(--espace-sm);
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
  padding: var(--espace-3xs) var(--espace-sm);
  /* Levee sur le sol comme les bulles : blanche, et du meme relief. */
  background: #fff;
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
}

.chat-message { display: flex; gap: var(--espace-sm); align-items: flex-start; max-width: 78%; }

/* Une serie commence par de l'air ; les bulles qui la suivent se serrent sous
   la premiere. `chat-message-suite` est pose par chat-prive.js : meme auteur,
   moins de cinq minutes, la regle `colles` de l'app. */
.chat-message:not(.chat-message-suite) { margin-top: var(--espace-xs); }

/* Les siens a droite : c'est ce qui permet de suivre une conversation sans
   lire les noms, exactement comme dans le fil du cabinet. Sans rond : on sait
   qui l'on est. */
.chat-message-moi { align-self: flex-end; flex-direction: row-reverse; }

.chat-message-avatar { --avatar-d: 26px; }
.chat-message-moi .chat-message-avatar { display: none; }

/* Un seul rond par serie, en tete. Sa place reste tenue sous les suivantes,
   pour que les bulles d'une serie gardent le meme bord. */
.chat-message-suite .chat-message-avatar { visibility: hidden; }

/* La bulle : blanche et levee sur le sol, sans filet, l'heure rangee dans son
   coin bas. Flexible et non en bloc, pour que l'heure d'un message court se
   pose au bout de sa ligne et descende seule sous un message long. */
.chat-bulle {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  column-gap: var(--espace-sm);
  min-width: 0;
  padding: var(--espace-xs) var(--espace-sm);
  background: #fff;
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-md);
  color: var(--gray-6);
}

.chat-message-moi .chat-bulle {
  background: var(--cyan-light);
}

/* La pointe, sur la premiere bulle d'une serie : le coin qui regarde l'auteur
   se ferme et se prolonge d'un petit triangle de la couleur de la bulle. */
.chat-message:not(.chat-message-suite) .chat-bulle { border-top-left-radius: 0; }

.chat-message:not(.chat-message-suite) .chat-bulle::before {
  content: "";
  position: absolute;
  top: 0;
  left: calc(var(--espace-xs) * -1);
  width: var(--espace-xs);
  height: var(--espace-sm);
  background: inherit;
  clip-path: polygon(100% 0, 0 0, 100% 100%);
}

.chat-message-moi:not(.chat-message-suite) .chat-bulle {
  border-top-left-radius: var(--radius);
  border-top-right-radius: 0;
}

.chat-message-moi:not(.chat-message-suite) .chat-bulle::before {
  left: auto;
  right: calc(var(--espace-xs) * -1);
  clip-path: polygon(0 0, 100% 0, 0 100%);
}

/* Tout ce que la bulle porte prend sa ligne, sauf le texte et l'heure, qui
   partagent la derniere quand elle a la place. */
.chat-bulle > :not(.chat-texte):not(.chat-meta):not(.chat-actions) { flex-basis: 100%; }
.chat-bulle > .chat-texte { flex: 1 1 auto; min-width: 0; }
/* Un nom de fichier ou une adresse sans espace se coupe dans la bulle au
   lieu de la faire deborder. */
.chat-bulle > * { overflow-wrap: anywhere; }

.chat-message-retire .chat-bulle { color: var(--gray-4); font-style: italic; }

.chat-texte, .chat-transcription { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }

/* Le nom d'un fichier depose, dans une notification de suivi : il mene a
   l'onglet du mandat ou le fichier est arrive (voir chat-prive.js). Souligne
   en pointille plutot qu'en plein -- une phrase de resume en compte dix, et dix
   traits pleins la hachent. */
.chat-lien-mandat {
  color: inherit;
  text-decoration: underline dotted currentColor;
  text-underline-offset: 2px;
  transition: color .15s var(--ease);
}

.chat-lien-mandat:hover,
.chat-lien-mandat:focus-visible { color: var(--cyan-dark); text-decoration-style: solid; }

.chat-transcription {
  margin-top: var(--espace-xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.chat-cite {
  border-left: 3px solid var(--cyan);
  padding: var(--espace-3xs) var(--espace-xs);
  margin-bottom: var(--espace-xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  /* Creuse d'un cran dans la bulle blanche ; dans les siennes, le cyan pale. */
  background: var(--gray-1);
  border-radius: var(--radius-xs);
}

.chat-message-moi .chat-cite {
  background: var(--cyan-pale);
}

.chat-meta {
  display: flex;
  gap: var(--espace-xs);
  margin-top: var(--espace-2xs);
  /* Poussee au bout de sa ligne : l'heure se lit dans le coin bas de la bulle. */
  margin-left: auto;
  white-space: nowrap;
  font-size: var(--fs-3xs);
  color: var(--gray-4);
}

/* « Lu » se distingue de « envoyé » par la couleur de la marque, pas par un
   dessin de plus : c'est la meme ligne d'informations discretes, et deux
   coches auraient demande a etre apprises. */
.chat-lu { color: var(--cyan-dark); }

/* « lu par 2 sur 5 » ouvre la liste de ces cinq-la : le nombre seul posait la
   question de savoir lesquels. Un bouton, mais qui doit se lire comme le reste
   de la ligne d'informations -- une marque discrete, pas une commande. */
.chat-lu-detail {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.chat-lu-detail:hover { text-decoration: underline; }

/* La liste de qui a lu et de qui n'a pas encore lu, ouverte depuis cette
   marque. Meme famille de surface flottante que les autres fenetres du site :
   la forme est posee plus haut, avec .dialogue. */
.dialogue-lecteurs::backdrop { background: var(--voile); }
.dialogue-lecteurs-form { display: flex; flex-direction: column; gap: var(--espace-md); }
.dialogue-lecteurs-titre { margin: 0; font-weight: 600; }
.dialogue-lecteurs-corps { display: flex; flex-direction: column; gap: var(--espace-md); }
.dialogue-lecteurs-groupe-titre {
  margin: 0 0 var(--espace-sm);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.dialogue-lecteurs-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--espace-sm); }
.dialogue-lecteurs-liste li { display: flex; align-items: center; gap: var(--espace-xs); font-size: var(--fs-sm); }
.dialogue-lecteurs-actions { display: flex; justify-content: flex-end; }

/* ---------- Le lecteur de messages vocaux ----------

   La barre grise du navigateur n'avait pas la forme du site, et elle changeait
   d'un systeme a l'autre : ni le meme dessin ni la meme hauteur sous macOS,
   Windows et iOS. Un vocal de huit secondes s'y presentait comme une video --
   bouton carre, curseur fin, volume, menu de telechargement.

   Ce lecteur-ci est celui de toutes les messageries : un rond sur lequel on
   appuie, des barres qui se remplissent a mesure et ou l'on peut viser un
   endroit, une duree. C'est la seule chose du produit qui quitte le controle
   natif alors que la regle generale est de le garder -- un lecteur audio dans
   un fil de conversation n'est pas un controle de formulaire, c'est le message
   lui-meme. */
.vocal {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  min-width: 190px;
  max-width: 260px;
}

.vocal-source { display: none; }

.vocal-jouer {
  flex: none;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 999px;
  background: var(--cyan);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background .15s var(--ease);
}

.vocal-jouer:hover { background: var(--cyan-dark); }
.vocal-jouer .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* Les deux dessins voyagent ensemble ; seul celui de l'etat courant se voit,
   lu sur la classe du bloc. Rien a remplacer en JS a chaque bascule. */
.vocal-icone-pause { display: none; }
.vocal-en-lecture .vocal-icone-lire { display: none; }
.vocal-en-lecture .vocal-icone-pause { display: inline-block; }

.vocal-onde {
  flex: 1;
  height: 26px;
  display: flex;
  align-items: center;
  gap: 2px;
  cursor: pointer;
}

.vocal-onde:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: var(--radius-xs); }

/* Une barre par pas du message. Grise tant qu'elle n'est pas atteinte, cyan
   une fois lue : l'avancement se voit sans curseur a suivre. */
.vocal-barre {
  flex: 1;
  min-width: 2px;
  border-radius: 999px;
  background: var(--gray-3);
  transition: background .1s linear;
}

.vocal-barre-lue { background: var(--cyan); }

/* Dans sa propre bulle, le fond est deja cyan clair : les barres non lues y
   passeraient inapercues. */
.chat-message-moi .vocal-barre { background: var(--gray-4); }
.chat-message-moi .vocal-barre-lue { background: var(--cyan-dark); }

.vocal-temps {
  flex: none;
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  /* Le chiffre change a chaque seconde : une largeur fixe empeche les barres
     de bouger sous le pointeur pendant qu'on ecoute. */
  min-width: 2.2em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.chat-image { max-width: 240px; border-radius: var(--radius-sm); display: block; }

.chat-piece {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  color: var(--cyan-dark);
  text-decoration: none;
}

.chat-piece-poids { font-size: var(--fs-3xs); color: var(--gray-4); }

.chat-reactions { display: flex; gap: var(--espace-2xs); flex-wrap: wrap; }
.chat-reactions:empty { display: none; }

.chat-reaction {
  border: 1px solid var(--gray-3);
  background: #fff;
  border-radius: 999px;
  padding: 0 var(--espace-xs);
  font-size: var(--fs-2xs);
  cursor: pointer;
}

.chat-reaction.active { border-color: var(--cyan); background: var(--cyan-light); }

/* La barre d'outils d'un message : elle n'apparait qu'au survol, sinon chaque
   bulle porterait six boutons et le fil deviendrait illisible. */
.chat-actions {
  position: absolute;
  top: -14px;
  right: .4rem;
  display: none;
  gap: var(--espace-3xs);
  padding: var(--espace-3xs) var(--espace-2xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
}

.chat-message:hover .chat-actions,
.chat-message:focus-within .chat-actions { display: flex; }

.chat-reagir, .chat-action {
  border: none;
  background: none;
  padding: var(--espace-3xs) var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  cursor: pointer;
  line-height: 1;
}

.chat-reagir:hover, .chat-action:hover { color: var(--cyan-dark); }
.chat-action-danger:hover { color: var(--red); }
.chat-action .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* La barre d'ecriture, posee sur le sol du fil comme dans une messagerie :
   aucune bande a elle, une pilule blanche pour ecrire et, au bout, un rond.

   Le rond change de role selon le champ, c'est le geste de toutes les
   messageries : le micro tant qu'il n'y a rien a envoyer, l'avion en papier
   des qu'on a ecrit. La bascule se lit dans le champ lui-meme
   (`:placeholder-shown`), sans une ligne de script ; les deux boutons restent
   dans la page avec leurs roles. Un micro qui enregistre reste affiche quoi
   qu'on ecrive : c'est lui qui arrete l'enregistrement.

   Une hauteur pour toute la rangee, `--chat-ligne` : la pilule et le rond la
   partagent, au barreau du logo sur le bureau et a la cible tactile sur le
   telephone (voir mobile.css).

   A droite, `--chat-reserve` tient la barre hors du bouton de ticket, pose en
   bas a droite de la fenetre : le panneau descend jusqu'au bas de l'ecran, et
   ce bouton tomberait sur le rond d'envoi. */
.chat-ecrire {
  --chat-ligne: calc(var(--h-logo) + var(--espace-2xs));
  --chat-reserve: calc(52px + var(--espace-xl) + var(--espace-sm));
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
  padding: var(--espace-xs) var(--espace-md) var(--espace-sm);
  /* Le meme creux lateral que le fil : ce qu'on ecrit se pose dans la colonne
     ou on le lira. */
  padding-inline: max(var(--espace-md), (100% - var(--largeur-bloc)) / 2);
  padding-right: max(var(--chat-reserve), (100% - var(--largeur-bloc)) / 2);
}

.chat-ecrire[hidden] { display: none; }

/* Le rappel du message auquel on repond, leve au-dessus de la pilule et de sa
   largeur : il s'arrete la ou commence le rond. */
.chat-citation {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
  margin-right: calc(var(--chat-ligne) + var(--espace-xs));
  padding: var(--espace-2xs) var(--espace-sm);
  background: #fff;
  border-left: 3px solid var(--cyan);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.chat-citation[hidden] { display: none; }
.chat-citation-auteur { font-weight: 600; color: var(--gray-6); margin-right: var(--espace-xs); }

.chat-ecrire-ligne {
  display: flex;
  align-items: flex-end;
  gap: var(--espace-xs);
}

/* La pilule : le champ et la trombone dans une seule forme. Elle porte le fond
   et l'anneau de mise au point, le champ n'a qu'a recevoir le texte ; `flex-end`
   garde la trombone au bas de la pilule quand le champ grandit sous la frappe. */
.chat-ecrire-coque {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: flex-end;
  min-height: var(--chat-ligne);
  background: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: box-shadow .15s var(--ease);
}

.chat-ecrire-coque:focus-within { box-shadow: var(--shadow-sm), var(--anneau-champ); }

.chat-ecrire-coque .btn-icon-only {
  flex: none;
  min-width: var(--chat-ligne);
  min-height: var(--chat-ligne);
  border-radius: 999px;
}

.chat-ecrire textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  min-height: var(--chat-ligne);
  /* Ce plafond-la n'est pas une mesure d'espace mais la hauteur ou le champ
     se met a defiler, et il se lit avec `chat-prive.js`, qui grandit le champ
     par `Math.min(champ.scrollHeight, 140)`. Les deux chiffres vont ensemble :
     changer celui-ci sans l'autre ne ferait rien du tout. */
  max-height: 140px;
  /* Une ligne de texte centree dans la pilule : ce que la rangee laisse autour
     d'elle, partage dessus et dessous. */
  line-height: 1.25;
  padding: calc((var(--chat-ligne) - 1.25em) / 2) var(--espace-2xs) calc((var(--chat-ligne) - 1.25em) / 2) var(--espace-md);
  font-family: var(--sans);
  font-size: var(--fs-md);
  color: var(--black);
  /* Le cadre est a la pilule : deux cadres emboites pour un seul controle
     donneraient un champ dans une boite, ce qu'il n'est pas. */
  border: none;
  background: none;
}

.chat-ecrire textarea:focus { outline: none; box-shadow: none; }

/* Le rond au bout de la rangee : le micro, ou l'envoi. */
.chat-rond {
  --icon: var(--icon-md);
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--chat-ligne);
  height: var(--chat-ligne);
  padding: 0;
  border: none;
  border-radius: 999px;
  background: var(--cyan);
  color: #fff;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: background-color .15s var(--ease);
}

.chat-rond:hover { background: var(--cyan-dark); }
.chat-rond:disabled { opacity: .5; cursor: default; }

.chat-ecrire:has(#chat-texte:placeholder-shown) #chat-envoyer,
.chat-ecrire:not(:has(#chat-texte:placeholder-shown)) #chat-micro:not(.chat-micro-actif) { display: none; }

/* Le micro allume pendant qu'il enregistre : sans ce signal on ne sait pas
   si l'on parle dans le vide. */
.chat-micro-actif { color: var(--red); animation: chat-micro-pouls 1.2s infinite; }
.chat-rond.chat-micro-actif { background: var(--red); color: #fff; }

@keyframes chat-micro-pouls {
  0%, 100% { opacity: 1; }
  50% { opacity: .35; }
}

/* Ce que dit la barre (un envoi en cours, une erreur) flotte au-dessus d'elle,
   sur le sol du fil, au lieu de lui garder une ligne vide sous la pilule. Vide,
   elle reste dans la page, transparente : un lecteur d'ecran suit une region
   vivante qu'on ne retire pas. */
.chat-statut {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  max-width: 90%;
  padding: var(--espace-3xs) var(--espace-sm);
  background: #fff;
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
  transition: opacity .15s var(--ease);
}

.chat-statut:empty { opacity: 0; }
.chat-statut-erreur { color: var(--red); }

/* Sur telephone, la colonne des conversations et le fil ne tiennent pas cote
   a cote : la colonne passe au-dessus, sur un tiers de la hauteur. */
@media (max-width: 720px) {
  .chat {
    grid-template-columns: minmax(0, 1fr);
    /* Ce tiers se dit ici, dans la piste, et non en `max-height` sur la
       colonne. Une hauteur en pourcentage posee sur un element de grille se
       mesure sur sa piste, et la piste, elle, restait `auto` : elle prenait la
       hauteur de la liste entiere. La colonne recevait donc 34 % de son propre
       contenu -- 132 px pour 390 --, et les 257 px que la piste gardait en
       trop ne revenaient a personne. Un trou blanc, entre une liste tranchee
       au milieu du deuxieme nom et un fil relegue tout en bas du panneau.

       Deux pistes explicites : le tiers se mesure sur la hauteur du panneau,
       et il ne reste plus rien a distribuer. Cette hauteur etait de 620 px
       jusqu'au 9 septembre 2026 ; c'est desormais celle de l'ecran moins
       l'en-tete, les onglets et la barre d'onglets du bas -- le telephone
       affiche une messagerie comme les autres messageries du telephone. */
    grid-template-rows: minmax(0, 34%) minmax(0, 1fr);
  }

  /* Tant qu'aucune conversation n'est ouverte, le fil n'a rien a montrer
     qu'une invitation de deux lignes. Lui laisser les deux tiers de l'ecran
     pendant que la liste -- seul contenu de la page a cet instant -- se coupe
     au troisieme nom, c'est ranger la page a l'envers. Les proportions
     s'inversent donc jusqu'au premier choix : la liste prend la hauteur,
     l'invitation ne prend que sa place, et la mise en page nominale revient
     des qu'un fil s'ouvre. La condition est celle qui centre deja cette
     phrase-la vingt lignes plus haut -- le fil ne contient qu'elle. */
  .chat:has(#chat-fil-vide:not([hidden])) {
    grid-template-rows: minmax(0, 1fr) auto;
  }

  .chat-colonne { border-right: none; border-bottom: 1px solid var(--gray-2); }
  .chat-message { max-width: 92%; }
}

/* ---------------------------------------------------------------------------
   La visionneuse de documents (Juridique, Comptable).

   La meme fenetre que les autres (.modal), a ceci pres qu'elle est plus haute
   et plus large : ce qu'on y regarde est une page A4, et une page A4 lue dans
   une lucarne ne se lit pas.
   --------------------------------------------------------------------------- */

.visionneuse {
  max-width: var(--largeur-fenetre);
  width: min(1100px, 100%);
  height: 88vh;
  max-height: 88vh;
}

/* L'EN-TETE SE RESSERRE, ET TOUT CE QU'IL PORTE REMONTE AVEC LUI (« remonte
   legerement la barre d'etat et la barre laterale », suivi du 8 septembre
   2026). C'est une rangee de commandes de 28 px posee dans un rembourrage
   ecrit pour un titre de fenetre : le nom ayant retrouve la taille qu'il a
   dans la liste, ce blanc-la n'avait plus rien a espacer. Les elements
   s'alignent desormais sur leur milieu plutot que sur leur haut, faute de quoi
   le nom flotterait au-dessus des boutons. */
.visionneuse .modal-header {
  padding-top: var(--espace-sm);
  padding-bottom: var(--espace-sm);
  padding-left: 0;
  align-items: center;
}

/* CE QUI COMMANDE LA BARRE LATERALE SE TIENT AU-DESSUS D'ELLE.

   « Place le bouton Barre laterale juste au-dessus de la barre laterale.
   Deplace le nombre de pages a gauche de ce bouton » (suivi du 8 septembre
   2026). Le bouton vivait a l'autre bout de la rangee, avec le zoom : il
   fallait faire le lien entre un bouton de droite et une colonne de gauche.
   Pose sur elle, a sa largeur exacte, il ne le demande plus.

   La largeur est celle de `.lecteur-pdf-cote`, et les deux se tiennent : si
   l'une change, l'autre suit, sans quoi le bouton cesserait d'etre au-dessus
   de ce qu'il replie. */
.visionneuse-cote {
  flex: none;
  width: 150px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-2xs);
  padding-right: var(--espace-sm);
}

/* Le nom du document se corrige la ou il s'affiche : le champ vient prendre
   la place exacte du titre, meme police et meme corps, plutot que d'ouvrir
   une boite de dialogue par-dessus le document qu'on est en train de lire.
   La zone garde donc la largeur disponible, sans quoi le champ se serait
   retrouve a la taille du nom le plus court. */
.visionneuse-titre-zone {
  flex: 1;
  min-width: 0;
  margin-right: var(--espace-sm);
  /* Une rangee depuis le 10 septembre 2026 : le cycle que la piece justifie se
     pose devant son nom (« je voudrais voir devant le nom du fichier le ou les
     cycles auxquels la piece est rattachee, comme cela apparait aujourd'hui
     dans "Comptable" »). Empiles en bloc, la marque et le nom auraient tenu
     deux lignes dans une barre qui en fait une. */
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  /* Il commence apres la colonne des vignettes, et non sur elle : « decale le
     nom du fichier vers la droite de la barre laterale » (suivi du 8 septembre
     2026). Le retrait negatif que le titre porte pour que son survol epouse le
     mot le ramenerait de trois pixels sur la colonne. */
  padding-left: var(--espace-sm);
}

/* Le titre se vise comme le crayon quand le document se renomme : le nom est
   ce qu'on regarde, c'est donc lui qu'on clique. Discret tant qu'on ne le
   survole pas -- c'est un titre avant d'etre un bouton. */
#visionneuse-titre {
  /* LA TAILLE DU NOM DANS LA LISTE, et non celle d'un titre de fenetre :
     « decale le nom du fichier vers la droite de la barre laterale et reduis sa
     taille pour qu'elle soit identique a celle du fichier selectionne » (suivi
     du 8 septembre 2026). C'est `--fs-sm`, celle de `.tree-table`, ou le meme
     nom se lit une seconde plus tot. Le document ouvert est sous les yeux : son
     nom n'a pas a l'annoncer en corps de titre. */
  font-size: var(--fs-sm);
  /* Le fond du survol ne doit couvrir que le nom, pas la largeur de la
     fenetre : sur un nom court, une bande grise de mille pixels ne designe
     plus rien. */
  display: inline-block;
  max-width: 100%;
  padding: 0 var(--espace-2xs);
  margin: 0 -.2rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border-radius: var(--radius-xs);
  transition: background .15s var(--ease);
}

/* `display` pose sur un identifiant l'emporte sur le `display: none` que le
   navigateur donne a `hidden` : sans cette ligne, le titre resterait affiche
   sous le champ pendant la saisie. */
#visionneuse-titre[hidden] { display: none; }

/* Le nom garde toute la place qui reste, et se coupe avant de pousser la
   marque de cycle hors de la fenetre : c'est le nom qu'on tronque, jamais ce
   qui le qualifie. */
#visionneuse-titre, .visionneuse-titre-champ { flex: 1; min-width: 0; }
#visionneuse-cycles { flex: none; }

#visionneuse-titre.renommable { cursor: text; }
#visionneuse-titre.renommable:hover { background: var(--gray-1); }

.visionneuse-titre-champ {
  font-family: var(--sans);
  font-weight: 600;
  /* La meme taille que le titre qu'il remplace : le champ prend sa place
     exacte, il ne la redessine pas. */
  font-size: var(--fs-sm);
  width: 100%;
  padding: 0 var(--espace-2xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.visionneuse-titre-champ:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Les commandes de la fenetre se posent entre le nom du fichier et la croix,
   comme le bouton « Valider l'ecriture » de la fenetre voisine. Elles etaient
   deux -- telecharger, ouvrir dans un onglet -- et sont huit : renommer, les
   deux quarts de tour, les trois ateliers, les deux sorties.

   Huit carres de 28 px du meme dessin, a 4 px les uns des autres, ne se
   lisaient plus comme des commandes mais comme une trame. Ils se rangent donc
   par ce qu'ils font, et un filet separe les familles. */
.visionneuse-actions {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin-left: auto;
  margin-right: var(--espace-xs);
}

.visionneuse-groupe {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
}

/* Six des huit commandes s'affichent ou non selon la nature du fichier, et les
   trois ateliers s'excluent : un groupe peut donc n'avoir plus rien a montrer.
   Il disparait alors en entier -- sans cette ligne il n'en resterait que
   l'ecart et le filet, une barre grise separant deux vides. */
.visionneuse-groupe:not(:has(> :not([hidden]))) { display: none; }

/* Le filet appartient au groupe qui le precede, pose a sa droite, et ne se
   dessine que s'il reste apres lui un groupe qui a quelque chose a montrer :
   une piece jointe de ticket n'ouvre que les deux sorties, et la rangee aurait
   commence par deux barres grises. */
.visionneuse-groupe::after { content: none; }
.visionneuse-groupe:has(~ .visionneuse-groupe > :not([hidden]))::after { content: ""; }

/* Feuilleter une liasse : deux fleches et un rang, juste avant la croix
   (ticket du 10 septembre 2026). Replie tant que la fenetre n'ouvre qu'une
   piece, ce qui reste le cas courant. */
.visionneuse-serie {
  display: flex;
  align-items: center;
  gap: var(--espace-3xs);
  margin-right: var(--espace-xs);
}

.visionneuse-serie-rang {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  min-width: 3.5em;
  text-align: center;
}

/* Un bout de liasse n'a pas de suite : la fleche reste, pour que la paire ne
   se deplace pas d'une piece a l'autre, mais elle s'eteint. */
.visionneuse-serie button[disabled] { opacity: 0.35; cursor: default; }

/* CE QUE LA PIECE EST CENSEE PROUVER, entre la barre et le document (ticket du
   12 septembre 2026). Un bandeau bas, dense, en retrait du document : il est la
   pour etre lu d'un coup d'oeil pendant qu'on regarde la facture, pas pour
   prendre la place de celle-ci. Sa hauteur est donc plafonnee, et c'est lui qui
   defile quand une ecriture porte vingt lignes. */
.visionneuse-contexte {
  flex: none;
  max-height: 30vh;
  overflow: auto;
  padding: var(--espace-2xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
  background: var(--gray-1);
  font-size: var(--fs-xs);
}

.visionneuse-contexte-titre {
  display: flex;
  align-items: baseline;
  gap: var(--espace-2xs);
  flex-wrap: wrap;
}

.visionneuse-contexte-detail { color: var(--gray-5); }

.visionneuse-contexte-tableau { margin-top: var(--espace-3xs); }

.visionneuse-contexte-tableau table {
  width: 100%;
  border-collapse: collapse;
}

.visionneuse-contexte-tableau th,
.visionneuse-contexte-tableau td {
  padding: var(--espace-3xs) var(--espace-2xs);
  text-align: left;
  border-bottom: 1px solid var(--gray-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 24ch;
}

.visionneuse-contexte-tableau th { color: var(--gray-5); font-weight: 600; }

.visionneuse-contexte-tableau .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* La ligne d'ou l'on vient, quand la piece justifie une ligne et non l'ecriture
   entiere : c'est son montant qu'on confronte a la facture, et une ecriture en
   porte souvent six. */
.visionneuse-contexte-marquee { background: var(--cyan-pale); font-weight: 600; }

.visionneuse-cadre {
  flex: 1;
  min-height: 0;
  /* Le pincement va au document, pas au navigateur : sans cela, deux doigts
     sur un ecran tactile agrandissent la page entiere, bandeau du haut
     compris. Le defilement a un doigt reste, lui, celui du navigateur. Meme
     reglage que la zone de defilement du lecteur de PDF, et pour la meme
     raison (ticket du 9 septembre 2026). */
  touch-action: pan-x pan-y;
}

/* Le cadre agrandi deborde de son bloc : c'est le bloc qui defile sous lui, et
   c'est ce qui fait la loupe. Au repos, rien ne depasse et la barre de
   defilement n'a pas lieu d'etre. */
.visionneuse-cadre-zoome { overflow: auto; }

/* Aucune bordure, aucun fond : le cadre disparait, seul le document se voit.
   Le fond gris qu'il portait ne servait a rien -- le lecteur de PDF du
   navigateur peint le sien par-dessus -- et il ne se voyait que le temps du
   chargement, en carre gris pose de travers dans une fenetre blanche. */
.visionneuse-cadre iframe {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
  transition: opacity .15s var(--ease);
}

/* Tant que le document n'est pas arrive, le cadre reste invisible plutot que
   d'exposer ce que le lecteur du navigateur dessine en attendant : Safari y
   pose un rectangle gris qui ne couvre ni toute la largeur ni toute la hauteur
   et qu'on lisait comme un document casse. La fenetre blanche attend, puis le
   document apparait d'un coup. La classe est retiree au chargement du cadre :
   si rien n'arrivait jamais, on prefere encore une fenetre vide a un carre. */
.visionneuse-cadre.chargement iframe { opacity: 0; }

/* ---------- Le lecteur de PDF de la fenetre de lecture ----------

   Les pages d'un PDF peintes ici plutot que dans le cadre du navigateur, avec
   la barre de vignettes a gauche et le pincement pris au vol : les deux
   demandes du suivi du 8 septembre 2026, dont aucune n'etait possible dans un
   <iframe> (la raison entiere est en tete de static/js/lecteur-pdf.js).

   Il occupe la meme place que le cadre, et jamais en meme temps que lui : l'un
   porte le document, l'autre attend. */
.lecteur-pdf {
  display: flex;
  width: 100%;
  height: 100%;
  min-height: 0;
  background: var(--gray-2);
}

/* Le gris derriere les pages est celui d'Apercu et de tous les lecteurs : une
   page blanche posee sur du blanc n'a plus de bord, et c'est le bord qui dit
   ou finit la feuille. */
.lecteur-pdf-defilement {
  flex: 1;
  min-width: 0;
  overflow: auto;
  padding: var(--espace-md) 0;
  /* CE N'EST PAS UNE MISE EN PAGE, C'EST CE QUI REND LES POSITIONS JUSTES.
     Le lecteur mesure ou commence chaque page (`cadre.offsetTop`) pour savoir
     laquelle est lue et ou se caler ; cette mesure se prend depuis le premier
     ancetre POSITIONNE. Sans cette ligne, c'etait la fenetre entiere : chaque
     page se croyait 79 px plus bas qu'elle n'est -- la hauteur du bandeau --,
     et « page entiere » calait sur le tiers de la page suivante. */
  position: relative;
  /* Retire au navigateur le zoom de page sur cette zone, et lui laisse le
     defilement : c'est ce qui permet au pincement de n'agrandir que le
     document. Sans cette ligne, deux doigts agrandiraient le site entier,
     bandeau compris -- exactement ce qui etait signale. */
  touch-action: pan-x pan-y;
}

.lecteur-pdf-colonne {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-md);
  /* La colonne prend au moins la largeur de la zone : sans cela, une page
     zoomee au-dela de la fenetre serait callee a gauche, et les pages plus
     etroites cesseraient d'etre centrees. */
  min-width: min-content;
  padding: 0 var(--espace-md);
}

.lecteur-pdf-page {
  position: relative;
  flex: none;
  background: #fff;
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--gray-3);
}

/* Le canvas suit son cadre, et c'est ce qui rend le pincement continu : la
   page deja peinte s'etire tout de suite a la nouvelle echelle, la nettete
   revient au repos du geste (voir `programmerRendu`). */
.lecteur-pdf-page canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* La barre laterale, celle d'Apercu : les vignettes a gauche, celle qu'on lit
   mise en avant, un clic pour y aller. Repliable, et son etat suit le lecteur
   d'un document a l'autre. */
.lecteur-pdf-cote {
  flex: none;
  width: 150px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--gray-1);
  border-right: 1px solid var(--gray-3);
}

.lecteur-pdf-vignettes {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-sm) var(--espace-xs);
}

.lecteur-pdf-vignette {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-3xs);
  width: 100%;
  padding: var(--espace-3xs);
  border-radius: var(--radius-sm);
}

/* L'IMAGE EMMENE A LA PAGE, LA CASE LA PREND : deux cibles sur la meme
   vignette, donc deux elements. Le bouton porte la toile et rien d'autre. */
.lecteur-pdf-vignette-page {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}

.lecteur-pdf-vignette canvas {
  width: 100%;
  display: block;
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
}

/* La case, posee sur le coin de la page.

   « Permets de selectionner une ou plusieurs pages grace aux cases a cocher »
   (suivi du 8 septembre 2026). Elle remplace la ligne qui comptait les pages
   prises au pied de la colonne : on voit ce qui est pris au lieu de le lire.

   Sur la page et non a cote : une colonne de cent cinquante pixels n'a pas de
   place pour une gouttiere, et c'est de toute facon la ou l'oeil regarde. Le
   halo blanc la detache d'un fond de page blanc, qui est le cas ordinaire. */
.lecteur-pdf-coche {
  position: absolute;
  top: var(--espace-2xs);
  left: var(--espace-2xs);
  z-index: 1;
  box-shadow: 0 0 0 2px #fff;
}

.lecteur-pdf-vignette-numero {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.lecteur-pdf-vignette:hover { background: var(--gray-2); }

/* La page lue se designe par son cadre, pas par un fond : c'est la vignette
   elle-meme qu'on cherche des yeux, et un fond colore derriere une page blanche
   se lit comme une selection en cours plutot que comme un reperage. */
.lecteur-pdf-vignette.est-courante canvas {
  border-color: var(--cyan);
  box-shadow: 0 0 0 2px var(--cyan);
}

.lecteur-pdf-vignette.est-courante .lecteur-pdf-vignette-numero {
  color: var(--cyan-dark);
  font-weight: 600;
}

/* UNE PAGE CHOISIE, ce qui n'est pas la meme chose que la page qu'on lit : la
   premiere est designee pour qu'on en fasse quelque chose -- la tourner, la
   deplacer, la retirer --, la seconde est simplement celle qui passe devant les
   yeux. D'ou deux marques differentes : un cadre cyan pour la lecture, un fond
   plein pour la selection, comme une icone selectionnee dans le Finder. */
.lecteur-pdf-vignette.est-choisie {
  background: var(--cyan-pale);
}

.lecteur-pdf-vignette.est-choisie canvas {
  border-color: var(--cyan-dark);
  box-shadow: 0 0 0 2px var(--cyan-dark);
}

.lecteur-pdf-vignette.est-choisie .lecteur-pdf-vignette-numero {
  color: var(--cyan-dark);
  font-weight: 600;
}

/* La vignette qu'on tient s'efface a moitie, et un trait dit ou le bloc va
   tomber. Sans lui on lache au juge : c'est la difference entre deplacer une
   page et essayer de la deplacer. La colonne etant verticale, le trait est
   horizontal -- il l'etait dans l'autre sens sur la planche de contact. */
.lecteur-pdf-vignette.est-prise { opacity: .4; }

.lecteur-pdf-vignette.depot-avant::before,
.lecteur-pdf-vignette.depot-apres::after {
  content: "";
  position: absolute;
  left: var(--espace-2xs);
  right: var(--espace-2xs);
  height: 3px;
  border-radius: 2px;
  background: var(--cyan);
}

.lecteur-pdf-vignette.depot-avant::before { top: calc(var(--espace-2xs) * -1); }
.lecteur-pdf-vignette.depot-apres::after { bottom: calc(var(--espace-2xs) * -1); }

/* LA COLONNE NE PORTE PLUS QUE LES PAGES. Un cadre la fermait en bas -- une
   ligne d'etat et trois boutons, tout ce qui restait de la fenetre « Organiser
   les pages » --, retire le 8 septembre 2026 : ses gestes sont montes dans la
   barre du haut, ou vivent deja tous les autres.

   Le seul geste des pages qui ne se defait pas par le calcul inverse porte donc
   la teinte que tout le produit donne a ce qui retire, la ou il est desormais :
   la corbeille de cette barre. */
.lecteur-pdf-danger:not(:disabled) { color: var(--red); }
.lecteur-pdf-danger:not(:disabled):hover { background: var(--red-pale); }

/* Le numero de la page lue, dans la barre d'outils. Chasse fixe : le nombre
   change a chaque page, et une chasse proportionnelle ferait danser les
   boutons de zoom qui l'encadrent. */
.visionneuse-page {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  min-width: 4.5ch;
  text-align: center;
}

/* Le cadre qui porte le PDF a imprimer, le temps que le systeme ouvre sa boite.
   Hors de l'ecran plutot que `display: none` : un cadre qu'on ne dessine pas
   n'a pas de fenetre, donc rien a imprimer. */
.lecteur-pdf-impression {
  position: fixed;
  width: 1px;
  height: 1px;
  left: -9999px;
  top: 0;
  border: none;
  opacity: 0;
}

/* Sur telephone, la colonne de vignettes se resserre : cent cinquante pixels
   sur trois cent vingt, c'est la moitie de la page pour des miniatures. Elle
   part d'ailleurs repliee la (voir `barreOuverte` dans lecteur-pdf.js) ; ceci
   ne vaut que pour qui la rouvre. */
@media (max-width: 720px) {
  .lecteur-pdf-cote { width: 104px; }
}

/* Sur telephone, la fenetre prend tout : une page A4 dans une fenetre de
   fenetre ne se lirait plus du tout.

   Et le nom du document passe sur sa propre ligne. Les commandes prennent la
   largeur qu'il leur faut, le nom se contente du reste, et le reste tombait a
   24 px de large a 320 -- une initiale suivie de points de suspension (mesure
   au navigateur le 31 aout 2026). Ce qu'on lit d'abord dans cet en-tete, c'est
   quelle piece est ouverte. L'ecart entre les deux rangs est celui que
   mobile.css donne deja a l'en-tete des fenetres. */
@media (max-width: 720px) {
  .visionneuse { height: 92vh; max-height: 92vh; }
  .visionneuse .modal-header { flex-wrap: wrap; }
  .visionneuse-titre-zone { flex: 1 0 100%; margin-right: 0; }
  /* L'atelier suit la fenetre de lecture, dont il prend la suite : meme
     largeur de nom, donc meme rang a soi quand il n'en reste plus assez. Sa
     rangee d'outils est la plus longue des deux. */
  .annotation-atelier .modal-header { flex-wrap: wrap; }
  #annotation-titre { flex: 1 0 100%; }
}

/* ---------------------------------------------------------------------------
   Le filet qui separe deux familles de commandes dans une meme rangee.

   Ecrit une fois pour ses deux porteurs : la barre d'outils de l'atelier
   d'annotation et l'en-tete de la fenetre de lecture, qui l'ouvre. Les deux
   en-tetes se succedent a l'ecran -- on annote la piece qu'on etait en train
   de lire --, ils separent donc au meme ecart et du meme gris.

   `flex: none` : un trait d'un pixel dans une rangee qui deborde se laisse
   comprimer jusqu'a zero, et c'est alors la seule chose qui separait les
   familles qui disparait, exactement la ou il fallait la voir.
   --------------------------------------------------------------------------- */

.annotation-separateur,
.visionneuse-groupe::after {
  width: 1px;
  align-self: stretch;
  flex: none;
  margin: var(--espace-3xs) var(--espace-2xs);
  background: var(--gray-3);
}

/* ---------- L'atelier d'annotation du justificatif ----------

   Meme famille que la visionneuse -- une grande surface flottante, donc
   `--radius-lg`, un fond blanc et une ombre portee, tous trois donnes par
   `.modal` -- mais un contenu que la visionneuse ne pouvait pas porter : ici
   les pages sont peintes une a une dans un canvas, et un second canvas
   transparent recoit les traits. Le cadre ferme d'un <iframe> ne dit pas ou il
   a pose la page ; celui-ci, si (demande du 21 aout 2026). */
/* L'atelier des classeurs : la meme famille de fenetre que celui des
   annotations -- large, haute, une barre en tete et un cadre qui defile --
   parce que c'est le meme geste sur l'autre famille de documents (demande du
   26 aout 2026). */
.classeur-atelier {
  max-width: var(--largeur-fenetre);
  width: min(1180px, 100%);
  height: 92vh;
  max-height: 92vh;
}

/* Les onglets de feuilles, entre le titre et les actions : un classeur
   d'audit en porte cinq, et les empiler ferait defiler trois mille lignes
   pour atteindre la derniere. */
.classeur-feuilles {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin-left: var(--espace-md);
  margin-right: auto;
  flex-wrap: wrap;
}

.classeur-feuille-btn {
  padding: var(--espace-2xs) var(--espace-sm);
  border: none;
  border-radius: var(--radius-xs);
  background: none;
  font-family: inherit;
  font-size: var(--fs-sm);
  color: var(--gray-5);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.classeur-feuille-btn:hover { background: var(--gray-2); color: var(--gray-6); }
.classeur-feuille-btn.active { background: var(--cyan-light); color: var(--cyan-dark); font-weight: 600; }

.classeur-actions { display: flex; align-items: center; gap: var(--espace-sm); }

.classeur-etat {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 22ch;
}

.classeur-etat-erreur { color: var(--red); }

/* Pourquoi ce classeur-ci ne s'enregistrera pas. Au-dessus de la grille et non
   a la place : il reste lisible, et c'est justement ce qu'on vient faire quand
   on ne peut pas le corriger. */
.classeur-avertissement {
  margin: 0;
  padding: var(--espace-sm) var(--espace-md);
  background: var(--yellow-pale);
  color: var(--gray-6);
  font-size: var(--fs-sm);
  line-height: 1.5;
}

.classeur-cadre {
  flex: 1;
  overflow: auto;
  background: var(--gray-1);
  padding: var(--espace-sm);
}

.classeur-vide {
  margin: var(--espace);
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

.classeur-grille {
  border-collapse: separate;
  border-spacing: 0;
  background: #fff;
  font-variant-numeric: tabular-nums;
}

/* Les tetes de lignes et de colonnes restent en vue quand la grille defile :
   sans elles, on ne sait plus quelle colonne on corrige des la trentieme
   ligne. */
.classeur-grille th {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-2);
  background: var(--gray-1);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--gray-5);
  text-align: center;
}

.classeur-grille tbody th {
  left: 0;
  top: auto;
  z-index: 1;
  min-width: 3rem;
}

.classeur-grille td { padding: 0; border: 1px solid var(--gray-2); }

.classeur-cellule {
  width: 12rem;
  padding: var(--espace-2xs) var(--espace-xs);
  border: none;
  background: none;
  font-family: inherit;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.classeur-cellule:focus {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
  background: #fff;
}

.classeur-cellule:read-only { color: var(--gray-5); }

/* Ce qui a ete touche et pas encore enregistre. Sans cette marque, on ne sait
   plus ce qu'on a corrige des la troisieme cellule -- et le compteur de la
   barre dit combien, pas lesquelles. */
.classeur-cellule-changee { background: var(--cyan-light); color: var(--black); font-weight: 600; }

.annotation-atelier {
  max-width: var(--largeur-fenetre);
  width: min(1180px, 100%);
  height: 92vh;
  max-height: 92vh;
}

/* LE BANDEAU DE L'ATELIER EST CELUI DE LA FENETRE DE LECTURE, et pour les
   memes raisons : une rangee de commandes posee dans un rembourrage ecrit pour
   un titre de fenetre laisse un blanc que rien n'espace. Les elements
   s'alignent sur leur milieu, sans quoi le nom flotterait au-dessus des
   boutons. */
.annotation-atelier .modal-header {
  padding-top: var(--espace-sm);
  padding-bottom: var(--espace-sm);
  align-items: center;
}

/* LA TAILLE DU NOM DANS LA FENETRE PRECEDENTE, et non celle d'un titre de
   fenetre : « le nom du fichier ne doit pas grossir, il doit conserver la meme
   taille que dans la fenetre precedente » (ticket du 8 septembre 2026). C'est
   `--fs-sm`, celle de `#visionneuse-titre`, ou le meme nom se lit une seconde
   plus tot. Sur une seule ligne, coupe par des points de suspension : un nom de
   scan juridique fait quatre-vingts caracteres, et le bandeau passait a deux
   rangs pour le montrer en entier. */
#annotation-titre {
  font-size: var(--fs-sm);
  /* Base nulle, comme la zone du titre de la fenetre de lecture : le nom prend
     la place qui reste une fois la rangee de commandes posee, au lieu de se la
     disputer avec elle. Sans cela les deux retrecissaient ensemble et la barre
     d'outils passait sur un second rang. */
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.annotation-outils {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin-left: auto;
  margin-right: var(--espace-xs);
  flex-wrap: wrap;
}

/* Le mot d'etat prend la place qui reste et se coupe plutot que de passer a la
   ligne : en passant, il poussait la barre sur deux rangs et tout le document
   descendait de trente pixels -- sous le pointeur, en pleine gomme, la marque
   suivante n'etait plus la ou on la visait (constate au navigateur le 22 aout
   2026). */
.annotation-outils .reglages-hint-inline {
  flex: 0 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* L'outil retenu s'allume, comme un onglet : sans cela rien ne dit si le
   prochain geste tracera un trait ou posera un texte. */
.annotation-outil.annotation-actif {
  background: var(--cyan-pale);
  color: var(--cyan-dark);
}

/* Les quatre couleurs : des pastilles, pas des mots. Completement rondes,
   donc 999px et non un barreau de l'echelle d'arrondis. */
.annotation-couleur {
  width: var(--icon-md);
  height: var(--icon-md);
  padding: 0;
  border: 2px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(14, 18, 22, .15);
  transition: transform .15s var(--ease), border-color .15s var(--ease);
}

.annotation-couleur:hover { transform: scale(1.12); }

/* La couleur retenue porte un anneau, a distance de la pastille : un simple
   epaississement de bord se confondrait avec la teinte elle-meme. */
.annotation-couleur.annotation-actif {
  border-color: var(--gray-6);
  box-shadow: inset 0 0 0 2px #fff;
}

.annotation-couleur-rouge { background: var(--red); }
.annotation-couleur-bleu { background: var(--blue); }
.annotation-couleur-vert { background: var(--green); }
.annotation-couleur-noir { background: var(--black); }

/* LES TROIS EPAISSEURS. Un bouton montre ce qu'il pose : une barre de la
   grosseur du trait qu'on aura. Les memes reperes que les pastilles de couleur
   d'a cote -- meme carre d'icone, meme anneau sur celle qu'on tient --, pour
   que la barre d'outils n'ait pas deux facons de dire « c'est celle-ci ». */
.annotation-epaisseur {
  width: var(--icon-md);
  height: var(--icon-md);
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 2px solid transparent;
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: border-color .15s var(--ease);
}

.annotation-epaisseur span {
  display: block;
  width: 100%;
  border-radius: 999px;
  background: var(--gray-6);
}

.annotation-epaisseur[data-epaisseur="fin"] span { height: 1px; }
.annotation-epaisseur[data-epaisseur="moyen"] span { height: 3px; }
.annotation-epaisseur[data-epaisseur="epais"] span { height: 6px; }

.annotation-epaisseur:hover { border-color: var(--gray-3); }
.annotation-epaisseur.annotation-actif { border-color: var(--gray-6); }

/* Le rouleau des pages. Le fond gris les detache les unes des autres : une
   suite de feuilles blanches sur blanc n'a plus de bord. */
.annotation-pages {
  flex: 1;
  min-height: 0;
  overflow: auto;
  background: var(--gray-2);
  /* L'atelier mesure ou commence chaque page (`bloc.offsetTop`) pour savoir
     lesquelles sont sous les yeux et n'agrandir que celles-la ; cette mesure se
     prend depuis le premier ancetre POSITIONNE. Sans cette ligne, ce serait la
     fenetre entiere, hauteur du bandeau comprise. */
  position: relative;
  /* Retire au navigateur le zoom de page sur cette zone, et lui laisse le
     defilement : c'est ce qui permet au pincement de n'agrandir que le
     document. Sans cette ligne, deux doigts agrandiraient le site entier,
     bandeau compris -- exactement ce qui etait signale. */
  touch-action: pan-x pan-y;
}

/* La colonne prend au moins la largeur de la zone : sans cela, une page
   agrandie au-dela de la fenetre serait callee a gauche et l'on ne pourrait
   plus atteindre son bord, et les pages plus etroites cesseraient d'etre
   centrees. Meme construction que `.lecteur-pdf-colonne`. */
.annotation-colonne {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espace-md);
  min-width: min-content;
  padding: var(--espace-md);
}

/* `flex: 0 0 auto` : dans une colonne flexible, une page se serait ecrasee
   pour tenir dans la fenetre -- les quatorze pages d'un PV revenaient en
   quatorze bandes de soixante pixels, constate au navigateur le 21 aout 2026.
   C'est le rouleau qui defile, pas les pages qui retrecissent.

   PAS DE `max-width` : c'est le zoom qui pose la taille du cadre, en pixels
   (`dimensionner` dans atelier-annotation.js), et une page agrandie doit
   pouvoir depasser la fenetre -- c'est meme tout ce qu'on lui demande. Le
   cadrage a l'ouverture, lui, se calcule au lieu de se subir : l'atelier ouvre
   a la largeur de la zone. */
.annotation-page {
  position: relative;
  flex: 0 0 auto;
  line-height: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

/* Les deux canvas suivent leur cadre, et c'est ce qui rend le pincement
   continu : la page deja peinte s'etire tout de suite a la nouvelle echelle, la
   nettete revient au repos du geste (voir `programmerRendu`). */
.annotation-fond,
.annotation-calque {
  display: block;
  width: 100%;
  height: 100%;
}

/* Le calque se pose exactement sur la page : c'est lui qui recoit les gestes,
   la page peinte n'en voit aucun. Le viseur en croix dit qu'on est sur une
   surface ou l'on trace, et non sur un document ou l'on selectionne.
   `touch-action: none` : sans elle, le premier mouvement du doigt fait defiler
   le rouleau au lieu de dessiner. */
.annotation-calque {
  position: absolute;
  inset: 0;
  cursor: crosshair;
  touch-action: none;
}

/* La gomme ne trace pas : elle designe ce qui est deja la. Le viseur en croix
   annoncerait le contraire, donc la fleche revient tant qu'on n'a rien sous le
   pointeur, et la main quand une marque est visee -- la meme grammaire que
   partout ailleurs sur le site. */
.annotation-gomme .annotation-calque { cursor: default; }
.annotation-gomme .annotation-calque.annotation-calque-vise { cursor: pointer; }

/* L'outil de selection non plus ne trace pas. Meme regle, un curseur pres :
   ce qu'on peut faire d'une marque tenue est la deplacer, et c'est la croix
   flechee qui le dit -- pas la main, qui annoncerait un lien. */
.annotation-selection .annotation-calque { cursor: default; }
.annotation-selection .annotation-calque.annotation-calque-vise { cursor: move; }

/* Un bouton eteint dit ce qui n'est plus possible : rien a defaire, rien a
   effacer. Sans cela, « annuler » sur un document vierge ne repond pas et on
   le reclique. */
.annotation-outils button:disabled {
  opacity: .4;
  cursor: default;
}

/* ---------- Les bulles de notification ----------

   Une conversation ne se remarquait que depuis la zone Messages, ou l'on n'est
   jamais : on est dans un mandat, dans un cycle, dans un grand livre. Ces
   bulles arrivent donc par-dessus n'importe quelle page (notifications.js,
   charge par _base.html).

   Elles se posent en bas a droite, au-dessus de la fenetre « Suggerer une
   modification » -- meme coin, et c'est voulu : c'est le coin des choses qui
   flottent, celui ou l'on regarde deja. Le decalage vertical laisse le rond
   cyan visible dessous plutot que de le couvrir. */
.notif-pile {
  position: fixed;
  right: 1.5rem;
  bottom: calc(1.5rem + 52px + .75rem);
  z-index: 1001;
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
  max-width: min(340px, calc(100vw - 3rem));
}

/* La famille des surfaces flottantes : --radius-lg, fond blanc, bordure
   --gray-3, ombre portee. Voir la fenetre de dialogue et la visionneuse. */
.notif-bulle {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  color: var(--black);
  text-decoration: none;
  opacity: 1;
  transform: translateY(0);
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}

a.notif-bulle:hover { background: var(--cyan-pale); color: var(--black); }

/* L'etat de sortie : la bulle glisse vers sa droite en s'effacant, puis
   notifications.js retire le noeud. */
.notif-partante {
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
}

.notif-avatar { --avatar-d: 30px; }

/* La bulle du verificateur de navigateur n'a personne a montrer : ce qui
   parle est le navigateur lui-meme. Un pictogramme prend donc la place du
   rond d'avatar, a la meme taille, pour que les deux sortes de bulles
   s'empilent droit dans la meme pile. */
.notif-icone {
  flex: none;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--orange-dark);
}

.notif-icone .icon { width: var(--icon-md); height: var(--icon-md); }

/* Une bulle qui s'ouvre au clic sans etre un lien : elle appelle du script,
   pas une adresse. Le survol est celui de `a.notif-bulle` juste au-dessus --
   ce qui se clique se signale pareil, quel que soit l'element. */
.notif-bulle-cliquable { cursor: pointer; }
.notif-bulle-cliquable:hover { background: var(--cyan-pale); }

.notif-corps {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  min-width: 0;
  flex: 1;
}

.notif-titre { font-size: var(--fs-sm); font-weight: 600; }

/* Deux lignes au plus : un apercu qui deroule tout un paragraphe cesse d'etre
   un apercu, et la bulle finirait par couvrir l'ecran qu'elle interrompt. */
.notif-texte {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.notif-fermer {
  flex: none;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  color: var(--gray-4);
  line-height: 0;
}

.notif-fermer:hover { color: var(--gray-6); }
.notif-fermer .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* « + 3 autres » : le reste d'un lot trop gros pour s'empiler. Sans le mot
   « messages » depuis le 7 septembre 2026 : le lot melange desormais des
   messages et des mouvements de pieces chez des clients, et il mene aux
   notifications, qui savent les ranger. */
.notif-bulle-reste {
  justify-content: center;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  font-weight: 500;
}

/* Sur telephone, la pile prend la largeur et se pose au-dessus de la barre
   d'onglets basse plutot que dans un coin de 340 px qui n'existe pas. */
@media (max-width: 720px) {
  .notif-pile {
    left: .75rem;
    right: .75rem;
    max-width: none;
    bottom: calc(1.5rem + 52px + .75rem + env(safe-area-inset-bottom));
  }
}

/* ---------- La chronologie d'un client, et la page des notifications -------
 *
 * Une seule frise, lue a deux echelles : la tuile « Chronologie » de
 * l'Assistant montre ce qui est arrive chez un client ; la page /notifications
 * montre les dernieres lignes de chacun des clients suivis, groupees par
 * client. Les deux posent le meme balisage -- `chrono-lignes`, `chrono-jour`,
 * `chrono-ligne` --, donc une seule regle a corriger. La page n'a plus de
 * `notif-ligne` a elle : c'etait la meme regle ecrite deux fois, et une regle
 * ecrite deux fois se corrige une fois sur deux.
 *
 * « Integre chronologie a l'assistant et fait un plus beau design » (demande du
 * 7 septembre 2026). C'etait une liste : une heure en colonne, une phrase a
 * cote, un filet entre chaque. Rien n'y disait de quelle nature etait la ligne
 * -- une piece deposee, une piece retiree et une echeance qui approche s'y
 * lisaient de la meme encre --, et il fallait lire la phrase pour le savoir. La
 * frise le dit avant les mots : une puce par nature, sur un rail continu qui
 * fait lire une suite de faits plutot qu'un tableau de lignes. */

/* La page etait une colonne de lecture : 860 px de cartes au milieu de la
   fenetre, et 850 px de blanc de chaque cote a 2 560. Le contenu s'arretait a
   264 px d'une fenetre de 1 440. Un client, c'est un nom et cinq lignes de
   frise -- ca ne se lit pas mieux dans une colonne longue et solitaire, et
   quinze clients s'y suivaient a la queue leu leu alors qu'ils tiennent cote a
   cote.

   Les cartes se rangent donc en voies de --largeur-colonne (440 px, le meme
   jeton et la meme formule que les grilles de reglages) : cinq de front a
   2 560, quatre a 1 920, trois a 1 512, deux a 1 280, une sur telephone. Ce
   qui parle de la page entiere -- le decompte en tete, « vous etes a jour »,
   la carte du vide -- tient les voies d'un bord a l'autre.

   `auto-fill` et non `auto-fit` : avec deux clients seulement, `auto-fit`
   replierait les voies vides et etirerait les deux cartes a 1 250 px chacune,
   ou l'heure d'une ligne flotterait a un metre de son texte. Une voie vide se
   remarque moins qu'une carte deformee.

   `align-items: start` : un client qui a deux lignes n'a pas a porter un cadre
   de la hauteur du voisin qui en a dix.

   `grid-auto-rows: max-content` n'est pas un ornement, c'est ce qui empeche la
   grille de s'effondrer. Elle defile pour son compte (voir plus bas), donc sa
   hauteur est fermee ; une grille de hauteur fermee repartit la place entre ses
   rangees, et une rangee ne descend alors pas sous ce que ses cartes exigent au
   minimum -- sauf qu'une carte en `overflow: hidden`, comme l'est `.notif-client`,
   n'exige plus rien : son plancher automatique tombe a zero. Mesure a 390 sans
   cette ligne : douze rangees de 20,77 px pour des cartes de 222 a 426, les
   douze clients ecrits les uns par-dessus les autres. La rangee se mesure donc
   sur son contenu, et c'est la grille qui deborde -- ce qu'elle sait faire. */
.notifs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--largeur-colonne), 100%), 1fr));
  grid-auto-rows: max-content;
  align-items: start;
  gap: var(--espace);
}

.notifs-tete,
.notifs-a-jour,
.notifs-vide {
  grid-column: 1 / -1;
}

/* La bande de l'appareil reste en tete, la grille defile sous elle. C'est la
   forme de /dossiers et des onglets : un seul enfant flexible, qui prend la
   hauteur laissee et qui deborde pour son compte.

   La reserve du bouton flottant (voir `.app-main`) descend dans la grille.
   Laissee sur la page, elle aurait fait une bande morte de cent pixels au bas
   de la fenetre, en permanence, sous une zone qui ne bouge plus ; posee ici,
   elle ne se voit qu'une fois arrive au bout. */
.app-main-pleine.notifs-page {
  padding-bottom: 0;
}

.app-main-pleine > .notifs {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding-bottom: calc(52px + var(--espace-xl) * 2);
}

/* Rien a signaler : la carte se pose au milieu de la hauteur plutot que collee
   en haut d'une fenetre vide. La reserve du pied la remonte de cinquante
   pixels au-dessus du centre geometrique, ce qui est justement ou l'oeil
   attend un centre. */
.notifs:has(.notifs-vide) {
  align-content: center;
}

/* Ce que la page annonce d'elle-meme, en tete : combien, et chez combien de
   clients. « 12 » puis quinze cartes ne demande pas de compter les cartes. */
.notifs-tete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  padding: var(--espace-2xs) 0;
}

.notifs-tete-compte {
  background: var(--cyan);
  color: #fff;
  font-size: var(--fs-2xs);
  font-weight: 700;
  border-radius: 999px;
  padding: var(--espace-3xs) var(--espace-xs);
  font-variant-numeric: tabular-nums;
}

.notifs-a-jour {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  color: var(--gray-5);
  font-size: var(--fs-sm);
  padding: var(--espace-2xs) 0;
}

.notifs-a-jour .icon { width: var(--icon-sm); height: var(--icon-sm); color: var(--green); }

/* Rien a montrer : une carte, et non une phrase seule au milieu du blanc. Elle
   dit ce que la page servira a lire, puisque c'est le seul moment ou personne
   ne peut le deviner de ce qu'elle affiche. */
.notifs-vide {
  display: flex;
  align-items: flex-start;
  gap: var(--espace);
  /* La seule mesure de lecture qui reste sur cette page, et pour la seule
     chose qui soit de la prose suivie : trois phrases qui disent a quoi la
     page sert. Etirees sur les 2 496 px de la grille, elles feraient une ligne
     unique que l'oeil ne saurait pas reprendre. */
  max-width: var(--largeur-lecture);
  margin: 0 auto;
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: var(--espace-lg);
  color: var(--gray-5);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.notifs-vide p { margin: 0; }

.notifs-vide-rond {
  flex: none;
  width: var(--h-champ);
  height: var(--h-champ);
  border-radius: 999px;
  display: grid;
  place-items: center;
  background: var(--cyan-light);
  color: var(--cyan-dark);
}

.notifs-vide-rond .icon { width: var(--icon-md); height: var(--icon-md); }

/* L'etat des notifications du systeme sur cet appareil, en tete de la page.
   Meme surface que le bloc vide juste au-dessus -- c'est la meme nature de
   chose, une phrase et un rond --, avec le bouton pousse au bout de la ligne
   et le texte centre verticalement plutot qu'aligne en haut : il n'y a qu'une
   phrase, et l'aligner en haut la decalerait du rond et du bouton. */
.notifs-appareil {
  display: flex;
  align-items: center;
  gap: var(--espace);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: var(--espace-lg);
  color: var(--gray-5);
  font-size: var(--fs-sm);
  line-height: 1.6;
  margin-bottom: var(--espace);
}

.notifs-appareil-texte { flex: 1 1 auto; min-width: 0; }
.notifs-appareil-texte p { margin: 0; }

/* Le bouton ne se laisse pas ecraser par la phrase quand la place manque. */
.notifs-appareil .btn-primary { flex: none; }

@media (max-width: 600px) {
  /* En colonne plutot qu'un bouton reduit a rien : sur un telephone, la
     phrase prend toute la largeur et le bouton passe dessous, sous le rond. */
  .notifs-appareil { flex-wrap: wrap; }
  .notifs-appareil-texte { flex: 1 1 100%; order: 2; }
  .notifs-appareil .btn-primary { order: 3; margin-left: auto; }
}

/* Un client, ses dernieres lignes. Meme famille de surface que partout
   ailleurs : fond blanc, bordure --gray-3, --radius. */
.notif-client {
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

/* Ce qui est neuf se voit au lisere, pas au fond : un fond colore sur quinze
   cartes ferait une page qui crie. Le lisere tient sur le bord gauche, la ou
   l'oeil descend. */
.notif-client-neuf { border-left: 3px solid var(--cyan); }

/* L'en-tete est le lien : c'est le nom du client qu'on vise quand on veut
   aller voir, pas une fleche posee au bout de la ligne. */
.notif-client-entete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace);
  text-decoration: none;
  color: var(--black);
  border-bottom: 1px solid var(--gray-2);
}

.notif-client-entete:hover { background: var(--cyan-pale); color: var(--black); }
.notif-client-rond { --avatar-d: var(--h-logo); flex: none; }
.notif-client-nom { font-weight: 600; font-size: var(--fs); flex: 1; min-width: 0; }

.notif-client-compte {
  flex: none;
  background: var(--cyan);
  color: #fff;
  font-size: var(--fs-3xs);
  font-weight: 700;
  border-radius: 999px;
  padding: 1px var(--espace-xs);
  font-variant-numeric: tabular-nums;
}

.notif-client-fleche {
  flex: none;
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
}

.notif-client-reste {
  display: block;
  padding: var(--espace-xs) var(--espace);
  border-top: 1px solid var(--gray-2);
  font-size: var(--fs-3xs);
  color: var(--gray-5);
  text-decoration: none;
}

.notif-client-reste:hover { background: var(--cyan-pale); }

/* Arriver ici par un lien qui visait la chronologie pose la tuile SOUS
   l'en-tete collant, pas dessous lui. Sans ce retrait, le haut du bloc -- son
   titre, sa phrase de resume et « Tout afficher » -- se rangeait derriere la
   barre du mandat, et le lien des notifications semblait ouvrir la frise sans
   sa tete. Meme valeur que `.cycle-section`, qui se descend de la meme facon
   depuis l'ecran de controle juridique. */
#chrono-module { scroll-margin-top: 100px; }

/* ---------- La frise elle-meme ---------- */

/* Le rail : un filet continu derriere les puces, du premier fait au dernier.
   Pose sur la liste et non sur chaque ligne -- une ligne qui porte son propre
   bout de rail laisse un blanc a chaque separateur de jour, et c'est justement
   la que la suite doit se voir continuer.

   `--chrono-marge` est le retrait horizontal de la frise : nul dans une tuile,
   qui a deja le sien, egal a la gouttiere dans une carte de client. Le rail
   suit, puisqu'il se pose au centre de la colonne des puces. */
.chrono-lignes {
  --chrono-puce: var(--icon-xl);
  --chrono-marge: 0px;
  --chrono-tete: calc(var(--espace-xs) + var(--chrono-puce) / 2);
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.chrono-lignes::before {
  content: "";
  position: absolute;
  left: calc(var(--chrono-marge) + var(--chrono-puce) / 2);
  top: var(--chrono-tete);
  bottom: var(--chrono-tete);
  width: 1px;
  background: var(--gray-2);
}

.notif-client .chrono-lignes { --chrono-marge: var(--espace); }

/* Une ligne : de quelle nature, ce qui s'est passe, a quelle heure. L'heure a
   droite et non a gauche : la phrase commence alors toujours au meme endroit,
   et c'est elle qu'on lit. */
.chrono-ligne {
  display: grid;
  grid-template-columns: var(--chrono-puce) minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--espace-sm);
  padding: var(--espace-xs) var(--chrono-marge);
  font-size: var(--fs-xs);
  color: var(--gray-6);
}

/* La puce porte la nature avant les mots. Opaque, donc elle coupe le rail
   d'elle-meme : pas d'anneau blanc a poser par-dessus. */
.chrono-puce {
  width: var(--chrono-puce);
  height: var(--chrono-puce);
  border-radius: 999px;
  display: grid;
  place-items: center;
  background: var(--cyan-light);
  color: var(--cyan-dark);
}

.chrono-puce .icon { width: var(--icon-xs); height: var(--icon-xs); }

/* Retirer une piece n'est pas un fait de meme poids que la deposer : la puce
   reste grise, la ligne ne tire pas l'oeil. */
.chrono-ligne-suppression .chrono-puce { background: var(--gray-2); color: var(--gray-5); }

/* Une alerte n'est pas un mouvement de piece : c'est une echeance qui approche
   sans que ce qu'elle attend soit arrive. Elle garde l'orange de « À valider »,
   qui dit partout ailleurs la meme chose -- quelque chose attend un geste. */
.chrono-ligne-alerte .chrono-puce { background: var(--orange-pale); color: var(--orange-dark); }
.chrono-ligne-alerte .chrono-ligne-texte { color: var(--orange-dark); white-space: pre-line; }

.chrono-ligne-texte { min-width: 0; overflow-wrap: anywhere; line-height: 1.55; }

.chrono-ligne-texte a { color: var(--cyan-dark); text-decoration: none; font-weight: 500; }
.chrono-ligne-texte a:hover { text-decoration: underline; }

/* Ce qu'on n'a pas encore lu. L'encre et la graisse, rien d'autre : la couleur
   est deja prise par les liens de la phrase. */
.chrono-ligne-neuve .chrono-ligne-texte { color: var(--black); font-weight: 500; }

.chrono-ligne-quand {
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  line-height: var(--chrono-puce);
}

/* La date change : un intitule sur le rail, comme dans une messagerie. Sans
   lui, quarante lignes d'un meme versement et trois lignes de la semaine
   derniere se lisent d'un seul tenant. Le rail passe derriere, dans la colonne
   laissee vide : c'est le meme fil qui continue, pas un nouveau depart. */
.chrono-jour {
  display: grid;
  grid-template-columns: var(--chrono-puce) minmax(0, 1fr);
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--chrono-marge) var(--espace-3xs);
}

.chrono-jour-nom {
  grid-column: 2;
  font-size: var(--fs-3xs);
  font-weight: 600;
  color: var(--gray-5);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
}

/* ---------- La tuile « Chronologie » de l'Assistant ---------- */

.chrono-etat {
  margin: 0;
  color: var(--gray-5);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

@media (max-width: 720px) {
  /* La colonne de l'heure passe sous la phrase : sur un telephone, trois
     colonnes laissent a la phrase une largeur de mot. */
  .chrono-ligne {
    grid-template-columns: var(--chrono-puce) minmax(0, 1fr);
    gap: var(--espace-xs) var(--espace-sm);
  }
  .chrono-ligne-quand { grid-column: 2; line-height: 1.2; }
}


/* --- Formulaire CNCC : mandat et declaration d'activite -------------------
 *
 * Cent cinquante champs sur deux onglets. En une colonne, comme le reste des
 * reglages, l'onglet Mandat faisait quatre ecrans de haut et il fallait le
 * derouler entierement pour verifier une date de nomination. La grille les
 * range par deux ou trois selon la largeur, et garde le libelle au-dessus de
 * la case : une etiquette a gauche, sur des libelles de cette longueur,
 * pousse les cases a des largeurs differentes d'une ligne a l'autre. */

/* Flex-wrap plutot qu'une grille de colonnes egales : cent cinquante champs
   de longueurs tres differentes -- « oui/non », « 31/12/2024 », « 4 200 » --
   dans des cases toutes larges de 260 pixels donnaient un formulaire trop
   long a l'oeil et un rendu ou une date paraissait porter la meme quantite
   d'information qu'une denomination sociale. Chaque champ demande maintenant
   la largeur dont son type a besoin, et une phrase (`texte_long`, `liste`)
   passe seule sur sa ligne. */
.aglae-grille {
  display: flex;
  flex-wrap: wrap;
  /* Deux rangees de cases se suivent au rythme du panneau, deux cases de la
     meme rangee au barreau du dessus : la grille se lit par lignes. */
  gap: var(--espace-sm) var(--espace-md);
  align-items: flex-start;
}

.aglae-champ {
  display: flex;
  flex-direction: column;
  /* L'intitule et sa case ne font qu'une chose : le meme ecart que les deux
     teintes d'une charte ou les trois outils d'une piece. */
  gap: var(--espace-2xs);
  min-width: 0;
  /* Un champ de texte a defaut : il occupe ce qu'il reste sur sa ligne, sans
     descendre en dessous de 16rem -- en dessous, un libelle du CNCC passe a
     deux lignes et rompt l'alignement. */
  flex: 1 1 16rem;
}

/* Le meme plafond que ses deux voisines, qui l'ecrivent chacune : « au-dela de
   vingt-deux rem, un intitule a rallonge rendrait la grille bancale ». Il avait
   ete pose sur les largeurs `courte`, `libelle` et sur les genres -- toutes
   `flex: 0 0`, donc les seules qui ne pouvaient de toute facon pas le franchir
   -- et oublie sur le champ de texte par defaut, le seul qui s'etire. La regle
   existait donc partout ou elle ne servait a rien, et nulle part ou elle
   servait.

   Ce que ca donnait : « Autre conseil (nom) », dernier de sa grille et donc
   seul sur sa ligne, prenait les 1336 pixels du panneau pour recevoir le nom
   d'un cabinet, sous quatre cases de 322 qui recoivent la meme chose ;
   « Offre au public de titres financiers » en prenait 919 a la fin de sa
   rangee. Rien ne debordait, rien ne se chevauchait : les cases mentaient
   simplement sur ce qu'on y ecrit, et c'est ce que la grille se donne pour
   regle de ne pas faire -- « chaque champ demande la largeur dont son type a
   besoin », quatre lignes plus haut.

   Une ligne qui ne se remplit pas jusqu'au bord n'est pas un defaut ici : la
   rangee des supplements s'arrete deja au milieu du panneau, et toutes les
   cases a largeur fixe font pareil. Le bord droit regulier etait obtenu en
   etirant la derniere case, c'est-a-dire en payant l'alignement du contenant
   avec la largeur du contenu.

   Pose au-dessus de `.aglae-champ-large` pour que la phrase garde sa ligne
   entiere : meme poids de selecteur, c'est l'ordre qui tranche. Et seulement
   a partir de 600 px, la ou une ligne peut porter deux cases -- en dessous il
   n'y en a qu'une par ligne, large de 362, et un plafond a 352 la laisserait
   dix pixels en retrait des blocs pleine largeur qui l'encadrent. */
@media (min-width: 600px) {
  .aglae-champ { max-width: 22rem; }
}

/* Largeurs propres a chaque type. Le libelle reste toujours au-dessus, seule
   la case change : une date ne demande pas la meme place qu'une denomination.

   Onze rem tient un montant, une duree ou une date -- c'est le plancher --,
   mais pas toujours l'intitule pose au-dessus : « Certification des comptes
   annuels » s'y coupait en deux, dans « Temps passe » comme dans
   « Honoraires », et « Total des produits financiers (K€) » de meme (demandes
   du 22 aout 2026). Une case coupee descend d'un cran celles de sa rangee, et
   la ligne se lit sur deux etages.
   `max-content` mesure le plus large des deux contenus -- l'intitule entier,
   ou ce que la case doit pouvoir montrer -- et c'est deja la regle des listes
   deroulantes et des cases passees a `largeur="libelle"` : trois façons
   d'ecrire la meme chose, une case ne descend jamais sous son libelle.
   Plafonnee comme elles : au-dela de vingt-deux rem, un intitule a rallonge
   rendrait la grille bancale.

   `:not([data-largeur])` : le genre ne decide que la ou rien de plus precis
   n'a ete decide. Une case qui porte une `largeur` (app/aglae.py) a ete taillee
   au cas par cas, et le plancher de onze rem la rouvrait par-dessous --
   « Effectif », qui tient en quatre chiffres et dont l'intitule fait soixante
   pixels, s'est retrouve large de cent soixante-seize (« reduis la taille de
   l'effectif », demande du 22 aout 2026, le jour meme du plancher). Trois cases
   etaient dans ce cas : l'effectif des comptes annuels, la duree en mois et
   l'annee de debut d'activite. */
/* `min()` et non `22rem` seul : le plafond doit ceder devant la grille. Ces
   cases-la sont `width: max-content` -- elles se mesurent sur leur plus longue
   option, pas sur la place disponible -- et un plafond ecrit en rem ne les
   ramene qu'a 352 px, quelle que soit la largeur de l'ecran. Sous 370 px de
   fenetre, trois d'entre elles -- « Type d'entite », « Forme juridique »,
   « Activite » -- sortaient donc du panneau et emmenaient la page entiere en
   defilement horizontal : six pixels de trop a 360, quarante-six a 320, la
   largeur d'un iPhone SE ou de n'importe quel telephone en zoom d'affichage.

   La regle existait deja au-dessus, sur la case de texte ordinaire, mais elle
   n'y servait a rien : `flex: 1 1 16rem` avec `min-width: 0` sait retrecir tout
   seul. Ce sont les cases a `flex: 0 0 auto` qui ne le savent pas, et c'est
   precisement a elles que le plafond absolu avait ete laisse.

   Au-dessus de 370 px rien ne change : le contenant est plus large que 352, et
   `min()` rend les memes 22rem qu'avant. */
.aglae-champ[data-genre="date"]:not([data-largeur]),
.aglae-champ[data-genre="nombre"]:not([data-largeur]),
.aglae-champ[data-genre="montant"]:not([data-largeur]),
.aglae-champ[data-genre="heures"]:not([data-largeur]) {
  flex: 0 0 auto;
  width: max-content;
  min-width: 11rem;
  max-width: min(22rem, 100%);
}

/* Les listes deroulantes -- un choix parmi un referentiel, ou le oui / non /
   non renseigne d'un booleen -- se mesurent sur ce qu'elles portent, comme les
   cases passees a `largeur="libelle"` une par une depuis le 21 aout : « pour
   toutes les combo-box de DA et de Mandat les cases doivent etre de la largeur
   de son libelle et/ou de la longueur du selecteur de sa plus longue option »
   (demande du 22 aout 2026).
   C'est exactement ce que `max-content` mesure : le plus large des deux, sans
   qu'il faille l'ecrire champ par champ. Un oui/non tenu a onze rem coupait son
   intitule en deux des qu'il passait trente caracteres -- « Incertitude
   significative sur la continuite », « Derniere declaration de ce mandat ? » --
   et un choix, laisse extensible, s'etirait sur toute la place que ses voisines
   venaient de liberer, si bien qu'une meme liste n'avait pas deux fois la meme
   largeur d'une ligne a l'autre. Plafonnees comme avant : au-dela de vingt-deux
   rem, un referentiel a rallonge rendrait la grille bancale. */
.aglae-champ[data-genre="choix"],
.aglae-champ[data-genre="booleen"] {
  flex: 0 0 auto;
  width: max-content;
  max-width: min(22rem, 100%);
}

/* Le plancher de la plus longue option, pose sur le selecteur et non sur la
   case qui le porte. `max-content` ne suffit pas : le navigateur mesure un
   `<select>` sur l'option *retenue*, si bien que la case de « ETF » faisait la
   largeur de « - » et coupait « Non » des qu'on le choisissait -- sans se
   redimensionner. `--options` (pose par le gabarit, qui seul connait le
   referentiel) compte les caracteres de la plus longue ; `ch` les convertit.

   Sur le selecteur, parce que la mesure est en `em` -- une fraction de la
   taille du texte -- et que les options s'ecrivent dans la police du
   selecteur, plus petite que celle de la case qui le porte.

   `--options` est une largeur, pas un nombre de caracteres : compter les
   caracteres donnait a « Immatriculation » la place de quinze « M », et six
   listes s'en trouvaient elargies d'un quart -- « Nomination du commissaire
   aux comptes », « Immatriculation », « SACC realises ? », « Opinion emise »,
   « Procedure d'alerte », « Statut de la declaration » (demande de suivi du
   22 aout 2026, la ou le resserrement de la veille etait cense s'appliquer).
   Le reste est la fleche et les marges interieures.

   `min()` garde le plancher sous le plafond de la case : passe au-dessus, le
   selecteur deborderait sur sa voisine au lieu de rester dedans -- trois
   referentiels sont plus longs que vingt-deux rem. */
.aglae-champ[data-genre="choix"] > select.aglae-input,
.aglae-champ[data-genre="booleen"] > select.aglae-input {
  min-width: min(22rem, 100%, calc(var(--options, 0) * .01em + 2.6rem));
}

/* Le genre dit ce qu'un champ contient, pas toujours combien de place il
   demande : deux textes libres peuvent porter l'un une denomination sociale,
   l'autre un matricule de dix chiffres. `largeur` (app/aglae.py) tranche au
   cas par cas quand le genre ne suffit pas -- la moitie du barreau ordinaire,
   soit de quoi tenir un numero et son libelle sur une ligne. Fixe et non
   flexible : laissee extensible, la case reprenait toute la place que ses
   voisines venaient de liberer. */
.aglae-champ[data-largeur="courte"] {
  flex: 0 0 8rem;
}

/* « libelle » : la case fait exactement la largeur du plus long de ses deux
   contenus -- son intitule, ou ce qu'on y ecrit. C'est la reponse a une
   observation juste (21 aout 2026) : sur ces champs-la, ce n'est pas le
   numero qui fixait la limite, c'est le libelle au-dessus, et une case taillee
   plus large que lui n'ajoutait que du vide.
   `max-content` laisse le navigateur mesurer les deux : l'intitule ne se coupe
   pas, et `size` (pose par le gabarit depuis `caracteres`) dit combien de
   caracteres le contenu doit pouvoir montrer. Un `<select>`, lui, se mesure a
   sa plus longue option -- sans quoi le choix retenu s'y afficherait tronque.
   Plafonnee comme un champ de choix : au-dela, un intitule tres long
   rendrait la grille bancale. */
.aglae-champ[data-largeur="libelle"] {
  flex: 0 0 auto;
  width: max-content;
  max-width: min(22rem, 100%);
}

/* Sauf une date, qui ne se mesure pas comme le reste.
   « Dans "lettre de mission et honoraires" : on ne voit pas la date de
   signature, elle est tronquee » (ticket du 1er septembre 2026).

   Une case taillee sur son intitule marche parce que le contenu ne pese pas
   dans la balance : `size` le neutralise, et `width: 100%` fait remplir la
   place que l'intitule donne. Un `input[type="date"]` echappe aux deux --
   `size` ne s'y applique pas, et ce qu'il montre n'est pas du texte mais trois
   champs numeriques suivis d'un calendrier, que le navigateur dessine a sa
   taille a lui. On comptait donc sur sa largeur naturelle pour faire plancher.
   Elle ne le fait pas partout : sous `width: max-content`, la largeur en
   pourcentage d'un enfant ne compte pas toujours dans la mesure du parent, et
   la case retombe alors sur le seul intitule. « Date de signature » fait
   123 px la ou la meme case demande son calendrier en plus : la date y est
   coupee, et sur Safari plus tot qu'ailleurs.

   9 rem, c'est-a-dire la place de « 31/12/2024 » et de son calendrier avec le
   rembourrage du champ. La voisine « Date de la lettre de mission », plus
   large de son intitule, ne bouge pas : un plancher ne rabote rien. */
.aglae-champ[data-genre="date"][data-largeur] {
  min-width: 9rem;
}

/* `display` sur une classe l'emporte sur le `display: none` que le navigateur
   attache a l'attribut `hidden`. Sans cette ligne, les dix-sept branches se
   fermaient dans le DOM et restaient a l'ecran : le formulaire montrait ses
   cent champs d'un coup, dont ceux que la CNCC refuse de voir remplis --
   exactement ce que les branches existent pour empecher. Constate au
   navigateur le 20 aout 2026. */
.aglae-champ[hidden],
.aglae-groupe[hidden],
.declaration-exercice[hidden] {
  display: none;
}

/* Un texte libre ou une liste tient sur toute la largeur : ce qu'on y ecrit
   est une phrase, pas une valeur, et la couper en colonne courte la rend
   illisible. En flex, on force la ligne complete. */
.aglae-champ-large {
  flex: 1 1 100%;
  max-width: 100%;
}

/* Une seconde partie a la fin d'un groupe, « legerement separee » (demande du
   5 septembre 2026 pour le projet de lettre de mission). Un filet et un peu
   d'air : ce n'est pas un autre sujet -- le projet et la lettre signee sont
   deux etats de la meme piece --, c'est la meme rangee qu'on ne veut pas lire
   d'un trait. Un titre de section les aurait separes pour de bon, ce que la
   demande ne veut pas : elle dit « a la fin du meme bloc ». */
.aglae-champ-detache {
  margin-top: var(--espace-sm);
  padding-top: var(--espace);
  border-top: 1px solid var(--gray-2);
}

.aglae-label {
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

/* La marque du cabinet au fil du titre du groupe qui porte les commissaires
   aux comptes : `.toolbar-label-marque`, plus haut dans la feuille. Ce titre
   avait sa propre regle jusqu'au 22 aout 2026 ; « Titulaire » ayant recu la
   meme marque le meme jour, les deux se posent desormais de la meme facon --
   une marque au fil d'un intitule, un seul endroit qui le dit. */

/* La marque du co-commissariat, au fil de l'intitule de la case qui nomme les
   co-commissaires. Elle est seulement recalee sur la ligne du texte :
   `inline-flex` pose une image sur la ligne de base, ou un dessin centre sur
   son carre parait remonte d'un tiers de cadratin. */
.aglae-label .dossier-cocac-badge {
  margin-left: var(--espace-2xs);
  vertical-align: -.3em;
}

/* `:not([type="checkbox"])` : les cases d'un choix multiple portent la meme
   classe -- c'est par elle que dossier-aglae.js les lit --, mais rien de ce qui
   suit ne leur va. La largeur pleine et le rembourrage d'un champ de saisie les
   deformaient : mesurees a trois pixels de large au navigateur le 20 aout 2026.
   Exemptees, elles retombent sur la case du site (regle `input[type=
   "checkbox"]` en tete de fichier), taille tactile de mobile.css comprise. */
.aglae-input:not([type="checkbox"]) {
  font-family: var(--sans);
  font-size: var(--fs-md);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  width: 100%;
  min-width: 0;
  min-height: var(--h-champ);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
  /* Une valeur trop longue s'arrete sur des points de suspension, comme
     l'option d'une liste deroulante -- la regle est deja ecrite sur `select`
     en tete de fichier, avec sa raison : « l'option choisie se coupe proprement
     plutot que de deborder ». Le champ de texte pose a cote ne l'avait jamais
     recue, et retombait donc sur le `clip` du navigateur : la valeur y est
     tranchee au pixel, en plein milieu d'une lettre.

     Les deux se voient sur la meme ligne du volet CNCC. « Activite » est un
     `select` de 352 px : « Association sportive affiliee nationale et loc... ».
     « Offre au public de titres financiers » est un champ de texte de la meme
     largeur, dont la valeur en demande 427 : « Les titres de l'entite ne font
     pas l'objet d'une offi ». Rien ne dit au lecteur que la phrase continue --
     elle a simplement l'air d'avoir ete coupee par un bug.

     Sans effet sur la saisie : le navigateur ne rend l'ellipse que sur un champ
     au repos, et rend la main au texte des qu'il recoit le curseur. */
  text-overflow: ellipsis;
}

/* `height` et non `min-height` : c'est le seul champ du panneau qu'il faut
   faire descendre, pas monter. La cible tactile du telephone n'est pas en jeu
   -- le volet CNCC n'a aucune regle dans mobile.css --, et une hauteur fixe
   cederait de toute facon devant un `min-height`, qui l'emporte toujours. */
.aglae-input[type="date"] {
  height: var(--h-champ);
}

.aglae-input:not([type="checkbox"]):focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Une liste deroulante garde la voie de sa fleche, meme rhabillee. Le
   rembourrage d'un champ de saisie vaut autant a gauche qu'a droite ; celui
   d'un `<select>` non -- la fleche y est un fond dessine dans la marge droite,
   et --chevron-reserve la lui garde. Deux rhabillages ecrits pour des
   champs de texte attrapaient le selecteur pose a cote et ramenaient cette
   marge a .7rem : la fleche revenait alors se poser sur le texte.

   Invisible tant que l'option retenue est courte, et flagrant des qu'elle
   remplit la case : dans le panneau Mandat, « Association (declaree ou non,
   groupement d'e... » et « Association sportive affiliee nationale et
   locale... » dessinaient leurs points de suspension et leur chevron dans les
   memes pixels. Le plancher de largeur des cases de choix comptait deja cette
   voie -- « le reste est la fleche et les marges interieures », 2.6rem --,
   c'est le rembourrage qui ne la rendait pas.

   Le troisieme rhabillage est celui du selecteur de cloture, pose a meme une
   rangee de reglages et non dans une case du volet. Il ne s'est vu qu'une fois
   la largeur rendue a cette rangee, juste au-dessus : tant que le selecteur
   prenait mille pixels pour une ligne qui en demande trois cents, il restait
   sept cents pixels de vide entre le texte et sa fleche. Ramene a son contenu,
   il ne laissait plus que neuf dixiemes de pixel, et le chevron se dessinait
   sur le « 6 » de « campagne 2026 ». Une voie qui n'est reservee que par
   accident n'est pas reservee. */
.aglae-champ > select.aglae-input,
.reglages-row > select.aglae-input,
.reglages-presence-row select {
  padding-right: var(--chevron-reserve);
}

textarea.aglae-input {
  resize: vertical;
  line-height: 1.45;
}

/* Un nombre se lit par la droite : c'est l'unite qui dit l'ordre de grandeur,
   et deux montants ranges a gauche donnent a « 900 » l'air d'etre plus grand
   que « 1 200 » (demande du 21 aout 2026, sur l'effectif). La classe est celle
   que le gabarit pose sur les trois genres chiffres -- nombre, montant,
   heures --, et les aligner tous plutot que le seul effectif evite qu'une case
   d'un groupe se lise autrement que sa voisine.
   `tabular-nums` fige la largeur des chiffres : sans elle, les colonnes de la
   grille dansent d'une valeur a l'autre. */
.aglae-input-nombre {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Un choix multiple : une case par code, et non un selecteur. La bordure du
   groupe est transparente au repos -- elle n'est la que pour recevoir le rouge
   quand l'enregistrement echoue, que dossier-aglae.js pose sur le groupe et
   non sur une case, qui designerait la mauvaise coupable. */
.aglae-cases {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-2xs) var(--espace);
  padding: var(--espace-xs) var(--espace-2xs);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
}

.aglae-case {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  font-size: var(--fs-md);
  color: var(--black);
  cursor: pointer;
}

/* Le libelle passe a la ligne dans une colonne de 260 pixels, la case non :
   c'est elle qui dit si la reponse est cochee. */
.aglae-case > span {
  min-width: 0;
}

/* Le selecteur de cloture et le champ de date qui ouvre la suivante, en tete
   du volet DA. Ils se dimensionnent sur leur contenu -- une cloture s'annonce
   en trente-huit caracteres, pas en mille pixels -- avec un plancher pour que
   le libelle tienne.

   `.aglae-input` porte la classe deux fois. Ce n'est pas une coquetterie : la
   regle de base s'ecrit `.aglae-input:not([type="checkbox"])`, et `:not()`
   prend le poids de son argument -- un selecteur d'attribut, soit celui d'une
   classe. Elle pese donc deux classes, cette regle-ci n'en pesait qu'une, et
   son `width: auto` n'a jamais rien fait : le selecteur gardait la largeur
   pleine que la base donne a un champ de saisie.

   Ce que cela coutait se mesure sur la rangee, qui ne se replie pas. Le
   selecteur prenait 1026 px pour une ligne qui en demande 318, et les deux
   controles d'a cote payaient la difference : le champ de date tombait a
   154 px alors qu'il en declare 176, et le bouton « Ouvrir cette cloture »
   etait comprime jusqu'a ce que son intitule se casse en deux lignes -- 43 px
   de haut a cote de champs de 32, un « + » centre contre un texte a deux
   etages. Un bouton dont le libelle se brise est ce qu'on voit en premier en
   ouvrant l'onglet.

   La largeur rendue, les trois retombent d'eux-memes : 318, 176, et un bouton
   d'une seule ligne a --h-sm. */
.aglae-input.aglae-input-exercice {
  width: auto;
  min-width: 16rem;
}

.reglages-row .aglae-input-exercice[type="date"] {
  min-width: unset;
  width: 11rem;
}

.aglae-lecture {
  font-size: var(--fs-md);
  color: var(--black);
  padding: var(--espace-xs) 0;
}

/* Un champ deduit, au milieu d'une rangee de cases a remplir. Il n'a pas de
   cadre -- il n'y a rien a y saisir --, et sans marque il se lisait comme une
   case qu'on aurait oublie de remplir. La demi-graisse et le fond pale disent
   ce qu'il est : une reponse, deduite de ce qui est repondu au-dessus. La
   duree d'un mandat est ce qu'on vient verifier en ouvrant ce volet ; elle ne
   doit pas se chercher (demande du 21 aout 2026). */
.aglae-calcul {
  font-weight: 600;
  /* La plaque se tient a la hauteur des cases de sa rangee -- c'est ce qui la
     fait lire comme leur reponse et non comme un bloc pose a cote. Le
     remplissage vertical retombe d'un barreau et la hauteur prend le relais :
     a .4rem, la demi-graisse et sa hauteur de ligne de 21,6 px la portaient a
     34,4, deux pixels et demi au-dessus de ses voisines. Le centrage sert la
     ligne unique ; le plancher laisse la plaque grandir si la phrase passe a
     la ligne. */
  display: inline-flex;
  align-items: center;
  min-height: var(--h-champ);
  padding: var(--espace-2xs) var(--espace-sm);
  background: var(--cyan-light);
  border-radius: var(--radius-sm);
}

/* Le meme champ deduit, sans sa marque. « La case de la mention RCS ne doit
   plus etre en gras. Elle doit etre comme les autres cases, elle ne doit pas
   se distinguer » (demande du 30 aout 2026).

   La marque de `.aglae-calcul` reste ou elle a ete decidee -- sur la duree du
   mandat, qui est ce qu'on vient verifier en ouvrant ce volet. La mention RCS
   ne recopie que deux cases voisines : la mettre en avant au milieu d'elles la
   faisait lire comme une reponse importante alors qu'elle ne dit rien de plus
   qu'elles.

   Reste la hauteur de champ : sans elle, la ligne remonterait au-dessus de
   celles de sa rangee, et « comme les autres cases » veut aussi dire a leur
   hauteur. C'est le seul trait garde de la plaque -- le seul qui ne distingue
   pas. */
.aglae-calcul-discret {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-champ);
}

.aglae-aide {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

/* Ce que le serveur a refuse, sous la case refusee. La forme de l'aide qui la
   precede -- meme corps, meme place --, l'encre en moins : ces deux lignes se
   lisent l'une apres l'autre, et un second dessin les aurait separees. */
.aglae-refus {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--red);
}

.aglae-etat-erreur {
  color: var(--red);
  font-style: normal;
}

/* Les propositions de l'annuaire des entreprises.

   Une ligne par champ, et les trois choses qu'il faut pour trancher en un
   coup d'oeil : quel champ, ce que l'Etat en dit, et ce que le formulaire
   porte deja. La valeur proposee est en demi-graisse, l'existante en gris et
   plus petite -- c'est la proposition qu'on lit, l'existante n'est la que
   pour la contredire. */
.insee-propositions {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  margin-top: var(--espace-sm);
}

.insee-ligne {
  display: grid;
  grid-template-columns: auto 11rem minmax(0, 1fr) minmax(0, 1fr);
  align-items: baseline;
  gap: var(--espace-sm);
  padding: var(--espace-xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.insee-ligne:hover {
  background: var(--gray-1);
}

.insee-libelle {
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

.insee-valeur {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--black);
  overflow-wrap: anywhere;
}

.insee-actuel {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  overflow-wrap: anywhere;
}

.insee-pied {
  margin-top: var(--espace-sm);
}

/* Le compte rendu des registres, en pied du panneau.

   Il repond a une question qu'on se pose une fois et qu'on veut pouvoir se
   reposer : « ou est-ce que ca a cherche ? ». Donc en pied et non en tete --
   ce qu'on est venu chercher, ce sont les cases a cocher --, et en plus petit
   que les propositions, mais toujours present : un compte rendu qu'il faudrait
   deplier ne serait pas lu, et c'est la moitie de la reponse. */
.insee-registres {
  margin-top: var(--espace-md);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-3);
}

.insee-registres-titre {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--gray-4);
}

.insee-registres ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

.insee-registres li {
  display: grid;
  grid-template-columns: 16rem 10rem minmax(0, 1fr);
  align-items: baseline;
  gap: var(--espace-sm);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.insee-registre-nom { font-weight: 600; color: var(--gray-6); }

/* Un registre ferme se lit avant d'etre cherche : c'est lui la reponse a la
   question posee, pas ceux qui ont marche. */
.insee-registres li[data-acces="compte"] .insee-registre-nom { color: var(--gray-4); }
.insee-registre-etat { color: var(--gray-4); }
.insee-registres li[data-etat="repondu"] .insee-registre-etat { color: var(--green); }
.insee-registres li[data-acces="compte"] .insee-registre-etat { color: var(--orange); }
.insee-registre-porte { color: var(--gray-4); }

@media (max-width: 720px) {
  /* Quatre colonnes ne tiennent pas sur un telephone : la ligne se replie,
     case a gauche et les trois textes empiles a droite. */
  .insee-ligne {
    grid-template-columns: auto minmax(0, 1fr);
  }
  .insee-libelle,
  .insee-valeur,
  .insee-actuel {
    grid-column: 2;
  }
  /* Le compte rendu passe en deux lignes : le nom et l'etat sur la premiere,
     ce que le registre porte sous eux. */
  .insee-registres li { grid-template-columns: minmax(0, 1fr) auto; }
  .insee-registre-porte { grid-column: 1 / -1; }
}

/* --- Recherche de tickets ---------------------------------------------------
   Le panneau qui remplace la liste tant qu'une recherche est en cours, sur
   /tickets comme sur /tickets/archives. Voir tickets-recherche.js : les
   resultats ne peuvent pas etre des cartes demasquees, la plupart d'entre eux
   vivant sur l'autre page. */

.recherche-resultats {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
}

.recherche-resultats[hidden] { display: none; }

/* Pendant l'aller-retour, la liste palit sans bouger : elle porte deja le
   classement local, et la faire disparaitre pour la redessiner une demi-
   seconde plus tard ferait clignoter l'ecran a chaque frappe. */
.recherche-resultats-attente .recherche-resultats-liste {
  opacity: .55;
  transition: opacity .15s var(--ease);
}

.recherche-resultats-tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace);
  padding: 0 var(--espace-2xs) var(--espace-2xs);
}

.recherche-resultats-compte {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.recherche-resultats-mode {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  text-align: right;
}

/* Le classement compris se signale, parce qu'il ne se lit pas comme l'autre. */
.recherche-resultats-mode-ia { color: var(--cyan-dark); }

.recherche-resultats-liste {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
}

.recherche-resultat {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace-md);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  color: inherit;
  text-decoration: none;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.recherche-resultat:hover {
  border-color: var(--cyan);
  box-shadow: var(--shadow-sm);
}

.recherche-resultat-corps {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  min-width: 0;
  flex: 1;
}

.recherche-resultat-tete {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  flex-wrap: wrap;
}

.recherche-resultat-tete strong {
  font-size: var(--fs-md);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.recherche-resultat-badge {
  flex-shrink: 0;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: 999px;
  background: var(--gray-2);
  color: var(--gray-5);
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-serre);
}

.recherche-resultat-badge-urgent {
  background: var(--orange-pale);
  color: var(--orange-dark);
}

/* La phrase du modele, teintee : c'est la seule ligne de l'ecran qui n'est pas
   du ticket mais de son classement, et la confondre avec un extrait
   reviendrait a lui preter les mots de l'auteur. */
.recherche-resultat-pourquoi {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--cyan-dark);
}

.recherche-resultat-extrait {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.recherche-resultat-meta {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* La ligne qui coupe les resultats en deux. Le filtre par emetteur n'ecarte
   plus rien de la recherche : il dit ou l'on regarde, pas ce qui existe, donc
   ce qui ne lui repond pas passe dessous au lieu de ne pas etre montre. Un
   titre, un compte, puis un trait qui va jusqu'au bord -- assez pour separer
   deux groupes, pas assez pour peser autant qu'un resultat. */
.recherche-hors-filtre {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  margin: var(--espace-sm) var(--espace-2xs) var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.recherche-hors-filtre::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--gray-3);
}

.recherche-hors-filtre-titre {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
}

.recherche-hors-filtre-compte { color: var(--gray-4); }

/* Arrivee depuis un resultat : la carte se designe le temps qu'on la voie. */
.ticket-card-designee {
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* ---------- L'annexe des comptes annuels ----------

   « Creer un onglet Annexe entre Compte de resultat et Bilan fonctionnel [...]
   Reprends ce modele mais garde le style habituel pour que cela soit
   harmonieux » (demande du 26 aout 2026).

   D'ou ce qui suit : la forme du modele joint -- des sections numerotees en
   chiffres romains, des notes numerotees dessous, des paragraphes et de petits
   tableaux --, mais les jetons de la maison. Le modele encadre chaque cellule
   d'un filet noir ; ici les tableaux sont ceux de l'analyse, un filet clair
   sous chaque ligne, un cadre arrondi et une ombre douce. Un tableau qui ne
   ressemble a aucun autre du produit se remarque avant de se lire. */
.annexe {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xl);
  max-width: 62rem;
}

.annexe-entete {
  display: flex;
  align-items: baseline;
  gap: var(--espace);
}

.annexe-titre {
  font-size: var(--fs-xl);
  font-weight: 700;
  margin: 0;
  color: var(--gray-6);
}

.annexe-exercice {
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

.annexe-section {
  display: flex;
  flex-direction: column;
  gap: var(--espace-lg);
}

/* Le titre d'une section romaine. Bleu comme dans le modele -- c'est la seule
   couleur qu'il porte --, mais le bleu de la maison. */
.annexe-section-titre {
  font-size: var(--fs-lg);
  font-weight: 700;
  margin: 0;
  color: var(--cyan-dark);
}

.annexe-note {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* Un bloc qui prolonge la note du dessus -- les dotations et reprises par
   nature, les lignes « dont » des reprises -- n'a ni numero ni titre : le
   modele le pose sous le tableau de la note, pas a cote d'elle. Il se rapproche
   donc de ce qu'il prolonge, au lieu de flotter a la distance qui separe deux
   notes (.annexe-section, gap 1.25rem). */
.annexe-note-suite {
  margin-top: -.75rem;
}

.annexe-note-titre {
  font-size: var(--fs);
  font-weight: 600;
  margin: 0;
  color: var(--gray-6);
}

.annexe-paragraphe {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--gray-6);
  /* Le modele justifie ses paragraphes de doctrine ; on les aligne a gauche,
     comme tout le texte du produit : le justifie creuse des rivieres blanches
     dans une colonne etroite. */
  max-width: 55rem;
}

/* Une rubrique de l'annexe qui se renseigne a la main : l'objet social, les
   faits caracteristiques (demandes du 27 aout 2026). Elle se tient dans la
   colonne de lecture, a la largeur des paragraphes qu'elle prolonge, et
   s'enregistre quand on la quitte -- l'etat le dit a cote. */
.annexe-saisie {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  max-width: 55rem;
  margin-top: var(--espace-xs);
}

.annexe-saisie-champ {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  padding: var(--espace-sm) var(--espace);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--gray-6);
  resize: vertical;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.annexe-saisie-champ:hover { background: var(--gray-2); }

.annexe-saisie-champ:focus {
  outline: none;
  background: #fff;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Une case de tableau qu'on remplit soi-meme : les deux lignes « dont » des
   reprises sur provisions, « Dont remboursements aux tiers financeurs »
   (demandes du 27 aout 2026). Elle se lit comme les cases voisines -- meme
   police, meme alignement a droite --, et elle se voit sans qu'on la cherche :
   « toutes les cases a remplir doivent apparaitre plus distinctement et pas
   seulement quand on clique dessus » (demande du 27 aout 2026).

   Elle etait transparente au repos et n'apparaissait qu'au survol : une case
   vide dans un tableau ou la moitie des cases sont vides ne disait pas qu'elle
   attendait quelqu'un, et personne ne survole un tableau case par case pour le
   decouvrir. Elle porte donc un fond et un filet en permanence -- assez pour se
   distinguer d'une case calculee, pas assez pour faire de ces lignes-la un
   formulaire au milieu d'un document. Le survol et le clavier montent d'un
   cran a partir de la. */
.annexe-cellule-champ {
  width: 100%;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  padding: var(--espace-3xs) var(--espace-2xs);
  font-family: inherit;
  font-size: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--gray-6);
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.annexe-cellule-champ:hover {
  background: var(--gray-2);
  border-color: var(--gray-4);
}

.annexe-cellule-champ:focus {
  outline: none;
  background: #fff;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.annexe-cellule-champ.en-cours { color: var(--gray-4); }

.annexe-saisie-etat {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  flex: none;
  min-width: 6rem;
}

/* Le groupe d'un mandat : la pastille posee a cote du nom sur la liste des
   clients, et le bandeau de la vue d'un groupe (ticket du 28 aout 2026).

   Discrete par construction : deux cent quatre-vingts lignes sur trois cents
   n'en portent aucune, et une marque voyante sur les vingt autres se lirait
   comme une alerte plutot que comme un rangement. */
.dossier-groupe-chip {
  flex: none;
  padding: var(--espace-3xs) var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 12rem;
}

/* Le bandeau qui coiffe la liste bornee a un groupe. Il dit sur quoi elle est
   bornee, ce que le groupe porte de commun, et par ou on en sort -- sans quoi
   une liste de quatre clients au milieu de trois cents se lit comme un filtre
   oublie.

   C'est une zone de la page a part entiere, donc une tuile depuis le 30 aout
   2026, et il ne lui reste ici que sa mise en colonne. Il ecrivait le cadre de
   la tuile a la main -- meme gris, meme rayon --, plus un fond `--gray-1` et un
   creux d'un cran plus serre : trois facons de differer de ses voisines sans
   qu'aucune ne dise pourquoi. Il etait aussi range entre la rangee de tri et la
   premiere ligne de la liste, c'est-a-dire dans le tableau qu'il annonce ; il
   se lit maintenant avant lui. */
.dossier-groupe-bandeau {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
}

.dossier-groupe-bandeau-titre {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  color: var(--gray-6);
}

.dossier-groupe-bandeau-titre .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--cyan-dark);
}

.dossier-groupe-compte {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.dossier-groupe-notes {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
  white-space: pre-wrap;
}

/* Les sorties du bandeau : l'ecran du groupe, et le portefeuille entier. Elles
   se tiennent au debut de la ligne plutot que de s'etirer sur toute sa largeur
   -- une colonne `flex` etire ses enfants par defaut, et deux liens etires
   auraient donne deux zones cliquables larges de mille pixels. */
.dossier-groupe-bandeau > .btn-link,
.dossier-groupe-bandeau > .reglages-row { align-self: flex-start; }

/* La note commune d'un groupe, sous son selecteur dans l'onglet Mandat.

   Elle porte `.reglages-input-grow` comme la liste posee juste au-dessus,
   mais elle est ecrite en dehors de la `.reglages-row` -- soeur de la rangee,
   pas fille --, et la regle de la classe demande cette ancetre : la note ne
   recevait donc aucune de ses trois lignes. Mesure au navigateur le 29 aout
   2026 : 177,2 px de large sous une liste de 736, la largeur que le
   navigateur donne a un `textarea` sans `cols`. Le plafond de lecture se
   redit donc ici. Pas le plancher de 320 px : il n'a de sens que dans une
   rangee ou d'autres blocs se partagent la place.

   Le reste s'aligne sur `textarea.aglae-input`, l'autre zone de texte du meme
   panneau -- meme corps, meme creux et meme arrondi que les cases qui
   l'entourent. La note etait la seule case du panneau a --radius-xs, quatre
   pixels au milieu de sept. */
.reglages-groupe-notes {
  width: 100%;
  max-width: var(--largeur-lecture);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--espace-sm);
  font: inherit;
  font-size: var(--fs-md);
  color: var(--gray-6);
  resize: vertical;
  line-height: 1.45;
}

.reglages-groupe-notes:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* La pastille reduite a sa marque (ticket du 29 aout 2026) : « le logo du
   groupe est uniquement le logo [...] et tu ajustes la pastille a la taille du
   logo ». La boite n'a plus de nom a border : elle epouse l'image, et rien
   d'autre.

   Sur la liste des clients et nulle part ailleurs. Le nom y est revenu a cote
   de la marque le 30 aout 2026, en meme temps que partout ou un groupe se
   nomme, puis en est reparti le meme jour : « dans "clients" et uniquement
   dans "clients" [...] tu ne mets que le logo du groupe ». C'est la seule
   surface ou la marque se repete sur des centaines de lignes.

   `inline-flex`, contrairement a la pastille qui porte un nom : il n'y a plus
   de texte a couper aux points de suspension, donc plus de raison de rester en
   ligne -- et c'est ce qui fait que la boite tient exactement la hauteur de
   l'image, la ou une image `inline-block` trainerait sous elle l'espace du
   jambage. La largeur maximale part avec le nom, pour la meme raison : ce qui
   la borne desormais est celle du logo, juste en dessous.

   Ni fond ni filet, depuis le meme jour : « j'ai l'impression que le fond
   n'est pas blanc, mais il est gris [...] on pense que c'est pas detoure ».
   Le gris etait celui de la pastille, pas celui de l'image -- mais une fois la
   boite reduite a epouser la marque, plus rien ne les distingue : un aplat
   gris aux dimensions exactes du logo se lit comme le fond du logo. Une
   pastille qui porte un nom reste une boite, parce qu'un mot a besoin d'etre
   borde ; une marque detouree se pose a nu, comme elle le fait deja en tete du
   bandeau de groupe. Le filet garde sa place en transparent : l'enlever
   decalerait la ligne d'un pixel selon que le groupe a une marque ou un nom. */
.dossier-groupe-chip-marque {
  display: inline-flex;
  align-items: center;
  padding: var(--espace-3xs) var(--espace-2xs);
  max-width: none;
  border-color: transparent;
  background: none;
}

/* L'icone du groupe (ticket du 29 aout 2026) : « on doit pouvoir associer une
   icone a un groupe [...] apres avoir bien rogne pour que le logo soit le plus
   clair dans la pastille ».

   La pastille est etroite, et c'est la hauteur qui s'y tient -- meme arbitrage
   que le logo des carres d'etats financiers (.type-seg-logo) : ramener une
   bulle de 72 sur 26 a la largeur d'une icone la reduirait a une trainee. Une
   largeur bornee tout de meme, pour qu'une marque tres allongee ne pousse pas
   l'exercice hors de la ligne.

   A --icon-sm et non plus --icon-xs depuis que le nom a quitte la pastille :
   la marque y etait un indice a cote du mot qui identifiait, elle est
   maintenant ce qui identifie, et douze pixels de haut ne se lisent pas seuls.
   Un barreau, pas deux -- la ligne d'un client n'est pas une enseigne. */
.dossier-groupe-chip-logo {
  display: block;
  height: var(--icon-sm);
  width: auto;
  max-width: 4.5rem;
  object-fit: contain;
}

/* La meme marque en tete du bandeau, a la place du pictogramme : elle y prend
   la taille de l'icone qu'elle remplace, pas davantage -- le bandeau annonce
   une liste, il n'est pas une enseigne. */
.dossier-groupe-bandeau-logo {
  flex: none;
  height: var(--icon-md);
  width: auto;
  max-width: 6rem;
  object-fit: contain;
}

/* La marque du groupe devant son nom, en tete de son ecran, et devant le
   selecteur de l'onglet Mandat (ticket du 30 aout 2026) : « s'il y a un logo
   pour le groupe, mais logo devant le nom du groupe, ce sera plus visuel ».

   Deux barreaux differents parce que les deux titres le sont : le nom d'un
   ecran est ecrit en --fs-xl, une rangee de reglage en --fs-md. La marque
   prend a chaque fois la taille de l'icone qui l'entoure, jamais davantage --
   ni l'en-tete d'une page ni une ligne de reglage n'est une enseigne. */
.groupe-titre-marque {
  flex: none;
  height: var(--icon-lg);
  width: auto;
  max-width: 7rem;
  object-fit: contain;
}

.reglages-groupe-marque {
  flex: none;
  height: var(--icon-md);
  width: auto;
  max-width: 6rem;
  object-fit: contain;
}

/* Ce que la pastille montrera, en grand : un cadre de taille fixe, rendu meme
   vide, pour que la rangee ne se decale pas quand l'icone arrive ou part.

   Sur un damier, et non plus sur l'aplat gris de la pastille (ticket du 29
   aout 2026 : « j'ai l'impression que le fond n'est pas blanc, mais il est
   gris [...] on pense que c'est pas detoure »). Le cadre etait gris pour une
   raison juste -- une marque au fond blanc doit se voir ici, ce que le blanc
   du cadre voisin, celui du logo du client, ne montre pas --, mais un aplat
   repond mal : le gris qu'on voit au travers d'une marque bien detouree et le
   gris d'une marque qui a garde son fond se ressemblent trait pour trait. Le
   damier, lui, ne se confond avec le fond d'aucune image : il apparait en
   entier sous une marque detouree, et un fond -- blanc, gris ou colore -- le
   masque d'un rectangle net des qu'il en reste un. Le cadre repond ainsi tout
   seul a la question qu'on lui posait, et le bouton « Detourer le fond » se
   juge a ce qu'il fait au damier.

   La marge a droite separe ce qu'on regarde de ce sur quoi on clique -- sans
   elle, l'apercu se lit comme un troisieme bouton. */
.reglages-groupe-apercu {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 5.5rem;
  height: var(--h-sm);
  margin-right: var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  /* Le blanc du cadre du logo client, damie du gris le plus clair qui se voie
     sur lui. Le carreau prend un barreau de l'echelle d'espacement plutot
     qu'une taille a lui : a 4,8 px de cote il reste un fond, pas un motif. */
  background-color: #fff;
  background-image: conic-gradient(var(--gray-2) 25%, transparent 0 50%,
                                   var(--gray-2) 0 75%, transparent 0);
  background-size: var(--espace-sm) var(--espace-sm);
  overflow: hidden;
}

.reglages-groupe-apercu img {
  max-width: calc(100% - var(--espace-xs));
  max-height: calc(100% - var(--espace-2xs));
  object-fit: contain;
}

.reglages-groupe-apercu-vide {
  font-size: var(--fs-3xs);
  color: var(--gray-4);
}

/* Les structures du groupe, listees sous le reste (ticket du 29 aout 2026).

   Bornee en hauteur et non deployee : soixante-cinq mandats OCCE pousseraient
   tout le reste de l'onglet Mandat hors de l'ecran. La liste defile chez elle,
   comme le fait deja le detail des exercices. */
.reglages-groupe-membres { max-width: 34rem; }

/* Le lien qui mene a la liste des clients touchait le cadre des structures :
   deux boites bordees se rejoignaient sur un meme trait, sans un pixel entre
   elles. Une `.reglages-row` n'a pas de marge verticale, et les six autres de
   cet ecran tiennent la leur du titre de leur tuile ; celle-ci suit un contenu,
   elle n'avait donc rien. Meme defaut et meme barreau que sur Mon compte
   (`.compte-groupe > .reglages-row`, raison ecrite la-bas) : le geste appartient
   a la liste, il se pose sous elle sans prendre le cran qui separe deux tuiles.
   Mesure : 0 px avant, 9.6 apres, a 1512 comme a 390. */
.reglages-groupe-membres + .reglages-row { margin-top: var(--espace-sm); }

.reglages-groupe-membres-titre {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
}

.reglages-groupe-membres-liste {
  margin: 0;
  padding: var(--espace-2xs) 0;
  list-style: none;
  max-height: 11rem;
  overflow-y: auto;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background-color: var(--gray-1);
}

/* Sur l'ecran du groupe, la liste est ce qu'on est venu voir : elle a droit a
   plus de la moitie de la hauteur utile, la ou elle n'avait que onze rangs
   sous un selecteur (ticket du 30 aout 2026). Bornee tout de meme -- soixante-
   cinq mandats OCCE feraient une page de deux ecrans dont la moitie est une
   liste --, et le defilement reste chez elle. */
#groupe-ecran .reglages-groupe-membres-liste {
  max-height: 24rem;
}

.reglages-groupe-membres-liste li {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  padding: var(--espace-xs) var(--espace-2xs) var(--espace-xs) var(--espace-sm);
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

/* Un filet entre deux structures, et le meme creux qu'ailleurs : cette liste
   et celle de la ronde de nommage (`.ronde-liste`, plus bas) sont la meme
   chose -- un cadre --gray-3 sur fond --gray-1, borne en hauteur, qui defile,
   en --fs-sm sur --gray-6 --, et l'une separait ses rangees quand l'autre les
   collait, a 2,4 px de creux contre 6,4. Quarante-quatre noms colles les uns
   aux autres se lisent comme un paragraphe, pas comme une liste ou l'on vient
   reperer l'intrus a retirer. */
.reglages-groupe-membres-liste li + li {
  border-top: 1px solid var(--gray-3);
}

/* Le nom prend la place, la croix reste au bout : c'est lui qu'on coupe quand
   la ligne est trop longue, jamais le geste. */
.reglages-groupe-membre-nom {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reglages-groupe-membres-liste a {
  color: var(--gray-6);
  text-decoration: none;
}

.reglages-groupe-membres-liste a:hover {
  color: var(--cyan-dark);
  text-decoration: underline;
}

/* Celui qu'on regarde : reconnaissable sans etre un lien vers soi-meme. */
.reglages-groupe-membre-ici {
  color: var(--gray-4);
  font-style: italic;
}

/* Retirer une structure du groupe, sur sa propre ligne (ticket du 29 aout
   2026) : « si on a mis une societe dans un groupe a tort, on doit pouvoir
   retirer cette societe du groupe ».

   Grise au repos et rouge au survol, comme les corbeilles de la feuille :
   quarante-quatre croix rouges alignees se liraient comme quarante-quatre
   alertes, alors qu'aucune ligne n'a rien de fautif tant qu'on ne l'a pas dit.
   Grise et non effacee -- un geste qui n'apparait qu'au survol n'existe pas
   pour qui lit la page sans promener sa souris, ni sur un ecran tactile. */
.reglages-groupe-membre-retirer {
  flex: none;
  width: var(--icon-md);
  height: var(--icon-md);
  padding: 0;
  border: none;
  border-radius: var(--radius-xs);
  background-color: transparent;
  color: var(--gray-4);
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
  transition: color .15s var(--ease), background-color .15s var(--ease);
}

.reglages-groupe-membre-retirer:hover {
  background-color: var(--red-pale);
  color: var(--red);
}

/* La tete du groupe, signalee dans sa propre liste (ticket du 29 aout 2026) :
   la designer et ne pas la reconnaitre ensuite laisserait a rouvrir le
   selecteur pour savoir laquelle c'est. */
.reglages-groupe-membre-mere {
  margin-left: var(--espace-2xs);
  padding: var(--espace-3xs) var(--espace-2xs);
  border-radius: var(--radius-xs);
  background-color: var(--cyan-pale);
  color: var(--cyan-dark);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* Les documents attendus du client, sous les deux organes de « Nature du
   mandat » (ticket du 10 septembre 2026).

   Le meme cadre que la liste des structures d'un groupe juste au-dessus, et
   pour la meme raison : c'est la meme chose -- une liste bornee, qui defile
   chez elle, ou l'on vient cocher ou retirer une ligne. Deux cadres dessines
   separement dans le meme panneau auraient diverge, et le lecteur aurait vu
   l'ecart avant de lire le texte.

   L'ordre de la rangee est celui qu'on lit : l'intitule d'abord, la mention
   « Bloquant » ensuite, la corbeille au bout. La case a ouvert la ligne
   jusqu'au 10 septembre 2026, au motif qu'une colonne de cases se parcourt du
   regard ; elle se parcourt aussi bien au bout, `flex: none` la tenant droite,
   et ce qui ne se reparait pas etait de lire dix-huit fois le mot BLOQUANT
   avant d'arriver a ce que la ligne nomme. On lit une liste de documents. */
.documents-attendus-liste {
  margin: 0;
  padding: var(--espace-2xs) 0;
  list-style: none;
  max-height: 16rem;
  overflow-y: auto;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background-color: var(--gray-1);
}

.documents-attendus-liste li {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  padding: var(--espace-xs) var(--espace-2xs) var(--espace-xs) var(--espace-sm);
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.documents-attendus-liste li + li {
  border-top: 1px solid var(--gray-3);
}

/* LA MENTION APRES LE NOM, ET DISCRETE TANT QU'ELLE NE DIT RIEN.

   « Il serait preferable que le nom du document attendu apparaisse avant la
   mention "Bloquant". Cette derniere pourrait etre rendue plus discrete tout
   en continuant a attirer l'attention » (suivi du 10 septembre 2026).

   Decochee, elle est grise et minuscule : elle propose un geste, elle
   n'annonce rien. Cochee, elle devient une gelule rouge, et c'est la qu'elle
   attire l'oeil -- la ligne dit alors qu'une piece manquante arrete l'emission
   de nos rapports, et c'est le rouge du produit qui dit cela partout ailleurs.
   Dix-huit mentions grises laissent voir les deux rouges ; dix-huit capitales
   rouges n'auraient rien laisse voir du tout.

   La case et son mot ne se separent jamais : c'est une etiquette, on coche en
   cliquant l'un ou l'autre. `flex: none` et une largeur fixe tiennent la
   colonne droite quand les intitules changent de longueur. */
.documents-attendus-bloquant {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-3xs);
  padding: var(--espace-3xs) var(--espace-2xs);
  border-radius: var(--radius-xs);
  color: var(--gray-4);
  font-size: var(--fs-2xs);
  cursor: pointer;
  user-select: none;
}

.documents-attendus-bloquant:hover { color: var(--gray-5); }

.documents-attendus-bloquant:has(input:checked) {
  background-color: var(--red-pale);
  color: var(--red);
  font-weight: 600;
}

.documents-attendus-bloquant input {
  accent-color: var(--red);
  margin: 0;
}

/* L'intitule prend la place, la croix reste au bout : c'est lui qu'on coupe
   quand la ligne est trop longue, jamais le geste. La situation de l'actif
   realisable et disponible tient en dix-sept mots, et c'est le plus long des
   dix-huit. */
.documents-attendus-nom {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* La corbeille du produit, celle du cabinet et de la visionneuse
   (`btn-link btn-danger btn-icon-only` sur `#icon-trash`) : « l'action
   permettant de retirer un document pourrait reprendre l'icone de poubelle
   rouge deja utilisee ailleurs sur le site » (suivi du 10 septembre 2026). La
   croix qui tenait cette place n'etait dessinee que la. Il ne reste donc ici
   que ce que la rangee lui demande : ne pas se retrecir, et ne pas ecarter les
   deux lignes voisines. */
.documents-attendus-retirer {
  flex: none;
  padding: var(--espace-3xs);
  line-height: 1;
}

/* Ce que disait la gelule « proposés » posee a cote du titre jusqu'au
   10 septembre 2026 (« la mention "Proposé" ne semble pas apporter
   d'information utile »), ecrit en clair sous la liste. La chose reste vraie
   et vaut d'etre dite -- une liste deduite et une liste arbitree n'ont pas le
   meme poids --, mais c'est une phrase et non une etiquette : on la lit une
   fois, on comprend l'etat de la rubrique, et le premier geste l'emporte. */
.documents-attendus-propose { margin-top: var(--espace-2xs); }

/* La rangee du retour sonore, dans Mon compte. Le verdict du test tient en
   trois lignes -- il nomme les endroits ou le son peut se perdre --, et sans
   cette regle c'est le bouton qui se pliait en deux pour lui faire place :
   « Tester / le son » sur deux lignes a cote d'une phrase qui en occupe deux.
   Le bouton garde sa largeur, la phrase prend le reste et se replie. */
.retour-sonore-ligne { align-items: flex-start; }
.retour-sonore-ligne > button { flex: none; white-space: nowrap; }
.retour-sonore-ligne > .reglages-hint-inline { flex: 1 1 auto; }

/* Et dans le bandeau du groupe, sur sa propre ligne : c'est un renseignement
   sur le groupe, au meme titre que sa note commune. */
.dossier-groupe-mere {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

.dossier-groupe-mere-libelle {
  margin-right: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.dossier-groupe-mere a { color: var(--cyan-dark); text-decoration: none; }
.dossier-groupe-mere a:hover { text-decoration: underline; }

/* Une ligne qu'on a ouverte soi-meme dans un tableau de l'annexe : son
   intitule s'ecrit, et la corbeille la retire (tickets du 28 aout 2026, fonds
   dedies et acquisitions). La corbeille se tient au bout du champ et non a
   cote du tableau : c'est la ligne qu'on retire, et le geste doit tomber sur
   elle. */
.annexe-ligne-ajoutee {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

/* Le meme champ que les cases de montants, aligne a gauche : c'est du texte.
   Il prend toute la premiere colonne, qui est deja la plus large du tableau. */
.annexe-ligne-libelle {
  flex: 1 1 auto;
  min-width: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  padding: var(--espace-3xs) var(--espace-2xs);
  font-family: inherit;
  font-size: inherit;
  color: var(--gray-6);
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.annexe-ligne-libelle:hover {
  background: var(--gray-2);
  border-color: var(--gray-4);
}

.annexe-ligne-libelle:focus {
  outline: none;
  background: #fff;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* UNE CORBEILLE EST ROUGE, PARTOUT.

   Elle etait eteinte au repos ici, et le commentaire de cette regle disait que
   c'etait « le meme accord que les autres corbeilles du produit ». Ce n'etait
   vrai que d'une moitie d'entre elles : les quinze boutons `btn-danger` du
   produit -- le logo d'un client, un projet de lettre de mission, une piece du
   dossier permanent -- sont rouges des le repos, et trois seulement etaient
   grises. Deux familles, deux raisons ecrites, et rien qui les tienne
   ensemble : c'est ainsi qu'une charte se defait.

   « Verifie egalement l'ensemble du site pour reperer les autres boutons de
   suppression qui ne suivent pas cette logique et harmonise-les si necessaire »
   (ticket du 6 septembre 2026). Les trois grises passent donc au rouge, et le
   survol descend d'un barreau (--red-dark) : il reste quelque chose a voir
   quand on vise, sans que la couleur ait a dire deux choses.

   Ce que l'ancienne regle voulait proteger -- ne pas faire crier une corbeille
   repetee sur chaque ligne -- est tenu autrement, et l'etait deja : ces
   corbeilles-la sont a --icon-sm, la plus petite taille d'icone du produit. */
.annexe-ligne-retirer {
  flex: none;
  display: inline-flex;
  padding: 0;
  border: 0;
  background: none;
  color: var(--red);
  cursor: pointer;
  transition: color .15s var(--ease);
}

.annexe-ligne-retirer:hover,
.annexe-ligne-retirer:focus-visible { color: var(--red-dark); }

.annexe-ligne-retirer .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* Le grand livre d'une ligne dont l'intitule est devenu un champ : le texte
   bleu qui l'ouvrait n'est plus la, le bouton rend le geste (suivi du 31 aout
   2026). Meme dessin que la corbeille voisine -- eteint au repos, teinte a la
   visee -- et le bleu des comptes, celui de `.row-account`. */
.annexe-ligne-compte {
  flex: none;
  display: inline-flex;
  padding: 0;
  border: 0;
  background: none;
  color: var(--gray-4);
  cursor: pointer;
  transition: color .15s var(--ease);
}

.annexe-ligne-compte:hover,
.annexe-ligne-compte:focus-visible { color: var(--blue); }

.annexe-ligne-compte .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* « + Ajouter une ligne », sous le tableau qui l'accepte. Discret : c'est une
   porte, pas une action qu'on cherche a chaque ouverture du document. */
.annexe-ajout-ligne {
  align-self: flex-start;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-xs);
  color: var(--cyan-dark);
  cursor: pointer;
}

.annexe-ajout-ligne:hover:not(:disabled) { text-decoration: underline; }
.annexe-ajout-ligne:disabled { color: var(--gray-4); cursor: default; }

.annexe-note-de-bas {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* L'aide qui dit comment se servir d'un tableau de l'annexe -- « proposee
   d'apres l'intitule des comptes et modifiable case par case ». Elle se lit a
   l'ecran et nulle part ailleurs : « peut rester a l'ecran si necessaire, mais
   ne doit jamais apparaitre a l'impression/PDF » (ticket du 8 septembre 2026).
   Les exports ne la connaissent pas, et l'impression du navigateur la retire.

   En italique et non dans le gris des notes de bas : ce qui n'est pas dans le
   document ne doit pas ressembler a ce qui y est. */
.annexe-aide-ecran {
  margin: 0;
  font-size: var(--fs-xs);
  font-style: italic;
  color: var(--gray-4);
}

@media print {
  .annexe-aide-ecran { display: none !important; }
}

/* ---------- L'annexe a l'ecran : l'apercu de sa page imprimee ----------

   « Dans l'annexe, l'affichage doit etre le plus proche possible du rendu
   final en PDF, selon le principe WYSIWYG. La largeur des contenus, les
   alignements, la justification du texte, les tableaux et les espacements
   doivent correspondre a la mise en page du PDF, meme si l'apercu doit etre
   legerement reduit pour tenir dans l'ecran. » (ticket du 6 septembre 2026)

   CE QUI CHANGE N'EST PAS UN STYLE, C'EST UN STATUT. L'annexe se presentait
   comme les autres vues de l'onglet Analyse : une colonne souple de 62 rem,
   des tableaux encadres et ombres, des en-tetes gris en petites capitales.
   C'etait juste tant qu'on la lisait a l'ecran et qu'on l'imprimait ailleurs ;
   ca ne l'est plus, parce que ce qu'on relit ici est ce qu'on va signer. Une
   phrase qui tient sur trois lignes a l'ecran et sur quatre au PDF se relit
   deux fois.

   La page est donc dessinee : une feuille A4 de 210 mm, ses marges de 10 et
   12, le texte a 8,5 points et justifie comme le `multi_cell` de fpdf,
   les tableaux a 8 points, une rangee de 5 mm, les trois fonds de
   `export_pdf` -- l'intitule de section, l'en-tete d'un tableau, le total.
   Chaque valeur a son jeton dans `:root`, en face de la constante Python d'ou
   elle vient.

   Ce qui n'est PAS repris, et volontairement : les champs de saisie gardent
   leur cadre et leur fond. Ils ne s'impriment pas -- ce qui s'imprime est leur
   contenu --, et une zone de texte sans bord dans une page justifiee ne se
   trouve plus. La feuille montre ce qui sortira ; elle ne cache pas ce sur
   quoi on travaille.

   Seul le vrai document prend cette classe : `.annexe` sert aussi de gabarit
   au CRF et aux outils, qui restent des ecrans de travail. */
.annexe-apercu-cadre {
  /* Sous les 210 mm de la feuille, l'apercu glisse plutot que de deborder.
     Le repli des ecrans etroits est plus bas, en `zoom`. */
  overflow-x: auto;
  padding-bottom: var(--espace-sm);
}

.annexe.annexe-apercu {
  box-sizing: border-box;
  width: var(--annexe-page);
  max-width: none;
  /* Centree dans ce qui reste de place : une feuille posee a gauche d'un grand
     ecran vide se lit comme un bloc de la page, pas comme une page. */
  margin: 0 auto;
  padding: var(--annexe-marge-v) var(--annexe-marge-h);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  /* Les espacements viennent du PDF, pas du flux : chaque bloc pose le sien,
     comme un `pdf.ln()` pose le sien. */
  gap: 0;
  font-size: var(--annexe-fs-texte);
  color: var(--black);
}

/* L'en-tete de l'apercu -- le titre « Annexe », l'exercice, le bouton de
   remise a zero -- n'est pas dans le document : c'est la barre de l'ecran. Elle
   garde donc ses mesures a elle, et se separe de la page par une regle. */
.annexe.annexe-apercu > .annexe-entete {
  padding-bottom: var(--espace-sm);
  margin-bottom: var(--espace-md);
  border-bottom: 1px solid var(--gray-2);
}

.annexe-apercu .annexe-section {
  gap: 0;
  margin-top: 3mm;  /* pdf.ln(3) devant un titre de section */
}

/* Ce qu'on n'a pas su preremplir, et ce qui manque pour le faire.

   « Si une information necessaire ne peut pas etre retrouvee, indique
   clairement ce qui manque » (ticket du 6 septembre 2026). C'est une liste de
   courses posee en tete du document : avant de lire, on sait ce qu'il reste a
   aller chercher.

   Elle ne s'imprime pas -- elle n'est pas dans l'annexe, elle est sur le
   chemin qui y mene --, donc elle garde les mesures de l'ecran et non celles
   de la page. En orange et non en rouge : rien n'est faux, il manque des
   pieces. */
.annexe-manques {
  margin-bottom: var(--espace-md);
  padding: var(--espace-sm) var(--espace);
  background: var(--orange-pale);
  border-radius: var(--radius-sm);
}

.annexe-manques-titre {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--orange-dark);
}

.annexe-manques-liste {
  margin: 0;
  padding-left: var(--espace-lg);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--gray-6);
}

/* La bande d'un titre de section : pleine largeur, fond d'intitule, 7 mm de
   haut. Le PDF la remplit (`teintes["rubrique"]`), l'ecran ne la posait pas et
   le document commencait chaque partie par une ligne bleue en l'air. */
.annexe-apercu .annexe-section-titre {
  font-size: var(--annexe-fs-section);
  font-weight: 700;
  color: var(--black);
  background: var(--cyan-pale);
  line-height: 7mm;
  padding: 0 var(--annexe-gouttiere);
  margin-bottom: 1mm;
}

.annexe-apercu .annexe-note {
  gap: 0;
  margin-top: 2mm;  /* pdf.ln(2) devant une note */
}

.annexe-apercu .annexe-note-suite { margin-top: 0; }

.annexe-apercu .annexe-note-titre {
  font-size: var(--annexe-fs-note);
  font-weight: 700;
  line-height: 5mm;
  color: var(--black);
}

/* Le paragraphe du document : justifie, sur toute la largeur utile, a
   l'interligne du PDF. La justification etait refusee ici -- « le justifie
   creuse des rivieres blanches dans une colonne etroite » -- et elle avait
   raison de l'etre tant que la colonne etait etroite. Elle ne l'est plus : la
   colonne fait 190 mm, exactement celle du document imprime, ou la meme
   justification se lit sans riviere. */
.annexe-apercu .annexe-paragraphe {
  font-size: var(--annexe-fs-texte);
  line-height: var(--annexe-ligne);
  text-align: justify;
  max-width: none;
  color: var(--black);
  margin-bottom: .8mm;  /* pdf.ln(0.8) entre deux paragraphes */
}

/* Une rubrique qu'on renseigne : elle prend la largeur de la page et la police
   du document, pour que ce qu'on tape occupe la place qu'il occupera. Le cadre
   du champ reste, lui : voir l'entete de ce bloc.

   « Les zones de saisie [...] doivent avoir la meme largeur que dans le
   document final. Le texte saisi doit etre justifie a gauche et a droite,
   comme dans le PDF » (suivi du 6 septembre 2026). L'etat de l'enregistrement
   se posait a cote du champ, sur la meme ligne, et lui prenait six rem : le
   texte se coupait donc six rem plus tot qu'il ne se coupera. Il passe
   dessous, ou il ne prend la place de rien. */
.annexe-apercu .annexe-saisie {
  max-width: none;
  display: block;
}

.annexe-apercu .annexe-saisie-champ {
  display: block;
  width: 100%;
  font-size: var(--annexe-fs-texte);
  line-height: var(--annexe-ligne);
  /* Justifie des deux cotes, comme le `multi_cell` de fpdf : une phrase qui
     tient sur trois lignes ici doit tenir sur trois lignes la-bas. */
  text-align: justify;
}

.annexe-apercu .annexe-saisie-etat {
  display: block;
  min-width: 0;
  margin-top: var(--espace-3xs);
}

/* Le tableau d'une note : sans cadre ni ombre, ferme par le filet clair que le
   PDF trace sous lui. Les colonnes sont fixes des deux cotes -- deux notes
   rangees a la meme grille doivent tomber l'une sous l'autre. */
.annexe-apercu .annexe-tableau-cadre {
  overflow-x: visible;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  border-bottom: 1px solid var(--gray-3);
}

.annexe-apercu .annexe-tableau { font-size: var(--annexe-fs-tableau); }

/* UNE COLONNE DE TEXTE SE SERRE SUR SON CONTENU, ET SE CENTRE.

   « Reduis au minimum la largeur des cases de la colonne Taux lineaire, ICI
   33 %, et centre leur contenu par rapport au titre de la colonne » (ticket du
   6 septembre 2026). Un taux tient en quatre caracteres ; lui donner la
   largeur d'un montant a six chiffres ouvrait un couloir blanc au milieu du
   tableau, qu'on prend pour une colonne vide avant d'y voir le « 33 % » perdu
   au bout, a droite.

   `width: 1%` avec `white-space: nowrap` est la facon dont une table en
   largeur automatique donne a une colonne juste ce qu'il lui faut : la
   largeur demandee est intenable, le navigateur retombe sur le contenu, et ce
   qui reste va aux autres colonnes. L'export PDF fait le meme calcul
   (`_annexe_largeurs`, les colonnes de texte sortent de la largeur uniforme
   des chiffres), et les deux lectures du tableau se ressemblent. */
.annexe-tableau th.annexe-col-texte,
.annexe-tableau td.annexe-col-texte {
  width: 1%;
  white-space: nowrap;
  text-align: center;
}

.annexe-apercu .annexe-tableau th:first-child,
.annexe-apercu .annexe-tableau td:first-child {
  width: 40%;      /* _ANNEXE_PART_POSTE */
  min-width: 0;    /* les 18 rem d'ecran deborderaient la feuille */
}

/* L'en-tete d'un tableau : le fond de bande du PDF, du gras, et la casse du
   libelle. Les petites capitales grises etaient une convention d'ecran ; elles
   n'existent nulle part dans le document imprime. */
.annexe-apercu .annexe-tableau thead th {
  background: var(--cyan-light);
  color: var(--black);
  font-weight: 700;
  font-size: var(--annexe-fs-tableau);
  text-transform: none;
  letter-spacing: 0;
  white-space: normal;
  padding: 0 var(--annexe-gouttiere);
  line-height: var(--annexe-rangee);
  border-bottom: 0;
}

.annexe-apercu .annexe-tableau-chapeaux th { padding-bottom: 0; }

.annexe-apercu .annexe-tableau td {
  padding: 0 var(--annexe-gouttiere);
  line-height: var(--annexe-rangee);
  border-bottom: 1px solid var(--gray-2);
  color: var(--black);
}

.annexe-apercu .annexe-tableau tr.annexe-total > td {
  background: var(--cyan-total);
  border-top: 0;
  border-bottom: 0;
}

.annexe-apercu .annexe-tableau tr.annexe-compte > td { font-size: var(--annexe-fs-tableau); }

.annexe-apercu .annexe-note-de-bas {
  font-size: var(--annexe-fs-tableau);
  line-height: 4.2mm;
  color: var(--gray-6);
  font-style: italic;
  margin-top: 1mm;
}

/* « Meme si l'apercu doit etre legerement reduit pour tenir dans l'ecran. »

   La feuille ne se retrecit pas : elle se regarde de plus loin. Le `zoom`
   reduit la page entiere d'un coup -- texte, tableaux, marges --, ce qui est
   exactement la difference entre un apercu reduit et une mise en page
   different. Deux crans suffisent : au-dela, l'apercu glisse dans son cadre
   plutot que de devenir illisible. */
@media (max-width: 1240px) {
  .annexe.annexe-apercu { zoom: .88; }
}

@media (max-width: 1080px) {
  .annexe.annexe-apercu { zoom: .78; }
}

/* La boîte d'un cadrage de l'onglet Outils. « Entoure l'ensemble du cadrage et
   laisse le fond gris comme cela est fait dans l'onglet Mandat, pour que cela
   soit plus esthétique » (ticket du 14 septembre 2026).

   Les onze cadrages du réseau OCCE se suivaient à même le fond de la page. Ils
   n'ont pourtant rien de commun : l'un compte des coopérateurs, un autre des
   calendriers, un autre des quinzaines de Livret A. Sans filet entre eux, un
   titre au milieu de deux cents lignes ne fait pas la coupure -- on lisait la
   provision retraite en croyant lire encore les agendas.

   Exactement la recette de `.frise-mandat`, et non une écriture voisine : le
   ticket dit « comme dans l'onglet Mandat », c'est cette boîte-là qu'il
   désigne, et deux recettes pour un seul dessin finissent par diverger d'un
   pixel. Fond gris et non blanc, donc : le blanc est celui d'une tuile, le gris
   celui d'un bloc qu'on encadre.

   La marge du premier et du dernier enfant s'efface : les fabriques de cadrages
   (`.outils-provision`, `.outils-livret-a`, `.outils-impots`,
   `.outils-calendriers`) posent chacune la leur pour s'écarter du cadrage
   précédent, et c'est le `gap` de `.annexe` qui fait ce travail depuis qu'il y
   a des boîtes. Gardée, elle se lirait comme un rembourrage de plus, en haut
   seulement. */
.outils-cadre {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: var(--gray-2);
  padding: var(--espace-md) var(--espace-lg);
  /* Et la boîte ne se laisse pas traverser. Deux cadrages ont un tableau plus
     large que la colonne (`.outils-impots-categorie` en réserve 52 rem, celui
     des salariés 44) ; dans un espace de travail, c'est le panneau qui défile
     de côté et non le tableau (`.app-main-pleine .table-defilante`), donc le
     tableau dépasse, et ce qu'il dépassait jusqu'ici était le vide. Il
     dépasserait maintenant le filet et le fond gris : le cadrage se lirait
     hors de son cadre entre 720 et 912 px de large, la seule bande où cela
     arrive. Le minimum suit donc le contenu -- la boîte s'élargit avec son
     tableau, et le panneau défile comme avant. */
  min-width: fit-content;
}

.outils-cadre > :first-child { margin-top: 0; }
.outils-cadre > :last-child { margin-bottom: 0; }

/* Les trois lignes « Dont » de la ventilation des adhérents, et le contrôle
   qui les suit (suivi du 1er septembre 2026). Un retrait dit qu'elles
   détaillent la ligne du dessus, et le message se lit en rouge parce que
   c'est une erreur de saisie -- pas un avertissement de plus. */
.outils-dont { padding-left: var(--espace-lg); color: var(--gray-5); }

/* Les deux lignes qui confrontent le cadrage au grand livre : le solde des
   comptes 7561 du siege, et l'ecart avec les cotisations cadrees (suivi du
   2 septembre 2026, « crée une ligne en grisé et pas en gras »). Elles portent
   un montant comme les lignes deduites juste au-dessus, mais elles
   n'appartiennent pas au cadrage -- elles le verifient. D'ou le gris et le
   poids ordinaire, la ou un total est noir et gras. */
.outils-rapprochement > td {
  color: var(--gray-5);
  font-weight: 400;
}

/* Le titre d'une rubrique du cadrage, dans le fil du tableau : « présenter ces
   informations dans un formulaire très simple, séparé en deux parties »
   (ticket du 2 septembre 2026, les deux assurances du réseau).

   La cellule ne met plus rien en forme : elle porte un `h2.annexe-titre`,
   comme l'en-tête du haut (suivi du 2 septembre 2026). Ce qui reste ici est
   donc l'air seul -- au-dessus, la distance qui sépare l'en-tête de son
   tableau (le `gap` de .annexe), parce que c'est exactement la coupure que le
   titre doit faire ; en dessous, celle d'une ligne ordinaire, parce que le
   titre appartient aux lignes qui le suivent.

   Et pas de filet sous un titre : le tableau en pose un par ligne, mais une
   rubrique n'est pas une ligne. Souligné, il redeviendrait une rangée
   d'en-tête au lieu du titre qu'on a demandé. */
.outils-rubrique > td {
  padding-top: var(--espace-2xl);
  border-bottom: none;
}

.outils-rubrique:first-child > td { padding-top: 0; }

.outils-erreur {
  padding: var(--espace-2xs) 0;
  color: var(--red);
  font-size: var(--fs-xs);
}

/* Le cadrage des calendriers, seul tableau de l'onglet a cinq colonnes (ticket
   du 2 septembre 2026). Les deux cadrages du dessus posent un nombre par
   ligne ; celui-ci pose des lignes d'achat -- une date, une quantite, un tarif,
   un montant --, d'ou un second tableau plutot que trois cellules vides ajoutees
   a chaque ligne du premier.

   Il reprend `.annexe-tableau` en entier : meme largeur, meme filet, meme
   colonne d'intitules a deux cinquiemes. Ce qui suit n'est donc que ce qui lui
   est propre -- l'ecart qui le detache du tableau qu'il prolonge, et ses
   colonnes de saisie, plus etroites que la colonne d'intitules. */
.outils-calendriers { margin-top: var(--espace-2xl); }

/* La colonne des dates avant les trois colonnes de nombres : une date occupe
   une largeur fixe et connue, la laisser negocier avec le reste ferait bouger
   les colonnes de montants d'une categorie a l'autre. */
.outils-calendriers td:nth-child(2) { width: 11rem; }

/* L'en-tete des colonnes, dans le corps du tableau et non dans un `thead` : il
   ne coiffe que la partie des achats, la ou les cessions n'ont pas de date et
   les ecarts pas de tarif. Un `thead` aurait annonce quatre colonnes pour tout
   le tableau. Le meme dessin que celui d'une note, en revanche, parce qu'il
   dit la meme chose. */
.outils-calendriers-entete > td {
  background: var(--gray-1);
  border-bottom: 1px solid var(--gray-3);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--gray-5);
}

/* Les trois parties du cadrage -- achats, cessions et dons, ecarts --, un cran
   sous son titre. Elles ne sont pas des cadrages a elles seules : les mettre au
   rang de « Cadrage des calendriers » aurait fait six rubriques de meme rang
   dans l'onglet, la ou il y a trois cadrages. */
.outils-sous-rubrique {
  font-size: var(--fs-md);
  font-weight: 600;
  margin: 0;
  color: var(--gray-6);
}

/* Un article du cadrage des agendas dont rien n'est saisi : son titre reste,
   ses quinze lignes vides non. « Masquer les details des categories non
   concernees » (ticket du 3 septembre 2026) -- un formulaire de six articles
   deroulerait quatre-vingt-dix lignes sur un cadrage ou l'on en remplit deux.
   Le titre garde sa place : on doit voir d'avance ce qu'il est possible de
   remplir, et c'est la difference entre replier et cacher. */
.outils-article-replie > td { display: flex; align-items: baseline; gap: var(--espace-sm); }
/* Les rangees d'un article replie. Une classe et non `[hidden]` : sur un `tr`,
   la regle `[hidden] { display: none }` du navigateur perd contre la moindre
   regle qui pose `display`, et la rangee restait visible. */
.outils-ligne-repliee { display: none; }
.outils-article-ouvrir {
  font-size: var(--fs-2xs);
  color: var(--cyan-dark);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}

/* Ce qui empeche de valider le cadrage : un stock final negatif, une cession
   sans prix. En rouge et sur toute la largeur -- ce n'est pas un montant qui
   manque, c'est une saisie qui ne peut pas etre vraie. */
.outils-blocage > td {
  background: var(--red-pale);
  color: var(--red-dark);
  font-size: var(--fs-xs);
}

/* Un montant calcule, a cote des cases qui le font : meme alignement de
   chiffres que partout ailleurs dans le produit. */
.outils-montant { font-variant-numeric: tabular-nums; }

/* La provision retraite. Elle ne se pose pas dans un tableau, elle en aligne
   quatre -- parametres, salaries, totaux, ecriture -- et c'est ce bloc qui les
   tient ensemble sous un seul titre. */
.outils-provision { margin-top: var(--espace-lg); }
/* Onze colonnes de salariés, et LES ONZE TIENNENT DANS LA TUILE.

   « Je souhaite que la ligne total de la provision à la clôture N et total de la
   provision à la clôture N-1, ainsi que la ligne dotation nette ou reprise, et
   la ligne analytique soit mise à la fin de chaque salarié, sur la même ligne
   [...] qu'on ait aussi l'information salarié par salarié » (suivi du
   7 septembre 2026).

   Ces quatre colonnes existaient depuis la 16.80, à leur place exacte, et le
   calcul était juste. Elles étaient simplement HORS DU CADRE : le tableau
   mesurait 1 693 px dans une tuile de 992, et rien ne disait qu'il fallait le
   faire défiler de côté. La lecture s'arrêtait donc au salaire brut mensuel, et
   la provision d'un salarié n'existait que dans le total du bas.

   Ce qui l'élargissait n'était pas le contenu, c'étaient les règles générales de
   `.annexe-tableau`, écrites pour une note à deux ou trois colonnes : la colonne
   des intitulés y prend 18 rem au minimum, et les en-têtes ne se replient pas.
   288 px pour un nom, 174 pour « Provision au 31/08/2026 » écrit d'un seul
   tenant, et il ne restait rien pour les cinq dernières.

   `table-layout: fixed` avec une largeur par colonne : c'est le seul réglage qui
   GARANTIT que le tableau tienne, quel que soit le contenu -- un nom à rallonge
   ne peut plus repousser la provision hors du cadre. Les proportions suivent ce
   qu'on y écrit : quatre chiffres pour une année, deux pour un mois, un nom et
   trois montants pour le reste.

   Le défilement latéral reste, et il n'a pas disparu pour rien : sous 44 rem --
   un téléphone -- onze colonnes ne tiennent d'aucune façon, et c'est le tableau
   qui défile, pas la page. */
.outils-provision-salaries {
  table-layout: fixed;
  width: 100%;
  min-width: 44rem;
}

/* Les en-têtes se replient ici, au lieu d'élargir leur colonne : c'est le même
   arbitrage que `thead th.num` des notes d'annexe, appliqué à un tableau dont
   TOUS les intitulés sont longs et dont aucune valeur ne l'est. */
/* Le nom de la classe est double de `.annexe-tableau` sur les regles qui
   suivent, et ce n'est pas decoratif : les regles generales des notes
   d'annexe portent la meme specificite et sont ecrites plus bas dans la
   feuille, donc elles gagnaient. Doubler la classe passe devant elles sans
   `!important` et sans toucher a ce qu'elles font ailleurs. */
.annexe-tableau.outils-provision-salaries thead th {
  white-space: normal;
  /* Ils se replient entre les mots et JAMAIS au milieu d'un mot : `body` pose
     `overflow-wrap: break-word` pour tout le site, ce qui coupait « ANCIENNETÉ »
     en « ANCIENNET / É » et « ANALYTIQUE » en « ANALYTIQ / UE ». Les colonnes
     ci-dessous sont donc taillees sur leur plus long mot. */
  overflow-wrap: normal;
}

/* Et le rembourrage se resserre : onze colonnes paient onze fois la marge que
   trois colonnes paient trois fois. */
.annexe-tableau.outils-provision-salaries th,
.annexe-tableau.outils-provision-salaries td {
  padding-left: var(--espace-2xs);
  padding-right: var(--espace-2xs);
}

/* La colonne des intitulés d'une note d'annexe prend 18 rem : ici la première
   colonne porte un nom de salarié, pas un intitulé de poste, et ces 18 rem
   étaient à eux seuls le tiers de ce qui débordait. */
.annexe-tableau.outils-provision-salaries th:first-child,
.annexe-tableau.outils-provision-salaries td:first-child { width: 12%; min-width: 0; }

.annexe-tableau.outils-provision-salaries th:nth-child(2) { width: 9%; }
.annexe-tableau.outils-provision-salaries th:nth-child(3) { width: 8%; }
.annexe-tableau.outils-provision-salaries th:nth-child(4) { width: 8%; }
.annexe-tableau.outils-provision-salaries th:nth-child(5) { width: 10%; }
.annexe-tableau.outils-provision-salaries th:nth-child(6) { width: 9%; }
.annexe-tableau.outils-provision-salaries th:nth-child(7) { width: 10%; }
.annexe-tableau.outils-provision-salaries th:nth-child(8) { width: 10%; }
.annexe-tableau.outils-provision-salaries th:nth-child(9) { width: 9%; }
/* La case à cocher « hors CDI » : rien à écrire, juste de quoi la viser. */
.annexe-tableau.outils-provision-salaries th:nth-child(10) { width: 5%; }
.annexe-tableau.outils-provision-salaries th:nth-child(11) { width: 10%; }
.outils-provision-parametres,
.outils-provision-totaux,
.outils-provision-ecriture { margin-top: var(--espace); }
/* Le rapprochement des ecritures proposees avec la balance de cloture du siege
   (ticket du 7 septembre 2026). Le meme air que les tableaux qu'il suit, et
   rien de plus : ses lignes portent deja les deux teintes de l'onglet -- le
   gris de `.outils-rapprochement` pour ce qui verifie, le noir de
   `.annexe-total` pour l'ecart. Il sert les quatre calculs qui produisent une
   ecriture, du site comme du telephone. */
.outils-rapprochement-table { margin-top: var(--espace); }

/* L'impot sur les produits financiers (ticket du 7 septembre 2026). Comme la
   provision retraite et les trois cadrages d'interets courus, ce n'est pas un
   tableau mais une pile : les parametres, quatre categories, les totaux, les
   deux montants qui se lisent seuls, les deux ecritures. Ce bloc les tient
   ensemble sous un seul titre, et l'air entre eux est celui des voisins. */
.outils-impots { margin-top: var(--espace-lg); }
.outils-impots-categorie,
.outils-impots-totaux,
.outils-impots-resultats { margin-top: var(--espace); }
/* Les deux tableaux a six colonnes sont les plus larges du module : quatre
   colonnes de chiffres, un intitule saisissable et deux cases a cocher. Meme
   reglage que le tableau des periodes du Livret A, et pour la meme raison --
   les 18 rem que `.annexe-tableau` reserve a la colonne des intitules
   pousseraient le produit de l'exercice hors du cadre. */
.outils-impots-categorie {
  table-layout: fixed;
  width: 100%;
  min-width: 52rem;
}
.annexe-tableau.outils-impots-categorie th,
.annexe-tableau.outils-impots-categorie td { min-width: 0; }
/* Et les en-tetes se replient, comme ceux des periodes du Livret B et des
   lignes de CAT : « A recevoir a l'ouverture » et « Encaisses sur l'exercice »
   ecrits d'un seul tenant se chevauchaient, parce que `.annexe-tableau thead
   th` les tient en `nowrap` -- un reglage juste pour un tableau a trois
   colonnes, faux pour celui-ci qui en a six et dont quatre portent des phrases. */
.annexe-tableau.outils-impots-categorie thead th { white-space: normal; }
.annexe-tableau.outils-impots-categorie th:first-child { width: 26%; }
.annexe-tableau.outils-impots-categorie th:nth-child(2),
.annexe-tableau.outils-impots-categorie th:nth-child(3),
.annexe-tableau.outils-impots-categorie th:nth-child(4),
.annexe-tableau.outils-impots-categorie th:nth-child(5) { width: 15%; }
.annexe-tableau.outils-impots-categorie th:last-child { width: 14%; }
/* Le tableau des totaux porte les memes quatre en-tetes, sans les cases a
   cocher : il plie donc pour la meme raison. */
.annexe-tableau.outils-impots-totaux thead th { white-space: normal; }
/* Les deux cases a cocher du controle des placements de plus d'un an, cote a
   cote dans leur cellule : la seconde ne parait que sur une ligne cochee, donc
   l'espace ne s'ouvre que quand il y a deux choses a montrer.

   Dans une boite A ELLES et non sur la cellule : un `display: flex` pose sur
   un `td` lui fait perdre sa boite de cellule, et la rangee s'arrete alors
   avant le bord droit du tableau. */
.outils-impots-coches {
  display: flex;
  gap: var(--espace-2xs);
}
/* Les trois rappels du fichier remplace : ils se lisent comme une reserve,
   donc en gris et en petit, mais ils ne se cachent pas. Meme traitement que
   les hypotheses actuarielles non appliquees de la provision retraite. */
.outils-impots-rappels { color: var(--gray-5); }
/* Ce qu'on signale sans bloquer : un salarie hors CDI reste dans les totaux,
   et il faut le voir. Orange et non rouge -- le rouge dit « ceci ne peut pas
   etre vrai », l'orange dit « regardez ceci ». */
.outils-alerte {
  color: var(--orange-dark);
  font-size: var(--fs-xs);
}
/* Les hypotheses que la methode ne prend PAS : elles se lisent comme une
   reserve, donc en gris et en petit, mais elles ne se cachent pas. */
.outils-provision-hypotheses { color: var(--gray-5); }
/* Un blocage hors tableau : la meme couleur que dans les cadrages du dessus,
   posee sur le paragraphe puisqu'il n'y a pas de rangee a teinter. */
p.outils-blocage {
  background: var(--red-pale);
  color: var(--red-dark);
  font-size: var(--fs-xs);
  padding: var(--espace-2xs) var(--espace-sm);
  border-radius: var(--radius-xs);
}

/* LA PRESENTATION FINANCIERE : les comptes en une page (ticket du 7 septembre
   2026). C'est le seul onglet d'Analyse qui ne montre pas un tableau : il
   montre des parts, et une part se lit sur une longueur avant de se lire sur
   un chiffre.

   Rien de neuf dans les echelles : les tuiles reprennent le rayon et l'ombre
   des tuiles du produit, les barres la teinte cyan des elements actifs, et les
   deux couleurs de variation sont celles des etats metier. */
.presentation { display: flex; flex-direction: column; gap: var(--espace-xl); }
.presentation-entete { display: flex; flex-direction: column; gap: var(--espace-2xs); }
.presentation-periode { color: var(--gray-5); font-size: var(--fs-sm); margin: 0; }

/* Les chiffres cles. Une grille qui se replie toute seule : six tuiles sur un
   ecran large, deux sur un telephone, sans point de rupture ecrit a la main. */
.presentation-tuiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--espace);
}
.presentation-tuile {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  padding: var(--espace) var(--espace-md);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.presentation-tuile-libelle {
  color: var(--gray-5);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.presentation-tuile-valeur { font-size: var(--fs-xl); font-weight: 600; }
.presentation-tuile-variation { font-size: var(--fs-xs); }

/* La variation : une fleche, un ecart, un pourcentage. La couleur redit ce que
   la fleche dit deja, elle ne le dit pas a sa place. */
.presentation-delta-hausse { color: var(--green-dark); }
.presentation-delta-baisse { color: var(--red-dark); }
.presentation-delta-stable { color: var(--gray-5); }

.presentation-bloc { display: flex; flex-direction: column; gap: var(--espace-2xs); }
.presentation-bloc-titre { font-size: var(--fs-md); font-weight: 600; margin: 0; }
.presentation-bloc-soustitre {
  color: var(--gray-5);
  font-size: var(--fs-xs);
  margin: 0 0 var(--espace-2xs);
}

/* Une barre par ligne : le nom a gauche, la jauge au milieu, le montant et la
   part a droite. La jauge prend la place qui reste, ce qui rend les longueurs
   comparables d'une ligne a l'autre : c'est tout ce qu'on demande a une barre.

   Sous 40 rem -- un telephone --, les trois colonnes s'empilent : une jauge de
   deux centimetres ne compare plus rien. */
.presentation-barres { list-style: none; margin: 0; padding: 0; }
.presentation-barre {
  display: grid;
  grid-template-columns: minmax(9rem, 18rem) 1fr minmax(9rem, auto);
  align-items: center;
  gap: var(--espace);
  padding: var(--espace-2xs) 0;
  border-bottom: 1px solid var(--gray-2);
}
.presentation-barre-nom { font-size: var(--fs-sm); }
.presentation-barre-jauge {
  display: block;
  height: .6rem;
  background: var(--gray-2);
  border-radius: 999px;
  overflow: hidden;
}
.presentation-barre-remplie {
  display: block;
  height: 100%;
  background: var(--cyan);
  border-radius: 999px;
}
.presentation-barre-chiffres {
  color: var(--gray-6);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.presentation-soldes td:last-child { white-space: nowrap; }
@media (max-width: 40rem) {
  .presentation-barre { grid-template-columns: 1fr; gap: var(--espace-3xs); }
  .presentation-barre-chiffres { text-align: left; }
}

/* Les interets courus du Livret A. Comme la provision retraite, ce n'est pas
   un tableau mais une pile : les bornes, le bareme, un couple saisie/periodes
   par livret, le total, les deux ecritures. Ce bloc les tient ensemble sous un
   seul titre. */
.outils-livret-a { margin-top: var(--espace-lg); }
.outils-livret-parametres,
.outils-livret-taux,
.outils-livret-saisie,
.outils-livret-total,
.outils-livret-ecriture { margin-top: var(--espace); }
/* Le tableau des periodes est le seul du module a etre large : six colonnes,
   dont quatre de chiffres. Meme reglage que celui des salaries, et pour la
   meme raison -- les regles generales de `.annexe-tableau` reservent 18 rem a
   la colonne des intitules, ce qui pousse les interets hors du cadre. Ici la
   premiere colonne porte une date, pas un nom : elle n'a besoin que de sa
   largeur. */
.outils-livret-periodes {
  table-layout: fixed;
  width: 100%;
  min-width: 34rem;
  margin-top: var(--espace-2xs);
}
.annexe-tableau.outils-livret-periodes th,
.annexe-tableau.outils-livret-periodes td { min-width: 0; }
.annexe-tableau.outils-livret-periodes th:first-child,
.annexe-tableau.outils-livret-periodes td:first-child { width: 22%; }
.annexe-tableau.outils-livret-periodes th:nth-child(2) { width: 14%; }
.annexe-tableau.outils-livret-periodes th:nth-child(3) { width: 15%; }
.annexe-tableau.outils-livret-periodes th:nth-child(4) { width: 17%; }
.annexe-tableau.outils-livret-periodes th:nth-child(5) { width: 14%; }
.annexe-tableau.outils-livret-periodes th:nth-child(6) { width: 18%; }
/* La colonne de gauche des deux tableaux de saisie : elle porte des phrases
   entieres (« Mouvement 1 : montant place apres ce mouvement »), et sans cette
   borne elle prendrait toute la largeur au premier libelle un peu long. */
.annexe-tableau.outils-livret-saisie td:nth-child(2),
.annexe-tableau.outils-livret-parametres td:nth-child(2) { width: 14rem; }
/* Les periodes du Livret B se SAISISSENT, la ou celles du Livret A se
   deduisent : quatre des six colonnes portent une case (ticket du 7 septembre
   2026). Une case y prend toute la colonne plutot que sa largeur par defaut,
   sans quoi la date et le taux flotteraient chacun a leur taille dans un
   tableau a colonnes fixes. Le tableau est aussi plus large qu'a cote : six
   colonnes de cases ne tiennent pas dans les 34 rem qui suffisent a six
   colonnes de texte. */
.outils-livret-b .outils-livret-periodes { min-width: 48rem; }
.outils-livret-b .outils-livret-periodes td .annexe-cellule-champ { width: 100%; }
/* Quatre colonnes de cases et deux de chiffres, la ou le Livret A n'a que du
   texte : les largeurs de son tableau y collaient « Nombre de quinzaines » a
   « Montant place ». Les intitules se replient ici comme ceux des montants
   ailleurs -- c'est le titre qui plie, pas la case. */
.outils-livret-b .outils-livret-periodes thead th { white-space: normal; }
.annexe-tableau.outils-livret-b-periodes th:first-child,
.annexe-tableau.outils-livret-b-periodes td:first-child { width: 18%; }
.annexe-tableau.outils-livret-b-periodes th:nth-child(2) { width: 18%; }
.annexe-tableau.outils-livret-b-periodes th:nth-child(3) { width: 12%; }
.annexe-tableau.outils-livret-b-periodes th:nth-child(4) { width: 19%; }
.annexe-tableau.outils-livret-b-periodes th:nth-child(5) { width: 16%; }
.annexe-tableau.outils-livret-b-periodes th:nth-child(6) { width: 17%; }

/* Les Comptes a Terme : le meme tableau, une colonne de plus. Sept en-tetes
   dont cinq portent une case, et une largeur minimale qui suit -- au-dessous,
   le selecteur de date et le montant se marchent dessus. Le cadre defilant
   (`conso-table-large`) prend le relais sur un ecran etroit.

   La reference est la plus large des cinq : « CAT 1 Credit Mutuel 3 ans » tient
   dans une case, un numero de contrat aussi ; les quatre autres portent une
   date, un montant ou un taux, qui ont tous une longueur connue. */
.annexe-tableau.outils-cat-lignes { min-width: 46rem; }
.annexe-tableau.outils-cat-lignes th:first-child,
.annexe-tableau.outils-cat-lignes td:first-child { width: 19%; }
.annexe-tableau.outils-cat-lignes th:nth-child(2) { width: 14%; }
.annexe-tableau.outils-cat-lignes th:nth-child(3) { width: 15%; }
.annexe-tableau.outils-cat-lignes th:nth-child(4) { width: 15%; }
.annexe-tableau.outils-cat-lignes th:nth-child(5) { width: 11%; }
.annexe-tableau.outils-cat-lignes th:nth-child(6) { width: 11%; }
.annexe-tableau.outils-cat-lignes th:nth-child(7) { width: 15%; }
/* Un intitule de colonne qui se replie plutot que de deborder sur son voisin :
   le tableau est a colonnes fixes, et « Intérêts bruts acquis » est plus long
   que sa part. */
.annexe-tableau.outils-cat-lignes th { white-space: normal; }

/* La case qui n'existe pas : le tarif des calendriers donnes. « Dans le
   fichier, leur tarif est vide et non saisissable. » Un tiret et non une case
   grisee -- une case grisee se clique, et on cherche pourquoi elle refuse. */
.outils-sans-saisie { color: var(--gray-4); }

/* Le controle d'un tableau de flux, ecrit au bout de sa ligne : « OK avec le
   bilan », ou l'ecart en toutes lettres (ticket du 1er septembre 2026, « que
   tu materialises ce controle-la »). Une pastille et non une couleur de
   ligne : c'est la ligne du bilan qu'on lit, la marque dit seulement si elle
   tombe. */
.bilan-pcg-controle {
  margin-left: var(--espace-sm);
  padding: 0 var(--espace-xs);
  border-radius: var(--radius-xs);
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  white-space: nowrap;
}

.bilan-pcg-controle-ok {
  background: var(--green-pale);
  color: var(--green-dark);
}

.bilan-pcg-controle-ecart {
  background: var(--orange-pale);
  color: var(--orange-dark);
}

/* « Repris de Dons en nature » : une charge des contributions volontaires qui
   recopie son produit (ticket du 15 septembre 2026). Ni vert ni orange -- ce
   n'est pas un controle qui tombe ou qui ne tombe pas, c'est la provenance
   d'un montant que personne ne tape. En bas de casse, pour la meme raison :
   c'est une phrase, pas une etiquette d'etat. */
.bilan-pcg-controle-repris {
  background: var(--gray-2);
  color: var(--gray-6);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
}

/* Tout effacer et repartir du modele. Rouge parce que c'est ce qu'on demande
   -- « ce bouton doit etre en rouge car on perd toute la saisie » (ticket du
   1er septembre 2026) --, et discret parce qu'il est pose a cote d'un titre :
   un bouton plein a cet endroit se lirait comme l'action de la page, alors
   qu'il en est le dernier recours. Il vire au plein au survol, quand la main
   est deja dessus. */
.annexe-reinitialiser {
  margin-left: auto;
  padding: var(--espace-3xs) var(--espace-sm);
  border: 1px solid var(--red);
  border-radius: var(--radius-sm);
  background: transparent;
  font: inherit;
  font-size: var(--fs-xs);
  color: var(--red);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.annexe-reinitialiser:hover:not(:disabled) {
  background: var(--red);
  color: #fff;
}

.annexe-reinitialiser:disabled { opacity: .5; cursor: default; }

/* L'import d'un export RETKOOP, dans la ligne de titre des CRF : « le bouton
   d'import devrait figurer en haut » (ticket du 2 septembre 2026). Meme
   dessin que le bouton rouge a cote duquel il se tient -- c'est la meme
   rangee --, la couleur du produit plutot que celle du danger. Il pousse la
   paire a droite du titre. */
.crf-importer {
  margin-left: auto;
  padding: var(--espace-3xs) var(--espace-sm);
  border: 1px solid var(--cyan);
  border-radius: var(--radius-sm);
  background: transparent;
  font: inherit;
  font-size: var(--fs-xs);
  color: var(--cyan-dark);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.crf-importer:hover:not(:disabled) {
  background: var(--cyan);
  color: #fff;
}

/* Deux boutons d'import depuis le 2 septembre 2026 -- un par logiciel de saisie
   (RETKOOP, COMPTA COOP WEB). Seul le premier pousse la rangee vers la droite :
   `margin-left: auto` sur les deux les aurait ecartes l'un de l'autre de toute
   la largeur restante, et deux boutons qui font la meme chose se lisent
   ensemble. */
.crf-importer + .crf-importer { margin-left: var(--espace-xs); }

.crf-importer:disabled { opacity: .5; cursor: default; }

/* Les deux boutons de la rangee se tiennent ensemble : c'est le premier qui
   prend la place libre, le second se colle a lui. */
.crf-importer + .annexe-reinitialiser { margin-left: var(--espace-xs); }

/* ---------- Les CRF des cooperatives (reseau OCCE) ----------

   « Les donnees issues des CRF (onglet a creer) » (suivi du 1er septembre
   2026). Le tableur du reseau, tel qu'il est : une ligne par cooperative, une
   vingtaine de colonnes, un cumul en bas.

   Une grille qui deborde de la page, donc, et c'est le seul endroit du produit
   qui defile horizontalement. Ce qui la rend lisible malgre cela : la colonne
   des noms reste collee a gauche -- sans elle, on ne sait plus quelle
   cooperative on remplit des la troisieme colonne. */
/* La feuille prend toute la largeur : `.annexe` s'arrete a 62 rem, ce qui est
   la bonne mesure pour un document qui se lit et la mauvaise pour une grille de
   trente colonnes. */
.crf { max-width: none; }

/* La grille defile dans son cadre, en hauteur comme en largeur : « lorsque
   son descendant la liste, il faudrait que la liste de titres reste en haut a
   l'affichage » (ticket du 2 septembre 2026).

   C'est la condition pour que la rangee de titres tienne : `position: sticky`
   se cale sur le premier ancetre qui defile, et c'est ce cadre-la. Tant qu'il
   n'avait pas de hauteur, c'est la page qui defilait -- les titres partaient
   avec elle, et a la centieme cooperative on ne savait plus quelle colonne on
   remplissait. Une hauteur au moins egale a vingt-huit rem sur un petit ecran,
   sinon ce qui reste de la fenetre sous les onglets. */
.crf-cadre {
  overflow: auto;
  max-height: max(28rem, calc(100vh - 24rem));
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: #fff;
}

.crf-table {
  /* Ou la rangee des titres se pose sous celle des chapeaux quand les deux
     sont collees en haut du cadre. La valeur juste est mesuree apres le rendu
     et reecrite ici meme par `renderCrf` : celle-ci est le repli, la hauteur
     d'un chapeau sur une ligne, qui vaut le temps que la mesure arrive. */
  --crf-tete-groupes: 1.5rem;
  /* Ou les deuxieme et troisieme cases figees se collent : au bout de celle
     qui les precede (ticket du 2 septembre 2026). Mesurees et reecrites ici
     meme par `ajusterColonnesFigeesCrf` -- la colonne des noms prend la
     largeur du plus long d'entre eux. Celles-ci sont les replis, qui valent le
     temps que la mesure arrive. */
  --crf-fige-2: 4.5rem;
  --crf-fige-3: 24rem;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-xs);
}

/* Un filet vertical entre deux colonnes, et sur toute la hauteur : « il faut
   que l'on voit plus distinctement les colonnes avec des traits verticaux »
   (suivi du 1er septembre 2026). Sans lui, trente colonnes de chiffres se
   lisent comme une nappe. */
/* Le creux d'une case est celui du barreau du dessous : « il faut pouvoir
   augmenter le plus possible le nombre de lignes de CRF visible a l'ecran »
   (ticket du 2 septembre 2026). Trois pixels gagnes en haut et en bas de
   chaque ligne, ce qui en fait trois de plus a l'ecran -- et sur une grille
   qu'on parcourt trois cents fois, trois lignes valent la hauteur qu'elles
   coutent. */
.crf-table th,
.crf-table td {
  padding: var(--espace-3xs) var(--espace-xs);
  border-bottom: 1px solid var(--gray-2);
  border-right: 1px solid var(--gray-2);
  white-space: nowrap;
  background: #fff;
}

/* La rangee des chapeaux se colle en haut du cadre, celle des titres juste
   dessous : deux rangees collees a zero se recouvriraient. La hauteur de la
   premiere est mesuree apres le rendu et posee sur la table
   (`--crf-tete-groupes`, voir renderCrf) -- l'ecrire ici en dur laisserait un
   liseré ou un chevauchement des que la police change d'un demi-pixel. */
.crf-table thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--gray-1);
  color: var(--gray-5);
  font-weight: 600;
  text-align: left;
  vertical-align: bottom;
}

/* Les intitules de colonne sont longs -- « 75600008 Participations volontaires
   des familles » -- et il y en a une cinquantaine. Ils ont d'abord ete debout,
   puis couches a 45 degres (« on est oblige de pencher la tete pour lire le
   libelle »), et le biais a coute la lecture des colonnes : un intitule qui
   part en diagonale ne dit plus ou finit sa colonne. « Essaye une autre mise
   en forme avec des colonnes droites et des titres avec renvoi a la ligne »
   (suivi du 1er septembre 2026).

   Donc droits, et replies : une largeur fixe, le texte qui passe a la ligne
   dedans, et une hauteur commune a toute la rangee pour que les intitules
   s'alignent par le bas -- c'est ce qui rend la rangee de titres lisible d'un
   coup d'oeil plutot que ligne a ligne. */
.crf-table thead tr.crf-titres th.num {
  width: 6.5rem;
  min-width: 6.5rem;
  height: 7rem;
  padding: var(--espace-2xs) var(--espace-xs);
  vertical-align: bottom;
  white-space: normal;
  font-weight: 500;
  line-height: 1.25;
}

/* Le numero de compte au-dessus de l'intitule, sur sa propre ligne : c'est la
   cle du formulaire papier, et l'avoir en tete de colonne evite de relire
   l'intitule pour rapprocher une ligne du CRF. */
.crf-tete-numero {
  display: block;
  margin-bottom: var(--espace-3xs);
  color: var(--gray-4);
  font-size: var(--fs-3xs);
  font-variant-numeric: tabular-nums;
}

.crf-tete-label { display: block; }

.crf-table thead tr.crf-groupes th {
  border-bottom: 1px solid var(--gray-3);
  text-align: center;
  text-transform: uppercase;
  font-size: var(--fs-3xs);
  letter-spacing: .04em;
}

/* Le chapeau d'une question du compte rendu d'activite -- « Gardez-vous des
   traces des reunions de conseil de cooperative ? ». Ce n'est pas un nom de
   rubrique mais une phrase : elle se replie dans sa bande plutot que de
   pousser les colonnes qu'elle coiffe. */
.crf-table thead tr.crf-groupes th.crf-cra-groupe {
  white-space: normal;
  line-height: 1.25;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--fs-3xs);
}

/* Le filet qui separe deux questions du CRA, et le financier du CRA : plus
   marque que celui qui separe deux colonnes d'une meme question. */
.crf-table .crf-cra-debut { border-left: 2px solid var(--gray-3); }

/* Le suivi de la collecte, entre l'identite et les chiffres : une ligne
   d'observations et cinq cases a cocher (ticket du 1er septembre 2026). Les
   cases se centrent sous leur intitule -- une colonne de cases alignees se
   parcourt d'un coup d'oeil, ce qui est tout ce qu'on lui demande. */
.crf-table th.crf-suivi-texte { width: 11rem; min-width: 11rem; }

.crf-table th.crf-suivi-marque {
  width: 4.5rem;
  min-width: 4.5rem;
  white-space: normal;
  text-align: center;
  line-height: 1.25;
}

.crf-table td.crf-suivi-marque { text-align: center; }

/* « Controle » n'est pas une croix mais une date : « pour la colonne controle
   il s'agit en fait de dates a renseigner » (ticket du 2 septembre 2026). Plus
   large que ses voisines, donc -- une date en toutes lettres et le petit
   calendrier du navigateur ne tiennent pas dans une colonne de case a
   cocher. */
.crf-table th.crf-suivi-date {
  width: 9rem;
  min-width: 9rem;
  white-space: normal;
  text-align: center;
  line-height: 1.25;
}

.crf-table td.crf-suivi-date { text-align: center; }

.crf-champ-date {
  width: 8.25rem;
  font-variant-numeric: tabular-nums;
}

/* La date du controle porte le selecteur du site comme toutes les autres dates
   du produit (`selecteur-date.js`) : elle etait la seule restee au controle nu
   du navigateur, qui montrait sa propre idee d'une case vide -- la date du jour
   sur trois cents lignes, chez le lecteur qui l'a signale le 2 septembre 2026.

   Ce qu'il faut lui donner ici, c'est la mesure d'une case de tableau : le
   selecteur est dessine pour un champ de formulaire, deux fois plus haut. Il
   prend donc la taille, le rembourrage et le cadrage de la case qu'il occupe,
   et l'enveloppe se serre sur le champ d'origine plutot que sur la colonne. */
.crf-table .date-champ {
  display: inline-block;
  width: 8.25rem;
  vertical-align: middle;
  --chevron-taille: var(--icon-sm);
  --chevron-retrait: var(--espace-2xs);
}

.crf-table .date-champ > .date-champ-saisie[type="text"] {
  padding: var(--espace-3xs) var(--chevron-reserve)
           var(--espace-3xs) var(--espace-2xs);
  font-size: inherit;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: inherit;
}

/* Le texte du champ d'origine s'efface, comme partout ailleurs
   (`.date-champ-source`) : ici il faut le redire, parce que `.crf-champ` --
   qui rend sa couleur a la case de la grille -- est ecrit plus bas dans la
   feuille et l'emportait a specificite egale. Sans cette ligne, la date du
   systeme se lit par-dessus la francaise, les deux superposees. */
.crf-table .date-champ > .date-champ-source { color: transparent; }

/* Une date jamais renseignee s'efface : sur trois cents lignes, le gabarit
   « jj/mm/aaaa » repete ferait une colonne pleine la ou rien n'est saisi, et
   les quelques dates posees s'y perdraient. */
.crf-table .date-champ > .date-champ-saisie[type="text"]::placeholder {
  color: var(--gray-3);
}

.crf-champ-observations { width: 10rem; }

/* Le bouton qui replie ou deplie les trente-trois colonnes du questionnaire.
   Pose dans le chapeau de la premiere d'entre elles : c'est de la qu'on les
   ouvre, et c'est la qu'on les referme. */
.crf-cra-bascule {
  margin-right: var(--espace-2xs);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-3xs);
  font-weight: 600;
  color: var(--cyan-dark);
  cursor: pointer;
  white-space: nowrap;
}

.crf-cra-bascule:hover { text-decoration: underline; }

/* La colonne qui reste quand le questionnaire est replie : elle porte le
   nombre de reponses de la ligne, pour qu'un CRA rempli ne disparaisse pas
   avec ses colonnes. */
.crf-table .crf-cra-repliee {
  width: 9rem;
  min-width: 9rem;
  text-align: center;
  color: var(--gray-5);
}

.crf-table thead tr.crf-groupes th.crf-cra-repliee { text-align: left; }

/* Les colonnes du CRA sont plus etroites que celles des montants : une reponse
   fermee tient en une lettre, et cinquante colonnes larges ne se parcourent
   pas. */
.crf-table thead tr.crf-titres th.crf-cra-colonne {
  width: 5.5rem;
  min-width: 5.5rem;
  /* Un cran plus petit que les intitules de comptes : ce sont des phrases de
     questionnaire, plus longues, dans des colonnes plus etroites -- et c'est
     la plus longue d'entre elles qui fait la hauteur de toute la rangee. */
  font-size: var(--fs-3xs);
}

/* Une question qui n'a pas de chapeau porte tout son texte dans sa colonne :
   elle est plus large que les reponses fermees qui l'entourent. */
.crf-table thead tr.crf-titres th.crf-cra-seule {
  width: 9rem;
  min-width: 9rem;
}

.crf-table thead tr.crf-titres th.crf-cra-texte {
  width: 13rem;
  min-width: 13rem;
}

/* La colonne d'identite, collee a gauche. Trois cases -- numero, nom, commune
   -- qui restent visibles quel que soit le defilement.

   Chacune se colle a sa place et non toutes a zero : « cela bug quand je
   decale vers la droite, la colonne nom vient ecraser la colonne n° puis la
   colonne commune vient ecraser la colonne nom, il faudrait conserver les 3 »
   (ticket du 2 septembre 2026). Trois cases collees au meme bord se recouvrent
   -- la derniere par-dessus les deux autres --, et il ne restait que la
   commune : on savait dans quel village on etait, plus dans quelle ecole.

   Les deux retraits sont mesures apres le rendu et poses sur la table
   (`ajusterColonnesFigeesCrf`, et leurs replis sur `.crf-table` plus haut) :
   la colonne des noms prend la largeur du plus long d'entre eux, qu'aucune
   valeur ecrite ici ne saurait deviner. */
.crf-fige {
  position: sticky;
  z-index: 3;
}

.crf-table .crf-fige { left: 0; }
.crf-table .crf-fige:nth-child(2) { left: var(--crf-fige-2); }
/* Le filet qui ferme le bloc fige, a droite de la troisieme case : il marque
   ou finit ce qui reste et ou commence ce qui defile. */
.crf-table .crf-fige:nth-child(3) {
  left: var(--crf-fige-3);
  box-shadow: 1px 0 0 var(--gray-2);
}

/* L'intitule des trois rangees de statistiques tient les trois colonnes d'un
   coup : il se colle donc au bord, et il ferme le bloc comme la troisieme. */
/* Le selecteur est aussi lourd que celui qui pose `position: static` sur les
   trois rangees (plus haut) : c'est lui qu'il doit reprendre a cette
   case-ci. */
.crf-table thead tr.crf-stats th.crf-stat-tete {
  position: sticky;
  left: 0;
  z-index: 3;
  box-shadow: 1px 0 0 var(--gray-2);
}

.crf-table thead tr.crf-titres th { top: var(--crf-tete-groupes, 1.5rem); }

/* La colonne d'identite passe par-dessus les lignes quand on defile de cote,
   et l'en-tete par-dessus elle quand on defile vers le bas : le coin haut
   gauche appartient a l'en-tete. */
.crf-table thead .crf-fige { z-index: 6; }

.crf-champ {
  width: 8rem;
  padding: var(--espace-3xs) var(--espace-2xs);
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
  background: transparent;
  font: inherit;
  color: inherit;
}

.crf-champ:hover { border-color: var(--gray-2); }

.crf-champ:focus {
  outline: none;
  border-color: var(--cyan);
  background: #fff;
  box-shadow: var(--anneau-champ);
}

.crf-champ-montant,
.crf-champ-nombre {
  width: 5.5rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Une reponse fermee du CRA : « O » ou « N », centre. Un champ large invite a
   ecrire une phrase la ou le formulaire attend une lettre. */
.crf-champ-oui_non {
  width: 3rem;
  text-align: center;
  text-transform: uppercase;
}

/* Une reponse libre -- « Idees, commentaires, suggestions » : elle prend la
   place d'une phrase, et sa colonne s'elargit avec elle. */
.crf-champ-texte { width: 12rem; }

.crf-total {
  font-variant-numeric: tabular-nums;
  background: var(--gray-1);
  font-weight: 600;
}

.crf-table thead .crf-total-tete { background: var(--gray-2); }

/* Les trois rangees de statistiques, sous les titres : le total de la colonne,
   son montant moyen et le nombre de cases remplies (ticket du 2 septembre
   2026). Elles remplacent le pied du tableau -- « supprimer les totaux a la
   fin » --, qui se lisait trois cents lignes plus bas.

   Elles ne se collent pas en haut du cadre, a la difference des deux rangees
   de titres : cinq rangees collees prendraient onze rem de fenetre en
   permanence, et « il faut pouvoir augmenter le plus possible le nombre de
   lignes de CRF visible a l'ecran » (ticket du meme jour). Elles defilent donc
   avec la grille, et on les retrouve en remontant -- ce qu'on fait de toute
   facon pour chercher une colonne. */
.crf-table thead tr.crf-stats th {
  position: static;
  top: auto;
  background: var(--gray-1);
  font-weight: 500;
  font-size: var(--fs-3xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
  vertical-align: middle;
}

/* Leur intitule se colle a gauche comme la colonne d'identite des lignes (voir
   `.crf-stat-tete` plus bas) : il occupe exactement les trois colonnes figees,
   donc il ne masque rien de plus qu'elles. Chaque case porte tout de meme dans
   son infobulle ce qu'elle dit (« Total : Banque 1 »), pour les fenetres
   etroites ou le bloc fige serait replie. */
.crf-stat-tete {
  text-align: left;
  font-weight: 600;
  color: var(--gray-5);
}

/* Le total porte le poids : c'est le chiffre du tableur, les deux autres
   l'eclairent. */
.crf-table thead tr.crf-stat-total th {
  font-weight: 700;
  color: var(--gray-6);
  border-top: 1px solid var(--gray-3);
}

.crf-table thead tr.crf-stat-moyenne th,
.crf-table thead tr.crf-stat-remplies th { color: var(--gray-4); }

/* La derniere des trois ferme le bloc des titres : sans ce filet, les
   statistiques et la premiere cooperative se lisent comme une meme rangee. */
.crf-table thead tr.crf-stat-remplies th {
  border-bottom: 1px solid var(--gray-3);
}

/* Un titre de colonne trie le tableau (ticket du 2 septembre 2026, « prevoir
   les tris de colonnes »). Meme dessin que dans les balances de tiers, ou le
   geste existe depuis le 25 aout : le curseur dit qu'on peut cliquer, la
   colonne triee passe au cyan, et la fleche donne le sens. */
.crf-table thead tr.crf-titres th.th-triable {
  cursor: pointer;
  user-select: none;
  transition: color .15s var(--ease);
}

.crf-table thead tr.crf-titres th.th-triable:hover { color: var(--gray-6); }
.crf-table thead tr.crf-titres th.crf-tri-actif { color: var(--cyan-dark); }
.crf-tete-fleche { font-variant-numeric: normal; }

/* Un compte rendu qui ne tombe pas juste : « lorsqu'un CRF est desequilibre,
   la cellule Erreur debitrice ou creditrice se renseigne : il faut alors mettre
   le desequilibre en evidence » (ticket du 2 septembre 2026).

   Un filet orange le disait jusqu'a ce que les deux comptes d'erreur deviennent
   calcules, et il a ete retire ce jour-la : l'ecart tombant dans l'un d'eux des
   la frappe, plus aucune ligne ne paraissait fausse. Elle l'est pourtant -- un
   compte d'erreur renseigne est un formulaire a reprendre avec l'ecole, pas un
   formulaire repare --, et c'est bien un rouge que cela demande, non l'orange
   d'un avertissement.

   La ligne entiere, depuis le suivi du 2 septembre 2026 : « il faudrait que
   toute la ligne soit rouge ». Elle ne l'etait pas -- seuls la case d'erreur
   et le bloc fige l'etaient, par crainte qu'une bande rosee ne cache ses
   propres chiffres. C'etait mal peser ce qui compte : sur trois cents lignes,
   une ligne fausse doit se reperer d'un coup d'oeil ou qu'on soit dans le
   defilement, et `--red-pale` reste un fond de lecture -- les chiffres s'y
   lisent comme sur le blanc des autres lignes. Les cases figees et les totaux
   sont repris nommement : les premieres se peignent elles-memes pour rester
   opaques quand elles passent par-dessus, les seconds portent le gris qui les
   distingue et l'auraient garde au milieu du rouge.

   La case ou l'ecart est tombe garde sa marque propre : sur un fond desormais
   de la meme couleur, c'est son chiffre en rouge sombre et en gras qui dit
   dans lequel des deux comptes d'erreur il est alle. */
.crf-table tr.crf-desequilibre > td,
.crf-table tr.crf-desequilibre > td.crf-total,
.crf-table tr.crf-desequilibre .crf-fige {
  background: var(--red-pale);
}

.crf-table td.crf-erreur {
  color: var(--red-dark);
  font-weight: 700;
}

/* Le filet ne tombe que sur la premiere des trois cases figees : elle est
   collee au bord gauche du cadre, donc il est a l'ecran quoi qu'on defile. Sur
   les trois, il ferait trois barres rouges pour une seule ligne. */
.crf-table tr.crf-desequilibre .crf-fige:first-child {
  box-shadow: inset 3px 0 0 var(--red);
}

/* Rouge au repos comme toutes les corbeilles depuis le 6 septembre 2026 : voir
   .annexe-ligne-retirer, ou la regle est ecrite. */
.crf-retirer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--red);
  cursor: pointer;
}

.crf-retirer:hover { color: var(--red-dark); }
.crf-retirer .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* L'ecart entre le total d'une note et le poste du bilan qu'elle detaille
   (ticket du 28 aout 2026). Rouge parce que c'en est un : une note dont le
   total ne vaut pas la page d'en face est une anomalie, pas une remarque. */
.annexe-ecart {
  margin: 0;
  padding: var(--espace-xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  background: var(--red-pale);
  color: var(--red-dark);
  font-size: var(--fs-xs);
}

/* Le cadre d'un tableau de note : le meme que celui des tables d'analyse
   (.tree-table-wrap), pour que l'onglet ne detonne pas a cote des autres. */
.annexe-tableau-cadre {
  overflow-x: auto;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.annexe-tableau {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--fs-sm);
}

/* Une note et les blocs qui la prolongent : meme grille, donc mêmes largeurs
   de colonnes d'un tableau a l'autre (demande du 27 aout 2026). En largeur
   automatique, chaque tableau prend ses largeurs sur son propre contenu et les
   deux « Dotations » ne tombent pas au meme endroit -- ce qui est justement ce
   qu'un bloc pose sous un tableau doit permettre de lire. La colonne des
   intitules garde la moitie de la largeur ; les colonnes de montants se
   partagent le reste a egalite. */
.annexe-tableau-aligne { table-layout: fixed; }

/* Deux cinquiemes de la largeur pour l'intitule, sur TOUTE note et non plus sur
   les seules notes alignees : « il faut que pour la visualisation du tableau la
   colonne de l'intitule soit egalement plus large » (suivi du 28 aout 2026,
   apres la meme correction dans l'export PDF).

   Une note en largeur automatique donnait a l'intitule ce qui restait apres des
   colonnes de montants qui ne se replient pas : « Fonds propres sans droit de
   reprise » et « Excedent ou deficit de l'exercice » passaient a la ligne dans
   le tableau de variation des fonds propres, la ou l'export PDF les tient
   depuis la 12.6. C'est la meme proportion que lui (_ANNEXE_PART_POSTE), pour
   que les deux lectures du meme document se ressemblent.

   Une indication et non une contrainte hors des tableaux alignes : en largeur
   automatique le navigateur elargit encore la colonne si un intitule le
   demande, et c'est ce qu'on veut -- une note a deux colonnes n'a aucune raison
   de rogner son libelle. */
.annexe-tableau th:first-child,
.annexe-tableau td:first-child { width: 40%; min-width: 18rem; }

/* Et les en-tetes de montants se replient, au lieu d'elargir leur colonne :
   c'est ce qui rend les deux cinquiemes ci-dessus atteignables. « Diminution ou
   consommation » et « Affectation du resultat », ecrits d'un seul tenant,
   prenaient a eux deux la moitie de la note et l'intitule se repliait a leur
   place -- exactement l'inverse de ce qu'on veut lire. Meme arbitrage que dans
   l'export PDF depuis la 12.6 : c'est le titre qui plie, pas le libelle. */
.annexe-tableau thead th.num { white-space: normal; }

.annexe-tableau thead th {
  background: var(--gray-1);
  text-align: left;
  font-weight: 500;
  padding: var(--espace-sm) var(--espace);
  border-bottom: 1px solid var(--gray-3);
  white-space: nowrap;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--gray-5);
}

.annexe-tableau thead th.num { text-align: right; }

/* L'etage des chapeaux : « Exercice clos » au-dessus d'Effectif et E.T.P.
   (demande du 27 aout 2026). Centre sur ce qu'il coiffe, et separe de lui par
   un filet -- sans quoi les deux etages se liraient comme deux lignes de
   titres sans rapport. La cellule vide de la colonne des intitules ne porte
   aucun filet : elle ne coiffe rien. */
.annexe-tableau-chapeaux th { border-bottom: none; padding-bottom: var(--espace-2xs); }

.annexe-tableau th.annexe-tableau-chapeau {
  text-align: center;
  border-bottom: 1px solid var(--gray-3);
  color: var(--gray-6);
}

.annexe-tableau td {
  padding: var(--espace-sm) var(--espace);
  border-bottom: 1px solid var(--gray-2);
  text-align: right;
  white-space: nowrap;
}

.annexe-tableau td.label-cell {
  text-align: left;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* La ligne de total ferme le tableau : un fond clair et du gras, comme le
   sous-total d'un cycle. */
.annexe-tableau tr.annexe-total > td {
  font-weight: 700;
  background: var(--gray-1);
  border-top: 1px solid var(--gray-3);
  border-bottom: none;
}

/* L'ACCOLADE DES « DONT » : « pour les points 4 et 5, il faut que tu adoptes
   la meme presentation que dans le fichier joint (accolades) » (ticket du
   8 septembre 2026). Les deux lignes qui coupent un total en deux -- ce que le
   siege y met, ce que les cooperatives y mettent -- sont tenues par une
   accolade, comme dans le modele que le reseau depose chez ses soixante-cinq
   associations.

   Chaque rangee dessine son morceau et les morceaux se rejoignent : le trait
   vertical court sur toute la hauteur de la case, la premiere le referme d'une
   courbe vers le haut, la derniere d'une courbe vers le bas. Rien n'est
   mesure, donc l'accolade suit la hauteur reelle des lignes, y compris quand
   un intitule passe a la ligne, et elle s'imprime comme elle s'affiche.

   La pointe tombe a la jointure des deux lignes, c'est-a-dire au milieu de
   l'accolade : elles sont toujours deux (voir annexe_engine,
   `_lignes_de_l_agregation`). */
.annexe-tableau td.label-cell.annexe-accolade {
  position: relative;
  padding-left: calc(var(--espace) + var(--retrait-pas));
}

.annexe-tableau td.label-cell.annexe-accolade::before {
  content: "";
  position: absolute;
  left: var(--espace);
  width: 6px;
  top: 0;
  bottom: 0;
  border-left: 1px solid var(--gray-4);
}

.annexe-tableau td.label-cell.annexe-accolade-debut::before {
  top: 50%;
  border-top: 1px solid var(--gray-4);
  border-top-left-radius: 6px;
}

.annexe-tableau td.label-cell.annexe-accolade-fin::before {
  bottom: 50%;
  border-bottom: 1px solid var(--gray-4);
  border-bottom-left-radius: 6px;
}

/* La pointe, a la jointure des deux lignes : elle designe le total ecrit
   au-dessus, et c'est elle qui fait l'accolade plutot qu'un simple filet. */
.annexe-tableau td.label-cell.annexe-accolade-debut::after {
  content: "";
  position: absolute;
  left: calc(var(--espace) - 5px);
  bottom: -1px;
  width: 5px;
  border-top: 1px solid var(--gray-4);
}

/* Un compte deplie sous une ligne du modele (suivi du 27 aout 2026) : decale
   sous elle et en retrait de ton, pour qu'on voie du premier coup d'oeil que
   c'est le detail de la ligne du dessus et non une rubrique de plus. Le meme
   decalage que .row-leaf-label -- desormais parce que les deux l'ecrivent
   pareil, et non parce qu'un chiffre y avait ete recopie : 2.1rem tombait a
   6,7 px de ce qu'il annoncait. */
.annexe-tableau tr.annexe-compte > td {
  font-size: var(--fs-sm);
  color: var(--gray-6);
  border-bottom-style: dashed;
}

.annexe-tableau tr.annexe-compte > td.label-cell {
  padding-left: calc(var(--espace) + var(--retrait-pas));
}

/* Une part de subvention qui se glisse d'une categorie a l'autre (ticket du
   31 aout 2026). Le curseur dit le geste avant qu'on l'essaie -- une ligne de
   tableau ne se prend nulle part ailleurs dans le produit, et rien d'autre ne
   l'annoncerait. */
.annexe-tableau tr.annexe-glissable > td.label-cell { cursor: grab; }
.annexe-tableau tr.annexe-en-vol > td { opacity: .45; }

/* La categorie survolee pendant le vol : un liseré cyan sur toute la rangee,
   comme la cible d'un depot de fichier. On vise une LIGNE, pas une case. */
.annexe-tableau tr.annexe-cible > td {
  background: var(--cyan-pale);
  box-shadow: inset 0 -2px 0 var(--cyan);
}

/* Le cadrage des cotisations OCCE (onglet Outils) : l'unite a cote du champ,
   le compte et la formule sous le libelle d'un montant deduit. Trois mentions
   discretes -- ce qu'on lit est le nombre, elles ne font que dire de quoi il
   s'agit. */
.outils-unite {
  margin-left: var(--espace-xs);
  color: var(--gray-5);
}

.outils-compte,
.outils-formule {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--gray-5);
}

/* --- L'analyse de coherence du reseau OCCE -------------------------------

   « Integre cet onglet intitule coherence entre CRF et Bilan » (ticket du
   8 septembre 2026). Onze petits tableaux les uns sous les autres, chacun
   avec son verdict : ce n'est pas un document, c'est une liste de controles,
   et ce qu'on y cherche est celui qui ne tombe pas juste.

   D'ou la forme : le verdict est a cote du titre et non au bout de la ligne,
   parce qu'on parcourt la page par ses titres. */
.coherence-resume {
  margin: 0;
  color: var(--gray-5);
}

.coherence-resume-alerte {
  color: var(--orange-dark);
  font-weight: 600;
}

.coherence-bloc { margin-top: var(--espace-2xl); }
.coherence-bloc:first-of-type { margin-top: var(--espace-lg); }

.coherence-bloc-tete {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  flex-wrap: wrap;
  margin-bottom: var(--espace-xs);
}

.coherence-bloc-titre { margin: 0; }

/* Le verdict d'un bloc : les trois etats se distinguent, parce qu'un controle
   muet n'est pas un controle reussi. Le gris de « rien a controler » dit
   precisement cela -- il n'y a rien a lire ici, et ce n'est pas une bonne
   nouvelle. */
.coherence-verdict {
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: var(--espace-3xs) var(--espace-sm);
  border-radius: 999px;
}

.coherence-verdict-ok {
  color: var(--green-dark);
  background: var(--green-pale);
}

.coherence-verdict-alerte {
  color: var(--orange-dark);
  background: var(--orange-pale);
}

.coherence-verdict-vide {
  color: var(--gray-5);
  background: var(--gray-2);
}

/* Le libelle prend la place qui reste, les quatre cases chiffrees la meme
   largeur : c'est ce qui aligne les onze tableaux les uns sur les autres, sans
   quoi chacun placerait ses colonnes selon son plus long intitule. */
.annexe-tableau.coherence-tableau th.coherence-colonne,
.annexe-tableau.coherence-tableau td.coherence-colonne {
  width: 11%;
  text-align: right;
  white-space: nowrap;
}

.annexe-tableau.coherence-tableau td.coherence-part {
  color: var(--gray-5);
  font-weight: 400;
}

.annexe-tableau.coherence-tableau td.coherence-valeur-texte {
  text-align: right;
  font-weight: 600;
}

/* La ligne qui porte l'ecart, quand il n'est pas nul : c'est elle qu'on vient
   chercher dans le bloc, et elle se lit avant qu'on ait lu le titre. */
.annexe-tableau.coherence-tableau tr.coherence-ligne-ecart > td {
  color: var(--orange-dark);
  font-weight: 600;
}

.coherence-commentaire {
  margin: var(--espace-xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* La liste des cooperatives derriere une ligne de controle (ticket du
   9 septembre 2026). Elle est dans le tableau et non a cote : c'est le detail
   d'une ligne, et l'en foncer d'un ton la donne a lire comme telle plutot que
   comme un douzieme bloc. */
.annexe-tableau.coherence-tableau tr.coherence-detail > td {
  padding: var(--espace-xs) var(--espace-sm) var(--espace-sm);
  background: var(--gray-1);
}

.coherence-detail-tableau {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}

.coherence-detail-tableau th,
.coherence-detail-tableau td {
  padding: var(--espace-3xs) var(--espace-xs);
  text-align: left;
  border-bottom: 1px solid var(--gray-2);
}

.coherence-detail-tableau th {
  color: var(--gray-5);
  font-weight: 600;
}

.coherence-detail-tableau th.coherence-colonne,
.coherence-detail-tableau td.coherence-colonne {
  text-align: right;
  white-space: nowrap;
}

/* La cooperative que la rubrique designe comme une anomalie : c'est elle qu'on
   vient chercher en depliant, et la lire suppose de la trouver dans la liste. */
.coherence-detail-tableau tr.coherence-detail-alerte > td {
  color: var(--orange-dark);
  font-weight: 600;
}

/* Le detail des controles d'une liasse (suite du ticket du 22 septembre
   2026) : un repli sous les constats, du meme dessin que les autres, et ses
   tableaux empruntes a la coherence ci-dessus. */
.controle-etats-detail { margin-top: var(--espace-sm); }
.controle-etats-detail .assistant-titre { margin-top: var(--espace-sm); }
/* Les quatre tableaux se lisent l'un sous l'autre : memes colonnes aux memes
   places, sinon l'oeil recale chaque montant. */
.controle-etats-detail .coherence-detail-tableau { table-layout: fixed; min-width: 36rem; }
.controle-etats-detail .coherence-detail-tableau th:first-child { width: 40%; }

.coherence-detail-vide {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* --- Le budget previsionnel du siege ------------------------------------

   « Cree un onglet budget en t'inspirant du modele ci-joint. Le budget
   concerne uniquement les comptes du siege » (ticket du 9 septembre 2026). Le
   compte de resultat du siege lu par avance : il se dessine donc comme lui,
   avec ses quatre colonnes de la meme largeur. */
.annexe-tableau.budget-tableau th.coherence-colonne,
.annexe-tableau.budget-tableau td.coherence-colonne {
  width: 15%;
  text-align: right;
  white-space: nowrap;
}

/* Le titre d'une rubrique du compte de resultat, pose sur toute la largeur :
   c'est ce qui range quarante postes en six groupes. */
.annexe-tableau.budget-tableau tr.annexe-rubrique > td {
  padding-top: var(--espace-md);
  font-weight: 700;
  text-transform: uppercase;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* L'ecart entre le vote et le realise : c'est ce qu'on vient chercher dans un
   budget, et il se lit avant qu'on ait lu la ligne. */
.annexe-tableau.budget-tableau td.budget-ecart { color: var(--orange-dark); }

.annexe-tableau.budget-tableau tr.budget-resultat > td {
  border-top: 2px solid var(--gray-3);
}

/* --- Le rapport financier de l'assemblee generale ------------------------

   « Cree un onglet intitule "Rapport financier" [...] selon le modele
   ci-joint » (ticket du 9 septembre 2026). Ce n'est pas un etat financier de
   plus : c'est le texte que le conseil lit devant l'assemblee. Il se dessine
   donc comme un texte -- une colonne de lecture, des paragraphes, des chiffres
   dedans -- et non comme un tableau de plus. */
.rapport-financier { max-width: 62rem; }

.rapport-association {
  margin: 0 0 var(--espace-lg);
  font-weight: 600;
  text-transform: uppercase;
}

.rapport-partie { margin-top: var(--espace-xl); }
.rapport-partie-titre { margin: 0 0 var(--espace-sm); }

.rapport-phrase {
  margin: 0 0 var(--espace-sm);
  line-height: 1.6;
}

/* Un chiffre du rapport : il vient des comptes, et se lit comme tel au milieu
   de la phrase. Ce n'est pas une mise en valeur, c'est un reperage -- un
   lecteur qui verifie le rapport cherche les nombres. */
.rapport-chiffre { font-weight: 600; }

/* Une case que rien ne calcule, posee dans la phrase meme : la composition du
   conseil, la cotisation votee, le budget previsionnel. Soulignee plutot
   qu'encadree, pour que la phrase reste une phrase. */
.rapport-champ {
  font: inherit;
  color: inherit;
  padding: 0 var(--espace-3xs);
  border: 0;
  border-bottom: 1px dashed var(--gray-4);
  background: transparent;
  border-radius: 0;
}

.rapport-champ:hover { background: var(--gray-1); }

.rapport-champ:focus {
  outline: none;
  border-bottom-color: var(--blue);
  background: var(--blue-pale);
}

.annexe-tableau.rapport-tableau {
  width: auto;
  min-width: 28rem;
  margin: 0 0 var(--espace-md);
}

.annexe-tableau.rapport-tableau td.rapport-ligne-decalee {
  padding-left: var(--espace-xl);
  color: var(--gray-5);
}

.rapport-pour {
  margin: var(--espace-xl) 0 0;
  font-style: italic;
}

/* Les deux signatures du modele : elles se tiennent cote a cote, comme sur le
   papier qui circule en assemblee. */
.rapport-signatures {
  display: flex;
  gap: var(--espace-3xl);
  margin-top: var(--espace-sm);
}

.rapport-signature { font-weight: 600; }

/* Une categorie vide, reposee en cible le temps du vol : en pointille, pour
   qu'on voie qu'elle n'est pas une ligne du tableau mais une place ou poser. */
.annexe-tableau tr.annexe-cible-vide > td {
  color: var(--gray-5);
  font-style: italic;
  border: 1px dashed var(--gray-4);
  border-left: 0;
  border-right: 0;
}

/* Une part qui n'est pas la ou la lecture la mettait : un point cyan devant
   son intitule. Sans lui, le tableau ne distingue plus ce qu'il a lu de ce
   qu'on lui a impose, et une correction posee il y a six mois passe pour un
   calcul. L'infobulle de la ligne dit d'ou elle vient. */
.annexe-tableau tr.annexe-deplacee > td.label-cell::before {
  content: "•";
  margin-right: var(--espace-2xs);
  color: var(--cyan);
}

.annexe-tableau td.annexe-vide {
  color: var(--gray-5);
  font-style: italic;
}

/* Le temps que l'annexe se calcule (elle se descend a l'ouverture de son
   onglet, voir api_dossier_annexe), et le cas ou l'exercice n'en porte pas.

   C'est le seul contenu de la vue quand elle s'affiche : une phrase grise
   posee a nu sous la barre des cycles, dans une colonne ou tout le reste est
   encadre. Elle prend donc la meme tuile que ce qu'elle remplace. */
.annexe-attente {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  padding: var(--espace-md) var(--espace-lg);
  font-size: var(--fs-sm);
  color: var(--gray-5);
  margin: 0;
}

/* LE RAPPROCHEMENT DU MECENAT : cinq sections, une par verdict du ticket
   RUGBY CLUB DE DRANCY du 17 septembre 2026.

   Chaque section est une tuile comme les autres vues de l'Analyse ; ce qui
   leur est propre est la fiche -- une convention, sa pièce, sa raison, et les
   écritures qu'on lui rapporte -- et le filet de couleur qui dit le verdict.
   La couleur seule ne dit rien : le titre de la section le dit déjà, le filet
   ne fait que le rendre reconnaissable en descendant la page. */
.mecenat-section { margin-top: var(--espace-lg); }
.mecenat-entete { margin-top: 0; }
.mecenat-fiche {
  border-left: 3px solid var(--gray-3);
  padding: var(--espace-sm) 0 var(--espace-sm) var(--espace);
  margin-top: var(--espace);
}
.mecenat-ok .mecenat-fiche { border-left-color: var(--green); }
.mecenat-confirmer .mecenat-fiche { border-left-color: var(--orange); }
.mecenat-manque .mecenat-fiche { border-left-color: var(--red); }
.mecenat-fiche-tete {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin: 0;
}
.mecenat-fiche-detail {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.mecenat-piece {
  margin: var(--espace-2xs) 0 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.mecenat-objet,
.mecenat-raison,
.mecenat-sous-titre { margin: var(--espace-2xs) 0 0 0; }
.mecenat-raison { color: var(--orange-dark); }
.mecenat-attente { color: var(--gray-5); }
.mecenat-non-lues { color: var(--orange-dark); }
.mecenat-table { margin-top: var(--espace-sm); }
/* Les colonnes chiffrées d'un rapprochement s'alignent a droite et en chiffres
   tabulaires : « 27 500,00 € » et « 7 000,00 € » ne se comparent que si la
   virgule tombe au même endroit. */
.mecenat-table .mecenat-num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.mecenat-synthese { margin-top: var(--espace); }

/* Le programme de travail d'un cycle : une conclusion, et le questionnaire qui
   la justifie (demande du 27 aout 2026).

   « Par defaut, si aucun probleme n'est detecte, seule une conclusion globale
   satisfaisante devra apparaitre sous le cycle [...] si des anomalies sont
   relevees, elles devront apparaitre clairement et de maniere visible. »

   D'ou la forme : un bandeau qui se lit d'un coup d'oeil sous le tableau, et
   qui porte la couleur de ce qu'il annonce -- vert quand tout est repondu,
   ambre quand des pieces manquent, rouge quand un chiffre dit non. Le detail
   se replie derriere lui, sauf en cas d'anomalie : celle-la ne se cache pas. */
/* Le creux au-dessus du bandeau vaut celui que le titre laisse sous lui :
   depuis que les trois blocs sont dans une meme tuile, ils se lisent comme une
   colonne, et une colonne n'a qu'un rythme. Il valait --espace, soit 3,2 px de
   plus que l'air sous le titre. */
.programme-travail {
  margin-top: var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  overflow: hidden;
}

.programme-conclusion {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  width: 100%;
  padding: var(--espace-sm) var(--espace);
  border: 0;
  background: var(--gray-1);
  font-family: inherit;
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
  transition: background .15s var(--ease);
}

.programme-conclusion:hover { background: var(--gray-2); }

.programme-marque { display: inline-flex; flex: none; }
.programme-marque .icon { width: var(--icon-sm); height: var(--icon-sm); }

.programme-titre { font-weight: 600; flex: none; }

/* Le detail de la conclusion tient sur une ligne : le bandeau annonce, le
   questionnaire explique. Une anomalie longue ne doit pas pousser le tableau
   du cycle suivant hors de vue. */
.programme-detail {
  flex: 1;
  min-width: 0;
  color: var(--gray-5);
  font-size: var(--fs-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Des quatre chevrons de repli du site, celui-ci est le seul enveloppe dans un
   `<span>` -- `app.js` le construit ainsi. Les trois autres sont l'icone
   elle-meme, posee directement dans la rangee : `.dossier-chevron`,
   `.cabinet-identite-titre > .icon`, `.row-toggle .arrow`.

   L'enveloppe suffisait a le decaler. Un `<svg>` est en ligne : dans un bloc,
   il s'appuie sur la ligne d'ecriture et le jambage de la fonte continue sous
   lui. Le span mesurait donc 17 pour une icone de 14, l'icone calee en haut, et
   son milieu tombait 1,5 px au-dessus du milieu de son propre libelle -- sur
   les trois autres, l'ecart est nul.

   Pire au clic qu'au repos : `rotate(90deg)` tourne autour du milieu du span,
   pas de celui de l'icone. A l'ouverture le chevron redescendait de 1,5 px et
   glissait de 1,5 px vers la droite, puis remontait a la fermeture. Il sautait
   en diagonale a chaque repli. Mesure le 30 aout 2026.

   `display: flex` rend au span la taille de ce qu'il contient -- l'icone, seule
   dedans, cesse d'etre en ligne -- et rend du meme coup a la rotation le bon
   centre. Releve apres : 14 pour 14, ecart nul ferme comme ouvert. */
.programme-chevron { display: flex; flex: none; color: var(--gray-4); }
.programme-chevron .icon { width: var(--icon-sm); height: var(--icon-sm); }
.programme-conclusion[aria-expanded="true"] .programme-chevron { transform: rotate(90deg); }

.programme-travail[data-etat="satisfaisant"] .programme-conclusion { background: var(--green-pale); }
.programme-travail[data-etat="satisfaisant"] .programme-marque { color: var(--green); }
.programme-travail[data-etat="satisfaisant"] .programme-titre { color: var(--green-dark); }

.programme-travail[data-etat="anomalie"] .programme-conclusion { background: var(--red-pale); }
.programme-travail[data-etat="anomalie"] .programme-marque { color: var(--red); }
.programme-travail[data-etat="anomalie"] .programme-titre { color: var(--red-dark); }

/* Le tableau de variation des immobilisations, sous le tableau du cycle du
   meme nom (ticket du 8 septembre 2026, voir variation_immobilisations.py).
   Meme cadre que la saisonnalite et le programme de travail : les trois sont
   des encarts poses en pied de section. */
.variation-immo {
  /* En tete de cycle et non plus en pied (ticket du 10 septembre 2026) : le
     creux passe donc dessous, avant la feuille de soldes. */
  margin: 0 0 var(--espace-sm);
  padding: var(--espace) var(--espace-md) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
}

/* CHAQUE TABLEAU D'UN CYCLE PORTE SON NOM, ET SE MASQUE.

   « Chaque cycle doit avoir une feuille maitresse comme tableau principal [...]
   Ces tableaux doivent etre rattaches au cycle concerne et pouvoir etre
   affiches ou masques » (ticket du 12 septembre 2026).

   Le titre EST le bouton : un chevron a cote d'un intitule cliquable, c'est
   deux cibles pour un geste, et c'est le titre qu'on vise. Meme dessin que les
   chevrons des lignes de tableau, pour que le geste se reconnaisse. */
.cycle-tableau-titre {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

/* Le bouton prend `.row-toggle` de l'arbre d'analyse : meme boite, meme
   chevron, meme rotation. Ces deux regles sont ecrites apres
   `.row-toggle.open .arrow`, elles la couvrent donc a egalite de specificite,
   comme celles du chevron des tableaux de variation juste au-dessus. */
.cycle-tableau-bascule { padding: var(--espace-3xs) 0; }
.cycle-tableau-bascule[aria-expanded="true"] .arrow { transform: rotate(90deg); }
.cycle-tableau-bascule[aria-expanded="false"] .arrow { transform: none; }

/* Le tableau suivant respire, sans quoi son titre se colle au total de celui
   du dessus. Le premier du bloc n'en a pas besoin : le cadre l'espace deja. */
.cycle-tableau + .cycle-tableau { margin-top: var(--espace-md); }

/* La feuille maitresse est le tableau principal du cycle, pas un encart : son
   titre se detache du bloc des tableaux d'analyse pose au-dessus. */
.cycle-section > .cycle-tableau { margin-top: var(--espace-sm); }

/* LE CYCLE D'OU VIENT UN COMPTE ETRANGER AU TABLEAU.

   « Si un compte présenté dans ce tableau appartient à un autre cycle, indique
   le cycle dans lequel il se trouve ainsi que son numéro de compte » (ticket du
   12 septembre 2026). Le tableau des provisions porte des dépréciations
   d'usagers et d'immobilisations financières, qui vivent ailleurs.

   Une étiquette discrète devant le numéro, et non une seconde colonne : elle ne
   concerne que trois lignes sur cinq, et une colonne vide aux quatre cinquièmes
   se lit comme une donnée manquante. */
.variation-immo-cycle {
  display: inline-block;
  margin-right: var(--espace-2xs);
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-sm);
  background: var(--gray-2);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--gray-5);
  text-transform: uppercase;
  letter-spacing: .02em;
  vertical-align: baseline;
}

/* La meme etiquette, quand elle porte le dessin du cycle et non son nom
   (« dans tous les tableaux, n'affiche jamais le nom du cycle, mais uniquement
   son icone », ticket du 13 septembre 2026) : plus de fond ni de cadre, le
   dessin se suffit, et la place gagnee revient au numero de compte. */
.variation-immo-cycle-icone {
  padding: 0;
  background: none;
}

.variation-immo-cycle-icone .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  vertical-align: -.15em;
}

/* L'exercice d'un tableau, quand plusieurs sont affiches. */
.variation-immo-annee {
  margin-top: var(--espace-sm);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* LES DEUX TABLEAUX DE VARIATION PARTAGENT LEURS COLONNES, ET EUX SEULS.

   « Les colonnes des deux tableaux doivent etre parfaitement en phase. La fin
   est actuellement correcte, mais pas le debut : aligne egalement le debut, les
   acquisitions et diminutions pour les immobilisations, ainsi que le debut, les
   dotations et reprises pour les amortissements » (suivi du 10 septembre 2026).

   Ils se dimensionnaient sur leur contenu, et leur contenu differe :
   « Acquisitions » est plus large que « Dotations », et les montants d'un
   amortissement plus courts que ceux du brut. Seule la derniere colonne
   tombait juste, parce qu'elle est calee sur le bord droit.

   Ils reprennent donc la mecanique des cycles -- largeurs figees, colonne de
   poste qui absorbe le reste -- avec une largeur a eux : ils ne s'alignent
   toujours pas sur la feuille de soldes, qui porte une colonne par exercice
   quand ceux-ci en portent quatre. */
#tree-tables-container .variation-immo-table { table-layout: fixed; }
/* DIX REM ET NON NEUF : LE PLUS LONG MOT D'UN EN-TETE TIENT ENTIER.

   La largeur etait de 9rem tant que les en-tetes tenaient sur une ligne. Celui
   du tableau des fonds propres ne tient pas, et le passage a la ligne (voir
   `th.num` plus bas) ne suffisait pas seul : sur 9rem, une cellule d'en-tete
   offre 91 px de texte une fois la bande du trombone et la gouttiere prises, et
   « CONSOMMATION » en demande 96. Le mot se coupait donc en son milieu,
   « CONSOMMATIO » puis « N », ce qui se lit plus mal qu'un chevauchement.

   A 10rem la cellule offre 107 px : « Diminution ou » puis « consommation »,
   « Affectation du » puis « resultat », chaque mot entier et deux lignes au
   plus. La colonne de poste absorbe la difference, comme toujours ici, et les
   quatre tableaux gardent la meme largeur -- ils se lisent l'un sous l'autre,
   et c'est tout l'objet de cette regle. */
#tree-tables-container .variation-immo-table col.col-variation-montant {
  width: 10rem;
}
.variation-immo-table td.num,
.variation-immo-table th.num { text-align: right; }
/* Un montant ne se coupe jamais : « 1 266,00 » passe a la ligne au milieu du
   nombre et ne se lit plus. Le titre de la colonne, lui, a le droit -- voir
   juste en dessous. */
.variation-immo-table td.num { white-space: nowrap; }

/* L'EN-TETE PASSE A LA LIGNE PLUTOT QUE DE DEBORDER SUR SA VOISINE.

   « Mets simplement la ligne d'en-tete sur deux lignes, car le texte se
   chevauche » (suivi du 13 septembre 2026, sur le tableau de variation des
   fonds propres).

   Les colonnes de ces tableaux sont figees (`table-layout: fixed`), et leurs
   en-tetes portaient le `nowrap` des montants. « Affectation du resultat » et
   « Diminution ou consommation » sortaient donc de leur cellule et venaient
   s'ecrire par-dessus le titre d'a cote : deux textes au meme endroit, dont
   aucun ne se lit.

   Les en-tetes courts des trois autres tableaux -- « Acquisitions »,
   « Dotations », « Reprises » -- tiennent toujours sur une ligne : rien ne se
   deplie qui n'en avait pas besoin. Et tous se calent en bas de la rangee,
   pour que la derniere ligne d'un titre en deux lignes tombe a la hauteur de
   celui qui n'en a qu'une, juste au-dessus du filet.

   `break-word` est un filet de securite et non la regle : la largeur choisie
   juste au-dessus fait tenir chaque mot entier, et rien ne se coupe. Il est la
   pour le jour ou un libelle plus long que « consommation » entrera dans un
   modele d'annexe : mieux vaut alors un mot coupe qu'un titre pose sur son
   voisin. */
.variation-immo-table th.num {
  white-space: normal;
  overflow-wrap: break-word;
}
.variation-immo-table thead th { vertical-align: bottom; }
/* L'intitule du poste tient la gauche, comme dans toute table de l'analyse :
   `.tree-table td` aligne a droite par defaut, ce qui est bon pour un montant
   et ne l'est pour rien d'autre. */
.variation-immo-table td:first-child { text-align: left; }
.variation-immo-table td { padding: var(--espace-2xs) var(--espace); }
.variation-immo-total td { font-weight: 700; border-top: 1px solid var(--gray-3); }
/* Le sous-total pose au milieu du tableau : « Situation nette », dans les
   variations des fonds propres (ticket du 13 septembre 2026). Il additionne
   les six lignes du dessus et ne compte pas dans le total ; il se lit donc
   comme un total, en gras, mais sans le filet qui ferme le tableau. */
.variation-immo-sous-total td { font-weight: 700; }

/* LE TROMBONE NE POUSSE PAS LE MONTANT : IL SE POSE DANS UNE GOUTTIERE.

   « Le trombone associe a une ecriture ou a une ligne d'ecriture doit rester
   place a droite du montant qu'il justifie, sans le decaler. Tous les montants
   doivent rester parfaitement alignes dans leur colonne. Applique la meme
   logique a l'ensemble du tableau » (ticket du 11 septembre 2026).

   Le trombone etait pose DANS la cellule du montant, a la suite du nombre. Une
   colonne de montants s'aligne par la droite : le bouton prenait donc sa place
   sur le bord, et poussait « 1 266,00 » de trente pixels vers la gauche pendant
   que « 2 620,80 », juste au-dessus, restait cale. Deux montants de la meme
   colonne ne tombaient plus l'un sous l'autre, et c'est justement ce qu'on
   demande a une colonne.

   La place du trombone est donc reservee A TOUTES les cellules de montant du
   tableau, en-tetes compris : une bande a droite ou le nombre n'ecrit jamais.
   Les montants se calent sur son bord gauche, tous sur la meme verticale, qu'ils
   portent un trombone ou non -- et le bouton, sorti du flux, se pose dans la
   bande sans rien deplacer.

   La largeur est mesuree sur le bouton le plus large qu'une ligne puisse
   porter : l'icone, ses deux marges et un nombre a deux chiffres, soit 35 px.
   La bande en fait 40, et le bouton s'y tient a 4 px du bord. Trop etroite, un
   trombone a deux pieces recouvrirait le montant, ce qui est pire que de le
   decaler. */
.variation-immo-table td.num,
.variation-immo-table th.num {
  position: relative;
  padding-right: calc(var(--icon-lg) + var(--espace-lg));
}

.variation-immo-table td.num > .controle-justificatif-btn {
  position: absolute;
  right: var(--espace-2xs);
  top: 50%;
  transform: translateY(-50%);
  margin-left: 0;
}

/* Les deux colonnes qu'on rapproche du bilan : « les montants de debut
   d'exercice doivent etre en bleu, sans gras, comme dans les comptes ; les
   montants de fin d'exercice doivent etre en bleu et en gras, car ce sont les
   montants a justifier » (ticket du 10 septembre 2026). Le bleu est celui des
   comptes, `.row-account`. Les deux colonnes du milieu gardent l'encre
   ordinaire : ce sont des mouvements, pas des montants a rapprocher. */
.variation-immo-table td.variation-immo-debut,
.variation-immo-table td.variation-immo-fin { color: var(--blue); }
.variation-immo-table tr:not(.variation-immo-total) td.variation-immo-debut {
  font-weight: 400;
}
.variation-immo-table td.variation-immo-fin { font-weight: 700; }

/* Le chevron d'un tableau de variation : le meme dessin que celui de l'arbre
   des cycles, mais son etat se lit dans `aria-expanded` et non dans la classe
   `open` -- `refreshVisibility` reecrit cette classe sur tous les `.row-toggle`
   du conteneur d'apres les noeuds de l'arbre, ou ces lignes-ci n'en ont pas.
   Ecrites apres `.row-toggle.open .arrow`, ces deux regles la couvrent donc a
   specificite egale. */
.variation-immo-toggle[aria-expanded="true"] .arrow { transform: rotate(90deg); }
.variation-immo-toggle[aria-expanded="false"] .arrow { transform: none; }

/* Les trois etages du tableau, chacun en retrait du precedent : la rubrique du
   modele de l'annexe, les comptes qui la composent, les lignes d'ecriture qui
   composent leurs mouvements. */
.variation-immo-table tr.variation-immo-compte > td:first-child {
  padding-left: calc(var(--espace) + var(--retrait-pas));
}
.variation-immo-table tr.variation-immo-mouvement > td:first-child {
  padding-left: calc(var(--espace) + 2 * var(--retrait-pas));
}

/* Une ligne d'ecriture se lit comme une note sous son compte : plus petite et
   plus grise que le montant qu'elle explique. */
.variation-immo-table tr.variation-immo-mouvement > td {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* La saisonnalite du chiffre d'affaires, sous le tableau du cycle Clients
   (ticket du 8 septembre 2026, voir saisonnalite_ca.py). Meme cadre que le
   programme de travail juste dessous : les deux sont des encarts poses en pied
   de section, et deux cadres differents a la suite se verraient. */
.saisonnalite {
  margin: var(--espace-sm) 0 0;
  padding: var(--espace) var(--espace-md) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
}

.saisonnalite-titre {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

/* Le graphique replie sur son titre : il occupait trois cents pixels au bas de
   chaque cycle qu'on le regarde ou non (ticket du 9 septembre 2026). Il
   s'ouvre au survol d'un agregat du tableau, et un clic sur le titre
   l'epingle. La transition porte sur la hauteur maximale et non sur
   `display` : un graphique qui apparaitrait d'un coup ferait sauter la page
   sous les yeux. */
.saisonnalite-repliable .saisonnalite-legende,
.saisonnalite-repliable .saisonnalite-cadre {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height .18s ease, opacity .18s ease;
}

.saisonnalite-repliable.saisonnalite-ouverte .saisonnalite-legende {
  max-height: 6rem;
  opacity: 1;
}

.saisonnalite-repliable.saisonnalite-ouverte .saisonnalite-cadre {
  max-height: 40rem;
  opacity: 1;
}

/* Le titre dit qu'il se clique, et dit ce que le clic fait : sans cette
   invite, un graphique qui ne parait qu'au survol se decouvre par hasard. */
.saisonnalite-repliable .saisonnalite-titre {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
}

.saisonnalite-repliable .saisonnalite-titre::after {
  content: "survolez un agrégat du cycle pour l’ouvrir";
  font-weight: 400;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.saisonnalite-repliable.saisonnalite-epinglee .saisonnalite-titre::after {
  content: "épinglé : cliquer pour refermer";
}

.saisonnalite-repliable .saisonnalite-titre:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.saisonnalite-legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-md);
  margin-top: var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* La pastille qui dit de quelle serie il s'agit : la meme teinte que la barre
   de meme rang, et c'est le seul endroit ou l'exercice est nomme. */
.saisonnalite-legende-item {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
}

/* La marque de la legende suit ce qu'elle designe : c'etait un carre quand le
   graphique portait des barres, c'est un trait rond depuis qu'il porte des
   courbes. */
.saisonnalite-legende-item::before {
  content: "";
  width: var(--icon-sm);
  height: 3px;
  border-radius: 999px;
  background: var(--cyan);
}

/* UNE TEINTE PAR ANNÉE SÉLECTIONNÉE, et non deux (ticket du 9 septembre
   2026 : « si j'ai sélectionné n, n-1, n-3, je dois avoir trois lignes »).
   Cinq teintes de la palette, prises dans les jetons existants : l'année
   auditée en cyan, celle d'avant en gris -- un repère, pas la courbe qu'on
   lit --, puis violet, bleu et vert. Au-delà de cinq courbes le graphique
   n'est plus lisible, et la sixième reprend le cyan : mieux vaut deux courbes
   de même teinte, que la légende distingue, qu'une couleur choisie à l'oeil
   dans une règle, qui fait dériver une palette. */
.saisonnalite-legende-item[data-rang="1"]::before { background: var(--gray-4); }
.saisonnalite-legende-item[data-rang="2"]::before { background: var(--purple); }
.saisonnalite-legende-item[data-rang="3"]::before { background: var(--blue); }
.saisonnalite-legende-item[data-rang="4"]::before { background: var(--green); }

.saisonnalite-graphe {
  display: block;
  width: 100%;
  height: auto;
  margin-top: var(--espace-xs);
}

.saisonnalite-grille { stroke: var(--gray-2); stroke-width: 1; }
.saisonnalite-axe { stroke: var(--gray-3); stroke-width: 1.5; }

/* « Fais plutot des courbes, soigne la presentation » (suivi du 8 septembre
   2026). Une saison est une forme, et une forme se suit du regard : douze
   couples de barres se comparaient deux a deux, la courbe se lit d'un trait.

   Les extremites rondes et la jointure ronde ne sont pas un ornement : une
   ligne brisee a angles vifs accroche l'oeil sur ses sommets, qui sont
   justement les mois qu'on regarde. */
.saisonnalite-courbe {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* L'exercice de comparaison, en gris et non dans un cyan plus pale : il court
   sur l'aire pale de l'exercice audite, et un bleu clair sur un bleu tres clair
   ne se distingue plus. Le gris dit aussi ce qu'il est -- un repere, pas la
   courbe qu'on lit. */
.saisonnalite-courbe[data-rang="1"] {
  stroke: var(--gray-4);
  stroke-width: 2;
}

.saisonnalite-courbe[data-rang="2"] { stroke: var(--purple); stroke-width: 2; }
.saisonnalite-courbe[data-rang="3"] { stroke: var(--blue); stroke-width: 2; }
.saisonnalite-courbe[data-rang="4"] { stroke: var(--green); stroke-width: 2; }

/* La courbe de cumul : « ajoute une courbe en cumul » (ticket du 10 septembre
   2026). Meme teinte que la saison de la meme annee -- c'est la meme serie,
   lue autrement --, mais en pointille et plus fine : elle se lit sur l'axe de
   DROITE, et rien ne serait plus trompeur qu'un trait plein de meme poids sur
   une autre echelle. */
.saisonnalite-cumul {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 1.5;
  stroke-dasharray: 5 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.saisonnalite-cumul[data-rang="1"] { stroke: var(--gray-4); }
.saisonnalite-cumul[data-rang="2"] { stroke: var(--purple); }
.saisonnalite-cumul[data-rang="3"] { stroke: var(--blue); }
.saisonnalite-cumul[data-rang="4"] { stroke: var(--green); }

/* Sa marque de legende dit le pointille, sinon deux entrees de meme teinte ne
   se distinguent que par le mot « cumul ». */
/* Deux classes et non une : les marques par rang juste au-dessus en portent
   deux aussi (`.saisonnalite-legende-item[data-rang="1"]::before`), et a
   specificite egale c'est la derniere ecrite qui gagne. */
.saisonnalite-legende-item.saisonnalite-legende-cumul::before {
  height: 0;
  border-radius: 0;
  background: none;
  border-top: 2px dashed var(--cyan);
}

.saisonnalite-legende-item.saisonnalite-legende-cumul[data-rang="1"]::before {
  background: none;
  border-top-color: var(--gray-4);
}
.saisonnalite-legende-item.saisonnalite-legende-cumul[data-rang="2"]::before {
  background: none;
  border-top-color: var(--purple);
}
.saisonnalite-legende-item.saisonnalite-legende-cumul[data-rang="3"]::before {
  background: none;
  border-top-color: var(--blue);
}
.saisonnalite-legende-item.saisonnalite-legende-cumul[data-rang="4"]::before {
  background: none;
  border-top-color: var(--green);
}

/* Ce que la courbe de l'exercice audite couvre, entre elle et la ligne des
   zeros : de quoi lui donner un poids sans la doubler d'une seconde ligne. */
.saisonnalite-aire {
  fill: var(--cyan-pale);
  stroke: none;
}

/* Un point par mois : c'est lui qui porte l'infobulle, et c'est lui qui dit ou
   la mesure tombe -- une courbe seule laisse deviner les mois entre deux
   sommets. Cercle plein cerne de blanc, pour qu'il se detache quand les deux
   courbes se croisent. */
.saisonnalite-point {
  fill: var(--cyan);
  stroke: #fff;
  stroke-width: 1.5;
}

.saisonnalite-point[data-rang="1"] { fill: var(--gray-4); }
.saisonnalite-point[data-rang="2"] { fill: var(--purple); }
.saisonnalite-point[data-rang="3"] { fill: var(--blue); }
.saisonnalite-point[data-rang="4"] { fill: var(--green); }

/* --- La bulle qui suit le curseur ---------------------------------------

   « Lorsque je place mon curseur a n'importe quel endroit du graphique, cela
   doit me mettre une bulle avec le chiffre correspondant, cela doit etre
   dynamique » (ticket du 9 septembre 2026). Le cadre est relatif pour que la
   bulle se pose au-dessus du mois vise ; le graphique, lui, garde sa largeur
   pleine. */
.saisonnalite-cadre { position: relative; }

/* La barre verticale du mois vise : c'est le MOIS qu'on compare, pas le point.
   Elle se lit sous les courbes, comme la grille. */
.saisonnalite-repere {
  stroke: var(--gray-4);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  pointer-events: none;
}

/* Le halo pose sur le point du mois vise : il dit lequel des douze points la
   bulle est en train de lire. */
.saisonnalite-halo {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 2;
  pointer-events: none;
}

.saisonnalite-halo[data-rang="1"] { stroke: var(--gray-4); }
.saisonnalite-halo[data-rang="2"] { stroke: var(--purple); }
.saisonnalite-halo[data-rang="3"] { stroke: var(--blue); }
.saisonnalite-halo[data-rang="4"] { stroke: var(--green); }

/* La bulle elle-meme : toutes les annees d'un coup, sous le nom du mois. Elle
   se pose au-dessus du graphique et se centre sur le mois vise ; elle ne prend
   pas le curseur, sans quoi elle se ferait fuir elle-meme. */
.saisonnalite-bulle {
  position: absolute;
  top: var(--espace-xs);
  transform: translateX(-50%);
  z-index: 2;
  min-width: 11rem;
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-md);
  font-size: var(--fs-xs);
  pointer-events: none;
}

.saisonnalite-bulle-mois {
  font-weight: 600;
  color: var(--gray-6);
  margin-bottom: var(--espace-3xs);
}

.saisonnalite-bulle-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
}

.saisonnalite-bulle-annee { color: var(--gray-5); }

/* Le montant a droite, toujours a la meme place : c'est ce qu'on vient lire,
   et trois montants qui ne s'alignent pas ne se comparent pas. */
.saisonnalite-bulle-montant {
  margin-left: auto;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.saisonnalite-bulle-pastille {
  width: var(--icon-sm);
  height: 3px;
  border-radius: 999px;
  background: var(--cyan);
}

.saisonnalite-bulle-pastille[data-rang="1"] { background: var(--gray-4); }
.saisonnalite-bulle-pastille[data-rang="2"] { background: var(--purple); }
.saisonnalite-bulle-pastille[data-rang="3"] { background: var(--blue); }
.saisonnalite-bulle-pastille[data-rang="4"] { background: var(--green); }

/* La meme distinction dans la bulle : un rond creux pour le cumul, plein pour
   le mois. */
.saisonnalite-bulle-pastille-cumul {
  background: none;
  box-shadow: inset 0 0 0 2px var(--cyan);
}

.saisonnalite-bulle-pastille-cumul[data-rang="1"] {
  background: none;
  box-shadow: inset 0 0 0 2px var(--gray-4);
}
.saisonnalite-bulle-pastille-cumul[data-rang="2"] {
  background: none;
  box-shadow: inset 0 0 0 2px var(--purple);
}
.saisonnalite-bulle-pastille-cumul[data-rang="3"] {
  background: none;
  box-shadow: inset 0 0 0 2px var(--blue);
}
.saisonnalite-bulle-pastille-cumul[data-rang="4"] {
  background: none;
  box-shadow: inset 0 0 0 2px var(--green);
}

/* Les seules tailles ecrites en clair de ce bloc, et elles ne sont pas des
   pixels : a l'interieur d'un viewBox, une taille de texte est une unite du
   dessin, qui s'etire avec lui. Un jeton --fs-* la figerait en rem, donc a la
   taille de l'ecran et non a celle du graphique : les etiquettes de mois
   deborderaient les unes sur les autres des que le volet se retrecit. */
.saisonnalite-graduation,
.saisonnalite-mois {
  fill: var(--gray-5);
  font-size: 17px;
}

.programme-questions {
  padding: var(--espace-sm) var(--espace) var(--espace);
  border-top: 1px solid var(--gray-3);
  background: #fff;
}

.programme-section-titre {
  margin: var(--espace) 0 var(--espace-2xs);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-4);
}

.programme-section-titre:first-child { margin-top: var(--espace-3xs); }

/* L'ecart et l'air de la rangee etaient les deux valeurs hors echelle que le
   controle relevait vingt-quatre fois sur cette page : 11,2 px entre la
   pastille et l'intitule, 8 px au-dessus et au-dessous. Ni l'un ni l'autre
   n'est un barreau. Ils prennent le meme, --espace-sm : la meme mesure separe
   la colonne de statut de son texte et deux questions l'une de l'autre, ce qui
   donne au questionnaire un seul pas au lieu de deux valeurs voisines qu'on ne
   sait pas distinguer mais qu'on sent. */
.programme-question {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-sm);
  padding: var(--espace-sm) 0;
  border-top: 1px solid var(--gray-2);
}

.programme-question:first-of-type { border-top: 0; }

/* La pastille du statut : la meme largeur pour toutes, sans quoi les intitules
   ne s'alignent pas d'une question a l'autre. */
.programme-statut {
  flex: none;
  width: 8.5rem;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-2);
  color: var(--gray-5);
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-align: center;
}

.programme-question[data-statut="realise"] .programme-statut { background: var(--green-pale); color: var(--green-dark); }
.programme-question[data-statut="anomalie"] .programme-statut { background: var(--red-pale); color: var(--red-dark); }

.programme-question-corps { flex: 1; min-width: 0; }

.programme-question-intitule {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.programme-constat {
  margin: var(--espace-3xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* La piece que le constat cite, cliquable en place. Elle garde la taille et la
   graisse de la phrase qui la porte -- ce n'est pas un bouton pose dans le
   texte, c'est le nom du document qui s'ouvre --, et ne se distingue que par
   la couleur d'accent et le trait qui la souligne au survol. */
.programme-piece {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--blue);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: .15em;
  transition: text-decoration-color .15s var(--ease);
}

.programme-piece:hover,
.programme-piece:focus-visible { text-decoration-color: currentColor; }

/* Les quatre reponses qu'on peut donner soi-meme. Toujours posees, et non
   revelees au survol : reservees a un survol, elles auraient occupe la meme
   hauteur sans se montrer -- quatorze questions valent quatorze rangees de
   blanc -- et rien n'aurait dit qu'on peut repondre. */
/* L'ecart d'un rang de pastilles, celui que .avancement-pill et
   .cabinet-toggle ont deja pose deux fois pour la meme raison : a quatre
   virgule huit, deux reponses voisines se lisaient comme une seule etiquette
   coupee. Les trois lisent aujourd'hui le meme barreau, --espace-xs : celui
   qui les encadre, invisiblement plus large que les six pixels ecrits a la
   main qu'il a remplaces chez les deux autres le 28 aout 2026, et sur
   l'echelle. */
.programme-choix {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-xs);
  margin-top: var(--espace-xs);
}

/* Les quatre reponses sont la seule chose qu'on clique dans ce panneau, et
   elles mesuraient 20,78 px de haut : le plus petit controle du site, quatre-
   vingt-seize fois sur un ecran. Tout ce qui se clique ailleurs tient --h-sm.
   Le remplissage vertical passe donc sous le plancher et c'est le plancher qui
   decide, comme pour la bande d'unites de la barre d'outils ; l'horizontal
   monte d'un barreau, une pastille plus haute ayant besoin d'un peu plus d'air
   de chaque cote pour rester une pastille. */
.programme-choix-btn {
  display: inline-flex;
  align-items: center;
  min-height: var(--h-sm);
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: 999px;
  background: #fff;
  font-family: inherit;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.programme-choix-btn:hover:not(:disabled) { background: var(--gray-1); }

.programme-choix-btn:disabled { cursor: default; opacity: .45; }
.programme-choix.fige { opacity: .7; }

.programme-choix-btn.actif {
  border-color: var(--cyan);
  background: var(--cyan-light);
  color: var(--cyan-dark);
  font-weight: 600;
}

/* La carte d'un intervenant du client : « mets en place le meme systeme pour
   les intervenants, un clic sur un stylo sera necessaire pour modifier les
   infos pour rendre la carte plus pure » (suivi du 27 aout 2026).

   Le meme dessin que les cartes de l'equipe -- un rond, une identite en pile,
   le reste en pastilles -- et pour la meme raison : six champs alignes se
   lisaient comme un tableur, alors qu'on vient y chercher qui appeler chez le
   client. La saisie existe toujours, entiere ; elle attend derriere le
   crayon. */
.intervenant-carte {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.intervenant-carte:hover {
  border-color: var(--gray-3);
  box-shadow: var(--shadow-md);
}

/* Une face ou l'autre, jamais les deux : la carte se lit, ou elle se remplit.
   Les deux boutons, eux, restent la des deux cotes -- c'est ce qui permet de
   refermer la saisie sans chercher, et de supprimer sans l'ouvrir (suivi du
   27 aout 2026). */
.intervenant-carte > .reglages-intervenant-row { display: none; }
.intervenant-carte[data-edition] > .intervenant-lecture { display: none; }
.intervenant-carte[data-edition] > .reglages-intervenant-row { display: grid; }
.intervenant-carte > .reglages-intervenant-row,
.intervenant-carte > .intervenant-lecture { flex: 1; min-width: 0; }

/* Le second etage de la saisie : civilite, anniversaire, adresses postales,
   sites, et les notes ou atterrit ce que la fiche de contact portait sans case
   a lui (4 septembre 2026).

   Pleine largeur, sous la rangee, parce que sept colonnes ne pouvaient pas en
   porter douze : chacune y aurait valu deux centimetres, et la carte de saisie
   serait redevenue le tableur dont le crayon nous avait sortis.

   Et referme par defaut : « que ca ne prenne pas trop de place, les champs qui
   ne sont pas remplis [...] c'est une proposition ». Une fiche qui n'a rien
   dedans ne montre qu'un lien de deux mots ; le script ouvre l'etage des qu'un
   de ces champs porte quelque chose, sans quoi on ne saurait pas que c'est
   ecrit (voir `basculerEdition` dans dossier-intervenants.js). */
.intervenant-carte { flex-wrap: wrap; }

.intervenant-carte > .intervenant-complement,
.intervenant-carte > .intervenant-complement-plus {
  display: none;
  flex: 1 0 100%;
  min-width: 0;
}

.intervenant-carte[data-edition] > .intervenant-complement-plus { display: inline-flex; }
.intervenant-carte[data-edition][data-complement] > .intervenant-complement-plus { display: none; }
.intervenant-carte[data-edition][data-complement] > .intervenant-complement { display: grid; }

.intervenant-complement {
  /* La civilite est le plus etroit des champs du produit -- « M. » --, les
     notes le plus large : elles prennent la rangee entiere en dessous. */
  grid-template-columns: minmax(0, .45fr) minmax(0, .75fr) minmax(0, 1.4fr) minmax(0, 1.1fr);
  gap: var(--espace-sm);
  align-items: start;
  padding-top: var(--espace-sm);
  border-top: 1px dashed var(--gray-2);
}

.intervenant-complement > .reglages-intervenant-notes {
  grid-column: 1 / -1;
  resize: vertical;
}

/* Ce que la personne recoit, et a quel titre (ticket du 18 septembre 2026).

   Sur toute la largeur, sous les notes : quatre listes deroulantes rangees
   dans les quatre colonnes du second etage auraient mis chaque intitule sur
   deux lignes, et « Lettres de mission » sur trois. Elles se placent donc
   d'elles-memes, autant par rangee que la largeur en porte.

   `auto-fit` plutot qu'un nombre fixe : un type de document ajoute au serveur
   parait ici sans qu'on revienne compter les colonnes. */
.intervenant-complement > .reglages-intervenant-documents {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--espace-xs) var(--espace-sm);
  align-items: end;
}

/* L'intitule du bloc, du meme corps que les autres etiquettes discretes du
   panneau : il annonce quatre listes qui ne se comprendraient pas seules --
   « Rapports » suivi de « Ne recoit pas » ne dit pas de quoi il s'agit. */
.reglages-intervenant-documents-titre {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.reglages-intervenant-document {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  min-width: 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Discret comme le « + adresse » d'une cellule multivaleur, et pour la meme
   raison : il est sur chaque carte ouverte, alors qu'on s'en sert une fois par
   fiche. */
.intervenant-complement-plus {
  align-self: flex-start;
  font-size: var(--fs-xs);
  color: var(--gray-4);
  padding-top: var(--espace-2xs);
}

.intervenant-complement-plus:hover { color: var(--cyan-dark); }
.intervenant-complement-plus .icon { width: var(--icon-xs); height: var(--icon-xs); }

/* Les notes sur la carte refermee : une bande pleine largeur sous les
   pastilles, pliee a deux lignes. Une fiche de carnet d'adresses porte parfois
   une page entiere de notes -- codes d'acces, horaires, historique --, et une
   liste de dix intervenants ne peut pas devenir dix pages. Un clic deplie. */
.intervenant-note {
  flex: 1 0 100%;
  margin-top: var(--espace-2xs);
  padding: var(--espace-2xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  white-space: pre-line;
  overflow-wrap: anywhere;
  max-height: 3.2em;
  overflow: hidden;
  cursor: pointer;
}

.intervenant-note[data-depliee] { max-height: none; }

.intervenant-lecture {
  display: flex;
  align-items: center;
  /* Les notes se replient sous les pastilles, sur toute la largeur : elles
     sont la seule chose de la carte qui puisse tenir en phrases. */
  flex-wrap: wrap;
  gap: var(--espace-sm);
}

/* Le crayon et la poubelle, cote a cote mais separes : le second est le seul
   bouton rouge de la carte, et il demande confirmation.

   Separes pour de bon depuis le 26 aout 2026 : ils se touchaient au barreau le
   plus serre de l'echelle, et rien ne les entourait -- deux dessins gris poses
   sur le blanc de la carte, a quatre pixels l'un de l'autre. Ils prennent
   l'ecart de rang du reste de la feuille, et le meme carre cerne que les autres
   boutons du panneau Mandat : la carte etait le dernier endroit ou une icone
   restait nue, ce qui la faisait ressortir au lieu de la fondre. */
.intervenant-actions {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  flex: none;
}

/* Le remplissage de .icon-btn donnait 42x34 : un rectangle, la ou tout le
   panneau tient des carres de --h-sm. `min-height: 0` desarme les deux
   planchers poses sur .icon-btn -- celui de la base et, au telephone, la cible
   tactile qui vaut plus que la hauteur demandee ici et laisserait un carre de
   28 de large sur 44 de haut ; le telephone reprend les deux mesures ensemble,
   en cible tactile pleine. */
.intervenant-actions > .icon-btn {
  width: var(--h-sm);
  height: var(--h-sm);
  min-height: 0;
  padding: 0;
  gap: 0;
  justify-content: center;
  flex: none;
  border-color: var(--gray-3);
  background: #fff;
  transition: background .15s var(--ease), border-color .15s var(--ease),
              color .15s var(--ease);
}

/* Le fond blanc pose ci-dessus est plus specifique que `.icon-btn:hover` : sans
   ces deux regles, le survol ne repeindrait plus rien du tout. Il prend donc la
   couleur du geste, comme les boutons cernes des lignes de reglages. */
.intervenant-actions > .icon-btn:hover {
  background: var(--cyan-pale);
  border-color: var(--cyan);
  color: var(--cyan-dark);
}

.intervenant-actions > .icon-btn.btn-danger:hover {
  background: var(--red-pale);
  border-color: var(--red);
  color: var(--red);
}

/* Le rond porte des initiales quand rien n'a ete pose dessus. Pas de couleur a
   lui pour autant : un intervenant du client n'a pas de compte, et une teinte
   tiree au sort laisserait croire a un profil. Un gris neutre le dit mieux.

   Une image depuis le 31 aout 2026 : « dans "Intervenant du client", on doit
   pouvoir associer un logo ou une photo ». Les initiales restent le defaut --
   une fiche sans image se reconnait comme avant. */
.intervenant-rond {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: var(--gray-2);
  color: var(--gray-5);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .02em;
  overflow: hidden;
}

/* Le relief commun aux ronds de profil s'applique ici aussi : un rond habille
   d'une image appartient a cette famille-la (voir --avatar-relief). Le fond
   blanc plutot que le gris : un logo arrive souvent detoure, et le gris se
   verrait au travers comme une salissure. */
.intervenant-rond-photo {
  background-color: #fff;
  box-shadow: var(--avatar-relief);
}

.intervenant-rond-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Le meme rond dans la saisie, mais cliquable : c'est la ou l'image se lit
   qu'on la pose. Le bouton n'est que le rond -- aucune bordure, aucun fond a
   lui --, et la croix qui retire l'image se pose dessus en haut a droite,
   comme sur les autres vignettes du produit. */
.intervenant-photo {
  position: relative;
  justify-self: start;
}

.intervenant-photo-btn {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 999px;
}

.intervenant-photo-btn:disabled { cursor: default; opacity: .55; }

.intervenant-photo-btn:not(:disabled):hover .intervenant-rond {
  outline: 2px solid var(--cyan);
  outline-offset: 1px;
}

.intervenant-photo-retirer {
  position: absolute;
  top: -4px;
  right: -4px;
  width: var(--icon);
  height: var(--icon);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: 999px;
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-xs);
  line-height: 1;
  cursor: pointer;
}

.intervenant-photo-retirer:hover { color: var(--red); border-color: var(--red); }

/* Le nom et la fonction sur la meme ligne, la fonction contre le nom : « il
   faut qu'on puisse voir la fonction au premier coup d'oeil [...] et que ce
   soit meme une des informations les plus importantes » (ticket du 28 aout
   2026). Elle etait empilee dessous, en gris et en petit -- la place de ce
   qu'on peut ne pas lire. */
.intervenant-identite {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--espace-2xs);
  min-width: 0;
}

.intervenant-nom {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
}

.intervenant-fonction {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--cyan-pale);
  color: var(--cyan-dark);
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
}

/* Une fonction qui manque se voit : sans elle, une fiche incomplete avait
   exactement l'allure d'une fiche complete. */
.intervenant-fonction-vide {
  background: var(--gray-2);
  color: var(--gray-4);
  font-weight: 400;
  font-style: italic;
}

.intervenant-details {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-2xs);
  flex: 1;
  min-width: 0;
}

/* La pastille tenait sur une ligne quoi qu'il arrive. Une adresse de trente-
   quatre caracteres est plus large que la place qui lui reste des que la tuile
   se met en paire : elle etait coupee en plein milieu d'un mot, sans rien pour
   le dire, et passait sous le crayon de la carte.

   La liste des pastilles revient deja a la ligne d'elle-meme (`flex-wrap` sur
   `.intervenant-details`) ; ce qui manquait est le cran d'apres. La cadence
   voulue : on passe a la ligne entre deux pastilles d'abord, a l'interieur
   d'une pastille seulement si elle ne tient pas a elle seule. `anywhere` et
   non `break-word` parce qu'une adresse n'a pas de cesure a offrir. */
.intervenant-detail {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  min-width: 0;
  overflow-wrap: anywhere;
}

.intervenant-detail .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--gray-4);
}

/* « Egalement dans 3 autres mandats ». Teinte a l'accent, la ou une adresse et
   un numero restent gris : ce n'est pas une coordonnee de plus, c'est ce que
   l'application sait de la personne en regardant les autres mandats. Le meme
   gris les aurait alignes, et on aurait cherche le numero de telephone dans
   la phrase. */
.intervenant-detail-lien {
  position: relative;
  background: var(--cyan-pale);
  color: var(--cyan-dark);
  cursor: help;
}

.intervenant-detail-lien > .icon { color: var(--cyan-dark); }

/* Les mandats nommes, et ouverts d'un clic.
 *
 * « Quand on survole "Egalement dans 2 autres mandats", on peut voir un
 * affichage de mandat associe en fenetre flottante type survol du nombre de
 * FEC, et possibilite de cliquer sur le dossier en question » (suivi du
 * 28 aout 2026). La pastille disait combien, et une infobulle native disait
 * lesquels -- apres quoi il fallait retenir le nom, revenir a la liste des
 * clients et l'y chercher. Le panneau y mene.
 *
 * Meme famille de surface flottante que `.dossier-fec-resume` : blanc,
 * `--radius-lg`, bordure `--gray-3`, ombre portee. Une difference, qui est
 * tout l'objet de la demande -- celui-la se regarde, celui-ci se clique : il
 * garde donc ses `pointer-events`, et comme il est enfant de la pastille, le
 * survol tient tant que la souris le traverse. */
.intervenant-mandats {
  position: absolute;
  bottom: calc(100% + var(--espace-xs));
  right: 0;
  z-index: 40;
  display: none;
  flex-direction: column;
  gap: var(--espace-3xs);
  min-width: 100%;
  width: max-content;
  max-width: min(24rem, calc(100vw - 2rem));
  padding: var(--espace-xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  text-align: left;
  white-space: normal;
  cursor: default;
}

/* Le pont : l'écart entre la pastille et le panneau, rendu survolable. Sans
   lui, le pointeur qui monte vers les liens quitte la pastille avant d'avoir
   atteint le panneau, et la fenêtre se referme au milieu du geste (suivi du
   28 août 2026). Il fait partie du panneau, donc il ne s'ouvre pas tout seul. */
.intervenant-mandats::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: var(--espace-xs);
}

/* `.ouvert` et non `:hover` : le survol de la seule pastille se ferme à
   l'instant où on la quitte, et le pointeur qui monte vers les liens la quitte
   en chemin. C'est la tuile entière qui tient la fenêtre ouverte -- la
   frontière de survol-frontiere.js, dont c'est ici le premier usage.

   `:focus-within` et non `:focus` : la mise au point peut etre sur la pastille
   comme sur un des liens qu'elle contient, et le panneau doit rester ouvert
   dans les deux cas -- sans quoi tabuler d'un mandat au suivant le refermerait
   sous le doigt. */
.intervenant-detail-lien.ouvert .intervenant-mandats,
.intervenant-detail-lien:focus-within .intervenant-mandats { display: flex; }

.intervenant-mandats-titre {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
  padding: 0 var(--espace-2xs) var(--espace-3xs);
}

.intervenant-mandat {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  padding: var(--espace-2xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  font-size: var(--fs-xs);
  color: var(--gray-6);
  text-decoration: none;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.intervenant-mandat:hover,
.intervenant-mandat:focus-visible {
  background: var(--cyan-pale);
  color: var(--cyan-dark);
}

.intervenant-mandat-nom {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Le chevron dit que la ligne mene ailleurs, comme au bout d'une ligne de
   mandat dans la liste des clients : meme dessin, meme gris, meme taille. */
.intervenant-mandat > .icon {
  flex: none;
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--gray-4);
}

.intervenant-mandat:hover > .icon,
.intervenant-mandat:focus-visible > .icon { color: var(--cyan-dark); }

/* ---------------------------------------------------------------------------
   L'onglet Assistant : le releve de ce qui manque, se contredit ou merite
   d'etre dit sur un mandat.

   Un releve se parcourt de haut en bas et s'arrete sur ce qui saute aux yeux :
   la marque de gauche porte donc la nature du constat, et rien d'autre ne la
   porte. Le titre reste noir dans les trois cas -- une liste ou chaque ligne
   est d'une couleur differente ne se hierarchise plus.
   --------------------------------------------------------------------------- */

/* Le resume et le bouton de la zone, sous son titre.

   Ils portaient un filet gris en dessous d'eux, du temps ou rien d'autre ne
   disait ou commencait la zone. La tuile le dit maintenant, et deux traits pour
   une seule separation font un cadre a l'interieur d'un cadre. */
.assistant-entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace-md);
  flex-wrap: wrap;
  margin-bottom: var(--espace-md);
}

/* Les groupes de constats, hors de la tuile d'entete et avant celle de la
   veille. Chacun est une tuile : 16 px les separent entre eux (`.tuile +
   .tuile`), 32 les separent des zones (`.panel`), et cette difference suffit a
   les lire comme la suite de l'entete plutot que comme trois zones de plus. */
.assistant-groupes {
  margin-bottom: var(--espace-2xl);
}

.assistant-entete-texte {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  flex-wrap: wrap;
}

/* Le compte de ce qui a ete trouve. Il etait en 600 du temps ou il tenait lieu
   de titre a une zone qui n'en avait pas ; il en a un maintenant, une ligne
   au-dessus, et deux graisses pleines l'une sur l'autre ne se hierarchisent
   plus. Un cran en dessous : le titre nomme, le resume compte. */
.assistant-resume {
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--gray-6);
}

.assistant-constats {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* La carte d'un constat porte `.tuile-encart` : elle est dans une tuile, elle
   en prend donc le dessin de second rang -- `--radius-sm`, bordure `--gray-2`.
   Elle avait celui du premier (`--radius`, `--gray-3`), ce qui allait tant que
   rien ne l'entourait ; sous une tuile de groupe, c'etait une fenetre sur une
   fenetre.

   La barre de gauche, elle, reste, et reste epaisse : le titre du groupe sort
   de l'ecran des qu'on descend dans une longue liste, la couleur de la barre
   non. Ecrite en `border-left` seul, apres le raccourci de `.tuile-encart`
   qu'elle recouvre sur ce seul cote. */
.assistant-constat {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: var(--espace);
  padding: var(--espace-sm) var(--espace);
  border-left: 3px solid var(--gray-4);
}

.assistant-constat[data-gravite="incoherence"] { border-left-color: var(--red); }
.assistant-constat[data-gravite="manque"] { border-left-color: var(--orange); }
.assistant-constat[data-gravite="remarque"] { border-left-color: var(--gray-4); }
/* Ce qui est reglé, et non ce qui n'a rien a dire : « quand c'est validé passe
   du rouge au vert plutot que gris » (ticket du 4 septembre 2026). Le suivi de
   l'arrete des comptes peint trois etats -- rouge en retard, orange bientot,
   gris en attente -- et le quatrieme, celui des lignes faites, tombait sur le
   gris par defaut : une convocation dont on venait de preciser le mode passait
   du rouge au gris, c'est-a-dire de « il manque quelque chose » a « rien a
   signaler », quand elle voulait dire « c'est fait ».

   Vert et non gris, donc, et c'est le vert de la palette, celui du resultat
   positif et du mandat a jour. Sur le telephone, l'ecran compose du suivi
   n'a pas de couleur d'etat au catalogue (`ligne_valeur`) : c'est le mot
   « Fait » qui porte la meme distinction, deja, a cote de « En retard » et
   « Bientot ». */
.assistant-constat[data-gravite="fait"] { border-left-color: var(--green); }

.assistant-marque {
  width: var(--icon);
  height: var(--icon);
  margin-top: var(--espace-3xs);
  color: var(--gray-4);
}

/* LE CADENAS DU BLOC DE CLOTURE, a la place du rond d'etat : « remplace le
   petit rond placé devant "Clôture du dossier" par l'icône carrée avec le
   cadenas déjà créée, qui signifie "Verrouiller l'exercice" » (suivi du
   8 septembre 2026).

   Le carre est celui de l'en-tete du mandat (`.avancement-seg`), a la lettre :
   c'est le meme geste, il ne doit pas avoir un second dessin. Ce qui change est
   qu'il n'appartient a aucun groupe, donc rien ne le designe comme retenu : le
   voile qui attenue un carre non choisi n'a pas lieu d'etre ici, il n'y a pas
   de choix a faire, il y a un geste a offrir. La place du rond qu'il remplace
   se retrouve d'un rien de marge haute -- le rond en avait autant. */
.arrete-verrou {
  --seg-voile: 1;
  margin-top: var(--espace-3xs);
}

.arrete-verrou:hover {
  border-color: var(--red);
  background: var(--red-pale);
}

.arrete-verrou:hover .avancement-lock-icon { color: var(--red); }

.assistant-constat[data-gravite="incoherence"] .assistant-marque { color: var(--red); }
.assistant-constat[data-gravite="manque"] .assistant-marque { color: var(--orange); }
.assistant-constat[data-gravite="fait"] .assistant-marque { color: var(--green); }

.assistant-titre {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.assistant-detail {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* L'exercice concerne, en gelule a cote de ce qu'il date : le titre du module,
   les deux intitules d'organe de la saisie, et les deux etapes d'organe du
   releve. « Il faut toujours indiquer l'exercice concerne pour eviter toute
   ambiguite » (suivi du 1er septembre 2026) -- une date d'arrete sans son
   exercice ne dit pas de quel exercice elle est l'arrete, et un exercice
   decale rend l'annee seule inutilisable.

   Neutre, et volontairement : ce n'est pas un etat, c'est une precision. Les
   couleurs de ce module sont prises par les trois etats d'une etape (fait,
   proche, en retard), et une quatrieme teinte a cote d'eux se lirait comme un
   quatrieme etat. Completement ronde -- 999px, pas une valeur intermediaire. */
.assistant-exercice {
  display: inline-block;
  margin-left: var(--espace-xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: 999px;
  background: var(--gray-2);
  color: var(--gray-5);
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-titre);
  text-transform: none;
  vertical-align: middle;
}

/* « BLOQUANT », CONTRE L'INTITULE D'UNE PIECE ATTENDUE.

   « Si un document attendu est qualifié de bloquant dans Mandat, le document
   attendu dans l'Assistant doit indiquer qu'il est bloquant » (ticket du
   12 septembre 2026).

   Le meme rouge pale que la case cochee de « Nature du mandat »
   (`.documents-attendus-bloquant:has(input:checked)`) : c'est la meme notion,
   dite au meme endroit du produit, et une seconde teinte l'aurait detachee de
   la case ou elle se decide. Meme boite que l'exercice juste au-dessus, parce
   que les deux se posent contre le meme titre et doivent s'aligner. */
.arrete-bloquant {
  display: inline-block;
  margin-left: var(--espace-xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: 999px;
  background: var(--red-pale);
  color: var(--red);
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-titre);
  text-transform: none;
  vertical-align: middle;
}

/* Les cases citees, sur deux colonnes quand il y en a beaucoup : une liste de
   dix intitules en pleine largeur repousse le constat suivant hors de l'ecran,
   et c'est le suivant qu'on cherche.

   Deux colonnes, mais pas sur toute la largeur d'un ecran de bureau : la carte
   fait mille sept cents pixels, et « Telephone » se retrouvait a huit cents
   pixels de « Courriel » -- deux items d'une meme liste qu'on ne lit plus comme
   une liste. La largeur de lecture est le barreau fait pour ca. */
.assistant-elements {
  margin: var(--espace-2xs) 0 0;
  padding-left: var(--espace-md);
  max-width: var(--largeur-lecture);
  columns: 2;
  column-gap: var(--espace-xl);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.assistant-elements li {
  break-inside: avoid;
  margin-bottom: var(--espace-3xs);
}

/* ---------- Les blocs de l'arrete et de l'approbation ----------

   « Simplifie la partie "Arrete et approbation des comptes" en supprimant les
   informations redondantes [...] presente l'ensemble de la maniere la plus
   simple et intuitive possible » (ticket du 2 septembre 2026).

   Un bloc reprend la carte d'un constat de l'Assistant -- meme encart, meme
   filet de gauche colore par la gravite, meme marque -- et lui ajoute les
   dates qui s'y saisissent. Elles etaient dans un formulaire a part, sous le
   releve, ou chaque date se lisait une seconde fois.

   Il n'y a plus de lignes repliees dedans depuis le 4 septembre 2026 : la
   convocation etait une ligne de plus sous un titre qui nommait deja la meme
   seance, et les deux ont fusionne dans la tete du bloc (voir
   arrete_comptes._blocs). Les regles .arrete-ligne* sont parties avec elles. */
.arrete-blocs {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* Reprendre une analyse qui a échoué. Un bouton-texte au fil du bloc, pas un
   bouton de formulaire : il ne vaut que pour cette convocation-là, il disparaît
   dès que la lecture aboutit, et un bouton plein l'aurait rendu plus visible
   que l'alerte qu'il répare. */
.arrete-reprendre {
  margin-left: var(--espace-xs);
  padding: 0;
  border: 0;
  background: none;
  color: var(--cyan);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
}

.arrete-reprendre[disabled] { color: var(--gray-4); cursor: default; }

/* Le mode de réception, choisi dans la liste close des six formes. Le contrôle
   lui-même est déjà rhabillé à la base de la feuille, par l'élément : rien à
   redessiner ici, seulement une largeur qui tienne « lettre recommandée avec
   avis de réception » sans pousser la case voisine hors du bloc. */
.arrete-mode { max-width: 22rem; }

/* Une pièce qu'on peut ouvrir. Discrète tant qu'on ne la vise pas : c'est une
   preuve posée sous un constat, pas un appel à cliquer -- et une ligne de liens
   colorés dans une tuile de suivi se lirait comme un menu. */
.arrete-piece {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--gray-3);
}

.arrete-piece:hover,
.arrete-piece:focus-visible {
  color: var(--cyan);
  border-bottom-color: currentColor;
}

/* Le nom d'une pièce tient sur une ligne.

   « Affiche si possible sur une seule ligne le nom de chaque fichier PDF,
   notamment celui des deux convocations » (ticket du 5 septembre 2026). La
   liste des éléments d'un constat est faite pour des libellés courts, posés sur
   deux colonnes dans une largeur de lecture : un nom de convocation en fait
   soixante caractères (« 2026-09-08 BUREAU ADP94 CPTS ADP ARRETES COMPTES
   CONVOCATION CAC (SIGNE).pdf ») et se repliait donc sur deux lignes, au milieu
   d'un bloc que le même ticket du 4 septembre venait de rendre compact.

   Une seule colonne, toute la largeur du bloc, et la coupure au bout : c'est
   déjà ce que fait la ligne d'un rapport (.arrete-compact-appoint), et il n'y a
   pas deux façons d'écrire un nom de fichier dans cette tuile. Le nom entier
   reste au survol, porté par la puce. */
.arrete-pieces {
  columns: 1;
  max-width: 100%;
}

.arrete-pieces li {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Les deux marques de la pièce, dans le suivi comme dans le Juridique.

   « Les tags verts et la mention "CC" doivent être entièrement synchronisés
   entre l'Assistant et le Juridique » (ticket du 5 septembre 2026). Ce sont les
   mêmes contrôles, donc le même dessin : la pastille de pointage est déjà
   habillée pour tout le produit (`.controle-pastille`), la marque du CAC aussi
   (`.badge-maison`). Ce qui se pose ici est ce que la ligne d'un tableau posait
   de son côté et qu'une puce n'a pas : la teinte de l'état, écrite pour `tr`, et
   le creux d'une marque qu'on n'a pas encore posée.

   La marque en creux et non absente : une marque qui n'apparaît qu'une fois
   posée ne se pose jamais, faute de se trouver. C'est déjà le parti de la
   pastille de pointage, grise avant tout pointage. */
.arrete-pieces li[data-controle="valide"] .pastille-valide { color: var(--green); }
.arrete-pieces li[data-controle="valide"] .controle-pastille { opacity: 1; }
.arrete-pieces li[data-controle="probleme"] .pastille-probleme {
  color: var(--orange);
  display: inline-block;
}
.arrete-pieces li[data-controle="probleme"] .pastille-valide { display: none; }
.arrete-pieces li[data-controle="probleme"] .controle-pastille { opacity: 1; }

.arrete-compact-appoint[data-controle="valide"] .pastille-valide { color: var(--green); }
.arrete-compact-appoint[data-controle="valide"] .controle-pastille { opacity: 1; }
.arrete-compact-appoint[data-controle="probleme"] .pastille-probleme {
  color: var(--orange);
  display: inline-block;
}
.arrete-compact-appoint[data-controle="probleme"] .pastille-valide { display: none; }
.arrete-compact-appoint[data-controle="probleme"] .controle-pastille { opacity: 1; }

/* La marque du CAC posée dans le suivi : un bouton, puisqu'elle s'y pose et s'y
   retire, là où le Juridique la range dans le menu de la ligne. Sans fond ni
   filet -- c'est une marque, pas une commande --, en creux tant qu'elle n'est
   pas posée, et pleine dès qu'elle l'est. */
.arrete-marque-cac {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  opacity: .3;
  transition: opacity .12s var(--ease);
}

.arrete-marque-cac[data-maison="1"],
.arrete-marque-cac:hover,
.arrete-marque-cac:focus-visible { opacity: 1; }

/* La marque précède le nom : c'est la marge de gauche du badge qui n'a plus
   lieu d'être, et une marge de droite qui la sépare de ce qu'elle qualifie. */
.arrete-pieces .badge-maison,
.arrete-compact-appoint .badge-maison {
  margin-left: 0;
  margin-right: var(--espace-2xs);
}

.arrete-pieces .controle-pastille,
.arrete-compact-appoint .controle-pastille {
  margin-right: var(--espace-2xs);
}

@media (prefers-reduced-motion: reduce) {
  .arrete-marque-cac { transition: none; }
}

/* Les rapports que nous devons émettre, un par ligne.

   « Affiche clairement tous les rapports que nous devons émettre [...] regroupe
   les rapports dans un seul bloc » (ticket du 5 septembre 2026). Le bloc
   portait un intitulé au pluriel et une date : il disait combien, jamais
   lesquels.

   Une liste et non des blocs : c'est un seul bloc que le ticket demande, et ces
   deux lignes-là ne se saisissent pas, elles se constatent. Le nom du rapport
   ne se coupe jamais, celui du fichier si : c'est le second qui est de longueur
   imprévisible, comme partout ailleurs dans cette tuile. */
.arrete-rapports {
  list-style: none;
  margin: var(--espace-2xs) 0 0;
  padding: 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.arrete-rapports li {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  min-width: 0;
  margin-bottom: var(--espace-3xs);
}

.arrete-rapports .assistant-marque {
  margin-top: 0;
  flex: none;
  color: var(--gray-4);
}

.arrete-rapports li[data-etat="fait"] .assistant-marque { color: var(--green); }

/* Le logo du cabinet devant le nom du rapport : « affiche le logo du
   commissaire aux comptes devant chaque rapport » (ticket du 7 septembre 2026).

   La marge de gauche que `.badge-maison` porte partout ailleurs n'a pas lieu
   d'être ici, et pour la même raison qu'elle tombe sur une pièce de la tuile :
   la rangée est un `flex` dont le `gap` fait déjà l'écart, et les deux
   s'ajouteraient. C'est le même retrait que `.arrete-pieces .badge-maison`
   quelques règles plus haut. */
.arrete-rapports .badge-maison {
  margin-left: 0;
  flex: none;
}

.arrete-rapport-nom {
  flex: none;
  color: var(--gray-6);
}

/* Le nom du fichier, ou son absence : c'est lui qui prend la place restante et
   qui se coupe. « À émettre » se lit en gris, comme une échéance qui n'est pas
   encore une alerte : le bloc porte déjà sa couleur. */
.arrete-rapports li > a,
.arrete-rapports li > .arrete-rapport-attendu {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.arrete-rapport-attendu { color: var(--gray-4); }

/* « Émettre le rapport », au bout de la ligne du rapport qui manque.

   « Je souhaite générer automatiquement le rapport du commissaire aux comptes
   sur les comptes annuels à partir de l'assistant, simplement en cliquant sur
   "Émettre le rapport" » (ticket du 6 septembre 2026).

   Le dessin de « Réessayer » quelques lignes plus haut (`.arrete-reprendre`),
   et pour la même raison : c'est un geste offert dans une ligne de texte, pas
   un bouton de formulaire. Il ne prend donc ni fond ni filet, et se tient au
   bout de sa ligne. */
.arrete-emettre {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  color: var(--cyan);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.arrete-emettre:hover:not([disabled]),
.arrete-emettre:focus-visible { text-decoration: underline; }
.arrete-emettre[disabled] { color: var(--gray-4); cursor: default; }

/* Le même rapport en PDF, à côté du premier et en second.

   « Le rapport doit pouvoir être généré à la fois en Word et en PDF » (suivi du
   6 septembre 2026). Le Word garde le geste nommé, parce que c'est celui qu'on
   relit et qu'on retouche avant de signer ; le PDF est celui qu'on envoie, et
   trois lettres suffisent à le désigner. Deux boutons de même poids auraient
   posé un choix là où il n'y en a pas à faire. */
.arrete-emettre-second {
  margin-left: var(--espace-xs);
  color: var(--gray-5);
  font-weight: 500;
}

/* Ce qui manque au rapport, sous la liste des rapports.

   Nommé et non demandé : chaque manque dit l'écran où la valeur se saisit déjà
   pour autre chose (« Volet CNCC du mandat », « Réglages du mandat »), parce
   que le ticket écarte explicitement un questionnaire de plus. L'endroit se
   lit donc en gris, derrière ce qui manque, comme une indication. */
.arrete-rapport-manques {
  margin-top: var(--espace-xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.arrete-rapport-manques p { margin: 0 0 var(--espace-3xs); }

.arrete-rapport-manques ul {
  margin: 0;
  padding-left: var(--espace-md);
}

.arrete-rapport-manques strong { font-weight: 500; color: var(--gray-6); }

.arrete-manque-ou { color: var(--gray-4); }

/* Le questionnaire d'avant émission, à la place des manques quand il s'ouvre.

   « Avant d'émettre le rapport, propose un questionnaire très simple contenant
   uniquement les informations que le logiciel n'a pas trouvées » (ticket du
   6 septembre 2026). Il vit dans la même boîte que les manques, sous la ligne
   du rapport, parce que c'est le même sujet vu de plus près : ouvrir une
   fenêtre par-dessus la tuile aurait fait perdre de vue ce qu'on vient
   d'émettre.

   Un fond, un filet, et rien d'autre : les champs du produit sont déjà
   habillés, et un formulaire de quatre lignes n'a pas besoin d'une carte. */
.arrete-questionnaire {
  position: relative;
  margin-top: var(--espace-2xs);
  padding: var(--espace-sm);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: var(--gray-1);
}

.arrete-questionnaire h5 {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.arrete-questionnaire h6 {
  margin: 0 0 var(--espace-3xs);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-6);
}

.arrete-q-bloc { margin-top: var(--espace-sm); }
.arrete-q-bloc ul { margin: 0; padding-left: var(--espace-md); }

/* Le connu, en deux colonnes : « les réponses déjà connues doivent être
   préremplies et ne doivent pas être redemandées ». Il se relit, il ne se
   remplit pas, et c'est pourquoi il n'est pas fait de champs. */
.arrete-q-connu {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--espace-3xs) var(--espace-md);
  margin: 0;
}

.arrete-q-connu-ligne {
  display: flex;
  gap: var(--espace-2xs);
  justify-content: space-between;
}

.arrete-q-connu dt { color: var(--gray-4); }
.arrete-q-connu dd { margin: 0; color: var(--gray-6); text-align: right; }

.arrete-q-question { margin-bottom: var(--espace-xs); }

.arrete-q-question label {
  display: block;
  margin-bottom: var(--espace-3xs);
  color: var(--gray-6);
}

.arrete-q-question .arrete-q-champ { width: 100%; }

.arrete-q-aide {
  margin: var(--espace-3xs) 0 0;
  color: var(--gray-4);
}

/* LA PARTIE « OBSERVATIONS » DU QUESTIONNAIRE.

   « Permettre au commissaire aux comptes de sélectionner facilement les
   différentes observations susceptibles de devoir figurer dans son rapport,
   puis de générer automatiquement une formulation adaptée » (ticket du
   12 septembre 2026).

   Une carte par observation, sur le fond de la page et non sur celui du
   questionnaire : c'est le seul bloc du questionnaire qui porte plusieurs
   choses du même genre, et sans cette séparation les quatre champs de la
   deuxième se lisaient comme la suite des quatre de la première. */
.arrete-q-observations > label { font-weight: 500; }

.arrete-obs {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
  margin-top: var(--espace-xs);
}

.arrete-obs-aucune { margin: 0; color: var(--gray-4); }

.arrete-obs-ligne {
  padding: var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* Les champs par rangs, autant que la largeur en porte : « Note de l'annexe »
   se contente de quelques caractères, « Sujet » prend ce qui reste. */
.arrete-obs-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--espace-xs);
}

.arrete-obs-tete + .arrete-obs-tete { margin-top: var(--espace-xs); }

/* SOUS `.arrete-obs`, ET C'EST NÉCESSAIRE.

   Les étiquettes du questionnaire sont peintes par `.arrete-q-question label`,
   qui pèse une classe et un élément : une règle de classe seule y perdait, et
   les cinq contrôles se retrouvaient en `display: block`, leur liste déroulante
   à la suite du texte de la question au lieu d'être dessous. La marge et la
   couleur de la même règle passaient devant les nôtres pour la même raison. */
.arrete-obs .arrete-obs-champ {
  display: block;
  flex: 1 1 10rem;
  margin: 0;
  color: var(--gray-4);
  font-size: var(--fs-xs);
}

.arrete-obs .arrete-obs-champ input,
.arrete-obs .arrete-obs-champ select,
.arrete-obs .arrete-obs-champ textarea { width: 100%; }

.arrete-obs .arrete-obs-champ + .arrete-obs-champ { margin-top: 0; }

.arrete-obs .arrete-obs-ligne > .arrete-obs-champ { margin-top: var(--espace-xs); }

/* La situation et le sujet portent la ligne : les autres champs se rangent
   autour d'eux plutôt que de prendre le même tiers qu'eux. */
.arrete-obs .arrete-obs-famille { flex: 2 1 18rem; }
.arrete-obs .arrete-obs-sujet { flex: 2 1 16rem; }

.arrete-obs-retirer {
  flex: 0 0 auto;
  padding: var(--espace-2xs) var(--espace-xs);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: color .15s var(--ease), border-color .15s var(--ease);
}

.arrete-obs-retirer:hover {
  border-color: var(--red);
  color: var(--red);
}

.arrete-obs-ajouter {
  align-self: flex-start;
  padding: var(--espace-2xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  color: var(--gray-6);
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: border-color .15s var(--ease);
}

.arrete-obs-ajouter:hover { border-color: var(--cyan); }

.arrete-obs-regime {
  margin: var(--espace-2xs) 0 0;
  color: var(--gray-4);
  font-size: var(--fs-xs);
}

/* Les cinq questions de cohérence, en colonnes : elles se répondent d'un coup
   et non l'une après l'autre, et empilées elles doublaient la hauteur de la
   carte pour cinq listes de trois valeurs. */
.arrete-obs-controles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--espace-2xs) var(--espace-xs);
  margin-top: var(--espace-xs);
}

/* La question au-dessus de sa réponse, et non à côté : deux d'entre elles
   tiennent sur deux lignes, et la liste déroulante posée à côté se retrouvait
   à mi-hauteur d'un texte pendant que sa voisine était en haut du sien. */
.arrete-obs .arrete-obs-controle {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--espace-3xs);
  color: var(--gray-4);
  font-size: var(--fs-xs);
}

.arrete-obs .arrete-obs-controle select { width: 8rem; }

/* CE QUI SÉPARE UNE OBSERVATION D'UNE RÉSERVE SE VOIT DE LOIN.

   L'alerte est rouge parce qu'elle ne dit pas « attention » : elle dit que la
   situation relève d'une réserve, d'un refus ou d'une impossibilité de
   certifier, et que l'observation ne partira pas dans le rapport. */
.arrete-obs-alerte {
  margin: var(--espace-xs) 0 0;
  padding: var(--espace-2xs) var(--espace-xs);
  border-left: 2px solid var(--red);
  border-radius: var(--radius-xs);
  background: var(--red-pale);
  color: var(--red-dark);
  font-size: var(--fs-xs);
}

.arrete-obs-etiquette {
  margin: var(--espace-sm) 0 var(--espace-3xs);
  color: var(--gray-4);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* La phrase telle que le rapport l'écrira : c'est le cœur de la demande, donc
   elle se lit comme une citation du document et non comme une aide. */
.arrete-obs-phrase {
  margin: 0;
  padding: var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  color: var(--gray-6);
  font-size: var(--fs-sm);
}

.arrete-obs-phrase.est-attente { color: var(--gray-4); font-style: italic; }

/* Écartée : la phrase reste lisible -- on la corrige, on ne la retape pas --
   mais elle ne se lit plus comme ce que le rapport dira. */
.arrete-obs-phrase.est-ecartee {
  color: var(--gray-4);
  text-decoration: line-through;
  text-decoration-color: var(--red);
}

.arrete-q-actions {
  display: flex;
  align-items: center;
  gap: var(--espace-md);
  margin-top: var(--espace-sm);
}

.arrete-questionnaire-emettre,
.arrete-questionnaire-projet {
  padding: 0;
  border: 0;
  background: none;
  color: var(--cyan);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

/* « Garde le bouton "PDF" pour visualiser le projet » (ticket du 16 septembre
   2026). Le même dessin que le second bouton de la ligne du rapport, et pour
   la même raison : ce n'est pas le geste de la boîte, c'est celui d'à côté. */
.arrete-questionnaire-projet {
  color: var(--gray-5);
  font-weight: 500;
}

/* LA CROIX ROUGE, À LA PLACE DE « FERMER » ET DANS LE COIN.

   « Remplace le bouton "Fermer" par une croix rouge et ajoute une croix rouge
   en haut à droite pour fermer la fenêtre » (même ticket). Le dessin est celui
   de la croix des fenêtres du produit (`.modal-close`) : rond, rouge, fond
   pâle au survol. Il est repris ici plus petit, parce que la boîte se déplie
   dans la tuile et non par-dessus la page -- une cible de 32 px y pèserait
   autant que le bouton d'émission. */
.arrete-questionnaire-fermer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--red);
  cursor: pointer;
  transition: background .15s var(--ease);
}

.arrete-questionnaire-fermer .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

.arrete-questionnaire-fermer:hover,
.arrete-questionnaire-fermer:focus-visible { background: var(--red-pale); }

/* Celle du haut se pose dans le coin de la boîte, en face de la première
   question : le geste de fermeture est là où l'œil le cherche, et la question
   garde toute sa largeur -- la croix tient dans le creux du cadre. */
.arrete-q-croix-haut {
  position: absolute;
  top: var(--espace-2xs);
  right: var(--espace-2xs);
}

/* Et la première question lui laisse la place : hors du flux, la croix se
   poserait sinon sur la fin de son étiquette dès que la tuile est étroite. */
.arrete-q-croix-haut + .arrete-q-question label { padding-right: 26px; }

.arrete-questionnaire-emettre:hover:not([disabled]),
.arrete-questionnaire-emettre:focus-visible,
.arrete-questionnaire-projet:hover:not([disabled]),
.arrete-questionnaire-projet:focus-visible { text-decoration: underline; }

.arrete-questionnaire-emettre[disabled],
.arrete-questionnaire-projet[disabled] {
  color: var(--gray-4);
  cursor: default;
}

/* Les rendez-vous d'intervention, en tête de la tuile (ticket du 6 septembre
   2026 : « ces interventions doivent apparaître clairement dans l'assistant,
   par exemple : "Intervention sur place le 26 août 2025" »).

   La même liste que celle des rapports juste au-dessus, et c'est voulu : ce
   sont les deux seuls blocs qui énumèrent NOTRE travail, ils portent la même
   marque de commissaire aux comptes dans leur titre, et deux listes dessinées
   différemment dans la même tuile se liraient comme deux natures de chose.

   La phrase ne se coupe pas : elle est écrite par le serveur et fait trois
   mots de plus qu'une date. Ce qui se coupe dans cette tuile est ce qui est de
   longueur imprévisible -- un nom de fichier --, et un rendez-vous n'en a
   pas. */
.arrete-rdvs {
  list-style: none;
  margin: var(--espace-2xs) 0 0;
  padding: 0;
  font-size: var(--fs-xs);
  color: var(--gray-6);
}

.arrete-rdvs li {
  display: flex;
  align-items: baseline;
  gap: var(--espace-xs);
  margin-bottom: var(--espace-3xs);
}

.arrete-rdvs .assistant-marque {
  margin-top: 0;
  flex: none;
  color: var(--green);
  align-self: center;
}

/* Ce qu'un événement de calendrier a apporté, sous la phrase : le titre, le
   lieu, les personnes conviées (ticket du 6 septembre 2026). En retrait et en
   gris, parce que ce sont des précisions et non ce qu'on vient lire -- la
   phrase porte déjà le mode, les dates et les horaires.

   La ligne se coupe au bout : une liste de huit participants ne doit pas
   déborder de la carte. Le tout reste au survol. */
.arrete-rdv-corps {
  flex: 1;
  min-width: 0;
}

/* La phrase du rendez-vous et la corbeille qui le retire, sur la même ligne et
   collées l'une à l'autre.

   « Mets la poubelle qui est en bout de ligne. Juste après le rendez-vous et
   non pas au bout de la ligne » (ticket du 7 septembre 2026). La corbeille
   était rejetée à l'extrémité droite de la carte, où trois rendez-vous empilés
   alignaient trois corbeilles identiques loin de ce qu'elles retirent : on
   visait une ligne, pas un rendez-vous.

   La phrase ne pousse pas : elle prend ce qu'il lui faut, la corbeille suit, et
   le vide reste à droite. `min-width: 0` pour qu'une phrase plus large que la
   carte se coupe au lieu de repousser la corbeille dehors. */
.arrete-rdv-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
}

.arrete-rdv-phrase {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.arrete-rdv-details {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Retirer un rendez-vous : la corbeille rouge du reste du produit.

   C'était un bouton-texte souligné, « Retirer », copié sur le « Réessayer » de
   l'analyse : « remplace le bouton "Retirer" par une icône de poubelle rouge,
   afin d'utiliser la même présentation et la même logique de suppression que
   dans le reste du site » (ticket du 6 septembre 2026). Il avait raison, et pas
   seulement sur la forme : c'était le SEUL bouton de suppression du site à
   écrire son verbe, quinze autres portant déjà la corbeille (le logo d'un
   client, un projet de lettre de mission, une pièce du dossier permanent). Un
   mot souligné au bout d'une ligne se lit d'ailleurs comme un lien, pas comme
   une suppression.

   La forme entière vient donc des classes communes -- `btn-link btn-danger
   btn-sm btn-icon-only` --, et il ne reste ici que ce qui lui est propre : il
   ne se comprime pas, et il s'éteint pendant l'appel. Sa place, elle, est
   celle que lui donne `.arrete-rdv-ligne` juste au-dessus. Ce qui n'est plus
   écrit ici ne peut plus diverger. */
.arrete-rdv-retirer { flex: none; }

.arrete-rdv-retirer[disabled] { color: var(--gray-4); cursor: default; }

/* Poser un rendez-vous : la rangée de saisie du bloc, bâtie comme celle des
   dates de séance (`.arrete-champs`), au même écart et sur la même ligne tant
   que la place le permet. Deux rangées différentes pour deux saisies du même
   module obligeraient à apprendre deux fois. */
.arrete-rdv-ajout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs) var(--espace);
  margin-top: var(--espace-sm);
}

.arrete-rdv-poser {
  padding: var(--espace-3xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--gray-6);
  font: inherit;
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.arrete-rdv-poser:hover {
  border-color: var(--cyan);
  background: var(--cyan-pale);
}

/* Le cadre où l'on lâche un événement de calendrier.

   « Je voudrais pouvoir glisser-déposer un événement provenant d'Apple
   Calendrier, de Google Agenda ou d'un autre calendrier » (ticket du
   6 septembre 2026).

   Le trait pointillé des zones de dépôt du produit, en plus discret : c'est un
   raccourci, pas la façon ordinaire de poser un rendez-vous, et on en pose dix
   à la main pour un qu'on lâche. Il vient donc SOUS le formulaire, et n'en
   prend ni la hauteur ni le contraste.

   `dragover` est posée par le module, pas par le navigateur : c'est la classe
   que les zones de fichiers utilisent déjà, et la même teinte les allume. */
.arrete-rdv-lacher {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px dashed var(--gray-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  transition: border-color .15s var(--ease), background .15s var(--ease);
}

.arrete-rdv-lacher .icon {
  flex: none;
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
}

.arrete-rdv-lacher.dragover {
  border-color: var(--cyan);
  background: var(--cyan-pale);
  color: var(--gray-6);
}

/* Les deux sens de l'échange avec l'agenda, sur la même ligne.

   « Pour importer des événements dans la zone de rendez-vous, il faut aussi
   pouvoir les exporter en fichier ICS » (ticket du 7 septembre 2026). Ce qui
   entre et ce qui sort se lisent côte à côte : chercher l'export ailleurs dans
   le bloc, sous la corbeille d'un rendez-vous, l'aurait détaché de la zone dont
   il est le pendant.

   La marge du haut est portée par la rangée depuis ce ticket, et non plus par
   le cadre de dépôt : deux marges sur deux enfants d'une même rangée se seraient
   ajoutées à la première ligne repliée.

   `flex-wrap` et une base large sur le cadre : sous une colonne étroite, les
   deux passent l'un sous l'autre plutôt que de se serrer à quatre mots. */
.arrete-rdv-echanges {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--espace-xs);
  margin-top: var(--espace-xs);
}

.arrete-rdv-echanges .arrete-rdv-lacher { flex: 1 1 18rem; }

/* Le lien qui rend le fichier. Le trait PLEIN là où le dépôt a le pointillé :
   le pointillé dit « posez quelque chose ici », et un lien qu'on clique n'attend
   rien. Même hauteur, même taille de texte, même teinte au survol que la zone
   voisine : c'est la même famille, dans l'autre sens. */
.arrete-rdv-exporter {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  text-decoration: none;
  transition: border-color .15s var(--ease), background .15s var(--ease),
              color .15s var(--ease);
}

.arrete-rdv-exporter .icon {
  flex: none;
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
}

.arrete-rdv-exporter:hover {
  border-color: var(--cyan);
  background: var(--cyan-pale);
  color: var(--gray-6);
}

.arrete-rdv-exporter:hover .icon { color: var(--cyan); }

/* La marque du CAC dans le titre d'un bloc : elle suit l'intitulé, comme elle
   suit le nom d'un fichier dans les zones de dépôt, et elle ne se clique pas
   ici -- c'est un repère sur ce que le bloc suit, pas un état à changer. */
.assistant-titre .badge-maison { vertical-align: -.15em; }

/* Le compte à rebours de la séance, en page de calendrier.

   « Remplace "Arrêter les comptes dans 3 jours" par un calendrier compte à
   rebours très visuel, affichant clairement "J-3" et permettant de comprendre
   immédiatement que la clôture est dans trois jours » (ticket du 5 septembre
   2026). La phrase disait déjà le compte ; elle le disait en huit mots au
   milieu d'une ligne qui en porte d'autres, et il fallait la lire pour la
   trouver.

   La forme d'une page de calendrier -- un bandeau de date, un grand caractère
   dessous -- parce que c'est la forme qu'on reconnaît avant de lire. Flottée à
   GAUCHE : « déplace la vignette de la droite vers la gauche pour améliorer la
   lisibilité » (suivi du 5 septembre 2026). Elle était à droite, dans la marge
   que la colonne laisse vide, et c'est précisément ce qui la desservait : ce
   qu'on lit d'abord, sur une page qui se lit de gauche à droite, est le bord
   gauche. La vignette y prend le rang qui est le sien -- on ouvre le bloc pour
   savoir combien de jours il reste --, et le texte se replie autour d'elle
   comme il se repliait de l'autre côté.

   **Sous l'intitulé et non devant lui**, et plus étroite : « réduis la largeur
   de la vignette et place-la sous "Convocation", sans qu'elle chevauche la
   première ligne » (suivi du 5 septembre 2026). Le déplacement se fait dans le
   gabarit -- un flottant ne pousse que ce qui le suit, donc il suffit de la
   poser après le titre (voir dossier-arrete.js) --, et la largeur ici : 3,9 rem
   amputaient la ligne d'intitulé de quatre centimètres, « Convocation au bureau
   d'arrêté des comptes 2025 » y passait sur deux lignes serrées contre elle.
   3,1 rem tiennent « Jour J » comme « J-12 » et laissent la ligne respirer.

   Le grand caractère est le repère et non le quantième : « mets surtout en
   évidence "J-3", plutôt que la date du calendrier » (même suivi). La date,
   elle, passe entière au bandeau : elle reste lisible, elle ne se lit plus la
   première.

   **Le tableau a rabats**, depuis le ticket du 5 septembre 2026 : « donne a la
   vignette du compte a rebours un style inspire des anciens tableaux a rabats
   des aeroports, avec un affichage tres visuel de "J-3" ». La forme de la page
   de calendrier reste -- un bandeau de date, le repere dessous --, c'est la
   matiere qui change : fond d'encre, volets clairs, un caractere par volet et
   la charniere qui les fend en deux. Trois choses font qu'on reconnait un
   Solari avant de le lire, et ce sont exactement celles-la.

   Aucune couleur nouvelle. Le fond est `--black`, l'encre du produit (le noir
   pur n'existe pas dans cette charte) ; les volets sont `--gray-6`, le gris le
   plus sombre ; la charniere est le fond lui-meme, ce qui est la verite d'un
   vrai tableau -- on voit le noir entre les deux moities du volet. L'urgence,
   elle, teinte les caracteres et non plus le bandeau : sur fond d'encre, ce
   sont les barreaux PLEINS qui se lisent (--orange, --red), la ou les barreaux
   sombres etaient faits pour un fond pale.

   La vignette ne porte aucune valeur ecrite a la main hors celles qui n'ont pas
   de barreau : la largeur d'un volet, qui se mesure en chasse de caractere. */
/* La rangée d'un bloc de séance : le tableau à rabats, puis tout le reste dans
   une colonne.

   « Lorsque le fichier de convocation existe, la troisième ligne et le tableau
   doivent être parfaitement alignés avec la deuxième, sans aucun décalage »
   (suivi du 6 septembre 2026). La vignette était flottée à gauche, et un
   flottant n'aligne rien : chaque ligne se replie à sa droite avec sa propre
   marge de gauche, si bien que la puce de la pièce -- qui porte le retrait
   d'une liste (`.assistant-elements`) -- partait seize pixels plus loin que la
   ligne de saisie juste au-dessus.

   Une colonne les tient toutes sur le même bord, quelles que soient les marges
   que chacune porte pour son propre compte ailleurs dans la feuille. Et la
   rangée commence en haut : le tableau est une page de calendrier, il se lit à
   la hauteur de la première ligne qu'il date, pas au milieu du bloc.

   `min-width: 0` sur la colonne, sans quoi un nom de fichier de quatre-vingts
   caractères la pousserait au-delà de la carte au lieu de se couper au bout :
   la largeur naturelle d'un élément flexible est celle de son contenu. */
.arrete-seance {
  display: flex;
  align-items: flex-start;
  gap: var(--espace);
}

.arrete-seance-corps {
  flex: 1;
  min-width: 0;
}

/* La première ligne de la colonne colle au haut du tableau : la marge que la
   boîte de saisie porte pour se détacher de ce qui la précède n'a plus rien à
   détacher quand elle ouvre la colonne, et elle décalerait les deux d'un
   demi-centimètre. */
.arrete-seance-corps > :first-child { margin-top: 0; }

/* La puce de la pièce n'a plus de retrait dans un bloc de l'arrêté : elle en
   tient un de `.assistant-elements`, écrit pour une liste à puces de constats,
   et c'est lui qui décalait la troisième ligne de la deuxième. */
.arrete-pieces { padding-left: 0; }

.arrete-rebours {
  float: left;
  width: 3.1rem;
  margin: 0 var(--espace) var(--espace-xs) 0;
  border: 1px solid var(--black);
  border-radius: var(--radius-sm);
  overflow: hidden;
  text-align: center;
  background: var(--black);
}

/* La même vignette, posée en cellule au lieu d'être flottée : c'est la forme
   qu'elle prend dans la liste commune de « Messages » (onglet « À faire »), où
   elle occupe la colonne de tête de la carte. Un élément de grille ignore
   `float` tout seul ; la marge, elle, ferait double emploi avec le `gap` de la
   carte. */
.assistant-constat > .arrete-rebours { margin: 0; }

/* Et dans la rangée du bloc, où c'est le `gap` qui écarte : le flottant n'a
   plus lieu d'être -- un élément flexible l'ignore de toute façon --, la marge
   ferait double emploi, et `flex: none` garde à la vignette sa largeur de
   trois centimètres quand la colonne d'à côté réclame la place. */
.arrete-seance > .arrete-rebours {
  float: none;
  flex: none;
  margin: 0;
}

/* Le jour de la semaine, tout en haut de la page de calendrier.

   « Affiche également la date concernée avec le jour de la semaine, par exemple
   "LUN 8 SEPT." » (suivi du 6 septembre 2026). Sur sa propre ligne : la
   vignette fait trois centimètres et « LUN 8 SEPT. » d'un seul tenant s'y
   couperait en « LUN 8 » et « SEPT. ». C'est de toute façon la forme d'une page
   de calendrier -- le jour en tête, la date dessous.

   Le bandeau du tableau se poursuit sous lui : même encre, même casse, même
   graisse. Il n'a que son rembourrage en moins, le bandeau étant désormais à
   deux étages et non à un. */
.arrete-rebours-jour {
  display: block;
  padding: var(--espace-3xs) 0 0;
  background: var(--black);
  color: var(--gray-4);
  font-size: var(--fs-3xs);
  font-weight: 600;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
}

/* Le bandeau du tableau : la destination d'un Solari, en petites capitales
   grises sur l'encre. Il ne prend plus la teinte de l'urgence -- c'est le
   repere qui la porte desormais, et deux signaux pour une meme information
   sur un objet de trois centimetres se marchent dessus. */
.arrete-rebours-date {
  display: block;
  padding: var(--espace-3xs) 0;
  background: var(--black);
  color: var(--gray-4);
  font-size: var(--fs-3xs);
  font-weight: 600;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
}

/* Sous le jour de la semaine, le bandeau n'a plus de rembourrage haut : les
   deux étages n'en font qu'un, et l'espacer deux fois écarterait le jour de sa
   propre date. */
.arrete-rebours-jour + .arrete-rebours-date { padding-top: 0; }

.arrete-rebours-compte {
  display: flex;
  justify-content: center;
  gap: 1px;
  padding: var(--espace-3xs) var(--espace-3xs) var(--espace-2xs);
  line-height: 1;
}

/* L'heure de la seance, sous les volets : « ajoute l'heure de l'echeance »
   (ticket du 5 septembre 2026). Le pied du tableau, la ou un Solari affiche
   l'horaire de depart -- meme encre, meme casse, meme graisse que le bandeau,
   parce que c'est le meme objet vu par en dessous. Elle n'apparait que dans la
   liste commune : l'Assistant ecrit deja l'heure contre le champ de date de la
   seance, et le meme ticket interdit de l'ecrire deux fois. */
.arrete-rebours-heure {
  display: block;
  padding: 0 0 var(--espace-3xs);
  background: var(--black);
  color: var(--gray-4);
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: var(--suivi-entete);
}

/* Un volet. Chasse fixe, parce que c'est ce qui fait la rangee : sur un vrai
   tableau, tous les volets ont la meme largeur, quel que soit le caractere
   qu'ils portent. La charniere est un trait de fond, pose au milieu par un
   degrade plutot que par un pseudo-element -- une seule declaration, et rien
   a positionner. */
.arrete-flap {
  flex: none;
  min-width: .72em;
  padding: var(--espace-3xs) 0;
  border-radius: 2px;
  background: var(--gray-6);
  background-image: linear-gradient(var(--black), var(--black));
  background-size: 100% 1px;
  background-position: center;
  background-repeat: no-repeat;
  font-family: var(--mono);
  font-size: var(--fs-h3);
  font-weight: 600;
  color: #fff;
}

/* La chasse suit le nombre de volets, parce que la vignette, elle, ne bouge
   pas : trois centimetres accueillent trois volets a --fs-h3, quatre a
   --fs-sm. Elargir la vignette pour « J-19 » aurait defait ce que le suivi du
   5 septembre 2026 venait de demander (« reduis la largeur »), et laisser
   deborder aurait coupe un chiffre. */
.arrete-rebours[data-volets="4"] .arrete-flap { font-size: var(--fs-sm); }

/* « Jour J » ne se decoupe pas : six volets de trois millimetres ne se lisent
   pas. Un seul volet porte le mot entier, comme la ligne de destination d'un
   tableau porte un nom de ville. */
.arrete-rebours[data-volets="mot"] .arrete-flap {
  min-width: 0;
  padding: var(--espace-3xs) var(--espace-2xs);
  font-size: var(--fs-2xs);
}

/* L'urgence teinte les caractères des volets, et elle ne se confond pas avec
   l'état du bloc : un arrêté dans trois jours est proche sans que rien ne
   manque. Les deux teintes sont celles que le produit emploie déjà pour dire
   la même chose ailleurs -- le rouge pour aujourd'hui et pour le retard,
   l'orange pour ce qui approche --, prises à leur barreau PLEIN : sur fond
   d'encre, les barreaux sombres ne se lisent pas, ils sont faits pour un fond
   pâle. Ce qui n'est ni proche ni en retard reste blanc, comme un vol qui
   part à l'heure. */
.arrete-rebours[data-urgence="proche"] .arrete-flap { color: var(--orange); }

.arrete-rebours[data-urgence="aujourdhui"] .arrete-flap,
.arrete-rebours[data-urgence="retard"] .arrete-flap { color: var(--red); }

/* Une séance passée ne se réclame plus : la vignette s'efface au lieu de
   crier, comme une ligne « faite » s'efface dans le relevé. Une chose À FAIRE
   dont l'échéance est passée fait l'inverse, et c'est pourquoi elle porte une
   autre urgence (« retard », voir `compte_a_rebours_visuel`) : la même date,
   selon qu'elle date un fait ou une dette, ne se peint pas pareil. */
.arrete-rebours[data-urgence="passe"] { opacity: .6; }

/* Les dates du bloc, sur une ligne qui se replie quand la place manque : elles
   sont deux ou trois, jamais neuf, parce que chacune appartient maintenant au
   bloc qui la commente. */

/* Ce qui manque au controle de conformite, sous les blocs : le mandat n'a pas
   de statuts au Juridique, ou l'acte lu ne dit rien des convocations. Une
   indication et non une alerte -- il ne manque rien a la convocation, il manque
   la regle a laquelle la comparer. */
.arrete-conformite-manque {
  margin: var(--espace-xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
}

/* Ce qu'une convocation doit a l'acte qui la regit. « Toute anomalie ou
   non-conformite doit etre clairement signalee dans l'Assistant » (suivi du
   5 septembre 2026) : CLAIREMENT, donc un filet colore et une etiquette, et non
   une phrase de plus dans le detail du bloc.

   Deux gravites, deux teintes deja employees pour dire la meme chose ailleurs :
   le rouge d'une incoherence pour un manquement constate, l'orange d'un manque
   pour une verification qui n'a pas pu se faire. Aucune couleur nouvelle. */
.arrete-conformite {
  margin: var(--espace-2xs) 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}
.arrete-conformite-ligne {
  padding: var(--espace-2xs) var(--espace-xs);
  border-left: 3px solid var(--orange);
  border-radius: var(--radius-xs);
  background: var(--orange-pale);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.5;
}
.arrete-conformite-ligne[data-genre="anomalie"] {
  border-left-color: var(--red);
  background: var(--red-pale);
}
/* L'etiquette de gravite : la meme pastille que les marques d'une reponse
   d'acceptation, en plus petit, parce que c'est le meme geste de lecture -- on
   balaie la tuile et on s'arrete dessus. */
.arrete-conformite-marque {
  display: inline-block;
  margin-right: var(--espace-3xs);
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: var(--orange);
  color: #fff;
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  white-space: nowrap;
}
.arrete-conformite-ligne[data-genre="anomalie"] .arrete-conformite-marque {
  background: var(--red);
}
/* D'ou vient la regle : le nom de l'acte lu, en encre d'indication. Sans lui,
   « le delai n'est pas tenu » serait une affirmation sans source, et c'est la
   source qu'on vient verifier. */
.arrete-conformite-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Où et comment la séance se tient, sous le titre du bloc.

   « Ajoute le lieu et le mode de réunion : sur place, en visio ou hybride [...]
   affichées de manière courte et claire, afin de savoir immédiatement où et
   comment la réunion se déroule sans ouvrir le document » (ticket du
   6 septembre 2026).

   L'épingle devant : c'est elle qui dit « lieu » avant qu'on ait lu, et
   « immédiatement » est le mot du ticket. Même encre et même taille que le
   détail du bloc juste au-dessus -- c'est une information de même rang, pas un
   avertissement. */
.arrete-reunion {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin: var(--espace-3xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.arrete-reunion .icon {
  flex: none;
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
}

.arrete-champs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs) var(--espace);
  margin-top: var(--espace-sm);
}

.arrete-champs:empty { margin-top: 0; }

.arrete-champ {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
}

/* Ce qui se dit contre le champ, a sa droite : aujourd'hui l'heure de la
   seance, lue sur la convocation (ticket du 5 septembre 2026). En italique et
   dans l'encre des indications, comme l'intitule a gauche : ce n'est pas une
   valeur qu'on saisit, c'est ce que la piece dit de celle qui est saisie. */
.arrete-champ-apres {
  font-size: var(--fs-sm);
  font-style: italic;
  color: var(--gray-5);
  white-space: nowrap;
}

/* Une date ne mesure pas ce que mesure un exercice.

   « Reduis la largeur de la case de la "date de l'arrete" et "date de
   l'assemblee" et "Emis le" » (suivi du 5 septembre 2026). Les trois champs
   prenaient 256 px pour montrer « 08/09/2026 », soit un tiers de la ligne
   occupe par du vide : ils heritaient du plancher de `.aglae-input-exercice`,
   pose pour un libelle d'exercice, qui est une phrase.

   11 rem est la largeur qu'un champ de date a deja ailleurs dans la feuille
   (`.reglages-row .aglae-input-exercice[type="date"]`) : ce n'est pas une
   mesure de plus, c'est la meme, redite la ou le meme controle sert. Le champ
   francais du selecteur est pose par-dessus celui-ci, en absolu : c'est donc
   bien ici, sur le champ d'origine, que la largeur se decide. */
/* Et depuis le 5 septembre 2026, la largeur STRICTEMENT necessaire : « ajuste
   la largeur des trois champs "Date d'arrete", "Date d'assemblee" et "Emis le"
   a la largeur strictement necessaire pour afficher leur contenu. Cela
   permettra de rendre l'ensemble plus compact et plus lisible » (suivi du meme
   jour). 11 rem etait la mesure d'un champ de date ailleurs dans la feuille, ce
   qui valait mieux que le plancher d'un libelle d'exercice, mais restait une
   mesure prise d'ailleurs : mesure au navigateur, « 08/09/2026 » occupe 72 px
   dans un champ qui en fait 176.

   La largeur s'ecrit donc comme la somme de ce qu'elle contient : le cadre, le
   rembourrage de gauche, la place du texte, la voie du glyphe de calendrier.
   Elle se recalcule toute seule si l'echelle bouge, ce qu'une valeur en rem ne
   ferait pas.

   9,5 `ch` pour « 08/09/2026 » : c'est dix caracteres, dont deux barres
   obliques plus etroites qu'un chiffre dans la fonte du site. Neuf suffiraient
   au pixel pres ici (72 px pour 72 px) ; le demi-caractere de plus est la
   marge que laisse une fonte de repli aux proportions differentes, et il coute
   quatre pixels sur les soixante que la regle rend.

   `--chevron-reserve` est pose par `.date-champ`, l'enveloppe que le selecteur
   de date ajoute autour du champ. Le repli couvre la fraction de seconde qui
   precede, et la page ou le JavaScript n'aurait pas pris : sans lui le calcul
   serait invalide et le champ reprendrait sa largeur naturelle. */
.arrete-champ .aglae-input-exercice[type="date"] {
  min-width: 0;
  width: calc(2px + var(--espace-sm) + 9.5ch + var(--chevron-reserve, 1.8rem));
}

/* L'heure d'un rendez-vous, a cote de ses dates (suivi du 6 septembre 2026).

   Meme cadre et meme hauteur qu'elles -- c'est `aglae-input` qui les pose --,
   et la largeur calculee de la meme facon, sur ce qu'elle contient : « 9 h 30 »
   fait six caracteres la ou une date en fait dix. Une largeur de champ de
   date lui aurait laisse la moitie de sa case vide, juste a cote de deux cases
   pleines. Pas de voie de glyphe a reserver : le champ d'heure n'ouvre aucun
   panneau, on y tape quatre chiffres.

   `[type="text"]` et non `[type="time"]` depuis le ticket du 6 septembre 2026 :
   le champ segmente du navigateur bloquait le formulaire entier des qu'une
   heure y restait a moitie tapee, avec un message qui parlait de la date. Il
   est desormais un champ a nous, comme les dates a cote de lui, et l'ecriture
   francaise y est admise autant que l'ISO (voir `dossier-arrete.js`). Le
   selecteur reste plus lourd que les regles de page qui habillent les champs
   de texte, pour la meme raison que `.date-champ-saisie` : deux classes et un
   attribut passent devant `.dossier-form input[type="text"]` et son plancher
   de largeur. */
.arrete-champ .aglae-input-heure[type="text"] {
  min-width: 0;
  width: calc(2px + var(--espace-sm) * 2 + 6.5ch);
}
/* Un montant ne mesure pas ce que mesure une phrase.

   « Reduis la largeur des champs "Provision HT" et "Honoraires factures HT".
   Les montants sont limites a six chiffres. Fais egalement en sorte que les
   intitules et les champs tiennent sur une seule ligne » (suivi du 16 septembre
   2026). Les deux cases de la facturation des honoraires prenaient 224 et
   251 px pour montrer « 4 200 € » : elles n'avaient pas de largeur a elles, donc
   elles heritaient du `width: 100%` de `.aglae-input` et se partageaient toute
   la ligne du bloc. Ce qui restait pour les intitules ne suffisait pas, et
   « Provision HT » se cassait en deux lignes a cote d'une case aux trois quarts
   vide.

   La largeur s'ecrit donc comme la somme de ce qu'elle contient, comme celle
   des champs de date et d'heure au-dessus : le cadre, les deux rembourrages, la
   place du texte. Elle se recalcule toute seule si l'echelle bouge, ce qu'une
   valeur en rem ne ferait pas.

   8,5 `ch` pour « 999 999 € », le plus grand montant que la case accepte
   (`arrete_comptes.CHIFFRES_MONTANT_MAX`, six chiffres) : mesure au navigateur,
   la chaine en occupe exactement huit dans la fonte du site, et le
   demi-caractere de plus est la marge que laisse une fonte de repli aux
   proportions differentes. `tabular-nums`, pose par `.aglae-input-nombre`, fige
   la largeur des chiffres : la case ne danse donc pas d'une valeur a l'autre.

   `flex: none` parce que la rangee est une boite flexible : sans lui la case
   reprendrait au partage ce que la largeur lui retire. */
.arrete-champ .aglae-input-nombre[type="text"] {
  flex: none;
  min-width: 0;
  width: calc(2px + var(--espace-sm) * 2 + 8.5ch);
}

/* Et l'intitule sur une seule ligne, a cote de sa case. La largeur rendue
   suffit a l'y tenir aujourd'hui ; cette regle fait qu'un intitule plus long,
   ou une fenetre plus etroite, replie la RANGEE plutot que le mot -- c'est
   `.arrete-champs` qui sait passer a la ligne, et il le fait entre deux champs,
   pas au milieu d'un. */
.arrete-champ-montant .reglages-hint-inline { white-space: nowrap; }

/* Une reception se coche : la case d'abord, son intitule ensuite (« Recu »,
   « Commissaire aux comptes convoque »). La case elle-meme n'est pas rhabillee
   ici -- elle l'est une fois pour tout le produit, par l'element -- et
   l'intitule reprend la couleur du texte : ce n'est plus la legende d'un champ
   a remplir, c'est la chose qu'on coche, et une legende grise se lit comme une
   aide. */
.arrete-champ-case { cursor: pointer; }
.arrete-champ-case .reglages-hint-inline { color: var(--gray-6); }

/* Un bloc de rapport sur une seule ligne.

   « Améliore la présentation pour rendre les blocs plus compacts et limiter le
   nombre de lignes [...] présente-les plutôt sur une seule ligne » (ticket du
   4 septembre 2026). Les trois rapports -- activité, financier, le nôtre --
   posaient chacun trois lignes pour un oui-ou-non : leur intitulé, leur phrase,
   leur case. Ils tiennent maintenant en une, et le corps du bloc devient une
   rangée au lieu d'une pile.

   Ce qu'on a trouvé au Juridique est le seul membre de longueur imprévisible :
   c'est donc lui qui prend la place restante et qui se coupe, le nom entier
   restant au survol. L'intitulé et la case, eux, ne se coupent jamais -- ce
   sont les deux choses qu'on vient lire. */
.arrete-compact {
  display: flex;
  align-items: center;
  gap: var(--espace-xs) var(--espace);
}

.arrete-compact .assistant-titre { white-space: nowrap; }

/* Ce qu'on a trouvé au Juridique, ou le motif qui appelle une pièce : la
   seule chose de longueur imprévisible de la rangée, donc la seule qui se
   coupe. Elle ne POUSSE plus la case au bout de la ligne depuis le 5 septembre
   2026 : « déplace vers la gauche la marque "Reçu", qui va trop à droite, pour
   le rapport d'activité et le rapport financier ». Ces deux blocs-là n'ont rien
   à dire entre leur intitulé et leur case, si bien que la case partait seule à
   l'autre bout d'une ligne de treize cents pixels : l'oeil faisait la traversée
   pour chacune des deux, et devait revenir vérifier de quelle ligne elle
   était.

   `flex-grow: 0` suffit : la rangée reste alignée à gauche, chaque membre
   prend sa place et la case suit son intitulé. Ce qui déborde se coupe
   toujours, `flex-shrink` restant à 1. */
.arrete-compact-appoint {
  flex: 0 1 auto;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* La case, ou la date, a la suite de la ligne : plus de marge au-dessus, elle
   n'est plus dessous, et plus de marge automatique a gauche, elle n'est plus au
   bout (voir .arrete-compact-appoint juste au-dessus). */
.arrete-compact .arrete-champs {
  flex: 0 0 auto;
  flex-wrap: nowrap;
  margin-top: 0;
}

.assistant-cible {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  white-space: nowrap;
  /* La cellule de droite ne pese pas ce qu'elle montre : son bouton-lien porte
     un plancher de 28 px (`--h-sm`), arbitre plus haut -- une hauteur de bouton
     ne se decide pas dans le parent --, quand le titre qu'elle longe n'est
     qu'une ligne de 19,2 px (`--fs-sm` par l'interligne 1,5 du corps de page).
     La carte alignant ses cellules par le haut, les deux boites commencaient
     ensemble et leurs milieux finissaient a 4,4 px l'un de l'autre : la source
     d'une publication lisait sous le titre au lieu de lire sur sa ligne. Elle
     portait l'etiquette « MANQUE » quand cette note a ete ecrite -- le releve
     nomme sa nature en tete de groupe depuis le 30 aout 2026, la voie reste. On
     remonte
     donc la cellule de la moitie de l'ecart, ecrit comme la difference de ses
     termes pour qu'il suive si l'echelle bouge. Le retrait mord 4,4 px du creux
     de 9,6 px de la carte, qui les a. */
  margin-top: calc((var(--h-sm) - var(--fs-sm) * 1.5) / -2);
}

.assistant-gravite {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--gray-4);
}

@media (max-width: 640px) {
  .assistant-constat { grid-template-columns: auto 1fr; }
  /* La cellule passe sous le corps : elle n'a plus de titre a rejoindre, et le
     retrait qui l'y remontait mangerait l'espace qui l'en separe. */
  .assistant-cible { grid-column: 2; margin-top: 0; }
  .assistant-elements { columns: 1; }
  /* Sur un telephone, la rangee d'un rapport se replie : trois membres cote a
     cote sur trois cent cinquante pixels ne laisseraient au nom de la piece
     que deux caracteres avant les points de suspension. La case revient donc
     sous l'intitule, comme avant -- c'est la largeur qui manque, pas la
     forme. */
  .arrete-compact { flex-wrap: wrap; }
  .arrete-compact .assistant-titre { white-space: normal; }
  .arrete-compact-appoint { flex-basis: 100%; }
}

/* ---------------------------------------------------------------------------
   La veille en ligne, second panneau de l'onglet Assistant.

   Elle emprunte la carte des constats (`.assistant-constat`) plutot que d'en
   dessiner une seconde : ce sont les memes lignes, lues au meme endroit, et
   deux cartes voisines aux dessins differents feraient croire a deux natures de
   releve. Ce qui lui est propre tient en deux regles : l'effet a verifier, en
   italique dans la carte, et la barre des sources sous la liste.

   Son titre de section n'en fait plus partie : les deux zones de l'onglet sont
   des tuiles depuis le 30 aout 2026, et une tuile se titre avec `.tuile-titre`
   comme partout ailleurs. `.assistant-section-titre`, qui ne servait qu'ici et
   qu'une fois, a ete retiree avec le filet de l'entete.
   --------------------------------------------------------------------------- */

.veille-effet { font-style: italic; }

/* Lu ou non lu (demande du 30 août 2026). Ce qui reste à lire est plein et
   porte une pastille ; ce qui a été ouvert s'éteint sans disparaître -- une
   publication lue reste une publication du relevé, et l'effacer ferait douter
   qu'on l'ait bien vue.

   La marque est posée sur la publication non lue et non retirée de la lue :
   c'est le nouveau qui doit se signaler, pas l'ancien s'excuser. */
.assistant-constat[data-lu="1"] { background: var(--gray-1); }
.assistant-constat[data-lu="1"] .assistant-titre { font-weight: 500; }

.assistant-constat[data-lu="0"] .assistant-titre::before {
  content: "";
  display: inline-block;
  width: var(--espace-sm);
  height: var(--espace-sm);
  margin-right: var(--espace-2xs);
  border-radius: 999px;
  background: var(--blue);
  vertical-align: middle;
}

.veille-sources {
  margin-top: var(--espace-md);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-3);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.veille-source {
  margin-right: var(--espace-sm);
  color: var(--blue);
}

/* Une adresse qui n'a pas repondu se reconnait avant d'etre cherchee : elle
   n'est pas un lien, et elle est barree. Sans quoi une source muette se lit
   comme une source lue qui n'a rien appris -- ce qui est le contraire. */
.veille-source-muette {
  color: var(--gray-4);
  text-decoration: line-through;
  cursor: help;
}

/* ==========================================================================
   L'analyse des tickets : /cabinet/dashboard-tickets

   « Dans dashboard crée une nouvelle tuile et menu analytics tickets, où tu
   vois le nombre de ticket fait par personne, les thèmes abordés etc. Sois
   créatif pour cette nouvelle zone mais mets le plus de statistique que tu
   peux » (demande du 30 août 2026).

   La page reprend la carte du Dashboard système (`.conso-bloc`) plutôt que
   d'inventer une troisième surface : c'est le même écran, sous un autre
   onglet, et deux cartes de dessins différents dans une même rangée d'onglets
   se liraient comme deux produits.

   Aucune trace n'est dessinée sans son chiffre écrit à côté. Une barre seule se
   compare à ses voisines et à rien d'autre : elle montre une forme, elle ne
   donne pas une valeur, et un tableau de bord se cite.
   ========================================================================== */
/* Une rangée de l'analyse, à l'intérieur du volet des tickets. Pas une carte :
   le volet en est déjà une (`.conso-bloc`), et sept cartes dans une carte
   feraient une pile de cadres. Ce qui sépare les rangées est un trait, comme
   entre deux sections d'un même bloc -- sauf la première, qui suit le bord du
   volet et n'a rien à séparer. */
.tka-bloc + .tka-bloc {
  margin-top: var(--espace-xl);
  padding-top: var(--espace-lg);
  border-top: 1px solid var(--gray-2);
}

/* Les titres de ces rangees sont ceux de tout le tableau de bord
   (`.conso-sous-titre`, plus haut dans cette feuille). Ils etaient a `--fs-h3`
   en noir, quand les cinq autres volets marquent leurs sections d'une petite
   etiquette capitale : le plus long des sept volets etait aussi le seul a se
   lire comme une autre page. Le trait qui separe deux rangees fait deja ce que
   faisait le gros titre.

   La premiere rangee d'un volet ne prend pas la marge haute de ce titre : elle
   suit le bord du bloc, qui a deja son espace, et les suivantes ont leur
   `padding-top` a elles. */
.tka-bloc > .conso-sous-titre:first-child { margin-top: 0; }

.tka-note {
  font-size: var(--fs-xs);
  color: var(--gray-4);
  max-width: 70ch;
}

/* Ce qui n'est pas mesuré, dit à la fin et non tu : une case absente d'un
   tableau de bord se lit comme un oubli, et c'est un choix. */
.tka-avertissement {
  margin-top: var(--espace-md);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
}

.tka-avertissement p { margin: 0; }

/* Les grands chiffres. `auto-fit` et non un nombre de colonnes : la rangée en
   porte six ici et sept ailleurs, et une grille qui compterait ses colonnes
   laisserait un trou dans celle qui en a une de moins. */
.tka-chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--espace-md);
}

/* Un chiffre est une carte, comme `.conso-mesure` : « uniformise les tuiles
   a l'interieur des dashboards » (23 septembre 2026). Le volet Vercel ouvrait
   sur des chiffres nus, celui d'OpenAI sur des cartes, pour la meme sorte de
   grandeur ; l'app, elle, les encadrait deja tous (`ChiffreDashboard`). Meme
   cadre, meme graisse, memes chiffres tabulaires : un nombre se lit de la
   meme facon d'un volet a l'autre. */
.tka-chiffre {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  padding: var(--espace-md) var(--espace-lg);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: #fff;
  min-width: 0;
}

.tka-chiffre-valeur {
  font-size: var(--fs-hero);
  font-weight: 600;
  letter-spacing: var(--suivi-serre);
  color: var(--black);
  font-variant-numeric: tabular-nums;
}

.tka-chiffre-libelle { font-size: var(--fs-xs); color: var(--gray-5); }
.tka-chiffre-note { font-size: var(--fs-2xs); color: var(--gray-4); }

/* Le pipeline : les quatre paliers côte à côte, chacun sous la couleur qu'il
   porte déjà sur la carte d'un ticket. Un état peint de deux couleurs selon la
   page est exactement ce que le vérificateur de parité refuse : ici c'est la
   même page qui se contredirait. */
.tka-pipeline {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: var(--espace-sm);
}

.tka-palier {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  padding: var(--espace-sm) var(--espace-md);
  border-left: 3px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
}

.tka-palier-nouveau { border-left-color: var(--cyan); }
.tka-palier-envoye_a_claude { border-left-color: var(--blue); }
.tka-palier-repondu { border-left-color: var(--orange); }
.tka-palier-resolu { border-left-color: var(--green); }

/* La pile du pipeline, au-dessus des boites. Les couleurs sont ecrites ici et
   non dans le gabarit : ce sont les memes quatre etats, et un etat n'a qu'une
   teinte -- la boite et la part la lisent au meme endroit. */
.tka-pipeline-pile { margin: 0 0 var(--espace-md); }

.tka-pipeline-pile .conso-pile-part[data-part="nouveau"],
.tka-barre-pile .conso-pile-part[data-part="nouveau"] { background: var(--cyan); }
.tka-pipeline-pile .conso-pile-part[data-part="envoye_a_claude"],
.tka-barre-pile .conso-pile-part[data-part="envoye_a_claude"] { background: var(--blue); }
.tka-pipeline-pile .conso-pile-part[data-part="repondu"],
.tka-barre-pile .conso-pile-part[data-part="repondu"] { background: var(--orange); }
.tka-pipeline-pile .conso-pile-part[data-part="resolu"],
.tka-barre-pile .conso-pile-part[data-part="resolu"] { background: var(--green); }

.tka-palier-nb {
  font-size: var(--fs-h2);
  font-weight: 700;
  color: var(--gray-6);
}

.tka-palier-nom { font-size: var(--fs-xs); color: var(--gray-5); }
.tka-palier-part { font-size: var(--fs-2xs); color: var(--gray-4); }

/* Les barres horizontales : nom, trace, chiffre. Trois colonnes fixes pour que
   les traces partent toutes du même endroit, sans quoi on compare des
   longueurs qui ne commencent pas au même point. */
.tka-barres {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  min-width: 0;
}

/* `--tka-teinte` est la couleur de la trace, posee ici avec sa valeur par
   defaut : le cyan, celle qu'ont toutes les barres du tableau de bord. Le
   volet du temps la reecrit ligne par ligne avec la couleur du profil, celle
   qui fait reconnaitre quelqu'un partout ailleurs sur le site. */
.tka-barre {
  --tka-teinte: var(--cyan);
  display: grid;
  grid-template-columns: minmax(6rem, 12rem) 1fr auto;
  align-items: center;
  gap: var(--espace-sm);
  font-size: var(--fs-xs);
}

.tka-barre-nom {
  color: var(--gray-5);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tka-barre-piste {
  display: block;
  height: var(--espace-sm);
  border-radius: 999px;
  background: var(--gray-2);
  overflow: hidden;
}

.tka-barre-trace {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--tka-teinte);
}

.tka-barre-nb {
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
  white-space: nowrap;
}

/* La trace d'un theme, decoupee comme le pipeline du haut du volet : sa
   longueur reste le volume du theme, ses segments disent a quel palier ce
   volume se trouve. Deux echelles emboitees -- la longueur compare les themes
   entre eux, la decoupe compare l'interieur d'un seul.

   Les couleurs sont celles du pipeline et pas d'autres : c'est la regle
   d'affichage que le verificateur de parite tient, un etat metier ne peut pas
   etre peint de deux teintes selon l'endroit ou on le montre. D'ou le
   selecteur ajoute a la liste plus bas plutot qu'une seconde table de
   couleurs. Le rayon et le rognage sont ici comme sur `.conso-rail-pile` : les
   segments sont carres, c'est leur contenant qui les arrondit. */
.tka-barre-pile {
  display: flex;
  border-radius: 999px;
  overflow: hidden;
}

/* Le deposant dans la marge d'un rail : son rond a mi-taille, cale sur le
   milieu de la ligne plutot que sur sa base. Vingt-quatre pixels poses sur la
   ligne de base d'un `--fs-xs` en pousseraient le bas, et six rails de suite
   se liraient comme six lignes d'inegale hauteur.

   Les deux selecteurs nomment leurs deux classes : `.tka-rond` est declare plus
   bas dans la feuille, et une classe seule perdrait contre lui a specificite
   egale. */
.tka-personne.tka-personne-mini {
  gap: var(--espace-2xs);
  vertical-align: middle;
  font-weight: 500;
}

.tka-rond.tka-rond-mini {
  width: var(--espace-lg);
  height: var(--espace-lg);
}

/* Le detail d'une personne dans le compteur de temps : ses mandats sous sa
   barre (demande du 4 septembre 2026, « surtout sur quel dossier ils le
   passent »).

   Une liste indentee sous la barre, et non des barres de barres : la seconde
   echelle serait relative a la personne quand la premiere l'est au cabinet, et
   deux traces de meme longueur ne diraient pas la meme chose sur deux lignes
   voisines. Des durees ecrites, donc, alignees a droite -- c'est la forme d'un
   releve d'heures, celle qu'on recopie sur une note d'honoraires. */
.temps-personne { margin-bottom: var(--espace-sm); }

.temps-detail {
  /* Decalee sous la piste de la barre et non sous la marge de la carte : les
     mandats d'une personne se lisent sous sa trace, pas sous son nom. La
     largeur est celle de la premiere colonne de `.tka-barre`, a son minimum. */
  margin: var(--espace-2xs) 0 0 calc(6rem + var(--espace-sm));
  padding: 0;
  list-style: none;
}

.temps-detail li {
  display: flex;
  justify-content: space-between;
  gap: var(--espace-sm);
  padding: var(--espace-3xs) 0;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.temps-detail-nom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.temps-detail-duree {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* La barre d'un mandat, decoupee aux couleurs des personnes qui y ont passe du
   temps. Deux echelles emboitees, et c'est voulu : la longueur de la pile
   compare les mandats entre eux, la largeur d'un segment compare les personnes
   a l'interieur d'un seul mandat. L'objection ecrite plus haut sur
   `.temps-detail` -- deux traces de meme longueur qui ne diraient pas la meme
   chose -- ne vaut pas ici : les segments vivent dans une barre unique, aucun
   ne se lit contre celui de la ligne du dessous.

   Avant, le « avec qui » d'un mandat n'existait que dans l'infobulle du
   navigateur, donc nulle part au doigt.

   Les segments se partagent la pile par `flex-grow` et non par une largeur en
   pourcentage : six parts arrondies au dixieme laissent sinon un lisere de
   fond au bout de la barre. Le facteur de croissance est pose en ligne, en
   minutes -- la seule valeur de la regle serait un nombre invente. */
.temps-pile {
  display: flex;
  height: 100%;
  border-radius: 999px;
  overflow: hidden;
}

.temps-part {
  flex-basis: 0;
  height: 100%;
}

/* Le meme compteur, vu depuis un seul mandat : la tuile « Honoraires : le temps
   passe » de l'onglet Mandat (suivi du 7 septembre 2026, « qu'on puisse voir
   dans le detail de chaque client le temps passe et par qui »).

   Pas de barres ici, contrairement au volet du Dashboard : une barre compare
   des mandats entre eux, et il n'y en a qu'un. Ce qui reste est la forme d'un
   releve d'heures, celle qu'on recopie sur une note d'honoraires : des noms a
   gauche, des durees alignees a droite en chiffres de meme chasse. */
.mandat-temps-total {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--espace-xs);
}

.mandat-temps-chiffre {
  font-size: var(--fs-h3);
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
}

.mandat-temps-borne {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.mandat-temps-liste {
  margin: var(--espace-sm) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--gray-3);
}

.mandat-temps-liste li {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  padding: var(--espace-xs) 0;
  border-bottom: 1px solid var(--gray-2);
  font-size: var(--fs-xs);
}

.mandat-temps-qui {
  /* La colonne qui pousse : les deux chiffres gardent leur place a droite
     quel que soit le nom, sans quoi deux lignes voisines ne s'alignent pas. */
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

.mandat-temps-nom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--gray-6);
}

.mandat-temps-dernier {
  font-size: var(--fs-3xs);
  color: var(--gray-4);
}

.mandat-temps-part {
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--gray-4);
  white-space: nowrap;
}

.mandat-temps-duree {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--gray-6);
}

/* Les colonnes du rythme mensuel. Le chiffre au-dessus de la colonne et non
   dans une infobulle : trente jours tiennent dans une rangée, et un chiffre qui
   demande un survol n'est pas lu.

   La rangée défile plutôt que de se resserrer (ticket du 7 septembre 2026,
   « graphique temporel sur les 30 jours 3 mois all »). Trente barreaux dans la
   largeur d'un téléphone donneraient des colonnes de six pixels et des
   chiffres qui se chevauchent : on aurait remplacé une mesure par une texture.
   Un barreau garde donc une largeur minimale, et c'est la rangée qui glisse
   sous le doigt quand la carte est trop étroite pour les tenir tous. */
.tka-colonnes {
  display: flex;
  align-items: flex-end;
  gap: var(--espace-xs);
  height: 8rem;
  margin-bottom: var(--espace-lg);
  overflow-x: auto;
  overflow-y: hidden;
}

/* Bornée en largeur : la série commence au premier ticket et peut n'avoir que
   deux mois. Sans borne, deux colonnes prendraient chacune la moitié de la
   carte et se liraient comme deux pavés, pas comme un rythme. */
.tka-colonne {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-3xs);
  flex: 1 0 1.5rem;
  max-width: 5rem;
  height: 100%;
}

/* Un pas d'un jour porte deux chiffres sous le barreau, un pas d'une semaine
   ou d'un mois porte un nom de mois : le second demande plus de place que le
   premier, sans quoi « sept. » se coupe en deux. */
.tka-colonnes-semaine .tka-colonne,
.tka-colonnes-mois .tka-colonne { flex-basis: 3rem; }

/* Les sept jours du volet du temps ne sont pas une série qui s'allonge : c'est
   un ensemble fermé, et le week-end qu'on vient y chercher tient à son extrémité
   droite. La rangée qui glisse sous le doigt, juste pour trente barreaux, mettait
   ici samedi et dimanche hors de l'écran sur un téléphone. Les sept colonnes se
   partagent donc la largeur, quelle qu'elle soit. */
.tka-colonnes-jours {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  overflow-x: hidden;
}

/* Un barreau porte ici une durée et non un compte. « 12 h 30 » ne tient pas dans
   la largeur taillée pour trois chiffres : il se couperait au milieu de l'unité,
   et « 12 h » posé au-dessus de « 30 » se lirait comme deux mesures. */
.tka-colonnes-jours .tka-colonne { max-width: none; }
.tka-colonnes-jours .tka-colonne-nb { white-space: nowrap; }

/* Sous la tablette les sept colonnes se resserrent : l'écart descend au plus
   petit barreau et la durée au plus petit corps, ce qui suffit jusqu'à 351 px.
   En dessous, une colonne mesure moins de 38 px et aucune durée n'y tient : elle
   s'efface plutôt que de mordre sur sa voisine, la forme de la semaine restant
   lisible et le relevé au survol gardant le chiffre. */
@media (max-width: 640px) {
  .tka-colonnes-jours { gap: var(--espace-3xs); }
  .tka-colonnes-jours .tka-colonne-nb { font-size: var(--fs-3xs); }
}

@media (max-width: 350px) {
  .tka-colonnes-jours .tka-colonne-nb { display: none; }
}

/* Un jour qui n'est pas encore revenu depuis que le compteur tourne. Son
   barreau est vide comme celui d'un jour chome, et rien ne les distinguait :
   le graphique disait « on ne travaille pas le mardi » alors qu'il n'y avait
   pas eu de mardi. Le nom passe en pointille -- la meme encre, pas une
   couleur de plus, parce qu'un jour absent n'est pas un etat metier. */
.tka-colonne-jamais .tka-colonne-nom {
  border-bottom: 1px dotted var(--gray-3);
  color: var(--gray-3);
}

.tka-colonne-nb {
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--gray-5);
}

/* La pile d'un barreau : un segment par personne, dans la couleur de son
   profil et dans le même ordre d'un barreau à l'autre. `flex-grow` porte le
   compte, donc les segments se partagent la hauteur du barreau sans qu'aucun
   pourcentage n'ait à être calculé deux fois -- une fois pour le barreau, une
   fois pour chaque part. La hauteur du barreau, elle, est écrite dans le
   gabarit : c'est la seule mesure du graphique. */
.tka-pile {
  display: flex;
  flex-direction: column-reverse;
  width: 100%;
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
  overflow: hidden;
}

/* Un pixel au moins : celui qui a déposé un ticket un jour où quelqu'un d'autre
   en a déposé cent doit rester visible, sinon la pile dit qu'il n'y était pas. */
.tka-pile-part {
  display: block;
  width: 100%;
  min-height: 1px;
  background: var(--cyan);
}

.tka-colonne-nom {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  white-space: nowrap;
}

/* La légende des couleurs de la pile. Les mêmes ronds que partout ailleurs :
   c'est le rond qui fait reconnaître quelqu'un d'un coup d'œil. */
.tka-legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm) var(--espace-md);
  margin-bottom: var(--espace-lg);
}

.tka-legende-entree {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
}

.tka-legende-nom { color: var(--gray-6); }

.tka-legende-nb {
  font-variant-numeric: tabular-nums;
  color: var(--gray-4);
}

/* L'appariement, a l'interieur d'un volet. Ces deux volets nomment les memes
   personnes quatre fois -- le tableau, les trois fenetres du rythme, leurs
   legendes -- et le volet du temps deux fois de plus, par mandat et par
   personne. Pointer quelqu'un quelque part eteint les autres partout ailleurs :
   c'est la meme mecanique que la pile et sa legende, ecrite plus haut, et le
   volet entier devient un seul graphique.

   Eteindre plutot que souligner, pour la meme raison qu'ailleurs : ce qu'on
   cherche est de retrouver une part parmi sept, et six teintes qui baissent la
   designent mieux qu'une qui monte. */
.tka-pile-part,
.temps-part,
.temps-personne,
.tka-legende-entree,
.tka-palier,
.tka-table tbody tr,
.tka-rond { transition: opacity .15s var(--ease), transform .15s var(--ease); }

/* Le rond de l'entree eclairee grossit un peu : la legende est loin de la pile,
   et l'oeil qui en revient doit retrouver ou il en etait. Moins fort que la
   pastille d'une legende ordinaire (1,4) -- un rond de vingt-quatre pixels
   portant deux initiales bougerait ses lettres. */
.tka-legende-entree.conso-part-vive .tka-rond { transform: scale(1.12); }

.tka-rythme-note { margin: 0 0 var(--espace-sm); }

/* Les vingt-quatre heures, en peigne : trop étroit pour porter un chiffre, et
   ce n'est pas ce qu'on y cherche, on y lit une forme, à quelle heure on
   dépose. Le chiffre est dans l'infobulle, faute de place, et c'est la seule
   trace de la page dans ce cas. */
.tka-heures {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 6rem;
  min-width: 0;
}

.tka-heure {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-3xs);
  flex: 1 1 0;
  height: 100%;
  min-width: 0;
}

.tka-heure-trace {
  display: block;
  width: 100%;
  min-height: 2px;
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
  background: var(--purple);
}

.tka-heure-nom {
  font-size: var(--fs-3xs);
  color: var(--gray-4);
}

.tka-deux {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--espace-xl);
}

.tka-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}

.tka-table th {
  /* Symetrique, comme dans les tables maison : la table est desormais posee
     dans un cadre, et un en-tete sans marge haute touchait son trait. */
  padding: var(--espace-2xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--suivi-titre);
  color: var(--gray-5);
  text-align: left;
}

.tka-table td {
  padding: var(--espace-xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-2);
  vertical-align: middle;
}

/* Un nombre ne se coupe pas. Dans le cadre defilant, « 41,7 % » passait a la
   ligne entre le chiffre et son signe et « 383 (99 %) » sur trois lignes : une
   colonne de chiffres se lit d'un seul coup d'oeil ou ne se lit pas. */
.tka-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tka-secondaire { color: var(--gray-4); }

.tka-personne {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-sm);
  font-weight: 600;
}

/* Le rond du profil, à la taille des ronds de liste. Il porte la couleur de la
   personne : c'est ainsi qu'on la reconnaît partout ailleurs sur le site, et
   une page qui la nommerait sans la colorer obligerait à lire. */
.tka-rond {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--espace-xl);
  height: var(--espace-xl);
  border-radius: 999px;
  font-size: var(--fs-3xs);
  font-weight: 700;
  letter-spacing: var(--suivi-serre);
  color: #fff;
}

/* ---------- Le rapport de controle du FEC ---------- */
/* Cent six points, ecrits par le gabarit avant tout resultat, et le verdict
   qui vient se poser dessus. La page se lit de deux facons : en entier, du
   premier chapitre au dernier, ou par le resume, les pastilles du haut sont
   des filtres, et c'est ainsi qu'on va droit aux points qui demandent quelque
   chose. Aucune couleur nouvelle ici : les verdicts empruntent la palette
   deja partagee avec l'app. */

/* Les cinq zones du rapport portent `tuile` dans le gabarit : l'entete,
   l'attente, le resume, la carte d'identite et chacun des vingt chapitres.
   Aucune n'avait de cadre, et sur une page de quatre-vingt-seize mille pixels
   rien ne disait ou une zone finissait. Le cadre est pose sur l'element
   lui-meme plutot que sur une enveloppe : trois de ces zones se montrent et se
   cachent par l'attribut `hidden`, et une enveloppe restee visible aurait
   laisse une boite vide a l'ecran pendant les dix secondes du calcul, puis
   pour toujours si le moteur echouait. */
/* La bande de tete. Le rapport est le plus long document du site --
   quatre-vingt-seize mille pixels mesures a 2560, cent six points ranges en
   vingt chapitres -- et tout ce qui sert a s'y deplacer tenait dans son
   premier ecran : le nom du fichier, « Repasser le fichier », « Imprimer », et
   surtout les sept pastilles du resume, qui sont le filtre par verdict. Passe
   le premier ecran, il n'y avait plus aucun moyen d'aller aux quinze anomalies
   autrement qu'en remontant.

   La bande se colle donc en tete du defilement. Elle prend le creux du haut de
   la page (`padding-top` rendu par `.cfec-page`) et le peint, sans quoi un
   chapitre defilerait dans les trente-deux pixels laisses au-dessus d'elle :
   une boite collante ne sort pas de son bloc contenant, un `margin-top`
   negatif n'y peut rien. Le `flow-root` sert au meme but par le bas : sans
   lui, la marge du dernier enfant s'echappe de la bande et ouvre sous elle un
   ecart transparent de seize pixels. */
.cfec-page.app-main-pleine { padding-top: 0; }

.cfec-tete {
  display: flow-root;
  position: sticky;
  top: 0;
  z-index: 15;
  margin-left: calc(var(--gouttiere) * -1);
  margin-right: calc(var(--gouttiere) * -1);
  padding: var(--espace-2xl) var(--gouttiere) 0;
  background: var(--gray-1);
}

.cfec-entete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace);
  flex-wrap: wrap;
  margin-bottom: var(--espace-md);
}

.cfec-entete-nom {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  min-width: 0;
}

.cfec-entete-nom .icon { color: var(--gray-5); }

.cfec-nom-fichier {
  font-family: var(--mono);
  font-size: var(--fs-md);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.cfec-entete-actions { display: flex; align-items: center; gap: var(--espace-sm); }

/* L'attente. Un gros FEC prend une dizaine de secondes : sans rien a l'ecran,
   la page passerait pour cassee. */
.cfec-attente {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-md);
  color: var(--gray-5);
  font-size: var(--fs-sm);
}

.cfec-rond {
  width: var(--espace-md);
  height: var(--espace-md);
  flex: none;
  border: 2px solid var(--gray-2);
  border-top-color: var(--cyan);
  border-radius: 999px;
  animation: cfec-tourne .8s linear infinite;
}

@keyframes cfec-tourne { to { transform: rotate(360deg); } }

.cfec-erreur {
  margin: 0 0 var(--espace-md);
  padding: var(--espace-md) var(--espace-lg);
  border: 1px solid var(--red);
  border-radius: var(--radius);
  background: var(--red-pale);
  color: var(--red-dark);
  font-size: var(--fs-sm);
}

/* Le resume : le compte par verdict, et le filtre. */
.cfec-resume {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-md);
}

.cfec-pastille {
  display: flex;
  align-items: baseline;
  gap: var(--espace-2xs);
  padding: var(--espace-xs) var(--espace-md);
  border: 1px solid var(--gray-2);
  border-radius: 999px;
  background: #fff;
  font-family: var(--sans);
  font-size: var(--fs-xs);
  color: var(--gray-6);
  cursor: pointer;
  transition: box-shadow .12s ease, border-color .12s ease;
}

.cfec-pastille:hover { border-color: var(--gray-4); }

/* Le filtre actif se distingue par un cerne, pas par une couleur : la couleur
   de chaque pastille dit deja de quel verdict elle parle, et la reecrire
   ferait perdre cette lecture-la. */
.cfec-pastille.actif { border-color: var(--gray-6); box-shadow: 0 0 0 1px var(--gray-6); }

.cfec-pastille-nombre { font-size: var(--fs-lg); font-weight: 700; }
.cfec-pastille-libelle { font-size: var(--fs-2xs); }

.cfec-pastille.cfec-verdict-anomalie { background: var(--red-pale); border-color: var(--red-pale); color: var(--red-dark); }
.cfec-pastille.cfec-verdict-a_recuperer { background: var(--purple-pale); border-color: var(--purple-pale); color: var(--purple); }
.cfec-pastille.cfec-verdict-a_controler { background: var(--orange-pale); border-color: var(--orange-pale); color: var(--orange); }
.cfec-pastille.cfec-verdict-information { background: var(--blue-pale); border-color: var(--blue-pale); color: var(--blue-dark); }
.cfec-pastille.cfec-verdict-reussi { background: var(--green-pale); border-color: var(--green-pale); color: var(--green); }
.cfec-pastille.cfec-verdict-sans_objet { background: var(--gray-1); border-color: var(--gray-2); color: var(--gray-5); }
.cfec-pastille.cfec-verdict-erreur { background: var(--yellow-pale); border-color: var(--yellow-pale); color: var(--gray-6); }

/* La carte d'identite du fichier. Un rapport qui ne dit pas ce qu'il a lu ne
   se verifie pas : deux fichiers d'un meme exercice n'ont ni le meme nombre
   de lignes ni les memes journaux. */
/* Le cadre et le fond gris sont passes de la liste a chacune de ses cases. Les
   seize couples formaient un pave de trente lignes de texte ou l'oeil ne
   trouvait pas la valeur qu'il cherchait ; encadrees une par une, elles se
   comptent du regard comme la rangee de chiffres d'un tableau de bord. Le
   cadre de la zone, lui, est celui de la tuile qui entoure la liste. */
.cfec-fiche {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--espace-sm);
  margin: 0;
  font-size: var(--fs-sm);
}

.cfec-case {
  min-width: 0;
  padding: var(--espace-sm) var(--espace);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

.cfec-fiche dt {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
}

.cfec-fiche dd {
  margin: var(--espace-3xs) 0 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.cfec-fiche dd.cfec-alerte { color: var(--red); }

/* Deux chapitres s'ecartent comme deux tuiles voisines partout ailleurs. Les
   trente-deux pixels d'avant separaient des zones sans cadre ; le cadre fait
   le travail, et la moitie de l'ecart suffit. */

/* Un chapitre range ses points de front. Mesure a 2560 : un point faisait
   2454 px de large pour deux lignes de prose, et soixante-dix des cent six
   points tiennent sous 260 px de haut. La largeur etait prise sans etre
   employee, et la page s'allongeait d'autant. Quatre colonnes a 2560, trois a
   1920, deux a 1512 et a 1280, une sur telephone.

   Les quarante-quatre points qui portent un tableau font exception et gardent
   la rangee entiere : leurs cellules sont en `nowrap`, un tableau de dix
   colonnes ne se lit pas dans un quart d'ecran. C'est ce qui evite la grille
   en escalier -- ce qui depasse en hauteur est justement ce qui prend toute la
   largeur. Les cartes courtes se calent donc a la meme hauteur dans leur
   rangee, sans etre etirees par un voisin de cinq mille pixels. */
.cfec-chapitre {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 34rem), 1fr));
  gap: var(--espace-md);
  margin-bottom: var(--espace-md);
}

.cfec-chapitre-titre { grid-column: 1 / -1; }

.cfec-chapitre .cfec-point:has(.cfec-tableau:not([hidden])) { grid-column: 1 / -1; }

/* Le trait sous le titre est devenu une division interne de tuile : un pixel,
   comme celui de `.ticket-card-header`, et non deux. */
.cfec-chapitre-titre {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  margin: 0 0 var(--espace-md);
  padding-bottom: var(--espace-xs);
  border-bottom: 1px solid var(--gray-2);
  font-size: var(--fs-h3);
  font-weight: 700;
}

.cfec-chapitre-code {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--cyan-dark);
}

.cfec-chapitre-compte {
  margin-left: auto;
  font-size: var(--fs-2xs);
  font-weight: 500;
  color: var(--gray-5);
}

.cfec-chapitre-compte.cfec-chapitre-a-traiter { color: var(--red); font-weight: 700; }

/* Un point. Le liseré de gauche porte le verdict : c'est ce qui se voit en
   faisant defiler, avant meme de lire le titre. */
.cfec-point {
  padding: var(--espace-md);
  border: 1px solid var(--gray-2);
  border-left: 3px solid var(--gray-2);
  border-radius: var(--radius);
}

.cfec-point[data-verdict="anomalie"] { border-left-color: var(--red); }
.cfec-point[data-verdict="a_recuperer"] { border-left-color: var(--purple); }
.cfec-point[data-verdict="a_controler"] { border-left-color: var(--orange); }
.cfec-point[data-verdict="information"] { border-left-color: var(--blue); }
.cfec-point[data-verdict="reussi"] { border-left-color: var(--green); }
.cfec-point[data-verdict="sans_objet"] { border-left-color: var(--gray-3); }
.cfec-point[data-verdict="erreur"] { border-left-color: var(--yellow); }

.cfec-point-tete {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  flex-wrap: wrap;
}

.cfec-code {
  font-family: var(--mono);
  font-size: var(--fs-2xs);
  font-weight: 700;
  color: var(--gray-5);
  flex: none;
}

.cfec-point-titre { margin: 0; font-size: var(--fs-md); font-weight: 600; }

.cfec-mesure {
  margin-left: auto;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
}

.cfec-verdict {
  flex: none;
  padding: var(--espace-3xs) var(--espace-sm);
  border-radius: 999px;
  font-size: var(--fs-3xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  background: var(--gray-1);
  color: var(--gray-5);
  white-space: nowrap;
}

.cfec-verdict.cfec-verdict-anomalie { background: var(--red-pale); color: var(--red-dark); }
.cfec-verdict.cfec-verdict-a_recuperer { background: var(--purple-pale); color: var(--purple); }
.cfec-verdict.cfec-verdict-a_controler { background: var(--orange-pale); color: var(--orange); }
.cfec-verdict.cfec-verdict-information { background: var(--blue-pale); color: var(--blue-dark); }
.cfec-verdict.cfec-verdict-reussi { background: var(--green-pale); color: var(--green); }
.cfec-verdict.cfec-verdict-sans_objet { background: var(--gray-1); color: var(--gray-5); }
.cfec-verdict.cfec-verdict-erreur { background: var(--yellow-pale); color: var(--gray-6); }

.cfec-objectif {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.cfec-message {
  margin: var(--espace-sm) 0 0;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

/* Un tableau est une boite, pas une rallonge de page. Seize des cent six
   points portent une liste de deux cents lignes, et ces seize-la faisaient a
   eux seuls quatre-vingt mille des quatre-vingt-seize mille pixels du
   document : le rapport se lisait a travers ses annexes. La boite garde les
   deux axes -- les cellules sont en `nowrap` -- et se borne aux deux tiers de
   la fenetre, mesure qui n'a pas de barreau dans l'echelle des espaces parce
   qu'elle se prend sur la fenetre et non sur la page. L'en-tete se colle en
   haut de la boite : sans lui, on lit des colonnes sans nom des la dixieme
   ligne. */
.cfec-tableau {
  margin-top: var(--espace-sm);
  max-height: 66vh;
  overflow: auto;
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
}

.cfec-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-2xs);
  font-family: var(--mono);
}

.cfec-table th,
.cfec-table td {
  padding: var(--espace-2xs) var(--espace-sm);
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--gray-2);
}

.cfec-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--gray-1);
  font-family: var(--sans);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
}

.cfec-table tbody tr:last-child td { border-bottom: 0; }

/* « 200 lignes affichees sur 3 412 » reste au bas de la boite pendant qu'on
   la parcourt : la note se lit avec les lignes qu'elle chiffre, pas apres. */
.cfec-tronque {
  position: sticky;
  bottom: 0;
  margin: 0;
  padding: var(--espace-2xs) var(--espace-sm);
  border-top: 1px solid var(--gray-2);
  background: var(--gray-1);
  font-size: var(--fs-3xs);
  color: var(--gray-5);
}

/* Ce que le point met en jeu. Ecrit en bas et en petit : on le lit quand le
   verdict oblige a decider quoi faire, pas avant. */
.cfec-enjeux {
  margin: var(--espace-sm) 0 0;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.cfec-enjeux-marque {
  display: inline-block;
  margin-right: var(--espace-2xs);
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  font-size: var(--fs-3xs);
}

@media print {
  .cfec-entete-actions,
  .cfec-attente { display: none !important; }

  .cfec-point,
  .cfec-chapitre { break-inside: avoid; }

  /* Le papier n'a ni fenetre ni defilement : la bande de tete redevient un
     bloc ordinaire, la boite du tableau rend toutes ses lignes, et un chapitre
     redescend sur une colonne -- trois colonnes sur une feuille A4 donneraient
     des cartes de six centimetres. */
  .cfec-tete { position: static; }

  .cfec-chapitre { grid-template-columns: 1fr; }

  .cfec-tableau { overflow: visible; max-height: none; }

  .cfec-table th { position: static; }

  .cfec-tronque { position: static; }

  .cfec-table { font-size: 8pt; }

  .cfec-table th,
  .cfec-table td { white-space: normal; }
}

/* ---------- Les rondes ---------- */

/* Le compte rendu d'une ronde : quatre ou cinq nombres et ce qu'elle a trouve.
   Meme encart que les autres blocs de la page Cabinet ; ce qui lui est propre
   est la rangee de chiffres, qui doit se lire d'un coup d'oeil -- c'est la
   reponse a « combien de messages as-tu envoyes ». */
.ronde {
  padding: var(--espace-sm) var(--espace-md);
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* Une grille, pas une rangee libre. En flex, chaque case ne faisait que la
   largeur de son propre libelle -- « alertes » 38 px contre « publications
   retenues » 122 px -- donc rien ne s'alignait a l'interieur d'un bloc.
   auto-fit resserre les colonnes vides : les quatre ou cinq chiffres d'un bloc
   se partagent sa largeur a egalite, sans case morte au bout. Les deux blocs
   de la page n'ont pas la meme largeur de case -- l'un compte cinq chiffres,
   l'autre quatre -- et c'est voulu : chacun est une tuile a lui, remplir sa
   largeur vaut mieux que laisser un trou pour s'aligner sur le voisin. C'est
   la geometrie que la feuille emploie deja pour une rangee de chiffres
   (.tka-chiffres) : une seule grille de chiffres dans la maison, pas deux. */
.ronde-chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--espace-sm);
}

/* Une case pleine, pas encadree : la ronde est deja un .tuile-encart pose dans
   une .tuile, et un trait ici serait le troisieme cadre emboite. */
.ronde-chiffre {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  padding: var(--espace-sm) var(--espace-md);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.ronde-chiffre strong {
  font-size: var(--fs-h2);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
  line-height: 1.2;
}

.ronde-actions {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
}

/* Le compte rendu est la seconde moitie du panneau, pas la suite de la
   premiere : au-dessus les nombres et le bouton, en dessous ce que la ronde a
   trouve. Un filet les separe, comme deux `.reglages-group` dans une tuile et
   comme l'identite d'un etablissement plus haut dans la meme page. Un filet,
   pas un cadre -- voir `.ronde-chiffre`.

   Le `<summary>` lui-meme n'a plus de regle ici : il est habille avec l'autre
   `<summary>` de la page, plus haut dans la feuille. */
.ronde-detail {
  border-top: 1px solid var(--gray-2);
  padding-top: var(--espace-sm);
}

/* Quatre listes qui se suivaient sans rien entre elles ni entre leurs lignes :
   109 puces sur 2091 px pour les seuls mandats ecartes d'un cabinet, et le
   meme motif (« Rien de publie recemment... ») repete quatre-vingt-dix fois.
   C'etait le dernier mur du produit -- un conteneur dont les enfants directs
   ne portent ni cadre, ni fond, ni ombre, ni filet.

   Chaque liste devient donc une case pleine : le fond la detache du blanc de
   l'encart, un filet separe deux lignes, et rien n'est encadre. La ronde est
   deja un `.tuile-encart` pose dans une `.tuile` ; un cadre ici serait le
   troisieme emboite, ce que `.ronde-chiffre` refuse plus haut pour la meme
   raison. Le filet est `--gray-3` et non `--gray-2` : sur un fond `--gray-1`,
   `--gray-2` ne se voit pas -- meme appariement que la liste des mandats d'un
   groupe (`.reglages-groupe-membres-liste`).

   Bornee, aussi, et pour la meme raison que celle-la : 109 mandats ecartes
   font deux ecrans et demi d'une page qui en compte huit, et le defilement
   reste chez elle.

   Une liste vide disparait au lieu de laisser une barre grise. Elle ne part
   jamais seule : le gabarit et cabinet.js masquent tous deux l'etiquette
   d'une liste sans lignes, donc l'etiquette et la case s'en vont ensemble.

   `:not(:has(li))` et non le `:empty` que la maison emploie ailleurs : un
   `<ul>` rendu par Jinja contient un retour a la ligne meme quand la boucle
   n'a rien produit, et une liste qui contient un blanc n'est pas vide au sens
   de `:empty`. Constate au navigateur -- la case des echecs restait la, haute
   de zero pixel donc invisible, mais emportant sa marge. `:empty` continue de
   convenir aux listes que seul le JavaScript remplit, pas a celles qu'un
   gabarit ecrit. */
.ronde-liste {
  margin: var(--espace-2xs) 0 0;
  padding: 0;
  list-style: none;
  max-height: 18rem;
  overflow-y: auto;
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  font-size: var(--fs-sm);
  color: var(--gray-6);
}

.ronde-liste:not(:has(li)) { display: none; }

.ronde-liste > li { padding: var(--espace-xs) var(--espace-sm); }

.ronde-liste > li + li { border-top: 1px solid var(--gray-3); }

.ronde-rates { color: var(--red-dark); }

/* Les noms sous une ligne : les fichiers deposes, les exercices qui manquent.
   Sur leur propre ligne et en retrait, pour que la ligne du mandat reste
   lisible d'un coup d'oeil et que les noms se lisent quand on les cherche. */
.ronde-noms {
  display: block;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Le titre d'une des listes du detail. Une ronde finie en aligne quatre -- ce
   qu'elle a trouve, ce qui manque, ce qu'elle a ecarte, ce qui a echoue -- et
   sans intitule on ne sait pas laquelle on lit. Ce commentaire disait trois et
   la regle valait pour deux : les listes des trouvailles et des echecs
   n'avaient pas d'etiquette du tout. Elles en ont une depuis le 31 aout 2026.

   La forme vient de `.toolbar-label`, l'etiquette de section du site : petites
   capitales grises, la meme au-dessus d'une liste qu'au-dessus d'une barre
   d'outils. Il ne reste ici que l'ecart au-dessus, qui est ce qui separe une
   sous-zone de la precedente ; rien en dessous, la liste portant sa propre
   marge. */
.ronde-sous-titre { margin: var(--espace) 0 0; }

.ronde-manques { color: var(--orange-dark); }

.ronde-ecartes { color: var(--gray-5); }

/* ---------- Les rapports et attestations du commissaire aux comptes ---------- */

/* Une carte par piece deposee, et non plus une par nature.
   « J'ajoute mon document, puis je precise ce que c'est » (suivi du 31 aout
   2026) : la tuile n'a plus qu'une rangee de boutons en tete, puis la liste de
   ce qui a ete depose. La carte reste la meme -- celle des intervenants et des
   exercices --, parce que ce qu'elle cerne n'a pas change de famille : c'est
   toujours une liste de reglages dans le panneau du mandat. Ce qu'elle contient,
   si : un nom, ce que ce nom est, et de quoi le retirer.

   Une grille et non un `flex` : le nom, ce qu'il est et la corbeille doivent
   s'aligner d'une carte a l'autre, sinon ils ondulent avec la longueur des
   noms de fichiers -- qui se mesurent en dizaines de caracteres. Le nom prend
   ce qui reste (`minmax(0, 1fr)`, sans quoi un nom long pousse le reste hors
   de la tuile au lieu de se couper).

   **Deux lignes et non une** : « pour les documents et le type de documents
   fais-le sur 2 lignes pour une meilleure visibilite » (ticket du 2 septembre
   2026). Le nom et sa nature se disputaient une seule ligne, et c'est le nom
   qui payait : les trois colonnes se partageaient la largeur de la tuile, si
   bien qu'un nom de rapport un peu long repliait sur deux ou trois lignes a
   cote d'une liste deroulante qui, elle, n'en occupait qu'une. Le nom a
   desormais la ligne pour lui -- avec sa corbeille au bout, la ou l'on va la
   chercher --, et la nature la ligne du dessous. */
.rapport-cac {
  display: grid;
  /* Quatre colonnes depuis le millesime (ticket du 15 septembre 2026, « ne
     faire apparaitre que les documents de l'annee N+1, N et N-1 [...] les plus
     recents en haut ») : l'annee en tete de rangee, le nom prend ce qui reste,
     les deux gestes tiennent leur largeur au bout de sa ligne -- ranger, puis
     jeter. L'annee est ce qui ordonne la liste, elle se lit donc en premier,
     et une colonne de millesimes alignes se parcourt d'un coup d'oeil la ou
     une annee noyee dans le nom se cherche ligne a ligne. */
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-areas:
    "annee   nom      renommer retirer"
    "nature  nature   nature   nature";
  /* Moins d'air entre les deux lignes d'une meme piece qu'entre le nom et ses
     gestes : ce sont deux facons de dire la meme chose, pas deux rubriques. */
  gap: var(--espace-2xs) var(--espace-sm);
  /* `start` et non `center` : depuis que le nom passe a la ligne au lieu de se
     couper, sa ligne peut faire deux lignes de haut, et un centrage ferait
     alors flotter la corbeille au milieu du vide. */
  align-items: start;
}

.rapport-cac-nom { grid-area: nom; }

/* Le millesime de la piece, lu dans son nom. Meme encre et meme chasse fixe
   que la colonne d'annee des versions anciennes : c'est la meme information
   au meme endroit de la page, et deux facons de l'ecrire se verraient. Une
   largeur fixe pour que les noms s'alignent, y compris sous les pieces qui ne
   portent pas de date. */
.rapport-cac-annee {
  grid-area: annee;
  width: 3.2em;
  color: var(--gray-5);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

.rapport-cac > [data-role="renommer"] { grid-area: renommer; }

.rapport-cac > [data-role="retirer"] { grid-area: retirer; }

/* Le champ de renommage prend la place du nom, donc sa cellule : sans cela il
   se posait en quatrieme colonne implicite et poussait les deux gestes hors de
   la tuile le temps de la saisie. */
.rapport-cac > .ligne-nom-champ { grid-area: nom; }

.rapport-cac + .rapport-cac {
  margin-top: var(--espace-xs);
}

/* Le nom depose, qui ouvre la piece.

   Il passe a la ligne plutot que de se couper -- « le nom complet du fichier
   doit etre visible, sans etre coupe » (demande du 31 aout 2026). Il finissait
   en points de suspension, et c'etait un raisonnement de mise en page applique
   a la mauvaise chose : ce nom n'est pas un libelle decoratif, c'est la SEULE
   facon de distinguer deux rapports de la meme nature, et « Rapport general
   ACBB 2025 v… » les rend justement indistinguables. Les trois colonnes tiennent
   toujours -- c'est la rangee qui grandit d'une ligne, pas la liste deroulante
   qui sort de la tuile --, et `anywhere` coupe les noms d'un seul tenant, ceux
   qu'aucune espace ne sait plier.

   `align-items: start` sur la carte, du coup : sur deux lignes de nom, un
   `center` ferait flotter la liste deroulante et la corbeille au milieu du
   vide. */
.rapport-cac-nom {
  min-width: 0;
  overflow-wrap: anywhere;
  /* Justifie a gauche dans sa cellule : un lien est un bloc en ligne, et rien
     ne l'etirerait sans cela sur toute la largeur restante. */
  justify-self: start;
}

/* Le nom d'une piece deposee dans le volet du mandat -- la lettre de mission,
   son projet, le papier a en-tete. Meme regle et meme raison que ci-dessus : un
   nom de fichier se mesure en dizaines de caracteres, le groupe plie deja
   (`flex-wrap` sur `.reglages-piece`), mais un nom d'un seul tenant poussait
   ses icones hors du panneau au lieu de se plier avec lui. Le `<a>` designe le
   nom et rien d'autre : les gestes voisins sont des `<button>`. */
.reglages-piece > a.btn-link {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* La liste deroulante qui dit ce que la piece est. `select` est deja habille a
   la base de la feuille -- rien a reecrire ici que sa taille de texte, celle du
   reste de la carte, et le fait qu'elle ne doit pas s'etirer. */
.rapport-cac-genre {
  grid-area: nature;
  justify-self: start;
  font-size: var(--fs-sm);
  width: auto;
  max-width: 100%;
}

/* Le creux entre la rangee de boutons et la liste n'existe que s'il y a
   quelque chose : une tuile ou rien n'est encore depose ne doit pas laisser de
   couloir sous ses deux boutons. `:has` et non `:empty` -- le gabarit laisse un
   retour a la ligne dans le bloc, qui suffit a le rendre non vide. */
.rapports-cac-liste:has(> .rapport-cac) {
  margin-top: var(--espace-sm);
}

/* ------------------------------------------------------------------
   Les anciennes versions d'une case du mandat
   ------------------------------------------------------------------
   « Tu vas bien sur avoir en premiere page le fichier actuel, mais tu vas
   pouvoir aussi, si on deploie, voir les anciens » (demande du 7 septembre
   2026). Une case du volet Mandat ne montre qu'une piece ; ce qui la precedait
   dort desormais sous une depliure, repliee par defaut.

   Ecrite discrete, et delibrement : la case est faite pour montrer la piece du
   jour. Une depliure qui pese autant que ce qu'elle accompagne deplacerait le
   regard vers le passe a chaque ouverture du mandat. */
.anciennes-versions {
  margin-top: var(--espace-xs);
  font-size: var(--fs-sm);
}

.anciennes-versions-titre {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  cursor: pointer;
  color: var(--gray-5);
  /* La fleche par defaut du navigateur n'a pas la meme allure d'un moteur a
     l'autre, et l'icone d'historique dit mieux ce qui se deplie. */
  list-style: none;
}

.anciennes-versions-titre::-webkit-details-marker { display: none; }

.anciennes-versions-titre:hover { color: var(--gray-6); }

.anciennes-versions-titre .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

/* Le nombre de versions, lisible sans deplier : c'est ce qui decide si l'on
   deplie. */
.anciennes-versions-compte {
  margin-left: var(--espace-2xs);
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: var(--gray-2);
  font-variant-numeric: tabular-nums;
}

.anciennes-versions-liste {
  margin: var(--espace-2xs) 0 0;
  padding-left: calc(var(--icon-sm) + var(--espace-xs));
  list-style: none;
}

.anciennes-versions-item {
  display: flex;
  align-items: baseline;
  gap: var(--espace-xs);
  min-width: 0;
}

/* L'annee en colonne fixe : les versions se lisent l'une sous l'autre, et un
   millesime qui se decale d'une ligne a l'autre ne se lit plus en colonne.
   Vide quand l'annee est inconnue -- la colonne reste, la ligne s'aligne. */
.anciennes-versions-annee {
  flex: 0 0 auto;
  width: 3.2em;
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
}

.anciennes-versions-nom {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------
   L'onglet Livrable, et la revue analytique qui l'occupe
   ------------------------------------------------------------------
   « Je souhaiterais que tu crees un nouvel onglet a droite de l'onglet
   assistant qui s'appelle livrable [...] et je voudrais que tu fasses une revue
   analytique du bilan et du compte de resultat » (ticket du 1er septembre
   2026).

   Rien de neuf en jetons : la tuile, la barre d'outils et la table defilante
   sont celles du reste du produit. Ce qui s'ecrit ici, c'est ce que cet ecran
   a de propre -- trois natures de lignes dans un document de synthese, et deux
   sens de variation. */

/* Un module annonce mais pas encore ecrit -- le plan de mission, la synthese.
   Une carte d'une ligne : elle tient la place dans l'ordre demande sans se
   faire passer pour un module vide, et le module qui existe reste a portee de
   regard sous elle. */
/* Un onglet de l'Analyse qui n'a rien a montrer : « les onglets doivent
   apparaitre meme si vide » (suivi du 3 septembre 2026). La tuile se pose sous
   la rangee de boutons, a la place des tableaux, et n'a rien d'autre a faire
   que se lire -- un titre, une phrase qui dit ce que l'onglet attend, et le
   bouton qui mene la ou l'on depose les ecritures. */
.analyse-vide {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--espace-xs);
}

.analyse-vide .tuile-titre { margin-bottom: 0; }

.analyse-vide .reglages-hint { margin: 0; max-width: 46rem; }

.livrable-annonce {
  padding-top: var(--espace-md);
  padding-bottom: var(--espace-md);
}

.livrable-annonce .tuile-titre {
  margin-bottom: var(--espace-2xs);
}

/* Les phrases d'ouverture, avant les tableaux : ce qu'on lit pour savoir si
   l'exercice est ordinaire. Sur un fond pale et non sur du blanc -- c'est un
   texte redige au milieu de chiffres, et il doit se distinguer d'un commentaire
   perdu entre deux tables. */
.revue-synthese {
  background: var(--cyan-pale);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  padding: var(--espace-md);
  margin-bottom: var(--espace-lg);
}

.revue-synthese p {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-md);
}

.revue-synthese p:last-child { margin-bottom: 0; }

.revue-bloc-titre {
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--black);
  margin: var(--espace-xl) 0 var(--espace-sm);
}

.revue-section-titre {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--gray-6);
  margin: var(--espace-md) 0 var(--espace-xs);
}

/* L'analyse poste par poste : un sous-titre, puis la phrase qui dit ce que le
   poste a fait et a quoi c'est du. « Chaque poste analyse doit faire l'objet
   d'un sous-titre afin que ce soit plus clair » (ticket du 2 septembre 2026) --
   c'etait une liste a puces ou les stocks et le chiffre d'affaires se
   suivaient, et il fallait lire la phrase entiere pour savoir de quoi elle
   parlait.

   Plus petit que le titre d'une section de tableau (`.revue-section-titre`) :
   c'est un cran plus bas dans le document, et un sous-titre aussi gros que le
   titre du dessus ferait deux titres au lieu d'un titre et de son detail. */
.revue-fait-titre {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--black);
  margin: var(--espace-md) 0 var(--espace-3xs);
}

.revue-fait {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-md);
}

.revue-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs);
}

.revue-table th {
  text-align: left;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--suivi-entete);
  color: var(--gray-5);
  padding: var(--espace-2xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
  /* La bande de titres porte le fond de l'export, et non le blanc de la page :
     c'est le meme document des deux cotes, et un tableau dont l'en-tete se
     detache a l'ecran mais pas sur le papier se lit comme deux tableaux.
     Pas de `position: sticky` : la bande passerait sous la barre de navigation,
     qui est fixe -- une ligne collee sous une barre opaque ne colle rien. Les
     deux feuilles du bilan reannoncent donc leurs colonnes, comme dans le PDF
     (voir export_pdf._element_tableau). */
  background: var(--cyan-light);
}

.revue-table td {
  padding: var(--espace-2xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-2);
}

.revue-table th.num, .revue-table td.num { text-align: right; }

/* Les trois natures de lignes d'un document de synthese, peintes comme dans
   l'export (voir export_pdf) : l'intitule d'une rubrique sur le fond le plus
   pale, le sous-total sur le plus soutenu -- c'est le chiffre qui conclut un
   bloc qui doit se voir en premier, pas le titre qui l'ouvre. */
.revue-ligne-rubrique td {
  background: var(--cyan-pale);
  font-weight: 600;
  color: var(--black);
}

.revue-ligne-total td {
  background: var(--cyan-light);
  font-weight: 600;
}

/* Le point qui marque une variation retenue par les seuils. Discret : il
   accompagne l'intitule, il ne le remplace pas -- la phrase qui l'explique est
   plus haut, dans les faits marquants. */
.revue-marque {
  color: var(--cyan-dark);
  font-weight: 700;
}

/* Les deux colonnes d'ecart, en gris et non en vert et rouge.
   C'est la regle des variations du produit (`.variation-cell`, plus haut dans
   la feuille), et sur un livrable elle vaut plus qu'ailleurs : le vert et le
   rouge portent un jugement que le chiffre ne porte pas. Des charges « en
   baisse » peintes en rouge se lisent comme une mauvaise nouvelle, alors que
   c'en est une bonne, et un compte de resultat est fait pour moitie de charges.
   Le sens se lit au signe, qui est explicite (+120 000 EUR, -45 000 EUR) et ne
   dit rien de plus que ce qu'il dit. */
.revue-table td.revue-ecart { color: var(--gray-5); }

/* Le choix de l'exercice dans la barre d'outils du module : la largeur du
   contenu, pas celle de la barre. */

/* ---------- Le menu d'une piece, et son histoire ----------

   « Prevois egalement un menu evolutif regroupant les actions et informations
   liees aux fichiers » et « cet historique doit [...] rester discret dans
   l'interface, car il s'agit d'une fonction secondaire » (ticket du
   2 septembre 2026).

   Trois points en bout de rangee. Ils y etaient en gris clair tant qu'ils
   n'ouvraient que le tiroir du reste, a cote de six icones ; depuis le suivi
   du 2 septembre 2026 -- « regroupe toutes les actions situees en fin de ligne
   dans un seul bouton "..." » -- ils sont seuls et portent tout, donc ils ont
   la couleur d'un bouton d'action de la rangee, celle que `.btn-link` donne.
   Un bouton pale est un bouton secondaire, et celui-ci ne l'est plus.

   Le fond du survol vient de `.btn-link` ; ce qui s'ajoute ici est de le
   garder tant que le menu est ouvert, comme tout bouton qui deroule. */
.fichier-menu-btn[aria-expanded="true"] { background: var(--cyan-pale); }

/* La meme famille de surface flottante que les autres menus de la feuille
   (`.ticket-card-transfert-menu`, `.choix-fichier-ou-menu`) : fond blanc,
   bordure --gray-3, ombre portee, --radius-lg.

   Pose en coordonnees d'ecran (`fixed`) et non dans la cellule : une liste de
   fichiers defile dans une boite a `overflow`, ou un menu en absolu se ferait
   couper au bord du tableau. C'est le script qui le place sous son bouton et
   le rabat dans la fenetre. */
.fichier-menu {
  position: fixed;
  z-index: 120;
  min-width: 210px;
  padding: var(--espace-2xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: modal-pop-in .15s var(--ease);
}

.fichier-menu-choix {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--espace-sm);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-6);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.fichier-menu-choix:hover,
.fichier-menu-choix:focus-visible { background: var(--cyan-light); color: var(--cyan-dark); }
.fichier-menu-choix .icon { width: 16px; height: 16px; flex: none; }

/* La suppression garde le rouge qu'elle a dans la rangee : c'est le seul
   geste du menu qu'on ne defait pas d'un clic, et il doit se distinguer avant
   d'etre lu, pas apres. */
.fichier-menu-choix-danger { color: var(--red); }
.fichier-menu-choix-danger:hover,
.fichier-menu-choix-danger:focus-visible {
  background: var(--red-pale);
  color: var(--red-dark);
}

/* Le trait qui separe deux familles d'entrees -- ouvrir, ranger, sortir,
   qualifier, supprimer. C'est le trait des menus du systeme, et il fait ici le
   meme travail : dix entrees d'affilee se relisent a chaque ouverture, les
   memes en quatre paquets se visent du premier coup. Il deborde des marges du
   menu pour aller d'un bord a l'autre, comme dans le Finder. */
.fichier-menu-trait {
  height: 1px;
  margin: var(--espace-2xs) calc(-1 * var(--espace-2xs));
  background: var(--gray-2);
}

/* La fenetre d'historique, en fil : une pastille de couleur par geste, un rail
   qui les relie, un intertitre a chaque changement de jour.

   Etroite, et elle le reste : chaque evenement tient sur trois lignes courtes,
   et une fenetre large en ferait des rubans ou l'oeil perdrait le lien entre
   la pastille et sa phrase. */
.historique-fenetre {
  width: min(32rem, calc(100vw - 2rem));
  max-height: min(34rem, calc(100vh - 4rem));
  overflow: auto;
  padding: var(--espace-lg);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  background: #fff;
  color: var(--gray-6);
}

.historique-fenetre::backdrop { background: var(--voile); }

.historique-titre {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--gray-6);
}

.historique-nom {
  margin: var(--espace-2xs) 0 var(--espace-md);
  font-size: var(--fs-sm);
  color: var(--gray-5);
  word-break: break-word;
}

.historique-liste {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Le jour, en toutes lettres, une fois pour toutes les lignes qu'il porte.
   Sans lui, la date se repetait a chaque ligne et noyait la seule chose qui y
   change vraiment : l'heure. */
.historique-jour {
  margin: var(--espace-md) 0 var(--espace-xs);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-4);
}

.historique-jour:first-child { margin-top: 0; }

/* Une ligne du fil : la pastille a gauche, le geste a droite, et le rail qui
   descend de l'une vers la suivante. */
.historique-ligne {
  position: relative;
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: var(--espace-sm);
  padding-bottom: var(--espace-md);
  font-size: var(--fs-sm);
}

/* Le rail. Il part du bas de la pastille et va jusqu'a la suivante : c'est ce
   trait, et non l'alignement seul, qui fait lire les gestes comme une suite
   plutot que comme une liste. Il s'arrete a la derniere ligne, ou il ne
   menerait nulle part. */
.historique-ligne::before {
  content: "";
  position: absolute;
  left: calc(1rem - 1px);
  top: 2.25rem;
  bottom: 0;
  width: 2px;
  background: var(--gray-2);
}

.historique-ligne:last-child { padding-bottom: 0; }
.historique-ligne:last-child::before { display: none; }

.historique-pastille {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
}

.historique-pastille .icon {
  width: 1rem;
  height: 1rem;
}

/* Six familles de gestes, six teintes. Elles ne decorent pas : elles separent
   ce qui se confond quand on parcourt. Ou est passe le nom, qui a dessine
   dessus, quand la piece a-t-elle change de dossier -- trois questions qui se
   repondent a la couleur avant de se lire.

   Les memes teintes sur le telephone, ou elles sont declarees dans
   `FamilleGesteFichier.swift` et tenues par le verificateur de parite : une
   piece racontee en deux couleurs selon l'ecran ne raconterait plus rien. */
.historique-famille-depot .historique-pastille {
  color: var(--cyan);
  background-color: var(--cyan-pale);
}

.historique-famille-nom .historique-pastille {
  color: var(--blue);
  background-color: var(--blue-pale);
}

.historique-famille-automatique .historique-pastille {
  color: var(--purple);
  background-color: var(--purple-pale);
}

.historique-famille-rangement .historique-pastille {
  color: var(--orange);
  background-color: var(--orange-pale);
}

.historique-famille-contenu .historique-pastille {
  color: var(--green);
  background-color: var(--green-pale);
}

.historique-famille-retrait .historique-pastille {
  color: var(--red);
  background-color: var(--red-pale);
}

.historique-corps { min-width: 0; }

.historique-entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--espace-sm);
}

.historique-mot { color: var(--gray-6); }

.historique-heure {
  flex: none;
  color: var(--gray-4);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

/* Le couple avant/apres d'un renommage ou d'un deplacement : « quel etait
   l'ancien nom » est la question la plus posee a cet ecran, et la reponse doit
   se lire sans lire la ligne.

   Deux lignes plutot que deux cadres cote a cote. Un nom de piece juridique
   fait quatre-vingts caracteres -- « 2011 RAPPORT SUR LES COMPTES ANNUELS
   COMBINE AROEVEN FEDERATION.pdf » -- et deux de ces noms ne tiennent jamais
   sur une largeur de fenetre : la rangee se repliait, et la fleche finissait
   au hasard, tantot apres l'ancien nom, tantot devant le nouveau. Elle tient
   maintenant sa propre colonne, au debut de la seconde ligne, et dit toujours
   la meme chose au meme endroit. C'est la disposition du telephone, ou la
   largeur imposait deja deux lignes. */
.historique-bascule {
  display: grid;
  grid-template-columns: .9rem 1fr;
  row-gap: var(--espace-3xs);
  align-items: baseline;
  margin-top: var(--espace-2xs);
}

.historique-bascule-avant,
.historique-bascule-apres {
  grid-column: 2;
  font-size: var(--fs-xs);
  word-break: break-word;
}

/* Barre : le nom d'avant n'est plus le nom du fichier, et c'est la seule
   chose qu'on ait besoin de savoir de lui. */
.historique-bascule-avant {
  color: var(--gray-4);
  text-decoration: line-through;
}

.historique-bascule-apres {
  color: var(--gray-6);
  font-weight: 600;
}

.historique-bascule-fleche {
  grid-column: 1;
  width: .75rem;
  height: .75rem;
  align-self: center;
  color: var(--gray-4);
}

.historique-detail,
.historique-auteur { display: block; }

.historique-detail {
  margin-top: var(--espace-2xs);
  color: var(--gray-6);
  word-break: break-word;
}

.historique-auteur {
  margin-top: var(--espace-2xs);
  color: var(--gray-5);
  font-size: var(--fs-xs);
}

/* Un geste defait reste dans l'histoire -- c'est meme ce qu'on y cherche quand
   un nom est revenu en arriere tout seul -- mais il se lit comme ce qu'il est :
   quelque chose qui n'a plus cours. Sa pastille perd sa couleur avec lui, sans
   quoi elle continuerait d'annoncer un geste qui n'a plus eu lieu. */
.historique-ligne-annulee { color: var(--gray-4); }
.historique-ligne-annulee .historique-mot { text-decoration: line-through; }

.historique-ligne-annulee .historique-pastille {
  color: var(--gray-4);
  background-color: var(--gray-1);
}

.historique-attente {
  padding: var(--espace-sm) 0;
  color: var(--gray-5);
  font-size: var(--fs-sm);
}

/* Pourquoi la piece porte ce nom, sous le fil des gestes.

   Separe du fil par un filet, et non pose a sa suite : ce n'est pas un geste
   de plus, ce n'est arrive a aucun moment. C'est ce que les regles disent du
   nom maintenant, et la seule reponse a « pourquoi rien n'a bouge ». */
.historique-nommage {
  margin-top: var(--espace-md);
  padding-top: var(--espace-md);
  border-top: 1px solid var(--gray-2);
}

.historique-nommage-entete {
  margin: 0 0 var(--espace-sm);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-4);
}

/* Les mots du moteur, sous la phrase qui les resume : « type PROCES-VERBAL »,
   « objet conserve : ASSEMBLEE ANNUELLE ». C'est le vocabulaire de l'onglet
   Nommage du mapping, la ou l'on va corriger la regle qui a lu de travers. */
.historique-nommage-lecture-titre {
  display: block;
  margin-top: var(--espace-xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.historique-nommage-lecture {
  margin: var(--espace-2xs) 0 0;
  padding-left: var(--espace-md);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.historique-nommage-lecture li { margin-top: var(--espace-3xs); }

.historique-pied {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--espace-md);
}

/* CHANGER UNE PIECE DE MANDAT (ticket du 9 septembre 2026 : « transfert le
   fichier suivant vers la federation des buralistes d'Ile de France »).

   La meme fenetre que l'historique du fichier -- meme largeur, meme cadre,
   meme pied --, ce qui evite une famille de plus pour une boite de plus. Ce
   qu'elle ajoute est la liste des mandats, et cette liste est celle du menu de
   portee de l'Assistant, aux memes classes : trois cent soixante-dix-neuf
   mandats se filtrent, ils ne se deroulent pas.

   La fenetre ne grandit pas avec la liste : elle occupe sa hauteur maximale
   des l'ouverture, et c'est la liste qui defile a l'interieur. Une boite dont
   la taille suit le filtre saute a chaque lettre tapee. */
.mandat-fenetre {
  display: flex;
  flex-direction: column;
  height: min(34rem, calc(100vh - 4rem));
  overflow: hidden;
}

.mandat-filtre { margin-bottom: var(--espace-sm); }

/* ---------- L'acceptation d'un mandat ----------

   « Le parcours le plus simple possible » (ticket du 2 septembre 2026) : une
   colonne, six sections dans l'ordre ou la procedure se deroule, la decision au
   bout. Rien d'autre a decider que de repondre a la question qu'on a sous les
   yeux -- pas d'onglets, pas de volets a deplier, pas de bouton
   « Enregistrer ».

   « Ameliore egalement la presentation des blocs : ils sont actuellement trop
   petits et difficiles a lire. Leur organisation et leur taille doivent
   permettre de comprendre immediatement les informations disponibles, les
   elements manquants et les actions a effectuer » (suivi du 5 septembre 2026).

   Ce qui a change, et ce qui n'a pas bouge. La colonne unique reste, l'ordre
   des sections reste, le questionnaire reste : ce n'etait pas la structure qui
   se lisait mal, c'etait sa taille. La page tenait dans 900 px, les libelles
   etaient a --fs-md et leur aide a --fs-xs, c'est-a-dire douze pixels pour la
   phrase qui explique la question. Trois barreaux montent d'un cran (la
   largeur, le libelle, l'aide), l'en-tete d'une section porte desormais son
   etat en toutes lettres au lieu d'un seul compte, et les questions se
   separent par un filet plutot que de se toucher. */
/* La page prenait 1040 px et se collait a gauche : `.app-main` n'a ni
   plafond ni marges automatiques, si bien que le plafond pose ici ne centrait
   rien. A 2 560 cela faisait 1 520 pixels de blanc d'un seul cote, et le
   questionnaire descendait sur 4 339 px pour cinq sections (demande du 6
   septembre 2026 : que la fenetre soit prise en entier, de haut en bas et de
   bord a bord, comme un logiciel et non comme un article). */

/* La frise reste en tete pendant qu'on repond : c'est elle qui dit d'ou l'on
   vient et ou l'on peut aller, et un questionnaire de trois mille pixels la
   faisait partir au premier tour de molette.

   `top: 0` et non `--h-entete` : `position: sticky` se mesure depuis la
   premiere boite qui defile, et c'est desormais le corps de la page, dont le
   bord haut est deja sous l'en-tete de l'application.

   Le creux du haut passe de la page a la frise, et il le faut : une boite
   collante ne sort pas du bloc qui la contient, donc elle ne peut pas remonter
   plus haut que le contenu de la page. Laisse sur la page, ce creux faisait
   une bande de trente-deux pixels au-dessus d'elle -- constate a 1 512 : on y
   voyait passer « Premier exercice a certifier » et « Y a-t-il un
   co-commissaire aux comptes ? ». Rendu a la frise, il est peint par elle, et
   rien ne passe plus au-dessus. Le telephone redit sa propre valeur dans
   mobile.css : la page y creusait treize pixels, pas trente-deux.

   Les marges negatives et le fond opaque vont ensemble : la frise doit
   reprendre la gouttiere qu'elle rend pour couvrir toute la largeur, et
   peindre le fond de la page sous elle. */
.acceptation-page.app-main-pleine { padding-top: 0; }

.acceptation-page .acceptation-frise {
  position: sticky;
  top: 0;
  z-index: 15;
  margin-left: calc(var(--gouttiere) * -1);
  margin-right: calc(var(--gouttiere) * -1);
  padding: var(--espace-2xl) var(--gouttiere) 0;
  background: var(--gray-1);
}

/* La frise du mandat en tete de l'acceptation (ticket du 5 septembre 2026 :
   « depuis "Prospect", je dois pouvoir acceder a la frise de navigation
   "Analyse - Source - Juridique - Comptable - Mandat" »).

   La meme barre que dans le mandat, aux memes noms et dans le meme ordre :
   ses items sont ici des liens et non des boutons, parce que ces panneaux-la
   vivent dans une autre page. Deux proprietes suffisent a les faire tenir
   dans la rangee -- un `<a>` n'est pas un bloc et se souligne. Le dernier
   item, « Acceptation », est un `<span>` : on y est deja, il n'y a nulle part
   ou aller. */
.acceptation-frise a.dossier-tab-btn,
.acceptation-frise span.dossier-tab-btn {
  display: inline-block;
  text-decoration: none;
}
.acceptation-frise span.dossier-tab-btn { cursor: default; }

.acceptation-entete {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

/* Prospect, client, prospect refuse : l'etiquette dit d'un mot ou en est le
   mandat, avant meme qu'on lise le resume. */
.acceptation-etiquette {
  align-self: flex-start;
  padding: var(--espace-3xs) var(--espace-sm);
  border-radius: 999px;
  background: var(--orange-pale);
  color: var(--orange-dark);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.acceptation-etiquette-client { background: var(--green-pale); color: var(--green-dark); }
.acceptation-etiquette-refuse { background: var(--gray-2); color: var(--gray-5); }

.acceptation-resume {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--gray-6);
}

/* La jauge : une procedure d'acceptation se fait en plusieurs fois, souvent a
   plusieurs jours d'intervalle. Savoir ce qu'il reste sans relire les six
   sections est ce qui evite de la laisser en plan. */
.acceptation-jauge {
  height: var(--espace-2xs);
  border-radius: 999px;
  background: var(--gray-2);
  overflow: hidden;
}
.acceptation-jauge-remplissage {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--cyan);
  transition: width .3s var(--ease);
}

/* Les deux encarts d'alerte reprennent les teintes des constats de
   l'Assistant : un empechement se peint comme une incoherence, un point a
   documenter comme un manque. Deux vocabulaires visuels dans le meme produit
   obligeraient a apprendre deux fois. */
.acceptation-alerte { border-left: 3px solid var(--orange); }
.acceptation-alerte-empeche { border-left-color: var(--red); }
.acceptation-alerte .tuile-titre { display: flex; align-items: center; gap: var(--espace-xs); }
.acceptation-alerte-empeche .tuile-titre { color: var(--red-dark); }
.acceptation-alerte-texte { margin: 0 0 var(--espace-sm); color: var(--gray-5); font-size: var(--fs-md); }
.acceptation-alerte-liste { margin: 0; padding-left: var(--espace-lg); color: var(--gray-6); font-size: var(--fs-md); }

/* L'en-tete d'une section : son titre, son « ? », et son etat en toutes
   lettres. Le titre et les jetons sur deux lignes plutot que sur une : une
   section qui porte trois jetons (« 4 / 5 renseignees », « 1 a repondre »,
   « 2 a documenter ») ne laisserait rien lire de son titre a leur gauche. */
/* Les cinq sections du questionnaire se rangent sur la largeur disponible.
   Empilees, elles faisaient une colonne de 976 px et 4 339 px de haut : on
   descendait cinq fois pour voir cinq blocs qui tiennent cote a cote.

   `minmax(min(100%, 40rem), 1fr)` : quarante rem est la largeur en dessous de
   laquelle une question et son aide cessent de se lire d'un trait, et le
   `min(100%, ...)` empeche la colonne d'etre plus large que la grille sur un
   telephone. Une colonne jusqu'a 1 300 px de contenu, deux jusqu'a 1 950,
   trois au-dela -- mesure : trois de front a 2 560, deux a 1 920 et 1 512,
   une a 1 280 et sur le telephone.

   `align-items: start` parce que les sections n'ont pas la meme hauteur (405
   a 1 179 px) : sans lui, chacune s'etirerait a la hauteur de la plus haute
   de sa rangee et son filet de pied flotterait dans le vide. */
#acceptation-sections {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 40rem), 1fr));
  gap: var(--espace-xl);
  align-items: start;
}

/* Le cran entre deux tuiles vient de la grille, plus de leur marge. En
   colonne, `margin-top` separait deux sections qui se suivaient ; en grille,
   il decale chaque tuile a l'interieur de sa rangee -- la premiere n'en a pas,
   et les deux suivantes tombaient donc seize pixels plus bas qu'elle. */
#acceptation-sections > .panel { margin-top: 0; margin-bottom: 0; }

.acceptation-section-entete {
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
  margin-bottom: var(--espace-2xs);
}
.acceptation-section-titre {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin: 0;
}
/* Le « pourquoi » d'une section ne s'affiche plus sous son titre : il est
   derriere le « ? », avec les references dont il decoule (ticket du 5 septembre
   2026). La regle de mise en page reste ici, pour le panneau. */
.acceptation-refs-pourquoi {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.55;
}
.acceptation-refs-pourquoi:last-child { margin-bottom: 0; }

/* Ce qui est la, ce qui manque, ce qui appelle une phrase : trois jetons dans
   cet ordre. C'est ce que le suivi du 5 septembre 2026 demande de comprendre
   « immediatement » -- l'ecran ne montrait que le deuxieme des trois, si bien
   qu'une section entierement remplie et une section jamais ouverte portaient
   le meme titre. */
.acceptation-jetons { display: flex; flex-wrap: wrap; gap: var(--espace-2xs); }
.acceptation-jeton {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-2);
  color: var(--gray-5);
  font-size: var(--fs-2xs);
  font-weight: 600;
  white-space: nowrap;
}
/* Les teintes sont celles des marques posees a cote des reponses
   (`.acceptation-marque*`), et pas d'autres : un point a documenter est orange
   dans le titre de la section comme il l'est sur la ligne de la question. Deux
   vocabulaires visuels pour le meme etat, sur le meme ecran, obligeraient a
   apprendre deux fois. Le bleu, lui, est celui de la provenance
   (`.acceptation-marque-registre`) : ce qui est deja la. */
.acceptation-jeton-pose { background: var(--blue-pale); color: var(--blue-dark); }
.acceptation-jeton-manque { background: var(--gray-2); color: var(--gray-5); }
.acceptation-jeton-ok { background: var(--green-pale); color: var(--green-dark); }
.acceptation-jeton-alerte { background: var(--orange-pale); color: var(--orange-dark); }
.acceptation-jeton-empeche { background: var(--red-pale); color: var(--red-dark); }

/* Le « ? » du titre, et ce qu'il ouvre : les references applicables de la
   section (« elles doivent rester discretes, mais etre accessibles en cliquant
   dessus »). Discret veut dire ici : un rond gris de la taille d'une icone,
   qui ne dit rien tant qu'on ne le demande pas. */
.acceptation-refs-btn {
  flex: none;
  width: var(--icon-md);
  height: var(--icon-md);
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: 999px;
  background: transparent;
  font-family: var(--sans);
  font-size: var(--fs-2xs);
  font-weight: 700;
  color: var(--gray-4);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease),
              border-color .15s var(--ease);
}
.acceptation-refs-btn:hover,
.acceptation-refs-btn[aria-expanded="true"] {
  background: var(--cyan-light);
  border-color: var(--cyan);
  color: var(--cyan-dark);
}
.acceptation-refs {
  margin: 0 0 var(--espace-md);
  padding: var(--espace-sm) var(--espace);
  border-left: 3px solid var(--cyan);
  background: var(--gray-1);
  border-radius: var(--radius-xs);
}
.acceptation-refs-titre {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-6);
}
.acceptation-refs-liste {
  margin: 0;
  padding-left: var(--espace);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.6;
}
.acceptation-refs-liste li + li { margin-top: var(--espace-2xs); }

/* Une question : le libelle a gauche, la reponse a droite. Deux colonnes et non
   une pile, parce qu'un questionnaire de trente questions empilees se lit comme
   un formulaire d'administration -- et parce que les reponses alignees se
   parcourent d'un coup d'oeil pour trouver celle qui manque. */
.acceptation-question {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--espace-md);
  padding: var(--espace-sm) 0;
  border-top: 1px solid var(--gray-2);
  /* `wrap` depuis le 3 septembre 2026 : l'eclairage des registres se pose sous
     les deux colonnes, sur toute la largeur (voir `.acceptation-eclairage`).
     Les deux colonnes, elles, tiennent toujours cote a cote -- 50 % et
     260 px de minimum --, donc rien d'existant ne descend d'une ligne. */
  flex-wrap: wrap;
}
.acceptation-question:first-of-type { border-top: none; }
/* Le libelle garde la moitie de la ligne : une rangee de trois choix larges
   (« Mission legale -- six exercices ») ecrasait sinon la colonne de gauche a
   quatre centimetres, et c'est elle qu'on lit. */
.acceptation-question-texte { flex: 1 1 50%; min-width: 260px; }
.acceptation-question-reponse {
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--espace-xs);
}
.acceptation-choix { flex-wrap: wrap; justify-content: flex-end; }

/* Le libelle et son aide montent chacun d'un barreau : la phrase qui explique
   une question de dossier d'acceptation etait a --fs-xs, douze pixels, sous un
   libelle a --fs-md. « Ils sont actuellement trop petits et difficiles a
   lire » (suivi du 5 septembre 2026). */
.acceptation-libelle {
  display: block;
  font-size: var(--fs-lg);
  font-weight: 500;
  color: var(--gray-6);
  line-height: 1.45;
}
.acceptation-aide {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
  line-height: 1.5;
}

/* Deux boutons cote a cote plutot qu'une liste deroulante : vingt questions sur
   trente se repondent par oui ou par non, et ouvrir un menu pour choisir entre
   deux mots est un geste de trop, repete vingt fois. */
.acceptation-choix { display: flex; gap: var(--espace-3xs); }
.acceptation-bouton {
  min-height: var(--h-sm);
  padding: 0 var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--gray-5);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease),
              border-color .15s var(--ease);
}
.acceptation-bouton:hover:not(:disabled) { border-color: var(--cyan); color: var(--cyan-dark); }
.acceptation-bouton.selected {
  background: var(--cyan-light);
  border-color: var(--cyan);
  color: var(--cyan-dark);
}
.acceptation-bouton:disabled { opacity: .55; cursor: default; }

.acceptation-champ { width: 160px; }
/* Les champs libres tiennent trois lignes et non deux : « Représentant légal
   de l'entité » prérempli du registre s'écrit « CHRISTOPHE JEAN CHARLES
   RAMBEAU (Président de SAS) », que deux lignes de 320 px coupaient au
   milieu -- une réponse préremplie qu'on ne peut pas lire en entier est une
   réponse qu'on ne relit pas. */
/* Une reponse libre prend la ligne entiere et sa hauteur suit son contenu.
   « Les zones "Beneficiaire effectif identifie" et "Objet et nature de la
   relation d'affaires" ont chacune une petite case a droite, peu lisible »
   (ticket du 5 septembre 2026) : posee dans la colonne de droite, la case
   tombait a 203 pixels au lieu des 380 que cette regle lui donnait, et elle
   montrait trois lignes d'un contenu qui en demandait douze.

   `overflow: hidden` parce que la hauteur est posee au pixel par le script
   (voir `ajusterTextes`) : la barre de defilement n'aurait rien a faire
   defiler, sauf sur une case repliee, ou elle sert. */
.acceptation-texte-zone {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--espace-3xs);
  width: 100%;
}
.acceptation-texte { width: 100%; max-width: 100%; overflow: hidden; }
.acceptation-texte-zone.deplie .acceptation-texte { overflow: auto; }

/* « Tout afficher » : un lien discret sous la case, pas un bouton de plus dans
   une page qui en porte deja soixante. Il n'apparait que lorsque le contenu
   deborde vraiment. */
.acceptation-texte-plier {
  padding: 0;
  border: none;
  background: none;
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--cyan-dark);
  cursor: pointer;
}
.acceptation-texte-plier:hover { text-decoration: underline; }

/* La marque d'une reponse : ce qui manque, ce qui appelle une phrase, ce qui
   ferme la porte. Elle est a cote de la reponse et non dans un recapitulatif
   plus loin -- c'est la qu'on est quand on repond. */
.acceptation-marque {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-2);
  color: var(--gray-5);
  font-size: var(--fs-3xs);
  font-weight: 600;
  white-space: nowrap;
}
.acceptation-marque-alerte { background: var(--orange-pale); color: var(--orange-dark); }
.acceptation-marque-empeche { background: var(--red-pale); color: var(--red-dark); }
/* Une reponse transcrite d'un registre public. Bleue et non grise : elle n'est
   ni un manque ni une alerte, c'est une provenance -- et un controle qualite
   doit pouvoir distinguer d'un coup d'oeil ce que quelqu'un a repondu de ce
   qu'une base a rendu (suivi du 3 septembre 2026). */
.acceptation-marque-registre { background: var(--blue-pale); color: var(--blue-dark); }

/* L'eclairage pose SOUS une question : ce que les registres savent et qui
   n'est pas une reponse -- les dirigeants au RNE sous le beneficiaire
   effectif, les facteurs de risque sous la classification. Encadre et decale,
   pour qu'on ne le lise jamais comme la reponse elle-meme. */
.acceptation-eclairage {
  flex: 1 0 100%;
  margin-top: var(--espace-sm);
  padding: var(--espace-sm) var(--espace);
  border-left: 3px solid var(--gray-3);
  background: var(--gray-1);
  border-radius: var(--radius-xs);
}
/* Celui du beneficiaire effectif porte un avertissement et non un
   renseignement : la liste qu'il montre n'est PAS la reponse a la question
   au-dessus, et c'est precisement ce qu'il faut qu'on lise. */
.acceptation-eclairage-attention { border-left-color: var(--orange); }
.acceptation-eclairage-titre {
  margin: 0 0 var(--espace-2xs) 0;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-6);
}
/* Un eclairage porte parfois deux blocs : sous la question de l'identite, les
   actes rapatries du registre puis les fiches ecrites du releve (voir
   `app/fiches_registres.py`). Sans cet espace, le second titre se colle a la
   note du premier et se lit comme sa suite. */
.acceptation-eclairage-titre:not(:first-child) { margin-top: var(--espace); }
.acceptation-eclairage-liste {
  margin: 0;
  padding-left: var(--espace);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.6;
}
.acceptation-eclairage-liste .acceptation-eclairage-liste {
  margin: var(--espace-3xs) 0 var(--espace-2xs);
  font-size: var(--fs-xs);
}
.acceptation-eclairage-vide,
.acceptation-eclairage-note {
  margin: var(--espace-2xs) 0 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
}
/* Ce qui, dans un eclairage, ne peut pas passer inapercu : une piece qui porte
   les statuts, une structure qui est deja un mandat du cabinet. La meme
   pastille que les marques d'une reponse, en plus petit, parce que c'est le
   meme geste de lecture -- on balaie et on s'arrete dessus. */
.acceptation-eclairage-marque {
  display: inline-block;
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: var(--blue-pale);
  color: var(--blue-dark);
  font-size: var(--fs-3xs);
  font-weight: 600;
  white-space: nowrap;
}
/* Le rapprochement avec le portefeuille du cabinet : ce n'est plus de
   l'eclairage, c'est un lien professionnel au sens de l'article L. 822-11, et
   la reponse au-dessus en depend. */
.acceptation-eclairage-lien {
  margin-bottom: var(--espace-sm);
  padding-bottom: var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
}
.acceptation-eclairage-lien .acceptation-eclairage-marque,
.acceptation-eclairage-lien .acceptation-eclairage-titre { color: var(--orange-dark); }
/* Le depot d'une piece, dans la colonne des reponses : ce qui a ete recu, puis
   le bouton qui le remplace. L'entree de fichier elle-meme reste cachee -- nue,
   elle prend l'apparence du systeme, et « Choisir un fichier / Aucun fichier
   selectionne » n'est ni du francais du produit ni un bouton d'aiudit. C'est
   l'etiquette qui l'ouvre, et c'est le geste courant du reste de la feuille. */
.acceptation-piece {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-xs);
}
.acceptation-piece-nom {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--green-dark);
}
.acceptation-piece-nom .icon { width: var(--icon-sm); height: var(--icon-sm); flex: none; }
/* L'espace des pieces d'identite (ticket du 5 septembre 2026 : « je dois
   pouvoir deposer plusieurs pieces d'identite pour le representant legal et les
   beneficiaires effectifs [...] utilise si possible le logo joint pour
   identifier visuellement cet espace »).

   Sur toute la largeur de la question et non dans la colonne des reponses :
   ce n'est plus une case a remplir, c'est une petite zone de fichiers, avec sa
   liste, ses actions et son depot. La forme est celle de l'eclairage des
   registres -- meme fond, meme retrait --, parce que c'est le meme geste de
   lecture : on parcourt, on s'arrete sur une ligne. */
.acceptation-pieces {
  flex: 1 0 100%;
  margin-top: var(--espace-sm);
  padding: var(--espace) var(--espace-md);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  border: 1px solid var(--gray-2);
}
.acceptation-pieces-entete {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-sm);
}
/* Le logo joint au ticket : une carte d'identite. Il ne porte aucune
   information que le titre ne porte pas -- il sert a reconnaitre l'endroit
   sans le lire, ce qui est exactement ce que le ticket demande. D'ou la
   taille : celle d'une grande icone, pas celle d'une illustration. */
.acceptation-pieces-logo {
  width: var(--espace-2xl);
  height: var(--espace-2xl);
  flex: none;
  object-fit: contain;
}
.acceptation-pieces-titre {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
}
.acceptation-pieces-compte {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.acceptation-pieces-liste {
  margin: 0 0 var(--espace-sm);
  padding: 0;
  list-style: none;
}
.acceptation-piece-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  padding: var(--espace-xs) 0;
  border-top: 1px solid var(--gray-2);
  cursor: pointer;
}
.acceptation-piece-ligne:first-child { border-top: none; }
.acceptation-piece-libelle {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}
.acceptation-piece-ligne:hover .acceptation-piece-libelle { text-decoration: underline; }
.acceptation-piece-actions { display: flex; gap: var(--espace-3xs); flex: none; }
.acceptation-piece-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-sm);
  height: var(--h-sm);
  padding: 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  color: var(--gray-5);
  cursor: pointer;
  transition: color .15s var(--ease), border-color .15s var(--ease);
}
.acceptation-piece-action .icon { width: var(--icon-sm); height: var(--icon-sm); }
.acceptation-piece-action:hover { border-color: var(--cyan); color: var(--cyan-dark); }
.acceptation-piece-action-danger:hover { border-color: var(--red); color: var(--red-dark); }
.acceptation-pieces-depot {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  flex-wrap: wrap;
}
.acceptation-piece-bouton { cursor: pointer; }
.acceptation-piece-entree { display: none; }
/* L'invite du glisser-deposer, tant qu'il n'y a rien. « Le glisser-deposer de
   la piece d'identite ne fonctionne pas » (ticket du 5 septembre 2026) : il ne
   fonctionnait pas parce qu'il n'existait pas, et rien ne le proposait non
   plus. Elle disparait des que la piece est la -- une invite a deposer sous une
   piece deposee ferait douter qu'elle le soit. */
.acceptation-piece-invite {
  margin: 0;
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

.acceptation-question-alerte { background: var(--orange-pale); }
.acceptation-question-empeche { background: var(--red-pale); }
.acceptation-question-alerte,
.acceptation-question-empeche {
  border-radius: var(--radius-sm);
  padding-left: var(--espace-sm);
  padding-right: var(--espace-sm);
}

/* Les modeles a utiliser tout de suite, au bas de la section de la diligence
   qu'ils servent.

   « Dans l'acceptation du mandat, propose aussi les modeles necessaires pour
   realiser immediatement les diligences, notamment la lettre au predecesseur »
   (suivi du 5 septembre 2026). Dans la section et non dans un bloc a part au
   bas de la page : la lettre se telecharge sous la question qui demande la
   date de son envoi, c'est-a-dire au moment ou l'on s'en sert. Le fond bleu
   pale les separe des questions -- ce ne sont pas des reponses a poser, ce
   sont des gestes a faire. */
.acceptation-modeles {
  margin-top: var(--espace-md);
  padding: var(--espace) var(--espace-md);
  border-radius: var(--radius-sm);
  background: var(--cyan-light);
}
.acceptation-modeles-titre {
  margin: 0 0 var(--espace-sm);
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--cyan-dark);
}
.acceptation-modele {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  padding: var(--espace-sm) 0;
  border-top: 1px solid var(--cyan);
}
.acceptation-modele:first-of-type { border-top: none; padding-top: 0; }
/* Un modele qu'une reponse manquante retient reste affiche, eteint : le faire
   disparaitre laisserait croire qu'il n'existe pas, et c'est justement la
   lettre au predecesseur qu'on irait chercher ailleurs. */
.acceptation-modele-eteint { opacity: .65; }
.acceptation-modele-texte { flex: 1 1 300px; }
.acceptation-modele-titre {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--gray-6);
}
.acceptation-modele-quoi {
  margin: var(--espace-3xs) 0 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
  line-height: 1.5;
}
.acceptation-modele-refs,
.acceptation-modele-attente {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.acceptation-modele-attente { flex: 0 1 260px; text-align: right; }
.acceptation-modele-btn { flex: none; text-decoration: none; }
.acceptation-modeles-note {
  margin: var(--espace-sm) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  line-height: 1.5;
}

.acceptation-decision-formulaire { display: flex; flex-direction: column; gap: var(--espace-sm); }
.acceptation-verdict { margin: 0; font-size: var(--fs-lg); font-weight: 600; }
.acceptation-verdict-acceptee { color: var(--green-dark); }
.acceptation-verdict-refusee { color: var(--red-dark); }
.acceptation-motif { margin: var(--espace-2xs) 0 0; color: var(--gray-5); font-size: var(--fs-md); }

/* Le journal, dans la forme de l'historique d'un fichier : une date en tete de
   ligne, ce qui a ete fait, par qui. Deux journaux du meme produit ne se lisent
   pas de deux facons. */
.acceptation-journal { margin: 0; padding: 0; list-style: none; }
.acceptation-journal-ligne {
  display: flex;
  gap: var(--espace-sm);
  padding: var(--espace-xs) 0;
  border-top: 1px solid var(--gray-2);
  font-size: var(--fs-md);
}
.acceptation-journal-ligne:first-child { border-top: none; }
.acceptation-journal-quand { flex: none; width: 130px; color: var(--gray-5); font-size: var(--fs-xs); }
.acceptation-journal-detail { display: block; color: var(--gray-6); }
.acceptation-journal-auteur { display: block; color: var(--gray-5); font-size: var(--fs-xs); }
.acceptation-journal-vide { padding: var(--espace-xs) 0; color: var(--gray-5); font-size: var(--fs-md); }

/* La pastille d'un prospect sur la liste des clients : le meme mot et la meme
   teinte que l'etiquette de l'ecran d'acceptation, pour qu'on reconnaisse la
   ligne avant de l'ouvrir. */
.dossier-prospect-badge {
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--orange-pale);
  color: var(--orange-dark);
  font-size: var(--fs-3xs);
  font-weight: 700;
  letter-spacing: .03em;
}

@media (max-width: 700px) {
  .acceptation-question { flex-direction: column; align-items: stretch; gap: var(--espace-xs); }
  .acceptation-texte, .acceptation-champ { width: 100%; }
}

/* Le bandeau d'un prospect, en tete de son mandat. Meme forme que le bandeau
   d'un groupe (`.dossier-groupe-bandeau`) : c'est la meme famille -- une bande
   qui dit sur quoi l'on est avant que les onglets ne commencent. */
.dossier-prospect-bandeau {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-md);
  border-left: 3px solid var(--orange);
  margin-bottom: var(--espace-md);
}
.dossier-prospect-bandeau strong { margin-left: var(--espace-xs); color: var(--gray-6); }
.dossier-prospect-bandeau .reglages-hint { margin: var(--espace-2xs) 0 0; }
.dossier-prospect-bandeau .btn-primary { flex: none; }

/* Une question a plus de deux choix pose ses boutons sous son libelle : trois
   intitules de mission font sept cents pixels, qui ne tiennent pas a droite
   d'un libelle sur une page de neuf cents. */
.acceptation-question-large { flex-direction: column; align-items: stretch; }
.acceptation-question-large .acceptation-question-reponse { justify-content: flex-start; }
.acceptation-question-large .acceptation-choix { justify-content: flex-start; }

/* Le bouton « Prospects » de la barre des filtres : un carre de la meme taille
   que les trois etats a cote (--h-sm), et l'orange du prospect quand il est
   allume. Il portait le mot « PROSPECTS » en pastille, qui debordait de la
   tuile et se faisait couper par le bouton d'ajout : une rangee de carres de
   vingt-huit pixels n'accueille pas un mot de neuf lettres. */
.filtre-prospects { color: var(--gray-4); }
.filtre-prospects:hover { color: var(--orange-dark); }
.filtre-prospects[aria-pressed="true"] {
  background: var(--orange-pale);
  border-color: var(--orange);
  color: var(--orange-dark);
}

/* ---------- La connexion au logiciel comptable ----------

   « Ajoute la connexion au logiciel comptable par API [...] inspire-toi de la
   presentation tres sobre de Finthesis » (ticket du 2 septembre 2026).

   Sobre veut dire ici : une ligne par logiciel, un filet entre elles, et rien
   d'autre. Pas de carte, pas d'ombre, pas de logo -- sept lignes encadrees
   chacune sous une zone de depot qui, elle, tient en trois lignes feraient de
   la connexion le sujet de l'onglet, alors que c'est la seconde porte du meme
   fichier. Le filet suffit a les separer, et c'est celui des lignes de
   reglages, qui font deja ce travail ailleurs dans le produit. */
.connexions-liste {
  display: flex;
  flex-direction: column;
  margin-top: var(--espace-sm);
}

/* Ce que le volet Mandat declare du logiciel du client, en tete de la liste :
   la seule phrase de ce bloc qui parle de CE mandat, les sept autres lignes
   etant le catalogue. Encadree comme un eclairage et non comme une alerte --
   elle renseigne, elle ne reclame rien --, et teintee selon ce qu'elle dit :
   verte quand la reprise directe est en place, cyan quand elle est a portee,
   grise quand il n'y a rien a brancher ou rien de declare. */
.connexion-mandat {
  margin: 0 0 var(--espace-sm) 0;
  padding: var(--espace-sm) var(--espace);
  border-left: 3px solid var(--gray-3);
  background: var(--gray-1);
  border-radius: var(--radius-xs);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  line-height: 1.6;
}
.connexion-mandat[data-etat="possible"] { border-left-color: var(--cyan); }
.connexion-mandat[data-etat="relie"] { border-left-color: var(--green); }
.connexion-mandat-modalites {
  display: block;
  margin-top: var(--espace-2xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  white-space: pre-line;
}

.connexion-ligne {
  padding: var(--espace-sm) 0;
  border-top: 1px solid var(--gray-2);
}

.connexion-ligne:first-child { border-top: none; }

/* La premiere ligne perd son trait de separation, et ce n'est plus elle depuis
   que le bandeau du mandat la precede : sans cette regle, un trait paraissait
   entre le bandeau et le premier logiciel, la ou les six autres n'en ont un
   qu'entre eux. */
.connexion-mandat + .connexion-ligne { border-top: none; }

.connexion-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
}

.connexion-identite {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  min-width: 0;
}

.connexion-nom {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

/* L'etat, en gelule : la meme forme que l'exercice a cote du titre d'un module,
   et les memes teintes que le reste du produit -- le vert de ce qui est fait,
   l'orange de ce qui demande un geste, le gris de ce qui attend. */
.connexion-etat {
  padding: 1px var(--espace-xs);
  border-radius: 999px;
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  background: var(--gray-1);
  color: var(--gray-5);
}

.connexion-etat[data-etat="reliee"] { background: var(--green-pale); color: var(--green-dark); }
.connexion-etat[data-etat="erreur"] { background: var(--orange-pale); color: var(--orange-dark); }
.connexion-etat[data-etat="libre"] { background: var(--cyan-pale); color: var(--cyan-dark); }

.connexion-message {
  margin: var(--espace-3xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.connexion-message[data-erreur="1"] { color: var(--orange-dark); }

/* Le parcours, deplie dans la ligne. Il n'a pas de cadre non plus : ce qui le
   detache est l'air au-dessus de lui et le retrait de la liste numerotee. */
.connexion-parcours { margin-top: var(--espace-sm); }

.connexion-etapes {
  margin: 0 0 var(--espace-sm);
  padding-left: var(--espace-lg);
  max-width: var(--largeur-lecture);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.connexion-etapes li { margin-bottom: var(--espace-3xs); }

.connexion-ligne-saisie {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs);
}

/* Le champ du jeton prend la place qu'il faut pour qu'un jeton colle se voie
   en entier -- une chaine de quarante caracteres tronquee a vingt laisse
   douter de ce qu'on vient de coller, meme masquee. */
.connexion-jeton { flex: 1 1 22rem; min-width: 0; }

.connexion-etat-travail {
  margin: var(--espace-xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.connexion-etat-travail[data-erreur="1"] { color: var(--red); }

/* La Conso, transformee en outil technique de controle des comptes
   consolides (ticket du 3 septembre 2026 : « transforme l'onglet conso en
   t'inspirant de cette reflexion »).

   Dix sous-vues qui partagent un `.unit-toggle` en tete de panneau. Chaque
   vue tient dans un `.conso-vue`, masquable par l'attribut `hidden`. */
.conso-nav { margin-bottom: var(--espace); }

.conso-vue { padding: var(--espace) 0; }

/* L'apercu et les Rapprochements ont ete retires le 14 septembre 2026
   (« l'onglet apercu n'apporte rien », « l'onglet rapprochements n'apporte
   rien »), et leurs styles avec eux : le titre, la ligne de resume du
   perimetre, la pile des six controles et la pastille qui les teintait. Elle
   etait le seul rond de statut de l'onglet, et plus rien ici ne porte de
   `data-statut`. Le `.conso-pastille` du tableau de bord, qui est un rond de
   profil de 24 px, n'a jamais ete celui-la et reste ou il est. */

/* Le compte des entites, en tete de la fiche du perimetre. Il s'ecrivait dans
   l'apercu ; il se lit desormais a cote de la liste qu'il compte. */
.conso-perimetre-compte {
  margin: 0 0 var(--espace-2xs) 0;
  font-weight: 600;
  color: var(--gray-6);
}

/* Les documents structurants du cabinet : cinq lignes en pile, chacune cochee
   ou en attente. En tete des Imports depuis le 14 septembre 2026, avec le
   retrait de l'apercu qui les portait : c'est la liste de ce qui doit etre
   depose, elle se lit donc la ou l'on depose. */
.conso-structurants {
  margin-top: var(--espace);
  padding: var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}
.conso-structurants h3 {
  margin: 0 0 var(--espace-sm) 0;
  font-size: var(--fs);
  color: var(--gray-6);
}
.conso-structurants ul { list-style: none; margin: 0; padding: 0; }
.conso-structurant {
  padding: var(--espace-2xs) 0;
  font-size: var(--fs-xs);
  color: var(--gray-6);
}
.conso-structurant.absent { color: var(--gray-4); }

/* L'exploitation des sources, au-dessus des documents structurants : la meme
   famille de bloc, et pour cause -- l'un dit ce que la Source porte, l'autre
   ce qu'on en a fait. Le bouton se pose sous la liste des vues calculees, sur
   sa propre ligne, avec la mention orange quand des pieces ont bouge depuis le
   dernier calcul. Voir `conso_exploitation` : « une fois que les choses ont
   ete calculees, les differents tableaux restent figes et ne se mettent a jour
   que lorsqu'il y a une modification » (suivi du ticket AMBISTRATE du
   17 septembre 2026). */
.conso-exploitation-action {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  flex-wrap: wrap;
  margin: var(--espace-sm) 0 0 0;
  font-size: var(--fs-xs);
}
.conso-exploitation-etat {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin: var(--espace-sm) 0 0 0;
}
/* La date du calcul, en tete de la vue qu'elle date : elle se lit avant le
   tableau et ne doit pas le pousser. */
.conso-exploitation-date {
  margin: 0 0 var(--espace-sm) 0;
}

/* La liste des entites deduites du perimetre : une pile simple, avec un
   filet a gauche qui rappelle la marque des lignes de tableau. */
.conso-perimetre-liste {
  list-style: none;
  margin: var(--espace) 0 0 0;
  padding: 0;
  border-left: 2px solid var(--gray-3);
}
.conso-perimetre-liste li {
  padding: var(--espace-2xs) var(--espace-sm);
  font-size: var(--fs);
  color: var(--gray-6);
}

/* La fiche du perimetre, quand le tableau depose par le cabinet a pu etre lu :
   le meme `revue-table` que partout ailleurs, avec deux ajouts.

   Les colonnes chiffrees (Siren, pourcentages) passent en chiffres tabulaires
   et s'alignent a droite -- « 59,8 % » et « 48,26 % » l'un sous l'autre ne se
   comparent que si la virgule tombe au meme endroit.

   Et une entite pour laquelle rien n'a ete depose se signale : c'est la seule
   information que l'ancienne liste, tiree des noms de fichiers, ne pouvait par
   construction pas porter -- une entite sans fichier n'y apparaissait pas du
   tout. Orange et non rouge : ce n'est pas une erreur, c'est une piece qui
   manque encore. */
.conso-perimetre-table .conso-num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.conso-perimetre-table tr[data-sans-document] td { background: var(--orange-pale); }
.conso-perimetre-manque { color: var(--orange-dark); }

/* Les etats consolides. Les chiffres de tete d'abord : six tuiles en rangee,
   le chiffre d'affaires et le resultat net en premier -- ce qu'on vient
   chercher avant d'ouvrir quoi que ce soit. */
.conso-cles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin: var(--espace) 0;
}
.conso-cle {
  display: flex;
  flex-direction: column;
  gap: var(--espace-2xs);
  flex: 1 1 12rem;
  padding: var(--espace-sm) var(--espace);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}
.conso-cle-libelle { font-size: var(--fs-xs); color: var(--gray-5); }
.conso-cle-valeur {
  font-size: var(--fs-h3);
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
}
/* L'exercice precedent sous le chiffre : il l'eclaire, il ne le concurrence
   pas -- d'ou la meme taille que l'intitule et non celle du chiffre. */
.conso-cle-precedent {
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--gray-5);
}

.conso-etat { margin-top: var(--espace-lg); }
.conso-etat-table .conso-num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
/* Un sous-total que le cabinet pose lui-meme (« CHIFFRE D'AFFAIRES NET »,
   « TOTAL ACTIF ») : il ferme la serie de comptes au-dessus de lui, donc il
   se lit comme un trait tire dessous, pas comme une ligne de plus. */
.conso-etat-table tr[data-type="total"] td {
  font-weight: 600;
  background: var(--gray-1);
}
/* Une ligne dont la somme des entites ou du passage ne fait pas le consolide.
   Orange, comme une entite sans piece au perimetre : c'est un point a
   regarder dans le classeur, pas une panne du logiciel. */
.conso-etat-table tr[data-ecart] td { background: var(--orange-pale); }
/* Une note du modele (« dont ecarts d'acquisition ») se retirait d'un cran ici
   sous `.conso-modele-table`. Les etats consolides se peignent depuis le 15
   septembre 2026 avec le balisage de l'Analyse, et cette ligne-la y porte
   `.bilan-pcg-informatif`, qui dit deja la meme chose une fois pour les deux
   ecrans (« garde la meme presentation que dans Analyse »). */
/* Dans le tableau des capitaux propres, l'ecart se pose sur la CASE et non
   sur la rangee : c'est une colonne qui ne boucle pas, pas la ligne entiere. */
.conso-capitaux-table td[data-ecart] { background: var(--orange-pale); }

/* Ce qu'une ligne du tableau de flux dit d'elle-meme : que les montants tapes
   dessous ne tombent pas sur elle, ou qu'elle est un residu. Sur sa propre
   ligne et en petit gris, comme dans le tableau des capitaux propres : colle
   au libelle, la glose se lisait comme la suite du libelle. */
.conso-flux-table td:first-child .conso-code-entite {
  display: block;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Un mouvement brut tape dans le tableau de flux consolide (ticket AMBISTRATE
   du 15 septembre 2026). Il se retire d'un cran : c'est un « dont », il
   explique la ligne nette au-dessus de lui et ne s'ajoute a aucun total. */
.conso-flux-table tr[data-saisie] td:first-child {
  padding-left: var(--espace-md);
  color: var(--gray-5);
}

/* Le champ lui-meme, a la meme main que les cases de l'annexe : assez pour le
   distinguer d'une case calculee, pas assez pour faire de ces lignes-la un
   formulaire au milieu d'un document. */
.conso-flux-saisie {
  width: 100%;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: var(--gray-1);
  padding: var(--espace-3xs) var(--espace-2xs);
  font-family: inherit;
  font-size: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--gray-6);
  transition: background .15s var(--ease), border-color .15s var(--ease);
}

.conso-flux-saisie:hover {
  background: var(--gray-2);
  border-color: var(--gray-4);
}

.conso-flux-saisie:focus {
  outline: none;
  background: #fff;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

/* Ce qu'une saisie a donne : en cours d'envoi elle palit, refusee elle
   s'encadre de rouge. Rien quand tout va bien -- le tableau qui se refait
   dessous est deja la confirmation. */
.conso-flux-saisie[data-etat="envoi"] { color: var(--gray-4); }
.conso-flux-saisie[data-etat="erreur"] { border-color: var(--red-dark); }

/* LA QUESTION DES ETATS A RELIER, dans le questionnaire d'emission.

   « Avant la validation, poser la question : "Souhaitez-vous integrer les
   etats financiers a la suite du rapport ?" » (ticket AUTOUR DU PATIENT 94 du
   16 septembre 2026). Trois choix empiles plutot qu'en rangee : le second et
   le troisieme portent une phrase entiere, et trois phrases cote a cote ne se
   lisent pas. Le selecteur du fichier se retire d'un cran sous son choix, pour
   dire qu'il en depend. */
.arrete-q-etats-choix {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-2xs);
  margin-top: var(--espace-2xs);
  font-size: var(--fs);
  color: var(--gray-6);
  cursor: pointer;
}
.arrete-q-etats-choix input { margin-top: 0.2em; }
.arrete-q-etats .arrete-q-etats-piece {
  margin: var(--espace-2xs) 0 0 var(--espace-md);
  max-width: 32rem;
}

/* LE RESULTAT CONSOLIDE, CONFRONTE A LUI-MEME.

   « On doit verifier que le resultat consolide dans la ligne total correspond
   bien au resultat consolide des etats consolides qu'on audite » (ticket
   AMBISTRATE du 16 septembre 2026). Le bloc se tient sous la ligne des totaux
   du passage, et une seconde fois a cote de l'egalite du bilan : un controle
   se lit la ou est le nombre qu'il controle. La liste reprend le filet gauche
   des entites du perimetre, parce que c'est la meme forme -- quelques lignes
   qui s'enumerent sous une phrase. */
/* LA COCHE DU RESULTAT CONSOLIDE, dans la ligne des totaux du passage.

   « Il faut faire une annotation uniquement s'il y a un ecart ; si pas
   d'ecart, rajouter une sorte de tic vert a cote du resultat consolide du
   tableau de passage » (suivi du 16 septembre 2026). Un controle qui passe ne
   raconte plus rien, il se voit -- et a l'endroit exact ou l'on regarde le
   nombre, pas trois lignes plus bas.

   Vert plein, la couleur de ce qui est en regle partout ailleurs (une source
   traitee, un televersement abouti), et `--icon-sm`, le barreau des icones
   voisines. `vertical-align: middle` la cale sur le chiffre sans chiffre a
   soi : la ligne des totaux est en gras, et une coche posee sur la ligne de
   base y flottait un pixel trop bas. */
.conso-coche {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--green);
  margin-left: var(--espace-2xs);
  vertical-align: middle;
}

.conso-controle-resultat { margin-top: var(--espace); }
.conso-controle-resultat .conso-perimetre-liste { margin-top: var(--espace-2xs); }
.conso-controle-resultat .conso-code-entite {
  display: block;
  margin-left: 0;
}

/* LA CASE DU TAUX ANNUEL DU GROUPE, en tete de la preuve d'impot.

   « Prevoir une case modifiable manuellement "Taux annuel Groupe" » (ticket
   AMBISTRATE du 16 septembre 2026). Une seule case pour tout le tableau, donc
   une rangee et non un formulaire : l'intitule, le champ, son unite, et la
   glose qui dit si le taux a ete arbitre ou s'il est celui par defaut. */
.conso-impot-taux {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
  margin: var(--espace) 0;
  font-size: var(--fs);
  color: var(--gray-6);
}
.conso-impot-taux label { font-weight: 600; }
.conso-impot-taux .conso-flux-saisie { width: 5rem; }
.conso-impot-taux .conso-impot-unite { color: var(--gray-5); }
.conso-impot-taux .reglages-hint-inline { margin-left: var(--espace-2xs); }

/* Le rapprochement de la preuve d'impot : deux colonnes, l'intitule et le
   montant, et la glose de chaque ligne sous son intitule comme dans le
   tableau des capitaux propres. */
.conso-impot-table td:first-child { min-width: 20rem; }
.conso-impot-table td:first-child .conso-code-entite {
  display: block;
  margin-left: 0;
}
/* L'ecart par structure : sept colonnes de nombres, donc le meme cadre qui
   defile que les autres tableaux larges de la Conso. */
.conso-impot-structures { min-width: 62rem; }
/* Huit colonnes de montants : le tableau defile dans son cadre plutot que de
   pousser la page, et sa colonne d'intitules garde de quoi ecrire une phrase
   -- sans largeur minimale elle se replie sur trois mots par ligne. */
.conso-table-large { overflow-x: auto; }
.conso-capitaux-table { min-width: 60rem; }
.conso-capitaux-table td:first-child,
.conso-capitaux-table th:first-child { min-width: 16rem; }
/* La glose d'une ligne (« deduit : ... ») passe SOUS son intitule : a la
   suite, elle s'y colle et les deux se lisent comme une seule phrase. */
.conso-capitaux-table td:first-child .conso-code-entite {
  display: block;
  margin-left: 0;
}

.conso-ouvrir {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-2xs);
  padding: var(--espace-3xs) var(--espace-2xs);
  cursor: pointer;
  transition: color .15s var(--ease), border-color .15s var(--ease);
}
.conso-ouvrir:hover { color: var(--cyan); border-color: var(--cyan); }

/* Le detail d'un compte : deux colonnes cote a cote sur un ecran large -- le
   passage a gauche, les entites a droite -- et l'une sous l'autre quand la
   place manque. */
.conso-detail-bloc {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--espace-lg);
  padding: var(--espace) 0;
}
.conso-detail-bloc h4 {
  margin: 0 0 var(--espace-sm) 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.conso-passage { list-style: none; margin: 0; padding: 0; }
.conso-passage li {
  display: flex;
  justify-content: space-between;
  gap: var(--espace);
  padding: var(--espace-2xs) 0;
  font-size: var(--fs-xs);
  color: var(--gray-6);
  border-bottom: 1px solid var(--gray-2);
}
.conso-passage .conso-num { font-variant-numeric: tabular-nums; }
/* La table des colonnes du classeur et des societes du perimetre. Une paire
   dont le serveur n'est pas sur porte le meme fond orange qu'une ligne de
   compte qui ne boucle pas : ce n'est pas une erreur, c'est une chose a
   regarder, et les deux se lisent du meme coup d'oeil. */
.conso-appariement-table tr[data-ecart] td { background: var(--orange-pale); }
/* Le code de colonne, a cote du nom de la societe qu'il designe : la
   contribution se lit par societe, mais c'est le code qui est dans le
   classeur, et celui qui verifie doit retrouver la colonne. En gris et en
   petit, donc -- il accompagne le nom, il ne le concurrence pas. */
.conso-passage .conso-code-entite {
  margin-left: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}
.conso-passage-total {
  font-weight: 600;
  border-bottom: none;
  border-top: 1px solid var(--gray-3);
}

/* Le tableau de passage du resultat social au resultat consolide : une
   structure par ligne, un retraitement par colonne. Onze colonnes de montants
   ne tiennent pas sur un ecran, donc il defile dans son cadre
   (`conso-table-large`) et sa colonne de structures garde de quoi ecrire une
   raison sociale. */
.conso-passage-table { min-width: 72rem; }
.conso-passage-table td:first-child,
.conso-passage-table th:first-child { min-width: 18rem; }
/* Le depart et l'arrivee restent en place pendant qu'on fait defiler les
   retraitements : sans cela la colonne d'arrivee -- celle qu'on vient lire --
   sort de l'ecran des le huitieme retraitement, et on ne sait plus de quelle
   structure on lit la ligne. Un fond opaque est ce qui fait tenir une cellule
   collante : sans lui, les colonnes defilent dessous. */
.conso-passage-table th:first-child,
.conso-passage-table td:first-child,
.conso-passage-table .conso-passage-arrivee {
  position: sticky;
  background: #fff;
  z-index: 1;
}
.conso-passage-table th:first-child,
.conso-passage-table td:first-child { left: 0; }
.conso-passage-table .conso-passage-arrivee {
  right: 0;
  border-left: 1px solid var(--gray-2);
}
/* La bande de titres garde son fond (`revue-table th`) : une cellule collante
   opaque d'une autre teinte couperait l'en-tete en trois. */
.conso-passage-table thead th:first-child,
.conso-passage-table thead .conso-passage-arrivee { background: var(--cyan-light); }
.conso-passage-table tr[data-type="total"] td:first-child,
.conso-passage-table tr[data-type="total"] .conso-passage-arrivee {
  background: var(--gray-1);
}
/* Le point d'arrivee : la contribution au resultat consolide, qui est ce que
   la ligne sert a lire. Elle se detache du chemin qui y mene. */
.conso-passage-table .conso-passage-arrivee { font-weight: 600; }
/* Le bouton d'ouverture est dans la cellule du nom, pas dans une colonne a
   lui : la derniere colonne doit rester l'arrivee. */
.conso-passage-table .conso-ouvrir { margin-left: var(--espace-xs); }
.conso-passage-table td[data-ecart],
/* Le meme signal dans le tableau des comptes sociaux : une cellule
   d'ecart au-dela de la tolerance, teintee de la meme facon que partout
   ailleurs dans la Conso. La regle est jointe a celle du passage plutot
   que recopiee : deux ecritures du meme etat auraient fini par diverger. */
.conso-cumul-table td[data-ecart] { background: var(--orange-pale); }
/* Le nom du fichier de plaquette, sous la raison sociale : la source du
   chiffre de droite, ecrite la ou on la cherche -- au moment de juger un
   ecart. Meme glose grise que le code de colonne, mais sur sa ligne. */
.conso-cumul-table .conso-cumul-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}
.conso-cumul-table .conso-code-entite {
  margin-left: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}
/* Le nom du compte a cote de son numero, et le code de colonne a cote de la
   raison sociale : la meme glose grise que dans le detail d'un compte, mais
   dans une cellule de tableau -- d'ou la reprise du style, `conso-passage`
   n'etant qu'une liste. */
.conso-passage-table .conso-code-entite {
  margin-left: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}
/* Les comptes d'une structure, ouverts sous sa ligne : le meme tableau, d'un
   cran a l'interieur, pour qu'on voie qu'ils detaillent la ligne du dessus. */
.conso-detail-comptes { padding: var(--espace) 0 var(--espace) var(--espace-lg); }
.conso-detail-comptes h4 {
  margin: 0 0 var(--espace-sm) 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
/* Les entites qui portent un retraitement, ouvertes sous sa ligne : un cran a
   l'interieur et l'encre d'un detail, pour qu'on voie qu'elles decomposent la
   ligne du dessus et non qu'elles s'y ajoutent (ticket ENCRES DUBUIT du
   16 septembre 2026). Meme geste que les comptes d'une structure juste
   au-dessus, a ceci pres qu'ici la fille est une rangee du meme tableau : ses
   montants tombent donc dans les memes colonnes que ceux du total. */
.conso-detail-ligne > .conso-detail-nom {
  padding-left: var(--espace-lg);
  color: var(--gray-5);
}
/* Le code que le classeur donne a la colonne (« CAPPRO », « ELIDIV* ») : sous
   l'intitule et non a sa suite, comme partout ailleurs dans l'onglet. C'est ce
   qui permet de retrouver la colonne dans le fichier. */
.conso-retraitements-table td:first-child .conso-code-entite {
  display: block;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}
/* Le lien du classeur, entre la note et le tableau : un bouton-lien pose seul
   sur sa ligne, aligne sur le texte au-dessus de lui. */
.conso-telecharger { margin: 0 0 var(--espace-sm) calc(var(--espace-sm) * -1); }

/* D'ou viennent les chiffres d'une filiale qui a son mandat chez nous : de son
   FEC, pas d'une piece deposee ici. Gris et non orange, parce que ce n'est pas
   un manque -- l'orange de « Aucune piece deposee » envoyait chercher un
   fichier qui n'a aucune raison d'exister dans ce mandat. */
.conso-perimetre-table .conso-pieces-du-mandat { color: var(--gray-5); }

/* La mention du mandat aiudit sous la raison sociale du perimetre, et la
   marque d'un Siren repris de ce mandat. La mention reprend le meme vert que
   dans le tableau des comptes sociaux : c'est le meme fait dit au meme
   lecteur, et deux ecritures d'un meme signe se lisent comme deux signes. */
.conso-perimetre-table .conso-source-mandat {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--green-dark);
}
.conso-perimetre-table .conso-cumul-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* QUI AUDITE CHAQUE SOCIETE DU PERIMETRE.

   « Audite par : [nom du cabinet] [...] si un RCA recupere est signe par le
   co-commissaire aux comptes, indique son nom comme cabinet auditeur,
   eventuellement avec une couleur distincte » (ticket AMBISTRATE du
   16 septembre 2026).

   Quatre etats, quatre teintes, et elles disent toutes la meme chose : quelle
   confiance la couverture d'audit merite sur cette ligne. Le vert du cabinet
   titulaire est celui qui marque deja nos propres travaux ailleurs dans la
   Conso (« Filiale auditee par BA ») : c'est le meme fait dit au meme lecteur.
   Le violet du co-commissaire est la couleur distincte que le ticket demande.
   Le bleu d'un autre commissaire s'en distingue sans crier : ce n'est pas un
   defaut, c'est une part du perimetre que notre opinion ne couvre pas. Le gris
   de l'auditeur non identifie est celui de tout ce qui n'a pas ete lu. */
.conso-auditeur-titulaire { font-weight: 600; color: var(--green-dark); }
.conso-auditeur-cocac { font-weight: 600; color: var(--purple); }
.conso-auditeur-autre { font-weight: 600; color: var(--blue-dark); }
.conso-auditeur-inconnu { color: var(--gray-5); }

/* La synthese de la couverture, sous le tableau du perimetre : la reponse que
   la vue existe pour donner. Sa derniere ligne est un total, donc elle se lit
   comme les totaux des autres tableaux de la Conso. */
.conso-couverture { margin-top: var(--espace-xl); }
/* Les trois colonnes de chiffres, en-tete compris : un titre a gauche et ses
   chiffres a droite tombent chacun sous la colonne du voisin, et c'est la
   seule raison pour laquelle on ne savait plus quel nombre repondait a quel
   titre (ticket du 17 septembre 2026). Une largeur au plus juste et un cran
   d'espace a gauche separent les trois, pour que le regard descende d'un titre
   a ses valeurs sans traverser la colonne d'a cote. */
.conso-couverture-table .conso-num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
  width: 1%;
  padding-left: var(--espace-lg);
}
.conso-couverture-table tr[data-type="total"] td {
  font-weight: 600;
  background: var(--gray-1);
  color: var(--gray-6);
}

/* Les quatre sous-parties des Etats consolides (bilan, compte de resultat,
   TFT, preuve d'impot). La meme rangee de `unit-btn` que les vues de
   l'Analyse, un cran plus bas dans la hierarchie : c'est la presentation que
   le ticket du 15 septembre 2026 demande de reprendre. Le retrait a gauche est
   ce qui dit le cran : sans lui, deux rangees identiques l'une sous l'autre se
   liraient comme deux rangees de meme niveau. */
.conso-etats-nav { margin-left: var(--espace); }
.conso-etat-partie { margin-top: var(--espace); }

/* Le rapprochement agregat par agregat, sous le tableau des trois grandeurs.
   Les structures y sont en COLONNES, trois par entite : vingt-trois entites
   font soixante-neuf colonnes, qu'aucun ecran ne montre d'un coup. Le tableau
   defile donc dans sa propre enveloppe, et c'est la seule facon de ne rien
   tronquer -- une colonne coupee dans un rapprochement est un ecart qu'on ne
   verra pas. */
.conso-comparaison { margin-top: var(--espace-xl); }
.conso-table-large { overflow-x: auto; }
.conso-comparaison-table td[data-ecart] { background: var(--orange-pale); }
.conso-comparaison-table .conso-code-entite {
  margin-left: var(--espace-2xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}
/* La feuille du classeur en tete de son bloc d'agregats (l'actif, ses
   amortissements, le passif, le compte de resultat) : un intertitre dans le
   tableau, pas une ligne de chiffres, d'ou le fond gris et l'absence de
   nombres. */
.conso-comparaison-table tr[data-type="section"] td {
  font-weight: 600;
  background: var(--gray-1);
  color: var(--gray-6);
}
/* « Filiale auditée par BA », sous la raison sociale : la mention que le
   ticket demande de mettre en evidence. Elle ne se glose pas en gris comme le
   nom d'un fichier -- elle dit que la colonne de gauche vient de nos propres
   travaux, ce qui est la meilleure des sources et doit se voir. */
.conso-comparaison-table .conso-source-mandat {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--green-dark);
}

/* Les vues vides -- toutes celles qui attendent leur moteur. Meme cadre que
   les autres tuiles, avec un titre, un texte d'explication et une invite
   grise en bas pour dire ce qu'il n'y a pas encore. */
.conso-vide {
  display: flex;
  flex-direction: column;
  gap: var(--espace);
  padding: var(--espace-lg);
  border: 1px dashed var(--gray-3);
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  color: var(--gray-5);
  font-size: var(--fs);
  line-height: 1.5;
}

.conso-vide h3 {
  margin: 0;
  font-size: var(--fs-h3);
  color: var(--gray-6);
}

.conso-vide p { margin: 0; }

.conso-vide-hint {
  font-size: var(--fs-xs);
  color: var(--gray-4);
  font-style: italic;
}

/* ---------------------------------------------------------------------------
   L'Assistant de conformite de la Conso (ticket AMBISTRATE du 16 septembre
   2026).

   Une carte par disposition du referentiel qui concerne reellement le groupe,
   et dans chaque carte quatre phrases : ce qui a ete identifie, ce que prevoit
   le referentiel, l'ecart, le controle a faire.

   Aucune teinte nouvelle : les quatre verdicts reprennent les couleurs deja
   posees pour les etats metier du produit -- rouge pour ce qui ne va pas,
   orange pour ce qui est incomplet, gris pour ce sur quoi on ne peut pas
   conclure, vert pour ce qui est constate. Une couleur creee pour cette seule
   vue aurait demande son pendant dans Palette.swift, et l'ecran de l'app rend
   les memes verdicts avec les memes noms.

   Le bord gauche porte la couleur, pas le fond : quinze cartes a fond teinte
   les unes sous les autres se lisent comme un avertissement general, ou plus
   rien ne ressort. La barre de couleur se voit du coin de l'oeil et laisse le
   texte sur du blanc. */
.conso-points {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
  margin-top: var(--espace);
}

.conso-point {
  border: 1px solid var(--gray-3);
  border-left: 3px solid var(--gray-4);
  border-radius: var(--radius);
  background: #fff;
  padding: var(--espace);
}

.conso-point-tete {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--espace-sm);
}

.conso-point-verdict {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--gray-2);
  color: var(--gray-5);
  white-space: nowrap;
}

.conso-point-titre {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
}

.conso-point-article {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  margin-left: auto;
  white-space: nowrap;
}

.conso-point-corps {
  margin: var(--espace-sm) 0 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--espace-3xs);
}

.conso-point-corps dt {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--gray-4);
  margin-top: var(--espace-xs);
}

.conso-point-corps dd {
  margin: 0;
  font-size: var(--fs);
  line-height: 1.5;
  color: var(--gray-6);
}

.conso-point-anomalie { border-left-color: var(--red); }
.conso-point-anomalie .conso-point-verdict { background: var(--red-pale); color: var(--red); }
.conso-point-manquant { border-left-color: var(--red); }
.conso-point-manquant .conso-point-verdict { background: var(--red-pale); color: var(--red); }
.conso-point-incomplet { border-left-color: var(--orange); }
.conso-point-incomplet .conso-point-verdict { background: var(--orange-pale); color: var(--orange-dark); }
.conso-point-insuffisant { border-left-color: var(--gray-4); }
.conso-point-conforme { border-left-color: var(--green); }
.conso-point-conforme .conso-point-verdict { background: var(--green-pale); color: var(--green); }

/* Le conforme se replie : il se compte, il ne se lit pas. */
.conso-points-replies {
  margin-top: var(--espace);
  border-top: 1px solid var(--gray-2);
  padding-top: var(--espace-sm);
}

.conso-points-replies > summary {
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--gray-4);
}

.conso-points-replies > summary:hover { color: var(--gray-6); }

/* La pastille de l'onglet Assistant : le nombre de points a regarder, c'est-a
   -dire tout sauf le conforme. Le meme dessin que les pastilles des onglets du
   mandat, en plus petit -- la barre des vues de la Conso est deja dense. */
.conso-nav-pastille {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  margin-left: var(--espace-2xs);
  padding: 0 var(--espace-2xs);
  border-radius: 999px;
  background: var(--red-pale);
  color: var(--red);
  font-size: var(--fs-3xs);
  font-weight: 700;
}

/* ---------------------------------------------------------------------------
   L'Analyse de la Conso : les controles menes sur les chiffres, etape par
   etape (ticket ENCRES DUBUIT du 16 septembre 2026).

   Une etape est un `<details>` : son resume porte le numero, l'intitule et le
   verdict, et c'est tout ce qu'on lit quand elle ne trouve rien. Celle qui
   trouve un ecart s'ouvre d'elle-meme. La vue est ecrite pour en empiler
   d'autres sans que la page s'allonge d'un ecran a chaque controle ajoute.

   Aucune teinte nouvelle : le rouge de l'ecart est le `--red` de la palette,
   deja apparie dans `Palette.swift`. Il est ici plus franc que l'orange des
   autres tableaux de la Conso, et c'est le ticket qui le demande : « en cas
   d'ecart, fais-le ressortir clairement en rouge ». Un ecart de reprise n'est
   pas du meme ordre qu'une somme de colonnes qui ne boucle pas : le premier
   dit qu'un chiffre faux est entre en consolidation.
   --------------------------------------------------------------------------- */
.conso-analyse-entete { margin-bottom: var(--espace-md); }
.conso-analyse-entete h3 { margin: 0 0 var(--espace-2xs); }

.conso-etape {
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  padding: var(--espace-md);
  background: #fff;
}

.conso-etape + .conso-etape { margin-top: var(--espace-md); }

.conso-etape > summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  list-style: none;
}

.conso-etape > summary::-webkit-details-marker { display: none; }

/* Le numero de l'etape, dans une pastille carree : c'est par lui qu'on la
   nomme (« 01 - Reprise »), et il doit se retrouver d'un coup d'oeil dans une
   pile d'etapes repliees. */
.conso-etape-numero {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-xs);
  background: var(--cyan-light);
  color: var(--cyan-dark);
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.conso-etape-titre {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
}

/* Le verdict, a droite du resume : le seul mot qu'on lit d'une etape repliee. */
.conso-etape-verdict {
  margin-left: auto;
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: var(--radius-xs);
  background: var(--green-pale);
  color: var(--green);
  font-size: var(--fs-2xs);
  font-weight: 600;
  white-space: nowrap;
}

.conso-etape-verdict[data-ecart] { background: var(--red-pale); color: var(--red); }

.conso-etape-objectif {
  margin: var(--espace-md) 0 var(--espace-2xs);
  font-size: var(--fs);
  line-height: 1.5;
  color: var(--gray-6);
}

/* Les taux retenus, avec leur source : un controle de conversion ne se relit
   pas sans savoir sur quel cours il repose. */
.conso-analyse-taux {
  margin: var(--espace-md) 0 0;
  padding: var(--espace-sm) var(--espace-md);
  list-style: none;
  border-radius: var(--radius-sm);
  background: var(--gray-1);
}

.conso-analyse-taux li + li { margin-top: var(--espace-xs); }
.conso-analyse-taux li { font-size: var(--fs-sm); color: var(--gray-6); }
.conso-analyse-taux strong { margin-right: var(--espace-2xs); }
/* La source sur sa propre ligne, sous le taux : collee a lui, elle se lisait
   comme la suite du nombre (« 7,7314 pour 1 euroBanque de France »). */
.conso-analyse-taux .conso-cumul-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.conso-analyse-grandeur { margin-top: var(--espace-xl); }
.conso-analyse-grandeur h5 {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--gray-6);
}
.conso-analyse-grandeur > .conso-vide-hint { margin: 0 0 var(--espace-sm); }

/* Un grand bloc du controle, replie sur une ligne : l'intitule a gauche, les
   deux cotes cumules et leur ecart a droite, et le verdict au bout. C'est la
   ligne qu'on parcourt du regard pour voir ou ca coince, et les montants sont
   donc alignes d'un bloc a l'autre -- d'ou les largeurs fixes. */
.conso-analyse-bloc {
  border-top: 1px solid var(--gray-2);
  padding: var(--espace-2xs) 0;
}
.conso-analyse-bloc:last-of-type { border-bottom: 1px solid var(--gray-2); }

.conso-analyse-bloc > summary {
  cursor: pointer;
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  list-style: none;
  padding: var(--espace-2xs) var(--espace-2xs);
  border-radius: var(--radius-xs);
}
.conso-analyse-bloc > summary::-webkit-details-marker { display: none; }
.conso-analyse-bloc > summary:hover { background: var(--gray-1); }

.conso-bloc-titre {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.conso-bloc-montant {
  flex: 0 0 auto;
  min-width: 8.5rem;
  text-align: right;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--gray-6);
  white-space: nowrap;
}
.conso-bloc-ecart { color: var(--red); font-weight: 600; }

/* La note d'un bloc sans contrepartie contributive, a la place du verdict et
   de la meme largeur : les deux se lisent dans la meme colonne. */
.conso-bloc-note {
  flex: 0 0 auto;
  min-width: 5.5rem;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  white-space: nowrap;
}

.conso-analyse-bloc > summary > .conso-etape-verdict {
  flex: 0 0 auto;
  margin-left: 0;
  min-width: 5.5rem;
  text-align: center;
}

/* Un « dont » : il detaille le bloc du dessus au lieu de s'y ajouter, et le
   retrait le dit avant qu'on lise son intitule. */
.conso-analyse-bloc-dont { border-top-style: dashed; }
.conso-analyse-bloc-dont > summary { padding-left: var(--espace-lg); }
.conso-analyse-bloc-dont .conso-bloc-titre {
  font-weight: 400;
  color: var(--gray-5);
}

/* Le total de la section : c'est lui qui boucle, et il se lit en gras sous
   les blocs qu'il totalise. */
.conso-analyse-bloc-total { border-top-width: 2px; border-top-color: var(--gray-3); }
.conso-analyse-bloc-total .conso-bloc-titre,
.conso-analyse-bloc-total .conso-bloc-montant { font-weight: 700; }

.conso-analyse-bloc > .conso-vide-hint {
  margin: var(--espace-2xs) var(--espace-2xs) var(--espace-xs);
}
.conso-analyse-bloc .conso-table-large { margin-bottom: var(--espace-sm); }

.conso-analyse-reciproques { margin-top: var(--espace-sm); }

.conso-analyse-table { min-width: 44rem; }
.conso-analyse-table .conso-num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.conso-analyse-entite { font-weight: 600; }
/* Le nom du pack sous la raison sociale, et la conversion sous son montant :
   la meme glose grise que dans le tableau des comptes sociaux, ou elle dit
   deja d'ou vient le chiffre d'en face. */
.conso-analyse-table .conso-cumul-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  font-weight: 400;
  color: var(--gray-5);
}
/* L'ecart : la rangee se teinte, et la case de l'ecart porte le chiffre en
   rouge. La rangee seule aurait dit « regarde cette filiale » sans dire
   laquelle des quatre grandeurs bouge. */
.conso-analyse-table tr[data-ecart] td { background: var(--red-pale); }
.conso-analyse-table td[data-ecart] { color: var(--red); font-weight: 600; }
.conso-analyse-table td[data-ecart] .conso-cumul-source { color: var(--red-dark); }

.conso-analyse-reste { margin-top: var(--espace-sm); }

/* ---------------------------------------------------------------------------
   Les ecritures de consolidation (ticket ENCRES DUBUIT du 17 septembre 2026).

   Deux familles, chacune dans une `.conso-etape` comme les etapes de
   l'Analyse : le dessin est deja celui d'un controle replie qui porte son
   verdict dans son resume, et deux dessins pour la meme idee auraient fini par
   diverger. Sous la famille, une nature par `<details>`, plus discret que
   l'etape qui le contient -- une nature n'est pas un controle a elle seule,
   c'est une ligne de son sommaire.

   Aucune teinte nouvelle : le vert, le rouge et l'orange sont ceux de la
   palette, deja apparies dans `Palette.swift`. L'orange est celui des etats
   « a surveiller » du produit, et c'est bien ce qu'il dit ici : le chiffre
   tombe juste, mais quelque chose n'est pas justifie.
   --------------------------------------------------------------------------- */
.conso-etape-verdict[data-etat="a_expliquer"] {
  background: var(--orange-pale);
  color: var(--orange-dark);
}

/* Les journaux ouverts, et ceux qui ne l'ont pas ete. En tete de la vue :
   un controle qui ne dit pas sur quel fichier il porte ne se relit pas. */
.conso-ecritures-journaux {
  margin: 0 0 var(--espace-md);
  padding: var(--espace-sm) var(--espace-md);
  list-style: none;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: var(--gray-1);
  font-size: var(--fs-sm);
}
.conso-ecritures-journaux li + li { margin-top: var(--espace-xs); }
.conso-ecritures-journaux li[data-lu="0"] strong { color: var(--gray-5); }
.conso-ecritures-journaux .conso-cumul-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.conso-ecritures-nature {
  margin-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
  padding-top: var(--espace-sm);
}
.conso-ecritures-nature > summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  list-style: none;
}
.conso-ecritures-nature > summary::-webkit-details-marker { display: none; }

/* Le code de la nature (« RETLEA ») : c'est par lui qu'on la retrouve dans le
   journal, donc il precede son intitule et garde sa casse. */
.conso-ecritures-code {
  flex: 0 0 auto;
  min-width: 5.5rem;
  padding: var(--espace-3xs) var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: var(--gray-2);
  color: var(--gray-6);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-align: center;
}

.conso-ecritures-compte {
  margin-left: auto;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.conso-ecritures-nature > summary > .conso-etape-verdict {
  flex: 0 0 auto;
  margin-left: 0;
  min-width: 5.5rem;
  text-align: center;
}

/* Les constats : une puce coloree par l'etat, et la phrase. Le vert se lit
   autant que le rouge -- c'est lui qui dit ce qui a ete verifie. */
.conso-ecritures-constats {
  margin: var(--espace-sm) 0 0;
  padding-left: var(--espace-lg);
  list-style: none;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--gray-6);
}
.conso-ecritures-constats li { position: relative; }
.conso-ecritures-constats li + li { margin-top: var(--espace-2xs); }
.conso-ecritures-constats li::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--espace-sm));
  top: 0.45em;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--green);
}
.conso-ecritures-constats li[data-etat="ecart"] { color: var(--red-dark); }
.conso-ecritures-constats li[data-etat="ecart"]::before { background: var(--red); }
.conso-ecritures-constats li[data-etat="a_expliquer"]::before { background: var(--orange); }

.conso-ecritures-pieces {
  margin: var(--espace-sm) 0 0;
  font-size: var(--fs-sm);
  color: var(--gray-6);
}
.conso-ecritures-pieces-titre { color: var(--gray-5); }

.conso-ecritures-table { min-width: 52rem; }
.conso-ecritures-table .conso-num {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.conso-ecritures-numero { font-weight: 600; }
.conso-ecritures-table .conso-cumul-source {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-2xs);
  font-weight: 400;
  color: var(--gray-5);
}
.conso-ecritures-table tr[data-ecart] td { background: var(--red-pale); }
.conso-ecritures-controle .conso-etape-verdict {
  display: inline-block;
  margin-left: 0;
}
/* La colonne du controle prend sa largeur et pas davantage : laissee libre,
   elle absorbait la moitie du tableau et repoussait le libelle de l'ecriture,
   qui est pourtant ce qu'on lit en premier. */
.conso-ecritures-table th:last-child,
.conso-ecritures-table td:last-child { width: 15rem; }

/* ===========================================================================
   Journal des modifications
   ---------------------------------------------------------------------------
   Deux surfaces : la page (`.jm-page`) et la fenetre du matin (`.jm-fenetre`).
   Elles vivent ici, dans la feuille chargee partout, parce que la fenetre
   paraissant sur n'importe quelle page ne peut pas dependre d'une feuille
   chargee par une page.

   Aucune teinte nouvelle : tout est pris dans la palette existante. Une
   couleur ajoutee dans `:root` pour ce seul journal aurait demande son
   pendant dans `Palette.swift` (le verificateur de parite le controle), et
   le journal de l'app est fait de texte, pas de pastilles.

   Le prefixe `jm-` n'est pas decoratif : c'est le seul prefixe qu'un fragment
   HTML insere par la routine a le droit de porter (voir la liste blanche de
   `journal.nettoyer_html`). Un apercu ne peut donc pas emprunter les classes
   du produit et se faire passer pour un bandeau d'alerte.
   =========================================================================== */

/* --- La page ------------------------------------------------------------ */

/* La gouttiere partagee et non --espace-md : le journal se lisait a 16 px du
   bord quand l'en-tete au-dessus se lit a 32, et les deux se voyaient l'un sous
   l'autre des que la page a pris la fenetre entiere. C'est exactement ce que
   `--gouttiere` dit d'elle : la meme marge dans l'en-tete et dans le corps,
   pour que le titre et la premiere colonne s'alignent. */
.jm-page {
  padding: var(--espace-lg) var(--gouttiere) var(--espace-3xl);
}

.jm-grille {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 274px;
  gap: var(--espace-xl);
  align-items: start;
}

@media (max-width: 900px) {
  .jm-grille { grid-template-columns: minmax(0, 1fr); }
  .jm-aside { order: -1; }
}

/* Le journal tenu par la fenetre. La page mesurait 5 842 px de haut a
   2560x1440 : un article de quatre ecrans, et un sommaire des editions
   precedentes qui n'avait d'autre moyen de rester visible que de se coller en
   haut (`position: sticky`) pendant que tout le reste s'en allait.

   La grille prend la hauteur laissee par la barre du haut, et c'est la colonne
   de l'article qui defile -- elle seule. Le sommaire cesse d'etre colle : il
   n'a plus rien a suivre, il est deja la ou il doit etre, et il s'etire sur
   toute la hauteur (`align-items: stretch`) plutot que de flotter en haut d'une
   colonne vide.

   Le retrait du bas de la page passe dans la colonne qui defile : laisse sur la
   page, il aurait reserve du blanc sous une zone qui ne bouge plus, et la
   derniere entree se serait arretee net sur le bord de la fenetre. */
.app-main-pleine.jm-page {
  padding-bottom: 0;
}

.app-main-pleine > .jm-grille {
  flex: 1;
  min-height: 0;
  align-items: stretch;
}

.app-main-pleine .jm-corps {
  min-height: 0;
  overflow: auto;
  padding-bottom: var(--espace-3xl);
}

/* Le sommaire garde la hauteur de ses editions et ne s'etire pas sur la
   colonne : un cadre blanc de mille trois cents pixels dont neuf dixiemes sont
   vides se remarque plus que le fond de page qu'il remplace. Il defile pour
   lui-meme quand les editions passent la fenetre. Sa liste avait un plafond de
   60 % de la fenetre, mesure prise quand elle etait collee en haut d'une page
   qui defilait ; c'est la colonne qui borne sa hauteur maintenant. */
.app-main-pleine .jm-aside {
  position: static;
  align-self: start;
  max-height: 100%;
  min-height: 0;
  overflow: auto;
}

.app-main-pleine .jm-aside-liste {
  max-height: none;
}

/* Deux entrees cote a cote sur un grand ecran. La mesure de lecture
   (--largeur-lecture, 46 rem) borne le texte d'une entree : sur une colonne
   d'article de 2 198 px, elle laissait les deux tiers de chaque carte vides.
   A partir de 1 920 px, la colonne se coupe en deux voies de 771 px, ou la
   mesure tient encore entiere (736 px de texte pour 731 px disponibles, l'ecart
   ne se voit pas). En dessous, une seule voie : couper plus etroit rognerait la
   mesure, et une page de lecture serree en deux colonnes se lit moins bien
   qu'une colonne juste.

   Le chapeau et la preuve tiennent les deux voies : l'un ouvre l'edition,
   l'autre la ferme. Leurs marges passent dans l'ecart de la grille, sans quoi
   elles s'ajouteraient a lui. */
@media (min-width: 1920px) {
  .app-main-pleine .jm-corps {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--espace-md);
    align-content: start;
    align-items: start;
  }

  .app-main-pleine .jm-corps > .jm-entete,
  .app-main-pleine .jm-corps > .jm-preuve {
    grid-column: 1 / -1;
    margin: 0;
  }

  .app-main-pleine .jm-corps > .jm-entree {
    margin-bottom: 0;
  }
}

/* Sous 900 px la grille n'a plus qu'une colonne et le sommaire passe devant, en
   bande qui defile en largeur. Les deux rangees se partagent alors la hauteur :
   la bande garde la sienne, l'article prend le reste. Sans cette ligne, deux
   rangees `auto` se contentent de leur contenu et l'article n'a aucune hauteur
   definie a rendre defilante. */
@media (max-width: 900px) {
  .app-main-pleine > .jm-grille {
    grid-template-rows: auto minmax(0, 1fr);
  }
}

.jm-entete {
  padding: var(--espace-lg) var(--espace-lg) var(--espace-md);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  background:
    linear-gradient(180deg, var(--cyan-pale) 0%, #fff 60%);
  margin-bottom: var(--espace-lg);
}

.jm-entete-surtitre {
  margin: 0;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--cyan-dark);
}

.jm-entete-titre {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-h1);
  line-height: 1.15;
  letter-spacing: var(--suivi-titre);
  color: var(--black);
}

.jm-entete-periode {
  margin: var(--espace-2xs) 0 0;
  color: var(--gray-5);
  font-size: var(--fs-md);
}

.jm-entete-chapeau {
  margin-top: var(--espace-sm);
  color: var(--gray-6);
  font-size: var(--fs);
  line-height: 1.6;
  max-width: var(--largeur-lecture);
}

.jm-mesures {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-lg);
  margin: var(--espace-md) 0 0;
  padding: var(--espace-sm) 0 0;
  border-top: 1px solid var(--gray-3);
  list-style: none;
}

.jm-mesures li { display: flex; flex-direction: column; gap: var(--espace-3xs); }
.jm-mesures strong {
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--black);
  font-variant-numeric: tabular-nums;
}
.jm-mesures span { font-size: var(--fs-2xs); color: var(--gray-5); }

/* --- Une entree --------------------------------------------------------- */

.jm-entree {
  position: relative;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  background: #fff;
  padding: var(--espace-md) var(--espace-lg);
  margin-bottom: var(--espace-md);
  box-shadow: var(--shadow-sm);
}

/* Le liseré dit la portee avant qu'on ait lu le titre : c'est ce qui permet
   de parcourir une edition sans la lire entierement. */
.jm-entree::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  background: var(--gray-3);
}
.jm-entree-majeur::before { background: var(--cyan); }
.jm-entree-notable::before { background: var(--blue); }

.jm-entree-entete {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-bottom: var(--espace-2xs);
}

/* L'avatar de qui a demande la modification, en haut a droite de l'entree :
   exactement comme sur un ticket, mais la, positionne dans le coin plutot
   qu'en tete de ligne, faute d'un en-tete a partager avec lui (demande du
   16 septembre 2026). */
.jm-entree-demandeur {
  position: absolute;
  top: var(--espace-md);
  right: var(--espace-lg);
}

.jm-pastille {
  display: inline-flex;
  align-items: center;
  padding: var(--espace-3xs) var(--espace-sm);
  border-radius: 999px;
  font-size: var(--fs-3xs);
  font-weight: 700;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  white-space: nowrap;
}
.jm-pastille-majeur { background: var(--cyan-light); color: var(--cyan-dark); }
.jm-pastille-notable { background: var(--blue-pale); color: var(--blue-dark); }
.jm-pastille-detail { background: var(--gray-2); color: var(--gray-5); }

.jm-domaine {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
}

.jm-entree-numero {
  margin-left: auto;
  font-family: var(--mono);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

.jm-entree-titre {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-h3);
  line-height: 1.25;
  color: var(--black);
}

.jm-entree-texte {
  color: var(--gray-6);
  font-size: var(--fs);
  line-height: 1.65;
  max-width: var(--largeur-lecture);
}
.jm-entree-texte p { margin: 0 0 var(--espace-xs); }
.jm-entree-texte p:last-child { margin-bottom: 0; }
.jm-entree-texte ul,
.jm-entree-texte ol { margin: 0 0 var(--espace-xs); padding-left: var(--espace-md); }
.jm-entree-texte li { margin-bottom: var(--espace-3xs); }
.jm-entree-texte code {
  font-family: var(--mono);
  font-size: 0.92em;
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  padding: 0 var(--espace-2xs);
}
.jm-entree-texte a { color: var(--cyan-dark); }

.jm-pour-qui {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin: var(--espace-sm) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.jm-pour-qui .icon { width: var(--icon-xs); height: var(--icon-xs); }

.jm-auteur {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-4);
}
.jm-auteur .icon { width: var(--icon-xs); height: var(--icon-xs); }

/* --- Les apercus -------------------------------------------------------- */

.jm-apercu {
  margin: var(--espace-md) 0 0;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--gray-1);
}

.jm-apercu img { display: block; width: 100%; height: auto; }

/* Le fragment insere, montre tel quel. Fond blanc et cadre : sans quoi un
   morceau d'interface pose au milieu d'une page se lit comme faisant partie
   de la page, et on cherche a cliquer dessus. */
.jm-apercu-html {
  background: #fff;
  padding: var(--espace-md);
  overflow-x: auto;
}

.jm-apercu-code {
  margin: 0;
  padding: var(--espace-sm) var(--espace-md);
  background: var(--gray-6);
  color: var(--gray-1);
  font-family: var(--mono);
  font-size: var(--fs-2xs);
  line-height: 1.55;
  overflow-x: auto;
}
.jm-apercu-code code { font-family: inherit; }

.jm-apercu figcaption {
  padding: var(--espace-xs) var(--espace-md);
  border-top: 1px solid var(--gray-3);
  background: var(--gray-1);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

.jm-entree-pied {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  flex-wrap: wrap;
  margin-top: var(--espace-sm);
}

.jm-ou {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-2xs);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--cyan-dark);
}
.jm-ou .icon { width: var(--icon-xs); height: var(--icon-xs); }

.jm-shas { margin-left: auto; display: flex; gap: var(--espace-2xs); }
.jm-shas code {
  font-family: var(--mono);
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  padding: var(--espace-3xs) var(--espace-2xs);
}

/* --- La preuve ---------------------------------------------------------- */

.jm-preuve {
  margin-top: var(--espace-lg);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  background: var(--gray-1);
}
.jm-preuve > summary {
  cursor: pointer;
  padding: var(--espace-sm) var(--espace-md);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-5);
}
.jm-table { width: 100%; border-collapse: collapse; font-size: var(--fs-2xs); }
.jm-table th,
.jm-table td {
  padding: var(--espace-xs) var(--espace-md);
  border-top: 1px solid var(--gray-3);
  text-align: left;
  vertical-align: top;
}
.jm-table th { color: var(--gray-5); font-weight: 600; }
.jm-table code { font-family: var(--mono); color: var(--gray-5); }
.jm-table .jm-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.jm-plus { color: var(--green); }
.jm-moins { color: var(--red); }

/* --- La colonne des editions -------------------------------------------- */

/* Cette colonne etait la seule zone de la page a n'etre pas une surface : un
   titre et une liste de dates poses a meme le fond gris, a cote de l'entete,
   des entrees et de la preuve, qui sont toutes des cartes a bordure et rayon.
   Une navigation qui flotte de cette facon se lit comme une legende de la
   page plutot que comme la liste ou l'on va cliquer. Meme cadre que les
   entrees, donc, et le meme rayon. Le lisere de l'edition ouverte, lui, reste
   a gauche du lien et non de la carte : c'est le lien qui est actif. */
.jm-aside {
  position: sticky;
  top: var(--espace-lg);
  padding: var(--espace-md);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  background: #fff;
}
.jm-aside-titre {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--gray-5);
}
.jm-aside-liste { list-style: none; margin: 0; padding: 0; max-height: 60vh; overflow-y: auto; }
.jm-aside-lien {
  display: block;
  padding: var(--espace-xs);
  border-left: 2px solid transparent;
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  color: var(--gray-5);
}
.jm-aside-lien:hover { background: var(--gray-1); }
.jm-aside-lien.actif {
  border-left-color: var(--cyan);
  background: var(--cyan-pale);
  color: var(--black);
}
.jm-aside-date { display: block; font-size: var(--fs-xs); font-weight: 600; }
.jm-aside-sujet {
  display: block;
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.jm-vide {
  max-width: var(--largeur-lecture);
  margin: var(--espace-3xl) auto;
  text-align: center;
  color: var(--gray-5);
}
.jm-vide .icon { width: var(--icon-xl); height: var(--icon-xl); color: var(--gray-4); }
.jm-vide h2 { margin: var(--espace-sm) 0 var(--espace-2xs); color: var(--black); }

/* --- La fenetre du matin ------------------------------------------------ */

.jm-fenetre {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--espace-md);
}

.jm-fenetre-voile {
  position: absolute;
  inset: 0;
  background: var(--voile-flou);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 200ms var(--ease);
}
.jm-fenetre.ouverte .jm-fenetre-voile { opacity: 1; }

.jm-fenetre-carte {
  position: relative;
  width: min(560px, 100%);
  max-height: min(80vh, 720px);
  overflow-y: auto;
  padding: var(--espace-lg);
  border-radius: var(--radius-lg);
  background: #fff;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(14px) scale(0.985);
  transition: opacity 220ms var(--ease), transform 260ms var(--ease-spring);
}
.jm-fenetre.ouverte .jm-fenetre-carte {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .jm-fenetre-voile,
  .jm-fenetre-carte { transition: none; transform: none; }
}

.jm-fenetre-croix {
  position: absolute;
  top: var(--espace-xs);
  right: var(--espace-xs);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--gray-4);
  cursor: pointer;
}
.jm-fenetre-croix:hover { background: var(--gray-1); color: var(--gray-6); }
.jm-fenetre-croix .icon { width: var(--icon-sm); height: var(--icon-sm); }

.jm-fenetre-surtitre {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin: 0;
  font-size: var(--fs-3xs);
  font-weight: 700;
  letter-spacing: var(--suivi-entete);
  text-transform: uppercase;
  color: var(--cyan-dark);
}
.jm-fenetre-surtitre .icon { width: var(--icon-xs); height: var(--icon-xs); }

.jm-fenetre-titre {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-h2);
  line-height: 1.2;
  letter-spacing: var(--suivi-titre);
  color: var(--black);
  padding-right: var(--espace-lg);
}

.jm-fenetre-periode {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.jm-fenetre-liste {
  list-style: none;
  margin: var(--espace-md) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--espace-xs);
}

.jm-fenetre-item {
  display: flex;
  gap: var(--espace-xs);
  align-items: flex-start;
  padding: var(--espace-xs);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: var(--gray-1);
}
.jm-fenetre-item-texte { display: flex; flex-direction: column; gap: var(--espace-3xs); min-width: 0; }
.jm-fenetre-item strong { font-size: var(--fs-sm); color: var(--black); }
.jm-fenetre-item span { font-size: var(--fs-2xs); color: var(--gray-5); line-height: 1.5; }

.jm-fenetre-reste {
  margin: var(--espace-xs) 0 0;
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  font-style: italic;
}

.jm-fenetre-pied {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  margin-top: var(--espace-md);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
}
.jm-fenetre-compte {
  margin-left: auto;
  font-size: var(--fs-3xs);
  color: var(--gray-4);
  font-variant-numeric: tabular-nums;
}

/* ---------- L'Assistant IA, seconde position de la fenetre de signalement ---
 *
 * « Un switch qui peut passer du mode ticket au mode chatbot » (demande du 7
 * septembre 2026). Rien ici ne cree de teinte : tout est pris aux variables
 * deja appariees avec `Palette.swift`, ce que le verificateur de parite
 * controle depuis le 3 aout 2026.
 */

/* La bascule prend la place du titre de la fenetre, l'onglet actif disant
   desormais ce qu'elle fait. Deux positions dans une gouttiere, comme les
   groupes `.unit-btn` du site. */
.ticket-widget-bascule {
  display: flex;
  gap: var(--espace-3xs);
  padding: var(--espace-3xs);
  background: var(--gray-2);
  border-radius: var(--radius);
}

.ticket-widget-onglet {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-xs);
  border: none;
  background: none;
  cursor: pointer;
  padding: var(--espace-xs) var(--espace-sm);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-5);
}

.ticket-widget-onglet .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
}

.ticket-widget-onglet:hover { color: var(--gray-6); }

.ticket-widget-onglet.est-actif {
  background: #fff;
  color: var(--cyan);
  box-shadow: var(--shadow-sm);
}

/* 320 px vont pour un champ et trois cases ; ils ne vont pas pour un fil de
   conversation, ou une reponse de dix lignes devient une colonne. La fenetre
   s'elargit donc en mode Assistant -- sans jamais depasser l'ecran, la marge
   de 3rem etant celle que le rond laisse deja des deux cotes. */
.ticket-widget-panel.est-en-assistant {
  width: min(440px, calc(100vw - 3rem));
}

/* L'ouverture. La fenetre sortait d'un coup, deja entiere, a cote du bouton
   qui l'appelle : rien ne disait qu'elle en venait. Elle nait donc du coin du
   bouton, un peu plus petite et transparente, et prend sa place sur la courbe
   a rebond de la maison. Une animation CSS se rejoue d'elle-meme chaque fois
   que l'attribut `hidden` tombe (l'element repasse de `display: none` a
   affiche), donc a chaque ouverture, sans une ligne de JS. */
.ticket-widget-panel {
  transform-origin: bottom right;
  animation: ticket-widget-ouverture .26s var(--ease-spring) both;
}

@keyframes ticket-widget-ouverture {
  from { opacity: 0; transform: translateY(12px) scale(.94); }
  to { opacity: 1; transform: none; }
}

/* La feuille du telephone monte du bas (mobile.css la choisit). */
@keyframes ticket-widget-feuille {
  from { transform: translateY(100%); }
  to { transform: none; }
}

@keyframes ticket-widget-voile {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .ticket-widget-panel,
  .ticket-widget-voile { animation: none; }
}

/* Le bouton Agrandir et la croix se tiennent ensemble a droite de l'en-tete. */
.ticket-widget-actions {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

/* Absent en mode Ticket et sur telephone : voir plus bas. */
.ticket-widget-agrandir {
  display: none;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--gray-5);
  cursor: pointer;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}

.ticket-widget-agrandir:hover { background: var(--gray-2); color: var(--gray-6); }
.ticket-widget-agrandir .icon { width: var(--icon-md); height: var(--icon-md); }
.ticket-widget-agrandir .icon-reduire { display: none; }
.ticket-widget-panel.est-agrandie .ticket-widget-agrandir .icon-agrandir { display: none; }
.ticket-widget-panel.est-agrandie .ticket-widget-agrandir .icon-reduire { display: block; }

.ticket-widget-voile { display: none; }

/* La fenetre agrandie : « qu'il prenne la majorite de l'ecran, mais qu'il
   reste sous la forme d'une fenetre pop-up » (demande du 14 septembre 2026).
   Ordinateur seulement, la ou mobile.css s'arrete : sur telephone le panneau
   est deja une feuille de 86 % de l'ecran, et l'agrandir ne gagnerait rien.

   Elle reste une surface flottante de la famille (arrondi, bordure, ombre du
   panneau) posee au milieu de l'ecran. Les marges ne sont pas symetriques par
   hasard : 6rem de chaque cote gardent le bouton rond du coin hors de la
   fenetre, 2rem en haut et en bas suffisent pour qu'elle se lise comme posee
   sur la page et non comme la page. Au-dela de 1180 x 920, une ligne de
   reponse deviendrait trop longue a suivre. */
@media (min-width: 821px) {
  .ticket-widget-panel.est-en-assistant .ticket-widget-agrandir { display: flex; }

  .ticket-widget-panel.est-en-assistant.est-agrandie {
    position: fixed;
    inset: 0;
    margin: auto;
    width: min(1180px, calc(100vw - 12rem));
    height: min(920px, calc(100vh - 4rem));
    display: flex;
    flex-direction: column;
    transform-origin: center;
  }

  /* `display: flex` l'emporterait sinon sur l'attribut, et la fenetre ne se
     fermerait plus. */
  .ticket-widget-panel.est-agrandie[hidden] { display: none; }

  .ticket-widget-panel.est-agrandie > .ticket-widget-header { flex: none; }

  .ticket-widget-panel.est-agrandie #ticket-widget-vue-chat:not([hidden]) {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .ticket-widget-panel.est-agrandie #ticket-widget-vue-chat > * { flex: none; }

  /* Le fil et les deux menus qui prennent sa place avaient 320 px fixes pour
     ne pas faire sortir la fenetre par le plafond. Agrandie, la fenetre a sa
     hauteur a elle : ils prennent tout ce qui reste. L'identifiant est repete
     dans le selecteur pour passer devant la regle `> *` juste au-dessus. */
  .ticket-widget-panel.est-agrandie #ticket-widget-vue-chat > .chatbot-fil,
  .ticket-widget-panel.est-agrandie #ticket-widget-vue-chat > .chatbot-choix-menu {
    flex: 1 1 0;
    height: auto;
    min-height: 0;
  }

  .ticket-widget-panel.est-agrandie #ticket-widget-vue-chat > .chatbot-fil[hidden],
  .ticket-widget-panel.est-agrandie #ticket-widget-vue-chat > .chatbot-choix-menu[hidden] { display: none; }

  /* 85 % de 1180 px ferait des lignes de cent quarante signes. */
  .ticket-widget-panel.est-agrandie .chatbot-bulle { max-width: min(85%, 46rem); }

  .ticket-widget:has(> .ticket-widget-panel.est-en-assistant.est-agrandie:not([hidden])) > .ticket-widget-voile {
    display: block;
    position: fixed;
    inset: 0;
    background: var(--voile-flou);
    animation: ticket-widget-voile .2s var(--ease) both;
  }
}

.chatbot-portee {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace-md);
  border-bottom: 1px solid var(--gray-3);
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

.chatbot-portee-etiquette { flex: none; }
.chatbot-choix { flex: 1; min-width: 0; }

/* Le controle pose dans la page : le meme dessin que « Ou chercher » de la
   boite de choix de piece -- bordure, chevron, teinte du texte. Deux menus
   maison dans le produit, un seul dessin. */
.chatbot-choix-bouton {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  text-align: left;
  padding: var(--espace-xs) var(--chevron-reserve) var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background-color: #fff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--chevron-retrait) center;
  background-size: var(--chevron-taille);
  cursor: pointer;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.chatbot-choix-bouton:focus-visible {
  outline: none;
  border-color: var(--cyan);
  box-shadow: var(--anneau-champ);
}

.chatbot-choix-bouton .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  flex: none;
  color: var(--gray-4);
}

.chatbot-choix-libelle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Le menu se deploie dans le flux, a la place du fil, et non en absolu :
   la fenetre est etroite et `overflow: hidden`, une surface flottante y serait
   coupee -- c'est deja la raison du menu de transfert des tickets. Il prend
   la hauteur du fil pour que la fenetre ne saute pas en s'ouvrant. */
.chatbot-choix-menu {
  display: flex;
  flex-direction: column;
  height: 320px;
  padding: var(--espace-sm) var(--espace-md);
  gap: var(--espace-sm);
  background: var(--gray-1);
  border-bottom: 1px solid var(--gray-3);
}

/* `hidden` seul ne cache pas un element qu'une regle met en `flex`. */
.chatbot-choix-menu[hidden] { display: none; }

.chatbot-choix-filtre { background: #fff; flex: none; }

.chatbot-choix-liste {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

.chatbot-choix-liste:focus { outline: none; }

/* « Récents », « Tous les mandats » : des reperes, pas des titres. */
.chatbot-choix-groupe {
  padding: var(--espace-sm) var(--espace-2xs) var(--espace-2xs);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gray-4);
}

.chatbot-choix-groupe:first-child { padding-top: 0; }

.chatbot-choix-item {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  width: 100%;
  padding: var(--espace-xs) var(--espace-sm);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  text-align: left;
  font-family: var(--sans);
  cursor: pointer;
}

.chatbot-choix-item:hover,
.chatbot-choix-item.est-vise { background: var(--gray-2); }
.chatbot-choix-item[aria-selected="true"] { background: var(--cyan-light); }
.chatbot-choix-item:focus-visible { outline: none; box-shadow: var(--anneau-champ); }

.chatbot-choix-item .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  flex: none;
  color: var(--gray-4);
}

.chatbot-choix-item[aria-selected="true"] .icon { color: var(--cyan); }

.chatbot-choix-textes { display: flex; flex-direction: column; min-width: 0; flex: 1; }

.chatbot-choix-nom {
  font-size: var(--fs-sm);
  color: var(--gray-6);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* La denomination legale sous le nom court : c'est elle qui leve le doute
   entre deux abreviations voisines, mais on lit le nom court d'abord. */
.chatbot-choix-sous {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Le mandat de la page ouverte, marque dans la liste : sans cela, la portee
   preselectionnee ressemble a un choix arbitraire du logiciel. */
.chatbot-choix-marque {
  flex: none;
  padding: 0 var(--espace-2xs);
  border-radius: var(--radius-xs);
  background: var(--cyan-pale);
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--cyan-dark);
}

/* L'historique et la nouvelle conversation, poses au bout de la barre de
   portee. Des boutons d'icone sans cadre : le cadre est reserve au menu de
   portee, qui est un champ, et ces deux-la sont des gestes. */
.chatbot-portee-action {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--mic-taille);
  height: var(--mic-taille);
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--gray-5);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.chatbot-portee-action:hover { background: var(--gray-2); color: var(--gray-6); }
.chatbot-portee-action[aria-expanded="true"] { background: var(--cyan-light); color: var(--cyan-dark); }
.chatbot-portee-action:focus-visible { outline: none; box-shadow: var(--anneau-champ); }
.chatbot-portee-action .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* Une ligne d'historique : la conversation a rouvrir, et deux gestes au bout
   qui ne paraissent qu'au survol. Toujours visibles sur un ecran tactile, qui
   n'a pas de survol pour les reveler. */
.chatbot-histo-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-3xs);
}

.chatbot-histo-ligne .chatbot-choix-item { flex: 1; min-width: 0; }

.chatbot-histo-actions {
  display: flex;
  align-items: center;
  gap: var(--espace-3xs);
  opacity: 0;
  transition: opacity .15s var(--ease);
}

.chatbot-histo-ligne:hover .chatbot-histo-actions,
.chatbot-histo-ligne:focus-within .chatbot-histo-actions,
.chatbot-histo-ligne.est-a-confirmer .chatbot-histo-actions { opacity: 1; }

@media (hover: none) {
  .chatbot-histo-actions { opacity: 1; }
}

.chatbot-histo-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-xl);
  height: var(--icon-xl);
  padding: 0;
  border: none;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--gray-4);
  cursor: pointer;
}

.chatbot-histo-action:hover { background: var(--gray-2); color: var(--gray-6); }
.chatbot-histo-action.est-danger:hover { background: var(--red-pale); color: var(--red); }
.chatbot-histo-action:focus-visible { outline: none; box-shadow: var(--anneau-champ); }
.chatbot-histo-action .icon { width: var(--icon-xs); height: var(--icon-xs); }

/* Effacer se confirme sur la ligne meme : une fenetre de dialogue pour une
   conversation serait plus lourde que ce qu'elle protege. */
.chatbot-histo-confirmer,
.chatbot-histo-garder {
  padding: var(--espace-3xs) var(--espace-xs);
  border: none;
  border-radius: var(--radius-xs);
  font-family: var(--sans);
  font-size: var(--fs-2xs);
  font-weight: 600;
  cursor: pointer;
}

.chatbot-histo-confirmer { background: var(--red); color: #fff; }
.chatbot-histo-garder { background: var(--gray-2); color: var(--gray-6); }

.chatbot-histo-champ {
  flex: 1;
  min-width: 0;
  padding: var(--espace-xs) var(--espace-sm);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  color: var(--gray-6);
  border: 1px solid var(--cyan);
  border-radius: var(--radius-sm);
  box-shadow: var(--anneau-champ);
  outline: none;
}

/* « 3 autres conversations » : un mandat travaille tout l'automne ne doit pas
   repousser les autres hors de la fenetre. */
.chatbot-histo-plus {
  align-self: flex-start;
  padding: var(--espace-3xs) var(--espace-sm);
  border: none;
  background: none;
  font-family: var(--sans);
  font-size: var(--fs-2xs);
  color: var(--cyan-dark);
  cursor: pointer;
}

.chatbot-histo-plus:hover { text-decoration: underline; }

.chatbot-choix-vide {
  padding: var(--espace-md) var(--espace-sm);
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--gray-4);
}

/* Le fil a une hauteur fixe et non une hauteur libre : la fenetre est ancree
   en bas a droite, et un panneau qui grandit vers le haut a chaque reponse
   finit par sortir de l'ecran par le plafond. */
.chatbot-fil {
  height: 320px;
  overflow-y: auto;
  padding: var(--espace-md);
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
  background: var(--gray-1);
}

/* Le fil s'efface pendant que le menu de portee est ouvert : les deux ont la
   meme hauteur, et la fenetre ne bouge donc pas d'un pixel en s'ouvrant. Le
   `[hidden]` doit etre ecrit, `display: flex` l'emportant sinon. */
.chatbot-fil[hidden] { display: none; }

.chatbot-bulle {
  max-width: 85%;
  padding: var(--espace-sm) var(--espace-md);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  line-height: 1.5;
  white-space: normal;
  overflow-wrap: anywhere;
}

.chatbot-bulle-moi {
  align-self: flex-end;
  background: var(--cyan);
  color: #fff;
}

.chatbot-bulle-assistant,
.chatbot-bulle-assistant-attente {
  align-self: flex-start;
  background: #fff;
  border: 1px solid var(--gray-3);
  color: var(--gray-6);
}

.chatbot-bulle-assistant-attente { color: var(--gray-5); }

/* La mise en forme reconnue dans une reponse de l'Assistant (voir `enrichir`
   dans chatbot.js) : titre, paragraphe, puce, tableau, code. Chaque bloc
   porte sa propre marge, sans quoi le dernier de la bulle laisserait un
   creux en bas que les autres bulles n'ont pas. */
.chatbot-bulle-assistant p,
.chatbot-bulle-assistant table,
.chatbot-bulle-assistant pre {
  margin: 0 0 var(--espace-xs);
}
.chatbot-bulle-assistant :last-child { margin-bottom: 0; }

.chatbot-titre {
  font-weight: 600;
  margin-top: var(--espace-xs);
}
.chatbot-titre:first-child { margin-top: 0; }

.chatbot-puce { padding-left: var(--espace-xs); }
.chatbot-puce-imbriquee { padding-left: var(--espace-md); }

.chatbot-tableau {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}
.chatbot-tableau th,
.chatbot-tableau td {
  border: 1px solid var(--gray-3);
  padding: var(--espace-3xs) var(--espace-2xs);
  text-align: left;
}
.chatbot-tableau th { background: var(--gray-1); font-weight: 600; }

.chatbot-bulle-assistant code {
  font-family: var(--mono);
  font-size: .9em;
  background: var(--gray-1);
  border-radius: var(--radius-xs);
  padding: 0 .3em;
}
.chatbot-code {
  overflow-x: auto;
  background: var(--gray-1);
  border-radius: var(--radius-xs);
  padding: var(--espace-xs);
}
.chatbot-code code { background: none; padding: 0; }

/* Ce que dit la fenetre elle-meme -- l'accueil, un changement de portee, une
   panne. Ni a gauche ni a droite : au milieu, en petit, pour qu'on ne le lise
   pas comme une reponse. */
.chatbot-bulle-systeme {
  align-self: center;
  max-width: 100%;
  text-align: center;
  background: none;
  padding: var(--espace-xs) 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.chatbot-pieces-lues {
  margin: var(--espace-xs) 0 0;
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Ce que l'Assistant vient d'ecrire dans le mandat.
   Vert et non gris : une lecture se note en passant, une ecriture se voit. Le
   filet a gauche est celui d'une citation -- c'est bien de cela qu'il s'agit,
   le serveur cite le geste qu'il a fait. */
.chatbot-ecriture {
  margin: var(--espace-xs) 0 0;
  padding-left: var(--espace-sm);
  border-left: 2px solid var(--green);
  font-size: var(--fs-xs);
  color: var(--green-dark);
}

/* Un geste que l'Assistant n'a pas fait : il attend un clic.
   Audit securite du 16 septembre 2026 : ce qui supprime ou touche aux acces
   ne part que sur cette confirmation, posee par le serveur. Orange et non
   vert, puisque rien n'est encore ecrit. */
.chatbot-attente {
  margin: var(--espace-xs) 0 0;
  padding-left: var(--espace-sm);
  border-left: 2px solid var(--orange);
  font-size: var(--fs-xs);
}

.chatbot-attente-libelle { margin: 0 0 var(--espace-3xs); }

.chatbot-attente-actions { display: flex; gap: var(--espace-3xs); flex-wrap: wrap; }

/* La page que l'Assistant vient d'ouvrir.
   Bleue et non verte : ce n'est pas une ecriture, rien n'a bouge dans le
   mandat -- c'est l'ecran qui a bouge. Un bouton et non une phrase, parce
   qu'on a pu naviguer depuis et qu'on doit pouvoir y retourner sans reposer
   la question. */
.chatbot-ouverture {
  display: block;
  width: 100%;
  margin: var(--espace-xs) 0 0;
  padding: 0 0 0 var(--espace-sm);
  border: 0;
  border-left: 2px solid var(--blue);
  background: none;
  font: inherit;
  font-size: var(--fs-xs);
  color: var(--blue);
  text-align: left;
  cursor: pointer;
}
.chatbot-ouverture:hover { text-decoration: underline; }

.chatbot-saisie { padding-bottom: var(--espace-sm); }

/* ---------- La synthèse de groupe ----------
   Dix-huit lignes de mesures et une quarantaine de structures en colonnes,
   chacune portant autant de sous-colonnes qu'il y a d'exercices cochés, plus
   sa variation : le seul tableau du produit qui ne tient pas dans la largeur
   d'un écran. Il défile donc horizontalement, avec la colonne des libellés
   figée à gauche et les deux rangées d'en-tête figées en haut -- sans quoi on
   lit des chiffres sans savoir de qui ils parlent ni de quelle année, ce qui
   était exactement le défaut du classeur repris ici.

   Les deux rangées d'en-tête se figent l'une sous l'autre, et c'est la seule
   raison pour laquelle la première a une hauteur écrite (`--entete-h`) : le
   `top` de la seconde doit valoir exactement la hauteur de la première, sans
   quoi elles se chevauchent au défilement. */
.synthese-groupe-barre { align-items: center; gap: var(--espace); flex-wrap: wrap; }
.synthese-groupe-titre { margin: 0; font-size: var(--fs-h2); color: var(--gray-6); }
.synthese-groupe-exercices { margin-left: auto; }
.synthese-groupe-filtre-label {
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.synthese-groupe-filtre { min-width: 15em; max-width: 20em; }
.synthese-groupe-etat {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  min-width: 12em;
}
.synthese-groupe-etat.est-erreur { color: var(--orange-dark); }

.synthese-groupe-cadre {
  overflow: auto;
  max-height: 70vh;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* Le decalage d'une colonne figee. Zero par defaut, mesure et pose case par
   case par le navigateur : il depend du nombre d'exercices coches et de la
   largeur que le contenu leur donne (voir figerLesVolets). */
:root { --fige-gauche: 0; }

.synthese-groupe-table {
  --entete-h: 2.4rem;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.synthese-groupe-table thead th {
  position: sticky;
  z-index: 2;
  background: var(--gray-1);
  padding: var(--espace-2xs) var(--espace-sm);
  border-bottom: 1px solid var(--gray-3);
  text-align: right;
  font-weight: 600;
  color: var(--gray-6);
}
.synthese-groupe-table thead tr:first-child th { top: 0; height: var(--entete-h); }
.synthese-groupe-table thead tr + tr th { top: var(--entete-h); }

/* La tête d'une structure chapeaute ses années : centrée, séparée de sa
   voisine par un trait, et bornée en largeur pour que « FRANCAS UR BOURGOGNE
   FRANCHE COMTE » ne pousse pas ses colonnes au double de leur besoin. */
.synthese-groupe-table thead th.synthese-groupe-col-structure {
  text-align: center;
  border-left: 2px solid var(--gray-3);
  max-width: 18em;
  overflow: hidden;
  text-overflow: ellipsis;
}
.synthese-groupe-col-structure a { color: var(--gray-6); text-decoration: none; }
/* Le nom se clique pour n'afficher que cette structure, en projection comme
   dans l'onglet (suivi du 9 septembre 2026). En projection ce n'est pas un
   lien mais un `<span>` : il lui faut donc dire lui-même qu'il se clique. */
.synthese-groupe-col-structure .est-cliquable { cursor: pointer; }
.synthese-groupe-col-structure a:hover,
.synthese-groupe-col-structure .est-cliquable:hover { text-decoration: underline; }
/* Le signataire, sous le nom de la structure : « rajoute le nom du signataire
   pour chaque structure » (ticket du 9 septembre 2026). Plus petit et plus
   pâle que le nom du mandat -- c'est une précision sur la colonne, pas son
   titre --, et sur sa propre ligne : deux noms côte à côte dans une tête de
   colonne étroite se liraient comme un seul nom composé. */
/* LES TROIS DERNIERS JOURS SE VOIENT, ET S'ÉTEIGNENT UNE FOIS TRAITÉS.

   « Il faudrait simplement mieux mettre en évidence visuellement les mentions
   Aujourd'hui, Hier et Avant-hier, de manière cohérente avec le reste du site,
   pour repérer rapidement ce qui est récent et potentiellement à traiter. Dès
   que le document est qualifié avec une coche verte ou orange, cette mise en
   évidence disparaît puisqu'il a été traité » (suivi du 9 septembre 2026).

   La teinte est celle de la marque du produit, celle des liens et des états
   ouverts : ce n'est ni une alerte ni une réussite, c'est « regarde ici ». Un
   gras d'un cran, et rien d'autre -- une pastille de plus dans une colonne de
   dates ferait un tableau qui clignote.

   L'extinction est écrite ici et non en JavaScript : une ligne pointée porte
   `data-controle`, celui-là même que pose la pastille verte ou orange, et la
   mise en évidence suit l'attribut sans que personne n'ait à la resynchroniser.
   Les deux états sont nommés plutôt que `[data-controle]` tout court : demain
   un troisième état pourrait vouloir rester allumé. */
.date-recente {
  color: var(--cyan-dark);
  font-weight: 600;
}
tr[data-controle="valide"] .date-recente,
tr[data-controle="probleme"] .date-recente {
  color: inherit;
  font-weight: inherit;
}

.synthese-groupe-col-signataire {
  display: block;
  font-size: var(--fs-3xs);
  font-weight: 400;
  color: var(--gray-4);
  overflow: hidden;
  text-overflow: ellipsis;
}
/* L'année coiffe sa colonne en son milieu. « L'année de l'exercice doit
   également être centrée sur chaque colonne » (ticket du 10 septembre 2026) :
   elle héritait du `text-align: right` des en-têtes, donc « 2025 » se collait
   au bord droit de son bloc, contre la colonne de variation qui suit. Le nom
   de la structure, juste au-dessus, est centré depuis toujours ; l'année ne
   l'était pas, et les deux rangées ne s'alignaient sur rien.

   La variation garde le sien : « Var. » n'est pas une année, sa colonne est
   étroite et son libellé y tient à peine. */
.synthese-groupe-table thead th.synthese-groupe-col-annee {
  font-weight: 500;
  color: var(--gray-5);
  cursor: help;
  text-align: center;
}

/* La colonne des libellés à gauche, et la case d'angle qui la coiffe. */
.synthese-groupe-table th.synthese-groupe-mesure,
.synthese-groupe-table thead th.synthese-groupe-col-mesure {
  position: sticky;
  left: 0;
  z-index: 3;
  background: #fff;
  text-align: left;
  font-weight: 500;
  padding: var(--espace-2xs) var(--espace-sm);
  border-right: 1px solid var(--gray-2);
  /* Largeur tenue, et le libelle qui revient a la ligne plutot que de
     deborder : sans cela « Zones de risques et recommandations » sortait de la
     colonne figee et se superposait aux chiffres pendant le defilement. */
  width: 17em;
  min-width: 17em;
  white-space: normal;
}
.synthese-groupe-table thead th.synthese-groupe-col-mesure {
  background: var(--gray-1);
  z-index: 4;
}
.synthese-groupe-table th.synthese-groupe-mesure.est-saisissable {
  color: var(--gray-5);
  font-style: italic;
}

/* LES VOLETS FIGÉS (ticket du 9 septembre 2026 : « il faut qu'on ait la
   possibilité de figer les volets, après les colonnes de total, c'est-à-dire
   après la variation »).

   La colonne des libellés l'était déjà ; c'est le bloc de total qui ne l'était
   pas, et c'est lui qu'on garde sous les yeux : quarante-trois structures
   défilent à droite, et sans lui on compare un chiffre à rien. Le décalage de
   chaque colonne ne peut pas s'écrire ici -- il dépend du nombre d'exercices
   cochés et de la largeur que le contenu leur donne --, il est donc mesuré et
   posé par le navigateur dans `--fige-gauche` (voir synthese-groupe.js).

   Le fond est déjà opaque sur ces cases (`.est-total`), ce qui est la
   condition pour qu'une case figée ne laisse pas passer ce qui glisse
   dessous. La dernière colonne du bloc, la variation, porte le trait épais qui
   sépare le total des structures : il tient déjà dans `.est-variation`. */
.synthese-groupe-table .est-total.est-figee {
  position: sticky;
  left: var(--fige-gauche, 0);
  z-index: 3;
}
.synthese-groupe-table thead th.est-total.est-figee { z-index: 4; }

/* Le total : première colonne, et la seule qui se lise sans savoir de quelle
   structure elle parle. Un fond pâle et un trait plus épais la séparent des
   structures, sans quoi elle se lirait comme la première d'entre elles. */
.synthese-groupe-table .est-total { background: var(--gray-1); }
.synthese-groupe-table thead th.est-total { background: var(--gray-2); }
.synthese-groupe-table td.est-total { font-weight: 600; }

/* `.synthese-groupe-fiche-btn` vivait ici : le « Fiche » posé sous le nom de
   chaque structure, donc quarante-quatre fois sur une rangée où le nom du
   mandat et son signataire tiennent déjà mal. « Supprime "Fiche" de toutes les
   structures » (ticket du 9 septembre 2026) : il est passé dans la barre, en un
   seul exemplaire, et n'a plus de style à lui -- c'est un `.btn.btn-secondary`
   comme ses voisins. */

.synthese-groupe-case {
  padding: var(--espace-2xs) var(--espace-sm);
  border-top: 1px solid var(--gray-2);
  text-align: right;
  color: var(--gray-6);
}
.synthese-groupe-case.est-vide { color: var(--gray-3); }
.synthese-groupe-case.est-negatif { color: var(--orange-dark); }
/* Une valeur qui s'ouvre se signale avant d'être cliquée : rien ne dit
   autrement qu'un nombre cache la formule qui l'a fait. */
.synthese-groupe-case.est-decomposable { cursor: pointer; }
.synthese-groupe-case.est-decomposable:hover {
  background: var(--cyan-pale);
  text-decoration: underline dotted;
}
/* L'exercice le plus récent affiché, en gras, l'en-tête comme les chiffres.
   « Mets davantage en évidence la colonne N par rapport aux colonnes N-1, N-2,
   etc. » (suivi du 7 septembre 2026) : c'est la règle de `col-annee-active`
   dans Cycle > Analyse, où l'exercice sur lequel porte la campagne se distingue
   de ceux qu'on ne fait que comparer.

   Le gras SEUL, et pas une couleur : les cases portent déjà la leur pour dire
   autre chose (un montant négatif est ambre, une case vide est grise, un écart
   au rapport est rouge). Une règle de colonne qui repeindrait tout écraserait
   ces trois-là, qui disent chacune quelque chose que l'année ne dit pas. */
.synthese-groupe-table td.synthese-groupe-case.est-reference { font-weight: 700; }
.synthese-groupe-table thead th.synthese-groupe-col-annee.est-reference {
  font-weight: 700;
  color: var(--gray-6);
}

/* La variation ferme le bloc d'une structure : elle est en italique, plus pâle
   et PLUS PETITE que les montants, pour qu'on ne la confonde pas avec l'un
   d'eux. « Réduis la taille de l'affichage de la variation » (suivi du
   7 septembre 2026) : elle passe d'un cran sous le tableau, comme la variation
   d'une tuile de Présentation financière, et sa colonne se resserre d'autant. */
.synthese-groupe-case.est-variation {
  font-style: italic;
  font-weight: 400;
  font-size: var(--fs-3xs);
  color: var(--gray-5);
  padding-left: var(--espace-3xs);
  padding-right: var(--espace-3xs);
  border-right: 2px solid var(--gray-3);
}
.synthese-groupe-case.est-variation.est-negatif { color: var(--orange-dark); }
.synthese-groupe-table thead th.synthese-groupe-col-annee.est-variation {
  font-size: var(--fs-3xs);
  padding-left: var(--espace-3xs);
  padding-right: var(--espace-3xs);
  /* « Var. » n'est pas une année : sa colonne est étroite, son libellé y tient
     à peine, et il reste calé à droite au-dessus de ses pourcentages. */
  text-align: right;
}

/* SEULES LES CASES EN ÉCART SE MARQUENT (ticket du 9 septembre 2026 : « tu
   peux retirer le vert quand c'est juste. Ce qui compte, c'est d'avoir
   uniquement les cellules pour lesquelles tu relèves des écarts »).

   Le liseré vert d'une case conforme et le liseré gris d'une case que le
   rapport ne peut pas confronter ont donc disparu : dans un tableau de
   quarante-trois colonnes, marquer ce qui va bien peint presque tout et noie
   les quelques cases qui ne vont pas. Ce qui a été vérifié, et ce qui n'a pas
   pu l'être, se lit toujours au survol de la case ; c'est l'œil qui est
   déchargé, pas l'information qui est retirée.

   Et une valeur reprise du classeur tenu à la main ne se colore plus non plus
   (« il ne faut pas mettre la colonne d'une couleur différente, il faut
   qu'elle soit comme pour les autres ») : son origine reste au survol. */
.synthese-groupe-case.est-ecart {
  background: var(--red-pale);
  box-shadow: inset 2px 0 0 var(--red);
}
.synthese-groupe-marque {
  margin-left: var(--espace-3xs);
  color: var(--red-dark);
  font-weight: 700;
}

/* L'ASSISTANT DES ANOMALIES, SOUS LA BARRE.

   « Un assistant visible permettant de faire ressortir les éventuelles
   anomalies et d'y accéder facilement » (ticket du 9 septembre 2026).

   Dans le flux et non par-dessus : le tableau défile horizontalement, et une
   liste posée en absolu s'y ferait rogner dès qu'on fait glisser les colonnes.
   C'est le choix déjà fait pour le menu de portée de l'Assistant IA, et pour
   la même raison. */
.synthese-groupe-anomalies-appel { color: var(--red-dark); }

.synthese-groupe-anomalies-panneau {
  margin-bottom: var(--espace-sm);
  padding: var(--espace-sm) var(--espace-md);
  border: 1px solid var(--red);
  border-radius: var(--radius);
  background: var(--red-pale);
  max-height: 30vh;
  overflow: auto;
}

.synthese-groupe-anomalies-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

.synthese-groupe-anomalie-structure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-2xs);
}

.synthese-groupe-anomalie-nom {
  font-size: var(--fs-xs);
  font-weight: 700;
  min-width: 14em;
}

/* Une anomalie est un bouton parce qu'elle mène quelque part : elle isole sa
   structure, amène sa case sous les yeux et la fait clignoter. */
.synthese-groupe-anomalie {
  display: inline-flex;
  align-items: baseline;
  gap: var(--espace-2xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border: 1px solid var(--red);
  border-radius: 999px;
  background: #fff;
  font-size: var(--fs-2xs);
  color: var(--black);
  cursor: pointer;
  transition: background .15s var(--ease);
}

.synthese-groupe-anomalie:hover { background: var(--red-pale); }

.synthese-groupe-anomalie-ecart {
  font-weight: 700;
  color: var(--red-dark);
}

/* La case qu'une ligne de l'assistant vient d'ouvrir. Elle clignote deux fois
   puis redevient elle-même : sur une colonne où plusieurs cases portent déjà
   la pastille d'écart, c'est la seule façon de dire LAQUELLE on a demandée. */
.synthese-groupe-case.est-visee {
  animation: synthese-groupe-visee 1.2s var(--ease) 2;
}

@keyframes synthese-groupe-visee {
  0%, 100% { box-shadow: inset 2px 0 0 var(--red); }
  50% { box-shadow: inset 0 0 0 2px var(--red-dark); }
}

/* UNE QUESTION TRANCHÉE NE SE REPOSE PLUS.

   « Quand il y a des différences signalées, reprends les chiffres figurant
   dans le rapport sur les comptes annuels », « je valide manuellement le
   chiffre que tu as calculé, tu peux retirer l'écart mentionné » (tickets du
   9 septembre 2026).

   Une case arbitrée perd le fond rouge et le liseré rouge : elle ne signale
   plus rien, quelqu'un l'a regardée.

   Reste ici la seule des deux décisions qui CHANGE LE CHIFFRE AFFICHÉ. « Le
   rapport fait foi » remplace la valeur de la case : le « R » cyan dit d'où
   vient un nombre qui n'est plus celui du FEC, et le liseré le rattache à la
   colonne. « Le calcul fait foi » ne remplace rien, et sa coche a été retirée
   (« vire le tic, même format que pour les autres chiffres », suivi du
   9 septembre 2026) : la case porte le chiffre qu'elle portait déjà, calculé
   comme les quarante-deux autres de sa ligne, et la marquer distinguait deux
   cases que rien ne sépare à l'écran. Ce qui a été décidé se lit au survol.

   Le cyan est la teinte de ce qui a été fait, pas de ce qui alerte. */
/* Le chiffre vient du rapport signé et non du FEC. Un liseré au bord gauche et
   rien d'autre : le « R » qui s'écrivait après le montant a été retiré le
   9 septembre 2026 (« enlève la mention du R en bleu après les chiffres »).
   Collé à un nombre, il se lisait comme un nombre, et sur une ligne en milliers
   il faisait douter de l'unité. Ce qu'il disait tient dans l'infobulle, qui
   nomme le document et donne le calcul du FEC. */
.synthese-groupe-case.est-arbitre {
  box-shadow: inset 2px 0 0 var(--cyan);
}

/* Les trois boutons de décision, au pied de l'infobulle d'une case en écart :
   c'est le seul endroit où l'on voit en même temps les deux chiffres et le
   poste qui les sépare. Empilés et non en rangée : leurs libellés sont des
   phrases, et trois phrases côte à côte ne tiendraient pas dans les 28em de
   l'infobulle. */
.synthese-groupe-popover-arbitrage {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--espace-3xs);
  margin-top: var(--espace-sm);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-3);
}
.synthese-groupe-popover-arbitrage-titre {
  margin: 0 0 var(--espace-3xs);
  font-weight: 600;
  color: var(--gray-6);
}
.synthese-groupe-popover-arbitrage-btn {
  justify-content: flex-start;
  text-align: left;
  font-size: var(--fs-xs);
}
/* Ce qui est retenu se voit sans qu'on le survole : le fond de la teinte du
   fait, et non de celle de l'alerte. */
.synthese-groupe-popover-arbitrage-btn.est-retenu {
  background: var(--cyan-pale);
  color: var(--cyan-dark);
  font-weight: 600;
}
/* Le nom de la structure quand l'une de ses mesures diverge du rapport signé :
   « il faut que le nom de la structure soit mis en évidence lorsqu'il y a un
   écart sur un agrégat » (ticket du 8 septembre 2026). Le même fond et le même
   signe que la case, pour que l'œil fasse le lien sans qu'on l'explique. */
.synthese-groupe-table thead th.synthese-groupe-col-structure.est-ecart {
  background: var(--red-pale);
}
.synthese-groupe-col-structure.est-ecart a {
  color: var(--red-dark);
  font-weight: 600;
}
/* « ND » : non déterminé, sur les deux lignes de journées (ticket du
   9 septembre 2026). Ce n'est ni un chiffre ni un vide : c'est une réponse, et
   elle se lit comme les autres mentions du tableau, en gris et sans appuyer.
   La case reste saisissable -- « ND » y est un repère, pas une valeur --, d'où
   le passage par le texte de substitution du champ. */
.synthese-groupe-case.est-non-determine .synthese-groupe-champ::placeholder {
  color: var(--gray-4);
  opacity: 1;
}

/* Une case qui se saisit se voit sans être cliquée : un fond très pâle, qui
   sépare d'un coup d'oeil les onze colonnes recalculées des neuf autres. */
.synthese-groupe-case.est-saisissable { background: rgba(46, 158, 91, .05); }

/* Une case lue dans le rapport sur les comptes annuels n'est pas une case
   saisie : elle vient d'un document, donc elle se verifie. Le pointille sous
   le chiffre est l'usage du web pour « ceci a une source », et l'infobulle
   nomme le document. Sans cette marque, une valeur lue par le modele serait
   indiscernable d'un chiffre tape par un collaborateur, et personne ne
   saurait laquelle des deux aller controler. */
.synthese-groupe-case.est-lue { background: rgba(0, 122, 194, .05); }
.synthese-groupe-case.est-lue .synthese-groupe-champ {
  text-decoration: underline dotted var(--gray-4);
  text-underline-offset: 3px;
}
/* Le pointille dit « lu » ; il n'a plus rien a dire des qu'on ecrit par
   dessus, et la case redevient une case ordinaire. */
.synthese-groupe-case.est-lue .synthese-groupe-champ:focus {
  text-decoration: none;
}

/* Une case restée vide parce que la lecture a refusé le chiffre, ou parce que
   le rapport ne porte pas la ligne. Le motif est au survol ; ici il ne s'agit
   que de dire qu'il y en a un, sans quoi personne ne penserait à survoler un
   trou (ticket du 9 septembre 2026 : « tous ceux pour lesquels tu n'as rien
   renseigné »).

   Le même pointillé que « lu », posé sous la case entière plutôt que sous un
   texte qui n'existe pas, et de la même encre grise : c'est la même famille --
   « le rapport a été ouvert » --, l'une avec un chiffre, l'autre sans. Ni
   rouge ni orange : une ligne que le rapport ne porte pas n'est pas une
   anomalie du dossier. */
.synthese-groupe-case.est-refusee {
  border-bottom: 1px dotted var(--gray-4);
  cursor: help;
}
.synthese-groupe-champ {
  width: 100%;
  min-width: 5em;
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--gray-6);
  text-align: left;
  /* Un champ garde le curseur d'un champ, quelle que soit la case qui le
     porte. Sans cette ligne il heritait du `cursor: help` de la case refusée,
     et un « ND » sous un point d'interrogation ne se tape pas : « quoi qu'il
     arrive, le chiffre doit pouvoir être modifiable même quand c'est écrit
     ND » (ticket du 9 septembre 2026). Il l'était ; rien ne le disait. */
  cursor: text;
}
.synthese-groupe-champ.est-nombre { text-align: right; }

/* LE TYPE DE CERTIFICATION SE CENTRE ET SE PEINT.

   « Il faut que cette information (exemple SR) soit centrée dans la cellule.
   Si le rapport comprend un paragraphe intitulé "Observation" ou "Incertitude
   significative liée à la continuité d'exploitation", il faut alors inscrire
   R/O (utiliser une couleur différente que SR) » (ticket du 9 septembre 2026).

   Deux ou trois signes calés à gauche se perdaient au bord d'une colonne
   large, et la ligne ne se lisait plus d'un regard.

   SR ne se peint pas : c'est le cas ordinaire, quarante fois sur
   quarante-quatre, et le peindre reviendrait à peindre le tableau -- même
   arbitrage que les cases en écart, et même raison (voir `.est-ecart`). Ce
   qui s'en écarte se voit, en deux degrés : R/O accompagne l'opinion sans la
   changer, R la restreint et RC la refuse.

   LA CASE AUTANT QUE LE CHAMP. Une case saisissable porte un champ, une case
   en lecture seule porte son texte : c'est la même ligne, vue par les deux
   portes de `_synthese_groupe.html`. Ne peindre que le champ laissait la
   projection -- celle qu'on branche en HDMI, donc celle qu'une salle regarde
   -- avec sa ligne calée à droite et ses R/O à l'encre ordinaire. */
.synthese-groupe-case.est-centre,
.synthese-groupe-champ.est-centre { text-align: center; }

.synthese-groupe-case.est-observation,
.synthese-groupe-case.est-observation .synthese-groupe-champ {
  color: var(--orange-dark);
  font-weight: 600;
}
.synthese-groupe-case.est-reserve,
.synthese-groupe-case.est-reserve .synthese-groupe-champ {
  color: var(--red-dark);
  font-weight: 700;
}
.synthese-groupe-champ:focus {
  outline: 2px solid var(--cyan);
  outline-offset: 1px;
  border-radius: 2px;
  background: #fff;
}

/* LA CASE DE L'OPINION S'OUVRE SUR LE RAPPORT QUI LA JUSTIFIE.

   « Lorsque l'on clique dans la synthèse Francas sur type de certification
   (exemple SR) on doit faire apparaître en visualisation le rapport sur les
   comptes annuels de l'exercice et de la structure concernés » (ticket du
   12 septembre 2026).

   Le champ garde sa place et son centrage ; seul son curseur change, parce
   qu'un clic n'y écrit plus mais ouvre la pièce. Le crayon ne paraît qu'au
   survol de la case : il rend la saisie à qui en a besoin sans peupler
   quarante-quatre colonnes d'une icône de plus. */
.synthese-groupe-case.est-ouvrable { position: relative; }
.synthese-groupe-case.est-ouvrable .synthese-groupe-champ { cursor: pointer; }
.synthese-groupe-crayon {
  position: absolute;
  top: 50%;
  right: var(--espace-xs);
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  border: none;
  background: none;
  padding: 0;
  color: var(--gray-4);
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s var(--ease);
}
.synthese-groupe-crayon .icon { width: .85em; height: .85em; }
.synthese-groupe-case.est-ouvrable:hover .synthese-groupe-crayon,
.synthese-groupe-crayon:focus-visible { opacity: 1; }
.synthese-groupe-crayon:hover { color: var(--gray-6); }

/* La pièce elle-même, dans une fenêtre posée sur la synthèse : la même
   famille que le grand livre d'un compte, en plus haut, parce qu'un rapport
   se lit page après page. */
.modal.synthese-groupe-rapport { max-height: 92vh; }
.synthese-groupe-rapport-cadre {
  flex: 1;
  width: 100%;
  min-height: 70vh;
  border: none;
  background: var(--gray-1);
}

/* La composition d'une valeur, ouverte au clic : une surface flottante de la
   famille des autres (rayon large, fond blanc, bordure grise, ombre portée),
   posée en absolu dans la page parce que la cellule qui l'appelle vit dans un
   cadre à débordement caché. */
/* LA COURBE MENSUELLE D'UNE MESURE, DANS SA BULLE

   « Lorsque je place le curseur sur un chiffre, une bulle doit afficher un
   graphique presentant l'evolution mensuelle de la rubrique selectionnee sur
   l'ensemble des exercices disponibles [...] La bulle contenant le graphique
   doit pouvoir etre fermee » (ticket du 10 septembre 2026).

   Le meme cadre que l'infobulle de composition juste en dessous -- fond blanc,
   filet gris, grand rayon, ombre portee -- parce que les deux sont la meme
   sorte d'objet : une reponse posee au-dessus du tableau, a cote du chiffre
   qui l'a appelee. Ce qui change est la largeur : un graphique de douze mois
   ne se lit pas dans vingt-huit cadratins. */
.synthese-groupe-courbe {
  position: absolute;
  z-index: 61;
  width: min(44rem, calc(100vw - 2rem));
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--espace);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

.synthese-groupe-courbe-tete {
  display: flex;
  align-items: baseline;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-xs);
}

.synthese-groupe-courbe-titre {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  color: var(--gray-6);
}

/* La croix : grise au repos, rouge au survol, comme toutes les fermetures de
   la feuille. Elle est le geste que le ticket exige nommement, donc elle est
   visible en permanence et non au survol de la bulle. */
.synthese-groupe-courbe-fermer {
  flex: none;
  width: var(--icon-md);
  height: var(--icon-md);
  padding: 0;
  border: none;
  border-radius: var(--radius-xs);
  background-color: transparent;
  color: var(--gray-4);
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
  transition: color .15s var(--ease), background-color .15s var(--ease);
}

.synthese-groupe-courbe-fermer:hover {
  background-color: var(--red-pale);
  color: var(--red);
}

.synthese-groupe-courbe-svg { width: 100%; height: auto; }

.synthese-groupe-courbe-note {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* La grille : assez pale pour que les courbes passent devant, assez presente
   pour qu'on lise une hauteur. Le zero est plus marque -- c'est la seule
   graduation qui veut dire quelque chose par elle-meme. */
.synthese-groupe-courbe-svg .courbe-grille { stroke: var(--gray-2); stroke-width: 1; }
.synthese-groupe-courbe-svg .courbe-zero { stroke: var(--gray-4); stroke-width: 1; }
.synthese-groupe-courbe-svg .courbe-graduation,
.synthese-groupe-courbe-svg .courbe-mois {
  fill: var(--gray-5);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.synthese-groupe-courbe-svg .courbe-trait {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* Quatre teintes, prises a la charte du produit : au-dela de quatre exercices
   affiches les couleurs se repetent, et c'est la legende qui les nomme. Le
   cyan d'abord, parce que c'est la couleur du produit et que le premier
   exercice de la liste est le plus ancien -- celui qu'on compare aux autres. */
.synthese-groupe-courbe-svg .courbe-trait-0,
.synthese-groupe-courbe-legende .courbe-trait-0 { stroke: var(--cyan); color: var(--cyan-dark); }
.synthese-groupe-courbe-svg .courbe-trait-1,
.synthese-groupe-courbe-legende .courbe-trait-1 { stroke: var(--purple); color: var(--purple); }
.synthese-groupe-courbe-svg .courbe-trait-2,
.synthese-groupe-courbe-legende .courbe-trait-2 { stroke: var(--orange); color: var(--orange-dark); }
.synthese-groupe-courbe-svg .courbe-trait-3,
.synthese-groupe-courbe-legende .courbe-trait-3 { stroke: var(--green); color: var(--green-dark); }

.synthese-groupe-courbe-svg .courbe-point { fill: #fff; stroke-width: 2; }

/* Le second et le troisieme tour des quatre teintes : dix exercices
   disponibles se sont deja vus, et dix courbes de quatre couleurs ne se
   distinguent plus. Le trait change alors de forme, dans le graphique comme
   dans la legende. */
.synthese-groupe-courbe-svg .courbe-forme-1 { stroke-dasharray: 6 4; }
.synthese-groupe-courbe-svg .courbe-forme-2 { stroke-dasharray: 2 3; }
.synthese-groupe-courbe-legende .courbe-forme-1::before { border-top-style: dashed; }
.synthese-groupe-courbe-legende .courbe-forme-2::before { border-top-style: dotted; }

.synthese-groupe-courbe-legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin: var(--espace-2xs) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-2xs);
}

.synthese-groupe-courbe-legende li {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-3xs);
  font-weight: 600;
}

/* Le trait de la legende : un segment de la couleur de la courbe, dessine par
   la bordure plutot que par un carre de fond -- une courbe est une ligne, et
   une pastille pleine ne dit pas laquelle. */
.synthese-groupe-courbe-legende li::before {
  content: "";
  width: 1.2em;
  border-top: 2px solid currentColor;
}

/* Une case dont on peut tracer la courbe : rien au repos, un fond pale au
   survol. Le meme signal que les cases decomposables, et volontairement pas un
   second : deux marques sur la meme cellule pour deux gestes differents
   feraient chercher laquelle repond a quoi. */
/* LE BOUTON QUI OUVRE L'ÉVOLUTION MENSUELLE, DANS LA CASE.

   « L'apparition du graphique n'est pas évidente et un peu aléatoire »
   (suivi du 10 septembre 2026) : la bulle s'ouvrait d'elle-même après une
   demi-seconde de survol. Elle s'ouvre désormais sur ce bouton-ci.

   Posé en absolu à GAUCHE de la case, où il ne pousse aucun chiffre : les
   nombres sont calés à droite, et un bouton dans le flux aurait décalé toute
   la colonne d'un cran. Effacé au repos et rendu au survol de la case ou dès
   qu'il prend le focus -- quatre cent quatre-vingts icônes visibles en
   permanence feraient une trame par-dessus le tableau, et c'est le tableau
   qu'on vient lire. Il reste atteignable au clavier : c'est justement ce que
   le survol ne donnait pas. */
.synthese-groupe-case.est-tracable { position: relative; }
.synthese-groupe-courbe-btn {
  position: absolute;
  left: var(--espace-3xs);
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1px;
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--gray-4);
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s var(--ease), color .15s var(--ease),
              background .15s var(--ease);
}
.synthese-groupe-courbe-btn .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
}
.synthese-groupe-case.est-tracable:hover .synthese-groupe-courbe-btn,
.synthese-groupe-courbe-btn:focus-visible { opacity: 1; }
.synthese-groupe-courbe-btn:hover {
  background: var(--cyan-pale);
  color: var(--cyan-dark);
}

.synthese-groupe-popover {
  position: absolute;
  z-index: 60;
  min-width: 20em;
  max-width: 28em;
  max-height: 60vh;
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--espace);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}
.synthese-groupe-popover-titre {
  font-weight: 600;
  color: var(--gray-6);
  margin-bottom: var(--espace-sm);
}
.synthese-groupe-popover-liste {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--espace-2xs) var(--espace);
  margin: 0;
}
.synthese-groupe-popover-liste dt {
  color: var(--gray-5);
  white-space: normal;
}
.synthese-groupe-popover-liste dd {
  margin: 0;
  text-align: right;
  color: var(--gray-6);
}
.synthese-groupe-popover-liste dd.est-negatif { color: var(--orange-dark); }

/* LE MONTANT SE DÉPLIE SUR SES COMPTES : « il faudrait que l'on puisse
   déplier le montant et que l'on voie le détail par compte, puis qu'on puisse
   aller jusqu'à l'écriture comme c'est le cas pour le bilan ou le compte de
   résultat » (suivi du 9 septembre 2026).

   La même logique, donc le même dessin : le chevron est celui de l'arbre
   d'analyse (`.row-toggle`, `.arrow`), et chaque compte est une ligne qu'on
   clique. Trois colonnes, le numéro, le libellé et le montant, alignées comme
   dans un grand livre -- c'est ce qu'on vient y lire.

   La liste est EXHAUSTIVE depuis le 9 septembre 2026 (« il faut être
   exhaustif, ne pas mettre 7 comptes de moindre poids ») : elle en porte donc
   parfois mille, et c'est elle qui défile, dans sa propre hauteur, plutôt que
   de pousser le total de l'infobulle hors de l'écran. */
.synthese-groupe-popover-toggle {
  margin-right: var(--espace-3xs);
  vertical-align: middle;
}
.synthese-groupe-popover-comptes {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--espace-3xs) var(--espace-2xs);
  margin-top: var(--espace-3xs);
  max-height: 16em;
  overflow-y: auto;
  font-size: var(--fs-3xs);
  font-variant-numeric: tabular-nums;
}
/* Une ligne de compte est un bouton depuis qu'elle ouvre le grand livre dans
   la page au lieu d'un onglet neuf : il faut donc lui retirer ce qu'un
   navigateur pose sur un bouton (fond, bordure, police, centrage) pour
   qu'elle reste la ligne de tableau qu'elle était. */
.synthese-groupe-popover-compte {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: baseline;
  gap: inherit;
  width: 100%;
  background: none;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  color: var(--gray-5);
  text-decoration: none;
  border-radius: var(--radius-xs);
  padding: 1px var(--espace-3xs);
}
.synthese-groupe-popover-compte:hover {
  background: var(--cyan-pale);
  color: var(--gray-6);
}
.synthese-groupe-popover-compte-num { color: var(--cyan-dark); }
.synthese-groupe-popover-compte-lib {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.synthese-groupe-popover-compte-val { text-align: right; }
.synthese-groupe-popover-compte-val.est-negatif { color: var(--orange-dark); }
.synthese-groupe-popover-total {
  display: flex;
  justify-content: space-between;
  gap: var(--espace);
  margin-top: var(--espace-sm);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-3);
  font-weight: 600;
  color: var(--gray-6);
}
.synthese-groupe-popover-total .est-negatif { color: var(--orange-dark); }
.synthese-groupe-popover-note {
  margin: var(--espace-sm) 0 0;
  font-size: var(--fs-3xs);
  color: var(--gray-4);
}

.synthese-groupe-vide {
  padding: var(--espace-lg);
  text-align: center;
  color: var(--gray-4);
}

/* Le rapprochement des comptes reciproques, sous le tableau de synthese
   (ticket du 10 septembre 2026, voir reciprocites_groupe.py). Un bloc et non un
   second panneau : c'est une lecture du meme groupe, et elle se lit a la suite
   de ce qu'on regardait. */
.synthese-groupe-reciproques-bloc {
  margin-top: var(--espace-lg);
  padding-top: var(--espace);
  border-top: 1px solid var(--gray-3);
}

.synthese-groupe-reciproques-titre {
  margin: 0 0 var(--espace-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

/* Ce que le rapprochement n'a pas pu regarder : une structure sans exercice sur
   l'annee demandee explique un ecart, et se taire ferait lire un solde non
   rapproche comme une anomalie. */
.synthese-groupe-reciproques-note {
  margin: 0 0 var(--espace-sm);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

/* Le tableau defile pour son compte : trois colonnes de montants et une de noms
   ne se compriment pas, et le panneau est deja etroit sous la synthese. */
.synthese-groupe-reciproques-cadre { overflow-x: auto; }

.synthese-groupe-reciproques-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.synthese-groupe-reciproques-table th,
.synthese-groupe-reciproques-table td {
  padding: var(--espace-2xs) var(--espace);
  border-bottom: 1px solid var(--gray-2);
  text-align: left;
  vertical-align: top;
}

.synthese-groupe-reciproques-table th {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-5);
  text-transform: uppercase;
}

.synthese-groupe-reciproques-table th.num,
.synthese-groupe-reciproques-table td.num { text-align: right; }

.synthese-groupe-reciproques-paire { font-weight: 600; }

.synthese-groupe-reciproques-solde {
  font-weight: 600;
  white-space: nowrap;
}

/* Les comptes qui composent un solde, sous lui : ils sont deux ou trois, et
   c'est precisement ce qu'on veut voir quand un ecart parait -- lequel des
   comptes n'a pas de pendant en face. */
.synthese-groupe-reciproques-compte {
  display: flex;
  gap: var(--espace-sm);
  justify-content: space-between;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  text-align: left;
}

.synthese-groupe-reciproques-compte-montant { white-space: nowrap; }

.synthese-groupe-reciproques-ecart { font-weight: 700; white-space: nowrap; }

/* Rapproche ou non : c'est la seule chose qu'on cherche en parcourant la
   colonne, et une teinte se lit plus vite qu'un montant. */
.synthese-groupe-reciproques-table tr[data-rapproche="0"] .synthese-groupe-reciproques-ecart {
  color: var(--red);
}
.synthese-groupe-reciproques-table tr[data-rapproche="1"] .synthese-groupe-reciproques-ecart {
  color: var(--green);
  font-weight: 600;
}

.synthese-groupe-reciproques-vide {
  color: var(--gray-5);
  font-size: var(--fs-xs);
}

.synthese-groupe-notes {
  margin-top: var(--espace);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.synthese-groupe-notes summary { cursor: pointer; color: var(--gray-5); }
.synthese-groupe-notes ul { margin: var(--espace-sm) 0 0; padding-left: var(--espace-lg); }
.synthese-groupe-notes li { margin-bottom: var(--espace-2xs); line-height: 1.5; }

/* Le titre pousse les deux boutons ensemble a droite : « Relire le rapport »
   et « Fermer » sont deux gestes sur la meme fiche, ils se tiennent cote a
   cote. Sans cela le premier flottait au milieu de la barre. */
.synthese-groupe-fiche-titre { margin: 0; margin-right: auto; }

.synthese-groupe-fiche-champs {
  display: flex;
  flex-direction: column;
  gap: var(--espace);
}
.synthese-groupe-fiche-champ label {
  display: block;
  margin-bottom: var(--espace-2xs);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-6);
}
.synthese-groupe-fiche-champ textarea,
.synthese-groupe-fiche-champ .synthese-groupe-fiche-segment {
  width: 100%;
  font: inherit;
  font-size: var(--fs-xs);
  line-height: 1.5;
  padding: var(--espace-sm);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  resize: vertical;
}
.synthese-groupe-fiche-champ .synthese-groupe-fiche-segment { max-width: 16em; }

/* ==========================================================================
   LES ÉTATS FINANCIERS OUVERTS DEPUIS LA SYNTHÈSE D'UN GROUPE

   « Sous chaque colonne (Total et chaque structure), ajouter les boutons
   Bilan, Compte de résultat, Annexe et États financiers [...] présenter le
   bilan, le compte de résultat, l'annexe et les états financiers avec une mise
   en page très soignée, identique à un rendu PDF imprimable » (ticket du
   10 septembre 2026).

   Deux objets ici : la rangée de boutons sous une tête de colonne, et la
   feuille qui s'ouvre par-dessus le tableau.
   ========================================================================== */

/* LA RANGÉE DES DOCUMENTS, EN PIED DE TABLEAU.

   « Les boutons Bilan, Compte de résultat, Annexe et États financiers
   devraient peut-être se trouver sous les colonnes plutôt que dans le titre.
   Essaie de faire quelque chose de plus élégant » (suivi du 10 septembre
   2026). Quatre libellés entassés dans une tête de colonne large de deux
   sous-colonnes revenaient à la ligne comme ils pouvaient, et la rangée des
   noms se lisait en escalier. Un `tfoot` leur donne une rangée à eux, de même
   hauteur d'un bout à l'autre du tableau. */
.synthese-groupe-table tfoot .synthese-groupe-documents-case {
  padding: var(--espace-2xs) var(--espace-sm);
  border-top: 2px solid var(--gray-3);
  border-left: 2px solid var(--gray-3);
  text-align: center;
  background: #fff;
}
.synthese-groupe-table tfoot .synthese-groupe-documents-case.est-total {
  background: var(--gray-1);
}
.synthese-groupe-table tfoot th.synthese-groupe-mesure {
  border-top: 2px solid var(--gray-3);
  color: var(--gray-5);
}
/* Un bouton par colonne, et un seul : voir `boutonEtats`. Discret au repos --
   une rangée de quarante-quatre boutons pleins se lirait comme une barre
   d'outils posée en travers du tableau --, franc au survol. */
.synthese-groupe-doc-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--espace-3xs);
  border: 1px solid var(--gray-3);
  border-radius: 999px;
  background: #fff;
  color: var(--gray-5);
  font-family: inherit;
  font-size: var(--fs-3xs);
  font-weight: 500;
  line-height: 1.2;
  padding: var(--espace-3xs) var(--espace-xs);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease),
              border-color .15s var(--ease);
}
.synthese-groupe-doc-btn .icon { width: 1em; height: 1em; }
.synthese-groupe-doc-btn:hover {
  background: var(--cyan-pale);
  color: var(--cyan-dark);
  border-color: var(--cyan);
}

/* LA FEUILLE. Elle se pose par-dessus la synthèse comme le grand livre d'un
   compte, et pour la même raison : on revient au tableau en la fermant. Le
   voile est celui des fenêtres du produit ; ce qu'elle porte, en revanche, est
   une page et non un panneau -- fond blanc, larges marges, un seul filet par
   ligne de total. C'est ce que « identique à un rendu PDF imprimable »
   demande, et c'est aussi ce qui sort de l'imprimante : voir `@media print`
   plus bas. */
.etats-groupe-feuille {
  /* Les quatre teintes du document, celles que le PDF pose. Écrites ici en
     repli du produit : `poserLaCharteDuDocument` les remplace par celles du
     client quand le groupe a une charte, exactement comme
     `export_pdf.teintes_du_mandat` le fait sur le papier. */
  --doc-bande: var(--cyan-light);
  --doc-rubrique: var(--cyan-pale);
  --doc-total: var(--cyan-total);
  --doc-encre: var(--black);
  background: var(--gray-1);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  /* Assez large pour porter la page en paysage du bilan Francas sans la
     rogner : c'est la plus large des trois de la liasse. */
  width: min(100%, 80rem);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* La barre d'outils, hors de la page : elle ne s'imprime pas, et elle ne fait
   donc pas partie du document. Deux gestes seulement, alignés à droite. */
.etats-groupe-barre {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espace-2xs);
  padding: var(--espace-2xs) var(--espace-md);
  border-bottom: 1px solid var(--gray-2);
  background: #fff;
}

/* L'ASSISTANT NE SE POSE PAS SUR UN DOCUMENT.

   « Aucun bouton (du type Complet ou Synthétique) ne doit apparaître ni
   assistant » (suivi du 10 septembre 2026). Le rond de « Suggérer une
   modification » est fixé au coin de la fenêtre, donc au-dessus du voile : il
   restait posé sur la page du bilan, à l'endroit même où le PDF n'a rien. Une
   règle plutôt qu'un geste en JavaScript : la feuille est dans la page ou elle
   n'y est pas, et le rond suit sans que personne ait à le refermer. */
body:has(.etats-groupe-voile) .ticket-widget { display: none; }

.etats-groupe-corps {
  overflow: auto;
  padding: var(--espace-lg);
}

/* LA PAGE. Elle est dessinée comme la feuille qui sort de l'imprimante : fond
   blanc posé sur le gris de la fenêtre, marges larges, le logo du client en
   haut à gauche et son nom centré en pied sous un filet -- c'est le PDF d'une
   structure, trait pour trait (voir `export_pdf._Document`). */
.etats-groupe-page {
  background: #fff;
  border: 1px solid var(--gray-2);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm, none);
  padding: var(--espace-2xl);
  margin: 0 auto;
  max-width: 52rem;
  display: flex;
  flex-direction: column;
}
/* La page du bilan Francas s'imprime en paysage : elle porte l'actif et le
   passif côte à côte et se lit donc plus large que les deux autres. */
.etats-groupe-page.est-paysage { max-width: 74rem; }
.etats-groupe-page + .etats-groupe-page { margin-top: var(--espace-lg); }
/* L'en-tête ne porte QUE le logo. Le PDF n'y met rien d'autre : ni titre de
   liasse, ni périmètre, ni ligne d'exercices (suivi du 10 septembre 2026). Sa
   hauteur est celle du logo, et elle reste la même sans logo pour que les
   trois pages d'une liasse commencent à la même ligne. */
.etats-groupe-page-tete {
  display: flex;
  align-items: flex-start;
  min-height: 3.6rem;
}
.etats-groupe-page-logo {
  max-height: 3.6rem;
  max-width: 14rem;
  object-fit: contain;
}
/* Le nom du document, centré et en noir, comme le PDF le titre. L'encre de la
   charte est celle du pied, pas celle du titre : c'est le nom du client qui
   porte la couleur de la maison, pas le mot « BILAN ». */
.etats-groupe-titre {
  margin: var(--espace-xs) 0 var(--espace-lg);
  font-size: var(--fs-h2);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  text-align: center;
  color: var(--black);
}
.etats-groupe-page-corps { flex: 1; }
.etats-groupe-page-pied {
  margin-top: var(--espace-2xl);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--doc-bande);
  text-align: center;
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--doc-encre);
}

/* LA BASCULE SYNTHÉTIQUE / DÉTAILLÉE AVAIT SA RÈGLE ICI.

   « Ailleurs, supprime les boutons synthétiques et détaillés » (suivi du
   14 septembre 2026). Elle poussait Imprimer et la croix vers la droite d'un
   `margin-right: auto` ; la barre les y met déjà toute seule
   (`justify-content: flex-end`), et il ne reste donc rien à poser. */
.etats-groupe-imprimer { margin-left: var(--espace-2xs); }
.etats-groupe-document + .etats-groupe-document { margin-top: var(--espace-2xl); }

/* Le bilan du modèle Francas : deux feuilles côte à côte, comme sa page en
   paysage. Elles se remettent l'une sous l'autre dès que la fenêtre ne les
   porte plus : deux colonnes de chiffres écrasées ne se lisent pas. Collées
   l'une à l'autre, sans gouttière : sur le papier elles partagent leur filet
   médian, et c'est cette page-là qu'il faut retrouver. */
.etats-groupe-document.est-cote-a-cote {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--espace-xl);
}
.etats-groupe-document.est-cote-a-cote .etats-groupe-cadre + .etats-groupe-cadre {
  margin-top: 0;
}
@media (min-width: 62rem) {
  .etats-groupe-document.est-cote-a-cote {
    grid-template-columns: 1fr 1fr;
    gap: 0;
    /* Les deux grilles ne demandent pas la même largeur -- l'actif porte trois
       colonnes de chiffres par exercice détaillé, le passif une seule -- et
       `alignerLesDeuxCotes` leur donne exactement ce qu'elles demandent, en
       pixels. Le bloc est alors plus étroit que la page : il se centre, comme
       le tableau d'un document imprimé. */
    justify-content: center;
  }
  /* LE FILET MÉDIAN SE DESSINE, IL NE SE DEVINE PAS.

     « Il me manque le trait de séparation vertical entre l'actif et le passif
     du bilan » (suivi du 13 septembre 2026). Le passif partait `border-left:
     0`, pour que les deux feuilles collées ne fassent pas un filet de deux
     pixels : c'était compter sur le filet droit de l'actif, qui passe dessous
     -- les deux tableaux se chevauchent d'un pixel et les cases du passif,
     peintes après, l'effaçaient. Le bilan se lisait donc comme un seul bloc de
     vingt et une lignes traversant la page.

     C'est le passif qui le porte, et lui seul : peint en dernier, il est
     toujours celui qu'on voit, alors que le filet de l'actif est toujours celui
     qu'on recouvre. Le filet droit de l'actif reste sous lui, à la même
     abscisse : un seul trait, comme sur le papier. */
  .etats-groupe-document.est-cote-a-cote
    > .etats-groupe-cadre + .etats-groupe-cadre .etats-groupe-table {
    border-left: 1px solid var(--gray-4);
  }
  /* ET LE CADRE NE COUPE PLUS LE FILET QU'IL PORTE.

     « Il manque le trait vertical tout à droite à la fin du passif » (suivi du
     14 septembre 2026). Les bords fusionnés peignent la moitié du filet du
     pourtour HORS de la boîte du tableau : un cadre en `overflow-x: auto`
     coupait donc ce demi-pixel, à droite du passif comme ailleurs, et c'est là
     que ça se voit puisque c'est le seul des quatre bords qui n'a rien
     derrière lui.

     La barre de défilement n'a rien à faire ici de toute façon : `mettreAuFormat`
     met les deux grilles à la mesure de la page, réduisant lettres et colonnes
     ensemble jusqu'à ce qu'elles y tiennent. Il n'y a jamais rien à faire
     défiler, et donc rien à couper. Le repli sous 62rem, lui, garde son cadre :
     là, les deux feuilles se remettent l'une sous l'autre et un bilan à six
     exercices peut demander plus que l'écran. */
  .etats-groupe-document.est-cote-a-cote > .etats-groupe-cadre {
    overflow: visible;
  }
}

/* LES DEUX CÔTÉS DU BILAN, MIS À LA MÊME MESURE.

   « Les rubriques à l'actif ont des renvois à la ligne, ce qui crée un décalage
   entre l'actif et le passif [...] Il faut que les colonnes de chiffres du
   passif soient de la même largeur que chaque colonne de chiffres de l'actif
   (brut, net, etc.) » (ticket du 12 septembre 2026).

   Les trois valeurs sont posées par le script, qui les mesure sur le document
   dessiné : la taille des lettres, la largeur d'une colonne d'intitulés, celle
   d'une colonne de chiffres. Les replis ci-dessous ne servent qu'au temps d'un
   rendu, avant la mesure. */
.etats-groupe-document.est-cote-a-cote .etats-groupe-table {
  table-layout: fixed;
}
.etats-groupe-document.est-cote-a-cote col.etats-col-libelle {
  width: var(--etats-col-libelle);
}
.etats-groupe-document.est-cote-a-cote col.etats-col-chiffre {
  width: var(--etats-col-chiffre);
}
/* Un intitulé ne se replie pas : la police est mesurée pour qu'il tienne, ce
   qui est le sens même de « ajuster la taille de police à la taille des
   cellules ». Une ligne de document comptable écrite sur deux hauteurs n'est
   plus la ligne du PDF. */
.etats-groupe-document .etats-groupe-libelle,
.etats-groupe-document .etats-groupe-rubrique td { white-space: nowrap; }
/* Le détail déplié sous un poste, lui, se replie : le nom d'une structure
   (« FRANCAS UR BOURGOGNE FRANCHE COMTE ») ou l'intitulé d'un compte est bien
   plus long qu'un poste du PCG, et il n'a pas à fixer la largeur du document.
   Il est d'ailleurs hors de la mesure (voir `mesurerUnTableau`) : ouvrir une
   rubrique en vue détaillée ne rétrécit pas la page. */
.etats-groupe-document .etats-groupe-part .etats-groupe-libelle,
.etats-groupe-document .etats-groupe-compte .etats-groupe-libelle,
.etats-groupe-document .etats-groupe-attente td { white-space: normal; }
/* Le temps de la mesure, les tableaux reprennent leur largeur naturelle :
   c'est elle qu'on relève, et non celle qu'une mise en page déjà contrainte
   leur laissait. */
.etats-groupe-document.est-en-mesure .etats-groupe-table {
  table-layout: auto;
  width: max-content;
  font-size: var(--fs-sm);
}
.etats-groupe-document.est-en-mesure col.etats-col-libelle,
.etats-groupe-document.est-en-mesure col.etats-col-chiffre { width: auto; }
.etats-groupe-cadre { overflow-x: auto; }
.etats-groupe-cadre + .etats-groupe-cadre { margin-top: var(--espace-xl); }

/* LA GRILLE DU PDF, ET NON UN TABLEAU DE PAGE WEB.

   « Les états financiers doivent scrupuleusement respecter ce format, à
   l'identique » (suivi du 10 septembre 2026). Le document imprimé est une
   grille : un filet autour du tableau, un filet entre chaque colonne sur toute
   la hauteur, et pas de filet entre deux postes -- ce qui coupe
   horizontalement, ce sont les bandes de rubrique et les totaux. Un tableau
   ligné poste par poste se lirait comme un relevé ; c'est un document
   comptable. */
.etats-groupe-table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--gray-4);
  /* « Ajuster automatiquement la taille de police à la taille des cellules
     pour le tableau uniquement » (ticket du 12 septembre 2026) : la mesure est
     posée sur la table par `mettreAuFormat`, et sur elle seule -- le titre du
     document, la note sous la grille et le pied de page gardent la leur, ce
     sont eux qui donnent l'échelle de la page. */
  font-size: var(--etats-fs);
  font-variant-numeric: tabular-nums;
}
.etats-groupe-table th,
.etats-groupe-table td {
  padding: var(--espace-2xs) var(--espace-sm);
  vertical-align: top;
  border-left: 1px solid var(--gray-4);
}
.etats-groupe-table th:first-child,
.etats-groupe-table td:first-child { border-left: 0; }
/* Une bande de rubrique traverse la grille : elle n'a pas de colonnes, et les
   filets verticaux ne la coupent donc pas. */
.etats-groupe-table tr.etats-groupe-rubrique td { border-left: 0; }
/* LA BANDE DE TITRES, ET LES TROIS FONDS DU PDF.

   « L'affichage doit reprendre le format utilisé lors de l'export en PDF depuis
   une structure Francas » (suivi du 10 septembre 2026). Ce PDF pose trois fonds
   et une encre : une bande derrière le titre d'une section, un fond pâle sur
   l'intitulé d'une rubrique, un fond plus soutenu sur un sous-total -- c'est le
   chiffre qui conclut un bloc qui doit se voir en premier, pas l'intitulé qui
   l'ouvre (demande du 26 août 2026). Les trois viennent de la charte du client
   quand il en a une, et des cyans du produit sinon. */
.etats-groupe-table thead th {
  background: var(--doc-bande, var(--cyan-light));
  border-bottom: 1px solid var(--gray-4);
  font-weight: 700;
  color: var(--gray-6);
  text-align: right;
  white-space: nowrap;
}
/* « ACTIF », « PASSIF » : la case de coin, centrée sur les deux rangs de
   l'en-tête comme celle du PDF. Elle nomme le côté du bilan, elle ne titre pas
   une colonne de chiffres. */
.etats-groupe-table th.etats-groupe-col-poste {
  text-align: center;
  vertical-align: middle;
  width: 45%;
  /* En `em` et non en jeton : la taille du tableau se mesure (voir
     `--etats-fs`), et une taille fixe posee ici serait restee grande pendant
     que la grille se reduisait -- « Amort. et depreciations » se serait ecrit
     par-dessus la colonne d'a cote. Le rapport au corps du tableau, lui, ne
     change pas : c'est celui de --fs-md a --fs-sm. */
  font-size: 1.125em;
  text-transform: uppercase;
  letter-spacing: .03em;
}
.etats-groupe-table thead tr.etats-groupe-sous-titres th {
  border-top: 1px solid var(--gray-4);
  /* En `em`, pour la meme raison que la case de coin : le rapport de --fs-2xs
     a --fs-sm, suivi quelle que soit la taille mesuree du tableau. */
  font-size: .85em;
  font-weight: 700;
  color: var(--gray-6);
}
/* Le rang de sous-titres du passif est vide : ses cases sont celles du rang du
   dessus, montées d'un cran. Sa hauteur ne se calcule pas ici : une hauteur
   posée en CSS passait sous celle que les cases à cheval imposent déjà, et ne
   servait donc à rien -- l'en-tête du passif mesurait 30,6 px quand celui de
   l'actif en faisait 53,5, et les deux grilles ne démarraient pas à la même
   ligne. C'est `alignerLesTraits` (synthese-groupe.js) qui la mesure et la
   pose, avec le pas des lignes du document. */
/* La date de clôture est centrée au-dessus de ses trois colonnes, les
   sous-titres restent alignés sur les chiffres qu'ils nomment. */
.etats-groupe-table th.etats-groupe-col-exercice[colspan] { text-align: center; }
.etats-groupe-table td.num { text-align: right; white-space: nowrap; }
.etats-groupe-libelle { text-align: left; }

/* L'intitulé d'une rubrique du PCG annonce les postes qui suivent : ce n'est
   pas un total, il ne porte donc aucun chiffre et se distingue par la casse.
   Sur le papier c'est une bande qui traverse la page, filet au-dessus et
   filet au-dessous. */
.etats-groupe-rubrique td {
  background: var(--doc-rubrique, var(--cyan-pale));
  border-top: 1px solid var(--gray-4);
  border-bottom: 1px solid var(--gray-4);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--black);
}
.etats-groupe-poste td { color: var(--gray-6); }
/* Une ligne « dont » : elle détaille celle du dessus et n'entre dans aucun
   total. Écrite autrement pour qu'on ne l'additionne pas de l'œil non plus. */
.etats-groupe-informatif td {
  font-style: italic;
  color: var(--gray-5);
}
.etats-groupe-total td {
  background: var(--doc-total, var(--cyan-total));
  border-top: 1px solid var(--gray-4);
  font-weight: 700;
}
/* Le résultat de l'exercice n'a plus de ligne à lui (`.etats-groupe-resultat`,
   partie le 10 septembre 2026). Le PDF ne le distingue pas : au bilan c'est un
   poste des fonds propres, au compte de résultat un total comme le résultat
   courant. Un filet de plus, posé sur la seule ligne qu'on cherche du regard,
   était une aide de lecture -- et une aide de lecture ajoutée au document
   n'est plus le document. */

/* Les deux crans du dépliement, décalés l'un sous l'autre : une structure sous
   un poste, un compte sous une structure. Le retrait dit le rang, comme dans
   l'arbre d'analyse. */
.etats-groupe-part td { background: var(--gray-1); font-size: var(--fs-xs); }
.etats-groupe-part .etats-groupe-libelle { padding-left: var(--espace-lg); }
.etats-groupe-compte td {
  background: var(--gray-1);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.etats-groupe-compte .etats-groupe-libelle { padding-left: var(--espace-2xl); }
/* Un intitulé de compte est un intitulé : il se lit de gauche à droite comme
   les postes au-dessus de lui, même quand il tient sur deux lignes. Le bouton
   de lien centrait son texte, ce qui ne se voyait pas tant qu'on n'ouvrait
   qu'un poste à la fois -- la vue détaillée en montre cent soixante-dix. */
.etats-groupe-compte-lien { font-size: var(--fs-xs); text-align: left; }
.etats-groupe-attente td {
  background: var(--gray-1);
  font-size: var(--fs-xs);
  color: var(--gray-5);
  padding-left: var(--espace-lg);
}

.etats-groupe-note {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  line-height: 1.6;
}
.etats-groupe-note.est-erreur { color: var(--orange-dark); }
.etats-groupe-notes {
  margin-top: var(--espace-md);
  padding-top: var(--espace-sm);
  border-top: 1px solid var(--gray-2);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
.etats-groupe-notes p { margin: 0 0 var(--espace-2xs); line-height: 1.5; }
/* L'ANNEXE, DANS LA FEUILLE DU DOCUMENT

   « Pour une structure, l'annexe doit apparaître dans la synthèse lorsque l'on
   clique sur le bouton correspondant » (suivi du 10 septembre 2026). Elle
   menait à l'onglet du mandat, par une liste de liens (`.etats-groupe-annexes`,
   partie avec eux).

   Elle se pose sur la même page que le bilan et le compte de résultat, et elle
   en reprend donc les cadres et les tableaux : ce sont les mêmes classes
   (`.etats-groupe-cadre`, `.etats-groupe-table`). Ce qui lui est propre est ce
   qu'un bilan n'a pas -- des titres de section, des paragraphes, des renvois
   sous les tableaux. */
/* « I - Faits caractéristiques de l'exercice » : sur le papier, une bande pâle
   qui traverse la page, le titre en gras dedans. C'est ce qui découpe l'annexe
   et ce qu'on suit du pouce en la feuilletant. */
.etats-groupe-annexe-section {
  margin: var(--espace-lg) 0 var(--espace-sm);
  padding: var(--espace-2xs) var(--espace-sm);
  background: var(--doc-rubrique, var(--cyan-pale));
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--black);
}

/* La case de coin d'un tableau d'annexe nomme ce que la colonne énumère
   (« Valeurs brutes », « Amortissements ») : c'est un intitulé, pas un
   montant, et il s'aligne à gauche comme sur le papier. */
.etats-groupe-annexe-table thead th:first-child { text-align: left; }

.etats-groupe-annexe-note { margin-bottom: var(--espace-md); }

/* Un bloc « suite » prolonge la note du dessus sans numéro ni titre : il se
   colle à elle, sinon la grille qu'ils partagent ne se lit plus comme une. */
.etats-groupe-annexe-note-suite { margin-top: calc(-1 * var(--espace-sm)); }

.etats-groupe-annexe-note-titre {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--black);
}

.etats-groupe-annexe-paragraphe {
  margin: 0 0 var(--espace-2xs);
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--gray-6);
  text-align: justify;
}

.etats-groupe-annexe-note-de-bas {
  margin: var(--espace-2xs) 0 0;
  font-size: var(--fs-2xs);
  color: var(--gray-5);
}

/* Ce qu'on n'a pas su préremplir, en tête du document : une liste de courses,
   pas une note de bas de page. Même encadré que dans l'annexe du mandat
   (`.annexe-manques`), et la même raison -- une annexe à demi remplie sans
   qu'on sache ce qui manque se relit en cherchant ce qu'on aurait oublié. */
.etats-groupe-annexe-manques {
  margin: 0 0 var(--espace-md);
  padding: var(--espace-sm) var(--espace-md);
  border-left: 3px solid var(--orange);
  border-radius: var(--radius-xs);
  background: var(--orange-pale);
  font-size: var(--fs-xs);
  color: var(--gray-6);
}

.etats-groupe-annexe-manques-titre {
  margin: 0 0 var(--espace-2xs);
  font-weight: 600;
}

.etats-groupe-annexe-manques ul {
  margin: 0;
  padding-left: var(--espace-md);
}

/* La bascule COMPLET / SYNTHÉTIQUE, dans la barre du panneau. Elle est une
   commande et non une partie du document : elle ne s'imprime pas, comme le
   bouton « Imprimer » à côté d'elle (voir `@media print` plus bas). */

/* CE QUI SORT DE L'IMPRIMANTE, c'est la feuille et rien d'autre. « Une mise en
   page très soignée, identique à un rendu PDF imprimable » : le document est
   déjà dessiné comme une page, il ne reste qu'à retirer ce qui est autour --
   la synthèse dessous, le voile, la barre du produit -- et à rendre à la
   feuille sa pleine largeur, sans ombre ni arrondi qu'aucune imprimante ne
   sait poser. */
@media print {
  body:has(.etats-groupe-voile) > *:not(.etats-groupe-voile) { display: none !important; }
  .etats-groupe-voile {
    position: static;
    display: block;
    background: none;
    padding: 0;
  }
  .etats-groupe-feuille {
    width: 100%;
    max-height: none;
    border-radius: 0;
    box-shadow: none;
    background: none;
    display: block;
  }
  /* La barre d'outils ne s'imprime pas : ce sont deux gestes de l'écran, pas
     une partie du document. La page, elle, s'imprime telle quelle -- sans son
     cadre ni son ombre, qu'aucune imprimante ne sait poser. */
  .etats-groupe-barre { display: none; }
  .etats-groupe-corps { overflow: visible; padding: 0; }
  .etats-groupe-page {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
    max-width: none;
  }
  /* Un document par page, comme la liasse exportée : le compte de résultat ne
     commence pas sous le dernier total du bilan. */
  .etats-groupe-page + .etats-groupe-page { break-before: page; margin-top: 0; }
  /* Le logo en tête et le nom en pied se répètent sur chaque page du PDF ;
     le navigateur ne sait pas les répéter, mais il sait au moins ne pas les
     couper en deux. */
  .etats-groupe-page-tete,
  .etats-groupe-page-pied { break-inside: avoid; }
  .etats-groupe-document { break-inside: auto; }
  .etats-groupe-table tr { break-inside: avoid; }
  /* Les fonds du document sont sa mise en page, pas une décoration : sans eux
     un sous-total ne se distingue plus d'un poste sur le papier. */
  .etats-groupe-page * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* UNE SEULE STRUCTURE : LE TABLEAU PREND LA HAUTEUR, PAS LA LARGEUR.

   « Lorsqu'une seule structure est affichée, optimiser la taille du tableau
   pour exploiter au maximum la hauteur disponible, sans l'étirer excessivement
   en largeur et en conservant des proportions esthétiques » (ticket du
   10 septembre 2026).

   Le cadre est borné à 70 % de la fenêtre parce qu'il y a quarante-trois
   colonnes à faire défiler derrière : le fond de page reste visible, on sait
   qu'on est dans une page. Avec une seule structure il n'y a plus rien à faire
   défiler horizontalement, et dix-huit lignes tenaient dans un cadre qui en
   laissait la moitié vide sous elles. Le cadre prend donc la hauteur, et
   `width: max-content` l'empêche d'étirer trois colonnes sur deux mètres
   d'écran -- c'est la règle que la page de projection s'était déjà écrite pour
   la même raison. */
.synthese-groupe-cadre.est-seule {
  /* Une hauteur ferme, et non un plafond : c'est elle que le tableau va
     remplir juste en dessous. Un plafond laissait le cadre épouser ses
     dix-huit rangées, et la question ne se posait donc jamais. */
  height: calc(100vh - 16rem);
  width: max-content;
  /* « Lorsqu'on clique sur une structure, l'affichage agrandi doit être plus
     harmonieux : conserver toute la hauteur disponible et augmenter légèrement
     la largeur » (suivi du 10 septembre 2026).

     UN PLANCHER, ET NON UN ÉTIREMENT. `width: max-content` répondait à la
     première demande -- « sans l'étirer excessivement en largeur » -- en serrant
     le tableau sur son contenu ; trois colonnes serrées à côté d'une hauteur
     d'écran entier font une bande, et c'est cette bande que le suivi trouve
     inharmonieuse. Le plancher lui donne une largeur de document sans jamais le
     laisser courir sur un écran de deux mètres : `min()` le rend d'abord à la
     largeur disponible dès que la fenêtre est plus étroite que lui. */
  min-width: min(100%, 54rem);
  max-width: 100%;
}

/* « Lorsque je clique sur le titre d'une structure, tu affiches uniquement
   cette structure. Il faut alors optimiser la taille du tableau afin
   d'exploiter au maximum la hauteur disponible » (suivi du 10 septembre 2026).

   Le cadre prenait la hauteur, le tableau non : dix-huit rangées de 1,6 rem
   laissaient la moitié du cadre vide sous elles. `height: 100%` sur le tableau
   distribue la place restante entre ses rangées, à proportion de ce que
   chacune mesure déjà -- les rangées respirent, le tableau descend jusqu'en
   bas, et rien n'est étiré de travers. Un cran de police avec, parce qu'une
   colonne unique lue en 0,75 rem sur un écran de deux mètres est illisible ;
   la largeur, elle, ne bouge pas : `width: max-content` sur le cadre l'empêche
   déjà de s'étaler, comme le demande « sans l'étirer excessivement en largeur
   et en conservant des proportions esthétiques ». */
.synthese-groupe-cadre.est-seule .synthese-groupe-table {
  height: 100%;
  /* Et la largeur du cadre, désormais : sans elle le tableau resterait serré
     sur son contenu au milieu d'un cadre plus large que lui, ce qui déplace la
     bande au lieu de la supprimer. Les colonnes se partagent la place comme les
     rangées se partagent la hauteur juste au-dessus. */
  width: 100%;
  font-size: var(--fs-sm);
}

/* =====================================================================
   LA FACTURATION ET LE RECOUVREMENT (/facturation)

   « Le système doit permettre à chaque titulaire de voir très facilement sa
   facturation et ses impayés, avec un suivi simple, clair et très visuel »
   (ticket du 16 septembre 2026).

   « Très visuel » se joue en deux endroits, et pas ailleurs : la rangée de
   carreaux chiffrés en tête de page, qui répond en une seconde à « où j'en
   suis », et la pastille d'état au bout de chaque ligne, qui dit d'un coup
   d'œil laquelle réclame un geste. Le reste est un tableau, et un tableau de
   factures se lit d'autant mieux qu'il ne se déguise pas.

   Aucune valeur n'est écrite à la main : arrondis, ombres, espaces, tailles et
   teintes sortent des jetons de `:root` (voir la skill design-aiudit).
   ===================================================================== */

/* L'entete, la liste et la vision globale sont des `.tuile` : c'est la forme
   que le produit donne a une zone qui porte un nom (cadre, fond, creux). Ces
   classes-ci ne portent donc que ce qui leur est propre -- la disposition. Et
   la page n'est pas `app-main-pleine` : cette classe-la fait grandir LE panneau
   d'une page qui n'en a qu'un, et quatre blocs s'y seraient partage la hauteur
   de la fenetre, l'entete la premiere, haute de quatre cents pixels pour une
   ligne de texte. */
/* UNE SEULE RANGEE DE BLOCS, LE BLOC DE COMMANDE A GAUCHE. « Il serait bien de
   revoir l'organisation des blocs pour n'avoir qu'une seule ligne de blocs,
   avec le premier bloc place a gauche » (ticket du 18 septembre 2026).

   La barre de tete prenait une rangee entiere pour une liste deroulante, une
   phrase et deux boutons, et les six carreaux chiffres s'alignaient dessous :
   deux rangees pour ce qui se lit d'un seul regard en ouvrant la page.

   Une disposition flexible et non une grille commune : les carreaux ont deja la
   leur, qui se replie toute seule a la largeur d'un telephone, et les mettre
   dans la meme grille que l'entete aurait donne a celle-ci la largeur d'un
   carreau. Le bloc de commande prend donc ce qu'il lui faut, les carreaux
   prennent le reste, et la rangee se replie quand les deux ne tiennent plus
   ensemble. */
.fact-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-lg);
}

/* SA HAUTEUR EST CELLE DE LA RANGEE, DONC ELLE SE COMPTE. « Dans Facturation,
   essaie de reduire la hauteur du premier bloc a gauche. Cela devrait permettre
   de reduire aussi la hauteur des autres blocs et d'avoir un ensemble plus
   compact » (ticket du 18 septembre 2026).

   Trois choses le faisaient haut de cent vingt-sept pixels pour deux rangees de
   commandes : le rembourrage d'une `.tuile`, taille pour une zone qui porte un
   titre et du texte, l'ecart entre les deux rangees, et la marge que la
   vignette du compte a rebours traine depuis son usage flotte (voir
   `.fact-rebours` plus bas). Les trois sont reprises ici, et le bloc tombe a
   cent deux, ce qui est la hauteur des carreaux eux-memes : plus bas, il ne
   ferait plus la rangee et raboter davantage ne gagnerait rien.

   Le rembourrage vertical seul est repris, pas l'horizontal : la largeur du
   bloc est ce qui decide si les six carreaux tiennent sur une rangee a 1280
   pixels, et l'elargir d'un cote comme le retrecir de l'autre deferait la
   rangee unique que le meme ticket venait de demander. */
/* DEUX RANGEES, MAIS UNE SEULE COLONNE DE CHAMPS. « Ajuste la largeur du champ
   "Periode 2024-2025" pour qu'elle soit coherente avec celles des champs "Moi"
   et "Cabinet". Prevois suffisamment d'espace afin de placer la pastille "J-12"
   a droite de la periode, entre les deux champs » (ticket du 18 septembre
   2026).

   Deux rangees de flex ne savaient pas se le dire : la liste des exercices se
   serrait sur « 2025-2026 », le segment des vues sur ses deux mots, et les deux
   commandes l'une sous l'autre finissaient a dix pixels d'ecart -- assez pour
   se voir, pas assez pour passer pour un choix.

   Une grille de deux colonnes les accorde sans qu'aucune largeur ne soit
   ecrite : la premiere colonne prend la plus large des deux commandes et les y
   etire toutes les deux, la seconde porte la vignette du compte a rebours et le
   mot d'etat. La pastille reste donc a droite de la periode, et la place qu'il
   lui faut est celle d'une colonne, pas une marge devinee. Les cases sont
   posees a la main plutot que laissees au remplissage automatique : le segment
   des vues est cache aux non-administrateurs, et un mot d'etat remonte alors
   d'une case. */
.fact-entete {
  display: grid;
  grid-template-columns: max-content max-content;
  /* La rangee du mot d'etat est toujours la, haute d'une ligne meme vide : le
     mot parait et disparait a chaque enregistrement, et une rangee qui
     n'existerait que lorsqu'il est affiche ferait sauter le bloc -- donc les
     six carreaux avec lui, qui s'etirent a sa hauteur. Reservee, elle ne coute
     rien : le bloc retrouve exactement la hauteur qu'il avait quand le mot
     tenait dans la seconde colonne. `minmax` laisse la rangee grandir pour une
     erreur qui se replie sur deux lignes, ce qui est rare et vaut mieux qu'un
     message coupe. */
  grid-template-rows: auto auto minmax(calc(var(--fs-sm) * 1.25), auto);
  align-content: center;
  align-items: center;
  justify-content: start;
  flex: 0 1 auto;
  gap: var(--espace-2xs) var(--espace-sm);
  /* LE REMBOURRAGE DU BAS EST LA RANGEE DU MOT D'ETAT, PAS UN SECOND CREUX.
     « Dans Facturation, reduis legerement la hauteur des blocs en diminuant
     l'espace vide situe en bas, afin d'obtenir un affichage plus compact »
     (ticket du 18 septembre 2026).

     C'est ce bloc qui commande la hauteur de la rangee, les six carreaux s'y
     etirant : ils avaient dix pixels de creux au-dessus de leur titre et
     vingt-quatre sous leur pied, et c'est ce desequilibre qu'on voyait. Les
     vingt-quatre n'etaient pas les leurs, c'etait le surplus de la rangee, et
     le surplus de la rangee etait ici -- la rangee du mot d'etat, reservee et
     vide la plupart du temps, POSEE SUR un rembourrage du bas de meme taille.
     Deux creux superposes au meme endroit pour un seul besoin.

     Le rembourrage du bas part donc : la rangee reservee le remplace exactement
     quand le mot ne s'affiche pas, et le porte quand il s'affiche. Rien ne
     saute pour autant, ce qui etait tout l'objet de la reserve. Celui du haut
     descend d'un barreau pour rester du meme ordre que ce qui lui repond en
     bas. La rangee tombe de cent deux pixels a quatre-vingt-neuf, et les
     carreaux retrouvent a peu pres autant de creux sous leur pied qu'au-dessus
     de leur titre. */
  padding-top: var(--espace-xs);
  padding-bottom: 0;
  margin-bottom: 0;
}

/* Les deux moities n'ont plus de boite a elles : ce sont leurs enfants qui
   entrent dans la grille, sans quoi chaque moitie aurait pris une case entiere
   et rien ne se serait aligne. Elles restent dans le gabarit, ou elles disent
   ce qui va ensemble. */
.fact-entete-gauche,
.fact-entete-droite { display: contents; }

/* LA VIGNETTE EST ENTRE LES DEUX CHAMPS, PAS AU-DESSUS DE L'UN D'EUX. « La
   pastille J-12 est actuellement trop haute et elargit inutilement le bloc.
   Ajuste sa position afin d'obtenir un ensemble compact, equilibre et
   esthetique » (suivi du 18 septembre 2026).

   Posee dans la premiere rangee, elle etait centree sur la liste des exercices
   seule : haute de cinquante-deux pixels contre trente-deux, elle la
   surplombait de dix pixels en haut et s'arretait au milieu du vide qui la
   separe du segment des vues. Elle ne se rapportait donc a aucun des deux
   champs -- « a droite de la periode, ENTRE les deux champs » disait deja le
   ticket precedent, et c'est ce « entre » qui manquait.

   Elle prend les deux rangees et se centre dessus : son milieu est celui du
   couple, et les trois objets forment un bloc au lieu de deux rangees plus une
   piece rapportee. Aucune hauteur n'est ecrite pour autant -- le couple mesure
   soixante et un pixels, la vignette cinquante-deux, c'est le couple qui
   commande et la vignette se loge dedans.

   Le mot d'etat descend d'une rangee, sous les deux colonnes. Il ne coute rien
   en hauteur : le bloc est etire a la hauteur des carreaux de la rangee (voir
   `.fact-tete`, `align-items: stretch`) et gardait une vingtaine de pixels de
   creux sous son contenu -- c'est la que la rangee se pose. Il ne coute rien en
   largeur non plus, tant qu'on le borne : sans cela, « Il faut un client : un
   mandat d'aiudit, ou un nom saisi » se serait ecrit sur une seule ligne et
   aurait pousse le bloc a trois cents pixels, defaisant la rangee unique de
   carreaux que le meme ticket avait demandee. */
.fact-entete .fact-exercice { grid-area: 1 / 1; }
.fact-entete .fact-vues { grid-area: 2 / 1; }

.fact-entete .fact-rebours {
  grid-area: 1 / 2 / 3 / 3;
  align-self: center;
}

/* Sauf quand il n'y a qu'un champ. Le segment des vues est cache aux
   non-administrateurs, et « entre les deux champs » n'a alors plus d'objet :
   la vignette revient dans la rangee de la liste, ou elle se centre sur elle.
   Sans cette reprise, elle continuait de descendre sur une seconde rangee
   vide et pendait dix pixels sous la liste, ce qui est le defaut du ticket
   remis a l'envers. */
.fact-entete:has(.fact-vues[hidden]) .fact-rebours { grid-area: 1 / 2 / 2 / 3; }

.fact-entete .champ-etat {
  grid-area: 3 / 1 / 4 / 3;
  justify-self: start;
  max-width: 13rem;
  line-height: 1.25;
}

/* LA LISTE DES EXERCICES, SERREE SUR CE QU'ELLE ECRIT. « Dans le premier bloc,
   essaie de reduire un peu sa largeur. Pour gagner de la place, la combo box
   des exercices pourrait etre plus compacte » (ticket du 18 septembre 2026).

   `.aglae-input.fact-exercice` ET NON `.fact-exercice` SEUL, et c'est tout le
   sujet : l'habillage des champs s'ecrit `.aglae-input:not([type="checkbox"])`,
   dont la specificite vaut deux classes. La regle qui tenait ici depuis
   l'origine, `.fact-exercice { width: auto; min-width: 6rem; }`, en portait une
   seule : elle ne s'est jamais appliquee, pas une fois, et la liste prenait la
   largeur pleine et la chasse de tous les champs du produit. Rien ne le disait,
   puisqu'une regle perdante ne fait rien echouer. Deux classes suffisent a la
   reprendre, la regle etant de toute facon plus bas dans la feuille.

   Ce qui est repris se limite a la largeur et a ce qui la fait : la chasse
   descend a celle des deux boutons d'a cote, qui sont ses voisins de bloc, le
   champ se serre sur « 2025-2026 » au lieu de s'etaler, et le chevron garde sa
   place reservee pour ne pas venir sur le texte. La hauteur ne bouge pas : elle
   est celle de la vignette, et la rogner ici n'aurait rien rendu. */
.aglae-input.fact-exercice {
  --chevron-taille: var(--icon-sm);
  --chevron-retrait: var(--espace-2xs);
  width: auto;
  font-size: var(--fs-sm);
  padding-left: var(--espace-xs);
  padding-right: var(--chevron-reserve);
}

/* La case de la grille commande desormais la chasse des deux : ce que la liste
   demande pour ecrire « 2025-2026 » reste son plancher, et c'est le segment des
   vues, un peu plus large, qui decide. Les deux segments se partagent la case
   des qu'elle est plus large qu'eux, ce qui arrive sur un ecran etroit : sans
   cela le cadre du segment se serait etire seul et aurait laisse un blanc a
   droite de « Cabinet ». */
.fact-entete .fact-exercice,
.fact-entete .fact-vues { width: 100%; }

.fact-vue { flex: 1; }

/* La vignette prend sa hauteur et rien de plus : posee dans une rangee alignee
   sur le centre, elle s'y etirerait et ses volets se decolleraient de leur
   bandeau. */
.fact-rebours { display: flex; align-items: center; }

/* Et la meme remise a zero que dans les deux autres endroits ou la vignette est
   posee autrement que flottee (`.assistant-constat`, `.arrete-seance`) : la
   regle de base lui donne une marge a droite et en dessous, faite pour un texte
   qui vient s'enrouler autour d'elle. Ici rien ne s'enroule, et ces six pixels
   du bas etaient six pixels de hauteur de bloc que personne ne voyait. */
.fact-rebours .arrete-rebours { float: none; margin: 0; }

/* Les carreaux prennent la place qui reste, et la rendent au bloc de commande
   quand la fenetre se serre : vingt-quatre rem est la largeur en dessous de
   laquelle six carreaux ne valent plus mieux qu'une rangee a eux. Trente
   jusqu'au 22 septembre 2026, quand deux titres disaient encore « Facturation
   prevue » et « Facturation realisee » et qu'un pied ecrivait « HT, d'ici au
   30 septembre » : les carreaux se sont resserres, leur plancher avec. */
.fact-chiffres { flex: 1 1 24rem; }

/* Les deux vues, dessinées comme les autres choix binaires du produit : deux
   segments dans un même cadre, celui qui est actif porte le fond. */
.fact-vues {
  display: inline-flex;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.fact-vue {
  border: 0;
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-sm);
  padding: var(--espace-2xs) var(--espace-sm);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}

.fact-vue.actif { background: var(--cyan); color: #fff; }
.fact-vue:not(.actif):hover { background: var(--gray-1); }

/* Les carreaux chiffrés. Six, sur une grille qui se replie : à la largeur d'un
   téléphone ils passent à deux par ligne plutôt que de rétrécir jusqu'à ce que
   « Facturation réalisée » tienne sur quatre lignes.

   Neuf rem et non dix depuis le 18 septembre 2026, où les six carreaux ont
   rejoint le bloc de commande sur une rangée unique : dix les faisaient
   déborder sur deux lignes dès 1280 pixels, qui est la largeur d'un portable
   ordinaire, et la rangée unique n'aurait tenu que sur les grands écrans. En
   dessous de 1152 elle se replie de toute façon, et c'est bien : six carreaux
   de moins de dix centimètres ne se lisent plus. */
.fact-chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--espace-sm);
}

/* Leur rembourrage descend d'un barreau avec le meme ticket du 18 septembre
   2026, et c'est ce qui fait la seconde moitie du travail : le bloc de commande
   ne decidait pas seul de la hauteur de la rangee, les carreaux valaient deja
   cent vingt-deux pixels a eux tout seuls. Abaisser le premier sans les
   toucher aurait rendu quatre pixels sur cent vingt-sept, et la rangee aurait
   eu l'air aussi haute qu'avant. */
.fact-carreau {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  padding: var(--espace-sm) var(--espace);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

/* « Facturation realisee » et « Reste a recouvrer » passent a deux lignes des
   que la fenetre se serre, et c'est bien : les couper serait pire. Mais deux
   lignes a l'interligne du texte courant ouvrent le carreau de vingt pixels
   pour un titre qui se lit d'un regard, et cet ecart se paie sur les six a la
   fois puisqu'ils partagent la hauteur de la rangee. */
.fact-carreau-titre {
  font-size: var(--fs-xs);
  line-height: 1.25;
  color: var(--gray-5);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.fact-carreau-valeur {
  font-size: var(--fs-h2);
  font-weight: 600;
  color: var(--black);
}

.fact-carreau-pied {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

/* Le retard est le seul carreau qui change de couleur, et seulement quand il
   porte quelque chose : un carreau rouge à zéro euro crie sans raison. */
.fact-carreau[data-alerte="1"] { border-color: var(--red); background: var(--red-pale); }
.fact-carreau[data-alerte="1"] .fact-carreau-valeur { color: var(--red-dark); }

.fact-bloc { margin-bottom: var(--espace-lg); }

.fact-bloc-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-md);
}

.fact-bloc-tete .tuile-titre { margin: 0; margin-right: auto; }

.fact-aide {
  font-size: var(--fs-sm);
  color: var(--gray-5);
  margin: 0 0 var(--espace-sm);
}

.fact-filtres { display: flex; flex-wrap: wrap; gap: var(--espace-2xs); }

.fact-filtre {
  border: 1px solid var(--gray-3);
  background: #fff;
  color: var(--gray-5);
  font-size: var(--fs-xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: 999px;
  cursor: pointer;
}

.fact-filtre.actif { background: var(--cyan-pale); border-color: var(--cyan);
                     color: var(--cyan-dark); }

/* Les mandats que l'Assistant annonce à facturer : une ligne chacun, le
   montant à droite, le geste au bout. */
.fact-attente-ligne {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-xs) 0;
  border-bottom: 1px solid var(--gray-2);
}

.fact-attente-ligne:last-child { border-bottom: 0; }
.fact-attente-nom { font-weight: 600; }
.fact-attente-exercice { font-size: var(--fs-xs); color: var(--gray-4); }
.fact-attente-montant { margin-left: auto; font-variant-numeric: tabular-nums; }

/* LE TABLEAU EST SERRE D'UN CRAN. « Reduire legerement la taille au niveau des
   factures, pour rendre l'ensemble plus compact et plus lisible » (ticket du
   18 septembre 2026).

   Un cran sur l'echelle de texte et un cran sur l'espacement vertical, pas
   davantage : ce registre compte cent quarante lignes, et ce qu'on gagne a les
   voir ensemble se perd des que le nom d'un client demande d'approcher
   l'ecran. Les deux crans pris ensemble rendent une ligne sur huit. */
.fact-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}

.fact-table th {
  text-align: left;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--gray-5);
  padding: var(--espace-2xs) var(--espace-xs);
  border-bottom: 1px solid var(--gray-3);
  white-space: nowrap;
}

/* UNE CELLULE DE REGISTRE TIENT SUR UNE LIGNE, comme son en-tete le fait deja.
   Ce n'etait pas dit tant que le tableau etait large : chaque colonne recevait
   sa part du surplus, et rien ne repliait jamais. Une fois les colonnes
   serrees sur leur contenu (voir la colonne des actions, plus bas), « VC-6127 »
   se coupait en deux lignes et la rangee doublait de hauteur, ce qui est
   exactement le contraire de ce qu'on cherchait. */
.fact-table td {
  padding: var(--espace-2xs) var(--espace-xs);
  border-bottom: 1px solid var(--gray-2);
  vertical-align: middle;
  white-space: nowrap;
}

.fact-table tr:hover td { background: var(--gray-1); }

/* Les colonnes de montants alignées à droite et en chiffres de même chasse :
   deux montants qui ne s'alignent pas ne se comparent pas d'un coup d'œil, et
   c'est tout ce qu'on demande à une colonne de montants. */
.fact-num { text-align: right; font-variant-numeric: tabular-nums; }

/* LA COLONNE DU MONTANT EST TAILLEE POUR SIX CHIFFRES, ET PAS PLUS. « Réduis
   la largeur de la colonne "Montant HT", en prévoyant un montant maximal à six
   chiffres » (ticket du 22 septembre 2026). L'en-tête a d'abord été abrégé en
   « HT » (voir `facturation.js`), sans quoi le titre tenait la colonne à lui
   seul.

   Reste à dire sur quoi elle se règle, et ce n'est pas sur les montants du
   jour : le plus gros de l'exercice fait « 40 750 € », la colonne se serrerait
   dessus, et la première facture à six chiffres décalerait d'un coup les sept
   colonnes qui suivent. Une largeur posée ici évite ce saut : c'est
   « 999 999 € » qui la donne, soit le plafond que le ticket demande de prévoir.
   Un montant plus gros élargirait la colonne plutôt que de se couper, comme
   toute largeur sur une cellule de tableau. */
.fact-table th.fact-montant,
.fact-table td.fact-montant { width: 9ch; }

.fact-table td[data-alerte="1"] { color: var(--red-dark); font-weight: 600; }

/* MES PRIMES, SOUS « MON COMPTE » (suivi du 18 septembre 2026). Le suivi des
   primes vivait en tete de Facturation, en tableau a deux colonnes par type ;
   il est ici, une ligne par prime, parce qu'il n'y a plus qu'une personne a
   lire -- celle qui ouvre la page.

   Tous les nombres a droite et en chiffres de meme chasse, comme partout ou ce
   produit aligne des montants : deux montants qui ne s'alignent pas ne se
   comparent pas d'un coup d'oeil. */
/* PLUS COMPACT ET PLUS SOBRE (ticket du 18 septembre 2026 : « reduis la largeur
   des colonnes [...] fais un affichage plus compact et plus sobre »). Le tableau
   ne s'etire pas sur toute la tuile : il prend la largeur de ce qu'il ecrit, et
   quatre colonnes serrees se lisent d'un regard la ou quatre colonnes etirees
   obligeraient l'oeil a traverser la page entre la structure et son montant.

   LA TUILE A LA LARGEUR DES AUTRES depuis le suivi du 20 septembre 2026
   (« reduis la largeur de la fenetre afin qu'elle soit identique a celle des
   autres ») : `pleine-largeur` a quitte le gabarit. Elle prenait la rangee
   entiere parce que cinq colonnes, dont deux de montants et la plus large de
   toutes -- le type de prime repete a chaque rang --, debordaient sous la tuile
   voisine. Le type dit une seule fois sur son sous-total, il en reste quatre, et
   le tableau tient dans une colonne de grille.

   Les deux colonnes de texte se replient donc, et elles seules : un nom de
   structure va a la ligne plutot que de pousser le tableau hors de la tuile,
   tandis qu'un montant coupe en deux lignes ne se comparerait plus. Ce qui
   deborde quand meme -- un nom d'un seul mot, tres long -- defile a
   l'horizontale dans son cadre. */
.compte-primes-table {
  width: auto;
  max-width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}

/* Le defilement est sur l'enveloppe du tableau et non sur la tuile : un
   `overflow` pose sur un `fieldset` qui porte une legende le sort du calcul de
   hauteur de sa rangee de grille, et les tuiles suivantes viennent se poser
   par-dessus -- constate a l'essai. */
.compte-primes-cadre { overflow-x: auto; }

.compte-primes-table th,
.compte-primes-table td {
  padding: var(--espace-2xs) var(--espace-xs) var(--espace-2xs) 0;
  border-bottom: 1px solid var(--gray-2);
  text-align: left;
  white-space: nowrap;
}

/* LES ECARTS ENTRE COLONNES, resserres d'un cran, et aucun a droite de la
   derniere : il n'y a rien apres elle. Ces quelques pixels sont exactement ce
   qui faisait deborder le tableau de sa tuile sur un telephone, largeur ou
   quatre colonnes tiennent a un demi-caractere pres. Les montants tombent donc
   au bord droit du tableau, la ou un registre les pose. */
.compte-primes-table th:last-child,
.compte-primes-table td:last-child { padding-right: 0; }

/* LA STRUCTURE SEULE SE REPLIE, et c'est ce qui laisse le tableau tenir dans
   une colonne de grille : un nom de mandat va a la ligne plutot que de pousser
   les montants hors de la tuile. Rien d'autre ne se coupe -- un montant sur
   deux lignes ne se compare plus, et « CAC 2025 » casse en deux se relit.

*/
.compte-primes-table tbody th { white-space: normal; }

.compte-primes-table thead th {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--gray-5);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.compte-primes-table tbody th {
  font-weight: 600;
  color: var(--black);
}

/* LES DEUX COLONNES DE NOMBRES, ALIGNEES A DROITE, en-tete compris : « les
   valeurs des colonnes "Facture hors taxes" et "Montant" doivent etre alignees
   a droite » (suivi du 18 septembre 2026). La regle existait et ne s'appliquait
   pas : `.compte-primes-table td` pese une classe et un type, `.compte-primes-
   nombre` une classe seule, et c'est donc l'alignement a gauche des cellules
   ordinaires qui l'emportait. La classe du tableau la remet au-dessus. Des
   montants alignes a gauche ne se comparent pas du regard : les unites ne
   tombent pas l'une sous l'autre. */
.compte-primes-table .compte-primes-nombre {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* LE TOTAL SUR LA LIGNE DU TITRE, et non plus au-dessus du tableau dans une
   phrase a lui (ticket du 18 septembre 2026). La legende est deja flottante et
   large de toute la tuile (`.compte-groupe > legend`) : elle devient une rangee,
   le titre a gauche, le chiffre pousse a droite. */
.compte-primes-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--espace-lg);
}

/* Le chiffre qu'on vient chercher, a la hauteur du titre : un cran au-dessus du
   tableau, pas deux. Il pesait celui d'un titre de page quand il ouvrait le
   bloc a lui seul. */
.compte-primes-gagne {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--black);
  font-variant-numeric: tabular-nums;
}

/* LE DETAIL SE DEMANDE (ticket du 20 septembre 2026 : « le detail pourrait
   etre replie par defaut et affiche uniquement lorsque je souhaite le
   consulter »). Le repli lui-meme est habille avec les autres `<summary>` du
   produit, plus haut dans la feuille ; ce qui reste ici est l'ecart qui le
   detache du total au-dessus, et celui qui separe le tableau de la ligne qui
   vient de l'ouvrir. Sans le second, la premiere colonne d'en-tete se colle au
   libelle du repli et les deux se lisent comme un seul rang. */
.compte-primes-detail > summary { margin-top: var(--espace-xs); }

.compte-primes-detail[open] > summary { margin-bottom: var(--espace-xs); }

/* LES EXERCICES PRECEDENTS, UNE SEULE LIGNE QUI LES CHOISIT. « Remplace
   l'affichage d'une ligne par exercice par une seule ligne plus compacte
   contenant une combo box. [...] L'objectif est d'obtenir une presentation plus
   courte et moins large » (suivi du 20 septembre 2026).

   Un rang par exercice faisait douze rangs sous « Mon compte », plus haut a lui
   seul que les deux exercices qu'on vient lire. La rangee porte donc la liste a
   gauche et, quand un exercice est choisi, son total au bord droit : c'est la
   place ou l'exercice en cours ecrit deja le sien (`.compte-primes-tete`), donc
   le meme chiffre au meme endroit dans les deux tuiles.

   L'ecart au-dessus est celui qui detache un repli de son total dans la tuile
   voisine (`.compte-primes-detail > summary`) : les deux tuiles se suivent, et
   leur premiere ligne doit tomber a la meme hauteur. */
.compte-primes-choix {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-sm);
  margin-top: var(--espace-xs);
}

/* La liste ne prend que la largeur de sa plus longue option, et non celle de la
   tuile : c'est le « moins large » du ticket. Elle reste bornee a son contenant
   par la regle de base des `select`, donc rien ne deborde a 390 px. */
.compte-primes-choix-liste { max-width: 100%; }

/* Le total de l'exercice choisi, pousse au bord droit. Vide, il n'occupe rien :
   la ligne se lit alors comme la seule liste qu'elle est. */
.compte-primes-choix-total { margin-left: auto; }

/* Le tableau de l'exercice choisi, separe de la ligne qui vient de le demander
   comme le detail d'un exercice en cours l'est de la sienne. */
.compte-primes-passe { margin-top: var(--espace-sm); }

/* LE SOUS-TOTAL FERME SA CATEGORIE, et ne s'aligne plus avec l'autre au pied du
   tableau (suivi du 18 septembre 2026). Il se detache des lignes qu'il compte
   par un filet plus marque au-dessus et par sa graisse, comme un pied de
   registre : c'est le nombre qu'on vient chercher quand on ne lit pas le
   detail. Le nom se pose a droite de sa colonne, contre le montant qu'il
   annonce.

   L'espace sous le sous-total separe les deux categories : sans lui, la
   derniere ligne d'une section et le sous-total de la precedente se toucheraient
   et la coupure ne se verrait plus. La derniere section n'en porte pas, pour ne
   pas laisser un blanc au bas de la tuile. */
.compte-primes-soustotal th {
  text-align: right;
  font-weight: 600;
  color: var(--black);
}

.compte-primes-soustotal th,
.compte-primes-soustotal td {
  border-top: 1px solid var(--gray-3);
  border-bottom: none;
}

.compte-primes-soustotal td { font-weight: 600; }

.compte-primes-section:not(:last-child) .compte-primes-soustotal th,
.compte-primes-section:not(:last-child) .compte-primes-soustotal td {
  padding-bottom: var(--espace-md);
}

/* Le signe du type devant son sous-total, comme devant sa ligne : c'est le meme
   type, il se reconnait au meme signe. */
.compte-primes-soustotal .compte-prime-signe {
  vertical-align: -.1em;
  margin-right: var(--espace-3xs);
}

/* Le taux qu'un coefficient de detention a reduit, a la suite du taux plein :
   gris, parce que c'est une precision sur le nombre d'a cote et non un second
   renseignement. */
.compte-prime-coefficient {
  color: var(--gray-5);
  white-space: nowrap;
}

/* LE TAUX DU TYPE, a la suite de son nom sur le sous-total (suivi du
   20 septembre 2026). Il n'est plus sur la ligne, ou il se repetait ; il est
   sur le rang qui nomme la categorie, en gris et sans graisse : le nombre qu'on
   vient chercher sur ce rang est le sous-total, pas le taux qui l'a produit. */
.compte-prime-taux {
  font-weight: 400;
  color: var(--gray-5);
}

/* LE TAUX DE CHARGES PATRONALES ET SUR COMBIEN DE PIECES LE SOUS-TOTAL EST
   ASSIS : deux renseignements de meme rang sur la meme somme, donc ecrits du
   meme gris, sans graisse, et separes du meme point median. Les distinguer
   aurait fait croire que l'un compte plus que l'autre. Le taux de charges est
   arrive le 20 septembre 2026, celui des pieces le meme jour.
*/
/* SUR COMBIEN DE PIECES LE SOUS-TOTAL EST ASSIS (ticket du 20 septembre 2026).
   Meme gris et meme absence de graisse que le taux, a la suite duquel il se
   lit : ce sont deux renseignements de meme rang sur la meme somme, et les
   ecrire differemment aurait fait croire que l'un compte plus que l'autre.

   Separe par un point median et non par une virgule : « 100 % , 3 pieces » se
   serait lu comme une enumeration ouverte, ou l'on attend une suite. Le point
   ferme chaque moitie. Il est pose ici plutot que dans le gabarit, parce qu'il
   ne doit pas se selectionner ni se faire lire a voix haute avec le nombre. */
.compte-prime-pieces,
.compte-prime-charges {
  font-weight: 400;
  color: var(--gray-5);
  white-space: nowrap;
}

.compte-prime-pieces::before,
.compte-prime-charges::before {
  content: "·";
  margin: 0 var(--espace-3xs);
  color: var(--gray-4);
}

/* Le signe du type est gris et a la taille d'une minuscule : il se reconnait
   sans se faire lire, ce qui est tout ce qu'on lui demande. */
.compte-prime-signe {
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--gray-4);
}

/* Ce qui n'est pas encore gagne se lit en retrait : la prime existe, la piece
   n'est pas partie. La mention l'ecrit, la couleur evite qu'on additionne du
   regard deux colonnes qui ne s'additionnent pas. */
.compte-prime-a-venir th,
.compte-prime-a-venir td { color: var(--gray-4); }

.compte-prime-mention {
  display: block;
  font-size: var(--fs-xs);
  color: var(--gray-4);
}

/* Le numero de piece reste a la taille du tableau, alors qu'il en etait un cran
   en dessous avant le resserrement du 18 septembre 2026 : c'est l'identifiant
   de la ligne, celui qu'on cherche du regard et qu'on recopie dans l'outil
   comptable. Ce qui le distingue de son voisin est la chasse fixe, pas la
   petitesse. */
.fact-numero { font-family: var(--mono); font-size: var(--fs-xs); }

/* LA COLONNE SE REGLE SUR LES NUMEROS, PAS SUR LES MENTIONS QUI LES SUIVENT.
   « La colonne Client devrait etre davantage a gauche, car il y a actuellement
   trop d'espace perdu » (ticket du 22 septembre 2026).

   L'espace perdu tenait a une poignee de lignes. Le genre d'une piece et la
   mention « pour un tiers » se marquent a la suite du numero ; seize factures
   sur huit cent trente-quatre en portaient une, et une colonne prend la
   largeur de sa cellule la plus large : cent quarante-cinq pixels pour une
   colonne dont les numeros en demandent soixante-cinq, soit cinquante pixels
   de vide entre le numero et le client, sur tous les autres rangs.

   Le plafond est celui du plus long numero du registre, et c'est le numero
   seul qui refuse de se couper (`.fact-numero-valeur`). La mention se replie
   donc sous lui, sur les seuls rangs qui en portent une : deux lignes de haut
   sur une facture sur cinquante, contre un vide permanent sur les autres. */
.fact-table td.fact-numero {
  min-width: 10ch;
  max-width: 10ch;
  white-space: normal;
}

/* DIX CARACTERES, NI PLUS NI MOINS, ET LE NUMERO LONG SE REPLIE COMME LA
   MENTION. « Décale la colonne "Client" vers la gauche » (ticket du
   22 septembre 2026). Le plafond précédent, quatorze caractères, était atteint
   par une seule ligne du registre, « VB-2026-09-22 », et une colonne prend la
   largeur de sa cellule la plus large : quatre cent seize rangs portaient
   trente pixels de vide pour celui-là, quand les numéros de la série en font
   sept et les plus longs des autres neuf.

   Le numéro ne refuse plus de se couper : ses tirets lui disent où le faire,
   donc celui qui dépasse dix caractères se replie sur deux lignes, sur le seul
   rang qui en porte un, exactement comme la mention « pour un tiers » se replie
   sous lui. Sans `overflow-wrap`, surtout : « anywhere » coupe un numéro au
   milieu d'un groupe de chiffres, la colonne se serre alors sur un caractère et
   chaque rang monte à cinq lignes de haut.

   ET LA LARGEUR EST DITE DEUX FOIS, EN PLANCHER ET EN PLAFOND. Le plafond seul
   ne tient pas : la colonne des actions prend tout le surplus
   (`.fact-actions-cellule`), celle-ci devient la variable d'ajustement dès que
   son contenu sait se couper, et « VC-6121 » se replierait à son tour. */
.fact-numero-valeur { white-space: normal; }

/* La mission, juste apres le client : elle le qualifie, elle ne le concurrence
   pas. Un cran plus petit et plus gris que le nom, comme la seconde ligne
   d'une carte -- le regard descend la colonne des clients et ne s'arrete sur
   la mission que lorsqu'elle sort de l'ordinaire. */
.fact-mission {
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  white-space: nowrap;
  width: 1%;
}

/* LE SIGLE SE CHOISIT DANS LA COLONNE, ET LA COLONNE RESTE UN TABLEAU.
   « Lorsque la mission est absente, incorrecte ou a ete supprimee, affiche une
   liste deroulante permettant de selectionner manuellement une mission parmi
   tous les types disponibles » (suivi du ticket du 18 septembre 2026).

   Cent quarante listes deroulantes bordees les unes sous les autres auraient
   fait de la colonne une grille de boutons, et le regard ne serait plus
   descendu jusqu'au montant. Le controle se tait donc tant qu'on ne le vise
   pas : ni bordure, ni fond, ni chevron, la taille du texte de la cellule. Il
   reprend sa bordure au survol et au clavier, ou l'on sait alors qu'il se
   change. C'est le meme `<select>` en dessous, avec son menu maison, sa valeur
   et son focus. */
/* LA DATE COLLE AU SIGLE, ET C'EST LA LISTE QUI LUI FAISAIT DE LA PLACE.
   « Dans la colonne Mission, rapproche au maximum la date du nom de la mission,
   en la decalant vers la gauche » (ticket du 18 septembre 2026).

   Une liste deroulante se dimensionne sur sa plus longue OPTION, pas sur celle
   qu'elle affiche : « Non precisee », qui sert a effacer la mission, en faisait
   onze caracteres alors qu'aucune ligne n'en montre plus de trois. Cinquante
   pixels de vide separaient donc « CAC » de son annee, et aucun n'appartenait
   a personne. La largeur est donc posee ici, sur ce qu'on lit, et non sur ce
   que le menu propose.

   ET LE CHEVRON S'EN VA, parce qu'il etait l'autre moitie du vide. Il ne se
   dessine qu'au survol, mais il faut lui reserver sa place en permanence, sans
   quoi l'annee glisserait d'un demi-centimetre des que la souris passe sur le
   sigle, sur la ligne que l'on vise precisement : dix-huit pixels de plus,
   toujours vides. Ce qu'il disait est deja dit : la bordure et le fond blanc
   qui paraissent au survol sont ce que la cellule du client et celle de
   l'annee emploient, a deux doigts de la, pour dire qu'on peut y toucher, et
   c'est le meme geste sur les trois. Le menu, lui, s'ouvre au clic comme
   avant.

   Quatre `ch` et demi, et non trois : un `ch` est la chasse du zero, six
   pixels ici, quand « CAC » en capitales en occupe pres de vingt-quatre. Trois
   coupaient le sigle en « C... » des le survol, et quatre le rasaient d'un
   cheveu une fois la bordure posee. */
.fact-mission-choix {
  font-size: inherit;
  color: inherit;
  padding: 0;
  border-color: transparent;
  background-color: transparent;
  background-image: none;
  width: calc(4.5ch + var(--espace-2xs));
}

/* Le meme reveil que ses deux voisines de rangee, et rien de plus : une
   bordure, un fond blanc, le sigle qui reste ou il est. */
.fact-mission-choix:hover,
.fact-mission-choix:focus-visible {
  border-color: var(--gray-3);
  background-color: #fff;
  padding: 0 0 0 var(--espace-2xs);
}

/* Une mission seulement DEDUITE s'affiche en retrait : ce qu'on lit n'a ete
   choisi par personne, et c'est precisement ce que la liste deroulante sert a
   corriger. Une deduction presentee comme une saisie se recopie sans qu'on la
   verifie. */
.fact-mission-choix[data-deduite] { color: var(--gray-4); }

/* UNE MISSION QUI N'EST PAS UN COMMISSARIAT AUX COMPTES SE VOIT AVANT D'ETRE
   LUE. « Conserve un affichage normal pour les missions CAC. Pour toutes les
   autres missions, ajoute un indicateur visuel discret, par exemple une
   couleur specifique, afin d'identifier immediatement qu'il s'agit d'une
   mission ponctuelle ou inhabituelle » (ticket du 18 septembre 2026).

   Cent quarante lignes portent « CAC » et une quinzaine autre chose : trois
   lettres de plus dans une colonne grise, c'est une aiguille dans une botte de
   foin. La teinte est celle que le produit donne deja a ce qui sort de
   l'ordinaire sur cette page : le violet de la marque de nature (`.fact-genre`,
   « Acompte », « Avoir »), a deux cellules de la. Deux violets sur une meme
   ligne se reconnaissent comme un seul signe, la ou une teinte de plus aurait
   fait un code a apprendre.

   Discret, c'est-a-dire une encre et non une pastille : la couleur suffit a
   arreter le regard, un fond colore aurait fait de la colonne une suite de
   boutons et aurait concurrence l'etat de recouvrement, qui est ce qu'on vient
   voir en premier. La demi-graisse tient le sigle lisible en violet a cette
   taille. Le survol et le clavier gardent le dessin de la liste deroulante :
   c'est le meme controle, il se change de la meme facon. */
.fact-mission-choix[data-ponctuelle] {
  color: var(--purple);
  font-weight: 600;
}

/* L'ANNEE CONTROLEE, A COTE DU SIGLE ET DE LA MEME FAMILLE. « Dans la colonne
   Mission, il faudrait avoir la possibilite de modifier la date » (ticket du
   18 septembre 2026) : ce qui se lisait est devenu un champ, et il se tait
   comme ses deux voisins tant qu'on ne le vise pas. Neuf caracteres de large,
   c'est « 2025-2026 » : un exercice a cheval s'ecrit de ses deux millesimes,
   et un champ plus court l'aurait coupe au milieu.

   Une annee seulement DEDUITE s'affiche en retrait, comme le sigle : ce qu'on
   lit n'a ete choisi par personne, et c'est ce que le champ sert a corriger. */
.fact-mission-annee {
  font: inherit;
  color: inherit;
  margin-left: var(--espace-2xs);
  width: 9ch;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
  background: transparent;
}

.fact-mission-annee:hover,
.fact-mission-annee:focus-visible {
  border-color: var(--gray-3);
  background: #fff;
}

.fact-mission-annee[data-deduite] { color: var(--gray-4); }

/* LE NOM DU CLIENT SE CORRIGE DANS LA COLONNE, ET LA COLONNE RESTE UN TABLEAU.
   « Je dois pouvoir modifier directement le nom du client dans la colonne
   Client » (ticket du 18 septembre 2026).

   Meme parti que la liste des missions, juste a cote : le champ se tait tant
   qu'on ne le vise pas, ni bordure ni fond, la taille et l'encre du texte de
   la cellule. Il reprend son dessin au survol et au clavier, ou l'on sait
   alors qu'il se change. Cent quarante cadres les uns sous les autres auraient
   fait de cette page un formulaire, et le regard ne serait plus descendu
   jusqu'au montant.

   La largeur suit la cellule : un nom de mandat est long, la colonne est celle
   que le tableau lui laisse, et un champ de largeur fixe l'aurait coupe plus
   tot que le texte qu'il remplace. */
/* La cellule reste une ligne : le champ prend la place qui reste, la mention
   « hors aiudit » garde la sienne a cote. Un champ large de toute la cellule
   l'aurait poussee dessous, et trois cents lignes du registre en portent une :
   la page aurait grandi d'un tiers pour un champ qui ne se voit pas.

   L'alignement est dans un enrobage et non sur la cellule : une cellule de
   tableau passee en `flex` cesse de s'etirer a la hauteur de sa rangee, et son
   filet du bas remontait de sept pixels au milieu du tableau. */
/* LA COLONNE DU CLIENT SE REGLE SUR LES NOMS, ET NON SUR CE QUI RESTE.
   « Reduire la largeur de la colonne Client pour qu'elle s'adapte davantage a
   la longueur du nom du client et evite trop d'espace vide » (ticket du
   18 septembre 2026).

   Le tableau tient toute la largeur de sa tuile, et un tableau a disposition
   automatique repartit le surplus au prorata du contenu : la colonne des noms,
   qui a le plus long, en recevait le plus. Trois cent trente pixels pour des
   noms qui en font soixante-seize au milieu du registre, depuis que le nom
   court s'y affiche. Le plancher de quatorze rem n'y etait pour rien, mais il
   ne servait plus a rien non plus : il est parti avec.

   Un plafond plutot qu'une largeur, parce que la demande est que la colonne
   s'ADAPTE : elle prend la place du plus long nom qu'elle montre, et s'arrete
   la. Les noms qui depassent se coupent au bord, avec le nom entier en
   infobulle et le champ qui le fait defiler des qu'on y entre.

   LE PLAFOND EST A QUARANTE CARACTERES ET NON A VINGT-QUATRE. « Tu peux
   egalement voir s'il est pertinent d'adapter sa largeur en fonction du nom
   des clients » (ticket du 22 septembre 2026). Vingt-quatre coupaient
   soixante-quatre des cent quarante et un noms d'un exercice, pendant que
   quatre cents pixels restaient vides au bout du rang : couper un nom sur
   deux pour garder du vide n'est pas un arbitrage. Quarante en laissent
   entier dix-neuf sur vingt, et la colonne ne les prend que si elle en a
   besoin ; ce qu'elle ne prend pas continue de tomber dans la derniere
   colonne.

   Et le plafond ne suffisait pas a lui seul : c'est `size`, pose sur le champ
   par `facturation.js`, qui fait que la colonne connait la longueur de ses
   noms. Sans lui elle se reglait sur les vingt caracteres par defaut d'un
   champ de saisie, c'est-a-dire sur rien. */
.fact-client { min-width: 0; max-width: 40ch; }

/* ET LE SURPLUS TOMBE DANS LA DERNIERE COLONNE, celle du menu d'une ligne, qui
   n'a pas de titre et rien a aligner. Sans quoi la largeur reprise au client
   se serait redistribuee aux dix autres colonnes, qui se seraient elargies
   d'autant : le vide aurait change de place sans diminuer. Il se range donc
   apres le dernier bouton, la ou une ligne de tableau se termine et ou l'oeil
   ne cherche rien. */
.fact-actions-cellule { width: 100%; }

.fact-client-champ {
  display: flex;
  align-items: center;
  gap: var(--espace-2xs);
}

.fact-client-nom {
  font: inherit;
  color: inherit;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
  background: transparent;
}

.fact-client-nom:hover,
.fact-client-nom:focus-visible {
  border-color: var(--gray-3);
  background: #fff;
  padding: 0 var(--espace-2xs);
}


/* La colonne du cabinet, en tete de ligne et reduite a sa marque : une tuile
   de trois lettres n'a pas besoin de la largeur d'un nom, et la colonne se
   serre pour que le numero de piece reste au bord gauche du texte.

   `width: 1%` ne suffisait pas : une colonne ne descend jamais sous la largeur
   de son en-tete, et « CABINET » en capitales espacees en faisait vingt-cinq
   pixels de plus que la tuile. L'en-tete est donc une icone (voir
   `facturation.js`), et il ne reste ici qu'a rendre l'espace que les deux
   marges prenaient entre la marque et le numero. */
.fact-cabinet-cellule { width: 1%; white-space: nowrap; }

.fact-table th.fact-cabinet-cellule,
.fact-table td.fact-cabinet-cellule { padding-right: var(--espace-2xs); }

.fact-table th.fact-numero-tete,
.fact-table td.fact-numero { padding-left: var(--espace-2xs); }

.fact-cabinet-icone { width: var(--icon-xs); height: var(--icon-xs); }

/* La colonne du titulaire, devant celle du cabinet et seulement dans la vue du
   cabinet (voir `avecTitulaire` dans `facturation.js`). Meme gabarit que sa
   voisine, pour la meme raison : la tuile fait vingt-six pixels, le mot
   « TITULAIRE » en capitales espacees en ferait six fois plus, donc l'en-tete
   est une icone et la colonne se serre sur ce qu'elle porte.

   Elle passe DEVANT le cabinet et non entre lui et le numero : « rapprocher
   davantage le numero de facture du logo du cabinet » (ticket du 18 septembre
   2026) les a colles l'un a l'autre, et s'intercaler la aurait defait ce
   ticket-la pour en servir un autre. */
.fact-titulaire-cellule { width: 1%; white-space: nowrap; }

.fact-table th.fact-titulaire-cellule,
.fact-table td.fact-titulaire-cellule { padding-right: var(--espace-2xs); }

.fact-titulaire-icone { width: var(--icon-xs); height: var(--icon-xs); }

/* Le rond du signataire, a la taille d'une rangee de tableau (suivi du ticket
   du 22 septembre 2026). Le diametre est le seul reglage du rond : les
   initiales s'en deduisent, et c'est le meme barreau que les autres ronds
   poses dans une liste dense. Vingt-deux et non vingt-huit : la rangee tient
   la hauteur d'une tuile de cabinet, vingt pixels, et un disque plus gros
   l'aurait fait grandir sur mille sept cents lignes. */
.fact-signataire-rond { --avatar-d: 22px; }

/* Le tiret d'une ligne sans titulaire : lisible, mais en retrait, parce qu'il
   dit une absence et non une valeur. */
.fact-titulaire-vide { color: var(--gray-4); }

/* La mention garde sa place entiere et c'est le champ qui cede : elle fait deux
   mots, et une colonne serree la repliait en « hors / aiudit », sur deux lignes
   dans une rangee qui n'en a qu'une. */
.fact-hors {
  flex: none;
  white-space: nowrap;
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  padding: 0 var(--espace-3xs);
}

.fact-genre {
  display: inline-block;
  margin-left: var(--espace-3xs);
  font-family: var(--sans);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  color: var(--purple);
}

/* La pastille d'état. Les cinq teintes sont celles que le serveur nomme
   (`facturation.COULEURS_RECOUVREMENT`), et non cinq classes écrites ici :
   l'app lira les mêmes noms par la même route. */
.fact-pastille {
  display: inline-block;
  font-size: var(--fs-2xs);
  padding: var(--espace-3xs) var(--espace-xs);
  border-radius: 999px;
  white-space: nowrap;
}

.fact-pastille[data-etat="ok"] { background: var(--green-pale); color: var(--green); }
.fact-pastille[data-etat="urgent"] { background: var(--red-pale); color: var(--red-dark); }
.fact-pastille[data-etat="encours"] { background: var(--orange-pale); color: var(--orange); }
.fact-pastille[data-etat="attente"] { background: var(--gray-1); color: var(--gray-5); }
.fact-pastille[data-etat="neutre"] { background: var(--gray-2); color: var(--gray-4); }

.fact-relances {
  display: inline-block;
  margin-left: var(--espace-3xs);
  font-size: var(--fs-3xs);
  background: var(--yellow-pale);
  color: var(--yellow);
  border-radius: 999px;
  padding: 0 var(--espace-3xs);
}

.fact-vide { color: var(--gray-4); font-size: var(--fs-sm); margin: var(--espace-sm) 0; }

/* LA VISION GLOBALE : UN DECOUPAGE CHOISI, DES RANGS QUI S'OUVRENT (ticket du
   20 septembre 2026). Trois tableaux etaient empiles ici, tous ouverts, et les
   memes lignes y etaient comptees trois fois ; il n'y en a plus qu'un, dont le
   decoupage se choisit, et dont chaque rang s'ouvre sur les lignes qu'il
   additionne. `.fact-groupe` et `.fact-groupe-titre` sont partis avec eux. */
.fact-groupe-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-sm);
  margin-bottom: var(--espace-sm);
}

/* La phrase qui dit ce que le rang fait quand on le pousse : elle s'efface a
   l'etroit, ou la liste deroulante prend la rangee entiere et ou l'on a deja
   ouvert un rang pour le savoir. */
.fact-aide-inline { font-size: var(--fs-xs); color: var(--gray-4); }

@media (max-width: 720px) { .fact-aide-inline { display: none; } }

/* Un rang, ferme, est une ligne de tableau : un nom a gauche, ses nombres a
   droite, un filet dessous. Ouvert, il pose son tableau en dessous. Le chevron
   est celui des autres replis du produit, habille plus haut dans la feuille
   avec les `<summary>` de /cabinet et de /compte. */
.fact-groupe-rang { border-bottom: 1px solid var(--gray-2); }

.fact-groupe-rang > summary {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
  list-style: none;
  padding: var(--espace-xs) 0;
  cursor: pointer;
  user-select: none;
}

.fact-groupe-rang > summary::-webkit-details-marker { display: none; }

.fact-groupe-rang > summary > .icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--gray-4);
  flex: none;
  transition: transform .15s var(--ease);
}

.fact-groupe-rang[open] > summary > .icon { transform: rotate(90deg); }

.fact-groupe-rang > summary:hover .fact-groupe-nom { color: var(--cyan-dark); }

.fact-groupe-nom { font-weight: 600; color: var(--black); }

/* LES NOMBRES DU RANG, POUSSES A DROITE ET NOMMES CHACUN. Une rangee de six
   colonnes aurait redit six en-tetes au-dessus de chaque decoupage ; ici chaque
   nombre porte son mot, ce qui tient sur un rang et se replie tout seul quand
   la fenetre se serre. Chiffres de meme chasse, comme tous les montants de
   cette page : c'est ce qui permet de comparer deux rangs du regard. */
.fact-groupe-chiffres {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--espace-xs) var(--espace);
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--gray-5);
  font-variant-numeric: tabular-nums;
}

.fact-groupe-chiffres b { color: var(--black); font-weight: 600; }

/* A L'ETROIT, LE NOM PREND SON RANG ET LES NOMBRES PASSENT DESSOUS. Serres sur
   la meme ligne, les deux se disputaient la largeur et c'est le nom qui cedait :
   « audit france · Qonto » se coupait en quatre lignes, une par mot, autour
   d'un point median. Un nom de groupe ne se lit pas en colonne. */
@media (max-width: 720px) {
  .fact-groupe-rang > summary { flex-wrap: wrap; }
  /* Le nom se retrecit et se replie, il ne s'etale pas : ce sont les chiffres
     qui prennent le rang du dessous, leur `flex-basis` le dit deja. Etale, il
     poussait la marque de l'outil a l'autre bout de la rangee, ou elle ne
     qualifiait plus rien (ticket du 23 septembre 2026). */
  .fact-groupe-nom { flex: 0 1 auto; }
  .fact-groupe-chiffres {
    flex-basis: 100%;
    justify-content: flex-start;
    margin-left: calc(var(--icon-sm) + var(--espace-xs));
  }
}

.fact-groupe-chiffres [data-alerte="1"] { color: var(--red-dark); font-weight: 600; }

/* LA FACTURATION FAITE POUR UN TIERS, PARTOUT DU MEME SIGNE : sur le rang d'une
   ligne, sur le rang d'un groupe, et sur le carreau de tete. « Clairement
   identifiable » veut dire reconnaissable sans etre lu, donc une seule couleur
   pour les trois endroits (ticket du 20 septembre 2026).

   Le bleu et non l'orange ni le rouge : ce n'est ni une alerte ni un retard,
   c'est une nature de facturation, et la page reserve ses teintes chaudes a ce
   qui demande un geste. Il se distingue du violet de la marque de nature d'une
   piece, sa voisine immediate sur le rang. */
.fact-tiers-marque {
  display: inline-block;
  margin-left: var(--espace-3xs);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: .02em;
  background: var(--blue-pale);
  color: var(--blue);
  border-radius: var(--radius-xs);
  padding: 0 var(--espace-3xs);
  white-space: nowrap;
}

.fact-groupe-chiffres .fact-tiers-part { color: var(--blue); white-space: nowrap; }

.fact-carreau[data-carreau="tiers"] {
  border-color: var(--blue);
  background: var(--blue-pale);
}

.fact-carreau[data-carreau="tiers"] .fact-carreau-valeur { color: var(--blue); }

/* Le tableau d'un rang ouvert respire sous son resume, et se decale du chevron
   pour qu'on voie d'un coup d'oeil a quel rang il appartient quand deux rangs
   voisins sont ouverts. */
.fact-groupe-rang[open] > .fact-table,
.fact-groupe-rang[open] > .fact-vide {
  margin: 0 0 var(--espace-md) calc(var(--icon-sm) + var(--espace-xs));
}

/* La fiche d'une ligne : surface flottante de la même famille que les autres
   du produit, `--radius-lg`, fond blanc, bordure et ombre portée. */
.fact-voile {
  position: fixed;
  inset: 0;
  background: rgba(14, 18, 22, .45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: var(--espace-xl);
  overflow-y: auto;
  z-index: 60;
}

.fact-fiche {
  width: min(52rem, 100%);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--espace-lg);
}

.fact-fiche-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--espace-md);
}

.fact-fiche-tete h3 { margin: 0; font-size: var(--fs-h3); }

.fact-fermer {
  border: 0;
  background: none;
  color: var(--red);
  cursor: pointer;
  padding: var(--espace-3xs);
}

.fact-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--espace-sm);
}

.fact-champs label,
.fact-panneau label {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}

.fact-champ-large { grid-column: 1 / -1; }

/* UN CHOIX QUI SE MONTRE PAR SA MARQUE. « Pour le Cabinet qui facture, garde le
   nom dans la liste de choix, mais une fois selectionne, affiche plutot la
   pastille/logo du cabinet [...] Remplace "Titulaire" par "Signataire" et, une
   fois selectionne, affiche sa pastille avec ses initiales et sa couleur »
   (ticket du 22 septembre 2026).

   UN `<select>` FERME NE SAIT MONTRER QUE LE TEXTE DE SON OPTION. La marque est
   donc posee par-dessus, a la place ou ce texte s'ecrivait, et le texte devient
   transparent. Le controle ne bouge pas d'un pixel : meme bordure, meme
   chevron, meme anneau de focus, meme boite, et c'est toujours lui qui porte la
   valeur, les evenements, le clavier et la synthese vocale. La marque, elle, ne
   recoit aucun clic : il traverse et va au controle, sans quoi la moitie gauche
   du champ ne l'aurait plus ouvert.

   LE MENU GARDE LES NOMS, comme le ticket le demande, et il les garde sans rien
   faire : c'est `liste-deroulante.js` qui le dessine, entree par entree, dans
   ses propres elements. La transparence ne porte que sur le controle ferme.
   L'option reprend donc son encre pour le seul cas ou ce menu ne tournerait pas
   et ou celui du navigateur reparaitrait. */
.fact-choix-cadre {
  position: relative;
  display: block;
}

.fact-choix-select { width: 100%; color: transparent; }

.fact-choix-select option { color: var(--gray-6); }

.fact-choix-marque {
  position: absolute;
  left: var(--espace-sm);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: var(--espace-3xs);
  max-width: calc(100% - var(--espace-sm) - var(--chevron-reserve));
  overflow: hidden;
  pointer-events: none;
}

/* Tant que rien n'est choisi, la marque porte le mot que le controle portait :
   une case vide se lit comme un champ mal rempli plutot que comme un choix a
   faire. A l'encre du controle, puisqu'elle prend sa place. */
.fact-choix-vide {
  font-size: var(--fs-sm);
  color: var(--gray-4);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Une liste qu'on ne peut pas changer se voit : le controle grise le sien, la
   marque posee dessus ne le saurait pas. C'est le cas du signataire pour qui
   n'administre pas le cabinet. */
.fact-choix-cadre:has(.fact-choix-select:disabled) .fact-choix-marque {
  opacity: .55;
}

/* L'OUTIL DE FACTURATION, A COTE DE LA TUILE DU CABINET. Vingt pixels de haut,
   comme la tuile qu'il suit : deux marques sur une meme rangee se lisent comme
   une seule des qu'elles ont la meme hauteur, et se voient comme deux objets
   des qu'elles ne l'ont pas.

   Neutre et non colore : la tuile du cabinet porte deja la couleur, et deux
   marques colorees cote a cote se disputeraient le regard pour une information
   qui n'est qu'un moyen. Le nom entier reste en infobulle, et la liste
   deroulante l'ecrit en toutes lettres.

   DEUX ENDROITS DESORMAIS, ET C'EST POURQUOI LA CLASSE NE DIT PLUS « choix » :
   la fiche d'une ligne, ou la marque est nee, et le rang d'un cabinet dans la
   vision globale, ou elle a pris la place de « · Pennylane » (ticket du
   23 septembre 2026). La meme taille aux deux endroits, parce que ce sont les
   deux fois la meme rangee : une marque a cote d'un nom. */
.fact-outil-marque {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: var(--gray-1);
  color: var(--gray-5);
  font-size: var(--fs-3xs);
  font-weight: 700;
}

/* LA MARQUE ELLE-MEME, quand le depot l'a. Les deux fichiers sont arrives au
   suivi du ticket, deposes par le demandeur : `outil-qonto.png` et
   `outil-pennylane.png`, cadres a la meme taille optique pour qu'une fiche
   Qonto et une fiche Pennylane pesent pareil a cote de la tuile.

   ELLE N'A PAS DE JETON SOUS ELLE, a la difference du monogramme ci-dessus, et
   ce n'est pas un oubli : une marque deposee porte son propre fond, et lui en
   poser un second aurait dessine un cadre autour d'un cadre. L'arrondi reste la
   pour le fond colore qu'un troisieme outil pourrait apporter, et
   `object-fit: contain` pour que ce fichier-la garde ses proportions quelle que
   soit sa forme. */
.fact-outil-logo {
  flex: none;
  width: 20px;
  height: 20px;
  object-fit: contain;
  border-radius: var(--radius-xs);
}

/* LA PHRASE QUI SUIT LE CHOIX D'ETAT. Elle traverse la grille sous le champ
   qu'elle explique, a la chasse des libelles et non a celle du texte courant :
   c'est une legende de champ, pas un paragraphe de la fiche, et `.fact-aide`
   seule la faisait plus grosse que le libelle au-dessus d'elle. Sa marge du bas
   part aussi, le `gap` de la grille ecartant deja la ligne suivante. */
.fact-champs .fact-aide {
  font-size: var(--fs-xs);
  margin: 0;
}

/* UNE CASE QUE LE SERVEUR A REFUSEE, ET CE QU'IL LUI REPROCHE. « Lorsque
   "Enregistrer et fermer" est bloque par un ou plusieurs champs mal renseignes,
   je veux voir clairement quels champs sont concernes » (ticket du 22 septembre
   2026).

   Le refus s'ecrivait dans l'en-tete de la page, a un ecran de la fiche : on
   lisait « Exercice controle illisible » sans savoir laquelle des quinze cases
   le serveur visait. Le cadre la designe, la phrase dit ce qu'on attend, et les
   deux vivent sous `[aria-invalid]` plutot que sous une classe : c'est
   l'attribut que lit une synthese vocale, et la feuille s'y accroche aussi
   bien.

   Le cadre EPAISSIT au lieu de seulement rougir : un liseré d'un pixel change
   de teinte sans se voir dans une fiche qui en porte quinze, et la couleur
   seule ne dit rien a qui ne la distingue pas.

   LE SECOND SELECTEUR EST LE MEME, REPETE PLUS FORT. On ramene le curseur sur
   la premiere case en faute (voir `marquerFautes`), donc elle est focalisee au
   moment ou on la regarde, et l'anneau cyan du focus, plus specifique, la
   repeignait en case ordinaire : la seule case designee etait la seule a ne
   pas le paraitre. */
.fact-fiche-corps [aria-invalid="true"],
.fact-fiche-corps .aglae-input[aria-invalid="true"]:focus {
  border-color: var(--red);
  box-shadow: inset 0 0 0 1px var(--red);
}

.fact-faute {
  font-size: var(--fs-xs);
  color: var(--red);
  font-style: normal;
}

/* « CHERCHER UN MANDAT », ET LE MENU QU'IL OUVRE (ticket du 20 septembre 2026).

   Meme famille que la portee de l'Assistant -- surface claire, rangee a deux
   lignes, nom court dessus, denomination dessous -- et des classes a elle :
   celui-la se deploie DANS LE FLUX, a la place du fil, parce que la fenetre de
   ticket est etroite et en `overflow: hidden` ; celui-ci flotte sous son champ,
   dans une fiche qui ne rogne rien. Deux poses differentes pour une meme forme,
   et le meme jeu de jetons.

   La surface flottante prend ce que prennent les autres : `--radius`, fond
   blanc, bordure `--gray-3`, ombre portee. `--radius` et non `--radius-lg` :
   elle est collee sous un champ, dont elle prolonge le bord.

   Le `z-index` la pose au-dessus des champs voisins de la grille, et de rien
   d'autre : la fiche entiere est deja sur son propre fond (`z-index: 60`). */
.fact-mandat { position: relative; }

.fact-mandat-menu {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 5;
  margin-top: var(--espace-3xs);
  max-height: 17rem;
  overflow-y: auto;
  padding: var(--espace-3xs);
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

.fact-mandat-item {
  display: flex;
  align-items: center;
  width: 100%;
  padding: var(--espace-2xs) var(--espace-xs);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  text-align: left;
  font-family: var(--sans);
  cursor: pointer;
}

.fact-mandat-item:hover,
.fact-mandat-item.est-vise { background: var(--gray-2); }
.fact-mandat-item:focus-visible { outline: none; box-shadow: var(--anneau-champ); }

.fact-mandat-textes { display: flex; flex-direction: column; min-width: 0; flex: 1; }

.fact-mandat-nom {
  font-size: var(--fs-sm);
  color: var(--gray-6);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* La denomination legale sous le nom court, quand elle en differe : c'est elle
   qui leve le doute entre deux abreviations voisines, mais on reconnait son
   client au nom court, et c'est lui que le champ portera. */
.fact-mandat-sous {
  font-size: var(--fs-2xs);
  color: var(--gray-4);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Ce que la liste ne montre pas. Sans cette ligne, une recherche trop large
   rendait quarante rangs qui ressemblaient a tout le portefeuille, et on
   cessait d'affiner. */
.fact-mandat-reste {
  margin: 0;
  padding: var(--espace-2xs) var(--espace-xs);
  font-size: var(--fs-2xs);
  color: var(--gray-4);
}

/* QUI RECOIT LA FACTURE, CHOISI DANS LA FICHE (ticket du 18 septembre 2026).

   Le bloc traverse la grille sous le nom du client : une liste pour le
   destinataire principal, des cases pour les copies. Les cases sont posees en
   lignes qui se replient, et non en colonne : un client compte rarement plus de
   six interlocuteurs, et six lignes auraient pousse le reste de la fiche hors
   de l'ecran pour un renseignement qu'on ne touche pas a chaque facture.

   Les cases sont nues, donc deja habillees par la feuille
   (`input[type="checkbox"]`) : la classe ne sert qu'a poser la case a cote de
   son nom, ce que le `label` en colonne de `.fact-champs` ferait sinon l'un
   sous l'autre. */
.fact-destinataires {
  display: flex;
  flex-direction: column;
  gap: var(--espace-sm);
}

.fact-destinataires-copies {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs) var(--espace-md);
}

.fact-destinataires-titre {
  font-size: var(--fs-xs);
  color: var(--gray-5);
  width: 100%;
}

.fact-champs .fact-destinataire-copie {
  flex-direction: row;
  align-items: center;
  gap: var(--espace-2xs);
  cursor: pointer;
}

/* Celui qui est deja destinataire principal : la case reste lisible, elle ne
   se coche plus. Quelqu'un ne recoit pas deux fois la meme piece. */
.fact-champs .fact-destinataire-copie:has(input:disabled) {
  color: var(--gray-4);
  cursor: default;
}

/* LA CROIX QUI VIDE UNE DATE. « Si une date a deja ete renseignee, il faudrait
   pouvoir la supprimer pour revenir a une situation ou aucune date n'est
   prevue » (ticket du 18 septembre 2026) : un `input[type="date"]` rempli ne se
   vide qu'en effacant ses trois cases une a une, et le calendrier du navigateur
   ne propose que d'en choisir une autre.

   Elle est posee au bout du LIBELLE et non a cote du champ. A cote, elle lui
   prenait seize pixels : les deux dates devenaient plus courtes que les champs
   au-dessus et au-dessous d'elles dans la meme colonne de la grille, et le bord
   droit de la fiche se mettait a onduler. Sur la ligne du libelle, qui est du
   texte gris avec de la place a sa droite, elle ne coute rien a personne. */
.fact-date-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-2xs);
}

/* Le meme dessin que la croix des barres de recherche (`.toolbar-search-clear`),
   pour le meme geste : meme icone, meme gris, meme eclaircissement au survol.
   A la taille du libelle qu'elle termine, et non a celle des icones de
   commande : une croix plus haute que sa ligne aurait ecarte les deux champs de
   date de leurs voisins. */
.fact-date-effacer {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--gray-5);
  cursor: pointer;
}

.fact-date-effacer .icon {
  width: var(--icon-xs);
  height: var(--icon-xs);
}

.fact-date-effacer:hover { color: var(--gray-6); }
.fact-date-effacer[hidden] { display: none; }

.fact-fiche-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espace-sm);
  margin-top: var(--espace-md);
}

.fact-sous-bloc {
  margin-top: var(--espace-lg);
  padding-top: var(--espace-md);
  border-top: 1px solid var(--gray-2);
}

.fact-sous-bloc h4 {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-md);
  display: flex;
  gap: var(--espace-sm);
  align-items: baseline;
}

.fact-sous-total { font-size: var(--fs-xs); color: var(--gray-5); font-weight: 400; }

.fact-liste { list-style: none; margin: 0; padding: 0; }

.fact-liste li {
  display: flex;
  align-items: center;
  gap: var(--espace-sm);
  padding: var(--espace-2xs) 0;
  border-bottom: 1px solid var(--gray-2);
  font-size: var(--fs-sm);
}

.fact-liste li:last-child { border-bottom: 0; }
.fact-liste li span:nth-child(2) { margin-left: auto; }

/* LE RÈGLEMENT TIENT SUR UNE SEULE LIGNE. « Améliorer et compacter la
   présentation afin que toutes les informations du règlement tiennent sur une
   seule ligne [...] puisqu'il n'y aura généralement qu'un seul règlement par
   facture » (ticket du 22 septembre 2026).

   Le titre, la couverture et le règlement se suivent donc au lieu de s'empiler,
   et se replient d'eux-mêmes dès qu'il y en a plusieurs : c'est ce que fait
   `flex-wrap`, et c'est pour cela que la règle n'a pas de point de rupture
   écrit à la main. La ligne de base est l'alignement, pas le centre : le titre
   et la couverture n'ont pas la même taille de texte, et centrés ils auraient
   flotté l'un par rapport à l'autre. */
.fact-reglements-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--espace-2xs) var(--espace-md);
}

/* Le titre n'a plus de rang à lui : ce qui l'en séparait le renvoyait à la
   ligne suivante. */
.fact-sous-bloc-reglements h4 { margin-bottom: 0; }

.fact-liste-reglements {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--espace-2xs) var(--espace-sm);
  font-size: var(--fs-sm);
}

/* Le trait de séparation et le rang d'une ligne de liste n'ont plus lieu
   d'être quand la liste est une suite de mots : ce qui sépare ici est le point
   médian posé ci-dessous, et c'est le même signe qui sépare le titre du
   premier règlement. */
.fact-liste-reglements li {
  padding: 0;
  border-bottom: 0;
  gap: var(--espace-2xs);
  /* Sur une fenêtre étroite, un moyen de règlement long se replie sur deux
     lignes dans sa propre case ; centrés, la date et le bouton auraient
     flotté au milieu de ce bloc. Ils restent sur la première ligne du
     texte. */
  align-items: baseline;
}

.fact-liste-reglements li span:nth-child(2) { margin-left: 0; }

/* LA CORBEILLE SE CALE SUR LE MILIEU DU TEXTE, pas sur sa ligne de base. Le
   rang aligne ses mots par la ligne de base, ce qui est juste tant qu'il n'y a
   que des mots ; un bouton sans texte n'en a pas a poser, et la corbeille
   remontait d'un cheveu au-dessus de la date (suivi du 22 septembre 2026, qui
   a remplace le mot « Retirer » par l'icone). */
.fact-liste-reglements li .btn-icon-only { align-self: center; }

.fact-liste-reglements li span + span::before {
  content: "·";
  color: var(--gray-4);
  margin-right: var(--espace-2xs);
}

/* Le même point ENTRE deux règlements, jamais devant le premier. Devant, il
   servait à le détacher de la couverture ; mais dès qu'il y a deux règlements
   la liste passe à la ligne suivante, et ce point se retrouvait seul en tête de
   rang, à ponctuer un blanc. Ce qui détache la liste de la couverture est
   l'écart de la rangée, plus large que celui qui sépare les mots d'un même
   règlement. */
.fact-liste-reglements li + li::before { content: "·"; color: var(--gray-4); }

.fact-ajout-reglement {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-xs);
  margin-top: var(--espace-sm);
}

/* TROIS CASES À LA LARGEUR DE CE QU'ELLES REÇOIVENT. « Réduire la largeur des
   champs Date, Montant et Mode de règlement » (même ticket). Les trois
   partageaient un plancher de 8 rem, posé pour qu'aucune ne soit trop étroite,
   et qui donnait à « Montant » -- cinq chiffres -- la largeur d'une date. Elles
   prennent désormais chacune la place de sa valeur la plus longue : une date
   complète et son calendrier, un montant à six chiffres et ses centimes,
   « Virement » et son chevron. La saisie entière, bouton compris, tient sur une
   ligne. */
.fact-ajout-reglement .aglae-input { width: auto; min-width: 0; }
.fact-ajout-reglement input[type="date"] { width: 7.5rem; }
.fact-ajout-reglement input[data-reglement="montant"] { width: 6rem; }
.fact-ajout-reglement select[data-reglement="moyen"] { width: 7.5rem; }

.fact-panneau {
  margin-top: var(--espace-lg);
  padding: var(--espace-md);
  background: var(--gray-1);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
}

.fact-panneau h4 { margin: 0 0 var(--espace-sm); font-size: var(--fs-md); }
.fact-relance-corps { font-family: var(--sans); line-height: 1.5; }

/* Au téléphone et sur une fenêtre étroite, le tableau garde ses colonnes et
   défile plutôt que de les empiler : une facture se lit en ligne, et huit
   colonnes empilées en huit paragraphes ne se comparent plus. */
@media (max-width: 760px) {
  .fact-tableau { overflow-x: auto; }
  .fact-table { min-width: 44rem; }
  /* Le bloc de commande est deja en colonne depuis le 18 septembre 2026 ; ce
     qui lui reste a gagner ici est que ses commandes prennent toute la
     largeur, plutot que de se serrer a gauche d'un bloc qui fait l'ecran. La
     premiere colonne prend donc toute la place que la seconde laisse, ce qui
     ecarte la pastille jusqu'au bord droit comme le faisait l'espacement des
     deux rangees. */
  .fact-entete { grid-template-columns: 1fr max-content; }
}

/* LE MAPPING : L'EN-TETE DE CHAQUE ONGLET SORT DE SA TUILE (23 septembre
   2026, passe d'uniformisation). Chacun des cinq onglets s'ouvrait sur une
   tuile qui ne tenait que son titre, le lien Excel, parfois la bascule des
   modeles, et le texte d'aide : un cadre autour d'un en-tete, au-dessus des
   vraies tuiles. C'est desormais l'en-tete de l'onglet, pose a meme la page,
   comme ceux de la liste des clients ou de la facturation. Les ids, la
   bascule et le lien ne changent pas. */
.mapping-tete {
  margin: 0 0 var(--espace-md);
  padding: 0 var(--espace-2xs);
}
.mapping-tete > .toolbar { margin-bottom: var(--espace-2xs); }
.mapping-tete .tuile-titre { font-size: var(--fs-h3); }
.mapping-tete > .disclaimer { max-width: 72rem; margin-top: 0; }
.mapping-tete + .tuile { margin-top: 0; }

/* L'ASSISTANCE SUR TOUTE LA FENETRE (23 septembre 2026). Voir le gabarit :
   la colonne de lecture sert un texte suivi, pas six tuiles qui se lisent
   chacune pour elle-meme. La grille reprend l'ecart et le tassement des
   autres pages ; la marge haute qu'une tuile porte dans `.doc-wrap` y est
   rendue a la grille. */
.doc-wrap.doc-wrap-large { max-width: none; }
.doc-grille { margin-top: var(--espace-xl); }
.doc-grille > .tuile { margin: 0; }

/* L'ACCEPTATION, TASSEE COMME LES AUTRES ONGLETS (23 septembre 2026,
   « unifomise le design sur toutes les pages »). Les six sections se
   rangeaient par rangees : « La nomination » (270 px) laissait 400 px de blanc
   sous elle a cote de « L'entite et la mission », « Competences » restait
   seule a gauche d'une colonne vide. Elles passent par `grille-tassee.js`,
   comme l'onglet Mandat : chaque section monte a l'endroit le plus haut ou
   elle tient, dans l'ordre du document.

   L'ecart revient a celui des autres grilles (`--espace-md`), et les tuiles
   hors grille le reprennent : l'en-tete etait a 32 px des sections, la
   decision collee a elles, la tracabilite a 32 px de la decision. Trois
   ecarts pour une seule page. `#acceptation-sections.est-tassee` repete le
   `row-gap: 0` de la grille tassee parce que l'identifiant pose plus haut son
   propre `gap` et l'emporterait sur la classe. */
#acceptation-sections { gap: var(--espace-md); }
#acceptation-sections.est-tassee { row-gap: 0; }
.acceptation-page > .panel,
.acceptation-page > #acceptation-sections { margin-top: 0; margin-bottom: var(--espace-md); }

/* LA RANGEE DES EXERCICES TIENT DANS L'ECRAN (23 septembre 2026). Onze
   exercices, onze boutons : au telephone la rangee mesurait sept cents pixels
   et poussait toute la page de la synthese de groupe (ecran du groupe, onglet
   du mandat, projection) a defiler de cote. Le selecteur savait deja defiler
   en lui-meme (`overflow-x: auto` sur `.unit-toggle`) ; il lui manquait une
   largeur bornee, qu'un element flex n'a pas tant que `min-width` reste a
   `auto`. */
.synthese-groupe-exercices { max-width: 100%; min-width: 0; }
.synthese-groupe-exercices > .unit-toggle { min-width: 0; max-width: 100%; }

/* L'ECRAN DU GROUPE : LA LISTE A COTE DES REGLAGES (23 septembre 2026,
   passe d'uniformisation). Les six reglages occupaient deux rangees de trois
   tuiles, et « Structures du groupe », la seule tuile haute, tombait seule
   sous eux avec deux colonnes vides a sa droite : 500 px de blanc sur la
   largeur de la page. Sur un ecran large elle prend la troisieme colonne, de
   la premiere rangee a la derniere, et les reglages se rangent deux par deux
   a sa gauche. La liste ne fixe plus la hauteur des rangees (`contain`) : elle
   prend celle des reglages et defile dedans, comme elle defilait deja sous
   sa borne de 24rem. Les deux tuiles d'une rangee prennent la meme hauteur :
   deux cadres voisins qui s'arretent a trente pixels l'un de l'autre se
   lisent comme un oubli. */
@media (min-width: 1100px) {
  #groupe-ecran {
    grid-template-columns: repeat(2, minmax(0, 1fr)) minmax(0, 1.15fr);
    align-items: stretch;
  }
  #groupe-ecran > .groupe-structures {
    grid-column: 3;
    grid-row: 1 / span 3;
    align-self: stretch;
    display: flex;
    flex-direction: column;
  }
  #groupe-ecran > .groupe-structures > .reglages-groupe-membres {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  #groupe-ecran .groupe-structures .reglages-groupe-membres-liste {
    flex: 1 1 auto;
    contain: size;
    min-height: 14rem;
    max-height: none;
  }
}

/* LE DASHBOARD SYSTEME, AU PAS DU RESTE DU PRODUIT (23 septembre 2026,
   passe d'uniformisation).

   Le verdict, les neuf tuiles et leurs volets portaient `--radius-lg`, le
   barreau des surfaces flottantes : la page etait la seule du produit dont les
   tuiles avaient l'arrondi d'une fenetre de dialogue. Elles reprennent celui
   des tuiles, `--radius`.

   Les onglets portaient leur marge basse en plus de l'ecart de la colonne, et
   l'ecart lui-meme etait `--espace-lg` quand toutes les grilles de tuiles sont
   a `--espace-md` : quarante pixels entre les onglets et le verdict, vingt-
   quatre entre le verdict et les tuiles, seize entre deux tuiles. La colonne
   passe a l'ecart des tuiles, et la page a 1512 px tient dans la fenetre. */
.conso-verdict,
.conso-tuile,
.conso-volet .conso-bloc { border-radius: var(--radius); }
.conso-main { gap: var(--espace-md); }
.conso-main > .dossier-tabs { margin-bottom: 0; }

/* LE PIED DE LA PAGE CABINET (23 septembre 2026) : le renvoi vers la vision
   globale de la facturation, sans cadre, sous la tuile de l'onglet ouvert. La
   grille a onglets ne porte pas d'ecart entre ses enfants ; la marge haute le
   rend ici. */
.cabinet-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espace-2xs) var(--espace-md);
  margin-top: var(--espace-md);
}
.cabinet-pied .compte-renvoi .icon-btn {
  margin-left: calc(-1 * (var(--espace-sm) + 1px));
}
.cabinet-pied-aide {
  flex: 1 1 24rem;
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--gray-5);
}

/* LE JOURNAL, AU PAS DU RESTE DU PRODUIT (23 septembre 2026, passe
   d'uniformisation). Trois ecarts :

   1. Le titre de l'edition portait `--suivi-titre`, l'espacement pense pour
      les petites capitales : sur une phrase en minuscules a la taille d'un
      titre de page, il ecartait les lettres comme un en-tete de colonne.
   2. La colonne des editions heritait du soulignement des liens : chaque
      date et chaque sujet etaient soulignes, trente traits dans une liste
      de navigation. Un lien de liste se signale par son survol et son
      lisere, comme les onglets et la liste des clients. Le sujet, a 9,6 px,
      passe au barreau lisible au-dessus.
   3. Les cartes portaient `--radius-lg`, le rayon des surfaces flottantes ;
      posees dans la page, elles prennent celui des tuiles. */
.jm-entete-titre { letter-spacing: -.01em; font-weight: 600; }
.jm-aside-lien,
.jm-aside-lien:hover { text-decoration: none; }
.jm-aside-lien { transition: background .15s var(--ease); }
.jm-aside-lien:not(.actif) .jm-aside-date { color: var(--gray-6); }
.jm-aside-sujet { font-size: var(--fs-2xs); }
.jm-entete,
.jm-aside,
.jm-entree { border-radius: var(--radius); }
.jm-entree { box-shadow: none; }

/* LES NOTIFICATIONS, AU PAS DU RESTE DU PRODUIT (23 septembre 2026, passe
   d'uniformisation). Deux cartes pour deux phrases : la bande de l'appareil
   etait une tuile ombree haute de soixante-dix pixels pour une ligne d'etat,
   et l'etat vide une seconde tuile flottant au milieu du blanc. Une tuile se
   reserve a un ensemble. La bande devient une ligne d'etat mince, sans
   ombre ; l'etat vide redevient ce qu'il est ailleurs (les conversations,
   la consommation) : un rond et une phrase centres, sans cadre. */
.notifs-appareil {
  gap: var(--espace-sm);
  box-shadow: none;
  border-radius: var(--radius-sm);
  padding: var(--espace-xs) var(--espace-md);
  line-height: 1.45;
  margin-bottom: var(--espace-md);
}
.notifs-appareil .notifs-vide-rond {
  width: calc(var(--h-champ) * .75);
  height: calc(var(--h-champ) * .75);
}
.notifs-appareil .notifs-vide-rond .icon { width: var(--icon-sm); height: var(--icon-sm); }
.notifs-vide {
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--espace-md);
  max-width: 34rem;
  background: none;
  border: 0;
  box-shadow: none;
  padding: var(--espace-xl) var(--espace-lg);
}
.notifs-vide > .notifs-vide-rond {
  width: calc(var(--h-champ) * 1.6);
  height: calc(var(--h-champ) * 1.6);
}
.notifs-vide > .notifs-vide-rond .icon { width: var(--icon-xl); height: var(--icon-xl); }
/* Au telephone, le rond reste a gauche de la phrase ; seul le bouton passe
   dessous. Seul sur sa rangee, il laissait une ligne presque vide. */
@media (max-width: 600px) {
  .notifs-appareil { align-items: flex-start; }
  .notifs-appareil-texte { flex: 1 1 0; order: 0; }
}

/* LE VOTE DES NOMS, AU PAS DU RESTE DU PRODUIT (23 septembre 2026 :
   « reprends et uniformise le design sur toutes les pages, en particulier
   les nouvelles »).

   La page venait d'ailleurs : une page autonome, importee telle quelle,
   avec sa propre echelle (un titre a 27 px, des racines a 30 px, tout en
   graisse 700), son bouton actif noir, son bouton principal vert, ses
   arrondis de 9 et 12 px, et un contenu centre dans 1 420 px au lieu de la
   gouttiere commune. Rien n'y change de ce qu'elle fait ni de ce qu'elle
   dit ; seule la forme rejoint les jetons de `:root`.

   Pourquoi ici et non dans noms.css : cette feuille et le corps du gabarit
   sont regeneres par la fabrique du tri des noms. Chaque regle porte donc
   `body` en tete, ce qui la fait passer devant la leur quel que soit
   l'ordre de chargement. */
body .tn {
  --vert: var(--green);
  font-size: var(--fs-md);
}
body .tn button,
body .tn select {
  font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
  transition: background .15s var(--ease), border-color .15s var(--ease), color .15s var(--ease);
}
body .tn button:focus-visible,
body .tn select:focus-visible,
body .tn .combi:focus-visible,
body .tn .index a:focus-visible,
body .tn a.fin:focus-visible { outline-color: var(--cyan); }

/* Le choix actif et le bouton principal, dans la teinte de tout le site. */
body .tn button.on,
body .tn .bascule button.on {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #fff;
}
body .tn .bascule { border-radius: var(--radius-sm); border-color: var(--gray-3); }
body .tn .bascule button:not(.on):hover { background: var(--gray-1); }
body .tn button.prime {
  background: var(--cyan);
  border-color: var(--cyan);
}
body .tn button.prime:hover { background: var(--cyan-dark); filter: none; }

/* La barre : la gouttiere commune, des compteurs a l'echelle. */
body .tn .barre {
  padding: var(--espace-sm) var(--gouttiere);
  gap: var(--espace-sm) var(--espace-lg);
  background: #fff;
}
body .tn .outils { margin-left: 0; }
body .tn .cpt b { font-size: var(--fs-h3); }
body .tn .cpt span,
body .tn .sess label { font-size: var(--fs-2xs); }
body .tn .index a { border-radius: 999px; font-size: var(--fs-xs); }

/* L'ouverture : le titre de page, puis deux colonnes, l'explication a
   gauche et les chiffres a droite, au lieu de trois paragraphes pleine
   hauteur suivis d'une rangee de cartes. */
body .tn .ouverture {
  max-width: none;
  padding: var(--espace-xl) var(--gouttiere) 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: var(--espace-2xl);
  align-items: start;
}
body .tn .ouverture > h1 {
  grid-column: 1 / -1;
  font: 600 var(--fs-h1)/1.2 var(--sans);
  letter-spacing: -.01em;
  margin: 0 0 var(--espace-sm);
}
body .tn .ouverture > p {
  grid-column: 1;
  font-size: var(--fs-sm);
  line-height: 1.55;
  margin: 0 0 var(--espace-xs);
  max-width: 72ch;
}
body .tn .ouverture > .faits { grid-column: 2; grid-row: 2 / span 3; }
body .tn .ouverture > details.note-methode {
  grid-column: 1 / -1;
  max-width: none;
  margin-top: var(--espace-sm);
}
body .tn details.note-methode summary { font-size: var(--fs-2xs); }
body .tn details.note-methode div { font-size: var(--fs-sm); max-width: 90ch; }

/* Les sept chiffres : un seul bandeau coupe de filets, comme la tete de la
   facturation, et non sept cartes. */
body .tn .faits {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 0;
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  overflow: hidden;
}
body .tn .fait {
  flex: 1 1 7.5rem;
  flex-direction: column;
  gap: var(--espace-3xs);
  border: 0;
  border-radius: 0;
  box-shadow: -1px 0 0 var(--gray-2), 0 -1px 0 var(--gray-2);
  padding: var(--espace-sm) var(--espace-md);
}
body .tn .fait b { font: 600 var(--fs-h2)/1 var(--sans); font-variant-numeric: tabular-nums; }
body .tn .fait span { font-size: var(--fs-xs); }

/* Les racines : des tuiles du site, a la gouttiere commune. */
body .tn main#racines {
  max-width: none;
  padding: var(--espace-lg) var(--gouttiere) calc(52px + var(--espace-xl) * 3);
  gap: var(--espace-md);
}
body .tn .racine {
  border-color: var(--gray-3);
  border-radius: var(--radius);
  box-shadow: none;
}
body .tn .rtete { background: var(--gray-1); padding: var(--espace-md) var(--espace-lg); }
body .tn .rtete h2 { font: 600 var(--fs-h2)/1.1 var(--sans); letter-spacing: -.01em; }
body .tn .rtete .gl { font-size: var(--fs-md); }
body .tn .rtete .rq,
body .tn .rtete .rc { font-size: var(--fs-xs); }
body .tn .bilan .lab { font-size: var(--fs-3xs); }
body .tn .fin { border-radius: var(--radius-xs); font-size: var(--fs-xs); }
body .tn .combi { padding: var(--espace-sm) var(--espace-lg); }
body .tn .cb-nom h3 { font: 600 var(--fs-h3)/1.15 var(--sans); letter-spacing: -.01em; }
body .tn .cb-nom small { font-size: var(--fs-xs); }
body .tn .cb-note b { font-size: var(--fs-h3); }
body .tn .ext .c { border-radius: var(--radius-xs); }
body .tn .morceau,
body .tn .avert { border-radius: var(--radius-sm); }
body .tn .puce { border-radius: 999px; }

/* Le pied : il laisse la place du bouton d'assistance, qui masquait
   « Voir le releve ». */
body .tn .pied {
  padding: var(--espace-xs) calc(52px + var(--espace-xl) * 2) var(--espace-xs) var(--gouttiere);
  box-shadow: var(--shadow-sm);
}
body .tn .pied .etatmot { font-size: var(--fs-xs); }
body .tn .pied button { white-space: nowrap; }

/* Les deux surfaces flottantes : la forme commune. */
body .tn #nouv,
body .tn #rel textarea { border-radius: var(--radius-lg); }
body .tn #nouv { border-color: var(--gray-3); box-shadow: var(--shadow-lg); }
body .tn #nouv h3 { font: 600 var(--fs-h3)/1.2 var(--sans); }
body .tn #nouv input { border-radius: var(--radius-sm); }
body .tn #avis { border-radius: var(--radius); }

@media (max-width: 820px) {
  body .tn .ouverture { grid-template-columns: minmax(0, 1fr); }
  body .tn .ouverture > .faits { grid-column: 1; grid-row: auto; margin-top: var(--espace-sm); }
  body .tn .fait { flex-basis: 40%; }
  body .tn .barre,
  body .tn .ouverture,
  body .tn main#racines { padding-left: var(--espace-md); padding-right: var(--espace-md); }
  body .tn .pied { padding-left: var(--espace-md); }
}

/* LA PAGE FACTURATION, AU PAS DU RESTE DU PRODUIT (21 septembre 2026 :
   « reprends le design de la zone facturation et mets-le au niveau du reste
   de notre design »).

   Trois ecarts la separaient des autres tableaux de bord, et les trois sont
   repris ici sans qu'aucun id, aucun champ ni aucun geste ne change :

   1. SEPT CARTES POUR UNE SEULE LECTURE. Le bloc de commande et les six ou
      sept carreaux etaient chacun leur tuile, bordee et ombree : sept cadres
      alignes pour ce qui se lit d'un seul regard, et un « 2 028 969,76 € »
      qui se cassait en deux lignes, l'euro seul en dessous. Ils forment
      desormais UN bandeau, une seule tuile coupee de filets, comme les
      mosaiques du tableau de bord systeme. Le filet est une ombre d'un pixel
      portee a gauche et en haut de chaque case, rognee par le bandeau : il
      separe donc ce qui se touche, et rien d'autre, quelle que soit la facon
      dont la rangee se replie.

   2. UNE PAGE QUI S'ARRETAIT AU TIERS DE LA FENETRE. Sur ordinateur, la
      liste des lignes tient maintenant toute la hauteur qui reste et defile
      en elle-meme, son en-tete colle au bord, comme la liste des clients.
      La vision globale du cabinet passe AU-DESSUS d'elle : c'est la synthese
      qu'on vient lire en ouvrant « Cabinet », les lignes en sont le detail.
      Au telephone la page defile comme avant, dans l'ordre du gabarit : un
      tableau qui defile dans une page qui defile ne se manie pas au pouce.

   3. SEPT PILULES POUR UN SEUL CHOIX. Les filtres sont un controle segmente,
      dessine comme le choix « Moi / Cabinet » du bandeau : un seul cadre, le
      segment actif porte le fond. */
.fact-tete {
  gap: 0;
  background: #fff;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: var(--espace-md);
}
.fact-tete > .fact-entete {
  padding: var(--espace-sm) var(--espace-lg);
  background: #fff;
}
/* Les cases se rangent en flex et non en grille : quand la rangee se replie,
   la derniere s'etire sur ce qui reste au lieu de laisser une case vide a
   cote d'elle. */
.fact-tete > .fact-chiffres {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
}
/* LA CHASSE D'UN CARREAU EST CELLE DE SON MONTANT, PLUS CELLE DE SON TITRE.
   « Reduis autant que possible la largeur des blocs de la frise afin qu'ils
   puissent tous tenir sur une seule ligne » (suivi du 22 septembre 2026).

   Neuf rem et demi tenaient « FACTURATION REALISEE » sur un rang ; les titres
   tiennent maintenant en un ou deux mots et les pieds en deux (« 21 factures »),
   si bien que le plus large de ce qu'un carreau porte est redevenu son montant,
   « 675 550 € », qui ne se replie jamais. Sept rem le logent avec son
   rembourrage, et six carreaux a sept rem tiennent a cote du bloc de commande
   la ou six a neuf rem et demi passaient a la ligne des que la fenetre
   descendait sous mille trois cents pixels. */
.fact-tete .fact-carreau {
  flex: 1 1 7rem;
  border: 0;
  border-radius: 0;
  box-shadow: -1px 0 0 var(--gray-2), 0 -1px 0 var(--gray-2);
  justify-content: center;
  padding: var(--espace-sm) var(--espace-md);
}
.fact-tete .fact-carreau-titre { font-size: var(--fs-2xs); }

/* UN PIED VIDE GARDE SA LIGNE. Depuis le 22 septembre 2026, deux carreaux n'en
   ont pas : « Prevu », dont le suivi supprime la mention, et « Pour un tiers »,
   dont le nombre de factures est monte a la place du montant. Les carreaux
   centrent leur contenu sur la hauteur de la rangee, que le bloc de commande
   tient : sans cette ligne reservee, les deux montants de ces carreaux
   descendaient d'un demi-rang sous les quatre autres, et c'est le genre
   d'ecart qu'on voit sans savoir le nommer. */
.fact-carreau-pied:empty::before { content: "\00a0"; }
.fact-tete .fact-carreau-valeur {
  font-size: var(--fs-h3);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* La case qui porte une alerte ou une part a signaler garde sa teinte pale
   (regles plus haut) et gagne un trait de sa couleur au bord haut : le fond
   seul, sans cadre, se lisait comme un reflet. */
.fact-tete .fact-carreau[data-alerte="1"] {
  box-shadow: -1px 0 0 var(--gray-2), inset 0 3px 0 var(--red);
}
.fact-tete .fact-carreau[data-carreau="tiers"] {
  box-shadow: -1px 0 0 var(--gray-2), inset 0 3px 0 var(--blue);
}

/* Les filtres, en segments. Le cadre les tient sur une rangee ; a l'etroit,
   c'est la rangee qui defile, pas les segments qui se replient sur deux
   lignes dans un cadre qui n'en a qu'une. */
.fact-filtres {
  flex-wrap: nowrap;
  gap: 0;
  max-width: 100%;
  overflow-x: auto;
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-sm);
  scrollbar-width: none;
}
.fact-filtre {
  flex: none;
  border: 0;
  border-radius: 0;
  padding: var(--espace-2xs) var(--espace-sm);
  white-space: nowrap;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.fact-filtre + .fact-filtre { border-left: 1px solid var(--gray-3); }
.fact-filtre.actif { background: var(--cyan); border-color: var(--gray-3); color: #fff; }
.fact-filtre:not(.actif):hover { background: var(--gray-1); }
.fact-bloc-tete { margin-bottom: var(--espace-sm); }

/* L'en-tete du tableau, du gris et de la taille des en-tetes de la liste des
   clients. */
.fact-table th {
  font-size: var(--fs-2xs);
  font-weight: 500;
  color: var(--gray-4);
  background: #fff;
}
.fact-table tbody tr { transition: background .15s var(--ease); }

/* La vision globale : le titre, puis le choix du decoupage sur la meme
   rangee. La liste prenait toute la largeur de la tuile pour ecrire « Par
   cabinet ». Le conteneur que peint le script s'efface (`display: contents`)
   pour que sa rangee de tete se range a cote du titre. */
.fact-bloc#fact-bloc-global {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: center;
  column-gap: var(--espace-md);
}
#fact-bloc-global > .tuile-titre { margin: 0 0 var(--espace-sm); }
#fact-groupes { display: contents; }
#fact-groupes > .fact-groupe-tete { margin-bottom: var(--espace-sm); }
#fact-groupes > :not(.fact-groupe-tete) { grid-column: 1 / -1; }
#fact-groupement.aglae-input { width: auto; font-size: var(--fs-sm); }
.fact-groupe-rang > summary {
  padding-left: var(--espace-xs);
  padding-right: var(--espace-xs);
  border-radius: var(--radius-sm);
  transition: background .15s var(--ease);
}
.fact-groupe-rang > summary:hover { background: var(--gray-1); }

/* LA PAGE TENUE PAR LA FENETRE, sur ordinateur seulement (voir le 2 plus
   haut). La hauteur vient du corps, comme pour `app-main-pleine` ; la classe
   elle-meme n'est pas reprise, ses regles visent un panneau unique. */
@media (min-width: 821px) {
  body:has(.fact-page) {
    height: 100vh;
    height: 100dvh;
  }
  .app-main.fact-page {
    display: flex;
    flex-direction: column;
    gap: var(--espace-md);
    min-height: 0;
    padding-top: var(--espace-lg);
    padding-bottom: var(--espace-md);
  }
  .fact-page > * { flex: none; }
  .fact-page > *,
  .fact-page > .tuile + .tuile { margin: 0; }
  .fact-page > #fact-bloc-attente { order: 1; max-height: 30vh; overflow: auto; }
  .fact-page > #fact-bloc-global { order: 2; max-height: 42vh; overflow: auto; }
  .fact-page > .fact-bloc-lignes {
    order: 3;
    flex: 1 1 auto;
    min-height: 16rem;
    display: flex;
    flex-direction: column;
    padding-bottom: 0;
  }
  /* Le tableau defile dans sa tuile ; le creux du bas laisse passer la
     derniere ligne au-dessus du bouton d'assistance, comme sous la liste des
     clients. */
  .fact-bloc-lignes > .fact-tableau {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding-bottom: calc(52px + var(--espace-xl) * 2);
  }
  .fact-bloc-lignes .fact-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    border-bottom: 0;
    box-shadow: inset 0 -1px 0 var(--gray-3);
  }
}

/* Au telephone, le bloc de commande prend sa rangee et les chiffres passent
   deux par deux, un cran plus petits : « 1 820 569,76 € » doit tenir entier
   dans une demi-largeur d'ecran. */
@media (max-width: 820px) {
  .fact-tete > .fact-entete {
    flex-basis: 100%;
    padding: var(--espace-sm) var(--espace-md);
  }
  .fact-tete .fact-carreau {
    flex-basis: 40%;
    padding: var(--espace-xs) var(--espace-sm);
  }
  .fact-tete .fact-carreau-valeur { font-size: var(--fs-xl); }
}

/* LA FENETRE DU MEMO : une surface flottante qui reste ouverte pendant qu'on
   travaille.

   « Ce bouton doit ouvrir une fenetre separee intitulee "Memo" [...] La
   fenetre Memo doit pouvoir rester ouverte pendant que l'utilisateur continue
   a naviguer dans les autres menus » (ticket RUGBY CLUB DE DRANCY du
   17 septembre 2026).

   Meme famille que les autres surfaces flottantes du produit, donc meme forme :
   `--radius-lg`, fond blanc, bordure `--gray-3`, ombre portee. Ce qui la
   distingue est ce qu'elle N'A PAS : pas de voile derriere elle. Une fenetre
   modale prend le clavier et eteint la page, et c'est exactement ce que le
   ticket interdit -- on doit pouvoir cliquer un onglet pendant qu'elle est la.

   Son `z-index` est celui des surfaces qui flottent au-dessus de la page sans
   la couvrir (le meme barreau que les infobulles et les menus), en dessous des
   fenetres modales : une modale ouverte par-dessus doit passer devant elle. */
.memo-fenetre {
  position: fixed;
  /* A gauche du bouton d'assistance, qui occupe le coin (52 px de large,
     1,5 rem de marge, et il passe devant tout) : une fenetre posee dessus
     cacherait la poignee par laquelle on la redimensionne. Sa place se retient
     des qu'on la deplace, celle-ci n'est que celle du premier jour. */
  right: calc(52px + 3rem);
  bottom: var(--espace-lg);
  z-index: 60;
  display: flex;
  flex-direction: column;
  width: min(24rem, calc(100vw - 2 * var(--espace)));
  height: min(22rem, calc(100vh - 2 * var(--espace-lg)));
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-lg);
  background: #fff;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  /* On la redimensionne par son coin, comme une vraie fenetre : un memo tient
     en trois lignes un jour et en deux pages le lendemain. */
  resize: both;
  min-width: 16rem;
  min-height: 12rem;
}
.memo-fenetre[hidden] { display: none; }

.memo-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espace-sm);
  padding: var(--espace-sm) var(--espace);
  border-bottom: 1px solid var(--gray-2);
  background: var(--gray-1);
  /* La prise par laquelle on deplace la fenetre. Le curseur le dit avant le
     premier essai, ce qu'aucune phrase ne ferait. */
  cursor: grab;
  user-select: none;
}
.memo-fenetre.memo-en-deplacement .memo-tete { cursor: grabbing; }
.memo-fenetre.memo-en-deplacement { box-shadow: var(--shadow-lg); }

.memo-titre {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.memo-fermer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-sm);
  height: var(--h-sm);
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--gray-5);
  cursor: pointer;
  transition: background .12s var(--ease), color .12s var(--ease);
}
.memo-fermer:hover { background: var(--gray-2); color: var(--gray-6); }
.memo-fermer .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* La zone de saisie occupe tout ce qui reste : un memo est fait pour etre
   ecrit, pas pour etre encadre. Sans bordure ni arrondi propres -- c'est la
   fenetre qui porte la forme, et une boite dans la boite se verrait. */
.memo-texte {
  flex: 1;
  min-height: 0;
  border: none;
  outline: none;
  resize: none;
  padding: var(--espace);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--gray-6);
  background: #fff;
}
.memo-texte::placeholder { color: var(--gray-4); }

.memo-etat {
  margin: 0;
  padding: var(--espace-2xs) var(--espace) var(--espace-sm);
  font-size: var(--fs-2xs);
  color: var(--gray-5);
  min-height: 1.2em;
}
.memo-etat-echec { color: var(--orange-dark); }

/* ------------------------------------------------------------------------
   LES ATTESTATIONS DU COMMISSAIRE AUX COMPTES, dans l'Assistant.

   « Prévoit une rubrique Attestations entre Type de mission et Etats
   financiers [...] cela doit se générer via l'assistant comme pour le
   rapport » (ticket FEDESAP du 21 septembre 2026).

   Une tuile faite des blocs de la clôture (`.arrete-bloc`), parce que c'est
   le même geste au même endroit : rien à redessiner, seulement ce que la
   clôture n'a pas -- une rangée de gestes, un formulaire, un catalogue de
   modèles. Ces trois-là suivent le dessin du questionnaire d'avant émission
   juste au-dessus, pour la même raison.
   ------------------------------------------------------------------------ */

/* La rangée des gestes d'une attestation : remplir, relire, sortir, déposer.
   Ils se replient sur une ligne étroite plutôt que de déborder, et gardent
   l'interligne d'une ligne de texte -- ce sont des gestes offerts dans une
   ligne, pas des boutons de formulaire (voir `.arrete-emettre`). */
.attestation-gestes {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--espace-xs);
  margin-top: var(--espace-2xs);
}

/* Le document du client relié à l'attestation, nommé sur la ligne : c'est lui
   qui dit qu'une attestation est complète, puisqu'elle atteste des
   informations qui y figurent. L'absence se lit en gris pâle par
   `.arrete-rapport-attendu`, comme un rapport qui manque. */
.attestation-annexe {
  display: block;
  color: var(--gray-5);
  font-size: var(--fs-xs);
}

/* Le formulaire d'une attestation, sous ses gestes. Le dessin du questionnaire
   d'avant émission (`.arrete-questionnaire`) : même fond, même filet, même
   arrondi -- c'est le même objet, un formulaire court qui se déplie sous la
   ligne qu'il complète. */
.attestation-formulaire {
  margin-top: var(--espace-2xs);
  padding: var(--espace-sm);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: var(--gray-1);
}

.attestation-champ { margin-bottom: var(--espace-xs); }

.attestation-champ label {
  display: block;
  margin-bottom: var(--espace-3xs);
  color: var(--gray-6);
}

.attestation-champ input,
.attestation-champ textarea,
.attestation-champ select { width: 100%; }

.attestation-champ .reglages-hint-inline {
  display: block;
  margin-top: var(--espace-3xs);
  color: var(--gray-4);
}

/* Les diligences libres : une case qui se répète, chacune dans son bloc.

   « Prévoir un bouton "+" permettant d'ajouter plusieurs diligences, chacune
   dans un bloc distinct » (ticket FEDESAP du 21 septembre 2026). Les blocs
   s'empilent, chacun avec sa croix au bout ; le « + » ferme la pile. Aucun
   filet autour d'eux : ils sont déjà dans le cadre du formulaire, et un
   second cadre à l'intérieur du premier aurait fait croire à une rubrique
   séparée alors que ces phrases entrent dans la liste du modèle. */
.attestation-liste {
  display: flex;
  flex-direction: column;
  gap: var(--espace-3xs);
}

.attestation-liste-bloc {
  display: flex;
  align-items: flex-start;
  gap: var(--espace-3xs);
}

.attestation-liste-bloc textarea { flex: 1 1 auto; min-width: 0; }

/* La croix garde la hauteur de la première ligne du bloc : alignée sur le
   texte qu'elle retire, et non centrée sur une zone qui grandit à la frappe. */
.attestation-liste-bloc button { flex: 0 0 auto; margin-top: var(--espace-3xs); }

.attestation-liste-plus { align-self: flex-start; }

/* Le document à annexer, désigné plutôt que saisi : le nom de la pièce et les
   deux gestes qui l'ouvrent ou la retirent, sur une seule ligne. Le champ
   porte le nom et non l'identifiant -- c'est le nom qu'on relit pour savoir ce
   qui sera relié --, et il est en lecture seule parce qu'on ne tape pas un nom
   de pièce : on va la chercher là où elle est rangée. */
.attestation-annexe-choix {
  display: flex;
  align-items: center;
  gap: var(--espace-xs);
}

.attestation-annexe-choix input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--gray-6);
}

.attestation-annexe-choix button { flex: 0 0 auto; white-space: nowrap; }

/* Le catalogue des six modèles, sous la liste.

   Une liste dépliée et non un menu déroulant : on choisit un modèle sur ce
   qu'il atteste, pas sur son nom. Chaque entrée porte donc son libellé et les
   deux lignes qui disent ce qu'elle couvre, et elles tiennent en colonnes dès
   que la tuile est assez large. */
.attestation-catalogue { margin-top: var(--espace-sm); }

.attestation-catalogue h4 {
  margin: 0 0 var(--espace-xs);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.attestation-catalogue ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--espace-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.attestation-modele {
  display: block;
  width: 100%;
  padding: var(--espace-xs) var(--espace-sm);
  border: 1px solid var(--gray-2);
  border-radius: var(--radius);
  background: #fff;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color .15s var(--ease), background .15s var(--ease);
}

.attestation-modele:hover:not([disabled]),
.attestation-modele:focus-visible {
  border-color: var(--cyan);
  background: var(--cyan-pale);
}

.attestation-modele strong {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--gray-6);
}

.attestation-modele span {
  display: block;
  margin-top: var(--espace-3xs);
  font-size: var(--fs-xs);
  color: var(--gray-5);
}
