/* =====================================================================
   KHAZINA v2 — Dictionnaire vintage × moderne (100 % local)
   Papier d'archive, vert sceau, serif d'apparat, composants dessinés.
   ===================================================================== */
/* --------------------------------------------------------------------------
   L'attribut « hidden » doit toujours l'emporter. Sans cette règle, la
   moindre déclaration « display » ailleurs le neutralise en silence — piège
   classique qui laisse apparaître des zones censées être masquées.
   -------------------------------------------------------------------------- */
[hidden] { display: none !important; }

:root {
  --h-topbar: 55px;
  /* R1492 — LA HAUTEUR DU PIED, NOMMÉE UNE FOIS. Elle était écrite en
     clair à trois endroits (la barre du pied, le corps, le panneau
     d'aide) et OUBLIÉE à un quatrième : la barre latérale, qui passait
     donc sous le pied et s'y faisait manger son bouton du bas.
     Une mesure recopiée est une mesure qu'on oubliera quelque part. */
  --h-pied: 28px;
  /* R447 — LA MESURE COMMUNE au bloc de recherche et au logo.
     Quarante-six pixels dans un en-tête de cinquante-cinq : quatre et demi de
     marge en haut comme en bas. C'est le plus grand format où les deux
     tiennent encore sans toucher les bords.
     Elle est relevée de quarante à quarante-six : les aligner sur l'ancienne
     valeur aurait RAPETISSÉ le logo, qui faisait quarante-huit — l'inverse de
     ce qu'on cherchait. Le bloc de recherche grandit donc avec lui, ce qui
     lui va bien : un champ de recherche gagne à être franc. */
  --h-recherche: 46px;
  --h-filtres: 0px;   /* mesurée au chargement, ceci est le repli */
  --ctl: 36px;
  --bg: #F5F4EF;
  --panel: #FFFFFF;
  --ink: #21302E;
  --muted: #6A7570;
  --faint: #98A19B;
  --line: #E5E2D8;
  --line2: #CFCBBD;
  /* Fonds nommés d'après le papier : --paper est la surface de la page,
     --paper2 le ton légèrement plus soutenu des encarts. Sans ces deux
     définitions, toute règle « background: var(--paper) » restait sans effet. */
  --paper:  #FFFFFF;
  --paper2: #FAF9F5;
  /* Fonds d'état, accordés aux couleurs de texte correspondantes. */
  --err-bg:  #FBEDEA;
  --warn-bg: #FDF4E3;
  --info-bg: #E6F4EF;
  /* Largeur de base d'une carte de document dans la grille. */
  --cardw: 200px;
  /* Accent du type de fichier : chaque classe .ext-* la redéfinit. Cette
     valeur sert de repli pour un format inconnu. */
  --xc: #6B675E;
  /* Rembourrage latéral du conteneur principal. Toute marge négative qui
     veut couvrir la pleine largeur doit s'y référer. */
  --pad-main: 32px;
  --seal: #0E6B5C;
  --seal-dark: #0A5044;
  --seal-soft: #E4F1EC;
  --seal-ghost: #F0F7F4;
  /* R573 — LE BLEU DE LA SÉLECTION : ce qui est CHOISI (onglet ouvert,
     version regardée, mode retenu, filtre actif, carte cochée) se dit en bleu
     clair ; le vert reste à ce qui est VALIDÉ, et aux gestes de la maison. */
  --sel: #2F6FA8; --sel-dark: #235684; --sel-bg: #EAF3FB; --sel-line: #BBD6EE;
  --gold: #C29A3A;
  /* R1050 — L'AMBRE DE LA VISITE. Exactement au milieu de l'or (#C29A3A) et
     de l'orange brûlé de la maison (--warn #9A5B00) : une couleur chaude qui
     DÉSIGNE sans imiter le vert du sceau, avec lequel elle s'accorde. */
  /* R1066 — SIX VARIABLES FANTÔMES ont été rattachées ici : --radius, --r1,
     --r2, --texte, --ink-2 et --panel2 étaient EMPLOYÉES sans avoir jamais
     été déclarées. Une var() sans repli qui ne résout pas rend la
     déclaration INVALIDE : le navigateur l'ignore en silence. Vingt-deux
     déclarations mortes — des coins qui ne s'arrondissaient pas, des
     couleurs qui ne s'appliquaient pas — corrigées d'un coup. */
  --ambre: #B8822A;  --ambre-doux: rgba(184, 130, 42, .38);
  /* R1060 — L'ORANGE DU RAPPEL. L'ambre bronze convient AU-DEDANS de la
     visite (il désigne sans crier) ; au pied de page, il paraissait terne,
     presque gris. Le bouton qui appelle mérite un orange franc. */
  --ambre-vif: #E07A1F;
  --seal2: #18A184;
  --grad: linear-gradient(135deg, #0E6B5C 0%, #18A184 100%);
  --grad-warm: linear-gradient(135deg, #C29A3A, #E0BE6A);
  --shadow-pop: 0 6px 18px rgba(14,107,92,.13), 0 2px 6px rgba(33,48,46,.07);
  --warn: #9A5B00;  --warn-bg: #FCF1DC;
  --err:  #A93A31;  --err-bg:  #FBEAE8;
  --info: #1F5FA8;  --info-bg: #E8F0FA;
  --r: 12px;
  --shadow: 0 1px 2px rgba(33,48,46,.05), 0 4px 14px rgba(33,48,46,.05);
  --serif: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  --sans: 'Segoe UI', Tahoma, system-ui, Arial, sans-serif;
  --mono: Consolas, 'Courier New', monospace;
  font-size: 15px;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background:
    radial-gradient(900px 420px at 85% -140px, rgba(24,161,132,.10), transparent 60%),
    radial-gradient(700px 380px at -140px 30%, rgba(194,154,58,.07), transparent 55%),
    var(--bg);
  color: var(--ink); font-family: var(--sans); line-height: 1.55; min-height: 100vh;
}
@keyframes fadeUp { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
@keyframes floaty { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
.main > * { animation: fadeUp .38s ease both; }

/* L'animation d'apparition, avec « both », laisse un plan d'affichage
   PERMANENT sur chaque bloc de la page — même une fois terminée. Ce plan
   emprisonne le panneau de période : quel que soit son niveau, il reste
   sous les blocs qui suivent. Élever la barre le libérerait, mais la
   déplacerait. On retire donc l'animation UNE FOIS TERMINÉE : le bloc a
   déjà son aspect final, rien ne bouge, et le panneau retrouve sa liberté. */
.main > *.anim-finie { animation: none; }
.main > *:nth-child(2) { animation-delay: .04s; } .main > *:nth-child(3) { animation-delay: .08s; }
.main > *:nth-child(4) { animation-delay: .12s; } .main > *:nth-child(5) { animation-delay: .16s; }
.main > *:nth-child(n+6) { animation-delay: .2s; }
a { color: var(--seal); text-decoration: none; }
a:hover { color: var(--seal-dark); }
.ic { vertical-align: -3px; flex-shrink: 0; }
/* R857 : les icônes de la maison sont tracées au TRAIT ; « play » est une forme
   PLEINE — un triangle creux se lit mal à quatorze pixels, et son contour se
   confond avec le chevron voisin. */
.ic-plein { fill: currentColor; stroke: none; }
mark { background: #FFF3B0; color: #5C4300; border-radius: 3px; padding: 0 2px; }
::selection { background: var(--seal-soft); }

/* ------------------------- Typo « dictionnaire » -------------------- */
.entry-title { font-family: var(--serif); font-weight: 400; letter-spacing: .1px; }
.cap { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
/* R615 — L'AIR SOUS L'EN-TÊTE NE DÉPEND PLUS DES BOUTONS. L'espace donné en
   R565-R567 ne paraissait que lorsque la rangée d'actions se repliait : sans
   boutons, ou quand ils tenaient sur la ligne du titre, le trait remontait
   contre les pastilles. Le trait garde donc toujours la même distance. */
.pagehead + .rule-double { margin-top: 12px; }
/* R621 — L'AIR SEULEMENT QUAND IL N'Y A PAS DE BOUTONS. Sans rangée
   d'actions, le trait remontait contre les pastilles (R615) ; avec des
   boutons, l'espace ajouté faisait un trou. La classe « pagehead-nu »,
   posée par la page quand aucun bouton n'a été rendu, donne l'air à ces
   en-têtes-là seulement. Le repli « :has() » sert aux pages qui n'ont pas
   à la poser ; les navigateurs sans « :has() » gardent l'écart de base. */
.pagehead.pagehead-nu + .rule-double,
.pagehead:not(:has(.actions .btn, .actions button, .actions a)) + .rule-double { margin-top: 28px; }
.rule-double {
  border: 0; height: 3px; margin: 12px 0 16px; border-radius: 999px;
  background: linear-gradient(90deg, var(--seal) 0%, var(--seal2) 34%, var(--gold) 72%, transparent 100%);
  background-size: 220% 100%; animation: ruleIn .9s ease both;
}
@keyframes ruleIn { from { background-position: 120% 0; opacity: 0; } to { background-position: 0 0; opacity: 1; } }
.middot { color: var(--gold); padding: 0 4px; }

/* ------------------------- Barre haute ------------------------------ */
.topbar {
  /* R442 — HAUTEUR FIXE, ENFIN DÉCLARÉE. Elle valait cinquante-cinq pixels par
     accident : huit de marge, trente-six de contenu, huit encore, plus le
     trait. Rien ne la tenait — un élément plus haut l'aurait fait grandir sans
     qu'on s'en aperçoive, et la barre latérale, calée sur cette mesure, se
     serait décalée d'autant.
     Elle est désormais DÉCLARÉE : le contenu s'y plie, elle ne se plie plus au
     contenu. C'est ce qui permet au logo de l'occuper de bord à bord. */
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 14px;
  height: var(--h-topbar, 55px); box-sizing: border-box;
  background: var(--panel);
  border-bottom: 1px solid var(--line); padding: 0 16px;
}
.brand { display: flex; align-items: center; gap: 11px; }
.brand:hover .brand-mark { transform: rotate(-5deg) scale(1.05); box-shadow: 0 1px 3px rgba(33,48,46,.06); }
.brand-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 8px;
  background: var(--grad); color: #fff; font-size: 20px; font-family: var(--serif);
  box-shadow: 0 1px 3px rgba(33,48,46,.06);
  transition: transform .18s, box-shadow .18s;
}
.brand-txt { display: flex; flex-direction: column; line-height: 1.05; }
.brand-txt b { font-family: var(--serif); font-size: 17px; font-weight: 400; color: var(--ink); letter-spacing: .3px; }
.brand-txt i { font-style: italic; font-family: var(--serif); font-size: 11px; color: var(--faint); }
.topsearch {
  /* R447 — HAUTEUR DÉCLARÉE, comme pour l'en-tête. Elle résultait jusqu'ici du
     texte et des marges : personne ne pouvait dire combien elle valait, et le
     logo ne pouvait donc pas s'y caler. Une mesure nommée, et les deux s'y
     réfèrent — si l'une change un jour, l'autre suit d'elle-même. */
  flex: 1; max-width: 520px; margin: 0 auto;
  display: flex; align-items: center; gap: 9px;
  height: var(--h-recherche, 40px); box-sizing: border-box;
  background: var(--bg); border: 1px solid var(--line2);
  border-radius: 999px; padding: 0 16px; color: var(--muted);
  transition: box-shadow .15s, border-color .15s;
}
.topsearch:focus-within { border-color: var(--seal2); box-shadow: 0 1px 3px rgba(33,48,46,.06); background: #fff; transform: scale(1.012); }
.topsearch { transition: box-shadow .18s, border-color .18s, transform .18s; }
.topsearch input { border: 0; background: transparent; outline: 0; flex: 1; font: inherit; color: var(--ink); min-width: 0; }
.badgebtn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--warn-bg); color: var(--warn);
  border-radius: 999px; padding: 8px 12px; font-size: 13px;
}
/* R785 — UNE PASTILLE GARDE SA COULEUR AU SURVOL. « À vérifier » est un LIEN,
   pas « À répondre » ni « À valider » : la règle générale « a:hover → vert
   foncé » ne l'attrapait qu'elle, et son encre ambrée virait au vert dès que
   la souris passait — trois pastilles côte à côte, une seule qui change.
   C'est le même remède qu'en R560 pour les boutons-liens : la pastille garde
   SA teinte, et l'on marque le survol par le FOND, qui vaut pour toutes. */
a.badgebtn:hover, a.badgebtn:focus-visible { color: var(--warn); }
.badgebtn:hover { background: #F8E9CE; }
.badgebtn.notif:hover { background: var(--seal-soft); }
a.badgebtn.notif:hover { color: var(--seal-dark); }
.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 8px; border: 0;
  background: transparent; color: var(--muted); cursor: pointer;
}
.iconbtn:hover { background: var(--bg); color: var(--ink); }
.avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--seal-soft); color: var(--seal-dark);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 12px; border: 1px solid var(--line);
  cursor: pointer; transition: box-shadow .15s;
}
.usermenu { position: relative; }
.usermenu > summary { list-style: none; cursor: pointer; }
.usermenu > summary::-webkit-details-marker { display: none; }
.usermenu[open] .avatar { box-shadow: 0 1px 3px rgba(33,48,46,.06); }
/* R764 — LE MENU S'ADAPTE À LA HAUTEUR DE L'ÉCRAN. Il n'avait aucune borne :
   sur un portable peu haut, ou avec toutes les entrées visibles, il descendait
   SOUS le bas de la page — les dernières lignes, « Réglages » et « Se
   déconnecter », devenaient inatteignables, et faire défiler la page derrière
   ne les ramenait pas puisqu'il est ancré à l'en-tête.

   Il ne dépasse donc plus la place disponible sous l'en-tête, et défile
   lui-même quand il n'y tient pas. Le défilement est DISCRET et VERT — la
   teinte de la maison — plutôt qu'une barre grise du système. */
.menu-pop {
  /* R782 — LA LARGEUR SUIT LE CONTENU. Deux cent quarante pixels en dur : dès
     qu'une pastille portait DEUX chiffres, « Validation des documents 12 » ne
     tenait plus sur la ligne et le nombre tombait dessous, décalant l'entrée
     entière. La largeur s'ajuste à ce qu'il y a de plus long — « max-content » —
     entre un plancher de 240, pour que le menu garde son allure quand les
     libellés sont courts, et un plafond qui l'empêche de sortir de l'écran. */
  position: absolute; inset-inline-end: 0; top: calc(100% + 10px);
  width: max-content;
  min-width: 240px;
  max-width: min(340px, calc(100vw - 24px));
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: 0 1px 3px rgba(33,48,46,.06); padding: 8px; z-index: 50;
  /* « 100dvh » suit la barre d'adresse des téléphones, qui se rétracte ;
     on retire la hauteur de l'en-tête et une marge, pour ne jamais toucher
     le bas de l'écran. */
  max-height: calc(100vh - 96px);
  max-height: calc(100dvh - 96px);
  overflow-y: auto; overscroll-behavior: contain;
  /* R777 — LA BARRE DE DÉFILEMENT RESTE GRISE. Je l'avais mise en vert pour le
     menu du compte : elle attirait l'œil sur une commande qui ne demande rien,
     et se distinguait de toutes les autres de la maison — la barre latérale,
     les listes, les fenêtres — qui emploient le gris du trait. Une barre de
     défilement est un OUTIL, pas un signal : elle se fait oublier. */
  scrollbar-width: thin; scrollbar-color: var(--line) transparent;
}
.menu-pop::-webkit-scrollbar { width: 8px; }
.menu-pop::-webkit-scrollbar-track { background: transparent; margin: 8px 0; }
.menu-pop::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 99px;
  border: 2px solid var(--panel);     /* le curseur paraît plus fin — comme la barre latérale */
}
.menu-pop:hover::-webkit-scrollbar-thumb { background: var(--muted); }
/* L'en-tête du menu — nom et rôle — reste visible pendant qu'on défile :
   sans lui, on ne sait plus de quel compte on règle les affaires. */
.menu-pop .menu-head {
  position: sticky; top: -8px; z-index: 1;
  background: var(--panel); margin-top: -8px; padding-top: 16px;
}
.menu-head { padding: 8px 12px 8px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.menu-head b { display: block; font-family: var(--serif); font-weight: 400; font-size: 15px; }
.menu-head small { color: var(--muted); text-transform: capitalize; font-size: 12px; }
.menu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border-radius: 8px; color: var(--ink); font-size: 13px;
  /* R782 : le libellé et sa pastille restent sur UNE ligne ; c'est la largeur
     du menu qui cède, pas le texte qui se plie. */
  white-space: nowrap;
}
.menu-item > span:first-of-type { flex: 1 1 auto; min-width: 0; }
.menu-item .compte, .menu-item b { flex: 0 0 auto; }
.menu-item .ic { color: var(--muted); }
.menu-item:hover { background: var(--seal-ghost); color: var(--seal-dark); }
.menu-item.on { background: var(--seal-soft); color: var(--seal-dark); font-weight: 600; }
.menu-item span { flex: 1; }
.menu-sep { border-top: 1px solid var(--line); margin: 8px 4px; }
.mini-badge { background: var(--warn-bg); color: var(--warn); border-radius: 999px; font-size: 11px; padding: 1px 8px; font-weight: 700; }

/* ------------------------- Structure -------------------------------- */
.shell { display: flex; min-height: calc(100vh - var(--h-topbar, 55px)); }
.sidebar {
  /* Colonne d'arborescence : FIXE sous l'en-tête, avec son propre défilement.
     Tout est réuni ici — une règle séparée ailleurs finirait par contredire
     celle-ci sans qu'on s'en aperçoive. */
  position: fixed;
  top: var(--h-topbar, 55px); inset-inline-start: 0;
  width: 258px;
  /* R1492 : on retire AUSSI la barre du pied. Sans cela la colonne
     descend jusqu'au bas de la fenêtre, le pied (z-index 80) se dessine
     par-dessus elle (z-index 20), et le bouton « Nouveau dossier racine »
     — collé en bas par « .tree-pied » — disparaît dessous. */
  height: calc(100vh - var(--h-topbar, 55px) - var(--h-pied, 28px));   /* R519 : repli des navigateurs sans dvh */
  height: calc(100dvh - var(--h-topbar, 55px) - var(--h-pied, 28px));
  z-index: 20;
  flex-shrink: 0;
  background: var(--panel);
  border-inline-end: 1px solid var(--line);
  padding: 16px 12px 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.side-home {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 12px; border-radius: 8px; color: var(--ink); font-size: 14px;
}
.side-home:hover { background: var(--bg); }
.side-home.active { background: var(--seal-soft); color: var(--seal-dark); font-weight: 600; position: relative; }
.side-home.active::before, .tree-row.active::before {
  content: ""; position: absolute; inset-inline-start: -12px; top: 18%; bottom: 18%; width: 3.5px;
  border-radius: 999px; background: var(--grad); animation: barIn .25s ease both;
}
@keyframes barIn { from { transform: scaleY(0); } }
.tree-row.active { position: relative; }
.side-cap { margin: 16px 12px 8px; font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); font-weight: 700; }

/* Arborescence */
.tree { font-size: 13px; }
.tree-node { }
.tree-row { display: flex; align-items: center; position: relative; border-radius: 8px; }
.tree-row:hover { background: var(--bg); }
.tree-row.active { background: var(--seal-soft); }
.tree-row.active .tree-link { color: var(--seal-dark); font-weight: 600; }
.tree-row.active .tree-link .ic { color: var(--seal); }
.tree-caret {
  width: 22px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
  color: var(--faint); background: none; border: 0; cursor: pointer; padding: 0; flex-shrink: 0;
  transition: transform .15s;
}
.tree-node.open > .tree-row > .tree-caret { transform: rotate(90deg); }
.tree-caret.leaf { cursor: default; }
.tree-link {
  flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 4px 4px; color: var(--ink);
}
.tree-link .ic { color: var(--gold); opacity: .85; }
.tree-children { display: none; margin-inline-start: 20px; border-inline-start: 1px dotted var(--line2); padding-inline-start: 4px; }
.tree-node.open > .tree-children { display: block; }
.tree-plus, .tree-add-root {
  border: 0; background: none; cursor: pointer; color: var(--muted);
  font: inherit; border-radius: 8px;
}
.tree-plus {
  width: 24px; height: 24px; margin-inline-end: 4px; flex-shrink: 0;
  display: none; align-items: center; justify-content: center;
}
.tree-row:hover .tree-plus { display: inline-flex; }
.tree-plus:hover { background: var(--seal-soft); color: var(--seal-dark); }
.tree-add-root {
  margin: 16px 8px 0; padding: 8px 8px; font-size: 12px;
  display: flex; align-items: center; gap: 7px; width: calc(100% - 12px);
  border: 1px dashed var(--line2);
}
.tree-add-root:hover { color: var(--seal); border-color: var(--seal); }

.main { flex: 1; padding: 24px var(--pad-main) 72px; min-width: 0; }

/* ------------------------- En-tetes de page ------------------------- */
/* R776 — L'EN-TÊTE DE PAGE SE SÉPARE DE CE QUI SUIT, TOUJOURS PAREIL.
   Mesuré sur quatre pages : l'écart entre la ligne de définition et le bloc
   suivant valait 4, 20 ou 28 pixels selon ce qui venait après — un message,
   un trait, une barre de boutons. Rien ne le tenait : chaque bloc apportait
   sa propre marge, ou n'en apportait aucune. Sur les questionnaires, quatre
   pixels : le message d'avertissement se collait à la phrase.

   L'en-tête porte donc lui-même sa séparation, à « --e4 » — vingt pixels, la
   mesure de la maison entre deux blocs, et le maximum demandé. Les marges de
   ce qui suit s'effacent devant elle, pour que le total ne double pas selon
   le voisin. */
.pagehead { margin-bottom: var(--e4); }
.pagehead:has(+ .rule-double) { margin-bottom: 0; }
/* Le trait de la bibliothèque garde SA distance : R621 l'a réglée exprès selon
   qu'il y a ou non des boutons dans l'en-tête. On ne l'écrase pas — une règle
   générale ne doit pas défaire une décision prise pour un cas précis. */
.pagehead + .msg,
.pagehead + .card,
.pagehead + .quest-tete-actions { margin-top: 0; }
.pagehead .crumbs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 12px; color: var(--muted); margin-bottom: 8px; }
.pagehead .crumbs a { color: var(--muted); }
.pagehead .crumbs a:hover { color: var(--seal); }
/* R809 — LE TITRE FAIT VINGT-QUATRE PIXELS, D'OÙ QU'IL VIENNE. La règle ne
   visait que « .pagehead h1 » : les pages bâties sur « quest-tete » — la
   création d'une mission, sa fiche — gardaient la taille par défaut du
   navigateur, trente pixels. Un titre plus gros sur deux écrans que sur tous
   les autres n'est pas une emphase, c'est un oubli. On nomme les deux
   conteneurs plutôt que de répéter la règle, pour qu'elle n'ait qu'un endroit
   où changer. */
.pagehead h1, .quest-tete h1 { font-family: var(--serif); font-weight: 400; font-size: 24px; margin: 0; letter-spacing: .2px; }
.pagehead .defline { font-family: var(--serif); font-style: italic; color: var(--muted); font-size: 13px; margin: 4px 0 0; }
.headrow { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; row-gap: 36px; }   /* R567 : le double de la norme (18 px) quand la rangée se replie */
/* R565 — quand les boutons passent SOUS le bloc du titre (fenêtre étroite, ou
   beaucoup de boutons), un peu d'air les sépare des pastilles d'état. */
.headrow .actions { margin-inline-start: auto; display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.spacer { flex: 1; }

/* ------------------------- Composants ------------------------------- */
.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 1px 3px rgba(33,48,46,.06);
  padding: 16px 20px; margin-bottom: 16px;
}
.card h2 { font-family: var(--serif); font-weight: 400; font-size: 17px; margin: 0 0 12px; display: flex; align-items: center; gap: 8px; }
.card h2 .ic { color: var(--seal); }

.btn {
  /* R693 — UN BOUTON A LA TAILLE D'UN CHAMP. Ils tombaient à 34 px là où les
     champs de la même barre en font 36 à 40 : à côté d'une liste déroulante ou
     d'une recherche, ils paraissaient tassés, et la cible du doigt était juste.
     Une hauteur plancher les aligne — sans changer leur dessin ni leur texte. */
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 38px;
  border: 1px solid var(--line2); background: var(--panel);
  color: var(--ink); border-radius: 8px; padding: 8px 16px;
  font: inherit; font-size: 13px; cursor: pointer;
  transition: background .12s, border-color .12s, transform .05s;
}
.btn:hover { background: var(--bg); border-color: var(--faint); transform: translateY(-1px); }
/* R1391 — UN BOUTON ÉTEINT DOIT AVOIR L'AIR ÉTEINT, et il ne l'avait pas.
   L'attribut « disabled » était posé — le navigateur refusait bien le clic —
   mais rien ne le DISAIT : le bouton gardait son dessin plein, et l'on cliquait
   dessus sans comprendre pourquoi rien ne se passait. Trouvé en regardant
   l'écran livré, non le code : « Demander son relevé » naît éteint tant
   qu'aucune clé d'administration n'est posée. Trois règles valent pour tous les
   boutons de Khazina ; les styles particuliers qui existent déjà ailleurs les
   affinent et continuent de l'emporter. */
.btn[disabled], .btn:disabled { opacity: .45; cursor: default; }
.btn[disabled]:hover, .btn:disabled:hover {
  background: var(--panel); border-color: var(--line2); transform: none; }
/* R560 — un bouton-lien (« Télécharger ») garde SA couleur de texte au survol :
   la règle générale des liens (a:hover → vert foncé) ne s'y applique pas. */
a.btn:hover { color: var(--ink); }
a.btn.primary:hover, a.btn.principal:hover { color: #fff; }
a.btn.danger:hover { color: var(--err); }
a.btn.outline:hover { color: var(--seal-dark); }
.btn:active { transform: translateY(1px); }
/* Bouton de validation — UN SEUL rendu dans toute l'application.
   Deux classes coexistaient (`primary` : dégradé, `principal` : aplat) et le
   bouton qui valide n'avait pas la même tête d'une page à l'autre. Les deux
   noms pointent désormais sur la même règle : aplat vert du projet, hover
   assombri — le rendu de la page de connexion, étendu partout. */
.btn.primary, .btn.principal {
  background: var(--seal); border-color: var(--seal);
  color: #fff; font-weight: 500;
  box-shadow: 0 1px 3px rgba(33,48,46,.06);
}
.btn.primary:hover, .btn.principal:hover { background: var(--seal-dark); border-color: var(--seal-dark); transform: translateY(-1px); }
.btn.primary:active, .btn.principal:active { transform: translateY(1px); }
.btn.primary svg, .btn.principal svg { stroke: #fff; }

/* Pagination — une seule définition ; sept pages recopiaient ce style en
   ligne (recherche, journal, vérification, corbeille, notifications,
   utilisateurs, fiche document). */
.pagination { display: flex; gap: var(--e2); align-items: center; justify-content: center; margin: var(--e4) 0; }

/* --------------------------------------------------------------------- */
/* UTILITAIRES — remplacent les styles en ligne identiques qui s'étaient  */
/* dispersés dans les pages (90 occurrences recensées au moment de la     */
/* factorisation). Un nom par usage constaté, rien de spéculatif.         */
/* Les largeurs calculées en PHP (barres du tableau de bord…) restent en  */
/* ligne : c'est leur place.                                              */
/* --------------------------------------------------------------------- */
.muted        { color: var(--muted); }           /* texte secondaire */
.txt-err      { color: var(--err); }
.m0           { margin: 0; }
.mt2          { margin-top: var(--e2); }
.mt3          { margin-top: var(--e3); }
.mb3          { margin-bottom: var(--e3); }
.mb4          { margin-bottom: var(--e4); }
.ml-auto      { margin-inline-start: auto; }
.nowrap       { white-space: nowrap; }
.form-inline  { display: inline; }               /* petit formulaire posé dans une ligne de tableau */
.contents     { display: contents; }             /* enveloppe de teinte des étiquettes d'extension */
.p-aide       { color: var(--muted); margin: var(--e1) 0 var(--e3); }  /* paragraphe d'aide sous un titre */
.etat-vide    { color: var(--muted); padding: var(--e3) var(--e1); margin: 0; }  /* « rien ici » dans une carte */
.rows-nus     { border-top: 0; }                 /* .rows collé au bord haut de sa carte */
.case-bloc    { display: block; padding: var(--e1) 0; }  /* case à cocher sur sa propre ligne */
.actions-nues { border-top: none; padding-top: 0; margin-top: var(--e5); }  /* form-actions sans filet */
.mt1          { margin-top: var(--e1); }
.txt-faint    { color: var(--faint); }
.maxw-580     { max-width: 580px; }
.maxw-720     { max-width: 720px; }

/* --------------------------------------------------------------------- */
/* FICHE DOCUMENT (document.php) — composants propres à la page, sortis  */
/* des styles en ligne où ils s'étaient accumulés.                        */
/* --------------------------------------------------------------------- */
.doc-titre-ligne { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.piece-jointe    { border: 1px dashed var(--line2); border-radius: 11px; padding: var(--e3) var(--e4); }
.note-ouverture  { margin: 9px 0 0; color: var(--muted); }
.pg-nbcar        { margin-inline-start: auto; color: var(--muted); font-weight: 400; font-size: 12.5px; }
.langs-choix        { display: flex; gap: var(--e4); flex-wrap: wrap; padding: var(--e2) var(--e1); }
.langs-choix label  { display: flex; align-items: center; cursor: pointer; font-size: 13.5px; }
.note-consignee  { margin-inline-start: var(--e3); color: var(--faint); font-size: var(--t-detail); font-family: var(--serif); font-style: italic; }
/* « -var(--e2) » (en ligne, avant factorisation) est une syntaxe invalide
   que le navigateur ignorait : la marge annoncée n'a jamais été appliquée.
   calc() la rend réelle. */
.defline-serree  { margin: calc(-1 * var(--e2)) 0 var(--e3); }
.consult-resume  { display: flex; gap: var(--e3); flex-wrap: wrap; margin: 0 0 var(--e3); }
.consult-carte   { flex: 1; min-width: 165px; padding: var(--e3); }
.consult-nombre  { font-size: var(--t-sect); }
.consult-libelle { font-weight: 500; }
.consult-detail  { color: var(--muted); font-size: var(--t-detail); }

/* ---- Utilitaires (suite : recensés lors de la seconde passe) -------- */
.mt4          { margin-top: var(--e4); }
.flex2        { display: flex; gap: var(--e2); }
.flex3        { display: flex; gap: var(--e3); }
.wrap         { flex-wrap: wrap; }
.gras         { font-weight: 600; }
.va1          { vertical-align: 1px; }
.txt-petit    { font-size: 12.5px; }
.txt-detail   { font-size: var(--t-detail); }
.txt-centre   { text-align: center; }
.mention-legere { color: var(--faint); font-size: var(--t-detail); font-family: var(--serif); font-style: italic; }
.sans-anim    { animation: none; }
.cache        { display: none; }
.pleine-largeur { width: 100%; }
.champ-auto   { width: auto; }
/* Trois modales « étroites » vivaient à 440, 460 et 470 px — écarts
   accidentels, pas des choix. Une seule largeur pour toutes. */
.modal-compact { max-width: 470px; }

/* ---- Recherche (search.php) ---- */
.row-pointille { border-bottom: 1px dashed var(--line); }
.extrait       { flex: 1; min-width: 200px; font-size: var(--t-corps); }

/* ---- Journal d'audit (audit.php) ---- */
.section-export   { margin: var(--e4) 0; }
.resume-cliquable { cursor: pointer; font-weight: 600; padding: var(--e2) 0; }
.audit-filtres    { display: flex; gap: var(--e3); align-items: end; flex-wrap: wrap; margin-top: var(--e2); }
.barre-export     { display: flex; gap: var(--e3); align-items: center; justify-content: center; margin: var(--e4) 0 var(--e2); }

/* ---- Utilisateurs & accès (admin_users.php) ---- */
.champ-bouton   { flex: 0; display: flex; align-items: flex-end; }
.select-compact { width: auto; padding: var(--e1) var(--e2); font-size: var(--t-corps); }
.popover                { display: inline-block; position: relative; }
.popover > summary      { list-style: none; }
.popover-carte  { position: absolute; z-index: 10; width: 240px; margin-top: var(--e2); inset-inline-end: 0; }

/* ---- Permissions (admin_perm.php) ---- */
.perm-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--e1); }
/* Deux cadres défilants vivaient à 210 et 230 px : même hauteur pour les deux. */
.liste-cadre { max-height: 230px; overflow: auto; border: 1px solid var(--line); border-radius: 8px; padding: var(--e2); }
.suivi-ligne { display: flex; align-items: center; gap: var(--e3); padding: var(--e1) 0; flex-wrap: wrap; }
.suivi-nom   { flex: 1; min-width: 170px; }

/* ---- Sauvegarde (sauvegarde.php) ---- */
.cartes-sauvegarde { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--e3); margin: var(--e4) 0; }
/* Deux blocs de chemin s'affichaient chacun à sa façon : un seul style. */
.bloc-chemin { background: var(--panel); padding: var(--e3); border-radius: 8px; overflow: auto; font-size: var(--t-corps); }

/* ---- Réglages (admin_settings.php) ---- */
/* R1336 — ICI VIVAIT UNE COPIE MORTE DE « .lec-label-ligne ».
   La classe est écrite DEUX FOIS dans cette feuille : ici, et bien plus bas
   (bloc du courriel). Cette copie-ci posait « flex-direction: row » sur une
   classe dont la règle de base — « .lec-label », neuf cents lignes PLUS BAS —
   pose « column » : à égalité de poids, la dernière écrite gagne, et celle-ci
   ne peignait rien. On l'ôte ; la seconde, qui elle s'applique, reste.
   Constaté en voulant m'en servir pour le réglage du dossier scanner : les
   cases se sont empilées AU-DESSUS de leur texte. La classe de la maison pour
   une case et son mot sur la même ligne est « .lec-case ». */
.btn.ghost { border-color: transparent; color: var(--seal); }
.btn.ghost:hover { background: var(--seal-ghost); }
.btn.danger { color: var(--err); border-color: #E8C4C0; }
.btn.danger:hover { background: var(--err-bg); }
/* R693 — le petit bouton reste petit, mais plus tassé : 30 px devenaient une
   cible étroite au doigt, et une barre d'outils entière semblait s'écraser
   sous le titre. */
.btn.small { min-height: 34px; padding: 6px 13px; font-size: 12.5px; border-radius: 8px; }

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; padding: 2.5px 8px; border-radius: 999px; white-space: nowrap;
  letter-spacing: .02em;
}
.chip.ok   { background: var(--seal-soft); color: var(--seal-dark); }
.chip.warn { background: var(--warn-bg); color: var(--warn); }
.chip.ok::before, .chip.warn::before, .chip.err::before, .chip.info::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .75;
}
.chip.warn::before { animation: blip 1.6s ease-in-out infinite; }
@keyframes blip { 0%,100% { transform: scale(1); opacity: .75; } 50% { transform: scale(1.5); opacity: .35; } }
.chip.err  { background: var(--err-bg); color: var(--err); }
.chip.info { background: var(--info-bg); color: var(--info); }
.chip.lang { background: var(--bg); color: var(--muted); border: 1px solid var(--line); font-family: var(--serif); font-style: italic; }
.tag-ext {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 42px; padding: 4px 8px; border-radius: 4px;
  font-family: var(--serif); font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  background: var(--seal-ghost); color: var(--seal-dark); border: 1px solid var(--seal-soft);
}
.hash { font-family: var(--mono); font-size: 12px; color: var(--muted); word-break: break-all; }

.flash {
  display: flex; align-items: center; gap: 10px;
  border-radius: 12px; padding: 12px 16px; margin-bottom: 16px; font-size: 13px;
  border: 1px solid transparent;
}
.flash { position: relative; overflow: hidden; animation: fadeUp .3s ease both; }
.flash::after { content: ""; position: absolute; left: 0; bottom: 0; height: 2.5px; width: 100%; background: currentColor; opacity: .3; transform-origin: left; animation: lifebar 6s linear forwards; }
@keyframes lifebar { to { transform: scaleX(0); } }
.flash.gone { opacity: 0; transform: translateY(-6px); transition: opacity .3s, transform .3s; }
.flash.ok { background: var(--seal-soft); color: var(--seal-dark); }
.flash.err { background: var(--err-bg); color: var(--err); }
.flash.warn { background: var(--warn-bg); color: var(--warn); }

/* ------------------------- Dossiers (grille) ------------------------ */
.foldergrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr)); gap: 12px; margin: 16px 0 24px; }
.foldercard {
  position: relative; display: flex; align-items: center; gap: 12px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 16px 16px; color: var(--ink);
  box-shadow: 0 1px 3px rgba(33,48,46,.06); transition: border-color .12s, transform .12s;
}
.foldercard::after { content: ""; position: absolute; inset: 0 auto auto 0; height: 3px; width: 100%; border-radius: 12px 12px 0 0; background: var(--grad); opacity: 0; transition: opacity .16s; }
.foldercard { overflow: hidden; }
.foldercard:hover { border-color: transparent; transform: translateY(-3px); color: var(--ink); box-shadow: 0 1px 3px rgba(33,48,46,.06); }
.foldercard:hover::after { opacity: 1; }
.foldercard:hover .ic { transform: rotate(-8deg) scale(1.12); }
.foldercard .ic { transition: transform .18s; }
.foldercard .ic { color: var(--gold); }
.foldercard b { display: block; font-family: var(--serif); font-weight: 400; font-size: 15px; line-height: 1.25; }
.foldercard small { display: block; color: var(--muted); font-size: 12px; margin-top: 2px; font-style: italic; font-family: var(--serif); }
.foldercard.add { font: inherit;
  border-style: dashed; border-color: var(--line2); box-shadow: none;
  color: var(--muted); justify-content: center; min-height: 66px; cursor: pointer;
}
.foldercard.add:hover { color: var(--seal); border-color: var(--seal); transform: none; }
.foldercard.add summary { list-style: none; display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; }
.foldercard.add summary::-webkit-details-marker { display: none; }

/* ------------------------- Documents (liste détaillée) -------------- */
.doc {
  display: flex; align-items: center; gap: 14px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 12px 16px; box-shadow: 0 1px 3px rgba(33,48,46,.06);
  transition: border-color .12s;
}
.doc:hover { border-color: var(--line2); }
.doc-title { font-family: var(--serif); font-size: 15px; color: var(--ink); display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.doc-title:hover { color: var(--seal-dark); text-decoration: underline; text-decoration-color: var(--line2); text-underline-offset: 3px; }
.doc-meta { font-size: 12px; color: var(--muted); margin-top: 4px; display: flex; align-items: center; gap: 4px 0; flex-wrap: wrap; }
/* R515 — l'original papier, sous les repères du fichier : une ligne, coupée
   proprement si le libellé est long, jamais deux. */
.doc-empl { font-size: 12px; color: var(--muted); margin-top: 3px; display: flex; align-items: center; gap: 5px; min-width: 0; }
.doc-empl svg { flex: none; opacity: .75; }
.doc-empl span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-actions { display: flex; gap: 6px; }
.act {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 12px; border-radius: 8px; font-size: 12px;
  border: 1px solid var(--line); color: var(--ink); background: var(--panel); cursor: pointer;
}
.act { transition: background .14s, border-color .14s, color .14s, transform .1s; }
.act:hover { background: var(--seal-ghost); border-color: var(--seal2); color: var(--seal-dark); transform: translateY(-1px); }
.empty {
  text-align: center; color: var(--muted); padding: 40px 16px;
  border: 1px dashed var(--line2); border-radius: var(--r); background: rgba(255,255,255,.5);
}
.empty .big { font-family: var(--serif); font-size: 17px; color: var(--ink); margin-bottom: 4px; }
.empty i { font-family: var(--serif); }

/* ------------------------- Zone d'import (dropzone) ----------------- */
.dropzone {
  position: relative; border: 1px dashed var(--line2); border-radius: var(--r);   /* R581 : bordure fine */
  background: var(--seal-ghost); padding: 24px 16px; text-align: center;
  transition: border-color .15s, background .15s; cursor: pointer;
}
.dropzone:hover, .dropzone.drag { border-color: var(--seal); background: var(--seal-soft); }
.dropzone input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; z-index: 2; }
.dropzone > *:not(input) { position: relative; z-index: 1; pointer-events: none; }
.dropzone .dz-files { pointer-events: auto; }
.dz-icon { color: var(--seal); margin-bottom: 8px; }
.dz-title { font-family: var(--serif); font-size: 15px; }
.dz-sub { font-size: 12px; color: var(--muted); margin-top: 4px; }
.dz-files { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.dz-file { background: #fff; border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px; font-size: 12px; color: var(--ink); max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uploadrow { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; align-items: center; }
.uploadrow input[type=text] { flex: 1; min-width: 200px; }

/* ------------------------- Formulaires (rien de brut) --------------- */
label.f { display: block; font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); font-weight: 600; margin: 12px 0 4px; }
/* R1023 — « email », « tel » et « time » entrent dans l'habit commun. La règle
   ne les nommait pas : un input[type=email] rendait NU — sans padding, sans
   plancher de 36 px, police du navigateur — et son rayon de 8 px en faisait
   une pilule de 18 px (vu sur « Adresse d'envoi »). C'est pour cela que le
   champ d'essai s'était cousu un habit sur mesure en R146. Un type de champ
   texte qui arrive doit trouver l'habit prêt. */
input[type=text], input[type=password], input[type=search], input[type=number],
input[type=email], input[type=tel], input[type=time], select, textarea {
  width: 100%; font: inherit; font-size: 14px; color: var(--ink);
  border: 1px solid var(--line2); border-radius: 8px;
  padding: 8px 12px; background: var(--panel);
  transition: border-color .12s, box-shadow .12s;
}
input:focus, select:focus, textarea:focus { outline: 0; border-color: var(--seal); box-shadow: 0 1px 3px rgba(33,48,46,.06); }
input::placeholder, textarea::placeholder { color: var(--faint); }
select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-inline-end: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236A7570' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
textarea { min-height: 130px; resize: vertical; line-height: 1.7; }
input[type=checkbox] {
  appearance: none; -webkit-appearance: none; width: 17px; height: 17px;
  border: 1.5px solid var(--line2); border-radius: 4px; background: #fff;
  cursor: pointer; vertical-align: -3px; margin: 0 8px 0 0; position: relative;
  transition: background .1s, border-color .1s;
}
input[type=checkbox]:checked { background: var(--seal); border-color: var(--seal); }
input[type=checkbox]:checked::after {
  content: ""; position: absolute; inset-inline-start: 4.5px; top: 1.5px; width: 4px; height: 8px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(42deg);
}
.formrow { display: flex; gap: 14px; flex-wrap: wrap; }
.formrow > div { flex: 1; min-width: 190px; }
.filters {
  /* Rangée de filtres — définition UNIQUE. Éparpillée sur trois endroits,
     elle se contredisait : la dernière lue gagnait, sans qu'on le voie. */
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  width: 100%; margin: 0;
}
.filters select, .filters input { width: auto; padding: 8px 12px; font-size: 13px; }
.filters select { padding-inline-end: 32px; }
/* R653 : un nom de dossier à rallonge ne pousse plus le reste de la rangée hors de la ligne. */
.filters select { max-width: 160px; }
/* Le bouton d'effacement, un peu plus serré : c'est lui qui tombait à la ligne. */
.barre-filtres > .reset { padding: 0 11px; }


/* ------------------------- Tableaux --------------------------------- */
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl th { text-align: start; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 700; padding: 8px 8px; border-bottom: 2px solid var(--line2); }
.tbl td { padding: 8px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.tbl tr:hover td { background: #FBFAF6; }

/* ------------------------- Fiche / texte extrait -------------------- */
.kv { display: grid; grid-template-columns: 175px 1fr; gap: 6px 16px; font-size: 13px; }
.kv .k { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); font-weight: 600; padding-top: 2px; }
.statgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(135px, 1fr)); gap: 11px; margin: 8px 0 16px; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 12px 16px; box-shadow: 0 1px 3px rgba(33,48,46,.06); }
.stat { transition: transform .16s, box-shadow .16s; }
.stat:hover { transform: translateY(-2px); box-shadow: 0 1px 3px rgba(33,48,46,.06); }
.stat b { display: block; font-family: var(--serif); font-weight: 400; font-size: 24px; background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.stat span { color: var(--muted); font-size: 11px; letter-spacing: .05em; text-transform: uppercase; }
.pagetext {
  background: #FCFBF7; border: 1px solid var(--line);
  border-radius: 8px; padding: 16px 16px;
  white-space: pre-wrap; font-size: 14px; max-height: 340px; overflow: auto;
  unicode-bidi: plaintext; line-height: 1.8;
}
[dir=auto] { unicode-bidi: plaintext; }
details.pg { border: 1px solid var(--line); border-radius: 12px; margin-bottom: 8px; background: var(--panel); }
details.pg summary {
  cursor: pointer; padding: 12px 16px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  list-style: none;
}
details.pg summary::-webkit-details-marker { display: none; }
details.pg summary .pg-label { font-family: var(--serif); font-style: italic; font-size: 14px; }
details.pg[open] summary { border-bottom: 1px solid var(--line); }
details.pg .inner { padding: 12px 16px; }

/* ------------------------- Vérification côte à côte ----------------- */
.split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 15px; }
.scanbox {
  border: 1px solid var(--line); border-radius: 12px; background: var(--bg);
  min-height: 280px; display: flex; align-items: center; justify-content: center;
  overflow: auto; padding: 8px;
}
.scanbox img { max-width: 100%; height: auto; border-radius: 8px; box-shadow: 0 1px 3px rgba(33,48,46,.06); }
.verify-text { min-height: 280px; font-size: 15px; line-height: 2; }

/* ------------------------- Connexion -------------------------------- */
.loginwrap { min-height: 100vh; display: flex; flex-direction: column;
             align-items: center; justify-content: center;
             gap: var(--e4); padding: var(--e5) var(--e4);
             background: radial-gradient(1200px 600px at 50% -10%, #FBFAF5, var(--bg)); }
/* Carte et textes partagent la meme largeur : la colonne reste droite. */
.loginwrap > * { width: 100%; max-width: 400px; }

.loginwrap::before, .loginwrap::after {
  content: ""; position: absolute; width: 420px; height: 420px; border-radius: 50%; filter: blur(70px); opacity: .5; z-index: 0;
}
.loginwrap::before { background: rgba(24,161,132,.20); top: -140px; right: -110px; animation: floaty 7s ease-in-out infinite; }
.loginwrap::after { background: rgba(194,154,58,.16); bottom: -150px; left: -120px; animation: floaty 9s ease-in-out infinite reverse; }
.logincard { position: relative; z-index: 1; }
.login-brand .brand-mark { animation: floaty 5s ease-in-out infinite; }
.logincard { width: 100%; max-width: 400px; }
/* R1509 — le sélecteur de langue de l'écran de connexion. « flex-end » suit
   le SENS D'ÉCRITURE et non un côté physique : à droite en français, à
   gauche en arabe, sans seconde règle pour le rtl. Le menu qu'il déroule
   porte déjà son style (.langmenu, plus bas) : rien à redire ici. */
.login-langue { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.login-brand { text-align: center; margin-bottom: 16px; }
.login-brand .brand-mark { width: 54px; height: 54px; font-size: 30px; border-radius: 12px; margin: 0 auto 8px; }
.login-brand h1 { font-family: var(--serif); font-weight: 400; font-size: 24px; margin: 0; letter-spacing: .5px; }
.login-def { font-family: var(--serif); font-style: italic; color: var(--muted); font-size: 13px; text-align: center; margin: 8px 0 0; line-height: 1.6; }
.login-def b { font-style: normal; font-weight: 400; }

/* ------------------------- Voile « scan » --------------------------- */

/* ------------------------- Responsive ------------------------------- */
.only-mobile { display: none; }
@media (max-width: 900px) {
  .only-mobile { display: inline-flex; }
  .sidebar {
    /* R1492 : « bottom: 0 » la faisait passer sous le pied ici aussi. */
    position: fixed; top: 55px; inset-inline-start: 0; bottom: var(--h-pied, 28px); z-index: 45; width: 280px;
    transform: translateX(-105%); transition: transform .22s ease;
    box-shadow: 0 10px 30px rgba(33,48,46,.14); overflow-y: auto;
  }
  .sidebar.open { transform: translateX(0); }
  .main { padding: 16px 16px 72px; }
  .brand-txt i { display: none; }
  .kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kv .k { margin-top: 8px; }
  .doc { flex-wrap: wrap; }
  .doc-side { width: 100%; justify-content: flex-start; }
}
@media (max-width: 600px) {
  .topbar { gap: 8px; padding: 8px 8px; }
  .brand-txt { display: none; }
  .headrow .actions { margin-inline-start: 0; width: 100%; margin-top: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}


/* =====================================================================
   v3 — Barre d'outils collante, vues carte/liste, modal, progression
   ===================================================================== */
.toolbar {
  /* .toolbar n'existe plus dans aucune page : plus de position collante. */
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 8px 12px; margin: 0 0 16px; box-shadow: 0 1px 3px rgba(33,48,46,.06);
  transition: box-shadow .2s, border-color .2s;
}
.toolbar.stuck { box-shadow: 0 10px 30px rgba(33,48,46,.14); border-color: transparent; }
.toolbar .grow { flex: 1; min-width: 140px; }
.scoped-search {
  display: flex; align-items: center; gap: 8px; flex: none; width: 100%;
  min-width: 0; max-width: 340px;
  background: var(--panel); border: 1px solid var(--line2); border-radius: 8px;
  height: var(--ctl); padding: 0 12px; color: var(--muted);
}
.scoped-search:focus-within { border-color: var(--seal); box-shadow: 0 1px 3px rgba(33,48,46,.06); }
.scoped-search input { border: 0; outline: 0; background: none; flex: 1; font: inherit; font-size: 13px; min-width: 0; color: var(--ink); }
.seg { display: inline-flex; background: var(--panel); border: 1px solid var(--line2); border-radius: 8px; padding: 2px; }
.seg button {
  border: 0; background: none; font: inherit; font-size: 12px; color: var(--muted);
  padding: 4px 8px; border-radius: 8px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
}
.seg button.on { background: var(--seal-soft); color: var(--seal-dark); font-weight: 600; }
.toolbar .filters { margin: 0; }

/* Barre d'actions groupees (selection) */
/* --------------------------------------------------------------------------
   BARRE DE SÉLECTION — fond vert CLAIR pour que les actions, en vert foncé,
   se détachent nettement. Le fond sombre d'avant écrasait les libellés et
   rendait le rouge de la suppression illisible.
   -------------------------------------------------------------------------- */
.bulkbar {
  position: sticky; top: calc(var(--h-topbar, 55px) + var(--h-filtres, 0px)); z-index: 31; display: none;
  align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 4px;
  padding: 12px 14px;
  background: var(--seal-soft);
  border: 1px solid var(--seal);
  border-radius: 12px;
}
.bulkbar.on { display: flex; }
.bulkbar > b {
  font-family: var(--serif); font-weight: 400; font-size: 14px;
  color: var(--seal-dark); margin-inline-end: 4px;
}
.bulkbar.on { display: flex; }
.bulkbar b { font-family: var(--serif); font-weight: 400; }

/* Conteneur documents : deux vues */
.docs { display: grid; gap: 12px; }
.docs.view-list { grid-template-columns: 1fr; }
.docs.view-cards { grid-template-columns: repeat(auto-fill, minmax(min(var(--cardw, 210px), 100%), 1fr)); }
.docs.size-s { --cardw: 160px; }
.docs.size-m { --cardw: 210px; }
.docs.size-l { --cardw: 280px; }
.docitem { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); box-shadow: 0 1px 3px rgba(33,48,46,.06); transition: border-color .12s, transform .12s; }
.docitem { --xc: var(--seal); }
.docitem::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px; border-radius: 12px 12px 0 0; background: var(--xc); opacity: 0; transition: opacity .16s; z-index: 2; }
.docitem:hover { border-color: transparent; box-shadow: 0 1px 3px rgba(33,48,46,.06); transform: translateY(-2px); }
.docitem:hover::after { opacity: .9; }
.dprev img { transition: transform .35s ease; }
.docitem:hover .dprev img { transform: scale(1.045); }
.xf-pdf  { --xc: #C0533B; } .xf-word { --xc: #3B6FB4; } .xf-excel { --xc: #2F8F5B; }
.xf-ppt  { --xc: #C77A2E; } .xf-img  { --xc: #7A5FB8; } .xf-web  { --xc: #2E8F98; }
.xf-txt  { --xc: #6A7570; }
.docitem .tag-ext, .xf .tag-ext { border-color: transparent; }
.xf-pdf .tag-ext  { background: #F9E9E5; color: #A34430; }
.xf-word .tag-ext { background: #E7EEF8; color: #315E9C; }
.xf-excel .tag-ext{ background: #E5F3EB; color: #257247; }
.xf-ppt .tag-ext  { background: #F9EEDF; color: #A5641F; }
.xf-img .tag-ext  { background: #EFEAF9; color: #644CA0; }
.xf-web .tag-ext  { background: #E3F2F3; color: #23747C; }
.xf-txt .tag-ext  { background: #EEF0EE; color: #57615C; }
.dprev .bigext { color: var(--xc); opacity: .55; }
.dprev .corner { border-color: transparent var(--bg) transparent transparent; }
.docitem .sel {
  position: absolute; top: 9px; inset-inline-start: 9px; z-index: 3; opacity: 0; transition: opacity .1s;
  background: #fff; border-radius: 8px; padding: 4px; box-shadow: 0 1px 3px rgba(33,48,46,.06); line-height: 0;
}
.docitem:hover .sel, .docitem.selected .sel, .docs.selecting .sel { opacity: 1; }
.docitem.selected { border-color: var(--sel); background: var(--sel-bg); }   /* R573 : la carte cochée, en bleu ; R579 : liseré fin */
.docitem .sel input { margin: 0; }
/* — vue carte — */
.view-cards .docitem { display: flex; flex-direction: column; overflow: hidden; }
.view-cards .dprev {
  display: block; height: calc(var(--cardw) * .72); background: #FCFBF7;
  border-bottom: 1px solid var(--line); overflow: hidden; position: relative;
}
.dprev img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dprev .sheet {
  position: absolute; inset: 12px 14px auto; bottom: -8px;
  background: #fff; border: 1px solid var(--line); border-radius: 4px 6px 0 0;
  padding: 12px 12px 0; box-shadow: 0 1px 3px rgba(33,48,46,.06);
  font-size: 7.5px; line-height: 1.75; color: #7d8781; overflow: hidden;
  font-family: var(--serif); unicode-bidi: plaintext; word-break: break-word;
}
.dprev .bigext {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--serif); letter-spacing: .12em; text-transform: uppercase;
  color: var(--faint); font-size: 15px;
}
.dprev .corner { position: absolute; top: 0; inset-inline-end: 0; border-style: solid; border-width: 0 16px 16px 0; border-color: transparent var(--bg) transparent transparent; }
.view-cards .dbody { padding: 8px 12px 12px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.view-cards .dbody .doc-meta { font-size: 11px; }
.view-cards .dbody .doc-empl { font-size: 11px; }   /* R515 : même corps que les repères, en carte */
/* Le titre réserve TOUJOURS deux lignes : sans hauteur minimale, un titre
   court remonte les boutons et les cartes ne s'alignent plus entre elles. */
.view-cards .dbody .doc-title {
  font-size: 14px; line-height: 1.35;
  white-space: normal; display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
  min-height: calc(2 * 1.35 * 14px);   /* deux lignes, occupées ou non */
}
.view-cards .drow2 { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.view-cards .doc-actions { margin-top: 8px; display: flex; gap: 6px; min-width: 0; }
.view-cards .doc-actions .act {
  flex: 1 1 auto; min-width: 0; justify-content: center;
  padding: 4px 8px; font-size: 12px; white-space: nowrap; overflow: hidden;
}
/* Le libellé ne se coupe qu'en dernier recours : sur une carte étroite, un
   mot tronqué en dit moins qu'une icône seule. (R626 : retour à R622 — les
   essais de repli et de « container query » sont abandonnés.) */
.view-cards .doc-actions .albl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Petites cartes : icônes seules, jamais de texte tronqué */
.docs.size-s .doc-actions .albl { display: none; }
.docs.size-s .doc-actions .act { padding: 8px 4px; }
/* TAILLE S — on retire par la FIN, jamais du milieu : d'abord les méta et
   l'état, qui se consultent en ouvrant la pièce. Le format et la LANGUE
   restent : ce sont les deux repères qui permettent de reconnaître une pièce
   sans l'ouvrir, et ils doivent occuper la même place dans les trois tailles
   pour que l'œil n'ait pas à se réapprendre en changeant de vue. */
.docs.size-s .dbody .doc-meta,
.docs.size-s .drow2 .chip:not(.lang),
.docs.size-s .drow2 .doc-date { display: none; }
/* — vue liste — */
.view-list .docitem { display: flex; align-items: center; gap: 13px; padding: 12px 16px 12px 40px; }
.view-list .dprev { width: 46px; height: 58px; flex-shrink: 0; border: 1px solid var(--line); border-radius: 4px; background: #FCFBF7; overflow: hidden; position: relative; }
.view-list .dprev .sheet { inset: 4px 4px auto; bottom: -4px; padding: 4px 4px 0; font-size: 3.5px; line-height: 1.6; border-radius: 4px 3px 0 0; }
.view-list .dprev .bigext { font-size: 11px; }
.view-list .dbody { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.view-list .drow2 { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.view-list .doc-actions { display: flex; gap: 6px; }
.view-list .sel { top: 50%; transform: translateY(-50%); }

/* ------------------------- Rangées (listes simples) ----------------- */
.rows { display: flex; flex-direction: column; }
.row {
  display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  padding: 12px 8px; border-bottom: 1px solid var(--line);
  transition: background .12s;
}
.row:last-child { border-bottom: 0; }
.row:hover { background: #FBFAF6; }
.row .name { font-family: var(--serif); font-size: 14px; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
a.name:hover { color: var(--seal-dark); text-decoration: underline; text-decoration-color: var(--line2); text-underline-offset: 3px; }
.row .meta { color: var(--muted); font-size: 12px; flex: 1; min-width: 140px; }
.row .end { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-inline-start: auto; }
.sub { color: var(--muted); font-size: 12px; }

/* Modals */
.modal { position: fixed; inset: 0; z-index: 90; display: none; align-items: center; justify-content: center; padding: 16px; background: rgba(33,48,46,.32); backdrop-filter: blur(2px); }
.modal.on { display: flex; }
.modal { overflow: auto; }
/* --------------------------------------------------------------------------
   FENÊTRE MODALE — hauteur adaptée à l'écran, contenu qui défile à
   l'intérieur, actions toujours accessibles en bas. Les ombres en haut et en
   bas apparaissent SEULEMENT s'il reste du contenu caché : l'utilisateur voit
   qu'il peut faire défiler, sans avoir à le deviner.
   -------------------------------------------------------------------------- */
.modal-card {
  display: flex; flex-direction: column;
  max-height: min(88vh, 780px);   /* R519 : repli sans dvh (Chrome < 108, Firefox < 101) — sans lui, une fenêtre haute débordait l'écran sans défiler */
  max-height: min(88dvh, 780px);
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(33,48,46,.14);
  width: 100%; max-width: 520px; overflow: hidden;
  animation: pop .26s cubic-bezier(.2,1.4,.4,1);
}
.modal-head { flex: none; }
.modal-foot {
  flex: none; padding: 12px 16px; border-top: 1px solid var(--line);
  background: var(--panel);
}
.modal-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px 16px 16px;
  /* Ombres de défilement : les deux premiers dégradés masquent l'ombre quand
     on est en butée, les deux suivants la révèlent quand il reste à voir. */
  background:
    linear-gradient(var(--panel) 30%, rgba(255,255,255,0)) top    / 100% 26px no-repeat local,
    linear-gradient(rgba(255,255,255,0), var(--panel) 70%) bottom / 100% 26px no-repeat local,
    radial-gradient(farthest-side at 50% 0,   rgba(33,48,46,.16), rgba(33,48,46,0)) top    / 100% 13px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, rgba(33,48,46,.16), rgba(33,48,46,0)) bottom / 100% 13px no-repeat scroll;
  background-color: var(--panel);
}
@media (max-width: 600px) { .modal-card { max-height: 92vh; max-height: 92dvh; } }
@keyframes pop { from { transform: translateY(8px) scale(.985); opacity: 0; } }
.modal-head { display: flex; align-items: center; gap: 10px; padding: 16px 16px; border-bottom: 1px solid var(--line); }
.modal-head b { font-family: var(--serif); font-weight: 400; font-size: 17px; flex: 1; }
.modal-body { padding: 16px 16px 16px; }
/* R573 — DE L'AIR DANS LES FENÊTRES : les champs, les blocs d'aide et les
   listes ne se touchent plus ; chaque étiquette de champ respire. */
.modal-body .lec-label { margin-bottom: 14px; }
.modal-body .lec-label:last-child { margin-bottom: 0; }
/* R1344 — ET LA RÈGLE CONNAÎT AUSSI LES CASES À COCHER. Elle ne nommait que
   « lec-label », l'étiquette d'un champ de saisie : une case à cocher posée
   entre deux champs ne portait donc rien sous elle, et le champ suivant venait
   se coller à elle — zéro pixel, là où tout le reste en a quatorze. On l'a vu
   dans la fenêtre de classement, entre « Lecture OCR » et « Note » ; c'était
   vrai partout où une case vit dans une fenêtre. Une règle qui nomme une
   forme en oublie les voisines : elle les nomme toutes les deux. */
.modal-body .lec-case { margin-bottom: 14px; }
.modal-body .lec-case:last-child { margin-bottom: 0; }
.modal-body .lec-bascule { margin-top: 14px; }
.modal-body .empty-hint, .modal-body .sub, .modal-body p.k { margin-bottom: 14px; }
/* R590 — dans une fenêtre, aucun bloc ne colle à l'étiquette qui suit : listes,
   encarts, tableaux et blocs d'information gardent leur air en dessous. */
.modal-body > ul, .modal-body > ol, .modal-body > .msg, .modal-body > .kv, .modal-body > table { margin-bottom: 14px; }
.modal-body .lec-label { margin-top: 0; }
.modal-body form > .lec-label:first-child { margin-top: 2px; }
.modal-body .empty-hint.m0.mb3 { margin-bottom: 14px !important; }
.modal-body .dz-sub + p, .modal-body .dropzone + p { margin-top: 12px; }
.modal-body .val-avert { margin-top: 14px; }

@keyframes spin { to { transform: rotate(360deg); } }

/* Segmentation (page document) */
/* R622 — LES ONGLETS REVIENNENT À LA LIGNE, ILS NE DÉFILENT PLUS. Sur une
   tablette ou un téléphone, la barre glissait de côté : les derniers onglets
   (« Validation ») restaient cachés, et rien ne disait qu'il fallait pousser.
   Elle se replie désormais sur plusieurs lignes, chaque onglet entier. */
.tabs { display: flex; flex-wrap: wrap; max-width: 100%; background: var(--panel); border: 1px solid var(--line2); border-radius: 12px; padding: 4px; margin: 2px 0 16px; gap: 2px; }
/* R689 — un onglet peut être un LIEN : la page des questionnaires ne charge
   que la liste regardée, donc changer d'onglet charge la sienne. Même dessin
   pour les deux, sinon on verrait la différence. */
.tabs button, .tabs > a { border: 0; background: none; font: inherit; font-size: 13px; color: var(--muted); padding: 8px 16px; border-radius: 8px; cursor: pointer; white-space: nowrap; text-decoration: none; display: inline-block; }
.tabs button, .tabs > a { transition: color .15s, background .18s; }
.tabs button.on, .tabs > a.on { background: var(--grad); color: #fff; box-shadow: 0 1px 3px rgba(33,48,46,.06); }   /* R575 : l'onglet ouvert reprend le dégradé vert de la maison (le bleu de R573 est retiré des onglets) */
.tabpane { display: none; } .tabpane.on { display: block; }

/* Corrections diverses */
.tblwrap { overflow-x: auto; margin: 0 -4px; -webkit-overflow-scrolling: touch; }
.tblwrap > table { min-width: 560px; }
.popover > summary { list-style: none; cursor: pointer; }
.popover > summary::-webkit-details-marker { display: none; }
@media (max-width: 900px) {
  .toolbar, .bulkbar { top: 55px; }
}


/* =====================================================================
   Responsive & tactile — chaque page, chaque composant
   ===================================================================== */
@media (hover: none) {
  .docitem .sel { opacity: 1; }
  .tree-plus > summary { display: inline-flex; }
  .btn:hover, .foldercard:hover, .docitem:hover, .act:hover, .stat:hover { transform: none; }
}
@media (max-width: 900px) {
  details.popover > .card {
    position: fixed !important; inset-inline-start: 12px !important; inset-inline-end: 12px !important;
    top: auto !important; bottom: 12px !important; width: auto !important;
    max-height: 72vh; max-height: 72dvh; overflow: auto; z-index: 75;
    box-shadow: 0 10px 30px rgba(33,48,46,.14); margin: 0 !important;
  }
  .tree-plus .tree-add-form { inset-inline-end: auto; inset-inline-start: 0; }
  .main > * { animation-duration: .28s; }

  /* R773 — LE MENU DU COMPTE PASSE DEVANT, SUR UN ÉCRAN ÉTROIT.
     Mesuré : sous 900 pixels, ce que l'on touche au milieu du menu ouvert est
     le TITRE DE LA PAGE — le menu se dessine, mais le contenu passe par-dessus
     et l'on clique à travers. La cause n'est pas son « z-index » (cinquante,
     supérieur à la barre) : c'est que la barre elle-même crée un plan à
     quarante, dont le menu, qui en est l'enfant, ne peut pas sortir.
     Les fenêtres surgissantes de la maison avaient déjà leur règle ici —
     « details.popover » — mais le menu du compte n'en était pas. Il la reçoit :
     posé par rapport à l'ÉCRAN, à soixante-quinze, comme ses semblables. */
  /* R775 — LE MENU RESTE SOUS SON BOUTON, MÊME SUR UN TÉLÉPHONE. En R773 je
     l'avais fait monter du bas comme une feuille : il passait bien devant,
     mais il perdait son ancrage — on ne voyait plus D'OÙ il venait, et
     l'expérience différait de celle du bureau sans raison. Il reste donc
     accroché au bloc du compte, en haut à droite, et se borne à la place
     disponible sous l'en-tête. */
  details.usermenu > .menu-pop,
  details.usermenu .menu-pop {
    position: fixed; z-index: 75;
    top: calc(var(--h-topbar, 55px) + 6px); bottom: auto;
    inset-inline-start: auto; inset-inline-end: 10px;
    width: min(280px, calc(100vw - 20px));
    max-height: calc(100dvh - var(--h-topbar, 55px) - 24px);
    overflow-y: auto;
    box-shadow: 0 10px 30px rgba(33,48,46,.14); margin: 0;
  }
  /* Le voile s'arrête SOUS l'en-tête : couvrant tout l'écran, il interceptait
     les clics sur la cloche et sur la recherche — on ne pouvait plus passer
     d'un panneau à l'autre sans refermer d'abord. */
  details.usermenu[open] > summary::after {
    content: ''; position: fixed; z-index: 74;
    top: var(--h-topbar, 55px); inset-inline-start: 0; inset-inline-end: 0; bottom: 0;
    background: rgba(33, 48, 46, .18);
  }
}
@media (max-width: 600px) {
  .main { padding: 16px 12px 72px; }
  .pagehead h1, .quest-tete h1, h1.entry-title { font-size: 20px; }
  .pagehead .defline { font-size: 12px; }
  .brand-mark { width: 32px; height: 32px; font-size: 17px; border-radius: 8px; }
  .topsearch { padding: 0 12px; }
  .toolbar { gap: 6px; padding: 8px 8px; }
  .scoped-search { flex-basis: 100%; max-width: none; order: 5; }
  #sizeSeg { display: none !important; }
  .bulkbar { gap: 6px; padding: 8px 8px; }
  .bulkbar .act { padding: 4px 8px; font-size: 12px; }
  .view-list .docitem { padding: 8px 12px 8px 40px; }
  .view-list .doc-actions { width: 100%; }
  .view-list .doc-actions .act { flex: 1; justify-content: center; }
  .docs { gap: 10px; }
  .foldergrid { grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); gap: 9px; }
  .foldercard { padding: 12px 12px; gap: 9px; }
  .foldercard b { font-size: 13px; }
  .tbl th, .tbl td { padding: 8px 8px; font-size: 12px; }
  .card { padding: 16px 16px; }
  .kv { font-size: 13px; }
  .pagetext { font-size: 13px; max-height: 280px; }
  .row { padding: 8px 2px; }
  .row .end { width: 100%; margin-inline-start: 0; }
  .row .end .btn { flex: 1; justify-content: center; }
  .statgrid { grid-template-columns: repeat(2, 1fr); }
  .tabs button { padding: 8px 12px; font-size: 13px; }
  .login-brand h1 { font-size: 24px; }
}
@media (max-width: 420px) {
  .pagehead h1, .quest-tete h1, h1.entry-title { font-size: 20px; }
    .badgebtn b { display: none; }
  .btn { padding: 8px 12px; }
  .modal-body { padding: 12px 12px 16px; }
}


/* =====================================================================
   v6 — File d'attente d'import, pagination, harmonisation "Drive"
   ===================================================================== */
/* Hauteur de controle UNIQUE : plus aucun CTA desaligne */
.btn, .act, input[type=text], input[type=password], input[type=search],
input[type=number], input[type=date], input[type=email], input[type=tel],
input[type=time], select, .seg, .scoped-search, .badgebtn {
  min-height: var(--ctl); box-sizing: border-box;
}
/* R693 : la même hauteur plancher que plus haut — une règle posée après
   l'emportait et ramenait les petits boutons à 30 px. */
.btn.small, .act { min-height: 34px; }
.seg { align-items: stretch; }
.seg button { display: inline-flex; align-items: center; }
input[type=date] { padding: 8px 8px; width: auto; }
.toolbar { row-gap: 8px; }
.toolbar.offstage { display: none; }
.headrow .actions { align-items: center; }
.headrow .actions form { display: contents; }
.pagehead .headmeta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-top: 8px; }

/* Pagination */
.pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 24px 0 4px; }
.pager-info { font-family: var(--serif); font-style: italic; color: var(--muted); font-size: 13px; }
.btn.disabled { opacity: .4; pointer-events: none; }

/* File d'attente d'import */ .qres.err { color: var(--err); } .qres.doing { color: var(--muted); }

/* Tablette */
@media (max-width: 1140px) {
  .sidebar { width: 232px; }
  .main { padding: 24px 20px 72px; }
  .docs.size-l { --cardw: 240px; }
}
@media (max-width: 600px) {
  .qitem { grid-template-columns: 18px 1fr auto; }
  .qnote { grid-column: 1 / -1; }
}

/* ============ Tableau de bord ============ */
/* R998 — LES CARTES DU TABLEAU DE BORD, REPRISES.
   À 150 px, un libellé comme « À vérifier (lecture incertaine) » se cassait sur
   trois lignes et la carte doublait de hauteur : la grille devenait irrégulière,
   et l'on croyait à un désordre. 190 px laisse tenir deux lignes au plus.

   Les cartes gardent la MÊME hauteur, quel que soit leur libellé — une grille
   régulière se lit d'un regard, une grille en dents de scie se déchiffre. */
.dash-grid {
  display: grid; gap: 12px; margin-bottom: var(--e3);
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  align-items: stretch;
}
.kpi {
  display: flex; flex-direction: column; justify-content: space-between; gap: 8px;
  min-height: 92px; padding: 14px 16px;
  background: var(--paper2); border: 1px solid var(--line); border-radius: 12px;
}
/* Le chiffre d'abord, en serif : c'est lui qu'on vient chercher. */
.kpi b {
  display: block; font-family: Georgia, serif; font-size: 25px; line-height: 1;
  color: var(--seal-dark);
}
/* Le libellé tient sur deux lignes ; au-delà, il s'abrège plutôt que de pousser
   la carte — le titre complet reste dans l'infobulle du navigateur. */
.kpi span {
  font-size: 10.5px; line-height: 1.35; color: var(--muted);
  letter-spacing: .04em; text-transform: uppercase;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.kpi.warn b { color: #9a6b1f; }
.kpi.link { text-decoration: none; transition: border-color .15s, box-shadow .15s, transform .15s; }
.kpi.link:hover {
  border-color: var(--seal); transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .06);
}
/* Sur téléphone, deux colonnes valent mieux qu'une : on voit quatre chiffres
   sans défiler, et chacun reste lisible. */
@media (max-width: 560px) {
  .dash-grid { grid-template-columns: repeat(2, 1fr); gap: 9px; }
  .kpi { min-height: 78px; padding: 12px; }
  .kpi b { font-size: 21px; }
}

/* Les titres de section respirent : ils séparent les groupes plutôt que de
   flotter au-dessus d'eux. */
.dash-titre {
  display: flex; align-items: center; gap: 8px;
  margin: var(--e4) 0 var(--e2); padding-bottom: 7px;
  border-bottom: 1px solid var(--line);
  font-size: 14px; color: var(--seal-dark);
}
.dash-titre:first-of-type { margin-top: 0; }

.dash-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 16px; }
@media (max-width: 900px) { .dash-cols { grid-template-columns: 1fr; } }
.bar-row { display: grid; grid-template-columns: 72px 1fr 44px; align-items: center; gap: 9px; margin: 8px 0; font-size: 12px; }
.bar-row .lbl { color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-row .val { text-align: right; font-family: Georgia, serif; color: var(--seal-dark); }
.bar-track { height: 13px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.bar-fill { height: 100%; background: linear-gradient(90deg, var(--seal) 0%, #1d8a77 100%); border-radius: 4px; min-width: 2px; }
.bar-fill.gold { background: linear-gradient(90deg, #b8862b, #d4a94e); }
.dash-list { list-style: none; margin: 0; padding: 0; font-size: 13px; }
/* R1334 — UNE LIGNE QUI NE TIENT PAS SE REPLIE, À TOUTE LARGEUR.
   Le repli n'existait que sous un petit écran (une règle de R1066 dans la
   requête de média). Or l'arabe dit en plus de signes ce que le français dit
   en peu : sur l'écran des réglages, « قارئ الخط اليدوي — الخدمة تستجيب لكن
   لا محرك محمَّل » poussait la carte des outils externes à 926 px dans une
   place de 748, la page prenait une barre de défilement horizontale, et TOUT
   l'écran se décalait — c'est la bande blanche que le client a photographiée.
   Une ligne qui déborde n'attend pas un petit écran : elle déborde. */
.dash-list li { position: relative; display: flex; flex-wrap: wrap; row-gap: 4px; gap: 9px;
  align-items: baseline; padding: 8px 2px; border-bottom: 1px dashed var(--line); }
/* Et le premier morceau — le nom de l'outil — doit pouvoir se couper : sans
   min-width, un élément de flex refuse de descendre sous la largeur de son
   contenu, et le repli ne sert à rien. */
.dash-list li .dash-nom, .dash-list li > span:first-of-type { min-width: 0; overflow-wrap: anywhere; }
.dash-list li:last-child { border-bottom: 0; }
.dash-list .when { color: var(--muted); font-size: 11px; white-space: nowrap; margin-inline-start: auto; }

/* ============ Cartes : responsive fin ============ */
@media (max-width: 600px) {
  .docs.view-cards { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  /* R631 : les libellés des gestes restent — la carte d'un téléphone est
     celle du bureau, à toute la largeur, elle a la place de les écrire. */
  .view-cards .doc-actions .act { padding: 8px 6px; }
  .doc-thumb { height: 108px; }
}
@media (max-width: 420px) {
  .docs.view-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
  .dbody { padding: 8px 8px; }
  .dash-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bar-row { grid-template-columns: 58px 1fr 36px; font-size: 12px; }
}

/* ============ Filtres du dossier : hauteur unique & états ============ */
.filters select, .filters input[type="date"] {
  height: var(--ctl); border: 1px solid var(--line2); background: var(--panel);
  border-radius: 8px; padding: 0 8px; font: inherit; font-size: 13px; color: var(--ink);
}
.filters input[type="date"] { width: 138px; color: var(--muted); }
.filters input[type="date"].on { color: var(--ink); }
.filters .on { border-color: var(--seal); background: #fff; }
.filters select.on { color: var(--sel-dark); font-weight: 600; border-color: var(--sel); }   /* R573 ; R583 : sans fond bleu — le texte et le liseré suffisent */
.chip.count {
  height: var(--ctl); display: inline-flex; align-items: center; padding: 0 12px;
  background: var(--seal-soft); color: var(--seal-dark); border: 0; border-radius: 8px;
  font-size: 12px; white-space: nowrap;
}
.btn.reset { color: #8a3b2e; border-color: #d9b8ae; }
.btn.reset:hover { background: #fbf1ee; border-color: #8a3b2e; }
.tb-right { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }
@media (max-width: 900px) {
  .tb-right { flex-basis: 100%; justify-content: flex-end; }
  .filters input[type="date"] { width: 128px; }
}

/* ============ Champs métier détectés ============ */
.fields-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.field-chip {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px;
  background: var(--paper2); border: 1px solid var(--line); border-radius: 8px; font-size: 13px;
}
.field-chip .fk {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted);
}
.field-chip b { font-family: Georgia, serif; color: var(--seal-dark); user-select: all; }

/* ============ Glisser-déposer vers l'arbre ============ */
.docitem.dragging { opacity: .45; }
.tree-row.drop-ok {
  outline: 2px dashed var(--seal); outline-offset: -2px;
  background: var(--seal-soft); border-radius: 8px;
}

/* ============ En-têtes cliquables (vue liste) ============ */
.docs .list-head { display: none; }
.docs.view-list .list-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 12px 8px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted);
}
.list-head a:hover { color: var(--seal); }

@media (prefers-reduced-motion: reduce) { .qitem.scanning::after { animation: none; } }

/* Bouton de reprise d'un fichier en échec */

/* ============ Import d'UN seul fichier : mode individuel ============ */

/* ============ Modale de confirmation ============ */
.modal-card.modal-sm { max-width: 420px; }
.confirm-text {
  margin: 4px 0 16px; font-size: 15px; line-height: 1.6; color: var(--ink);
}
.confirm-actions { display: flex; gap: 10px; justify-content: flex-end; }
.confirm-actions .btn { min-width: 110px; justify-content: center; }

/* État « à vérifier » dans la file d'import : ni succès, ni échec */

/* ============ Texte de page : lecture structurée ============ */
.pagetext.structure {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 15px; line-height: 1.75; color: var(--ink);
  white-space: normal; max-width: 76ch;
}
.pagetext.structure .pg-l { margin: 0 0 2px; padding: 1px 0; }
.pagetext.structure .pg-l[dir="rtl"] { text-align: right; font-size: 15px; }
.pagetext.structure .pg-titre {
  font-weight: 700; letter-spacing: .02em; color: var(--seal-dark);
  margin-top: 8px; font-size: 15px;
}
.pagetext.structure .pg-data {
  font-family: "SF Mono", Consolas, monospace; font-size: 13px;
  background: var(--paper2); border-radius: 4px; padding: 4px 8px;
  display: inline-block; margin-bottom: 4px;
}
.pagetext.structure .pg-num {
  background: var(--seal-soft); border-radius: 4px; padding: 0 4px;
  font-weight: 700; letter-spacing: .03em; user-select: all;
}
.pagetext.structure .pg-sep { height: 12px; }
.pagetext.structure .pg-empty { color: var(--muted); font-style: italic; }

/* ============ Conseil de capture dans la fenêtre d'import ============ */

/* ============ Progression de lecture, étape par étape ============ */

@media (prefers-reduced-motion: reduce) {
  .qitem.scanning::before, .qitem.scanning::after { animation: none; opacity: .2; }
}

/* ============ Barre de progression de lecture ============ */

@media (prefers-reduced-motion: reduce) { .qitem.scanning .qprog-bar i { animation: none; } }


/* ============ Cloche de notifications ============ */
.badgebtn.notif { position: relative; }
.badgebtn.notif.on { color: var(--seal-dark); }
.badgebtn.notif.on b {
  background: var(--seal); color: #fff; font-size: 11px;
  padding: 1px 4px; border-radius: 99px; margin-inline-start: 4px;
}

/* Liste des notifications */
.notif-list { display: flex; flex-direction: column; gap: 8px; }
.notif-item {
  display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--paper);
  text-decoration: none; color: inherit;
}
.notif-item.neuf { background: var(--seal-soft); border-color: var(--seal); }
.notif-item:hover { border-color: var(--seal); }
.notif-item .nt { font-weight: 700; color: var(--seal-dark); }
.notif-item .nd { color: var(--muted); font-size: 13px; margin-top: 2px; }
.notif-item .nq { margin-inline-start: auto; color: var(--muted); font-size: 12px; white-space: nowrap; }


/* ============ Fenêtre d'import : présentation compacte ============ */

/* Une ligne = un fichier : en-tête, champs, barre */

/* Vignette : apparaît quand la lecture commence */
@media (prefers-reduced-motion: reduce) { .qitem.scanning .qvign::before { animation: none; } }



/* ==========================================================================
   LECTURE D'UN DOCUMENT — parcours à un seul fichier.
   Principe : une chose à la fois. On dépose, on voit, on nomme, on lit.
   ========================================================================== */
.lecture-card { max-width: 560px; }

/* --- Message d'information : posé, lisible, sans crier --- */
.info-bloc {
  display: flex; gap: 11px; align-items: flex-start;
  margin-top: 16px; padding: 12px 16px;
  background: var(--paper2); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--seal); border-radius: 8px;
}
.info-ico { flex: none; color: var(--seal); margin-top: 1px; }
.info-txt {
  font-family: system-ui, sans-serif; font-size: 12px; line-height: 1.6; color: var(--muted);
}
.info-txt b {
  display: block; color: var(--seal-dark); font-size: 12px; margin-bottom: 4px;
  text-transform: uppercase; letter-spacing: .05em;
}

/* --- Le document : aperçu centré, format portrait --- */
.lec-doc { display: flex; flex-direction: column; align-items: center; gap: 9px; margin-bottom: 16px; }
.lec-cadre {
  position: relative; width: 148px; height: 196px; overflow: hidden;
  border-radius: 8px; border: 1px solid var(--line);
  background: #fff; box-shadow: 0 1px 3px rgba(33,48,46,.06);
  display: flex; align-items: center; justify-content: center;
}
.lec-cadre img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lec-fallback {
  width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
}
.lec-fallback svg { display: block; width: 100%; height: 100%; }
.lec-nom {
  font-size: 12px; color: var(--muted); max-width: 320px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: system-ui, sans-serif;
}

/* Le faisceau : il ne tourne QUE pendant la lecture réelle */
.lec-faisceau { display: none; }
.lec-cadre.lit .lec-faisceau {
  display: block; position: absolute; inset-inline-start: 0; inset-inline-end: 0; height: 38%; z-index: 2;
  background: linear-gradient(180deg, transparent, rgba(14,107,92,.28), transparent);
  box-shadow: 0 10px 30px rgba(33,48,46,.14);
  animation: lecBalai 1.9s ease-in-out infinite;
}
@keyframes lecBalai { 0% { top: -38%; } 100% { top: 100%; } }
.lec-cadre.lit { border-color: var(--seal); }
@media (prefers-reduced-motion: reduce) { .lec-cadre.lit .lec-faisceau { animation: none; opacity: .3; } }

/* --- Champs : empilés, pleine largeur, jamais coupés --- */
.lec-champs { display: flex; flex-direction: column; gap: 11px; }
.lec-label {
  display: flex; flex-direction: column; gap: 5px;
  font-size: 12px; color: var(--muted); font-family: system-ui, sans-serif;
}
/* Les cases à cocher et boutons radio sont EXCLUS : cette géométrie est
   celle des champs de saisie. Sans cette garde, une case posée dans un
   .lec-label héritait de height:36px + padding + rayon 8 et devenait une
   pilule verte géante (constaté sur les Réglages) — trois demi-rustines
   locales (.lec-case, .fiche-prefs, .envoi-garder) tentaient déjà de
   colmater la fuite, chacune à moitié. La source est bouchée ici. */
.lec-label input:not([type=checkbox]):not([type=radio]) {
  width: 100%; height: var(--ctl); padding: 0 12px; font-size: 14px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--paper);
  color: var(--ink); font-family: inherit;
}
.lec-label input:focus { outline: none; border-color: var(--seal); }

/* --- Suivi : barre + étape réelle du moteur --- */
.lec-suivi { margin-top: 16px; }
.lec-bar { height: 6px; background: var(--line); border-radius: 99px; overflow: hidden; }
.lec-bar i {
  display: block; height: 100%; width: 6%; border-radius: 99px;
  background: linear-gradient(90deg, var(--seal), #1a8c78);
  transition: width .6s ease;
}
.lec-etat {
  margin-top: 8px; font-size: 12px; color: var(--seal-dark);
  font-family: system-ui, sans-serif; min-height: 18px;
}

/* --- Verdict --- */
.lec-verdict {
  display: flex; flex-direction: column; gap: 3px;
  margin: 4px 0 20px; padding: 12px 16px; border-radius: 8px;
  font-family: system-ui, sans-serif; font-size: 12px; line-height: 1.55;
}
.lec-verdict b { font-size: 13px; }
.lec-verdict.ok        { background: #E6F4EF; border: 1px solid var(--seal); color: var(--seal-dark); }
.lec-verdict.attention { background: #FDF4E3; border: 1px solid #B07908; color: #7A5406; }
.lec-verdict.ko        { background: #FBEDEA; border: 1px solid #A33A22; color: #8A2E1B; }
.lec-verdict span { color: inherit; opacity: .85; }

.lec-actions { display: flex; gap: 9px; margin-top: 16px; }
.lec-actions .btn { flex: 1; justify-content: center; }
.lec-actions .btn:not(.primary) { flex: 0 0 auto; }

/* Bloc SQL des migrations : lisible et sélectionnable d'un coup */
.sqlbox {
  background: var(--paper2); border: 1px solid var(--line); border-radius: 8px;
  padding: 12px 16px; margin: 12px 0; overflow-x: auto;
  font-family: "SF Mono", Consolas, monospace; font-size: 12px; line-height: 1.6;
  color: var(--ink); user-select: all; white-space: pre;
}

/* ============ Bandeau de confirmation ============ */
.flash-toast {
  /* R1334 — physique avec physique : « translate(-50%) » plus bas ne se
     retourne pas, donc l'ancrage ne doit pas se retourner non plus. */
  position: fixed; left: 50%; bottom: 26px; z-index: 9999;
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; border-radius: 8px;
  background: var(--seal); color: #fff;
  font-family: system-ui, sans-serif; font-size: 14px;
  box-shadow: 0 10px 30px rgba(33,48,46,.14);
  transform: translate(-50%, 14px); opacity: 0;
  transition: transform .28s ease, opacity .28s ease;
  max-width: min(90vw, 460px);
}
.flash-toast.on { transform: translate(-50%, 0); opacity: 1; }
.flash-toast .ft-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  background: rgba(255,255,255,.22); font-size: 12px; flex: none;
}
@media (prefers-reduced-motion: reduce) { .flash-toast { transition: none; } }

/* ============ Filtres repliables : la recherche d'abord ============ */
.filters[hidden] { display: none !important; }

/* ============ Dossiers : en-tête, filtre, expansion ============ */
.dossiers-tete {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 4px;
}
.dossiers-tete .cap { margin: 0; }
.cap-n {
  background: var(--paper2); border: 1px solid var(--line); border-radius: 99px;
  padding: 0 8px; font-size: 11px; color: var(--muted); margin-inline-start: 6px;
}
.dossiers-filtre {
  margin-inline-start: auto; height: 32px; width: min(240px, 45vw);
  padding: 0 12px; font-size: 13px; font-family: system-ui, sans-serif;
  border: 1px solid var(--line); border-radius: 99px;
  background: var(--paper); color: var(--ink);
}
.dossiers-filtre:focus { outline: none; border-color: var(--seal); }
.voir-tout {
  margin-top: 12px; color: var(--seal-dark);
  border-style: dashed; width: 100%; justify-content: center;
}
.dossiers-vide {
  grid-column: 1 / -1; margin: 8px 0; color: var(--muted);
  font-size: 13px; font-style: italic;
}

/* ============ Dossier d'origine sur la carte document ============ */
.doc-chemin {
  display: inline-flex; align-items: center; gap: 5px;
  align-self: flex-start;   /* épouse le texte, ne s'étire pas */
  width: fit-content;
  margin: 4px 0 2px; padding: 3px 10px 3px 8px;
  max-width: 100%; border-radius: 12px;
  background: var(--paper2); border: 1px solid var(--line);
  color: var(--muted); font-family: system-ui, sans-serif;
  font-size: 11px; text-decoration: none; line-height: 1.7;
}
.doc-chemin span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch;
}
.doc-chemin svg { flex: none; opacity: .7; }
.doc-chemin:hover { border-color: var(--seal); color: var(--seal-dark); }
.doc-chemin:hover svg { opacity: 1; }

/* Sous-titre dans une carte : hiérarchie sans multiplier les cadres */
.sous-titre {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 12px; font-family: var(--serif); font-weight: 400;
  font-size: 15px; color: var(--seal-dark);
}
.rule-fine { border: 0; border-top: 1px solid var(--line); margin: 20px 0 16px; }

/* ==========================================================================
   BARRE EN DEUX BLOCS — « ce que je fais » puis « ce que je cherche ».
   Séparer les deux évite la barre fourre-tout où l'œil ne sait plus regarder.
   ========================================================================== */
.barre-actions {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 12px 0 12px;
}
.ba-gauche, .ba-droite { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ba-droite { margin-inline-start: auto; }
.ba-sep {
  width: 1px; height: 20px; background: var(--line); margin: 0 4px;
}
.barre-separateur {
  border: 0; border-top: 1px solid var(--line); margin: 0 0 12px;
}
.barre-filtres {
  /* Disposition, espacements et habillage RÉUNIS. Éparpillées sur quatre
     endroits, ces déclarations se contredisaient sans qu'on le voie. */
  display: flex; align-items: flex-end; gap: 7px 9px; flex-wrap: wrap;
  padding: 14px 9px 16px;
  background: var(--paper2);
  border: 1px solid var(--line);
  border-radius: 12px;
  margin-bottom: 4px;
}
.barre-filtres .filters {
  border: 0; margin: 0; padding: 0; width: auto; gap: 8px;
}
.barre-filtres .scoped-search { flex: none; width: 100%; max-width: none; }

/* --- Période : un seul champ, un panneau, des raccourcis --- */
.periode { position: relative; }
.periode-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: var(--ctl); padding: 0 12px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--paper); color: var(--ink);
  font-family: system-ui, sans-serif; font-size: 13px;
}
.periode-btn:hover { border-color: var(--seal); }
.periode.on .periode-btn { border-color: var(--seal); color: var(--seal-dark); font-weight: 600; }
.periode-raccourcis button:hover { background: var(--seal-soft); color: var(--seal-dark); border-color: var(--seal); }

/* Le type de document porte une icône via son fond */
.sel-type { padding-inline-start: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236B675E' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3v5h5M6 3h8l5 5v13a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 9px center;
}


/* ==========================================================================
   BARRE COLLANTE — les deux blocs forment un ensemble solidaire. Ils se
   collent SOUS l'en-tête, jamais dessous : d'où le calcul de décalage.
   ========================================================================== */
.barre-filtres.collante {
  position: sticky; top: var(--h-topbar, 55px); z-index: 30;
  /* Fond PLEIN, sans transparence ni flou : rien ne doit transparaître du
     contenu qui défile dessous, sinon la barre devient illisible. */
  background: var(--paper2);
  /* Aucune marge négative : la barre reste DANS la colonne de contenu, à
     droite de la barre latérale. Le rembourrage est celui de l'état normal —
     collée ou non, le bloc garde exactement la même géométrie. */
  margin-inline-start: 0;
  margin-inline-end: 0;
  width: auto;
  border-bottom: 1px solid var(--line);
  transition: box-shadow .2s ease;
}
@media (prefers-reduced-motion: reduce) { .barre-filtres.collante { transition: none; } }
/* Collée : une ombre nette sous le bloc, pour qu'on voie qu'il flotte
   au-dessus du contenu plutôt que d'en faire partie. */
.barre-filtres.collante.collee {
  box-shadow: 0 10px 30px rgba(33,48,46,.14);
  border-bottom-color: transparent;
}




/* ============ Rappel d'arborescence (création de dossier) ============ */
.arbo-rappel {
  margin-bottom: 16px; padding: 12px 14px;
  background: var(--paper2); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--seal); border-radius: 8px;
}
.ar-cap {
  display: block; margin-bottom: 8px; font-size: 11px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--seal-dark); font-weight: 700;
  font-family: system-ui, sans-serif;
}
.ar-chemin {
  display: flex; align-items: flex-start; gap: 6px; flex-wrap: wrap;
  font-family: system-ui, sans-serif; font-size: 12px;
}
.ar-seg {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 12px; border-radius: 12px;
  background: var(--paper); border: 1px solid var(--line); color: var(--muted);
  /* Le nom complet, jamais coupé : un dossier tronqué ne renseigne pas sur
     l'emplacement. Il passe à la ligne s'il est long. */
  white-space: normal; overflow-wrap: anywhere; line-height: 1.45;
  text-align: start;
}
.ar-seg svg { flex: none; opacity: .65; margin-top: 1px; }
.ar-fleche { color: var(--line); font-size: 14px; align-self: center; }
.ar-seg.neuf {
  background: var(--seal-soft); border-color: var(--seal); color: var(--seal-dark);
  font-weight: 600; border-style: dashed;
}
.ar-seg.neuf i { font-style: italic; opacity: .75; }
.ar-seg.neuf.rempli i { font-style: normal; opacity: 1; }


/* --------------------------------------------------------------------------
   PÉRIODE — panneau assez large pour ses champs. Un input[type=date] réclame
   ~150 px : deux côte à côte dans 234 px débordaient forcément. On les empile,
   et le panneau s'aligne à droite pour ne jamais sortir de l'écran.
   -------------------------------------------------------------------------- */
/* PANNEAU DE PÉRIODE — définition UNIQUE. Il était défini à quatre endroits
   distants ; c'est ce morcellement qui rendait ses corrections si difficiles
   à suivre. Position, dimensions, plan et défilement sont réunis ici. */
.periode-panneau {
  position: absolute;
  top: calc(100% + 6px);
  inset-inline-start: 0;
  z-index: 39;
  /* au-dessus des barres, sous l'en-tête */
  width: 268px;
  max-width: calc(100vw - 32px);
  padding: 10px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: 0 10px 30px rgba(33,48,46,.14);
  max-height: calc(100vh - var(--h-topbar, 55px) - 28px);
  max-height: calc(100dvh - var(--h-topbar, 55px) - 28px);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* en butée, la page ne suit pas */
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

/* Deux par ligne : cinq entrées empilées faisaient un panneau trop haut. */
.periode-raccourcis {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
}
.pr-large { grid-column: 1 / -1; }
.periode-raccourcis button {
  display: flex; align-items: center; justify-content: center;
  padding: 8px 4px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--paper); color: var(--ink);
  font-family: system-ui, sans-serif; font-size: 12px; white-space: nowrap;
}

.periode-libre {
  display: flex; flex-direction: column; gap: 8px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
}
.periode-libre-cap {
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); font-family: system-ui, sans-serif; font-weight: 700;
}
.periode-libre label {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--muted); font-family: system-ui, sans-serif;
}
.periode-libre label > span { flex: none; width: 26px; }
.periode-libre input {
  flex: 1 1 auto; min-width: 0;      /* la clé : le champ peut rétrécir */
  height: 32px; font-size: 13px; padding: 0 8px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--paper); color: var(--ink); font-family: inherit;
}
.periode-libre input:focus { outline: none; border-color: var(--seal); }
.periode-appliquer { margin-top: 2px; width: 100%; justify-content: center; }


.periode-panneau.vers-gauche { inset-inline-start: auto; inset-inline-end: 0; }
/* R710 — QUAND LA PLACE MANQUE EN BAS, LE PANNEAU MONTE. Il s'ouvrait toujours
   vers le bas : près du bord de la fenêtre, il se réduisait et se mettait à
   DÉFILER en lui-même — on ne voyait plus que deux raccourcis sur cinq, et
   « Appliquer » disparaissait. Ouvert vers le haut, il tient entier. */
.periode-panneau.vers-haut { top: auto; bottom: calc(100% + 6px); }

/* ============ Champs de filtre : chacun son intitulé ============ */
.champ-filtre {
  display: flex; flex-direction: column; gap: 5px;
}
.champ-filtre > label {
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); font-family: system-ui, sans-serif; font-weight: 700;
  padding-inline-start: 2px;
}
.barre-filtres .filters { align-items: flex-end; }
/* Le compteur et l'effacement s'alignent sur la base des champs */
.barre-filtres > .chip.count, .barre-filtres > .reset { margin-bottom: 4px; }


/* ==========================================================================
   VALIDATION DES CHAMPS — une bannière discrète, pas du texte rouge nu.
   Le champ signale la faute par sa bordure ; le message l'explique sans
   crier. On veut aider à corriger, pas réprimander.
   ========================================================================== */
.champ-erreur {
  border-color: #C4553A !important;
  outline: 3px solid rgba(196,85,58,.10); outline-offset: 0;
}
.champ-erreur:focus {
  border-color: #A33A22 !important;
  outline: 3px solid rgba(163,58,34,.16); outline-offset: 0;
}

.champ-message {
  /* R675 — LE MESSAGE SE POSE SOUS LE CHAMP, JAMAIS À CÔTÉ. Il s'insère après
     le champ (l'ordre de lecture le veut) ; mais dans une grille, la case
     suivante est à DROITE, et dans une rangée souple il se glisse entre deux
     éléments — on l'a vu s'installer à côté du choix du type de question, en
     écrasant la mise en page. Ces deux lignes le forcent à prendre une ligne
     entière, quelle que soit la disposition du parent : toutes les colonnes
     d'une grille, toute la largeur d'une rangée. */
  grid-column: 1 / -1; flex-basis: 100%; max-width: 100%;
  /* R696 — et il se place EN DERNIER dans une rangée souple. Inséré juste après
     le champ (l'ordre de lecture le veut, et le lecteur d'écran l'annonce là),
     il séparait le champ de sa croix : « champ / message / ✕ ». L'ordre visuel
     le renvoyait au bout — on lit « champ ✕ », puis le message dessous.

     R760 — MAIS SEULEMENT DANS UNE RANGÉE. « order: 99 » vaut dans TOUS les
     conteneurs souples, y compris ceux qui empilent EN COLONNE : sur la page
     du premier accès, les deux messages sautaient au bas du formulaire, sous
     le bouton « Enregistrer », loin des champs qu'ils désignaient — on lisait
     deux fois « ce champ est obligatoire » sans savoir lequel. Le renvoi au
     bout n'a de sens que là où les éléments se suivent HORIZONTALEMENT : on
     l'y borne. En colonne, le message reste où le balisage le met, c'est-à-dire
     juste sous son champ. */
  order: 0;
  display: flex; align-items: flex-start; gap: 8px;
  margin: 8px 0 2px; padding: 8px 11px;
  background: #FCF1EE; border: 1px solid #EBCFC7;
  border-inline-start: 3px solid #C4553A; border-radius: 8px;
  color: #8A2E1B; font-family: system-ui, sans-serif;
  font-size: 12px; line-height: 1.5;
  animation: cmApparait .22s ease;
}
@keyframes cmApparait {
  from { opacity: 0; transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) { .champ-message { animation: none; } }

/* R760 : le renvoi au bout, réservé aux conteneurs qui alignent en RANGÉE. */
.form-inline > .champ-message, .flex2 > .champ-message,
.lec-actions > .champ-message, .val-actions > .champ-message,
.quest-qb-tete > .champ-message, .kb-champ > .champ-message { order: 99; }

.champ-message .cm-ico {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-top: 1px; border-radius: 99px;
  background: #C4553A; color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
}
.champ-message .cm-txt { flex: 1; min-width: 0; }

/* Effacer les filtres : la flèche circulaire dit « revenir à l'état initial » */
.btn.reset { gap: 6px; color: var(--muted); }
.btn.reset:hover { color: var(--seal-dark); border-color: var(--seal); }
.btn.reset svg { transition: transform .3s ease; }
.btn.reset:hover svg { transform: rotate(-180deg); }
@media (prefers-reduced-motion: reduce) { .btn.reset svg { transition: none; } }






/* --------------------------------------------------------------------------
   Un enfant ne peut pas passer au-dessus du niveau de son parent. Le panneau
   de période vit dans la barre (niveau 30), sous l'en-tête (niveau 40) : il
   restait donc dessous. Quand un panneau est ouvert, la barre s'élève.
   -------------------------------------------------------------------------- */
/* Repli pour les navigateurs sans :has() : voir « .periode-ouverte », posé par le script (R519). */

/* ============ Portée de la recherche ============ */
.portee-recherche {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin: 10px 0 0; padding: 8px 12px;
  background: var(--paper2); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--seal); border-radius: 8px;
  font-family: system-ui, sans-serif; font-size: 12px; color: var(--muted);
}
.portee-recherche svg { flex: none; opacity: .7; }
.portee-recherche b { color: var(--seal-dark); }
.portee-recherche a { margin-inline-start: auto; color: var(--seal-dark); font-weight: 600; }

/* ============ En-tête de section avec ses commandes ============ */

/* Zone de note : deux lignes par défaut, redimensionnable verticalement */
.lec-label textarea {
  width: 100%; padding: 9px 11px; font-size: 14px; line-height: 1.5;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--paper); color: var(--ink);
  font-family: inherit; resize: vertical; min-height: 62px; max-height: 200px;
}
.lec-label textarea:focus { outline: none; border-color: var(--seal); }

/* Suivi de lecture, rattaché au document */
.lec-doc .lec-suivi { width: 100%; max-width: 320px; margin-top: 4px; }

/* Garde-fou : aucun bloc ne doit provoquer de défilement horizontal. */
body { max-width: 100vw; }
.main { max-width: 100%; }

/* ==========================================================================
   ADAPTATION AUX PETITS ÉCRANS
   Quatre seuils : 1140 (tablette large), 900 (tablette), 600 (mobile),
   420 (petit mobile). Principe : rien ne doit jamais déborder du cadre —
   une barre de défilement horizontale sur mobile rend une page inutilisable.
   ========================================================================== */

/* --- Garde-fous universels, tous écrans --- */
img, svg, video, canvas { max-width: 100%; height: auto; }
pre, code { max-width: 100%; overflow-x: auto; }
/* Un mot très long (référence, URL, nom de fichier) ne doit pas élargir la page */
.doc-title, .entry-title, .kv span, .notif-item, .lec-nom { overflow-wrap: anywhere; }

@media (max-width: 900px) {
  :root { --pad-main: 20px; }
  /* Les filtres passent sur deux rangées plutôt que de se comprimer */
  .barre-filtres { gap: 10px 8px; }
  .champ-recherche { flex: 1 1 100%; max-width: none; }
  .section-tete { gap: 8px; }
  /* Grille de documents : cartes plus étroites, jamais rognées */
  .docs.view-cards { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

@media (max-width: 600px) {
  :root { --pad-main: 14px; }
  /* Une seule colonne : la lecture prime sur la densité */
  .barre-actions { gap: 6px; }
  .ba-gauche, .ba-droite { width: 100%; }
  .ba-droite { justify-content: flex-start; margin-inline-start: 0; }
  .champ-filtre { flex: 1 1 100%; }
  .champ-filtre select, .periode-btn { width: 100%; }
  .barre-filtres > .chip.count, .barre-filtres > .reset { margin-bottom: 0; }

  /* Les tableaux défilent DANS leur cadre, sans élargir la page */
  table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tblwrap { margin: 0; }

  /* Fenêtres : presque plein écran, le contenu a besoin de place */
  .modal { padding: 8px; }
  .modal-card { max-height: 94vh; max-height: 94dvh; }
  .lec-actions { flex-direction: column; }
  .lec-actions .btn { width: 100%; }

  /* Panneau de période : pleine largeur, ancré à gauche */
  .periode-panneau { width: calc(100vw - 36px); left: 0; right: auto; }

  /* Cartes de document : la vue liste devient plus lisible que les cartes */
  .docs.view-cards { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .foldergrid { grid-template-columns: 1fr 1fr; }
  .dossiers-filtre { margin-inline-start: 0; width: 100%; }
  .dossiers-tete { gap: 8px; }
}

@media (max-width: 420px) {
  :root { --pad-main: 10px; }
  .docs.view-cards { grid-template-columns: 1fr 1fr; }
  .foldergrid { grid-template-columns: 1fr; }
  .lec-cadre { width: 120px; height: 160px; }
  .periode-raccourcis { grid-template-columns: 1fr; }
  /* Les segments d'affichage restent tactiles */
  .seg button { min-width: 34px; min-height: 34px; }
}

/* Les largeurs minimales conçues pour le bureau empêchent les blocs de
   rétrécir : elles créent un débordement sur mobile. On les libère. */
@media (max-width: 600px) {
  .uploadrow input[type=text],
  .formrow > div,
  .scoped-search { min-width: 0; }
  /* Le tableau garde sa largeur mais défile dans son cadre */
  .tblwrap { overflow-x: auto; max-width: 100%; }
}



/* --------------------------------------------------------------------------
   CHAMP DE RECHERCHE — définition UNIQUE. Il vit dans un conteneur en colonne
   (avec son intitulé) : sans hauteur ferme il s'étirerait sur toute la hauteur
   disponible. Une seule règle, pour qu'aucune autre ne vienne la contredire.
   -------------------------------------------------------------------------- */
.champ-recherche {
  display: flex; flex-direction: column; gap: 5px;
  /* R653 — LE CHAMP CÈDE CE QU'IL FAUT POUR QUE « EFFACER » RESTE SUR LA
     PREMIÈRE LIGNE. Il partait de 220 px et grandissait jusqu'à 300 : sur un
     écran d'un peu moins de 1 300 px, les six filtres remplissaient la ligne
     et le bouton d'effacement tombait seul en dessous. Il part maintenant de
     140 px et grandit jusqu'à 240 selon la place restante.
     Le point de rupture ne tenait pas à la largeur de départ mais à un
     PLANCHER INVISIBLE : la boîte de recherche est marquée « flex: none »
     dans cette barre, donc incompressible, et un champ de saisie mesure de
     lui-même vingt caractères — la colonne ne pouvait pas descendre sous
     240 px, quoi qu'on écrive comme largeur de départ. Un plancher déclaré
     (min-width) lève cette contrainte : la colonne peut alors céder, et
     « Effacer » reste sur la ligne. */
  flex: 1 1 140px; min-width: 140px; max-width: 240px;   /* R582 ; R625 ; R653 */
}
.champ-recherche .scoped-search {
  flex: none;
  height: var(--ctl); min-height: var(--ctl); max-height: var(--ctl);
  width: 100%; max-width: none; align-self: stretch;
}

/* ============ Styles manquants relevés par la revue ============ */
/* Message d'absence de contenu : présent sur 10 pages, jamais stylé */
.empty-hint {
  color: var(--muted); font-size: 13px; line-height: 1.6;
  font-family: system-ui, sans-serif; margin: 8px 0 0;
}
/* Arbre latéral : compte de pièces et nom du dossier */
.tree-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-count {
  flex: none; margin-inline-start: auto; padding: 0 6px;
  font-size: 11px; color: var(--muted);
  background: var(--paper2); border-radius: 99px;
}
.tree-empty {
  padding: 12px 4px; color: var(--muted); font-size: 12px;
  line-height: 1.6; font-family: system-ui, sans-serif;
}


/* Les groupes de boutons s'alignent sur la base du menu, pas sur le haut. */



/* --------------------------------------------------------------------------
   RÉGLAGES D'AFFICHAGE — tri, vue cartes/liste et taille. Placés APRÈS les
   filtres, juste au-dessus de la liste : au plus près de ce qu'ils gouvernent.
   Alignés à droite pour ne pas concurrencer les filtres à gauche.
   -------------------------------------------------------------------------- */
.section-tete {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 24px 0 12px;
}
.section-tete .cap { margin: 0; }

.barre-affichage {
  display: flex; justify-content: flex-end; align-items: center; gap: 12px;
  margin: 14px 0 4px;
}
/* R625 → R627 : le compte est retiré ; la règle qui lui gardait sa place aussi. */
.section-vues {
  display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap;
}
.tri-vues { gap: 5px; }
.tri-vues select { height: var(--ctl); min-width: 148px; }

@media (max-width: 640px) {
  .barre-affichage { justify-content: stretch; }
  .section-vues { width: 100%; }
  .tri-vues { flex: 1 1 100%; }
  .tri-vues select { width: 100%; }
}

/* La section des résultats s'arrête sous les barres collantes, pas dessous */
#resultats { scroll-margin-top: 120px; }


/* --------------------------------------------------------------------------
   CARTES DE MÊME HAUTEUR — le corps s'étire et pousse les actions vers le bas.
   Ainsi les boutons de toutes les cartes d'une rangée s'alignent, quel que
   soit le nombre de lignes du titre ou la présence d'une pastille de dossier.
   -------------------------------------------------------------------------- */
.view-cards .dbody { flex: 1 1 auto; }
.view-cards .doc-actions { margin-top: auto; padding-top: 8px; }


/* --------------------------------------------------------------------------
   La barre de filtres ne se colle QUE si un filtre agit. Règle explicite :
   si une autre déclaration tentait de la coller sans condition, celle-ci
   reprendrait la main.
   -------------------------------------------------------------------------- */
.barre-filtres:not(.collante) {
  position: static;
  box-shadow: none;
}

/* ============ Où le terme a été trouvé (résultats de recherche) ============ */

/* --------------------------------------------------------------------------
   PANNEAU DE PÉRIODE AU-DESSUS DES DOCUMENTS
   Chaque enfant direct de .main porte une animation d'apparition conservée
   (fill-mode « both ») : elle crée un plan d'empilement permanent. Le panneau
   reste donc enfermé dans le plan de la barre, que la grille des documents —
   plan suivant — recouvre. On élève le plan de la barre quand il est ouvert.
   -------------------------------------------------------------------------- */
.barre-filtres .sel-type { padding-inline-start: 28px; }
.barre-filtres .periode-btn { font-size: 13px; padding: 0 11px; }
/* Compteur et effacement : compacts, collés à la fin de la rangée */
.barre-filtres > .chip.count { padding: 0 9px; font-size: 12px; white-space: nowrap; }
.barre-filtres > .reset { padding: 0 10px; white-space: nowrap; }


/* ==========================================================================
   OÙ LE TERME A ÉTÉ TROUVÉ — une ligne par zone : l'étiquette dit OÙ,
   l'extrait montre QUOI. Sans cela, un résultat oblige à ouvrir le document
   pour comprendre pourquoi il remonte.
   ========================================================================== */
.zones-trouve {
  display: flex; flex-direction: column; gap: 5px;
  margin: 6px 0 4px;
}
.zone-l {
  display: flex; align-items: baseline; gap: 7px;
  min-width: 0;
}
.zone-t {
  flex: none; display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px 2px 6px; border-radius: 99px;
  background: var(--seal-soft); border: 1px solid var(--seal);
  color: var(--seal-dark); font-family: system-ui, sans-serif;
  font-size: 11px; line-height: 1.6; white-space: nowrap;
}
.zone-t svg { flex: none; opacity: .75; }
.zone-x {
  flex: 1 1 auto; min-width: 0;
  font-size: 12px; line-height: 1.5; color: var(--muted);
  font-family: system-ui, sans-serif;
  /* Deux lignes au plus : un extrait long ne doit pas déformer la carte. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.zone-x mark { background: #FFF3B0; color: inherit; font-weight: 600; border-radius: 3px; padding: 0 2px; }

/* --- Vue cartes : toutes les cartes d'une rangée à la même hauteur --- */
.docs.view-cards .docitem { display: flex; flex-direction: column; }
.docs.view-cards .dbody { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
/* Les métadonnées et les actions restent collées en bas, quelle que soit
   la hauteur des zones au-dessus. */
.docs.view-cards .doc-meta { margin-top: auto; }
/* En vue cartes, une seule ligne d'extrait suffit : la largeur est réduite. */
.docs.view-cards .zone-x { -webkit-line-clamp: 1; }

/* --- Écrans étroits : l'étiquette passe au-dessus de son extrait --- */
@media (max-width: 600px) {
  .zone-l { flex-direction: column; align-items: flex-start; gap: 3px; }
  .zone-x { -webkit-line-clamp: 2; }
}

/* --------------------------------------------------------------------------
   BARRE DE FILTRES — de l'air sur les quatre côtés. Collée aux bords, elle
   donnait l'impression de déborder de la page. Le fond léger la pose comme
   un bloc à part entière plutôt qu'une rangée flottante.
   -------------------------------------------------------------------------- */
/* Collée en haut, elle perd ses angles bas pour s'ancrer proprement. */
.barre-filtres.collante {
  border-radius: 12px 12px 0 0;
  margin-bottom: 0;
}

/* --------------------------------------------------------------------------
   PIED DE CARTE — type de document et actions alignés en bas de chaque carte.
   Les titres et extraits ont des longueurs variables : sans ancrage, la
   pastille et les boutons flottaient à des hauteurs différentes d'une carte
   à l'autre. Le pied les met au même niveau, quelle que soit la hauteur.
   -------------------------------------------------------------------------- */
.docs.view-cards .doc-pied {
  margin-top: auto;            /* pousse le pied vers le bas */
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
/* En vue liste, la rangée reste dans le flux : pas de pied. */
.docs.view-list .doc-pied { margin-top: 4px; padding-top: 0; border-top: 0; }

/* --------------------------------------------------------------------------
   BARRE LATÉRALE FIXE — l'arborescence reste à portée pendant qu'on parcourt
   une longue liste. Elle se cale sous l'en-tête et défile pour elle-même,
   sans entraîner la page. Sa barre de défilement reprend les teintes du site
   plutôt que le gris par défaut du navigateur.
   -------------------------------------------------------------------------- */
/* La colonne étant hors du flux, le conteneur lui réserve sa place. */
.shell { padding-inline-start: 258px; }
.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }
.sidebar::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 99px;
  border: 2px solid var(--panel);     /* le curseur paraît plus fin */
}
.sidebar:hover::-webkit-scrollbar-thumb { background: var(--muted); }

/* Le bouton « Nouveau dossier racine » reste visible au bas de la colonne. */

@media (max-width: 900px) {
  /* Le panneau coulissant mobile prend le relais : plus de place réservée. */
  .shell { padding-inline-start: 0; }
}

/* --------------------------------------------------------------------------
   NOMS DE DOSSIER TRONQUÉS — un nom long est coupé par « … » plutôt que de
   pousser la ligne au-delà de la colonne. Chaque conteneur doit accepter de
   rétrécir (min-width: 0), sinon le nom impose sa largeur et déborde.
   -------------------------------------------------------------------------- */
.sidebar .tree-row { min-width: 0; max-width: 100%; }
.sidebar .tree-link { min-width: 0; overflow: hidden; }
.sidebar .tree-name {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Le compte de pièces et le bouton « + » gardent leur place. */
.sidebar .tree-count, .sidebar .tree-plus, .sidebar .tree-caret { flex: none; }
/* L'arbre lui-même ne déborde jamais de la colonne. */
.sidebar .tree { max-width: 100%; overflow-x: hidden; }

/* --------------------------------------------------------------------------
   CARTE DE DOSSIER — un nom long est coupé par « … » au lieu de déborder de
   la carte. Chaque conteneur doit accepter de rétrécir, sinon le nom impose
   sa largeur. L'infobulle porte le nom entier.
   -------------------------------------------------------------------------- */
.foldercard > span { min-width: 0; flex: 1 1 auto; }
.foldercard b {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}
.foldercard small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.foldercard svg { flex: none; }


/* --------------------------------------------------------------------------
   PIED DE L'ARBORESCENCE — un bloc à part entière derrière le bouton. Il court
   sur toute la largeur de la colonne et descend jusqu'en bas : rien ne peut
   passer derrière ni en dessous. Opaque uniquement quand la liste défile.
   -------------------------------------------------------------------------- */
.tree-pied {
  position: sticky; bottom: 0; z-index: 2;
  margin: 8px -12px 0;
  padding: 8px 12px 14px;
}
.sidebar.defile .tree-pied {
  background: var(--panel);
  box-shadow: 0 -6px 14px -6px rgba(33,48,46,.22);
}
/* Le bouton lui-même reste tel qu'il était : pointillés, arrondi, en retrait. */
.tree-pied .tree-add-root { margin: 0; width: 100%; }

/* ============ Rappel des pièces à supprimer ============ */
/* R516 — le motif de suppression dans la corbeille : dit à voix basse,
   mais dit. */
.motif-suppr { color: var(--seal-dark); font-style: italic; }
.liste-suppr {
  list-style: none; margin: 0 0 14px; padding: 0;   /* R590 : de l'air avant l'étiquette qui suit */
  max-height: 240px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--paper2);
}
.liste-suppr li {
  padding: 7px 11px; font-size: 13px; color: var(--ink);
  border-bottom: 1px solid var(--line);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.liste-suppr li:last-child { border-bottom: 0; }
.act.danger { color: #A33A22; }
.act.danger:hover { background: #FCF1EE; border-color: #C4553A; }

/* Actions de la barre : vert foncé sur fond blanc, lisibles et cliquables. */
.bulkbar .act {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 0 12px; min-height: 32px; border-radius: var(--r);
  background: var(--panel); border: 1px solid var(--seal);
  color: var(--seal-dark); font-size: 13px; cursor: pointer;
  transition: background .14s ease, border-color .14s ease;
}
.bulkbar .act:hover { background: var(--seal); color: #fff; }
.bulkbar .act svg { flex: none; opacity: .85; }

/* Suppression : teinte terre cuite, texte foncé — lisible, jamais criard. */
.bulkbar .act.danger {
  background: #FCF1EE; border-color: #E0B4A6; color: #8A2E1B;
}
.bulkbar .act.danger:hover { background: #C4553A; border-color: #C4553A; color: #fff; }

/* Fermeture de la sélection, à droite. */
.bulkbar .close {
  margin-inline-start: auto; border: 0; background: none; cursor: pointer;
  color: var(--seal-dark); display: inline-flex; padding: 4px;
  border-radius: var(--r);
}
.bulkbar .close:hover { background: var(--panel); }

/* Télécharger : deux choix dans un menu ancré sous le bouton. */
.bulk-groupe { position: relative; display: inline-flex; }
.bulk-pop {
  position: absolute; top: calc(100% + 6px); inset-inline-start: 0; z-index: 50;
  display: flex; flex-direction: column; gap: 4px;
  padding: 6px; min-width: 208px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: 0 10px 30px rgba(33,48,46,.14);
}
.bulk-pop .act { width: 100%; justify-content: flex-start; border-color: transparent; }
.bulk-pop .act:hover { background: var(--seal-soft); color: var(--seal-dark); }

/* Bandeau d'échec : même forme que le succès, teinte d'alerte */
.flash-toast.erreur { background: #8A2E1B; }
.flash-toast.erreur .ft-ico { background: rgba(255,255,255,.22); }

/* Nom du fichier dans la fenêtre de téléchargement */
.tel-nom {
  margin: 0 0 12px; font-size: 14px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Rappel des pièces avant suppression : titre, type, nom de fichier */
.sup-item {
  display: block; padding: 9px 12px;
  background: var(--paper2); border-radius: 8px; margin-bottom: 6px;
}
.sup-haut { display: flex; align-items: center; gap: 8px; min-width: 0; }
.sup-haut b {
  font-weight: 500; font-size: 13px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sup-ext {
  flex: none; padding: 1px 7px; border-radius: 99px;
  background: var(--panel); border: 1px solid var(--line);
  font-size: 11px; letter-spacing: .04em; color: var(--muted);
  font-family: system-ui, sans-serif;
}
.sup-fichier {
  display: block; margin-top: 2px; font-size: 11px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Titre et note empilés : chacun sur toute la largeur */
.formcol { display: flex; flex-direction: column; gap: 12px; }
.formcol > div { min-width: 0; }
/* R1447 — SIX LIGNES ICI AUSSI. C’est la MEME note que sur l’écran de
   découpage : depuis R1434 la fiche d’un document seul y écrit le même état
   civil — nature, numéro, client, fournisseur, total — PUIS le résumé. La
   laisser à trois lignes d’un côté et six de l’autre ferait deux vérités pour
   un même contenu. « .formcol » ne sert qu’à document.php, et n’y porte que
   cette zone-là : la règle ne déborde sur rien. */
.formcol textarea { width: 100%; resize: vertical; min-height: calc(6 * 1.7em + 16px); }

/* --------------------------------------------------------------------------
   BARRE DE DÉFILEMENT DE LA PAGE — même traitement que la colonne latérale :
   un trait fin aux teintes du site plutôt que le gris épais du navigateur.
   S'applique aussi aux zones défilantes internes (fenêtres, aperçus), pour
   qu'un seul langage visuel règne partout.
   -------------------------------------------------------------------------- */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
html::-webkit-scrollbar,
.modal-body::-webkit-scrollbar,
.pg-corps::-webkit-scrollbar,
.lec-corps::-webkit-scrollbar { width: 10px; height: 10px; }

html::-webkit-scrollbar-track,
.modal-body::-webkit-scrollbar-track,
.pg-corps::-webkit-scrollbar-track,
.lec-corps::-webkit-scrollbar-track { background: transparent; }

html::-webkit-scrollbar-thumb,
.modal-body::-webkit-scrollbar-thumb,
.pg-corps::-webkit-scrollbar-thumb,
.lec-corps::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 99px;
  border: 2px solid var(--bg);        /* le curseur paraît plus fin */
}
html:hover::-webkit-scrollbar-thumb,
.modal-body:hover::-webkit-scrollbar-thumb,
.pg-corps:hover::-webkit-scrollbar-thumb,
.lec-corps:hover::-webkit-scrollbar-thumb { background: var(--muted); }

/* Les fenêtres ont un fond distinct : leur curseur s'y fond. */
.modal-body::-webkit-scrollbar-thumb { border-color: var(--panel); }

/* Angle entre les deux barres, sinon un carré gris apparaît. */
html::-webkit-scrollbar-corner { background: transparent; }

.modal-body, .pg-corps, .lec-corps {
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

/* --------------------------------------------------------------------------
   RETOUR AU DOSSIER — action de navigation principale, donc un bouton lisible
   et non un lien effacé. Le nom du dossier est tronqué s'il est long ; il
   reste entier dans l'infobulle.
   -------------------------------------------------------------------------- */
.retour-dossier {
  /* R694 — CE BOUTON-LÀ RESTE FIN. R693 a donné trente-quatre pixels à tous les
     petits boutons, ce qui va bien dans une barre d'outils ; celui-ci n'en est
     pas une : c'est un fil d'Ariane posé au-dessus du titre, qui porte le nom
     du dossier. Haussé, il prenait le poids d'une action alors qu'il ne fait
     que ramener en arrière. Il retrouve sa hauteur d'avant. */
  display: inline-flex; align-items: center; gap: 7px;
  max-width: min(100%, 460px);
  text-decoration: none;
}
/* R694 puis R697 — TOUS LES RETOURS SONT FINS, PARTOUT. R693 a haussé les
   petits boutons parce qu'ils vivent dans des barres d'outils, où chacun
   DÉCLENCHE quelque chose. Un retour ne déclenche rien : il ramène d'où l'on
   vient, posé au-dessus du titre comme un fil d'Ariane. Haussé, il prenait le
   poids d'une action. Les trois de la maison — la fiche d'une pièce, la fiche
   d'un questionnaire, le bâtisseur — partagent la même règle et la même
   hauteur. Deux classes dans le sélecteur, comme la règle commune : une règle
   d'une seule classe perdrait, où qu'elle soit écrite. */
.btn.small.retour-dossier, .btn.small.quest-retour { min-height: 30px; padding: 4px 12px; }
.retour-dossier svg { flex: none; opacity: .8; }
.retour-dossier span { flex: none; color: var(--muted); }
.retour-dossier b {
  font-weight: 600; color: var(--seal-dark); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* R558 — même survol que les boutons (« Télécharger ») : fond, bordure, légère levée */
.retour-dossier { transition: background .12s, border-color .12s, transform .05s; }
.retour-dossier:hover { background: var(--bg); border-color: var(--faint); transform: translateY(-1px); color: inherit; }
.retour-dossier:active { transform: translateY(1px); }
/* R560 : le texte garde sa couleur de base au survol (gris pour « Retour au dossier », vert du nom du dossier inchangé) */
.retour-dossier:hover span { color: var(--muted); }
.retour-dossier:hover b { color: var(--seal-dark); }

/* Rouet du message d'attente : la page se recharge, on le montre. */
.flash-toast .ft-rouet {
  display: inline-block; width: 15px; height: 15px; flex: none;
  border: 2px solid rgba(255,255,255,.35);
  border-top-color: #fff; border-radius: 99px;
  animation: ftTourne .7s linear infinite;
}
@keyframes ftTourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .flash-toast .ft-rouet { animation-duration: 2s; }
}

/* La pièce qui vient d'arriver se signale, puis s'apaise. */
.docitem.vient-darriver {
  border-color: var(--seal);
  animation: nouvelleP 2.4s ease both;
}
@keyframes nouvelleP {
  0%, 45% { background: var(--seal-soft); }
  100%    { background: var(--panel); }
}
@media (prefers-reduced-motion: reduce) {
  .docitem.vient-darriver { animation: none; background: var(--seal-soft); }
}

/* Barre de progression de l'archive : la préparation peut durer, on montre
   où l'on en est plutôt que de laisser croire à un blocage. */
.prg {
  height: 8px; border-radius: 99px; overflow: hidden;
  background: var(--paper2); border: 1px solid var(--line);
}
.prg-barre {
  display: block; height: 100%; width: 8%;
  background: linear-gradient(90deg, var(--seal), var(--seal2));
  transition: width .3s ease;
}
@media (prefers-reduced-motion: reduce) { .prg-barre { transition: none; } }

/* Bouton de lecture verrouillé : on voit qu'il travaille, on ne reclique pas. */
[aria-busy="true"] { cursor: progress; opacity: .75; }

/* --------------------------------------------------------------------------
   MENU DE DOSSIER — les libellés indentés de l'arborescence sont longs et
   étiraient le menu sur toute la largeur restante, rejetant les autres
   filtres à la ligne. On le borne : le nom complet reste lisible à
   l'ouverture, et l'infobulle le donne en entier.
   -------------------------------------------------------------------------- */
.barre-filtres select[name="folder"],
.barre-filtres select[name="dest"] {
  max-width: 190px;
  text-overflow: ellipsis;
}
/* Le panneau de période passe AU-DESSUS des résultats : ouvert, il doit
   couvrir la liste, pas se glisser dessous. */
.card .periode-panneau,
.barre-filtres .periode-panneau { z-index: 39; }

/* Terme cherché mis en évidence, où qu'il se trouve. */
mark, .surligne {
  background: #FFF3B0; color: inherit;
  border-radius: 3px; padding: 0 2px;
  font-weight: 600;
}

/* Titre de dossier : l'icône rappelle la nature de ce qu'on regarde. */
.entry-title.titre-dossier {
  display: flex; align-items: center; gap: 10px;
}
.entry-title.titre-dossier svg { flex: none; color: var(--gold); }
.entry-title.titre-dossier span { min-width: 0; overflow-wrap: anywhere; }

/* Sous-menu ouvert : la flèche se retourne, on voit qu'il est déployé. */
#bulkDlMenu svg:last-child { transition: transform .18s ease; }
#bulkDlMenu[aria-expanded="true"] svg:last-child { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { #bulkDlMenu svg:last-child { transition: none; } }

/* --------------------------------------------------------------------------
   PANNEAU DE PÉRIODE OUVERT — la barre se FIGE le temps du choix. Sans cela,
   un panneau qui déborde du haut fait défiler la page pour se montrer, et
   tout le bloc semble sauter sous le curseur.
   Le panneau reçoit une hauteur maximale et son propre défilement : il ne
   dépasse plus jamais l'écran, donc plus rien ne bouge.
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   PANNEAU DE PÉRIODE OUVERT — on élève seulement le PLAN, jamais la position.
   Imposer « relative » à une barre collée la décrochait : elle retombait à sa
   place naturelle, et toute la rangée de filtres semblait glisser vers le bas.
   -------------------------------------------------------------------------- */
/* Sans filtre la barre est statique : le plan n'agirait pas. On la positionne
   sans la déplacer — « relative » sans décalage ne bouge rien. */


/* Le panneau de période défile en lui-même plutôt que de sauter au-dessus :
   il reste toujours sous son bouton, rien d'autre ne se déplace. */

/* Interrupteur de lecture : l'intitulé explique le compromis, pas seulement l'état. */
.lec-bascule {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 12px; margin-top: 10px;
  background: var(--paper2); border: 1px solid var(--line); border-radius: 12px;
  cursor: pointer;
}
.lec-bascule input { margin-top: 2px; flex: none; }
.lec-bascule b { display: block; font-weight: 500; font-size: 13px; color: var(--ink); }
.lec-bascule small { display: block; margin-top: 2px; font-size: 11px; color: var(--muted); }

/* Progression de l'envoi. */
.lec-envoi { margin-top: 10px; }
.lec-envoi small { display: block; margin-top: 5px; font-size: 11px; color: var(--muted); }


/* --------------------------------------------------------------------------
   PANNEAU DE PÉRIODE OUVERT — la barre ne DOIT PAS bouger.
   Une seule règle, sans sélecteur conditionnel : « relative » sans décalage
   ne déplace rien, et le plan élevé fait passer le panneau au-dessus des
   résultats. Les variantes groupées précédentes étaient fragiles et l'une
   d'elles ne s'appliquait pas.
   -------------------------------------------------------------------------- */
/* La barre NE CHANGE PAS de nature à l'ouverture du panneau. Lui imposer
   « relative » alors qu'elle était statique — cas où aucun filtre n'est
   actif — la décrochait et faisait glisser toute la rangée. Le plan
   d'affichage est porté par le PANNEAU, qui est déjà positionné. */
/* Barre déjà collée : on garde « sticky », l'imposer en « relative » la
   décrocherait et toute la rangée semblerait glisser vers le bas. */
.barre-filtres.collante.panneau-ouvert {
  position: sticky;
  top: var(--h-topbar, 55px);
  z-index: 39;
}
/* L'encart parent enferme sinon le panneau dans son propre plan. */
.card:has(.periode-panneau:not([hidden])),
.main > *:has(.periode-panneau:not([hidden])),
/* La barre garde sa nature : lui imposer une position quand aucun filtre
   n'est actif la faisait passer de statique à positionnée, et toute la
   rangée glissait. Le panneau n'a plus besoin de ce relais — le plan des
   blocs est déjà libéré une fois l'animation d'apparition terminée. */
/* La barre déjà collée garde son ancrage : « relative » la décrocherait. */
.barre-filtres.collante:has(.periode-panneau:not([hidden])) {
  position: sticky;
  top: var(--h-topbar, 55px);
  z-index: 60;
}
/* R519 — LA MÊME ÉLÉVATION SANS « :has() ». Firefox avant la version 121
   (dont la 115 ESR, dernière sous Windows 7) ignore le sélecteur, et jette
   avec lui TOUTE la règle qui le contient : d'où une règle À PART, sur des
   classes que le script pose sur les mêmes ancêtres (kzPanneauPeriode). */
.card.periode-ouverte,
.main > .periode-ouverte,
.barre-filtres.collante.periode-ouverte {
  position: sticky;
  top: var(--h-topbar, 55px);
  z-index: 60;
}

/* Menus de la barre de filtres : largeur au contenu, avec la place du chevron.
   (Règle restaurée — un nettoyage trop large l'avait emportée.) */
.barre-filtres select {
  min-width: 0;
  width: auto;
  padding-inline-end: 26px;
}

/* Date de dépôt sur la carte : repère discret, poussé à droite pour ne pas
   concurrencer le type et la langue qui, eux, servent à filtrer. */
.doc-date {
  margin-inline-start: auto;
  min-width: 52px;
  text-align: right;
  flex: none;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* En vue liste, la rangée est déjà dense : la date reste alignée à droite. */
.docs.view-list .doc-date { margin-inline-start: auto; }

/* Extrait de note dans les résultats : on montre le passage trouvé plutôt
   que de signaler seulement où il se trouve. */
.zone-note {
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
  overflow-wrap: anywhere;
}


/* PIED DE FICHE — trois zones, jamais en concurrence :
   étiquettes à gauche, date au centre-droit à largeur fixe, actions à droite.
   Auparavant la date et les actions réclamaient toutes deux l'espace restant :
   la date se calait derrière les étiquettes, donc à une position différente
   sur chaque fiche selon leur nombre et leur longueur. */
.doc-pied {
  display: flex;
  align-items: center;
  gap: 6px;
}
.doc-pied .doc-actions {
  margin-inline-start: 8px;
  flex: none;
}


/* Cartes très étroites : plutôt que d'afficher « Téléchar… », on garde
   l'icône seule — reconnaissable, et l'infobulle donne le mot entier. */
@media (max-width: 640px) {
  .view-cards.size-s .doc-actions .albl { display: none; }
}

/* Séparateur du chemin : discret, il sépare sans peser. */
.doc-chemin .ar-sep {
  font-style: normal;
  margin: 0 4px;
  color: var(--muted);
  opacity: .7;
}

/* Alerte du mot de passe d'installation : impossible à manquer, impossible
   à fermer. Elle disparaît d'elle-même dès que le mot de passe change. */
.alerte-mdp {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 16px;
  padding: 12px 16px;
  border-radius: 12px;
  background: var(--err-bg);
  border: 1px solid var(--err);
  color: var(--err);
}
.alerte-mdp b { display: block; }
.alerte-mdp span { font-size: 13px; }
.alerte-mdp .btn { margin-inline-start: auto; flex: none; }

/* ===================================================================== */
/* ÉCHELLE D'ESPACEMENT                                                  */
/*                                                                       */
/* Seize valeurs différentes circulaient dans les pages — 2px, 3px, 4px, */
/* .2rem, .4rem… L'œil perçoit ces écarts sans pouvoir les nommer : la   */
/* page paraît « bricolée » sans qu'on sache dire pourquoi.              */
/*                                                                       */
/* Une échelle géométrique donne des rapports que l'œil reconnaît. Six   */
/* valeurs suffisent à tout composer.                                    */
/* ===================================================================== */
:root {
  --e1: 4px;    /* collé — icône et son libellé                */
  --e2: 8px;    /* proche — éléments d'un même groupe          */
  --e3: 12px;   /* lié — champs d'un formulaire                */
  --e4: 20px;   /* séparé — blocs d'une même carte             */
  --e5: 32px;   /* distinct — sections d'une page              */
  --e6: 48px;   /* aéré — respiration autour d'un contenu seul */
}

/* --------------------------------------------------------------------- */
/* FORMULAIRES — un rythme unique, quelle que soit la page.              */
/* --------------------------------------------------------------------- */
.form-bloc { display: flex; flex-direction: column; gap: var(--e3); }
.form-bloc + .form-bloc { margin-top: var(--e5); }

.form-titre {
  font-size: 15px; font-weight: 600; margin: 0 0 var(--e1);
}
.form-aide {
  font-size: 13px; color: var(--muted); margin: 0 0 var(--e3); line-height: 1.5;
}

/* Une consigne sous un champ se lit AVANT la saisie, pas après l'erreur.
   Elle reste discrète mais lisible : 12px est le plancher du confort. */
.champ-aide {
  display: block; font-size: 12px; color: var(--muted);
  margin-top: var(--e1); line-height: 1.45;
}

/* --------------------------------------------------------------------- */
/* VALIDATION — l'état se voit avant de lire le texte.                   */
/* --------------------------------------------------------------------- */
.msg { display: flex; gap: var(--e2); align-items: flex-start;
       padding: var(--e3) var(--e4); border-radius: 12px;
       margin: 0 0 var(--e4); font-size: 14px; line-height: 1.5; }
.msg b { display: block; margin-bottom: 2px; }
.msg-err  { background: var(--err-bg);  border: 1px solid var(--err);  color: var(--err); }
.msg-ok   { background: var(--info-bg); border: 1px solid var(--seal-dark);   color: var(--seal-dark); }
.msg-warn { background: var(--warn-bg); border: 1px solid var(--warn); color: var(--warn); }
/* R774 — LA NOTE QUI RENSEIGNE, SANS ALERTER. La maison n'avait que trois
   habits : l'erreur, la réussite, l'avertissement — tous colorés fort, tous
   faits pour ARRÊTER l'œil. Un simple conseil, lui, n'avait rien : il tombait
   sous un bouton en petit texte gris, sans cadre, comme une pensée oubliée
   là. « msg-info » lui donne sa place : un fond très pâle, un liseré discret,
   pas de bordure criante. Elle se lit après le geste, elle ne l'interrompt
   pas. */
/* R807 — LA NOTE N'A PLUS DE FOND. Elle portait un vert très pâle qui, sur le
   fond crème de la maison, se lisait comme une teinte de plus : deux nuances
   voisines sans intention. Le fond disparaît ; le liseré vert et l'encadré
   suffisent à la détacher — c'est le liseré qui dit « ceci renseigne », pas la
   couleur derrière. */
.msg-info {
  background: transparent;
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--seal);
  color: var(--muted);
}
.msg-info .ic { color: var(--seal); opacity: .85; }
/* R774 — LES CLASSES D'ÉCART DOIVENT POUVOIR AGIR SUR UNE NOTE. « .msg » pose
   « margin: 0 0 20px », un raccourci qui remet la marge du HAUT à zéro et
   écrase donc « .mt4 », déclarée plus haut dans le fichier : la note se
   collait au bouton malgré la classe. On rend la combinaison plus précise —
   deux classes valent mieux qu'une — plutôt que de poser un écart en dur, qui
   se serait désaccordé du reste au premier changement d'échelle. */
.msg.mt3 { margin-top: var(--e3); }
.msg.mt4 { margin-top: var(--e4); }
.msg-info b { color: var(--ink); }

/* La règle non respectée s'allume ; les autres restent lisibles mais
   discrètes. Un texte tout rouge ne dit pas CE qui manque. */
.regles { list-style: none; padding: 0; margin: var(--e2) 0 0;
  display: none; }               /* R196 : cachée tant que tout va bien */
.regles.err { display: block; }  /* n'apparaît QUE comme message d'erreur */
.regles li { font-size: 12px; color: var(--err, #a33a22); padding: 2px 0 2px 18px;
             position: relative; line-height: 1.5; }
.regles li::before { content: '✗'; position: absolute; inset-inline-start: 2px; }

/* --------------------------------------------------------------------- */
/* CARTES DE RÉGLAGE — même gabarit partout.                             */
/* --------------------------------------------------------------------- */
.carte-reglage { padding: var(--e4); }
.carte-reglage h2 { display: flex; align-items: center; gap: var(--e2);
                    font-size: 16px; margin: 0 0 var(--e2); }
.carte-reglage > p:first-of-type { margin-top: 0; }
.carte-reglage .btn { margin-top: var(--e3); }

/* Une page centrée sur une seule action mérite de l'air autour d'elle :
   sans marge, le formulaire semble collé au bord et paraît inachevé. */
.page-solo { max-width: 520px; margin: var(--e6) auto; padding: 0 var(--e4); }

/* Un dossier vide n'est pas une erreur : le message reste calme, centré,
   et laisse respirer. C'est souvent le premier écran qu'une personne voit. */
.accueil-vide {
  text-align: center; padding: var(--e6) var(--e4); color: var(--muted);
}
.accueil-vide-titre {
  font-weight: 500; color: var(--ink); margin: var(--e3) 0 var(--e1);
}
.accueil-vide .sub { margin: 0; }

/* ===================================================================== */
/* PAGES D'ACCES — connexion, premier acces, reinitialisation.           */
/*                                                                       */
/* Elles partageaient trois largeurs (400, 320, 520px) et deux methodes  */
/* de centrage. Le message sous la carte de connexion, plus etroit       */
/* qu'elle, creait un decrochage que l'oeil percoit immediatement.       */
/*                                                                       */
/* Une seule largeur, un seul centrage : la colonne est droite.          */
/* ===================================================================== */
.acces-wrap {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e4);
  padding: var(--e5) var(--e4);
}

/* Tout ce qui vit dans cette colonne partage sa largeur : la carte, le
   message d'aide, la mention de bas de page. Aucun decrochage possible. */
.acces-wrap > * { width: 100%; max-width: 400px; }

.acces-carte { padding: var(--e5) var(--e4); }
.acces-carte h1 { font-size: 20px; margin: 0 0 var(--e2); }
.acces-carte > p:first-of-type { margin-top: 0; }

/* Le bouton principal occupe toute la largeur : sur une page qui ne
   propose qu'une action, l'hesitation n'a pas lieu d'etre. */
.acces-carte .btn[type="submit"] { width: 100%; margin-top: var(--e4); }

/* Aide sous la carte : lisible sans concurrencer le formulaire. */
.acces-aide {
  font-size: 13px; line-height: 1.55; color: var(--muted);
  text-align: center; margin: 0;
}
.acces-aide b { display: block; color: var(--ink); margin-bottom: var(--e1); }
.acces-aide a { color: var(--muted); }

.acces-pied {
  font-size: 12px; color: var(--faint); text-align: center; margin: 0;
}

/* ===================================================================== */
/* ECHELLE TYPOGRAPHIQUE                                                 */
/*                                                                       */
/* Huit tailles circulaient en dur : 10, 11, 12, 13, 15px... Ces ecarts  */
/* d'un pixel ne creent aucune hierarchie — ils brouillent celle qui     */
/* existe. Quatre niveaux suffisent, et chacun a un role.                */
/* ===================================================================== */
:root {
  --t-titre:  20px;  /* titre de page — un seul par ecran         */
  --t-sect:   16px;  /* titre de bloc — ce que l'oeil balaie      */
  --t-corps:  14px;  /* texte courant                             */
  --t-detail: 12px;  /* mention, aide, horodatage — plancher lisible */
}

/* En dessous de 12px, le texte devient penible pour beaucoup de gens.
   Ce n'est pas une preference : c'est une limite de confort. */
.t-detail { font-size: var(--t-detail); color: var(--muted); line-height: 1.5; }
.t-corps  { font-size: var(--t-corps); line-height: 1.6; }

/* --------------------------------------------------------------------- */
/* RÉGLAGES DE COURRIEL                                                  */
/* --------------------------------------------------------------------- */
.mail-fournisseurs { display: flex; gap: var(--e2); flex-wrap: wrap; margin-bottom: var(--e3); }
.mail-fournisseurs .btn.on { border-color: var(--seal); color: var(--seal-dark);
                             background: var(--seal-soft); }
.mail-aide { display: flex; gap: var(--e2); align-items: flex-start;
             background: var(--info-bg); border-radius: 12px;
             padding: var(--e3) var(--e4); font-size: 13px; line-height: 1.5; }
.mail-grille  { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: var(--e3); }
.mail-grille2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e3); }
@media (max-width: 720px) {
  .mail-grille, .mail-grille2 { grid-template-columns: 1fr; }
}
/* R1020 — LE FORMULAIRE D'ESSAI PERD SON TRAIT ET SES VINGT PIXELS. Cette
   règle date d'avant le pied commun (R143) : l'essai vivait seul sous les
   champs, et se détachait par un trait et un retrait. Depuis, il vit DANS la
   barre d'actions — et ce padding-top de 20 px poussait son contenu 10,5 px
   sous le centre de la rangée (mesuré au navigateur), pendant que son
   border-top dessinait un demi-trait que R1018 croyait avoir retiré. Le trait
   employait d'ailleurs « --line », un jeton qui n'existe pas (le nôtre est
   « --ligne »). */
.mail-essai { display: flex; gap: var(--e2); align-items: center; flex-wrap: wrap; }
.mail-essai input { max-width: 260px; }
.mail-essai-ok { font-size: 12px; color: var(--seal-dark);
                 display: flex; align-items: center; gap: var(--e1); }

/* Préférences de notification : des cases serrées se lisent comme un groupe,
   ce qu'elles sont — inutile de les espacer comme des champs distincts. */
.fiche-prefs { border-top: 1px solid var(--line); padding-top: var(--e4); }
.fiche-prefs label { display: flex; align-items: center; gap: var(--e2);
                     font-size: 13px; padding: var(--e1) 0; cursor: pointer; }
/* R1063 — MÊME PIÈGE QU'À « .lec-case » : « width: auto » écrase une case
   dessinée à la main (appearance:none) à deux pixels. La géométrie des
   champs de saisie ne doit jamais toucher aux cases ni aux boutons radio. */
.fiche-prefs input:not([type="checkbox"]):not([type="radio"]) { width: auto; margin: 0; }

/* --------------------------------------------------------------------- */
/* ENVOI D'UN DOCUMENT PAR COURRIEL                                      */
/* --------------------------------------------------------------------- */
.envoi-doc { display: flex; gap: var(--e3); align-items: center;
             background: var(--panel); border-radius: 12px;
             padding: var(--e3); margin-bottom: var(--e4); }
.envoi-doc-titre { font-size: 13px; font-weight: 500; }
.envoi-doc-sub   { font-size: 12px; color: var(--muted); margin-top: 2px; }
.envoi-carnet { display: flex; gap: var(--e2); flex-wrap: wrap; align-items: center; }
.envoi-vars   { display: flex; gap: var(--e1); flex-wrap: wrap; margin-top: var(--e2); }
.envoi-vars .btn.mono { font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
                        font-size: 11px; padding: 3px 8px; }
/* L'aperçu conserve les retours à la ligne : c'est ce que verra vraiment
   le destinataire, pas une reformulation. */
.envoi-apercu pre { background: var(--panel); border-radius: 12px;
                    padding: var(--e3); font-size: 12px; color: var(--muted);
                    line-height: 1.6; white-space: pre-wrap; word-break: break-word;
                    margin: var(--e1) 0 0; max-height: 190px; overflow: auto;
                    font-family: inherit; }
.envoi-pied { display: flex; align-items: center; gap: var(--e3);
              justify-content: space-between; flex-wrap: wrap; }
.envoi-garder { display: flex; align-items: center; gap: var(--e2);
                font-size: 12px; color: var(--muted); cursor: pointer; }
.envoi-garder input:not([type="checkbox"]):not([type="radio"]) { width: auto; margin: 0; }
.envoi-garder input[type="checkbox"] { flex: 0 0 auto; margin: 0 6px 0 0; }

/* --------------------------------------------------------------------- */
/* BOUTON D'ACTION PRINCIPALE                                            */
/*                                                                       */
/* Le bouton neutre a le même fond pâle et la même bordure fine qu'un    */
/* champ de saisie : dans un formulaire, l'œil ne le distingue plus.     */
/* Le vert du projet lui donne le poids qui manque — un seul par         */
/* formulaire, celui qui valide.                                         */
/* --------------------------------------------------------------------- */
/* `.btn.principal` : fusionné avec `.btn.primary` — règle unique définie
   dans la section des boutons, en tête de feuille. */

/* Un bouton collé au champ qui le précède paraît en faire partie. Une
   séparation nette dit : ici s'arrête la saisie, ici commence l'action. */
.form-bloc > div:last-child,
.form-actions {
  display: flex; gap: var(--e2); align-items: center;
  margin-top: var(--e2); padding-top: var(--e4);
  border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------------- */
/* PAGE UTILISATEURS                                                     */
/*                                                                       */
/* Les actions d'une ligne doivent se lire d'un coup d'œil. Sans gouttière
   ni retour à la ligne, elles se collent et débordent sur les écrans
   étroits — on ne sait plus quel bouton appartient à quelle personne. */
/* --------------------------------------------------------------------- */
.u-actions { display: flex; gap: var(--e2); flex-wrap: wrap; align-items: center; }

/* Le nom d'utilisateur est la clé de lecture du tableau : il mérite d'être
   reconnaissable sans être criard. */
.u-nom { font-weight: 500; }
.u-mail { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.u-fonction { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }

/* Une ligne inactive doit se distinguer sans disparaître : on la lit encore,
   mais on voit qu'elle ne compte pas. */
tr.u-inactif td { opacity: .55; }

/* --------------------------------------------------------------------- */
/* PAGE DE RÉGLAGES                                                      */
/*                                                                       */
/* Vingt-six réglages dans une seule carte : on ne trouve rien, et l'on   */
/* n'ose rien changer. Quatre blocs nommés — identité, lecture,          */
/* performance, outils — rendent chaque chose trouvable.                 */
/* --------------------------------------------------------------------- */
.carte-reglage + .carte-reglage { margin-top: var(--e4); }

/* Deux réglages liés côte à côte : ils se lisent comme un couple, ce
   qu'ils sont — qualité et résolution, file et parallélisme. */
.reglage-duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e3); }
@media (max-width: 720px) { .reglage-duo { grid-template-columns: 1fr; } }

/* Une case à cocher n'est pas un champ : son libellé se lit à droite. */
/* R1063 — LA CASE À COCHER RÉDUITE À UNE BARRE DE DEUX PIXELS. Deux fautes
   se cumulaient. UNE : « .lec-case » posait flex-direction et align-items
   SANS JAMAIS DÉCLARER display:flex — la règle ne s'appliquait à rien, et le
   label restait un bloc. DEUX, la vraie : « width: auto » sur l'input. Les
   cases de la maison sont dessinées à la main (appearance:none) : elles
   n'ont AUCUNE taille naturelle, et « auto » les écrasait à deux pixels de
   large — la barre verticale que l'on voyait à l'écran. On ne redonne donc
   pas sa taille « naturelle » à une case qui n'en a pas : on la pose. */
.lec-case { display: flex; flex-direction: row; align-items: flex-start;
  gap: var(--e2); cursor: pointer; }
/* R1336 — « margin: 2px 8px 0 0 » EST PHYSIQUE : les huit pixels se posent
   toujours à DROITE de la case. En français ils la séparent de son texte ; en
   arabe le texte est à gauche, et les huit pixels s'en vont du mauvais côté —
   la case et son mot se touchent, et un blanc inutile pend à l'autre bout.
   C'est la leçon de R1334, au même endroit : une propriété logique dit
   « du côté où l'on écrit », une propriété physique dit « à droite ».
   Et le BOUTON ROND est ajouté à la règle : il vit dans les mêmes lignes que
   la case (le réglage du dossier scanner en pose deux) et n'avait aucune
   taille — il paraissait plus petit, mal aligné, à côté de ses voisines. */
.lec-case > input[type="checkbox"],
.lec-case > input[type="radio"] { width: 17px; height: 17px; flex: 0 0 auto;
  margin: 2px 0 0; margin-inline-end: 8px; }
.lec-case > span { flex: 1; min-width: 0; line-height: 1.55; color: var(--ink); }
/* L'explication passe à la ligne : en la laissant dans le fil, un mot ou deux
   restaient orphelins au bout du titre. */
.lec-case > span .sub { display: block; margin-top: 3px; color: var(--muted); }
.lec-case:hover > span { color: var(--ink); }
.lec-case .champ-aide { margin-top: 2px; }
/* R1342 — DEUX CASES QUI SE SUIVENT NE SE TOUCHENT PAS. C'était la leçon de
   R1096, écrite alors pour les seules fenêtres du scanner, qui avaient leurs
   propres classes ; en les faisant passer aux classes de la maison, la leçon
   se serait perdue avec elles. Elle vaut pour toutes : une liste de choix se
   lit comme une liste, non comme un paragraphe compressé.
   R1344 : dans une fenêtre, c'est la marge du bas qui gouverne (voir
   « .modal-body .lec-case ») ; celle-ci sert partout ailleurs — les Réglages. */
.lec-case + .lec-case { margin-top: 10px; }

/* Le bouton d'enregistrement vaut pour les quatre blocs : il se pose
   après eux, détaché, plutôt que répété dans chacun. */
.reglages-pied { justify-content: flex-end; margin-top: var(--e4);
                 padding-top: var(--e4); border-top: 1px solid var(--line); }

/* Les testeurs répondent tout de suite : sans eux, il faut déposer un
   document pour savoir si le chemin d'un outil est bon. */
.reglages-tests { justify-content: flex-start; }

/* --------------------------------------------------------------------- */
/* PAGE DE CONNEXION — adaptation aux petits écrans                      */
/*                                                                       */
/* La carte n'avait aucune marge : sur un téléphone de 360 px elle       */
/* touchait les deux bords, et le clavier virtuel recouvrait le bouton.  */
/* --------------------------------------------------------------------- */
.loginwrap { padding: var(--e5) var(--e4); box-sizing: border-box; }

/* 100vh compte la barre d'adresse du navigateur mobile, qui se rétracte
   au défilement : la page « saute ». min-height suffit à centrer. */
@media (max-width: 600px) {
  .loginwrap { min-height: auto; padding: var(--e5) var(--e3) var(--e6); }
  .login-brand .brand-mark { width: 46px; height: 46px; font-size: 25px; }
  .login-brand h1 { font-size: 21px; }
  .login-def { font-size: 12px; }
  .logincard .card { padding: var(--e4) var(--e3); }
  /* Un champ sous 16 px déclenche le zoom automatique d'iOS : la page
     part de travers dès qu'on touche le premier champ. */
  .logincard input { font-size: 16px; }
  .logincard .btn { width: 100%; justify-content: center; }
}

/* Le message d'orientation ne doit pas coller au bouton : c'est une
   information, pas une seconde action. */
.acces-aide { margin-top: var(--e5); font-size: 12px; line-height: 1.6;
              text-align: center; color: var(--muted); }
.acces-aide a { color: var(--muted); text-decoration: underline; }

/* ---------------------------------------------------------------------------
   RÉGLAGES — SOMMAIRE LATÉRAL COLLANT. La page aligne six cartes ; ce
   sommaire suit le défilement et mène à chacune. Il emprunte l'ADN de
   .card (panneau, filet, rayon, ombre) pour appartenir à la famille.
   Sur écran étroit, il se couche en rangée de puces défilantes sous la
   barre haute plutôt que de voler de la largeur au contenu. */
.regl-agencement { display: flex; gap: var(--e4); align-items: flex-start; }
.regl-colonne { flex: 1 1 auto; min-width: 0; }
.regl-sommaire {
  position: sticky; top: 66px; flex: 0 0 188px;
  display: flex; flex-direction: column; gap: 2px; padding: 8px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 1px 3px rgba(33,48,46,.06);
}
.regl-sommaire a {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px;
  border-radius: 8px; color: var(--muted); font-size: 13px;
  text-decoration: none;
}
.regl-sommaire a:hover { color: var(--ink); background: var(--paper); }
.regl-sommaire a.on {
  color: var(--seal); background: var(--paper);
  box-shadow: inset 2px 0 0 var(--seal);
}
.regl-sommaire svg { flex: none; }

/* L'ancre s'arrête sous la barre haute collante, jamais derrière elle. */
[id^="regl-"] { scroll-margin-top: 76px; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

@media (max-width: 960px) {
  .regl-agencement { display: block; }
  .regl-sommaire {
    position: sticky; top: 54px; z-index: 30;
    flex-direction: row; overflow-x: auto; margin-bottom: var(--e3);
  }
  .regl-sommaire a { white-space: nowrap; }
}

/* --- Fenêtre de permissions : noms de dossiers longs ----------------------
   Le nom se termine par une ellipse au lieu de replier la ligne et de
   disperser les cases ; le nom complet vit dans l'infobulle (title) que
   le survol révèle. dir=auto garde les noms arabes bien alignés. */
.doss-ligne { display: flex; align-items: center; gap: 8px; min-width: 0; }
.doss-ligne .doss-nom {
  flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}

/* --- LOGIN : plus de défilement horizontal, page responsive -------------
   Les deux halos décoratifs (420 px, right:-110px / left:-120px) étaient
   absolus dans un parent NON positionné et sans découpe : celui de droite
   dépassait la fenêtre et créait la barre de défilement horizontale. Le
   parent devient le repère et découpe — les halos fondent dans les bords,
   comme voulu, sans pousser la page. 100dvh suit la barre d'adresse des
   téléphones ; sous 480 px, marges, titre et halos se font plus légers. */
.loginwrap {
  position: relative; overflow: hidden;
  /* R514 — LA BARRE DE PIED NE FAIT PLUS DÉFILER L'ÉCRAN D'ENTRÉE. Depuis
     qu'elle y figure (R512), le corps de page porte sa marge basse de vingt-huit
     pixels — et cet écran réclamait de son côté toute la hauteur de la fenêtre.
     Les deux s'additionnaient : la page dépassait la fenêtre d'exactement la
     hauteur de la barre, et défilait pour rien. On retire la barre de la
     hauteur demandée ; la carte reste centrée dans ce qui se voit. */
  min-height: calc(100vh - 28px); min-height: calc(100dvh - 28px);
}
@media (max-width: 700px) {
  .loginwrap { min-height: calc(100vh - 26px); min-height: calc(100dvh - 26px); }
}
@media (max-width: 480px) {
  .loginwrap { padding: var(--e4) var(--e3); }
  .login-brand h1 { font-size: 22px; }
  .loginwrap::before, .loginwrap::after {
    width: 280px; height: 280px; filter: blur(50px);
  }
}

/* --- LOGIN : économie verticale ------------------------------------------
   Le bouton occupe toute la largeur — plus de question d'alignement, cible
   plus franche. Le filet des form-actions n'a rien à séparer sur cette
   carte. L'aide « Mot de passe oublié ? » se replie sur une ligne : le
   texte complet s'ouvre au clic. Sur écran court, la page respire moins
   mais tient sans défiler. */
.logincard .form-bloc > div:last-child { border-top: 0; padding-top: 0; margin-top: 0; }
.acces-aide summary { cursor: pointer; font-weight: 600; color: var(--ink); list-style: none; }
.acces-aide summary::-webkit-details-marker { display: none; }
.acces-aide summary::after { content: " ▾"; color: var(--muted); }
.acces-aide[open] summary::after { content: " ▴"; }
@media (max-height: 760px) {
  .loginwrap { gap: var(--e3); padding: var(--e3); }
  .login-brand { margin-bottom: 8px; }
  .login-brand .brand-mark { width: 46px; height: 46px; font-size: 26px; }
  .login-def { font-size: 12px; }
  .login-def br { display: none; }
  .form-bloc { gap: var(--e2); }
  .mention-legere { display: none; }
}

/* Après un filtre, la page atterrit au sommet des résultats — sous la
   barre haute ET la barre de filtres collante, jamais derrière elles. */
#resultats { scroll-margin-top: 128px; }

/* --- RECHERCHE : une seule grille, comme un dossier -----------------------
   Chaque résultat trouvé par son texte est une colonne fiche + extraits ;
   en vue cartes, seul le premier extrait reste, sur une ligne, pour que
   les cartes gardent leur rang — la liste, vue par défaut, montre tout. */
.docs > .doc-res { display: flex; flex-direction: column; gap: var(--e2); min-width: 0; }
.doc-res .extraits-doc { min-width: 0; }
.view-cards .doc-res {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 1px 3px rgba(33,48,46,.06);
  overflow: hidden; gap: 0;
}
.view-cards .doc-res .docitem { border: 0; border-radius: 0; box-shadow: none; }
.view-cards .doc-res .extraits-doc { display: none; }
.res-apercu { display: none; }
.view-cards .res-apercu {
  display: flex; gap: 7px; align-items: flex-start;
  border-top: 1px dashed var(--line); background: var(--paper);
  padding: 8px 10px; font-size: 12.5px; color: var(--muted); min-width: 0;
}
.res-apercu .chip { flex: none; }
.res-apercu .res-extrait {
  min-width: 0; overflow: hidden; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
/* --- Densité de la LISTE : S serrée, M d'origine, L confortable ----------
   Les tailles ne réglaient que les cartes ; elles règlent désormais aussi
   la liste — même bouton, même mémoire (kz_size), mêmes deux pages. M
   reste exactement la liste d'origine, rien ne bouge pour qui ne touche
   à rien. */
.view-list.size-s .docitem { padding: 6px 12px 6px 40px; gap: 10px; }
.view-list.size-s .dprev   { width: 34px; height: 44px; }
.view-list.size-s .dbody   { gap: 1px; font-size: 12.5px; }
.view-list.size-l .docitem { padding: 18px 20px 18px 44px; gap: 16px; }
.view-list.size-l .dprev   { width: 58px; height: 74px; }
.view-list.size-l .dbody   { gap: 5px; font-size: 15px; }

/* En LISTE, chaque résultat trouvé par son texte est UNE entrée : la
   fiche et ses extraits partagent le même cadre — une seule rangée
   épaisse, au rythme exact de la bibliothèque, au lieu d'une fiche
   bordée suivie d'extraits flottants. */
.view-list .doc-res {
  gap: 0; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 1px 3px rgba(33,48,46,.06);
  overflow: hidden;
}
.view-list .doc-res .docitem { border: 0; border-radius: 0; box-shadow: none; }
.view-list .doc-res .extraits-doc {
  border-top: 1px dashed var(--line);
  padding: 8px 16px 10px 40px; background: var(--paper);
}

/* Le message « dossier vide » vit DANS la grille des pièces : il doit
   occuper toute la rangée et se poser au centre de l'espace libre — pas
   se ranger dans la première case comme une carte de plus. */
.docs .accueil-vide {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center;
  min-height: 300px; gap: 6px; color: var(--muted);
}
.docs .accueil-vide .sub { max-width: 420px; }

/* L'état « dossier vide » n'a plus besoin d'un hall de gare : le message
   respire sans pousser la page vers le bas. */
.accueil-vide { padding: 22px 12px 26px; }
.accueil-vide .accueil-vide-titre { margin: 10px 0 4px; }
.accueil-vide .sub { margin: 0; }

/* La pièce qui vient d'arriver se signale d'un bref éclat — assez pour
   guider l'œil, pas assez pour fatiguer. */
@keyframes kz-eclat {
  0%   { box-shadow: 0 0 0 3px rgba(24,161,132,.45); background: rgba(24,161,132,.10); }
  100% { box-shadow: 0 0 0 3px rgba(24,161,132,0);   background: transparent; }
}
.docitem.vient-darriver { animation: kz-eclat 2.4s ease-out 1; }
@media (prefers-reduced-motion: reduce) {
  .docitem.vient-darriver { animation: none; box-shadow: 0 0 0 3px rgba(24,161,132,.35); }
}

/* L'aperçu montre la PAGE ENTIÈRE, jamais rognée : cadre au format A4
   (210 × 297, portrait), image CONTENUE et centrée sur fond de feuille
   blanche — un paysage se letterboxe, un portrait s'ajuste, rien ne se
   coupe. Vaut pour « Lire un document » ET « Relecture » (même cadre). */
.lec-cadre {
  aspect-ratio: 210 / 297;
  height: auto;
  width: clamp(120px, 24vh, 170px);   /* plus discret : la fenêtre respire, le défilement se fait rare */
  margin-inline: auto;
  background: #fff;
  overflow: hidden;
}
.lec-cadre img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}



/* VIGNETTES DES FICHES (vue carte ET vue liste, toutes tailles) : le
   BLOC garde son format D'ORIGINE — hauteurs et proportions telles
   qu'elles étaient. Seul le contenu change : le document s'y montre EN
   ENTIER, contenu et centré sur fond de papier blanc — jamais rogné, un
   paysage comme un portrait se letterboxent dans le cadre normal. (À la
   demande : l'A4 essayé en R58 est retiré des fiches ; il demeure dans
   les fenêtres de lecture et l'affiche, R56–R57.) */
.dprev img { object-fit: contain; object-position: center; background: #fff; }

/* « Retour au dossier » : l'icône vit DANS le nom — même vert, même corps.
   Le SVG hérite de currentColor : une seule couleur à gouverner. */
.retour-doss { color: var(--seal); display: inline-flex; align-items: center; gap: 5px; }
.retour-doss svg { flex: none; }

/* R65 — la carte « Pièce jointe — l'original » restaurée : ses règles
   d'origine reviennent avec elle, telles quelles. */


/* R65 — les habits de la carte restaurée (texte exact d'avant R61). */
.apercu-pdf      { width: 100%; height: 560px; border: 1px solid var(--line); border-radius: 10px; background: #fff; }
.apercu-img      { max-width: 100%; border: 1px solid var(--line); border-radius: 10px; }
.apercu-audio    { width: 100%; }
.apercu-video    { width: 100%; border-radius: 10px; }

/* Nœud d'arbre « chemin seulement » : le nom se voit, la porte est fermée. */
.tree-link.tree-off { pointer-events: none; opacity: .55; cursor: default; }

/* « Alléger le journal » : des RANGÉES, pas des colonnes — le choix, puis
   le geste, sur une même ligne ; les champs à leur taille, jamais pleine
   page. */
.purge-ligne { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.purge-ligne .lec-label { margin: 0; }
.purge-ligne select, .purge-ligne input[type="date"] { width: auto; min-width: 130px; }

/* En-têtes du journal : des leviers de tri — sobres au repos, verts en main. */
.th-tri { color: inherit; text-decoration: none; }
.th-tri:hover, .th-tri.actif { color: var(--seal); }

/* PAGINATION CLASSIQUE — le visuel validé, mot pour mot. */
.pgn { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.pgn .pg-b { display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-width: 34px; height: 32px; padding: 0 10px; border: 1px solid var(--line2);
  background: var(--panel); color: var(--ink); border-radius: 8px; font-size: 13.5px;
  text-decoration: none; user-select: none; }
.pgn a.pg-b:hover { border-color: var(--seal); color: var(--seal); }
.pgn .pg-actif { background: var(--seal); border-color: var(--seal); color: #fff; font-weight: 600; }
.pgn .pg-off { opacity: .38; }
.pgn .pg-pts { color: var(--muted); padding: 0 2px; user-select: none; }
.pgn .pg-compte { margin-inline-start: 10px; color: var(--muted); font-size: 12.5px; }

/* Le texte de la fenêtre de confirmation respecte ses retours à la ligne :
   « période » sur une ligne, « compte » sur l'autre, l'avertissement seul. */
#confirmText { white-space: pre-line; }

/* APERÇU CONTEXTUEL DE LA CORBEILLE — le fichier à gauche dans le cadre
   de lecture, les informations à droite ; le retour annoncé dessous. */
.cap-deux { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.cap-cadre { flex: 0 0 240px; min-height: 170px; display: flex; align-items: center; justify-content: center; }
.cap-cadre img, .cap-cadre object { max-width: 100%; max-height: 320px; }
.cap-cadre object { width: 240px; height: 320px; }
.cap-vide { color: var(--muted); font-size: 13px; padding: 18px; text-align: center; }
.cap-infos { flex: 1 1 220px; margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 13.5px; }
.cap-infos dt { color: var(--muted); }
.cap-infos dd { margin: 0; overflow-wrap: anywhere; }

/* R118 — Le champ « Mot » de la corbeille respire : un mot de recherche
   se tape mieux dans un champ qui montre ce qu'on écrit. */
#cQd { min-width: 280px; }

/* R120 — La carte « Tous les dossiers actifs » montre TOUT : au-delà
   d'une dizaine, elle défile en elle-même plutôt que d'étirer la page. */
.liste-dossiers { max-height: 340px; overflow-y: auto; padding-inline-end: 4px; }

/* R130 — Le consentement de l'audit SE VOIT : case native visible, bouton
   verrouillé visiblement éteint, et la ligne se secoue si l'on clique trop tôt. */
.mir-consent { display: flex; align-items: flex-start; gap: 10px; margin-top: 14px;
  cursor: pointer; padding: 8px 10px; border: 1px dashed var(--ligne, #cfc8ba); border-radius: 8px; }
.mir-consent input[type="checkbox"] { width: 18px; height: 18px; flex: none; margin-top: 1px;
  accent-color: #0f6b53; cursor: pointer; appearance: auto; -webkit-appearance: checkbox; }
.mir-consent span { user-select: none; }
#mirGo:disabled { opacity: .45; cursor: not-allowed; filter: saturate(.4); }
.mir-consent.attention { animation: mirSecousse .45s ease; border-color: #b4231f; }
@keyframes mirSecousse { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-5px)}
  55%{transform:translateX(5px)} 80%{transform:translateX(-3px)} }

/* R133 — La réparation du miroir AVANCE sous les yeux : barre pleine
   largeur, remplissage aux couleurs de la maison, texte d'étape dessous. */
.mir-prog-barre { height: 14px; border: 1px solid var(--ligne, #cfc8ba); border-radius: 8px;
  overflow: hidden; background: #f3efe6; margin-top: 10px; }
.mir-prog-fait { height: 100%; width: 0%; background: linear-gradient(90deg, #0f6b53, #17987a);
  transition: width .25s ease; }

/* R141 — Réglages par blocs : chaque carte enregistre pour elle-même, le
   message se pose AU-DESSUS d'elle, et l'ancre revient à la bonne hauteur. */
.regl-pied-carte { display: flex; justify-content: flex-end; margin-top: var(--e3); }
.regl-flash-bloc { margin-bottom: var(--e2); }
.carte-reglage, #regl-integrite, #regl-courriel { scroll-margin-top: 84px; }

/* R142 — Le bloc Courriel remis d'aplomb : grilles aérées, fournisseurs en
   rangée propre, note d'aide encadrée, essai dans son cadre, pied à droite. */
.mail-grille { display: grid; grid-template-columns: 2fr 110px 170px; gap: var(--e3); align-items: end; }
.mail-grille2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e3); }
.mail-fournisseurs { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 8px; }
.mail-fournisseurs .btn.on { background: #0f6b53; color: #fff; border-color: #0f6b53; }
.mail-aide { display: flex; gap: 8px; align-items: flex-start; padding: 8px 10px;
  border: 1px dashed var(--ligne, #cfc8ba); border-radius: 8px; font-size: .92em; color: #5c574c; }
/* R1020 : « .mail-essai-cadre » est retirée — plus aucune page ne la porte,
   et un style que personne n'emploie fait douter au prochain passage (R1018). */
.mail-essai { display: flex; gap: 10px; align-items: center; margin-top: 8px; }
.mail-essai input[type="email"] { flex: 1; min-width: 0; }
.lec-label-ligne { display: flex; align-items: center; gap: 10px; }
.lec-label-ligne input[type="checkbox"] { width: 18px; height: 18px; appearance: auto;
  -webkit-appearance: checkbox; accent-color: #0f6b53; flex: none; }
@media (max-width: 720px) { .mail-grille, .mail-grille2 { grid-template-columns: 1fr; } }

/* R143 — Le bloc Courriel à la manière de la maison : trois sections
   encadrées à en-tête teinté, et un pied unique — l'essai à gauche,
   Enregistrer à droite (attribut form : deux formulaires, une seule barre). */
.mail-section { border: 1px solid var(--ligne, #d9d2c2); border-radius: 10px;
  overflow: hidden; background: #fffdf8; }
.mail-section + .mail-section { margin-top: 2px; }
.mail-section-tete { display: flex; align-items: center; gap: 8px;
  padding: 9px 12px; background: #f4efe4; border-bottom: 1px solid var(--ligne, #e2dbc9);
  font-weight: 600; color: #3f3a2f; }
.mail-section-tete svg { color: #0f6b53; }
.mail-section-corps { padding: var(--e3); display: grid; gap: var(--e3); }
/* R1020 — LE TRAIT AU-DESSUS DU PIED EST RETIRÉ. C'était la dernière ligne
   avant la carte des modèles : on la lisait comme un séparateur entre les
   deux cartes, alors que chacune a déjà son cadre (R1008) et que R1018 avait
   retiré son jumeau. L'espace (padding) suffit à détacher la barre d'actions. */
.mail-pied { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: var(--e3); padding-top: var(--e3); }
.mail-pied .mail-essai { margin: 0 auto 0 0; }
.mail-pied .btn.principal { margin-inline-start: auto; }
.mail-essai .sub { white-space: nowrap; }
/* R1015 — LE PIED S'ALIGNE SUR UNE SEULE HAUTEUR.
   Le champ mesurait 41 px, « Envoyer un essai » 34, « Enregistrer » 38 : trois
   objets d'une même rangée, trois tailles, et le regard butait sur chacune.

   On les fixe à la même hauteur et l'on centre leur contenu — c'est ce que
   l'œil attend d'une barre d'actions. */
.mail-pied .essai-champ input,
.mail-pied .btn {
  height: 38px; min-height: 38px;
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box;
}
/* Le champ garde son texte à gauche : ce n'est pas un bouton. */
.mail-pied .essai-champ input { justify-content: flex-start; }
/* R1020 — LA MARGE DE « .carte-reglage .btn » NE TRAVERSE PAS LE PIED.
   Cette règle pose 12 px au-dessus de tout bouton d'une carte de réglage —
   utile sous un formulaire, faux dans une rangée centrée : mesuré au
   navigateur, « Envoyer un essai » descendait de 6 px et « Enregistrer »
   montait de 4,5 px par rapport au champ. Trois classes battent les deux
   de la règle générale : dans le pied, la marge revient à zéro. */
.carte-reglage .mail-pied .btn { margin-top: 0; }
/* Les trois objets restaient décalés de onze pixels : le formulaire d'essai a
   ses propres marges, et « align-items: center » du parent ne les traverse pas.
   On aligne les enfants directs sur leur ligne, marges remises à zéro. */
.mail-pied > *, .mail-pied .mail-essai, .mail-pied .essai-champ {
  display: flex; align-items: center; margin-top: 0; margin-bottom: 0;
}
.mail-pied .essai-champ { gap: 8px; position: relative; }
/* R1018 : le message d'erreur se pose SOUS le champ, hors du flux. Dans la
   rangée, il poussait le champ vers le haut et brisait l'alignement des trois
   objets — on lisait l'erreur, mais la barre penchait.
   Hors du flux, la rangée ne bouge pas ; seul le message s'ajoute dessous. */
.mail-pied #essaiErreur {
  position: absolute; top: calc(100% + 6px); inset-inline-start: 0;
  margin: 0; white-space: nowrap; z-index: 2;
}
/* La rangée s'aligne au centre, quoi qu'elle contienne. */
.mail-pied { align-items: center; }

/* R146 — Le champ d'essai porte l'habit de la maison : bordure douce, focus
   vert, et quand il faut le dire — secousse et mot juste dessous, jamais la
   bulle brune du navigateur. */
.essai-champ { display: flex; flex-direction: column; gap: 3px; }
.mail-essai input[type="email"] { min-width: 240px; padding: 8px 11px;
  border: 1px solid var(--ligne, #cfc8ba); border-radius: 8px; background: #fffdf8;
  font: inherit; transition: border-color .15s ease, box-shadow .15s ease; }
.mail-essai input[type="email"]:focus { outline: none; border-color: #0f6b53;
  box-shadow: 0 0 0 3px rgba(15, 107, 83, .14); }
.mail-essai input[type="email"].attention { border-color: #b4231f;
  animation: mirSecousse .45s ease; }
/* R1015 : « .essai-erreur » retirée — le message d'essai porte « msg msg-err », comme partout. */

/* R147 — Le lien « mot de passe d'application » vit sous l'aide, aux
   couleurs de la maison, et change avec le fournisseur choisi. */
.mail-aide { align-items: flex-start; }
.mail-aide-corps { display: flex; flex-direction: column; gap: 5px; }
.mail-aide-lien { color: #0f6b53; font-weight: 600; width: fit-content;
  text-decoration: underline dotted; text-underline-offset: 3px; }
.mail-aide-lien:hover { text-decoration-style: solid; }

/* R148 — Les obligatoires du courriel : l'astérisque discret de la maison,
   et le mot juste sous le champ fautif (secousse comprise). */
.champ-oblig { color: #b4231f; font-weight: 700; margin-inline-start: 2px; }
/* R1023 — la seconde « .champ-erreur » de R148 est RETIRÉE. Elle habillait le
   MESSAGE du courriel (texte rouge rapetissé), du temps où cette classe
   servait aux deux. Depuis R1020, « champ-erreur » habille le CHAMP — et son
   « font-size: .84em » écrasait l'input fautif à 18 px : le rayon de 8 px en
   faisait une pilule. Une classe, un rôle. */
.mail-section input.attention { border-color: #b4231f; animation: mirSecousse .45s ease; }

/* R149 — L'interrupteur du courriel n'existe plus : une puce d'état dit la
   vérité en direct — verte quand la configuration tient, muette sinon. */
.mail-etat { display: flex; align-items: center; gap: 9px; padding: 8px 12px;
  border: 1px solid var(--ligne, #d9d2c2); border-radius: 8px; background: #f7f4ec;
  color: #6a6455; font-weight: 600; }
.mail-etat-point { width: 10px; height: 10px; border-radius: 50%;
  background: #b9b2a1; flex: none; transition: background .2s ease; }
.mail-etat.on { border-color: #bfe3d4; background: #eef8f3; color: #0f6b53; }
.mail-etat.on .mail-etat-point { background: #0f6b53;
  box-shadow: 0 0 0 3px rgba(15, 107, 83, .18); }

/* R149bis — L'étoile vit SUR la ligne du libellé, pas sur la sienne :
   libellé + étoile ne font qu'un seul enfant de la colonne. */
.lec-entete { display: inline-flex; align-items: baseline; gap: 2px; }

/* R153 — La première page du PDF s'affiche sur la fiche ; en son absence,
   le « .PDF » d'origine reste dessous, intact. */
.dprev { position: relative; }
.doc-thumb { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top; background: #fff; }
/* R532 — la vignette n'apparaît qu'une fois chargée (fondu), et le cadre
   montre une roue en attendant. « prete » et « chargee » sont posées par le
   script ; « sans-vignette » (image retirée) rend le repli. */
.dprev .doc-thumb { opacity: 0; transition: opacity .25s ease; }
.dprev .doc-thumb.chargee { opacity: 1; }
.dprev .dprev-attente { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: var(--paper, #FCFBF7); pointer-events: none; }
.dprev .dprev-attente::after { content: ''; width: 26px; height: 26px; border-radius: 50%;
  border: 3px solid var(--line2, #CFCBBD); border-top-color: var(--seal, #0E6B5C); animation: kz-tourne .9s linear infinite; }
.view-list .dprev .dprev-attente::after { width: 16px; height: 16px; border-width: 2px; }
.dprev.prete .dprev-attente, .dprev.sans-vignette .dprev-attente { display: none; }
@keyframes kz-tourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .dprev .dprev-attente::after { animation: none; border-top-color: var(--line2, #CFCBBD); } }

/* R156 — Le modal d'envoi à la manière de la maison : deux sections
   encadrées, obligatoires qui secouent, aperçu étiqueté. */
#mEnvoi .mail-section-corps { gap: var(--e2); }
#mEnvoi input.attention, #mEnvoi textarea.attention {
  border-color: #b4231f; animation: mirSecousse .45s ease; }
.envoi-vars { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.envoi-apercu { border: 1px dashed var(--ligne, #cfc8ba); border-radius: 8px;
  padding: 8px 10px; background: #fffdf8; }
.envoi-apercu pre { margin: 6px 0 0; white-space: pre-wrap; font-size: .92em; }
.maxw-620 { max-width: 620px; }

/* R170 — Le petit « i » des lignes de santé : au survol (ou au clavier),
   le guide de configuration de l'outil manquant. */
/* R1334 — le point « i » n'est plus le repère de sa bulle : c'est la LIGNE
   qui l'est (voir « .dash-list li { position: relative } »). Tant que ce
   point portait « position: relative », la bulle se mesurait sur ses
   quinze pixels de large et tout le reste sortait de la carte. */
.sante-aide { display: inline-flex; margin-inline-start: 6px;
  color: var(--brun-2, #8a6d3b); cursor: help; outline: none; }
/* R1334 — UNE BULLE INVISIBLE POUSSE QUAND MÊME LA PAGE.
   Deux fautes tenaient dans cette seule règle.
   1) « inset-inline-start » se retourne en arabe (elle compte depuis la
      DROITE), « translateX » non (elle pousse toujours vers la gauche). En
      français les deux se répondaient par hasard ; en arabe la bulle partait
      d'un demi-tour hors de sa carte : la page s'élargissait de 145 px, une
      barre horizontale paraissait et TOUT l'écran se décalait — la bande
      blanche de la capture du client.
   2) Même recentrée, elle restait large de 340 px, « max-content », et une
      bulle ne disparaît pas de la mise en page parce qu'elle est
      transparente : sur un écran de 1024 px l'espagnol, l'anglais et l'arabe
      débordaient encore de 70, 62 et 27 px.
   La bulle n'a aucune raison d'être plus large que la ligne qu'elle explique.
   On l'arrime donc à sa ligne (« left: 0; right: 0 » — deux côtés, donc rien
   à retourner d'une langue à l'autre) : elle ne peut plus, par construction,
   dépasser sa carte, dans aucune langue et à aucune largeur. */
.sante-aide::after { content: attr(data-tip); position: absolute; left: 0; right: 0;
  bottom: calc(100% + 8px); transform: none; width: auto;
  max-width: none; background: var(--paper, #FAF9F4); border: 1px solid var(--line2, #CDC7B8);
  color: var(--ink, #1F2724); font-size: .84rem;
  line-height: 1.45; padding: 8px 10px; border-radius: 8px;
  box-shadow: 0 6px 18px rgba(33,48,46,.14); opacity: 0; pointer-events: none;   /* R638 : clair, liseré fin */
  transition: opacity .12s ease; z-index: 40; white-space: normal; }
.sante-aide:hover::after, .sante-aide:focus::after { opacity: 1; }
.sante-aide-i { width: 15px; height: 15px; border-radius: 50%;
  border: 1px solid currentColor; display: inline-flex; align-items: center;
  justify-content: center; font: 700 .68rem/1 var(--police, serif); }

/* R189 — La miniature du document dans la fenêtre d'envoi. */
.envoi-mini { width: 48px; height: 60px; object-fit: cover; border-radius: 7px;
  border: 1px solid var(--ligne, #d8cdb8); background: #fff; flex: 0 0 auto;
  box-shadow: 0 1px 4px rgba(0,0,0,.10); }

/* R190 — Le formulaire utilisateur respire, et l'arbre des dossiers se lit. */
.form-aere .lec-label { display: block; margin-top: 14px; }
.form-aere .lec-label:first-of-type { margin-top: 0; }
.lec-hint { color: var(--brun-2, #8a6d3b); font-weight: 400; font-size: .86em; }
.doss-ligne .doss-nom { display: block; max-width: 100%; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.doss-nom.doss-fils { padding-inline-start: calc(var(--prof, 1) * 18px); }
.doss-nom.doss-fils::before { content: '└ '; color: var(--brun-2, #9a8a6a); }
.doss-tous { border-bottom: 1px dashed var(--ligne, #d8cdb8);
  padding-bottom: 6px; margin-bottom: 4px; }

/* R192 — Gestion des notifications : grille par dossier, liste supprimable. */
.suivi-grille { display: flex; flex-direction: column; gap: 6px; max-height: 380px;
  overflow: auto; border: 1px solid var(--ligne, #d8cdb8); border-radius: 8px; padding: 8px; }
.suivi-doss summary { display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 4px 6px; border-radius: 6px; }
.suivi-doss summary:hover { background: var(--fond-2, #f6efe2); }
.suivi-doss[open] > summary { background: var(--fond-2, #f6efe2); }
.suivi-corps { padding: 6px 8px 10px 22px; }
.suivi-actions { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 2px 14px; }
.suivi-canaux { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 8px;
  padding-top: 8px; border-top: 1px dashed var(--ligne, #d8cdb8); }
.notif-row { display: flex; align-items: stretch; gap: 6px; }
.notif-row .notif-item { flex: 1 1 auto; }
.notif-coche { display: flex; align-items: center; padding: 0 2px; }
.notif-del { align-self: center; opacity: .55; }
.notif-del:hover { opacity: 1; color: var(--rouge, #a33a22); }

/* R194 — CTA collé au bas du modal, actions autorisées en grille. */
/* R619 — LE PIED COLLANT D'UNE FENÊTRE VA D'UN BORD À L'AUTRE. Il vit DANS le
   corps de la fenêtre, qui a seize pixels de marge de chaque côté : son fond
   et son filet s'arrêtaient donc court, et l'on voyait le contenu défiler
   dans les deux bandes laissées libres. Il déborde maintenant de sa marge,
   et la rattrape en garniture — même trait, même fond, toute la largeur. */
.modal-cta { position: sticky; bottom: -16px; display: flex; gap: 8px;
  justify-content: flex-end; margin: 14px -16px -16px; padding: 12px 16px;
  background: var(--panel); border-top: 1px solid var(--line); }
.perm-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 2px 12px; }
.perm-min { font-style: normal; font-size: .78em; color: var(--brun-2, #9a8a6a); }

/* R198 — Canaux globaux en trois blocs ; liste de dossiers sans ascenseur. */
.canaux-grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(235px, 1fr)); gap: 12px; }
.canal-bloc { border: 1px solid var(--line, #d8cdb8); border-radius: 10px;
  padding: 12px 14px; background: var(--card, #fffdf8); }
.canal-bloc h3 { margin: 0 0 6px; display: flex; align-items: center; gap: 8px; font-size: 15px; }
.canal-note { font-size: 12px; color: var(--muted, #8a7a5c); margin: 6px 0 0; }
.ok-txt { color: var(--seal-dark, #1e6b46); } .err-txt { color: var(--err, #a33a22); }
.liste-libre { max-height: none; overflow: visible; }

/* R204 — La cloche porte son compteur AU-DESSUS d'elle, en pastille. */
.badgebtn.notif { position: relative; overflow: visible; }
.badgebtn.notif b {
  position: absolute; top: -5px; inset-inline-end: -6px;
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: var(--err, #a33a22); color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 17px; text-align: center;
  box-shadow: 0 0 0 2px var(--card, #fffdf8);
}
.badgebtn.notif.on { animation: kz-cloche-tinte .45s ease 1; }
@keyframes kz-cloche-tinte {
  0%, 100% { transform: rotate(0); }
  30% { transform: rotate(-12deg); } 60% { transform: rotate(9deg); }
}

/* R212 — Le bloc des pages garde le fond commun : le titre suffit. */

/* R214 — Le bouton qui travaille le DIT : rondelle qui tourne, texte
   estompé, clic impossible. Une seule mécanique pour toute l'application. */
.btn.occupe, button.occupe { position: relative; pointer-events: none; opacity: .75; }
.btn.occupe > *, button.occupe > * { visibility: hidden; }
.btn.occupe::after, button.occupe::after {
  /* R1334 — « margin: … -8px » est une marge GAUCHE, physique : l'ancrage
     doit l'être aussi, sinon la roue se décale du mauvais côté en arabe. */
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 15px; height: 15px; margin: -8px 0 0 -8px;
  border: 2px solid currentColor; border-inline-end-color: transparent;
  border-radius: 50%; animation: kz-tourne .7s linear infinite;
}
@keyframes kz-tourne { to { transform: rotate(360deg); } }

/* R219 — La tuile de création : même gabarit que les dossiers, en pointillé. */
.foldercard-neuf { border: 1px dashed var(--line, #d8cdb8); background: transparent;   /* R581 */
  color: var(--muted, #8a7a5c); cursor: pointer; font: inherit; text-align: start; }
.foldercard-neuf:hover { border-color: var(--seal, #1e6b46); color: var(--seal, #1e6b46);
  background: var(--card, #fffdf8); }

/* R221 — L'erreur d'une fenêtre s'affiche DANS la fenêtre. */
.alerte-modal { display: flex; align-items: flex-start; gap: 8px;
  background: var(--err-bg, #fbeae6); color: var(--err, #a33a22);
  border: 1px solid currentColor; border-radius: 8px;
  padding: 9px 11px; margin: 0 0 12px; font-size: 13.5px; }

/* R226 — Une notification qui arrive en direct s'annonce un instant. */
.notif-row.neuve { animation: kz-neuve 2.2s ease 1; }
@keyframes kz-neuve { 0% { background: var(--warn-bg, #fdf3dd); } 100% { background: transparent; } }

/* R227 — Panneau de la cloche : liste défilante, pied fixe. */
.notif-zone { position: relative; display: inline-flex; }
.notif-panneau { position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 60;
  width: min(380px, calc(100vw - 24px)); display: flex; flex-direction: column;
  max-height: min(60vh, 480px); background: var(--card, #fffdf8);
  border: 1px solid var(--line, #d8cdb8); border-radius: 12px;
  box-shadow: 0 14px 34px rgba(0,0,0,.16); overflow: hidden; }
.np-tete { display: flex; align-items: center; justify-content: space-between;
  padding: 10px 12px; border-bottom: 1px solid var(--line, #d8cdb8); }
.np-liste { overflow: auto; flex: 1 1 auto; }
.np-item { display: block; padding: 10px 12px; border-bottom: 1px solid var(--line, #ece4d4);
  color: inherit; text-decoration: none; }
.np-item:hover { background: var(--bg, #f7f2e7); }
.np-item.neuf { border-inline-start: 3px solid var(--seal, #1e6b46); }
.np-item b { display: block; font-size: 13.5px; }
.np-detail { display: block; font-size: 12.5px; color: var(--muted, #8a7a5c); margin-top: 2px; }
.np-quand { display: block; font-style: normal; font-size: 11.5px; color: var(--muted, #8a7a5c); margin-top: 3px; }
.np-vide { padding: 18px 12px; text-align: center; color: var(--muted, #8a7a5c); font-size: 13px; }
.np-pied { position: sticky; bottom: 0; padding: 10px 12px;
  border-top: 1px solid var(--line, #d8cdb8); background: var(--card, #fffdf8); }
.np-cta { display: flex; justify-content: center; width: 100%; }

/* R651 — LE PANNEAU DE LA CLOCHE TIENT DANS L'ÉCRAN DU TÉLÉPHONE.
   Il était accroché au bord droit de la cloche (position: absolute ; inset-inline-end: 0)
   avec une largeur de « l'écran moins 24 px » : la cloche n'étant pas au bord
   de l'écran — l'avatar et les pastilles la suivent — le panneau partait
   vingt-huit pixels DANS LA MARGE GAUCHE, et son titre comme ses lignes
   étaient coupés. Sous 700 px, il quitte donc son ancrage : posé en fixe sous
   la barre haute, une marge égale à droite et à gauche, et sa hauteur bornée
   à ce qui reste sous la barre. */
@media (max-width: 700px) {
  .notif-panneau {
    position: fixed; top: calc(var(--h-topbar, 55px) + 8px); inset-inline-start: 12px; inset-inline-end: 12px;
    width: auto; max-height: calc(100vh - var(--h-topbar, 55px) - 24px);
    max-height: calc(100dvh - var(--h-topbar, 55px) - 24px);   /* la barre du navigateur mobile comprise */
  }
  .np-item b { font-size: 14px; }
  .np-tete { padding: 12px 14px; }
  .np-item { padding: 12px 14px; }
  .np-pied { padding: 12px 14px; }
}

/* R228 — Bloc de réglages replié : titre cliquable, contenu au besoin. */
.bloc-repli > summary { display: flex; align-items: baseline; gap: 10px;
  cursor: pointer; list-style: none; padding: 2px 0; }
.bloc-repli > summary::-webkit-details-marker { display: none; }
.bloc-repli > summary::after { content: '+'; margin-inline-start: auto;
  font-size: 26px; line-height: 1; font-weight: 400;
  color: var(--seal, #1e6b46); transition: transform .18s ease; }
.bloc-repli[open] > summary::after { content: '−'; }
.repli-titre { font-family: var(--serif, Georgia, serif); font-size: 17px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 8px; }
.repli-aide { font-size: 12.5px; color: var(--muted, #8a7a5c); }
.bloc-repli[open] > summary { margin-bottom: 10px; border-bottom: 1px solid var(--line, #d8cdb8);
  padding-bottom: 8px; }

/* R232 — Bandeaux de secours quand la notification système est étouffée. */
#kzToasts { position: fixed; inset-inline-end: 16px; bottom: 16px; z-index: 90;
  display: flex; flex-direction: column; gap: 8px; max-width: min(360px, 90vw); }
.kz-toast { background: var(--card, #fffdf8); border: 1px solid var(--line, #d8cdb8);
  border-inline-start: 3px solid var(--seal, #1e6b46); border-radius: 10px; padding: 10px 12px;
  box-shadow: 0 10px 26px rgba(0,0,0,.15); font-size: 13px;
  animation: kz-toast-in .22s ease; }
.kz-toast.avert { border-inline-start-color: var(--err, #a33a22); }
.kz-toast b { display: block; }
.kz-toast span { display: block; color: var(--muted, #8a7a5c); margin-top: 2px; }
.kz-toast i { display: block; font-style: normal; font-size: 11.5px;
  color: var(--err, #a33a22); margin-top: 5px; }
.kz-toast.part { opacity: 0; transform: translateY(6px); transition: .55s ease; }
@keyframes kz-toast-in { from { opacity: 0; transform: translateY(8px); } }

/* ── R248 — RESTAURER : un bloc qui se lit d'un regard ──────────────────── */
.resto-tete { display: flex; align-items: center; gap: 12px; margin-bottom: 4px; }
.resto-pastille { display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 10px; flex: 0 0 auto;
  background: var(--paper2); border: 1px solid var(--line); color: var(--muted); }

/* Les trois temps, annoncés avant qu'on ne dépose quoi que ce soit. */
.resto-etapes { display: grid; gap: 10px; margin: 16px 0 4px;
  padding: 14px; border-radius: 12px; background: var(--paper2);
  grid-template-columns: 1fr auto 1fr auto 1fr; align-items: start; }

/* R279 — LE ROND NE VAUT QUE POUR LE NUMÉRO. La règle visait « b » sans
   distinction : le mot en gras de chaque étape se retrouvait comprimé dans un
   cercle de vingt-deux pixels, d'où le chevauchement. On ne cible plus que
   l'enfant DIRECT. */
.resto-etape { display: grid; grid-template-columns: 24px 1fr; gap: 4px 10px;
  align-items: start; font-size: 13px; color: var(--ink); min-width: 0; }
.resto-etape > b { grid-row: 1 / span 2; display: inline-flex; align-items: center;
  justify-content: center; width: 24px; height: 24px; border-radius: 50%;
  border: 1px solid var(--line2); background: var(--paper); color: var(--muted);
  font-size: 12px; font-weight: 600; flex: 0 0 auto; }
.resto-etape > span { display: block; min-width: 0; }
.resto-etape > span > b { display: block; font-weight: 600; line-height: 1.3; }
.resto-etape > span > i { display: block; font-style: normal; font-size: 12px;
  color: var(--muted); line-height: 1.45; margin-top: 2px; }
.resto-fleche { color: var(--faint); display: flex; align-items: center;
  height: 24px; }

@media (max-width: 720px) {
  /* Sur écran étroit, les trois temps s'empilent et les chevrons s'effacent. */
  .resto-etapes { grid-template-columns: 1fr; }
  .resto-fleche { display: none; }
}


/* Les deux dépôts : cibles larges, état visible au survol. */
.resto-champs { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px; margin-top: 14px; }
.resto-depot { display: flex; align-items: flex-start; gap: 12px; cursor: pointer;
  padding: 14px; border: 1.5px dashed var(--line2); border-radius: 12px;
  background: var(--paper); transition: border-color .15s ease, background .15s ease; }
.resto-depot:hover { border-color: var(--seal); background: var(--paper2); }
.resto-depot .rd-ic { color: var(--muted); flex: 0 0 auto; margin-top: 2px; }
.resto-depot .rd-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.resto-depot .rd-txt b { font-size: 13.5px; }
.resto-depot .rd-txt em { font-style: normal; color: var(--muted); font-weight: 400; }
.resto-depot .rd-txt i { font-style: normal; font-size: 12px; color: var(--muted); }
.resto-depot input[type=file] { grid-column: 1 / -1; margin-top: 6px; font-size: 12px; width: 100%; }

/* Ce que fait chaque cas, côte à côte, sans paragraphe à lire. */
.resto-cas { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px; margin-top: 14px; }
.rc { padding: 12px 14px; border-radius: 12px; border-inline-start: 3px solid; background: var(--paper2); }
.rc b { display: block; font-size: 13px; margin-bottom: 3px; }
.rc span { font-size: 12.5px; color: var(--muted); }
.rc-vert  { border-inline-start-color: var(--line2); }
.rc-ambre { border-inline-start-color: var(--line2); }

.resto-plus { margin-top: 14px; }
.resto-plus > summary { cursor: pointer; font-size: 13px; color: var(--muted); }
.resto-plus[open] > summary { color: var(--ink); margin-bottom: 6px; }

.resto-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 18px; }

/* Pendant le travail : bilan, barre, ligne d'état. */
.resto-bilan { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.resto-barre { height: 12px; border-radius: 99px; background: var(--line); overflow: hidden; }
.resto-barre span { display: block; height: 100%; width: 0; border-radius: 99px;
  background: var(--seal); transition: width .35s ease; }
.resto-ligne { display: flex; align-items: baseline; gap: 10px; margin-top: 8px; font-size: 13px; }
.resto-ligne .resto-pct { margin-inline-start: auto; font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--ink); }

/* ── R249 — La base : un seul bloc, lu d'un regard ──────────────────────── */
.sauvbase .sb-etat { margin-inline-start: auto; }
.sb-trajet { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
.sb-pas { display: flex; flex-direction: column; gap: 2px; flex: 1 1 180px;
  padding: 10px 12px; border-radius: 12px; background: var(--paper2);
  border: 1px solid var(--line); }
.sb-pas svg { color: var(--muted); }
.sb-pas b { font-size: 13px; }
.sb-pas i { font-style: normal; font-size: 12px; color: var(--muted); }
.sb-fleche { display: flex; align-items: center; color: var(--faint); }
.sb-faits { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px; margin-top: 14px; }
.sb-fait { text-align: center; padding: 10px 8px; border-radius: 10px;
  background: var(--paper2); border: 1px solid var(--line); }
.sb-fait b { display: block; font-size: 16px; color: var(--ink); font-variant-numeric: tabular-nums; }
.sb-fait span { font-size: 12px; color: var(--muted); }
.sb-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

/* ── R251 — Sauvegarde : montrer plutôt que décrire ─────────────────────── */
.sv-pieces { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.sv-p { flex: 1 1 150px; padding: 10px 12px; border-radius: 10px;
  background: var(--paper2); border: 1px solid var(--line); }
.sv-p b { display: block; font-size: 12.5px; font-family: ui-monospace, Menlo, Consolas, monospace; }
.sv-p span { font-size: 11.5px; color: var(--muted); }
.sv-p.sv-vital { border-inline-start: 2px solid var(--ink); background: var(--paper2); }

.sv-regle { display: flex; align-items: center; gap: 12px; margin-top: 14px;
  padding: 10px 12px; border-radius: 10px; background: var(--paper2);
  border: 1px solid var(--line); font-size: 12.5px; }
.sv-3 { display: inline-flex; gap: 4px; flex: 0 0 auto; }
.sv-3 i { width: 12px; height: 16px; border-radius: 3px;
  border: 1px solid var(--line2); background: var(--paper); }
.sv-3 i:nth-child(2) { opacity: .75; }
.sv-3 i:nth-child(3) { opacity: .5; }

.sv-arbre { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
  line-height: 1.65; padding: 12px 14px; border-radius: 10px; overflow-x: auto;
  background: var(--paper2); border: 1px solid var(--line); color: var(--ink); }
.sv-arbre .sv-note { color: var(--muted); font-style: italic; }

/* ── R265 — ALIGNEMENTS. Les blocs de la page de sauvegarde étaient posés
   les uns après les autres sans discipline commune : cartes de hauteurs
   inégales, textes qui ne partaient pas de la même verticale, cases à cocher
   décalées de leur libellé. Une poignée de règles remet tout d'aplomb. */

/* Les têtes de bloc : icône, titre et sous-titre sur la même ligne de base. */
.resto-tete { align-items: center; gap: 12px; }
.resto-tete > div { min-width: 0; }
.resto-tete h2 { line-height: 1.25; }
.resto-tete .sb-etat { margin-inline-start: auto; white-space: nowrap; align-self: center; }

/* Les grilles : toutes les cartes d'une rangée à la même hauteur. */
.sb-faits, .resto-champs, .resto-cas, .sv-pieces { align-items: stretch; }
.sb-fait, .rc, .sv-p { display: flex; flex-direction: column; justify-content: center; }
.sb-fait b { line-height: 1.2; margin-bottom: 2px; }

/* Les trois pas : même hauteur, contenu centré verticalement. */
.sb-trajet { align-items: stretch; }
.sb-pas { justify-content: center; }
.sb-fleche { align-self: center; }

/* Les zones de dépôt : icône alignée sur la première ligne du texte,
   et le champ de fichier occupe toute la largeur, sous le libellé. */
.resto-depot { align-items: flex-start; flex-wrap: wrap; }
.resto-depot .rd-ic { line-height: 0; margin-top: 1px; }
.resto-depot .rd-txt { flex: 1 1 auto; }
.resto-depot input[type=file] { flex: 1 1 100%; margin-top: 8px; }

/* Case à cocher et libellé sur la même ligne de base. */
.lec-label-ligne { align-items: flex-start; gap: 10px; }
.lec-label-ligne input[type=checkbox] { margin-top: 3px; flex: 0 0 auto; }

/* Barre d'actions : boutons alignés, mention rejetée à droite. */
.resto-actions { align-items: center; }
.resto-actions > .sub { margin-inline-start: auto; text-align: right; }
.resto-actions form { display: inline-flex; margin: 0; }

/* Ligne d'état sous la barre : étape à gauche, détail au milieu, part à droite. */
.resto-ligne { align-items: center; gap: 12px; }
.resto-ligne #restoDetail { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

/* Chemins affichés : ne débordent plus sur les petits écrans. */
.bloc-chemin { overflow-x: auto; white-space: pre; }

/* R269 — La bibliothèque se donne d'une façon ou d'une autre, dans le même
   encadré : l'archive, ou le chemin. Le « ou » sépare sans couper. */
.resto-depot-large { flex: 1 1 100%; }
.resto-depot .rd-ou { flex: 1 1 100%; font-size: 12px; color: var(--faint);
  text-align: center; margin: 6px 0 2px; }
.resto-depot input[type=text] { flex: 1 1 100%; width: 100%; }
.resto-depot .rd-note { flex: 1 1 100%; margin-top: 8px; line-height: 1.5; }
.resto-depot.manque { border-color: var(--err, #a33a22); }

/* R275 — Le reproche se lit à l'endroit du manque, pas dans une fenêtre. */
.rd-erreur { flex: 1 1 100%; margin-top: 8px; font-size: 12.5px;
  color: var(--err, #a33a22); display: flex; align-items: flex-start; gap: 6px; }
.rd-erreur::before { content: '!'; display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%; border: 1px solid currentColor;
  font-size: 11px; font-weight: 700; flex: 0 0 auto; }

/* R276 — Ce que rend chaque dépôt, dit dans son propre encadré. */
.resto-depot .rd-rend { display: block; margin-top: 6px; font-size: 12.5px;
  color: var(--ink); line-height: 1.55; }
.resto-depot .rd-rend b { font-weight: 600; }

/* R282 — Le guide de synchronisation : replié, discret, une seule note verte. */
.sv-cloud { margin-top: 14px; padding: 12px 14px; border-radius: 12px;
  background: var(--paper2); border: 1px solid var(--line); }
.sv-cloud > summary { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  cursor: pointer; list-style: none; }
.sv-cloud > summary::-webkit-details-marker { display: none; }
.sv-cloud > summary::after { content: '+'; margin-inline-start: auto; font-size: 20px;
  line-height: 1; color: var(--muted); }
.sv-cloud[open] > summary::after { content: '−'; }
.sv-cloud > summary b { font-size: 13.5px; }
.sv-cloud > summary i { font-style: normal; font-size: 12px; color: var(--muted); }
.sv-reco { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 99px;
  background: var(--info-bg); color: var(--seal); font-size: 11.5px; font-weight: 600;
  letter-spacing: .02em; }
.sv-fournisseurs { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 10px; margin-top: 12px; }
.sv-f { padding: 10px 12px; border-radius: 10px; background: var(--paper);
  border: 1px solid var(--line); display: flex; flex-direction: column; gap: 4px; }
.sv-f b { font-size: 13px; }
.sv-f i { font-style: normal; font-size: 12px; color: var(--muted); line-height: 1.5; }
.sv-f em { font-style: normal; color: var(--ink); }
.sv-f a { font-size: 12px; margin-top: 2px; }

/* ── R299 — Vérification : deux onglets, sélection multiple, marche en cours ── */
.ver-onglets { display: flex; gap: 6px; margin: 14px 0 10px; flex-wrap: wrap; }
.ver-ong { display: inline-flex; align-items: center; gap: 7px; padding: 7px 13px;
  border-radius: 99px; border: 1px solid var(--line); background: var(--paper2);
  color: var(--muted); font-size: 13px; text-decoration: none; }
.ver-ong b { font-variant-numeric: tabular-nums; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line); border-radius: 99px;
  padding: 0 7px; font-size: 12px; }
.ver-ong.on { background: var(--paper); color: var(--ink); border-color: var(--line2); font-weight: 600; }
.ver-ong.on b { background: var(--info-bg); border-color: transparent; color: var(--seal); }

.ver-barre { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 10px; border-radius: 12px;
  background: var(--paper2); border: 1px solid var(--line); }
.ver-tout { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; cursor: pointer; }
.ver-compte { font-variant-numeric: tabular-nums; }
.ver-actions { margin-inline-start: auto; display: inline-flex; gap: 8px; flex-wrap: wrap; }
.ver-case { display: inline-flex; align-items: center; margin-inline-end: 4px; }
.ver-case input { width: 16px; height: 16px; }

.ver-marche { padding: 12px 14px; margin-bottom: 12px; border-radius: 12px;
  background: var(--paper2); border: 1px solid var(--line); }
.ver-journal { list-style: none; margin: 10px 0 0; padding: 0; max-height: 220px;
  overflow-y: auto; font-size: 12.5px; }
.ver-journal li { display: flex; gap: 8px; padding: 3px 0; border-top: 1px solid var(--line); }
.ver-journal li:first-child { border-top: 0; }
.ver-journal .ok { color: var(--seal); }
.ver-journal .ko { color: var(--err, #a33a22); }
.ver-journal .nom { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row.faite { opacity: .55; }

/* ── R308 — La fenêtre de lecture en masse ──────────────────────────────── */
.modal-large .modal-card, .modal-card.modal-large { max-width: 860px; width: 92vw; }
.vl-tete { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 16px; border-bottom: 1px solid var(--line); background: var(--paper2); }
.vl-points { display: flex; flex-wrap: wrap; gap: 4px; flex: 1 1 320px; }
.vl-pt { width: 10px; height: 10px; border-radius: 50%; border: 1px solid var(--line2);
  background: var(--paper); flex: 0 0 auto; }
.vl-pt.faite { background: var(--seal); border-color: var(--seal); }
.vl-pt.ratee { background: var(--err, #a33a22); border-color: var(--err, #a33a22); }
.vl-pt.encours { background: var(--paper); border-color: var(--seal); box-shadow: 0 0 0 3px var(--info-bg); }
.vl-compte { display: flex; flex-direction: column; gap: 2px; text-align: right; margin-inline-start: auto; }
.vl-compte b { font-variant-numeric: tabular-nums; }
.vl-corps { display: grid; grid-template-columns: 220px 1fr; gap: 16px; align-items: start; }
/* R360 : l'aperçu occupait près de la moitié de la fenêtre en hauteur, alors
   qu'il sert seulement à reconnaître la pièce en cours. Il perd un tiers : la
   progression et le journal remontent d'autant. */
.vl-apercu { border: 1px solid var(--line); border-radius: 10px; background: var(--paper2);
  min-height: 175px; max-height: 200px; display: flex; align-items: center;
  justify-content: center; overflow: hidden; }
.vl-apercu img { max-width: 100%; max-height: 190px; display: block; object-fit: contain; }
.vl-sansapercu { display: flex; flex-direction: column; align-items: center; gap: 6px;
  color: var(--faint); font-size: 12px; }
.vl-detail { min-width: 0; }
.vl-nom { display: block; font-size: 14px; }
#vlJournal { max-height: 200px; overflow-y: auto; }
@media (max-width: 720px) { .vl-corps { grid-template-columns: 1fr; }
  .vl-apercu { min-height: 130px; max-height: 150px; } }

/* R309 — Chaque onglet dit ce qu'il contient ; la liste ouverte dit pourquoi. */
.ver-ong { display: flex; align-items: center; }
.ver-ong .vo-titre { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; }
/* R327 — L'enseigne : la phrase de la liste ouverte, sous les onglets, dans la
   teinte dorée réservée à ce qui renseigne sans réclamer d'action. */
.ver-enseigne { display: flex; align-items: center; gap: 10px;
  margin: 12px 0 14px; padding: 10px 14px; border-radius: 10px;
  background: var(--warn-bg); color: var(--warn);
  font-size: 14.5px; font-weight: 500; line-height: 1.45; }
.ver-enseigne svg { flex: 0 0 auto; }
@media (max-width: 640px) { .ver-enseigne { font-size: 13.5px; padding: 9px 12px; } }
.ver-pourquoi { display: flex; align-items: flex-start; gap: 10px; margin: 12px 0 4px;
  padding: 12px 14px; border-radius: 12px; background: var(--paper2);
  border: 1px solid var(--line); font-size: 12.5px; line-height: 1.6; }
.ver-pourquoi svg { flex: 0 0 auto; margin-top: 2px; color: var(--muted); }
.ver-pourquoi b { font-weight: 600; }

/* ── R323 — LA CLASSE QUI N'EXISTAIT PAS ────────────────────────────────────
   Plusieurs endroits du code masquaient un élément en lui ajoutant « d-none » —
   classe jamais définie ici. Rien n'était donc masqué : une barre de progression
   restait affichée sous la liste de vérification, et le bouton « Continuer » de
   la fenêtre de confirmation apparaissait même quand il n'y avait rien à
   confirmer. On la définit, et l'on emploie « hidden » pour le neuf. */
.d-none { display: none !important; }

/* Le pied de la fenêtre de lecture : la note à gauche, les boutons à droite,
   tous alignés sur la même ligne médiane. */
.vl-pied { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; }
.vl-pied #vlNote { flex: 1 1 260px; margin: 0; line-height: 1.5; }
.vl-pied .lec-actions { margin: 0; flex: 0 0 auto; }
@media (max-width: 640px) {
  .vl-pied { align-items: stretch; }
  .vl-pied .lec-actions { width: 100%; justify-content: flex-end; }
}


/* R333 — Le bandeau d'arrivée après une restauration : ce qui vient d'entrer,
   ce qui reste à faire, et le chemin pour s'en occuper. */
.resto-arrivee { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 12px 16px; border-radius: 12px;
  background: var(--seal-soft); color: var(--seal-dark);
  border: 1px solid var(--seal); }
.resto-arrivee > svg { flex: 0 0 auto; }
.resto-arrivee .ra-texte { flex: 1 1 320px; display: flex; flex-direction: column; gap: 3px;
  font-size: 13.5px; line-height: 1.5; }
.resto-arrivee .ra-texte span { color: var(--seal-dark); opacity: .92; }
.resto-arrivee .btn { flex: 0 0 auto; }
@media (max-width: 640px) { .resto-arrivee .btn { width: 100%; } }

/* R334 — La fenêtre de lecture en masse montre deux progressions : celle des
   pièces (en bas) et celle des passages de la pièce en cours (en haut, plus
   proche de son nom). Le bouton d'abandon ne concerne que la pièce en cours. */
#vlJaugePiece { background: var(--seal); }
#vlPassage { display: block; margin-top: 6px; font-variant-numeric: tabular-nums; }
#vlSauter { padding: 4px 10px; font-size: 12px; }

/* R344 — Quand la vignette manque, le cadre reste une fiche lisible : le type
   du fichier s'y lit en grand, comme avant toute vignette. */
.sans-vignette .bigext { opacity: 1; }
.doc-thumb[hidden], .envoi-mini[hidden] { display: none !important; }

/* R349 — L'avertissement qui prévient AVANT le travail : même teinte que les
   messages d'attention, une icône, et le texte qui respire. */
.ver-alerte { display: flex; align-items: flex-start; gap: 10px;
  margin: 12px 0 14px; padding: 11px 15px; border-radius: 10px;
  background: var(--warn-bg); color: var(--warn);
  font-size: 13.5px; line-height: 1.55; }
.ver-alerte svg { flex: 0 0 auto; margin-top: 1px; }
.ver-alerte a { color: inherit; text-decoration: underline; }

/* ── R362 — L'ATTENTE LONGUE SE VOIT ───────────────────────────────────────
   Sur une page dense, un seul passage de lecture peut durer plusieurs
   minutes. Trois signes rassurent sans mentir : la barre bouge, un compteur
   monte, et un mot paraît au bout d'une minute. */
.kz-anime {
  background-image: linear-gradient(115deg,
    rgba(255,255,255,.34) 25%, transparent 25%, transparent 50%,
    rgba(255,255,255,.34) 50%, rgba(255,255,255,.34) 75%, transparent 75%);
  background-size: 28px 28px;
  animation: kz-glisse .85s linear infinite;
}
@keyframes kz-glisse { from { background-position: 0 0; } to { background-position: 28px 0; } }

.kz-attente-mot {
  margin: 6px 0 0; font-size: 12.5px; line-height: 1.5;
  color: var(--muted);
}
/* Passé deux minutes sans nouvelle, le ton change : rassurer à tort serait
   pire que se taire. */
.kz-attente-mot.souci { color: var(--warn); font-weight: 500; }

/* Un mouvement perpétuel gêne certaines personnes : on le retire pour qui
   demande à son navigateur de limiter les animations. Le compteur, lui,
   demeure — c'est lui qui porte la preuve. */
@media (prefers-reduced-motion: reduce) {
  .kz-anime { animation: none; background-image: none; }
}

/* R364 — Vider une période de la corbeille : le bandeau dit combien de pièces
   sont concernées avant de proposer de les effacer. */
.corb-periode { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 0 14px; padding: 11px 15px; border-radius: 10px;
  background: var(--warn-bg); color: var(--warn); }
.corb-periode > svg { flex: 0 0 auto; }
.corb-periode .cp-texte { flex: 1 1 320px; display: flex; flex-direction: column; gap: 2px;
  font-size: 13.5px; line-height: 1.5; }
.corb-periode .cp-aide { flex: 0 0 auto; }
@media (max-width: 640px) { .corb-periode form, .corb-periode .btn { width: 100%; } }

/* R388 — Le bouton de démarrage vit sur la ligne du diagnostic, à droite. */
.dash-list li .dash-acte { display: inline-flex; margin-inline-start: 10px; }
.dash-list li .dash-acte .btn { padding: 2px 10px; font-size: 12.5px; }

/* R392 — La ligne en cours de démarrage se distingue, le temps que le lecteur
   charge ses moteurs. */
.dash-list li.dash-encours { background: var(--warn-bg); border-radius: 8px; }
.dash-list li.dash-encours .dash-etat { color: var(--warn); font-weight: 500; }
.dash-list li .dash-acte button[disabled] { opacity: .55; cursor: default; }

/* R394 — Le journal du lecteur, replié sous le diagnostic. */
.journal-lecteur { margin: 14px 0 0; border-top: 1px solid var(--line); padding-top: 12px; }
.journal-lecteur > summary { cursor: pointer; font-size: 13.5px; color: var(--muted);
  display: flex; align-items: center; gap: 7px; list-style: none; }
.journal-lecteur > summary::-webkit-details-marker { display: none; }
.journal-lecteur > summary:hover { color: var(--ink); }
.journal-corps { background: var(--paper2); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 12px; font-size: 12.5px; line-height: 1.55; max-height: 260px;
  overflow: auto; white-space: pre-wrap; word-break: break-word; margin: 6px 0 12px; }

/* R408 — La fenêtre qui demande de remplacer la base : trois paragraphes
   courts, aérés, et un bouton qui nomme l'acte. */
.dire-txt { white-space: pre-line; line-height: 1.65; font-size: 14.5px; }
#mRestoDire .modal-card { max-width: 520px; }
#mRestoDire .modal-head svg { color: var(--warn); }

/* R409 — L'aperçu de la pièce jointe, au-dessus de son cartouche. */
.piece-vignette { display: flex; justify-content: center; margin: 0 0 14px; }
.piece-vignette img { max-width: 100%; border: 1px solid var(--line); border-radius: 10px;
  background: var(--paper2); box-shadow: 0 1px 3px rgba(0,0,0,.06); }
.piece-vignette img.sans-vignette, .piece-vignette:empty { display: none; }

/* R416 — L'avis sur un mot de passe fragile : visible, jamais bloquant. */
.mdp-avis { border: 1px solid var(--warn, #B4771F); background: #FDF5E6;
  border-radius: 10px; padding: 12px 14px; margin: 0 0 14px; }
.mdp-avis-tete { margin: 0 0 8px; font-weight: 600; color: #8A5A12;
  display: flex; align-items: center; gap: 7px; }
.mdp-avis ul { margin: 0 0 8px; padding-inline-start: 18px; line-height: 1.6; font-size: 14px; }
.mdp-avis li { margin: 0 0 5px; }
.mdp-assume { display: flex; align-items: flex-start; gap: 9px; margin: 0 0 14px;
  padding: 10px 12px; border: 1px dashed var(--line2); border-radius: 9px;
  cursor: pointer; font-size: 14px; }

/* R419 — Mon compte : en-tête, groupes de cases, note discrète. */
.wrap-etroit { max-width: 720px; margin: 0 auto; }
.prof-tete { display: flex; align-items: center; gap: 14px; margin: 4px 0 10px; }
.prof-avatar { width: 46px; height: 46px; border-radius: 50%; background: var(--vert-pale, #E3EFE9);
  color: var(--vert, #1F6A4D); display: flex; align-items: center; justify-content: center;
  font-weight: 600; letter-spacing: .5px; }
.prof-tete b { display: block; }
.prof-note { display: flex; align-items: center; gap: 6px; color: var(--muted); margin: 0; }
.prof-groupe { font-weight: 600; margin: 14px 0 6px; font-size: 14px; }

/* R422 — Mon compte : repères vers les trois blocs, conseils sous le champ. */
.prof-liens { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; }
.prof-liens a { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px;
  padding: 6px 12px; border: 1px solid var(--line2); border-radius: 20px;
  color: var(--ink); text-decoration: none; }
.prof-liens a:hover { border-color: var(--vert, #1F6A4D); color: var(--vert, #1F6A4D); }
.prof-conseil { margin: -6px 0 12px; }

/* R433 — LA BARRE DE PIED. Fixée en bas, contenu rangé à droite. La marge
   basse de la page compense sa hauteur : sans cela, la dernière ligne d'une
   liste se retrouverait cachée dessous — un défaut qu'on ne voit qu'en bas
   d'un long écran, donc tard. */
.pied-barre {
  position: fixed; inset-inline-start: 0; inset-inline-end: 0; bottom: 0; z-index: 80;
  height: var(--h-pied, 28px); display: flex; align-items: center; justify-content: flex-end;
  gap: 14px; padding: 0 14px;
  /* R437 : le même fond que la barre latérale. Les deux bordent la page ; une
     teinte commune les rattache l'une à l'autre au lieu d'en faire deux
     éléments étrangers posés côte à côte. */
  background: var(--panel); border-top: 1px solid var(--line);
}
.pied-droits { font-size: 11px; color: var(--muted); }
.pied-droits b { font-weight: 600; color: var(--ink); }
.pied-aide {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; cursor: pointer;
  font-size: 11.5px; color: var(--vert, #1F6A4D); padding: 3px 6px; border-radius: 6px;
}
.pied-aide:hover { background: var(--bg); }
.pied-aide svg { color: currentColor; }
body { padding-bottom: var(--h-pied, 28px); }
@media (max-width: 700px) {
  /* R1492 : on bouge LE JETON, pas la règle — ainsi la barre latérale,
     le corps et le panneau d'aide se recalent tous les trois. */
  :root { --h-pied: 26px; }
  .pied-barre { height: var(--h-pied, 26px); gap: 8px; padding: 0 9px; }
  /* R437 : sur un écran étroit, le numéro compte plus que la signature —
     c'est là qu'on appelle. On raccourcit donc le copyright, jamais le
     numéro : il doit rester lisible pour être composé. */
  .pied-droits { font-size: 10px; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; max-width: 42vw; }
  .pied-aide { font-size: 11px; padding: 3px 4px; flex-shrink: 0; }
  body { padding-bottom: 26px; }
}

.aide-liens { display: flex; flex-direction: column; gap: 8px; margin: 14px 0 4px; }
.aide-lien {
  display: flex; align-items: center; gap: 11px; text-decoration: none;
  border: 1px solid var(--line2); border-radius: 10px; padding: 10px 12px;
  color: var(--ink);
}
.aide-lien:hover { border-color: var(--vert, #1F6A4D); background: var(--bg); }
.aide-lien b { display: block; font-size: 13.5px; }
.aide-lien small { color: var(--muted); font-size: 12.5px; }
.aide-wa:hover { border-color: #25D366; }
.aide-droits { margin: 14px 0 0; font-size: 12px; color: var(--muted); text-align: center; }

/* R429 — Le groupe de réglages de l'assistance, séparé de ce qui l'entoure. */
.reglage-groupe { border: 1px solid var(--line2); border-radius: 11px;
  padding: 13px 15px; margin: 16px 0; }
.reglage-groupe > .f { margin-bottom: 2px; }

/* R430 — La version, discrète, au bas de la fenêtre d'assistance. */
.aide-rev { font-size: 11px; color: var(--muted); opacity: .8; }


/* R441 — LE LOGO DANS L'EN-TÊTE.
   La hauteur de l'en-tête ne change pas : c'est le logo qui s'y plie. Trente-
   six pixels de haut dans cinquante-cinq, marges comprises ; la largeur suit
   d'elle-même, le rapport de l'image étant conservé. */
.brand-logo {
  /* R442 : sur un grand écran, le logo occupe TOUTE la hauteur de l'en-tête —
     le trait du bas en moins, pour qu'il s'appuie dessus sans le recouvrir.
     Le parchemin dessiné dans l'image lui tient lieu de marge : il n'a pas
     besoin qu'on lui en ajoute. */
  /* R446 — LE NOUVEAU LOGO N'A PLUS DE CADRE. L'ancien portait un parchemin
     dessiné qui lui tenait lieu de marge : il pouvait occuper la hauteur
     entière sans paraître à l'étroit. Celui-ci commence directement par la
     lettre et finit par le mot ; collé aux deux bords, il donnerait l'aspect
     d'une image mal cadrée.
     Quarante-huit pixels dans cinquante-cinq : trois et demi de chaque côté,
     assez pour qu'il respire, assez peu pour qu'il occupe encore l'en-tête. */
  height: var(--h-recherche, 40px); width: auto; display: block;
  transition: transform .18s ease;
}
.brand:hover .brand-logo { transform: scale(1.03); }

/* Sur un écran étroit, l'en-tête doit loger le menu, la marque, la recherche,
   la cloche et le compte. Le logo cède le premier — il reste reconnaissable
   bien plus bas que du texte ne le resterait. */
/* R442 : les paliers étroits gardent leur retrait. Sur un grand écran le logo
   occupe la hauteur entière parce que la place ne manque pas ; sur un
   téléphone, l'en-tête doit encore loger le menu, la recherche, la cloche et
   le compte — un logo pleine hauteur y prendrait une largeur qu'il faut
   ailleurs, le rapport de l'image étant de deux et demi. */
/* R447 — LES PALIERS AGISSENT SUR LA MESURE, non sur le logo seul. En
   réduisant l'un sans l'autre, on les aurait désaccordés dès le premier écran
   étroit — et c'est précisément l'accord qui était demandé. On abaisse donc la
   MESURE COMMUNE : la recherche et le logo descendent ensemble.
   Le logo étant large de près de trois fois sa hauteur, il faut bien qu'il
   cède sur un téléphone, où l'en-tête loge aussi le menu, la cloche et le
   compte. */
@media (max-width: 1024px) { :root { --h-recherche: 42px; } }
@media (max-width: 860px)  { :root { --h-recherche: 38px; } }
/* Sous ces largeurs, le logo se détache de la mesure commune : large de près
   de trois fois sa hauteur, il prendrait la place du champ de recherche, qui
   sert plus souvent que la marque. La recherche garde donc sa taille, le logo
   cède seul. */
@media (max-width: 640px)  { :root { --h-recherche: 36px; } .brand-logo { height: 27px; } }
@media (max-width: 420px)  { :root { --h-recherche: 34px; } .brand-logo { height: 23px; } }

/* Écran d'entrée : le logo y a toute la place, il peut respirer. */
.login-logo { height: 84px; width: auto; display: block; margin: 0 auto 6px; }
@media (max-width: 480px) { .login-logo { height: 66px; } }

/* Un titre caché à l'œil mais lu par les lecteurs d'écran. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* R444 — « Rester connecté » : une case dont on doit lire la conséquence. */
.rester-case { display: flex; align-items: flex-start; gap: 9px; margin: 2px 0 14px;
  cursor: pointer; font-size: 13.5px; }
.rester-case input { margin-top: 3px; flex-shrink: 0; }
.rester-case small { display: block; color: var(--muted); font-size: 12px;
  line-height: 1.5; margin-top: 2px; }

/* R455 — Le rappel de redémarrage après écriture de php.ini. Teinté comme un
   avertissement : ce n'est pas une erreur, mais rien ne prendra effet tant
   qu'on n'aura pas agi. */
.msg-avert { display: flex; align-items: flex-start; gap: 10px;
  border: 1px solid var(--warn, #B4771F); background: #FDF5E6;
  border-radius: 10px; padding: 11px 13px; font-size: 13.5px; line-height: 1.6; }
.msg-avert svg { color: #8A5A12; flex-shrink: 0; margin-top: 2px; }
.msg-avert code { background: #fff; padding: 1px 5px; border-radius: 4px; }

/* R460 — La procédure de php.ini : repliée par défaut, lisible une fois ouverte. */
.proc-php { margin: 10px 0 0; border: 1px solid var(--line2); border-radius: 9px;
  background: var(--bg); }
.proc-php > summary { cursor: pointer; padding: 8px 12px; font-size: 12.5px;
  color: var(--ink); display: flex; align-items: center; gap: 7px; list-style: none; }
.proc-php > summary::-webkit-details-marker { display: none; }
.proc-php > summary::after { content: '▾'; margin-inline-start: auto; color: var(--muted); }
.proc-php[open] > summary::after { content: '▴'; }
.proc-php > summary:hover { background: var(--paper2, #fff); border-radius: 9px; }
.proc-corps { padding: 2px 14px 12px; font-size: 12.5px; line-height: 1.7; color: var(--texte2, #444); }
.proc-corps p { margin: 0 0 9px; }
.proc-tete { font-weight: 600; color: var(--ink); margin: 10px 0 5px !important; }
.proc-corps ol { margin: 0 0 8px; padding-inline-start: 20px; }
.proc-corps li { margin: 0 0 5px; }
.proc-corps code { background: var(--paper2, #fff); padding: 1px 5px; border-radius: 4px;
  font-size: 12px; border: 1px solid var(--line); }
.proc-lignes { display: block; background: var(--paper2, #fff); border: 1px solid var(--line);
  border-radius: 6px; padding: 7px 10px; margin: 6px 0; }

/* R493 — L'unité collée au champ. Le mot est posé PAR-DESSUS le champ, à
   droite, et la saisie s'arrête avant lui : sans cette marge, un nombre long
   passerait dessous et deviendrait illisible. */
.champ-unite { position: relative; display: block; }
.champ-unite > input { width: 100%; padding-inline-end: 46px; }
.champ-unite-mot {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  font-size: 13px; color: var(--muted); pointer-events: none;
}

/* R504 — La colonne du dossier dans le journal. Un chemin long ne doit pas
   écarter les autres colonnes : on borne sa largeur et l'on coupe proprement,
   l'infobulle donnant le chemin entier. */
.jrn-chemin { max-width: 230px; }
.jrn-chemin a { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* R508 — Le journal tient dans la largeur. La date passe sur deux lignes, les
   noms sont coupés par le milieu, et l'on ôte le repli automatique qui
   élargissait les colonnes. */
.jrn-quand { white-space: nowrap; line-height: 1.3; }
.jrn-quand .jrn-jour  { display: block; }
.jrn-quand .jrn-heure { display: block; font-size: 11px; color: var(--muted); }
.jrn-chemin { max-width: 210px; }
.jrn-chemin a { display: inline; white-space: nowrap; }

/* R511 — Le bouton d'envoi pendant l'attente. L'icône tourne à sa place :
   remplacer le bouton par autre chose ferait sauter la fenêtre au moment
   précis où l'on attend qu'elle ne bouge plus. */
.btn.en-attente { opacity: .78; cursor: progress; }
.btn.en-attente svg { animation: spin 900ms linear infinite; transform-origin: 50% 50%; }

/* R527 — les versions d'une pièce : une liste, la version actuelle mise en
   avant, les gestes à droite. Même vocabulaire que le reste des listes. */
.versions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--e2); }
.versions .version { display: flex; align-items: center; gap: var(--e3); padding: var(--e2) var(--e3); border: 1px solid var(--line); border-radius: 10px; background: var(--panel); }
.versions .version.actuelle { border-color: var(--sel); background: var(--sel-bg); }   /* R578 : la version actuelle, en bleu de sélection */
.versions .version.actuelle .vcorps b { color: var(--sel-dark); }
.versions .version.actuelle .vmeta, .versions .version.actuelle .vnote { color: var(--sel-dark); opacity: .85; }
.versions .version.actuelle .tag-ext { background: #fff; color: var(--sel-dark); }
.versions .vnum { flex: none; width: 34px; height: 34px; border-radius: 50%; background: var(--line2); color: #fff; font-weight: 700; font-size: 12px; display: inline-flex; align-items: center; justify-content: center; }
.versions .version.actuelle .vnum { background: var(--sel); }
.versions .vcorps { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.versions .vmeta { font-size: 12px; color: var(--muted); overflow-wrap: anywhere; }
.versions .vmeta .tag-ext { font-size: 10px; }
.versions .vextrait { font-size: 12px; color: var(--ink); }
.versions .vactions { flex: none; display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.versions .vactions form { display: inline; }
.chip.chip-version { background: var(--sel-bg); color: var(--sel-dark); border: 1px solid var(--sel); font-weight: 500; }   /* R585 : la pastille des versions, dans le bleu de la sélection (comme la version regardée) */
@media (max-width: 700px) {
  .versions .version { flex-wrap: wrap; }
  .versions .vactions { width: 100%; justify-content: flex-start; }
}

/* R540 — les commentaires d'une pièce : composeur en tête, fil en dessous,
   avatars aux initiales, version et heure discrètes, trace des suppressions. */
.com-avatar { flex: none; width: 36px; height: 36px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; color: #fff; background: var(--seal); letter-spacing: .02em; }
.com-avatar.t1 { background: #2F5D8A; } .com-avatar.t2 { background: #8A5A2F; } .com-avatar.t3 { background: #5A3E8A; }
.com-avatar.t4 { background: #1F7A4D; } .com-avatar.t5 { background: #A33A22; }
.com-composeur { display: flex; gap: var(--e3); align-items: flex-start; padding: var(--e3); border: 1px solid var(--line); border-radius: 12px; background: var(--paper); margin-bottom: var(--e4); }
.com-saisie { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--e2); }
.com-saisie textarea { width: 100%; min-height: 44px; resize: vertical; border: 1px solid var(--line2); border-radius: 10px; padding: 10px 12px; font: inherit; font-size: 14px; background: var(--panel); }
.com-saisie textarea:focus { outline: none; border-color: var(--seal); box-shadow: 0 0 0 3px var(--seal-soft); }
.com-outils { display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap; }
.com-outils .com-hint { font-size: 12px; margin-inline-end: auto; }
.com-photo { cursor: pointer; }
.com-apercu-image { display: flex; align-items: center; gap: var(--e2); }

/* ---- R1353 : taguer quelqu'un dans un commentaire -------------------------
   La liste FLOTTE sous le champ : elle ne doit pas pousser le composeur, sinon
   le bouton « Publier » se dérobe sous le doigt au moment où l'on tape. */
.com-zone { position: relative; }
.choix-mention { position: absolute; left: 0; right: 0; top: calc(100% + 5px); z-index: 30;
  background: var(--panel); border: 1px solid var(--line2); border-radius: 11px;
  box-shadow: var(--shadow-pop); overflow: hidden; }
.choix-mention ul { list-style: none; margin: 0; padding: 4px; max-height: 236px; overflow: auto; }
.choix-mention li { display: flex; align-items: center; gap: 10px; padding: 7px 9px;
  border-radius: 8px; cursor: pointer; }
.choix-mention li.actif { background: var(--seal-ghost); box-shadow: inset 0 0 0 2px var(--seal-soft); }
.choix-qui { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.choix-qui b { font-size: 14px; }
.choix-role { font-size: 12px; color: var(--muted); }
.choix-arob { font-size: 12px; color: var(--faint); font-family: ui-monospace, Menlo, Consolas, monospace; }
.choix-vide { margin: 0; padding: 13px; font-size: 13.5px; color: var(--muted); text-align: center; }
/* Sur un écran étroit, le nom de compte se télescopait avec le rôle. Il n'est
   pas ce qui sert à choisir : c'est le nom de la personne. */
@media (max-width: 560px) { .choix-arob { display: none; } }

/* Ce que l'on saura AVANT de publier : la conséquence s'écrit avant le geste. */
.com-prevenus { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px;
  background: var(--info-bg); border: 1px solid #BEE0D4; border-radius: 9px;
  padding: 7px 11px; color: var(--seal-dark); }
.com-avatar.sm { width: 26px; height: 26px; font-size: 11px; }

/* La pastille d'une mention dans le fil. Bleu : ce qui DÉSIGNE (R573).
   Ambre : ce qui vous désigne VOUS (R1050) — on repère sa propre mention
   d'un coup d'œil dans un fil long. */
.mention { background: var(--sel-bg); border: 1px solid var(--sel-line); color: var(--sel-dark);
  border-radius: 6px; padding: 1px 6px; font-weight: 600; white-space: nowrap; }
.mention.moi { background: #FFF3D6; border-color: #E9CE86; color: #7A5600; }

/* R1354 — une pastille d'état qui MÈNE quelque part. Elle garde l'aspect de
   toutes les autres : c'est une pastille, non un bouton — c'était le but. */
.chip-lien { text-decoration: none; }
.chip-lien:hover .chip { filter: brightness(.96); }
.chip-lien:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; border-radius: 99px; }

/* ---- R1355 : découper un lot ---------------------------------------------
   Une pièce par ligne, sa barre de couleur à gauche pour qu'on voie d'un coup
   d'œil combien il y en a. Une pièce FUSIONNÉE ne disparaît pas — elle pâlit
   et se décale : on doit pouvoir revenir sur son geste. */
.seg-lot { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.seg-piece { display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; background: var(--paper2); }
.seg-piece.a-confirmer { border-color: #E9CE86; background: var(--warn-bg); }
/* R1356 — une coupe posée par la personne se voit : c'est la sienne. */
.seg-piece.a-main { border-color: var(--seal); box-shadow: inset 3px 0 0 var(--seal); }
.seg-bar { flex: none; width: 4px; align-self: stretch; min-height: 34px; border-radius: 2px; background: var(--seal); }
.seg-bar.t1 { background: #2F5D8A; } .seg-bar.t2 { background: #8A5A2F; }
.seg-bar.t3 { background: #5A3E8A; } .seg-bar.t4 { background: #1F7A4D; }
.seg-bar.t5 { background: #A33A22; }
.seg-corps { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.seg-nom input { width: 100%; border: 1px solid var(--line2); border-radius: 8px; padding: 6px 9px;
  font: inherit; font-size: 14px; font-weight: 600; background: var(--panel); color: var(--ink); }
.seg-nom input:focus { outline: none; border-color: var(--seal); box-shadow: 0 0 0 3px var(--seal-soft); }
.seg-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 12px; }
.seg-pourquoi { font-style: italic; font-size: 11.5px; }
/* ── R1356 · LES PAGES D'UNE PIÈCE, POUR RÉGLER LA COUPE À LA MAIN ──────
   Chaque page montre son numéro et sa première ligne. Cliquer un numéro dit
   « un nouveau document commence ici ». La première page d'une pièce n'est
   pas cliquable : c'est déjà une coupe. */
.seg-pages { list-style: none; margin: 4px 0 0; padding: 0; display: flex;
  flex-direction: column; gap: 1px; }
.seg-page { display: flex; align-items: baseline; gap: 8px; min-width: 0;
  padding: 2px 0; font-size: 12px; }
.seg-pnum { flex: none; min-width: 26px; height: 20px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px; font-size: 11.5px; font-variant-numeric: tabular-nums;
  background: var(--panel); border: 1px solid var(--line2); color: var(--muted);
  text-decoration: none; }
.seg-page.est-debut .seg-pnum { background: var(--seal-soft); border-color: var(--seal);
  color: var(--seal); font-weight: 700; }
a.seg-pnum.coupable:hover, a.seg-pnum.coupable:focus-visible {
  background: var(--seal); border-color: var(--seal); color: #fff; outline: none; }
a.seg-pnum.coupable:focus-visible { box-shadow: 0 0 0 3px var(--seal-soft); }
.seg-ptxt { flex: 1 1 auto; min-width: 0; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* R1357 — un geste EMPÊCHÉ se montre, en retrait : il paraît, il ne promet
   pas. Le cacher rendait la fonction introuvable. */
.btn.empeche { opacity: .72; border-style: dashed; }
.card.seg-empeche h2 { display: flex; align-items: center; gap: 8px; margin-top: 0; }
.card.seg-empeche .btn { margin-inline-end: 8px; }
/* R1356 — LE BANDEAU « ce lot attend votre découpage », en tête de fiche.
   Il se retire d'un clic : un rappel qu'on ne peut pas taire devient un
   reproche. */
.seg-bandeau { display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  margin: var(--e3) 0 0; padding: 10px 13px; border-radius: 10px;
  border: 1px solid var(--seal); background: var(--seal-soft); }
.seg-b-ic { flex: none; display: inline-flex; color: var(--seal); }
.seg-b-txt { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.seg-b-txt b { font-size: 13.5px; }
.seg-b-txt span { font-size: 12.5px; color: var(--muted); }
.seg-b-non { margin: 0; }
/* La réponse donnée à l'import quand on ne peut pas mener au découpage. */
.seg-note { display: block; font-size: 12.5px; color: var(--muted); }
/* Le rappel « vous avez réglé vous-même », avec le chemin du retour. */
/* R1368 — LE BANDEAU TEINTÉ DEVIENT UNE SIMPLE LIGNE. Il enveloppait un
   lien écrit en petit ; maintenant qu'il porte un BOUTON, le fond vert le
   faisait passer pour un message d'information qu'on ne clique pas — et
   « .seg-regle a { color: inherit } » écrasait jusqu'à la couleur du
   bouton. La ligne ne fait plus que poser le bouton et sa suite. */
.seg-regle { display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap;
  margin: 0 0 var(--e3); font-size: 12.5px; }
.seg-regle > .btn { flex: none; }
/* La note qui explique pourquoi la lecture se verrouille quand on découpe. */
.lec-lie { color: #7A4A00; }
.com-apercu-image img { max-height: 120px; max-width: 220px; border-radius: 8px; border: 1px solid var(--line); object-fit: cover; }
.com-fil { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--e3); }
.com { display: flex; gap: var(--e3); align-items: flex-start; }
.com-corps { flex: 1 1 auto; min-width: 0; background: var(--paper); border: 1px solid var(--line); border-radius: 12px; padding: 10px 14px; }
.com-tete { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.com-tete time { font-size: 12px; }
.com-tete .com-suppr { margin-inline-start: auto; }
.chip.com-version { font-size: 10px; }
.com-texte { margin-top: 4px; font-size: 14px; line-height: 1.45; overflow-wrap: anywhere; }
.com-texte a { color: var(--seal-dark); text-decoration: underline; }
.com-image { display: inline-block; margin-top: var(--e2); }
.com-image img { max-width: 320px; max-height: 240px; border-radius: 10px; border: 1px solid var(--line); object-fit: cover; display: block; }
.com.supprime .com-corps { background: transparent; border-style: dashed; }
.com-trace { margin: 2px 0 0; font-size: 13px; }
@media (max-width: 600px) { .com-image img { max-width: 100%; } .com-tete .com-suppr { margin-inline-start: 0; } }
.com-image-relais { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--seal-dark); text-decoration: underline; }
.chip.chip-com { gap: 3px; }

/* R545 — le mot discret d'une mise à jour venue d'ailleurs */
.kz-maj { position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 14px); opacity: 0; background: var(--ink); color: #fff;
  padding: 8px 14px; border-radius: 999px; font-size: 12.5px; box-shadow: 0 6px 18px rgba(0,0,0,.18); z-index: 80; pointer-events: none;
  transition: opacity .25s ease, transform .25s ease; max-width: 92vw; text-align: center; }
.kz-maj.on { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) { .kz-maj { transition: none; } }
.kz-maj.durable { pointer-events: auto; background: #8A2E1C; }
.kz-maj-lien { color: #fff; text-decoration: underline; font-weight: 700; }
/* R549 — le bouton de suppression d'une ancienne version : discret, rouge à l'approche */
.btn.danger.ghost { background: transparent; border-color: transparent; color: var(--err); }   /* R562 : le rouge de la palette */
.btn.danger.ghost:hover { background: var(--err-bg); border-color: #E8C4C0; color: var(--err); }
/* R551 — le texte extrait, par version : une rangée de pastilles cliquables */
.texte-versions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 0 0 var(--e3); font-size: 12px; }
.texte-versions .chip { text-decoration: none; cursor: pointer; }
.texte-versions .chip { font-weight: 500; }   /* R586 : jamais de gras sur les pastilles de version */
.texte-versions .chip.seal { background: var(--sel-bg); color: var(--sel-dark); box-shadow: inset 0 0 0 1px var(--sel); font-weight: 500; }   /* R573 : la version regardée, en bleu ; R586 : liseré fin, sans gras */
.texte-versions .chip.info:hover { background: var(--sel-bg); color: var(--sel-dark); }
/* R556 — bouton « contour » : bordure et texte de la maison, fond transparent */
.btn.outline { background: transparent; border: 1px solid var(--seal); color: var(--seal); font-weight: 600; }   /* R581 : bordure fine, comme tous les boutons — règle du projet */
.btn.outline:hover { background: var(--seal-soft); color: var(--seal-dark); border-color: var(--seal-dark); }
.btn.outline:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; }
/* R581 — RÈGLE DU PROJET : une bordure de bouton, d'encart ou de champ fait 1 px ;
   l'épaisseur ne dit rien que la couleur ne dise déjà. Les contours de focus
   (accessibilité clavier) restent à 2 px : ils doivent se voir de loin. */
/* R559 — la note de version sur sa propre ligne, avec son étiquette */
.versions .vnote { display: block; margin-top: 3px; font-size: 12.5px; color: var(--ink); overflow-wrap: anywhere; }
.versions .vnote .k { color: var(--muted); font-weight: 600; margin-inline-end: 6px; }
.versions .vnote .k::after { content: ' :'; }

/* R563 → R573 — LE CIRCUIT DE VALIDATION, REFONDU : moins de boîtes pleines, plus
   d'air ; l'état se dit par un point, une barre latérale et un fond doux. */
/* pastilles d'état : une seule famille (point + fond doux + mot) */
/* R603 — l'état ne crie pas : jamais de gras, et un signe qui dit ce qu'il est
   (coche validée, croix refusée, point pour ce qui attend ou n'est plus valable). */
.chip.val-attente, .chip.val-ok, .chip.val-refus, .chip.val-depasse, .chip.val-annule { display: inline-flex; align-items: center; gap: 6px; border: 0; font-weight: 500; font-size: 12px; }   /* R616 : plus de gras du tout — la taille et la couleur portent */
.chip.val-attente::before, .chip.val-ok::before, .chip.val-refus::before, .chip.val-depasse::before, .chip.val-annule::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.chip.val-attente, .val-attente { background: #FDF4E3; color: #8A5A08; }
.chip.val-ok, .val-ok { background: var(--seal-soft); color: var(--seal-dark); }
/* R576 → R603 — un signe par état : ✔ validée, ✕ refusée ; les autres gardent leur point */
.chip.val-ok::before { content: '✔'; width: auto; height: auto; border-radius: 0; background: none; font-size: 11px; line-height: 1; }
.chip.val-refus::before { content: '✕'; width: auto; height: auto; border-radius: 0; background: none; font-size: 11px; line-height: 1; font-weight: 700; }
.chip.val-refus, .val-refus { background: var(--err-bg); color: var(--err); }
.chip.val-depasse, .val-depasse { background: #FAF3E1; color: #7A5A0E; }
.chip.val-annule, .val-annule { background: var(--paper); color: var(--muted); }
/* A · la carte de validation sous le titre (R584, V3) : icône ronde, état, détail, lien */
.val-carte { display: inline-flex; align-items: center; gap: 12px; margin-top: 10px; padding: 8px 14px 8px 10px; border-radius: 12px; border: 1px solid var(--line); background: var(--panel); text-decoration: none; color: var(--ink); max-width: 100%; }
.val-carte { cursor: pointer; }   /* R604 : toute la carte est cliquable */
.val-carte:hover { border-color: var(--line2); background: var(--paper); }
.val-carte:hover .val-carte-lien { text-decoration: underline; }
.val-carte:focus-visible { outline: 2px solid var(--sel); outline-offset: 2px; }
.val-carte-ic { flex: none; width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; }
.val-carte-corps { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.val-carte-corps b { font-size: 14px; font-weight: 500; }   /* R616 : plus de gras du tout */
.val-carte-corps small { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60vw; }
.val-carte-lien { flex: none; margin-inline-start: 8px; font-size: 12px; font-weight: 600; color: var(--seal); }   /* R617 */
.val-carte.val-ok .val-carte-ic { background: var(--seal-soft); color: var(--seal-dark); } .val-carte.val-ok b { color: var(--seal-dark); }
.val-carte.val-attente .val-carte-ic { background: #FDF4E3; color: #8A5A08; } .val-carte.val-attente b { color: #8A5A08; }
.val-carte.val-refus .val-carte-ic { background: var(--err-bg); color: var(--err); } .val-carte.val-refus b { color: var(--err); }
.val-carte.val-depasse .val-carte-ic { background: #FAF3E1; color: #7A5A0E; } .val-carte.val-depasse b { color: #7A5A0E; }
.val-carte.val-attente, .val-carte.val-ok, .val-carte.val-refus, .val-carte.val-depasse { background: var(--panel); color: var(--ink); }
@media (max-width: 600px) { .val-carte { width: 100%; } .val-carte-corps small { white-space: normal; max-width: none; } }
/* B · la tête de l'onglet, le message, la timeline */
/* R608 — la tête du circuit : un titre, puis des faits en lignes étiquetées */
.val-tete { padding: 12px 16px; border-radius: 10px; background: var(--paper); margin-bottom: 12px; }
.val-tete-haut { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.val-tete-haut b { font-size: 15px; font-weight: 500; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }   /* R616 : plus de gras du tout */
.val-tete-faits { display: grid; grid-template-columns: auto 1fr; gap: 3px 0; margin: 0; font-size: 12.5px; }
.val-tete-faits > div { display: contents; }
.val-tete-faits dt { color: var(--muted); font-weight: 600; padding-inline-end: 14px; white-space: nowrap; }
.val-tete-faits dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
@media (max-width: 600px) { .val-tete-faits { grid-template-columns: 1fr; } .val-tete-faits dt { padding: 4px 0 0; } }
.val-message { margin: 0 0 var(--e3); font-size: 12.5px; color: var(--muted); font-style: italic; }
.val-etapes { list-style: none; margin: 0 0 var(--e3); padding: 0 0 0 4px; position: relative; }
.val-etapes::before { content: ''; position: absolute; left: 21px; top: 22px; bottom: 22px; width: 2px; background: var(--line); }
.val-etape { display: flex; align-items: flex-start; gap: 14px; padding: 8px 0 10px; position: relative; }
.val-etape .com-avatar { width: 36px; height: 36px; flex: none; position: relative; z-index: 1; }
.val-etape.attente .com-avatar, .val-etape.passe .com-avatar { background: #BEC4C0; }
.val-etape.tour .com-avatar { box-shadow: 0 0 0 3px var(--panel), 0 0 0 6px #D9A400; }
.val-etape.ok .com-avatar::after { content: '✔'; position: absolute; right: -6px; bottom: -4px; width: 16px; height: 16px; border-radius: 50%; background: var(--seal-dark); color: #fff; font-size: 10px; line-height: 16px; text-align: center; }
.val-etape.refus .com-avatar::after { content: '✕'; position: absolute; right: -6px; bottom: -4px; width: 16px; height: 16px; border-radius: 50%; background: var(--err); color: #fff; font-size: 10px; line-height: 16px; text-align: center; }
.val-etape.passe { opacity: .6; }
.val-corps { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; padding-top: 2px; }
.val-corps b { font-size: 14px; font-weight: 500; }   /* R617 : le nom du validateur sans gras, comme les autres blocs du circuit */
.val-corps .muted { font-size: 12px; }
.val-etape.tour .val-corps .muted { color: #8A5A08; }
.val-etape.ok .val-corps .muted { color: var(--seal-dark); }
.val-etape.refus .val-corps .muted { color: var(--err); }
.val-corps i { display: inline-block; font-style: normal; font-size: 12.5px; background: var(--paper); border-radius: 8px; padding: 4px 10px; margin-top: 2px; align-self: flex-start; }
.val-etape > form { flex: none; margin-top: 4px; }
/* « C'est votre tour » */
.val-gestes { position: relative; padding: 14px 16px 14px 22px; border-radius: 12px; background: var(--seal-soft); margin-bottom: var(--e3); }
.val-gestes::before { content: ''; position: absolute; left: 0; top: 10px; bottom: 10px; width: 5px; border-radius: 3px; background: var(--seal); }
.val-gestes .sub { color: var(--seal-dark); margin: 0 0 10px; }
.val-gestes .sub b { font-size: 15px; display: block; margin-bottom: 2px; }
.val-gestes .lec-label { margin-bottom: 10px; }
.val-gestes .lec-label input { background: var(--panel); }
/* R605 — DANS « C'EST VOTRE TOUR », LES DEUX GESTES ONT LA MÊME TAILLE. La
   règle des fenêtres étire le bouton principal sur toute la largeur restante
   (elle a du sens dans une fenêtre étroite) ; ici, « Valider » écrasait
   « Refuser » — un geste irréversible ne doit pas être quatre fois plus gros
   que son contraire. */
.val-gestes .lec-actions .btn { flex: 0 0 auto; min-width: 150px; }
.val-pied { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: var(--e3); }
.val-h3 { font-size: 13px; margin: var(--e3) 0 8px; color: var(--muted); font-weight: 600; }   /* R617 */
.val-trace { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; }
.val-trace li { display: flex; gap: 10px; align-items: baseline; }
.val-trace time { flex: none; width: 92px; font-family: ui-monospace, "Consolas", "Courier New", monospace; font-variant-numeric: tabular-nums; font-size: 12px; color: var(--muted); }
.val-trace .val-glyphe { flex: none; width: 16px; text-align: center; color: var(--seal-dark); font-weight: 700; }
.val-histo { list-style: none; margin: 0; padding: 0; font-size: 12.5px; display: flex; flex-direction: column; gap: 6px; }
details.val-histo-det summary { cursor: pointer; font-size: 13px; color: var(--muted); font-weight: 600; margin: var(--e3) 0 8px; }   /* R617 */
/* C · la fenêtre de lancement */
.val-mode { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.val-mode .k { display: none; }
.val-radio { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--line); background: var(--panel); cursor: pointer; font-size: 13px; }
.val-radio .val-ic { font-size: 20px; color: var(--muted); flex: none; width: 24px; text-align: center; }
.val-radio .val-lib { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; }
.val-radio .val-lib b { font-size: 13px; } .val-radio .val-lib small { color: var(--muted); font-size: 11px; }
.val-radio input { margin: 0; accent-color: var(--sel); }
.val-radio.on { background: var(--sel-bg); border: 1px solid var(--sel); }   /* R573 : le mode retenu, en bleu ; R579 : bordure fine */
.val-radio.on .val-ic { color: var(--sel); } .val-radio.on .val-lib b { color: var(--sel-dark); }
p.k { font-weight: 600; font-size: 13px; }   /* R617 */
.val-liste { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; min-height: 0; }   /* R588 : la liste vient APRÈS le champ d'ajout */
.val-liste li { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); }
.val-liste .val-num { display: none; }   /* R580 : plus de numéro — l'ordre se lit dans la liste elle-même */
.val-liste .val-qui { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; } .val-liste .val-qui small { color: var(--muted); }
.val-liste .val-qui b { font-weight: 500; }   /* R618 : le nom d'un validateur choisi, sans gras */
.val-liste .chip { font-size: 11px; white-space: nowrap; background: transparent; padding: 0; font-weight: 500; }   /* R617 */
.val-liste .chip::before { display: none; }   /* R580 : pas de point devant le courriel */
.val-liste .chip.ok { color: var(--seal-dark); } .val-liste .chip.warn { color: #8A5A08; }
.val-outils { display: flex; gap: 4px; }
.val-outils .btn { width: 26px; height: 26px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border-radius: 7px; border: 0; background: var(--paper); color: var(--muted); font-size: 11px; }
.val-outils .btn:hover { background: var(--line); transform: none; }
.val-outils .btn.danger { color: var(--err); } .val-outils .btn.danger:hover { background: var(--err-bg); }
.val-outils .btn[disabled] { opacity: .35; }
/* R597 — le choix d'un validateur : recherche pleine largeur, liste de cinq */
.val-choix { position: relative; margin-bottom: 10px; }
.val-choix-champ { width: 100%; height: var(--ctl); border: 1px solid var(--line); border-radius: 10px; padding: 0 12px; background: var(--panel); font: inherit; font-size: 13px; }
.val-choix-champ:focus { outline: none; border-color: var(--sel); box-shadow: 0 0 0 3px var(--sel-bg); }
.val-choix-liste { position: absolute; z-index: 60; inset-inline-start: 0; inset-inline-end: 0; top: calc(100% + 4px); margin: 0; padding: 4px;
  list-style: none; background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 10px 24px rgba(33,48,46,.14); max-height: 232px; overflow-y: auto; }
.val-choix-liste li { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: 8px; cursor: pointer; }
.val-choix-liste li:hover, .val-choix-liste li.vise { background: var(--sel-bg); }
.val-choix-liste .com-avatar { width: 28px; height: 28px; font-size: 11px; flex: none; }
.val-choix-qui { display: flex; flex-direction: column; min-width: 0; }
.val-choix-qui b { font-size: 13px; font-weight: 500; } .val-choix-qui small { font-size: 11px; color: var(--muted); }   /* R618 */
.val-choix-vide { color: var(--muted); font-size: 12.5px; cursor: default; padding: 10px; }
.val-choix-vide:hover { background: transparent; }
.val-options { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; } .val-options .lec-label { margin-bottom: 0; }
.val-options select { height: var(--ctl); border: 1px solid var(--line); border-radius: 8px; padding: 0 12px; background: var(--paper); font: inherit; font-size: 13px; }
.val-avert { position: relative; margin-top: 14px; padding: 9px 12px 9px 18px; border-radius: 9px; background: #FDF4E3; color: #7A5008; font-size: 12.5px; }
.val-avert::before { content: ''; position: absolute; left: 6px; top: 8px; bottom: 8px; width: 4px; border-radius: 2px; background: #B8860B; }
.val-avert.on { display: block; }
@media (max-width: 600px) { .val-mode, .val-options { grid-template-columns: 1fr; } .val-liste li { flex-wrap: wrap; } .val-liste .chip { white-space: normal; } .val-etapes::before { display: none; } }
/* D · la page Validations : des cartes-lignes */
.val-table { display: flex; flex-direction: column; gap: 10px; }
.val-row { display: flex; align-items: center; gap: 14px; padding: 12px 16px 12px 20px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); position: relative; }
.val-row.urgent::before { content: ''; position: absolute; left: 6px; top: 10px; bottom: 10px; width: 5px; border-radius: 3px; background: #D9A400; }
.val-corps-ligne { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.val-titre { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 15px; }
.val-titre a { color: var(--ink); font-weight: 500; text-decoration: none; } .val-titre a:hover { color: var(--seal-dark); }   /* R617 : sans gras, comme partout dans le circuit */
/* R667 — UN TITRE D'UN SEUL MOT NE POUSSE PLUS LA PAGE. Une référence de
   scan, une adresse collée, un titre de cent quatre-vingt-dix signes sans
   espace : le lien ne pouvait pas se couper et la liste s'étirait à deux mille
   pixels. On autorise la coupure n'importe où — c'est le seul réglage qui
   permet à la ligne de RÉTRÉCIR sous la largeur de son plus long mot. */
.val-titre a, .val-meta { overflow-wrap: anywhere; min-width: 0; }
.val-meta { font-size: 12px; color: var(--muted); }
.val-ech { flex: none; font-size: 12px; color: var(--muted); }
.val-ech.urgent { color: #8A5A08; font-weight: 600; }   /* R617 */
.val-actions { flex: none; display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
.val-attend { display: inline-flex; align-items: center; gap: 6px; margin-inline-end: 10px; }
.val-attend .com-avatar { width: 24px; height: 24px; font-size: 10px; }
.val-vide { display: flex; align-items: center; gap: 18px; padding: 22px 24px; border-radius: 12px; background: var(--paper); }
.val-vide .val-vide-ic { font-size: 34px; color: var(--seal); font-weight: 700; }
.val-vide b { display: block; font-size: 15px; margin-bottom: 2px; } .val-vide span { color: var(--muted); font-size: 12.5px; }
/* R607 — le compte d'un onglet reprend le vert de la maison (celui du fond de
   l'onglet ouvert) et non le bleu de la sélection. */
.tabs .compte { display: inline-block; min-width: 18px; padding: 0 6px; margin-inline-start: 6px; border-radius: 999px; background: var(--seal); color: #fff; font-size: 11px; text-align: center; }
.tabs button.on .compte, .tabs > a.on .compte { background: #fff; color: var(--seal-dark); }
@media (max-width: 800px) { .val-row { flex-wrap: wrap; } .val-actions { width: 100%; justify-content: flex-start; } }

.menu-compte { display: inline-block; min-width: 18px; padding: 0 5px; margin-inline-start: 6px; border-radius: 999px; background: var(--seal); color: #fff; font-size: 11px; text-align: center; }
/* R606 — « À valider » est une ALERTE, pas une réussite : la pastille reprend
   exactement le fond et la teinte de la cloche (l'ambre des choses à faire).
   Le vert reste à ce qui est validé. */
.badgebtn.badge-val { color: var(--warn); background: var(--warn-bg); }
/* R785 : cette règle vient APRÈS le survol général et l'écrasait — « À valider »
   et « À répondre » ne réagissaient pas du tout. On lui donne la même
   précision : toutes les pastilles se marquent de la même façon. */
.badgebtn.badge-val:hover { background: #F8E9CE; color: var(--warn); }
.badgebtn.badge-val .badge-txt { font-weight: 600; font-size: 12.5px; }
/* R782 — LE NOMBRE PORTE PARTOUT LE MÊME HABIT. Seules « À valider » et
   « À répondre » avaient leur pastille ronde ; « À vérifier » et « En lecture »
   montraient un chiffre nu, comme s'ils comptaient autre chose. Quatre voisines
   qui disent la même chose — voilà ce qui vous attend — doivent le dire de la
   même façon. */
.badgebtn.badge-val b,
.badgebtn.badge-ocr b,
.badgebtn.badge-lire b { background: var(--warn); color: #fff; border-radius: 999px; padding: 1px 7px; font-size: 12px; }
@media (max-width: 700px) { .badgebtn .badge-txt { display: none; } }
.u-mail.ok { color: var(--seal-dark); } .u-mail.absent { color: #B8860B; font-weight: 600; } .u-mail.invalide { color: var(--err); font-weight: 600; }
/* R568 — l'adresse de courriel d'un compte : le lien de la ligne et l'état du champ */
.lien-courriel { background: none; border: none; padding: 0; margin-inline-start: 8px; font: inherit; font-size: 12px; font-weight: 700; color: var(--seal); text-decoration: underline; cursor: pointer; }
.lien-courriel:hover { color: var(--seal-dark); }
.courriel-etat { margin: 6px 0 0; font-size: 12.5px; min-height: 18px; }
.courriel-etat.bon { color: var(--seal-dark); } .courriel-etat.vide { color: #B8860B; } .courriel-etat.mauvais { color: var(--err); }
/* R573 — la fenêtre « Valider » de la page : l'aperçu à gauche, le reste à droite */
.val-confirm { display: flex; gap: 16px; align-items: flex-start; }
.val-confirm-apercu { flex: none; width: 110px; height: 90px; border-radius: 10px; background: var(--paper); border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.val-confirm-apercu img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.val-confirm-corps { flex: 1 1 auto; min-width: 0; }
@media (max-width: 600px) { .val-confirm { flex-direction: column; } }

/* R574 — LA BARRE DES ONGLETS DE LA FICHE RESTE EN VUE. Collée sous l'en-tête
   de l'application quand on défile (comme la barre de filtres, R519) : fond
   plein, même géométrie, une ombre nette quand elle flotte au-dessus du
   contenu. Sous 600 px, elle défile horizontalement sans déborder. */
.tabs-colle { position: sticky; top: var(--h-topbar, 55px); z-index: 30; background: var(--bg); padding: 8px 0 6px; margin: 0 0 10px; transition: box-shadow .2s ease; }
.tabs-colle .tabs { margin: 0; }
.tabs-colle.collee { box-shadow: 0 8px 22px rgba(33,48,46,.12); }
@media (prefers-reduced-motion: reduce) { .tabs-colle { transition: none; } }
/* R577 — bouton « icône seule » : carré, même hauteur que les autres boutons */
.btn.icon-only { padding: 0; width: 36px; justify-content: center; }
.btn.icon-only svg { margin: 0; }
/* R588 — le point d'aide « ? » et sa bulle */
/* R596 — l'étiquette et son « ? » tiennent sur une ligne (une étiquette est
   une colonne : sans ce conteneur, le « ? » passait à la ligne suivante). */
.lec-titre { display: inline-flex; align-items: center; gap: 6px; flex-wrap: nowrap; white-space: nowrap; position: relative; }
.lec-titre .muted { font-weight: 400; }
.aide-pt { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-inline-start: 0; padding: 0;
  border: 1px solid var(--line2); border-radius: 50%; background: var(--paper); color: var(--muted);
  font: inherit; font-size: 10px; font-weight: 700; line-height: 1; cursor: pointer; vertical-align: 1px; }
.aide-pt:hover, .aide-pt[aria-expanded="true"] { border-color: var(--seal); color: var(--seal); background: var(--seal-soft); }
/* R638 : la même langue pour les bulles d'aide — fond papier, liseré fin. */
.aide-bulle { position: absolute; z-index: 70; top: 100%; inset-inline-start: 0; inset-inline-end: auto; margin-top: 8px; width: max-content; max-width: min(320px, 100%);
  padding: 10px 12px; border-radius: 10px; background: var(--paper); border: 1px solid var(--line2); color: var(--ink); font-size: 12px; font-weight: 400;
  line-height: 1.5; white-space: normal; text-align: start; box-shadow: 0 8px 20px rgba(33,48,46,.12); }
.aide-bulle::before { content: ''; position: absolute; top: -6px; left: 14px; width: 10px; height: 10px; background: var(--paper);
  border-inline-start: 1px solid var(--line2); border-top: 1px solid var(--line2); transform: rotate(45deg); border-radius: 2px 0 0 0; }
.lec-label { position: relative; }
/* R599 — L'AIDE NE DÉBORDE PLUS. La bulle dessinée au survol sortait de la
   fenêtre et faisait apparaître une barre de défilement horizontale : le
   survol rend la main à l'infobulle du navigateur (attribut « title »), qui
   flotte au-dessus de tout sans rien déplacer. Le clic garde la bulle de la
   maison, désormais bornée à la largeur de la fenêtre. */
.aide-pt { position: relative; }
@media (max-width: 600px) { .aide-bulle { max-width: 78vw; } }
/* R620 — le mot de celui qui attend son tour : calme, informatif, sans geste */
.val-attente-mot { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border-radius: 12px;
  background: var(--paper); border: 1px solid var(--line); margin-bottom: var(--e3); }
.val-attente-mot .val-attente-ic { flex: none; font-size: 18px; color: var(--muted); line-height: 1.2; }
.val-attente-mot b { font-weight: 600; }
.val-attente-mot span { display: block; margin-top: 2px; font-size: 12.5px; color: var(--muted); }
.val-attente-mot span b { color: var(--ink); font-weight: 600; }
/* R620 — le mot adressé au validateur dont le tour n'est pas venu */
.val-mon-attente { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 var(--e3);
  padding: 11px 14px; border-radius: 10px; background: var(--paper); color: var(--ink); font-size: 12.5px; line-height: 1.55; }
.val-mon-attente svg { flex: none; margin-top: 2px; color: var(--muted); }
.val-mon-attente b { font-weight: 600; }

/* R622 — TABLETTE ET TÉLÉPHONE : chaque chose à sa largeur.
   Sous 900 px (tablette), les onglets serrent leur garniture et la barre
   collante suit ; sous 600 px (téléphone), ils prennent toute la largeur
   par deux, la barre d'actions s'étale, les fenêtres occupent l'écran. */
@media (max-width: 900px) {
  .tabs { gap: 3px; }
  .tabs button { padding: 8px 12px; font-size: 12.5px; }
  .tabs-colle { padding: 6px 0 5px; }
  .val-tete-faits { grid-template-columns: auto 1fr; }
  .val-row { gap: 10px; }
  .headrow .actions { gap: 6px; }
}
@media (max-width: 600px) {
  .tabs { gap: 4px; }
  .tabs button { flex: 1 1 calc(50% - 4px); padding: 9px 8px; font-size: 12.5px; text-align: center; white-space: normal; }
  .tabs button .compte { margin-inline-start: 4px; }
  .headrow .actions .btn { flex: 1 1 auto; justify-content: center; }
  .headrow .actions .btn.icon-only { flex: 0 0 auto; }
  .val-carte { width: 100%; }
  .val-etapes::before { inset-inline-start: 17px; }
  .val-etape { gap: 10px; }
  .val-etape .com-avatar { width: 30px; height: 30px; }
  .val-gestes .lec-actions { flex-wrap: wrap; }
  .val-gestes .lec-actions .btn { flex: 1 1 100%; min-width: 0; }
  .val-choix-liste { max-height: 208px; }
  /* R631 — SUR UN TÉLÉPHONE, LA CARTE EST CELLE DU BUREAU EN TAILLE MOYENNE.
     Rien n'est retiré : aperçu, titre, note, méta, pastilles et les deux
     gestes — c'est la MÊME carte, sur une seule colonne, à toute la largeur.
     (R626 en rabotait le contenu ; on n'en garde que la colonne unique.) */
  .docs.view-cards { grid-template-columns: 1fr; }
  .docs.view-cards .dprev { height: 150px; }   /* R634 : l'aperçu ne suit plus la largeur de carte du bureau */
  .val-trace li { flex-wrap: wrap; }
  .val-trace time { width: auto; }
  .texte-versions { gap: 4px; }
}

/* R628 — sur un téléphone, le choix de la vue n'a plus lieu d'être : la vue
   liste y est illisible, seules les cartes restent. Le bouton disparaît.
   R629 — et la garantie ne dépend plus du script : SOUS 700 px, toute grille
   encore marquée « liste » (l'accueil, un rendu venu du pouls, un navigateur
   sans script) prend la mise en page des cartes. */
@media (max-width: 700px) {
  .seg [data-view="list"] { display: none; }
  .seg:has([data-view="cards"]) { display: none; }   /* un seul choix : pas de choix à montrer */
  /* R634 — la grille « liste » devient une VRAIE carte : mêmes règles que la
     vue cartes, rien qui déborde. Sans cela, la rangée du bas (pastilles,
     date, gestes) restait sur une seule ligne et sortait de l'écran. */
  .docs.view-list { display: grid; grid-template-columns: 1fr; gap: 12px; padding: 0; border: 0; background: transparent; }
  .docs.view-list .docitem { display: flex; flex-direction: column; align-items: stretch; gap: 0;
    padding: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); }
  .docs.view-list .dprev { display: block; width: auto; height: 150px; flex: none;
    border: 0; border-bottom: 1px solid var(--line); border-radius: 0; overflow: hidden; position: relative; }
  .docs.view-list .dprev img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
  .docs.view-list .dprev .bigext { font-size: 15px; }
  .docs.view-list .dprev .sheet { inset: 12px 14px auto; bottom: -8px; padding: 12px 12px 0; font-size: 7.5px; line-height: 1.75; border-radius: 4px 6px 0 0; }
  .docs.view-list .dbody { padding: 8px 12px 12px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
  .docs.view-list .dbody .doc-title { font-size: 14px; line-height: 1.35; white-space: normal; overflow-wrap: anywhere; }
  .docs.view-list .dbody .doc-meta, .docs.view-list .dbody .doc-empl { font-size: 11px; }
  .docs.view-list .drow2 { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; min-width: 0; }
  .docs.view-list .doc-date { font-size: 11px; }
  .docs.view-list .doc-actions { margin-top: 8px; width: 100%; display: flex; gap: 6px; min-width: 0; }
  .docs.view-list .doc-actions .act { flex: 1 1 0; min-width: 0; justify-content: center; }
  .docs.view-list .sel { position: absolute; top: 8px; inset-inline-start: 8px; z-index: 2; }
  /* Une carte ne déborde jamais de l'écran, quel que soit son contenu. */
  .docs .docitem, .docs .dbody, .docs .drow2, .docs .doc-title { max-width: 100%; }
  .docs .doc-title { overflow-wrap: anywhere; }
}

/* R632 — la recherche de l'en-tête, repliée en icône sur un téléphone */
.topsearch-ouvre, .topsearch-ferme { display: none; }
/* R773 — LA RECHERCHE PASSE EN BLOC SOUS L'EN-TÊTE DÈS LA TABLETTE. Le seuil
   était à 700 pixels : sur une tablette de 768, le champ restait DANS la barre,
   coincé entre le logo et les pastilles, trop étroit pour y lire ce qu'on
   tape. On remonte le seuil à 900 — au-dessus, la barre a la place ; en
   dessous, la recherche s'ouvre en un bloc pleine largeur sous l'en-tête. */
@media (max-width: 900px) {
  /* R779 — SUR UN ÉCRAN ÉTROIT, LES COMMANDES SE RASSEMBLENT À DROITE. La
     bande des pastilles prenait la place restante : la cloche et le compte se
     retrouvaient repoussés au bord, et les pastilles flottaient au milieu, à
     égale distance de rien. Le bouton de la recherche reste seul PRÈS DU
     LOGO — c'est là qu'on le cherche, à gauche, comme le champ qu'il
     remplace — et tout le reste se serre à droite.
     Cette règle vit ici, au seuil où la recherche DEVIENT un bouton : posée
     plus bas, à sept cents, elle laissait la tablette de 768 sans alignement.

     ET C'EST LE GROUPE DE DROITE QU'ON POUSSE, non la recherche qu'on retient :
     un « margin-inline-end: auto » sur le bouton de recherche PARTAGE l'espace libre
     de part et d'autre — mesuré, il le laissait flotter à trois cent quarante
     pixels du bord au lieu de le coller au logo. La marge se pose sur le
     PREMIER élément du groupe de droite, quel qu'il soit. */
  /* R784 — LA RECHERCHE REJOINT LE GROUPE DE DROITE. En R779 je l'avais
     laissée près du logo : à l'usage, elle y est seule et déséquilibrée, alors
     que c'est une COMMANDE comme les autres. La poussée passe donc sur ELLE —
     le premier élément du groupe — et tout se serre à droite : recherche,
     pastilles, cloche, compte. Le logo garde la gauche pour lui seul. */
  .topsearch-ouvre { margin-inline-start: auto; }
  .topbadges { flex: 0 0 auto; }

  .topsearch-ouvre { display: inline-flex; align-items: center; justify-content: center;
    /* R779 : plus de « margin-inline-start: auto » ici — c'est LUI qui poussait le
       bouton loin du logo. Il reste à gauche, contre la marque ; c'est le
       groupe de droite qui se décolle. */
    width: 38px; height: 38px; flex: none;
    border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--ink); cursor: pointer; }
  .topsearch-ouvre[aria-expanded="true"] { background: var(--seal-soft); border-color: var(--seal); color: var(--seal-dark); }
  /* Le champ quitte la ligne de l'en-tête : il s'ouvre en dessous, sur toute
     la largeur, et ne pousse plus les pastilles hors de vue. */
  /* R773 : « top: 100% » se mesure par rapport au PARENT POSITIONNÉ le plus
     proche — ici le champ lui-même n'en avait pas de fiable, et il retombait
     DANS la barre, à trente-neuf pixels au-dessus de son bas. On le pose par
     rapport à l'écran, juste sous la hauteur de l'en-tête, qui est déclarée. */
  .topsearch { position: fixed; inset-inline-start: 10px; inset-inline-end: 10px; top: var(--h-topbar, 55px); z-index: 46;
    width: auto; max-width: none; margin: 6px 0 0; display: none;
    box-shadow: 0 10px 24px rgba(33,48,46,.16); }
  .topsearch.on { display: flex; }
  .topbar { position: sticky; }   /* « sticky » établit déjà le repère de position du champ ouvert */
  .topsearch-ferme { display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; flex: none; border: 0; background: none; color: var(--muted); cursor: pointer; }
}

/* R633 — SUR UN TÉLÉPHONE, LA BARRE DES FILTRES NE COLLE PLUS. Elle occupe
   déjà plusieurs lignes sur un écran étroit : figée en haut, elle mangeait
   la moitié de la hauteur utile et laissait à peine deux cartes en vue.
   Elle redevient un bloc ordinaire, qui défile avec la page ; la barre des
   onglets d'une fiche, elle, reste collée — une seule ligne, elle ne coûte
   rien. */
@media (max-width: 700px) {
  .barre-filtres.collante { position: static; box-shadow: none; border-radius: 12px; margin-bottom: 12px; padding: 12px; }
  .barre-filtres.collante.collee { box-shadow: none; }
}

/* R636 → R637 — LE MESSAGE D'ACTION : UNE PILULE PLEINE, CENTRÉE EN BAS.
   Au coin bas, il portait le dessin des avis de la cloche et l'on confondait
   les deux. Il a maintenant son propre logement, au milieu de l'écran, en
   bas : une pilule pleine — verte pour une réussite, rouge pour une erreur —
   qui flotte au-dessus de la page sans rien déplacer, et s'efface seule. Les
   avis de la cloche gardent le coin, leur fond clair et leur liseré. */
#kzMsgs { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 95;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  width: max-content; max-width: min(680px, calc(100vw - 32px)); pointer-events: none; }
/* R638 — TEINTE TRÈS PÂLE, LISERÉ DE LA COULEUR. Le fond plein pesait : deux
   grands aplats au milieu de l'écran. Le message garde sa place et sa forme,
   mais s'éclaircit — fond à peine teinté, liseré fin de la couleur, signe et
   texte dans cette couleur. On distingue la réussite de l'erreur du coin de
   l'œil, sans que l'écran soit barré. */
.kz-msg { display: flex; align-items: center; gap: 10px; pointer-events: auto;
  padding: 11px 16px 11px 18px; border-radius: 999px; border: 1px solid transparent;
  font-size: 13.5px; line-height: 1.4; box-shadow: 0 8px 22px rgba(33,48,46,.14);
  animation: kz-msg-in .22s ease; max-width: 100%; }
.kz-msg.ok  { background: var(--seal-soft); border-color: var(--seal); color: var(--seal-dark); }
.kz-msg.err { background: var(--err-bg);    border-color: var(--err);  color: var(--err); }
.kz-msg-ic { flex: none; font-size: 13px; font-weight: 700; line-height: 1; }
.kz-msg-txt { min-width: 0; overflow-wrap: anywhere; }
.kz-msg-x { flex: none; margin-inline-start: 4px; border: 0; background: none; color: currentColor; opacity: .55;
  font-size: 13px; line-height: 1; cursor: pointer; padding: 2px 0 0 2px; }
.kz-msg-x:hover { opacity: 1; }
.kz-msg.part { opacity: 0; transform: translateY(8px); transition: opacity .45s ease, transform .45s ease; }
@keyframes kz-msg-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .kz-msg { animation: none; } .kz-msg.part { transition: none; } }
@media (max-width: 600px) { #kzMsgs { left: 12px; right: 12px; bottom: 14px; transform: none; width: auto; max-width: none; }
  .kz-msg { width: 100%; border-radius: 14px; } }

/* R637 — LES RÉGLAGES SUR UN TÉLÉPHONE : plus de débordement. Le sommaire
   (une rangée d'ancres) et les lignes du diagnostic (libellé, état, bouton
   « Démarrer ») restaient sur un seul rang et poussaient la page de
   soixante-quatre pixels au-delà de l'écran. Ils se replient. La page
   elle-même n'est pas touchée : tout tient dans la feuille de style. */
@media (max-width: 700px) {
  /* Le sommaire réservait 188 px en colonne fixe, à côté du contenu : sur un
     écran de 360, il ne restait plus la place d'écrire. Il passe AU-DESSUS,
     en rangée qui se replie, et cesse de coller. */
  .regl-agencement { flex-direction: column; min-width: 0; }
  .regl-sommaire { position: static; flex: 0 0 auto; width: 100%; max-width: 100%;
    flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .regl-sommaire a { white-space: nowrap; }
  .regl-colonne { width: 100%; min-width: 0; }
  /* R1334 — le repli et la coupure du nom sont désormais GÉNÉRAUX (voir
     .dash-list li plus haut) : ils ne dépendaient pas de la largeur mais de
     la longueur du texte, et l'arabe l'a montré sur un grand écran. Ne
     restent ici que les marges, qui, elles, sont bien affaire de place. */
  .dash-list li .dash-acte { margin-inline-start: 0; }
  .dash-list li .when, .dash-list li .dash-etat { margin-inline-start: 0; }
  /* Les champs des réglages ne dépassent jamais leur carte. */
  .carte-reglage input[type=text], .carte-reglage input[type=number], .carte-reglage input[type=email],
  .carte-reglage select, .carte-reglage textarea { max-width: 100%; width: 100%; box-sizing: border-box; }
  .carte-reglage code, .carte-reglage pre { overflow-wrap: anywhere; white-space: pre-wrap; }
  /* R1334 — la bulle d'aide est désormais arrimée à sa ligne à TOUTE largeur
     (voir sa règle) : le rattrapage du petit écran n'a plus d'objet. */
}

/* ==========================================================================
   R644 — QUESTIONNAIRES. Même langue que le circuit de validation
   (lignes .val-row, pastilles, sélecteur de personnes) ; en plus : la barre
   d'avancement, le bâtisseur de questions, le formulaire de réponse (choix,
   étoiles, échelle, émoticônes) et les barres de résultat.
   ========================================================================== */
/* R648 — plus de retrait : « Questionnaires » est une entrée comme les autres.
   La classe reste définie, sans effet, pour une page qui l'aurait gardée. */
.menu-item.menu-sous { padding-inline-start: inherit; }
.badgebtn.badge-quest .badge-txt { font-weight: 600; font-size: 12.5px; }

.quest-retour { margin-bottom: 8px; }
/* R776 — LA RANGÉE DES ONGLETS RESPIRE DE FAÇON IDENTIQUE SUR LES DEUX PAGES.
   Elle n'avait qu'une marge en bas : au-dessus, l'écart dépendait de ce qui la
   précédait — vingt pixels après un avertissement de courriel sur la page des
   questionnaires, quatre après un simple titre sur celle des missions. Deux
   pages jumelles ne doivent pas dépendre de la présence d'un message pour se
   ressembler. On déclare aussi la marge du HAUT. */
.quest-tete-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: var(--e4) 0 var(--e3); }
.quest-tete-actions .tabs { margin: 0; }
.quest-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 8px; }
/* R650 : le mot du lanceur devient un bloc à part entière — voir plus bas. */
.quest-urgent { color: #8A5A08; font-weight: 600; }
.quest-avancement { display: flex; align-items: center; gap: 10px; margin: 6px 0 10px; font-size: 13px; }
.quest-avancement .quest-barre { flex: 1 1 200px; max-width: 360px; }
.quest-gestes { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.quest-gestes form { margin: 0; }
.quest-h2-note { font-weight: 400; font-size: 12.5px; margin-inline-start: 8px; }

/* ==========================================================================
   R692 — UNE SEULE BARRE POUR TOUT LE PROJET, ET SA COULEUR DIT L'ÉTAT.
   Elle était verte quoi qu'il arrive : à moitié pleine, on ne savait pas si
   ça avançait, si l'échéance était passée ou si tout s'était arrêté. Cinq
   états, cinq lectures :
     (rien)      — vide, avec un point de départ à gauche
     .en-cours   — vert, le bout plus clair : ça avance encore
     .en-retard  — ambre sur piste chaude : l'échéance est derrière nous
     .fini       — vert plein, la barre se ferme
     .arretee    — gris figé, là où ça s'est arrêté
   Et quand il y a peu d'unités (dix au plus : les étapes d'une validation,
   une poignée d'invités), elle se DÉCOUPE — on compte « trois sur cinq » sans
   lire le chiffre. Au-delà, elle redevient continue : des segments d'un pixel
   ne diraient plus rien.
   ========================================================================== */
.quest-barre { position: relative; height: 6px; border-radius: 999px; background: #E6EAE7; overflow: hidden; }
.quest-barre.grande { height: 10px; }
.quest-barre > span { display: block; height: 100%; border-radius: 999px; background: var(--seal); transition: width .35s ease; }
.val-corps-ligne .quest-barre { max-width: 260px; margin-top: 2px; }

/* Le point de départ, quand rien n'est encore arrivé. */
.quest-barre.vide::before { content: ''; position: absolute; left: 5px; top: 50%; transform: translateY(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: #B9C4BF; }
/* En cours : le bout du remplissage s'éclaircit — le mouvement se voit à l'arrêt. */
.quest-barre.en-cours > span { background: linear-gradient(90deg, var(--seal) 0%, var(--seal) calc(100% - 16px), #3E9A85 calc(100% - 16px), #3E9A85 100%); }
/* En retard : la piste chauffe aussi, pour qu'on le voie sans lire l'échéance. */
.quest-barre.en-retard { background: #F7E4DC; }
.quest-barre.en-retard > span { background: linear-gradient(90deg, #BA7517 0%, #BA7517 calc(100% - 16px), #D79A3E calc(100% - 16px), #D79A3E 100%); }
/* Terminé : plein, sans dégradé — il n'y a plus rien à attendre. */
.quest-barre.fini > span { background: var(--seal); }
/* Arrêté (annulé) : la barre reste où elle en était, sans couleur d'action. */
.quest-barre.arretee > span { background: #A8B2AE; }

/* Segmentée : une case par unité, quand elles sont peu nombreuses. */
.quest-barre.segments { display: flex; gap: 3px; background: none; overflow: visible; }
.quest-barre.segments > i { flex: 1; background: #E6EAE7; border-radius: 3px; }
.quest-barre.segments > i:first-child { border-radius: 999px 3px 3px 999px; }
.quest-barre.segments > i:last-child { border-radius: 3px 999px 999px 3px; }
.quest-barre.segments > i.plein { background: var(--seal); }
.quest-barre.segments.en-retard > i.plein { background: #BA7517; }
.quest-barre.segments.en-retard > i { background: #F7E4DC; }
.quest-barre.segments.arretee > i.plein { background: #A8B2AE; }
.quest-barre.segments.vide::before { content: none; }

/* Les questions — même squelette pour répondre et pour lire les résultats. */
.quest-questions, .quest-resultats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.quest-q { padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); }
.quest-q-tete { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; }
.quest-q-num { flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--seal-soft); color: var(--seal-dark); display: inline-flex; align-items: center; justify-content: center; font-size: 12.5px; font-weight: 700; }
.quest-q-lib { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.quest-q-lib b { font-size: 14.5px; font-weight: 500; overflow-wrap: anywhere; }
.quest-q-lib small { color: var(--muted); font-size: 12px; }
.quest-oblig { color: var(--err); font-weight: 700; }
.quest-q-corps { padding-inline-start: 36px; }
.quest-repondre .lec-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px; }
.quest-repondre .lec-actions .btn { flex: 0 0 auto; }   /* le bouton garde sa taille : il ne s'étire pas sur toute la ligne */
.quest-q-corps input[type=text], .quest-q-corps textarea, .quest-q-corps select { width: 100%; }
.quest-q-corps .quest-court { width: 220px; max-width: 100%; }

/* Choix : une ligne par option, toute la ligne cliquable. */
.quest-choix { display: flex; flex-direction: column; gap: 6px; }
.quest-opt { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 10px; cursor: pointer; font-size: 13.5px; background: var(--panel); }
.quest-opt:hover { background: var(--paper); }
.quest-opt input[type=radio], .quest-opt input[type=checkbox] { margin: 0; accent-color: var(--seal); width: 16px; height: 16px; flex: none; }
.quest-opt:has(input:checked), .quest-opt.on { border-color: var(--seal); background: var(--seal-ghost); }   /* .on : posé par le script, pour les navigateurs sans :has() */
.quest-opt.quest-autre input[type=text] { flex: 1 1 auto; width: auto; min-width: 0; height: 30px; }
.quest-ouinon { flex-direction: row; gap: 10px; }
.quest-ouinon .quest-opt { flex: 1 1 0; justify-content: center; }
.quest-liste select { max-width: 360px; }
.quest-autre-liste { margin-top: 8px; max-width: 360px; }

/* Émoticônes : cinq visages, celui qu'on choisit grandit. */
.quest-emojis { display: flex; gap: 8px; flex-wrap: wrap; }
.quest-emoji { position: relative; cursor: pointer; }
.quest-emoji input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.quest-emoji span { display: inline-flex; align-items: center; justify-content: center; width: 52px; height: 52px; border-radius: 14px; border: 1px solid var(--line); background: var(--panel); font-size: 28px; line-height: 1; transition: transform .15s, border-color .15s, background .15s; }
.quest-emoji:hover span { transform: scale(1.08); }
.quest-emoji input:checked + span { border-color: var(--seal); background: var(--seal-ghost); transform: scale(1.12); box-shadow: 0 0 0 3px var(--seal-soft); }
.quest-emoji input:focus-visible + span { outline: 2px solid var(--sel); outline-offset: 2px; }

/* Étoiles : elles s'allument jusqu'à celle qu'on désigne. */
.quest-etoiles { display: flex; align-items: center; gap: 2px; }
.quest-etoile { position: relative; cursor: pointer; }
.quest-etoile input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.quest-etoile span { display: inline-block; font-size: 30px; line-height: 1; color: #C9CFCB; padding: 2px 3px; transition: color .1s, transform .1s; }
.quest-etoile.on span { color: #D9A400; }
.quest-etoile:hover span { transform: scale(1.12); }
.quest-etoile input:focus-visible + span { outline: 2px solid var(--sel); outline-offset: 2px; border-radius: 6px; }
.quest-note-val { margin-inline-start: 10px; font-size: 13px; color: var(--muted); font-weight: 500; }

/* Échelle : les crans en ligne, le mot de chaque bout. */
.quest-echelle { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.quest-echelle > small { color: var(--muted); font-size: 12px; max-width: 120px; }
.quest-echelle-crans { display: flex; gap: 6px; flex-wrap: wrap; }
.quest-cran { position: relative; cursor: pointer; }
.quest-cran input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.quest-cran span { display: inline-flex; align-items: center; justify-content: center; min-width: 38px; height: 38px; padding: 0 8px; border-radius: 10px; border: 1px solid var(--line); background: var(--panel); font-size: 14px; font-weight: 500; }
.quest-cran:hover span { background: var(--paper); }
.quest-cran input:checked + span { background: var(--seal); border-color: var(--seal); color: #fff; }
.quest-cran input:focus-visible + span { outline: 2px solid var(--sel); outline-offset: 2px; }

/* Résultats : une barre par choix, la plus haute marquée. */
.quest-moyenne { margin: 0 0 8px; font-size: 13.5px; } .quest-moyenne b { font-size: 16px; }
.quest-barres { display: flex; flex-direction: column; gap: 6px; }
.quest-ligne { display: grid; grid-template-columns: minmax(90px, 1fr) 3fr auto; align-items: center; gap: 10px; }
.quest-lib { font-size: 13px; overflow-wrap: anywhere; }
.quest-lib-emoji { font-size: 22px; }
.quest-ligne .quest-barre { height: 10px; }
.quest-ligne.quest-gagne .quest-barre > span { background: var(--seal-dark); }
.quest-ligne.quest-gagne .quest-lib { font-weight: 600; }
.quest-cpt { font-size: 13px; font-weight: 600; min-width: 64px; text-align: right; white-space: nowrap; } .quest-cpt small { color: var(--muted); font-weight: 400; }
.quest-textes { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.quest-textes li { display: flex; justify-content: space-between; gap: 12px; padding: 8px 12px; border-radius: 10px; background: var(--paper); font-size: 13px; }
.quest-textes li span { overflow-wrap: anywhere; } .quest-textes li small { color: var(--muted); white-space: nowrap; font-size: 11.5px; }
/* Une longue liste se replie sur ses huit premières réponses ; le bouton la déploie. */
.quest-textes-longue { max-height: 330px; overflow: hidden; position: relative; }
.quest-textes-longue::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 70px; background: linear-gradient(to bottom, rgba(255,255,255,0), var(--panel)); pointer-events: none; }
.quest-voir-plus { margin-top: 8px; }
/* Le pouls a remplacé un bloc : il s'éclaire une seconde, puis rien. */
@keyframes quest-maj { 0% { box-shadow: 0 0 0 0 var(--seal-soft); } 100% { box-shadow: 0 0 0 10px rgba(0,0,0,0); } }
.pouls-maj { animation: quest-maj 1.1s ease-out; }
@media (prefers-reduced-motion: reduce) { .pouls-maj { animation: none; } }

/* Participants et trace. */
.quest-participants { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.quest-participants li { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--line); background: var(--panel); }
.quest-participants li.ok { border-color: var(--seal-soft); background: var(--seal-ghost); }
.quest-participants li form { margin-inline-start: auto; }
.quest-participants .val-qui { display: flex; flex-direction: column; min-width: 0; }
.quest-participants .val-qui b { font-size: 13.5px; font-weight: 500; } .quest-participants .val-qui small { color: var(--muted); font-size: 11.5px; }
.quest-participants li.ok .val-qui small { color: var(--seal-dark); }
.quest-trace { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.quest-trace li { display: flex; gap: 12px; padding: 6px 0; border-bottom: 1px dashed var(--line); }
.quest-trace li:last-child { border-bottom: 0; }
.quest-trace-quand { flex: none; color: var(--muted); font-size: 12px; min-width: 110px; }

/* Le bâtisseur. */
.quest-form .card { margin-bottom: var(--e3); }
.quest-coche { display: flex; align-items: center; gap: 10px; padding: 8px 0; cursor: pointer; font-size: 13.5px; }
.quest-coche input { margin: 0; accent-color: var(--seal); width: 16px; height: 16px; flex: none; }
.quest-coche b { font-weight: 500; } .quest-coche small { color: var(--muted); font-size: 12px; margin-inline-start: 4px; }
.quest-coche.compact { padding: 4px 0; font-size: 13px; }
.quest-reglages { display: flex; flex-direction: column; gap: 4px; }
.quest-reglages .lec-label { margin-top: 8px; } .quest-reglages .lec-label small { display: block; margin-top: 4px; }
.quest-reglages-ligne { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.quest-qb { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.quest-qb-tete { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; } .quest-qb-tete b { font-size: 14.5px; }
.quest-qb-liste { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.quest-qb-q { padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--paper); }
.quest-qb-tete-q { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.quest-qb-outils { margin-inline-start: auto; display: flex; gap: 4px; }
.quest-qb-opts { margin: 4px 0 8px; padding: 10px 12px; border-radius: 10px; background: var(--panel); border: 1px solid var(--line); }
.quest-qb-opts-lib { font-size: 12.5px; color: var(--muted); font-weight: 600; margin-bottom: 6px; }
.quest-qb-choix { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
/* R675 : la rangée d'un choix peut passer à la ligne — c'est ainsi qu'un
   message d'erreur se pose SOUS le champ et non entre le champ et sa croix. */
.quest-qb-choix li { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
/* R696 — LA CROIX RESTE SUR LA LIGNE DU CHAMP. Le champ porte « largeur 100 % »
   comme tous les champs de la maison ; avec « flex: 1 1 auto », cette largeur
   devient sa base et il réclame la ligne entière — depuis que la rangée peut
   passer à la ligne (R675, pour loger un message d'erreur sous le champ), la
   croix se retrouvait dessous, une par une. Base zéro : le champ ne prend que
   la place LIBRE, la croix garde la sienne, et le message d'erreur, qui
   demande une ligne entière, passe toujours dessous. */
.quest-qb-choix li input { flex: 1 1 0; width: auto; min-width: 120px; }
.quest-qb-opts-pied { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 8px; }
.quest-qb-ligne { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.quest-qb-ligne .lec-label { margin: 0; }
.quest-qb-ajout { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.quest-qb-ajout .lec-label { margin: 0; flex: 1 1 220px; max-width: 360px; }
.quest-invites { list-style: none; margin: 8px 0 6px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.quest-invites li { display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: 10px; border: 1px solid var(--line); background: var(--panel); }
.quest-invites .val-qui { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.quest-invites .val-qui b { font-size: 13.5px; font-weight: 500; } .quest-invites .val-qui small { color: var(--muted); font-size: 11.5px; }
.quest-invites .com-avatar { width: 28px; height: 28px; font-size: 11px; }
.quest-pied { margin-top: 4px; }

/* Téléphone et petite tablette. */
@media (max-width: 700px) {
  .quest-reglages-ligne { grid-template-columns: 1fr; }
  .quest-q-corps { padding-inline-start: 0; }
  .quest-ligne { grid-template-columns: 1fr; gap: 4px; } .quest-cpt { text-align: start; min-width: 0; }
  .quest-ouinon { flex-direction: column; }
  .quest-emoji span { width: 46px; height: 46px; font-size: 24px; }
  .quest-etoile span { font-size: 26px; }
  .quest-tete-actions .btn { width: 100%; justify-content: center; }
  .quest-participants li { flex-wrap: wrap; } .quest-participants li form { margin-inline-start: 38px; }
  .quest-trace li { flex-direction: column; gap: 2px; }
  .quest-qb-outils { flex-wrap: wrap; }
  .quest-textes li { flex-direction: column; gap: 2px; }
}

/* ==========================================================================
   R645 — UN SEUL OBJET, DE L'AIR, ET DES BULLES D'AIDE.
   L'intitulé d'un champ tient sur une ligne (le mot, sa précision, son « ? »),
   le champ dessous ; les blocs du bâtisseur respirent ; le bâtisseur vide le
   dit ; la bulle « ? » vaut pour toute l'application.
   ========================================================================== */
.aide-pt { cursor: help; margin-inline-start: 4px; transition: border-color .12s, color .12s, background .12s; }
.aide-pt:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--seal-soft); border-color: var(--seal); }
h1 .aide-pt, h2 .aide-pt { margin-inline-start: 2px; }
.entry-title .aide-pt { vertical-align: 5px; }
/* La bulle unique de la page : en fixe, calée sous (ou sur) son bouton, sa flèche sur lui. */
.aide-bulle.fixe { position: fixed; top: auto; inset-inline-start: auto; margin: 0; z-index: 9500; max-width: min(320px, calc(100vw - 16px)); width: max-content;
  opacity: 0; visibility: hidden; transform: translateY(-3px); transition: opacity .12s, transform .12s, visibility .12s; pointer-events: none; }
.aide-bulle.fixe.on { opacity: 1; visibility: visible; transform: none; pointer-events: auto; }
.aide-bulle.fixe::before { inset-inline-start: var(--fleche, 14px); }
.aide-bulle.fixe.dessus::before { top: auto; bottom: -6px; transform: rotate(225deg); }
@media (prefers-reduced-motion: reduce) { .aide-bulle.fixe { transition: none; } }
.quest-form .lec-titre, .quest-form .quest-qb-q .lec-titre { white-space: normal; flex-wrap: wrap; }
.quest-bloc h2 { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 14px; }
.quest-bloc > .lec-label, .quest-reglages > .lec-label { margin-top: 14px; }
.quest-bloc > .lec-label:first-of-type { margin-top: 0; }
.quest-form .lec-label small { display: block; margin-top: 5px; line-height: 1.45; }
.quest-form .lec-label input, .quest-form .lec-label select, .quest-form .lec-label textarea { margin-top: 1px; }
.quest-coche { padding: 10px 0; flex-wrap: wrap; }
.quest-coche small { flex: 1 1 200px; margin-inline-start: 0; line-height: 1.45; }
.quest-coche .aide-pt { margin-inline-start: 2px; }
.quest-reglages .quest-coche + .quest-coche { border-top: 1px dashed var(--line); }
.quest-reglages { gap: 0; }
.quest-reglages > .lec-label { padding-top: 12px; border-top: 1px dashed var(--line); }
.quest-reglages-ligne { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line); gap: 14px; }
.quest-qb { margin-top: 18px; padding-top: 16px; }
.quest-qb-tete { align-items: center; margin-bottom: 12px; }
.quest-apercu-tout-btn { margin-inline-start: auto; }
@media (max-width: 700px) { .quest-apercu-tout-btn { margin-inline-start: 0; flex: 1 1 100%; justify-content: center; } }
.quest-qb-vide { margin: 0 0 14px; padding: 16px 14px; border: 1px dashed var(--line); border-radius: 10px; background: var(--paper); color: var(--muted); font-size: 13px; text-align: center; }
.quest-qb-ajout { display: grid; grid-template-columns: minmax(220px, 380px) auto; gap: 10px 12px; align-items: start; }
.quest-qb-ajout .lec-label { max-width: none; }
.quest-qb-ajout .btn { margin-top: 23px; }
.quest-qb-q { padding: 14px 16px; }
.quest-qb-q > .lec-label { margin-top: 12px; }
.quest-qb-q > .quest-qb-opts { margin: 12px 0 4px; padding: 12px 14px; }
.quest-qb-q > .quest-coche { padding: 10px 0 2px; }
.quest-qb-ligne { gap: 12px; }
.quest-qb-choix { gap: 8px; }
.quest-qb-opts-lib { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
.quest-qb-opts-pied { margin-top: 10px; }
.quest-qb-ajout .btn { justify-self: start; }
.quest-gestes .aide-pt { align-self: center; }
@media (max-width: 700px) {
  .quest-qb-ajout { grid-template-columns: 1fr; }
  .quest-qb-ajout .btn { margin-top: 0; width: 100%; justify-self: stretch; justify-content: center; }
  .quest-qb-q { padding: 12px; }
  /* Les outils d'une question (▲ ▼ dupliquer retirer) sur leur propre ligne, alignés à droite : ils ne s'écrasent plus contre le titre. */
  .quest-qb-tete-q { flex-wrap: wrap; }
  .quest-qb-outils { margin-inline-start: 0; flex-basis: 100%; justify-content: flex-end; flex-wrap: nowrap; }
}

/* R646 — LES PIÈCES JOINTES D'UN QUESTIONNAIRE : dans le bâtisseur (ce qui
   partira), sur la fiche (ce qu'il y a à lire), dans la fenêtre de choix. */
.quest-pj { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.quest-pj-tete { display: flex; align-items: baseline; gap: 6px; margin-bottom: 8px; } .quest-pj-tete b { font-size: 14.5px; }
.quest-pj-liste, .quest-pieces-liste, .quest-pj-resultats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.quest-pj-liste li, .quest-pieces-liste li, .quest-pj-resultats li { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: 10px; border: 1px solid var(--line); background: var(--panel); min-width: 0; }
.quest-pj-liste .tag-ext, .quest-pieces-liste .tag-ext, .quest-pj-resultats .tag-ext { flex: none; }
/* R649 — ON VOIT LA PIÈCE, ON NE LA LIT PAS SEULEMENT.
   Sur la FICHE, les pièces jointes deviennent des cartes : un grand aperçu
   (image, première page d'un PDF, d'un Word ou d'un Excel — la même fabrique
   que la bibliothèque), le nom dessous, les gestes en pied. L'étiquette
   d'extension reste sous l'image et reparaît si l'aperçu ne vient pas (app.js
   retire l'image et pose « sans-vignette »).
   Dans le BÂTISSEUR, la liste de travail garde un cadre menu. */
.quest-pieces-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 10px; }
.quest-pieces-liste li { flex-direction: column; align-items: stretch; gap: 8px; padding: 8px; }
.quest-piece-vue { position: relative; display: block; width: 100%; aspect-ratio: 3 / 4; border-radius: 8px; overflow: hidden;
  background: var(--paper); border: 1px solid var(--line); }
.quest-piece-vue .tag-ext { position: absolute; inset-inline-start: 8px; top: 8px; z-index: 0; }
/* R720 — LA PIÈCE JOINTE SE MONTRE ENTIÈRE, comme à la bibliothèque. La
   vignette commune est cadrée « au plus large » et alignée en haut : sur une
   fiche de dossier c'est voulu (on reconnaît un document à son en-tête), mais
   ici on JOINT une pièce pour qu'elle soit vue — une photo en paysage perdait
   ses bords, un tableau perdait sa dernière colonne. Elle est maintenant
   contenue et centrée sur fond blanc, exactement comme l'aperçu d'une fiche
   (R58) : un paysage comme un portrait tient dans le cadre, sans être rogné.
   Le cadre s'allonge un peu (3/4 → 4/5) pour laisser respirer les portraits. */
.quest-piece-vue { aspect-ratio: 4 / 5; }
.quest-piece-vue .doc-thumb { z-index: 1; opacity: 0; transition: opacity .25s ease;
  object-fit: contain; object-position: center; background: #fff; }
.quest-piece-vue .doc-thumb.chargee { opacity: 1; }
.quest-piece-vue .dprev-attente { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 2; background: var(--paper, #FCFBF7); pointer-events: none; }
.quest-piece-vue .dprev-attente::after { content: ''; width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--line2, #CFCBBD); border-top-color: var(--seal); animation: kz-tourne .9s linear infinite; }
.quest-piece-vue.prete .dprev-attente, .quest-piece-vue.sans-vignette .dprev-attente { display: none; }
@media (prefers-reduced-motion: reduce) { .quest-piece-vue .dprev-attente::after { animation: none; border-top-color: var(--line2, #CFCBBD); } }
/* « Ouvrir » se pose sur l'aperçu au survol ; au toucher, il est toujours là. */
.quest-piece-loupe { position: absolute; inset-inline-start: 0; inset-inline-end: 0; bottom: 0; z-index: 3; display: flex; align-items: center; justify-content: center; gap: 5px;
  padding: 6px 4px; background: rgba(33,48,46,.82); color: #fff; font-size: 11.5px; opacity: 0; transition: opacity .15s ease; }
a.quest-piece-vue { cursor: zoom-in; transition: border-color .12s, box-shadow .12s; }
a.quest-piece-vue:hover, a.quest-piece-vue:focus-visible { border-color: var(--seal); box-shadow: 0 0 0 3px var(--seal-soft); outline: none; }
a.quest-piece-vue:hover .quest-piece-loupe, a.quest-piece-vue:focus-visible .quest-piece-loupe { opacity: 1; }
@media (hover: none) { .quest-piece-loupe { opacity: .92; } }
.quest-pieces-liste .quest-piece-nom b { font-size: 13px; }
/* Le cadre menu du bâtisseur : la vignette par-dessus l'étiquette. */
.quest-pj-vue { position: relative; flex: none; display: flex; align-items: center; justify-content: center;
  width: 46px; height: 58px; border-radius: 8px; overflow: hidden; background: var(--paper); border: 1px solid var(--line); }
.quest-pj-vue .tag-ext { position: relative; z-index: 0; }
.quest-pj-vue .doc-thumb { z-index: 1; opacity: 0; transition: opacity .25s ease; }
.quest-pj-vue .doc-thumb.chargee { opacity: 1; }
.quest-pj-nom, .quest-piece-nom { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.quest-pj-nom b, .quest-piece-nom b { font-size: 13.5px; font-weight: 500; overflow-wrap: anywhere; }
.quest-pj-nom small, .quest-piece-nom small { color: var(--muted); font-size: 11.5px; }
.quest-pj-gestes { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.quest-pj-resultats { margin-top: 8px; max-height: 50vh; overflow: auto; }
/* R662 — deux lignes sous le titre : où elle est rangée, puis ce qu'elle est. */
.quest-pj-resultats li { align-items: flex-start; padding: 9px 10px; }
.quest-pj-resultats .quest-pj-nom { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.quest-pj-ou { color: var(--seal-dark); font-size: 12px; overflow-wrap: anywhere; }
.quest-pj-ic { color: var(--faint); margin-inline-end: 2px; }
.quest-pj-det { color: var(--muted); font-size: 11.5px; overflow-wrap: anywhere; }
.quest-pj-resultats li .chip { align-self: center; }
.quest-pj-resultats li { cursor: pointer; } .quest-pj-resultats li:hover, .quest-pj-resultats li:focus-visible { border-color: var(--seal); background: var(--seal-ghost); outline: none; }
.quest-pj-resultats li.deja { opacity: .6; cursor: default; }
/* R660 — « + joindre » EST UN BOUTON, PAS UNE ÉTIQUETTE. Écrit en vert et
   sans contour, il se lisait comme un état (« ceci est vert ») et non comme
   le geste qu'il commande. Même dessin que les autres boutons de la maison :
   fond blanc, contour discret, et le vert seulement au survol de la ligne. */
.quest-pj-resultats li .chip {
  margin-inline-start: auto; white-space: nowrap;
  border: 1px solid var(--line2); background: var(--panel); color: var(--ink);
  border-radius: 8px; padding: 5px 12px; font-size: 12.5px; letter-spacing: 0;
}
.quest-pj-resultats li:hover .chip, .quest-pj-resultats li:focus-visible .chip { border-color: var(--seal); color: var(--seal-dark); }
.quest-pj-resultats li.deja .chip { border-style: dashed; color: var(--muted); }
.quest-pj-resultats .val-choix-vide { justify-content: center; color: var(--muted); font-size: 13px; }
#mPieceBib .val-choix-champ { width: 100%; }
.quest-pieces { margin: 6px 0 10px; padding: 10px 12px; border-radius: 12px; border: 1px solid var(--line); background: var(--paper); }
.quest-pieces-tete { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; font-size: 13.5px; } .quest-pieces-tete .muted { font-size: 12px; }
.quest-piece-gestes { display: flex; gap: 4px; flex-wrap: wrap; margin-inline-start: auto; }
.quest-piece-absente { opacity: .65; }
@media (max-width: 700px) {
  .quest-pieces-liste { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .quest-piece-gestes { width: 100%; }
  .quest-pj-gestes .btn { flex: 1 1 auto; justify-content: center; }
}

/* R649 (suite) — les gestes en pied de carte, posés après les règles de R646 :
   « Ouvrir » porte le mot, les autres leur icône seule — trois libellés côte à
   côte ne tiennent pas dans 168 px. margin-top auto les aligne d'une carte à
   l'autre, quelle que soit la longueur du nom. */
.quest-pieces-liste .quest-piece-gestes { margin-inline-start: 0; margin-top: auto; gap: 5px; flex-wrap: nowrap; width: auto; }
.quest-pieces-liste .quest-piece-ouvrir { flex: 1 1 auto; justify-content: center; min-width: 0; }
.quest-pieces-liste .quest-piece-gestes .btn.small.icon-only { flex: none; width: 30px; padding: 0; justify-content: center; }

/* ==========================================================================
   R650 — LA TÊTE D'UN QUESTIONNAIRE RESPIRE.
   Titre, pastilles, ligne d'auteur, mot du lanceur, pièces jointes,
   avancement et gestes s'empilaient à quelques pixels les uns des autres :
   on ne voyait plus où finissait un bloc et où commençait le suivant. Chaque
   partie a maintenant son air, et le mot du lanceur son intitulé.
   ========================================================================== */
/* Une colonne dont les blocs prennent toute la largeur — seul le bouton de
   retour garde sa taille (sinon la barre d'avancement se réduit à un trait et
   « ont répondu » passe à la ligne). */
.quest-tete { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
.quest-tete .quest-retour { align-self: flex-start; margin-bottom: 14px; }
.quest-tete .entry-title { margin: 0 0 10px; overflow-wrap: anywhere; }
.quest-tete .quest-chips { margin: 0 0 10px; }
.quest-tete .defline { margin: 0 0 16px; }
/* Le mot du lanceur : un bloc à lui, avec son intitulé — on ne le confond plus avec la ligne d'auteur. */
/* R676 — LE MOT DU LANCEUR N'EST PAS UNE CARTE. Son fond blanc le faisait
   passer pour un bloc de contenu au même rang que « Répondre » ou
   « Résultats », alors qu'il n'est qu'une phrase d'introduction. Fond de la
   page, contour discret, et le filet vert à gauche qui dit d'où ça vient. */
.quest-description { margin: 0 0 18px; padding: 12px 14px; border-radius: 10px;
  background: transparent; border: 1px solid var(--line); border-inline-start: 3px solid var(--seal); }
.quest-description-tete { display: flex; align-items: center; gap: 7px; margin-bottom: 6px; color: var(--muted); font-size: 12px; }
.quest-description-tete b { color: var(--ink); font-size: 12.5px; font-weight: 600; }
.quest-description-tete .ic { color: var(--seal); }
.quest-description p { margin: 0; line-height: 1.6; overflow-wrap: anywhere; }
.quest-pieces { margin: 0 0 18px; padding: 12px 14px; }
/* Pas d'aperçu (rien à dessiner, ou l'outil de rendu manque) : la carte se
   replie sur un bandeau à l'étiquette — un cadre vide de la hauteur d'une
   page ne montre rien et pousse tout le reste hors de l'écran. */
.quest-piece-vue.sans-vignette, li:not(:has(.doc-thumb)) > .quest-piece-vue { aspect-ratio: auto; height: 58px; display: flex; align-items: center; justify-content: center; }
.quest-piece-vue.sans-vignette .tag-ext, li:not(:has(.doc-thumb)) > .quest-piece-vue .tag-ext { position: static; }
.quest-piece-vue.sans-vignette .quest-piece-loupe, li:not(:has(.doc-thumb)) > .quest-piece-vue .quest-piece-loupe { position: static; margin-inline-start: 8px; opacity: 1; background: none; color: var(--muted); padding: 0; }
.quest-avancement { margin: 0 0 18px; }
/* Les gestes du lanceur : de l'air au-dessus et au-dessous, et entre eux. */
.quest-gestes { margin: 4px 0 22px; gap: 10px; row-gap: 10px; }
@media (max-width: 700px) {
  .quest-tete .quest-retour { margin-bottom: 12px; }
  .quest-description { margin-bottom: 16px; }
  .quest-pieces, .quest-avancement { margin-bottom: 16px; }
  .quest-gestes { margin: 2px 0 20px; }
  /* La barre prend sa ligne, le compte la sienne : « ont répondu » ne se coupe plus en deux. */
  .quest-avancement { flex-wrap: wrap; row-gap: 6px; }
  .quest-avancement .quest-barre { flex: 1 1 100%; max-width: none; }
}

/* ==========================================================================
   R652 — SUR TÉLÉPHONE, LES ONGLETS D'UNE LISTE S'EMPILENT.
   « À moi de valider », « En cours, lancées par moi », « Historique » : trois
   libellés longs, mis en grille par deux sous 600 px (R628). Le second passait
   sur deux lignes, le troisième restait seul, et la barre perdait sa lecture.
   Marquées « tabs-liste » (Validations, Questionnaires), elles prennent toute
   la largeur et posent UN onglet par ligne, comme un menu — la fiche d'une
   pièce garde ses six onglets par deux, où le mot est court.
   ========================================================================== */
@media (max-width: 600px) {
  .tabs.tabs-liste { width: 100%; flex-direction: column; align-items: stretch; gap: 3px; }
  .tabs.tabs-liste button, .tabs.tabs-liste > a { flex: 1 1 auto; width: 100%; padding: 11px 14px; text-align: start; font-size: 13.5px; white-space: normal; }
  .tabs.tabs-liste button .compte, .tabs.tabs-liste > a .compte { float: right; margin-inline-start: 8px; }
  /* La barre et le bouton « Lancer un questionnaire » l'un sous l'autre, chacun sur toute la largeur. */
  .quest-tete-actions { flex-direction: column; align-items: stretch; gap: 10px; }
  .quest-tete-actions .btn { width: 100%; justify-content: center; }
}

/* R653 (suite) — SUR TÉLÉPHONE, RIEN DE TOUT CELA : un filtre par ligne,
   chacun sur toute la largeur (R628). Ces garde-fous annulent le plafond et
   le plancher posés pour la rangée d'écran large ; ils viennent en FIN de
   feuille, car les règles du champ de recherche et du choix de dossier sont
   écrites plus bas que la partie « responsive » et l'emportaient. */
@media (max-width: 900px) {
  .champ-recherche { flex: 1 1 100%; min-width: 0; max-width: none; }
}
@media (max-width: 600px) {
  .filters select, .champ-filtre select,
  .barre-filtres select[name="folder"], .barre-filtres select[name="dest"] { max-width: none; }
}

/* R654 — les trois portes du rapport, sous le titre des résultats. */
.quest-rapport-liens { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
@media (max-width: 600px) { .quest-rapport-liens .btn { flex: 1 1 auto; justify-content: center; } }

/* ==========================================================================
   R655 — L'APERÇU D'UNE QUESTION ET DU QUESTIONNAIRE ENTIER.
   Chaque carte du bâtisseur porte deux vues, « Question » et « Aperçu » : la
   seconde montre le champ tel que l'invité le recevra, rendu par le serveur
   avec le code de la vraie fiche. Le bouton « Voir comme un invité » ouvre le
   questionnaire entier dans une fenêtre. Le rendu réemploie les classes de la
   fiche (quest-q, quest-choix, quest-etoiles…) : c'est le même habillage,
   posé sur un fond de papier pour dire « ceci est un aperçu ».
   ========================================================================== */
.quest-qb-vues { display: inline-flex; border: 1px solid var(--line2); border-radius: 8px; padding: 2px; gap: 2px; margin-inline-start: auto; }
.quest-qb-vues button { border: 0; background: none; font: inherit; font-size: 12px; color: var(--muted); padding: 5px 11px; border-radius: 6px; cursor: pointer; white-space: nowrap; }
.quest-qb-vues button.on { background: var(--grad); color: #fff; }
.quest-qb-vues button:not(.on):hover { color: var(--seal-dark); background: var(--seal-ghost); }
/* En aperçu, les champs d'édition de la carte s'effacent — la vue reste celle de l'invité. */
.quest-qb-q.en-apercu > .lec-label, .quest-qb-q.en-apercu > .quest-qb-opts, .quest-qb-q.en-apercu > .quest-coche { display: none; }
.quest-apercu { margin-top: 10px; padding: 12px 14px; border: 1px dashed var(--line2); border-radius: 10px; background: var(--paper2); }
.quest-apercu-tete { display: flex; align-items: center; gap: 6px; margin: 0 0 10px; font-size: 11px; color: var(--muted); }
.quest-apercu-tete .ic { color: var(--seal); }
.quest-apercu-vide { margin: 0; padding: 10px 0; color: var(--muted); font-size: 13px; }
.quest-apercu .quest-q, .quest-apercu-tout .quest-q { border: 0; padding: 0; background: none; }
.quest-apercu .quest-q-tete { margin-bottom: 8px; }
/* Un aperçu ne se remplit pas : les champs sont inactifs, mais lisibles. */
.quest-apercu [disabled], .quest-apercu-tout [disabled] { opacity: 1; cursor: default; }
.quest-apercu .quest-opt, .quest-apercu-tout .quest-opt { cursor: default; }
/* La fenêtre « Voir comme un invité » : la fiche en petit. */
.quest-apercu-tout { background: var(--bg); }
.quest-apercu-fiche { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 16px 18px; }
.quest-apercu-fiche .entry-title { margin: 0 0 6px; }
.quest-apercu-fiche .defline { margin: 0 0 12px; }
.quest-apercu-fiche .quest-q { margin-bottom: 12px; }
.quest-apercu-pieces { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.quest-apercu-pieces li { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink); }
.quest-apercu-pieces .ic { color: var(--muted); }
.quest-apercu-pied { display: flex; align-items: center; gap: 12px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.quest-apercu-pied .btn { pointer-events: none; }
@media (max-width: 700px) {
  .quest-qb-vues { margin-inline-start: 0; flex: 1 1 100%; }
  .quest-qb-vues button { flex: 1; text-align: center; }
  .quest-apercu { padding: 10px 12px; }
  .quest-apercu-fiche { padding: 12px 14px; }
}

/* ==========================================================================
   R656 — SUR GRAND ÉCRAN, L'APERÇU SE MET À CÔTÉ (option B).
   Au-delà de 1 180 px, la carte a la place de tout montrer : l'édition à
   gauche, l'aperçu à droite, en permanence, qui se redessine au fil de la
   frappe. Les deux vues n'ont plus lieu d'être — le bouton de bascule
   disparaît. En dessous, rien ne change : « Question | Aperçu ».
   ========================================================================== */
@media (min-width: 1181px) {
  .quest-qb-q.duo { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 16px; align-items: start; }
  .quest-qb-q.duo > .quest-qb-tete-q { grid-column: 1 / -1; }
  .quest-qb-q.duo > .lec-label, .quest-qb-q.duo > .quest-qb-opts, .quest-qb-q.duo > .quest-coche { grid-column: 1; }
  .quest-qb-q.duo > .quest-apercu { grid-column: 2; grid-row: 2 / span 30; margin-top: 12px; align-self: stretch; }
  /* R659 : le bouton de bascule RESTE — sur grand écran il sert à replier
     l'aperçu quand on veut toute la largeur pour écrire. Le cacher revenait à
     supprimer la fonction pour qui a un large écran : on ne la trouvait plus. */
  /* En duo, l'édition reste visible quoi qu'il arrive : la classe « en-apercu » ne masque plus rien. */
  .quest-qb-q.duo.en-apercu > .lec-label, .quest-qb-q.duo.en-apercu > .quest-qb-opts, .quest-qb-q.duo.en-apercu > .quest-coche { display: block; }
  .quest-qb-q.duo.en-apercu > .quest-coche { display: flex; }
  /* R660 — APERÇU REPLIÉ : L'ÉDITION PREND TOUTE LA LARGEUR. On gardait deux
     colonnes dont la droite était vide : la question restait tassée sur la
     moitié gauche alors qu'on avait justement demandé toute la place. */
  .quest-qb-q.duo[data-apercu-replie] > .lec-label,
  .quest-qb-q.duo[data-apercu-replie] > .quest-qb-opts,
  .quest-qb-q.duo[data-apercu-replie] > .quest-coche { grid-column: 1 / -1; }
}

/* ==========================================================================
   R664 — L'AIRE DE DÉPÔT DES PIÈCES JOINTES.
   Joindre un fichier, c'est d'abord le glisser. L'aire l'accepte et s'allume ;
   les deux boutons restent dedans pour qui préfère cliquer. Dès la première
   pièce jointe, elle se replie en une ligne discrète sous la liste — un grand
   rectangle vide au milieu d'un formulaire déjà long ne sert plus à rien.
   ========================================================================== */
.quest-pj-zone { border: 1px dashed var(--line2); border-radius: 12px; background: var(--paper2);
  padding: 20px 16px; text-align: center; transition: border-color .12s, background .12s; }
.quest-pj-zone.survol { border-color: var(--seal); background: var(--seal-ghost); }
.quest-pj-nuage { display: block; color: var(--faint); line-height: 1; margin-bottom: 6px; }
.quest-pj-zone.survol .quest-pj-nuage { color: var(--seal); }
.quest-pj-appel { margin: 0 0 2px; font-size: 14px; color: var(--ink); }
.quest-pj-limite { margin: 0 0 12px; font-size: 12.5px; color: var(--muted); }
.quest-pj-zone .quest-pj-gestes { justify-content: center; margin-top: 0; }
/* R672 — UN SEUL CADRE : la liste vit DANS l'aire de dépôt. Vide, l'aire
   s'affiche en grand ; dès la première pièce, le nuage s'efface, la liste
   prend le haut et les deux boutons passent sous un filet pointillé. */
.quest-pj-zone.repliee { padding: 12px; text-align: start; }
.quest-pj-zone.repliee .quest-pj-nuage, .quest-pj-zone.repliee .quest-pj-appel { display: none; }
.quest-pj-zone .quest-pj-liste { text-align: start; }
.quest-pj-zone.repliee .quest-pj-liste { margin: 0 0 12px; }
.quest-pj-pied { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: center; }
.quest-pj-zone.repliee .quest-pj-pied { justify-content: flex-start; padding-top: 12px; border-top: 1px dashed var(--line); }
.quest-pj-zone.repliee .quest-pj-limite { margin: 0; }
.quest-pj-zone:not(.repliee) .quest-pj-pied { flex-direction: column; gap: 10px; }
.quest-pj-zone:not(.repliee) .quest-pj-limite { order: -1; margin: 0 0 2px; }
.quest-pj-glisse { display: none; }
.quest-pj-zone.repliee .quest-pj-glisse { display: inline; }
/* R672 — UNE TOUCHE DE COULEUR, PAS UN APLAT. Le bouton reste celui de la
   maison — fond blanc, texte encre — mais son icône est verte et son contour
   s'affirme : sur le fond papier de l'aire, un contour trop fin se lisait
   comme une étiquette, et un bouton vert plein aurait volé la vedette au
   seul geste qui la mérite, « Lancer et prévenir les invités ». */
.quest-pj-btn { border-color: var(--line2); padding: 9px 15px; font-size: 13.5px; }
.quest-pj-btn .ic { color: var(--seal); }
.quest-pj-btn:hover { border-color: var(--seal); background: var(--seal-ghost); }
@media (max-width: 700px) {
  .quest-pj-zone { padding: 16px 12px; }
  .quest-pj-zone .quest-pj-gestes .btn { flex: 1 1 auto; justify-content: center; }
  .quest-pj-zone.repliee { flex-direction: column; align-items: stretch; }
}

/* R666 — la carte du rapport, à la clôture : ce qu'il contient, puis les trois sorties. */
.quest-rapport-carte { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.quest-rapport-mot b { display: flex; align-items: center; gap: 8px; font-size: 15px; margin-bottom: 3px; }
.quest-rapport-mot b .ic { color: var(--seal); }
.quest-rapport-mot .sub { display: block; max-width: 60ch; }
.quest-rapport-carte .quest-rapport-liens { display: flex; gap: 8px; flex-wrap: wrap; margin: 0; }
@media (max-width: 700px) {
  .quest-rapport-carte { flex-direction: column; align-items: stretch; }
  .quest-rapport-carte .quest-rapport-liens .btn { flex: 1 1 auto; justify-content: center; }
}

/* R671 — l'écran coché avec son action le dit, puis se tait. */
.perm-auto { margin-inline-start: 8px; color: var(--seal-dark); font-size: 11.5px; }
/* R1342 — CE QU'UN DROIT DE PAGE PORTE, dit sous son nom : une seconde ligne,
   discrète, pour que l'administrateur n'accorde pas un droit de trop. */
.perm-porte { display: block; margin-top: 2px; color: var(--muted); font-size: 11.5px; line-height: 1.45; }
@keyframes perm-souligne { 0% { background: var(--seal-soft); } 100% { background: transparent; } }
.perm-souligne { animation: perm-souligne 1.6s ease-out; border-radius: 6px; }
@media (prefers-reduced-motion: reduce) { .perm-souligne { animation: none; } }

/* R677 — la liste des personnes, quand elle flotte dans une fenêtre, passe
   au-dessus de la fenêtre elle-même (qui vit à 90). Et la fenêtre d'invitation
   garde de la hauteur : sinon la liste s'ouvrait dans un mouchoir de poche. */
.modal .val-choix-liste { z-index: 9600; box-shadow: 0 12px 30px rgba(33, 48, 46, .22); }
.modal-card .modal-body:has(.val-choix) { min-height: 280px; }
@media (max-width: 700px) { .modal-card .modal-body:has(.val-choix) { min-height: 220px; } }

/* R678 — la fenêtre qui explique pourquoi un questionnaire répondu ne se modifie plus. */
.quest-fige-liste { margin: 6px 0 0; padding-inline-start: 18px; }
.quest-fige-liste li { margin-bottom: 8px; line-height: 1.55; }
.quest-fige-liste li:last-child { margin-bottom: 0; }

/* R686 — la ligne qui annonce les traces plus anciennes : discrète, sans heure. */
.quest-trace-plus span { color: var(--muted); font-style: italic; }

/* R712 — la fenêtre qui montre une pièce jointe sans quitter le questionnaire. */
/* R721 — L'APERÇU TIENT DANS LA FENÊTRE, CENTRÉ. L'image était mesurée sur la
   HAUTEUR DE L'ÉCRAN (70 vh) alors qu'elle vit dans une fenêtre qui a, en plus,
   un en-tête et un pied : soixante-neuf et soixante-dix-neuf pixels. Sur un
   écran de huit cents pixels, cela faisait cinq cent soixante d'image pour cinq
   cent cinquante-quatre de place — le corps se mettait à défiler et l'on
   voyait une image coupée en haut et en bas. On la mesure désormais sur la
   PLACE RÉELLE : la carte est une colonne souple, le corps prend ce qui reste,
   et l'aperçu ne dépasse pas son corps. Un peu d'air au-dessus et au-dessous,
   et il est centré. */
/* R754 — L'APERÇU AU MILIEU, ET DE L'AIR AUTOUR. Le contenu était centré à
   l'horizontale mais collé aux bords à gauche et à droite : une image large
   touchait le cadre. Vingt pixels tout autour, et un centrage dans LES DEUX
   sens — c'est ce qu'on attend d'une fenêtre d'aperçu. */
.quest-piece-corps {
  min-height: 320px; display: flex; align-items: center; justify-content: center;
  padding: 20px; overflow: hidden;            /* plus de défilement : tout tient */
}
/* R721 — UNE HAUTEUR QU'ON PEUT CALCULER. Deux tentatives ont échoué avant
   celle-ci, et elles disent la même chose : dans une boîte souple, un
   POURCENTAGE de hauteur ne trouve pas à quoi se rapporter — ni « hauteur
   maximale 100 % » (ignorée, l'image reprenait ses deux mille quatre cents
   pixels), ni « hauteur 100 % » (qui a étiré la boîte au lieu de la borner).
   On calcule donc en longueurs FIXES, à partir de ce qu'on connaît : la carte
   ne dépasse pas min(88vh, 780px), son en-tête et son pied prennent environ
   cent cinquante pixels, l'air en haut et en bas vingt-huit. Il reste ceci
   pour l'aperçu — une valeur définie, que le navigateur applique toujours. */
.quest-piece-image {
  max-width: 100%; max-height: calc(min(88vh, 780px) - 190px);
  width: auto; height: auto;
  object-fit: contain; object-position: center; border-radius: 8px; display: block;
}
.quest-piece-media { width: 100%; max-width: 640px; }
/* Le cadre (PDF, texte) prend toute la place disponible, sans la dépasser. */
/* R780 — L'APERÇU PREND LA FORME D'UNE PAGE. Le cadre occupait TOUTE la
   largeur de la fenêtre : un document A4, qui est plus haut que large, s'y
   affichait perdu au milieu d'un bandeau, avec du blanc de part et d'autre et
   la visionneuse étirée. On lui donne les proportions du papier — la hauteur
   commande, la largeur en découle par le rapport A4 (1 : √2) — et on le centre.
   Il ne dépasse jamais la place disponible : c'est le plus petit des deux,
   la hauteur utile de la fenêtre ou la largeur qu'elle laisse. */
.quest-piece-cadre {
  --h-apercu: calc(min(88vh, 780px) - 190px);
  height: var(--h-apercu);
  width: min(calc(var(--h-apercu) / 1.414), 100%);
  min-height: 320px;
  margin: 0 auto;                       /* au milieu, quoi qu'il arrive */
  border: 1px solid var(--line2); border-radius: 8px; background: #fff;
  box-shadow: 0 2px 10px rgba(33,48,46,.08);   /* la page se détache du fond */
}
/* R780 : les images ont DÉJÀ leur règle plus bas — « object-fit: contain » et
   des dimensions calculées. La mienne, plus tardive, l'écrasait et une image
   très haute (600 × 2400) débordait de nouveau. On ne la garde pas : le format
   A4 ne vaut que pour les DOCUMENTS, qui s'affichent dans un cadre. */
.quest-piece-attente { color: var(--muted); font-size: 13px; }
.quest-piece-ext { display: inline-flex; align-items: center; justify-content: center; width: 76px; height: 76px;
  border-radius: 14px; background: var(--paper2); border: 1px solid var(--line2); color: var(--seal-dark);
  font-size: 18px; font-weight: 600; letter-spacing: .5px; margin-bottom: 12px; }
.quest-piece-repli .sub { margin: 0 0 14px; }
.quest-piece-vue { cursor: pointer; background: none; border: 0; padding: 0; font: inherit; text-align: inherit; }
/* Le repli aussi vit au milieu, et n'a plus de bouton : le pied porte le sien. */
.quest-piece-repli { text-align: center; padding: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px; }
.quest-piece-repli .sub { margin: 0; max-width: 34ch; }
@media (max-width: 700px) { .quest-piece-corps { padding: 14px; } }


/* ==========================================================================
   R714 — LA BARRE DE DÉFILEMENT DE LA PAGE PREND LE VERT DE LA MAISON.
   Le navigateur la dessinait en gris : sur un écran qui est vert du haut en
   bas, c'était la seule pièce qui ne l'était pas. Deux écritures, parce que
   les navigateurs ne s'entendent pas :
     · « scrollbar-color », comprise par Firefox et les Chromium récents ;
     · « ::-webkit-scrollbar », pour les autres — même dessin, plus de réglages.
   La piste reste très claire (le contenu ne doit pas paraître encadré) et le
   curseur s'assombrit quand la souris passe : on voit qu'il se prend.
   Seule la barre de la PAGE change ici ; celles des blocs intérieurs (la
   colonne des dossiers, les listes des fenêtres) gardent leur discrétion.
   ========================================================================== */
/* R777 — ET LA BARRE DE LA PAGE REDEVIENT GRISE. Elle était verte : sur une
   page longue, un trait de couleur courait le long du bord, à la teinte
   réservée aux actions — l'œil y revenait sans raison, et elle ne ressemblait
   à aucune autre barre de la maison. Elle reprend le gris du trait, comme la
   colonne des dossiers et les listes : présente quand on la cherche, invisible
   sinon. */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--line) #EDF2F0;
}
html::-webkit-scrollbar { width: 12px; height: 12px; }
html::-webkit-scrollbar-track { background: #EDF2F0; }
html::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 99px;
  border: 3px solid #EDF2F0;          /* le curseur paraît plus fin, détaché de la piste */
}
html::-webkit-scrollbar-thumb:hover { background: var(--muted); }
html::-webkit-scrollbar-corner { background: #EDF2F0; }

/* ==========================================================================
   R715 — DIRE QU'IL FAUT DESCENDRE, ET AIDER À REMONTER.
   Sur une page plus haute qu'un écran, rien ne le disait : on croyait avoir
   tout vu. Deux repères, translucides, au bord droit, ET SEULEMENT SUR
   ORDINATEUR — sur téléphone le pouce fait déjà le travail, et une pastille
   masquerait le bouton d'envoi.
     · une PASTILLE unique : un anneau qui dit l'avancement, une flèche qui
       pointe vers le bas tant qu'on n'est pas arrivé, vers le haut ensuite ;
     · un LISERÉ en bas de page, qui annonce qu'il reste à descendre et
       s'efface au premier geste, pour ne pas devenir un meuble.
   Elle ne paraît que si la page dépasse vraiment (plus d'un écran et demi),
   s'efface pendant qu'on défile et revient à l'arrêt.
   ========================================================================== */
.kz-defil {
  /* R716 — ELLE MONTE ET ELLE MAIGRIT. Posée à vingt-six pixels du bas, elle
     touchait le pied de page (« © Bold Horizon · Assistance », vingt-huit
     pixels de haut) : deux objets collés, dont l'un cachait l'autre. Elle passe
     à soixante-huit pixels du bas — le pied, plus une respiration — et perd
     six pixels de diamètre : un repère, pas un bouton d'action. */
  position: fixed; inset-inline-end: 18px; bottom: 38px; z-index: 60;
  width: 43px; height: 43px; border-radius: 50%;
  display: none; align-items: center; justify-content: center;
  border: 0; padding: 0; cursor: pointer;
  background: rgba(255, 255, 255, .72);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  color: var(--seal);
  opacity: 0; transform: translateY(6px); pointer-events: none;
  transition: opacity .22s ease, transform .22s ease, background .15s;
}
.kz-defil.on { opacity: .92; transform: none; pointer-events: auto; }
.kz-defil.discret { opacity: .35; }          /* pendant qu'on défile */
.kz-defil:hover { background: rgba(255, 255, 255, .95); opacity: 1; }
.kz-defil:focus-visible { outline: 2px solid var(--seal); outline-offset: 3px; opacity: 1; }
/* L'anneau d'avancement : un cercle dessiné par un dégradé conique. */
/* R718 — L'ANNEAU S'AMINCIT. Quatre pixels de trait, c'était une bague ; le
   repère pesait autant qu'un bouton d'action. Deux pixels suffisent : on lit
   encore la portion pleine — c'est l'avancement dans la page — sans que le
   cercle crie. La portion vide s'adoucit aussi. Ce n'est pas un « border » mais
   un dégradé circulaire : c'est lui qui permet de n'en remplir qu'une part. */
.kz-defil::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(rgba(15, 110, 86, .78) calc(var(--kz-part, 0) * 1%), rgba(15, 110, 86, .12) 0);
  /* Trou de 19,5 px dans un cercle de 43 : il reste deux pixels de trait. */
  -webkit-mask: radial-gradient(circle, transparent 0 19.5px, #000 19.5px);
  mask: radial-gradient(circle, transparent 0 19.5px, #000 19.5px);
}
.kz-defil svg { position: relative; }

/* Le liseré du bas : il dit qu'il reste à descendre. */
.kz-bord-bas {
  /* R716 : lui aussi remonte au-dessus du pied, sinon son texte s'y superpose. */
  position: fixed; inset-inline-start: 0; inset-inline-end: 0; bottom: 28px; height: 36px; z-index: 55;
  display: none; align-items: flex-end; justify-content: center;
  padding-bottom: 8px; pointer-events: none;
  /* R756 : le dégradé couvrait TOUTE LA LARGEUR et ternissait la moitié basse
     de la page — il cachait les boutons du bas.
     R758 : mais le retirer entièrement a coûté ce qu'il apportait — cette
     ombre verte, très douce, qui donnait de la profondeur au bas de page et
     disait « ça continue » avant même qu'on lise le mot. On la rend, mais
     BORNÉE : elle ne monte plus que sur trente-six pixels au lieu d'une
     moitié d'écran, et elle s'éteint sur les côtés — là où vivent les boutons
     — pour ne se voir qu'au centre, sous la pastille. Le repère retrouve sa
     douceur sans reprendre ce qu'il masquait. */
  background:
    radial-gradient(60% 100% at 50% 100%,
      rgba(14, 107, 92, .13) 0%,
      rgba(14, 107, 92, .06) 45%,
      rgba(14, 107, 92, 0) 100%);
  opacity: 0; transition: opacity .25s ease;
}
.kz-bord-bas.on { opacity: 1; }
.kz-bord-bas span {
  font-size: 12.5px; color: var(--seal-dark);
  /* R756 — LE LISERÉ NE DOIT RIEN CACHER. Son fond à quatre-vingts pour cent
     d'opacité passait DEVANT les boutons du bas de page — vu sur la fiche d'un
     questionnaire : « La bibliothèque » disparaissait derrière « Faites défiler
     pour voir la suite ». Il ne bloquait pas le clic (pointer-events: none),
     mais on ne pouvait plus lire ce qu'on visait. Le fond devient franc et
     l'ombre le détache : on lit le mot ET ce qu'il y a dessous reste net,
     puisqu'il ne couvre plus qu'une pastille au lieu d'une bande. */
  background: #fff; border-radius: 99px; padding: 4px 14px;
  box-shadow: 0 2px 10px rgba(33, 48, 46, .16);
  display: inline-flex; align-items: center; gap: 6px;
}
/* R717 — UN APPEL DU REGARD, LA PREMIÈRE FOIS SEULEMENT. En haut d'une longue
   page, la pastille ne se remarquait pas : elle est translucide, au bord, et
   rien ne bougeait. Sa flèche fait donc trois petits allers-retours — puis
   plus jamais : dès le premier geste de défilement, l'animation s'arrête et ne
   revient pas. Un appel discret, pas un clignotant. */
.kz-defil.appelle svg { animation: kzAppel 1.15s ease-in-out 3; }
@keyframes kzAppel {
  0%, 100% { transform: translateY(0); }
  45%      { transform: translateY(4px); }
}
@media (min-width: 901px) { .kz-defil, .kz-bord-bas { display: flex; } }
/* Sur le papier, ni l'un ni l'autre : ce sont des aides à l'écran. */
@media print { .kz-defil, .kz-bord-bas { display: none !important; } }
@media (prefers-reduced-motion: reduce) {
  .kz-defil, .kz-bord-bas { transition: none; }
  .kz-defil.appelle svg { animation: none; }   /* qui demande moins d'animation n'en a pas */
}

/* ==========================================================================
   R727 — MISSIONS & KANBAN. Le module prend l'habit de la maison : cartes
   crème, vert Khazina, sans-serif pour le texte, serif pour les titres. Ce
   qui est à lui : les colonnes, les cartes de tâche, le panneau latéral.
   ========================================================================== */
/* R814 — LE BANDEAU DES CHIFFRES RESPIRE COMME LE RESTE. Ses trois rangées —
   chiffres, jauge, gestes — se suivaient à HUIT pixels alors que la carte laisse
   dix-sept au-dessus et en dessous : l'intérieur était plus serré que ses bords,
   et le bloc paraissait comprimé. Elles suivent maintenant l'écart de la
   maison, le même partout. */
.mt-chiffres { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 10px; }
/* R818 — LES CHIFFRES SE RANGENT PAR PALIERS. « auto-fit » les tassait sans
   jamais passer à la ligne : à huit cent vingt pixels, six cases de cent
   trente-six — trop étroites pour leur libellé, trop nombreuses pour l'œil.
   On fixe le nombre de colonnes à chaque palier, plutôt que de laisser la
   grille décider seule. */
/* R842 : au-delà de cinq cases, « auto-fit » en pose autant que la place le
   permet — sept sur un grand écran, pour cinq compteurs. On borne à cinq. */
@media (min-width: 1101px) { .mt-chiffres { grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); } }
@media (max-width: 1100px) { .mt-chiffres { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .mt-chiffres { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) {
  /* Sur un téléphone, deux par ligne : plus étroit, le chiffre et son mot se
     chevaucheraient. */
  .mt-chiffres { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
}
.mt-chiffre { background: #FAF9F5; border-radius: 10px; padding: 12px 10px; text-align: center; }
/* R842 : la teinte du chiffre est portée par « mt-rouge », « mt-ambre »… mais
   « .mt-chiffre b » est PLUS SPÉCIFIQUE et l'écrasait — toutes les cases
   sortaient de la même encre. On ne colore donc ici que le chiffre SANS classe
   de couleur, ce qui laisse les autres parler. */
.mt-chiffre b { display: block; font-size: 24px; font-weight: 500; line-height: 1.1; }
.mt-chiffre b:not([class]) { color: var(--ink); }
.mt-chiffre span { display: block; font-size: 12px; color: #6B7A75; margin-top: 3px; }
.mt-chiffre.fort { background: #E4F1EC; }
.mt-vert { color: var(--seal); } .mt-rouge { color: #A32D2D; } .mt-ambre { color: #854F0B; } .mt-bleu { color: #185FA5; } .mt-violet { color: #534AB7; } .mt-gris { color: #5F5E5A; }
.chip.mt-prio-basse   { background: #F1EFE8; color: #444441; }
.chip.mt-prio-normale { background: #E6F1FB; color: #0C447C; }
.chip.mt-prio-haute   { background: #FAEEDA; color: #633806; }
.chip.mt-prio-urgente { background: #FCEBEB; color: #791F1F; }

/* Le Kanban : des colonnes côte à côte, qui défilent à l'horizontale s'il y en a trop. */
/* R763 — LE TABLEAU DÉFILE, LA PAGE NON. « overflow-x: auto » ne suffit pas si
   la boîte peut grandir : à trois cent vingt pixels, une colonne de deux cent
   soixante-douze plus les marges dépassait, et c'est LA PAGE ENTIÈRE qui
   glissait de côté — on perdait le menu et le titre en cherchant la troisième
   colonne. « max-width: 100% » borne la boîte, et le défilement redevient
   celui du tableau seul. */
.kb { display: flex; gap: 12px; align-items: stretch; overflow-x: auto; padding-bottom: 8px; min-height: 320px;
      max-width: 100%; }
/* R803 — LES COLONNES SE PARTAGENT TOUTE LA LARGEUR, ET NE SE BORNENT PLUS EN
   HAUTEUR.
   Elles faisaient DEUX CENT SOIXANTE-DOUZE pixels chacune, quelle que soit la
   place : sur un grand écran, trois colonnes laissaient un vide à droite plus
   large qu'une colonne — et l'on croyait qu'il manquait quelque chose. Elles
   se partagent maintenant l'espace à parts égales, avec le même écart partout.
   Et leur hauteur ne se borne plus : une colonne qui déborde ouvrait SON PROPRE
   défilement, si bien qu'on faisait défiler deux fois — la page, puis la
   colonne — pour lire une liste longue. La page défile, les colonnes suivent. */
.kb-col {
  flex: 1 1 0; min-width: 232px;
  background: #F3F1EA; border-radius: 12px;
  display: flex; flex-direction: column;
}
/* Sur un écran très étroit, une colonne fixe de 272 px ne laisse plus d'air :
   on la laisse rétrécir un peu, sans jamais descendre sous une largeur où une
   carte cesserait d'être lisible. */
@media (max-width: 380px) { .kb-col { flex: 0 0 min(272px, calc(100vw - 48px)) !important; } .kb { gap: 8px; } }
.kb-col-tete { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px 6px; font-weight: 600; font-size: 13px; color: var(--ink); }
.kb-col-tete .compte { font-weight: 500; color: #6B7A75; font-size: 12px; }
/* R803 : plus de défilement PROPRE à la colonne — c'est la page qui défile.
   Deux barres imbriquées obligeaient à défiler deux fois pour lire une liste
   longue, et l'on perdait le haut de la colonne en route. */
.kb-col-corps { flex: 1 1 auto; min-height: 60px; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 8px; }
.kb-col.survol .kb-col-corps { background: rgba(14, 107, 92, .06); border-radius: 10px; }
.kb-col-pied { padding: 6px 8px 10px; }
.kb-col-pied .btn { width: 100%; justify-content: flex-start; }
.kb-carte { background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 10px 11px; cursor: grab; box-shadow: 0 1px 2px rgba(33,48,46,.05); transition: box-shadow .12s, transform .12s; position: relative; }
.kb-carte:hover { box-shadow: 0 4px 12px rgba(33,48,46,.10); }
.kb-carte.traine { opacity: .45; transform: rotate(1.5deg); }
.kb-carte.fini { opacity: .78; }
.kb-carte.bloquee { border-color: #E24B4A; }
.kb-carte .kb-titre { font-size: 13.5px; line-height: 1.35; color: var(--ink); margin: 0; word-break: break-word; }
.kb-carte .kb-prio { position: absolute; inset-inline-start: 0; top: 10px; bottom: 10px; width: 3px; border-radius: 0 3px 3px 0; }
.kb-carte.prio-urgente .kb-prio { background: #E24B4A; } .kb-carte.prio-haute .kb-prio { background: #EF9F27; } .kb-carte.prio-normale .kb-prio { background: transparent; } .kb-carte.prio-basse .kb-prio { background: #D3D1C7; }
.kb-meta { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; font-size: 11.5px; color: #6B7A75; }
.kb-meta .kb-qui { display: inline-flex; align-items: center; gap: 5px; color: var(--ink); }
.kb-meta .kb-qui .com-avatar { width: 20px; height: 20px; font-size: 9px; }
.kb-meta .retard { color: #A32D2D; font-weight: 600; } .kb-meta .proche { color: #854F0B; font-weight: 600; }
.kb-meta .libre { color: var(--seal); font-weight: 600; }
.kb-cpt { display: flex; gap: 10px; margin-top: 6px; font-size: 11.5px; color: #6B7A75; }
.kb-cpt span { display: inline-flex; align-items: center; gap: 3px; }
.kb-vide { font-size: 12px; color: #9AA5A0; text-align: center; padding: 14px 6px; border: 1px dashed var(--line); border-radius: 8px; }
/* R796 — « JE PREND LA TÂCHE » RESTE, MAIS CESSE D'ÊTRE LE PLUS GROS. Le
   bouton occupait toute la largeur et un tiers de la hauteur de la carte : le
   geste le plus rare y prenait la place du titre. Il devient une ligne
   discrète — même geste, même endroit, mais il ne crie plus. */
/* « .btn.primary » vient après et impose son fond vert : on nomme les deux
   classes pour que la règle porte. */
.kb-carte .kb-prendre.btn.primary {
  margin-top: 6px; width: auto; align-self: flex-start;
  padding: 3px 10px; font-size: 12px; font-weight: 500;
  /* R870 — LE GESTE REDEVIENT VISIBLE. Il avait été rendu discret pour ne pas
     crier sur chaque carte libre ; à l'usage, on ne le voyait plus du tout —
     un bouton transparent au bas d'une carte se lit comme une étiquette.
     C'est pourtant le geste qui ouvre tous les autres : sans prendre la tâche,
     on ne peut ni la modifier ni la déplacer (R859). Un geste qui conditionne
     tout le reste doit se voir. */
  background: var(--seal); color: #fff; border: 1px solid var(--seal);
  box-shadow: none;
}
.kb-carte .kb-prendre.btn.primary:hover { background: var(--seal-dark); border-color: var(--seal-dark); color: #fff; }
/* « .btn.small » impose trente-quatre pixels de haut, deux fois dans la
   feuille : sur une carte qu'on veut compacte, c'est le tiers de la hauteur
   pour un geste occasionnel. On lève la borne ICI seulement — les autres
   petits boutons de la maison gardent leur taille de doigt. */
.kb-carte .kb-prendre.btn.small { min-height: 26px; padding: 3px 10px; }
/* La carte se resserre : les marges intérieures servaient six informations,
   il n'en reste que deux. */
.kb-carte { padding: 9px 11px; gap: 3px; }
/* Un titre long tenait sur deux ou trois lignes et gouvernait la hauteur. On
   le borne à DEUX lignes, avec des points de suspension : le titre entier se
   lit dans le panneau, et le tableau garde des cartes de hauteur comparable —
   c'est cette régularité qui permet de balayer une colonne des yeux. */
.kb-carte .kb-titre {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.kb-carte .kb-meta { margin: 0; font-size: 12px; }
.kb-carte .kb-titre { margin: 0; line-height: 1.35; }

/* Le panneau latéral : la tâche s'ouvre sans quitter le Kanban. */
.kb-panneau { position: fixed; top: 0; right: 0; bottom: 0; width: min(560px, 100vw); background: var(--panel); border-inline-start: 1px solid var(--line); box-shadow: -12px 0 30px rgba(33,48,46,.12); z-index: 70; display: flex; flex-direction: column; transform: translateX(100%); transition: transform .22s ease; }
.kb-panneau.on { transform: none; }
.kb-panneau-tete { display: flex; align-items: flex-start; gap: 10px; padding: 16px 18px 12px; border-bottom: 1px solid var(--line); }
.kb-panneau-tete h2 { margin: 0; font-size: 18px; flex: 1 1 auto; word-break: break-word; }
.kb-panneau-corps { flex: 1 1 auto; overflow-y: auto; padding: 14px 18px 24px; }
.kb-panneau-corps h4 { font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: #6B7A75; margin: 18px 0 8px; }
.kb-champ { display: grid; grid-template-columns: 110px 1fr; gap: 8px 12px; align-items: center; font-size: 13px; margin-bottom: 8px; }
.kb-champ > span:first-child { color: #6B7A75; }
.kb-check { list-style: none; margin: 0; padding: 0; }
.kb-check li { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 13.5px; }
.kb-check li.fait span { text-decoration: line-through; color: #9AA5A0; }
.kb-check li .iconbtn { margin-inline-start: auto; opacity: .5; } .kb-check li:hover .iconbtn { opacity: 1; }
.kb-com { display: flex; gap: 10px; padding: 8px 0; border-top: 1px solid #EEEAE0; font-size: 13px; }
.kb-com:first-child { border-top: 0; }
.kb-com .kb-com-corps b { font-size: 12.5px; } .kb-com .kb-com-corps small { color: #9AA5A0; margin-inline-start: 6px; }
.kb-com .kb-com-corps p { margin: 2px 0 0; white-space: pre-wrap; word-break: break-word; }
.kb-pj { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border: 1px solid var(--line); border-radius: 10px; margin-bottom: 6px; font-size: 13px; }
.kb-pj .tag-ext { flex: none; }
.kb-pj .kb-pj-nom { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-pj .kb-pj-src { font-size: 11px; color: #6B7A75; border: 1px solid var(--line); border-radius: 99px; padding: 1px 8px; white-space: nowrap; }
.kb-pj .kb-pj-src.bib { color: var(--seal); border-color: rgba(14,107,92,.3); }
.kb-acti { font-size: 12.5px; color: #6B7A75; padding: 4px 0; }
.kb-acti b { color: var(--ink); font-weight: 500; }
.kb-presence { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 12px; color: #6B7A75; }
.kb-presence .pt { display: inline-flex; align-items: center; gap: 4px; }
.kb-presence .pt::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: #B4B2A9; }
.kb-presence .pt.on::before { background: #1D9E75; }
.kb-lien { position: fixed; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 80; background: #21302E; color: #fff; font-size: 12.5px; padding: 8px 14px; border-radius: 99px; display: none; align-items: center; gap: 8px; }
.kb-lien.on { display: inline-flex; }
.kb-menu { position: absolute; z-index: 75; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 8px 24px rgba(33,48,46,.14); padding: 6px; min-width: 200px; }
.kb-menu button { display: flex; width: 100%; text-align: start; gap: 8px; align-items: center; background: none; border: 0; padding: 7px 10px; border-radius: 7px; font: inherit; font-size: 13px; color: var(--ink); cursor: pointer; }
.kb-menu button:hover { background: #F3F1EA; }
.kb-menu button.danger { color: #A32D2D; }
.kb-menu hr { border: 0; border-top: 1px solid var(--line); margin: 5px 0; }
/* R763 — LA BARRE DE FILTRES TIENT DANS L'ÉCRAN. Ses éléments avaient une base
   de deux cents pixels et refusaient de descendre en dessous : sur un écran de
   trois cent vingt, la barre faisait deux cent quatre-vingt-quatorze pixels
   pour deux cent quarante-six disponibles, et POUSSAIT LA PAGE ENTIÈRE de
   côté — on perdait le menu en cherchant le tableau. « min-width: 0 » autorise
   le rétrécissement, et la barre passe à la ligne au lieu de déborder. */
.kb-filtres { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; min-width: 0; max-width: 100%; }
.kb-filtres > * { min-width: 0; }
.kb-filtres .scoped-search { flex: 1 1 200px; max-width: 320px; min-width: 0; }
@media (max-width: 560px) {
  /* Sur un téléphone, la recherche prend toute la ligne et les listes se
     partagent la suivante : chacune reste lisible au lieu d'être écrasée. */
  .kb-filtres { width: 100%; }
  .kb-filtres .scoped-search { flex: 1 1 100%; max-width: none; }
  .kb-filtres select { flex: 1 1 calc(50% - 4px); }
}
.kb-droits td, .kb-droits th { padding: 6px 8px; font-size: 12.5px; }
.kb-droits td.c { text-align: center; }
@media (max-width: 900px) {
  /* Sur un téléphone, elles reprennent leur largeur propre et défilent
     latéralement : les mettre côte à côte les rendrait illisibles. */
  /* R818 — LA COLONNE PLEINE LARGEUR EST RÉSERVÉE AU TÉLÉPHONE. À huit cent
     vingt pixels — une tablette tenue en paysage — elle faisait SIX CENT
     QUATRE-VINGT-NEUF pixels : une seule colonne à l'écran, et il fallait
     glisser latéralement pour voir « en cours ». Or à cette largeur, trois
     colonnes de deux cent trente tiennent côte à côte, et c'est tout l'intérêt
     d'un tableau : voir les trois états d'un coup d'œil.
     La règle ne s'applique donc plus qu'en dessous de six cents pixels. */
  .kb-col { flex: 1 1 0; min-width: 218px; }
}
/* Sous six cents pixels, les colonnes reprennent leur largeur propre et
   glissent latéralement : côte à côte, elles seraient illisibles. Cette règle
   vient APRÈS celle des neuf cents — placée avant, elle était écrasée, et le
   téléphone gardait des colonnes de deux cent dix-huit pixels. */
@media (max-width: 600px) {
  .kb-col { flex: 0 0 84vw; min-width: 0; }
  .kb-panneau { width: 100vw; }
  .kb-champ { grid-template-columns: 1fr; gap: 2px; }
}
@media print { .kb-panneau, .kb-lien, .kb-menu { display: none !important; } }
/* R727 — la sous-entrée du menu : un cran en retrait, un trait discret qui dit d'où elle descend. */
.menu-item.menu-sous { padding-inline-start: 30px; position: relative; }
.menu-item.menu-sous::before { content: ''; position: absolute; inset-inline-start: 17px; top: 0; bottom: 50%; width: 8px; border-inline-start: 1px solid var(--line2); border-bottom: 1px solid var(--line2); border-radius: 0 0 0 6px; }
/* R728 — le calendrier d'une mission : sept colonnes, les tâches sur leur échéance. */
.kb-cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.kb-cal-tete { font-size: 11.5px; color: #6B7A75; text-align: center; padding: 4px 0; text-transform: uppercase; letter-spacing: .04em; }
.kb-cal-jour { min-height: 84px; background: #FAF9F5; border-radius: 8px; padding: 6px; font-size: 12px; }
.kb-cal-jour.vide { background: transparent; }
.kb-cal-jour.auj { outline: 2px solid var(--seal); outline-offset: -2px; }
.kb-cal-jour > b { display: block; font-weight: 500; color: #6B7A75; margin-bottom: 4px; }
.kb-cal-jour.auj > b { color: var(--seal); }
.kb-cal-t { display: block; background: #fff; border: 1px solid var(--line); border-inline-start-width: 3px; border-radius: 6px; padding: 3px 6px; margin-top: 3px; color: var(--ink); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; }
.kb-cal-t.prio-urgente { border-inline-start-color: #E24B4A; } .kb-cal-t.prio-haute { border-inline-start-color: #EF9F27; } .kb-cal-t.prio-basse { border-inline-start-color: #D3D1C7; } .kb-cal-t.prio-normale { border-inline-start-color: var(--seal); }
.kb-cal-t.retard { background: #FCEBEB; } .kb-cal-t.fini { opacity: .55; text-decoration: line-through; }
@media (max-width: 700px) { .kb-cal { gap: 2px; } .kb-cal-jour { min-height: 54px; padding: 3px; } .kb-cal-t { font-size: 10px; padding: 2px 3px; } }
/* R729 — l'ajout d'une tâche se fait SUR PLACE, et nos fenêtres remplacent celles du navigateur. */
.kb-neuf { margin-top: 6px; }
.kb-neuf input { width: 100%; font: inherit; font-size: 13px; padding: 8px 10px; border: 1px solid var(--seal); border-radius: 8px; background: #fff; }
.kb-neuf input:focus { outline: none; box-shadow: 0 0 0 3px var(--seal-soft); }
.kb-neuf-gestes { display: flex; gap: 6px; margin-top: 6px; }
.kb-neuf-gestes .btn { flex: 1; justify-content: center; }
.kb-demande { position: fixed; inset: 0; z-index: 90; background: rgba(33,48,46,.34); display: flex; align-items: center; justify-content: center; padding: 20px; }
.kb-demande-carte { background: var(--panel); border-radius: 12px; border: 1px solid var(--line); box-shadow: 0 12px 34px rgba(33,48,46,.18); padding: 18px 20px; width: min(420px, 100%); }
.kb-demande-carte h3 { margin: 0 0 10px; font-size: 16px; }
.kb-demande-carte p { margin: 0 0 14px; font-size: 13.5px; color: #4A5A55; }
.kb-demande-carte label { display: block; font-size: 12.5px; color: #6B7A75; margin-bottom: 14px; }
.kb-demande-carte input { width: 100%; margin-top: 5px; font: inherit; font-size: 14px; padding: 8px 10px; border: 1px solid var(--line2); border-radius: 8px; }
.kb-demande-gestes { display: flex; gap: 8px; justify-content: flex-end; }
/* Le « ⋯ » d'une carte : discret au repos, net au survol ET au focus clavier. */
/* R729 — INVISIBLE N'EST PAS ABSENT. Posé à « opacity: 0 », le bouton restait
   dans l'ordre du clavier mais ne se voyait jamais — et un navigateur peut
   sauter ce qui n'a aucune surface. On le garde toujours PRÉSENT, très pâle au
   repos, net au survol et au focus : il se tabule, et il se voit quand on
   l'atteint. */
.kb-carte .kb-plus { position: absolute; right: 4px; top: 4px; border: 0; background: none; font: inherit; font-size: 15px; line-height: 1; color: #C5CDC9; padding: 4px 6px; border-radius: 6px; cursor: pointer; transition: color .12s, background .12s; }
.kb-carte:hover .kb-plus { color: #6B7A75; }
.kb-carte .kb-plus:focus-visible { color: var(--seal); background: var(--seal-soft); outline: 2px solid var(--seal); outline-offset: 1px; }
.kb-carte .kb-plus:hover { background: #F3F1EA; color: var(--ink); }
@media (hover: none) { .kb-carte .kb-plus { color: #6B7A75; } }
/* R731 — la carte portée au doigt : elle suit, légèrement soulevée. */
.kb-carte.kb-porte { position: fixed; z-index: 95; pointer-events: none; opacity: .95; transform: rotate(2deg); box-shadow: 0 12px 28px rgba(33,48,46,.22); }
/* Au clavier : la carte qui a le focus se voit nettement — on la déplace aux flèches. */
.kb-carte:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; box-shadow: 0 4px 14px rgba(33,48,46,.12); }
/* Le rappel du geste, sous le tableau : discret, mais il faut qu'on le sache. */
.kb-aide { font-size: 12px; color: #6B7A75; margin: 10px 2px 0; }
.kb-aide kbd { font: inherit; font-size: 11px; border: 1px solid var(--line2); border-bottom-width: 2px; border-radius: 5px; padding: 1px 5px; background: #FAF9F5; }
/* R732 — le bandeau « Annuler », l'aire de dépôt, et les gestes d'un commentaire. */
.kb-retour { position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%); z-index: 92; display: flex; align-items: center; gap: 10px;
  background: #21302E; color: #fff; font-size: 13px; padding: 9px 10px 9px 16px; border-radius: 99px; box-shadow: 0 8px 24px rgba(33,48,46,.28); }
.kb-retour .btn { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.28); color: #fff; }
.kb-retour .btn:hover { background: rgba(255,255,255,.24); }
.kb-retour .kb-retour-x { color: rgba(255,255,255,.7); }
.kb-retour .kb-retour-x:hover { color: #fff; }
.kb-panneau-corps.kb-depot { outline: 2px dashed var(--seal); outline-offset: -8px; background: var(--seal-soft); }
.kb-com-corps { position: relative; }
/* R896 — LES GESTES D'UN COMMENTAIRE OCCUPENT LEUR PLACE.
   « float: right » les sortait du flux : ils ne poussaient rien, et venaient se
   coller à la date — par endroits la chevaucher. En flex, un espace élastique
   les pousse à droite ET leur réserve leur largeur. */
.kb-com-gestes { display: inline-flex; gap: 4px; margin-inline-start: auto; }
.kb-com-gestes button { border: 0; background: none; font: inherit; font-size: 11.5px; color: #6B7A75; cursor: pointer; padding: 0; }
.kb-com-gestes button:hover { color: var(--seal); text-decoration: underline; }
.kb-com:hover .kb-com-gestes button, .kb-com-gestes button:focus-visible { color: var(--ink); }
/* R897 : la règle du bouton « copier le lien » est partie avec lui. Un style
   que plus rien ne porte se lit comme un élément qu'on aurait oublié. */
/* R735 — la Liste se trie : les en-têtes deviennent des liens, discrets mais clairs. */
.card table.table thead a { color: inherit; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; }
.card table.table thead a:hover { color: var(--seal); text-decoration: underline; }
/* R738 — les étiquettes d'une carte : discrètes, sous les méta. */
.kb-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.kb-tags span { font-size: 10.5px; color: #4A5A55; background: #EFEDE6; border-radius: 99px; padding: 1px 7px; }
/* R739 — les sous-tâches dans le panneau : de vraies tâches, pas des cases. */
.kb-sous { list-style: none; margin: 0 0 8px; padding: 0; }
.kb-sous li { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 13.5px; border-bottom: 1px solid #F1EFE8; }
.kb-sous li:last-child { border-bottom: 0; }
.kb-sous li a { color: var(--ink); text-decoration: none; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-sous li a:hover { text-decoration: underline; }
.kb-sous li small { color: #6B7A75; font-size: 11.5px; white-space: nowrap; }
.kb-sous li.fait a { text-decoration: line-through; color: #9AA5A0; }
.kb-mere { font-size: 12.5px; color: #6B7A75; margin: 0 0 12px; }
.kb-mere a { color: var(--seal); }
/* R742 — une tâche qui en attend une autre le dit, sans crier. */
.kb-attente { font-size: 12.5px; color: #854F0B; background: #FAEEDA; border-radius: 8px; padding: 7px 10px; margin: 0 0 12px; }
.kb-attente a { color: #633806; }
.kb-cpt .attend { color: #854F0B; font-weight: 600; }
/* R750 — L'ERREUR SOUS LE CHAMP QUI L'A CAUSÉE. Un message posé en tête du
   formulaire oblige à remonter, à lire, puis à redescendre chercher lequel des
   champs est en cause. Sous le champ, il n'y a rien à chercher.

   R751 — ET DANS L'HABIT DE LA MAISON. J'avais écrit une couleur en dur
   une couleur en dur et une graisse à moi : le message ne ressemblait à aucun autre de
   Khazina. Il prend maintenant les MÊMES variables que « .flash » et
   « .msg-err » — fond, teinte, bordure —, la même icône, le même arrondi. Il
   est simplement plus compact, parce qu'il vit sous un champ et non en tête de
   page. Le jour où l'on changera « --err », il changera avec tout le reste. */
.kz-err-champ {
  display: flex; align-items: center; gap: 8px;
  margin: 6px 0 0; padding: 7px 11px;
  font-size: 12.5px; line-height: 1.35;
  background: var(--err-bg); color: var(--err);
  border: 1px solid var(--err); border-radius: 9px;
  animation: fadeUp .25s ease both;
}
.kz-err-champ svg { flex: 0 0 auto; }
/* R751 — LE CHAMP MARQUÉ DOIT GAGNER. Ma règle avait moins de poids que celle
   qui habille les champs des formulaires : la bordure rouge ne prenait pas, et
   le champ restait blanc à côté d'un message rouge. On la rend plus précise —
   la classe deux fois — plutôt que de recourir à « !important », qui ferait
   taire toute règle future au lieu de la surpasser proprement. */
/* R763 — LA BORDURE SUFFIT, LE FOND EST DE TROP. Un champ en faute était rempli
   de rose : sur un mot de passe, le texte saisi se lisait mal, et deux surfaces
   colorées l'une sur l'autre — le champ ET le message dessous — donnaient à la
   page un air d'alarme. La bordure rouge dit déjà « c'est ici » ; le fond ne
   fait que crier plus fort. On le retire, et le champ reste lisible : c'est
   dedans qu'on doit corriger. */
input.en-faute.en-faute, select.en-faute.en-faute, textarea.en-faute.en-faute,
.lec-label input.en-faute.en-faute, .lec-label select.en-faute.en-faute,
.form-bloc input.en-faute.en-faute, .form-bloc select.en-faute.en-faute {
  border-color: var(--err); background: #fff;
}
input.en-faute.en-faute:focus, select.en-faute.en-faute:focus, textarea.en-faute.en-faute:focus {
  outline: none; border-color: var(--err); box-shadow: 0 0 0 3px var(--err-bg);
}
@media (prefers-reduced-motion: reduce) { .kz-err-champ { animation: none; } }
/* R754 — LA FENÊTRE D'APERÇU : VINGT PIXELS DES BORDS, ET AU MILIEU.
   Demandé : la carte ne touche jamais le bord de l'écran, et son contenu est
   centré dans les deux sens. Le reste de la maison garde ses seize pixels ;
   seule cette fenêtre-ci, qui montre une pièce en grand, prend ses vingt. */
#mPiece { padding: 20px; align-items: center; justify-content: center; }
#mPiece .modal-card { max-height: calc(100vh - 40px); max-height: calc(100dvh - 40px); margin: 0; }
#mPiece .modal-body { display: flex; align-items: center; justify-content: center; }
/* R761 — « (Kanban) » dit la MÉTHODE, pas le besoin : il se lit en second.
   Un ton plus clair et un peu plus petit suffisent — on garde l'information
   sans qu'elle concurrence le nom. */
.menu-item .menu-note { opacity: .62; font-weight: 400; }
h1 .titre-note { color: #6B7A75; font-weight: 400; font-size: .78em; }
/* R763 — LA BARRE D'OUTILS DU KANBAN SE REPLIE. Ses deux moitiés — les filtres
   et les boutons — refusaient de rétrécir : sur un écran de 320 pixels elles
   poussaient la page entière de côté. Elles peuvent maintenant descendre sous
   leur largeur naturelle et passer à la ligne ; sur un téléphone, chacune prend
   toute la largeur, ce qui les rend plus lisibles qu'écrasées côte à côte. */
.kb-barre { min-width: 0; max-width: 100%; }
.kb-barre > * { min-width: 0; }
.kb-barre-gestes { flex-wrap: wrap; }
@media (max-width: 560px) {
  .kb-barre-gestes { width: 100%; }
  .kb-barre-gestes .btn { flex: 1 1 auto; justify-content: center; }
}

/* ==========================================================================
   R765 — LE BLOC DU COMPTE, ET LA RÉVISION DU RESPONSIVE DE L'EN-TÊTE
   --------------------------------------------------------------------------
   L'en-tête peut porter, selon les droits et le travail en attente : le logo,
   la recherche, JUSQU'À QUATRE pastilles (pages OCR, validations à donner,
   questionnaires à remplir, lectures en attente), la cloche, et le compte.
   Mesuré : quatre pastilles avec leur texte pèsent près de trois cents pixels.
   La règle de repli va donc du moins utile au plus utile, dans cet ordre :
   le NOM du compte cède le premier, puis le TEXTE des pastilles, puis la
   RECHERCHE devient un bouton. Le logo, la cloche et le compte ne cèdent
   jamais — ce sont les repères.
   ========================================================================== */
.usermenu > summary { display: inline-flex; }
.usermenu { flex: 0 0 auto; }
/* La bande des pastilles : en ligne, sans retour, et jamais plus large que
   la place que la barre lui laisse. */
.topbadges { display: flex; align-items: center; gap: 8px; flex: 0 1 auto; min-width: 0; }
.topbadges:empty { display: none; }
.um-decl {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 3px 8px 3px 3px; border-radius: 99px;
  border: 1px solid transparent; transition: background .15s, border-color .15s;
}
.um-decl:hover { background: var(--seal-soft); border-color: #CFE6DE; }
.usermenu > summary:focus-visible { outline: none; }
.usermenu > summary:focus-visible .um-decl {
  outline: 3px solid rgba(14,107,92,.28); outline-offset: 1px;
  background: var(--seal-soft); border-color: #CFE6DE;
}
.um-txt { display: none; flex-direction: column; line-height: 1.15; min-width: 0; }
.um-nom { font-size: 13px; font-weight: 500; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.um-role { font-size: 11px; color: var(--muted); text-transform: capitalize; }
/* R772 — LE CHEVRON PIVOTE, PAS TOUT LE MENU. « .usermenu .ic » atteignait
   TOUTES les icônes contenues dans le menu du compte — validation, tâches,
   questionnaires, corbeille, réglages… — et « [open] » les retournait donc
   toutes en même temps, la tête en bas. On ne vise plus que le chevron du
   déclencheur, qui est le seul à devoir tourner. */
.um-decl > .ic { color: var(--muted); flex: 0 0 auto; transition: transform .18s ease; }
.usermenu[open] .um-decl > .ic { transform: rotate(180deg); }
.usermenu[open] .um-decl { background: var(--seal-soft); border-color: #CFE6DE; }
.usermenu[open] .avatar { background: var(--seal); color: #fff; border-color: var(--seal); }

/* Le nom ne paraît qu'au-dessus de 1280 px : en dessous, quatre pastilles et
   une recherche de cinq cent vingt pixels ne lui laissent pas la place, et la
   recherche passe avant. */
@media (min-width: 1280px) { .um-txt { display: flex; } }

/* Le texte des pastilles s'efface plus tôt qu'avant — à 1100 au lieu de 700 :
   c'est précisément entre 820 et 1100 que la barre était le plus serrée. */
/* R767 — LES QUATRE PASTILLES SE COMPORTENT PAREIL. Deux d'entre elles — les
   pages OCR et les pièces en lecture — n'avaient AUCUN mot, même sur un grand
   écran : on voyait une icône et un nombre, sans savoir de quoi il s'agissait
   sans survoler. Elles ont maintenant leur mot, et toutes se replient au même
   palier. Le mot vaut aussi sur un téléphone, où le survol n'existe pas : c'est
   « aria-label » qui le porte alors, atteignable au doigt comme au lecteur
   d'écran. */
.badgebtn .badge-txt { font-weight: 600; font-size: 12.5px; }
@media (max-width: 1100px) { .badgebtn .badge-txt { display: none; } }

/* La recherche se rétracte, mais garde de quoi lire ce qu'on y tape. */
.topsearch { min-width: 0; }
@media (min-width: 901px) { .topsearch { min-width: 200px; } }

/* Sur un téléphone, on resserre les écarts plutôt que de rien retirer. */
@media (max-width: 480px) {
  .um-decl { gap: 3px; padding: 0; border: 0; background: none; }
  .um-decl > .ic { width: 12px; height: 12px; margin-inline-end: 1px; }
  /* Le bloc ne doit pas être plus large que l'avatar plus son chevron : sans
     cela il pesait soixante-deux pixels au lieu de trente-six et poussait la
     barre dehors — mesuré à 390 comme à 320. */
  .usermenu, .usermenu > summary, .um-decl { flex: 0 0 auto; }
  .usermenu[open] .um-decl { background: none; border-color: transparent; }
}

/* R765 — LE CAS OÙ TOUT S'ALLUME EN MÊME TEMPS. Mesuré : sur un téléphone de
   480 pixels avec SIX pastilles — cas rare mais possible quand tout attend à
   la fois —, la barre débordait de vingt-quatre pixels, et de soixante-six sur
   un écran de 320. Deux mesures, dans cet ordre :
   1. les pastilles se serrent et n'affichent plus que leur compte ;
   2. si cela ne suffit pas, elles DÉFILENT à l'horizontale dans leur propre
      bande — on les fait glisser du doigt — plutôt que de pousser le compte
      et la cloche hors de l'écran. Les repères restent ; ce qui varie glisse. */
@media (max-width: 700px) {
  .topbar { flex-wrap: nowrap; }
  .topbar .badgebtn b { font-size: 11.5px; }
}
@media (max-width: 700px) {
  /* Les pastilles se PARTAGENT la place qui reste, entre la recherche et la
     cloche : elles rétrécissent ensemble au lieu de pousser les repères
     dehors.
     ET L'ÉCART SE RESSERRE. Le vrai coupable n'était pas les pastilles mais
     les QUATORZE PIXELS entre chaque élément : à dix éléments, cela fait cent
     vingt-six pixels d'air, un tiers d'un écran de téléphone. Six suffisent. */
  .topbar { overflow: hidden; gap: 6px; padding: 0 8px; }
  .topbadges { flex: 0 0 auto; }
  /* La bande prend ce qui reste, et fait glisser ses pastilles plutôt que de
     pousser la cloche et le compte hors de l'écran. */
  .topbadges {
    /* R779 : « flex: 1 1 auto » lui faisait prendre toute la place restante et
       collait les pastilles au bouton de recherche, à gauche. Elle ne prend
       plus que sa taille — et ne RÉTRÉCIT qu'en cas de besoin, pour continuer
       de faire glisser ses pastilles quand elles sont trop nombreuses. */
    flex: 0 1 auto; min-width: 0;
    /* R784 : la poussée est passée sur le bouton de recherche, qui ouvre le
       groupe ; la bande ne la porte plus, sinon elle s'en détacherait. */
    overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -ms-overflow-style: none;
    /* « overflow-x: auto » rogne AUSSI en hauteur : sans cette respiration,
       la bulle de compte, posée sur le coin de l'icône, était coupée net. */
    padding: 5px 0; margin: -5px 0;
  }
  .topbadges::-webkit-scrollbar { display: none; }

  /* R765 — SUR UN TÉLÉPHONE, UNE PASTILLE DEVIENT UNE ICÔNE ET SON COMPTE.
     Serrée à trente-quatre pixels, elle ne montrait plus qu'un ovale vide :
     l'icône et le nombre s'y disputaient la place et sortaient tous deux. On
     garde l'ICÔNE, qui dit de quoi il s'agit, et le NOMBRE passe en petite
     bulle sur son coin — exactement ce que fait déjà la cloche à côté, donc
     rien de nouveau à apprendre. */
  .topbadges .badgebtn {
    position: relative; width: 34px; min-width: 34px; max-width: 34px;
    padding: 0; border-radius: 50%; justify-content: center;
    /* Une règle plus haut posait « overflow: hidden » pour serrer les
       pastilles : elle rognait la bulle de compte, qui déborde exprès sur le
       coin. Ici la largeur est fixe, il n'y a plus rien à rogner. */
    overflow: visible;
  }
  .topbadges .badgebtn .ic { margin: 0; }
  /* R766 — LA BULLE GARDE LA COULEUR DE SA PASTILLE. J'avais mis toutes les
     bulles en vert : les pastilles de l'en-tête, ambrées sur un bureau,
     devenaient vertes sur un téléphone — et le vert n'appartient qu'à la
     cloche des notifications. On perdait le repère qui dit, d'un coup d'œil,
     de quelle famille relève ce qui attend. La bulle reprend donc la teinte
     ambrée que la pastille porte déjà, et son chiffre se lit en blanc. */
  .topbadges .badgebtn b {
    position: absolute; top: -3px; inset-inline-end: -3px; margin: 0;
    background: var(--warn); color: #fff; font-size: 9.5px; font-weight: 700;
    min-width: 15px; height: 15px; padding: 0 3px; border-radius: 99px;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 0 0 2px var(--panel);
  }
  /* La cloche, elle, reste verte : c'est son signe, et lui seul. */
  .badgebtn.notif.on b { background: var(--seal); color: #fff; }
  .topbadges .badgebtn .badge-txt { display: none; }
  /* Cette règle venait APRÈS celle de la bande et l'emportait : son
     « overflow: hidden » rognait la bulle de compte. Elle ne vise plus que
     les pastilles hors de la bande, s'il en reste. */
  .topbar > .badgebtn {
    flex: 0 1 auto; min-width: 30px; max-width: 46px;
    overflow: hidden; justify-content: center;
  }
  .brand-logo { max-width: 62px; }
}
@media (max-width: 380px) {
  .topbar { gap: 6px; padding-inline-start: 6px; padding-inline-end: 6px; }
  .topbadges .badgebtn { width: 30px; min-width: 30px; max-width: 30px; }
  .brand-logo { max-width: 46px; }
}
@media (prefers-reduced-motion: reduce) { .um-decl > .ic { transition: none; } }

/* ==========================================================================
   R769 — LES DROITS RANGÉS PAR MODULE
   --------------------------------------------------------------------------
   Vingt-quatre cases à la file ne se lisaient pas : pour savoir ce qu'une
   personne peut faire dans un module, il fallait parcourir toute la liste.
   Chaque famille a maintenant son titre et son bloc. La grille reste la même
   à l'intérieur — on ne change que le regroupement, pas la façon de cocher.
   ========================================================================== */
.perm-liste { display: block; }
.perm-famille { margin: 0 0 14px; }
.perm-famille:last-child { margin-bottom: 2px; }
.perm-famille-nom {
  display: block; font-size: 11.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--seal); margin: 0 0 5px;
  padding-bottom: 4px; border-bottom: 1px solid var(--line);
}
.perm-cases { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 2px 12px; }
/* Les PAGES gardent leur grille d'un seul tenant : elles n'ont pas de familles,
   ce sont des écrans, et les regrouper n'apporterait rien. */
.perm-pages { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 2px 12px; }
@media (max-width: 560px) { .perm-cases, .perm-pages { grid-template-columns: 1fr; } }

/* ==========================================================================
   R770 — L'ESPACEMENT DES FORMULAIRES : UNE RÈGLE, PAS UN RATTRAPAGE
   --------------------------------------------------------------------------
   Signalé plusieurs fois, et toujours corrigé au cas par cas : les étiquettes,
   les champs et les blocs se touchent. Mesuré dans le panneau du Kanban : huit
   pixels entre deux lignes, douze entre l'étiquette et son champ — l'œil ne
   sait plus ce qui va ensemble.

   La maison a pourtant son échelle depuis longtemps : « --e2 » pour ce qui est
   proche, « --e3 » pour les champs d'un formulaire, « --e4 » pour séparer deux
   blocs. Le Kanban ne l'avait jamais suivie. On l'applique ici, et l'on énonce
   la règle pour tout le projet :

     · entre une ÉTIQUETTE et son champ ......... --e2 (8 px)
     · entre deux LIGNES d'un même formulaire ... --e3 (12 px)
     · entre deux BLOCS ......................... --e4 doublé (40 px)

   Les trois distances sont différentes : c'est cette différence, et non la
   valeur absolue, qui dit à l'œil ce qui va ensemble.

   R771 — ET ELLES RESTENT SERRÉES. J'avais pris « --e4 » entre les lignes,
   soit vingt pixels : le formulaire respirait, mais il s'étirait sur une
   hauteur que le reste du projet n'a nulle part — le panneau demandait à
   défiler pour ce qui tenait avant. On revient à « --e3 », la mesure que la
   maison emploie déjà partout ailleurs pour les champs d'un formulaire. Ce
   qui manquait n'était pas de la place : c'était la DIFFÉRENCE entre les
   trois distances, et douze contre huit suffit à la marquer.
   ========================================================================== */
.kb-champ {
  gap: var(--e2) 16px;
  margin-bottom: var(--e3);
  align-items: start;
}
/* L'étiquette se pose sur la même ligne que le début du champ, sans être
   collée : sur un champ haut — une description, une liste — elle restait
   centrée au milieu du vide. */
.kb-champ > span:first-child { padding-top: 8px; line-height: 1.3; }
.kb-champ:last-child { margin-bottom: 0; }

/* Un bouton isolé au milieu d'un formulaire respire des deux côtés : sans
   cela, « Je prends la tâche » se collait au champ du dessus. */
#kbPanneauCorps > button,
#kbPanneauCorps > .kb-gestes,
#kbPanneauCorps > [data-prendre] { margin: var(--e3) 0; }

/* Les blocs du panneau — commentaires, pièces, temps, sous-tâches — se
   séparent nettement les uns des autres. */
#kbPanneauCorps > h4,
#kbPanneauCorps > .kb-bloc { margin-top: calc(var(--e4) * 1.5); }

/* La même règle pour les formulaires en colonne de la maison, qui souffraient
   du même tassement. */
.lec-label { gap: var(--e1); }
.form-bloc > .lec-label { margin-bottom: var(--e3); }
.form-bloc > .lec-label:last-of-type { margin-bottom: var(--e2); }

/* R786 — LA LIGNE OÙ L'ON REVIENT SE DÉSIGNE. Après avoir répondu, on retombe
   sur la liste : sans repère, il faut chercher des yeux le questionnaire qu'on
   vient de quitter. La ligne visée s'éclaire quelques secondes, puis s'efface —
   assez pour la trouver, pas assez pour rester dans le chemin. */
.val-row:target {
  animation: kzViser 2.6s ease-out 1;
  scroll-margin-top: calc(var(--h-topbar, 55px) + 16px);
}
@keyframes kzViser {
  0%, 55% { background: var(--seal-soft); box-shadow: inset 3px 0 0 var(--seal); }
  100%    { background: transparent;      box-shadow: inset 3px 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .val-row:target { animation: none; box-shadow: inset 3px 0 0 var(--seal); }
}

/* R787 — L'OBLIGATION SE MARQUE, LE RESTE SE TAIT. La page disait
   « (facultatif) » derrière chaque champ libre : sur six champs dont un seul
   est requis, on répétait cinq fois ce qui n'a pas besoin d'être dit. On
   inverse — une étoile rouge sur ce qui est OBLIGATOIRE, rien ailleurs — et
   la page se lit d'un coup d'œil. */
/* L'ÉTOILE RESTE SUR LA LIGNE DU LIBELLÉ. « lec-label » dispose ses enfants en
   COLONNE : un span y devient un bloc à lui seul, et l'étoile tombait sous le
   mot. On enveloppe donc le texte ET son étoile dans un même bloc, qui occupe
   une ligne — et à l'intérieur, ils restent côte à côte. */
.lec-label > .lbl { display: block; }
.oblig { color: var(--err); font-weight: 700; margin-inline-start: 2px; }


/* R788 — QUAND LA RANGÉE NE TIENT PLUS, ELLE SE RANGE EN COLONNE. Elle passait
   « à la ligne » sans changer de dessin : les onglets restaient à gauche et le
   bouton tombait dessous, décalé, comme s'il avait glissé. Mesuré sur la page
   des missions à 768 pixels — ses onglets sont plus larges que ceux des
   questionnaires : cinquante-quatre pixels d'écart entre les deux, et un
   bouton à cinq cent soixante et un du bord droit.
   Le basculement se faisait à six cents ; il se fait désormais dès que la
   place manque vraiment. En colonne, le bouton prend toute la largeur et se
   pose franchement sous les onglets. */
@media (max-width: 900px) {
  .quest-tete-actions { flex-direction: column; align-items: stretch; gap: 10px; }
  .quest-tete-actions .btn { width: 100%; justify-content: center; }
}

/* R1327 — LA LISTE « mc-equipe » A ÉTÉ RETIRÉE, ET SES RÈGLES AVEC.
   Plus aucun élément ne portait cette classe : décor mort, que personne ne
   voyait. Elle est citée ici parce qu'elle cachait une phrase française dans
   un « content: » — du texte que ni PHP ni le pont ne peuvent traduire, et
   qu'aucun des treize cliquets ne regardait. Le quatorzième regarde le CSS. */

/* R790 — LE BLOC DE L'OBJECTIF. Le titre et la phrase se détachaient trop : un
   saut de ligne les séparait comme deux idées, alors que l'un annonce l'autre.
   Ils se suivent maintenant de près, et l'icône se cale sur le titre plutôt
   que de flotter en haut du bloc. */
.msg .kz-objectif { display: flex; flex-direction: column; gap: 2px; }
.msg .kz-objectif b { line-height: 1.3; }
.msg .kz-objectif span { line-height: 1.45; }

/* R792 — LES RANGÉES À DEUX COLONNES DU FORMULAIRE DE MISSION. La classe
   « duo » n'avait aucune règle hors du bâtisseur de questions : les champs
   s'empilaient sans l'écart de la maison entre eux — mesuré, zéro pixel. Ils
   se rangent maintenant côte à côte sur un écran large, l'un sous l'autre sur
   un téléphone, et gardent partout l'espacement des formulaires. */
.mc-duo { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--e3) 16px; }
.mc-duo > .lec-label { margin-bottom: 0; }
/* R801 — LA RANGÉE DES DATES GARDE L'ÉCART DE LA MAISON EN DESSOUS. Ses
   enfants ont leur marge annulée pour que la grille commande ; mais la rangée
   elle-même n'en avait aucune, et le champ suivant — le sélecteur de
   personnes — s'y collait de douze pixels au lieu des vingt qui séparent les
   autres blocs. */
/* Les blocs du formulaire se suivent à VINGT-QUATRE pixels — mesuré sur les
   autres. La rangée n'ayant aucune marge propre, ses enfants portaient déjà
   celle du bas : ajouter « --e4 » par-dessus donnait trente-deux. On pose la
   marge sur la RANGÉE et on la retire à ses enfants, pour qu'un seul écart
   compte. */
.mc-duo { margin-bottom: var(--e3); }
@media (max-width: 640px) { .mc-duo { grid-template-columns: 1fr; } }

/* R797 — LE PLI DU PANNEAU. Il ne doit pas ressembler à un bouton : c'est une
   invitation à en voir plus, pas une action. Un simple mot, un chevron, et la
   même règle d'espacement que les champs qu'il précède. */
.kb-plus-detail { margin: var(--e3) 0 0; border-top: 1px solid var(--line); padding-top: var(--e3); }
.kb-plus-detail > summary {
  cursor: pointer; list-style: none; color: var(--muted); font-size: 13px;
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 0;
}
.kb-plus-detail > summary::-webkit-details-marker { display: none; }
.kb-plus-detail > summary::before { content: '▸'; transition: transform .15s; }
.kb-plus-detail[open] > summary::before { transform: rotate(90deg); }
.kb-plus-detail > summary:hover { color: var(--seal); }
.kb-plus-detail > div { margin-top: var(--e3); }

/* R808 — L'ANCRE DES ONGLETS SE DÉGAGE DE L'EN-TÊTE. Sans cette marge, le
   navigateur pose la barre d'onglets pile en haut de la fenêtre — c'est-à-dire
   DERRIÈRE l'en-tête collant, qui la recouvre. On réserve sa hauteur, plus un
   peu d'air pour qu'elle ne touche pas le bord. */
#onglets { scroll-margin-top: calc(var(--h-topbar, 55px) + 16px); }

/* ==========================================================================
   R809 — LA BARRE D'OUTILS DU TABLEAU, ET LES ÉCARTS DES ONGLETS
   --------------------------------------------------------------------------
   Mesuré : cinq outils répartis sur TROIS lignes — la recherche seule, puis le
   filtre dessous, puis les trois boutons décalés à droite. Une barre d'outils
   se lit d'un balayage horizontal ; empilée, elle occupe cent vingt pixels de
   haut avant qu'on ait vu la première tâche.

   Une seule ligne : la recherche à gauche, le filtre à côté, les gestes à
   droite. La recherche cède la première quand la place manque, car c'est elle
   qui peut se contenter de peu.
   ========================================================================== */
.kb-barre {
  display: flex; align-items: center; gap: var(--e3);
  flex-wrap: nowrap; margin-bottom: var(--e4);
}
.kb-barre .kb-filtres { flex: 1 1 auto; flex-wrap: nowrap; }
/* La recherche PREND la place, le filtre garde la sienne : « flex: 1 » sur le
   champ et « flex: 0 0 » sur le select — je les avais écrits dans cet ordre,
   mais une règle plus ancienne donnait au select « flex: 1 » et il raflait
   tout, réduisant la recherche à son icône. On nomme les deux avec assez de
   précision pour que l'intention porte. */
.kb-barre .kb-filtres > .scoped-search { flex: 1 1 220px; max-width: 340px; min-width: 200px; }
.kb-barre .kb-filtres > select { flex: 0 0 auto; width: auto; min-width: 170px; max-width: 220px; }
.kb-barre .kb-barre-gestes { flex: 0 0 auto; margin-inline-start: auto; align-items: center; }
/* Les hauteurs différaient de huit pixels : la recherche fait trente-huit, les
   petits boutons trente-quatre, et « align-items: center » les centrait sur
   des milieux distincts. On leur donne la MÊME hauteur — c'est l'alignement
   par le bas et par le haut à la fois, celui que l'œil attend d'une barre. */
/* Hauteur commune de QUARANTE pixels, bordure comprise : la recherche porte un
   cadre d'un pixel de chaque côté, si bien qu'à « min-height: 38 » elle
   mesurait quarante quand les boutons en faisaient trente-huit. On fixe la
   hauteur RENDUE, pas la hauteur intérieure — « box-sizing » s'en charge. */
.kb-barre .scoped-search,
.kb-barre .kb-filtres > select,
.kb-barre .btn.small { height: 40px; min-height: 40px; box-sizing: border-box; }

/* Sous neuf cents pixels, la ligne se plie en deux : les outils au-dessus, les
   gestes en dessous — plutôt que de serrer six éléments sur une largeur de
   téléphone, où plus rien ne se lit. */
@media (max-width: 900px) {
  .kb-barre { flex-wrap: wrap; }
  .kb-barre .kb-filtres { flex: 1 1 100%; flex-wrap: wrap; }
  .kb-barre .kb-barre-gestes { flex: 1 1 100%; margin-inline-start: 0; flex-wrap: nowrap; }
  /* Les trois gestes se partagent la largeur au lieu de s'empiler : trois
     boutons l'un sous l'autre faisaient quatre lignes de barre avant la
     première tâche. Leur libellé se réduit, leur icône reste. */
  .kb-barre .kb-barre-gestes .btn.small { flex: 1 1 0; min-width: 0; justify-content: center; }
  .kb-barre .kb-barre-gestes .btn.small span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
@media (max-width: 560px) {
  /* Plus étroit encore : le champ prend sa ligne, le filtre la sienne. */
  .kb-barre .kb-filtres > .scoped-search,
  .kb-barre .kb-filtres > select { flex: 1 1 100%; max-width: none; }
}

/* Le tableau était COLLÉ à la barre — zéro pixel. Il prend l'écart des blocs,
   comme partout ailleurs dans la maison. */
.kb { margin-top: var(--e4); }

/* Chaque onglet respire de la même façon sous la barre : sans cette règle,
   l'écart dépendait de ce que l'onglet contenait, et l'on passait de seize
   pixels à zéro d'un onglet à l'autre. */
#onglets + * { margin-top: var(--e4); }

/* R811 — L'AVANCEMENT ET LE JOURNAL D'UNE TÂCHE. */
.kb-av { display: flex; align-items: center; gap: 10px; }
.kb-av-barre { flex: 1 1 auto; height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; min-width: 90px; }
.kb-av-barre > i { display: block; height: 100%; background: var(--seal); transition: width .25s; }

/* Les notes s'empilent du plus ancien au plus récent : on lit l'histoire dans
   l'ordre où elle s'est écrite. Un liseré à gauche les relie sans les enfermer
   dans des cadres, qui feraient de chaque note un objet à part. */
.kb-notes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--e3); }
.kb-notes > li { border-inline-start: 2px solid var(--line); padding: 0 0 0 12px; font-size: 13.5px; line-height: 1.5; }
.kb-note-tete { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 3px; }
.kb-note-av { color: var(--seal); font-weight: 500; font-size: 12.5px; }
.kb-note-pj { margin-top: 4px; font-size: 12.5px; color: var(--muted); }
.kb-note-neuve { margin-top: var(--e3); display: flex; flex-direction: column; gap: var(--e2); }
.kb-note-ligne { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.kb-note-ligne label { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }

/* R812 — LA TÂCHE TERMINÉE LE DIT. Une ligne verte discrète, non une pastille
   qui crierait : c'est un état, pas une alerte. */
.kb-fini { color: var(--seal); margin: 0 0 var(--e2); font-size: 13.5px; }

/* R814 — LE BOUTON QUI CLÔT UNE MISSION. Ambre : ni le vert du geste courant,
   ni le rouge de ce qui détruit — un geste rare, dont on veut qu'on le remarque
   avant de le faire. */
/* R826 — CLÔTURER PASSE AU ROUGE PÂLE. L'ambre plein le rendait aussi voyant
   que le bouton principal : sur une rangée de cinq, c'est lui que l'œil
   attrapait d'abord, alors que c'est le geste qu'on fait le moins souvent.
   Le fond pâle et l'encre rouge disent la même chose — attention, geste qui
   engage — sans crier. C'est la teinte que la maison emploie déjà pour ce qui
   demande à réfléchir, et l'on ne crée pas une sixième couleur pour un bouton. */
.btn.mt-clore {
  background: var(--err-bg); border-color: var(--err); color: var(--err);
}
.btn.mt-clore:hover { background: var(--err); border-color: var(--err); color: #fff; }

/* R815 — LA CARTE PORTE QUATRE FAITS, ESPACÉS. Chacun sur sa ligne, séparés
   par l'écart de la maison : collés, ils se lisaient comme une seule phrase et
   l'œil ne savait où s'arrêter. */
.kb-carte { display: flex; flex-direction: column; gap: var(--e2); position: relative; }
/* Le titre est un bloc : il occupe toute la largeur, et son « padding » ne
   déplace que le TEXTE, pas sa boîte. Pour que la mesure et l'œil s'accordent,
   on réduit sa boîte — le coin garde ses cinquante-deux pixels, et rien ne
   passe dessous. */
.kb-carte .kb-titre { padding-inline-end: 0; width: calc(100% - 52px); }

/* Les porteurs : des pastilles d'initiales, non des noms en toutes lettres —
   trois noms complets prendraient deux lignes sur une carte de 260 pixels. */
.kb-qui { display: flex; align-items: center; gap: 4px; min-height: 22px; }
.kb-pastille {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--seal); color: #fff;
  font-size: 10px; font-weight: 500; letter-spacing: .3px;
  display: inline-flex; align-items: center; justify-content: center;
}
.kb-pastille.kb-plusieurs { background: var(--line); color: var(--muted); }
.kb-qui .libre { color: var(--seal); font-size: 12px; font-weight: 500; }

/* Les dates : une ligne discrète, les points médians en gris clair pour
   séparer sans peser. */
.kb-dates { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.kb-dates i { color: var(--line); font-style: normal; }
.kb-dates .retard { color: var(--err); font-weight: 500; }
.kb-dates .proche { color: var(--warn); font-weight: 500; }

/* La barre : fine, pleine largeur, sous les faits qu'elle résume. */
/* R846 — LA BARRE D'UNE CARTE RESSEMBLE À UNE BARRE.
   Quatre pixels de haut sans chiffre, cela se lit comme un filet de séparation,
   non comme une mesure. Elle passe à six, garde un creux visible sous sa part
   remplie, et porte son pourcentage à côté : la barre donne le coup d'œil, le
   nombre donne la mesure. */
.kb-av-ligne { display: flex; align-items: center; gap: 8px; }
.kb-av-carte {
  flex: 1 1 auto; height: 6px; border-radius: 3px;
  background: var(--line); overflow: hidden; min-width: 40px;
}
.kb-av-carte > i {
  display: block; height: 100%; background: var(--seal);
  border-radius: 3px; transition: width .25s;
}
/* Le chiffre reste discret : c'est la barre qu'on regarde d'abord. À cent pour
   cent il prend le vert — c'est le seul moment où il annonce quelque chose. */
.kb-av-pc { flex: 0 0 auto; font-size: 11.5px; font-weight: 500; color: var(--muted); min-width: 30px; text-align: right; }
.kb-av-pc.fini { color: var(--seal); }

/* Les deux commandes, à l'angle : l'œil cherche là les boutons d'un objet. */
/* Le menu portait « position: absolute » depuis qu'il était seul dans l'angle :
   dans le coin, il se posait PAR-DESSUS le crayon, qui devenait inatteignable —
   le clic passait au menu. C'est le coin qui est placé maintenant ; ses deux
   boutons s'y rangent côte à côte. */
.kb-coin { position: absolute; top: 6px; inset-inline-end: 8px; display: flex; gap: 2px; z-index: 2; }
.kb-carte .kb-coin .kb-plus { position: static; inset-inline-end: auto; top: auto; }
.kb-editer, .kb-plus {
  border: 0; background: transparent; cursor: pointer;
  color: var(--muted); font-size: 13px; line-height: 1;
  width: 22px; height: 22px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
}
.kb-editer:hover, .kb-plus:hover { background: var(--seal-soft); color: var(--seal); }

/* R828 — QUAND ÇA DÉFILE SUR LE CÔTÉ, ON LE VOIT. Un tableau ou une rangée de
   colonnes plus large que l'écran se coupait net au bord : rien ne disait
   qu'il y avait autre chose plus loin, et l'on croyait tout voir. Les listes
   de tâches paraissaient vides à droite.

   Deux ombres portées en fond, l'une à gauche l'autre à droite, montées sur
   « background-attachment: local » : c'est le navigateur qui les efface quand
   on atteint le bord — aucun script à écrire, et le repère ne peut pas se
   désaccorder du défilement réel. */
/* R829 — L'OMBRE DE DÉFILEMENT, POSÉE SUR UN CADRE QUI NE DÉFILE PAS.
   Deux tentatives ont échoué avant celle-ci, pour la même raison : un fond ou
   un pseudo-élément placé DANS le conteneur qui défile passe derrière ses
   enfants — les colonnes du tableau sont opaques et le recouvraient. Mesuré au
   pixel : zéro contraste.
   On enveloppe donc le conteneur dans un cadre immobile, et l'on pose l'ombre
   sur CE cadre. Elle flotte au-dessus, elle ne défile pas, et rien ne peut la
   masquer. « data-defile » dit de quel côté il reste quelque chose à voir : le
   script le met à jour, et sans script les deux ombres restent — mieux vaut un
   repère toujours là qu'un repère absent. */
.kb-cadre, .tbl-cadre { position: relative; }
/* Le cadre ne doit rien changer d'autre : il ne fait qu'entourer. */
.kb-cadre > .kb, .tbl-cadre > .tblwrap { margin: 0; }
.kb-cadre::before, .kb-cadre::after,
.tbl-cadre::before, .tbl-cadre::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 26px;
  pointer-events: none; z-index: 4; opacity: 1; transition: opacity .18s;
}
.kb-cadre::before, .tbl-cadre::before {
  left: 0;
  background: linear-gradient(to right, rgba(33,48,46,.16), rgba(33,48,46,0));
}
.kb-cadre::after, .tbl-cadre::after {
  right: 0;
  background: linear-gradient(to left, rgba(33,48,46,.16), rgba(33,48,46,0));
}
/* Au bord, l'ombre de ce côté-là s'efface : il n'y a plus rien derrière. */
.kb-cadre[data-defile="debut"]::before, .tbl-cadre[data-defile="debut"]::before,
.kb-cadre[data-defile="aucun"]::before, .tbl-cadre[data-defile="aucun"]::before { opacity: 0; }
.kb-cadre[data-defile="fin"]::after, .tbl-cadre[data-defile="fin"]::after,
.kb-cadre[data-defile="aucun"]::after, .tbl-cadre[data-defile="aucun"]::after { opacity: 0; }

/* R830 — LE JOURNAL DE TRAVAIL D'UNE TÂCHE. */
.kb-travail { border-top: 1px solid var(--line); margin-top: var(--e4); padding-top: var(--e3); }
.kb-travail-tete { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.kb-travail-pc { color: var(--seal); font-size: 13px; }
.kb-note-duree { color: var(--muted); font-size: 12.5px; }

/* Le geste qui démarre : seul de son espèce, il prend toute la largeur —
   c'est la seule chose à faire sur une tâche qui n'a pas commencé. */
.kb-demarrer { margin-top: var(--e4); padding-top: var(--e3); border-top: 1px solid var(--line); }
.kb-demarrer .btn { width: 100%; justify-content: center; }

/* Terminer se distingue d'« ajouter » sans crier : le vert dit l'achèvement,
   le fond pâle dit que ce n'est pas le geste courant. */
.btn.kb-terminer { background: var(--seal-soft); border-color: var(--seal); color: var(--seal); }
.btn.kb-terminer:hover { background: var(--seal); border-color: var(--seal); color: #fff; }
.kb-note-gestes { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.kb-note-gestes .btn.primary { flex: 1 1 auto; }

/* R830 — CE QUI SERA PERDU, NOMMÉMENT. On ne dit pas « des données seront
   effacées » : on les liste, avec leurs durées. Le fond rouge pâle dit
   l'irréversible sans crier. */
.kb-perdu {
  background: var(--err-bg); border-radius: var(--r);
  padding: 10px 12px; margin: var(--e3) 0;
  font-size: 13px; color: var(--err); line-height: 1.6;
}
.kb-demande-case { display: flex; gap: 8px; align-items: flex-start; font-size: 13.5px; line-height: 1.5; margin-bottom: var(--e3); }
.kb-demande-gestes { display: flex; gap: 8px; }
.kb-demande-gestes .btn { flex: 1; justify-content: center; }

/* R833 — UN CHAMP LARGE PORTE SON LIBELLÉ AU-DESSUS. Mis en colonne à côté de
   son mot, il laisse une gouttière vide et rétrécit la zone d'écriture pour
   rien. C'est la disposition que la description emploie déjà. */
.kb-bloc-champ { margin-bottom: var(--e3); }
.kb-bloc-champ > label {
  display: block; font-size: 13px; color: var(--muted); margin-bottom: 5px;
}
.kb-bloc-champ > input, .kb-bloc-champ > textarea { width: 100%; }

/* Le pied : deux gestes, séparés du reste, sans bouton inutile entre eux. */
.kb-pied {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: var(--e4); padding-top: var(--e3); border-top: 1px solid var(--line);
}
.kb-pied .danger { margin-inline-start: auto; }

/* R835 — LA PIÈCE D'UNE ÉTAPE SE VOIT. Son étiquette d'extension la nomme d'un
   coup d'œil, comme partout ailleurs dans la maison ; le nom seul obligeait à
   le déchiffrer pour savoir ce qu'on allait ouvrir. */
.kb-note-pj { display: flex; align-items: center; gap: 6px; margin-top: 5px; font-size: 12.5px; color: var(--muted); }
.kb-note-pj .tag-ext { flex: 0 0 auto; }

/* R839 — LES PIÈCES DANS LE FORMULAIRE D'ÉTAPE. Elles font partie de ce qu'on
   prépare : un titre discret les sépare des réglages sans les détacher du
   bloc, et leurs deux boutons se rangent sous la liste. */
.kb-note-pj-titre {
  margin: var(--e3) 0 6px; font-size: 12px; font-weight: 600;
  letter-spacing: .5px; text-transform: uppercase; color: var(--muted);
}
.kb-note-neuve #kbPieces { display: flex; flex-direction: column; gap: 6px; }
.kb-note-pj-gestes { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }

/* R840 — LA RECHERCHE DANS LA BIBLIOTHÈQUE, EN FENÊTRE. Repliée sous le bouton,
   sa liste poussait le reste du panneau vers le bas et l'on perdait où l'on en
   était. Une fenêtre donne la place qu'une recherche demande, et se referme
   quand on a trouvé. */
.kb-bib-carte { width: min(520px, 92vw); }
.kb-bib-carte > input { width: 100%; margin-bottom: var(--e3); }
.kb-bib-liste {
  max-height: 46vh; overflow-y: auto; font-size: 13px;
  display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--e3);
}

/* R840 — LE LIBELLÉ DU CHAMP D'ÉTAPE. Un mot d'invite disparaît dès qu'on
   écrit ; un libellé reste, et le lecteur d'écran le rattache au champ. */
.kb-note-label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 5px; }

/* R840 : le nom du document prend la place, le bouton reste à droite. */
.kb-bib-liste .kb-pj { display: flex; align-items: center; gap: 8px; }
.kb-bib-nom { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-bib-liste .kb-pj > .btn { flex: 0 0 auto; }

/* R841 — LES QUATRE SEGMENTS DU PANNEAU D'UNE TÂCHE.
   Le panneau était une longue colonne où tout se suivait. Quatre blocs, séparés
   par un fond et un écart : ce qu'elle EST, ce qu'on y a FAIT, ce qu'on en DIT,
   ce qu'on peut en FAIRE. Chacun se lit seul.

   On sépare par le FOND, non par des traits : quatre filets dans une colonne
   étroite hachent la lecture, un fond porte le regard sans l'arrêter. */
.kb-bloc {
  display: block;
  padding: var(--e3) var(--e3) var(--e3);
  border-radius: var(--r);
  margin-bottom: var(--e3);
}
.kb-bloc:last-child { margin-bottom: 0; }

/* L'identité reste sur le fond du panneau : c'est le sujet, non un aparté. */
.kb-bloc-identite { padding: 0 0 var(--e3); }

/* Le travail — le cœur de la tâche — porte un fond très pâle qui le détache
   sans le cerner. */
/* « #F3F1EA » est le fond des colonnes du tableau : la même teinte pour la même
   idée — une zone de travail posée sur la page. On ne crée pas une nuance de
   plus pour dire ce qu'une nuance existante dit déjà. */
.kb-bloc-travail { background: #F3F1EA; }
.kb-bloc-travail .kb-travail { border-top: 0; margin-top: 0; padding-top: 0; }

/* Les échanges : même fond, pour dire qu'ils sont du même ordre — ce qu'on
   ajoute autour du travail. */
.kb-bloc-echanges { background: #F3F1EA; }
.kb-bloc-echanges h4:first-child { margin-top: 0; }

/* Les gestes, en dernier : pas de fond, une séparation nette. Ce ne sont pas
   des choses qu'on lit, ce sont des décisions. */
.kb-bloc-gestes {
  padding: var(--e3) 0 0;
  border-top: 1px solid var(--line);
}
.kb-bloc-gestes .kb-pied { margin-top: 0; padding-top: 0; border-top: 0; }

/* R843 — LES DEUX CHEMINS DES PIÈCES, ESPACÉS DU BOUTON QUI ENVOIE.
   Ils touchaient « Ajouter » : on ne voyait pas où finissait la préparation et
   où commençait l'envoi. Un écart les sépare, et leurs icônes disent d'où vient
   le fichier avant qu'on ait lu. */
.kb-note-pj-gestes { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0 var(--e4); }
.kb-note-pj-gestes .btn { display: inline-flex; align-items: center; gap: 6px; }
.kb-note-pj-gestes .btn svg { flex: 0 0 auto; opacity: .75; }

/* R848 — L'ACTIVITÉ, RANGÉE PAR JOUR ET PAR PERSONNE.
   C'était une liste plate où chaque ligne répétait le nom et la date entière :
   on relisait quatre fois « Administrateur » et « 2026-09-04 » pour lire quatre
   gestes faits dans la même minute. Ce qui change — le geste — se noyait dans ce
   qui ne change pas.

   Le bloc a son fond, comme les autres segments du panneau : il se lit seul. */
.kb-acti-tout {
  background: var(--panel); border-radius: var(--r);
  padding: var(--e3); display: flex; flex-direction: column; gap: var(--e3);
}
.kb-acti-jour + .kb-acti-jour { border-top: 1px solid var(--line); padding-top: var(--e3); }

/* La date ouvre la journée : petite, en capitales, elle sépare sans peser. */
.kb-acti-date {
  font-size: 11px; font-weight: 600; letter-spacing: .5px;
  text-transform: uppercase; color: var(--muted); margin-bottom: 6px;
}
.kb-acti-qui { font-size: 13px; margin-top: 8px; }
.kb-acti-jour > .kb-acti-qui:first-of-type { margin-top: 0; }

/* Les gestes d'une personne : un liseré les relie, l'heure reste à droite —
   on lit la suite des actions, non une colonne d'horaires. */
.kb-acti-gestes {
  list-style: none; margin: 4px 0 0; padding: 0 0 0 12px;
  border-inline-start: 2px solid var(--line);
  display: flex; flex-direction: column; gap: 8px;
}
/* R860 : les lignes respirent. À trois pixels d'écart, sept gestes formaient un
   pavé qu'on relisait deux fois pour trouver le sien ; à huit, chacun se
   détache. Une trace se PARCOURT — on y cherche un moment précis, on ne la lit
   pas d'un bout à l'autre. */
.kb-acti-gestes > li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  font-size: 13px; line-height: 1.55; padding: 2px 0;
}
.kb-acti-gestes small { flex: 0 0 auto; font-size: 11.5px; }

/* R849 — LE PANNEAU D'UNE ÉTAPE : CINQ POINTS.

   1. LE CURSEUR SE PREND. « Où ça en est » se règle en glissant : la main doit
      le dire avant qu'on essaie. Le pointeur devient une main sur la poignée,
      et une main FERMÉE pendant qu'on tire. */
input[type="range"] { cursor: pointer; }
input[type="range"]:active { cursor: grabbing; }
input[type="range"]::-webkit-slider-thumb { cursor: grab; }
input[type="range"]:active::-webkit-slider-thumb { cursor: grabbing; }
input[type="range"]::-moz-range-thumb { cursor: grab; }

/* 2. UN CHAMP OBLIGATOIRE LE DIT AVANT QU'ON SE TROMPE. Une étoile rouge à côté
      de son mot — c'est la convention que tout le monde connaît, et l'apprendre
      ne coûte rien. */
.kz-requis::after {
  content: ' *'; color: var(--err); font-weight: 600;
}

/* 3. UN CHAMP EN FAUTE PORTE UN LISERÉ ROUGE — et il PART dès qu'on écrit.
      Une bordure qui reste après la correction punit au lieu d'aider : on a
      fait ce qu'il fallait, l'écran devrait le reconnaître tout de suite. */
.kz-faute, .kz-faute:focus {
  border-color: var(--err) !important;
  box-shadow: 0 0 0 3px rgba(169, 58, 49, .12) !important;
}

/* R849 : le libellé du texte d'étape, au-dessus de son champ comme les autres. */
.kb-note-label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 5px; }

/* R850 — LE BOUTON D'ENREGISTREMENT, QUAND IL Y A QUELQUE CHOSE À ENREGISTRER.
   Titre et description partent déjà quand on quitte le champ, mais rien ne le
   disait : on tapait sans savoir si c'était parti. Le bouton rend le geste
   visible, et ne paraît que si une valeur a changé — toujours actif, il
   n'apprendrait rien. */
.kb-enreg {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: var(--e3);
}
.kb-enreg[hidden] { display: none; }

/* R852 — LA COLONNE SOUS LE TITRE DU PANNEAU. Le panneau disait ce qu'est la
   tâche, jamais OÙ elle se trouve : on ouvrait une carte sans savoir si elle
   attendait, avançait ou était finie. L'icône donne l'état d'un coup d'œil, le
   mot le nomme — une icône seule s'interprète mal. */
/* R852 : le texte prend la place restante, les boutons gardent la leur. Sans
   « flex: 1 », le bloc du titre ne s'étirait pas et les deux icônes se
   retrouvaient sous lui au lieu de rester à droite. */
.kb-tete-texte { flex: 1 1 auto; min-width: 0; }
.kb-tete-col {
  display: flex; align-items: center; gap: 6px;
  margin-top: 3px; font-size: 12.5px; color: var(--muted);
}
.kb-tete-col[hidden] { display: none; }
.kb-tete-col svg { flex: 0 0 auto; opacity: .8; }

/* R852 — UNE TÂCHE TERMINÉE RESPIRE COMME LES AUTRES. Sa ligne « Tâche
   terminée » collait à la dernière étape, sans le trait ni l'écart qui séparent
   les blocs d'une tâche en cours : on lisait un journal, puis un mot posé
   dessus. Elle prend la même respiration. */
.kb-fini {
  display: flex; align-items: center; gap: 8px;
  margin: var(--e3) 0 0; padding-top: var(--e3);
  border-top: 1px solid var(--line);
  font-size: 13.5px; color: var(--seal);
}


/* R860 — LA TRACE A SON PROPRE BLOC. Elle partageait le fond des commentaires :
   on écrivait un mot, et la suite des gestes se lisait dans la foulée, comme si
   elle en faisait partie. Ce sont deux choses différentes — ce qu'on DIT, et ce
   qui S'EST FAIT. Un fond neutre et un écart les séparent. */
.kb-bloc-trace { background: transparent; padding-inline-start: 0; padding-inline-end: 0; }
.kb-bloc-trace > h4:first-child { margin-top: 0; }

/* R873 — LE PIED DU PANNEAU : TROIS GESTES, TROIS ICÔNES.
   « Quitter » vivait plus haut, seul au milieu de ce qu'on lit. Il est pourtant
   de la même nature que « Signaler un blocage » et « Supprimer » : une décision,
   non une lecture. Les trois se rangent ensemble, du moins grave au plus grave. */
.kb-pied .btn { display: inline-flex; align-items: center; gap: 6px; }
.kb-pied .btn svg { flex: 0 0 auto; opacity: .8; }

/* R879 — LES GESTES RÉSERVÉS, VISIBLES MAIS ÉTEINTS.
   Ils disparaissaient pour qui ne porte pas la tâche : on ne savait pas ce qu'on
   ratait, ni qu'il suffisait de la prendre pour l'obtenir. Les cacher protège ;
   les griser enseigne. */
.kb-menu button.kz-eteint {
  color: var(--muted); cursor: not-allowed; opacity: .6;
}
.kb-menu button.kz-eteint:hover { background: transparent; }

/* R888 — LA CROIX DE LA FENÊTRE « NOUVELLE TÂCHE ».
   Le script la dessine et l'écoute, mais aucune règle ne la portait : elle
   s'affichait comme un bouton nu, à la taille du texte, sans zone de clic
   confortable. On lui donne la forme des autres croix de la maison. */
.kb-neuf-x {
  border: 0; background: transparent; cursor: pointer;
  color: var(--muted); font-size: 18px; line-height: 1;
  padding: 4px 8px; border-radius: var(--r);
}
.kb-neuf-x:hover { background: var(--line); color: var(--ink); }

/* R891 — « JE PRENDS LA TÂCHE » PREND TOUTE LA LARGEUR DANS LE PANNEAU.
   Sur une tâche à faire, c'est le SEUL geste offert : tout le reste attend qu'on
   l'ait prise. Un bouton de cent quarante pixels au milieu d'un panneau qui en
   fait cinq cents se cherche ; à pleine largeur, il dit qu'il n'y a rien
   d'autre à décider.
   Sur la CARTE il reste petit : là, il vit parmi d'autres informations. */
#kbPrendre {
  display: block; width: 100%; margin-top: var(--e3);
  padding: 10px 14px; font-size: 14px;
}

/* R894 — LE MESSAGE D'ERREUR SOUS LE CHAMP QU'IL CONCERNE.
   Un refus muet se confond avec une panne : on revalide en croyant le bouton
   cassé. Le mot se pose SOUS le champ — là où l'œil est déjà —, non en haut de
   la fenêtre où il faudrait aller le chercher. */
/* La fenêtre impose sa couleur à tous ses paragraphes — « .kb-demande-carte p »
   est plus spécifique qu'une classe seule. On nomme les deux pour que la règle
   porte, plutôt que de forcer avec « !important » : dire OÙ l'on veut agir vaut
   mieux que crier plus fort. */
.kz-erreur, .kb-demande-carte .kz-erreur {
  margin: 6px 0 0; font-size: 12.5px; color: var(--err);
  display: flex; align-items: center; gap: 6px;
}
.kz-erreur::before { content: '⚠'; font-size: 13px; }

/* R895 — UN ENVOI QUI DURE SE VOIT.
   Rien ne bougeait entre le choix du fichier et son apparition : sur une pièce
   lourde, on croyait que rien ne partait et l'on recliquait. Le bouton s'éteint
   et dit qu'il travaille. */
/* R1327 — LE MOT SORT DU CSS. Il était écrit dans un « content: », d'où
   aucune traduction ne pouvait l'atteindre : « envoi… » s'affichait en
   français sur les quatre langues. Le script pose maintenant le mot lui-même,
   par kz.t(), et le CSS ne fait plus que l'habiller. */
.kz-envoi { opacity: .6; pointer-events: none; position: relative; }
.kz-envoi-mot { font-size: 11.5px; color: var(--muted); margin-inline-start: 4px; }

/* R895 — L'APERÇU D'UNE IMAGE JOINTE.
   L'étiquette « JPG » dit le format, pas le contenu : sur cinq captures
   d'écran, on les ouvrait une par une pour retrouver la bonne. Une vignette de
   la taille de l'étiquette qu'elle remplace — elle informe sans encombrer. */
.kb-pj-vue {
  width: 34px; height: 34px; object-fit: cover; flex: 0 0 auto;
  border-radius: var(--r); border: 1px solid var(--line); background: var(--panel);
}


/* R896 — L'EN-TÊTE D'UN COMMENTAIRE, SUR UNE SEULE LIGNE.
   Nom, date, état, puis les gestes poussés à droite. « flex-wrap » les fait
   passer dessous quand la largeur manque, plutôt que de comprimer le nom. */
.kb-com-corps > b:first-child { margin-inline-end: 0; }
.kb-com-corps { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.kb-com-corps > .kb-com-texte { flex: 1 1 100%; margin-top: 4px; }

/* R899 — LE CHAMP DE CORRECTION PREND LA MÊME LARGEUR QUE CELUI D'AJOUT.
   R896 a mis l'en-tête d'un commentaire en flex ; le champ d'édition, enfant de
   ce conteneur, s'est retrouvé dimensionné par son contenu — « width:100% » ne
   vaut plus rien face à « flex » sans base. Il passe sur sa propre ligne, en
   pleine largeur : corriger un mot et en écrire un nouveau sont le même geste,
   ils doivent offrir la même place. */
.kb-com-corps > textarea,
.kb-com-corps > .kb-com-edit { flex: 1 1 100%; width: 100%; box-sizing: border-box; }
.kb-com-corps > .kb-com-edit-gestes { flex: 1 1 100%; display: flex; gap: 8px; margin-top: 6px; }

/* « corrigé » se lit comme un état, non comme la suite de la date. */
.kb-com-etat {
  font-size: 10.5px; padding: 1px 7px; border-radius: var(--r);
  background: var(--line); color: var(--muted);
}

/* Retirer ne coûte pas ce que corriger coûte : les deux en gris demandaient de
   lire pour les distinguer. Et la zone cliquable passe de la hauteur du texte à
   quelque chose qu'on atteint. */
.kb-com-gestes button { padding: 3px 8px; border-radius: var(--r); }
.kb-com-gestes button:hover { background: var(--line); text-decoration: none; }
.kb-com-gestes button[data-com-x] { color: var(--err); }
.kb-com-gestes button[data-com-x]:hover { background: var(--err-bg); color: var(--err); }

/* R904 — LA CARTE SE LIT SANS QU'ON L'OUVRE.
   Deux lignes de description, coupées net : au-delà, on ne lit plus une carte,
   on lit un paragraphe. Le texte entier reste en infobulle. */
.kb-carte-desc {
  margin: 6px 0 0; font-size: 11.5px; line-height: 1.45; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; cursor: help;
}
/* Le nombre d'étapes se pose CONTRE la barre qu'il produit. */
.kb-carte-etapes {
  /* R904 : six pixels, comme les autres écarts de la carte. Huit creusaient un
     trou de seize entre la description et la barre — la carte respirait moins
     qu'elle ne se disloquait. */
  margin-top: 6px; font-size: 11px; color: var(--muted); text-align: right;
}
/* Les commentaires passent sous un filet : ce qui fait avancer et ce qui en
   parle ne sont pas de même nature. */
.kb-carte-coms {
  margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line);
  font-size: 11.5px; color: var(--muted);
}

/* R910 — LA RANGÉE DATE ET ÉTAPES.
   Elles occupaient chacune leur ligne : trois rangées pour trois mots, et la
   carte s'allongeait sans rien dire de plus. Côte à côte, elles se lisent d'un
   regard — l'une à gauche, l'autre poussée à droite contre la barre. */
.kb-carte-rang {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-top: 6px;
}
.kb-carte-rang .kb-dates { margin: 0; }
.kb-carte-rang .kb-carte-etapes { margin: 0; white-space: nowrap; }

/* La bulle des commentaires s'aligne sur le chiffre qu'elle annonce. */
.kb-carte-coms { display: flex; align-items: center; gap: 6px; }

/* R910 — CE QU'ON SURVOLE S'ÉCLAIRE. Une infobulle met une seconde à venir ;
   d'ici là, rien ne dit que l'élément a quelque chose à raconter. Un fond léger
   le signale tout de suite. */
.kb-carte-desc:hover,
.kb-carte-etapes:hover,
.kb-carte-coms:hover,
.kb-av-pc:hover { background: var(--line); border-radius: var(--r); }
.kb-carte-etapes, .kb-carte-coms, .kb-av-pc { cursor: help; padding: 1px 4px; }

/* R910 — LA RANGÉE DATE ET ÉTAPES, côte à côte contre la barre. */
.kb-carte-rang {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-top: 6px;
}
.kb-carte-rang .kb-dates { margin: 0; }
.kb-carte-rang .kb-carte-etapes { margin: 0; white-space: nowrap; }

/* La bulle des commentaires s'aligne sur le chiffre qu'elle annonce. */
.kb-carte-coms { display: flex; align-items: center; gap: 6px; }

/* CE QU'ON SURVOLE S'ÉCLAIRE. Une infobulle met une seconde à venir ; d'ici là,
   rien ne dit que l'élément a quelque chose à raconter. */
.kb-carte-etapes, .kb-carte-coms, .kb-av-pc { cursor: help; padding: 1px 4px; }
.kb-carte-desc:hover, .kb-carte-etapes:hover,
.kb-carte-coms:hover, .kb-av-pc:hover { background: var(--line); border-radius: var(--r); }

/* R912 — LES GESTES D'UNE ÉTAPE, COMME CEUX D'UN COMMENTAIRE.
   Même forme, même place, mêmes couleurs : on apprend une fois, on s'en sert
   partout. Retirer prend le rouge — corriger et effacer ne coûtent pas pareil. */
.kb-note-tete { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.kb-note-gestes { display: inline-flex; gap: 4px; margin-inline-start: auto; }
.kb-note-gestes button {
  border: 0; background: transparent; font: inherit; font-size: 11.5px;
  color: var(--muted); cursor: pointer; padding: 3px 8px; border-radius: var(--r);
}
.kb-note-gestes button:hover { background: var(--line); }
.kb-note-gestes button[data-note-x] { color: var(--err); }
.kb-note-gestes button[data-note-x]:hover { background: var(--err-bg); }
/* « corrigée » se lit comme un état, non comme la suite de la date. */
.kb-note-etat {
  font-size: 10.5px; padding: 1px 7px; border-radius: var(--r);
  background: var(--line); color: var(--muted);
}

/* R914 — LE FORMULAIRE DE CRÉATION PREND TROIS CHAMPS.
   Le titre reste en tête ; la description et l'échéance suivent, plus discrètes.
   Une tâche jetée vite sur le tableau n'a qu'à remplir le premier. */
.kb-neuf-desc {
  width: 100%; margin-top: 6px; padding: 6px 8px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: var(--r);
  font: inherit; font-size: 12.5px; resize: vertical;
}
.kb-neuf-ech {
  display: flex; align-items: center; gap: 8px; margin-top: 6px;
  font-size: 11.5px; color: var(--muted);
}
.kb-neuf-date {
  flex: 1; padding: 5px 8px; border: 1px solid var(--line);
  border-radius: var(--r); font: inherit; font-size: 12.5px;
}

/* R916 — L'ÉCHÉANCE SE NOMME, SUR LA CARTE ET DANS LE PANNEAU.
   Une date nue se confond avec celle du démarrage, juste à côté. Le minuteur et
   le mot disent laquelle on regarde. */
/* R928 — UNE ÉCHÉANCE LOINTAINE NE S'ALLUME PAS.
   Le fond ambre paraissait dans tous les cas, à trente jours comme à deux. Une
   couleur qui s'allume toujours n'alerte plus : elle devient le fond normal, et
   l'on ne voit plus la vraie urgence.
   Par défaut, du texte gris — on le lit si on le cherche. Le fond n'arrive qu'à
   l'approche, puis vire au rouge une fois la date passée. */
.kb-ech-etiq {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; padding: 1px 7px; border-radius: var(--r);
  background: transparent; color: var(--muted);
}
.kb-ech-etiq svg { width: 12px; height: 12px; flex: none; }
.kb-ech-etiq.retard { background: var(--err-bg); color: var(--err); }
.kb-ech-etiq.proche { background: #FBF3E2; color: #8A6116; }
/* R919 : la MISSION nomme ses tons « mt-rouge » et « mt-ambre » — noms d'un
   autre écran, hérités. On les rattache ici plutôt que de les renommer : les
   renommer toucherait tout ce qui les emploie ailleurs, pour un gain nul. */
.kb-ech-etiq.mt-rouge { background: var(--err-bg); color: var(--err); }
.kb-ech-etiq.mt-ambre { background: #FBF3E2; color: #8A6116; }
/* Dans le panneau, la ligne suit le rythme des autres champs. */
.kb-champ .kb-ech.retard { color: var(--err); font-weight: 600; }
.kb-champ .kb-ech.proche { color: #8A6116; font-weight: 600; }
.kb-champ svg { width: 13px; height: 13px; vertical-align: -2px; margin-inline-end: 5px; }

/* R918 — LES PIÈCES DE L'ÉTAPE QU'ON CORRIGE.
   Elles paraissent sous le formulaire, chacune avec sa croix : on retire celle
   qui n'a plus lieu d'être sans avoir à défaire toute l'étape. */
.kb-corr-pieces { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line); }
.kb-corr-tete {
  font-size: 11px; text-transform: uppercase; letter-spacing: .5px;
  color: var(--muted); margin-bottom: 6px;
}
.kb-corr-piece {
  display: flex; align-items: center; gap: 8px; padding: 4px 0;
  font-size: 12.5px; color: var(--ink);
}
.kb-corr-piece span[dir] { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-corr-piece button {
  border: 0; background: transparent; color: var(--err); cursor: pointer;
  font-size: 13px; padding: 2px 7px; border-radius: var(--r);
}
.kb-corr-piece button:hover { background: var(--err-bg); }

/* R930 — UNE PIÈCE MARQUÉE POUR LE RETRAIT.
   Barrée et pâlie, elle dit ce qui va partir sans être encore partie. On la
   reprend d'un second clic : se tromper de croix doit se défaire. */
.kb-corr-piece.kz-a-retirer { opacity: .55; }
.kb-corr-piece.kz-a-retirer span[dir] { text-decoration: line-through; }
.kb-corr-piece.kz-a-retirer .tag-ext { opacity: .6; }

/* R933 — LE BANDEAU D'UNE TÂCHE TERMINÉE.
   Il dit l'état, puis offre d'en sortir. Le vert dit que c'est fait, non qu'il
   y a un problème : reprendre est un geste ordinaire, pas une réparation. */
.kb-fini { display: flex; align-items: center; gap: 10px; }
.kb-fini .kb-reprendre { margin-inline-start: auto; flex: none; }

/* R935 — LE CHAMP DE DESCRIPTION PREND TOUTE LA LARGEUR.
   Les autres champs tiennent sur une ligne : un titre, un nom, une date. La
   description en demande plusieurs — on l'écrit, on la relit, on la corrige.
   Son libellé passe donc AU-DESSUS, et le champ occupe la ligne entière. */
.kb-champ.kb-champ-large { grid-template-columns: 1fr; gap: 4px; align-items: stretch; }
.kb-champ.kb-champ-large > span:first-child { padding-top: 0; }
.kb-champ.kb-champ-large textarea { width: 100%; box-sizing: border-box; min-height: 84px; }
.kb-champ.kb-champ-large > span:last-child { display: block; }

/* R962 : le témoin et le gris viennent de « occupe », la classe de la maison.
   Mes règles « kz-tourne » et « kz-occupe » ont été retirées : deux façons de
   dire la même chose finissent par se contredire. */


/* R963 — LE MOT DE LA PREMIÈRE OUVERTURE.
   En bas à droite, discret : il informe sans barrer la page. Barrer aurait été
   pire que le silence — on attendrait sans pouvoir rien faire, alors que tout
   fonctionne déjà. */
.kz-prepare {
  position: fixed; inset-inline-end: 16px; bottom: 16px; z-index: 60;
  display: flex; align-items: center; gap: 9px;
  padding: 10px 14px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: 0 6px 18px rgba(0,0,0,.08);
  font-size: 12.5px; color: var(--muted);
  transition: opacity .4s ease;
}
.kz-prepare-anneau {
  width: 13px; height: 13px; flex: none; border-radius: 50%;
  border: 2px solid var(--seal); border-top-color: transparent;
  animation: kz-prepare-tourne .8s linear infinite;
}
@keyframes kz-prepare-tourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .kz-prepare-anneau { animation: none; } }

/* R963 — LE MOT S'EFFACE PAR L'ANIMATION, NON PAR UN SCRIPT.
   La politique de sécurité rejette les scripts écrits dans la page. Une
   animation fait mieux : elle part seule, ne dépend de rien, et rien ne peut la
   bloquer. Trois secondes visibles, puis une demi-seconde pour disparaître. */
.kz-prepare { animation: kz-prepare-part .5s ease 3.2s forwards; }
@keyframes kz-prepare-part {
  to { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  /* Sans animation, le mot reste : il partira au changement de page, ce qui
     suffit — mieux qu'un affichage qui saute. */
  .kz-prepare { animation: none; }
}

/* R978 — LES TROIS GRAPHIQUES DU TABLEAU DE BORD.
   Trois cartes côte à côte quand la place le permet, empilées sinon : sur un
   téléphone, une colonne se lit mieux que trois vignettes serrées. */
.dash-graphes { display: grid; gap: var(--e3); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.kz-barres { display: flex; align-items: flex-end; gap: 14px; height: 120px; }
.kz-barre { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; }
/* La tige naît en bas : une barre qui pousse vers le haut se lit d'instinct. */
.kz-barre-tige { width: 100%; background: var(--seal); border-radius: 4px 4px 0 0; }
.kz-barre-nom { font-size: 10.5px; color: var(--muted); margin-top: 5px; text-align: center; }
.kz-barre b { font-size: 11.5px; color: var(--ink); }

.kz-ruban { display: flex; height: 20px; border-radius: 5px; overflow: hidden; background: var(--line); }
.kz-ruban > i { display: block; height: 100%; }
.kz-legende { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 12px; margin-top: 10px; font-size: 11px; color: var(--muted); }
.kz-legende > span { display: flex; align-items: center; gap: 5px; }
.kz-legende i { width: 8px; height: 8px; border-radius: 2px; flex: none; }

.kz-courbe { width: 100%; height: 90px; display: block; }

/* R984 — LES TITRES QUI SÉPARENT LES GROUPES.
   Douze chiffres en vrac se lisent mal : on cherche celui qu'on veut au lieu de
   le trouver. Un titre discret suffit à faire des groupes — plus gros serait
   crier, plus petit ne séparerait rien. */
.dash-titre {
  margin: var(--e4) 0 var(--e2); font-size: 13px; font-weight: 600;
  color: var(--muted); text-transform: uppercase; letter-spacing: .05em;
  display: flex; align-items: center; gap: 7px;
}
.dash-titre:first-of-type { margin-top: var(--e2); }
.dash-titre svg { color: var(--seal); }

/* R984 — LE BALAYAGE DE L'APERÇU PENDANT LA LECTURE.
   Une ligne verte descend sur la page, comme celle d'un scanner. Personne n'a
   besoin qu'on l'explique : le geste est connu, et il dit que ça travaille.

   Le voile s'arrête au retour de la lecture — un balayage qui continue après
   coup mentirait sur ce qui se passe. */
/* R1337 — LE RAYON VERT NE BALAIE PLUS TOUTE LA PAGE : IL VIT DANS L'ICÔNE.
   Une barre verte de trois pixels traversait la CARTE ENTIÈRE, de haut en bas,
   sans fin. À l'échelle d'un écran, ce n'est plus un signe : c'est un objet qui
   passe devant ce qu'on lit, et l'oeil le suit malgré lui. Le geste du scanner
   se dit très bien à la taille d'une icône — là, il décore ; à la taille d'une
   page, il dérange. L'animation est donc descendue DANS le dessin du scanner
   (« .kz-scanner-ic »), où elle tient en quatre pixels. */
.kz-scan { position: relative; }

/* R1346 — ET LE BALAYAGE REVIENT, MAIS SUR L'APERÇU SEUL.
   R1337 avait raison de chasser le rayon vert : il traversait la CARTE
   ENTIÈRE, passait devant ce qu'on lit, et l'oeil le suivait malgré lui. Mais
   je l'avais retiré de PARTOUT, en supprimant « .kz-scan::after » — et avec
   lui le balayage que R984 avait posé sur l'aperçu de la fenêtre de lecture,
   où il disait la seule chose qu'on veut savoir : la machine travaille. Il
   n'y dessinait plus rien depuis, sans que rien ne le dise. Une règle écrite
   pour un écran, retirée pour tous.
   Il ne vit donc que là où il a un sens : SUR L'APERÇU d'un document en cours
   de lecture — jamais sur une carte, jamais sur une page. Une ligne claire
   descend la feuille, comme le fait un scanner ; chacun le reconnaît sans
   qu'on l'explique. */
/* La barre parcourt la HAUTEUR DE LA FEUILLE, non la sienne : « translateY
   (100%) » sur une barre de trois pixels la déplace de trois pixels. On
   anime donc sa position dans le cadre, qui est ce qu'on veut voir bouger. */
.vl-apercu.kz-scan::after {
  content: ''; position: absolute; inset-inline: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, transparent, var(--seal), transparent);
  box-shadow: 0 0 10px 2px color-mix(in srgb, var(--seal) 45%, transparent);
  animation: kz-balayage 1.9s cubic-bezier(.4, 0, .6, 1) infinite;
  pointer-events: none; z-index: 2;
}
@keyframes kz-balayage {
  0%   { top: 0;                  opacity: 0; }
  12%  {                          opacity: 1; }
  88%  {                          opacity: 1; }
  100% { top: calc(100% - 3px);   opacity: 0; }
}
/* R1346 : la feuille pâlit un peu pendant la lecture — on voit d'un regard
   qu'elle n'est pas encore acquise, même sans suivre la ligne des yeux. */
.vl-apercu.kz-scan img, .vl-apercu.kz-scan iframe { opacity: .78; }
/* Qui a demandé moins de mouvement garde le signe, sans la course. */
@media (prefers-reduced-motion: reduce) {
  .vl-apercu.kz-scan::after { animation: none; top: 50%; opacity: .9; }
}

/* R988 — LE TABLEAU DES ACTIONS, PLEINE LARGEUR.
   Vingt lignes d'affilée se lisent mal ; six sections de trois se parcourent.
   Chaque section rappelle ses trois canaux en tête : on sait toujours ce qu'on
   coche, même après avoir défilé. */
.kz-actions .kz-act-groupe { margin-bottom: var(--e3); }
.kz-act-tete {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding-bottom: 6px; border-bottom: 1px solid var(--line);
}
.kz-act-tete h3 { font-size: 13px; color: var(--seal-dark); }
.kz-act-canaux { display: flex; gap: 4px; }
.kz-act-canaux > span {
  display: flex; align-items: center; gap: 4px; width: 74px; justify-content: center;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
}
@media (max-width: 620px) { .kz-act-mot { display: none; } .kz-act-canaux > span { width: 46px; } }

.kz-act-ligne {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 7px 0; border-bottom: 1px solid var(--line-2, rgba(0,0,0,.04));
}
.kz-act-ligne:last-child { border-bottom: 0; }
.kz-act-nom { font-size: 13px; color: var(--ink); }
.kz-act-cases { display: flex; gap: 4px; flex: none; }

/* La case elle-même est cachée : on clique la pastille, plus large et plus
   franche qu'une case de six pixels. */
.kz-act-case { width: 74px; display: flex; justify-content: center; cursor: pointer; }
@media (max-width: 620px) { .kz-act-case { width: 46px; } }
.kz-act-case input { position: absolute; opacity: 0; width: 0; height: 0; }
.kz-act-case > span {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 8px;
  border: 1px solid var(--line); color: var(--muted);
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.kz-act-case:hover > span { border-color: var(--seal); color: var(--seal); }
/* Coché : le fond se remplit. Décoché : la pastille reste, pâle — on voit qu'il
   y a un choix à faire, non un trou dans le tableau. */
.kz-act-case input:checked + span {
  background: var(--seal); border-color: var(--seal); color: #fff;
}
.kz-act-case input:focus-visible + span { outline: 2px solid var(--seal); outline-offset: 2px; }

/* R1335 — LA LIGNE DES MODÈLES : UN réglage, un filet, rien de plus.
   Elle en portait deux ; « Rétablir l'origine » est parti rejoindre le bouton
   qui vit au bas de chaque onglet, contre le texte qu'il remplace. Restent la
   langue des modèles et ses deux filets, qui la posent comme une barre
   d'outils — non comme un encart de plus dans une carte qui en a déjà trois.
   Le séparateur et la mise en forme du bloc retiré s'en vont avec lui : une
   règle qui ne peint plus rien est une fausse piste pour qui lira ensuite. */
.kz-mod-ligne {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 11px 0; margin: var(--e3) 0 0;
}
.kz-mod-ligne > label {
  font-size: 12.5px; color: var(--muted); white-space: nowrap; margin: 0;
}
.kz-mod-ligne select {
  font: inherit; font-size: 13px; padding: 7px 10px;
  border: 1px solid var(--champ-bord, #CFD8D3); border-radius: 8px;
  background: var(--paper); color: var(--ink); width: auto; min-width: 0;
}
@media (max-width: 620px) {
  .kz-mod-ligne { gap: 8px; }
}

/* R1001 — LES ONGLETS DES MODÈLES, EN CAPSULES.
   Des onglets à angles droits, collés à un filet, évoquaient un classeur : ils
   promettaient une hiérarchie qui n'existe pas. Vingt actions sont des CHOIX de
   même rang — la capsule le dit mieux.

   Elles défilent horizontalement : vingt onglets sur six lignes feraient perdre
   plus de place que le bloc n'en mérite. */
.kz-mod-onglets {
  display: flex; gap: 7px; overflow-x: auto; padding: 2px 2px 12px;
  margin-bottom: var(--e3);
  scroll-snap-type: x proximity;
  /* Le rail se voit sans crier : discret au repos, net au survol. */
  scrollbar-width: thin; scrollbar-color: var(--line) transparent;
}
.kz-mod-onglets::-webkit-scrollbar { height: 7px; }
.kz-mod-onglets::-webkit-scrollbar-track { background: transparent; }
.kz-mod-onglets::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 99px;
}
.kz-mod-onglets:hover::-webkit-scrollbar-thumb { background: var(--muted); }

.kz-mod-ong {
  flex: none; scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 1px; text-align: start;
  padding: 7px 14px; border-radius: 99px;
  border: 1px solid var(--line); background: var(--panel);
  font: inherit; font-size: 12.5px; color: var(--ink);
  cursor: pointer; white-space: nowrap;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.kz-mod-ong small {
  font-size: 9px; text-transform: uppercase; letter-spacing: .5px;
  color: var(--muted); transition: color .15s ease;
}
.kz-mod-ong:hover { border-color: var(--seal); }
/* R1004 : la capsule active se teinte, elle ne se remplit plus. Le vert plein
   criait plus fort que le contenu qu'il désigne — un onglet indique, il ne
   proclame pas. Fond clair, trait vert, texte inchangé : on le repère sans que
   la page en soit déséquilibrée. */
.kz-mod-ong.on {
  background: rgba(14, 107, 92, .09);
  border-color: var(--seal);
  color: var(--ink);
}
.kz-mod-ong.on small { color: var(--seal-dark); }
.kz-mod-ong:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; }

.kz-mod-volet { display: none; }
.kz-mod-volet.on { display: block; }
.kz-modeles code { font-size: 11.5px; }

/* R1003 — LE MESSAGE D'ATTENTE DE LA PREMIÈRE CONNEXION.
   Il ne paraît qu'après une seconde et demie : une connexion rapide ne doit pas
   voir clignoter un avertissement pour rien. Au-delà, l'attente devient réelle,
   et le silence pèse. */
.kz-attente {
  display: flex; align-items: flex-start; gap: 12px;
  margin-top: var(--e3); padding: 14px 16px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  font-size: 12.5px; color: var(--ink);
  animation: kz-attente-vient .35s ease both;
}
@keyframes kz-attente-vient { from { opacity: 0; transform: translateY(6px); } }
.kz-attente b { display: block; margin-bottom: 6px; font-size: 13px; color: var(--seal-dark); }
.kz-attente-anneau {
  width: 16px; height: 16px; flex: none; margin-top: 2px; border-radius: 50%;
  border: 2px solid var(--seal); border-top-color: transparent;
  animation: kz-attente-tourne .8s linear infinite;
}
@keyframes kz-attente-tourne { to { transform: rotate(360deg); } }

.kz-attente-liste { margin: 0 0 6px; padding: 0; list-style: none; }
.kz-attente-liste li {
  position: relative; padding-inline-start: 18px; margin: 3px 0;
  font-size: 12px; color: var(--muted); transition: color .25s ease;
}
/* La puce se remplit à mesure : on voit la préparation avancer, plutôt que
   d'attendre devant une liste inerte. */
.kz-attente-liste li::before {
  content: ''; position: absolute; inset-inline-start: 0; top: 5px;
  width: 8px; height: 8px; border-radius: 50%;
  border: 1.5px solid var(--line); transition: background .25s ease, border-color .25s ease;
}
.kz-attente-liste li.faite { color: var(--ink); }
.kz-attente-liste li.faite::before { background: var(--seal); border-color: var(--seal); }
@media (prefers-reduced-motion: reduce) {
  .kz-attente, .kz-attente-anneau { animation: none; }
}

/* R1004 — LE GUIDE DES REPÈRES, SOUS LE MESSAGE.
   Il se lit au moment d'écrire, non en tête de bloc où l'on ne le relit jamais.
   Discret : c'est un aide-mémoire, pas le sujet de la page. */
.kz-mod-guide {
  display: flex; flex-wrap: wrap; gap: 4px 14px;
  margin-top: 8px; padding: 9px 12px;
  background: var(--paper2); border: 1px solid var(--line); border-radius: 8px;
  font-size: 11px; color: var(--muted);
}
.kz-mod-guide code {
  font-size: 11px; color: var(--seal-dark);
  background: rgba(14, 107, 92, .07); padding: 1px 5px; border-radius: 4px;
}

/* R1006 — LA SÉPARATION ENTRE DEUX CARTES DE SUJETS DIFFÉRENTS.
   Deux cartes qui se touchent se lisent comme un seul bloc : on ne sait plus
   quel bouton commande quoi. Un trait et de l'air disent qu'on change de sujet.

/* R1018 : « .kz-separation » retirée — les deux cartes ont chacune leur cadre,
   un trait entre elles ajoutait une ligne de plus à un endroit déjà marqué. */
/* La carte des modèles porte son propre cadre, plus marqué que ses voisines :
   c'est un bloc à part entière, non une suite du courrier. */
/* R1015 : la carte des modèles portait un trait vert à gauche, hérité d'une
   ronde où elle vivait dans un autre bloc. Elle a maintenant la classe
   « carte-reglage » comme les quatre autres — un cadre qui se distingue des
   siens se lit comme une exception, alors qu'il n'en est pas une. */

/* ==========================================================================
   R1040 — RESPIRATION ET RESPONSIVE DES DEUX MODULES (scanner, API).
   Les pages étaient justes mais serrées : lignes collées dans les listes,
   blocs de code de la documentation débordant de leur cadre sur mobile, et
   des tableaux qu'il fallait faire défiler pour atteindre « Classer ».
   Rien d'inventé ici : mêmes variables, mêmes ruptures (900 / 600 / 420)
   que le reste de la maison.
   ========================================================================== */

/* --- L'air dans les listes des deux modules --- */
.kz-scan .table td,
.kz-scan .table th,
.kz-api .table td,
.kz-api .table th { padding-top: 11px; padding-bottom: 11px; line-height: 1.55; }
.kz-scan .table td + td,
.kz-api .table td + td { padding-inline-start: 14px; }
/* R1048 — le filet se pose sur la LIGNE, non sur ses cellules : une cellule
   vide (la colonne des gestes, quand il n'y en a plus) le faisait s'arrêter
   à mi-chemin, et le tableau paraissait cassé. */
.kz-scan .table tbody tr + tr,
.kz-api .table tbody tr + tr { box-shadow: inset 0 1px 0 var(--line); }
.kz-scan h3, .kz-api h3 { margin-top: 26px; margin-bottom: 10px; }
.kz-scan .muted.small, .kz-api .muted.small { line-height: 1.6; }
/* Les gestes d'une ligne ne se collent jamais entre eux */
.kz-scan .table td .btn + .btn,
.kz-scan .table td form + form,
.kz-scan .table td form + .btn,
.kz-scan .table td .btn + form,
.kz-api .table td .btn + .btn,
.kz-api .table td form + form,
.kz-api .table td form + .btn,
.kz-api .table td .btn + form { margin-inline-start: 8px; }

/* R1342 — CES TROIS RÈGLES SONT PARTIES. Écrites quand la fenêtre de
   classement avait ses propres balises, elles visaient « #mClasser » par son
   IDENTIFIANT : une fois la fenêtre passée aux classes de la maison, elles
   battaient les règles de la maison sans qu'on le voie — quatre pixels entre
   deux cases à cocher au lieu de dix, parce qu'un sélecteur d'identifiant
   l'emporte toujours sur un sélecteur de classe. La leçon vaut au-delà : une
   règle écrite pour UN écran survit au balisage pour lequel elle a été écrite,
   et gouverne en silence celui qui le remplace. Le rythme vient désormais de
   « lec-label », « lec-case » et « modal-foot », comme partout ailleurs. */

/* --- La carte des clés d'API : le formulaire de création s'aligne --- */
.kz-api .row { row-gap: 10px; }
.kz-api code { word-break: break-all; }

/* --- La documentation : les blocs de code ne débordent JAMAIS --- */
.kz-doc pre { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch;
  padding: 14px 16px; line-height: 1.6; border-radius: 10px; }
.kz-doc pre code { white-space: pre; }
.kz-doc h3 { margin-top: 30px; }
.kz-doc h4 { margin: 22px 0 6px; }
.kz-doc p, .kz-doc li { line-height: 1.7; }
.kz-doc .table td { padding-top: 10px; padding-bottom: 10px; line-height: 1.6; }
.kz-doc code { word-break: break-word; }

@media (max-width: 900px) {
  /* Sous 900 px, les gestes passent SOUS le nom : plus besoin de défiler
     latéralement pour atteindre « Classer » ou « Révoquer ». */
  .kz-scan .table, .kz-scan .table tbody, .kz-scan .table tr, .kz-scan .table td,
  .kz-api .table, .kz-api .table tbody, .kz-api .table tr, .kz-api .table td { display: block; width: auto; }
  .kz-scan .table thead, .kz-api .table thead { display: none; }
  .kz-scan .table tbody tr, .kz-api .table tbody tr {
    border: 1px solid var(--line2); border-radius: 10px;
    padding: 10px 12px; margin-bottom: 10px; background: var(--panel); }
  .kz-scan .table tbody tr + tr, .kz-api .table tbody tr + tr { box-shadow: none; }
  .kz-scan .table td, .kz-api .table td { border: 0; padding: 3px 0; }
  .kz-scan .table td.right, .kz-api .table td.right { text-align: start; padding-top: 10px; }
  .kz-scan .table td + td, .kz-api .table td + td { padding-inline-start: 0; }
  .kz-scan .table td .btn, .kz-api .table td .btn { margin-inline-start: 0 !important; }
  .kz-scan .table td form, .kz-api .table td form { display: inline-block; margin: 0 8px 0 0; }
  /* Le réglage : chemin et « Tester » l'un sous l'autre plutôt que serrés */
  #regl-scanner .row, #regl-api .row { flex-direction: column; align-items: stretch; }
  #regl-scanner .row .btn, #regl-api .row .btn { width: 100%; }
  #regl-api select, #regl-api input[type="text"] { width: 100%; }
}

@media (max-width: 600px) {
  .kz-scan .table tbody tr, .kz-api .table tbody tr { padding: 10px; }
  .kz-doc pre { font-size: 12.5px; padding: 12px; }
  .kz-doc .table td { padding: 8px 6px; }
  /* Les cases à cocher des accès s'aèrent au doigt */
  #regl-scanner label, #regl-api label { padding: 3px 0; }
}

/* ==========================================================================
   R1045 — LA VISITE GUIDÉE. Un voile qui éteint la page, un projecteur qui
   découpe la vraie commande, un panneau qui l'explique à côté. Les couleurs
   sont celles de la maison ; les mouvements se taisent si la personne a
   demandé moins d'animation.
   ========================================================================== */
/* R1049 — le voile s'éclaircit (on doit RECONNAÎTRE la page derrière, pas
   l'effacer), et le projecteur passe à l'or de la maison : le vert du sceau
   se confondait avec les boutons qu'il désignait. */
.kzv-fond { position: fixed; inset: 0; z-index: 9000; background: rgba(33, 48, 46, .38);
  opacity: 0; visibility: hidden; transition: opacity .28s ease, visibility .28s; }
.kzv-fond.on { opacity: 1; visibility: visible; }
/* Le trou n'existe QUE porteur de « on » : sans quoi son ombre de neuf mille
   pixels survivait à la visite et gardait l'écran assombri. */
.kzv-trou { position: fixed; z-index: 9001; border-radius: 12px; pointer-events: none;
  box-shadow: none; opacity: 0; transition: all .34s cubic-bezier(.4, 0, .2, 1); }
.kzv-trou.on { box-shadow: 0 0 0 3px var(--ambre), 0 0 0 9999px rgba(33, 48, 46, .38);
  animation: kzv-halo 2.2s ease-in-out infinite; }
@keyframes kzv-halo {
  0%, 100% { box-shadow: 0 0 0 3px var(--ambre), 0 0 0 9999px rgba(33, 48, 46, .38); }
  50%      { box-shadow: 0 0 0 7px var(--ambre-doux), 0 0 0 9999px rgba(33, 48, 46, .38); }
}
.kzv-panneau { position: fixed; z-index: 9002; width: min(370px, calc(100vw - 24px));
  background: var(--panel); border: 1px solid var(--ambre); border-radius: 14px;
  box-shadow: 0 18px 46px rgba(33, 48, 46, .22); padding: 16px 18px 14px;
  opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility .2s; }
.kzv-panneau.on { opacity: 1; visibility: visible; }
.kzv-panneau.kzv-entre { animation: kzv-arrive .34s cubic-bezier(.34, 1.4, .5, 1); }
@keyframes kzv-arrive { from { transform: translateY(10px) scale(.97); opacity: 0; } to { transform: none; opacity: 1; } }
.kzv-x { position: absolute; top: 8px; right: 10px; border: 0; background: none; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--muted); padding: 2px 6px; border-radius: 6px; }
.kzv-x:hover { background: var(--paper2); }
.kzv-dessin { width: 62px; height: 62px; margin-bottom: 8px; }
/* R1049 — une couleur PAR DÉFAUT sur le dessin : le cercle de la toute
   première illustration ne portait aucune classe de couleur et s'affichait
   donc EN NOIR — la première chose que voyait le nouvel arrivant. */
.kzv-dessin svg { width: 100%; height: 100%; fill: var(--ambre); stroke: none; }
.kzv-dessin .d-plein { fill: var(--ambre); opacity: .92; }

/* ===== R1472 — le repère des deux temps, dans la fenêtre de classement =====
   ⚠ Sa carte est « display:flex; flex-direction:column », et l'« ol » s'y
   réduisait à son rembourrage : 16 px de large, poussé hors du cadre. Chez la
   vérification (R1413) la carte ne l'est pas, et il s'étendait tout seul — la
   même balise, le même style, deux résultats. Règle PORTÉE À CET IDENTIFIANT :
   « .kz-pas » sert ailleurs, et on ne déplace pas ce qui va bien. */
#clPas { align-self: stretch; width: auto; }

/* ===== R1470 — LE DESSIN COMPOSÉ : un objet, un verbe ===== */
/* ⚠ L'ORDRE DE L'ANIMATION PORTE LE SENS. L'objet se dessine d'abord, le verbe
   entre ensuite : c'est ce décalage qui fait lire « on fait CECI à CELA », dans
   cet ordre. Les deux ensemble, ce ne serait qu'un logo de plus. */
.kzv-dessin .d-trait,
.kzv-dessin .d-geste {
  /* Le tracé se dessine : la longueur du trait sert de pointillé, et l'on fait
     glisser le vide. 220 couvre le plus long chemin du vocabulaire — un pointillé
     plus long que le trait ne se voit pas, trop court il répéterait. */
  stroke-dasharray: 220; stroke-dashoffset: 220;
  animation: kzv-ecrire .55s ease-out forwards;
}
.kzv-dessin .d-geste {
  fill: none; stroke: var(--panel, #fff); stroke-width: 3.4;
  stroke-linecap: round; stroke-linejoin: round;
  animation-delay: .3s;            /* le verbe suit l'objet */
}
.kzv-dessin .d-pastille {
  fill: var(--ambre); opacity: 0;
  animation: kzv-pastille .3s ease-out .26s forwards;
  transform-origin: 51px 51px;
}
/* Le petit plein d'un verbe — la pupille de l'œil, le point du « ? ». */
.kzv-dessin .d-geste + .d-plein,
.kzv-dessin .d-pastille ~ .d-plein { fill: var(--panel, #fff); opacity: 0;
  animation: kzv-pastille .3s ease-out .5s forwards; }
@keyframes kzv-ecrire { to { stroke-dashoffset: 0; } }
@keyframes kzv-pastille { from { opacity: 0; transform: scale(.4); }
                          to   { opacity: 1; transform: scale(1); } }
/* ⚠ QUI DEMANDE MOINS DE MOUVEMENT N'EN REÇOIT PAS. Le réglage du système
   l'emporte : le dessin paraît d'un coup, entier et lisible. */
@media (prefers-reduced-motion: reduce) {
  .kzv-dessin .d-trait, .kzv-dessin .d-geste {
    stroke-dasharray: none; stroke-dashoffset: 0; animation: none;
  }
  .kzv-dessin .d-pastille, .kzv-dessin .d-pastille ~ .d-plein { opacity: 1; animation: none; }
}
.kzv-dessin .d-trait { fill: none; stroke: var(--ambre); stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }
.kzv-dessin .d-pulse  { animation: kzv-bat 1.8s ease-in-out infinite; transform-origin: center; }
.kzv-dessin .d-pulse2 { animation: kzv-bat 1.8s ease-in-out .3s infinite; transform-origin: center; }
@keyframes kzv-bat { 0%, 100% { transform: scale(1); opacity: .9; } 50% { transform: scale(1.12); opacity: 1; } }
.kzv-dessin .d-vole { fill: var(--ambre); opacity: .6; animation: kzv-vole 2s ease-in-out infinite; }
@keyframes kzv-vole { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
.kzv-dessin .d-sonne { animation: kzv-sonne 2.4s ease-in-out infinite; transform-origin: 35px 14px; }
@keyframes kzv-sonne { 0%, 70%, 100% { transform: rotate(0); } 78% { transform: rotate(9deg); } 86% { transform: rotate(-9deg); } 94% { transform: rotate(4deg); } }
.kzv-dessin .d-balaie { stroke: var(--ambre); stroke-width: 4; stroke-linecap: round;
  animation: kzv-balaie 2.2s ease-in-out infinite; }
@keyframes kzv-balaie { 0%, 100% { transform: translateY(-6px); opacity: .25; } 50% { transform: translateY(6px); opacity: 1; } }
.kzv-dessin .d-file { stroke: var(--ambre); stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 5 6; animation: kzv-file 1.4s linear infinite; }
@keyframes kzv-file { to { stroke-dashoffset: -22; } }
.kzv-dessin .d-tourne { animation: kzv-tourne 3.4s linear infinite; transform-origin: 36px 38px; }
@keyframes kzv-tourne { to { transform: rotate(360deg); } }
.kzv-dessin .d-trace { fill: none; stroke: var(--ambre); stroke-width: 6; stroke-linecap: round;
  stroke-linejoin: round; stroke-dasharray: 60; stroke-dashoffset: 60; animation: kzv-trace .7s ease-out .1s forwards; }
@keyframes kzv-trace { to { stroke-dashoffset: 0; } }
.kzv-corps b { display: block; font-size: 15.5px; margin-bottom: 5px; }
.kzv-corps p { margin: 0 0 13px; font-size: 14px; line-height: 1.62; color: var(--muted); }
.kzv-pied { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.kzv-points { display: flex; gap: 5px; align-items: center; }
.kzv-points i { width: 6px; height: 6px; border-radius: 50%; background: var(--line2); transition: all .25s; }
.kzv-points i.fait { background: var(--seal); opacity: .55; }
.kzv-points i.on { width: 18px; border-radius: 3px; background: var(--ambre); }
.kzv-gestes { display: flex; gap: 8px; }
@media (max-width: 720px) {
  .kzv-panneau { width: calc(100vw - 20px); padding: 14px 16px 12px; }
  .kzv-dessin { width: 48px; height: 48px; }
  .kzv-gestes { flex: 1; }
  .kzv-gestes .btn { flex: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .kzv-trou, .kzv-panneau.kzv-entre, .kzv-dessin * { animation: none !important; transition: none !important; }
}

/* R1046 — pendant la visite, la page ne défile plus sous le voile : c'est la
   visite qui amène chaque commande au centre. Le voile invite au clic. */
html.kzv-fige, html.kzv-fige body { overflow: hidden !important; }
.kzv-fond.on { cursor: pointer; }

/* R1047 — le chapitre, au-dessus du titre : vingt-deux étapes sans repère
   ressemblent à un couloir sans fin. */
.kzv-chap { display: block; font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ambre); font-weight: 600; margin-bottom: 3px; }

/* ==========================================================================
   R1048 — LES ÉTATS VIDES DU SCANNER. Un écran vide n'est pas un écran raté :
   il dit ce qui va se passer, montre que le circuit vit, et laisse un geste
   à faire. Motif .empty de la maison (cadre pointillé, titre en serif),
   palette de la maison (sceau, encre, papier) — rien d'inventé.
   ========================================================================== */
/* R1052 — LA FILE DU SCANNER, EN LIGNES AÉRÉES. Le tableau serré cédait la
   place à des lignes qu'on balaie du regard : vignette du type, nom en
   évidence, provenance et âge en dessous, gestes à droite. L'espacement
   entre les lignes est VOULU large — on classe à la chaîne, l'œil doit se
   poser sans hésiter d'une ligne à l'autre.
   ========================================================================== */
.scan-tete { justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; }
.scan-tete h2 { margin: 0; }
.scan-tete-gestes { display: flex; gap: 8px; flex-wrap: wrap; }
/* R1347 — « Regarder » est un ENVOI, non un lien : il balaie le dossier,
   écrit en base et peut prévenir du monde, et une adresse ne porte pas de
   jeton. Le formulaire qui l'enveloppe ne doit rien changer à sa place dans
   la rangée de boutons. */
.kz-enligne { display: inline-flex; margin: 0; }

.scan-faits-grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px; margin: 16px 0 18px; }
.scan-fait { background: var(--paper2); border-radius: var(--r); padding: 11px 14px; }
.scan-fait .lbl { margin: 0 0 3px; font-size: var(--t-detail); color: var(--muted); }
.scan-fait .val { margin: 0; font-size: 24px; font-weight: 600; color: var(--ink); line-height: 1.1; }
.scan-fait .chemin { margin: 5px 0 0; font-size: 13px; font-family: var(--mono); color: var(--ink);
  word-break: break-all; }
.scan-fait.chaud { background: rgba(184, 130, 42, .10); }
.scan-fait.chaud .lbl, .scan-fait.chaud .val { color: var(--ambre); }

.scan-lot { display: flex; align-items: center; gap: 10px; background: var(--seal-soft);
  border-radius: var(--r); padding: 9px 13px; margin-bottom: 12px; flex-wrap: wrap; }
.scan-lot-n { font-size: 13.5px; color: var(--seal); }
.scan-lot-n b { font-weight: 600; }

.scan-liste { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.scan-liste-attente { margin-top: 12px; border-style: dashed; }
.scan-ligne { display: grid; grid-template-columns: 22px 46px minmax(0, 1fr) auto;
  gap: 14px; align-items: center; padding: 16px 14px; }
.scan-ligne + .scan-ligne { border-top: 1px solid var(--line); }
.scan-ligne:hover { background: var(--paper2); }
.scan-ligne.pale { opacity: .6; }
.scan-ligne.pale:hover { background: none; }
.scan-coche { margin: 0; width: 16px; height: 16px; }
.scan-coche-vide { display: block; width: 16px; }
/* R1339 — LA VIGNETTE MONTRE LE DOCUMENT, l'extension n'est plus que son
   filet de sécurité. L'image se pose PAR-DESSUS la pastille : si le type ne
   donne pas de vignette, ou si la fabrique est occupée, l'image ne se charge
   pas et la pastille se voit — sans une ligne de script, que l'en-tête de
   sécurité refuserait de toute façon. */
.scan-vignette { position: relative; width: 46px; height: 58px; padding: 0;
  border: 1px solid var(--line); border-radius: 5px; overflow: hidden;
  background: var(--paper2); display: flex; align-items: center; justify-content: center;
  text-decoration: none; cursor: pointer; }
.scan-vignette img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top center; display: block; }
.scan-vignette:hover { border-color: var(--seal); }
.scan-vignette:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; }

/* C53 : la fenêtre d’aperçu du scanner est partie avec le module. */
.scan-vignette.pointille { border-style: dashed; }
.scan-ext { font-size: 10.5px; font-weight: 600; letter-spacing: .04em; color: var(--muted); }
.scan-nom { min-width: 0; }
.scan-nom .titre { margin: 0 0 4px; font-size: 14.5px; font-weight: 500; color: var(--ink);
  word-break: break-word; line-height: 1.4; }
.scan-nom .meta { margin: 0; font-size: var(--t-detail); color: var(--muted); line-height: 1.5; }
.scan-gestes { display: flex; gap: 7px; align-items: center; }
.scan-gestes .btn.iconseul { padding: 0 9px; }
.scan-patience { font-size: var(--t-detail); color: var(--muted); white-space: nowrap; }

.scan-traites > summary { cursor: pointer; font-size: var(--t-sect); color: var(--ink);
  padding: 9px 0; list-style: none; display: flex; align-items: center; gap: 7px; }
.scan-traites > summary::-webkit-details-marker { display: none; }
.scan-traites[open] > summary .ic { transform: rotate(90deg); }
.scan-traites > summary .ic { transition: transform .18s ease; }

/* Le classement : ce qu'on range est SOUS LES YEUX. */
.modal-large .modal-card { max-width: 860px; width: min(860px, 94vw); }
/* R1342 — LA FENÊTRE DE CLASSEMENT PREND LA FACTURE DE « verify.php ».
   Elle avait la sienne : un aperçu collé au bord sans cadre, un formulaire
   dont les boutons vivaient dans le corps, des étiquettes écrites à la main.
   Elle emploie maintenant « vl-tete », « vl-corps », « vl-apercu »,
   « vl-detail » et « vl-pied » — les classes de la fenêtre de lecture, donc
   les mêmes bordures, les mêmes rayons, le même pied. Ne restent ici que les
   PROPORTIONS propres au geste : on ne reconnaît pas une facture sur une
   vignette de 220 px, il faut pouvoir la lire pour la titrer. */
/* R1344 — L'APERÇU REPREND EXACTEMENT LES MESURES DU MODÈLE. J'avais élargi
   la colonne à 300 px et poussé le cadre à 340 px de haut, en me disant qu'on
   ne reconnaît pas une facture sur une vignette. Le résultat sur un écran
   d'ordinateur portable : la fenêtre ne tenait plus, le corps se mettait à
   défiler, et le champ « Titre » — le premier qu'on remplit — sortait par le
   haut. On voyait donc MOINS, non plus. Les mesures du modèle (220 × 175-200)
   font tenir la fenêtre entière sous les yeux ; l'aperçu y sert à ce qu'il
   sert — RECONNAÎTRE la pièce qu'on range —, et la fenêtre d'aperçu, d'un
   clic, la montre en grand quand il faut la LIRE. Ne restent ici que les
   règles de rendu : le cadre remplit sa boîte, l'image s'y contient. */
/* R1346 — L'APERÇU EST UNE FEUILLE A4. Il tenait dans un cadre de 220 × 200 :
   un timbre, où l'on devinait la pièce sans la lire. Une feuille debout, au
   rapport du format (210 × 297), dit tout de suite ce qu'on regarde — et le
   document s'y pose au centre, entier, quelle que soit sa forme : un scan à
   l'italienne garde ses marges en haut et en bas, comme sur une vraie feuille.

   LA LARGEUR N'EST PLUS CHOISIE, ELLE DÉCOULE. La carte prend toute la hauteur
   qu'elle a le droit de prendre, le corps la remplit, la feuille remplit le
   corps — et sa largeur suit, par le rapport. Rien ne défile : ce qu'on voit
   est ce qu'il y a. Le formulaire se centre en face d'elle, faute de quoi il
   se tasserait en haut d'une colonne deux fois plus haute que lui. */
#mClasser .modal-card { height: min(88dvh, 780px); }
#mClasser .modal-body.vl-corps { flex: 1 1 auto; min-height: 0;
  grid-template-columns: auto minmax(0, 1fr); align-items: stretch; }
.scan-cl-apercu { align-items: center; justify-content: center; padding: 0;
  height: 100%; width: auto; aspect-ratio: 210 / 297;   /* A4 debout */
  min-height: 0; max-height: none; overflow: hidden; }
.scan-cl-apercu iframe { width: 100%; height: 100%; border: 0;
  border-radius: 9px; background: var(--paper); }
.scan-cl-apercu img { width: 100%; height: 100%; object-fit: contain;
  /* « .vl-apercu img » borne l'image à 190 px de haut — la hauteur du timbre
     d'origine. Sans cette levée, le document restait minuscule au centre
     d'une grande feuille vide. */
  max-width: none; max-height: none;
  border-radius: 9px; background: var(--paper); }
.scan-cl-apercu [hidden] { display: none; }
/* ═══════════════════════════════════════════════════════════════════════
   R1479 — ⚠ « align-self: center » ET « overflow-y: auto » NE VONT PAS
   ENSEMBLE, et le client l'a vu avant moi : « le menu Ranger dans est collé
   au haut, descends-le un peu ».

   R1346 centrait le formulaire en face de la feuille A4, et c'était juste
   TANT QU'IL ÉTAIT PLUS COURT que sa colonne. Depuis, R1472 y a posé les
   quatre cartes de moteur, R1476 la liste des étapes, R1477 la case du titre :
   il est devenu plus HAUT qu'elle. Or un contenu centré qui déborde sort par
   les DEUX bouts — et le défilement ne rattrape que le bas. Mesuré sur sa
   capture : le champ « Titre », le PREMIER qu'on remplit, était hors
   d'atteinte, et rien ne le disait.

   La parade est la marge automatique portée par deux pseudo-éléments : quand
   le formulaire tient, l'espace libre se partage au-dessus et au-dessous et il
   reste centré comme R1346 le voulait ; quand il déborde, les marges tombent à
   zéro et il repart du HAUT, entier et défilable. ⚠ Et « flex: 0 0 auto » sur
   les vrais enfants, sans quoi un formulaire trop haut se ferait COMPRIMER au
   lieu de déborder — on aurait échangé un haut perdu contre un bas écrasé.
   ═══════════════════════════════════════════════════════════════════════ */
#mClasser .vl-detail { overflow-y: auto; align-self: stretch;
  display: flex; flex-direction: column; padding: 10px 2px; }
#mClasser .vl-detail > * { flex: 0 0 auto; }
#mClasser .vl-detail::before,
#mClasser .vl-detail::after { content: ''; margin: auto; }
/* Et le classement groupé reçoit le même air : il ne déborde pas, mais son
   premier champ était collé au bandeau des étapes tout autant. */
#mLot .vl-detail { padding: 10px 2px; }
/* Le nom du fichier, dans le bandeau : il peut être long, il ne pousse pas le compteur. */
.scan-cl-fichier { flex: 1 1 260px; min-width: 0; font-weight: 600; font-size: 13.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#mClasser .vl-detail .lec-label:first-child { margin-top: 0; }
@media (max-width: 720px) {
  .scan-cl-apercu iframe { min-height: 130px; }
}
@media (max-width: 600px) {
  .scan-ligne { grid-template-columns: 22px 40px minmax(0, 1fr); gap: 11px; padding: 14px 12px; }
  .scan-vignette { width: 40px; height: 50px; }
  .scan-gestes { grid-column: 1 / -1; padding-top: 4px; }
  .scan-gestes .btn { flex: 1; }
  .scan-patience { grid-column: 1 / -1; }
}

.scan-vide { padding: 34px 20px 28px; background: var(--paper2); }
/* R1336 — L'ICÔNE DU COPIEUR, IMMOBILE. Ici vivait un dessin animé : deux
   traits qui clignotaient sous le capot (« sv-lire ») et une veilleuse qui
   battait sans fin (« sv-veille »). Une image qui bouge attire l'oeil en
   permanence et promet qu'il se passe quelque chose ; or sur cet écran l'on
   ATTEND — rien ne se passe, et c'est justement ce qu'il faut dire. Une icône
   de la maison le dit et se tait. Les deux animations sont parties avec elle :
   une règle qui ne peint plus rien est une fausse piste pour qui lira ensuite. */
/* « margin: 0 auto » ne centre que ce qui a une largeur : le dessin d'avant
   était un SVG large de 118 px, l'icône est un signe dans une boîte qui prend
   toute la ligne. On centre donc le CONTENU, non la boîte. */
.scan-vide-img { display: flex; justify-content: center; margin: 0 0 10px;
  color: var(--seal); line-height: 0; }

/* R1337 — LE RAYON, SOUS LA VITRE, ET NULLE PART AILLEURS.
   Il balayait la carte entière ; il tient maintenant dans la boîte de l'icône,
   où il court sur quatre pixels — assez pour dire « ça numérise », trop peu
   pour tirer l'oeil hors de ce qu'on lit. */
.kz-scanner-ic .kz-scanner-ray {
  animation: kz-scanner-ray 2.6s ease-in-out infinite;
  opacity: .9;
}
@keyframes kz-scanner-ray {
  0%, 100% { transform: translateY(0);     opacity: .35; }
  50%      { transform: translateY(3.6px); opacity: 1; }
}
/* Qui a demandé moins de mouvement le voit posé, et lisible. */
@media (prefers-reduced-motion: reduce) {
  .kz-scanner-ic .kz-scanner-ray { animation: none; opacity: .75; }
}
.scan-vide-img .ic { display: block; }
/* Dans la tête de la mise en route, l'icône est posée À CÔTÉ du texte : elle
   ne se centre pas, elle ne s'étire pas. */
.scan-neuf-tete .scan-vide-img { display: inline-flex; flex: 0 0 auto; margin: 0; }
.scan-vide .big { margin-bottom: 6px; }
.scan-vide p i { color: var(--muted); font-style: normal; font-size: 13.5px; line-height: 1.65;
  display: inline-block; max-width: 46ch; }
.scan-vide-gestes { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }
.scan-vide-note { margin: 14px 0 0; font-size: var(--t-detail); color: var(--muted); }

/* R1053 — LA MISE EN ROUTE. Chaque geste a sa carte : un numéro, un titre
   court, une phrase, et son chemin sur sa PROPRE ligne — entier, copiable,
   jamais réduit à une pastille qui déborde. */
.scan-neuf { background: var(--paper2); border: 1px dashed var(--line2); border-radius: var(--r);
  padding: 26px 24px 22px; }
.scan-neuf-tete { display: flex; gap: 18px; align-items: center; margin-bottom: 22px; }
.scan-neuf-tete .scan-vide-img { flex: 0 0 auto; margin: 0; }
.scan-neuf-titre { font-family: var(--serif); font-size: 19px; color: var(--ink); margin: 0 0 6px; }
.scan-neuf-sous { margin: 0; font-size: 13.5px; color: var(--muted); line-height: 1.65; max-width: 62ch; }

.scan-pas-grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 12px; }
.scan-pas-carte { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
  padding: 14px 16px 16px; display: flex; flex-direction: column; align-items: flex-start; }
.scan-pas-carte .num { width: 23px; height: 23px; border-radius: 50%; background: var(--seal);
  color: #fff; font-size: 12px; font-weight: 600; display: flex; align-items: center;
  justify-content: center; margin-bottom: 9px; }
.scan-pas-carte .quoi { margin: 0 0 5px; font-size: 14.5px; font-weight: 600; color: var(--ink); }
.scan-pas-carte .detail { margin: 0 0 11px; font-size: 13px; color: var(--muted); line-height: 1.6; }
.scan-pas-carte .chemin { display: block; width: 100%; box-sizing: border-box; background: var(--paper2);
  border: 1px solid var(--line); border-radius: 6px; padding: 7px 10px; font-family: var(--mono);
  font-size: 12.5px; color: var(--ink); word-break: break-all; margin-bottom: 9px; }
.scan-pas-carte .btn { margin-top: auto; }
.scan-pas-carte .scan-pas-cta { margin-top: auto; }
.scan-neuf-pied { margin: 20px 0 0; font-size: var(--t-detail); color: var(--muted); line-height: 1.6; }

/* R1336 — LE RÉGLAGE DU DOSSIER SCANNER, AUX RÈGLES DES RÉGLAGES.
   Cet écran portait un formulaire à nu : pas de section, pas de titre, et des
   styles écrits à la main dans les balises. Trois sections titrées, comme sur
   la page des réglages ; les champs et les cases sont ceux de la maison
   (« lec-label », « lec-label-ligne ») et n'ont rien à redéfinir ici. */
.scan-regl + .scan-regl { margin-top: var(--e4); padding-top: var(--e4); border-top: 1px solid var(--line); }
.scan-regl > h3 {
  display: flex; align-items: center; gap: 8px; margin: 0 0 var(--e2);
  font-family: var(--serif); font-weight: 400; font-size: 16px; color: var(--ink);
}
.scan-regl > h3 .ic { color: var(--seal); flex: 0 0 auto; }
.scan-regl > .form-aide { margin-top: 0; }

/* Le chemin et son bouton « Tester » sur une seule ligne — et le champ prend
   ce qui reste. Il se replie de lui-même sur un écran étroit. */
.scan-chemin { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.scan-chemin input { flex: 1 1 220px; min-width: 0; }
.scan-chemin .btn { flex: 0 0 auto; }

/* R1337 — LES RÈGLES DE LA LISTE DES COMPTES SONT PARTIES AVEC ELLE.
   Le scanner tenait sa propre liste d'accès ; l'accès est désormais le droit
   « page_scanner », réglé dans « Utilisateurs & accès ». Un style que plus
   personne ne porte fait douter au passage suivant. */

@media (max-width: 600px) {
  .scan-vide { padding: 26px 14px 22px; }
  .scan-vide-gestes .btn { flex: 1; }
}
/* R1336 — plus rien ne bouge ici : le rattrapage « mouvement réduit » n'a plus d'objet. */

/* ==========================================================================
   R1054 — LA DOCUMENTATION DE L'API, EN PRÉSENTATION TECHNIQUE. Les actes
   étaient des lignes de tableau dont les colonnes « Acte » et « Méthode »
   mangeaient la largeur ; les exemples s'empilaient en coupant leurs lignes.
   Fiches à largeurs fixes, blocs de code à onglets, défilement INTERNE.
   ========================================================================== */
.api-base { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--paper2); border: 1px solid var(--line); border-radius: var(--r);
  padding: 10px 13px; margin: 14px 0 4px; }
.api-base .lbl { font-size: var(--t-detail); color: var(--muted); }
.api-base code { flex: 1; min-width: 200px; font-family: var(--mono); font-size: 13px;
  color: var(--ink); word-break: break-all; }

.api-acte { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin: 12px 0; }
.api-acte-tete { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--paper2); border-bottom: 1px solid var(--line); padding: 9px 13px; }
.api-verbe { font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .05em;
  padding: 3px 9px; border-radius: 4px; }
.api-verbe.get { background: var(--seal-soft); color: var(--seal); }
.api-verbe.post { background: rgba(184, 130, 42, .16); color: var(--ambre); }
.api-chemin { font-family: var(--mono); font-size: 13.5px; color: var(--ink); background: none;
  border: 0; padding: 0; }
.api-type { margin-inline-start: auto; font-size: var(--t-detail); color: var(--muted); }
.api-acte-corps { padding: 11px 13px 12px; }
.api-quoi { margin: 0 0 10px; font-size: 13.5px; color: var(--muted); line-height: 1.6; }
.api-params { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 12.5px;
  margin: 0 0 9px; }
.api-params td { padding: 5px 0; vertical-align: top; line-height: 1.55; }
.api-params .nom { width: 104px; font-family: var(--mono); color: var(--seal); word-break: break-all; }
.api-params .besoin { width: 74px; font-size: 11.5px; }
.api-params .besoin.requis { color: var(--err); }
.api-params .besoin.conseille { color: var(--ambre); }
.api-params .besoin.option { color: var(--muted); }
.api-params .desc { color: var(--muted); }
.api-rend { margin: 0; font-size: 12.5px; color: var(--muted); }
.api-rend b { color: var(--ink); font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  margin-inline-end: 6px; }
.api-rend code { font-size: 12px; word-break: break-word; }

.api-codes { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 13px;
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin: 12px 0; }
.api-codes th { text-align: start; background: var(--paper2); font-size: 12px; font-weight: 600;
  padding: 9px 11px; color: var(--ink); }
.api-codes th:first-child { width: 62px; }
.api-codes th:nth-child(2) { width: 132px; }
.api-codes td { padding: 8px 11px; border-top: 1px solid var(--line); color: var(--muted);
  line-height: 1.55; vertical-align: top; }
.api-codes td.nom { font-family: var(--mono); font-size: 12px; word-break: break-all; }
.api-code { font-family: var(--mono); font-size: 11.5px; font-weight: 700; padding: 2px 7px;
  border-radius: 4px; }
.api-code.ok { background: var(--seal-soft); color: var(--seal); }
.api-code.warn { background: rgba(184, 130, 42, .16); color: var(--ambre); }
.api-code.err { background: var(--err-bg); color: var(--err); }

.api-code-bloc { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin: 12px 0; }
.api-onglets { display: flex; align-items: center; gap: 2px; flex-wrap: wrap;
  background: var(--paper2); border-bottom: 1px solid var(--line); padding: 6px 8px; }
.api-onglets-vide { flex: 1; }
.api-onglets > button[data-lang] { background: none; border: 1px solid transparent; cursor: pointer;
  font-size: 12.5px; padding: 4px 11px; border-radius: 5px; color: var(--muted);
  font-family: var(--sans); }
.api-onglets > button[data-lang]:hover { color: var(--ink); }
.api-onglets > button[data-lang].on { background: var(--panel); border-color: var(--line);
  color: var(--ink); font-weight: 600; }
.api-code-bloc pre { margin: 0; padding: 13px 15px; background: var(--panel);
  overflow-x: auto; -webkit-overflow-scrolling: touch; }
.api-code-bloc pre code { font-family: var(--mono); font-size: 12.5px; line-height: 1.7;
  color: var(--ink); white-space: pre; display: block; }

@media (max-width: 600px) {
  .api-params .nom { width: 88px; }
  .api-params .besoin { width: 64px; font-size: 11px; }
  .api-codes th:nth-child(2), .api-codes td.nom { display: none; }
  .api-code-bloc pre { padding: 11px 12px; }
  .api-code-bloc pre code { font-size: 11.5px; }
}

/* R1055/R1057 — LE BOUTON DE LA VISITE, AU PIED DE PAGE. Aux mesures exactes
   d'« Assistance » (11,5 px, sans cadre, 3×6 de marge, interligne calé car un
   LIEN hérite celui du corps, pas celui des boutons).

   R1058 — UN TIC PAR SECONDE, SANS FIN, COMME UNE TROTTEUSE. Le double
   battement espacé de sept secondes se remarquait, mais laissait de longs
   silences : on veut une présence CONTINUE. La pastille bat donc une fois
   par seconde, d'une frappe nette — montée vive, retombée douce — et une
   onde s'en écarte à chaque tic. Le texte, lui, ne clignote PAS : à un
   battement par seconde il deviendrait illisible ; seule la pastille
   travaille. Il ne se grise jamais, même la visite faite. */
.pied-visite {
  display: inline-flex; align-items: center; gap: 6px; text-decoration: none;
  background: none; border: none; cursor: pointer;
  font-size: 11.5px; color: var(--ambre-vif); padding: 3px 6px; border-radius: 6px;
  line-height: 14px;
}
.pied-visite:hover { background: var(--bg); color: var(--ambre-vif); }
.pied-visite .pv-point { position: relative; width: 5px; height: 5px; border-radius: 50%;
  background: var(--ambre-vif); flex: 0 0 auto; animation: pv-tic 2s ease-out infinite; }
.pied-visite .pv-point::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  border: 1px solid var(--ambre-vif); opacity: 0;
  animation: pv-onde 2s ease-out infinite; }
.pied-visite:hover .pv-point { animation: none; opacity: 1; transform: none; }
.pied-visite:hover .pv-point::before { animation: none; opacity: 0; }

/* R1060 — LE TIC REVIENT TOUTES LES DEUX SECONDES. La frappe garde sa
   vivacité (le sommet en un dixième de seconde) : c'est l'ATTENTE qui
   s'allonge, pas le geste — un tic mou ne serait plus un tic. */
@keyframes pv-tic {
  0%        { transform: scale(1);    opacity: .55; }
  6%        { transform: scale(1.65); opacity: 1; }
  24%, 100% { transform: scale(1);    opacity: .55; }
}
@keyframes pv-onde {
  0%        { transform: scale(1);   opacity: .7; }
  31%, 100% { transform: scale(3.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .pied-visite .pv-point { animation: none !important; opacity: 1; transform: none; }
  .pied-visite .pv-point::before { animation: none !important; opacity: 0; }
}
}

/* R1059 — LE SCHÉMA DE L'API, aux couleurs de la maison : ambre pour le
   guichet (ce qui contrôle), vert du sceau pour Khazina (ce qui accueille),
   gris pour ce qui lui est extérieur. Aucune animation : un schéma se lit. */
.api-schema { border: 1px solid var(--line); border-radius: var(--r); background: var(--paper2);
  padding: 14px; margin: 16px 0 4px; }
.api-schema svg { display: block; width: 100%; height: auto; }
.api-schema .sc-neutre rect { fill: var(--panel); stroke: var(--line2); stroke-width: 1; }
.api-schema .sc-guichet rect { fill: rgba(184, 130, 42, .10); stroke: var(--ambre); stroke-width: 1; }
.api-schema .sc-ged rect { fill: var(--seal-ghost); stroke: var(--seal); stroke-width: 1; }
.api-schema .sc-note rect { fill: var(--panel); stroke: var(--line); stroke-width: 1;
  stroke-dasharray: 4 3; }
.api-schema .sc-t { font-family: var(--sans); font-size: 13px; font-weight: 600; fill: var(--ink); }
.api-schema .sc-s { font-family: var(--sans); font-size: 11.5px; fill: var(--muted); }
.api-schema .sc-guichet .sc-t { fill: var(--ambre); }
.api-schema .sc-ged .sc-t { fill: var(--seal); }
.api-schema .sc-fl { fill: none; stroke: var(--line2); stroke-width: 1.6; }
.api-schema marker path { fill: none; stroke: var(--line2); stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round; }

.api-lieux th:first-child, .api-lieux td.nom { width: 210px; white-space: normal;
  font-family: var(--sans); font-size: 12.5px; color: var(--ink); }
.api-lieux th:nth-child(2) { width: 240px; }
.api-lieux td code { word-break: break-all; }
.api-avert { border: 1px solid var(--line); border-inline-start: 3px solid var(--ambre); border-radius: 0 var(--r) var(--r) 0;
  background: var(--paper2); padding: 11px 14px; margin: 14px 0; font-size: 13px; line-height: 1.65;
  color: var(--muted); }
.api-avert b { color: var(--ink); }
@media (max-width: 700px) {
  .api-lieux th:first-child, .api-lieux td.nom { width: auto; }
  .api-lieux th:nth-child(2) { width: auto; }
}

/* R1062 — LES DEUX ONGLETS DE LA PAGE DE L'API : ce qu'il faut SAVOIR, et ce
   qu'il faut RÉGLER. Même moule que les onglets de langage, en plus affirmé
   puisqu'ils gouvernent la page entière. */
.api-vues, .kz-vues { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin: 14px 0 4px; }
.api-vues > button, .kz-vues > button { background: none; border: 0; border-bottom: 2px solid transparent; cursor: pointer;
  font-family: var(--sans); font-size: 14px; padding: 8px 14px; color: var(--muted); margin-bottom: -1px; }
.api-vues > button:hover, .kz-vues > button:hover { color: var(--ink); }
.api-vues > button.on, .kz-vues > button.on { color: var(--seal); border-bottom-color: var(--seal); font-weight: 600; }

/* R1062 — LE BLOC DE LA CLÉ FRAÎCHE EMPILE. « .msg-ok » est un message d'UNE
   ligne, donc un flex en rangée : mes quatre éléments s'y rangeaient côte à
   côte, en colonnes illisibles. Ce bloc-là empile. */
.api-cle-neuve { display: block !important; }
/* Dans les messages de la maison, le gras est un bloc (il porte un titre) :
   ici c'est une phrase, il doit rester dans le fil. */
.api-cle-neuve > b, .api-cle-neuve p b { display: inline; }
.api-cle-neuve .row { gap: 8px; }
.api-cle-neuve code { background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  font-family: var(--mono); font-size: 12.5px; }

/* R1070 — LA CARTE DE SANTÉ DES EXEMPLAIRES : verte quand tout va, ambre
   quand il manque quelque chose. Elle ne crie que s'il y a de quoi. */
.kz-sante-verdict:empty { display: none; }
.kz-sante-verdict { display: flex; align-items: center; gap: 7px; font-size: 14px; margin: 0 0 10px; }
.kz-sante-verdict.bon { color: var(--seal); }
.kz-sante-verdict.mauvais { color: var(--ambre-vif); }
#blobsEtat { margin-top: 12px; }

/* R1073 — LE BANDEAU DE LA SAUVEGARDE. Ambre, pas rouge : ce n'est pas une
   panne en cours, c'est une protection qui a cessé — grave, mais réparable.
   Il ne se ferme pas, car le problème ne se ferme pas non plus. */
.bandeau-veille { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: rgba(224, 122, 31, .08); border: 1px solid var(--ambre-vif);
  border-radius: var(--r); padding: 11px 14px; margin: 0 0 16px;
  font-size: 13.5px; line-height: 1.6; color: var(--ink); }
.bandeau-veille > span { flex: 1; min-width: 200px; }
.bandeau-veille .ic { color: var(--ambre-vif); flex: 0 0 auto; }
@media (max-width: 600px) { .bandeau-veille .btn { width: 100%; } }

/* ==========================================================================
   R1082 — LE CHOIX DE LA LANGUE, ET LE SENS DE LECTURE. L'interrupteur prend
   le moule du menu du compte, son voisin : mêmes mesures, même repli. Et la
   page entière se retourne pour l'arabe — c'est le navigateur qui le fait,
   par l'attribut « dir », ce qui vaut infiniment mieux qu'une feuille miroir
   écrite à la main et toujours en retard d'un écran.
   ========================================================================== */
.langmenu { position: relative; }
.langmenu > summary { display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  list-style: none; padding: 5px 8px; border-radius: 8px; color: var(--ink); font-size: 13px; }
.langmenu > summary::-webkit-details-marker { display: none; }
.langmenu > summary:hover { background: var(--paper2); }
.langmenu[open] > summary .ic { transform: rotate(180deg); }
.langmenu .lang-drapeau { display: inline-flex; line-height: 0; }
/* R1309 — LE DRAPEAU EST UN DESSIN, non un caractère. Il ne suit donc plus la
   taille de police : on lui donne la sienne, 20 sur 14, et le coin arrondi qui
   l'empêche de paraître collé au texte. Le trait de contour tient au cas où le
   drapeau porte du blanc sur un fond blanc — la France et l'Angleterre. */
.langmenu .dr { width: 20px; height: 14px; border-radius: 2px; display: block;
                box-shadow: 0 0 0 0.5px rgba(0,0,0,.14); }
.langmenu .lang-code { font-size: 11.5px; font-weight: 600; letter-spacing: .03em; color: var(--muted); }
.langmenu-liste { position: absolute; top: calc(100% + 6px); inset-inline-end: 0; z-index: 60;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--shadow-pop, 0 10px 30px rgba(33,48,46,.16)); padding: 5px; min-width: 168px; }
.langmenu-liste .menu-item { display: flex; align-items: center; gap: 9px; padding: 7px 10px;
  border-radius: 7px; font-size: 13.5px; }
.langmenu-liste .menu-item.on { background: var(--seal-ghost); color: var(--seal); font-weight: 600; }

/* Le sens de lecture : ce qui ne se retourne pas tout seul. */
[dir="rtl"] .langmenu-liste { inset-inline-end: 0; }
[dir="rtl"] .kzv-panneau, [dir="rtl"] .modal-card { text-align: right; }
[dir="rtl"] pre, [dir="rtl"] code, [dir="rtl"] .api-code-bloc,
[dir="rtl"] .scan-pas-carte .chemin, [dir="rtl"] .api-chemin {
  direction: ltr; text-align: start; unicode-bidi: embed; }
[dir="rtl"] .api-schema svg { direction: ltr; }
/* R1313 — LES FLÈCHES DE SENS SE RETOURNENT, PAS LES AUTRES. Une flèche
   « retour » dit une DIRECTION, pas une forme : en arabe le retour va vers la
   droite, et laisser le trait pointer à gauche fait mentir le dessin. On ne
   retourne donc que les icônes qui portent un sens de lecture — retour,
   suivant, précédent — et jamais les autres, qu'un miroir abîmerait. */
[dir="rtl"] svg.ico-retour,
[dir="rtl"] svg.ico-suivant,
[dir="rtl"] svg.ico-precedent { transform: scaleX(-1); }
@media (max-width: 720px) { .langmenu .lang-code { display: none; } }

/* ==========================================================================
   R1096 — LE SOUFFLE DES MODALS DU SCANNER. Ils étaient JUSTES : le libellé
   collé à son champ (deux pixels), les champs sans aucune marge — l'écart ne
   venant que de la hauteur de ligne des étiquettes —, les deux cases à cocher
   accolées, et les boutons touchant le dernier champ. Rien n'était cassé ;
   tout était SERRÉ, ce qui fatigue l'œil sur un geste répété trente fois par
   jour.

   PREMIÈRE ÉCRITURE : VISÉE À CÔTÉ. Les champs ne sont pas les enfants directs
   du corps — celui-ci est une GRILLE à deux colonnes, aperçu à gauche,
   formulaire à droite dans « .scan-classe-form ». Un sélecteur « > » ne
   rencontrait donc rien. On vise le formulaire lui-même.

   LE RYTHME VAUT POUR TOUT LE PARCOURS : classer une pièce, classer un lot,
   écarter un fichier, écarter un lot. Un même geste doit respirer de la même
   façon, quel que soit l'écran qui le demande.
   ========================================================================== */
/* R1342 — CE BLOC NE VISE PLUS QUE LES DEUX FENÊTRES D'ÉCART.
   Le rythme de R1096 avait été écrit à la main pour quatre fenêtres, parce
   qu'aucune d'elles n'employait les classes de la maison : « .scan-classe-form »,
   des étiquettes « label.muted.small », une rangée de boutons tenant lieu de
   pied. Les deux fenêtres de CLASSEMENT emploient désormais « lec-label »,
   « lec-case » et un vrai « modal-foot » : elles tiennent leur rythme de la
   maison, et ces règles-ci les combattraient — la première aplatirait les
   cases à cocher, qui se rangent en ligne.
   Restent « Ne plus proposer ce fichier » et son pendant groupé, qui gardent
   leur écriture propre ; le jour où elles passeront aux classes de la maison,
   ce bloc disparaîtra tout entier. */
#mIgnorer .modal-body, #mIgnorerLot .modal-body { line-height: 1.65; padding: 20px 22px; }
#mIgnorer .modal-body label, #mIgnorerLot .modal-body label { display: block; margin: 0 0 7px; }
#mIgnorer .modal-body input:not([type="checkbox"]), #mIgnorer .modal-body textarea,
#mIgnorerLot .modal-body input:not([type="checkbox"]), #mIgnorerLot .modal-body textarea {
  margin: 0 0 18px; max-width: 100%; box-sizing: border-box; }
#mIgnorer .modal-body p, #mIgnorerLot .modal-body p { margin: 0 0 15px; line-height: 1.7; }
#mIgnorer .kz-lab, #mIgnorerLot .kz-lab { display: block; margin: 0 0 7px; }
#mIgnorer .modal-body input[type="text"], #mIgnorerLot .modal-body input[type="text"] { margin-bottom: 16px; }
/* La décision n'est pas la suite du formulaire : un filet l'en sépare. */
#mIgnorer .modal-body > .row:last-child, #mIgnorerLot .modal-body > .row:last-child,
#mIgnorer .modal-body .row:last-of-type, #mIgnorerLot .modal-body .row:last-of-type {
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); gap: 10px; }

/* ==========================================================================
   R1097 — UN TITRE, UNE LIGNE ; UN PIED, DEUX BORDS.
   ========================================================================== */

/* LE TITRE D'UNE PIÈCE TIENT SUR UNE LIGNE. Il était coupé à DEUX, ce qui
   donnait des cartes à hauteur variable et une grille qui ondule — « Attestation
   de régularité fiscale » s'étalait sur deux lignes là où « Facture 42 » n'en
   prenait qu'une. Une seule ligne, suivie de points de suspension : la grille
   redevient régulière, et le titre entier reste lisible au survol comme dans
   la fiche. */
/* On vise AUSSI PRÉCISÉMENT que la règle qu'on remplace : « .view-cards .dbody
   .doc-title » impose deux lignes depuis longtemps, et une règle à un seul
   nom de classe ne la bat pas. Écrire moins précis, c'est écrire pour rien. */
/* Et l'on abaisse le MIN-HEIGHT qui réservait la place de deux lignes : il
   gardait la grille régulière quand les titres se coupaient en deux, mais sur
   une seule ligne il ne fait plus que du vide. La régularité vient désormais
   de ce que TOUS les titres tiennent sur une ligne. */
.doc-title,
.view-cards .dbody .doc-title,
.docs .dbody .doc-title {
  min-height: 0;
  display: block;
  -webkit-line-clamp: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.35;
}

/* LE PIED SE TIENT AUX DEUX BORDS. Tout était groupé à droite : la signature
   collée aux deux boutons, sans respiration au milieu. La mention de droits
   prend le bord de début, les gestes prennent le bord de fin — et tout reste
   sur UNE SEULE LIGNE, quelle que soit la largeur. En arabe, « début » et
   « fin » s'inversent d'eux-mêmes : c'est pourquoi on ne dit ni gauche ni
   droite. */
.pied-barre { justify-content: space-between; flex-wrap: nowrap; }
.pied-barre .pied-droits { margin-inline-end: auto; white-space: nowrap; }
.pied-barre .pied-visite, .pied-barre .pied-aide { white-space: nowrap; flex: 0 0 auto; }

@media (max-width: 560px) {
  /* Sur un écran étroit, la signature s'efface plutôt que de pousser les
     gestes à la ligne : ce sont eux qui servent. */
  .pied-barre .pied-droits { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
}


/* ===================================================================
   MISE EN ROUTE — le compte rendu du premier accès (R1363)
   Un inventaire, non un tableau : chaque ligne porte une pastille, ce
   qu'elle fait, où elle est, et son état. Les chemins restent de gauche
   à droite même en arabe — ce sont des chemins, pas du texte.
   =================================================================== */
.mev{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;margin:0 0 var(--e4)}
.mev-tete{background:var(--paper2);padding:10px 16px;font-size:12.5px;color:var(--muted);
  border-bottom:1px solid var(--line);display:flex;justify-content:space-between;
  align-items:center;letter-spacing:.02em}
.mev-l{display:flex;align-items:center;gap:12px;padding:11px 16px;
  border-bottom:1px solid var(--line);font-size:14px}
.mev-l:last-of-type{border-bottom:0}
.mev-nom{flex:1;min-width:0}
.mev-nom b{font-weight:500;display:block}
.mev-tech{color:var(--faint);font-weight:400}
.mev-nom small{color:var(--faint);font-size:12px;display:block;margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:ui-monospace,Menlo,Consolas,monospace;direction:ltr}
[dir="rtl"] .mev-nom small{text-align:right}
.pastille{width:9px;height:9px;border-radius:50%;flex:none}
.p-pret{background:var(--seal)}
.p-manquant{background:var(--line2)}
.p-avoir{background:var(--gold)}
.etat{font-size:11.5px;letter-spacing:.04em;font-weight:500;flex:none;
  padding:3px 9px;border-radius:20px}
.e-pret{background:var(--seal-ghost);color:var(--seal-dark)}
.e-manquant{background:var(--paper2);color:var(--muted);border:1px solid var(--line)}
.e-avoir{background:var(--warn-bg);color:var(--warn)}
.mev-pied{padding:12px 16px;background:var(--paper2);font-size:13px;color:var(--muted);
  border-top:1px solid var(--line)}
.mev-pied b{color:var(--ink);font-weight:500}
.fin{display:flex;gap:10px;align-items:center;margin-top:var(--e4)}
.fin .grandit{flex:1}


/* ===================================================================
   DÉCOUPER EN FAISANT GLISSER — R1364
   Les pages deviennent des vignettes qu'on prend et qu'on pose ; la
   pièce entière se prend par son en-tête. Les styles d'avant restent :
   sans Poppler, on retombe sur la liste à aperçu de texte.
   =================================================================== */
/* R1399 — 150 AU LIEU DE 112, DEMANDÉ À L'USAGE. R1370 était déjà passé de 74
   à 112 pour la même raison, et la raison tient encore : on reconnaît la
   silhouette d'une page, on ne lit pas ce qu'elle dit — or c'est en lisant
   qu'on décide où couper. La proportion est conservée au pixel près
   (146/112 = 196/150), sinon « object-fit: cover » rognerait autrement qu'avant.
   UNE SEULE SOURCE pour la taille : la hauteur de la fente de dépôt et la
   position du bouton « couper ici » s'en déduisent, au lieu d'être trois
   nombres à retrouver le jour où l'on rechange la taille. */
.seg-pages.avec-image { --seg-vig-l: 150px; --seg-vig-h: 196px;
  flex-direction: row; flex-wrap: wrap; gap: 9px; align-items: flex-start;
  min-height: 140px; padding: 4px 0 2px; }
.seg-pages.avec-image.cible { background: var(--seal-ghost); border-radius: 8px; }
/* R1374 — LE CURSEUR DIT QU'IL Y A UNE LOUPE. L'aperçu porte les deux gestes :
   on peut le GLISSER d'une pièce à l'autre, et s'y arrêter l'AGRANDIT (R1370).
   Le curseur n'en annonçait qu'un — une main ouverte — et la loupe restait à
   découvrir par hasard. Or c'est elle qu'on emploie le plus : on regarde dix
   pages pour une qu'on déplace. Le repos annonce donc la loupe, et la main se
   referme dès qu'on appuie (« grabbing » ci-dessous) : le glisser garde son
   signe au moment précis où il commence. */
.seg-pages.avec-image > .seg-page { display: block; width: var(--seg-vig-l); flex: none; position: relative;
  cursor: zoom-in; touch-action: none; padding: 0;
  /* R1364 — le navigateur ne doit pas lancer SON glisser par-dessus le nôtre :
     il enverrait « pointercancel » et notre prise mourrait dans l'œuf. */
  user-select: none; -webkit-user-select: none; -webkit-user-drag: none; }
.seg-pages.avec-image .seg-vig { -webkit-user-drag: none; user-select: none; pointer-events: none; }
.seg-tete { user-select: none; -webkit-user-select: none; }
.seg-tete input { user-select: text; -webkit-user-select: text; }
.seg-pages.avec-image > .seg-page:active { cursor: grabbing; }
/* R1370 — 112 AU LIEU DE 74. À l'ancienne taille on reconnaissait une
   silhouette de page, jamais ce qu'elle disait ; il fallait créer les pièces
   à l'aveugle ou rouvrir le document à côté. La loupe fait le reste. */
.seg-pages.avec-image .seg-vig,
.seg-pages.avec-image .seg-feuille { display: block; width: var(--seg-vig-l); height: var(--seg-vig-h); object-fit: cover;
  background: #fff; border: 1px solid var(--line2); border-radius: 4px;
  box-shadow: 0 1px 2px rgba(33,48,46,.07); transition: border-color .12s, box-shadow .12s; }
.seg-pages.avec-image > .seg-page:hover .seg-vig,
.seg-pages.avec-image > .seg-page:hover .seg-feuille { border-color: var(--seal);
  box-shadow: 0 2px 8px rgba(14,107,92,.16); }
.seg-pages.avec-image > .seg-page.est-debut .seg-vig,
.seg-pages.avec-image > .seg-page.est-debut .seg-feuille { border-color: var(--seal); border-width: 2px; }
.seg-pages.avec-image .seg-pnum { position: absolute; top: -5px; left: -5px; z-index: 1;
  min-width: 19px; height: 19px; padding: 0; border-radius: 19px; font-size: 10.5px; }
.seg-pages.avec-image .seg-ptxt { display: block; font-size: 10.5px; color: var(--faint);
  margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.seg-pages.avec-image > .seg-page.porte { opacity: .35; }
.seg-coupe-ici { position: absolute; top: calc(var(--seg-vig-h, 196px) * .4); left: -9px; z-index: 2; font-size: 11px;
  color: var(--faint); text-decoration: none; opacity: 0; transition: opacity .12s;
  background: var(--panel); border: 1px solid var(--line); border-radius: 5px; padding: 1px 3px; }
.seg-pages.avec-image > .seg-page:hover .seg-coupe-ici,
.seg-coupe-ici:focus { opacity: 1; }
.seg-fente { width: 3px; align-self: stretch; min-height: var(--seg-vig-h, 196px); background: var(--seal);
  border-radius: 3px; margin: 0 -4px; flex: none; list-style: none; }

.seg-piece { align-items: stretch; }
.seg-piece .seg-corps { flex: 1 1 auto; min-width: 0; }
.seg-tete { display: flex; align-items: center; gap: 8px; }
.seg-prise { flex: none; width: 24px; height: 32px; display: flex; align-items: center;
  justify-content: center; cursor: grab; touch-action: none; color: var(--line2);
  border-radius: 6px; font-size: 15px; line-height: 1; user-select: none; }
.seg-prise:hover { color: var(--muted); background: var(--paper2); }
.seg-prise:active { cursor: grabbing; }
.seg-prise:focus-visible { outline: 2px solid var(--seal); outline-offset: 1px; }
.seg-tete .grandit { flex: 1 1 auto; min-width: 0; }
.seg-piece.porte { opacity: .4; }
.seg-piece.cible { outline: 2px solid var(--seal); outline-offset: 2px; }

/* R1364 — LA BANDE GARDE SA HAUTEUR, TOUJOURS. Première version : elle
   passait de 0 à 32 px au début du glissement, et les cinq bandes d'un lot
   poussaient la page de cent soixante pixels SOUS LA MAIN. On visait une
   pièce, elle s'échappait — mesuré sur la vraie page, le curseur tombait sur
   le repli d'une autre pièce. Elle occupe donc dix pixels en permanence (le
   gap entre pièces, qui existait déjà) et s'ANNONCE sans grandir : le décor
   du glissement est dessiné en absolu, il déborde sans rien déplacer. */
.seg-lot { gap: 0; }
.seg-entre { list-style: none; height: 10px; position: relative; }
.seg-entre > span { display: none; }
body.seg-glisse .seg-entre::after { content: ''; position: absolute; inset: -9px 0;
  border: 1.5px dashed var(--line2); border-radius: 9px; background: var(--paper2); }
body.seg-glisse .seg-entre.cible::after { border-color: var(--seal);
  background: var(--seal-ghost); inset: -13px 0; }
body.seg-glisse .seg-entre > span { display: block; position: absolute; inset: -9px 0;
  z-index: 1; font-size: 12px; color: var(--faint); text-align: center; line-height: 28px;
  pointer-events: none; }
body.seg-glisse .seg-entre.cible > span { color: var(--seal-dark); }

/* R1365 — LES INFORMATIONS D'UNE PIÈCE, AFFICHÉES ET SUR UNE LIGNE.
   Elles étaient dans un volet fermé, donc ignorées. Dépliées les unes sous
   les autres, elles auraient triplé la hauteur de l'écran — or on y fait
   glisser des pièces d'un bout à l'autre, et chaque pixel de hauteur est un
   défilement de plus pendant le geste. Trois colonnes, donc, qui se replient
   en colonne quand la place manque. */
.seg-champs-3 { display: grid; gap: var(--e2); margin: var(--e2) 0 var(--e3);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.seg-champs-3 .lec-label { margin: 0; font-size: 12px; }
.seg-champs-3 input, .seg-champs-3 select, .seg-champs-3 textarea { width: 100%; }
/* R1423 — LA NOTE TIENT MAINTENANT SUR PLUSIEURS LIGNES : ce que la personne a
   écrit, puis le résumé de la récupération sous son trait. Elle s'étire à la
   main si l'on en veut plus — mais JAMAIS horizontalement : cet écran se fait
   glisser d'un bout à l'autre, et une barre de défilement latérale en travers
   d'une pièce rendrait la prise hasardeuse (R1364).

   R1447 — SIX LIGNES, et non plus trois. Le client les a demandées, et la
   mesure lui donne raison : depuis R1431 la note porte l'état civil de la
   pièce — nature, numéro, client, fournisseur, total, nombre de pages — PUIS
   le paragraphe de résumé. Sur sa capture, la pièce « Bon de commande
   N° 26121002213 » remplit déjà quatre lignes à elle seule, et le résumé est
   coupé net au milieu d'un mot. Trois lignes dataient d'avant ce contenu-là.

   ⚠ ET LA HAUTEUR SE DIT EN « em », NON EN PIXELS. Elle doit suivre la taille
   du texte : posée en dur, elle rendrait cinq lignes à qui grossit la police
   et sept à qui la réduit. Six interlignes de 1.45, plus les marges hautes et
   basses, plus les deux bordures. Le « rows » de la balise dit la même chose
   pour qui n'a pas la feuille de style — les deux doivent s'accorder, sans
   quoi la plus grande gagne et l'autre ment. */
.seg-champs-3 textarea { min-height: calc(6 * 1.45em + 16px); resize: vertical; font: inherit;
  line-height: 1.45; padding: 7px 9px; border-radius: 8px;
  border: 1px solid var(--line2); background: var(--panel); color: var(--ink); }
.seg-champs-3 textarea:focus-visible { outline: 2px solid var(--seal); outline-offset: 1px; }
.chip.main { background: var(--seal-ghost); color: var(--seal-dark); border-color: var(--seal); }

/* LE BANDEAU « POUR TOUTES LES PIÈCES ». Il se tient AU-DESSUS de la liste,
   parce qu'il la commande : on règle une fois, puis on corrige les rares
   pièces qui sortent du lot commun. */
.seg-global { border: 1px solid var(--line); border-radius: 10px; background: var(--paper2);
  padding: var(--e3); margin: 0 0 var(--e3); }
.seg-global-tete { display: flex; align-items: baseline; gap: var(--e2); flex-wrap: wrap;
  margin-bottom: var(--e2); }
.seg-global .seg-champs { display: grid; gap: var(--e2);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.seg-global .lec-label { margin: 0; font-size: 12px; }
.seg-global input, .seg-global select { width: 100%; }
.seg-global-pied { display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap;
  margin-top: var(--e2); font-size: 12px; }
.seg-regle.discret { color: var(--muted); }
[data-seg-reinit-bilan] { font-size: 12px; }

/* R1370 — LA LOUPE. Elle suit le curseur et montre, agrandie, la PARTIE
   pointée de la page : c'est ce qui permet de lire une référence ou un
   en-tête sans ouvrir le document à côté. Elle ne capte jamais le pointeur —
   sans quoi elle se mettrait entre la main et la page qu'on veut faire
   glisser. */
.seg-loupe { position: fixed; z-index: 120; pointer-events: none;
  width: 360px; height: 440px; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--seal); background: #fff no-repeat;
  box-shadow: 0 14px 34px rgba(33,48,46,.28); }
.seg-loupe::after { content: ''; position: absolute; inset: 0;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.6); border-radius: 10px; }
.seg-loupe.attend { background-image: none; }
.seg-loupe .seg-loupe-mot { position: absolute; inset: auto 0 0 0; padding: 4px 8px;
  font-size: 11px; color: var(--muted); background: var(--panel);
  border-top: 1px solid var(--line); text-align: center; }
/* Sur un écran tactile il n'y a pas de survol : la loupe n'y paraît jamais,
   et la page n'en est pas moins utilisable — on y agrandit avec deux doigts. */
@media (pointer: coarse) { .seg-loupe { display: none; } }

.seg-fantome { position: fixed; z-index: 99; pointer-events: none;
  transform: translate(-50%, -50%) rotate(-2deg); background: var(--panel);
  border: 1px solid var(--seal); border-radius: 8px; padding: 6px 12px; font-size: 13px;
  color: var(--seal-dark); box-shadow: 0 10px 24px rgba(33,48,46,.24); white-space: nowrap; }

.seg-plus > summary { font-size: 12.5px; color: var(--muted); cursor: pointer;
  list-style: none; display: inline-flex; align-items: center; gap: 5px; padding: 3px 0; }
.seg-plus > summary::-webkit-details-marker { display: none; }
.seg-plus > summary::before { content: '\25B8'; color: var(--faint); font-size: 11px; }
.seg-plus[open] > summary::before { content: '\25BE'; }
.seg-champs { display: grid; grid-template-columns: 1fr 250px; gap: 10px; padding: 4px 0 2px; }
@media (max-width: 760px) { .seg-champs { grid-template-columns: 1fr; } }

/* ===================================================================
   R1376 — LE MOTEUR IA DANS LES RÉGLAGES.
   Un bloc par fournisseur, encadré, pour qu'on voie d'un coup d'œil où
   finit l'un et où commence l'autre : trois clés qui se ressemblent, sur
   une page déjà longue, se confondent sans cette ligne.
   =================================================================== */
.ia-fourn { border: 1px solid var(--line); border-radius: 6px; padding: 12px 13px; margin: 0 0 11px; }
.ia-fourn-tete { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-bottom: 9px; }
.ia-fourn-tete b { font-size: 14px; }
.ia-fourn-pied { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 4px; }

/* R1391 — LA CONSOMMATION DE CE FOURNISSEUR, dans son bloc.
   Deux chiffres de nature différente s'y suivent, et la mise en page doit le
   montrer : ce que Khazina a dépensé est EXACT et se lit dans un tableau ;
   le solde restant est ESTIMÉ et se lit dans un bandeau, avec la phrase qui
   dit d'où il vient. Les mêler dans un seul tableau les ferait passer pour
   deux chiffres de même autorité. */
.ia-conso { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.ia-conso h5 { margin: 0 0 4px; font-size: 12.5px; font-weight: 600; }
.ia-conso h5 + * { margin-top: 0; }
.ia-conso h5 ~ h5 { margin-top: 14px; }
.ia-conso-t { width: 100%; border-collapse: collapse; font-size: 12.5px; margin: 4px 0 6px; }
.ia-conso-t th { text-align: start; font-weight: 500; color: var(--muted);
  padding: 3px 7px 3px 0; white-space: nowrap; }
.ia-conso-t thead th { font-size: 11.5px; font-weight: 600;
  border-bottom: 1px solid var(--line); padding: 3px 7px; }
.ia-conso-t td { padding: 3px 7px; }
/* Les montants s'alignent par la droite, chiffres de même largeur : comparer
   deux sommes ne doit pas demander de les relire. */
.ia-conso-t .n { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ia-conso-t td.muted, .ia-conso-t .muted { color: var(--muted); font-size: 11.5px; }
.ia-conso-d { margin: 2px 0 6px; }
.ia-conso-d summary { cursor: pointer; font-size: 12px; color: var(--muted); }
.ia-conso-d[open] summary { margin-bottom: 4px; }
/* Le verdict prend la couleur de ce qu'il annonce, et rien d'autre ne bouge :
   une ligne qui change de taille ferait sauter la page sous le curseur. */
.ia-verdict { font-size: 12.5px; color: var(--muted); min-height: 1.2em; }
.ia-verdict.ok { color: var(--seal-dark); }
.ia-verdict.mal { color: var(--err); }
.ia-guide { margin: 0 0 10px; padding-inline-start: 20px; font-size: 13.5px; line-height: 1.7; }
.ia-guide li { margin-bottom: 5px; }
/* La case du témoin est large : c'est le réglage le plus important du bloc,
   et une case minuscule au milieu d'un formulaire ne se voit pas. */
.case-large { display: flex; flex-direction: row; align-items: center; gap: 9px;
  margin: 14px 0 2px; font-weight: 600; font-size: 13px; color: var(--ink); }
/* « .lec-label » pose une COLONNE : sans cette ligne, la case se retrouvait
   au-dessus de son texte, seule au milieu du formulaire. */
.case-large input { width: 16px; height: 16px; flex: none; }
/* Le choix du moteur dans une modale : deux cartes, celle qu'on tient est
   bleue — le bleu de ce qui est CHOISI, comme partout depuis R573. */
/* C57 — LES QUATRE CARTES ONT LA MÊME HAUTEUR, quelle que soit leur phrase.
   ⚠ En « flex-wrap », les cartes s'étirent dans LEUR rangée seulement :
   mesuré, la rangée du haut faisait 89 px et celle du bas 66, parce que la
   description de « Classique » tenait sur deux lignes. Le client l'a vu.
   ⚠ On règle la STRUCTURE, non le texte : « grid-auto-rows: 1fr » rend
   toutes les rangées égales, et cela tiendra le jour où une phrase changera —
   *une correction qui dépend de la longueur d'un texte se défait au premier
   mot ajouté.* « auto-fit » garde le repli à une colonne sur un téléphone. */
.ia-choix { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  grid-auto-rows: 1fr; gap: 10px; margin: 0 0 12px; }
.ia-choix label { min-width: 0; border: 1px solid var(--line2); border-radius: 6px;
  padding: 10px 12px; background: var(--paper2); cursor: pointer; display: block; }
.ia-choix label:has(input:checked) { border-color: var(--sel-line); background: var(--sel-bg);
  box-shadow: inset 0 0 0 1px var(--sel-line); }
.ia-choix .t { font-weight: 600; font-size: 13.5px; display: flex; align-items: center; gap: 7px; }
.ia-choix .d { font-size: 12px; color: var(--muted); margin-top: 3px; }
.ia-choix input { margin: 0; }
/* R1376 — le rang « qui propose les coupes » : le moteur en cours se marque
   comme un onglet choisi, du même bleu que tout ce qui est retenu (R573). */
.seg-moteurs { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.seg-moteurs .btn.on { background: var(--sel-bg); border-color: var(--sel-line); color: var(--sel-dark); font-weight: 600; }
/* R1377 — UN FOURNISSEUR SANS CLÉ SE VOIT, éteint. Le masquer le rendait
   introuvable : le client, qui n'avait encore posé aucune clé, ne voyait rien
   et a cru la fonction absente. Une porte fermée qu'on voit apprend quelque
   chose ; une porte invisible, rien. */
.ia-choix label.sans-cle { opacity: .55; cursor: not-allowed; }
.ia-choix label.sans-cle .d { font-style: italic; }
.ia-choix .chip { margin-inline-start: 6px; font-size: 10.5px; }
.seg-moteurs .eteint { opacity: .55; cursor: not-allowed; }
/* L'intitulé au-dessus du rang de moteurs : sans lui, trois cartes de choix
   arrivaient sans qu'on sache de quoi elles parlent. */
.lib-choix { display: block; font-size: 12px; font-weight: 600; margin: 12px 0 5px; }
/* R1380 — LE CHOIX DU MOTEUR, commun aux deux fenêtres de lecture : le
   modèle par action cochée, le résumé « qui fait quoi », l'alerte quand le
   fournisseur refuse, et les étapes du modèle au travail. */
.ia-bloc.inactif .ia-choix { opacity: .5; }
.ia-modeles { margin: 0 0 8px; }
.ia-modeles select { width: 100%; }
.ia-resume { list-style: none; margin: 4px 0 10px; padding: 8px 12px; border-radius: 6px;
  background: var(--paper2); border: 1px dashed var(--line2); font-size: 12.5px; line-height: 1.6; }
.ia-resume:empty { display: none; }
.ia-resume b { font-weight: 600; }
.ia-alerte { margin: 0 0 12px; padding: 10px 12px; border-radius: 6px; background: var(--err-bg);
  color: var(--err); border: 1px solid currentColor; font-size: 13px; line-height: 1.55;
  display: flex; flex-direction: column; gap: 4px; }
.ia-alerte > span:not(.ia-alerte-actions) { color: var(--ink); }
.ia-alerte-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.ia-etapes { list-style: none; margin: 10px 0 0; padding: 0; font-size: 12.5px; line-height: 1.5; text-align: start; }
.ia-etapes li { position: relative; padding-inline-start: 20px; margin: 3px 0; color: var(--muted); }
.ia-etapes li::before { position: absolute; inset-inline-start: 0; top: 0; width: 16px; text-align: center; font-weight: 700; }
.ia-etapes li.fait { color: var(--ink); }
.ia-etapes li.fait::before { content: "✓"; color: var(--seal2); }
.ia-etapes li.encours { color: var(--ink); font-weight: 600; }
.ia-etapes li.encours::before { content: "●"; color: var(--sel); animation: blip 1.2s ease-in-out infinite; }
.ia-etapes li.avenir::before { content: "○"; }
.ia-etapes li.alerte { color: var(--warn); background: var(--warn-bg); border-radius: 4px; padding: 3px 6px; padding-inline-start: 24px; }
.ia-etapes li.alerte::before { content: "!"; color: var(--warn); top: 3px; inset-inline-start: 5px; }
@media (prefers-reduced-motion: reduce) { .ia-etapes li.encours::before { animation: none; } }
/* R1381 — l'offre de passer la main quand le moteur local s'éternise. Le ton
   de l'ATTENTION, non celui de l'erreur : rien n'est cassé, on propose. */
.ia-offre { margin: 12px 0 0; padding: 10px 12px; border-radius: 6px; background: var(--warn-bg);
  color: var(--warn); border: 1px solid currentColor; font-size: 12.5px; line-height: 1.55;
  display: flex; flex-direction: column; gap: 4px; text-align: start; }
.ia-offre > span:not(.ia-alerte-actions):not(.ia-offre-err) { color: var(--ink); }
.ia-offre.prise { background: var(--sel-bg); color: var(--sel-dark); border-color: var(--sel-line);
  font-weight: 600; display: block; }
.ia-offre-err { color: var(--err); }

/* ===================================================================
   R1384 — LE TABLEAU DE REPÈRES DES MODÈLES, sous la liste déroulante.
   Huit noms de modèles ne disent rien de ce qu'ils valent : ce tableau
   est ce qui permet de choisir. Il tient donc DANS la carte de réglage,
   sans renvoyer ailleurs.
   =================================================================== */
.ia-reperes { margin: 14px 0 4px; }
.ia-reperes h4 { font-size: 13.5px; margin: 0 0 5px; }
.ia-reperes-t { width: 100%; border-collapse: collapse; margin: 9px 0 8px; font-size: 12.5px; }
.ia-reperes-t th { text-align: start; font-weight: 600; color: var(--muted);
  font-size: 11.5px; padding: 4px 7px; border-bottom: 1px solid var(--line); }
.ia-reperes-t td { padding: 5px 7px; border-bottom: 1px solid var(--line); vertical-align: middle; }
/* Le prix s'aligne par la droite et garde des chiffres de même largeur :
   sans cela, comparer deux montants demande de les relire. */
.ia-reperes-t .n { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ia-reperes-t tr.rp-conseille td { background: var(--seal-pale, rgba(0,0,0,.03)); }
/* Trois barreaux : lisibles d'un coup d'œil, et qui ne demandent aucune
   couleur pour être compris — un écran en noir et blanc les rend aussi. */
.rp { display: inline-flex; gap: 2px; }
.rp-b { width: 11px; height: 9px; border: 1px solid var(--line); border-radius: 2px; }
.rp-b.on { background: var(--seal-dark, #2f6b4f); border-color: var(--seal-dark, #2f6b4f); }
.rp-rien { color: var(--muted); }

/* R1391 — LE RÔLE SOUS LE NOM, ET LA VITESSE À CÔTÉ.
   Le rôle est de la prose : il prend sa ligne, en petit, sous le nom du
   modèle — une sixième colonne de texte rendrait ce tableau illisible sur un
   téléphone, et c'est précisément là qu'on choisit son modèle.
   La vitesse, elle, tient en un mot et se pose près du nom. Elle NE DÉPEND
   PAS DE LA COULEUR pour être comprise : le mot est écrit, comme les trois
   barreaux au-dessus. C'est la règle de R1384, et un écran en noir et blanc
   la rend aussi bien. */
.rp-role { display: block; margin-top: 2px; font-size: 11.5px; line-height: 1.45;
  color: var(--muted); max-width: 46ch; }
.chip.rp-rapide { background: var(--seal-pale, rgba(0,0,0,.04)); }
.chip.rp-lent { border-style: dashed; }
.chip.rp-equilibre { opacity: .85; }

/* R1387 — LE CONSEIL D'EMPLOI, sous le modèle qu'on vient de choisir. Il doit
   se lire sans crier : c'est un repère, non un avertissement. */
.ia-conseil { margin: 6px 0 0; font-size: 12.5px; line-height: 1.55;
  color: var(--muted); border-inline-start: 2px solid var(--line);
  padding-inline-start: 9px; min-height: 1.2em; }
.ia-conseil:empty { display: none; }

/* R1389 — L'APERÇU D'UNE MINUTE. Il doit se lire comme un relevé, non comme un
   avertissement : les chiffres d'abord, le conseil ensuite, et rien qui crie. */
.ia-apercu { margin: 10px 0 0; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--fond-doux, rgba(0, 0, 0, .02)); }
.ia-apercu > small { display: block; margin-top: 6px; line-height: 1.5; font-size: 12px; }
.ia-apercu-vu { margin-top: 9px; padding-top: 9px; border-top: 1px dashed var(--line); }
.ia-apercu-vu p { margin: 0 0 5px; font-size: 12.5px; line-height: 1.55; }
.ia-apercu-vu p:last-child { margin-bottom: 0; }
.ia-apercu-mesure { color: var(--muted); font-variant-numeric: tabular-nums; }
.ia-apercu-verdict { font-weight: 600; }
.ia-apercu-conseil { color: var(--seal-dark, #2f6b4f); }

/* ===== Découpage : la méthode expliquée (R1401) ===== */
.seg-logique { margin-top: 10px; }
.seg-logique summary .sub { margin-left: auto; }
.seg-logique-l { margin: 0; padding-left: 22px; }
.seg-logique-l li { margin: 0 0 9px; line-height: 1.55; color: var(--muted); }
.seg-logique-l li:last-child { margin-bottom: 0; }

/* R1408 — « on vous emmène » : une attente annoncée, pas une fenêtre figée. */
.lec-verdict.en-route { background: var(--seal-ghost); border-color: var(--seal);
  color: var(--seal-dark, #2f6b4f); }

/* R1411 — pages qui se ressemblent sans être ensemble. */
.seg-disperses { border-color: var(--warn, #b5851f); margin-bottom: 10px; }
.seg-disperses-l { margin: 8px 0 0; padding-left: 20px; }
.seg-disperses-l li { margin: 0 0 6px; line-height: 1.5; color: var(--muted); }
.seg-disperses-l li:last-child { margin-bottom: 0; }

/* ===== R1413 — les deux temps de la lecture d'une sélection ===== */
.kz-pas { display: flex; gap: 0; list-style: none; margin: 0; padding: 0 16px;
  border-bottom: 1px solid var(--line); background: var(--bg); }
.kz-pas-un { display: flex; align-items: center; gap: 8px; padding: 11px 16px 10px;
  font-size: 13.5px; color: var(--faint); border-bottom: 2px solid transparent; }
.kz-pas-n { display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 20px; font-size: 11.5px;
  background: var(--line2); color: var(--muted); font-variant-numeric: tabular-nums; }
.kz-pas-un.on { color: var(--ink); border-bottom-color: var(--seal); }
.kz-pas-un.on .kz-pas-n { background: var(--seal); color: #fff; }
.kz-pas-un.fait { color: var(--muted); }
/* Le pas franchi garde une pastille VISIBLE : sur le bandeau clair,
   --seal-ghost disparaissait et le chiffre flottait tout nu. */
.kz-pas-un.fait .kz-pas-n { background: var(--line2); color: var(--seal-dark, #2f6b4f);
  box-shadow: inset 0 0 0 1px var(--seal); }
.vl-avant { padding-top: 16px; }
@media (max-width: 480px) { .kz-pas { padding: 0 8px; } .kz-pas-un { padding: 10px 10px 9px; font-size: 12.5px; } }

/* R1415 — le moteur au travail, dans le suivi d'une lecture groupée. */
.vl-moteur { align-self: flex-start; margin-top: 4px; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   R1420 — LE TEXTE RÉCUPÉRÉ, SOUS CHAQUE PIÈCE
   ==========================================================================
   Un volet replié dont L'EN-TÊTE PORTE DÉJÀ LA RÉPONSE : le taux, le poids, le
   numéro de la page douteuse. On n'ouvre que pour lire. Replié par défaut non
   par timidité mais par mesure — R1364/R1365 : sur cet écran on fait glisser
   des pièces, et chaque pixel de hauteur est un défilement de plus pendant le
   geste.
   ========================================================================== */
.seg-txt { margin-top: 6px; border-top: 1px dashed var(--line); }

/* ── L'EN-TÊTE REPLIÉ ──
   « list-style: none » ET le pseudo-élément de WebKit : sans les deux, le
   triangle natif reste, et il double le chevron qu'on dessine. */
.seg-txt-tete { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 2px 5px; cursor: pointer; list-style: none; user-select: none;
  border-radius: 7px; transition: background-color .12s; }
.seg-txt-tete::-webkit-details-marker { display: none; }
.seg-txt-tete:hover { background: var(--paper2); }
.seg-txt-tete:focus-visible { outline: 2px solid var(--seal); outline-offset: 1px; }
.seg-txt-chev { flex: none; width: 13px; height: 13px; position: relative; color: var(--muted); }
/* Un chevron en deux traits, sans police d'icônes ni fichier à charger. */
.seg-txt-chev::before { content: ''; position: absolute; top: 2px; left: 3px;
  width: 6px; height: 6px; border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor; transform: rotate(-45deg);
  transition: transform .14s ease; transform-origin: 60% 60%; }
.seg-txt[open] .seg-txt-chev::before { transform: rotate(45deg); }
.seg-txt-titre { font-size: 12px; font-weight: 600; color: var(--ink); }
.seg-txt-poids, .seg-txt-pcar { font-size: 11px; font-variant-numeric: tabular-nums; }

/* ── LA JAUGE ──
   Le nombre seul se compare mal sur vingt pièces ; la barre se lit sans se
   lire. Le seuil de 80 % est celui de seg_statut_piece() — un écran et un
   serveur qui annonceraient deux seuils feraient passer le produit pour cassé. */
.seg-jauge { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.seg-jauge-piste { display: block; width: 54px; height: 6px; border-radius: 6px;
  background: var(--line); overflow: hidden; }
.seg-jauge-plein { display: block; height: 100%; border-radius: 6px;
  background: var(--seal); transition: width .2s; }
.seg-jauge-n { font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
  letter-spacing: .1px; }
.seg-jauge.est-bon .seg-jauge-plein { background: var(--seal); }
.seg-jauge.est-bon .seg-jauge-n { color: var(--seal); }
.seg-jauge.est-faible .seg-jauge-plein { background: var(--warn); }
.seg-jauge.est-faible .seg-jauge-n { color: var(--warn); }
/* R1395 — « NON MESURÉE » N'EST PAS « ZÉRO », et cela doit se VOIR : une
   piste hachurée, jamais une barre vide, qu'on lirait comme un échec. */
.seg-jauge.non-mesuree .seg-jauge-piste { background: repeating-linear-gradient(
    135deg, var(--line) 0 3px, var(--panel) 3px 6px); }
.seg-jauge.non-mesuree .seg-jauge-n { color: var(--faint); font-weight: 600; font-style: italic; }
.seg-jauge.non-mesuree { cursor: help; }
.seg-jauge.mini .seg-jauge-piste { width: 38px; height: 5px; }
.seg-jauge.mini .seg-jauge-n { font-size: 10.5px; }

/* ── LE CORPS DÉPLIÉ ── */
.seg-txt-corps { padding: 2px 0 7px; }
/* UNE SEULE ZONE QUI DÉFILE, et redimensionnable à la souris : ouvrir une
   pièce ne doit pas repousser les suivantes à trois écrans de là.
   « resize » exige « overflow » autre que visible — les deux vont ensemble. */
.seg-txt-zone { max-height: 22em; overflow: auto; resize: vertical;
  background: var(--paper2); border: 1px solid var(--line);
  border-radius: 9px; padding: 7px 9px; }
.seg-txt-zone:focus-visible { outline: 2px solid var(--seal); outline-offset: 1px; }
.seg-txt-page + .seg-txt-page { margin-top: 9px; padding-top: 8px; border-top: 1px dashed var(--line2); }
/* L'en-tête d'une page COLLE EN HAUT de la zone : sur une facture de trois
   pages, on sait toujours quelle page on lit sans remonter. */
.seg-txt-ptete { position: sticky; top: -7px; z-index: 1; display: flex; align-items: center;
  gap: 8px; flex-wrap: wrap; padding: 4px 0 5px;
  background: linear-gradient(var(--paper2) 72%, rgba(250,249,245,0)); }
.seg-txt-pre { margin: 0; font-family: var(--mono); font-size: 11.5px; line-height: 1.5;
  color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere;
  -webkit-user-select: text; user-select: text; }
.seg-txt-page.est-vide .seg-txt-pre { color: var(--faint); font-style: italic; font-family: var(--sans); }

.seg-txt-pied { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 7px; font-size: 11px; }

/* ── TÉLÉPHONE À 360 px ──
   L'en-tête tient sur deux lignes au lieu de rogner la jauge : le taux est
   l'information même de ce volet, il passe avant la compacité. */
@media (max-width: 560px) {
  .seg-txt-zone { max-height: 16em; }
  .seg-txt-poids { width: 100%; }
}
@media (max-width: 400px) {
  .seg-jauge-piste { width: 42px; }
  .seg-txt-pre { font-size: 11px; }
}

/* R1420 — ON NE DÉPLIE RIEN PENDANT UN GLISSEMENT. La pièce prise devient
   translucide ; son volet ouvert suivrait la main sur vingt lignes de texte,
   et l'on ne verrait plus où l'on va. */
.seg-piece.porte .seg-txt-corps { visibility: hidden; }

/* À L'IMPRESSION, un <details> fermé cache son contenu : on l'ouvre. Qui
   imprime cet écran veut la preuve de ce qui a été lu. */
@media print {
  .seg-txt-corps { display: block !important; }
  .seg-txt-zone { max-height: none; overflow: visible; resize: none; border-color: var(--line2); }
  .seg-txt-pied { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .seg-txt-chev::before, .seg-jauge-plein { transition: none; }
}

/* ===== R1444 — l'écran qui dit qu'il travaille, avant de travailler ===== */
/* La page de découpage calculait son plan AVANT page_start() : le navigateur
   attendait trente secondes devant une page blanche. L'attente n'a pas
   disparu, elle est devenue visible — et cet écran est tout ce qu'on voit
   pendant que le vrai se prépare. Il doit donc être calme et centré, non une
   barre de plus en haut d'une page vide. */
.seg-attente { max-width: 34rem; margin: 3rem auto; text-align: center; padding: 2.2rem 1.6rem; }
.seg-attente h1 { font-size: 1.25rem; margin: 1.1rem 0 .5rem; }
.seg-attente p { margin: .35rem 0; }
.seg-attente .mt3 { margin-top: 1.4rem; display: flex; gap: .5rem; justify-content: center; flex-wrap: wrap; }
.seg-attente-rond {
  width: 2.6rem; height: 2.6rem; margin: 0 auto; border-radius: 50%;
  border: 3px solid var(--bord, #d8dee6);
  border-top-color: var(--accent, #0b6b53);
  animation: seg-tourne .9s linear infinite;
}
@keyframes seg-tourne { to { transform: rotate(360deg); } }
/* ⚠ Qui a demandé moins d'animation n'en reçoit pas : le rond s'arrête et
   reste un repère, le texte dit déjà tout. */
@media (prefers-reduced-motion: reduce) { .seg-attente-rond { animation: none; } }
@media (max-width: 400px) { .seg-attente { margin: 1.4rem auto; padding: 1.6rem 1rem; } }

/* R1480 — LA PORTE FERMÉE QU'ON VOIT. La case du titre et du résumé reste
   en vue quand le moteur est local : éteinte, avec sa raison en dessous.
   Cachée, elle n'existait pas — « Classique » étant coché par défaut, le
   client ouvrait la fenêtre et ne voyait rien. C'est la règle de R1377. */
.lec-fiche.inactif { opacity: .55; }
.lec-fiche.inactif input { cursor: not-allowed; }
.lec-fiche .lec-lie { display: block; margin-top: 2px; }
