/* ==========================================================================
   LEXPULSE — feuille de style du portail.

   Fichier SÉPARÉ, jamais un template literal dans du JS : un backtick posé
   dans un commentaire CSS y fermerait la chaîne et blanchirait toutes les
   pages d'un coup.

   Les couleurs d'accent (--accent, --accent-strong, --accent-ink) sont
   posées par brand.js sur <html>. Tout le reste s'en déduit par color-mix,
   ce qui évite d'avoir à recalculer une palette à chaque changement.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Jetons
   -------------------------------------------------------------------------- */

:root {
  --accent: #6644ff;
  --accent-strong: #4c2fd6;
  --accent-ink: #ffffff;

  --bg: #f6f7fb;
  --surface: #ffffff;
  --surface-2: #fbfbfd;
  --line: #e4e6ef;
  --line-soft: #eef0f6;
  --ink: #14141c;
  --ink-2: #4a4d60;
  --ink-3: #7c8098;

  --ok: #0f9d58;
  --warn: #d98324;
  --danger: #cf3050;
  --info: #2b7cd3;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 1px 2px rgba(20, 20, 30, .05), 0 8px 24px rgba(20, 20, 30, .06);
  --shadow-lg: 0 12px 48px rgba(20, 20, 30, .18);
  --rail: 248px;

  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
          'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

:root[data-theme='dark'] {
  --bg: #0f0f14;
  --surface: #17171f;
  --surface-2: #1c1c26;
  --line: #2a2a37;
  --line-soft: #23232f;
  --ink: #eceef6;
  --ink-2: #a8abc0;
  --ink-3: #767a92;

  --ok: #3ac07d;
  --warn: #e5a049;
  --danger: #f0637f;
  --info: #5aa2f0;

  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .35);
  --shadow-lg: 0 12px 48px rgba(0, 0, 0, .55);
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

/* L'attribut `hidden` ne vaut qu'une règle de feuille par défaut : n'importe
   quelle classe qui pose un `display` la bat. `.btn { display: inline-flex }`
   suffisait à peindre en permanence un bouton que le JS croyait masqué. */
[hidden] { display: none !important; }

/* Aucune hauteur fixe ici. `height: 100%` sur html ou body fige la boîte à
   la hauteur de la fenêtre : le contenu déborde, et le rail collant — qui ne
   peut pas coller au-delà de son parent — sort de vue dès le premier écran
   de défilement, en laissant une bande vide. La hauteur du châssis se dit
   une seule fois, en min-height sur .app. */

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* Le portail reste invisible tant que la charte n'est pas posée : sans ça,
   chaque page s'ouvre en violet Directus puis saute à la couleur choisie. */
html:not(.brand-ready) body { opacity: 0; }
html.brand-ready body { opacity: 1; transition: opacity .12s ease; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.01em; }
h1 { font-size: 22px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }

p { margin: 0 0 10px; }

hr { border: 0; border-top: 1px solid var(--line); margin: 18px 0; }

::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   3. Châssis : rail + contenu
   -------------------------------------------------------------------------- */

.app { display: flex; min-height: 100vh; }

.rail {
  width: var(--rail);
  flex: 0 0 var(--rail);
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  /* min-height:0 est ce qui autorise la colonne interne à défiler : sans
     lui, le rail pousse la page au lieu de se replier. */
  min-height: 0;
}

/* Le rail ne défile PAS. Il porte quinze liens, trois en-têtes, une porte
   épinglée, une tête et un pied : sur un écran de 768 px, la version 1.6
   sortait une barre de défilement dans le menu, et le bloc utilisateur —
   donc « Sign out » — passait sous la pliure. Tout ce qui suit est un budget
   de hauteur, pas une préférence esthétique : mesuré sur 768 px, la tête
   prend 59, la porte épinglée 37 et le pied 105 ; il reste 568 px de menu
   pour quinze liens de 28 et trois en-têtes de 27, soit 497. La tête et le
   pied ne se compriment jamais (flex: 0 0 auto) ; seul .rail-nav défile, et
   seulement une fois l'écran plus court que 700 px — là, c'est le menu qui
   glisse sous la main, pas le bouton de déconnexion qui disparaît. */
.rail-head, .rail-pinned, .rail-foot { flex: 0 0 auto; }

.rail-head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 14px 10px;
  border-bottom: 1px solid var(--line-soft);
}

.rail-logo { max-height: 26px; max-width: 128px; object-fit: contain; display: block; }
.rail-title { font-weight: 650; font-size: 13.5px; letter-spacing: -.01em; }
.rail-sub { font-size: 11px; color: var(--ink-3); }

.rail-nav {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* La gouttière est réservée en permanence : sans elle, l'apparition de la
     barre de défilement décale les quinze libellés de huit pixels au premier
     dépliage d'une catégorie. */
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  padding: 4px 8px 10px;
}

.rail-group {
  margin: 14px 0 6px;
  padding: 0 8px;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.rail-group:first-child { margin-top: 2px; }

.rail-link {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 9px;
  min-height: 28px;
  border-radius: 7px;
  color: var(--ink-2);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.35;
}
.rail-link:hover {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  color: var(--ink);
  text-decoration: none;
}
.rail-link[aria-current='page'] {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent-strong);
  font-weight: 620;
}
:root[data-theme='dark'] .rail-link[aria-current='page'] { color: var(--accent); }

/* L'icône n'est plus un glyphe mais un <svg> en trait : une grille centrée
   de 18 px, pour que les quinze libellés s'alignent quel que soit le dessin.
   Le trait suit la couleur du lien (currentColor), donc l'état « page
   courante » recolore l'icône sans qu'on ait à la redessiner. */
.rail-ico {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  /* Légèrement en retrait au repos : c'est le libellé qu'on lit, l'icône
     n'est qu'un repère de position dans la liste. */
  opacity: .68;
}
.rail-ico svg { width: 17px; height: 17px; flex: none; stroke: currentColor; }
.rail-link:hover .rail-ico { opacity: .9; }
.rail-link[aria-current='page'] .rail-ico { opacity: 1; }

.rail-foot {
  border-top: 1px solid var(--line-soft);
  padding: 8px;
}

.rail-user {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  width: 100%;
  background: none;
  border: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
  text-align: left;
}
.rail-user:hover { background: var(--surface-2); text-decoration: none; }

/* Le pied du rail est le poste le plus serré de la colonne : l'avatar y perd
   quatre pixels, que les liens du menu récupèrent. */
.rail-foot .avatar { width: 26px; height: 26px; flex: 0 0 26px; font-size: 11px; }

.avatar {
  width: 30px; height: 30px;
  flex: 0 0 30px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 650;
}

.main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 26px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.topbar h1 { flex: 0 1 auto; }
.topbar-sub { color: var(--ink-3); font-size: 12.5px; }
.topbar-spacer { flex: 1 1 auto; }
/* Le selecteur d entreprise ne doit pas manger la barre : il se dimensionne
   sur son contenu, pas sur la place disponible. */
.topbar select { max-width: 220px; width: auto; }

.page { padding: 22px 26px 60px; }

.burger { display: none; }

/* --------------------------------------------------------------------------
   4. Blocs
   -------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
/* L'en-tête d'une boîte se distinguait de son corps par un seul filet clair.
   Sur un fond de page déjà très proche du blanc, cela donnait des boîtes qui
   se lisaient comme un seul bloc dès qu'on en empilait trois. Un fond
   légèrement retiré et un titre plus ferme suffisent — pas une bordure de
   plus, qui aurait épaissi la grille. */
.card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface-2);
  border-radius: var(--radius) var(--radius) 0 0;
}
.card-head h2 { font-size: 13.5px; font-weight: 640; letter-spacing: -.005em; }
.card-body { padding: 16px; }

.grid { display: grid; gap: 14px; }
.grid.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* --- La tuile de compteur ------------------------------------------------ *
   Une icône teintée, l'intitulé à côté, le chiffre en dessous. Le lavis
   d'angle est une seule couche de dégradé : il donne du relief sans ajouter
   ni bordure ni ombre, et il disparaît de lui-même quand aucun ton n'est
   déclaré, ce qui laisse les tuiles neutres exactement comme avant.
 * ----------------------------------------------------------------------- */
.stat {
  --st: var(--accent);
  position: relative;
  overflow: hidden;
  padding: 14px 16px 15px;
}
.stat.t-danger { --st: var(--danger); }
.stat.t-warn   { --st: var(--warn); }
.stat.t-ok     { --st: var(--ok); }
.stat.t-info   { --st: var(--info); }
.stat.t-muted  { --st: var(--ink-3); }
.stat[class*='t-']::after {
  content: '';
  position: absolute;
  right: -34px; top: -34px;
  width: 96px; height: 96px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--st) 11%, transparent);
  pointer-events: none;
}
.stat-top { display: flex; align-items: center; gap: 7px; min-height: 20px; }
.stat-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  flex: none;
  border-radius: 6px;
  color: var(--st);
  background: color-mix(in srgb, var(--st) 13%, transparent);
}
.stat-icon svg { width: 14px; height: 14px; }
.stat-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.stat-value {
  font-size: 28px; font-weight: 680; letter-spacing: -.03em;
  margin-top: 7px;
  font-variant-numeric: tabular-nums;
}
.stat-note { font-size: 12px; color: var(--ink-3); margin-top: 3px; }

/* Barre de répartition : une mesure, pas une décoration. */
.bars { display: flex; flex-direction: column; gap: 9px; }
.bar-row { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center; }
.bar-name { font-size: 12.5px; color: var(--ink-2); }
.bar-num { font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.bar-track {
  grid-column: 1 / -1;
  height: 6px;
  border-radius: 3px;
  background: var(--line-soft);
  overflow: hidden;
}
.bar-fill { height: 100%; border-radius: 3px; background: var(--accent); }

/* Tout ce qui porte un chiffre porte un lien : un compteur sans moyen de
   voir ce qu'il recouvre oblige à refaire à la main le filtre qu'il vient
   d'appliquer. */
a.stat.linked, a.bar-row.linked, a.queue-row {
  color: inherit;
  text-decoration: none;
  display: block;
}
/* Une tuile qui mène quelque part le dit au survol : elle se soulève, et sa
   bordure prend SON ton plutôt que l'accent du portail — sinon quatre tuiles
   de quatre couleurs viraient toutes au violet sous le curseur. */
a.stat.linked {
  transition: border-color .14s, transform .14s, box-shadow .14s;
}
a.stat.linked:hover {
  border-color: color-mix(in srgb, var(--st) 55%, var(--line));
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(20, 20, 30, .05), 0 10px 28px rgba(20, 20, 30, .09);
  text-decoration: none;
}
:root[data-theme='dark'] a.stat.linked:hover {
  box-shadow: 0 2px 4px rgba(0, 0, 0, .45), 0 10px 28px rgba(0, 0, 0, .4);
}
a.bar-row.linked { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px;
                   align-items: center; padding: 2px 4px; margin: -2px -4px;
                   border-radius: var(--radius-sm); }
a.bar-row.linked:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }

a.queue-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 9px;
  margin: 0 -9px;
  border-radius: var(--radius-sm);
}
a.queue-row:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }

/* --------------------------------------------------------------------------
   5. Pastilles
   -------------------------------------------------------------------------- */

/* UNE QUESTION OUVERTE. Bord pointille, pas de fond : la pastille dit
   « rien n'est rempli » avant meme qu'on lise le mot. Le remplissage se
   compense sur l'interieur pour que la hauteur de ligne ne bouge pas —
   sinon une colonne d'axes ferait des marches d'escalier. */
.pill.gap {
  background: transparent;
  border: 1px dashed color-mix(in srgb, var(--ink-3) 48%, transparent);
  color: var(--ink-3);
  padding: 1px 7px;
  font-weight: 550;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
  background: var(--line-soft);
  color: var(--ink-2);
}
.pill.accent { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent-strong); }
.pill.ok     { background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok); }
.pill.warn   { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.pill.danger { background: color-mix(in srgb, var(--danger) 16%, transparent); color: var(--danger); }
.pill.info   { background: color-mix(in srgb, var(--info) 16%, transparent); color: var(--info); }
:root[data-theme='dark'] .pill.accent { color: var(--accent); }

/* --- Postures ------------------------------------------------------------
   Palette SÉPARÉE de ok/warn/danger, et le raisonnement est dans shell.js :
   une posture dit une DIRECTION, pas un mérite. Un acteur qui soutient un
   texte n'est une bonne nouvelle que si le texte sert le client, et le
   modèle sépare précisément les deux (`reg_assessments.direction` d'un côté,
   `reg_positions.stance` de l'autre). Le vert d'« opportunité » et le rouge
   de « risque » auraient réintroduit dans l'œil la confusion que le schéma
   écarte.

   D'où un axe teal → violet, lisible comme une orientation. Les deux teintes
   intermédiaires sont volontairement moins saturées : « conditionnel » et
   « réservé » sont des demi-pas, et se dessinent comme tels. La bordure porte
   l'essentiel du signal, ce qui laisse ces pastilles cohabiter avec une
   pastille de priorité dans la même cellule sans que l'une écrase l'autre. */
.pill.stance {
  border: 1px solid transparent;
  background: var(--line-soft);
  color: var(--ink-2);
}
.pill.stance-for {
  background: color-mix(in srgb, #0f9d8a 16%, transparent);
  border-color: color-mix(in srgb, #0f9d8a 42%, transparent);
  color: #0a7d6d;
}
.pill.stance-for-soft {
  background: color-mix(in srgb, #0f9d8a 9%, transparent);
  border-color: color-mix(in srgb, #0f9d8a 34%, transparent);
  color: #0a7d6d;
}
.pill.stance-mid {
  background: color-mix(in srgb, var(--ink-3) 12%, transparent);
  border-color: color-mix(in srgb, var(--ink-3) 34%, transparent);
  color: var(--ink-2);
}
.pill.stance-against-soft {
  background: color-mix(in srgb, #8c53d9 10%, transparent);
  border-color: color-mix(in srgb, #8c53d9 34%, transparent);
  color: #6b34bd;
}
.pill.stance-against {
  background: color-mix(in srgb, #8c53d9 18%, transparent);
  border-color: color-mix(in srgb, #8c53d9 46%, transparent);
  color: #6b34bd;
}
/* Le silence est une réponse, pas une absence : `not_public` veut dire que
   l'acteur a été cherché et n'a rien dit publiquement. Trait plein, teinte
   éteinte — l'inverse du pointillé d'`unknown`, qui dit qu'on ne sait pas. */
.pill.stance-silent {
  background: transparent;
  border-color: color-mix(in srgb, var(--ink-3) 40%, transparent);
  color: var(--ink-3);
  font-style: italic;
}
:root[data-theme='dark'] .pill.stance-for,
:root[data-theme='dark'] .pill.stance-for-soft { color: #4fd8bf; }
:root[data-theme='dark'] .pill.stance-against,
:root[data-theme='dark'] .pill.stance-against-soft { color: #bd93f5; }

.dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: 0 0 7px; }

/* --- En-têtes de tableau cliquables --------------------------------------
   Le bouton reprend la typographie du `th` plutôt que celle d'un bouton : ce
   n'est pas une action ajoutée au-dessus de la colonne, c'est la colonne qui
   devient cliquable. La flèche est le seul ajout visible, et elle est en
   place AVANT le survol — un affordance qui n'apparaît qu'au passage de la
   souris n'existe pas pour qui ne passe pas la souris. */
.th-sort {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
  max-width: 100%;
}
.th-sort > span:first-child { overflow: hidden; text-overflow: ellipsis; }
.th-arrow { opacity: .38; font-size: 11px; flex: 0 0 auto; }
.th-sort:hover { color: var(--ink); }
.th-sort:hover .th-arrow { opacity: .8; }
.th-sort:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
th.th-sorted { color: var(--ink); }
th.th-sorted .th-arrow { opacity: 1; color: var(--accent); }
th.num .th-sort { flex-direction: row-reverse; }

/* --------------------------------------------------------------------------
   6. Tables
   -------------------------------------------------------------------------- */

.table-wrap { overflow-x: auto; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
table.data th {
  text-align: left;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  background: var(--surface);
  /* PAS de `position: sticky` ici, et ce n'est pas un oubli : il y en avait
     un, et il n'a jamais tenu. `.table-wrap` porte `overflow-x: auto`, et
     par la specification Overflow un `overflow-y: visible` calcule alors
     `auto` — le cadre devient le port de defilement le plus proche de
     l'en-tete. Comme il n'a aucune contrainte de hauteur, il ne defile
     jamais : quand la page defile, le cadre s'en va en emportant son
     en-tete. Trois declarations pour rien sur toutes les listes.
     Un en-tete qui promet de tenir et ne tient pas vaut moins qu'un
     en-tete ordinaire. */
}
table.data td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
/* Seules les lignes qui S'OUVRENT prennent la main et la teinte. */
table.data.rows-open tbody tr { cursor: pointer; }
table.data.rows-open tbody tr:hover td {
  /* 5 % d'accent se voyait sur un fond blanc et disparaissait sur
     #17171f : la teinte y deplacait la surface de deux niveaux, sous le
     seuil du perceptible. Tous les autres jetons teintes de cette feuille
     sont poses entre 9 et 18 %. Le survol suit la clarte du theme. */
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) table.data.rows-open tbody tr:hover td {
    background: color-mix(in srgb, var(--accent) 15%, transparent);
  }
}
:root[data-theme="dark"] table.data.rows-open tbody tr:hover td {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
}
table.data td.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data td.tight { white-space: nowrap; }
.cell-strong { font-weight: 600; color: var(--ink); }
.cell-muted { color: var(--ink-3); font-size: 12px; }

/* --------------------------------------------------------------------------
   7. Formulaires et boutons
   -------------------------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.field label { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.field .hint { font-size: 11.5px; color: var(--ink-3); }

/* Les notes de section — « rapproché par le nom, pas par une jonction »,
   « priorité telle qu'évaluée pour XYLEM » — n'avaient de style que dans un
   `.field`. Partout ailleurs elles s'affichaient à la taille et à la couleur
   du corps de texte, donc exactement comme les faits qu'elles nuancent. Une
   réserve qui se lit comme une affirmation ne sert à rien. */
.hint {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-3);
}
.hint b, .hint strong { color: var(--ink-2); font-weight: 650; }
.sheet-section > .hint { margin: 0 0 9px; }

/* Une note de champ trop longue pour tenir sous le contrôle : la première
   phrase se lit d'un coup d'œil, le reste s'ouvre. */
details.ff-note-long > summary {
  cursor: pointer;
  list-style: none;
  color: var(--ink-3);
}
details.ff-note-long > summary::-webkit-details-marker { display: none; }
details.ff-note-long > summary::after {
  content: ' more';
  color: var(--accent);
  font-weight: 600;
}
details.ff-note-long[open] > summary::after { content: ' less'; }
details.ff-note-long > p { margin: 5px 0 0; }

input[type='text'], input[type='email'], input[type='password'],
input[type='search'], input[type='date'], input[type='datetime-local'],
input[type='number'], input[type='url'], input[type='time'],
select, textarea {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 6px 11px;
  width: 100%;
  min-width: 0;
}

/* UNE hauteur pour tous les contrôles. Le formulaire est déduit du schéma :
   il pose côte à côte un texte, une liste fermée et une date, dont les
   hauteurs natives diffèrent de plusieurs pixels selon le navigateur — la
   ligne partait alors de guingois sans qu'aucune règle ne l'explique.
   36 px est aussi le minimum confortable pour un doigt. */
input[type='text'], input[type='email'], input[type='password'],
input[type='search'], input[type='date'], input[type='datetime-local'],
input[type='number'], input[type='url'], input[type='time'], select {
  min-height: 36px;
}

/* L'anneau de focus est la BORDURE, pleine et à l'accent : c'est elle qui
   tient le rapport de contraste de 3:1 contre le fond des deux thèmes. Le
   halo ne fait que l'épaissir ; seul, à 20 % d'accent, il se lisait comme un
   reflet et disparaissait sur un écran mal réglé. */
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 32%, transparent);
}

/* Un champ qu'on ne peut pas écrire doit le dire AVANT qu'on y clique : sans
   fond distinct, on tape trois mots dans une case verrouillée avant de
   comprendre pourquoi rien ne s'affiche. Le trait discontinu distingue le
   champ en lecture seule — dont le texte se sélectionne et se copie — du
   champ désactivé, avec lequel il n'y a rien à faire du tout. */
input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-2);
  color: var(--ink-3);
  border-color: var(--line-soft);
  cursor: not-allowed;
}
input[readonly], textarea[readonly] {
  background: var(--surface-2);
  color: var(--ink-2);
  border-style: dashed;
}
input[type='color'] {
  padding: 2px;
  height: 36px;
  width: 56px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
}
select { appearance: none; padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
                    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 16px) 15px, calc(100% - 11px) 15px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font: inherit;
  font-weight: 600;
  /* Même hauteur que les champs : dans une barre de filtres, un bouton et un
     sélecteur se suivent sur la ligne, et trois pixels d'écart se voient
     autant qu'un décalage franc — sans qu'on sache d'où il vient. */
  padding: 6px 14px;
  min-height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { background: var(--surface-2); text-decoration: none; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn.ghost { border-color: transparent; background: transparent; color: var(--ink-2); }
.btn.ghost:hover { background: var(--surface-2); color: var(--ink); }
.btn.sm { padding: 4px 10px; font-size: 12.5px; min-height: 30px; }
.btn.block { width: 100%; }

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  align-items: center;
  margin-bottom: 14px;
}
.toolbar .grow { flex: 1 1 220px; min-width: 160px; }
.toolbar select, .toolbar input { width: auto; min-width: 140px; }

/* Choix en pilules : un select de trois valeurs se lit mieux comme trois
   boutons. Le label du .field ne doit PAS les déguiser en légendes. */
.choices { display: flex; gap: 6px; flex-wrap: wrap; }
.choice {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.choice[aria-pressed='true'] {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  color: var(--accent-strong);
}
:root[data-theme='dark'] .choice[aria-pressed='true'] { color: var(--accent); }

/* --------------------------------------------------------------------------
   8. États
   -------------------------------------------------------------------------- */

.empty {
  padding: 42px 20px;
  text-align: center;
  color: var(--ink-3);
}
.empty strong { display: block; color: var(--ink-2); font-size: 14px; margin-bottom: 4px; }

.notice {
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: 13px;
  color: var(--ink-2);
  margin-bottom: 14px;
}
.notice.warn   { border-color: color-mix(in srgb, var(--warn) 45%, var(--line));
                 background: color-mix(in srgb, var(--warn) 9%, transparent); }
.notice.danger { border-color: color-mix(in srgb, var(--danger) 45%, var(--line));
                 background: color-mix(in srgb, var(--danger) 9%, transparent); }

.skel {
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--line-soft), var(--line), var(--line-soft));
  background-size: 200% 100%;
  animation: sweep 1.2s linear infinite;
}
@keyframes sweep { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* Squelette de demarrage, pose par l'enveloppe HTML avant tout appel
   reseau. Il reprend la geometrie du chassis — rail de 248 px, barre
   haute, page — pour que la bascule vers le vrai contenu soit un
   remplissage et non un saut de mise en page. */
.bootskel { display: flex; min-height: 100vh; }
.bootskel-rail {
  width: var(--rail);
  flex: 0 0 var(--rail);
  background: var(--surface);
  border-right: 1px solid var(--line);
  padding: 20px 16px;
}
.bootskel-main { flex: 1 1 auto; min-width: 0; }
.bootskel-top {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 26px;
  border-bottom: 1px solid var(--line);
}
.bootskel-page { padding: 22px 26px; }
@media (max-width: 900px) { .bootskel-rail { display: none; } }

/* Le squelette de page pose par le chassis, entre la peinture du menu et
   la premiere ligne rendue par la page. */
.pskel { display: grid; gap: 18px; }
.pskel-bar { display: flex; gap: 10px; flex-wrap: wrap; }

/* Barre d'activite : deux pixels en haut de la fenetre, des qu'un appel
   depasse 250 ms (le seuil est dans api.js — une barre qui clignote a
   chaque frappe informe moins que le silence).

   Posee sur <html> et non sur la barre haute : elle doit exister aussi sur
   l'ecran de connexion et pendant que le chassis n'est pas encore peint,
   c'est-a-dire precisement quand l'attente est la plus longue. */
html[data-busy]::after {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  z-index: 900;
  pointer-events: none;
  background-image: linear-gradient(90deg,
    transparent, var(--accent), transparent);
  background-size: 42% 100%;
  background-repeat: no-repeat;
  animation: busybar 1.05s ease-in-out infinite;
}
@keyframes busybar {
  from { background-position: -42% 0; }
  to   { background-position: 142% 0; }
}
@media (prefers-reduced-motion: reduce) {
  /* Sans mouvement, une barre fixe pleine largeur dirait « fini » alors
     qu'elle dit « en cours » : on garde un liseré discret, immobile. */
  html[data-busy]::after {
    animation: none;
    background-image: none;
    background-color: var(--accent);
    opacity: .55;
  }
}

/* Un texte long dans une cellule de liste.
   reg_markets.regulatory_issues monte a 3 000 caracteres : rendu sans
   plafond, UNE ligne de tableau tenait sur plus de deux ecrans et la liste
   cessait d'etre parcourable. Le texte entier reste en infobulle, et la
   fiche le porte en entier. */
.clamp2, .clamp3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.clamp2 { -webkit-line-clamp: 2; line-clamp: 2; }
.clamp3 { -webkit-line-clamp: 3; line-clamp: 3; }

/* LE FILET DE SECURITE, et il compte plus que le plafond lui-meme.

   `-webkit-line-clamp` borne la HAUTEUR d'une boite, jamais sa largeur
   intrinseque. Sous `table-layout: auto` — le defaut — le navigateur
   dimensionne chaque colonne sur le texte ENTIER de la cellule la plus
   longue. Un `regulatory_issues` de 3 000 caracteres reclamait donc toute
   la table : mesure du 2026-08-31 sur la liste des marches, 2 148 px de
   tableau dans un cadre de 978, dont 1 682 px pour la seule colonne Size,
   et le nom du marche ecrase a 95 px, un mot par ligne.

   Le plafond en `ch` ne vaut QUE dans une cellule de tableau : dans une
   carte, la meme classe doit pouvoir occuper toute la largeur offerte. */
table.data td .clamp2,
table.data td .clamp3,
table.data td.clamp2,
table.data td.clamp3 { max-width: 44ch; }

/* Mise en page FIXE, demandee par le descripteur de la liste. Les
   proportions cessent d'etre le resultat du contenu le plus long : elles
   sont declarees, donc stables d'une page de resultats a l'autre. Sans
   cela, changer de page de resultats redessinait les colonnes. */
table.data.fixed { table-layout: fixed; }

/* Sous une largeur imposee, une reference sans espace, une URL ou un code
   de regle sortirait de sa cellule et passerait sous la colonne voisine. */
table.data.fixed th,
table.data.fixed td { overflow-wrap: anywhere; }

.toast-host {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 400;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.toast {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  padding: 10px 14px;
  font-size: 13px;
  max-width: 340px;
}
.toast.err { border-left-color: var(--danger); }

/* --------------------------------------------------------------------------
   9. Fiche (panneau latéral)
   -------------------------------------------------------------------------- */

/* La fiche est une PAGE, pas un volet. Un dossier réglementaire porte une
   dizaine de sections et plusieurs tableaux liés : dans une colonne de
   680 px, tout se lit deux fois plus long pour rien. Le rail reste en place,
   seule la zone de contenu est remplacée. */
.rec { padding: 22px 26px 60px; }

.rec-head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
.rec-head h2 { font-size: 21px; line-height: 1.3; letter-spacing: -.015em; }
.rec-kicker {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 4px;
}

/* Deux colonnes quand la place le permet : les sections sont courtes et
   nombreuses, les empiler gaspille toute la largeur gagnée. */
.rec-body { columns: 2; column-gap: 34px; max-width: 1500px; }
.rec-body > .sheet-section,
.rec-body > .lede { break-inside: avoid; }
.rec-body > .lede { column-span: all; }
@media (max-width: 1100px) { .rec-body { columns: 1; } }

.sheet-section {
  margin: 0 0 22px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.sheet-section > h3 {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 9px;
}

.kv { display: grid; grid-template-columns: 175px minmax(0, 1fr); gap: 8px 16px; }
.kv dt { font-size: 12.5px; color: var(--ink-3); }
.kv dd { margin: 0; font-size: 13px; overflow-wrap: anywhere; }
.kv dd.long { white-space: pre-wrap; }

.lede {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 12px 14px;
  margin-bottom: 18px;
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* Une pastille CLIQUABLE. Elle se distingue de `.pill` par cela seulement,
   et c'est ce qui doit se voir : une bordure au survol, un curseur de lien.
   Sert aux juridictions rattachées d'un dossier — l'émoji de drapeau vient
   de la base, donc aucune image à charger dans une cellule de tableau. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.7;
  white-space: nowrap;
  text-decoration: none;
}
a.chip:hover {
  border-color: var(--accent);
  color: var(--accent-strong);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
:root[data-theme='dark'] a.chip:hover { color: var(--accent); }
.chip.muted { color: var(--ink-3); background: none; }
/* Un axe encore ouvert MAIS déjà documenté. Les deux ne s'excluent pas : une
   pièce répond à la question, elle ne la tranche pas — seul un humain le
   fait. La pastille dit donc les deux à la fois, et le nombre distingue
   « à chercher » de « à lire ». */
.chip.chip-fed { border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
/* Un axe ouvert que RIEN NE PEUT CHERCHER. Trait pointillé, pas de curseur de
   lien : la pastille ne promet aucune action, parce qu'il n'y en a pas à
   cette place — la valeur manque faute de règle, pas faute de source. */
.chip.chip-mute {
  border-style: dashed;
  background: none;
  color: var(--ink-3);
  cursor: default;
}
.chip-x {
  margin-left: 5px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  opacity: .75;
}
.chip-n {
  margin-left: 5px;
  padding: 0 5px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ok) 20%, transparent);
  color: var(--ok);
  font-size: 10.5px;
  font-weight: 700;
}

/* reg_dossiers.sources est du HTML produit par un générateur, avec styles en
   ligne. On l'assainit en JS, et on neutralise ici ce qu'il reste. */
.rich { font-size: 13px; line-height: 1.55; overflow-wrap: anywhere; }
.rich * { max-width: 100%; font-family: inherit !important; font-size: inherit !important;
          color: inherit !important; background: none !important; }
.rich a { color: var(--accent) !important; }
.rich ul, .rich ol { padding-left: 20px; margin: 6px 0; }
.rich table { border-collapse: collapse; }
.rich td, .rich th { border: 1px solid var(--line); padding: 5px 8px; }

.mini { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.mini th { text-align: left; font-weight: 650; color: var(--ink-3); font-size: 11px;
           text-transform: uppercase; letter-spacing: .05em; padding: 6px 8px;
           border-bottom: 1px solid var(--line); }
.mini td { padding: 7px 8px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }

/* --------------------------------------------------------------------------
   10. Connexion
   -------------------------------------------------------------------------- */

/* Fond blanc net, sans dégradé ni vignette : c'est le premier écran, il n'a
   rien à raconter. En sombre il prend le fond sombre du portail — la bascule
   est dans le coin. */
.login {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: #ffffff;
}
:root[data-theme='dark'] .login { background: var(--bg); }

.login-card { width: 100%; max-width: 392px; padding: 28px; }
.login h1 { font-size: 19px; margin-bottom: 3px; }

.login-theme {
  position: fixed;
  top: 16px;
  right: 16px;
}
.login .sub { color: var(--ink-3); font-size: 13px; margin-bottom: 20px; }
.login .err {
  color: var(--danger);
  font-size: 12.5px;
  min-height: 18px;
  margin-bottom: 8px;
}
.login-foot { margin-top: 16px; font-size: 12px; color: var(--ink-3); text-align: center; }

/* --------------------------------------------------------------------------
   11. Calendrier
   -------------------------------------------------------------------------- */

.cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px;
       background: var(--line); border: 1px solid var(--line);
       border-radius: var(--radius); overflow: hidden; }
.cal-dow { background: var(--surface); padding: 7px 8px; font-size: 11px; font-weight: 650;
           letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); text-align: center; }
.cal-cell { background: var(--surface); min-height: 96px; padding: 6px 7px; }
.cal-cell.out { background: var(--surface-2); }
.cal-cell.today .cal-num { background: var(--accent); color: var(--accent-ink); }
.cal-num { display: inline-grid; place-items: center; width: 20px; height: 20px;
           border-radius: 50%; font-size: 11.5px; font-weight: 600; color: var(--ink-2); }
.cal-ev {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 11.5px;
  line-height: 1.3;
  margin-top: 3px;
  padding: 3px 5px;
  border: 0;
  border-left: 2px solid var(--accent);
  border-radius: 3px;
  background: color-mix(in srgb, var(--accent) 11%, transparent);
  color: var(--ink);
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Une échéance contraignante et une réunion supposée ne se dessinent pas
   pareil : le trait plein dit « confirmé », le pointillé dit « projeté ». */
.cal-ev.deadline { border-left-color: var(--danger);
                   background: color-mix(in srgb, var(--danger) 11%, transparent); }
.cal-ev.soft { border-left-style: dashed; }

/* Vue cartes — un événement ou un dossier qui se lit d'un coup d'œil, sans
   les colonnes d'un tableau. */
.cards { display: grid; gap: 12px;
         grid-template-columns: repeat(auto-fill, minmax(285px, 1fr)); }
.ev-card {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 13px 15px;
}
.ev-card:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
                 box-shadow: var(--shadow); }
.ev-card.deadline { border-left-color: var(--danger); }
.ev-card.soft { border-left-style: dashed; }
.ev-card h3 { font-size: 13.5px; line-height: 1.35; margin: 4px 0 6px; }
.ev-when { font-size: 11.5px; font-weight: 650; letter-spacing: .04em;
           text-transform: uppercase; color: var(--ink-3); }
.ev-meta { font-size: 12px; color: var(--ink-3); margin-bottom: 8px; }

/* --------------------------------------------------------------------------
   12 bis. Cartographie des acteurs

   Nuage de points : abscisse opposants → soutiens, ordonnée influence sur le
   dossier. Les deux axes sont des listes fermées, donc discrets : les points
   sont dispersés dans leur case pour ne pas se superposer.
   -------------------------------------------------------------------------- */

.map-wrap { position: relative; }
.map-plot {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  min-height: 380px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.map-quad { position: absolute; inset: 0; display: grid;
            grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.map-quad > span { border-right: 1px dashed var(--line);
                   border-bottom: 1px dashed var(--line); }
.map-quad > span:nth-child(2n) { border-right: 0; }
.map-quad > span:nth-child(n+3) { border-bottom: 0; }
.map-quad-label {
  position: absolute;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  opacity: .75;
  pointer-events: none;
}
/* Le point et son libelle voyagent ensemble : le conteneur porte la
   position, le point et le texte se placent par rapport a lui. */
.map-point { position: absolute; transform: translate(-50%, 50%); }
.map-point .map-dot { position: static; transform: none; }

.map-label {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  font-size: 10.5px;
  font-weight: 620;
  color: var(--ink-2);
  pointer-events: none;
  text-shadow: 0 0 3px var(--surface), 0 0 3px var(--surface), 0 0 3px var(--surface);
}
.map-label.right { left: calc(100% + 5px); }
.map-label.left { right: calc(100% + 5px); }
.map-point:hover .map-label { color: var(--ink); z-index: 3; }
.map-point:hover { z-index: 3; }

.map-dot {
  position: absolute;
  transform: translate(-50%, 50%);
  border: 0;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--surface);
}
.map-dot:hover, .map-dot:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.map-dot.supportive { background: var(--ok); }
.map-dot.opposed { background: var(--danger); }
.map-dot.neutral { background: var(--ink-3); }
.map-dot.mixed { background: var(--warn); }

.map-axis-x, .map-axis-y {
  display: flex; justify-content: space-between;
  font-size: 11px; font-weight: 600; color: var(--ink-3);
}
.map-axis-x { margin-top: 7px; }
/* Ordre naturel du DOM : High en tête, donc en haut. `column-reverse`
   retournait l'échelle sans toucher aux points — le nuage était juste et la
   graduation mentait. */
/* Bornée au cadre, pas au conteneur : étendue jusqu'en bas, la graduation
   verticale venait se poser sur la ligne de l'axe horizontal. */
.map-axis-y { flex-direction: column; align-items: flex-end;
              position: absolute; left: -74px; top: 0; bottom: 30px; width: 66px;
              text-align: right; }
.map-legend { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px;
              font-size: 12px; color: var(--ink-2); }
.map-legend b { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
                margin-right: 5px; vertical-align: baseline; }


/* --------------------------------------------------------------------------
   12. Révision 1.4.0 — assistant, recherche, sélecteurs, édition de fiche
   -------------------------------------------------------------------------- */

/* `.rail-cta` — l'encadré coloré de l'assistant — a été RETIRÉ en 1.7.0 :
   shell.js ne l'émet plus, l'assistant est devenu un lien épinglé comme le
   tableau de bord. Les règles partent avec lui plutôt que de rester à
   attendre un balisage qui ne reviendra pas : une classe stylée sans être
   émise se relit dans six mois comme une régression à réparer. */

/* --- Recherche globale de la barre haute --------------------------------- */

.gsearch { position: relative; flex: 0 1 300px; min-width: 150px; }
.gsearch-input { width: 100%; padding-right: 30px; }
.gsearch-key {
  position: absolute;
  right: 9px;
  top: 50%;
  transform: translateY(-50%);
  font: 600 10.5px/1 var(--mono);
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 3px 5px;
  pointer-events: none;
  background: var(--surface-2);
}
.gsearch-input:focus + .gsearch-key { display: none; }

/* Ancré sur le bord DROIT de la boîte de recherche : ouvert à gauche, un
   menu de 460 px posé sur un champ situé aux trois quarts de la barre sort
   de l'écran par la droite, et rien ne le rattrape. */
.gsearch-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 6px);
  right: 0;
  left: auto;
  width: min(460px, 88vw);
  max-width: min(92vw, 460px);
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 5px;
}
.gsearch-group {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 9px 10px 4px;
}
.gsearch-foot {
  border-top: 1px solid var(--line-soft);
  margin-top: 5px;
  padding: 9px 10px 5px;
  font-size: 12px;
}

/* --- Sélecteur cherchable ------------------------------------------------ */

.combo { position: relative; display: inline-block; min-width: 150px; }
.combo-input { width: 100%; padding-right: 26px; }
.combo-clear {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  border: 0;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
  padding: 4px;
}
.combo-clear:hover { color: var(--ink); }
/* Le menu d'un sélecteur cherchable est ancré à GAUCHE par défaut — c'est
   sûr partout où le contrôle est en début de ligne — et borné en largeur.
   Le débord constaté sur la carte d'influence vient du cas inverse : quatre
   sélecteurs alignés, dont le troisième commence à 928 px du bord dans une
   fenêtre de 1280 — son menu de 420 px finissait 68 px dehors, et rien ne
   le rattrapait. Deux garde-fous, dans cet ordre :
   `data-align="right"` posé par le JS gagne toujours ; à défaut, la règle
   ci-dessous bascule d'elle-même les sélecteurs tardifs d'une barre de
   filtres. Le défaut doit rester sûr, car rien ne garantit que l'attribut
   soit posé. */
.combo-menu {
  position: absolute;
  z-index: 55;
  top: calc(100% + 4px);
  left: 0;
  right: auto;
  min-width: 100%;
  width: max-content;
  max-width: min(92vw, 420px);
  max-height: 300px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  padding: 4px;
}
.combo-opt {
  padding: 7px 9px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  line-height: 1.35;
}
.combo-opt:hover, .combo-opt.on { background: var(--surface-2); }
.combo-opt[aria-selected='true'] {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-strong);
}
.combo-empty { padding: 10px; color: var(--ink-3); font-size: 12.5px; }

/* De quel côté s'ouvre le menu : c'est le JS qui tranche, à l'ouverture, en
   mesurant. Une règle de position dans la feuille de style ne peut que DEVINER
   — « à partir du troisième sélecteur d'une barre » — et une devinette ne se
   contredit pas : sur la carte d'influence, un filtre replié qui passait à la
   ligne se retrouvait aligné à droite pour rien, et son menu recouvrait le rail
   de navigation sur vingt-cinq pixels. La page qui mesure, elle, sait. */
.combo[data-align='right'] .combo-menu { right: 0; left: auto; }

@media (max-width: 860px) {
  /* Sur un écran étroit, aucun des deux alignements n'est sûr : le champ
     peut être n'importe où sur une ligne qui s'enroule. Le menu se cale donc
     sur la largeur de son champ, quitte à serrer les libellés — un menu
     étroit se lit, un menu hors cadre ne se lit pas. */
  .combo-menu { width: 100%; min-width: 0; max-width: 100%; }
}

/* --- Actions et sommaire d'une fiche ------------------------------------- */

.rec-actions { display: flex; gap: 6px; flex-wrap: wrap; }

/* --- Le pied d'archivage --------------------------------------------------
   Le geste le plus engageant de la fiche, seul en bas à droite, après tout
   le reste — discussion comprise. `column-span: all` lui fait traverser les
   deux colonnes de `.rec-body`, sinon il tomberait au milieu d'une colonne,
   à mi-hauteur de l'autre. Pas une `.sheet-section` : les onglets l'ignorent
   et il reste visible quel que soit l'onglet ouvert. */
.rec-archive-bar {
  column-span: all;
  display: flex;
  justify-content: flex-end;
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* Une fiche de dossier porte treize sections : sans ce sommaire, atteindre
   les positions publiques demande de faire défiler tout le reste. */
.rec-toc {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  gap: 5px;
  overflow-x: auto;
  padding: 8px 0 12px;
  margin-bottom: 4px;
  background: linear-gradient(to bottom,
    var(--bg) 70%, color-mix(in srgb, var(--bg) 0%, transparent));
  scrollbar-width: thin;
}
.rec-toc button {
  flex: 0 0 auto;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  border-radius: 999px;
  padding: 5px 11px;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}
.rec-toc button:hover { background: var(--surface-2); color: var(--ink); }

/* --- Formulaire d'édition ------------------------------------------------ */

/* Le corps d'une fiche est en deux colonnes ; un formulaire coupé en deux
   ferait passer un champ d'une colonne à l'autre au moindre redimensionnement,
   et le bandeau de sauvegarde se retrouverait au milieu. */
.rec-body.editing { columns: 1; max-width: 980px; }
.rec-body > .notice { column-span: all; }

.rec-editbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  position: sticky;
  top: 0;
  z-index: 6;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: 16px;
  box-shadow: var(--shadow);
}

/* Au-delà de 980 px, deux colonnes de champs deviennent deux colonnes de
   champs LOINTAINS : l'œil fait l'aller-retour d'un bord à l'autre entre
   l'intitulé et la case suivante. */
.rec-form { display: grid; grid-template-columns: 1fr 1fr; gap: 15px 20px;
            max-width: 980px; }
.rec-form .ff.wide { grid-column: 1 / -1; }
@media (max-width: 760px) { .rec-form { grid-template-columns: 1fr; } }

.ff { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

/* L'intitulé était en petites capitales espacées de 11 px : élégant sur
   « Status », illisible sur « Institutional footprint status ». Un formulaire
   déduit du schéma porte des noms longs — il lui faut une casse normale, une
   taille de lecture, et une couleur plus proche du texte que du gris de
   commentaire, parce que c'est l'intitulé qui dit ce qu'on remplit. */
.ff > label {
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink-2);
}
/* Visible sans crier : l'astérisque doit se remarquer en balayant la
   colonne, pas devenir le premier rouge de la page. */
.ff .req, .ff-required-note .req {
  margin-left: 2px;
  font-weight: 700;
  color: color-mix(in srgb, var(--danger) 78%, var(--ink-3));
}
.ff input, .ff select, .ff textarea { width: 100%; }
/* Une case à cocher ou un bouton radio n'est pas un champ de saisie : la
   règle ci-dessus l'étirait sur toute la largeur de la colonne, ce qui
   donnait une case de 400 px de large qu'on ne savait plus où cliquer. */
.ff input[type='checkbox'], .ff input[type='radio'] {
  width: 16px; height: 16px; flex: 0 0 16px;
  min-height: 0;
  accent-color: var(--accent);
}
.ff textarea { resize: vertical; min-height: 78px; font: inherit; }

/* L'aide se lit comme une phrase, pas comme un second intitulé : plus petite
   que le champ, en gris, sans graisse. Deux libellés empilés au-dessus d'une
   même case font hésiter sur lequel décrit quoi. */
.ff-note { font-size: 12px; color: var(--ink-3); margin: 0; line-height: 1.45;
           font-weight: 400; }

/* Une date, un entier ou un code pays occupaient toute une colonne : le champ
   annonçait une saisie longue là où trois caractères suffisent. */
.ff.narrow { max-width: 260px; }

/* Un compteur de caractères se pose sous le champ, à droite, en chiffres à
   chasse fixe — sinon il gigote à chaque frappe. */
/* L'avertissement d'approche de la limite. forms.js pose la classe `over` à
   90 % de `max_length` et rien ne la stylait : le compteur s'affichait à
   l'identique à 0/255 et à 250/255, donc l'alerte calculée n'existait pas à
   l'écran et l'utilisateur découvrait la troncature en tapant dans le vide. */
.ff-char.over { color: var(--warn); font-weight: 650; }

.ff-char {
  align-self: flex-end;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Une case à cocher n'a pas d'intitulé AU-DESSUS : la case et son libellé se
   lisent sur une ligne, comme dans toute case à cocher. */
.ff-inline { flex-direction: row; align-items: center; gap: 9px; }
.ff-inline > label {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
}
/* La taille de la case est posée plus haut, pour tous les .ff : il ne reste
   ici que la marge, que le navigateur pose d'office autour d'une case. */
.ff-inline input[type='checkbox'] { margin: 0; }

/* Le rappel de l'astérisque vit en pied de formulaire, une seule fois. */
.ff-required-note {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 11.5px;
  color: var(--ink-3);
}

/* --- Un groupe de champs ------------------------------------------------- */

/* Trente champs déduits du schéma se suivent sans respiration ; le groupe dit
   lesquels se répondent. C'est un <fieldset>, donc les lecteurs d'écran
   annoncent la légende avant chaque champ du groupe — un <div> n'aurait fait
   qu'un cadre. */
.ff-group {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px 20px;
  /* Un fieldset refuse par défaut de descendre sous la largeur de son
     contenu : sans min-width, un champ long élargit la page entière. */
  min-width: 0;
  margin: 2px 0 0;
  padding: 4px 16px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.ff-group > legend {
  grid-column: 1 / -1;
  padding: 0 6px;
  margin-left: -6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ff-group > .ff.wide, .ff-group > .ff-note { grid-column: 1 / -1; }
@media (max-width: 760px) { .ff-group { grid-template-columns: 1fr; } }

.switch { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.switch input { width: auto; }

/* --- Carte d'influence : la bulle partagée ------------------------------- */

/* Un acteur qui soutient un texte et s'oppose à un autre est placé à sa
   moyenne, qui n'est la position de personne. Les hachures le disent. */
.map-dot.split {
  background-image: repeating-linear-gradient(
    45deg, rgba(255, 255, 255, .55) 0 2px, transparent 2px 5px);
}
.map-legend b.hatch {
  background: var(--ink-3);
  background-image: repeating-linear-gradient(
    45deg, rgba(255, 255, 255, .6) 0 2px, transparent 2px 5px);
}
.map-label i { font-style: normal; opacity: .6; font-size: 9.5px; }
.mini tr[data-pos] { cursor: pointer; }
.mini tr[data-pos]:hover { background: var(--surface-2); }

/* --------------------------------------------------------------------------
   13. Assistant
   -------------------------------------------------------------------------- */

.asst {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
@media (max-width: 900px) { .asst { grid-template-columns: 1fr; } }

.asst-side {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

/* Collant SEULEMENT en deux colonnes. En une seule, la liste des
   conversations et le fil occupent deux rangees de la meme grille : un rail
   colle s'y peint par-dessus le fil des qu'on defile, et les deux
   deviennent illisibles. */
@media (min-width: 901px) {
  .asst-side { position: sticky; top: 12px; }
}
.asst-find { width: 100%; }
.asst-threads {
  display: flex;
  flex-direction: column;
  gap: 3px;
  max-height: 58vh;
  overflow-y: auto;
  /* min-height: 0 est ce qui autorise une colonne de grille à défiler :
     sans lui, la liste pousse la page au lieu de défiler elle-même. */
  min-height: 0;
}
.asst-thread {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  border: 1px solid transparent;
  background: transparent;
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  cursor: pointer;
  color: var(--ink-2);
  font: inherit;
}
.asst-thread:hover { background: var(--surface-2); color: var(--ink); }
.asst-thread.on {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-color: color-mix(in srgb, var(--accent) 28%, var(--line));
  color: var(--ink);
}
.asst-thread-t {
  font-size: 13px;
  font-weight: 560;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.asst-thread-d { font-size: 11px; color: var(--ink-3); }

.asst-main {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.asst-bar { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* La fiche sur laquelle porte la conversation. Elle vaut pour tout le fil,
   donc elle vit AU-DESSUS du flux de messages et non dedans : poussée avec
   les messages, elle disparaîtrait au troisième échange — au moment précis
   où l'on ne sait plus de quoi on parlait. */
.asst-context {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.asst-context-main { min-width: 0; flex: 1 1 auto; }
.asst-context-kicker {
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.asst-context-title {
  font-size: 15px;
  font-weight: 650;
  color: var(--ink);
  line-height: 1.35;
  margin-top: 2px;
}
.asst-context-sub { font-size: 12.5px; color: var(--ink-2); margin-top: 2px; }
.asst-context-act { flex: 0 0 auto; }
@media (max-width: 620px) {
  .asst-context { flex-direction: column; gap: 8px; }
}

.asst-stream {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 340px;
  max-height: 62vh;
  overflow-y: auto;
  padding: 4px 2px;
  scroll-behavior: smooth;
}

.asst-msg { display: flex; }
.asst-msg.me { justify-content: flex-end; }
.asst-bubble {
  max-width: 86%;
  border-radius: var(--radius);
  padding: 12px 15px;
  font-size: 14px;
  line-height: 1.6;
  border: 1px solid var(--line);
  background: var(--surface);
}
.asst-msg.me .asst-bubble {
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  border-color: color-mix(in srgb, var(--accent) 26%, var(--line));
}
.asst-bubble > :first-child { margin-top: 0; }
.asst-bubble > :last-child { margin-bottom: 0; }
.asst-bubble p { margin: 0 0 9px; }
.asst-bubble ul, .asst-bubble ol { margin: 0 0 9px; padding-left: 20px; }
.asst-bubble li { margin: 3px 0; }
.asst-bubble h3, .asst-bubble h4, .asst-bubble h5 {
  font-size: 13.5px;
  margin: 14px 0 6px;
  letter-spacing: -.01em;
}
.asst-bubble code {
  font: 12px/1.4 var(--mono);
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  padding: 1px 4px;
}

.asst-bubble pre {
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin: 0 0 9px;
  overflow-x: auto;
}
.asst-bubble pre code {
  background: none;
  border: 0;
  padding: 0;
  font: 12px/1.5 var(--mono);
  white-space: pre;
}

.asst-tool {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: 12px;
  color: var(--ink-3);
  padding: 5px 0;
  border-top: 1px dashed var(--line-soft);
  margin-top: 7px;
}
.asst-tool:first-child { border-top: 0; margin-top: 0; }
.asst-tool-ico { opacity: .7; }
.asst-sources { font-size: 12px; color: var(--ink-3); margin-top: 7px; }
.asst-sources summary { cursor: pointer; }
.asst-sources ul { margin: 6px 0 0; padding-left: 18px; }

.asst-wait { color: var(--ink-3); }
.dots { display: inline-flex; gap: 3px; }
.dots i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--ink-3);
  animation: asstdot 1.1s infinite ease-in-out;
}
.dots i:nth-child(2) { animation-delay: .16s; }
.dots i:nth-child(3) { animation-delay: .32s; }
@keyframes asstdot {
  0%, 70%, 100% { opacity: .25; transform: translateY(0); }
  35% { opacity: 1; transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .dots i { animation: none; opacity: .6; }
  .asst-stream { scroll-behavior: auto; }
}

/* Toute écriture proposée par l'assistant passe par cette carte. Elle est
   volontairement plus lourde que le reste : on ne clique pas Apply par
   inadvertance. */
.asst-approve {
  border: 1px solid color-mix(in srgb, var(--warn) 45%, var(--line));
  background: color-mix(in srgb, var(--warn) 7%, var(--surface));
  border-radius: var(--radius);
  padding: 14px 16px;
}
.asst-approve-head { font-weight: 650; font-size: 13.5px; margin-bottom: 6px; }
.asst-approve p { margin: 0 0 10px; font-size: 13px; color: var(--ink-2); }
.asst-approve .kv { margin: 0 0 12px; }

.asst-compose {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 8px;
}
.asst-compose textarea {
  flex: 1;
  border: 0;
  outline: none;
  resize: none;
  background: transparent;
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  padding: 6px 6px;
  color: var(--ink);
  max-height: 200px;
}
.asst-foot { font-size: 11.5px; margin: 0; }

.asst-blank { padding: 30px 6px; max-width: 620px; }
.asst-blank h2 { font-size: 18px; margin: 0 0 8px; letter-spacing: -.015em; }
.asst-seeds { display: flex; flex-direction: column; gap: 7px; margin-top: 18px; }
.asst-seed {
  text-align: left;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font: inherit;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.asst-seed:hover {
  background: var(--surface-2);
  color: var(--ink);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
}


/* --------------------------------------------------------------------------
   17. Révision 1.5.0 — favoris, encarts, pleine largeur, drapeau
   -------------------------------------------------------------------------- */

/* --- Favoris ------------------------------------------------------------ */

.star {
  border: 0;
  background: none;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 3px;
  color: var(--ink-3);
  transition: color .12s ease, transform .12s ease;
}
.star:hover { color: var(--warn); transform: scale(1.15); }
.star.on { color: var(--warn); }
.star.big { font-size: 20px; padding: 4px 6px; }
@media (prefers-reduced-motion: reduce) { .star { transition: none; } }

/* La colonne d'étoile ne prend que sa place, et n'attire pas l'œil avant le
   contenu de la ligne. */
td.fav-cell, th.fav-cell { padding-left: 6px; padding-right: 0; width: 34px; }

/* --- Une section qui refuse les deux colonnes --------------------------- */

/* Un tableau de six colonnes ou un graphique rétréci à une demi-largeur
   devient une bouillie qu'il faut faire défiler de côté. Ce qui est large se
   déclare large. */
.rec-body > .sheet-section.wide { column-span: all; break-inside: auto; }

/* --- Groupe etiquete dans une fiche -------------------------------------- */

/* Onze marches a la file ne disent pas qu'une entreprise fait de la
   manufacture ET du service d'eau ; deux groupes le disent d'un coup. */
.kv-block { margin: 0 0 12px; }
.kv-block:last-child { margin-bottom: 0; }
.kv-block > .cell-muted {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  margin-bottom: 5px;
}
.kv-block code.muted {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
}

/* --- Onglets de fiche ---------------------------------------------------- */

/* Le sommaire disait ou aller ; les onglets RETIRENT ce qu'on ne regarde pas.
   Colles sous la tete de fiche, ils restent atteignables en defilant une
   section longue. */
.rec-tabs {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
  margin: 0 0 18px;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--bg);
}
.rec-tabs button {
  font: inherit;
  font-size: 13px;
  font-weight: 550;
  color: var(--ink-2);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  padding: 9px 13px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}
.rec-tabs button:hover {
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.rec-tabs button[aria-selected="true"] {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
/* Le compte appartient a l'onglet et pas au libelle : il dit combien de
   sections attendent derriere, ce qui est la seule chose qu'on veut savoir
   avant de cliquer. */
.rec-tab-n {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 1px 7px;
  min-width: 20px;
  text-align: center;
}
.rec-tabs button[aria-selected="true"] .rec-tab-n {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
/* Sous onglets, le sommaire ne liste qu'un onglet : il redevient court, donc
   il se pose au fil du texte plutot qu'en colonne collante. */
.rec-tabs ~ .rec-toc { position: static; }

@media (max-width: 700px) {
  .rec-tabs { gap: 0; }
  .rec-tabs button { padding: 8px 10px; font-size: 12.5px; }
}

/* --- Encarts de chiffres ------------------------------------------------ */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
}
.tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* CENTRE. Un chiffre est une valeur, pas le debut d'une phrase : cale a
     gauche dans une boite large, il flotte loin de son intitule et l'oeil
     doit revenir en arriere pour les apparier. Centres, le nombre et son
     libelle forment un bloc qui se lit d'un coup. */
  align-items: center;
  text-align: center;
  justify-content: center;
  padding: 14px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: inherit;
  text-decoration: none;
  min-width: 0;
}
a.tile:hover {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 7%, var(--surface-2));
  text-decoration: none;
}
.tile-n { font-size: 21px; font-weight: 680; letter-spacing: -.02em; line-height: 1.1; }
.tile-l { font-size: 11.5px; color: var(--ink-2); }
.tile-h { font-size: 10.5px; color: var(--ink-3); }

/* --- Carte encastrée dans une fiche ------------------------------------- */

.rec-map { padding-left: 62px; margin-bottom: 14px; }
.map-wrap.compact .map-plot { height: 300px; }
.map-wrap.compact .map-label { font-size: 9.5px; }
@media (max-width: 700px) {
  .rec-map { padding-left: 46px; }
  .map-wrap.compact .map-plot { height: 260px; }
}

/* La ligne du client en périmètre, dans un tableau qui en liste plusieurs. */
.mini tr.mine > td { background: color-mix(in srgb, var(--accent) 8%, transparent); }

/* --- Chronologie : l'échéance en tête, le texte brut en pied ------------ */

.tl-head {
  margin: 0 0 12px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-size: 13px;
}
.tl-raw { margin-top: 14px; font-size: 12px; }
.tl-raw summary { cursor: pointer; color: var(--ink-3); }
.tl-raw pre {
  white-space: pre-wrap;
  font: 11.5px/1.5 var(--mono);
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  padding: 10px;
  margin: 8px 0 0;
  max-height: 260px;
  overflow-y: auto;
}

/* --- Bandeau de juridiction --------------------------------------------- */

.flag-hero { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.flag-glyph {
  font-size: 54px;
  line-height: 1;
  /* Les émoji drapeaux n'ont pas de glyphe sur toutes les plateformes ; la
     pile ci-dessous couvre Windows, macOS et Linux, et le code ISO reste
     affiché à côté pour le cas où aucune ne réponde. */
  font-family: 'Twemoji Country Flags', 'Noto Color Emoji', 'Apple Color Emoji',
               'Segoe UI Emoji', sans-serif;
}
.flag-facts { min-width: 0; flex: 1 1 260px; }
.flag-facts p { margin: 8px 0 0; font-size: 12.5px; }

/* --- Carte d'événement : l'étoile vit à côté du bouton ------------------ */

.ev-card-wrap { position: relative; }
.ev-card-wrap .star {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
}
.ev-card-wrap .ev-card { padding-right: 34px; }

/* --------------------------------------------------------------------------
   18. Petits écrans

   Le portail était utilisable sur téléphone ; il n'y était pas confortable.
   Ce qui suit règle les quatre gênes réelles : une barre haute qui tient sur
   une ligne au prix de tout écraser, des filtres qui prennent un écran
   entier, une fiche dont la tête bouge à chaque défilement, et des tableaux
   qu'on croit tronqués faute de voir qu'ils défilent.
   -------------------------------------------------------------------------- */

@media (max-width: 860px) {
  /* La barre haute passe sur deux rangées plutôt que de comprimer le titre
     à trois caractères. La recherche occupe la seconde, sur toute la
     largeur : c'est le contrôle le plus utilisé du portail. */
  .topbar { flex-wrap: wrap; gap: 8px 10px; row-gap: 8px; }
  /* L'espaceur pousse tout ce qui le suit sur une ligne à lui : sur un
     téléphone il laissait la bascule jour/nuit seule au milieu de rien. */
  .topbar-spacer { display: none; }
  .topbar h1 { font-size: 17px; }
  .topbar-sub { display: none; }
  .gsearch { order: 10; flex: 1 1 100%; min-width: 0; }
  .gsearch-menu { width: 100%; right: auto; left: 0; }
  .gsearch-key { display: none; }
  .topbar select { max-width: 150px; }

  /* Le rail ouvert assombrit ce qu'il recouvre : sans ce voile, on ne sait
     pas qu'un panneau est ouvert par-dessus la page. */
  .rail { box-shadow: var(--shadow-lg); }
  .rail.open::after {
    content: '';
    position: fixed;
    inset: 0 0 0 var(--rail);
    background: rgba(10, 10, 16, .34);
    z-index: -1;
  }

  /* Une fiche : la tête cesse d'être collante — sur 640 px de haut, elle
     mangeait un tiers de l'écran à chaque défilement. */
  .rec { padding: 16px 14px 48px; }
  .rec-head { flex-wrap: wrap; gap: 8px; }
  .rec-head h2 { font-size: 18px; }
  .rec-actions { flex: 1 1 100%; }
  .rec-toc { position: static; }

  /* Les tableaux défilent : sans cette ombre au bord, on les croit coupés. */
  .table-wrap {
    background:
      linear-gradient(to right, var(--surface) 30%, transparent),
      linear-gradient(to left, var(--surface) 30%, transparent) 100% 0,
      radial-gradient(farthest-side at 0 50%, rgba(20,20,30,.14), transparent),
      radial-gradient(farthest-side at 100% 50%, rgba(20,20,30,.14), transparent) 100% 0;
    background-repeat: no-repeat;
    background-size: 36px 100%, 36px 100%, 14px 100%, 14px 100%;
    background-attachment: local, local, scroll, scroll;
  }

  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .toolbar { gap: 8px; }
  .toolbar select, .toolbar input, .combo { min-width: 0; }
  .combo { flex: 1 1 140px; }

  /* Une cible de doigt fait 44 px. Les étoiles et les petits boutons étaient
     à 26 ; les pastilles de filtre portent désormais 36 px partout. */
  .btn.sm { min-height: 34px; }
  .star { font-size: 18px; padding: 6px; }
  .chip-off { min-height: 30px; }
}

@media (max-width: 620px) {
  /* Deux colonnes de bulles ne tiennent pas : la carte devient une bande. */
  .map-plot { height: 300px; }
  .map-quad-label { display: none; }
  /* Sans coupure, un nom d'organisation sort du cadre par la droite et
     se superpose au bord du graphique. */
  .map-label {
    max-width: 72px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .page { padding: 14px 12px 48px; }
  .card-body { padding: 13px; }
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tile-n { font-size: 18px; }

  /* La liste des conversations passe au-dessus du fil et se replie : sur un
     téléphone, on vient écrire, pas parcourir un historique. */
  .asst-threads { max-height: 180px; }
  .asst-bubble { max-width: 94%; }

  /* Le sommaire d'une fiche reste utile, en plus petit. */
  .rec-toc button { font-size: 11px; padding: 4px 9px; }

  .cards { grid-template-columns: minmax(0, 1fr); }
}


/* --- Un tableau de six colonnes dans 375 px n'est pas un tableau --------

   Sous 620 px, chaque ligne devient une CARTE : l'en-tête disparaît et
   chaque cellule porte son intitulé au-dessus d'elle. Le défilement
   horizontal, lui, oblige à balayer pour lire une seule ligne — et cache la
   moitié des colonnes sans le dire. */

@media (max-width: 620px) {
  .table-wrap { background: none; overflow-x: visible; }
  table.data thead { display: none; }
  table.data, table.data tbody, table.data tr, table.data td { display: block; width: auto; }
  table.data tr {
    position: relative;
    padding: 12px 40px 12px 14px;
    border-bottom: 1px solid var(--line);
  }
  table.data td {
    padding: 3px 0;
    border: 0;
    white-space: normal;
  }
  table.data td:empty { display: none; }
  table.data td[data-label]:not([data-primary])::before {
    content: attr(data-label);
    display: block;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-top: 4px;
  }
  table.data td[data-primary] { font-size: 14px; margin-bottom: 2px; }
  /* L'étoile va au coin, hors du flux : c'est une action, pas un champ. */
  table.data td.fav-cell {
    position: absolute;
    top: 8px;
    right: 6px;
    width: auto;
    padding: 0;
  }
  table.data td.fav-cell::before { content: none; }
  table.data td.num { text-align: left; }
  /* Le plafond de 44 ch n'a de sens que dans une CELLULE de tableau. Sur la
     carte empilee il laissait le texte s'arreter 250 px avant le bord
     droit, avec une marge en dents de scie qu'aucun autre element de la
     carte ne respecte. */
  table.data td .clamp2,
  table.data td .clamp3,
  table.data td.clamp2,
  table.data td.clamp3 { max-width: none; }
}

/* Les mini-tableaux d'une fiche défilent dans leur boîte plutôt que de
   pousser la page entière de côté. */
.mini-wrap { overflow-x: auto; }
.mini-wrap table.mini { min-width: 380px; }


/* --------------------------------------------------------------------------
   19. Révision 1.6.0 — menu repliable, file d'analyse
   -------------------------------------------------------------------------- */

/* --- Le rail : deux portes épinglées, trois catégories repliables ------- */

.rail-pinned {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 7px 8px 2px;
}

/* L'en-tête de catégorie est un BOUTON : il se replie, donc il doit
   s'annoncer comme actionnable au clavier et au lecteur d'écran. */
.rail-nav .rail-group {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
  color: var(--ink-3);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 8px 10px 3px;
  margin: 0;
}
.rail-nav .rail-group:hover { color: var(--ink-2); }

.rail-caret {
  font-size: 9px;
  transition: transform .14s ease;
  display: inline-block;
}
.rail-cat.shut .rail-caret { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) { .rail-caret { transition: none; } }

/* Le compteur ne sert QUE replié : ouvert, il dirait ce qu'on voit déjà. */
.rail-count {
  margin-left: auto;
  font-size: 10px;
  letter-spacing: 0;
  opacity: 0;
  transition: opacity .12s ease;
}
.rail-cat.shut .rail-count { opacity: .7; }

.rail-items { display: flex; flex-direction: column; gap: 1px; }
.rail-cat.shut .rail-items { display: none; }

/* --------------------------------------------------------------------------
   20. Analysis map — les cinq étapes et la file
   -------------------------------------------------------------------------- */

.strip { margin-bottom: 16px; }

.stages {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
}

.stage {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  font: inherit;
  text-align: left;
  color: inherit;
  min-width: 0;
}
.stage:hover { background: var(--surface-2); }
.stage.on {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, var(--surface));
}
/* Une étape vide n'est pas grisée au point de disparaître : zéro est une
   information, et c'est même la meilleure. */
.stage.empty .stage-n { color: var(--ink-3); }
.stage-n { font-size: 22px; font-weight: 690; letter-spacing: -.02em; line-height: 1; }
.stage-l { font-size: 11.5px; color: var(--ink-2); }

@media (max-width: 900px) {
  .stages { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .stages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stage { padding: 10px 11px; }
  .stage-n { font-size: 18px; }
}

/* --- Une carte de file -------------------------------------------------- */

.qcard {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 14px 16px;
  margin-bottom: 10px;
  box-shadow: var(--shadow);
}
.qcard-head { display: flex; align-items: flex-start; gap: 10px; }
.qcard-head h3 { font-size: 15px; margin: 0; letter-spacing: -.01em; line-height: 1.35; }
.qcard-sub { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.qcard-why {
  margin: 10px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-2);
  border-left: 2px solid var(--line);
  padding-left: 11px;
}
/* --- La grille des axes ---------------------------------------------------
   Une pastille sans son intitulé n'est pas une information : il faut
   connaître l'ordre des six axes de la matrice pour la lire. Chaque valeur
   porte donc sa question, en petit au-dessus.

   Les trois états se distinguent SANS lire le mot, et c'est le point : un axe
   tranché a un fond, un axe ouvert a un bord pointillé et pas de fond — la
   même convention que la pastille `gap` du reste du portail —, un axe non lu
   est effacé. Un expert doit voir en une seconde combien de cases restent
   vides, pas les compter en lisant. */
.qaxes {
  display: grid;
  /* 148 px : mesuré sur les valeurs les plus longues du vocabulaire —
     « Undetermined », « Targeted », « Difficult ». À 124 px la colonne
     coupait à « Unk… » et « Diffi… », ce qui rendait la grille exactement
     aussi illisible que les pastilles nues qu'elle remplace. */
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 6px;
  margin-top: 12px;
}
.qaxis {
  padding: 6px 9px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  min-width: 0;
}
/* L'INTITULÉ SE REPLIE, LA VALEUR NON. Deux règles opposées, et c'est
   délibéré : « Institutional actionability » coupé à « INSTITUTI… » ne dit
   plus quelle question il pose — l'intitulé doit passer en entier, quitte à
   prendre deux lignes. La valeur, elle, appartient à un vocabulaire fermé et
   court : la couper serait un défaut de largeur, pas de place. */
.qaxis-l {
  display: block;
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.3;
}
.qaxis-v {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.qaxis-open, .qaxis-empty {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
  background: none;
}
.qaxis-open .qaxis-v, .qaxis-empty .qaxis-v { color: var(--warn); }
.qaxis-unread { opacity: .5; border-style: dotted; background: none; }
/* Les deux SORTIES de la matrice ne se cherchent pas, elles se recalculent :
   elles sont mises à part par un fond d'accent plutôt que par une place. */
.qaxis-out {
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
}
.qaxis-out.qaxis-open, .qaxis-out.qaxis-empty {
  background: none;
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
}

/* --- Ce qui reste ouvert, et le moyen d'aller le chercher ---------------- */
.qcard-open {
  margin-top: 10px;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--warn) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 26%, transparent);
}
.qcard-open.none {
  background: color-mix(in srgb, var(--ok) 9%, transparent);
  border-color: color-mix(in srgb, var(--ok) 26%, transparent);
  color: var(--ink-2);
  font-size: 12.5px;
}
.qcard-open-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 7px;
}
.qcard-open-l { font-size: 12.5px; font-weight: 650; color: var(--warn); }
.qcard-open-head .btn { margin-left: auto; }

/* --- D'où vient ce résultat --------------------------------------------- */
.qcard-trace {
  margin-top: 9px;
  font-size: 11.5px;
  color: var(--ink-3);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: baseline;
}
.qcard-trace-l {
  font-size: 10px;
  font-weight: 650;
  letter-spacing: .045em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* Une conclusion sans un seul signal est une conclusion sans justification :
   la note de l'alias le dit, la ligne doit le montrer. */
.qcard-trace.thin { color: var(--danger); }
.qcard-trace.thin .qcard-trace-l { color: var(--danger); }

/* --- Les raisons qui se répètent ------------------------------------------
   Onze cartes identiques ne sont pas onze décisions. Le groupe se lit comme
   une ligne de travail : son compte, sa raison, et le geste qui le
   sélectionne. */
.qgroups { margin: 0 0 14px; }
.qgroup {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 9px 11px;
  margin-bottom: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.qgroup:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 5%, transparent); }
.qgroup-n {
  flex: 0 0 auto;
  min-width: 26px;
  text-align: center;
  font-weight: 700;
  font-size: 14px;
  color: var(--warn);
}
.qgroup-t { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--ink-2); line-height: 1.45; }
.qgroup-a { flex: 0 0 auto; font-size: 11.5px; font-weight: 650; color: var(--accent-strong); white-space: nowrap; }
:root[data-theme='dark'] .qgroup-a { color: var(--accent); }

/* --- Où en est le corpus dans le temps ------------------------------------
   Quatre tuiles qui SONT le filtre qu'elles comptent. Une tuile qui affiche
   un nombre sans mener à ses lignes oblige à refaire à la main la sélection
   qu'elle vient de décrire. */
/* --- La bande de faits (S.factBand) -------------------------------------- *
   Un rang de compteurs cliquables au-dessus d'une liste. Chaque tuile EST le
   filtre qu'elle compte : elle porte son état actif, et un second clic le
   retire. Trois pages s'en servent — Dossiers, Priorities, Timeline — et la
   bande temporelle bespoke qui vivait ici en est l'ancêtre.

   Le ton n'est pas un ornement : il dit ce qui presse. Rouge = une échéance
   dans le mois, ambre = quelque chose devant, neutre = derrière nous,
   pointillé = on ne sait pas. Une couleur qui ne voudrait rien dire coûterait
   plus qu'elle ne rend, parce qu'on la lirait quand même.
 * ----------------------------------------------------------------------- */
.fband {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 10px;
  margin: 0 0 14px;
}
.ftile {
  --ft: var(--accent);
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 12px 14px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
  transition: border-color .14s, transform .14s, box-shadow .14s, background .14s;
}
/* Le filet de couleur, à gauche : il tient sur trois pixels, se voit dans les
   deux thèmes, et ne dépend d'aucune police de symboles. */
.ftile::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--ft);
}
.ftile:hover {
  border-color: var(--ft);
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}
.ftile:focus-visible { outline: 2px solid var(--ft); outline-offset: 2px; }
.ftile.on {
  border-color: var(--ft);
  background: color-mix(in srgb, var(--ft) 12%, var(--surface));
}
.ftile.on::before { width: 4px; }
/* Une tuile à zéro reste lisible et cliquable : « personne ici » est une
   information sur la file, pas une absence de contrôle. */
.ftile.empty { opacity: .62; }
.ftile.empty:hover { opacity: 1; }
.ftile-n {
  font-size: 25px;
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ftile-l { font-size: 12px; font-weight: 560; color: var(--ink-2); }
.ftile-h { font-size: 11px; color: var(--ink-3); margin-top: 1px; }
.ftile.on .ftile-l { color: var(--ft); }

.ftile.t-danger { --ft: var(--danger); }
.ftile.t-warn   { --ft: var(--warn); }
.ftile.t-ok     { --ft: var(--ok); }
.ftile.t-info   { --ft: var(--info); }
.ftile.t-muted  { --ft: var(--ink-3); }
/* « On ne sait pas » ne se peint pas comme une valeur : le filet devient un
   pointillé, la seule marque que le portail réserve déjà aux lacunes. */
.ftile.t-gap { --ft: var(--ink-3); }
.ftile.t-gap::before {
  background: repeating-linear-gradient(
    to bottom, var(--ft) 0 3px, transparent 3px 6px);
}

/* --- Graphiques du journal de dépenses (AI usage) ----------------------- *
   Dessinés à la main : le portail n'embarque aucune bibliothèque de
   graphiques, et en ajouter une pour deux camemberts et un histogramme
   coûterait plus que les quarante lignes ci-dessous.
 * ----------------------------------------------------------------------- */
.pie-wrap { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.pie { width: 140px; height: 140px; flex: none; }
/* Le total, au centre de l'anneau. En SVG le texte n'hérite ni de la police
   ni de la couleur de la page : les deux se déclarent. */
.pie-total {
  text-anchor: middle;
  font-family: var(--font);
  font-size: 19px; font-weight: 700; letter-spacing: -.03em;
  fill: var(--ink);
}
.pie-unit {
  text-anchor: middle;
  font-family: var(--font);
  font-size: 9.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em;
  fill: var(--ink-3);
}
.pie-key { list-style: none; margin: 0; padding: 0; flex: 1; min-width: 180px; }
.pie-key li {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 0; font-size: 13px;
}
.pie-dot { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.pie-name { flex: 1; color: var(--ink-2); }
.pie-val { font-variant-numeric: tabular-nums; font-weight: 600; }

/* L'histogramme par jour. Les colonnes partagent la largeur : une fenêtre de
   90 jours doit tenir sans défilement, sinon la forme d'ensemble — la seule
   chose qu'un histogramme apporte — se perd. */
.tl-chart {
  display: flex; align-items: flex-end; gap: 2px;
  height: 132px; padding: 0 0 2px;
  border-bottom: 1px solid var(--line);
}
.tl-col {
  flex: 1; min-width: 2px; height: 100%;
  display: flex; align-items: flex-end; justify-content: center;
}
.tl-bar {
  display: block; width: 100%; max-width: 38px;
  background: var(--accent);
  border-radius: 2px 2px 0 0;
  min-height: 0;
}
.tl-col:hover .tl-bar { background: var(--accent-strong); }
.tl-axis {
  display: flex; justify-content: space-between;
  margin-top: 6px; font-size: 11.5px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* --- Le pipeline procédural --------------------------------------------- *
   Un RUBAN, pas une grille de tuiles. La forme porte l'information : chaque
   segment pointe vers le suivant, donc l'ordre se lit sans avoir à lire les
   rangs — et l'ordre est ici le sujet même, puisqu'il dit combien il reste
   d'occasions d'agir. La couleur suit la même pente, du vert d'une
   consultation ouverte au rouge sourd d'un texte qu'on ne peut plus
   qu'appliquer.

   Le remplissage horizontal de chaque segment est sa PART des dossiers
   classés. Il vit dans le segment plutôt que dans une barre séparée : à
   quinze pixels de haut, une barre sous un chiffre se lit comme une
   décoration, alors qu'un segment à moitié rempli se lit comme une part.

   Les non-classés sont EN TÊTE et hors du ruban — carte à bord pointillé,
   sans rang, sans flèche. Sur la même ligne parce qu'on veut les compter du
   même regard ; hors du ruban parce qu'ils ne sont pas une sixième étape,
   et qu'un entonnoir dont la dernière case pèse 94 % ressemble à un
   pipeline tout en n'en étant pas un.
 * ----------------------------------------------------------------------- */
.pipe { margin: 0 0 14px; }
.pipe-head {
  display: flex; align-items: baseline; gap: 10px;
  margin: 0 0 8px;
}
.pipe-title { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.pipe-sub { font-size: 11.5px; color: var(--ink-3); }

.pipe-flow {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin: 0; padding: 0;
  list-style: none;
}

/* La carte des non-classés : même hauteur que le ruban, forme opposée. */
.punstaged {
  flex: 0 1 176px;
  min-width: 0;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  margin-right: 14px;
  padding: 10px 13px;
  border: 1px dashed var(--line);
  border-left: 3px solid var(--ink-3);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  font: inherit; color: inherit; text-align: left;
  transition: border-color .14s, background .14s;
}
.punstaged:hover { border-color: var(--ink-3); background: var(--surface-2); }
.punstaged.on {
  border-style: solid;
  border-color: var(--ink-3);
  background: color-mix(in srgb, var(--ink-3) 12%, var(--surface));
}
.punstaged:focus-visible { outline: 2px solid var(--ink-3); outline-offset: 2px; }

/* Le segment. La flèche est un clip-path, donc bordure et ombre y seraient
   rognées : tout se dit par le fond, ce qui a l'avantage de survivre au
   thème sombre sans un seul override. */
.pflow {
  --pc: var(--ink-3);
  flex: 1 1 0;
  min-width: 0;
  position: relative;
  isolation: isolate;
  margin-left: -12px;
  padding: 10px 12px 10px 26px;
  border: 0;
  background: color-mix(in srgb, var(--pc) 17%, var(--surface));
  cursor: pointer;
  font: inherit; color: inherit; text-align: left;
  clip-path: polygon(0 0, calc(100% - 13px) 0, 100% 50%,
                     calc(100% - 13px) 100%, 0 100%, 13px 50%);
  transition: background .14s;
}
.pflow.pf-first {
  margin-left: 0;
  padding-left: 13px;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  clip-path: polygon(0 0, calc(100% - 13px) 0, 100% 50%,
                     calc(100% - 13px) 100%, 0 100%);
}
/* Le dernier segment est PLAT : le ruban s'arrête, ce qui est exactement ce
   que dit l'étape « Implementation ». Une flèche y promettrait une suite. */
.pflow.pf-last {
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 13px 50%);
}
.pflow:hover { background: color-mix(in srgb, var(--pc) 28%, var(--surface)); }
.pflow.on   { background: color-mix(in srgb, var(--pc) 34%, var(--surface)); }
.pflow:focus-visible { outline: 2px solid var(--pc); outline-offset: -2px; }

/* La part, peinte dans le segment. z-index négatif : elle passe derrière le
   texte sans avoir à empiler chaque libellé au-dessus d'elle. */
.pflow-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--pc) 22%, transparent);
  pointer-events: none;
}
.pflow.on .pflow-fill { background: color-mix(in srgb, var(--pc) 30%, transparent); }

.pflow-top { display: flex; align-items: baseline; gap: 6px; }
.pflow-rank {
  font-size: 9.5px; font-weight: 800;
  color: var(--pc);
  font-variant-numeric: tabular-nums;
}
.pflow-n, .punstaged-n {
  font-size: 21px; font-weight: 700; letter-spacing: -.03em; line-height: 1.15;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.pflow-l, .punstaged-l {
  display: block;
  font-size: 11.5px; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pflow.empty { opacity: .62; }
.pflow.empty:hover { opacity: 1; }

/* Sous 860 px un ruban de cinq segments donne des libellés de trois lettres.
   Il se replie alors en grille : la flèche disparaît, l'ordre reste dit par
   le rang, et le remplissage continue de porter la part. */
@media (max-width: 860px) {
  .pipe-flow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: 8px;
  }
  .punstaged { margin-right: 0; grid-column: 1 / -1; }
  .pflow {
    margin-left: 0;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    clip-path: none;
  }
  .pflow.pf-first, .pflow.pf-last {
    padding-left: 12px;
    border-radius: var(--radius-sm);
    clip-path: none;
  }
}

/* --- Le filet de ligne (renderTable rowClass) ---------------------------- *
   Trois pixels au bord gauche d'une ligne de tableau, peints sur la première
   cellule. Un `box-shadow` inset ne sait pas être pointillé, et le pointillé
   est justement ce qui distingue une date ESTIMÉE d'une date tenue : le filet
   est donc un dégradé de fond, qui sait faire les deux.

   LE PRÉFIXE EST `rrail` ET NON `rail`, et ce n'est pas une coquetterie :
   `.rail` est le rail de navigation — 248 px de large, `display: flex`,
   `position: sticky`, `height: 100vh`. La première version de ce filet a
   nommé ses lignes `rail`, et chaque ligne de chronologie à date confirmée
   est devenue une colonne sticky pleine hauteur au milieu du tableau. Une
   classe posée sur un `<tr>` par une fonction générique doit porter un
   préfixe que personne d'autre ne peut revendiquer.
 * ----------------------------------------------------------------------- */
table.data tr.rrail > td:first-child,
table.data tr.rrail-soft > td:first-child {
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 3px 100%;
}
table.data tr.rrail > td:first-child {
  background-image: linear-gradient(var(--rrail-c, var(--line)), var(--rrail-c, var(--line)));
}
table.data tr.rrail-soft > td:first-child {
  background-image: repeating-linear-gradient(
    to bottom, var(--rrail-c, var(--line)) 0 4px, transparent 4px 8px);
}
table.data tr.rrail-danger { --rrail-c: var(--danger); }
table.data tr.rrail-accent { --rrail-c: var(--accent); }
table.data tr.rrail-muted  { --rrail-c: var(--ink-3); }

/* Sous 620 px la ligne devient une carte : le filet passe sur son bord. */
@media (max-width: 620px) {
  table.data tr.rrail, table.data tr.rrail-soft {
    border-left: 3px solid var(--rrail-c, var(--line));
  }
  table.data tr.rrail-soft { border-left-style: dashed; }
  table.data tr.rrail > td:first-child,
  table.data tr.rrail-soft > td:first-child { background-image: none; }
}

/* --- La pastille de date ------------------------------------------------- *
   Le jour en grand, le mois et l'année dessous. Une colonne de dates au format
   « 27 Sept 2026 » se lit mot à mot ; la même en pastille se balaie, parce que
   le seul chiffre qui change d'une ligne à l'autre est aligné sur lui-même.
 * ----------------------------------------------------------------------- */
.datechip {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.05;
}
.datechip b {
  font-size: 17px; font-weight: 700; letter-spacing: -.02em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.datechip i {
  font-style: normal;
  font-size: 10.5px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-2);
}
.datechip.past b, .datechip.past i { color: var(--ink-3); }

/* Un nom d'hôte est un jeton INSÉCABLE : sous une mise en page de table
   FIXE, il déborde de sa colonne au lieu de la faire grandir — 26 px de
   débordement
   mesures sur la chronologie, et un lien coupe en plein milieu d'un mot.
   Meme defaut que les URL des marches en 1.8.0, meme remede : on tronque
   dans la cellule, l'adresse entiere restant dans l'infobulle. */
.srclink {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.qguard { margin: 0 0 12px; }
.qguard > summary { cursor: pointer; }
.qguard > p { margin: 8px 0 0; }

.qnote { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 4px; }
.qnote .sheet-section { padding: 0; border: 0; background: none; }

.qcard-pills { margin-top: 10px; }
.qcard-acts {
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px dashed var(--line);
  flex-wrap: wrap;
}
.qsep { width: 1px; align-self: stretch; background: var(--line); margin: 0 3px; }
.qpick { display: flex; align-items: center; padding-top: 2px; }
.qpick input { width: 16px; height: 16px; }

.bulkbar {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  padding: 9px 12px;
  margin-bottom: 10px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
}
.bulkbar.on {
  border-style: solid;
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}

/* --- Le formulaire d'arbitrage ------------------------------------------ */

.arb {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 16px;
  margin-top: 14px;
  padding: 14px;
  border-radius: var(--radius-sm);
  border: 1px solid color-mix(in srgb, var(--warn) 40%, var(--line));
  background: color-mix(in srgb, var(--warn) 6%, var(--surface-2));
}
.arb > .hint, .arb > .ff.wide { grid-column: 1 / -1; }
.arb .hint { margin: 0; }
@media (max-width: 700px) { .arb { grid-template-columns: 1fr; } }

/* --- La référence, repliée ---------------------------------------------- */

.ref { margin-top: 26px; }
.ref > summary {
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 620;
  color: var(--ink-2);
  padding: 10px 0;
  border-top: 1px solid var(--line);
}
.ref > summary:hover { color: var(--ink); }

/* --------------------------------------------------------------------------
   21. Petits écrans, seconde passe
   -------------------------------------------------------------------------- */

@media (max-width: 620px) {
  /* Un mois sur sept colonnes dans 375 px donne des cases de 45 px : le nom
     d'un événement y tient en trois lettres. Aucune application d'agenda ne
     fait ça — elles passent toutes en liste. On retire donc le choix « Month »
     plutôt que de l'offrir inutilisable, et la page retombe sur List.
     Le réglage enregistré n'est PAS écrasé : sur un écran large, le mois
     revient. */
  [data-view="month"] { display: none; }

  /* Le bouton de génération et son explication ne partagent pas une ligne :
     le texte s'enroulait autour du bouton. */
  .gen-row { flex-direction: column; align-items: flex-start; }

  /* Une carte de file : les actions passent sur toute la largeur et les
     boutons cessent d'être des cibles de 26 px. */
  .qcard { padding: 12px 13px; }
  .qcard-acts .btn { flex: 1 1 auto; justify-content: center; }
  .qsep { display: none; }
}

/* --------------------------------------------------------------------------
   12 ter. Rapport imprimable
   -------------------------------------------------------------------------- */

.report { max-width: 940px; }
.report h2 { font-size: 17px; margin: 26px 0 10px; }
.report h3 { font-size: 13px; margin: 18px 0 6px; }
.report-head { border-bottom: 2px solid var(--accent); padding-bottom: 14px; margin-bottom: 6px; }
.report-head h1 { font-size: 24px; }
.report-meta { font-size: 12.5px; color: var(--ink-3); margin-top: 5px; }
.report-block { border: 1px solid var(--line); border-radius: var(--radius);
                padding: 14px 16px; margin-bottom: 12px; background: var(--surface); }
.report-block h3 { margin-top: 0; }

@page {
  size: A4;
  margin: 16mm 14mm 18mm;
}

@media print {
  /* Tout le chassis disparait : il ne reste que le document. La cloche, la
     discussion et la barre de l'éditeur en font partie — ce sont des
     commandes, et une notification ou une note de travail n'a rien à faire
     dans un document remis à un client. Le texte déjà saisi dans l'éditeur,
     lui, s'imprime : c'est le document. */
  .rail, .topbar, .toast-host, [data-report-actions],
  .rec-head, .rec-toc, .rec-actions, .rec-archive-bar, .rec-editbar, .gsearch, .star,
  .bell, .bell-menu, .cmt-section, .rte-bar,
  .asst-side, .asst-compose, .asst-foot,
  .burger, .filter-chips, .toolbar { display: none !important; }

  /* L'éditeur redevient du texte : ni cadre, ni fenêtre de défilement, sans
     quoi la moitié d'un article part avec la barre de défilement. */
  .rte { border: 0 !important; box-shadow: none !important; }
  .rte-area { max-height: none !important; overflow: visible !important;
              min-height: 0 !important; padding: 0 !important; }
  .page, .rec, .rec-body { padding: 0 !important; margin: 0 !important; }
  .report { max-width: none; }

  body { background: #fff !important; color: #14141c !important; }
  .card, .report-block { box-shadow: none !important; }

  /* Sur papier, un mot bleu ne mene nulle part : les liens redeviennent du
     texte, sauf les liens externes dont on imprime l'adresse. */
  .report a { color: #14141c !important; text-decoration: none !important; }
  .report a[target="_blank"]::after {
    content: ' (' attr(href) ')';
    font-size: 9pt;
    color: #6b6f85;
    word-break: break-all;
  }

  /* Un bloc de dossier coupe en deux entre deux pages est illisible. */
  .report-block, .report-head, .actor-list li { break-inside: avoid; }
  .report h2 { break-after: avoid; page-break-after: avoid; }
  .report-head { break-after: avoid; }

  /* Les pastilles perdent leur fond a l'impression sans -webkit-print-
     color-adjust : sans lui, une priorite rouge sort en gris. */
  .pill, .bar-fill, .report-head { -webkit-print-color-adjust: exact;
                                   print-color-adjust: exact; }
}

/* --------------------------------------------------------------------------
   16. Le document lui-meme
   -------------------------------------------------------------------------- */

.report-brand { margin-bottom: 14px; }
.report-brand img { max-height: 34px; max-width: 190px; object-fit: contain; display: block; }
.report-wordmark { font-size: 15px; font-weight: 700; letter-spacing: -.01em; }

.report-block-head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-bottom: 8px;
}
.report-block-head h3 { font-size: 15px; line-height: 1.35; margin: 0; }
.report-block-sub { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.report-verdict { margin-left: auto; text-align: right; white-space: nowrap; }

.report .why {
  font-size: 14px;
  line-height: 1.55;
  border-left: 3px solid var(--accent);
  padding-left: 11px;
  margin: 0 0 12px;
}

/* Les six axes de la matrice, en grille : c'est ce qui separe une priorite
   affirmee d'une conclusion defendable. */
.report-axes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 6px 16px;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
}
.axis { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.axis-name { font-size: 11.5px; color: var(--ink-3); }

.report-kv { margin-bottom: 12px; }
.report-kv dd.long { white-space: pre-wrap; }

.actor-head { font-size: 12px; font-weight: 650; letter-spacing: .04em;
              text-transform: uppercase; color: var(--ink-3); margin: 12px 0 5px; }
.actor-list { list-style: none; margin: 0; padding: 0; }
.actor-list li { padding: 5px 0; border-bottom: 1px solid var(--line-soft); }
.actor-list li:last-child { border-bottom: 0; }
.actor-name { font-weight: 600; }
.actor-note { font-size: 12.5px; color: var(--ink-3); margin-top: 2px; }

/* --------------------------------------------------------------------------
   12. Divers
   -------------------------------------------------------------------------- */

.row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.right { margin-left: auto; }
.muted { color: var(--ink-3); }
.nowrap { white-space: nowrap; }
.mono { font-family: var(--mono); font-size: 12px; }
.mb0 { margin-bottom: 0; }
.mt16 { margin-top: 16px; }
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.logo-preview {
  display: grid;
  place-items: center;
  min-height: 74px;
  padding: 12px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}
.logo-preview img { max-height: 46px; max-width: 190px; object-fit: contain; }
.logo-preview.on-light { background: #ffffff; }
.logo-preview.on-dark { background: #14141c; }

/* --------------------------------------------------------------------------
   13. Étroit
   -------------------------------------------------------------------------- */

@media (max-width: 1080px) {
  .grid.c4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid.c3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  .rail {
    position: fixed;
    z-index: 200;
    transform: translateX(-100%);
    transition: transform .18s ease;
  }
  .rail.open { transform: none; }
  .burger { display: inline-flex; }
  .page { padding: 18px 16px 56px; }
  .topbar { padding: 12px 16px; }
  .grid.c2, .grid.c3, .grid.c4 { grid-template-columns: minmax(0, 1fr); }
  .kv { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  .kv dt { margin-top: 8px; }
}

/* --------------------------------------------------------------------------
   14. Barre de filtres : repli et pastilles retirables
   -------------------------------------------------------------------------- */

.filter-more {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  align-items: center;
  padding: 10px 0 2px;
  border-top: 1px dashed var(--line);
  margin-top: 4px;
}

.filter-chips {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding-top: 4px;
}

/* Retirer UN filtre, pas tous : « Clear all » oblige sinon à tout refaire
   pour en enlever un seul. */
.chip-off {
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-strong);
  cursor: pointer;
}
:root[data-theme='dark'] .chip-off { color: var(--accent); }
.chip-off:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.chip-off span { opacity: .6; margin-left: 2px; }

/* `.rail-scope` — le rappel du périmètre entreprise en tête de rail — a été
   RETIRÉ en 1.7.0 pour la même raison que `.rail-cta` : le sélecteur de la
   barre haute dit le même état, et lui est agissable. */

/* --------------------------------------------------------------------------
   15. Chronologie d'un dossier

   Un tableau de dates se lit ligne à ligne ; une chronologie se lit d'un
   coup. Le trait plein est une date confirmée, le creux une date estimée ou
   hypothétique, le rouge une échéance contraignante — et « Today » est le
   repère sans lequel il faut compter les jours.
   -------------------------------------------------------------------------- */

.timeline { list-style: none; margin: 0; padding: 0 0 0 20px; position: relative; }
.timeline::before {
  content: '';
  position: absolute;
  left: 4px; top: 6px; bottom: 6px;
  width: 2px;
  background: var(--line);
}
.timeline li { position: relative; padding: 0 0 16px 4px; }
.timeline li:last-child { padding-bottom: 0; }

.tl-dot {
  position: absolute;
  left: -20px; top: 5px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--surface);
}
.tl-item.past .tl-dot { background: var(--ink-3); }
.tl-item.deadline .tl-dot { background: var(--danger); }
/* Creux = date projetée. La différence doit se voir sans lire la pastille. */
.tl-item.soft .tl-dot { background: var(--surface); border: 2px solid var(--ink-3); }
.tl-item.past { opacity: .72; }

.tl-when { font-size: 11.5px; font-weight: 650; letter-spacing: .03em;
           text-transform: uppercase; color: var(--ink-3); }
.tl-name { font-size: 13.5px; font-weight: 600; margin: 1px 0 2px; }
.tl-meta { font-size: 12px; color: var(--ink-3); margin-bottom: 4px; }

.tl-now { padding-bottom: 16px; }
.tl-now .tl-dot { background: var(--accent); width: 12px; height: 12px; left: -21px;
                  box-shadow: 0 0 0 3px var(--surface),
                              0 0 0 6px color-mix(in srgb, var(--accent) 25%, transparent); }
.tl-now div { font-size: 12.5px; color: var(--accent-strong); }
:root[data-theme='dark'] .tl-now div { color: var(--accent); }

/* Fil d'Ariane d'une ligne de liste : un segment lu hors de son marché
   parent ne veut rien dire. */
.crumb {
  font-size: 11px;
  font-weight: 620;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 1px;
}

/* --------------------------------------------------------------------------
   22. Révision 1.7.0 — cartes, cloche, discussions, éditeur riche

   Tout ce que le JS de cette révision produit et que la feuille ne connaissait
   pas encore. Les noms viennent du contrat de la révision, à la lettre : ils
   sont écrits ici et émis là-bas par deux mains différentes, et ne se
   rencontrent qu'à la relecture. Aucun nom inventé, aucune classe stylée sans
   être émise.
   -------------------------------------------------------------------------- */

/* --- Une liste en cartes ------------------------------------------------- */

/* Deux entreprises et onze colonnes : le tableau en laissait huit vides. La
   carte montre ce qui est renseigné et tait le reste — c'est la même liste,
   lue par ce qu'elle contient plutôt que par ce qu'elle pourrait contenir. */
.reccards {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

.reccard {
  position: relative;
  min-width: 0;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
/* La carte n'est cliquable que lorsque le JS lui a donné un rôle : proposer
   un curseur de lien sur une carte qui n'ouvre rien est un mensonge. */
.reccard[role='button'] { cursor: pointer; }
.reccard[role='button']:hover {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
}
.reccard:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* L'étoile va au coin, hors du flux : c'est une action, pas un champ — et
   elle ne doit pas décaler le titre d'une carte à l'autre selon sa présence. */
.reccard-fav { position: absolute; top: 8px; right: 8px; z-index: 2; }

.reccard-top { display: flex; align-items: flex-start; gap: 8px; padding-right: 26px; }
.reccard-top h3 {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14.5px;
  line-height: 1.3;
  letter-spacing: -.01em;
  overflow-wrap: anywhere;
}
.reccard-top .pill { flex: 0 0 auto; margin-top: 1px; }

.reccard-sub { display: block; margin: 4px 0 0; font-size: 12px; color: var(--ink-3); }

/* --- La carte d'entreprise ----------------------------------------------- *
   Un monogramme teinté, l'identité à côté, l'avancement des validations en
   jauge. La teinte vient du nom (voir collections.js) : elle ne veut rien dire
   en soi, elle sert seulement à ce qu'une entreprise se retrouve à sa couleur
   dans une liste où toutes les cartes se ressemblent.
 * ----------------------------------------------------------------------- */
.cmono {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  border-radius: 10px;
  font-size: 13.5px; font-weight: 700; letter-spacing: .02em;
  color: var(--cm, var(--accent));
  background: color-mix(in srgb, var(--cm, var(--accent)) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cm, var(--accent)) 26%, transparent);
}
.cmono-id { flex: 1 1 auto; min-width: 0; }
.cmono-id h3 { margin: 0; }
.cmono-id .reccard-sub { margin-top: 2px; }

.cgauge { margin: 12px 0 0; padding-top: 11px; border-top: 1px solid var(--line-soft); }
.cgauge-track { display: flex; gap: 3px; }
.cgauge-seg {
  flex: 1;
  height: 5px;
  border-radius: 3px;
  background: var(--line);
}
.cgauge-seg.done { background: var(--ok); }
.cgauge-key {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin: 7px 0 0;
}
.cgauge-key dt {
  font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .045em;
  color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cgauge-key dd { margin: 1px 0 0; font-size: 11.5px; font-weight: 600; }
.cgauge-key dd.ok { color: var(--ok); }
.cgauge-key dd.draft { color: var(--warn); }

/* Une description de trois lignes suffit à reconnaître une ligne ; au-delà,
   les cartes d'une même rangée cessent d'avoir la même hauteur et la grille
   se met à ressembler à un mur mal monté. */
.reccard-text {
  margin: 8px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.reccard-flags {
  display: grid;
  gap: 5px;
  margin: 11px 0 0;
  padding-top: 9px;
  border-top: 1px solid var(--line-soft);
}
.reccard-flags > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.reccard-flags dt { font-size: 11.5px; color: var(--ink-3); min-width: 0; }
.reccard-flags dd { margin: 0; flex: 0 0 auto; }

.reccard-warn { margin: 9px 0 0; font-size: 11.5px; color: var(--warn); }

/* --- La cloche de la barre haute ----------------------------------------- */

.bell { position: relative; display: inline-flex; }
/* `.btn.sm` porte deux classes et l'emporte donc sur un sélecteur simple,
   quelle que soit la position dans le fichier : le rembourrage doit être écrit
   avec la même force, sans quoi la déclaration est morte et le prochain
   réglage se fait à l'aveugle. */
.btn.bell-btn { position: relative; padding: 6px 9px; }
.bell-btn svg { width: 17px; height: 17px; flex: none; stroke: currentColor; }

/* La pastille chevauche le bouton : posée à côté, elle élargissait la barre
   haute au premier message reçu et décalait tout ce qui la suit. */
.bell-count {
  position: absolute;
  top: -3px;
  right: -3px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  /* Le liseré de la couleur de fond détache le chiffre du dessin de la
     cloche, sur lequel il se pose. */
  box-shadow: 0 0 0 2px var(--bg);
}

/* Ancré sur le bord DROIT du bouton. La cloche siège aux trois quarts de la
   barre haute : un menu de 340 px ouvert vers la droite sortirait de l'écran
   sur un portable, et rien en CSS ne le ramènerait. */
.bell-menu {
  position: absolute;
  z-index: 70;
  top: calc(100% + 6px);
  right: 0;
  left: auto;
  width: 340px;
  max-width: min(92vw, 420px);
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 5px;
}

.bell-item {
  position: relative;
  padding: 9px 30px 9px 10px;
  border-radius: var(--radius-sm);
}
.bell-item + .bell-item { border-top: 1px solid var(--line-soft); }
.bell-item[role='button'] { cursor: pointer; }
.bell-item[role='button']:hover { background: var(--surface-2); }
.bell-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.bell-subject { font-size: 13px; font-weight: 600; line-height: 1.35; }
.bell-msg {
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.bell-when { margin-top: 3px; font-size: 11px; color: var(--ink-3); }

/* Discret, jamais caché : au survol seulement, la croix serait introuvable
   au doigt — un écran tactile n'a pas de survol. */
.bell-x {
  position: absolute;
  top: 6px;
  right: 5px;
  border: 0;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 11px;
  line-height: 1;
  padding: 5px;
  border-radius: 6px;
  opacity: .5;
}
.bell-item:hover .bell-x { opacity: 1; }
.bell-x:hover { color: var(--ink); background: var(--surface-2); opacity: 1; }

.bell-empty { padding: 20px 12px; text-align: center; color: var(--ink-3); font-size: 12.5px; }

/* --- La discussion d'une fiche ------------------------------------------- */

/* Une discussion se lit en colonne étroite comme n'importe quel fil : la
   section est large parce qu'elle porte un formulaire, pas parce que les
   phrases doivent traverser l'écran. */
.cmt-list {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-width: 760px;
}
.cmt-form { max-width: 760px; display: flex; flex-direction: column; gap: 8px; }
.cmt-form textarea { min-height: 62px; resize: vertical; }
.cmt-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 11.5px;
}

.cmt {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 9px 11px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* Ses propres mots se reconnaissent d'un coup d'œil, sans lire le nom. La
   teinte est légère : c'est un repère, pas une mise en avant. */
.cmt.mine {
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  border-color: color-mix(in srgb, var(--accent) 22%, var(--line-soft));
}

.cmt-body { flex: 1 1 auto; min-width: 0; }
.cmt-head { display: flex; align-items: baseline; gap: 8px; }
.cmt-head b { font-size: 12.5px; font-weight: 650; }
.cmt-head .muted { font-size: 11.5px; }

/* Les retours à la ligne sont ce que la personne a tapé : les écraser
   transforme une liste de trois points en un paragraphe. Et une URL collée
   sans espace doit se couper plutôt qu'élargir la fiche. */
.cmt-text {
  margin-top: 3px;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.cmt-x {
  margin-left: auto;
  flex: 0 0 auto;
  border: 0;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 11px;
  line-height: 1;
  padding: 4px 5px;
  border-radius: 6px;
  opacity: .55;
}
.cmt-x:hover { opacity: 1; color: var(--danger); background: var(--surface); }

/* La pastille d'un avatar dans un fil : plus petite que dans le rail, sinon
   elle pèse plus que le nom qu'elle abrège. */
.avatar.sm { width: 24px; height: 24px; flex: 0 0 24px; font-size: 10px; }

/* Le compteur d'un titre de section — « Discussion 4 ». Les h3 de fiche sont
   en petites capitales espacées : le chiffre reprend un interlettrage normal,
   sinon il se lit « 4 » suivi d'un blanc. */
h3 > .count {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--line-soft);
  color: var(--ink-2);
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  vertical-align: 1px;
}

/* --- L'éditeur de texte riche -------------------------------------------- */

/* Le cadre appartient au bloc entier, pas à la zone de saisie : c'est lui qui
   prend l'anneau de focus, sans quoi cliquer dans le texte allumait une
   bordure à l'intérieur d'une autre. */
.rte {
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.rte:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 32%, transparent);
}

/* Collante : sur un texte long, la mise en forme doit rester à portée quand
   la PAGE défile. Elle ne peut l'être que si aucun parent ne devient lui-même
   une boîte de défilement — d'où l'absence d'overflow sur .rte, et le coin
   arrondi posé sur la barre plutôt que découpé par le cadre. */
/* La barre d'outils NE COLLE PAS. Elle l'a fait, et elle allait se garer sous
   la barre haute de la page — `position: sticky; top: 0` en z-index 2, contre
   une `.topbar` elle-même collante en z-index 20 : les boutons finissaient
   couverts par un fond flouté à 88 %, et `elementFromPoint` rendait la barre
   haute. Un bouton invisible et incliquable exactement dans le cas où coller
   servait à quelque chose.

   Il n'y a rien à corriger, seulement à retirer : `.rte-area` a son propre
   défilement (max-height plus bas), donc la barre reste à l'écran tant que
   l'éditeur y est, sans avoir à se décrocher de lui. */
.rte-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  padding: 5px 6px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-soft);
  border-radius: calc(var(--radius-sm) - 1px) calc(var(--radius-sm) - 1px) 0 0;
}

/* Six boutons portent un glyphe, deux portent un mot — « Link » et « Clear »,
   parce qu'aucun symbole ne les dit sans légende. Une boîte de 28 px fixes
   rognait « Clear » de quatre pixels et laissait « Link » sans un pixel de
   marge : le fond de survol et l'état actif étaient alors plus étroits que le
   texte qu'ils sont censés désigner. La largeur est donc un MINIMUM. */
.rte-btn {
  display: inline-grid;
  place-items: center;
  min-width: 28px;
  height: 28px;
  padding: 0 5px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: 12.5px;
  font-weight: 650;
  line-height: 1;
  cursor: pointer;
}
.rte-btn.wide { padding: 0 9px; }
.rte-btn svg { width: 15px; height: 15px; flex: none; stroke: currentColor; }
.rte-btn:hover { background: var(--surface); border-color: var(--line); color: var(--ink); }
/* L'état actif se dit par le fond ET la bordure : une simple couleur de
   texte ne suffit pas à distinguer « gras appliqué » de « bouton survolé ». */
.rte-btn[aria-pressed='true'] {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent);
  color: var(--accent-strong);
}
:root[data-theme='dark'] .rte-btn[aria-pressed='true'] { color: var(--accent); }

.rte-area {
  min-height: 160px;
  max-height: 460px;
  overflow-y: auto;
  padding: 11px 13px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink);
  overflow-wrap: anywhere;
  /* Le focus est peint par .rte:focus-within : deux anneaux emboîtés se
     liraient comme un défaut d'affichage. */
  outline: none;
}
/* Le repère de saisie n'est pas un contenu : il disparaît au premier
   caractère, et ne doit jamais capturer le clic qui vise le curseur. */
.rte-area:empty::before {
  content: attr(data-placeholder);
  color: var(--ink-3);
  pointer-events: none;
}

.rte-area > :first-child { margin-top: 0; }
.rte-area > :last-child { margin-bottom: 0; }
.rte-area p { margin: 0 0 9px; }
.rte-area strong { font-weight: 680; }
.rte-area em { font-style: italic; }
.rte-area ul, .rte-area ol { margin: 0 0 9px; padding-left: 20px; }
.rte-area li { margin: 2px 0; }
.rte-area a { color: var(--accent); text-decoration: underline; }
.rte-area h3 {
  font-size: 13.5px;
  font-weight: 680;
  letter-spacing: -.01em;
  text-transform: none;
  color: var(--ink);
  margin: 14px 0 6px;
}
.rte-area blockquote {
  margin: 0 0 9px;
  padding-left: 11px;
  border-left: 3px solid var(--line);
  color: var(--ink-2);
}

.rte-hint { margin: 0; font-size: 11.5px; color: var(--ink-3); }

/* --- Deux petites choses ------------------------------------------------- */

/* L'ordre d'une liste est une question posée à la barre d'outils : « Sort »
   reste accroché à son sélecteur, et la paire ne se coupe pas en fin de
   ligne. */
.sortpick {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}
.sortpick > .muted {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.sortpick select { width: auto; min-width: 0; }

/* Un drapeau dans une cellule de tableau. Même pile de polices que le grand
   bandeau : sans elle, Windows rend le code ISO à deux lettres au lieu du
   drapeau, et la colonne se lit « FRDEIT ». */
.flag-inline {
  font-size: 15px;
  line-height: 1;
  font-family: 'Twemoji Country Flags', 'Noto Color Emoji', 'Apple Color Emoji',
               'Segoe UI Emoji', sans-serif;
}

/* --- Les mêmes, en petit écran ------------------------------------------- */

@media (max-width: 860px) {
  /* Une cible de doigt fait 44 px ; ces boutons-là en faisaient 28. */
  .rte-btn { min-width: 32px; height: 32px; }
  .bell-x, .cmt-x { padding: 7px; opacity: 1; }
}

@media (max-width: 620px) {
  /* Une carte par ligne : à 280 px de minimum, deux colonnes n'existent de
     toute façon plus sous 620 px — la règle rend la chose explicite plutôt
     que de la laisser dépendre d'un calcul de grille. */
  .reccards { grid-template-columns: minmax(0, 1fr); }

  /* La colonne de lecture ne se limite plus : la page fait déjà moins de
     760 px, et le fil aurait l'air décentré. */
  .cmt-list, .cmt-form { max-width: none; }
  .cmt { padding: 9px 10px; }

  /* Le menu de la cloche, sur petit écran : ancré à la BARRE HAUTE, pas au
     bouton et pas à l'écran.

     Deux tentatives ont échoué avant celle-ci, et les deux pour la même cause.
     `.topbar` porte un `backdrop-filter`, et un filtre d'arrière-plan fait de
     l'élément le BLOC CONTENEUR de ses descendants en position FIXE : une
     feuille calée en `bottom: 10px` se résolvait contre la barre haute et non
     contre l'écran — à 375 × 812 elle se mesurait de -101 à 136 px, ses entrées
     les plus récentes au-dessus du bord supérieur, et un élément fixe ne se
     fait pas défiler jusqu'à soi. Ancré au bouton, ensuite, le menu partait par
     la GAUCHE : la cloche siège à 196 px du bord et le menu en fait 345.

     Ce même `.topbar` est en revanche un excellent repère : il est en
     `position: sticky`, donc déjà bloc conteneur, et il occupe toute la
     largeur. On y ancre donc le menu — `left` et `right` à 10 px de l'écran,
     `top: 100%` sous la barre quelle que soit sa hauteur, qu'elle s'enroule sur
     deux rangées ou sur trois. C'est la seule des trois solutions qui n'ait
     rien à deviner. */
  .bell { position: static; }
  .bell-menu {
    top: calc(100% + 6px);
    left: 10px;
    right: 10px;
    width: auto;
    max-width: none;
    max-height: 60vh;
  }

  .rte-area { min-height: 140px; max-height: 55vh; }
}
