/* 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; }
a { color: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 ---- */
.app { display:grid; grid-template-columns:230px 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; font-weight:700; font-size:0.9rem; letter-spacing:0.02em;
  flex:0 0 auto; }
.rail .marque .nom { font-weight:600; font-size:1.05rem; letter-spacing:-0.01em;
  line-height:1.15; }
.rail .marque .nom span { display:block; font-family:var(--mono); font-size:0.62rem;
  text-transform:uppercase; letter-spacing:0.15em; opacity:0.5; font-weight:400;
  margin-top:0.15rem; }

.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; }
.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. */
.vue { padding:2rem 2.2rem 4rem; max-width:1180px; min-width:0; }
/* Un diagramme de Gantt à 1180px comprime trois mois dans une bande étroite.
   Les écrans qui montrent du temps prennent la largeur disponible. */
.vue-large { max-width:none; }
.entete { display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  margin-bottom:1.4rem; 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:1.05rem 1.15rem; }
.cadre > .defiler { margin:0.6rem -1.15rem -1.05rem; }
.cadre > .defiler:first-child { margin-top:-1.05rem; }
.cadre > :first-child { margin-top:0; }
.cadre > :last-child { margin-bottom:0; }
.cadre > p:last-child { margin-bottom:0; }
.defiler { 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; }
tbody td { padding:0.62rem 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. */

@media (max-width:620px) {
  .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; }

  .table-fiches tbody td { display:grid; grid-template-columns:6.5rem 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); 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 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); 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 ---- */
.formulaire { display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
  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; }
input[type=text], input[type=email], input[type=number], input[type=date],
input[type=password], 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; }
.barre { display:flex; gap:0.6rem; padding:1rem 1.4rem; border-top:1px solid var(--trait);
  background:var(--surface-2); }

/* ---- messages ---- */
.message { padding:0.7rem 0.95rem; border-radius:var(--r); border:1px solid;
  font-size:0.88rem; margin-bottom:1.2rem; }
.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); }

/* ---- accueil ---- */
.tuiles { display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,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 ---- */
.connexion { min-height:100vh; display:grid; place-items:center; padding:1.5rem; }
.connexion .boite { width:100%; max-width:23rem; }
.connexion .marque { font-size:1.5rem; font-weight:700; letter-spacing:-0.03em;
  margin-bottom:0.25rem; }
.connexion .sous { color:var(--gris); font-size:0.86rem; margin-bottom:1.5rem; }
.connexion form { display:flex; flex-direction:column; gap:0.9rem; padding:1.4rem;
  border:1px solid var(--trait); border-radius:var(--r); background:var(--surface); }

/* ═══════════════════════════════════════════════ 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) {
  .app { grid-template-columns: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; font-size:0.8rem; }

  /* 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; gap:0.32rem;
  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) ---- */
.gantt { min-width:820px; font-size:0.84rem;
  --largeur-semaine:calc(100% / 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; }
/*
 * 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; }
.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); }
.gantt-ligne:hover { background:var(--surface-2); }
.gantt-libelle { display:flex; align-items:center; gap:0.45rem; padding-right:1rem;
  overflow:hidden; }
.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; }

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

.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; }

.source {
  white-space: pre-wrap; font-size: 0.8rem; background: var(--surface-2);
  padding: 0.6rem; border-radius: 6px; max-height: 20rem; overflow: auto;
}

/* ---- 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(300px, 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; }
.poignee { position: absolute; top: 0; bottom: 0; width: 7px; cursor: ew-resize; }
.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. */
.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.55rem; margin: 1.6rem 0 0.9rem;
  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(150px, 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);
  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); }
.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); }

/* 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; }
.esp-noeud-marque { border-left-color: var(--violet, #5B1A8C); }
.esp-noeud-initiative { border-left-color: var(--accent); }
.esp-noeud-maison { 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);
  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 { max-width: 70ch; color: var(--gris); }

/* 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. */
.ech-bord { flex: none; width: 0.7rem; align-self: stretch; cursor: ew-resize; }
.ech-texte { padding: 0 0.2rem; overflow: hidden; text-overflow: ellipsis; }

/* ------------------------------------------------------------------
   Le cockpit — les chiffres en tête.

   *Direction, 06.08.2026 : « un mini tableau de bord en haut, des chiffres ».*
   Des tuiles cliquables, pas des cartes décoratives : chaque nombre mène au
   module qui le produit. Un chiffre qu'on ne peut pas ouvrir laisse la
   question « et alors ? » sans réponse.
   ------------------------------------------------------------------ */
.coc-chiffres { display: grid; gap: 0.7rem; margin-bottom: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); }

.coc-tuile { display: flex; flex-direction: column; gap: 0.1rem;
  padding: 0.85rem 1rem; border: 1px solid var(--trait); border-radius: var(--r);
  background: var(--surface); text-decoration: none; color: inherit;
  transition: border-color 0.15s, transform 0.15s; }
.coc-tuile:hover { border-color: var(--accent); transform: translateY(-1px); }

.coc-tuile-valeur { font-size: 1.9rem; font-weight: 650; line-height: 1;
  font-variant-numeric: tabular-nums; }
.coc-tuile-libelle { font-size: 0.82rem; }
.coc-tuile-detail { font-size: 0.72rem; color: var(--gris); }

.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 { max-width: 78ch; }
.asst-reformulation { max-width: 78ch; 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 { max-width: 78ch; 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 { max-width: 78ch; 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);
  max-width: 72ch; }

/* ─────────────────────────────────────────────────────────────────────────
   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(--fond-doux); 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 : la même piste, verrouillée, avec le motif du refus. */
.interrupteur-noyau .interrupteur-piste { background: var(--fond-doux); border-style: dashed; }

/* ──────────────────────────────────── 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. */
.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;
  background: var(--fond-doux);
}
.filtres-portefeuille label { display: flex; flex-direction: column; gap: 0.25rem; }
.filtres-portefeuille select { min-width: 10rem; }
.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. */
.cal-genre-rdv      { border-left: 3px solid var(--accent); }
.cal-genre-seance   { border-left: 3px solid var(--vert); }
.cal-genre-evenement{ border-left: 3px solid var(--ocre); }

/* 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-genre-rdv       { background: var(--accent); border: 0; }
.cal-legende .cal-genre-seance    { background: var(--vert); border: 0; }
.cal-legende .cal-genre-evenement { background: var(--ocre); border: 0; }
