/* Back-office YHB — écrit à la main, aucune chaîne de construction.
   Pas de Tailwind, pas de Vite, pas de node_modules : un fichier servi tel
   quel. C'est ce qui tient le mieux sur un hébergement mutualisé, et ce qui
   se relit dans deux ans sans réapprendre un outil. */

/*
 * Les couleurs, les fontes et les rayons vivent dans la peau —
 * public/css/peaux/. Ce fichier ne décrit que la structure.
 */

* { box-sizing:border-box; }
body { margin:0; background:var(--papier); color:var(--encre); font-family:var(--sans);
  font-size:15px; line-height:1.55; -webkit-font-smoothing:antialiased; }
/* ⚠️ LE LIEN PREND `--accent-encre`, PAS `--accent` — 20.10.2026.

   Mesuré sur les sept peaux : `--accent` est fait pour être un FOND ou un
   FILET, et deux peaux le posaient sur du texte sous le seuil AA de 4,5:1 —
   yhb à 3,93 et orange à 3,07. Les cinq autres passaient, et c'est justement
   ce qui rendait le défaut invisible : rien ne distingue à l'œil un 3,93 d'un
   4,56.

   ⚠️ LE REPLI EST DANS LA VARIABLE, et c'est ce qui rend le changement sûr :
   une peau qui ne déclare pas `--accent-encre` garde exactement le rendu
   qu'elle avait. Seules celles qui en ont besoin en posent une.

   La valeur de YHB n'est pas inventée : `accent-ink` #B7006F vient du design
   system de la marque, et rend 5,74:1 sur le papier. */
a { color:var(--accent-encre, var(--accent)); text-decoration:none; }
a:hover { text-decoration:underline; }
h1 { font-size:1.6rem; font-weight:700; letter-spacing:-0.025em; margin:0; }
h2 { font-size:1.1rem; font-weight:600; letter-spacing:-0.015em; margin:0; }
p { margin:0; }
code { font-family:var(--mono); font-size:0.85em; background:var(--surface-2);
  padding:0.1em 0.35em; border-radius:var(--r); }

/* ---- ossature ---- */
/* ⚠️ `minmax(0, 1fr)` ET NON `1fr` — C'EST CE QUI FAISAIT DÉBORDER TOUT L'ÉCRAN.
   *Direction, 03.10.2026, capture d'un iPhone en production : « adapte pour
   responsive ».* Le titre était coupé, les tuiles sortaient à droite, et les
   cartes de tâches dépassaient du cadre.

   Un `1fr` vaut `minmax(auto, 1fr)` : son MINIMUM est la largeur min-content
   de ce qu'il contient. Une seule ligne large au fond de la page — un tableau,
   un sélecteur, un titre qui refuse de se couper — suffisait donc à élargir la
   colonne entière, et avec elle la page. Toutes les grilles enfants héritaient
   d'une largeur qui n'existait nulle part à l'écran, et les règles mobiles
   n'y pouvaient rien : elles réglaient des enfants dans un parent déjà trop
   large.

   `minmax(0, …)` rend ce minimum nul. La colonne cesse d'écouter son contenu,
   le contenu se coupe ou défile dans SON cadre, et la page tient. */
.app { display:grid; grid-template-columns:230px minmax(0, 1fr); min-height:100vh; }
/* ---- le rail ----
   Clair, large, lisible. Les catégories étaient en 0,58rem : trop petit pour
   des libellés en capitales, qui perdent leur silhouette et se lisent lettre
   à lettre. Elles sont remontées, et les entrées ont gagné le poids et
   l'espace qui les rendent cliquables sans viser. */
.rail { background:var(--roche); color:var(--roche-encre); padding:1.5rem 0.9rem;
  display:flex; flex-direction:column; gap:1.1rem;
  border-right:1px solid var(--roche-trait); }

/* Le monogramme porte le dégradé signature — là où le violet a plus de force
   qu'étalé sur une colonne entière. */
.rail .marque { display:flex; align-items:center; gap:0.7rem; padding:0.35rem 0.4rem;
  color:inherit; text-decoration:none; border-radius:12px; }
.rail .marque:hover { background:color-mix(in srgb, var(--roche-encre) 6%, transparent);
  text-decoration:none; }
.rail .monogramme { width:2.4rem; height:2.4rem; border-radius:12px;
  background:var(--degrade); color:#fff; display:flex; align-items:center;
  justify-content:center; flex:0 0 auto; }
.rail .monogramme svg { width:62%; height:62%; display:block; }
/* ⚠️ PLUS DE RÈGLE POUR UN SOUS-TITRE : il n'y en a plus. Le rail portait
   « YHB » avec « Plateforme » en 0.62rem sous lui ; depuis le 07.10 il ne porte
   que « Plateforme », et c'est cette règle-ci qui l'habille. */
.rail .marque .nom { font-weight:600; font-size:1.05rem; letter-spacing:-0.01em;
  line-height:1.15; }

.rail nav { display:flex; flex-direction:column; gap:0.15rem; }

/* Les en-têtes de groupe.
   Elles étaient en 0,58rem capitales : trop petit pour des capitales, qui
   perdent leur silhouette et se lisent lettre à lettre. Elles gardent la
   casse normale, prennent du poids, et se distinguent des entrées par la
   couleur plutôt que par la taille — une hiérarchie qui se lit sans loupe. */
.rail-groupe { font-family:var(--mono); font-size:0.68rem; font-weight:500;
  text-transform:uppercase; letter-spacing:0.12em; opacity:0.42;
  padding:0.4rem 0.7rem; margin:0.6rem 0 0.1rem; gap:0.6rem; }
/* ══════════════════════════════════════════════════════════════════════════
   UNE ICÔNE A UNE TAILLE PAR DÉFAUT — 24.09.2026

   Elle n'en avait aucune : seules `.rail nav a .ico`, `.rail-groupe .ico` et
   `.module-liens a .ico` en donnaient une. Toute icône posée ailleurs revenait
   à la taille intrinsèque d'un SVG remplacé — 300 px — et faisait exploser la
   grille qui la contenait. C'est arrivé le 24.09 sur l'accueil de section.

   La règle de base ferme la famille entière de ce défaut ; les trois règles
   ci-dessous continuent de l'ajuster là où elles le faisaient déjà.
   ══════════════════════════════════════════════════════════════════════════ */
.ico { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }

.rail-groupe .ico { width:0.95rem; height:0.95rem; flex:0 0 auto; }
.rail-groupe > span { flex:1 1 auto; }
/* Le cockpit se détache du reste : une séparation dit qu'il n'est pas du même
   ordre que les modules qu'il dessert. */
.rail-principal { padding-bottom:0.6rem; margin-bottom:0.2rem;
  border-bottom:1px solid var(--roche-trait); }
.rail-pli:first-child .rail-groupe { margin-top:0; }
.rail nav a { color:var(--roche-encre); padding:0.46rem 0.7rem; border-radius:10px;
  font-size:0.95rem; font-weight:600; opacity:0.78; display:flex; align-items:center;
  gap:0.65rem; }
.rail nav a .libelle { flex:1 1 auto; }
.rail nav a .ico { width:1.05rem; height:1.05rem; flex:0 0 auto; opacity:0.6; }
.rail nav a .compteur { font-family:var(--mono); font-size:0.68rem; padding:0.1rem 0.42rem;
  border-radius:999px; background:color-mix(in srgb, var(--roche-encre) 8%, transparent);
  opacity:0.75; flex:0 0 auto; }
/* L'état d'un module, au rail — discret par construction.
   Il ne paraît que sur ce qui n'est pas stable : c'est un avertissement, pas
   une décoration, et un avertissement qui figure partout n'avertit plus. */
.rail nav a .reserve { font-family:var(--mono); font-size:0.6rem; letter-spacing:0.04em;
  text-transform:uppercase; padding:0.06rem 0.34rem; border-radius:4px;
  border:1px solid color-mix(in srgb, var(--roche-encre) 22%, transparent);
  opacity:0.6; flex:0 0 auto; white-space:nowrap; }

.rail nav a:hover { background:color-mix(in srgb, var(--roche-encre) 6%, transparent);
  opacity:1; text-decoration:none; }
.rail nav a:hover .ico { opacity:0.85; }
.rail nav a.actif { background:color-mix(in srgb, var(--roche-encre) 9%, transparent);
  opacity:1; }
.rail nav a.actif .ico { opacity:1; color:var(--accent); }

.rail .bas { margin-top:auto; font-size:0.82rem; padding:0.9rem 0.7rem 0;
  border-top:1px solid var(--roche-trait); display:flex; flex-direction:column;
  gap:0.4rem; }
.rail .bas .qui { display:flex; align-items:center; gap:0.6rem; }
.rail .bas .pastille { width:1.9rem; height:1.9rem; border-radius:50%;
  background:color-mix(in srgb, var(--roche-encre) 10%, transparent);
  display:flex; align-items:center; justify-content:center; font-size:0.7rem;
  font-weight:600; flex:0 0 auto; }
.rail .bas .qui div { line-height:1.25; }
.rail .bas .qui small { display:block; opacity:0.55; font-size:0.75rem; }
.rail .bas form { margin:0; }
.rail .bas button { background:none; border:0; color:inherit; font:inherit;
  padding:0; cursor:pointer; opacity:0.6; font-size:0.8rem; }
.rail .bas button:hover { opacity:1; text-decoration:underline; }

/* `min-width:0` n'est pas décoratif : un enfant de grille prend par défaut la
   largeur de son CONTENU (`min-width:auto`), pas celle de sa colonne. Un
   tableau de six colonnes élargissait donc `.vue`, puis `.app`, puis le
   document — et sur un téléphone on balayait la page entière pour atteindre un
   bouton, en perdant l'en-tête au passage. Constaté le 03.09.2026 sur iPhone,
   cockpit « Mes tâches ». Ici, le débordement redescend là où il se gère. */
/* ⚠️ PLUS DE LAISSE À 1180 PX, ET DES MARGES RESSERRÉES — 24.09.2026.
   *Direction : « n'hésite pas à utiliser toute la largeur du viewport à
   l'intérieur, que ça s'adapte à la taille de l'écran […] resserre les
   marges. »*

   La borne venait de la lisibilité d'un paragraphe — 60 à 80 signes par
   ligne. Elle valait quand les écrans portaient de la prose ; ils n'en
   portent plus depuis que les gloses sont parties. Ce qui reste est
   TABULAIRE, et un tableau ne se lit pas mieux serré au milieu d'un écran de
   27 pouces : il se lit avec ses colonnes visibles.

   La borne haute reste, très large : au-delà de 2200 px, une ligne de tableau
   devient un trajet de l'œil d'un bord à l'autre, et on perd la ligne en
   route. */
.vue { padding:1.1rem 1.4rem 3rem; max-width:2200px; min-width:0; }
/* `.vue-large` ne sert plus qu'à lever la borne haute — pour un Gantt à 52
   semaines, qui veut tout l'espace qu'on lui donne. */
.vue-large { max-width:none; }
.entete { display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  margin-bottom:0.9rem; flex-wrap:wrap; }
.fil { font-family:var(--mono); font-size:0.66rem; text-transform:uppercase;
  letter-spacing:0.13em; color:var(--gris); margin-bottom:0.4rem; }

/* ---- tableau ---- */
/*
 * Le cadre porte son rembourrage. Un tableau, lui, doit toucher les bords —
 * ses propres cellules portent déjà leur espacement, et une double marge
 * autour d'une grille se voit tout de suite.
 *
 * D'où l'annulation par marge négative : le contenu libre respire, le tableau
 * saigne jusqu'au bord. C'est le défaut signalé sur le fil d'action, où les
 * lignes collaient au cadre.
 */
.cadre { border:1px solid var(--trait); border-radius:var(--r); background:var(--surface);
  overflow:hidden; padding:0.75rem 0.9rem; }
.cadre > .defiler { margin:0.5rem -0.9rem -0.75rem; }
.cadre > .defiler:first-child { margin-top:-0.75rem; }
.cadre > :first-child { margin-top:0; }
.cadre > :last-child { margin-bottom:0; }
.cadre > p:last-child { margin-bottom:0; }
.defiler { overflow-x:auto; }

/* ══════════════════════════════════════════════════════════════════════════
   LE CALENDRIER DE LA SEMAINE S'OUVRE SUR LES HEURES OUVRÉES — 09.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « pour le calendrier hebdo il faut voir les events de 00h00 à
   24h00. Par défaut on ne voit que 8h00 - 20h00, ensuite il faut scroller. »*

   La grille porte désormais les vingt-quatre heures. Sans cadre, elle ferait
   une page de 82 rem : on verrait la nuit et il faudrait descendre pour
   atteindre la journée de travail.

   Le cadre borne donc la hauteur à douze heures — 8 h à 20 h — et le reste se
   rejoint au défilement.

   ⚠️ LE DÉCALAGE INITIAL EST POSÉ PAR UN SCRIPT, et c'est le seul moyen : le
   CSS ne sait pas ouvrir un conteneur ailleurs qu'en haut. Le script est un
   confort et ne conditionne rien — sans lui, la grille s'ouvre à minuit et
   tout reste atteignable. C'est la même règle que le repli du rail : « il
   ajoute du confort, il ne conditionne pas l'accès ». */
.cal-sem-defile { max-height: calc(var(--h-heure, 3.4rem) * 12 + 6rem);
  overflow-y: auto; overflow-x: auto; }
table { border-collapse:collapse; width:100%; font-size:0.88rem; }
thead th { text-align:left; font-family:var(--mono); font-size:0.6rem; text-transform:uppercase;
  letter-spacing:0.1em; color:var(--gris); font-weight:400; padding:0.7rem 0.9rem;
  background:var(--surface-2); border-bottom:1px solid var(--trait); white-space:nowrap; }
/* ⚠️ 0,42 rem ET NON 0,62 — mesuré, pas estimé. *Direction, 06.10.2026, cinq
   fois : « ça prend beaucoup trop de place en hauteur ».* Les 0,62 rem haut et
   bas faisaient 20 px par ligne ; sur les 90 tâches d'un cockpit, c'est 1 800 px
   de rembourrage pour zéro information. Le trait du bas sépare déjà les lignes :
   l'espace autour de lui ne porte rien, et c'est exactement ce que « compacter »
   veut dire ici — retirer ce qui ne dit rien, pas rétrécir ce qui parle. */
/* ══════════════════════════════════════════════════════════════════════════
   LE RÉPERTOIRE TIENT EN UNE LIGNE PAR TIERS — 09.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « il faudrait compacter un petit peu plus la liste, qu'elle
   tienne en une seule ligne. Ça prend trop de place. »*

   Deux colonnes débordaient : la fonction, posée sous le nom, et la prochaine
   action, qui s'enroulait. Sur 290 tiers, chaque ligne de trop se paie
   290 fois.

   ⚠️ LE TEXTE ENTIER RESTE LISIBLE AU SURVOL — l'attribut `title` le porte.
   Tronquer sans donner accès au reste cacherait l'information au lieu de la
   ranger. */
.rep-fonction { margin-left: .4rem; }
.rep-coupe { max-width: 22rem; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }

tbody td { padding:0.42rem 0.9rem; border-bottom:1px solid var(--trait-clair);
  vertical-align:middle; }
tbody tr:last-child td { border-bottom:0; }
tbody tr:hover { background:var(--surface-2); }
td.actions { text-align:right; white-space:nowrap; }

/* ═══════════════════════════════════════════ les tableaux sur un téléphone

   LE DÉFAUT N'ÉTAIT PAS QUE LE TABLEAU SOIT LARGE — C'EST QUE LA PAGE L'ÉTAIT.

   Un enfant de grille prend par défaut la largeur de son contenu, pas celle de
   sa colonne : `min-width:auto`. Un tableau de six colonnes élargissait donc
   `.vue`, puis `.app`, puis le document — et l'on balayait la page entière
   pour atteindre un bouton, en perdant l'en-tête au passage. `min-width:0`
   rend la colonne maîtresse de sa largeur, et le débordement redescend là où
   il se gère.

   Constaté le 03.09.2026 sur iPhone, cockpit « Mes tâches ». */

@media (max-width:820px) {
  /* Le filet : un tableau qui reste large défile DANS son cadre, pas dans la
     page. Aucun écran n'a besoin qu'on le sache pour en profiter. */
  .cadre { overflow-x:auto; }
}

/* ── Des lignes qui deviennent des fiches
   Faire défiler un tableau reste un pis-aller : on lit une ligne en six
   morceaux qu'on ne voit jamais ensemble. Sous 620 px, chaque ligne devient
   une fiche, et chaque cellule porte son intitulé — celui de l'en-tête, qui
   n'a plus lieu d'être répété en haut.

   `data-libelle` et non `::before` codé en dur : l'intitulé vient du gabarit,
   donc il suit le jour où la colonne change de nom. Une seconde vérité dans le
   CSS aurait menti au premier renommage. */

/* ── Ce qui refuse de rétrécir, et qu'il faut borner ───────────────────────
   Un `select` prend la largeur de sa plus longue option, un `input[type=date]`
   celle de son format, et aucun des deux ne se coupe. Dans une carte de
   390 px, ils débordaient par la droite. Mesuré sur iPhone le 03.10.2026, en
   même temps que le débordement de `.app`.

   `max-width:100%` suffit : ils se contentent de la place qu'il reste au lieu
   de l'imposer. Posé largement plutôt que cas par cas — la règle vaut partout
   où un formulaire entre dans une colonne étroite. */
@media (max-width:620px) {
  select, input[type="date"], input[type="time"], input[type="email"],
  input[type="text"], input[type="number"], input[type="url"], textarea {
    max-width: 100%;
  }

  .table-fiches thead { position:absolute; width:1px; height:1px;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap; }

  .table-fiches, .table-fiches tbody { display:block; }

  .table-fiches tbody tr { display:block; padding:0.85rem 0.9rem;
    border:1px solid var(--trait); border-radius:12px; margin-bottom:0.6rem;
    background:var(--surface); }
  .table-fiches tbody tr:hover { background:var(--surface); }
  .table-fiches tbody tr:last-child { margin-bottom:0; }

  /* Même piège, même correctif : le sélecteur d'étape et les intitulés longs
     imposaient leur min-content à la colonne de valeur, et la fiche sortait
     de la carte. */
  .table-fiches tbody td { display:grid; grid-template-columns:6.5rem minmax(0, 1fr);
    gap:0.35rem 0.7rem; align-items:baseline;
    padding:0.3rem 0; border:0; white-space:normal; }
  .table-fiches tbody td::before { content:attr(data-libelle);
    font-family:var(--mono); font-size:0.56rem; text-transform:uppercase;
    letter-spacing:0.1em; color:var(--gris); }
  .table-fiches tbody td:empty { display:none; }

  /* Une cellule sans intitulé — la ligne « rien à afficher », qui porte un
     `colspan` — ne doit pas se retrouver avec une colonne d'étiquette vide et
     un texte poussé à droite. */
  .table-fiches tbody td:not([data-libelle]) { display:block; }
  .table-fiches tbody td:not([data-libelle])::before { content:none; }

  /* Le conteneur de défilement n'a plus rien à faire défiler : sans cette
     ligne, il garde une barre horizontale résiduelle sur certains moteurs. */
  .table-fiches { overflow-x:visible; }

  /* Le titre porte la fiche : pleine largeur, sans intitulé — on ne légende
     pas ce qu'on lit en premier. */
  .table-fiches tbody td:first-child { display:block; font-size:1rem;
    line-height:1.35; padding-bottom:0.55rem; margin-bottom:0.3rem;
    border-bottom:1px solid var(--trait-clair); }
  .table-fiches tbody td:first-child::before { content:none; }

  /* Les gestes reprennent toute la largeur et cessent de fuir à droite : sur
     un pouce, un bouton aligné à droite d'une fiche se rate. */
  .table-fiches tbody td.actions { display:block; text-align:left;
    white-space:normal; padding-top:0.6rem; }
  .table-fiches tbody td.actions::before { content:none; }
  .table-fiches tbody td.actions form,
  .table-fiches tbody td.actions > div { display:flex; flex-wrap:wrap; gap:0.4rem; }
  .table-fiches tbody td.actions .bouton { min-height:40px; display:inline-flex;
    align-items:center; }
}
.vide { padding:2.6rem 1rem; text-align:center; color:var(--gris); font-size:0.9rem; }

/* Un intitulé que seul un lecteur d'écran entend.
   `display:none` le retirerait aussi de l'accessibilité : c'est précisément ce
   qu'on ne veut pas. On le sort du flux visuel sans le sortir du document. */
.visuellement-cache { position:absolute; width:1px; height:1px; padding:0;
  margin:-1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap;
  border:0; }

/* L'export du procès-verbal : le sélecteur et son bouton font un seul geste,
   donc un seul bloc. */
.exporter-pv { display:inline-flex; align-items:center; gap:0.4rem; }
.exporter-pv select { min-height:2.1rem; }

/* ---- étiquettes ---- */
.eti { font-family:var(--mono); font-size:0.58rem; text-transform:uppercase;
  letter-spacing:0.09em; padding:0.2rem 0.42rem; border-radius:var(--r);
  border:1px solid; white-space:nowrap; display:inline-block; }
.eti-neutre { color:var(--gris); border-color:var(--trait); background:var(--surface-2); }
.eti-accent { color:var(--accent-encre, var(--accent)); border-color:var(--accent); background:var(--accent-doux); }
.eti-vert   { color:var(--vert); border-color:var(--vert); background:var(--vert-doux); }
.eti-ocre   { color:var(--ocre); border-color:var(--ocre); background:var(--ocre-doux); }
.eti-rouge  { color:var(--rouge); border-color:var(--rouge); background:var(--rouge-doux); }

/* ---- boutons ---- */
.bouton { display:inline-block; font:inherit; font-size:0.86rem; font-weight:500;
  padding:0.46rem 0.9rem; border-radius:var(--r); border:1px solid var(--trait);
  background:var(--surface); color:var(--encre); cursor:pointer; }
.bouton:hover { background:var(--surface-2); text-decoration:none; }
.bouton-fort { background:var(--accent); border-color:var(--accent); color:var(--sur-accent); }
/* ⚠️ UN BOUTON DÉSACTIVÉ DOIT AVOIR L'AIR DÉSACTIVÉ — 11.10.2026.
   *Direction, en essayant de déposer une matière : « je peux cliquer, mais il
   ne se passe rien. »* Le bouton était `disabled` pour une bonne raison —
   aucun stockage privé n'est configuré — mais `.bouton` repeint tout, fond
   compris : il restait rose vif et parfaitement cliquable à l'œil.

   Vingt-deux boutons de l'application portent `@disabled`. AUCUN ne le
   montrait. C'est la même famille que les fenêtres aux identifiants doublés :
   la page répond, le bouton existe, et le clic ne fait rien. */
.bouton:disabled, .bouton[disabled] {
  opacity: 0.5; cursor: not-allowed; filter: grayscale(1);
}
.bouton:disabled:hover, .bouton[disabled]:hover { background: var(--surface); }
.bouton-fort:disabled:hover, .bouton-fort[disabled]:hover { background: var(--accent); }
/* Et la raison se lit À CÔTÉ du bouton, pas seulement en haut de l'écran :
   un encart lu il y a trente secondes n'explique pas un clic mort. */
.pourquoi-desactive { font-size: .82rem; color: var(--gris); margin: 0; }

/* Un bouton qui dit « ce filtre est en vigueur ».
   Il n'est pas fort — il ne propose pas l'action principale, il montre un état
   actif qu'on peut relâcher. D'où le fond doux plutôt que l'accent plein. */
.bouton-actif { background:var(--accent-doux); border-color:var(--accent);
  color:var(--accent-encre, var(--accent)); font-weight:600; }
.bouton-fort:hover { opacity:0.9; background:var(--accent); }
.bouton-danger { color:var(--rouge); border-color:var(--rouge); background:var(--rouge-doux); }
.bouton-mini { font-size:0.78rem; padding:0.28rem 0.6rem; }

/* ---- formulaire ---- */
/* 280 px de plancher n'ouvrait la deuxième colonne qu'à partir de 600 px de
   contenu : sur une fiche, les champs restaient en file indienne alors qu'il
   y avait la place. 15 rem suffisent à un libellé et à son champ. */
/* ── Une date n'a pas besoin d'une demi-page.
 *
 * *Direction : « la date, c'est beaucoup trop large. Début et échéance, ça
 * peut se coller l'un à côté de l'autre. »* Un champ de date rend toujours le
 * même nombre de caractères : lui donner une colonne entière de formulaire
 * laisse les deux tiers vides, et éloigne « début » de « échéance » alors
 * qu'on les lit ensemble. */
input[type="date"], input[type="time"] { max-width: 11rem; }

/* Un choix court se montre, il ne se déroule pas.
 *
 * *Direction : « tu as le droit d'utiliser autre chose que des drop-downs,
 * des boutons radio, d'autres styles de boutons. »* Une liste de trois ou
 * quatre valeurs cachée derrière un menu demande un clic pour apprendre ce
 * qu'elle contient — et deux pour changer d'avis. Posées côte à côte, les
 * valeurs se comparent. Au-delà de cinq, le menu reste plus sage. */
.choix { display:flex; flex-wrap:wrap; gap:0.3rem; }
.choix input { position:absolute; opacity:0; width:0; height:0; }
.choix label { display:inline-flex; align-items:center; padding:0.32rem 0.7rem;
  border:1px solid var(--trait); border-radius:999px; cursor:pointer;
  font-size:0.84rem; line-height:1.2; background:var(--surface);
  transition:border-color .12s, background .12s, color .12s; }
.choix label:hover { border-color:var(--accent); }
.choix input:checked + label { background:var(--accent-doux); border-color:var(--accent);
  color:var(--accent-encre, var(--accent)); font-weight:600; }
.choix input:focus-visible + label { outline:2px solid var(--accent); outline-offset:2px; }

/* Trois issues du même examen, posées côte à côte plutôt qu'empilées.
   `auto-fit` : la mise en page ne dépend pas du nombre de gestes offerts,
   qui varie avec les droits et l'état de la matière. */
.gestes-cote-a-cote { display: grid; gap: .8rem;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); align-items: start; }
/* ⚠️ `.formulaire` y perd sa borne de 78 rem : dans une colonne de 19 rem,
   une largeur de lecture de 1 250 px n'a plus de sens, et `max-width` sur une
   piste de grille l'empêche de se réduire. */
.gestes-cote-a-cote .formulaire { max-width: none; grid-template-columns: 1fr; }

/* Le repli d'une preuve : une empreinte se vérifie, elle ne se lit pas.
   Discret, et sans la flèche par défaut du navigateur, qui pèse plus que le
   mot qu'elle annonce. */
.cartel-preuve { margin-top: .2rem; }
.cartel-preuve > summary { font-size: .76rem; cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: .3rem; }
.cartel-preuve > summary::-webkit-details-marker { display: none; }
.cartel-preuve > summary::before { content: "▸"; font-size: .7em; }
.cartel-preuve[open] > summary::before { content: "▾"; }
.cartel-preuve code { word-break: break-all; }

/* ── La liste des habillages ─────────────────────────────────────────────
   *Direction, 10.10.2026 : « je préfère une liste plutôt que des mètres de
   gauche à droite. »*

   `.choix` reste ce qu'il est — une rangée de pastilles, juste pour deux ou
   trois valeurs courtes comme « Clair / Sombre ». À sept entrées dont trois
   portent une fenêtre de dates, la rangée s'enroulait sur trois lignes et on
   ne savait plus ce qui allait avec quoi.

   Même mécanique que `.choix` : le bouton radio natif est caché, le label
   porte tout. Le rond est dessiné en `::before` — sans lui, une ligne cochée
   ne se distingue que par sa couleur, et une couleur seule ne suffit pas. */
.liste-choix { display:flex; flex-direction:column; gap:0; max-width:34rem; }
.liste-choix input { position:absolute; opacity:0; width:0; height:0; }
.liste-choix label { display:flex; align-items:center; gap:0.6rem;
  padding:0.5rem 0.7rem; cursor:pointer; line-height:1.3;
  border:1px solid transparent; border-radius:var(--r);
  transition:background .12s, border-color .12s; }
.liste-choix label::before { content:""; flex:0 0 auto;
  width:0.85rem; height:0.85rem; border-radius:50%;
  border:1px solid var(--trait); background:var(--surface); }
.liste-choix label:hover { background:var(--surface-2); }
.liste-choix input:checked + label { background:var(--accent-doux);
  border-color:var(--accent); }
.liste-choix input:checked + label::before { border:0.27rem solid var(--accent);
  background:var(--surface); }
.liste-choix input:focus-visible + label { outline:2px solid var(--accent);
  outline-offset:2px; }
.liste-choix .choix-nom { font-size:0.9rem; }
.liste-choix input:checked + label .choix-nom { font-weight:600; color:var(--accent); }
/* La note — fenêtre de saison, ou ce que l'automatique donne aujourd'hui.
   Poussée à droite, elle aligne toutes les dates sur une colonne. */
.liste-choix .choix-note { font-size:0.76rem; color:var(--gris);
  margin-left:auto; text-align:right; }
/* Le trait qui sépare le MODE des habillages. C'est un élément à part et non
   une bordure du label : un label coché change de bordure, et le séparateur
   aurait sauté avec. */
.liste-trait { height:1px; background:var(--trait-clair); margin:0.4rem 0.7rem; }

/* Au pouce, la note passe sous le nom : à 390 px, « Saint-Valentin » et
   « 07.02 → 16.02 » sur la même ligne se touchent. */
@media (max-width: 620px) {
  .liste-choix label { flex-wrap:wrap; }
  .liste-choix .choix-note { width:100%; margin-left:1.45rem; text-align:left; }
}

/* ⚠️ UN FORMULAIRE A UNE LARGEUR DE LECTURE, ET CE N'EST PAS CELLE DE L'ÉCRAN.
   *Direction, 11.10.2026 : « des inputs texte qui font 2 500 px de large. Ça
   ne veut rien dire. Il faut mettre les boîtes les unes à côté des autres. »*

   `.vue` borne la page à 2 200 px — juste pour un Gantt de 52 semaines, faux
   pour un champ de saisie : un `.champ.large` prenait toute la grille et
   donnait une ligne de texte de deux mètres. L'œil ne suit pas, et deux
   champs côte à côte deviennent deux champs très loin l'un de l'autre.

   78 rem (~1 250 px) laisse quatre colonnes de 15 rem respirer, et aucune
   ligne ne dépasse ce qu'on relit sans tourner la tête. Les tableaux, les
   calendriers et les gantts ne sont pas concernés : la borne est sur
   `.formulaire`, pas sur la page. */
.formulaire { display:grid; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr)); max-width:78rem;
  gap:1.1rem 1.4rem; padding:1.4rem; }
.champ { display:flex; flex-direction:column; gap:0.34rem; }
.champ.large { grid-column:1 / -1; }
.champ label { font-size:0.82rem; font-weight:600; }
.champ label .requis { color:var(--rouge); }
.champ .aide { font-size:0.78rem; color:var(--gris); line-height:1.45; }
/* Une grille de champs POSÉE DANS UN CADRE ne se rembourre pas une seconde
   fois : `.cadre` paye déjà 0.9 rem, `.formulaire` en ajoutait 1.4. On imbrique
   les deux dès qu'un formulaire veut un pied hors de sa grille — sans quoi le
   `border-top` du pied devient une cellule et ne traverse qu'une colonne. */
.cadre > .formulaire { padding:0; }
/* La case à cocher est le seul champ dont le libellé se lit À DROITE : la case
   d'abord, la phrase ensuite. `.champ` empile en colonne, celle-ci se remet en
   ligne, et son libellé reprend un poids normal — ce n'est pas un en-tête de
   champ, c'est la phrase qu'on coche. */
.champ-case { display:flex; align-items:center; gap:0.5rem;
  font-weight:400; cursor:pointer; }
.champ-case input { margin:0; }
/* ⚠️ CETTE ÉNUMÉRATION DOIT SUIVRE LES VUES, ET RIEN NE L'Y OBLIGEAIT.
   `input[type=time]` y manquait : dix champs d'heure dans l'application
   portaient l'habillage du navigateur au milieu de champs habillés, et on ne
   le voyait qu'en les mettant côte à côte. *Direction, 10.10.2026, sur la
   fiche d'une tâche : « ergonomiquement, le champ de texte est un tout petit
   peu bizarre. »*

   Aucune erreur, aucun test rouge — c'est la même famille qu'un commentaire
   Blade orphelin ou une accolade en trop : une syntaxe que l'outil tolère et
   qui ment. `LesChampsPortentTousLHabillageTest` compte désormais les types
   employés dans les vues et exige qu'ils soient ici.

   `file`, `range` et `color` restent dehors VOLONTAIREMENT : leur rendu natif
   porte une fonction — le bouton « Parcourir », le curseur, la pastille — que
   `background` et `padding` abîment. */
/* ⚠️ `input:not([type])` EN TÊTE, ET C'EST LE MÊME DÉFAUT QUE `time`.
   *Direction, 11.10.2026 : « le texte input intitulé n'est pas bien
   affiché. »* Il s'écrivait `<input id="intitule" name="intitule">`, sans
   `type`. Le navigateur le traite comme du texte ; `input[type=text]` ne le
   voit pas. Il restait nu au milieu de champs habillés.

   Douze inputs de l'application étaient dans ce cas. On corrige le marquage
   ET le sélecteur : le premier est juste, le second empêche que l'oubli
   suivant se voie en production plutôt qu'ici. */
/* ⚠️ `url` EST ARRIVÉ LE 22.10.2026, ET L'OUBLI S'EST VU EN LIVRANT.
   Les deux champs de lien de visioconférence des évènements en ligne ont été
   posés en `type="url"` sans que l'énumération suive. Le défaut n'est pas
   tombé à l'écriture : il est tombé à l'étape de tests de `livrer`, qui a
   refusé la livraison. C'est la troisième fois que cette liste prend du
   retard sur les vues — `time`, puis `:not([type])`, puis `url`.

   Un champ d'URL est aussi le pire cas de la borne de largeur sous 620 px :
   un lien de visio ne se coupe pas et déborderait par la droite. Les deux
   règles sont complétées ensemble. */
input:not([type]),
input[type=text], input[type=email], input[type=number], input[type=date],
input[type=time], input[type=password], input[type=url], select, textarea {
  font:inherit; font-size:0.9rem; padding:0.46rem 0.6rem; border:1px solid var(--trait);
  border-radius:var(--r); background:var(--papier); color:var(--encre); width:100%;
}
input:focus, select:focus, textarea:focus { outline:2px solid var(--accent);
  outline-offset:1px; border-color:var(--accent); }
textarea { min-height:5rem; resize:vertical; }
.bascule { display:flex; align-items:center; gap:0.5rem; }
.bascule input { width:auto; }

/* Une case à cocher tient sur la ligne de son libellé — 23.10.2026.

   *Direction : « essaye de compacter les checkboxes aussi, pour être sur la
   même ligne que leur label. »* `.champ` empile en colonne : quatre cases
   faisaient quatre rangées de formulaire pour quatre carrés de 14 px. La
   case passe devant, le libellé reprend un poids de phrase — ce n'est plus
   un en-tête de champ, c'est l'étiquette de la case. */
.champ.champ-bascule { flex-direction: row; align-items: center; gap: 0.5rem; }
.champ.champ-bascule > label { order: 2; font-weight: 500; cursor: pointer; }
.champ.champ-bascule > .bascule { order: 1; }

/* ── La matrice des droits : des colonnes, et des coches de la maison
 *
 * *Direction, 05.10.2026 : « pour les verbes, il faut qu'ils soient un tout
 * petit peu plus organisés et structurés en colonnes, parce que ça manque un
 * petit peu de visibilité. Et puis les coches bleues, elles ne sont pas très
 * raccords avec le design. »*
 *
 * Les verbes étaient posés en `flex-wrap` : chaque ligne commençait où la
 * précédente avait fini, donc « modifier » ne tombait jamais sous
 * « modifier ». On ne pouvait pas lire une colonne du regard — or c'est
 * exactement ce qu'on fait devant une matrice : on compare un verbe d'un
 * domaine à l'autre.
 *
 * `accent-color` suffit à tenir la coche native dans la palette : pas de
 * fausse case en CSS, donc le clavier, le focus et les lecteurs d'écran
 * continuent de marcher sans qu'on ait à les réécrire. */
.mx-verbes { display:grid; grid-template-columns:repeat(8, 7.3rem);
  gap:0.3rem; align-items:center; }
.mx-verbes .bascule { font-size:0.84rem; min-width:0; }
/* ⚠️ `nowrap` EN PLUS DE L'ELLIPSE. Sans lui, « Retirer un consentement »
   se coupait en deux lignes et faisait grandir toute la rangée — c'est ce
   qui se voyait comme un défaut d'alignement le 11.10. Le titre complet
   reste lisible au survol par l'attribut `title`. */
.mx-verbes .bascule span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

input[type="checkbox"] { accent-color:var(--accent); }

/* Le domaine prend ce que les verbes ne prennent pas : avec huit colonnes
   fixes, il reste assez de place pour que l'explication tienne sur une ligne.
   *Direction : « ne fais jamais de retour à la ligne alors qu'il y a assez de
   place à droite. »* */
/* Le domaine tient sur UNE ligne : nom, code, et le « ? » qui porte le reste.
   Une phrase posée sous le nom coûtait deux lignes sur vingt-trois domaines. */
/* ── L'alignement d'une ligne de matrice ─────────────────────────────────
   *Direction, 07.10.2026 : « le texte ici, c'est pas très bien aligné en bas.
   Le rôle, il faudrait aligner ça correctement. »* — B6.

   ⚠️ LA CAUSE EST `vertical-align: middle`, POSÉ SUR TOUTES LES CELLULES.

   La plupart des domaines tiennent leurs verbes sur une rangée ; `Textus` en
   porte sept, donc deux. Sa cellule de droite fait alors le double de
   hauteur — et le nom du domaine, centré, descend d'une demi-ligne par
   rapport à tous les autres. C'est la DERNIÈRE ligne du tableau, celle qu'on
   regarde en dernier, et le décalage saute aux yeux.

   On aligne par le HAUT : le nom du domaine retrouve la première rangée de
   ses verbes, quelle que soit la hauteur de la cellule. Le rembourrage de
   `.mx-verbes` compense le demi-pixel qui resterait.

   ⚠️ SUR CETTE MATRICE SEULEMENT. `vertical-align: middle` est juste partout
   ailleurs : une cellule d'une ligne en face d'une cellule d'une ligne se lit
   mieux centrée. Changer la règle globale réglerait un écran et en dérangerait
   vingt. */
.mx-domaine,
.mx-domaine + td { vertical-align:top; }
.mx-domaine { white-space:nowrap; padding-top:0.55rem; }
.mx-domaine strong { font-weight:600; margin-right:0.45rem; }
.mx-domaine code { font-size:0.7rem; color:var(--gris); margin-right:0.35rem; }

@media (max-width:1280px) {
  .mx-verbes { grid-template-columns:repeat(4, minmax(0, 1fr)); }
}
/* ⚠️ UNE ACCOLADE FERMANTE EN TROP VIVAIT ICI — retirée le 09.10.2026.
   Les navigateurs l'ignorent silencieusement : aucun style ne manquait, rien
   ne se voyait. Mais une accolade orpheline est le même piège qu'un
   commentaire Blade sans ouverture — la prochaine règle collée juste au-dessus
   serait tombée hors de sa requête média, et personne n'aurait su pourquoi.
   `LesFeuillesDeStyleFermentCeQuElleOuvrentTest` compte désormais. */
.barre { display:flex; gap:0.6rem; padding:1rem 1.4rem; border-top:1px solid var(--trait);
  background:var(--surface-2); }

/* ---- messages ---- */
/* ── Le bandeau de confirmation, resserré — 06.10.2026 ───────────────────
   *Direction : « ici, c'est le message, il prend un peu trop de place.
   Compacter. »*

   « Enregistré. » tenait sur trois hauteurs de ligne : un rembourrage de
   formulaire pour un mot. ⚠️ Le réduire n'est pas le faire disparaître — c'est
   la seule confirmation qu'un geste a abouti, et un enregistrement muet fait
   recommencer. Une bande fine qui se lit d'un coup d'œil, et une marge qui ne
   repousse plus le contenu d'un cran entier. */
.message { padding:0.4rem 0.7rem; border-radius:var(--r); border:1px solid;
  font-size:0.84rem; line-height:1.35; margin-bottom:0.7rem; }
.message-ok { color:var(--vert); border-color:var(--vert); background:var(--vert-doux); }
.message-ko { color:var(--rouge); border-color:var(--rouge); background:var(--rouge-doux); }
.erreur { font-size:0.78rem; color:var(--rouge); }
/* Un manque qui bloque un geste, en une ligne.

   ⚠️ IL N'EXISTE PAS DE CLASSE `.ocre` AU PREMIER NIVEAU — seulement
   `.tuile-kpi.ocre`. La poser sur un paragraphe n'aurait rien donné, sans
   erreur et sans test rouge : c'est le même piège que `liste-trait`, `.vide`
   et `.type`, trois fois le 23.10.2026. */
.manque-bloquant { font-size:0.82rem; color:var(--ocre); font-weight:500; }

/* ---- accueil ---- */
.tuiles { display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr));
  gap:1px; background:var(--trait); border:1px solid var(--trait); border-radius:var(--r);
  overflow:hidden; }
.tuile { background:var(--surface); padding:1.1rem 1.2rem; display:flex;
  flex-direction:column; gap:0.25rem; }
.tuile .n { font-size:1.9rem; font-weight:700; letter-spacing:-0.03em;
  font-variant-numeric:tabular-nums; line-height:1; }
.tuile .q { font-family:var(--mono); font-size:0.62rem; text-transform:uppercase;
  letter-spacing:0.11em; color:var(--gris); }
.tuile .d { font-size:0.79rem; color:var(--gris); line-height:1.4; margin-top:0.2rem; }

/* ---- connexion ---- */
/* ═══════════════════════════════════════════════════════════════════════════
   LA PORTE — 12.10.2026

   *Direction : « que la page de login soit un petit peu plus design […] un
   peu au design de la constellation. Ça rendrait le truc un tout petit peu
   plus sexy. »*

   ⚠️ ELLE NE SUIT AUCUN HABILLAGE, ET C'EST UN ARGUMENT. Avant la connexion
   il n'y a pas d'utilisateur : aucune préférence n'existe encore, et ce qu'on
   affichait était l'habillage par défaut, choisi par personne. Les couleurs
   sont donc écrites ici, et non prises aux variables de peau — c'est le seul
   endroit de la feuille où cela se justifie.

   Le vocabulaire vient de `yhb-constellation`, `assets/recit.css` : l'encre
   `#0E0B14`, le dégradé radial qui éclaire le centre, le verre dépoli. Mêmes
   gestes, sur trois éléments au lieu de trente.
   ═══════════════════════════════════════════════════════════════════════ */
.connexion {
  min-height:100vh; display:grid; place-items:center; padding:1.5rem;
  background:radial-gradient(120% 90% at 50% 40%, #16101f 0%, #0E0B14 70%);
  color:#EDE9F2;
}
.connexion .boite { width:100%; max-width:23rem; text-align:center; }

/* Le monogramme respire : c'est la seule image de l'écran, et elle porte la
   maison. Le dégradé signature la remplit, comme dans la barre du haut. */
.connexion-monogramme {
  display:inline-flex; align-items:center; justify-content:center;
  width:3.4rem; height:3.4rem; border-radius:14px; margin-bottom:1rem;
  background:linear-gradient(112deg, #E6008A 0%, #7A3FD8 100%);
  color:#fff; box-shadow:0 10px 40px rgba(230, 0, 138, .22);
}
.connexion-monogramme svg { width:60%; height:60%; display:block; }

.connexion .marque { font-size:1.7rem; font-weight:700; letter-spacing:-0.03em;
  margin-bottom:1.6rem; color:#FFFFFF; }

/* Verre dépoli sur l'encre, comme les cartes du récit. */
.connexion form { display:flex; flex-direction:column; gap:0.9rem; padding:1.5rem;
  text-align:left; border-radius:14px;
  border:1px solid rgba(255,255,255,.09);
  background:rgba(27,27,34,.78); backdrop-filter:blur(10px);
  box-shadow:0 18px 60px rgba(0,0,0,.45); }
.connexion form label { color:#C9C4D2; }
.connexion input { background:rgba(255,255,255,.05); border-color:rgba(255,255,255,.14);
  color:#EDE9F2; }
.connexion input:focus { border-color:#E6008A; outline-color:#E6008A; }
.connexion .secondaire, .connexion a { color:#928E86; }
.connexion a:hover { color:#EDE9F2; }
.connexion .message { border-radius:10px; }

/* ═══════════════════════════════════════════════ le rail sur un téléphone
   CE QUI ÉTAIT ÉCRIT ICI SUPPOSAIT UN MENU PLAT, ET IL NE L'EST PLUS.

   La règle précédente passait `.rail` et `.rail nav` en `flex-direction:row`.
   Ça fonctionnait quand la navigation était une simple liste de liens. Depuis
   qu'elle est faite de groupes `<details>`, `row` aligne les GROUPES côte à
   côte — chacun gardant ses entrées empilées. Résultat mesuré au 03.09.2026
   sur un iPhone : quatre entrées en colonne, « Gouvernance » coupé au bord de
   l'écran, et le reste hors du viewport.

   Le rail devient donc une barre de haut, et le menu se replie derrière un
   bouton. Le bouton pose `hidden` sur `.rail-corps` ; tout le reste en découle.

   `display:contents` sur `.rail-corps` en écran large : le conteneur existe
   dans le HTML pour donner une prise au bouton, mais il ne doit pas s'insérer
   dans la colonne flex du rail, sinon `nav` et `.bas` cessent d'en être les
   enfants directs et l'espacement s'effondre. */

.rail-tete { display:contents; }
.rail-corps { display:contents; }
.rail-bascule { display:none; }

@media (max-width:820px) {
  /* ⚠️ `minmax(0, 1fr)` ET NON `1fr`, MÊME SEULE. Mesuré sur iPhone le
     06.10.2026 : avec un `1fr` nu, la page faisait 733 px de large dans un
     écran de 390. Un `1fr` vaut `minmax(auto, 1fr)`, dont le minimum est la
     largeur min-content du contenu — une colonne unique n'y change rien. */
  .app { grid-template-columns:minmax(0, 1fr); }

  /* La barre du haut colle en haut : sur une liste longue, remonter chercher
     le menu au début du document coûte un balayage entier. */
  .rail { position:sticky; top:0; z-index:30; display:block;
    padding:0.55rem 0.9rem; border-right:0;
    border-bottom:1px solid var(--roche-trait); }

  .rail-tete { display:flex; align-items:center; justify-content:space-between;
    gap:0.75rem; }
  .rail-tete .marque { padding:0.2rem 0.3rem; }
  .rail .monogramme { width:2rem; height:2rem; border-radius:10px; }

  /* 44 px de côté : la cible tactile en deçà de laquelle on vise au lieu de
     toucher. Ce n'est pas une marge de confort, c'est le seuil. */
  .rail-bascule { display:inline-flex; align-items:center; gap:0.45rem;
    min-height:44px; padding:0.5rem 0.8rem; border-radius:10px;
    border:1px solid var(--roche-trait); background:transparent;
    color:inherit; font:inherit; font-size:0.85rem; font-weight:600;
    cursor:pointer; }
  .rail-bascule svg { width:1.15rem; height:1.15rem; flex:0 0 auto; }
  .rail-bascule[aria-expanded="true"] { background:color-mix(in srgb, var(--roche-encre) 8%, transparent); }

  .rail-corps { display:block; margin-top:0.7rem;
    max-height:calc(100vh - 5rem); overflow-y:auto; }
  .rail-corps[hidden] { display:none; }

  .rail nav { flex-direction:column; gap:0.15rem; }
  .rail .bas { margin-top:0.8rem; }

  /* Les entrées deviennent des cibles tactiles, pas des lignes de liste. */
  .rail nav a, .rail-groupe { min-height:44px; align-items:center; }
  .rail nav a { padding:0.6rem 0.7rem; font-size:1rem; }

  .vue { padding:1.2rem 1rem 3rem; }
}

/* ---- tableau kanban ---- */
.colonnes { display:grid; grid-template-columns:repeat(4,minmax(210px,1fr)); gap:0.8rem;
  align-items:start; overflow-x:auto; padding-bottom:0.5rem; }
.colonne { background:var(--surface-2); border:1px solid var(--trait); border-radius:var(--r);
  display:flex; flex-direction:column; min-width:210px; }
.colonne header { display:flex; align-items:center; justify-content:space-between;
  padding:0.6rem 0.8rem; border-bottom:1px solid var(--trait);
  font-family:var(--mono); font-size:0.64rem; text-transform:uppercase;
  letter-spacing:0.11em; color:var(--gris); }
.colonne header .compte { font-variant-numeric:tabular-nums; }
.colonne .pile { display:flex; flex-direction:column; gap:0.5rem; padding:0.6rem; }
.carte-k { background:var(--surface); border:1px solid var(--trait); border-radius:10px;
  padding:0.65rem 0.7rem; display:flex; flex-direction:column;
  /* 0.4 et non 0.32 depuis le 22.09.2026 : la carte n'a plus cinq lignes
     mais trois étages, et trois étages respirent. */
  gap:0.4rem;
  transition:border-color 120ms ease; }
.carte-k .haut { display:flex; flex-wrap:wrap; gap:0.25rem; }
.carte-k .titre { font-size:0.86rem; font-weight:600; line-height:1.35; color:var(--encre); }
.carte-k .titre:hover { color:var(--accent); }
.carte-k .meta { font-size:0.74rem; color:var(--gris); }
.carte-k .deplacer { margin-top:0.25rem; }
.carte-k .deplacer select { font-size:0.74rem; padding:0.22rem 0.35rem; }
.colonne .rien { padding:1.1rem 0; text-align:center; color:var(--gris); font-size:0.8rem; }
/* ---- glisser-déposer kanban : signaux discrets ---- */
.carte-k[draggable="true"] { cursor:grab; }
.carte-k[draggable="true"].carte-porteuse { opacity:0.4; }
.colonne.colonne-cible { outline:2px dashed var(--accent); outline-offset:-2px; }
@media (max-width:900px) { .colonnes { grid-template-columns:repeat(2,minmax(210px,1fr)); } }
@media (max-width:560px) { .colonnes { grid-template-columns:1fr; } }
.colonne .sens { padding:0 0.8rem 0.55rem; font-size:0.72rem; color:var(--gris);
  line-height:1.35; border-bottom:1px solid var(--trait); margin-bottom:0; }

/* ---- planning (Gantt) ---- */
/*
 * ⚠️ LA LARGEUR DU DIAGRAMME SUIT LE NOMBRE DE SEMAINES, et c'est ce qui rend
 * le défilement possible.
 *
 * *Direction, 25.09.2026 : « pour le gantt, j'aimerais pouvoir scroller
 * horizontalement pour me déplacer. Actuellement, ce n'est pas possible. »*
 *
 * Elle avait raison, et la cause n'était pas le conteneur : `.defiler` porte
 * bien `overflow-x:auto` depuis toujours. C'était qu'IL N'Y AVAIT RIEN À FAIRE
 * DÉFILER. Avec un `min-width` fixe de 820 px, une fenêtre de 52 semaines ne
 * débordait pas — elle se COMPRIMAIT, chaque semaine tombant à quinze pixels.
 * Le planning devenait illisible au lieu de devenir long, et `overflow-x`
 * n'avait aucun débordement à gérer.
 *
 * 3,4rem par semaine : de quoi lire un repère hebdomadaire sans qu'il se
 * chevauche avec le suivant. Le `max()` garde le plancher historique pour les
 * fenêtres courtes.
 */
.gantt { min-width:max(820px, calc(20rem + var(--semaines, 10) * 3.4rem));
  font-size:0.84rem;
  --largeur-semaine:calc((100% - 20rem) / var(--semaines, 10)); }
.gantt-entete { display:grid; grid-template-columns:20rem 1fr; align-items:end;
  padding:0.5rem 0.9rem 0.6rem; border-bottom:1px solid var(--trait);
  background:var(--surface-2); position:sticky; top:0; z-index:2; }
.gantt-entete .gantt-piste { height:1.2rem; }
.repere { position:absolute; transform:translateX(-50%); font-family:var(--mono);
  font-size:0.62rem; color:var(--gris); white-space:nowrap; }
.gantt-flux { font-family:var(--mono); font-size:0.62rem; text-transform:uppercase;
  letter-spacing:0.12em; color:var(--gris); padding:1rem 0.9rem 0.3rem;
  position:sticky; left:0; width:max-content; }
/*
 * Le regroupement visuel — un bloc par initiative (ou marque, ou « Maison »).
 *
 * Le liseré gauche coloré porte l'identité du groupe : la couleur est stable
 * pour un même nom, calculée par hash côté contrôleur, avec saturation et
 * luminance fixes pour rester lisible en clair comme en sombre sans
 * concurrencer l'accent magenta. Les libellés y sont indentés d'un cran,
 * l'en-tête reçoit un fond très léger teinté par cette même couleur. On
 * distingue ainsi d'un coup d'œil ce qui va ensemble, même quand deux
 * groupes se suivent dans le même value stream.
 *
 * L'en-tête et le bandeau de flux reçoivent un liseré transparent de même
 * largeur : sans quoi leurs pistes (les repères de dates, la barre du jour)
 * décaleraient de 3 pixels par rapport à celles des lignes.
 */
.gantt-entete, .gantt-flux { border-left:3px solid transparent; }
.gantt-bloc { border-left:3px solid var(--gr, var(--trait)); }
.gantt-bloc + .gantt-bloc { margin-top:0.35rem; }
.gantt-groupe { font-weight:600; font-size:0.88rem; padding:0.4rem 0.9rem 0.35rem;
  display:flex; align-items:baseline; gap:0.6rem;
  position:sticky; left:0; width:max-content; }
.gantt-bloc .gantt-groupe {
  background:color-mix(in srgb, var(--gr, var(--gris)) 9%, transparent);
  border-bottom:1px solid var(--trait-clair); }
.gantt-groupe span { font-family:var(--mono); font-size:0.66rem; color:var(--gris);
  font-weight:400; }
.gantt-ligne { display:grid; grid-template-columns:20rem 1fr; align-items:center;
  padding:0.2rem 0.9rem; border-bottom:1px solid var(--trait-clair);
  /* Opaque, pour que `.gantt-libelle` puisse en hériter et couvrir les barres
     qui passent dessous pendant le défilement horizontal. */
  background:var(--surface); }
.gantt-ligne:hover { background:var(--surface-2); }
/*
 * La colonne des noms ne part pas avec le défilement.
 *
 * Conséquence directe du point ci-dessus : une fois que le diagramme dépasse
 * l'écran, défiler jusqu'à mars sans savoir de quel projet il s'agit ne sert à
 * rien. `sticky` la retient à gauche ; le fond est obligatoire, sans quoi les
 * barres défileraient en transparence par-dessous.
 */
.gantt-libelle { display:flex; align-items:center; gap:0.45rem; padding-right:1rem;
  overflow:hidden; position:sticky; left:0; z-index:1; background:inherit; }
.gantt-bloc .gantt-libelle { padding-left:1.2rem; }
.gantt-libelle a { font-size:0.84rem; color:var(--encre); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.gantt-libelle a:hover { color:var(--accent); }
/*
 * Les bandes de week-end.
 *
 * On ne travaille pas en jours ouvrés — décision de la direction du 31.07.2026 : chez YHB
 * on travaille le samedi et le dimanche, et un `lag` de trois jours posé un
 * vendredi tombe le lundi, pas le mercredi. Les bandes ne changent donc aucun
 * calcul ; elles répondent à un besoin de lecture, savoir où l'on est dans la
 * semaine sans compter les carreaux depuis le repère le plus proche.
 *
 * Un dégradé répété, et non un élément par week-end : la fenêtre monte à 52
 * semaines et il y a une piste par projet — ce serait plus de mille spans sur
 * un planning annuel. Le dégradé s'imprime, suit le défilement horizontal, et
 * ne coûte rien au DOM.
 *
 * La géométrie tient à ce que la fenêtre commence un lundi (`startOfWeek()`
 * côté contrôleur) : les cinq premiers septièmes de chaque semaine sont
 * ouvrés, les deux derniers sont le week-end. C'est la seule hypothèse que
 * font ces bandes — si le début de fenêtre cessait d'être un lundi, elles se
 * décaleraient.
 *
 * Couleur de fond et dégradé tiennent dans une seule déclaration : le dépôt
 * interdit qu'une classe soit définie deux fois au premier niveau, et un
 * second `.gantt-piste` aurait de toute façon écrasé le fond en silence.
 */
.gantt-piste { position:relative; height:1.6rem; border-radius:var(--r);
  background:var(--surface-2)
    repeating-linear-gradient(to right,
      transparent 0,
      transparent calc(var(--largeur-semaine) * 5 / 7),
      var(--trait-clair) calc(var(--largeur-semaine) * 5 / 7),
      var(--trait-clair) var(--largeur-semaine)); }
/*
 * `gantt-barre`, et non `barre`.
 *
 * Le nom entrait en collision avec la barre d'actions des formulaires, définie
 * plus haut en flex. Celle-ci, déclarée après et en position absolue, gagnait :
 * les boutons Enregistrer et Annuler quittaient le pied du formulaire pour
 * flotter au-dessus du fil d'ariane. Aucune erreur, juste deux règles portant
 * le même nom à deux cents lignes d'écart.
 */
.gantt-barre { position:absolute; top:0.3rem; height:1rem; border-radius:2px;
  background:var(--accent); }
.gantt-barre.en_cours { background:var(--accent); }
.gantt-barre.a_faire  { background:var(--ocre); }
.gantt-barre.backlog  { background:var(--gris); opacity:0.55; }
.gantt-barre.fait     { background:var(--vert); }
.gantt-barre.sans-fin { background:repeating-linear-gradient(45deg,
  var(--gris) 0 6px, transparent 6px 12px); opacity:0.6; }
.gantt-barre.en-retard { outline:2px solid var(--rouge); outline-offset:1px; }
.aujourdhui { position:absolute; top:0; bottom:0; width:2px; background:var(--rouge);
  opacity:0.65; }
.date-fin { position:absolute; top:0.32rem; font-family:var(--mono); font-size:0.62rem;
  color:var(--gris); white-space:nowrap; }
.hors-fenetre { position:absolute; left:0.5rem; top:0.35rem; font-size:0.7rem;
  color:var(--gris); font-style:italic; }

/* ------------------------------------------------------------------
   Acquisition.

   Le vocabulaire visuel du module tient en trois idées : un chiffre qu'on
   lit de loin, une puce qui compte, et un manque qui se voit. C'est le
   troisième qui compte le plus — le cockpit actuel affiche une fiche sans
   coordonnées exactement comme une fiche complète.
   ------------------------------------------------------------------ */

.chiffre { font-size: 1.9rem; font-weight: 500; line-height: 1.1; }
.chiffre .sur { font-size: 1rem; font-weight: 400; color: var(--gris); }
.chiffre.alerte { color: var(--rouge); }

.etiquette { font-size: 0.78rem; color: var(--gris); text-transform: none; margin-top: 0.15rem; }
.secondaire { font-size: 0.82rem; color: var(--gris); }

.jauge { height: 0.5rem; background: var(--trait); border-radius: 999px; overflow: hidden; }
.jauge span { display: block; height: 100%; background: var(--accent); }

.titre-groupe {
  font-size: 0.95rem; font-weight: 500; margin: 0 0 0.6rem;
  display: flex; align-items: center; gap: 0.5rem;
}
.titre-groupe .compte {
  font-size: 0.75rem; color: var(--gris); background: var(--surface-2);
  border-radius: 999px; padding: 0.05rem 0.45rem;
}

.puce {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.78rem; padding: 0.15rem 0.5rem; border-radius: 999px;
  border: 1px solid var(--trait); color: inherit; text-decoration: none;
}
.puce span { color: var(--gris); font-size: 0.72rem; }
.puce-active { border-color: var(--accent); background: var(--accent-doux); }
.puce-vide { opacity: 0.45; }
.puce-mini { font-size: 0.72rem; padding: 0.05rem 0.4rem; }
.puce-doute { border-color: var(--ocre); color: var(--ocre); }

.canal {
  display: inline-block; font-size: 0.75rem; padding: 0.05rem 0.4rem;
  border-radius: 4px; background: var(--surface-2); margin-right: 0.25rem;
}
.canal-doute { background: transparent; border: 1px dashed var(--ocre); color: var(--ocre); }
/* L'acquéreur — qui a encaissé pour nous. Distinct à l'œil du moyen de
   paiement, parce que ce sont deux notions et que le prestataire, lui,
   prélève une commission. */
.canal-acquereur { background: transparent; border: 1px solid var(--trait); color: var(--gris); }

/* Un manque n'est pas une erreur : il est signalé, pas alarmant. */
.manque { color: var(--ocre); font-size: 0.85rem; font-style: italic; }

.etat { font-size: 0.8rem; padding: 0.25rem 0.6rem; border-radius: 999px; border: 1px solid var(--trait); }
.etat-aucun { border-color: var(--rouge); color: var(--rouge); }
.etat-indirect { border-color: var(--ocre); color: var(--ocre); }
.etat-direct, .etat-verifie { border-color: var(--vert); color: var(--vert); }

/*
 * Une ligne est un texte qui s'adapte et des actions qui ne bougent pas. Sans
 * la contrainte, les boutons passaient à la ligne dès que le libellé
 * s'allongeait, et les lignes du fil n'avaient plus la même hauteur.
 */
.ligne-canal {
  display: flex; gap: 0.6rem; align-items: baseline; flex-wrap: wrap;
  padding: 0.4rem 0; border-bottom: 1px solid var(--trait);
}
.ligne-canal > form,
.ligne-canal > .actions { flex: 0 0 auto; }
.ligne-actions { margin-left: auto; display: flex; gap: 0.3rem; flex: 0 0 auto; }

/*
 * L'aperçu d'un logo, sur un damier.
 *
 * Un SVG blanc sur un fond blanc est invisible, et on ne saurait pas s'il est
 * cassé ou simplement clair. Le damier est un dégradé, pas une image : rien à
 * charger, et il reste juste dans les deux thèmes.
 *
 * Le fond suit le thème déclaré du fichier — un logo « sur fond sombre » se
 * regarde sur du sombre, sinon on juge un rendu qu'on ne verra jamais.
 */
.apercu-logo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 8rem; height: 3rem; padding: 0.3rem; border-radius: 4px;
  border: 1px solid var(--trait); flex: 0 0 auto;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, rgba(0,0,0,0.06) 25%, transparent 25%),
    linear-gradient(-45deg, rgba(0,0,0,0.06) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, rgba(0,0,0,0.06) 75%),
    linear-gradient(-45deg, transparent 75%, rgba(0,0,0,0.06) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}
.apercu-logo[data-theme="dark"] { background-color: #1c1c1e; }
.apercu-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }

/* Un couple « ce dont on parle » + « son étiquette » ne se coupe pas en deux. */
.paire-inseparable { display: inline-flex; align-items: baseline; gap: 0.35rem;
  white-space: nowrap; }
.paire-inseparable a { white-space: normal; }
.ligne-canal:last-child { border-bottom: 0; }

/* ── Réécrire un point d'ordre du jour ───────────────────────────────────
   *Direction, 08.10.2026 : « on doit pouvoir éditer les items de l'ordre du
   jour, pas le cas aujourd'hui ».*

   Un `<details>` dans la ligne, et rien de plus : zéro JavaScript (TR-23), le
   clavier marche, et ça s'imprime déplié.

   ⚠️ AUCUN `position: absolute` ICI, ET C'EST VOULU. `.ligne-canal` porte déjà
   `flex-wrap: wrap` : il suffit de dire que le panneau ouvert occupe toute la
   rangée, et il descend de lui-même sous le point. Un panneau flottant aurait
   réclamé de lever `overflow-x: auto` du `.cadre` sous 820 px — c'est le piège
   du menu de profil, payé le 07.10 : un parent qui borne, et le panneau coupé.

   Le ✎ passe sur sa propre ligne quand il est ouvert. C'est le prix de rester
   dans le flux, et ça dit clairement lequel des points on est en train de
   réécrire. */
.point-editer { flex: 0 0 auto; }
.point-editer > summary { cursor: pointer; list-style: none; }
.point-editer > summary::-webkit-details-marker { display: none; }
.point-editer[open] { flex: 1 0 100%; }
.point-editer[open] > summary { margin-bottom: 0.2rem; }
.point-editer > form label { display: block; font-size: 0.72rem; margin-bottom: 0.15rem; }
.point-editer > form input[type="text"] { width: 100%; }

/* ── Rattacher un participant à une fiche du répertoire ──────────────────
   *Direction, 09.10.2026 : « est-ce que, pour les personnes que j'ai
   rencontrées en événement, je peux les matcher, dire : telles personnes, je
   les ai rencontrées à tel événement ? »*

   Même mécanique que `.point-editer` au-dessus, et pour la même raison : un
   `<details>` dans la ligne, zéro JavaScript (TR-23), le clavier marche, ça
   s'imprime déplié, et le panneau ouvert prend toute la rangée grâce au
   `flex-wrap: wrap` que `.ligne-canal` porte déjà.

   ⚠️ UN BLOC À PART, PAS UN SÉLECTEUR AJOUTÉ À `.point-editer`. Les deux
   panneaux n'ont pas le même contenu — un champ texte là-bas, un `<select>` de
   195 tiers ici — et surtout : toucher aux règles de l'ordre du jour pour
   habiller un écran d'évènements casserait l'un en réglant l'autre, sans
   qu'aucun test ne le dise. Une règle CSS muette ne se voit pas. */
.rattacher-tiers { flex: 0 0 auto; }
.rattacher-tiers > summary { cursor: pointer; list-style: none; }
.rattacher-tiers > summary::-webkit-details-marker { display: none; }
.rattacher-tiers[open] > summary { margin-bottom: 0.3rem; }
.rattacher-tiers > form label {
  display: block; font-size: 0.72rem; margin-bottom: 0.15rem;
}
.rattacher-tiers > form p { margin: 0.25rem 0 0.4rem; }

/* ⚠️ `min-width: 0` N'EST PAS DÉCORATIF, ET LE `<select>` EST EXACTEMENT LE
   CAS DU 06.10.2026 : « un select qui ne se coupe pas » élargissait la page de
   390 px à 733. Un élément de flex garde `min-width: auto` par défaut, donc sa
   largeur min-content — ici le plus long des 195 libellés du répertoire, nom +
   statut. Sans ces deux lignes, le panneau ouvert pousse `.ligne-canal`, puis
   la colonne de `.deux-colonnes`, puis la page. Le borner ici est le seul
   endroit où ça se décide ; une `@media` n'y pourrait rien. */
.rattacher-tiers[open] { flex: 1 0 100%; min-width: 0; }
.rattacher-tiers > form select { width: 100%; max-width: 100%; min-width: 0; }

.deux-colonnes { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
@media (max-width: 900px) { .deux-colonnes { grid-template-columns: 1fr; } }

/* ── Les demi-colonnes ───────────────────────────────────────────────────
   *Direction, 24.09.2026 : « tu peux aussi utiliser des demi-colonnes. Là, tu
   mets tout l'un sous l'autre. »*

   Une classe UNIQUE pour toutes les fiches, plutôt qu'une grille par écran :
   c'est la condition pour que la densité soit la même partout. Les blocs se
   rangent d'eux-mêmes tant qu'ils tiennent en 22 rem, et repassent en pile
   sinon — sans qu'aucun écran ait à décider.

   ⚠️ `align-items: start` EST INDISPENSABLE : sans lui, deux cadres voisins
   s'étirent à la hauteur du plus grand, et un bloc de trois lignes se
   retrouve avec vingt centimètres de vide sous son texte. */
.demi-colonnes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  gap: .8rem; align-items: start; margin-bottom: .8rem;
}
/* Ce qui ne se coupe pas en deux : un tableau large, un journal, une frise. */
.demi-colonnes > .pleine-largeur { grid-column: 1 / -1; }

/* ── Pourquoi cet écran vous montre tout ─────────────────────────────────
   *Direction, 09.10.2026 : « ça reste ainsi, mais l'écran le DIT. »*

   ⚠️ GRIS, ET PAS ROUGE. Ce qu'on explique ici est NORMAL — l'accréditation
   porte sur le groupe, donc l'écran montre tout. Un encadré coloré ferait
   croire à une anomalie, et au bout de deux jours plus personne ne le lirait.
   C'est l'absence de cette phrase qui a fait poser trois fois la même question
   dans la même journée.

   Le filet à gauche suffit à la détacher du contenu sans l'en séparer : elle
   parle de ce qui suit, elle n'est pas un bloc à part. */
.portee-du-regard {
  margin: 0 0 .8rem; padding: .45rem 0 .45rem .7rem;
  border-left: 2px solid var(--trait);
  font-size: .82rem; line-height: 1.45; color: var(--gris);
}
.portee-du-regard strong { color: var(--encre); font-weight: 600; }

/* La fenêtre d'une peau de saison, sous son nom. Discrète : c'est une
   précision, pas une étiquette — on choisit « Halloween », on vérifie « du 24
   octobre au 2 novembre ». */
.peau-saison { display: block; font-family: var(--mono); font-size: .62rem;
  letter-spacing: .06em; color: var(--gris); margin-top: .15rem; }

.paires { display: grid; grid-template-columns: auto 1fr; gap: 0.3rem 1rem; margin: 0; }
.paires dt { color: var(--gris); font-size: 0.82rem; }
.paires dd { margin: 0; }

/* ── Le texte d'origine ──────────────────────────────────────────────────
   *Direction, 09.10.2026 : « en bas, le texte d'origine, c'est un tout petit
   peu mal fichu. Ça prend toute la largeur de la colonne. »*

   C'est de la prose — une note de recherche, un courriel repris — et elle était
   rendue comme du code : en chasse fixe, sur toute la largeur. Deux défauts
   d'un coup. Une ligne de 140 caractères se lit mal parce que l'œil perd son
   retour à la ligne, et la chasse fixe annonce « ceci est du code » à propos
   d'une phrase française.

   ⚠️ `white-space: pre-wrap` RESTE : la matière d'origine porte ses propres
   retours à la ligne, et les écraser ferait d'un courriel un pavé. Ce qui
   change, c'est la mesure et la police — pas le respect de la source. */
.source {
  white-space: pre-wrap; font-family: var(--sans); font-size: 0.85rem;
  line-height: 1.55; max-width: 68ch; background: var(--surface-2);
  padding: 0.8rem 1rem; border-radius: 6px; border-left: 3px solid var(--trait);
  max-height: 24rem; overflow: auto; margin: 0;
}

/* ── La carte d'identité d'un tiers ──────────────────────────────────────
   *Direction, 09.10.2026 : « j'aimerais vraiment plus un truc qui ressemble à
   une fiche de contact […] j'aimerais avoir les infos, l'adresse, en haut,
   toutes les infos. Où est-ce que je l'ai rencontré ? »*

   Trois colonnes de lecture, en tête de fiche : comment le joindre, où il est,
   où on s'est croisés. Elles se rangent en pile sous 18 rem — c'est la même
   mécanique que `.demi-colonnes`, avec un seuil plus bas parce qu'une
   coordonnée tient dans moins de place qu'un tableau.

   ⚠️ `align-items: start`, pour la même raison qu'aux demi-colonnes : sans
   lui, la colonne « Où » d'un tiers sans adresse s'étire à la hauteur de la
   liste des canaux. */
.carte-identite { margin-bottom: 1.25rem; }
.ci-colonnes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 0.8rem 1.6rem; align-items: start;
}
.ci-ligne {
  margin: 0 0 0.35rem; font-size: 0.9rem; line-height: 1.45;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.5rem;
}
/* L'intitulé du champ, en chasse fixe et discret : on lit la valeur, pas
   l'étiquette. Largeur fixée pour que les valeurs s'alignent d'une ligne à
   l'autre sans tableau. */
.ci-quoi {
  font-family: var(--mono); font-size: 0.64rem; text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--gris); flex: 0 0 5.5rem;
}
.ci-ligne .secondaire { font-size: 0.74rem; }

/* ---- calendrier ----
   Sept colonnes, en CSS pur. Aucune bibliothèque, aucun JavaScript : ça
   s'imprime, ça marche au clavier, et ça ne casse pas au prochain changement
   de version. */
.calendrier { display:grid; grid-template-columns:repeat(7, 1fr); gap:1px;
  background:var(--trait); border:1px solid var(--trait); }
.cal-entete { background:var(--surface-2); font-family:var(--mono); font-size:0.58rem;
  text-transform:uppercase; letter-spacing:0.1em; color:var(--gris); padding:0.45rem 0.5rem; }
.cal-case { background:var(--surface); min-height:5.4rem; padding:0.35rem 0.4rem;
  display:flex; flex-direction:column; gap:0.2rem; }
.cal-hors { background:var(--surface-2); opacity:0.55; }
.cal-aujourdhui { box-shadow:inset 0 0 0 2px var(--accent); }
.cal-jour { font-size:0.72rem; color:var(--gris); }
.cal-evenement { display:block; font-size:0.7rem; line-height:1.25; padding:0.15rem 0.3rem;
  border-radius:3px; background:var(--surface-2); border-left:2px solid var(--gris);
  text-decoration:none; color:inherit; }
.cal-evenement:hover { background:var(--accent-doux); text-decoration:none; }
.cal-a { border-left-color:var(--vert); }
.cal-b { border-left-color:var(--accent); }
.cal-c { border-left-color:var(--gris); }

@media (max-width: 820px) {
  .calendrier { grid-template-columns:repeat(2, 1fr); }
  .cal-entete { display:none; }
  .cal-case { min-height:3.6rem; }
}

/* La matrice de fit : deux niveaux seulement, chaud et fort. Trois auraient
   demandé une légende ; deux se lisent d'un coup d'œil. */
.fit-chaud { background: var(--accent-doux); font-weight: 500; }
.fit-fort { background: var(--vert-doux); font-weight: 500; }

/* ---- le rail dépliant ----
   Un <details> natif : clavier, impression, accessibilité, tout est déjà là.
   Le seul JavaScript retient quel groupe était ouvert. */
/*
 * Les liens d'un groupe vivent dans leur propre conteneur.
 *
 * Ils étaient les enfants directs d'un <details>, et se retrouvaient à couler
 * en ligne : « Fil d'action » et « Répertoire » se partageaient une ligne.
 * Mettre le <details> lui-même en flex marchait sur le papier mais reste
 * fragile — un <details> n'est pas un conteneur ordinaire, et son contenu
 * n'est pas dans un emplacement stylable de façon fiable d'un navigateur à
 * l'autre. Un div à l'intérieur ne dépend d'aucune subtilité.
 */
.rail-pli { border: 0; }
.rail-liens { display: flex; flex-direction: column; gap: 0.1rem; }
.rail-pli > summary {
  cursor: pointer; list-style: none; user-select: none;
  display: flex; align-items: center; justify-content: space-between;
  border-radius: var(--r);
}
.rail-pli > summary::-webkit-details-marker { display: none; }
.rail-pli > summary:hover { opacity: 0.75; }
.rail-pli > summary::after {
  content: "›"; font-size: 0.9rem; opacity: 0.5;
  transform: rotate(90deg); transition: transform 0.15s ease;
}
.rail-pli[open] > summary::after { transform: rotate(-90deg); }
/* Un groupe replié qui contient la page courante se signale quand même.
   Par la pastille et l'opacité, jamais par une couleur : `--sur-accent` est
   blanc, ce qui rendait le libellé illisible depuis que le rail est clair. */
.rail-pli:not([open]) > summary:has(+ .rail-liens a.actif),
.rail-pli:not([open]):has(a.actif) > summary { opacity: 1; color: var(--accent); }
.rail-pli:not([open]):has(a.actif) > summary::before {
  content: "•"; margin-right: 0.35rem; color: var(--accent);
}

/* Le pied du rail : le thème et la déconnexion sur une ligne. */
.rail .bas-actions { display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem; flex-wrap: wrap; }
/* La bascule de thème : un bouton rond, comme sur le site. */
.bascule-theme { width: 2rem; height: 2rem; border-radius: 50%; padding: 0;
  border: 1px solid var(--roche-trait); background: none; color: var(--roche-encre);
  cursor: pointer; opacity: 0.6; display: flex; align-items: center;
  justify-content: center; flex: 0 0 auto; }
.bascule-theme svg { width: 1rem; height: 1rem; }
.bascule-theme:hover { opacity: 1; border-color: var(--accent); color: var(--accent); }
.bascule-theme:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- le cockpit ----
   Un lanceur. Les modules à plat, chacun avec ses écrans — là où le rail se
   replie, le cockpit dépose tout et laisse choisir d'un coup d'œil. */
.modules { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1rem; }
.module { border: 1px solid var(--trait); border-radius: 12px; background: var(--surface);
  padding: 1.15rem 1.25rem; }
.module h2 { font-size: 1.05rem; font-weight: 600; margin: 0 0 0.3rem; }
.module > .secondaire { margin: 0 0 0.9rem; }
.module-liens { display: flex; flex-direction: column; gap: 0.1rem; }
.module-liens a { display: flex; align-items: center; gap: 0.6rem; padding: 0.42rem 0.55rem;
  border-radius: 8px; font-size: 0.92rem; font-weight: 500; color: inherit; }
.module-liens a .ico { width: 1rem; height: 1rem; flex: 0 0 auto; opacity: 0.5; }
.module-liens a:hover { background: var(--accent-doux); text-decoration: none; }
.module-liens a:hover .ico { opacity: 1; color: var(--accent); }

/* Les poignées du Gantt. Trois zones : les deux bords changent une date, le
   milieu décale l'ensemble en gardant la durée. */
.gantt-barre[data-projet] { cursor: grab; }
.gantt-barre[data-projet]:hover { filter: brightness(1.08); }
.gantt-barre-deplacee { cursor: grabbing; outline: 2px solid var(--encre);
  outline-offset: 1px; z-index: 2; }
/* ⚠️ UNE SEULE DÉCLARATION, et c'est `NavigationEtPeauTest` qui l'exige —
   « aucune classe CSS n'est définie deux fois ». J'en avais ajouté une seconde
   plus bas le 20.10 pour y poser la barrette visible : deux blocs portant le
   même sélecteur à la racine, dont le second gagnait en silence sur tout ce
   que le premier ne redit pas. Le garde-fou a rougi le soir même.

   La barrette qui rend la poignée visible est dans `::before`, juste en
   dessous. *Direction : « il manque les poignées pour pouvoir changer
   uniquement la longueur. »* Elles existaient — sept pixels et un curseur,
   sans un trait pour le dire. */
.poignee { position: absolute; top: 0; bottom: 0; width: 7px; cursor: ew-resize;
  display: flex; align-items: center; justify-content: center; }
.poignee::before { content: ''; width: 2px; height: 55%; border-radius: 1px;
  background: var(--sur-accent); opacity: .5; transition: opacity .12s; }
.gantt-barre:hover .poignee::before { opacity: .95; }
.poignee-debut { left: -3px; }
.poignee-fin { right: -3px; }
.gantt-barre[data-projet]:focus-visible { outline: 2px solid var(--accent);
  outline-offset: 2px; }

/* Les interdépendances entre projets.

   Pas de flèches tracées entre les barres : deux lignes liées peuvent être
   séparées par plusieurs blocs de hauteur variable, et joindre deux points
   demanderait de mesurer la mise en page en JavaScript à chaque
   redimensionnement. On marque les extrémités et on liste les liens en clair
   sous le diagramme — le trait manque, l'information reste, et elle survit à
   l'impression comme au défilement horizontal de la piste.

   La flèche du marqueur suit le temps, qui va de gauche à droite ici :
   « ←2 » = deux projets en amont, « →1 » = un projet attend celui-ci. */
.lien-dep { display: inline-flex; gap: 0.25rem; margin-left: 0.35rem; flex: none;
  font-family: var(--mono); font-size: 0.62rem; color: var(--gris);
  text-decoration: none; white-space: nowrap; }
.lien-dep span { background: var(--surface-2); border-radius: 2px;
  padding: 0.05rem 0.25rem; }
.lien-dep:hover { text-decoration: none; color: var(--encre); }
.lien-dep-violee { color: var(--ocre); }
.lien-dep-violee span { background: var(--ocre-doux); }

/* Le successeur démarre plus tôt que son lien ne l'autorise. Pointillé, pour ne
   pas se confondre avec le trait plein de « en retard » : l'un dit qu'une
   échéance est passée, l'autre qu'une contrainte est contredite. Rien n'est
   recalculé — le signalement *est* l'information utile. */
.gantt-barre.dep-violee { outline: 2px dashed var(--ocre); outline-offset: 1px; }

/* Une ligne de tableau dont le nom est cliquable doit le montrer avant qu'on
   la survole : sinon on cherche le bouton qu'on a retiré. */
tbody tr:hover { cursor: default; }
tbody td a:not(.bouton):not(.puce) { text-decoration: none; }
tbody tr:hover td:first-child a:not(.bouton) { text-decoration: underline; }

/* Un repli dans le contenu — même mécanique que le rail, même raison : ce qui
   est long se demande, il ne s'impose pas. */
.repli { margin-top: 0.9rem; }
.repli > summary { cursor: pointer; list-style: none; user-select: none;
  display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0;
  font-size: 0.88rem; font-weight: 500; border-top: 1px solid var(--trait); }
.repli > summary::-webkit-details-marker { display: none; }
.repli > summary::before { content: "›"; opacity: 0.5;
  transition: transform 0.15s ease; display: inline-block; }
.repli[open] > summary::before { transform: rotate(90deg); }
.repli > summary:hover { color: var(--accent); }

/* Le graphe du réseau. */
.graphe { width: 100%; height: auto; display: block; background: var(--surface); }
.graphe .arc { stroke: var(--trait); stroke-width: 1; }
.graphe .arc-relation { stroke: var(--gris); stroke-width: 1.2; }
.graphe .arc-appartenance { stroke: var(--trait); stroke-dasharray: 3 3; }
.graphe .noeud text { font-size: 10px; fill: var(--encre); text-anchor: middle;
  font-family: var(--sans); pointer-events: none; }
.graphe .noeud-organisation rect { fill: var(--ocre); stroke: var(--ocre); }
.graphe .noeud-organisation text { fill: var(--gris); font-weight: 500; }
.graphe .noeud-contact circle { fill: var(--gris); stroke: var(--surface);
  stroke-width: 2; transition: fill 0.12s; }
.graphe a:hover .noeud-contact circle { fill: var(--accent); r: 7; }
.graphe .seg-a circle { fill: var(--vert); }
.graphe .seg-b circle { fill: var(--accent); }
.graphe .seg-c circle { fill: var(--ocre); }
.graphe .seg-p circle { fill: var(--roche); }
.graphe .seg-e circle { fill: var(--accent-doux); stroke: var(--accent); }

/* ------------------------------------------------------------------
   Cockpit — vocabulaire visuel du cockpit prototype.

   Trois idées : une étiquette technique (mono, capitales, tracking large)
   qui nomme une section ; des tuiles KPI qui donnent un chiffre lisible de
   loin ; et des callouts colorés à border-left qui hiérarchisent sans
   agresser. Rien d'ornemental — chaque classe se justifie par un usage.
   ------------------------------------------------------------------ */

/* Une étiquette technique : « OKR EN COURS », « SCORECARD » — le nom
   d'une section, écrit dans le grain typographique de la marque. */
/* ── Les en-têtes de section d'un formulaire tiennent sur leur ligne.
 *
 * *Direction, 06.10.2026 : « ça prend beaucoup trop de place. Optimise
 * vraiment le design graphique de tout ça. »*
 *
 * 1.6rem au-dessus et 0.9rem en dessous, plus un trait : chaque intertitre
 * coûtait près de quatre centimètres sur un formulaire qui en compte trois.
 * Le trait suffit à séparer ; l'espace qui l'entoure était du décor. */
.etiquette-tech {
  font-family: var(--mono); font-size: 0.66rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--gris);
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0 0 0.3rem; margin: 0.9rem 0 0.5rem;
  border-bottom: 1px solid var(--trait);
}
.etiquette-tech:first-child { margin-top: 0; }
.etiquette-tech .compte {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.66rem; letter-spacing: 0.08em; padding: 0.1rem 0.4rem;
  border-radius: 999px; background: var(--surface-2); color: var(--gris);
}
.etiquette-tech .badge {
  margin-left: auto; font-family: var(--mono); font-size: 0.62rem;
  padding: 0.15rem 0.5rem; border-radius: 999px; letter-spacing: 0.08em;
  background: var(--surface-2); color: var(--gris);
}
.etiquette-tech .badge-vert { background: var(--vert-doux); color: var(--vert); }
.etiquette-tech .badge-ocre { background: var(--ocre-doux); color: var(--ocre); }
.etiquette-tech .badge-rouge { background: var(--rouge-doux); color: var(--rouge); }

/* Une rangée de tuiles KPI. Le chiffre au-dessus, l'étiquette technique
   en-dessous — c'est l'inverse de la hiérarchie du texte, mais c'est ce
   qu'on lit d'abord dans un tableau de bord. */
.kpi { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 0.7rem; margin-bottom: 1.2rem; }
.kpi .tuile-kpi { background: var(--surface); border: 1px solid var(--trait);
  border-radius: 12px; padding: 0.9rem 1rem; display: flex; flex-direction: column;
  gap: 0.2rem; }
.kpi .tuile-kpi .v { font-size: 1.6rem; font-weight: 700; letter-spacing: -0.02em;
  line-height: 1.05; font-variant-numeric: tabular-nums; }
.kpi .tuile-kpi .k { font-family: var(--mono); font-size: 0.6rem;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--gris); }
.kpi .tuile-kpi .sub { font-size: 0.76rem; color: var(--gris); }
.kpi .tuile-kpi.accent .v { color: var(--accent); }
.kpi .tuile-kpi.vert .v { color: var(--vert); }
.kpi .tuile-kpi.ocre .v { color: var(--ocre); }
.kpi .tuile-kpi.rouge .v { color: var(--rouge); }

/* Un cartel — carte plus dense qu'un cadre, sans compte-rendu.
   Utilisé pour poser une raison d'être, un objectif dans la liste, une
   métrique. Bord fin, radius 12px, pas d'ornement. */
.cartel { background: var(--surface); border: 1px solid var(--trait);
  border-radius: 12px; padding: 0.95rem 1.05rem; margin-bottom: 0.7rem; }
.cartel-titre { display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 0.55rem; margin-bottom: 0.4rem; }
.cartel-titre strong { font-size: 1rem; font-weight: 600; }
.cartel-corps { font-size: 0.92rem; line-height: 1.5; }
.cartel-meta { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem;
  font-size: 0.78rem; color: var(--gris); }
.cartel-actions { display: flex; flex-wrap: wrap; gap: 0.35rem;
  margin-top: 0.55rem; }

/* Un callout : encadré discret, border-left coloré. Sert à isoler un
   passage important (mission, contrainte, alerte) sans crier. */
.callout { border-left: 4px solid var(--trait); background: var(--surface-2);
  padding: 0.7rem 0.9rem; border-radius: 0 8px 8px 0; margin: 0.5rem 0;
  font-size: 0.92rem; line-height: 1.5; }
.callout .callout-h { font-family: var(--mono); font-size: 0.6rem;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--gris);
  margin-bottom: 0.25rem; }
.callout-accent { border-left-color: var(--accent); }
.callout-vert { border-left-color: var(--vert); }
.callout-ocre { border-left-color: var(--ocre); }
.callout-rouge { border-left-color: var(--rouge); }

/* Bandeau de tête d'écran, style cockpit : le titre, l'accroche, et à
   droite une pile d'actions. C'est l'.entete déjà en place, avec une
   version plus riche pour les écrans à CTA. */
.entete-cockpit { display: flex; align-items: flex-start;
  justify-content: space-between; gap: 1rem; margin-bottom: 1.4rem;
  flex-wrap: wrap; }
.entete-cockpit .actions { display: flex; flex-wrap: wrap; gap: 0.4rem; }

/* Une pastille de catégorie : petit tag mono, contour, couleur douce.
   Rangé sous le titre d'une section catégorielle. */
.pastille-cat { display: inline-flex; align-items: center; gap: 0.3rem;
  font-family: var(--mono); font-size: 0.62rem; text-transform: uppercase;
  letter-spacing: 0.11em; padding: 0.18rem 0.5rem; border-radius: 999px;
  background: var(--accent-doux); color: var(--accent-encre, var(--accent));
  border: 1px solid transparent; }
.pastille-cat.neutre { background: var(--surface-2); color: var(--gris); }

/* Une jauge un peu plus élégante, avec le pourcentage à droite,
   utilisée dans la liste des OKR et dans la fiche. */
.jauge-riche { display: flex; align-items: center; gap: 0.5rem; }
.jauge-riche .barre { flex: 1 1 6rem; height: 6px; background: var(--trait);
  border-radius: 999px; overflow: hidden; min-width: 5rem; }
.jauge-riche .barre span { display: block; height: 100%;
  background: var(--degrade, var(--accent)); }
.jauge-riche .val { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.85rem; font-weight: 600; color: var(--encre); }

/* Une puce de statut, dérivée des .etat mais adaptée aux OKR / métriques :
   un fond doux + un point coloré. */
.puce-etat { display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.15rem 0.55rem; border-radius: 999px; font-size: 0.75rem;
  background: var(--surface-2); color: var(--gris); }
.puce-etat::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--gris); }
.puce-etat-vert { background: var(--vert-doux); color: var(--vert); }
.puce-etat-vert::before { background: var(--vert); }
.puce-etat-ocre { background: var(--ocre-doux); color: var(--ocre); }
.puce-etat-ocre::before { background: var(--ocre); }
.puce-etat-rouge { background: var(--rouge-doux); color: var(--rouge); }
.puce-etat-rouge::before { background: var(--rouge); }
.puce-etat-accent { background: var(--accent-doux); color: var(--accent-encre, var(--accent)); }
.puce-etat-accent::before { background: var(--accent); }

/* Formulaire compact utilisé en pied de fiche pour ajouter un KR ou
   consigner une mesure. Aligné en ligne, prend toute la largeur. */
.forme-ligne { display: flex; flex-wrap: wrap; gap: 0.4rem;
  align-items: flex-end; margin-top: 0.8rem; }
.forme-ligne .champ { flex: 1 1 8rem; min-width: 6rem; margin: 0; gap: 0.2rem; }
.forme-ligne .champ.libre { flex: 2 1 12rem; }
.forme-ligne button { flex: 0 0 auto; }
.forme-ligne label { font-family: var(--mono); font-size: 0.58rem;
  text-transform: uppercase; letter-spacing: 0.1em; color: var(--gris);
  font-weight: 500; }

/* ------------------------------------------------------------------
   Journal.

   Un tableau très dense : une ligne par action, quatre colonnes fixes
   (heure, contact, canal, résumé), l'en-tête du jour collée au haut
   du défilement. Quand un contact a plusieurs interactions dans une
   même journée, elles sont regroupées sous son nom — deux appels et
   un message ne comptent pas comme trois contacts. Le résumé est
   tronqué ; le texte entier reste dans un `title` que le survol
   révèle sans clic.

   Le conteneur ne peut pas être un `.cadre` : son `overflow:hidden`
   priverait `position:sticky` de sa boîte de défilement. On lui donne
   le même vernis (bordure, radius, fond, rembourrage) sans le coupage.
   ------------------------------------------------------------------ */

.journal-histoire { border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface); padding: 0.65rem 1.15rem 1rem; }
.journal-histoire > .titre-groupe { margin: 0.4rem 0 0.5rem; }

.journal-jour + .journal-jour { margin-top: 0.5rem; }

/* L'en-tête du jour reste attachée en haut de l'écran. Elle prend le
   fond de la carte pour couvrir les lignes qui glissent dessous, et
   passe la largeur des marges internes pour manger toute la carte. */
.journal-entete-jour {
  position: sticky; top: 0; z-index: 2;
  margin: 0 -1.15rem;
  padding: 0.45rem 1.15rem 0.3rem;
  background: var(--surface);
  border-bottom: 1px solid var(--trait);
  font-family: var(--mono); font-size: 0.66rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--gris);
  display: flex; gap: 0.55rem; align-items: baseline;
}
.journal-entete-jour .compte {
  font-variant-numeric: tabular-nums; opacity: 0.75;
  background: var(--surface-2); color: var(--gris);
  border-radius: 999px; padding: 0.05rem 0.45rem;
  font-size: 0.62rem; letter-spacing: 0.06em;
}

/* Une entrée : une ligne, quatre colonnes, dépassement tronqué. */
.journal-entree {
  display: grid;
  grid-template-columns: 3rem minmax(9rem, 14rem) 5.5rem minmax(0, 1fr);
  column-gap: 0.7rem; align-items: baseline;
  padding: 0.22rem 0;
  border-bottom: 1px solid var(--trait-clair);
  font-size: 0.86rem; line-height: 1.35;
}
.journal-jour > .journal-entree:last-child,
.journal-groupe > .journal-entree:last-child { border-bottom: 0; }

.journal-heure { font-family: var(--mono); font-size: 0.76rem;
  color: var(--gris); font-variant-numeric: tabular-nums; }

.journal-contact-nom { color: var(--encre); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.journal-contact-nom:hover { color: var(--accent); text-decoration: none; }

.journal-note { overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--encre); min-width: 0; }

/* Regroupement contact-du-jour : bandeau du nom, lignes indentées, liseré. */
.journal-groupe { margin: 0.15rem 0 0.3rem;
  border-left: 2px solid var(--trait); padding: 0 0 0 0.55rem; }
.journal-groupe-tete { display: inline-flex; gap: 0.45rem; align-items: baseline;
  padding: 0.3rem 0 0.15rem; font-weight: 600; font-size: 0.9rem;
  color: var(--encre); text-decoration: none; }
.journal-groupe-tete:hover { color: var(--accent); text-decoration: none; }
.journal-groupe-tete .compte { font-family: var(--mono);
  font-size: 0.62rem; letter-spacing: 0.06em;
  padding: 0.05rem 0.4rem; border-radius: 999px;
  background: var(--surface-2); color: var(--gris);
  font-variant-numeric: tabular-nums; }
.journal-entree-groupee { grid-template-columns: 3rem 5.5rem minmax(0, 1fr); }

/* La version condensée du `.ligne-canal` pour « ce qu'il reste à faire ». */
.ligne-canal.ligne-serree { padding: 0.22rem 0; }

@media (max-width: 720px) {
  .journal-entree { grid-template-columns: 3rem 1fr;
    row-gap: 0.05rem; padding: 0.35rem 0; }
  .journal-entree > .canal,
  .journal-entree > .journal-note { grid-column: 2; }
  .journal-entree-groupee { grid-template-columns: 3rem 1fr; }
}


/* ─── arborescence : reprise du prototype cockpit gouvernance ───────────
   Racine en gradient (la maison), value streams en cadres pliables,
   marques et initiatives en enfants avec un liseré latéral coloré selon
   leur nature, projets encore indentés dessous. */

.arbo-racine {
  background: linear-gradient(112deg, #3A0E63 0%, #5B1A8C 28%, #E6008A 100%);
  color: #fff; border-radius: 12px;
  padding: 0.9rem 1.2rem; margin-bottom: 0.9rem;
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 0.7rem;
}
.arbo-racine b { font-size: 1rem; font-weight: 700; letter-spacing: -0.01em; }
.arbo-racine small { display: block; font-size: 0.78rem;
  color: rgba(255,255,255,.85); margin-top: 0.15rem; }
.arbo-racine .compteurs { display: flex; gap: 1.2rem; }
.arbo-racine .compteurs div { text-align: center; }
.arbo-racine .compteurs b { display: block; font-size: 1.35rem; line-height: 1; }
.arbo-racine .compteurs span { font-family: var(--mono); font-size: 0.6rem;
  text-transform: uppercase; letter-spacing: 0.09em;
  color: rgba(255,255,255,.8); }

/* Un value stream : cadre pliable, en-tête cliquable. */
.arbo-vs { border: 1px solid var(--trait); border-radius: 11px;
  background: var(--surface); margin-bottom: 0.7rem; overflow: hidden; }
.arbo-vs > summary { list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.7rem 0.95rem; background: var(--surface-2);
  user-select: none; }
.arbo-vs > summary::-webkit-details-marker { display: none; }
.arbo-vs > summary::before { content: '▸'; color: var(--gris);
  font-size: 0.65rem; transition: transform 0.15s; width: 0.7rem; }
.arbo-vs[open] > summary::before { transform: rotate(90deg); }
.arbo-vs > summary b { font-size: 0.92rem; font-weight: 650; }
.arbo-vs > summary .droite { margin-left: auto; display: inline-flex;
  align-items: center; gap: 0.5rem; font-family: var(--mono);
  font-size: 0.68rem; color: var(--gris); }
.arbo-vs .arbo-corps { padding: 0.5rem 0.7rem; }

/* Un regroupement — marque OU initiative OU maison — sous un value stream.
   Liseré coloré à gauche pour lire la nature d'un coup d'œil. */
.arbo-noeud { border-left: 3px solid var(--gris);
  padding: 0.5rem 0.7rem 0.5rem 0.85rem; margin: 0.35rem 0;
  border-radius: 0 8px 8px 0; background: var(--surface); }
.arbo-noeud.arbo-marque { border-left-color: var(--violet, #5B1A8C); }
.arbo-noeud.arbo-initiative { border-left-color: var(--accent); }
.arbo-noeud.arbo-maison { border-left-color: var(--gris); }
.arbo-noeud .arbo-noeud-tete { display: flex; align-items: baseline;
  flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.35rem; }
.arbo-noeud .arbo-noeud-tete strong { font-size: 0.92rem; font-weight: 600; }
.arbo-noeud .arbo-noeud-tete .type { font-family: var(--mono);
  font-size: 0.58rem; text-transform: uppercase; letter-spacing: 0.11em;
  color: var(--gris); padding: 0.1rem 0.4rem; background: var(--surface-2);
  border-radius: 999px; }
.arbo-noeud .compte-projets { margin-left: auto; font-family: var(--mono);
  font-size: 0.7rem; color: var(--gris); }

/* ─── organigramme : un vrai arbre, des cases, des traits ───────────────
   *Direction, 23.10.2026 : « je veux un vrai organigramme avec des cases,
   une case pour chacune des marques, et rattaché à chacune des marques. »*

   Trois niveaux, et ce qui les relie SE VOIT : la racine, les entités
   légales, les marques. Deux écrans ont précédé celui-ci, l'un et l'autre
   des listes indentées ; aucune ne se lisait comme un organigramme, parce
   qu'un trait qu'on ne voit pas n'est pas un rattachement.

   ⚠️ NE PAS MÉLANGER AVEC LES CLASSES `arbo-*`. Elles appartiennent au
   cockpit portefeuille et rendent une liste indentée, pas un arbre.

   Aucun JavaScript : les traits sont des bordures de pseudo-éléments, la
   grille se replie seule, et sous 860 px l'arbre devient un filet vertical
   unique — un arbre à trois colonnes sur un téléphone ne se lit pas. TR-23. */

.oc-liste > .oc-noeud { position: relative; padding-left: 1.7rem; }
/* La colonne de l'étage, interrompue au dernier enfant : sans ça elle pend
   sous le dernier coude et l'arbre a l'air inachevé. */
.oc-liste > .oc-noeud::before { content: ''; position: absolute;
  left: 0.55rem; top: 0; bottom: 0; border-left: 2px solid var(--trait); }
.oc-liste > .oc-noeud:last-child::before { bottom: auto; height: 1.5rem; }
/* Le coude, de la colonne vers la case. */
.oc-liste > .oc-noeud::after { content: ''; position: absolute;
  left: 0.55rem; top: 1.5rem; width: 1.15rem;
  border-top: 2px solid var(--trait); }

.oc-case { background: var(--surface); border: 1px solid var(--trait);
  border-radius: 10px; padding: 0.6rem 0.75rem; }

/* L'etiquette d'une case — nature, forme juridique, etat.

   ⚠️ NE PAS REPRENDRE `.type` : elle n'existe que sous
   `.arbo-noeud .arbo-noeud-tete`. Posee ailleurs, elle ne s'applique pas du
   tout, et le libelle sort en texte nu sans qu'aucune erreur ne le dise.
   Vu a la capture le 23.10.2026 — deuxieme fois dans la journee qu'une
   classe choisie a son nom ne fait pas ce qu'elle annonce. */
.oc-etiq { font-family: var(--mono); font-size: 0.58rem;
  text-transform: uppercase; letter-spacing: 0.11em; color: var(--gris);
  padding: 0.1rem 0.4rem; background: var(--surface-2);
  border-radius: 999px; white-space: nowrap; }
.oc-etiq.ombrelle { background: var(--accent-doux); color: var(--accent); }

/* L'entité légale : la case qui porte l'étage du dessous. */
.oc-noeud { margin-bottom: 0.2rem; }
.oc-case-entite { display: block;
  border-left: 4px solid var(--violet, #5B1A8C); }
/* La case entière ouvre la fiche, comme celle d'une marque — *Direction,
   23.10.2026 : « j'aimerais juste qu'on puisse cliquer sur les entités, de la
   même façon qu'on ouvre les marques ».* Deux boutons s'étaient succédé à
   cette place ; aucun n'était nécessaire. `oc-case-inerte` est pour les
   en-têtes qui n'ouvrent rien — une nature n'est pas une entité. */
a.oc-case-entite { text-decoration: none; color: inherit; }
a.oc-case-entite:hover { border-color: var(--accent); }
a.oc-case-entite:hover .tete b { color: var(--accent); }
.oc-case-entite .tete { display: flex; align-items: baseline;
  flex-wrap: wrap; gap: 0.5rem; }
.oc-case-entite .tete b { font-size: 1rem; font-weight: 700;
  letter-spacing: -0.01em; }
.oc-case-entite .tete .bouton { margin-left: auto; }
.oc-proprietaires { list-style: none; margin: 0.35rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.15rem 1.2rem; font-size: 0.83rem; }
.oc-proprietaires li b { font-weight: 600; }
.oc-proprietaires li small { font-family: var(--mono); font-size: 0.65rem;
  color: var(--gris); }
.oc-manque { margin: 0.35rem 0 0; font-size: 0.83rem; color: var(--gris); }

/* Les marques, par rangées de trois, chacune pendue au bus de sa rangée. */
.oc-marques { position: relative; padding-left: 1.7rem; }
.oc-rang { position: relative; display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.6rem; padding-top: 1.3rem; }
/* Le bus horizontal. Il s'arrête au centre de la DERNIÈRE case de la
   rangée : `--reste` vaut 100 % moins ce centre, calculé à l'affichage,
   sinon une rangée incomplète laisse pendre un trait vers nulle part. */
.oc-rang::before { content: ''; position: absolute; top: 0.65rem;
  left: -1.15rem; right: var(--reste, 16.67%);
  border-top: 2px solid var(--trait); }
/* Ce qui relie la rangée précédente — ou la case de l'entité — à ce bus. */
.oc-rang::after { content: ''; position: absolute; left: -1.15rem;
  top: 0; height: 0.65rem; border-left: 2px solid var(--trait); }

a.oc-case-marque { text-decoration: none; color: inherit; }
.oc-case-marque { position: relative; display: flex; flex-direction: column;
  gap: 0.3rem; border-left: 3px solid var(--accent); }
a.oc-case-marque:hover { border-color: var(--accent); }
/* La descente du bus vers la case : c'est elle qui dit « rattachée ». */
.oc-case-marque::before { content: ''; position: absolute; left: 50%;
  top: -0.65rem; height: 0.65rem; border-left: 2px solid var(--trait); }
.oc-case-marque .nom { font-size: 0.9rem; font-weight: 650;
  color: var(--encre); line-height: 1.25; }
a.oc-case-marque:hover .nom { color: var(--accent); }
.oc-case-marque .etiquettes { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.oc-case-marque .porteur { margin-top: auto; padding-top: 0.15rem;
  display: flex; align-items: center; gap: 0.4rem; font-size: 0.8rem; }
.oc-case-marque .porteur.sans { color: var(--ocre); }
.oc-ini { width: 1.45rem; height: 1.45rem; border-radius: 999px; flex: none;
  background: var(--accent-doux); color: var(--accent);
  font-family: var(--mono); font-size: 0.58rem; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; }
.oc-ini.vacante { background: var(--ocre-doux); color: var(--ocre); }
.oc-titulaire { font-family: var(--mono); font-size: 0.66rem;
  color: var(--gris); }

/* Sous 860 px, l'arbre devient un filet. Trois colonnes sur un téléphone
   font des cases de 90 px, et les traits ne relient plus rien de lisible. */
@media (max-width: 860px) {
  .oc-liste > .oc-noeud { padding-left: 0.8rem;
    border-left: 2px solid var(--trait); }
  .oc-liste > .oc-noeud::before, .oc-liste > .oc-noeud::after,
  .oc-rang::before, .oc-rang::after, .oc-case-marque::before { content: none; }
  .oc-marques { padding-left: 0.8rem;
    border-left: 2px solid var(--trait); }
  .oc-rang { grid-template-columns: minmax(0, 1fr); gap: 0.5rem;
    padding-top: 0.5rem; }
}

/* Un projet dans l'arbre, indenté et compact. */
.arbo-projet { display: grid;
  grid-template-columns: 2.3rem minmax(0, 1fr) auto auto auto;
  gap: 0.5rem; align-items: center; padding: 0.3rem 0.35rem;
  border-radius: 6px; font-size: 0.83rem;
  margin-left: 0.7rem; }
.arbo-projet:hover { background: var(--surface-2); }
.arbo-projet .prio { font-family: var(--mono); font-size: 0.62rem;
  text-align: center; padding: 0.1rem 0.35rem; border-radius: 999px;
  background: var(--surface-2); color: var(--gris);
  font-weight: 700; letter-spacing: 0.05em; }
.arbo-projet .prio-P0 { background: var(--rouge-doux); color: var(--rouge); }
.arbo-projet .prio-P1 { background: var(--ocre-doux); color: var(--ocre); }
.arbo-projet .titre { font-weight: 600; color: var(--encre);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.arbo-projet .titre:hover { color: var(--accent); }
.arbo-projet .statut, .arbo-projet .meta { font-family: var(--mono);
  font-size: 0.65rem; color: var(--gris); white-space: nowrap; }
.arbo-projet .statut.fait { color: var(--vert); }
.arbo-projet .manque { font-size: 0.65rem; color: var(--ocre);
  font-style: italic; }

@media (max-width: 720px) {
  .arbo-projet { grid-template-columns: 2rem 1fr; row-gap: 0.1rem; }
  .arbo-projet .statut, .arbo-projet .meta { grid-column: 2; }
}

/* ------------------------------------------------------------------
   Kanban — grain visuel cockpit (append).

   Les règles plus haut posent la mécanique ; celles-ci n'ajustent que
   des états et un descendant, sans redéfinir `.carte-k` au premier niveau
   (l'assertion CSS interdit deux règles top-level pour la même classe :
   la seconde gagnerait en silence). Le radius plus doux et la transition
   sont donc portés par la déclaration principale, un peu plus haut.
   ------------------------------------------------------------------ */
.carte-k:hover { border-color: var(--gris); }
.carte-k .titre { display: block; margin-top: 0.1rem; }


/* ------------------------------------------------------------------
   L'espace projets — maître-détail.

   Une grille à deux colonnes, l'arbre à gauche et le détail à droite. La
   colonne de gauche est `position:sticky` : c'est ce qui la fait « rester à
   l'écran » quand le détail défile, sans une ligne de JavaScript.

   Toutes les classes sont préfixées `esp-`. Le préfixe n'est pas cosmétique :
   sans chaîne de compilation, une classe redéfinie gagne en silence — c'est
   ce qui avait fait flotter les boutons d'un formulaire au-dessus du fil
   d'ariane, parce que `.barre` désignait deux choses. Un test le vérifie.
   ------------------------------------------------------------------ */
.esp { display: grid; grid-template-columns: 19rem 1fr; gap: 1.4rem;
  align-items: start; }

.esp-arbre { position: sticky; top: 1.2rem; max-height: calc(100vh - 2.4rem);
  overflow-y: auto; border: 1px solid var(--trait); border-radius: 11px;
  background: var(--surface); padding: 0.55rem; }

.esp-racine { display: block; padding: 0.4rem 0.55rem; border-radius: 8px;
  color: var(--encre); }
.esp-racine:hover { background: var(--surface-2); text-decoration: none; }
.esp-racine-nom { display: block; font-weight: 650; font-size: 0.9rem; }
.esp-racine-sous { display: block; font-family: var(--mono);
  font-size: 0.62rem; color: var(--gris); text-transform: uppercase;
  letter-spacing: 0.06em; }

.esp-branche { border-top: 1px solid var(--trait-clair); margin-top: 0.35rem;
  padding-top: 0.35rem; }
.esp-branche-tete { list-style: none; cursor: pointer; display: flex;
  align-items: center; gap: 0.4rem; padding: 0.3rem 0.55rem;
  border-radius: 8px; }
.esp-branche-tete::-webkit-details-marker { display: none; }
.esp-branche-tete::before { content: '▸'; color: var(--gris); font-size: 0.7rem;
  transition: transform .12s ease; }
.esp-branche[open] > .esp-branche-tete::before { transform: rotate(90deg); }
.esp-branche-tete:hover { background: var(--surface-2); }
.esp-branche-nom { font-weight: 600; font-size: 0.84rem; }

.esp-branche-lien { display: block; margin: 0 0 0.2rem 1.15rem;
  padding: 0.15rem 0.4rem; border-radius: 6px; font-family: var(--mono);
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--gris); }
.esp-branche-lien:hover { background: var(--surface-2); text-decoration: none; }

/* Le liseré gauche dit la nature du nœud, comme sur l'arborescence : une
   marque, une initiative, ou la maison. Trois couleurs, jamais un aplat. */
.esp-noeud { border-left: 3px solid var(--gris); margin: 0.25rem 0 0.25rem 1.15rem;
  padding-left: 0.45rem; }
/* Une couleur par axe de regroupement. `esp-noeud-maison` a disparu avec le
   nœud fantôme du même nom : « Maison » est désormais une valeur de l'axe de
   la marque, pas un type de nœud (décision `0014`, 16.10.2026). */
/* Un geste replié dans une section de la fiche. Le `<summary>` se lit comme un
   bouton discret : ouvrir une liste de cases n'est pas l'action, c'est son
   préalable. */
.esp-geste { margin-top: 0.6rem; }
.esp-geste > summary {
  cursor: pointer; font-size: 0.8rem; font-weight: 600; color: var(--accent);
  padding: 0.3rem 0; list-style: none;
}
.esp-geste > summary::-webkit-details-marker { display: none; }
.esp-geste > summary::before { content: '+ '; }
.esp-geste[open] > summary::before { content: '− '; }
.esp-geste .etiquette-tech { margin: 0.5rem 0 0.2rem; }

.esp-noeud-marque { border-left-color: var(--violet, #5B1A8C); }
.esp-noeud-initiative { border-left-color: var(--accent); }
.esp-noeud-tiers { border-left-color: var(--gris); }

.esp-noeud-tete { display: flex; align-items: baseline; gap: 0.35rem;
  padding: 0.2rem 0.4rem; border-radius: 6px; color: var(--encre); }
.esp-noeud-tete:hover { background: var(--surface-2); text-decoration: none; }
.esp-noeud-nom { font-weight: 600; font-size: 0.8rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

.esp-type { font-family: var(--mono); font-size: 0.58rem; color: var(--gris);
  text-transform: uppercase; letter-spacing: 0.06em; }
.esp-compte { margin-left: auto; font-family: var(--mono); font-size: 0.62rem;
  color: var(--gris); }

.esp-projet { display: flex; align-items: center; gap: 0.35rem;
  padding: 0.18rem 0.4rem 0.18rem 0.5rem; border-radius: 6px;
  color: var(--encre); }
.esp-projet:hover { background: var(--surface-2); text-decoration: none; }
.esp-projet-nom { font-size: 0.78rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.esp-prio { font-family: var(--mono); font-size: 0.55rem; padding: 0.05rem 0.25rem;
  border-radius: 4px; background: var(--surface-2); color: var(--gris);
  font-weight: 700; letter-spacing: 0.05em; flex: none; }
.esp-prio-P0 { background: var(--rouge-doux); color: var(--rouge); }
.esp-prio-P1 { background: var(--ocre-doux); color: var(--ocre); }
.esp-fait { margin-left: auto; color: var(--vert); font-size: 0.72rem; }

/* La sélection courante. Un fond, un poids, et rien d'autre : le magenta
   reste réservé à ce qui appelle une action. */
.esp-choisi { background: var(--accent-doux); color: var(--accent-encre, var(--accent));
  font-weight: 650; }
.esp-choisi:hover { background: var(--accent-doux); }

.esp-vide { font-size: 0.75rem; color: var(--gris); font-style: italic;
  padding: 0.2rem 0.55rem; margin: 0; }

.esp-detail { min-width: 0; }

.esp-fil { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem;
  font-family: var(--mono); font-size: 0.66rem; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--gris); margin-bottom: 0.5rem; }
.esp-fil-ici { color: var(--encre); font-weight: 700; }

.esp-lentilles { display: flex; gap: 0.3rem; margin: 0.9rem 0 1rem;
  border-bottom: 1px solid var(--trait); }
.esp-lentille { padding: 0.35rem 0.75rem; border-radius: 8px 8px 0 0;
  font-size: 0.82rem; font-weight: 600; color: var(--gris);
  border: 1px solid transparent; border-bottom: none; margin-bottom: -1px; }
.esp-lentille:hover { background: var(--surface-2); text-decoration: none; }
.esp-lentille.esp-choisi { background: var(--surface); color: var(--encre);
  border-color: var(--trait); }

.esp-fenetre { display: flex; gap: 0.4rem; align-items: center;
  margin-bottom: 0.8rem; font-size: 0.82rem; color: var(--gris); }
.esp-fenetre select { width: 9rem; }

.esp-fiche { display: grid; gap: 1rem; }
.esp-faits { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.8rem; margin: 0; padding: 0.9rem 1.1rem; border: 1px solid var(--trait);
  border-radius: 11px; background: var(--surface); }
.esp-faits dt { font-family: var(--mono); font-size: 0.6rem; color: var(--gris);
  text-transform: uppercase; letter-spacing: 0.06em; }
.esp-faits dd { margin: 0.15rem 0 0; font-size: 0.88rem; }

.esp-description { color: var(--gris); }

/* Le cockpit, regroupé par projet et tiers : un chantier par bloc. */
.coc-groupe { border-top: 1px solid var(--trait-clair); padding: 0.4rem 0; }
.coc-groupe:first-of-type { border-top: none; }
.coc-groupe > summary { cursor: pointer; display: flex; align-items: baseline;
  gap: 0.6rem; flex-wrap: wrap; padding: 0.3rem 0; list-style: revert; }
.coc-groupe > .table { margin-top: 0.3rem; }

/* L'identifiant d'une tâche (#104) ou d'un tiers (T317).
   Chasse fixe pour que les chiffres s'alignent d'une ligne à l'autre ; discret,
   parce qu'il sert à désigner, pas à lire. Sélectionnable d'un double-clic :
   on le copie pour le citer. */
.ident { font-family: var(--mono); font-size: 0.72em; font-weight: 500;
  color: var(--gris); letter-spacing: 0.02em; margin-right: 0.35em;
  white-space: nowrap; user-select: all; }
h1 .ident { font-size: 0.45em; vertical-align: middle; margin-left: 0.4em; }

/* La légende des états de module — un terme et ce qu'il engage, côte à côte
   tant que la largeur le permet. */
.modules-etats { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.35rem 1.2rem; margin: 0.5rem 0 0; }
.modules-etats dt { font-weight: 650; font-size: 0.8rem; }
.modules-etats dd { margin: 0; font-size: 0.8rem; color: var(--gris); }

/* Le titre d'une section et ses gestes, sur une ligne — qui retombe l'un sous
   l'autre quand la largeur manque, plutôt que de pousser la page à déborder. */
.esp-tete-section { display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 0.6rem; }

.esp-listes { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem; }
.esp-listes h3 { font-size: 0.82rem; font-weight: 650; margin: 0 0 0.35rem; }
.esp-ligne { display: flex; align-items: baseline; gap: 0.45rem;
  padding: 0.2rem 0; border-bottom: 1px solid var(--trait-clair);
  font-size: 0.84rem; }

.esp-bilan { margin-bottom: 1.1rem; }

/* Sous 980 px, l'arbre passe au-dessus du détail et cesse d'être collant :
   une colonne de 19 rem sur un écran de téléphone ne laisserait rien au
   détail, et un panneau collant qui occupe la moitié de la hauteur est pire
   qu'un panneau qui défile. */
@media (max-width: 980px) {
  .esp { grid-template-columns: 1fr; }
  .esp-arbre { position: static; max-height: 22rem; }
}

/* ------------------------------------------------------------------
   L'échéancier d'un projet — le Gantt d'une seule ligne.

   *Direction, 06.08.2026 : « dans le Gantt, c'est facile de déplacer les délais,
   j'aimerais bien qu'on voie la même chose avec un extrait du calendrier ».*
   Deux champs de date disent la vérité sans la montrer : « 12.08 » et
   « 30.09 » demandent de compter les semaines de tête.
   ------------------------------------------------------------------ */
.ech-piste { position: relative; height: 3.2rem; border: 1px solid var(--trait);
  border-radius: var(--r); background: var(--surface-2); overflow: hidden; }

.ech-repere { position: absolute; top: 0.25rem; font-family: var(--mono);
  font-size: 0.6rem; color: var(--gris); text-transform: uppercase;
  letter-spacing: 0.08em; transform: translateX(2px); pointer-events: none; }
.ech-repere::before { content: ''; position: absolute; left: -2px; top: 1rem;
  width: 1px; height: 2rem; background: var(--trait); }

.ech-aujourdhui { position: absolute; top: 0; bottom: 0; width: 2px;
  background: var(--accent); opacity: 0.55; pointer-events: none; }

.ech-barre { position: absolute; top: 1.5rem; height: 1.3rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--accent); color: #fff;
  font-size: 0.7rem; white-space: nowrap; cursor: grab; touch-action: none;
  user-select: none; }
.ech-barre-deplacee { cursor: grabbing; filter: brightness(1.1); }

/* Les bords sont larges au doigt, invisibles à l'œil : une poignée de deux
   pixels ne s'attrape pas. */
/* ⚠️ LA POIGNÉE SE VOIT — 20.10.2026.

   *Direction : « il manque les poignées pour pouvoir changer uniquement la
   longueur dans cette vue, parce que dans l'autre vue ici, on l'a, mais pas
   dans la première. »*

   Elle existait, et c'est pire qu'absente : `cursor: ew-resize` et sept pixels
   de large, sans un trait pour le dire. La fonction était là, personne ne
   pouvait la trouver — il fallait deviner qu'un bord de barre se tire.

   Une barrette claire à chaque bout, posée en `::before` pour ne pas changer la
   géométrie de la zone sensible : réduire la poignée à ce qui se voit la
   rendrait plus dure à attraper, alors qu'on vient d'essayer de la montrer. */
.ech-bord { flex: none; width: 0.7rem; align-self: stretch; cursor: ew-resize;
  display: flex; align-items: center; justify-content: center; }
.ech-bord::before { content: ''; width: 2px; height: 55%; border-radius: 1px;
  background: var(--sur-accent); opacity: .55; transition: opacity .12s; }
.ech-barre:hover .ech-bord::before { opacity: .95; }

/* La barrette du Gantt est posée avec `.poignee`, plus haut : la direction la
   disait présente « dans l'autre vue » parce que son geste marche — on finit
   par savoir où tirer sur l'écran qu'on utilise tous les jours. */

.ech-texte { padding: 0 0.2rem; overflow: hidden; text-overflow: ellipsis; }

/* ⚠️ LES TUILES DE CHIFFRES SONT PARTIES — 20.10.2026.

   *Direction : « implémente ce principe dans toutes les pages accueil. »*

   `.coc-chiffres` et `.coc-tuile*` rendaient les cinq chiffres de la maison en
   grandes tuiles cliquables, posées en tête d'« Aujourd'hui ». Les chiffres
   vivent toujours — `MesChiffres::tuiles()` les calcule — mais ils se lisent
   en LISTE, sous Pilotage, où l'on se demande où en est la maison.

   Les règles sont supprimées et non laissées en place : une classe CSS sans
   gabarit qui l'emploie se fait oublier, puis réemployer six semaines plus
   tard pour autre chose, et le style arrive avec. */

.coc-tete { display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-bottom: 0.6rem; flex-wrap: wrap; }

/* Le filtre des tâches : des puces, pas un menu déroulant — l'état courant
   doit se lire sans ouvrir. */
.coc-filtre { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.coc-filtre a { padding: 0.15rem 0.6rem; border: 1px solid var(--trait);
  border-radius: 999px; font-size: 0.8rem; text-decoration: none; color: var(--gris); }
.coc-filtre a:hover { color: var(--encre); border-color: var(--gris); }
.coc-filtre a.actif { color: var(--accent); border-color: var(--accent);
  background: var(--accent-doux); font-weight: 550; }
.coc-filtre a.actif .secondaire { color: inherit; }

/* ------------------------------------------------------------------
   L'assistant conversationnel.

   Classes préfixées `asst-`, pour la même raison que `esp-` plus haut :
   sans chaîne de compilation, une classe redéfinie gagne en silence.
   ------------------------------------------------------------------ */
/* Le catalogue, compact.
 *
 * *Direction, 06.08.2026 : « il n'y a que 8 commandes, donc fais plus court ».* Il
 * avait raison, et la cause était une classe mal choisie : `.etiquette-tech`
 * est un style d'EN-TÊTE DE SECTION — `display: flex`, bordure basse, marges
 * d'un centimètre. Employée en ligne pour un code de commande, elle forçait un
 * retour à la ligne et un trait sous chacune : huit commandes tenaient sur
 * vingt-quatre lignes. */
.asst-catalogue { margin: 0.4rem 0 0; padding: 0; list-style: none; }
.asst-catalogue li { display: flex; align-items: baseline; gap: 0.5rem;
  padding: 0.15rem 0; font-size: 0.85rem; }
.asst-catalogue li strong { font-weight: 550; }

/* Le code d'une commande : une puce en ligne, pas un en-tête. */
.asst-code { flex: none; font-family: var(--mono); font-size: 0.66rem;
  letter-spacing: 0.04em; color: var(--gris); padding: 0.05rem 0.35rem;
  border-radius: 4px; background: var(--surface-2); }

.asst-demande { margin-top: 1.2rem; }

.asst-ligne { display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 1rem; margin-top: 0.9rem; }

.asst-etat-titre { font-family: var(--mono); font-size: 0.6rem; color: var(--gris);
  text-transform: uppercase; letter-spacing: 0.06em; }
.asst-etat { margin: 0.35rem 0 0; padding: 0; list-style: none; font-size: 0.82rem; }
.asst-etat li { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.12rem 0; }

.asst-echange { margin-top: 0.9rem; }
.asst-tete { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem;
  margin-bottom: 0.5rem; }
.asst-statut { font-weight: 650; font-size: 0.85rem; }

.asst-dit { }
.asst-reformulation { margin-top: 0.35rem;
  padding: 0.5rem 0.7rem; border-left: 3px solid var(--accent);
  background: var(--surface-2); border-radius: 0 8px 8px 0; }
.asst-motif { margin-top: 0.35rem; color: var(--ocre); }

.asst-parametres { margin-top: 0.8rem; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.7rem; }
.asst-parametres .barre { grid-column: 1 / -1; }

.asst-corriger { margin-top: 0.7rem; display: flex; flex-wrap: wrap;
  align-items: center; gap: 0.4rem; }
.asst-corriger input[type="text"] { flex: 1; min-width: 10rem; }

/* ── Refonte du 06.08.2026 : saisir à gauche, valider à droite.
 *
 * *Direction : « il faut scroller en bas […] juste avoir le chat à gauche, comme un
 * chatbot, et puis un petit peu les choses à valider ».* Deux colonnes, la
 * saisie collée en haut pour qu'elle reste sous la main pendant qu'on lit ce
 * qui attend. */
/* Le chat est large, la validation étroite.
 *
 * *Direction, 06.08.2026 : « le chat doit être un peu plus large […] le truc à
 * valider prend un peu beaucoup de place ».* Les proportions d'origine
 * disaient l'inverse de l'usage : on écrit tout le temps, on valide par
 * à-coups. */
.asst-plan { display: grid; grid-template-columns: 1fr minmax(15rem, 19rem);
  gap: 1.2rem; align-items: start; }
@media (max-width: 900px) { .asst-plan { grid-template-columns: 1fr; } }

/* `min-width: 0` sur les deux colonnes, sinon `1fr` refuse de rétrécir
 * sous la largeur de son contenu et la reformulation déborde de l'écran au
 * lieu d'être tronquée. C'est le défaut par défaut d'une grille CSS. */
.asst-plan > * { min-width: 0; }
.asst-colonne-chat { position: sticky; top: 1rem; }
@media (max-width: 900px) { .asst-colonne-chat { position: static; } }

/* ── Le composeur, à la manière d'un chat.
 *
 * Un seul cadre : le champ, puis une barre basse à l'intérieur. Le champ n'a
 * ni bordure ni fond propres — c'est le cadre qui les porte, sinon on voit
 * deux boîtes imbriquées. */
.asst-composeur { border: 1px solid var(--trait); border-radius: 14px;
  background: var(--surface); padding: 0.7rem 0.8rem 0.55rem;
  transition: border-color 0.15s; }
.asst-composeur:focus-within { border-color: var(--gris); }
.asst-composeur textarea { width: 100%; border: 0; background: none; padding: 0;
  font: inherit; font-size: 0.95rem; line-height: 1.5; resize: none;
  min-height: 4.4rem; max-height: 22rem; }
.asst-composeur textarea:focus { outline: none; box-shadow: none; }

.asst-composeur-barre { display: flex; align-items: center; gap: 0.45rem;
  margin-top: 0.4rem; }
.asst-composeur-barre select { flex: none; width: auto; padding: 0.2rem 1.4rem 0.2rem 0.5rem;
  font-family: var(--mono); font-size: 0.72rem; }
.asst-composeur-aide { flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; font-size: 0.72rem; }

/* Un mot plutôt qu'une pastille : un rond muet n'apprend rien, et l'infobulle
 * ne se lit qu'après avoir cherché. */
.asst-outil { flex: none; height: 1.9rem; padding: 0 0.7rem; border-radius: 999px;
  border: 1px solid var(--trait); background: var(--surface-2); color: var(--gris);
  font: inherit; font-size: 0.72rem; line-height: 1; cursor: pointer; }
.asst-outil:hover { color: var(--encre); border-color: var(--gris); }
.asst-outil[aria-pressed="true"] { background: var(--accent); color: #fff;
  border-color: var(--accent); }

.asst-envoyer { flex: none; width: 1.9rem; height: 1.9rem; border-radius: 50%;
  border: 0; background: var(--accent); color: #fff; font-size: 0.95rem;
  line-height: 1; cursor: pointer; }
.asst-envoyer:hover { filter: brightness(1.08); }

/* Les replis : le périmètre et les connecteurs se lisent une fois. */
.asst-repli { margin-top: 0.7rem; padding: 0.7rem 0.9rem; }
.asst-repli > summary { cursor: pointer; font-weight: 650; font-size: 0.88rem; }
.asst-repli[open] > summary { margin-bottom: 0.4rem; }

/* La question de l'assistant : un ton d'échange, pas d'alerte. Le filet
 * d'accent la distingue sans crier — un cadre rouge dirait « panne » là où il
 * s'agit d'une information qui manque. */
/* La question vit au-dessus du composeur, dans la colonne où l'on parle. */
.asst-question { border-left: 3px solid var(--accent); padding: 0 0 0.2rem 0.8rem;
  margin-bottom: 0.7rem; }
.asst-composeur-repond { border-color: var(--accent); }
.asst-question-tete { font-family: var(--mono); font-size: 0.62rem; color: var(--gris);
  text-transform: uppercase; letter-spacing: 0.12em; margin: 0 0 0.3rem; }
.asst-question-texte { margin: 0 0 0.6rem; font-size: 0.92rem; }

.asst-attente { margin-bottom: 0.6rem; padding: 0.6rem 0.9rem; }
.asst-attente > summary { display: flex; align-items: baseline; gap: 0.5rem;
  cursor: pointer; list-style: none; }
.asst-attente > summary::-webkit-details-marker { display: none; }
/* La reformulation reste lisible fermée : c'est elle qu'on relit avant de
   valider. Fermé, on la tronque à une ligne ; ouvert, elle se déploie. */
.asst-attente-quoi { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 0.88rem; }
.asst-attente[open] > summary { margin-bottom: 0.5rem; }
.asst-attente[open] .asst-attente-quoi { white-space: normal; font-weight: 650; }
.asst-attente .asst-dit { margin: 0 0 0.3rem; font-size: 0.82rem; }

.asst-repli-champs > summary { cursor: pointer; font-size: 0.78rem; margin: 0.5rem 0; }
.asst-repli-champs .asst-parametres { margin-top: 0.4rem; margin-bottom: 0.6rem; }

.asst-gestes { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.5rem; }
.asst-gestes > form:first-child { flex: 1; min-width: 12rem; }

/* ── L'historique, une ligne par échange.
 *
 * Trente cadres pleins faisaient une page qu'on ne relit jamais. Une ligne
 * suffit à retrouver ; le détail s'ouvre à la demande. */
.asst-ligne-histo { border-bottom: 1px solid var(--trait-clair); }
.asst-ligne-histo > summary { display: flex; align-items: baseline; gap: 0.6rem;
  padding: 0.4rem 0.2rem; cursor: pointer; list-style: none; }
.asst-ligne-histo > summary::-webkit-details-marker { display: none; }
.asst-ligne-histo > summary:hover { background: var(--surface-2); }
.asst-histo-quand { flex: none; font-variant-numeric: tabular-nums; font-size: 0.78rem; }
.asst-histo-quoi { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 0.85rem; }
.asst-histo-detail { padding: 0.2rem 0.2rem 0.8rem 0.2rem; }

/* ------------------------------------------------------------------
   Les candidats évènements — la découverte.
   ------------------------------------------------------------------ */
.cand-chercher { margin: 1.1rem 0; }
.cand-ligne { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.3rem; }
.cand-ligne input[type="text"] { flex: 1; }

.cand-fiche { margin-top: 0.8rem; }
.cand-tete { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; }
.cand-note { margin-top: 0.4rem; color: var(--gris); }

.cand-decision { display: flex; flex-wrap: wrap; gap: 1.2rem; margin-top: 0.8rem;
  padding-top: 0.7rem; border-top: 1px solid var(--trait-clair); }
.cand-decision form { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.cand-decision label { font-family: var(--mono); font-size: 0.6rem; color: var(--gris);
  text-transform: uppercase; letter-spacing: 0.06em; }
.cand-decision input[type="text"] { min-width: 15rem; }

/* ------------------------------------------------------------------
   Le cycle de vie d'un objet, sur sa fiche.

   Direction, 04.08.2026 : « du moment que l'on choisit un statut, on doit
   pouvoir afficher le diagramme d'état. » Il est replié par défaut :
   la fiche garde sa densité, et l'on ne charge le dessin dans l'œil
   que de qui l'a demandé.

   Les passages fermés sont montrés, grisés, AVEC leur raison — c'est
   le point le plus utile de l'écran : montrer l'impossible et son
   motif répond à la question de quelqu'un qui est bloqué.
   ------------------------------------------------------------------ */
.cycle-de-vie { margin: 0.9rem 0 1.2rem; border: 1px solid var(--trait-clair);
  border-radius: var(--r); background: var(--surface); }
.cycle-de-vie > summary { cursor: pointer; padding: 0.5rem 0.8rem;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--gris); }
.cycle-de-vie > *:not(summary) { margin: 0 0.8rem 0.8rem; }

.cadre-etats { overflow-x: auto; border: 1px solid var(--trait-clair);
  border-radius: var(--r); background: var(--papier); padding: 0.4rem; }
.cadre-etats svg { display: block; min-width: 100%; height: auto; }
.cadre-etats .etat rect { fill: var(--papier); stroke: var(--encre); stroke-width: 1.4; }
.cadre-etats .etat .cerne { fill: none; stroke: var(--encre); stroke-width: 1.1; }
.cadre-etats .etat.courant rect { fill: var(--accent-doux); stroke: var(--accent); stroke-width: 2.2; }
.cadre-etats .nom-etat { font: 600 14px var(--sans); text-anchor: middle; fill: var(--encre); }
.cadre-etats .code-etat { font: 10px var(--mono); text-anchor: middle; fill: var(--gris); }
.cadre-etats .evenement { font: 11px var(--sans); text-anchor: middle; fill: var(--accent); }
.cadre-etats .transition.ouverte path { stroke: var(--encre); stroke-width: 1.5; }
.cadre-etats .transition.fermee path { stroke: var(--gris); stroke-width: 1.1; opacity: 0.55; }
.cadre-etats .transition.fermee { cursor: help; }

.transitions { list-style: none; padding: 0; display: grid; gap: 0.4rem; }
.transitions li { padding: 0.4rem 0.6rem; border-radius: var(--r);
  border: 1px solid var(--trait-clair); }
.transitions li.fermee { opacity: 0.85; border-style: dashed; }
.transitions .motif { margin: 0.2rem 0 0; font-size: 0.82rem; color: var(--gris); }

/* ─────────────────────────────────────────────────────────────────────────
   Modals — un geste, une fenêtre

   *Direction, 04.08.2026 : « préférer un modal chaque fois qu'on clique sur un
   bouton ».* Un <details> déplié poussait la ligne suivante et déformait le
   tableau à chaque clic.

   <dialog> natif : le fond, le focus, la touche Échap et le rôle ARIA sont
   gérés par le navigateur. Rien à réimplémenter, rien à compiler.
   ───────────────────────────────────────────────────────────────────────── */
.modal {
  border: 1px solid var(--trait, #d8d3c8);
  border-radius: 10px;
  padding: 1.25rem 1.4rem 1.1rem;
  min-width: min(30rem, 92vw);
  max-width: 34rem;
  background: var(--surface, #fff);
  color: inherit;
  /* La cellule qui porte les boutons est alignée à droite ; un modal hérite de
     cet alignement et se retrouve avec ses titres et ses labels à droite. */
  text-align: left;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .18);
}

.modal::backdrop { background: rgba(20, 17, 14, .38); }

.modal h3 { margin: 0 0 .2rem; font-size: 1.05rem; }

/* Le sujet du geste : présent pour confirmer ce qu'on traite, jamais dominant. */
.modal .modal-sujet {
  margin: 0 0 1rem;
  padding-bottom: .7rem;
  border-bottom: 1px solid var(--trait, #e6e2d8);
  font-size: .88rem;
}

.modal label { display: block; font-weight: 600; font-size: .85rem; margin-bottom: .3rem; }
.modal textarea,
.modal input[type="date"] { width: 100%; }
.modal .modal-aide { margin: .45rem 0 0; font-size: .8rem; }

.modal .modal-pied {
  display: flex;
  gap: .5rem;
  justify-content: flex-end;
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--trait, #e6e2d8);
}

/* Le parcours commercial : huit colonnes, pas quatre.
   `.colonnes` est calé sur les quatre colonnes du tableau des projets. Le
   parcours en a huit — elles défilent horizontalement plutôt que de se
   comprimer jusqu'à l'illisible. */
.colonnes-parcours {
  /* Toute la largeur, avec un plancher — puis l'ascenseur.

     *Direction, 04.08.2026 : « on devrait prendre toute la largeur et avoir une
     largeur minimale, et dès que ça atteint la minimale, on met un ascenseur
     horizontal ».*

     `minmax(230px, 1fr)` fait les deux : les colonnes s'étalent tant qu'il y a
     de la place, et cessent de se serrer à 230px — en dessous, un nom
     d'organisation se casse en cinq lignes et la carte devient illisible. Le
     défilement horizontal de `.colonnes` prend alors le relais. */
  grid-template-columns:repeat(8,minmax(230px,1fr));
  gap:0.6rem;
}
.colonnes-parcours .colonne { min-width:0; }
/* Un nom long se coupe au lieu de pousser sa colonne. */
.colonnes-parcours .carte-k .titre,
.colonnes-parcours .carte-k .meta { overflow-wrap:anywhere; }
.colonnes-parcours .carte-k .deplacer select { max-width:100%; }

/* Pas de repli en défilement horizontal.

   *Direction, 04.08.2026 : « il faut qu'il prenne toujours toute la largeur ».* Un
   plancher en pixels — même 170px — fait déborder la grille dès que huit
   colonnes ne tiennent plus, et le tableau se lit alors en poussant la barre.
   `minmax(0,1fr)` laisse les colonnes se serrer autant qu'il faut : plus
   étroites sur un petit écran, jamais hors cadre. Le texte se coupe, il ne
   déborde pas. */

/* ─────────────────────────────────────────────── L'interrupteur d'un module
   Un <button> et non une case à cocher : le geste part au serveur sans une
   ligne de JavaScript, et l'état affiché est celui de la base — jamais celui
   d'un widget qui aurait pu diverger de ce qu'il commande.

   `aria-pressed` porte l'état pour qui n'y voit pas les couleurs ; la piste et
   le bouton ne sont qu'un habillage. Voir TR-23 : aucune chaîne de
   construction, ce CSS est écrit à la main.

   Le nom n'est pas `.bascule` : cette classe existe depuis la ligne 170 et
   habille les cases à cocher des formulaires. La réutiliser l'écrasait en
   silence — `NavigationEtPeauTest` refuse toute classe définie deux fois,
   précisément parce que « la dernière gagne » est invisible jusqu'au jour où
   un écran se déforme sans qu'on sache pourquoi. */
.interrupteur {
  --piste: 2.6rem;
  display: inline-flex; align-items: center; gap: 0.6rem;
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--encre);
}
.interrupteur:disabled { cursor: default; opacity: 0.55; }

.interrupteur-piste {
  position: relative; flex: 0 0 auto;
  width: var(--piste); height: 1.4rem; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--trait);
  transition: background 120ms ease, border-color 120ms ease;
}
.interrupteur-piste::after {
  content: ''; position: absolute; top: 50%; left: 0.15rem;
  width: 1rem; height: 1rem; margin-top: -0.5rem;
  border-radius: 50%; background: var(--trait);
  transition: transform 120ms ease, background 120ms ease;
}
.interrupteur[aria-pressed="true"] .interrupteur-piste { background: var(--vert); border-color: var(--vert); }
.interrupteur[aria-pressed="true"] .interrupteur-piste::after {
  background: #fff; transform: translateX(calc(var(--piste) - 1.45rem));
}
.interrupteur:focus-visible .interrupteur-piste { outline: 2px solid var(--encre); outline-offset: 2px; }

.interrupteur-mot { font-size: 0.85rem; color: var(--gris); min-width: 4.2rem; text-align: left; }
.interrupteur[aria-pressed="true"] .interrupteur-mot { color: var(--encre); }

/* ── Le module de noyau ──────────────────────────────────────────────────
   ⚠️ IL EST ALLUMÉ, ET IL DOIT SE LIRE COMME TEL.

   *Direction, 24.09 au soir : « tous ceux qui sont marqués noyau en gris, il
   faudrait qu'ils soient allumés, parce qu'on dirait qu'ils sont éteints. On
   ne fait pas la différence entre un qui est éteint et un qui est noyau. »*

   La cause : la règle d'avant peignait la piste avec une variable QUI
   N'EXISTE DANS AUCUNE PEAU. Le fond retombait donc sur celui de
   la piste éteinte, pointeur à gauche : le dessin exact d'« Éteint », pour un
   module qu'on ne PEUT PAS éteindre.

   La piste est donc verte et le pointeur à droite, comme tout module allumé.
   Ce qui distingue le noyau n'est pas son état — c'est qu'il est VERROUILLÉ,
   et c'est le pointillé qui le dit. Un état et une permission sont deux
   choses ; les confondre dans une seule nuance de gris était l'erreur. */
.interrupteur-noyau .interrupteur-piste {
  background: var(--vert); border-color: var(--vert); border-style: dashed;
}
.interrupteur-noyau .interrupteur-piste::after {
  background: #fff; transform: translateX(calc(var(--piste) - 1.45rem));
}
.interrupteur-noyau .interrupteur-mot { color: var(--encre); }

/* ──────────────────────────────────── Le portefeuille en pleine largeur
   L'arbre ne pilote plus un panneau de droite : il occupe l'écran, et chaque
   projet porte son détail plutôt qu'un titre tronqué.

   `.esp-projet` existe déjà et garde sa mise en page de base ; on ne fait
   qu'étaler ses colonnes quand il est dans le portefeuille. Redéfinir
   `.esp-projet` l'écraserait partout ailleurs — c'est le défaut payé le 19.08
   avec `.bascule`, et `NavigationEtPeauTest` le refuse désormais. */
.portefeuille-arbre .esp-projet {
  display: grid;
  grid-template-columns: 3rem 1fr 8rem 12rem 7rem;
  align-items: center;
  gap: 0.75rem;
}
.portefeuille-arbre .esp-projet-nom { overflow: hidden; text-overflow: ellipsis; }

.esp-col { font-size: 0.85rem; color: var(--gris); white-space: nowrap; }
.esp-col-echeance { text-align: right; font-variant-numeric: tabular-nums; }

/* Ce qui manque se dit, sans crier. Un tiret se lirait comme une donnée qu'on
   n'a pas cherchée ; ces valeurs-là manquent vraiment et sont à poser. */
.esp-manque { font-style: italic; opacity: 0.7; }

@media (max-width: 900px) {
  .portefeuille-arbre .esp-projet { grid-template-columns: 3rem 1fr; }
  .portefeuille-arbre .esp-col { display: none; }
}

/* ──────────────────────────────────── Les filtres du kanban et du gantt
   Le même bloc pour les deux vues — voir partie-filtres.blade.php. */
/* La case « privée » du cockpit, posée à côté de la phrase. */
.capture-prive { display: inline-flex; align-items: center; gap: .3rem;
  font-size: .82rem; color: var(--gris); white-space: nowrap; cursor: pointer; }

.filtres-portefeuille {
  display: flex; flex-wrap: wrap; align-items: end; gap: 0.9rem;
  padding: 0.75rem 1rem; margin-bottom: 1rem;
  border: 1px solid var(--trait); border-radius: 0.5rem;
  /* Même variable fantôme que l'interrupteur de noyau, trouvée le 24.09 en
     corrigeant celui-ci : la barre de filtres était transparente, sans que
     personne ne s'en aperçoive. */
  background: var(--surface-2);
}
/* ⚠️ LE LIBELLÉ ET SON FILTRE TIENNENT SUR UNE LIGNE — 20.10.2026.

   *Direction, capture d'un iPhone sur le kanban : « filtres et labels toujours
   sur une ligne dans ce cas de figure. Partout. »*

   Le libellé était posé AU-DESSUS de son champ : quatre filtres prenaient huit
   lignes, soit un écran de téléphone entier avant la première colonne du
   kanban. Côte à côte, les quatre tiennent en quatre lignes, et deux par
   rangée dès qu'il y a la place.

   `white-space: nowrap` sur le libellé : sans lui, « Initiative » se coupe en
   deux au milieu d'une rangée serrée, et la ligne gagnée est reperdue. */
.filtres-portefeuille label { display: flex; align-items: center; gap: 0.45rem; }
.filtres-portefeuille label > .k { white-space: nowrap; }
.filtres-portefeuille select { min-width: 8rem; flex: 1 1 auto; }
.filtres-compte { margin-left: auto; font-size: 0.85rem; color: var(--gris); }
/* ─────────────────────────────────────────── Le calendrier, trois genres
   La couleur porte le genre — rendez-vous, séance, évènement — et non la
   pertinence. Dans un calendrier, savoir si c'est un rendez-vous ou une séance
   décide de la journée ; savoir qu'un évènement est « pertinence B » ne décide
   de rien. */
/* ⚠️ CHAQUE GENRE POSE SA COULEUR DANS `--genre`, ET PAS DIRECTEMENT SUR LE
   BORD. C'est ce qui manquait jusqu'au 28.09.2026 : la couleur était écrite
   ici en `border-left`, mais `.cal-g-bloc` redéclarait `border-left` six cents
   lignes plus bas. La dernière gagnait, en silence, et tous les blocs de la
   grille horaire sortaient gris. Les vues mois et liste, elles, montraient
   bien leurs couleurs — d'où un défaut qui ne se voyait que sur un écran.

   Avec une variable, chaque élément décide de l'ÉPAISSEUR de son bord et la
   couleur suit, sans que l'ordre des règles n'ait plus son mot à dire. */
.cal-genre-rdv {
  --genre: var(--accent);
  border-left: 3px solid var(--genre);
}
.cal-genre-seance {
  --genre: var(--vert);
  border-left: 3px solid var(--genre);
}
.cal-genre-evenement {
  --genre: var(--ocre);
  border-left: 3px solid var(--genre);
}
/* Ce que NOUS organisons — raccordé au calendrier le 25.09.2026. Une couleur
   à part : « où l'on va » et « ce qu'on organise » n'engagent pas les mêmes
   gens ni le même travail. */
.cal-genre-manifestation {
  --genre: var(--indigo);
  border-left: 3px solid var(--genre);
}

/* ⚠️ LE PROVISOIRE DOIT SE VOIR SANS SE LIRE.
   *Direction, 25.09.2026 : « des fois on ne sait pas quelle date il aura
   lieu, il y a plusieurs dates candidates. »* Une date envisagée occupe une
   case du calendrier comme les autres — c'est fait exprès, c'est ce qui permet
   de voir ce qu'elle heurterait. Mais la confondre avec une date tenue ferait
   réserver une salle pour une hypothèse : le trait pointillé et le fond rayé
   disent « pas encore » d'un coup d'œil, sans mot supplémentaire. */
.cal-provisoire {
  border-left-style: dashed;
  opacity: .82;
  background: repeating-linear-gradient(135deg,
    transparent 0 5px, var(--trait-clair) 5px 6px);
}
.cal-provisoire:hover { opacity: 1; }

/* Trois couleurs sans clef sont trois couleurs. */
.cal-legende { display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.75rem;
  font-size: 0.85rem; color: var(--gris); }
.cal-pastille { display: inline-block; width: 0.75rem; height: 0.75rem;
  border-radius: 2px; margin-left: 0.9rem; }
.cal-pastille:first-child { margin-left: 0; }
.cal-legende .cal-pastille { background: var(--genre, var(--trait)); border: 0; }
.cal-legende .cal-provisoire-temoin {
  background: repeating-linear-gradient(135deg,
    var(--gris) 0 3px, transparent 3px 5px);
  border: 1px dashed var(--gris);
}

/* L'heure, dans une case de mois : chasse fixe, avant le titre. */
.cal-heure { font-family: var(--mono); font-size: 0.92em; opacity: 0.7; margin-right: 0.3em; }

/* ── La semaine, du lundi au dimanche ─────────────────────────────────────
   Sept colonnes sur grand écran ; sous 820 px, les jours s'empilent. Sept
   colonnes à 390 px de large ne se lisent pas, et la semaine sert d'abord en
   déplacement. `minmax(0, 1fr)` et non `1fr` : sans lui, un titre long élargit
   sa colonne et pousse la page à déborder — le défaut déjà corrigé sur les
   grilles le 05.09. */
/* ── L'aperçu de la capture — 27.09.2026 ──────────────────────────────────
   On montre ce qui a été compris AVANT d'écrire. Le bandeau prend l'accent
   doux et non le vert : rien n'est fait, c'est une question posée. */
.apercu {
  margin: .7rem 0 1rem; padding: .8rem 1rem;
  background: var(--accent-doux); border-radius: var(--r);
}
.apercu-tete {
  margin: 0 0 .5rem; font-family: var(--mono); font-size: .62rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--accent);
}
.apercu-lu {
  display: grid; grid-template-columns: 6rem 1fr; gap: .2rem .8rem;
  margin: 0 0 .7rem; font-size: .86rem;
}
.apercu-lu dt { color: var(--gris); }
.apercu-lu dd { margin: 0; min-width: 0; }
/* Ce qui n'a pas été lu se dit, et se voit : une date absente décide du
   rangement de la ligne. */
.apercu-manque { color: var(--ocre); font-style: italic; }

/* ⚠️ LES WIDGETS D'« AUJOURD'HUI » SONT PARTIS — 20.10.2026.

   Quatre cartes de 20 rem minimum, en grille : « Ma journée », « À venir »,
   « Actualité », « Assistant ». Le kanban validé le 20.10 répond à la première
   et l'agenda à la deuxième, mieux et au même endroit. Les deux autres
   survivent en `.cadre` dans `socle/sections/aujourdhui.blade.php` — le cadre
   de la maison, celui que tout le reste de la plateforme emploie.

   C'était la seule famille de classes qui ne servait qu'à un écran. */

/* ═══════════════════════════════════════════════════════════════════════════
   LE MENU MOBILE — 26.09.2026

   *Direction, captures d'un iPhone : « gros problème responsive. Mets burger
   et pour sous-menu trouve astuce. Inspire-toi aussi des app Instagram,
   YouTube etc. »*

   ⚠️ LE BURGER N'EXISTE QUE SOUS 700 px. Au-delà, les onglets sont visibles
   et un burger cacherait ce qui tient déjà à l'écran — c'est le défaut qu'on
   avait justement retiré en sortant le rail latéral.
   ═══════════════════════════════════════════════════════════════════════ */

.menu-mobile { display: none; position: relative; flex: 0 0 auto; }
.menu-mobile > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  width: 2.2rem; height: 2.2rem; border-radius: var(--r);
}
.menu-mobile > summary::-webkit-details-marker { display: none; }
.menu-mobile > summary:hover { background: var(--surface-2); }

/* Trois traits, et le troisième se raccourcit quand c'est ouvert : la
   silhouette dit l'état sans changer d'icône. */
.burger { display: flex; flex-direction: column; gap: .22rem; width: 1.1rem; }
.burger i { display: block; height: 2px; border-radius: 1px; background: var(--encre); }
.menu-mobile[open] .burger i:last-child { width: 60%; }

/* Le panneau couvre l'écran sous la barre. Pas une pastille de 13 rem : sur
   un téléphone, un menu qui laisse voir le contenu derrière invite à viser à
   côté, et sept sections plus cinq écrans ne tiennent pas dans un coin. */
.menu-mobile-panneau {
  position: fixed; left: 0; right: 0; top: 3.1rem; bottom: 0; z-index: 50;
  overflow-y: auto;
  padding: .8rem 1rem 2rem;
  background: var(--surface);
  border-top: 1px solid var(--trait);
}
.menu-mobile-panneau nav { display: flex; flex-direction: column; gap: .1rem; margin-bottom: 1rem; }
.menu-mobile-panneau nav a {
  display: flex; align-items: center; gap: .6rem;
  padding: .7rem .6rem; border-radius: var(--r);
  color: var(--encre); text-decoration: none; font-size: .95rem; font-weight: 600;
}
.menu-mobile-panneau nav a:hover { background: var(--surface-2); }
.menu-mobile-panneau nav a.actif { background: var(--accent-doux); color: var(--accent-encre, var(--accent)); }
.menu-mobile-panneau nav a.vide { opacity: .5; font-weight: 500; }
.menu-mobile-panneau nav a .ico { opacity: .55; flex: 0 0 auto; }
.menu-mobile-panneau nav a.actif .ico { opacity: 1; }
.menu-mobile-nom { flex: 1 1 auto; min-width: 0; }

@media (max-width: 700px) {
  .menu-mobile { display: block; }

  /* ⚠️ LA LIGNE DES SECTIONS REVIENT SOUS LE BURGER — 20.10.2026, ET C'EST
     LA CONDITION DU GESTE DEMANDÉ.

     Elle portait `display: none` depuis le 26.09, quand le panneau du burger
     portait les deux niveaux. Le panneau a perdu les sections ce matin
     (`partie-barre-haute.blade.php`) : sans ce retour, on ne pouvait plus
     changer de section du tout sur un téléphone — un module atteignable
     seulement en tapant son adresse.

     ⚠️ ET LA RÈGLE QUI LA FAIT DÉFILER EXISTE DÉJÀ, PLUS BAS, DANS UNE AUTRE
     `@media (max-width: 700px)`. Elle était muette : `display: none` gagnait
     ici, et personne ne l'a vu puisque les deux blocs se lisent à cinq cents
     lignes d'écart. Deux blocs au même point de rupture est le piège lui-même.

     Le sous-rail, lui, reste hors de l'écran : c'est exactement ce que le
     burger porte maintenant, et l'afficher serait le doublon. */
  .sous-rail { display: none; }

  /* ⚠️ PAS DE `flex-wrap: nowrap` ICI. La barre doit s'enrouler pour que la
     ligne des sections prenne sa rangée (`flex: 1 1 100%`, plus bas). La
     déclaration qui vivait là était déjà contredite par le second bloc, donc
     inerte : elle ne décrivait plus l'écran. */
  .barre-haute { gap: .5rem; padding: .5rem .8rem; }
  /* ⚠️ LE NOM S'EFFACE, LE MONOGRAMME RESTE — et il est la marque. Cette règle
     visait `barre-sous` ; renommer la classe sans la reprendre aurait fait
     RÉAPPARAÎTRE le nom sur petit écran, là où la page faisait 733 px dans un
     écran de 390 et où chaque caractère de la ligne unique se paie. Un
     renommage qui laisse derrière lui une règle devenue muette ne casse rien
     tout de suite : il rouvre un défaut qu'on croyait fermé. */
}

/* ── La barre du calendrier — 26.09.2026 ──────────────────────────────────
   *Direction, capture d'un agenda à l'appui : « reprendre un peu ce style de
   bouton, c'est plus ergonomique. Mettre le bouton Semaine et Mois comme vu,
   mais pas exactement comme ça. Aller mettre sur la même hauteur de ligne. »*

   « Pas exactement comme ça » est la contrainte qui compte : la GÉOMÉTRIE est
   celle de l'agenda montré — segment groupé à gauche, flèches autour d'un
   point fixe à droite, tout sur une ligne — mais les couleurs, les rayons et
   les traits restent ceux de la maison. Aucun gris système, aucune ombre
   portée venue d'ailleurs.

   Cinq boutons de même poids obligeaient à lire chacun pour savoir lequel
   change la lentille et lequel déplace le temps. Deux gestes, deux formes. */
.cal-barre {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
}

/* Le segment : un seul contenant, des onglets dedans. Le fond porte le
   groupe, l'actif porte l'accent — c'est la même grammaire que le rail. */
.cal-segments, .cal-parcours {
  display: flex; align-items: center; gap: .15rem;
  padding: .2rem;
  background: var(--surface-2);
  border: 1px solid var(--trait);
  border-radius: 999px;
}
.cal-segments a, .cal-parcours a {
  display: inline-flex; align-items: center; justify-content: center;
  padding: .32rem .8rem; border-radius: 999px;
  color: var(--gris); text-decoration: none;
  font-size: .86rem; font-weight: 600; white-space: nowrap;
}
.cal-segments a:hover, .cal-parcours a:hover { background: var(--surface); color: var(--encre); }
.cal-segments a.actif { background: var(--accent-doux); color: var(--accent-encre, var(--accent)); }

/* Le filet sépare ce qui change la lentille de ce qui quitte le calendrier :
   « Liste » n'est pas une troisième vue du même écran. */
.cal-segments-trait {
  width: 1px; align-self: stretch; margin: .15rem .25rem;
  background: var(--trait);
}

/* Les flèches sont carrées et le chevron seul y tient : une flèche large
   comme un mot ne se vise plus au pouce. */
.cal-parcours-fleche { padding: .32rem .55rem; font-size: 1.05rem; line-height: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   LA SEMAINE EN GRILLE HORAIRE — 26.09.2026

   *Direction, capture d'un agenda à l'appui : « je préfère ce type de mise en
   page, c'est un petit peu le truc standard, j'aimerais quelque chose qui
   s'approche de ça tout en gardant la charte graphique de la plateforme. »*

   Remplace les trois plages — matin, après-midi, soir — du 24.09. « Garder la
   charte » est la contrainte qui décide de tout : la géométrie est celle d'un
   agenda standard, les couleurs et les traits restent ceux de la maison. Aucun
   bleu système, aucune ombre portée qui viendrait d'ailleurs.
   ═══════════════════════════════════════════════════════════════════════ */

/* Deux réglages, et tout le reste en découle. `--h-heure` est la hauteur d'une
   heure : la changer resserre ou aère la journée entière sans toucher à un
   seul bloc. */
.cal-grille {
  --h-heure: 3.4rem;
  --col-heures: 3.6rem;
  display: grid;
  grid-template-columns: var(--col-heures) repeat(7, minmax(7rem, 1fr));
  min-width: 56rem;
}

/* L'en-tête des jours colle en haut : sur une semaine chargée, on descend
   jusqu'à 20h et l'on doit savoir quel jour on lit. */
.cal-g-coin, .cal-g-jour {
  position: sticky; top: 0; z-index: 3;
  background: var(--surface);
  border-bottom: 1px solid var(--trait);
}
.cal-g-jour {
  display: flex; align-items: baseline; gap: .35rem;
  padding: .5rem .5rem .45rem;
  border-left: 1px solid var(--trait-clair);
}
.cal-g-jour-nom { font-size: .78rem; color: var(--gris); text-transform: capitalize; }
.cal-g-jour-num { font-size: 1.05rem; font-weight: 650; }
/* Le jour courant se marque par l'accent, jamais par un fond plein : une
   colonne entière colorée écrase les blocs qu'elle contient. */
.cal-g-jour.cal-aujourdhui { border-bottom: 2px solid var(--accent); }
.cal-g-jour.cal-aujourdhui .cal-g-jour-num { color: var(--accent); }

/* ── La bande « toute la journée »
   ⚠️ ELLE EXISTE POUR QU'ON N'INVENTE PAS D'HEURE. Une entrée sans heure
   posée à 8h dans la grille passerait pour un rendez-vous du matin. Ici, elle
   occupe le jour sans prétendre occuper un moment. */
.cal-g-coin-jour {
  font-family: var(--mono); font-size: .56rem; text-transform: uppercase;
  letter-spacing: .08em; color: var(--gris);
  padding: .35rem .4rem; text-align: right;
}
.cal-g-toutlejour {
  border-left: 1px solid var(--trait-clair);
  border-bottom: 1px solid var(--trait);
  padding: .25rem .3rem; min-height: 1.6rem;
  display: flex; flex-direction: column; gap: .15rem;
}
.cal-g-pastille {
  display: block; font-size: .72rem; line-height: 1.25;
  padding: .12rem .35rem; border-radius: 3px;
  /* La bande « toute la journée » porte les mêmes couleurs que la grille :
     un genre ne change pas de couleur selon l'endroit où on le regarde. */
  background: color-mix(in srgb, var(--genre, var(--trait)) 7%, var(--surface-2));
  border-left: 4px solid var(--genre, var(--trait));
  color: var(--encre); text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-g-pastille:hover { background: var(--accent-doux); }

/* ── La colonne des heures et les créneaux */
.cal-g-heures { border-top: 0; }
.cal-g-heure {
  height: var(--h-heure); position: relative;
  font-family: var(--mono); font-size: .68rem; color: var(--gris);
}
/* L'étiquette chevauche le trait, comme dans tous les agendas : posée SOUS
   lui, elle semble appartenir à l'heure suivante. */
.cal-g-heure span { position: absolute; top: -.45rem; right: .4rem; }

.cal-g-colonne {
  position: relative;
  border-left: 1px solid var(--trait-clair);
}
/* Une seule déclaration, et le trait de la demi-heure vit dedans : deux blocs
   `.cal-g-creneau` passaient le rendu mais tombaient sous la règle du dépôt —
   « la dernière gagne, en silence ». Le trait de demi-heure aide à viser sans
   quadriller la journée. */
.cal-g-creneau {
  height: var(--h-heure);
  border-bottom: 1px solid var(--trait-clair);
  background: linear-gradient(to bottom,
    transparent calc(50% - 1px), var(--trait-clair) calc(50% - 1px),
    var(--trait-clair) 50%, transparent 50%);
}
.cal-sem-weekend { background: color-mix(in srgb, var(--gris) 4%, transparent); }

/* ── Les blocs
   `--depuis` et `--duree` sont en HEURES, fournies par le gabarit. Le calcul
   vit donc ici, en un seul endroit : changer `--h-heure` déplace et
   redimensionne tout, d'un coup et sans erreur d'arrondi dispersée. */
.cal-g-bloc {
  position: absolute; left: .15rem; right: .15rem;
  top: calc(var(--depuis) * var(--h-heure));
  height: calc(var(--duree) * var(--h-heure) - .15rem);
  overflow: hidden;
  display: flex; flex-direction: column; gap: .05rem;
  padding: .2rem .35rem; border-radius: 4px;
  /* Un fond teinté du genre, très léger : il porte la même information que
     le bord, pour qui distingue mal un liseré de 4 px. */
  background: color-mix(in srgb, var(--genre, var(--trait)) 7%, var(--surface-2));
  border-left: 4px solid var(--genre, var(--trait));
  color: var(--encre); text-decoration: none;
  font-size: .76rem; line-height: 1.2;
}
.cal-g-bloc:hover { background: var(--accent-doux); z-index: 2; }
/* Le cadenas d'un rendez-vous privé — même signe qu'au fil, pour qu'il se
   reconnaisse d'un écran à l'autre sans réapprentissage. */
.cal-prive { font-size: .66rem; opacity: .75; }

.cal-g-bloc-titre { font-weight: 600; }
.cal-g-bloc-heure { font-family: var(--mono); font-size: .66rem; color: var(--gris); }
.cal-g-bloc-detail { font-size: .7rem; color: var(--gris);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ⚠️ DURÉE INCONNUE : LE BORD LE DIT.
   Un évènement ou une manifestation n'a pas d'heure de fin — la colonne `fin`
   y est une date. Le bloc garde une hauteur minimale pour rester lisible, mais
   son bord pointillé et l'absence d'heure de fin disent qu'on ne sait pas
   quand ça s'arrête. Sans ça, la grille afficherait une durée inventée avec
   l'aplomb d'une mesure — c'est l'objection qui avait fait écarter la grille
   le 24.09, et c'est elle qu'on lève ici. */
.cal-g-sans-duree {
  border-left-style: dashed;
  background: repeating-linear-gradient(135deg,
    var(--surface-2) 0 6px, transparent 6px 8px);
}

/* Sur téléphone, une grille de sept colonnes ne se lit pas. La semaine
   redevient une liste de jours — c'est la forme qui sert en déplacement, et
   `.defiler` garde la grille atteignable sur tablette. */
@media (max-width: 820px) {
  .cal-grille { --h-heure: 2.8rem; min-width: 48rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LA BOUCLE DU JOUR — le cockpit refondu du 21.09.2026

   Analyse et chiffres :
   docs/analyses/2026-09-21-refonte-cockpit-analyse-multicritere.md

   Ces règles vivent à la fin du fichier et ne touchent à aucune règle
   existante : l'ancien cockpit garde exactement son apparence. C'est la
   condition du retour arrière — retirer ce bloc suffirait.
   ═══════════════════════════════════════════════════════════════════════ */

.jour-tete { margin: 0 0 1rem; }
.jour-tete h1 { margin: .1rem 0 .2rem; }
.jour-tete .fil { margin: 0; font-size: .82rem; color: var(--gris);
  text-transform: uppercase; letter-spacing: .06em; }

/* ── La barre de capture ───────────────────────────────────────────────────
   Elle est large, haute, et la première chose qu'on voit. Ce n'est pas de
   l'emphase décorative : la courbe de saisie mesurée est en dents de scie
   (33, 25, 5, 5, 33 par semaine), et une barre discrète ne changerait rien à
   ce qui la cause — le coût d'inscrire. */
.capture { display: flex; gap: .5rem; margin: 0 0 .35rem; }
.capture input {
  flex: 1 1 auto; min-width: 0;
  padding: .7rem .9rem; font-size: 1rem;
  border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface); color: var(--encre);
}
.capture input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.capture button { white-space: nowrap; }
.capture-aide { margin: 0 0 1.1rem; font-size: .82rem; }
.capture-aide code {
  padding: .05rem .3rem; background: var(--surface-2);
  border-radius: 3px; font-weight: 600;
}

/* ── Les blocs ─────────────────────────────────────────────────────────────
   Un bloc vide n'existe pas : c'est le gabarit qui le supprime, pas le CSS
   qui le masque. Masquer laisse un trou dans l'espacement ; supprimer non. */
.bloc-jour { margin: 0 0 1.4rem; }
.bloc-jour > h2, .bloc-jour summary h2 {
  font-size: .95rem; margin: 0 0 .5rem;
  display: flex; align-items: baseline; gap: .5rem;
}
.bloc-jour .compte {
  font-family: var(--mono); font-size: .8rem; color: var(--gris);
  background: var(--surface-2); border-radius: 10px; padding: .05rem .45rem;
}
.bloc-jour .sens { font-size: .78rem; font-weight: 400; }

/* Le retard est la seule chose colorée de la page.
   Si tout appelle, plus rien n'appelle : l'accent reste réservé à l'action,
   et le rouge au seul état qui doit sauter aux yeux. */
.bloc-en_retard > h2 { color: var(--rouge); }
.ligne-jour.est-en-retard { border-left: 3px solid var(--rouge); }
.lj-retard { color: var(--rouge); font-weight: 600; }

.bloc-jour summary { cursor: pointer; list-style: none; }
.bloc-jour summary::-webkit-details-marker { display: none; }
.bloc-jour summary::before { content: "▸ "; color: var(--gris); }
.bloc-jour[open] > summary::before { content: "▾ "; }

/* ── La file ───────────────────────────────────────────────────────────────
   Une liste, et non un tableau : à cette largeur, six colonnes obligent à
   lire en travers alors qu'on ne cherche qu'une chose, l'intitulé. Le
   contexte passe dessous, en petit. */
.file { list-style: none; margin: 0; padding: 0;
  border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface); overflow: hidden; }

/* ⚠️ UNE GRILLE, ET NON PLUS DEUX LIGNES DE TEXTE.
   *Direction, 24.09.2026 : « il faut essayer de mettre plus de colonnes pour
   que ça reprenne moins de place en hauteur. Tout ce qui est acquisition,
   c'est dans une colonne, pas en dessous. »*

   La version d'avant posait le contexte SOUS le titre : chaque ligne coûtait
   deux hauteurs de texte, et 78 lignes devenaient un écran qu'on ne parcourt
   plus. Les colonnes sont à largeur FIXE — c'est ce qui permet à l'œil de
   descendre une colonne au lieu de relire chaque ligne en travers. */
.ligne-jour {
  display: grid;
  /* Une colonne de zéro pour la case : elle ne prend de place QUE dans le
     mode groupé. Réserver 1,4 rem en permanence décalerait toutes les lignes
     pour une case qu'on n'utilise presque jamais. */
  grid-template-columns: 0 minmax(0, 1fr) 6.5rem minmax(0, 13rem) 4.5rem auto;
  align-items: center; gap: .7rem;
  padding: .42rem .85rem;
  border-bottom: 1px solid var(--trait-clair);
}
.ligne-jour:last-child { border-bottom: 0; }
.ligne-jour:hover { background: var(--surface-2); }

/* ── La sélection multiple — 27.09.2026 ───────────────────────────────────
   *Direction : « on doit faire chacune des tâches uniquement. Un bouton
   sélection multiple, puis ça met en checkbox pour chacun. Puis après je peux
   faire en masse : faits, en attente, reporter, sans objet. »*

   ⚠️ TOUT EN CSS, AUCUN JAVASCRIPT (TR-23). Une case cachée porte l'état du
   mode ; son `:checked` révèle les cases des lignes et la barre d'actions.
   Le geste survit à un script cassé, et il n'y a aucun état à resynchroniser
   après un rechargement — le formulaire repart vierge, ce qui est le bon
   comportement pour une sélection qu'on vient d'appliquer. */
.lj-case, .lj-case-vide { width: 0; overflow: hidden; margin: 0; opacity: 0; }

#mode-groupe:checked ~ * .ligne-jour { grid-template-columns: 1.4rem minmax(0, 1fr) 6.5rem minmax(0, 13rem) 4.5rem auto; }
#mode-groupe:checked ~ * .lj-case { width: 1.1rem; height: 1.1rem; opacity: 1; cursor: pointer; }
#mode-groupe:checked ~ * .lj-case-vide { width: 1.1rem; }

/* La case qui porte le mode ne se voit jamais : c'est son label qui est le
   bouton. `position:absolute` et non `display:none` — une case masquée par
   `display` sort du focus clavier, et le mode deviendrait inatteignable
   autrement qu'à la souris. */
.mode-groupe-bascule { position: absolute; opacity: 0; width: 1px; height: 1px; }

.barre-groupee {
  display: none; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: .6rem 0; padding: .6rem .8rem;
  background: var(--accent-doux); border-radius: var(--r);
}
#mode-groupe:checked ~ .barre-groupee { display: flex; }
.barre-groupee-quoi { font-size: .82rem; color: var(--gris); margin-right: auto; }
/* « Tout cocher », en tête de la barre et avant le libellé : on le lit avant
   de choisir le geste, pas après. La case reste NATIVE et visible — contrairement
   à celle du mode, qui est cachée parce que son label fait le bouton. Ici, c'est
   une case qui doit se voir cochée, à demi cochée ou vide. */
.barre-groupee-tout { display: flex; align-items: center; gap: .4rem;
  font-size: .82rem; font-weight: 600; cursor: pointer; white-space: nowrap; }
.barre-groupee-tout input { width: 1.1rem; height: 1.1rem; margin: 0; cursor: pointer; }

/* ⚠️ PLUS AUCUNE RÈGLE POUR LA DATE DU LOT — elle a quitté la barre le
   09.10.2026 (B14).

   *Direction : « j'aimerais que pour la sélection multiple ce soit le même
   comportement : que ça ouvre la petite fenêtre, et puis on enlève le
   sélecteur de date. »*

   `.barre-groupee-date` bornait sa largeur à 9.5rem, et `.report-quand` la
   gardait collée à son bouton. Les deux répondaient à un problème réel —
   *« c'est trop large, ça fait un truc de 10 km de long »*, puis *« puis c'est
   outre large. J'ai déjà dit. »* : dans une barre en `flex-wrap: wrap`, un
   champ de date passe à la ligne et s'y étale, et seule une largeur EXPLICITE
   le tient. Une tentative de le replier derrière un déclencheur avait échoué
   deux fois — *« j'ai cliqué sur reporter, j'ai mis la date, et après, c'est
   impossible de valider »* — parce qu'elle ajoutait un geste et faisait porter
   le mot « Reporter » par deux éléments à la fois.

   Le champ vit désormais dans la fenêtre du report, où `.modal
   input[type="date"]` lui donne toute la largeur : c'est la largeur du modal
   qui le borne, et il n'y a plus rien à enrouler. Les deux règles sont donc
   supprimées plutôt que laissées muettes — une règle CSS sans élément ne
   tombe dans aucun test et se recopie pendant des mois. */

/* Le libellé du bouton change avec l'état : un seul bouton, deux verbes. */
.mode-groupe-bascule:checked + label .pour-ouvrir { display: none; }
.mode-groupe-bascule:not(:checked) + label .pour-fermer { display: none; }

/* Le cadenas d'une tâche privée. Discret mais pas effacé : il doit se
   remarquer en balayant la liste, sans voler la place du titre. */
.lj-prive { font-size: .72rem; opacity: .7; margin-right: .15rem; }

.lj-titre { font-weight: 600; font-size: .9rem; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lj-titre a { color: var(--encre); }
.lj-titre a:hover { color: var(--accent); }
/* Renommée de `.lj-module` le 09.10.2026 : la puce dit le type, plus le
   domaine — B21. ⚠️ Les DEUX règles de la requête média plus bas portent
   le même nom : un renommage qui en oublie une laisse une règle muette,
   sans erreur et sans test rouge. Payé le 07.10 sur `.barre-sous`. */
.lj-type { min-width: 0; }
.lj-sujet { font-size: .78rem; color: var(--gris); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lj-porteur { margin-left: .4rem; }
/* La date se lit en tabulaire : les chiffres s'alignent d'une ligne à
   l'autre, ce qui est tout l'intérêt d'une colonne. */
.lj-quand { font-size: .78rem; color: var(--gris); text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ⚠️ L'ENVELOPPE DES MÉTADONNÉES N'EXISTE PAS AU BUREAU. `display: contents`
   fait de ses trois enfants des éléments de la grille, à leur colonne : le
   dessin large est exactement celui d'avant. Le pourquoi est dans
   `partie-ligne-jour.blade.php`. */
.lj-meta { display: contents; }

/* ══════════════════════════════════════════════════════════════════════════
   SOUS 900 px : DEUX LIGNES PAR TÂCHE, PAS QUATRE — 12.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction, capture d'un téléphone : « la vue mobile, les box sont trop
   hautes. Les compacter et ne laisser que l'info essentielle. »*

   ⚠️ L'ANCIENNE RÈGLE NE POUVAIT PAS MARCHER, et elle était là depuis des
   semaines : elle donnait `display:inline-block` à trois ÉLÉMENTS DE GRILLE
   pour les mettre sur une ligne. Un élément de grille est placé par la
   grille ; son `display` ne décide pas de sa rangée. Les trois prenaient donc
   la leur, et une tâche faisait près de 350 px de haut — trois par écran.

   Réunis sous `.lj-meta`, ils tiennent sur une ligne : le type, le
   rattachement, la date. Le titre garde la sienne, les gestes restent à
   droite, à la même place qu'au bureau. */
@media (max-width: 900px) {
  /* Trois colonnes : la case (nulle hors du mode groupé), le reste, les
     gestes. Deux rangées, et pas une de plus. */
  .ligne-jour {
    grid-template-columns: 0 minmax(0, 1fr) auto;
    row-gap: .15rem; column-gap: .5rem;
    padding-block: .5rem;
  }
  #mode-groupe:checked ~ * .ligne-jour { grid-template-columns: 1.4rem minmax(0, 1fr) auto; }

  /* ⚠️ LE TITRE PREND TOUTE LA LARGEUR, et c'est là que se gagnait la
     hauteur. Partagée avec les gestes, sa colonne faisait 250 px sur un
     téléphone de 390 : « FamiVet : écrire le cahier des charges grossier »
     cassait en TROIS lignes. Sur toute la largeur, il en fait deux. */
  .lj-titre { grid-column: 2 / -1; grid-row: 1; white-space: normal; font-size: .88rem; }

  /* La seconde rangée porte les métadonnées à gauche et les gestes à droite.
     Les gestes ne s'étendent plus sur les deux rangées : leur colonne mangeait
     aussi la largeur du bas, et la date retombait seule sur une quatrième. */
  /* ⚠️ `nowrap`, ET C'EST CE QUI FORCE LE RATTACHEMENT À RÉTRÉCIR. En
     `wrap`, il gardait sa largeur entière et poussait la date sur une
     seconde ligne — une rangée de plus pour cinq caractères. En `nowrap`,
     c'est lui qui cède, avec ses points de suspension, et la date reste
     visible : c'est elle qu'on lit pour trier. */
  .lj-meta {
    display: flex; flex-wrap: nowrap; align-items: baseline;
    column-gap: .45rem;
    grid-column: 2 / 3; grid-row: 2; min-width: 0;
  }
  .lj-gestes { grid-column: 3 / 4; grid-row: 2; justify-self: end; }

  /* ⚠️ `min-width: 0` SUR LE RATTACHEMENT, sinon il refuse de rétrécir et
     pousse la date hors de l'écran : le défaut d'un élément souple est de ne
     jamais passer sous la largeur de son contenu. */
  .lj-meta .lj-sujet {
    min-width: 0; flex: 0 1 auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .lj-meta .lj-type, .lj-meta .lj-quand { flex: 0 0 auto; text-align: left; }
  .lj-meta .lj-sujet, .lj-meta .lj-quand { font-size: .72rem; }
  /* L'étiquette de type perd son coffre : sur une ligne de métadonnées, c'est
     elle qui prenait le plus de hauteur pour le moins d'information. */
  .lj-meta .eti { font-size: .62rem; padding: .05rem .3rem; }
}


/* Les gestes ne rétrécissent pas : c'est la cible qu'on vise en premier, et
   une cible qui change de taille selon la longueur du titre se rate. */
.lj-gestes { flex: 0 0 auto; display: flex; align-items: center; gap: .3rem; }
.lj-gestes form { display: inline; margin: 0; }

/* Le chemin long, replié. Les quatre gestes détaillés — avec leur note au
   journal — restent à un clic : ils cessent d'être obligatoires, ils ne
   disparaissent pas. */
.lj-plus { position: relative; display: inline-block; }
.lj-plus > summary { list-style: none; display: inline-block; }
.lj-plus > summary::-webkit-details-marker { display: none; }
.lj-plus-corps {
  position: absolute; right: 0; top: calc(100% + .25rem); z-index: 20;
  display: flex; flex-direction: column; gap: .25rem; align-items: stretch;
  padding: .45rem; white-space: nowrap;
  border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface); box-shadow: 0 6px 20px rgba(0,0,0,.14);
}

/* ⚠️ EN FIN DE LISTE, LE MENU S'OUVRE VERS LE HAUT — 27.09.2026.
   *Direction : « quand je clique sur les trois petits points du dernier
   élément, le dropdown se met à l'intérieur, mais n'est pas visible. »*

   Il s'ouvrait toujours vers le bas. Sur les dernières lignes d'un bloc, il
   sortait sous le pli, et rien ne disait qu'il s'était ouvert — on cliquait
   deux fois en croyant que le bouton ne répondait pas.

   `nth-last-child` plutôt qu'un calcul de position : sans JavaScript on ne
   sait pas où la page est déroulée, mais on sait toujours combien de lignes
   restent. Les deux dernières s'ouvrent vers le haut, où il y a forcément la
   place puisqu'on vient de les lire. */
.ligne-jour:nth-last-child(-n+2) .lj-plus-corps {
  top: auto; bottom: calc(100% + .25rem);
}

/* ══════════════════════════════════════════════════════════════════════════
   ET IL ÉTAIT QUAND MÊME COUPÉ — 06.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « quand on clique sur le "…", quand le menu s'affiche en drop
   up, il est masqué. »*

   Le correctif du 27.09 l'ouvrait bien vers le haut. Ce qui le coupait est
   ailleurs, et à DEUX endroits : `.file` et `.cadre` portent tous deux
   `overflow: hidden`. Le menu sortait de son conteneur, et le conteneur le
   rognait — la direction de l'ouverture n'y changeait rien.

   ⚠️ ON NE RETIRE PAS CES `overflow`. Sur `.file`, il arrondit les coins des
   premières et dernières lignes ; sur `.cadre`, il borne ce que `.defiler`
   fait défiler horizontalement — le correctif du débordement responsive du
   03.10. Les enlever ferait revenir deux défauts pour en corriger un.

   `:has()` lève le découpage **pendant que le menu est ouvert**, et seulement
   là. Un `<details>` fermé, et tout redevient comme avant.

   ⚠️ SANS `:has()`, LE MENU RESTE COUPÉ — il ne disparaît pas, et rien
   d'autre ne casse. C'est le bon sens du repli : un navigateur trop ancien
   retrouve le comportement d'hier, pas un écran cassé. */
.file:has(.lj-plus[open]),
.cadre:has(.lj-plus[open]) { overflow: visible; }

/* ── Au pouce ──────────────────────────────────────────────────────────────
   Le travail se note debout — en rendez-vous, en afterwork, en visite. Si la
   capture n'est pas utilisable d'une main, elle n'a pas lieu, et on retombe
   sur les rafales du soir que cette refonte cherche précisément à éviter. */
@media (max-width: 620px) {
  .capture { flex-wrap: wrap; }
  .capture input { flex: 1 1 100%; font-size: 16px; /* pas de zoom iOS sous 16px */ }
  .capture button { flex: 1 1 100%; padding: .7rem; }

  .ligne-jour { flex-wrap: wrap; }
  .lj-corps { flex: 1 1 100%; }
  /* Les gestes passent sous la ligne et s'étalent : des cibles tactiles, pas
     trois boutons de douze pixels collés au bord droit. */
  .lj-gestes { flex: 1 1 100%; justify-content: flex-start; margin-top: .45rem; }
  .lj-gestes .bouton { padding: .45rem .8rem; }
  .lj-plus-corps { right: auto; left: 0; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CONDENSER — 22.09.2026

   *Direction : « elle est beaucoup trop complexe, elle est trop éparpillée »*
   (formulaire de projet) et *« utiliser plus des tags […] des iconographies,
   compresser un peu plus »* (kanban).

   Les huit règles sont dans docs/SYSTEME-DE-VUES.md. Ce bloc les applique ;
   il ne les réinvente pas, et les écrans suivants s'y rattacheront.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── R1 · une colonne de lecture bornée ───────────────────────────────────
   Une grille `auto-fit` fabrique trois colonnes sur un écran de 2000 px :
   l'œil zigzague, et l'ordre dans lequel remplir les champs devient
   invisible. Deux colonnes au plus, et une largeur de lecture. */
.cadre-saisie { max-width: 62rem; }
.cadre-saisie .formulaire { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 720px) {
  .cadre-saisie .formulaire { grid-template-columns: 1fr; }
}

/* Ce qui se lit prend la largeur ; ce qui se choisit n'a pas besoin de 600 px. */
.cadre-saisie .champ.large { grid-column: 1 / -1; }
.cadre-saisie .champ textarea { min-height: 7rem; }

/* ── R3 · l'aide se demande ───────────────────────────────────────────────
   L'infobulle est un `?` discret, atteignable au clavier — `tabindex="0"` et
   `aria-label` dans le gabarit : une aide qu'un lecteur d'écran n'atteint pas
   n'est pas une aide. */
.aide-bulle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.05em; height: 1.05em; margin-left: .3em;
  border: 1px solid var(--trait); border-radius: 50%;
  font-size: .72rem; font-weight: 600; color: var(--gris);
  cursor: help; vertical-align: middle;
}
.aide-bulle:hover, .aide-bulle:focus { color: var(--accent); border-color: var(--accent); }

/* Une règle métier ne se survole pas : elle se lit. Le filet à gauche la
   distingue d'un commentaire décoratif. */
.aide-regle {
  border-left: 2px solid var(--trait); padding-left: .55rem;
  margin-top: .1rem;
}

/* ── R2 · le repli, qui nomme ce qu'il contient ───────────────────────────
   Replier n'est pas cacher : il dit combien ils sont, lesquels, et s'ouvre
   d'un clic. Les champs repliés restent dans le formulaire et partent au
   serveur comme les autres. */
.replis { margin: .4rem 1.4rem 0; border-top: 1px solid var(--trait-clair); }
.replis > summary {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  padding: .75rem 0; cursor: pointer; list-style: none;
}
/* ⚠️ AUCUN CHEVRON. *Direction, 25.09.2026 : « inutile de faire une flèche
   qui ferme "Préciser". »* Le repli s'ouvre d'un clic sur son titre et n'a
   pas besoin d'être refermé — ce qu'il cachait est alors à l'écran, et le
   rendre repliable à nouveau n'offre qu'une façon de le reperdre. Le survol
   suffit à dire que la ligne est vivante. */
.replis > summary::-webkit-details-marker { display: none; }
.replis > summary:hover .replis-titre { text-decoration: underline; }
/* ⚠️ LE TITRE EST UNE ACTION, ET IL DOIT LE DIRE — 09.10.2026.

   *Direction : « je vois les accréditations actuelles. On peut les retirer et
   modifier, mais on ne peut pas les ajouter. »* Le formulaire d'ajout EXISTE
   depuis le 05.10 — c'est un repli. Mais son titre s'affichait en gris, sans
   rien qui dise qu'on peut cliquer : la direction l'a pris pour un intitulé
   mort. **La fonction était là, l'affordance manquait.**

   ⚠️ TOUJOURS PAS DE CHEVRON. *Direction, 25.09 : « inutile de faire une
   flèche qui ferme Préciser. »* Les deux demandes ne se contredisent pas —
   là il s'agissait d'un repli déjà OUVERT, ici d'un repli FERMÉ qu'on ne sait
   pas ouvrir. La couleur d'accent suffit à dire que la ligne agit. */
.replis-titre { font-size: .82rem; font-weight: 600; color: var(--accent); }
.replis-noms { font-size: .78rem; color: var(--gris); }
.replis .formulaire { padding: 0 0 1rem; }

/* ── R6 · la barre d'action colle ─────────────────────────────────────────
   Faire défiler deux écrans pour trouver « Enregistrer » est un impôt payé à
   chaque enregistrement. */
.barre-collee {
  position: sticky; bottom: 0; z-index: 5;
  background: var(--surface-2);
  box-shadow: 0 -1px 0 var(--trait), 0 -8px 16px -12px rgba(0,0,0,.25);
}

/* ── R4 et R5 · la carte du kanban ────────────────────────────────────────
   Trois étages : les tags qui classent, le titre qu'on lit, une ligne de
   signaux avec une icône par nature d'information.

   L'écart entre les étages vit dans la règle `.carte-k` d'origine, plus haut :
   une classe ne se définit qu'une fois, sinon la dernière gagne en silence —
   et `NavigationEtPeauTest` le refuse. */
.carte-k .signaux {
  display: flex; flex-wrap: wrap; gap: .25rem .5rem;
  font-size: .72rem; color: var(--gris);
}
.carte-k .signal { display: inline-flex; align-items: center; gap: .22rem; min-width: 0; }
/* L'icône descend à 13 px : dans une ligne de signaux elle situe, elle
   n'illustre pas. À 18 px elle pèse autant que le texte qu'elle annonce. */
.carte-k .signal .ico { width: 13px; height: 13px; flex: 0 0 auto; opacity: .75; }

/* R5 — l'absence se marque, elle ne s'étale pas. */
.carte-k .signal-manque { color: var(--ocre); }
.carte-k .signal-manque .ico { opacity: .9; }
/* Une échéance dépassée sur un projet ouvert : le seul signal qui doit sauter
   aux yeux dans une carte. Si tout appelle, plus rien n'appelle. */
.carte-k .signal-alerte { color: var(--rouge); font-weight: 600; }

/* Le sélecteur de colonne reste atteignable — R6 — mais il ne doit pas peser
   autant que le titre. Il s'éclaircit au repos et revient au survol. */
.carte-k .deplacer select {
  width: 100%; border-color: var(--trait-clair); color: var(--gris);
  background: transparent;
}
.carte-k:hover .deplacer select,
.carte-k .deplacer select:focus { border-color: var(--trait); color: var(--encre); }

/* ═══════════════════════════════════════════════════════════════════════════
   LA FICHE DE SÉANCE — 23.09.2026 · règles R4, R5, R7 et R8

   *Direction : « c'est un petit peu complexe à suivre […] qui est là, inscrit,
   non, été présent, pas aligné […] il y a une incohérence aussi à ce
   niveau-là. »*
   ═══════════════════════════════════════════════════════════════════════ */

/* ── R8 · l'état se dit une fois ──────────────────────────────────────────
   Un menu qui porte l'état courant n'a pas besoin d'une pastille à côté de
   lui pour le répéter : il suffit de le colorer. La bordure porte la couleur,
   pas le fond — un fond coloré sur un <select> natif se comporte différemment
   d'un navigateur à l'autre, et le texte y devient parfois illisible. */
.select-etat { border-left-width: 3px; }
.select-etat-vert  { border-left-color: var(--vert); }
.select-etat-ocre  { border-left-color: var(--ocre); }
.select-etat-rouge { border-left-color: var(--rouge); }

/* ── La présence, alignée ─────────────────────────────────────────────────
   Les lignes étaient en `flex` : le menu se posait juste après le nom, donc à
   une abscisse différente selon la longueur du nom — d'où le « pas aligné ».
   Une grille pose les trois colonnes au même endroit pour tout le monde.

   `minmax(0, 1fr)` sur le nom : sans lui, un nom long élargit sa colonne et
   repousse les deux autres. Le défaut déjà corrigé sur les grilles du
   calendrier le 05.09. */
.presences { display: flex; flex-direction: column; }
.presence {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center; gap: .5rem;
  padding: .45rem 0; border-bottom: 1px solid var(--trait-clair);
}
.presence:last-child { border-bottom: 0; }
.presence-nom { min-width: 0; overflow-wrap: anywhere; }
.presence form { display: contents; }

@media (max-width: 560px) {
  /* Au pouce, le nom prend sa ligne et les deux contrôles se rangent
     dessous : trois colonnes à 390 px rendent le menu illisible. */
  .presence { grid-template-columns: 1fr auto; }
  .presence-nom { grid-column: 1 / -1; }
}

/* ── Une décision est un objet daté ───────────────────────────────────────
   La signature se collait à la fin du dernier mot, comme une incise : sur une
   décision de six lignes, on ne savait plus qui avait tranché sans relire
   jusqu'au bout. Elle remonte en tête, et le filet à gauche la fait lire
   comme une entrée de journal. */
.decision {
  display: flex; gap: .6rem; align-items: flex-start;
  padding: .7rem 0 .7rem .75rem; margin-bottom: .2rem;
  border-left: 2px solid var(--trait);
  border-bottom: 1px solid var(--trait-clair);
}
.decision:last-of-type { border-bottom: 0; }
.decision-corps { flex: 1 1 auto; min-width: 0; }
.decision-signe { margin: 0 0 .25rem; font-size: .76rem; }
/* `pre-line` : une décision qui énumère quatre choses se lit en quatre
   lignes, pas en paragraphe. */
.decision-texte { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }

/* ── Ce qui en sort, résumé en trois chiffres ─────────────────────────── */
.sorties-resume { display: flex; flex-wrap: wrap; align-items: center;
  gap: .4rem; margin: 0 0 .6rem; font-size: .8rem; }

/* ── « Quand » — une phrase, pas trois cellules ───────────────────────────
   *Direction, 22.09.2026 : « les champs de date prennent beaucoup de place,
   et l'heure c'est pas très clair. »* Les mots de liaison portent le sens :
   l'heure vient après « à », donc c'est celle du début. Aucune étiquette
   au-dessus ne le disait. */
.quand-ligne { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.quand-ligne input { flex: 0 1 auto; min-width: 0; }
.quand-mot { color: var(--gris); font-size: .85rem; }
.champ-quand .aide { margin-top: .3rem; }

@media (max-width: 560px) {
  /* Trois champs de date sur une ligne de 390 px deviennent illisibles :
     ils passent chacun sur la leur, les mots de liaison restant devant. */
  .quand-ligne input { flex: 1 1 8rem; }
}

/* ── Le silence, dans la cellule ──────────────────────────────────────────
   « sans réponse depuis 1 j » prenait une ligne sous chaque état, ce qui
   doublait la hauteur d'une liste de vingt-six personnes pour trois mots. */
.silence { display: inline-block; font-size: .74rem; white-space: nowrap; }

/* Une table dont deux colonnes ne servent à personne ne les affiche pas : la
   décision est dans le gabarit, qui les rend seulement si une ligne les
   remplit. Ici, on serre simplement les lignes qui restent. */
/* ⚠️ RESSERRÉ DE .45 À .25 REM — 12.10.2026. *Direction : « on pourrait
   resserrer un tout petit peu la liste des invités en hauteur […] ça prend
   trop, trop de place. Comme ça, on peut mettre plus de gens, surtout pour
   les évènements : il y a beaucoup de personnes. »*

   Trente invités faisaient un mètre de page. Chaque ligne ne porte qu'un
   nom, une étiquette et un menu — rien qui demande de l'air.

   ⚠️ ON RESSERRE CETTE TABLE-LÀ, PAS TOUTES. `.tbl` reste ce qu'il est
   partout ailleurs : une facture ou une fiche de projet se lisent posément.
   Et on touche la règle existante plutôt que d'en superposer une en
   `!important` — une spécificité forcée est une règle qu'on ne saura plus
   défaire. */
.table-venants td { padding-top: .25rem; padding-bottom: .25rem; }
.table-venants select, .table-venants .bouton-mini { padding-top: .15rem; padding-bottom: .15rem; }

/* ── Les trois lentilles de l'acquisition — 23.09.2026 ────────────────────
   *Direction : « il y a le répertoire, il y a le fil d'action, ça nous est
   très très très confus. »* Ce ne sont pas trois écrans mais un endroit vu à
   trois distances. La barre le dit, et dit où l'on est.

   Des liens et non un menu déroulant : on voit les trois choix sans ouvrir,
   et l'angle courant se lit d'un coup d'œil. Même raison que le filtre du
   cockpit — un menu cache l'état courant derrière un clic, et c'est
   justement celui qu'on oublie. */
.lentilles {
  display: flex; gap: .3rem; flex-wrap: wrap;
  margin: 0 0 1.1rem; padding-bottom: .1rem;
  border-bottom: 1px solid var(--trait);
}
.lentille {
  display: flex; flex-direction: column; gap: .05rem;
  padding: .5rem .85rem; border-radius: var(--r) var(--r) 0 0;
  color: var(--gris); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.lentille:hover { background: var(--surface-2); color: var(--encre); }
.lentille-titre { font-size: .92rem; font-weight: 600; }
/* L'onglet courant porte l'accent, et lui seul : c'est la seule chose de la
   barre qui appelle le regard. */
.lentille-active { color: var(--encre); border-bottom-color: var(--accent); }
.lentille-active .lentille-titre { color: var(--accent); }

@media (max-width: 620px) {
  /* Au pouce, la glose disparaît : trois onglets à 390 px ne tiennent que si
     chacun se réduit à son titre. */
  .lentille { flex: 1 1 auto; text-align: center; padding: .55rem .5rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LA NAVIGATION EN HAUT — 24.09.2026

   Cinq sections plates. Le rail reste, et revient par le réglage
   `interface.navigation` : passer la navigation de gauche en haut change toute
   la mémoire gestuelle, et sans retour possible ce n'est plus une proposition.

   ⚠️ `.barre-haute` et non `.barre` : `.barre` est la barre d'actions d'un
   formulaire, définie bien plus haut. Une classe ne se définit qu'une fois.
   ═══════════════════════════════════════════════════════════════════════ */

.barre-haute {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 1.2rem;
  padding: .55rem 1.1rem;
  background: var(--roche); border-bottom: 1px solid var(--roche-trait);
  /* ⚠️ AUCUN `overflow` ICI, ET C'EST UNE LEÇON PAYÉE LE 07.10.2026.
     On y avait posé `overflow: clip` le matin même, pour empêcher la pastille
     `.eti-stade` d'élargir la page de 6 px. Ça marchait — et ça COUPAIT le
     menu déroulant du profil, qui descend sous la barre. *Direction : « il y a
     bien le dropdown, mais il est masqué par le menu. »*

     Une barre qui porte un menu déroulant ne peut pas borner ce qui en sort :
     le menu EST ce qui en sort. On borne donc la pastille là où elle est, pas
     la barre qui la contient. */
}
.barre-haute-marque { display: flex; align-items: center; gap: .45rem;
  color: var(--roche-encre); text-decoration: none; flex: 0 0 auto; }
/* Le monogramme de la maison, au même gabarit que celui du rail mais posé
   dans une barre : plus petit, et sur le dégradé signature. */
.barre-monogramme { width: 1.6rem; height: 1.6rem; border-radius: 7px;
  background: var(--degrade); color: #fff; display: flex; align-items: center;
  justify-content: center; flex: 0 0 auto; }
.barre-monogramme svg { width: 62%; height: 62%; display: block; }
/* Le nom du produit, à côté du monogramme. ⚠️ IL A REMPLACÉ UN COUPLE
   `barre-sigle` + `barre-sous` — « YHB » en gras, « PLATEFORME » en petites
   capitales grises dessous. Le sigle est parti le 07.10 (le monogramme le
   dessine déjà), et le mot restant a pris sa place ET son poids : laissé en
   0.64rem gris, il devenait une mention de bas de page. */
/* Le nom de l'outil au pied du rail. Discret : il situe, il n'appelle pas.
   Même traitement que les étiquettes de groupe du rail — mono, petites
   capitales — pour qu'il se lise comme une signature et non comme une
   entrée de menu de plus. */
.rail-nom-outil { font-family: var(--mono); font-size: .62rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--gris);
  margin: 0 0 .5rem; padding: 0 .4rem; }

/* ⚠️ `.barre-nom` A ÉTÉ RETIRÉE AVEC SON MARQUAGE — 12.10.2026, en même temps
   que le mot « Plateforme » qu'elle habillait.

   J'avais d'abord écrit qu'elle servait encore « pour la barre de la
   documentation ». C'était faux : celle-là s'appelle `.doc-barre-nom`, et
   c'est une autre classe. Garder une règle sur une justification inventée est
   précisément comme ça qu'on se retrouve, un an plus tard, devant du CSS que
   personne n'ose toucher. Même geste que `.sous-rail-titre` ce matin. */

.barre-sections { display: flex; gap: .15rem; flex: 1 1 auto; flex-wrap: wrap; min-width: 0; }
.barre-section {
  padding: .4rem .7rem; border-radius: var(--r);
  color: var(--gris); text-decoration: none; font-size: .92rem; font-weight: 600;
  white-space: nowrap;
}
.barre-section:hover { background: var(--surface-2); color: var(--encre); }
/* L'onglet courant est la seule chose de la barre qui porte l'accent. */
.barre-section-ici { color: var(--accent-encre, var(--accent)); background: var(--accent-doux); }
/* Une section sans rien d'allumé reste visible — sinon la géographie change
   selon les modules et on ne l'apprend jamais — mais elle s'efface. */
.barre-section-vide { opacity: .5; }
.barre-rien { font-family: var(--mono); margin-left: .25rem; }

/* ⚠️ `margin-left: auto`, ET PAS SEULEMENT SUR GRAND ÉCRAN — 09.10.2026.
   *Direction : « l'icône profil doit être collée à droite en haut. »*
   Sur grand écran, `.barre-sections` porte `flex: 1 1 auto` et poussait déjà
   ce bloc au bord. Sous 700 px elle passe en `order: 3` sur sa propre rangée :
   plus rien ne remplit la première, et la pastille se collait au bouton au
   lieu du bord. La marge automatique tient dans les deux cas, sans règle
   conditionnelle — une règle qui ne vaut qu'à une taille se perd au prochain
   point de rupture. */
.barre-droite { display: flex; align-items: center; gap: .5rem; flex: 0 0 auto;
  margin-left: auto; }

/* ── Un bouton qui n'est qu'une icône ────────────────────────────────────
   *Direction, 09.10.2026 : « en mobile et desktop, le bouton commande
   remplacé par une icône d'ajouter. »*

   Carré, de la taille d'une pastille de profil, pour que les deux se répondent
   au bord de la barre. « Commande » prenait 250 px de la première rangée sur
   téléphone — plus que le monogramme, le burger et la pastille réunis.

   ⚠️ 2,25 REM DE CÔTÉ, SOIT 36 PX : c'est le plancher d'une cible tactile
   qu'on atteint sans viser. En dessous, on rate, et on rate surtout le geste
   le plus fréquent de la plateforme. */
.bouton-icone {
  width: 2.25rem; height: 2.25rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.bouton-icone .ico { width: 1.15rem; height: 1.15rem; stroke-width: 1.8; }
/* Un compte ouvert, et la croix qui le retire — 09.10.2026. Deux formulaires
   côte à côte : un `<form>` ne s'imbrique pas dans un autre, donc la croix a
   le sien. */
.barre-moi-compte { display: flex; align-items: center; gap: .25rem; }
.barre-moi-compte > form:first-child { flex: 1 1 auto; min-width: 0; }
.barre-moi-compte > form:first-child > .bouton { width: 100%; text-align: left; }
.barre-moi { position: relative; }
.barre-moi > summary { list-style: none; cursor: pointer; }
.barre-moi > summary::-webkit-details-marker { display: none; }
.barre-moi-corps {
  position: absolute; right: 0; top: calc(100% + .4rem); z-index: 40;
  min-width: 13rem; padding: .7rem .85rem;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r); box-shadow: 0 8px 24px rgba(0,0,0,.16);
}
.barre-moi-nom { margin: 0; font-weight: 600; }

/*
 * ⚠️ SUR TÉLÉPHONE, LA NAVIGATION DÉFILE — ELLE NE S'ENROULE PLUS.
 *
 * *Direction, 26.09.2026, capture d'un iPhone en production : « menu pas bien
 * en responsive sur prod. »*
 *
 * Elle avait raison, et le chiffre le dit : sept onglets de section plus cinq
 * entrées de sous-rail, enroulés, faisaient CINQ LIGNES de navigation —
 * environ un quart de la hauteur d'un iPhone avant d'avoir lu le premier
 * chiffre. Le commentaire d'origine parlait de « cinq onglets » ; il y en a
 * sept depuis le 24.09, et l'enroulement qui tenait à cinq ne tient plus.
 *
 * Une seule ligne qui défile, à chaque niveau. C'est le geste que le pouce
 * fait déjà, et il coûte une ligne au lieu de deux.
 *
 * `scrollbar-width: none` : une barre de défilement de bureau sur un écran
 * tactile prend de la place sans servir. L'affordance est portée par le
 * DÉGRADÉ DE FONDU à droite — on voit qu'il reste quelque chose, ce qu'une
 * barre masquée ne dirait pas.
 */
@media (max-width: 700px) {
  .barre-haute { flex-wrap: wrap; gap: .5rem .8rem; }

  .barre-sections {
    order: 3; flex: 1 1 100%;
    flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
    /* Le fondu vit sur le conteneur, pas sur un élément ajouté : un pseudo en
       `position:absolute` aurait défilé avec le contenu et serait parti hors
       de l'écran au premier glissement. */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.6rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 1.6rem), transparent);
  }
  .barre-sections::-webkit-scrollbar { display: none; }

  .barre-section { font-size: .86rem; padding: .35rem .5rem; scroll-snap-align: start; }
}

/* ── L'accueil d'une section ──────────────────────────────────────────────
   Ce qui attend un geste, puis la carte des écrans. Jamais l'inverse. */

/* L'icône de la section en grand, à gauche du titre : c'est le même dessin
   que dans la barre du haut, et c'est ce qui fait qu'on se reconnaît sans
   relire le titre. */
.sect-tete { margin: 0 0 1rem; display: flex; align-items: center; gap: .75rem; }
.sect-tete > .ico { width: 2rem; height: 2rem; flex: 0 0 auto; color: var(--accent); opacity: .9; }
.sect-tete h1 { margin: 0; }

/* ⚠️ LES TUILES DE COMPTEURS SONT PARTIES — 20.10.2026, ET C'EST LA DEMANDE.

   *Direction, après avoir arbitré les quatre aperçus : « implémente ce principe
   dans toutes les pages accueil. »*

   Neuf accueils portaient la même rangée : un gros chiffre, un libellé, un
   filet de couleur pour le ton. Ce que chacune disait d'utile est devenu une
   liste nommée dans `socle/sections/`.

   ⚠️ DEUX DÉCISIONS DE CE MOIS PARTENT AVEC, et il faut le savoir pour ne pas
   les redemander : le zéro écrit « 0 » plutôt que « · » (09.10), et les zéros
   rangés derrière les chiffres qui appellent un geste (20.10 au matin). Les
   deux étaient justes POUR UNE RANGÉE DE COMPTEURS. Sans la rangée, elles
   n'ont plus d'objet — et le bloc `@media (max-width: 30rem)` qui faisait
   tenir deux tuiles par rangée est parti avec elles.

   ── Ce qui rend une liste d'accueil, à la place

   `.sect-liste` l'espace, `.sect-liste-tete` la nomme et `.sect-liste-compte`
   dit combien il y en a. Le chiffre ne vit plus seul : il est le titre de ce
   qu'on lit en dessous. */
.sect-liste { margin: 0 0 1.6rem; }
/* Le dernier lien d'un cadre collait au bord : il se lisait comme posé sous le
   cadre plutôt que dedans. */
.esp-listes > .cadre > .sens:last-child { margin-bottom: 0; padding-top: .2rem; }

.sect-liste-tete { display: flex; align-items: baseline; gap: .5rem;
  margin: 0 0 .6rem; font-size: .95rem; font-weight: 650; }
.sect-liste-compte { font-family: var(--mono); font-size: .72rem; color: var(--gris);
  font-weight: 400; }

/* Le titre d'une liste et son geste sur la même ligne : un bouton seul sur sa
   rangée coûte une ligne entière pour deux mots, ce que la direction a déjà
   signalé le 12.10 sur l'atelier Textus. */
.sect-liste-barre { display: flex; align-items: baseline; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; margin-bottom: .6rem; }
.sect-liste-barre .sect-liste-tete { margin-bottom: 0; }

/* ⚠️ TROIS LISTES SEULEMENT PORTENT CE FILET, et c'est la règle héritée des
   tuiles : le rouge ne se pose que sur ce qui a déjà glissé — une facture
   impayée, un dépôt de marque à renouveler, un projet que personne ne porte.
   Le jour où tout est rouge, plus rien ne l'est. */
.sect-alerte { border-left: 3px solid var(--rouge); }

/* L'heure, la date ou le chiffre en tête de ligne, en chasse fixe et de
   largeur fixe : sans ça, les titres ne s'alignent pas d'une ligne à l'autre
   et l'œil doit chercher le début de chaque nom. */
.sect-heure { font-family: var(--mono); font-size: 0.8rem; color: var(--gris);
  flex: 0 0 auto; min-width: 4.2rem; }
.sect-chiffre { font-family: var(--mono); font-size: 1rem; font-weight: 650;
  font-variant-numeric: tabular-nums; flex: 0 0 auto; min-width: 2.5rem; }

/* Le fil des rencontres : quatre genres mélangés, triés par date. Le genre se
   lit à la couleur du filet, et le filet ne porte QUE le genre — pas la
   pertinence. Savoir si c'est une séance ou un rendez-vous décide de la
   journée ; savoir qu'un évènement est « pertinence B » ne décide de rien. */
.sect-fil { display: flex; gap: 0.7rem; padding: 0.5rem 0;
  border-bottom: 1px solid var(--trait-clair); align-items: flex-start; }
.sect-fil:last-child { border-bottom: 0; }
.sect-genre { width: 3px; align-self: stretch; border-radius: 2px; flex-shrink: 0; }

/* ⚠️ LES COLONNES DÉFILENT À L'HORIZONTALE, ELLES NE S'EMPILENT PAS.
   *Direction, 20.10.2026 : « les colonnes, j'aimerais pas les colonnes les unes
   sous les autres. Il faut faire un scroll horizontal. »* Quatre colonnes
   empilées font quatre écrans de téléphone, et la quatrième n'est jamais lue. */
.sect-colonnes { overflow-x: auto; padding-bottom: 0.3rem; }
.sect-colonnes > .colonnes { grid-auto-flow: column; grid-template-columns: none;
  grid-auto-columns: minmax(14rem, 1fr); }

/* Le champ de dictée de l'assistant, dans son cadre. */
.sect-dicter { display: flex; flex-direction: column; gap: .4rem; }
.sect-dicter textarea { width: 100%; resize: vertical; }

/* ── La description d'un projet ──────────────────────────────────────────
   *Direction, 20.10.2026, capture à l'appui : « l'affichage n'est pas optimal
   du tout ici. Faire mieux. »*

   ⚠️ `pre-line` RELÈVE LES RETOURS À LA LIGNE que HTML avale. La description
   d'un projet porte des intertitres et des séparateurs écrits à la ligne ; sans
   cette règle, la structure existe en base et disparaît à l'écran.
   `pre-line` et non `pre` : les espaces multiples restent repliés, sinon
   l'indentation d'un copier-coller déforme la mise en page.

   ⚠️ ET UNE LARGEUR DE LECTURE. Au-delà de 72 caractères environ, l'œil perd la
   ligne suivante en revenant à la marge — c'est la mesure que la typographie
   tient depuis cinq siècles, et un écran large ne la change pas. */
.desc-projet { margin: 0 0 1.2rem; }
.desc-projet > summary { cursor: pointer; font-weight: 650; font-size: .95rem;
  display: flex; align-items: baseline; gap: .5rem; }
.desc-projet > summary::-webkit-details-marker { display: none; }
.desc-projet > summary::before { content: '▸'; font-size: .7em; color: var(--gris);
  transition: transform .12s; }
.desc-projet[open] > summary::before { transform: rotate(90deg); }

.desc-projet-texte { white-space: pre-line; max-width: 72ch;
  margin-top: .6rem; font-size: .88rem; line-height: 1.55; color: var(--gris); }

/* ── Un champ qui se cherche ─────────────────────────────────────────────
   *Direction, 20.10.2026 : « un autocomplete, c'est du JavaScript qui va
   chercher dans la base de données. »*

   ⚠️ LA LISTE FLOTTE, ET IL LUI FAUT UN ANCRAGE. `position: absolute` se cale
   sur le premier ancêtre positionné : sans `position: relative` ici, elle se
   posait en haut de page, là où l'on ne la cherche pas. C'est le même piège
   que la fenêtre du profil dans la barre du haut.

   ⚠️ ET ELLE PASSE AU-DESSUS DU RESTE. Dans un formulaire, le champ suivant
   est rendu après : sans `z-index`, il se dessine PAR-DESSUS les suggestions,
   et l'on clique sur ce qu'on ne voit plus. */
.cherche { position: relative; display: flex; flex-direction: column; min-width: 0; }

/* ⚠️ LE CADRE S'OUVRE QUAND UNE LISTE EST OUVERTE — 20.10.2026.

   *Direction, capture à l'appui : « l'autocomplète semble effectivement faire
   quelque chose, mais c'est caché derrière, sous le panneau. »*

   `.cadre` porte `overflow: hidden` — pour que ses coins arrondis coupent ce
   qui dépasse. Un enfant en `position: absolute` est coupé avec : la liste
   existait, elle était rognée au bord du cadre. **Aucun `z-index` ne sort d'un
   `overflow`** — c'est la première chose qu'on essaie, et la seule qui ne peut
   pas marcher.

   `:has()` l'ouvre le temps que la liste soit là, et le referme après : laisser
   `overflow: visible` en permanence rendrait au cadre les débordements qu'il
   coupe exprès. C'est le motif que le dépôt emploie déjà pour le repli du
   journal, posé le 11.10 pour la même raison. */
.cadre:has(.cherche-liste:not([hidden])) { overflow: visible; }
.formulaire:has(.cherche-liste:not([hidden])) { overflow: visible; }

.cherche-liste { position: absolute; top: 100%; left: 0; right: 0; z-index: 30;
  list-style: none; margin: .15rem 0 0; padding: .2rem;
  max-height: 16rem; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r); box-shadow: 0 6px 18px rgba(11, 11, 14, .13); }

.cherche-liste [role="option"] { display: flex; align-items: baseline; gap: .5rem;
  padding: .35rem .5rem; border-radius: 6px; cursor: pointer; font-size: .86rem; }
/* La ligne visée se marque par `aria-selected`, qui est déjà ce que le clavier
   déplace : un second attribut pour le même état finirait par le contredire. */
.cherche-liste [role="option"][aria-selected="true"],
.cherche-liste [role="option"]:hover { background: var(--accent-doux);
  color: var(--accent-encre, var(--accent)); }

.cherche-nom { flex: 1 1 auto; min-width: 0; }
.cherche-detail { flex: 0 0 auto; font-size: .76rem; color: var(--gris); }

/* « Rien » se dit, et ne se clique pas. Une liste qui se referme sans un mot
   laisse croire que la recherche n'est pas partie. */
.cherche-vide { padding: .4rem .5rem; font-size: .82rem; color: var(--gris);
  font-style: italic; }

/* ── Le reste d'une liste, déplié sur place ──────────────────────────────
   *Direction, 20.10.2026 : « c'est marqué "afficher les 4", mais ça mène après
   vers le board entier. Ça, c'est trompeur : ça nous fait passer sur une autre
   vue. Soit un JavaScript qui déroule… »*

   `<details>` natif : il déplie vraiment, sans une ligne de JavaScript (TR-23).
   Le `<summary>` se lit comme un lien discret et porte son chevron — sans lui,
   rien ne dit qu'on peut l'ouvrir, et c'est la moitié du défaut qu'on corrige. */
.sect-reste > summary { list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .3rem 0; font-size: .78rem; color: var(--accent); }
.sect-reste > summary::-webkit-details-marker { display: none; }
.sect-reste > summary::before { content: '▸'; font-size: .7em; transition: transform .12s; }
.sect-reste[open] > summary::before { transform: rotate(90deg); }
.sect-reste > summary:hover { text-decoration: underline; }
/* Dans une colonne de kanban, le reste garde l'espacement des cartes. */
.colonne .pile .sect-reste[open] { display: flex; flex-direction: column; gap: .5rem; }
.colonne .pile .sect-reste > summary { padding: .2rem 0 0; }

/* ── Un invité qui ne répond pas, et ses trois réponses ──────────────────
   *Direction, 20.10.2026 : « les boutons Confirmer, Décliner, Relancer
   prennent trop de place par rapport à la colonne qui marque les noms à
   relancer, qui est trop étroite. »*

   Les boutons vivaient à côté du nom, dans un cadre de 16 rem : il restait six
   caractères de large pour « Chantal Dufaux », qui se coupait sur quatre lignes
   pendant que les boutons gardaient la leur. Le nom prend donc la largeur, et
   les gestes passent dessous, poussés à droite. */
.sect-relance { display: flex; flex-direction: column; gap: .3rem;
  padding: .45rem 0; border-bottom: 1px solid var(--trait-clair); }
.sect-relance:last-child { border-bottom: 0; }
.sect-relance-qui { display: flex; flex-direction: column; min-width: 0;
  font-size: .84rem; line-height: 1.3; }
.sect-relance .sect-gestes-ligne { justify-content: flex-end; }

/* ── Les gestes d'une ligne de liste ─────────────────────────────────────
   *Direction, 20.10.2026 : « je préfère le bouton "Fait", "Annuler", un petit
   peu comme on avait dans les autres. »*

   ⚠️ UN `<form>` NE S'IMBRIQUE PAS DANS UN AUTRE : chaque geste a le sien, et
   c'est pourquoi il faut un conteneur pour les ranger sur une ligne. Même
   contrainte, même solution que les deux gestes d'un compte dans la barre du
   haut, le 09.10. */
.sect-gestes-ligne { display: flex; align-items: center; gap: .3rem;
  flex: 0 0 auto; flex-wrap: wrap; }

/* ── La journée, heure par heure ─────────────────────────────────────────
   *Direction, 20.10.2026 : « avoir un petit calendrier sur la page d'accueil,
   ça, pour être sympathique, peut-être juste le calendrier d'aujourd'hui, du
   jour même. »*

   ⚠️ UNE HEURE VIDE GARDE SA LIGNE, et c'est ce qui en fait un calendrier
   plutôt qu'une liste : les trous se voient, donc on voit où il reste de la
   place. `min-height` plutôt qu'une hauteur fixe — une heure qui porte deux
   rendez-vous s'étire au lieu de les rogner. */
.sect-journee { display: flex; flex-direction: column; }
.sect-journee-heure { display: flex; gap: .6rem; align-items: flex-start;
  min-height: 1.6rem; padding: .15rem 0;
  border-top: 1px solid var(--trait-clair); }
.sect-journee-heure:first-child { border-top: 0; }
.sect-journee-corps { display: flex; flex-direction: column; gap: .15rem;
  flex: 1 1 auto; min-width: 0; }
.sect-journee-entree { display: flex; flex-direction: column; font-size: .84rem;
  line-height: 1.25; min-width: 0; }

/* ⚠️ L'HEURE EN COURS SE REPÈRE, par le fond et par l'accent sur le chiffre.
   Sur une colonne de dix heures identiques, retrouver « maintenant » demande
   sinon de lire l'horloge du système puis de compter les lignes. */
.sect-journee-heure.maintenant { background: var(--accent-doux); }
.sect-journee-heure.maintenant .sect-heure { color: var(--accent); font-weight: 600; }

/* ── Les écrans de la section, en tuiles ──────────────────────────────────
   *Direction, 24.09.2026 : « des tuiles et quelques indicateurs utiles. »*
   La liste plate d'avant mettait titre, compteur et réserve sur une seule
   ligne — « Marques 25 Bêta » se lisait comme une phrase sans en être une.

   ⚠️ PAS DE PHRASE SOUS LE TITRE : une glose par écran a été écrite puis
   retirée le 24.09 — « supprime toutes les phrases, on garde que les
   titres ». La tuile porte l'icône, le titre, le chiffre. Rien d'autre. */
/* ⚠️ DE L'AIR ENTRE LA LISTE ET LES TUILES — 20.10.2026.

   *Direction, capture à l'appui : « entre le premier box et les box en dessous
   (les tuiles), il manque d'espace et est trop fin. »*

   Le cadre de la liste et la grille des écrans se touchaient presque : deux
   blocs de même couleur à quelques pixels l'un de l'autre se lisent comme un
   seul, et le lien du bas du cadre semblait appartenir aux tuiles. Les deux
   répondent à des questions différentes — ce qui attend, puis où aller — et
   l'espace est ce qui le dit. */
.sect-ecrans { margin-top: 1.6rem; }
.sect-ecrans .etiquette-tech { margin-bottom: .6rem; }
/* ⚠️ `grid-auto-rows: 1fr` — TOUTES LES TUILES À LA MÊME HAUTEUR, D'UNE RANGÉE
   À L'AUTRE. *Direction, 07.10.2026 : « toutes les tuiles, de manière générale,
   devraient avoir la même hauteur et la même largeur. »*

   Mesuré dans Chromium avant de corriger : sur Paramètres, **89 px et 112 px**.
   En grille, les tuiles d'une MÊME rangée s'égalisent déjà — la rangée qui
   porte « Demandes de mot de passe » sur deux lignes fait 112, celle qui n'a
   que des textes courts en fait 89. C'est entre les rangées que ça se voit.

   ⚠️ LES LARGEURS, ELLES, ÉTAIENT DÉJÀ ÉGALES. La première mesure disait le
   contraire : son sélecteur attrapait aussi les compteurs du haut, qui sont un
   autre bloc et font 388 px. Elle fabriquait une inégalité qui n'existait pas,
   et aurait fait corriger une grille qui allait bien. */
.ecrans { list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  grid-auto-rows: 1fr; gap: .5rem; }
/* ⚠️ EN COLONNE, TOUJOURS — 08.10.2026.

   *Direction, capture des Paramètres à l'appui : « c'est pas très beau. Une
   fois, il y a un retour à la ligne, une fois, il n'y en a pas. Il faudrait un
   truc plus harmonisé pour cette partie-là. »*

   La tuile était `flex-wrap: wrap` avec `align-items: center` : « Équipe » et
   « Comptes » tenaient sur une ligne à côté de la pastille, « Accréditations »
   et « Demandes de mot de passe » passaient dessous. La grille montrait donc
   deux mises en page selon la longueur du titre, sans que rien ne le décide.

   ⚠️ ET ÇA NE COÛTE RIEN EN HAUTEUR : `.ecrans` porte `grid-auto-rows: 1fr`
   depuis le 07.10, donc toutes les tuiles font déjà la hauteur de la plus
   haute — c'est-à-dire celle d'un titre sur deux lignes. Uniformiser vers la
   forme la plus haute ne prend pas un pixel de plus.

   `flex-wrap: wrap` RESTE : c'est lui qui fait passer le compteur sous le
   titre quand la largeur manque, comportement demandé le 25.09. */
.ecran { position: relative; display: flex; flex-wrap: wrap;
  flex-direction: column; align-items: flex-start;
  column-gap: .75rem; row-gap: .35rem;
  padding: .9rem 1rem; border-radius: var(--r);
  color: var(--encre); text-decoration: none; border: 1px solid var(--trait);
  background: var(--surface); height: 100%;
  transition: border-color .12s, transform .12s, box-shadow .12s; }
.ecran:hover { border-color: var(--accent); transform: translateY(-1px);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .06); }

/* La pastille donne un point d'appui à l'œil : une grille de tuiles sans
   ancre se parcourt ligne à ligne, avec elle on saute d'icône en icône. */
.ecran-pastille { flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: var(--r);
  background: var(--accent-doux); color: var(--accent-encre, var(--accent)); }
/* ⚠️ `.ico` N'A DE TAILLE QUE PAR SA RÈGLE DE BASE : une icône posée sans
   taille revient à celle d'un SVG remplacé — 300 px de large — et fait
   exploser la grille. C'est ce qui est arrivé ici le 24.09. */
.ecran-pastille .ico { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }

/* ⚠️ NE JAMAIS REMETTRE `overflow-wrap: anywhere` ICI, ni `min-width: 0`.
   C'est ce couple qui a écrit « Clie/nts » et « Ambas/sad/eurs » le 25.09 :
   `min-width: 0` autorise le flex à comprimer le titre sous la largeur de
   son propre mot, et `anywhere` le casse alors au milieu. Un nom de section
   coupé en deux ne se lit plus — il vaut mieux une tuile plus haute.
   `min-content` pose le plancher : la largeur du mot le plus long, jamais
   moins. Ce qui déborde ensuite s'en va à la ligne, et c'est la réserve qui
   s'en va, parce qu'elle est le dernier élément. */
.ecran-titre { flex: 1 1 auto; min-width: min-content; font-size: .95rem; font-weight: 600; }
.ecran-compte { flex: 0 0 auto; font-family: var(--mono); font-size: .9rem;
  color: var(--gris); font-variant-numeric: tabular-nums; }
/* La réserve, en tout petit, après le compteur : on ne signale que ce qui
   surprend, et ça ne doit pas se lire à la place du titre.

   *Direction, 25.09.2026 : « le "en rodage" doit se mettre sous le titre
   quand il n'y a plus de place en largeur. »* C'est le conteneur qui le
   fait — `.ecran` est `flex-wrap: wrap` — et non cette règle : elle garde
   `nowrap` pour que l'étiquette ne se coupe pas elle-même en deux, et
   `margin-left: auto` pour qu'elle reste à droite, qu'elle tienne sur la
   ligne du titre ou qu'elle soit passée dessous. */
/* ── Le stade, dans le coin — 06.10.2026 ──────────────────────────────────
   *Direction : « le alpha beta, c'est un petit peu mal écrit comme ça. Il
   faudrait que ça soit plus dans le coin droit. »*

   `margin-left: auto` le poussait à droite DANS le flux : quand le titre
   était long, il passait à la ligne et la tuile grandissait d'une hauteur
   entière pour un caractère. Posé en absolu, il ne pousse plus rien.

   ⚠️ `.ecran` EST DÉJÀ `position: relative` — c'est ce qui rend ce
   positionnement possible sans rien ajouter. */
.ecran-stade { position: absolute; top: .45rem; right: .6rem;
  display: flex; align-items: center; justify-content: center;
  width: 1.05rem; height: 1.05rem; border-radius: 50%;
  font-size: .68rem; line-height: 1; font-weight: 600;
  color: var(--ocre); background: var(--surface-2); border: 1px solid var(--trait); }

/* La navigation en haut n'a pas de colonne : elle prend la largeur, et la
   grille repasse à une seule colonne. Sans ça, `.barre-haute` tombait dans la
   colonne du rail et s'écrasait à 230 px — le menu semblait avoir disparu. */
.app-haut {
  /* Deux colonnes quand la section porte une bande, une seule sinon. La barre
     s'étend sur toute la largeur — d'où `grid-column: 1 / -1` plus bas. */
  /* ⚠️ `minmax(0, …)` SUR LA COLONNE DE CONTENU, pour la même raison que
     `.app` : un `1fr` prend pour minimum la largeur min-content de la vue, et
     une seule ligne large la poussait au-delà de l'écran. Corrigé le
     03.10.2026, en même temps que `.app`. */
  grid-template-columns: auto minmax(0, 1fr);
  /* ⚠️ `auto 1fr` EST INDISPENSABLE, et l'oublier coûte la moitié de l'écran.
     `.app` porte `min-height: 100vh`. En DEUX COLONNES, cette hauteur étire le
     rail et la vue côte à côte — sans effet visible. En UNE colonne, la grille
     a deux RANGÉES, et `align-content: stretch` leur donne la moitié de la
     fenêtre chacune : la barre de navigation devenait haute de 390 px, avec
     ses cinq onglets flottant au milieu du vide. */
  grid-template-rows: auto 1fr;
}
.app-haut > .vue { margin: 0 auto; width: 100%; }

/* La pastille n'était dimensionnée que sous `.rail .bas` : hors du rail, elle
   revenait à la taille du texte. */
.barre-haute .pastille {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem; border-radius: 50%;
  background: var(--surface-2); font-size: .72rem; font-weight: 650;
}

/* ── La bande latérale d'une section — 24.09.2026 ─────────────────────────
   *Direction : « sinon c'est difficile à naviguer à l'intérieur d'une
   section. »*

   Elle ne contredit pas d'avoir sorti le rail : ce qui gênait, c'était
   l'accordéon — sept groupes repliés dont on ne voyait jamais l'état. Une
   bande qui montre les écrans de la section courante, tous dépliés, n'a rien
   à cacher.

   La barre s'étend sur les deux colonnes ; la bande prend la première, la vue
   la seconde. Quand le gabarit ne rend pas de bande, la première colonne vaut
   `auto` et se réduit à zéro toute seule. */
.app-haut > .barre-haute { grid-column: 1 / -1; }

.sous-rail {
  grid-column: 1; grid-row: 2;
  width: 13.5rem; padding: 1.1rem .7rem;
  border-right: 1px solid var(--trait);
  background: var(--surface);
}
/* ── L'accueil de la section, en tête du rail ────────────────────────────
   *Direction, 09.10.2026 : « une maison, pour qu'on comprenne que c'est la
   page d'accueil. »*

   Le lien existait ; il avait l'air d'une étiquette. Posé comme les écrans
   au-dessous — même rembourrage, même rayon, même accent quand il est
   courant — il se lit enfin comme ce qu'il est : une destination.

   ⚠️ IL GARDE SA MARGE DU BAS. Elle sépare l'accueil de la liste des écrans :
   ce n'est pas une entrée de plus, c'est ce qui les contient. Sans elle, la
   maison devient le premier élément d'une liste de cinq, et on perd
   exactement ce qu'on vient de gagner. */
.sous-rail-tete {
  display: flex; align-items: center; gap: .5rem;
  margin: 0 .5rem 1rem; padding: .42rem .55rem; border-radius: var(--r);
  text-decoration: none;
}
.sous-rail-tete:hover { background: var(--surface-2); }
.sous-rail-tete .ico { opacity: .55; }
.sous-rail-tete.actif { background: var(--accent-doux); }
.sous-rail-tete.actif .ico { opacity: 1; color: var(--accent); }
/* ⚠️ `.sous-rail-titre` A ÉTÉ RETIRÉE AVEC SON MARQUAGE — 11.10.2026.
   Le nom de la section a quitté la tête du rail ; laisser ses deux règles
   aurait fait ce que le dépôt a déjà payé ailleurs — des règles muettes qui
   survivent à leur classe et qu'on relit un an plus tard en se demandant ce
   qu'elles tenaient.

   « Accueil » porte donc la tête seul, et reprend le poids que le nom avait :
   ce n'est plus un qualificatif en petites capitales grises à droite, c'est
   le libellé du lien. */
.sous-rail-accueil { font-weight: 650; color: var(--encre); }
.sous-rail-tete.actif .sous-rail-accueil { color: var(--accent); }
.sous-rail nav { display: flex; flex-direction: column; gap: .1rem; }
.sous-rail nav a {
  display: flex; align-items: center; gap: .5rem;
  padding: .42rem .55rem; border-radius: var(--r);
  color: var(--gris); text-decoration: none; font-size: .88rem;
}
.sous-rail nav a:hover { background: var(--surface-2); color: var(--encre); }
.sous-rail nav a .ico { opacity: .55; }
/* L'écran courant, et lui seul, porte l'accent. */
.sous-rail nav a.actif { background: var(--accent-doux); color: var(--accent-encre, var(--accent)); font-weight: 600; }
.sous-rail nav a.actif .ico { opacity: 1; }
.sous-rail-nom { flex: 1 1 auto; min-width: 0; }
.sous-rail-compte { font-family: var(--mono); font-size: .74rem; }

@media (max-width: 860px) {
  /* Sous 860 px, la bande passe au-dessus de la vue et s'étale en ligne :
     13,5 rem de colonne sur un écran étroit ne laissent rien au contenu. */
  /* ⚠️ MÊME RAISON, ET C'EST ICI QUE ÇA SE JOUAIT. La déclaration de base de
     `.app-haut` portait bien `minmax(0, …)` — celle-ci, qui s'applique
     précisément sur un téléphone, l'avait perdu. Un garde qui ne regarde que
     la règle de base ne voit jamais celle qui compte sur mobile. */
  .app-haut { grid-template-columns: minmax(0, 1fr);
    /* ⚠️ TROIS RANGÉES ICI, ET C'EST TOUT LE SUJET. En deux colonnes, la
       grille a deux rangées — barre, puis (bande | vue) côte à côte — et
       `auto 1fr` est juste. En UNE colonne, la bande descend et il y en a
       TROIS : barre, bande, vue. `auto 1fr` laissait alors le `1fr` tomber
       sur la BANDE, qui s'étirait sur toute la hauteur restante à cause du
       `min-height: 100vh` de `.app` — sept cents pixels de vide entre le
       menu et le contenu, mesurés sur iPhone le 26.09.2026.

       Le commentaire de `.app-haut` avertissait déjà qu'oublier les rangées
       « coûte la moitié de l'écran ». Il avait raison, et la règle mobile
       posée le même jour a fait passer le nombre de rangées de deux à trois
       sans que personne ne revienne ici. */
    grid-template-rows: auto auto 1fr; }
  .sous-rail { grid-column: 1; width: auto; border-right: 0;
    border-bottom: 1px solid var(--trait); padding: .5rem .8rem; }
  .sous-rail-tete { display: none; }

  /* Même règle qu'au-dessus, même raison : une ligne qui défile plutôt que
     deux qui s'enroulent. */
  .sous-rail nav {
    flex-direction: row; flex-wrap: nowrap; gap: .25rem;
    overflow-x: auto; scrollbar-width: none;
    scroll-snap-type: x proximity;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.6rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 1.6rem), transparent);
  }
  .sous-rail nav::-webkit-scrollbar { display: none; }
  .sous-rail nav a { flex: 0 0 auto; scroll-snap-align: start; }
}

/* ── Le fil d'actualité — 24.09.2026 ──────────────────────────────────────
   *Direction : « les personnes puissent publier des informations
   générales. »* Le champ de publication est en tête, comme la barre de
   capture du cockpit : quand inscrire demande de changer d'écran, on
   n'inscrit pas. */
/* ⚠️ REPLIÉ PAR DÉFAUT DEPUIS LE 27.09.2026. *Direction : « il faut faire un
   bouton "Ajouter une information" et que ça se déplie, pas que le formulaire
   soit toujours ouvert. »* Le geste reste ici — c'est ce qui compte — mais il
   ne coûte plus un demi-écran à ceux qui viennent lire, ce qui est le cas le
   plus fréquent. */
.publier-repli { margin-bottom: 1.6rem; }
.publier-repli > summary {
  list-style: none; cursor: pointer; display: inline-flex; width: auto;
}
.publier-repli > summary::-webkit-details-marker { display: none; }
.publier-repli[open] > summary { margin-bottom: .7rem; }
.publier { margin-bottom: 0; }
.epingler-champ { display: flex; align-items: center; gap: .35rem;
  font-size: .84rem; color: var(--gris); }

.annonce {
  display: flex; gap: .8rem; align-items: flex-start;
  padding: .9rem 1rem; margin-bottom: .5rem;
  border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface);
}
/* Une annonce épinglée ne descend pas, et se voit sans crier : un filet
   d'accent à gauche, pas un fond coloré. Si tout appelle, plus rien n'appelle. */
.annonce-epinglee { border-left: 3px solid var(--accent); }
.annonce-corps { flex: 1 1 auto; min-width: 0; }
/* La signature EN TÊTE, comme pour les décisions de séance : sur un texte
   long, on ne doit pas lire jusqu'au bout pour savoir qui parle. */
.annonce-signe { display: flex; flex-wrap: wrap; align-items: center;
  gap: .35rem; margin: 0 0 .3rem; font-size: .76rem; }
.annonce-titre { margin: 0; font-size: 1rem; }
.annonce-texte { margin: .35rem 0 0; white-space: pre-line; overflow-wrap: anywhere; }
.annonce-gestes { flex: 0 0 auto; display: flex; gap: .3rem; }
.annonce-gestes form { display: inline; }

/* ── Le signe de protection d'une marque ─────────────────────────────────
   ™ pendant l'examen, ® une fois l'enregistrement obtenu. Petit, en exposant,
   collé au nom : c'est un attribut du nom, pas une colonne de plus.

   *Direction, 24.09.2026 : « juste on le voit quelque part avec le petit R. »*
   Le module des dépôts — 45 classes de Nice, territoires, échéances
   décennales — répondait à la même question en vingt fois plus de place. */
.marque-signe {
  font-size: 0.66em; vertical-align: super; letter-spacing: 0;
  color: var(--gris); text-decoration: none; border: 0; cursor: help;
  margin-left: 0.08em;
}

/* ── L'assistant flottant ────────────────────────────────────────────────
   *Direction, 24.09.2026 : « une fenêtre flottante pour l'assistant, qu'on
   puisse déplacer et prompter à l'intérieur […] qu'on puisse y accéder depuis
   n'importe où. »*

   `<dialog>` natif, ouvert par `show()` et non `showModal()` : on veut
   pouvoir continuer à lire l'écran pendant qu'on dicte. Un modal noircirait
   la page et ferait perdre justement ce qu'on veut décrire. */
/* ⚠️ La bulle flottante a été retirée le 25.09.2026 : elle faisait doublon
   avec « Commande » dans la barre du haut, qui ouvre la même fenêtre et porte
   son nom. La fenêtre ne tenait plus le bas de l'écran libre pour elle : elle
   remonte donc d'autant. */
.assistant-flottant {
  position: fixed; right: 1.1rem; bottom: 1.1rem; left: auto; top: auto;
  width: min(26rem, calc(100vw - 2rem)); max-height: 70vh; overflow: auto;
  padding: .9rem 1rem; z-index: 61;
  border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface); color: var(--encre);
  box-shadow: 0 6px 28px rgba(0, 0, 0, .18);
}
.assistant-flottant::backdrop { background: transparent; }
/* La poignée : `cursor: move` est la seule chose qui dise qu'on peut saisir. */
.af-tete {
  display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; margin-bottom: .6rem; cursor: move; user-select: none;
}
.af-forme { display: flex; flex-direction: column; gap: .5rem; }
.af-forme textarea { width: 100%; resize: vertical; }
.af-pied { margin: .6rem 0 0; font-size: .78rem; }


/* La suite du geste : ce que l'assistant propose, et ce qu'on en fait. */
.af-dernier { margin-top: .7rem; padding-top: .7rem;
  border-top: 1px solid var(--trait-clair); }
.af-reformulation { margin: 0 0 .5rem; font-size: .86rem; }
.af-refus { margin: 0 0 .6rem; font-size: .82rem; color: var(--rouge); }
.af-gestes { display: flex; align-items: center; gap: .5rem; }

/* La correction d'une annonce se voit — sinon on perdrait la garantie qu'on
   troque en rendant le fil modifiable. */
.annonce-corrigee { font-style: italic; }
.annonce-corriger { margin-top: .5rem; font-size: .84rem; }
.annonce-corriger summary { cursor: pointer; color: var(--gris); }
.annonce-corriger form { display: flex; flex-direction: column; gap: .4rem; margin-top: .5rem; }

/* Les comptes ouverts dans la session. Chacun s'est authentifié — ce n'est
   pas une usurpation, et le journal d'audit reste donc vrai. */
.barre-moi-comptes { margin: .6rem 0; display: flex; flex-direction: column; gap: .3rem; }
.barre-moi-comptes form { margin: 0; }
.barre-moi-comptes .bouton { width: 100%; text-align: left; }

/* Le défilement du Gantt. Sans lui, « hors de la fenêtre » était une impasse :
   on voyait qu'un projet existait sans pouvoir l'atteindre. */
.gantt-nav { display: inline-flex; gap: .25rem; margin-left: .6rem; }

/* ── La documentation des flux ───────────────────────────────────────────
   Écrit à la main, sans bibliothèque de diagramme : TR-23 interdit une
   dépendance front, et un enchaînement de cinq étapes n'en demande pas. Il
   s'imprime, se lit sans JavaScript, et se copie dans un courriel. */
.doc-flux-bloc { margin: 0 0 1.4rem; }
.doc-flux-bloc h2 { font-size: 1rem; margin: 0 0 .5rem; }
.doc-question { font-weight: 400; color: var(--gris); font-size: .84rem; margin-left: .5rem; }

/* La chaîne défile plutôt que de se replier : un flux qui passe à la ligne
   cesse de se lire comme une suite. */
.doc-chaine { display: flex; align-items: stretch; gap: .35rem; overflow-x: auto; padding-bottom: .4rem; }
.doc-etape {
  flex: 0 0 13rem; padding: .55rem .7rem;
  border: 1px solid var(--trait); border-radius: var(--r); background: var(--surface);
}
/* Une étape dont l'écran n'existe pas se voit. La masquer ferait croire que
   le flux est complet — c'est l'inverse qu'on veut montrer. */
.doc-etape-absente { border-style: dashed; opacity: .65; }
.doc-etape-tete { display: flex; align-items: baseline; gap: .4rem; font-size: .86rem; font-weight: 600; }
.doc-rang {
  flex: 0 0 auto; width: 1.15rem; height: 1.15rem; border-radius: 50%;
  background: var(--accent-doux); color: var(--accent-encre, var(--accent));
  font-family: var(--mono); font-size: .62rem; font-weight: 400;
  display: inline-flex; align-items: center; justify-content: center;
}
.doc-note { margin: .3rem 0 0; font-size: .75rem; color: var(--gris); line-height: 1.35; }
.doc-objets { margin: .35rem 0 0; display: flex; flex-wrap: wrap; gap: .2rem; }
.doc-objets code { font-size: .64rem; padding: .05rem .25rem; }
.doc-fleche { align-self: center; color: var(--gris); flex: 0 0 auto; }

.doc-rupture-quoi { margin: 0 0 .3rem; font-weight: 600; font-size: .88rem; }
.doc-ruptures, .doc-exigences { margin-top: 1.6rem; }

.doc-barres { display: flex; flex-direction: column; gap: .3rem; }
.doc-barre { display: grid; grid-template-columns: 9rem 1fr 4rem; align-items: center; gap: .6rem; }
.doc-barre-nom { font-size: .84rem; }
.doc-barre-piste { height: .55rem; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.doc-barre-part { display: block; height: 100%; background: var(--vert); }
.doc-barre-chiffre { font-family: var(--mono); font-size: .72rem; color: var(--gris); text-align: right; }

/* ─────────────────────────────────────────────────────────────────────────
   Les notes de version.

   *Direction, 06.10.2026 : « je veux un système plus compact. »* Une note de
   version se parcourt, elle ne se lit pas ligne à ligne : les puces se serrent
   et les intertitres ne coûtent qu'une demi-ligne de plus que le texte.
   ───────────────────────────────────────────────────────────────────────── */
.nv-section { margin-bottom: 1rem; }
.nv-section h2 { margin: 0 0 .6rem; font-size: 1.05rem; }
.nv-ligne { margin: 0 0 .25rem; padding-left: 1rem; position: relative; line-height: 1.4; }
.nv-ligne::before { content: "·"; position: absolute; left: .25rem; color: var(--accent); }

/* ─────────────────────────────────────────────────────────────────────────
   Le pied d'un cadre — là où vit le bouton qui valide ce qu'il contient.

   *Direction, 06.10.2026 : « problème d'espacement bouton enregistrer. »*

   `.barre` existait, et c'est elle qui était posée là. Elle est faite pour
   border un formulaire PLEINE LARGEUR : elle porte son propre fond, son bord
   haut et des marges intérieures qui doublent celles du cadre qui l'accueille.
   Dans un cadre, le bouton se collait au dernier choix et la bande débordait.

   Le pied de cadre fait le même travail — séparer, aérer — en acceptant
   d'être à l'intérieur de quelque chose.
   ───────────────────────────────────────────────────────────────────────── */
.cadre-pied { display: flex; gap: .6rem; align-items: center;
  margin-top: 1.2rem; padding-top: .9rem; border-top: 1px solid var(--trait); }

/* Les groupes de choix d'un écran de réglage respirent un peu plus que ceux
   d'un formulaire : il n'y en a que deux ou trois, et ils sont le sujet. */
.apparence .choix { margin-bottom: .3rem; }

/* ─────────────────────────────────────────────────────────────────────────
   La cellule « où ça en est » d'un participant.

   *Direction, 06.10.2026 : « c'est marqué "muet" 14 jours. Ça prend trop de
   place. J'aimerais un système plus compact. »*

   Le gabarit visait déjà le délai « DANS la cellule et non sous elle ». Il
   n'y arrivait pas : le <form> qui porte le menu d'état est un élément de
   BLOC, et le délai — même déclaré `inline-block` — retombait à la ligne.
   Vingt-trois invités, vingt-trois lignes de plus. Une intention juste qui
   ne produisait rien, et c'est ce qui l'a laissée passer.
   ───────────────────────────────────────────────────────────────────────── */
.cellule-etat { display: flex; align-items: center; gap: .4rem; flex-wrap: nowrap; }
.cellule-etat form { margin: 0; }

/* ─────────────────────────────────────────────────────────────────────────
   Mon profil.

   *Direction, 06.10.2026 : « pouvoir mettre une photo de profil dans la
   pastille en haut à droite […] une section "Profil". »*

   Deux champs par rangée — « Début/Échéance peut se coller l'un à côté de
   l'autre », même demande, même réponse.
   ───────────────────────────────────────────────────────────────────────── */
.profil-photo { display: flex; align-items: center; gap: 1rem; margin-bottom: .4rem; }
.profil-photo-gestes { display: flex; flex-direction: column; gap: .4rem; }
.profil-vignette { width: 4.5rem; height: 4.5rem; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--trait); display: block; }
.pastille-grande { width: 4.5rem; height: 4.5rem; font-size: 1.3rem; }
.profil-retirer { display: inline-flex; align-items: center; gap: .35rem;
  font-size: .82rem; color: var(--gris); }
.profil-champs { display: flex; gap: .8rem; flex-wrap: wrap; margin-bottom: .4rem; }
.profil-champs > div { flex: 1 1 14rem; min-width: 0; }

@media (max-width: 640px) {
  .profil-champs > div { flex: 1 1 100%; }
}

/* La photo dans la pastille du bandeau. Mêmes dimensions que les initiales :
   le bandeau ne doit pas changer de hauteur selon qui est connecté. */
.pastille-photo { width: 1.9rem; height: 1.9rem; border-radius: 50%;
  object-fit: cover; display: block; border: 1px solid var(--trait); }

/* La ligne qu'on vient d'atteindre par une ancre se signale un instant. Sans
   ça, « Ma journée » s'ouvre au bon endroit mais on ne sait pas laquelle des
   soixante lignes on cherchait. */
.ligne-jour:target { outline: 2px solid var(--accent); outline-offset: 2px;
  border-radius: var(--r); }

/* ─────────────────────────────────────────────────────────────────────────
   Le stade d'un geste — pas d'un module.

   *Direction, 06.10.2026 : « on met en version alpha […] aussi le bouton. »*

   Une mention, pas un bandeau : elle doit se voir sans se mettre en travers du
   geste qu'elle qualifie. Dire « alpha » n'excuse rien, ça empêche seulement
   de compter dessus.
   ───────────────────────────────────────────────────────────────────────── */
/* ⚠️ `.geste-alpha` A ÉTÉ RETIRÉE LE 09.10.2026, et la leçon reste écrite.

   Le bouton « Commande » est devenu une icône de 36 px : une pastille
   flottante n'y tient pas, et c'était précisément elle qui élargissait la page
   de 6 px. La classe n'avait plus aucun élément dans aucun gabarit.

   On la supprime plutôt que de la laisser dormir, parce qu'une classe sans
   élément est un piège : la prochaine personne la réutilisera en croyant
   qu'elle a été pensée pour son cas. Ce qui suit est ce qu'il faut savoir si
   quelqu'un veut un jour reposer une mention sur un bouton de bord. */
/* ⚠️ LA PASTILLE DÉBORDE DE SON BOUTON — C'EST VOULU, ET C'EST BORNÉ PLUS BAS.
   Mesuré le 06.10.2026 : `right: -.35rem` sur le bouton « Commande », qui est
   au bord droit de la barre, élargissait la PAGE de 6 px sur quatre tailles
   d'écran. Six pixels suffisent à faire défiler tout un téléphone.

   On ne corrige pas en posant `overflow-x: clip` sur `body` : ça marcherait,
   et ça rendrait AVEUGLE la mesure de débordement — `scrollWidth` vaudrait
   toujours `clientWidth`, et le prochain vrai défaut passerait inaperçu. Le
   garde est sur `.barre-haute` seule, avec `overflow-clip-margin` pour que la
   pastille reste visible. */
/* ⚠️ EN FLUX PAR DÉFAUT, EN SUPERPOSITION PAR EXCEPTION — la règle était
   écrite à l'envers, et ça se payait hors de l'endroit prévu.

   Mesuré sur iPhone le 06.10.2026 : la mention « en attente » d'un rôle, dans
   une cellule de tableau, élargissait la PAGE de 6 px. `position: absolute`
   sans ancêtre positionné se place par rapport au bloc conteneur initial —
   c'est-à-dire la page : `right: -.35rem` projetait la pastille six pixels
   hors de l'écran, où qu'elle se trouve dans le document.

   Six pixels suffisent à faire défiler tout un téléphone latéralement.

   L'exception se nomme donc, au lieu de se corriger après coup — et depuis le
   09.10.2026 il n'y en a plus aucune : `.geste-alpha`, la seule qui posait sa
   pastille en superposition, a disparu avec le bouton « Commande ». La règle
   ci-dessous est donc en flux, sans exception. Si quelqu'un en rouvre une, il
   lui faut un ancêtre en `position: relative` ET `right: 0`, jamais une valeur
   négative. */
.eti-stade { position: static; margin-left: .35rem;
  font-size: .62rem; line-height: 1; letter-spacing: .02em;
  padding: .12rem .28rem; border-radius: 3px;
  background: var(--surface-2); color: var(--gris); border: 1px solid var(--trait); }

/* ⚠️ `right: 0` ET NON `-.35rem`. Le débordement VERTICAL (`top`) n'élargit
   jamais la page ; le débordement HORIZONTAL, si — six pixels suffisaient à
   faire défiler un téléphone. La pastille se range donc au bord du bouton au
   lieu de mordre dessus : c'est la seule des deux directions qui coûtait
   quelque chose. */

/* ─────────────────────────────────────────────────────────────────────────
   Les blocs d'une fiche, côte à côte quand l'écran le permet.

   *Direction, 06.10.2026 : « je suis en 1920 × 1800, il y a beaucoup trop de
   place en largeur ; on pourrait mettre deux blocs, l'un d'un côté, l'autre de
   l'autre, pour les petits blocs. »*

   Les blocs sous un formulaire — personnes rattachées, capital, parties tenues
   — s'empilaient sur toute la largeur alors qu'ils tiennent chacun dans une
   demi-colonne. Sur un écran large, la page faisait trois fois sa hauteur utile
   et la moitié droite restait vide.

   ⚠️ CE N'EST PAS UNE GRILLE À DEUX COLONNES. `auto-fit` + `minmax` : le
   nombre de colonnes se calcule, il ne se décide pas. En dessous de 34 rem par
   bloc, on repasse à une seule colonne — un bloc comprimé se lit moins bien
   qu'un bloc empilé, et c'est exactement ce qu'on vient de corriger ailleurs.

   ⚠️ UN BLOC QUI PORTE UNE TABLE LARGE DÉCLARE `bloc-large`. Sans ça, la
   première table à quinze colonnes rendrait la grille illisible pour tous les
   blocs d'à côté — et l'on reviendrait en arrière au lieu de la corriger.
   ───────────────────────────────────────────────────────────────────────── */
.blocs { display: grid; grid-template-columns: repeat(auto-fit, minmax(34rem, 1fr));
  gap: 1rem; align-items: start; margin-top: 1.2rem; }
.blocs > .cadre { margin-top: 0; }
.bloc-large { grid-column: 1 / -1; }

/* Les deux raccourcis de report. Posés AVANT le sélecteur de date, parce que
   ce sont eux qu'on cherche neuf fois sur dix — et qu'une rangée de boutons
   sous un champ se lit comme une confirmation, pas comme un choix. */
.report-raccourcis { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .8rem; }

/* La revue Textus (#331) — un texte exact, ligne par ligne. Un <pre> rendrait
   CRLF comme LF : chaque ligne porte sa fin réelle, et pre-wrap garde les
   espaces de tête, de fin et multiples tels qu'écrits. */
.texte-exact { list-style: none; margin: 0 0 0.5rem; padding: 0.6rem 0.8rem; font-family: var(--mono);
  font-size: 0.86rem; line-height: 1.55; background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r); }
/* Le motif d'une décision garde ses retours à la ligne comme le texte ; les
   blancs de fin d'une ligne se voient, au lieu de disparaître à l'écran. */
.texte-exact-ligne, .motif-prive, .espaces-finaux { white-space: pre-wrap; overflow-wrap: anywhere; }
.espaces-finaux { background: var(--ocre-doux); }
.fin-de-ligne { margin-left: 0.35rem; font-size: 0.62rem; color: var(--gris); user-select: none; }
/* Relecture #415 : une image privée garde son rapport et reste dans la page. */
.image-revue { display: block; max-width: 100%; max-height: 28rem; object-fit: contain; }

/* ══════════════════════════════════════════════════════════════════════════
   LE RUBAN DE LA CHAÎNE — Réseaux sociaux, 12.10.2026
   ══════════════════════════════════════════════════════════════════════════

   Six cases dans l'ordre, celle où l'on se trouve allumée, celles qu'on n'a
   pas le droit de faire éteintes mais présentes. Le pourquoi est dans
   `socle/textus/partie-chaine.blade.php`.

   ⚠️ `list-style:none` ET `padding-left:0` : c'est un `<ol>` — sans les deux,
   le navigateur ajoute ses propres numéros À CÔTÉ des nôtres. */
.chaine {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem;
  list-style: none; padding: 0; margin: 0 0 1.1rem;
  font-size: .82rem;
}
.chaine > li { display: flex; align-items: center; }
/* La flèche entre deux cases vit sur le <li>, DEHORS de la pastille — posée
   en CSS et non dans le gabarit : elle se voit, elle ne se lit pas, et un
   lecteur d'écran n'a pas à l'entendre cinq fois. */
.chaine > li + li::before {
  content: "→"; margin: 0 .35rem; opacity: .4; color: var(--gris);
}
.chaine-pastille {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .3rem .7rem .3rem .4rem; border-radius: 999px;
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--gris); white-space: nowrap; text-decoration: none;
}
a.chaine-pastille:hover { color: var(--encre); border-color: var(--gris); }
.chaine-rang {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.3rem; height: 1.3rem; border-radius: 50%;
  background: var(--surface-2); font-variant-numeric: tabular-nums;
  font-size: .72rem; font-weight: 600;
}
.chaine-pastille.ici {
  border-color: var(--accent); background: var(--accent-doux);
  color: var(--accent); font-weight: 600;
}
.chaine-pastille.ici .chaine-rang { background: var(--accent); color: #fff; }
/* Éteint, mais lisible : une étape qu'on n'a pas le droit de faire est une
   information — elle dit où son travail s'arrête. */
.chaine-pastille.eteint { opacity: .45; }

/* ⚠️ LA RÉSERVE N'A PAS DE NUMÉRO, ET LE DESSIN DOIT LE DIRE. Ce n'est pas un
   geste : c'est l'endroit où la matière qualifiée attend qu'on vienne la
   prendre. Sans bordure pleine, elle se lit comme un palier entre deux
   étapes, et non comme une sixième case qu'on chercherait à faire. */
.chaine-pastille.chaine-palier {
  border-style: dashed; background: transparent;
  font-style: italic; padding-left: .7rem;
}

@media (max-width: 760px) {
  .chaine { font-size: .76rem; }
  .chaine-pastille { padding: .25rem .55rem .25rem .3rem; }
}

/* Un en-tête de colonne qui se clique le dit : il se souligne au survol et
   porte la flèche du sens courant. Même motif que la liste des évènements et
   celle des accréditations — zéro JavaScript, un lien et une requête. */
.tri-colonne { color: inherit; text-decoration: none; white-space: nowrap; }
.tri-colonne:hover { text-decoration: underline; color: var(--accent); }

/* L'intitulé d'un groupe dans la bande latérale. Il ne paraît que lorsque la
   section en porte plusieurs — voir `partie-sous-rail.blade.php`. Discret par
   construction : il sépare, il ne réclame pas d'être lu. */
.sous-rail-groupe {
  margin: 1.1rem 0 .3rem; padding: 0 .75rem;
  font-size: .68rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--gris);
}
.sous-rail-groupe:first-of-type { margin-top: .5rem; }

/* ── Les attestations de la qualification ─────────────────────────────────
   Une case qu'on coche, et sous elle la référence qui la soutient. Le
   décalage dit que le champ appartient à la case : sans lui, quatre lignes
   de même poids ne disent plus qui va avec quoi. */
.attestations { border: 0; padding: 0; margin: 0 0 .9rem; }
.attestations > legend {
  padding: 0; margin-bottom: .6rem;
  font-size: .78rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--gris);
}
.attestations .case {
  display: flex; align-items: flex-start; gap: .5rem;
  margin-top: .7rem; cursor: pointer; line-height: 1.35;
}
.attestations .case input { margin-top: .18rem; flex: none; }
/* Le champ vit sous sa case, décalé de la largeur de la coche. */
.champ-sous-case { margin: .35rem 0 0 1.45rem; }
.champ-sous-case label { font-size: .82rem; color: var(--gris); font-weight: 400; }

/* ⚠️ UNE IMAGE DÉPOSÉE DÉBORDAIT SA CARTE — 12.10.2026, dès qu'on a posé de
   vraies images au lieu d'un carré de 64 px. Aucune règle ne bornait les
   originaux : un visuel de 1200 px poussait la page au-delà de la fenêtre et
   le rail se décalait. Elles vivent dans `.cartel-corps`, sur la fiche d'une
   matière comme sur celle d'une publication. */
.cartel-corps img {
  display: block; max-width: 100%; height: auto;
  border-radius: 10px; border: 1px solid var(--trait-clair);
}

/* ══════════════════════════════════════════════════════════════════════════
   UN CHAMP NE S'ÉTIRE PAS SUR TOUTE LA FENÊTRE — 12.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction, quatre fois en deux jours : « le champ de texte est un tout
   petit peu bizarre » · « tout en largeur » · « t'as refait des inputs de
   texte de 1 000 px de large, ça ne fait pas de sens » · « plutôt que de
   faire un drop-down de 2 000 px de large ».*

   `.formulaire` était borné à 78 rem le 11.10, et ça n'a pas suffi : un champ
   posé DIRECTEMENT dans un `.cadre`, hors de la grille, n'héritait d'aucune
   borne et prenait toute la largeur de l'écran. Sur un portable en 2 560 px,
   une liste déroulante de deux mots faisait deux mètres.

   ⚠️ LA BORNE EST SUR LE CHAMP, PAS SUR LE FORMULAIRE : c'est la seule place
   qui attrape les deux cas, dans la grille comme hors d'elle.

   Les mesures viennent de la lecture : au-delà d'environ 70 caractères l'œil
   perd la ligne. 46 rem pour une ligne, 60 rem pour un bloc de texte qu'on
   relit. `.champ.large` et `.pleine-largeur` échappent délibérément — un
   tableau de saisie ou un éditeur veut sa largeur. */
.champ input, .champ select { max-width: 46rem; }
.champ textarea { max-width: 60rem; }

/* ⚠️ `.champ.large` N'EST PAS UNE EXEMPTION, et l'y mettre était une erreur
   faite puis mesurée le 12.10 : « large » dit que la CELLULE traverse la
   grille, pas que le champ doive faire deux mètres. L'intitulé du dépôt est
   `.champ.large` et tenait encore 1 248 px sur une fenêtre de 1 600.
   La seule échappatoire est explicite. */
.pleine-largeur input, .pleine-largeur select, .pleine-largeur textarea { max-width: none; }

/* Une liste déroulante suivie de son bouton : sur la même ligne, pas l'un
   sous l'autre. *Direction : « j'ai un bouton dessous. Tu mets ça sur la
   même ligne. »* */
.ligne-geste {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem;
  margin-top: .3rem;
}
.ligne-geste .champ { flex: 0 1 24rem; min-width: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   UNE BARRE DE FILTRES TIENT SUR UNE LIGNE, BOUTON COMPRIS — 12.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « le bouton filtre prend une ligne de largeur : c'est pas
   terrible, ce genre de design. »*

   Le bouton vivait hors de la grille `.formulaire`, donc sur sa propre rangée.
   Ici il est le dernier élément d'une rangée souple : les filtres prennent la
   place qu'ils demandent, le bouton se colle à leur suite, et tout passe à la
   ligne ensemble sur un écran étroit. */
.barre-filtres {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: .7rem;
}
/* Même règle pour l'autre barre de filtres, et pour la même raison : le
   libellé vit à côté de son champ, jamais au-dessus. `.champ` garde sa pile
   partout ailleurs — dans un formulaire, un libellé au-dessus de son champ est
   ce qui se lit le mieux. Ici, il coûte une ligne par filtre. */
.barre-filtres .champ { flex: 0 1 16rem; min-width: 0;
  flex-direction: row; align-items: center; gap: 0.45rem; }
.barre-filtres .champ > label { white-space: nowrap; }
.barre-filtres .champ input, .barre-filtres .champ select { max-width: none;
  flex: 1 1 auto; min-width: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   UN TABLEAU COMPACT — 12.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « on n'utilise pas la largeur : les lignes sont trop hautes.
   Il faudrait plutôt utiliser des colonnes. Il faut réduire la hauteur de ces
   listes aussi. »*

   Les listes du module empilaient des cartes de quatre lignes : onze sujets
   faisaient deux écrans, et 1 100 px restaient blancs à droite. Une rangée par
   objet, et ce qui varie devient une colonne — on compare au lieu de relire.

   ⚠️ LA PREMIÈRE COLONNE EST LA SEULE QUI S'ÉTIRE. Sans ça, cinq colonnes se
   partagent la largeur à parts égales et une date de dix caractères reçoit
   autant de place qu'un intitulé de dix mots. */
.table-compacte { table-layout: auto; }
.table-compacte th, .table-compacte td { padding: .4rem .6rem; vertical-align: top; }
.table-compacte td:first-child { width: 100%; }
.table-compacte .secondaire { font-weight: 400; }
.table-compacte .actions { white-space: nowrap; text-align: right; }

/* Les gestes d'une tâche, en tête de sa fiche. *Direction, 12.10.2026 : « il
   manque les boutons "Fait", "En attente", "Reporté". »* Ils vivaient sur les
   lignes des listes et nulle part sur la fiche. */
.gestes-de-la-fiche {
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  margin-bottom: 1.1rem;
}

/* ══════════════════════════════════════════════════════════════════════════
   LA POIGNÉE POUR DÉPLACER UN RENDEZ-VOUS — 13.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « il n'existe aucun moyen de déplacer l'heure dans
   Rendez-vous […] Toi, un petit modal. »*

   ⚠️ ELLE EST SŒUR DU BLOC, PAS SON ENFANT : le bloc est un `<a>`, et un
   bouton dans un lien est du HTML invalide — le navigateur en fait ce qu'il
   veut, et souvent rien. Elle se repositionne donc sur la même ligne de temps,
   avec le même `--depuis`.

   ⚠️ ET ELLE RESTE VISIBLE, sans survol. Un geste qui n'apparaît qu'au
   passage de la souris n'existe pas sur un téléphone — et c'est justement là
   qu'on consulte son agenda. Discrète, mais présente. */
.cal-g-deplacer {
  position: absolute;
  top: calc(var(--depuis) * var(--h-heure) + .15rem);
  right: .3rem;
  width: 1.15rem; height: 1.15rem;
  display: flex; align-items: center; justify-content: center;
  padding: 0; border: 0; border-radius: 4px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  color: var(--gris); font-size: .7rem; line-height: 1;
  cursor: pointer;
}
.cal-g-deplacer:hover, .cal-g-deplacer:focus-visible {
  background: var(--surface); color: var(--encre);
}

/* ══════════════════════════════════════════════════════════════════════════
   L'HEURE N'APPARTIENT QU'AU RENDEZ-VOUS — 13.10.2026
   ══════════════════════════════════════════════════════════════════════════

   *Direction : « les heures, ça ne doit être que sur les rendez-vous. Une
   tâche peut avoir un délai. »*

   ⚠️ `:has()` LIT L'OPTION SÉLECTIONNÉE, et c'est ce qui rend la bascule
   possible sans une ligne de JavaScript : `option:checked` s'applique à
   l'option retenue d'un `<select>`, et `:has()` la remonte au formulaire.
   Changer la nature montre ou cache les deux champs à l'instant, sans
   rechargement — TR-23 tenu, pas contourné.

   Le pourquoi de la règle est dans `taches/fiche.blade.php`. */
.champ-du-rdv { display: none; }
form:has(select[name="type"] option[value="rdv"]:checked) .champ-du-rdv { display: flex; }
