/* ============================================================
   Oxygène — design system de l'intranet.
   Tokens de la charte (identité) + coquille de l'app + contrat
   de classes documenté dans ui-guide.md (à côté de ce fichier).
   Densité « outil financier » : alignements stricts, chiffres
   tabulaires, hiérarchie sobre. Aucun asset externe (CSP).
   ============================================================ */
@import url("tokens/fonts.e19e53bbdb18.css");
@import url("tokens/colors.fa81bc675122.css");
@import url("tokens/typography.c61d0b2f62a1.css");
@import url("tokens/spacing.d8d6f638055f.css");
@import url("tokens/effects.71f3a78951f4.css");
@import url("tokens/base.7a269685ea17.css");

/* ---- Variables de coquille (dérivées des tokens) ---- */
:root {
  --topbar-h: 64px;
  --control-h: 38px;      /* hauteur commune boutons / champs */
  --control-h-sm: 30px;
  --libelle-col: minmax(200px, 300px);   /* colonne libellés des formulaires */
}

/* ---- Animations ---- */
@keyframes ox-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* ---- FOCUS — anneau visible unique, pour tout ce qui reçoit le clavier (audit a11y
   2026-08-29 : 35 `:hover` pour 2 `:focus-visible` dans ce fichier). `:where()` garde
   une spécificité de 0 : les focus déjà dessinés ailleurs (.btn, .onglets a) continuent
   de gagner sans être touchés par cette règle transversale. */
:where(a, button, summary, [tabindex], input, select, textarea):focus-visible {
  outline: var(--border-thick) solid var(--focus-ring);
  outline-offset: 2px;
}

/* ============================================================
   COQUILLE — topbar + conteneur de page
   ============================================================ */
.topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: var(--space-8);
  padding: 0 var(--space-8); height: var(--topbar-h);
  background: rgba(255, 255, 255, 0.94); backdrop-filter: blur(8px);
  border-bottom: var(--border-hairline) solid var(--border-default);
}
.brand { display: inline-flex; align-items: center; text-decoration: none; }
.brand img { height: 40px; display: block; }
.nav-main { display: flex; align-items: center; gap: var(--space-7); }
.nav-user { margin-left: auto; display: flex; align-items: center; gap: var(--space-6); }

/* Tous les éléments d'en-tête : même police, même taille, même couleur.
   :not(.avatar) exclut les ronds d'avatar-initiales (aussi des <span>) : sinon le
   gris --text-secondary (spécificité 0,1,1) l'emporterait sur la teinte blanche des
   initiales (.avatar-bleu…, 0,1,0) → texte illisible sur fond coloré. */
.nav-main a, .nav-user span:not(.avatar), .nav-user .link {
  font-family: var(--font-ui); font-size: var(--fs-body-sm); font-weight: var(--fw-medium);
  color: var(--text-secondary); text-decoration: none; line-height: 1;
}

/* Liens de nav principaux (à gauche) — pastille + souligné or */
.nav-main a { position: relative; z-index: 0; transition: color var(--dur-fast) var(--ease-out); }
.nav-main a::before {
  content: none;
}
.nav-main a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -8px; height: 2px;
  background: var(--ox-gold); border-radius: 2px; transform: scaleX(0); transform-origin: center;
  transition: transform var(--dur-fast) var(--ease-out);
}
.nav-main a:hover { color: var(--color-brand-hover); text-decoration: none; }
.nav-main a:hover::after { transform: scaleX(1); }
/* Entrée ACTIVE (« où suis-je », retour Maxime 2026-07-17) : même langage que les
   onglets — texte affirmé + le soulignement or du hover rendu PERSISTANT. */
.nav-main a.actif, .nav-main a[aria-current="page"] {
  color: var(--text-primary); font-weight: var(--fw-semibold);
}
.nav-main a.actif::after, .nav-main a[aria-current="page"]::after { transform: scaleX(1); }
.nav-user .link:hover { color: var(--color-brand); }

/* ---- Avatar (photo Graph ou initiales) ---- */
.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  object-fit: cover; flex: none; display: inline-flex;
  align-items: center; justify-content: center;
  border: var(--border-hairline) solid var(--border-subtle);
  background: var(--color-surface);
}
.avatar-initiales {
  font-family: var(--font-ui); font-size: var(--fs-caption);
  font-weight: var(--fw-semibold); line-height: 1; letter-spacing: .02em;
  color: var(--text-on-brand); text-transform: uppercase; user-select: none;
  border-color: transparent;
}
.avatar-mini { width: 20px; height: 20px; }
.avatar-mini.avatar-initiales { font-size: 10px; }
/* Teintes déterministes dérivées des tokens (jamais de hex en dur ni d'aléa). */
.avatar-bleu    { background: var(--blue-600);    color: #fff; }
.avatar-or      { background: var(--gold-900);    color: #fff; }   /* était gold-700 : 3,28:1, échec AA — 6,75:1 */
.avatar-ardoise { background: var(--neutral-600); color: #fff; }
.avatar-sauge   { background: var(--success-600); color: #fff; }
.avatar-brique  { background: var(--danger-600);  color: #fff; }
.avatar-prune   { background: var(--blue-800);    color: #fff; }

/* ---- Présence « N en ligne » ---- */
.presence {
  position: relative; display: inline-flex; align-items: center;
  gap: var(--space-2); cursor: default;
  /* `outline: none` retiré (2026-08-29, audit a11y A11Y-02) : cet élément porte
     `tabindex="0"` (base.html) — sans remplacement c'était un échec WCAG 2.4.7
     caractérisé. L'anneau de focus transversal ci-dessus s'applique désormais. */
}
.presence-point {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--success-600);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--success-600) 22%, transparent);
}
.presence-libelle {
  font-family: var(--font-ui); font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium); color: var(--text-secondary); line-height: 1;
}
/* Panneau au survol/focus — sous la pastille, masqué par défaut. */
.presence-panneau {
  position: absolute; top: calc(100% + var(--space-3)); left: 0;
  min-width: 200px; max-width: min(280px, calc(100vw - 2 * var(--space-5)));
  padding: var(--space-4); z-index: 60;
  background: var(--color-surface); color: var(--text-primary);
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .18s var(--ease-out), transform .18s var(--ease-out), visibility .18s;
}
.presence:hover .presence-panneau,
.presence:focus-within .presence-panneau,
.presence:focus .presence-panneau { opacity: 1; visibility: visible; transform: none; }
.presence-panneau-titre {
  margin: 0 0 var(--space-3); font-size: var(--fs-caption);
  font-weight: var(--fw-semibold); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted);
}
.presence-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.presence-item { display: flex; align-items: center; gap: var(--space-3); }
.presence-nom {
  font-size: var(--fs-body-sm); color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.presence-moi {
  font-size: var(--fs-caption); color: var(--text-muted);
  font-weight: var(--fw-medium);
}
.presence-liste:empty::after {
  content: 'Personne d’autre en ligne.'; color: var(--text-muted); font-size: var(--fs-caption);
}

/* Conteneur de page — `main` reçoit .page dans base.html.
   Largeur large : {% block classe_page %} large{% endblock %} */
main, .page {
  max-width: var(--container-max);
  margin: var(--space-7) auto var(--space-11);
  padding: 0 var(--space-8);
  animation: ox-rise .4s var(--ease-out) both;
}
main.large, .page.large { max-width: var(--container-wide); }

/* ============================================================
   EN-TÊTE DE PAGE — .page-head (fil d'ariane, eyebrow, h1, actions)
   ============================================================ */
.page-head { margin-bottom: var(--space-7); }
.fil-ariane {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-1);
  font-size: var(--fs-caption); color: var(--text-muted); margin-bottom: var(--space-3);
}
.fil-ariane a { color: var(--text-muted); font-weight: var(--fw-medium); }
.fil-ariane a:hover { color: var(--color-brand); text-decoration: none; }
.fil-ariane a:not(:first-child)::before,
.fil-ariane span:not(:first-child)::before {
  content: '/'; margin: 0 var(--space-2); color: var(--border-strong); font-weight: var(--fw-regular);
}
.page-head-ligne {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-6); flex-wrap: wrap;
}
.page-head h1 { font-size: var(--fs-h1); font-weight: var(--fw-light); margin: 0; }
.page-head h1::after {
  content: ''; display: block; width: 48px; height: 2px;
  background: var(--ox-gold); margin-top: var(--space-3);
}
.page-head .eyebrow { margin-bottom: var(--space-2); }
.page-sous-titre { color: var(--text-muted); font-size: var(--fs-body-sm); margin: var(--space-3) 0 0; max-width: 72ch; }
.page-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-left: auto; }

/* Titres hors .page-head : filet or optionnel (compat existant) */
h1 { font-size: var(--fs-h1); }
h1.avec-filet::after { content: ''; display: block; width: 48px; height: 2px; background: var(--ox-gold); margin-top: var(--space-4); }

/* Titres de section dans le flux d'une page (h2 « nus ») */
main h2 { font-size: var(--fs-h2); margin: var(--space-8) 0 var(--space-4); }
main h3 { font-size: var(--fs-h3); font-family: var(--font-display); margin: var(--space-6) 0 var(--space-3); }
.eyebrow { font-family: var(--font-ui); font-size: var(--fs-caption); font-weight: var(--fw-medium); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--color-accent-text); }

/* ============================================================
   BOUTONS
   ============================================================ */
/* Le fond de marque passe par --color-brand / --color-brand-hover (et non par
   --ox-blue / --blue-700 écrits en dur) depuis le lot 8, 2026-08-29 : VALEURS
   IDENTIQUES sur l'intranet, mais le bouton devient surchargeable par PORTÉE DE
   THÈME. C'est ce qui permet au site client (`.site-client`, bleu nuit) de
   partager cette définition au lieu d'en forker une seconde. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  font-family: var(--font-ui); font-weight: var(--fw-medium); font-size: var(--fs-body-sm); line-height: 1; letter-spacing: 0;
  height: var(--control-h); padding: 0 18px; border-radius: var(--radius-sm);
  border: var(--border-hairline) solid var(--color-brand); cursor: pointer; text-decoration: none;
  background: var(--color-brand); color: var(--text-on-brand); white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.btn:hover { background: var(--color-brand-hover); text-decoration: none; }
.btn:active { transform: none; }
.btn:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; box-shadow: none; }
.btn.sm { height: var(--control-h-sm); padding: 0 12px; font-size: 13px; gap: 6px; }
.btn.lg { height: 48px; padding: 0 26px; font-size: 16px; gap: 10px; }
.btn.gold { background: var(--ox-gold); border-color: var(--ox-gold); color: var(--text-on-gold); }
.btn.gold:hover { background: var(--gold-600); }
.btn.secondary { background: var(--white); border-color: var(--border-default); color: var(--color-brand); }
.btn.secondary:hover { background: var(--blue-50); border-color: var(--border-brand); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--color-brand); }
.btn.ghost:hover { background: var(--blue-50); }
.btn.danger { background: var(--danger-600); border-color: var(--danger-600); color: #fff; }
.btn.danger:hover { background: var(--danger-700); }

.link { background: none; border: 0; color: var(--text-secondary); cursor: pointer; font: inherit; padding: 0; position: relative; transition: color var(--dur) var(--ease-out); }
.link:hover { color: var(--color-brand); }

/* ============================================================
   CARTES & PANNEAUX
   ============================================================ */
/* .card — carte libre (compat existant) */
.card { position: relative; display: flex; flex-direction: column; align-items: flex-start; background: var(--color-surface); border: var(--border-hairline) solid var(--border-default); border-radius: var(--radius-md); box-shadow: none; padding: var(--space-7); overflow: hidden; }
.card > .btn { margin-top: auto; }   /* CTA calé en bas : cartes voisines alignées */
.card > p, .card > h3 { align-self: stretch; }
.card.gold-rule::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: var(--border-accent); background: var(--ox-gold); }
.card.interactive { transition: background var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out); }
.card.interactive:hover { background: var(--blue-50); transform: none; box-shadow: none; border-color: var(--border-strong); }

/* .panneau — panneau structuré avec barre de titre (le standard des pages) */
.panneau {
  background: var(--color-surface);
  border: var(--border-hairline) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: none;
  margin-bottom: var(--space-6);
}
.panneau-titre {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
  padding: var(--space-3) var(--space-5); min-height: 46px;
  border-bottom: var(--border-hairline) solid var(--border-default);
  background: var(--white);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
.panneau-titre :is(h2, h3, h4) {
  margin: 0; font-family: var(--font-ui); font-size: var(--fs-body-sm); font-weight: var(--fw-medium);
  letter-spacing: .02em; color: var(--text-primary); line-height: var(--lh-snug);
}
.panneau-titre .compteur { color: var(--text-muted); font-weight: var(--fw-regular); }
.panneau-titre .panneau-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.panneau-corps { padding: var(--space-5); }
.panneau-corps > :last-child { margin-bottom: 0; }
/* .panneau.vedette — panneau mis en avant (« L'essentiel » en tête de page) :
   filet or en tête, comme .card.gold-rule, pour le distinguer sans styles inline. */
.panneau.vedette { position: relative; border-color: var(--border-subtle); box-shadow: none; }
.panneau.vedette::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: var(--border-accent); background: var(--ox-gold); border-radius: var(--radius-md) var(--radius-md) 0 0; }
.panneau.vedette .panneau-titre { background: var(--white); }
.panneau-pied {
  padding: var(--space-3) var(--space-5);
  border-top: var(--border-hairline) solid var(--border-subtle);
  font-size: var(--fs-caption); color: var(--text-muted);
}
/* Table posée directement dans un panneau : pleine largeur, marges internes alignées */
.panneau > table { margin: 0; }
.panneau > table th:first-child, .panneau > table td:first-child { padding-left: var(--space-5); }
.panneau > table th:last-child,  .panneau > table td:last-child  { padding-right: var(--space-5); }
.panneau > table tbody tr:last-child td { border-bottom: 0; }
.panneau > .table-scroll { margin: 0; }
.panneau > .table-scroll table tbody tr:last-child td { border-bottom: 0; }
.panneau > .table-scroll th:first-child, .panneau > .table-scroll td:first-child { padding-left: var(--space-5); }
.panneau > .table-scroll th:last-child,  .panneau > .table-scroll td:last-child  { padding-right: var(--space-5); }

/* Grilles de cartes / panneaux */
.grille-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); }
.grille-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-5); }

/* ---- .tdb-grille — grille de widgets hétérogènes (tableau de bord) ----
   Deux colonnes régulières ; un widget peut occuper toute la largeur avec
   `.span-2`. La kpi-grille reste pour les rangées d'indicateurs homogènes. */
.tdb-grille { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); align-items: start; }
.tdb-grille > .span-2 { grid-column: 1 / -1; }

/* ---- .jauge — barre de progression (couverture / complétude) ----
   Deux div : la piste et le remplissage. La largeur du remplissage est le SEUL
   style inline toléré (comme `.court`) ; toutes les couleurs sont des tokens.
   Variantes de teinte par état : .jauge.att (ambre), .jauge.bas (rouge). */
.jauge { height: 8px; border-radius: var(--radius-pill); background: var(--neutral-100); overflow: hidden; }
.jauge > i { display: block; height: 100%; background: var(--success-600); border-radius: inherit; }
.jauge.att > i { background: var(--warning-600); }
.jauge.bas > i { background: var(--danger-600); }

/* ---- .delta — tendance ↑ / ↓ ----
   La SÉMANTIQUE (hausse = bien ou mal) n'est jamais implicite : la classe de
   COULEUR (.up = vert, .down = rouge) est choisie par l'appelant selon le sens
   métier, la FLÈCHE dit seulement la direction. */
.delta { display: inline-flex; align-items: center; gap: 2px; font-size: var(--fs-caption); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.delta.up   { color: var(--success-600); }
.delta.down { color: var(--danger-600); }
.delta .fleche { font-size: .9em; line-height: 1; }

/* ---- .sparkline — mini-graphe SVG des flux annuels (BP) ----
   Généré CÔTÉ SERVEUR (template tag tdb_format.sparkline), aucune lib/CDN. Le
   SVG s'étire (preserveAspectRatio="none") : on fixe sa taille d'affichage ici,
   toutes les teintes en tokens. Le trait ne se déforme pas (vector-effect). */
.sparkline { display: block; width: 120px; height: 28px; max-width: 100%; flex-shrink: 0; }
.sparkline .spark-trace { stroke: var(--ox-blue); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.sparkline .spark-zero { stroke: var(--border-subtle); stroke-width: 1; stroke-dasharray: 2 2; vector-effect: non-scaling-stroke; }
.sparkline .spark-point { fill: var(--ox-blue); }

/* ---- Strate « Archives » repliable (page Portefeuille) : affordance de pliage ----
   Le <summary> réutilise .panneau-titre (flex) qui masque le marqueur natif ; on
   restaure le curseur et un chevron qui pivote à l'ouverture. */
.strate-archivee > summary { cursor: pointer; list-style: none; }
.strate-archivee > summary::-webkit-details-marker { display: none; }
.strate-archivee > summary .chevron { display: inline-block; color: var(--text-muted); transition: transform var(--dur) var(--ease-out); }
.strate-archivee[open] > summary .chevron { transform: rotate(90deg); }

/* ---- Panneau REPLIABLE générique (même affordance que .strate-archivee) ----
   Le récap « Documents (N) » est masqué par défaut, une flèche le démasque (retour
   Maxime 2026-07-08). Le <summary> réutilise .panneau-titre (flex → marqueur natif
   masqué) ; on restaure le curseur et un chevron qui pivote à l'ouverture. */
.panneau-repliable > summary { cursor: pointer; list-style: none; }
.panneau-repliable > summary::-webkit-details-marker { display: none; }
.panneau-repliable > summary .chevron { display: inline-block; color: var(--text-muted); transition: transform .22s ease; }
.panneau-repliable[open] > summary .chevron { transform: rotate(90deg); }

/* ---- Bouton DÉSACTIVÉ (rendu en <span> non navigable) : grisé + curseur d'interdiction ;
   l'infobulle explique pourquoi. Sert aux actions d'analyse AU NIVEAU SECTION (coût). ---- */
.btn.disabled, .btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

/* ---- .tuile-deal — tuile de deal (page Portefeuille) ----
   Une .card.interactive dont TOUT le corps est le lien vers le tableau de bord
   du deal. Structure verticale : en-tête (nom + statut), rangée d'indicateurs,
   jauge de complétude, pied BP (KPI + sparkline). Aucune couleur en dur. */
.tuile-deal { text-decoration: none; color: inherit; gap: var(--space-4); }
.tuile-deal:hover .tuile-nom { color: var(--color-brand); }
.tuile-deal-tete { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); align-self: stretch; }
.tuile-nom { font-weight: var(--fw-semibold); color: var(--text-primary); line-height: var(--lh-snug); }
.tuile-indics { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-self: stretch; font-size: var(--fs-caption); color: var(--text-muted); }
.tuile-indics b { color: var(--text-primary); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
/* Motif d'un deal abandonné sur sa tuile (lot 5, base de connaissance) : discret, sur
   une ligne (l'intégralité reste en title). */
.tuile-abandon-motif { align-self: stretch; font-size: var(--fs-caption); }
.tuile-jauge { align-self: stretch; }
.tuile-jauge .jauge { margin-top: 4px; }
.tuile-bp { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); align-self: stretch; margin-top: auto; padding-top: var(--space-3); border-top: var(--border-hairline) solid var(--border-subtle); }
.tuile-bp-kpi { font-size: var(--fs-caption); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tuile-bp-kpi b { color: var(--text-primary); font-weight: var(--fw-semibold); }

/* ---- Widgets du tableau de bord : valeurs de faits, blocs, listes ---- */
/* Valeur d'un fait (deux colonnes) : la vérité forte, la reco discrète, le lien
   de drill-down neutre (souligné au survol, pas d'aplat). */
.fait-val { display: inline-flex; align-items: baseline; gap: var(--space-1); flex-wrap: wrap; justify-content: flex-end; }
.fait-verite { font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); color: var(--text-primary); }
.fait-lien { color: inherit; text-decoration: none; }
.fait-lien:hover { text-decoration: underline; text-decoration-color: var(--border-default); }
/* Bloc intra-panneau (valeur vénale multi, ratios par actif) : petit intertitre. */
.fait-bloc { margin-bottom: var(--space-4); }
.fait-bloc-titre { font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); margin: var(--space-4) 0 var(--space-2); }
/* Listes nues (candidats, red flags, échéances) : sans puce, aérées. */
.liste-nue { list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.liste-nue > li { padding: var(--space-1) 0; border-bottom: var(--border-hairline) solid var(--border-subtle); line-height: var(--lh-body); }
.liste-nue > li:last-child { border-bottom: 0; }
/* Regroupement red flags par section / échéances par état. */
.rf-section { margin-bottom: var(--space-4); }
.rf-section-tete { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-3) 0 var(--space-1); font-size: var(--fs-body-sm); }

/* ---- KPI (indicateurs chiffrés en tête de page) ----
   Fond = surface (pas la couleur des filets) : une dernière rangée incomplète
   reste blanche au lieu de laisser un pavé gris. Les filets entre cellules
   sont peints par ombre portée de chaque cellule. */
.kpi-grille {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1px;
  background: var(--color-surface); border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-md); overflow: hidden; margin-bottom: var(--space-6);
}
.kpi {
  background: var(--color-surface); padding: var(--space-3) var(--space-4);
  box-shadow: 1px 0 0 var(--border-subtle), 0 1px 0 var(--border-subtle), 1px 1px 0 var(--border-subtle);
}
.kpi-libelle { font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); }
.kpi-valeur { font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--text-primary); font-variant-numeric: tabular-nums; line-height: var(--lh-snug); margin-top: 2px; }
.kpi-valeur .unite { font-size: var(--fs-caption); color: var(--text-muted); font-weight: var(--fw-regular); margin-left: 2px; }
.kpi-note { font-size: var(--fs-caption); color: var(--text-muted); margin-top: 2px; }

/* ============================================================
   TABLES — denses, chiffres tabulaires
   ============================================================ */
table { border-collapse: collapse; width: 100%; font-size: var(--fs-body-sm); line-height: var(--lh-normal, 1.5); }
th, td {
  text-align: left; vertical-align: middle;
  padding: var(--space-2) var(--space-3);
  border-bottom: var(--border-hairline) solid var(--border-subtle);
}
th {
  color: var(--text-muted); font-weight: var(--fw-semibold); font-size: var(--fs-micro);
  letter-spacing: var(--ls-caps); text-transform: uppercase; white-space: nowrap;
  border-bottom-color: var(--border-default);
}
tbody tr { transition: background var(--dur-fast) var(--ease-out); }
tbody tr:hover { background: var(--blue-50); }
td a { font-weight: var(--fw-medium); }

/* Chiffres : alignés à droite, chasse fixe — sur th ET td */
.num { text-align: right !important; font-variant-numeric: tabular-nums; font-feature-settings: var(--num-tabular); white-space: nowrap; }
/* Ligne de total / sous-total */
tr.total td { font-weight: var(--fw-semibold); border-top: var(--border-thick) solid var(--border-default); background: var(--paper-alt); }
/* Ligne d'intitulé de groupe au sein d'une table */
tr.groupe td {
  background: var(--paper-alt); color: var(--text-secondary);
  font-size: var(--fs-micro); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps); text-transform: uppercase;
}

/* En-têtes collants (longues tables de saisie / résultats).
   OBSOLÈTE (lot 4) — préférer `.table-figee` (plus bas), qui fonctionne. Ce
   mécanisme-ci ne colle QUE si la table n'est enfermée dans aucun conteneur à
   `overflow` : dès qu'elle est dans un `.table-scroll` (ou dans un `.panneau`
   sous 768 px), le conteneur devient le contexte de défilement et le `top:
   var(--topbar-h)` se mesure sur LUI — un conteneur qui ne défile jamais
   verticalement. Le collage est alors un no-op silencieux. Plus aucun gabarit
   de `bp` / `tdb` ne pose cette classe ; règle conservée le temps que les
   autres briques migrent. */
.table-sticky thead th {
  position: sticky; top: var(--topbar-h); z-index: 5;
  background: var(--paper);
  box-shadow: 0 1px 0 var(--border-default);
  border-bottom: 0;
}
/* Défilement horizontal maîtrisé (à la place du `display:block` global) */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-bottom: var(--space-6); }
.table-scroll > table { margin: 0; }

/* ============================================================
   FORMULAIRES — grille libellé / champ, unités, aides
   ============================================================ */
input[type=text], input[type=email], input[type=number], input[type=date],
input[type=password], input[type=search], input[type=url], select, textarea {
  height: var(--control-h); padding: 0 12px;
  border: var(--border-hairline) solid var(--border-default);
  border-radius: var(--radius-sm); font-family: var(--font-ui); font-size: var(--fs-body-sm);
  background: var(--white); color: var(--text-primary);
  transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
select { padding: 0 8px; max-width: 100%; }
textarea { height: auto; min-height: 96px; padding: var(--space-2) 12px; line-height: var(--lh-body); resize: vertical; }
input:focus, select:focus, textarea:focus {
  outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; border-color: var(--border-brand); box-shadow: none;
}
/* Même largeur de base pour tous les champs texte (email compris — sinon
   deux champs empilés d'un même formulaire n'ont pas la même largeur). */
input[type=text], input[type=email], input[type=search], input[type=url] { min-width: 16rem; max-width: 100%; }
input.num, td input, td select { text-align: right; font-variant-numeric: tabular-nums; }
td input[type=date], td select { text-align: left; }
input.court { min-width: 0; width: 8rem; }
input.sm, select.sm { height: var(--control-h-sm); font-size: var(--fs-caption); }

label { font-size: var(--fs-body-sm); }

/* .form-grille — grille 2 colonnes stricte : libellés à gauche, champs à droite.
   Enfants directs : <label class="form-libelle"> puis <div class="form-champ">
   (et, si besoin, <p class="form-aide"> qui se cale sous le champ). */
.form-grille {
  display: grid;
  grid-template-columns: var(--libelle-col) minmax(0, 1fr);
  column-gap: var(--space-6); row-gap: var(--space-3);
  align-items: center;
  margin-bottom: var(--space-5);
}
.form-libelle {
  font-size: var(--fs-body-sm); font-weight: var(--fw-medium); color: var(--text-secondary);
  line-height: var(--lh-snug); justify-self: start;
}
.form-libelle .unite, .form-libelle small { display: block; font-size: var(--fs-micro); font-weight: var(--fw-regular); color: var(--text-muted); }
.form-champ { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; min-width: 0; }
.form-champ > .unite { font-size: var(--fs-caption); color: var(--text-muted); white-space: nowrap; }
/* Un <textarea> dans la colonne champ occupe TOUTE la largeur (sinon il retombe sur
   sa largeur intrinsèque ~cols, tassé à gauche du panneau — cas « commentaire » des
   écrans Arbitrer un fait / Éditer une ligne). align-items:center reste sans effet
   sur un bloc pleine largeur. */
.form-champ > textarea { flex: 1 1 100%; width: 100%; align-self: stretch; }
/* Écran « Éditer une ligne » de checklist (gabarit large — retour Maxime 2026-07-07 :
   les zones de saisie étaient toutes petites). Dans ce formulaire, le champ texte
   « Valeur » remplit toute la largeur de sa colonne (au lieu de rester à sa base de
   16rem à gauche) ; le bouton « Adopter la reco » passe alors à la ligne. Scopé à
   `.edition-ligne` : les autres formulaires (BP, arbitrage de fait…) restent inchangés. */
.edition-ligne .form-champ > input[type=text] { flex: 1 1 100%; width: 100%; }
.form-aide { grid-column: 2; margin: calc(-1 * var(--space-1)) 0 0; font-size: var(--fs-caption); color: var(--text-muted); }
/* Intertitre au sein d'une .form-grille (sous-section) */
.form-section {
  grid-column: 1 / -1; margin: var(--space-4) 0 0;
  font-size: var(--fs-micro); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted);
  border-bottom: var(--border-hairline) solid var(--border-subtle); padding-bottom: var(--space-1);
}

/* .form-ligne — groupe vertical libellé + champ, pour rangées horizontales
   (à combiner avec .barre : filtres, petits formulaires inline). */
.form-ligne { display: flex; flex-direction: column; gap: var(--space-1); }
.form-ligne > label { font-size: var(--fs-caption); font-weight: var(--fw-medium); color: var(--text-secondary); }

/* Champ + unité soudés (suffixe dans le cadre) */
.champ-unite { display: inline-flex; align-items: stretch; }
.champ-unite input { border-radius: var(--radius-sm) 0 0 var(--radius-sm); min-width: 0; }
.champ-unite .unite {
  display: inline-flex; align-items: center; padding: 0 10px;
  border: var(--border-hairline) solid var(--border-default); border-left: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--paper-alt); color: var(--text-muted);
  font-size: var(--fs-caption); white-space: nowrap;
}

/* Barre d'actions / de filtres (compat existant) */
.barre { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin: 0 0 var(--space-6); }
.etiquette { align-self: center; color: var(--text-muted); font-size: var(--fs-caption); }
.cellule-section { display: inline-flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

/* Libellé d'une rangée haute (groupe de cases à cocher…) : calé en haut,
   aligné optiquement sur la première ligne du champ. */
.form-libelle.haut { align-self: start; padding-top: 2px; }

/* Pied de formulaire : bouton principal + note, aligné sur la colonne champs */
.form-pied { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-5); }
.form-grille + .form-pied { margin-left: 0; }

/* .form-encart — encart d'avertissement PLEINE LARGEUR au sein d'un formulaire
   (ex. « qualité réduite », « surcoût »). Bloc autonome — NE PAS lui donner
   .form-grille : il n'a pas de colonne libellé et serait tassé dans les 200-300px
   de gauche. Empile verticalement pastille + explication + case de confirmation. */
.form-encart {
  display: flex; flex-direction: column; gap: var(--space-2);
  margin: var(--space-4) 0 var(--space-5);
  padding: var(--space-4);
  border: var(--border-hairline) solid var(--border-subtle);
  border-left: var(--border-accent) solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--paper-alt);
}
.form-encart .form-aide { grid-column: auto; margin: 0; }   /* neutralise le calage grille */
.form-encart > label { display: flex; align-items: baseline; gap: var(--space-2); color: var(--text-secondary); }
/* Teinte « attention » quand l'encart porte un risque (dégradé/coût) */
.form-encart.attention { border-left-color: var(--warning-600); background: var(--warning-100); }
/* Ligne de tableau « à écart » (page Écarts constaté/projeté, #51-C4c) : même jeton
   warning que la pastille, en teinte de fond discrète — sans cette règle la classe
   tr.attention posée par le gabarit était un signal mort (constat de revue). */
tr.attention > td { background: var(--warning-100); }

/* ============================================================
   ONGLETS & NAVIGATION SECONDAIRE
   ============================================================ */
.onglets {
  display: flex; align-items: flex-end; gap: var(--space-1);
  border-bottom: var(--border-hairline) solid var(--border-default);
  margin-bottom: var(--space-6); overflow-x: auto;
  /* overflow-y EXPLICITEMENT masqué : `overflow-x: auto` seul force overflow-y à
     `auto` aussi (règle CSS : les deux axes ne peuvent pas être `visible`/`auto`
     indépendamment), et Windows affichait alors des ASCENSEURS VERTICAUX parasites
     sur chaque barre d'onglets — signalé par Maxime le 2026-08-28, capture à l'appui.
     Le débord vertical d'une barre d'onglets n'existe pas : on peut le masquer. */
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;   /* défilement à inertie sur mobile */
}
.onglets a {
  padding: var(--space-2) var(--space-4); margin-bottom: -1px;
  font-size: var(--fs-body-sm); font-weight: var(--fw-medium); color: var(--text-secondary);
  border-bottom: 2px solid transparent; white-space: nowrap; text-decoration: none;
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.onglets a:hover { color: var(--color-brand); text-decoration: none; }
.onglets a.actif, .onglets a[aria-current="page"] {
  color: var(--text-primary); font-weight: var(--fw-semibold);
  border-bottom-color: var(--ox-gold);
}
.onglets a:focus-visible {
  outline: 2px solid var(--focus-ring); outline-offset: 2px;
}
.onglets .pastille { margin-left: var(--space-1); }

/* Pastille de COMPTAGE sur le ruban de sections (retour Maxime 2026-07-08) : DORÉE,
   pour bien la distinguer du numéro de section (00, 01…). L'italique a été retirée
   (2026-08-29) : remplacée par l'interlettrage capitales utilisé pour un texte
   « secondaire ». Couleur passée à gold-900 (était gold-700 : 3,02:1, échec AA — 6,22:1). */
.pastille.compte-sec {
  background: var(--gold-50); color: var(--gold-900);
  font-weight: var(--fw-medium); letter-spacing: var(--ls-caps);
}

/* Panneau de SURVOL des onglets de section (nom complet de la section) — position:fixed
   (posé par JS sur l'onglet survolé) pour ÉCHAPPER à l'overflow-x du ruban (un tooltip CSS
   y serait rogné). Petite flèche vers le bas. Retour Maxime 2026-07-08. */
.onglet-survol {
  position: fixed; z-index: 60; display: none; pointer-events: none;
  transform: translate(-50%, calc(-100% - 8px));
  background: var(--color-brand); color: #fff;
  padding: 5px 10px; border-radius: var(--radius-sm);
  font-size: var(--fs-caption); font-weight: var(--fw-medium); white-space: nowrap;
  box-shadow: var(--shadow-lg);
}
.onglet-survol::after {
  content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--color-brand);
}
/* Ruban de filtre COLLANT (page Documents, nav #traitement — retour Maxime 2026-07-08 :
   « que la barre apparaisse en haut pour faciliter le passage d'un dossier à un autre ») :
   colle sous la topbar fixe quand on fait défiler la liste des documents. Fond PLEIN
   (var(--paper)) pour que les lignes du tableau ne transparaissent pas dessous ; même
   patron que .table-sticky. z-index 4 (le tableau Documents n'a pas d'en-tête collant). */
.onglets-collant {
  position: sticky; top: var(--topbar-h); z-index: 4;
  background: var(--paper); box-shadow: 0 1px 0 var(--border-default);
  /* Ancre #traitement : sans marge, l'ancre tombe à y=0 SOUS la topbar fixe (64px) → le
     ruban ET le titre de section « NN. Nom » sont masqués dessous (« quelques lignes trop
     bas », retour Maxime 2026-07-08). On décale l'atterrissage juste sous la topbar. */
  scroll-margin-top: calc(var(--topbar-h) + var(--space-2));
}

/* --- Navigation PRINCIPALE d'un deal — {% onglets_deal %} -------------------
   Raffinements « pro/quali » réservés à la barre transverse du deal (classe
   `onglets-deal`), pour ne pas toucher aux autres usages de `.onglets` (ex.
   filtre de sections de la page Documents, qui reste au ruban sobre).
   Le soulignement or est ANIMÉ (scaleX) au survol comme la nav principale
   (patron `.nav-main a::after`) ; l'onglet actif porte un trait or PLEIN. */
.onglets-deal { gap: var(--space-2); margin-bottom: var(--space-7); }
.onglets-deal a {
  position: relative; border-bottom-color: transparent;
  border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm);
  transition: color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}
/* léger fond au survol (jamais sur l'onglet actif, qui se lit au trait) */
.onglets-deal a:hover { background: var(--paper-alt); }
/* soulignement or qui grandit depuis le centre — survol ET actif */
.onglets-deal a::after {
  content: ''; position: absolute; left: var(--space-3); right: var(--space-3); bottom: -1px;
  height: 2px; background: var(--ox-gold); border-radius: 2px;
  transform: scaleX(0); transform-origin: center;
  transition: transform var(--dur) var(--ease-out);
}
.onglets-deal a:hover::after { transform: scaleX(.62); }
.onglets-deal a.actif::after, .onglets-deal a[aria-current="page"]::after {
  transform: scaleX(1);
}

/* ============================================================
   SOMMAIRE — sidebar d'ancres (saisie BP, pages longues)
   ============================================================ */
.avec-sommaire {
  display: grid; grid-template-columns: 210px minmax(0, 1fr);
  gap: var(--space-8); align-items: start;
}
.sommaire {
  position: sticky; top: calc(var(--topbar-h) + var(--space-5));
  display: flex; flex-direction: column; gap: 1px;
  font-size: var(--fs-caption); max-height: calc(100vh - var(--topbar-h) - var(--space-8));
  overflow-y: auto; border-left: 2px solid var(--border-subtle); padding-left: 0;
}
.sommaire a {
  padding: 5px var(--space-3); margin-left: -2px;
  color: var(--text-muted); font-weight: var(--fw-medium); text-decoration: none;
  border-left: 2px solid transparent;
}
.sommaire a:hover { color: var(--color-brand); text-decoration: none; }
.sommaire a.actif { color: var(--color-brand); border-left-color: var(--ox-gold); font-weight: var(--fw-semibold); }
.sommaire-titre {
  padding: 0 var(--space-3) var(--space-2); margin-left: -2px;
  font-size: var(--fs-micro); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted);
}
/* Les sections cibles gardent leur titre visible sous la topbar */
.avec-sommaire [id] { scroll-margin-top: calc(var(--topbar-h) + var(--space-4)); }

/* ============================================================
   PASTILLES, DIVERS
   ============================================================ */
.pastille {
  display: inline-block; padding: 2px var(--space-2); border-radius: var(--radius-pill);
  font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: .02em;
  line-height: 1.5; white-space: nowrap; vertical-align: baseline;
}
.pastille.ok        { background: var(--success-100); color: var(--success-600); }
.pastille.ko        { background: var(--danger-100);  color: var(--danger-600); }
.pastille.attention { background: var(--warning-100); color: var(--warning-600); }
.pastille.info      { background: var(--info-100);    color: var(--blue-700); }
.pastille.neutre    { background: var(--neutral-100); color: var(--neutral-600); }
.pastille.or        { background: var(--gold-100);    color: var(--gold-900); }
/* Statut SUGGÉRÉ par la webapp (passe Opus, étage 3) : pastille volontairement
   plus discrète que le statut humain — fond effacé, contour pointillé, léger
   estompage — pour se lire « proposition » et non « décision ». Se combine avec la
   couleur du statut (.pastille.ok.suggere, .attention.suggere…) et n'apparaît que
   tant que l'humain n'a rien tranché. */
.pastille.suggere {
  background: transparent; border: var(--border-hairline) dashed currentColor;
  opacity: .8; font-weight: var(--fw-medium);
}

.muted { color: var(--text-muted); }
.inline { display: inline; }
.chip-on { color: var(--color-brand); font-weight: var(--fw-semibold); }

/* Lecteur de documents intégré */
.lecteur { width: 100%; height: calc(100vh - 240px); min-height: 480px; border: var(--border-hairline) solid var(--border-subtle); border-radius: var(--radius-md); background: var(--white); }
.lecteur-image { max-width: 100%; border: var(--border-hairline) solid var(--border-subtle); border-radius: var(--radius-md); }
.doc-liens { font-size: .75rem; color: var(--text-muted); }
.doc-liens a { color: var(--text-muted); }
.doc-liens a:hover { color: var(--color-brand); }

/* ============================================================
   EXPLORATEUR D'ARBORESCENCE — page Documents (site Deals)
   Modale <dialog> native + aperçu live de destination. Remplace les menus
   cascade n°1/n°2 (retour Maxime 2026-07-08) : « explorateur de fichiers ».
   ============================================================ */
/* Ligne de tri (site Deals) : occupe TOUTE la largeur de la cellule pour pousser
   « Analyser » + « Valider » À DROITE (retour Maxime 2026-07-08). `.cellule-section`
   fournit déjà align-items/gap/flex-wrap ; on ne change que display + largeur. */
.js-ligne-tri { display: flex; width: 100%; }
.js-ligne-tri .case-analyser { margin-left: auto; }
/* La modale : largeur bornée, centrée, ombrée ; ::backdrop discret. */
.explorateur {
  width: min(640px, calc(100vw - 2 * var(--space-4)));
  max-height: calc(100vh - 4 * var(--space-6));
  padding: 0; border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  background: var(--color-surface); color: var(--text-primary);
}
.explorateur::backdrop { background: rgba(20, 24, 33, .38); }
.explorateur-tete {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-5) var(--space-5) var(--space-3);
  border-bottom: var(--border-hairline) solid var(--border-subtle);
}
/* Fil d'Ariane : niveaux cliquables (boutons nus), séparés par « / ». */
.explorateur-fil { display: flex; flex-wrap: wrap; align-items: baseline; }
.explorateur-fil .fil-niveau {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--color-brand); font: inherit; font-size: var(--fs-caption);
}
.explorateur-fil .fil-niveau:hover { text-decoration: underline; }
.explorateur-fil .fil-sep { color: var(--border-strong); font-size: var(--fs-caption); }
/* Liste des dossiers-enfants : items pleine largeur, cliquables au hover. */
.explorateur-liste {
  list-style: none; margin: 0; padding: var(--space-2) var(--space-3);
  overflow-y: auto; max-height: 42vh;
}
.explorateur-liste li { margin: 0; }
.explorateur-item {
  display: block; width: 100%; text-align: left;
  padding: var(--space-2) var(--space-3); border: none; border-radius: var(--radius-sm);
  background: none; cursor: pointer; font: inherit; color: var(--text-primary);
}
/* Marqueurs DOSSIER / FICHIER — traits dessinés, jamais d'emoji (2026-08-29).
   `.ico-dossier` / `.ico-fichier` sont la forme RÉUTILISABLE (ajoutées au lot 8) :
   à poser sur un <span aria-hidden="true"> quand le type est déjà porté par le
   texte ou par un attribut. `.explorateur-item::before` reprend la même géométrie
   pour le cas où le marqueur ne peut pas être un élément (bouton généré). */
.ico-dossier, .ico-fichier {
  content: ''; display: inline-block; width: 10px; height: 8px;
  margin-right: var(--space-2); vertical-align: baseline;
  border: var(--border-hairline) solid var(--color-accent-strong);
}
/* Dossier : languette en haut (bord supérieur épaissi), coin supérieur gauche vif. */
.ico-dossier { border-radius: 1px 2px 2px 2px; border-top-width: var(--border-thick); }
/* Fichier : feuille plus haute que large, coin supérieur droit rogné. */
.ico-fichier {
  width: 8px; height: 10px; border-radius: 1px;
  border-color: var(--border-strong);
}
.explorateur-item::before {
  content: ''; display: inline-block; width: 10px; height: 8px;
  margin-right: var(--space-2); vertical-align: baseline;
  border: var(--border-hairline) solid var(--color-accent-strong);
  border-radius: 1px 2px 2px 2px; border-top-width: var(--border-thick);
}
.explorateur-item:hover { background: var(--color-surface-alt); }
.explorateur-vide {
  padding: var(--space-3); color: var(--text-muted); font-size: var(--fs-caption);
}
/* Champ « créer un sous-dossier ici » : discret, séparé du reste. */
.explorateur-creer {
  display: flex; gap: var(--space-2); align-items: center;
  padding: var(--space-3) var(--space-5);
  border-top: var(--border-hairline) solid var(--border-subtle);
}
.explorateur-creer input { flex: 1 1 auto; }
/* Pied : actions primaire (Choisir) + secondaire (Annuler). */
.explorateur-pied {
  display: flex; justify-content: flex-end; gap: var(--space-2);
  padding: var(--space-3) var(--space-5) var(--space-5);
}

/* ============================================================
   VUE SCINDÉE — analyse (gauche) ↔ lecteur PDF collant (droite)
   Page analyse d'un document : à gauche points/synthèses, à droite un
   lecteur pdf.js sticky. En < 980 px : le lecteur passe AU-DESSUS, replié.
   ============================================================ */
/* (#47 « max d'espace dispo ») : la colonne ANALYSE garde une largeur de lecture
   bornée (480→820 px par défaut), le LECTEUR prend TOUT le reste — c'est lui qui
   profite des grands écrans. Entre les deux, une POIGNÉE (.vue-splitter) : le drag
   pose --scindee-analyse en px (mémorisé localStorage). Sans JS : défauts. */
.vue-scindee {
  display: grid;
  grid-template-columns: minmax(480px, var(--scindee-analyse, 820px)) 10px minmax(0, 1fr);
  gap: 0 var(--space-3); align-items: start;
}
.vue-scindee.sans-lecteur { display: block; }   /* image/autre : pas de lecteur */
.vue-colonne { min-width: 0; }   /* évite que les tables larges forcent la grille */

.vue-splitter {
  cursor: col-resize; width: 10px; align-self: stretch;
  position: sticky; top: calc(var(--topbar-h) + var(--space-4));
  height: calc(100vh - var(--topbar-h) - var(--space-7));
  touch-action: none;   /* le drag tactile ne doit pas défiler la page */
}
.vue-splitter::before {
  content: ''; display: block; width: 2px; height: 100%; margin: 0 auto;
  background: var(--border-subtle); border-radius: 2px;
  transition: background var(--dur) var(--ease-out);
}
.vue-splitter:hover::before, .vue-splitter.actif::before { background: var(--ox-gold); }
.vue-scindee.sans-lecteur .vue-splitter { display: none; }

.lecteur-lateral {
  position: sticky; top: calc(var(--topbar-h) + var(--space-4));
  display: flex; flex-direction: column;
  height: calc(100vh - var(--topbar-h) - var(--space-7));
  min-height: 420px;
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-md); background: var(--color-surface);
  overflow: hidden;
}
.lecteur-lateral-barre {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-bottom: var(--border-hairline) solid var(--border-subtle);
  background: var(--color-surface-alt);
}
.lecteur-lateral-titre {
  font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.lecteur-lateral-actions { display: flex; align-items: center; gap: var(--space-2); flex: none; }
.lecteur-lateral-cadre { flex: 1 1 auto; min-height: 0; }
.lecteur-lateral-iframe { width: 100%; height: 100%; border: 0; background: var(--white); display: block; }

/* Masqué : le lecteur se réduit à sa barre, la colonne de gauche s'élargit
   (la poignée disparaît : rien à redimensionner). */
.vue-scindee.lecteur-masque { grid-template-columns: minmax(0, 1fr) 0px auto; }
.vue-scindee.lecteur-masque .vue-splitter { display: none; }
.vue-scindee.lecteur-masque .lecteur-lateral { height: auto; min-height: 0; }
.vue-scindee.lecteur-masque .lecteur-lateral-cadre { display: none; }

/* SIDE PANEL « situation actuelle » (#63-C4d M4) — RÉUTILISE le châssis .lecteur-lateral
   (collant, barre + corps) mais son corps porte du CONTENU DÉFILANT (constaté du deal) et
   non un iframe : on lui donne donc le défilement vertical et un padding de lecture. */
.side-constate-corps { overflow-y: auto; padding: var(--space-3) var(--space-4); }
.side-constate-intro { font-size: var(--fs-caption); margin-top: 0; }
.side-constate-actif { padding-bottom: var(--space-4); margin-bottom: var(--space-4); border-bottom: var(--border-hairline) solid var(--border-subtle); }
.side-constate-actif:last-child { border-bottom: 0; margin-bottom: 0; }
.side-constate-sous {
  font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--text-muted); margin: var(--space-3) 0 var(--space-2);
}

/* Séparateur horizontal sobre */
hr, .filet { border: 0; border-top: var(--border-hairline) solid var(--border-subtle); margin: var(--space-8) 0 var(--space-6); }

/* Zone dangereuse (suppression) */
.zone-danger {
  border: var(--border-hairline) solid var(--danger-100); border-radius: var(--radius-md);
  background: color-mix(in oklab, var(--danger-100) 35%, var(--white));
  padding: var(--space-4) var(--space-5); margin-top: var(--space-8);
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
}
.zone-danger .muted { font-size: var(--fs-caption); }

/* État vide */
.vide {
  padding: var(--space-8) var(--space-6); text-align: center;
  color: var(--text-muted); font-size: var(--fs-body-sm);
  border: 1px dashed var(--border-default); border-radius: var(--radius-md);
  background: var(--white);
}

/* ---- Utilitaires d'espacement (échelle 4px) ---- */
.mt-0 { margin-top: 0 !important; }        .mb-0 { margin-bottom: 0 !important; }
.mt-2 { margin-top: var(--space-2) !important; }  .mb-2 { margin-bottom: var(--space-2) !important; }
.mt-4 { margin-top: var(--space-4) !important; }  .mb-4 { margin-bottom: var(--space-4) !important; }
.mt-6 { margin-top: var(--space-6) !important; }  .mb-6 { margin-bottom: var(--space-6) !important; }
.mt-8 { margin-top: var(--space-8) !important; }  .mb-8 { margin-bottom: var(--space-8) !important; }

/* ============================================================
   MESSAGES (toasts) — mécanisme flash.js conservé
   ============================================================ */
.flash-zone {
  position: fixed; top: calc(var(--topbar-h) + var(--space-3)); right: var(--space-6); z-index: 200;
  display: flex; flex-direction: column; gap: var(--space-3);
  width: min(380px, calc(100vw - 2 * var(--space-5))); pointer-events: none;
}
.flash {
  pointer-events: auto; cursor: pointer;
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-md);
  font-size: var(--fs-body-sm); line-height: var(--lh-body);
  background: var(--white); color: var(--text-primary);
  border: var(--border-hairline) solid var(--border-subtle);
  border-left: 3px solid var(--border-strong); box-shadow: var(--shadow-lg);
  animation: ox-toast-in .32s var(--ease-out) both;
}
.flash.success { border-left-color: var(--success-600); }
.flash.error   { border-left-color: var(--danger-600); }
.flash.info    { border-left-color: var(--info-600); }
.flash.warning { border-left-color: var(--warning-600); }
@keyframes ox-toast-in  { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes ox-toast-out { to { opacity: 0; transform: translateX(18px); } }

/* ============================================================
   HERO (page de connexion / accueil)
   ============================================================ */
.hero {
  position: relative; overflow: hidden; border-radius: var(--radius-lg);
  background: var(--blue-800);
  padding: var(--space-13) var(--space-10); box-shadow: none;
}
.hero::after {
  content: none;
}
.hero-in { position: relative; z-index: 1; max-width: 640px; }
.hero-in > * { animation: ox-rise .7s var(--ease-out) both; }
.hero-in > *:nth-child(2) { animation-delay: .09s; }
.hero-in > *:nth-child(3) { animation-delay: .18s; }
.hero-in > *:nth-child(4) { animation-delay: .27s; }
.hero .eyebrow { color: var(--ox-gold); }
.hero h1 {
  font-family: var(--font-display); font-size: var(--fs-display-m); line-height: var(--lh-tight);
  letter-spacing: var(--ls-display); color: #fff; margin: var(--space-4) 0 0;
}
/* Accent typographique livré en vraie italique Jost. */
.hero h1 .accent { color: var(--ox-gold); font-style: italic; font-weight: var(--fw-regular); }
.hero p.lead { font-size: var(--fs-body-lg); line-height: var(--lh-body); color: var(--text-inverse); opacity: .85; margin: var(--space-5) 0 var(--space-8); }
.hero .symbole { display: none; }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 980px) {
  .avec-sommaire { display: block; }
  .sommaire { display: none; }
  .grille-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Vue scindée : on empile (le lecteur passe SOUS l'analyse) et il n'est plus
     collant (une iframe sticky pleine hauteur volerait tout l'écran en mobile).
     Le cadre garde une hauteur de lecture bornée au viewport. La poignée de
     redimensionnement n'a pas de sens en 1 colonne. */
  .vue-scindee { grid-template-columns: 1fr; }
  .vue-splitter { display: none; }
  .lecteur-lateral { position: static; height: auto; }
  .lecteur-lateral-cadre { height: min(72vh, 560px); }
}
@media (max-width: 768px) {
  /* COQUILLE — la topbar ne doit JAMAIS déborder le document (audit responsive
     RWD-01 : +26 à +42px à 768px, +140 à +159px à 375px, mesuré sur 12/12 écrans —
     `.nav-user` ne s'enroulait ni ne se réduisait). `flex-wrap` la laisse passer sur
     plusieurs lignes plutôt que de pousser le document en largeur ; `height: auto`
     l'autorise à grandir (elle reste sticky, juste plus haute quand elle s'enroule). */
  .topbar { flex-wrap: wrap; height: auto; min-height: var(--topbar-h); row-gap: var(--space-2); }
  .nav-main, .nav-user { flex-wrap: wrap; row-gap: var(--space-2); }
  /* Barre de filtres (ex. Conformité) : un <select>/<input> ne rétrécit jamais sous sa
     largeur de contenu par défaut — sans ce `min-width: 0` sur l'item flex parent, il
     pousse le document en largeur au lieu de passer à la ligne (RWD-03). */
  .barre > .form-ligne { min-width: 0; }
  .barre .form-ligne select, .barre .form-ligne input { max-width: 100%; }
  /* Tables : on garde de VRAIES tables (filets et fonds pleine largeur) ;
     si le contenu déborde, c'est le panneau qui défile horizontalement.
     (l'ancien `display:block` faisait rétrécir les tables étroites : les
     filets s'arrêtaient avant le bord du panneau) */
  .panneau { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  /* Les tables larges défilables gardent une largeur de lecture confortable */
  .table-scroll > table.fixe { min-width: 640px; }
  .form-grille { grid-template-columns: 1fr; row-gap: var(--space-1); }
  .form-libelle { margin-top: var(--space-3); }
  .form-aide { grid-column: 1; }
  .grille-2, .grille-3 { grid-template-columns: 1fr; }
  /* Tableau de bord : les widgets s'empilent en 1 colonne (comme .grille-2) —
     sinon les tables denses restent tassées à ~165 px côte à côte sur mobile. */
  .tdb-grille { grid-template-columns: 1fr; }
  .page-head-ligne { align-items: flex-start; flex-direction: column; }
  .page-actions { margin-left: 0; }
}
@media (max-width: 640px) {
  :root { --topbar-h: 56px; }
  .topbar { padding: 0 var(--space-5); gap: var(--space-4); }
  .topbar .brand img { height: 32px; }
  .nav-main { gap: var(--space-5); }
  .nav-user { gap: var(--space-4); }
  main, .page { padding: 0 var(--space-5); margin-top: var(--space-6); }
  h1 { font-size: var(--fs-h2); }
  .hero { padding: var(--space-10) var(--space-6); }
  .hero h1 { font-size: var(--fs-h1); }
  .flash-zone { left: var(--space-4); right: var(--space-4); width: auto; }
}
@media (max-width: 520px) {
  .nav-user span { display: none; }   /* garde « Se déconnecter », masque le nom long */
  /* …mais l'avatar ET la présence (pastille + libellé) restent visibles. Comme le
     sélecteur ci-dessus masque TOUS les <span> de .nav-user, on ré-affiche
     explicitement ceux de la présence — sinon le point vert et « N en ligne »
     disparaissent sur mobile (constat bloquant : la présence exige de rester visible). */
  .nav-user .avatar, .nav-user .avatar-initiales { display: inline-flex; }
  .nav-user .presence { display: inline-flex; }
  .nav-user .presence-point { display: block; }
  .nav-user .presence-libelle { display: inline; }
  /* Noms du panneau de survol : préfixés .nav-user pour BATTRE en spécificité
     `.nav-user span` (0,1,1) — sans le préfixe, `.presence-nom` (0,1,0) perd et
     les noms restent masqués sur mobile (constat QA réel). */
  .nav-user .presence-nom, .nav-user .presence-moi { display: inline; }
  .presence-panneau { left: auto; right: 0; }   /* ne déborde pas à droite de l'écran */
}
@media (max-width: 400px) {
  /* Très étroit : on réduit à la pastille verte seule (le point RESTE affiché). */
  .nav-user .presence-libelle { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hero::after, .hero-in > *, main, .page { animation: none; }
  .topbar nav a:hover, .card.interactive:hover, .btn:active { transform: none; }
}

/* Tables à colonnes fixes : des panneaux empilés partageant le même schéma
   de colonnes (via <colgroup>) s'alignent parfaitement entre eux. */
table.fixe { table-layout: fixed; width: 100%; }
table.fixe td, table.fixe th { overflow: hidden; text-overflow: ellipsis; }
/* Colonne « Document » d'une table.fixe (espace documents Analyse) : le nom de
   fichier WRAPPE au lieu d'être tronqué à l'ellipse — jamais d'overflow, la colonne
   flexible absorbe la hauteur. Les autres colonnes gardent le comportement par défaut. */
table.fixe td.col-doc { white-space: normal; overflow-wrap: anywhere; }

/* Tables dont CHAQUE ligne doit tenir sur UNE ligne de texte (activité documentaire :
   noms de fichiers, chemins et identités viennent de SharePoint et n'ont aucune
   longueur garantie). Sans « nowrap », `text-overflow: ellipsis` ne s'applique PAS :
   le texte se replie, la cellule s'étire en hauteur, et une ligne à 5 862 fichiers
   monte à plusieurs milliers de pixels — c'est ce qui figeait le moteur de rendu.
   Le texte complet reste accessible dans l'attribut « title » de la cellule.
   `.libre` rouvre le repli sur les cellules qui empilent des gestes (boutons,
   formulaire de note) et n'affichent aucune donnée externe. */
table.fixe.ligne-unique td, table.fixe.ligne-unique th { white-space: nowrap; }
table.fixe.ligne-unique td.libre { white-space: normal; }

/* Table de saisie par actif (BP) : colonne des libellés lisible, sans
   repli en 4-5 lignes — le reste défile dans .table-scroll. */
.table-saisie th:first-child, .table-saisie td:first-child { min-width: 230px; white-space: normal; }

/* Extraits techniques (chemins SharePoint, destinations) : mono discret. */
code { font-family: 'Cascadia Mono', Consolas, 'SF Mono', monospace; font-size: .88em; letter-spacing: 0; }

/* Chips de saisie rapide (éditeur BP) — valeurs suggérées cliquables */
.chips { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
td .chips { margin-top: 3px; }
.chip {
  font-family: var(--font-ui); font-size: 11px; line-height: 1;
  padding: 3px 8px; border-radius: var(--radius-pill); cursor: pointer;
  border: var(--border-hairline) solid var(--border-default);
  background: var(--white); color: var(--text-secondary); white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.chip:hover { background: var(--blue-50); border-color: var(--border-brand); color: var(--color-brand); }
.chip:active { transform: none; }
.chip.chip-prop { border-style: dashed; color: var(--color-accent-text); }
.chip.chip-prop:hover { background: var(--gold-50); border-color: var(--border-gold); }

/* Case à cocher étiquetée en ligne (ex. commutateur « exploitation hôtelière »
   des actifs) : la case et son libellé restent alignés, jamais séparés. */
.case-a-cocher {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .9em; color: var(--text-secondary); white-space: nowrap; cursor: pointer;
}
.case-a-cocher input[type="checkbox"] { margin: 0; }

/* Matrice checklist (deux colonnes §3) : la cellule empile la VÉRITÉ validée
   (forte) et la reco webapp (muted) sur une ligne compacte, badges alignés.
   Reste lisible avec 11 colonnes d'actifs (troncature + title complet). */
.cl-cellule { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 6px; margin-top: 3px; }
.cl-verite { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.cl-reco { font-size: var(--fs-micro); }
/* Marqueur commentaire : petite plume discrète, sans occuper de place. */
.cl-note { color: var(--color-accent-text); font-size: var(--fs-caption); cursor: help; line-height: 1; }
/* Pied de matrice : trace discrète de la dernière passe IA (recos, omissions, coût). */
.cl-pied-ia { margin-top: var(--space-4); }

/* Synthèses (niveaux 2 & 3) : texte LLM rendu, avec références [#id] aux points.
   Le corps de synthèse respire un peu ; les références sont des liens discrets
   soulignés en pointillés (drill-down vers le point extrait et sa page). */
.texte-synthese { max-width: 78ch; line-height: 1.6; }
.ref-point {
  font-variant-numeric: tabular-nums; white-space: nowrap;
  text-decoration: underline; text-decoration-style: dotted;
  text-underline-offset: 2px; color: var(--color-brand);
}
.ref-point:hover { text-decoration-style: solid; }

/* Main humaine sur les points (doctrine « l'IA propose, l'humain dispose ») :
   la NOTE humaine prime l'affichage (bloc bleu clair, EN PREMIER), la reco IA
   reste intacte dessous ; un point désactivé est grisé et replié à part. */
.note-humaine {
  background: var(--info-100); border-left: 3px solid var(--blue-700);
  border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2); font-size: var(--fs-body-sm);
}
.note-humaine-tete { display: flex; align-items: baseline; gap: var(--space-2); margin-bottom: 2px; }
/* Marqueur ✎ : plume discrète signalant qu'un point cité en source porte une
   note humaine (title = la note). Reprend le ton de .cl-note (checklist). */
.marqueur-note { color: var(--color-accent-text); font-size: var(--fs-caption); cursor: help; line-height: 1; }
/* Bloc d'un point cité en SOURCE d'une reco (étage 3) : plusieurs empilés dans un
   même panneau, séparés par un filet léger (le dernier sans marge basse). */
.bloc-source { padding-bottom: var(--space-3); margin-bottom: var(--space-3); border-bottom: var(--border-hairline) solid var(--border-subtle); }
.bloc-source:last-child { padding-bottom: 0; margin-bottom: 0; border-bottom: none; }
/* Ligne désactivée : grisée, sans jamais disparaître (désactiver ≠ supprimer). */
.ligne-desactivee td { opacity: .72; }
/* Désactivation EN PLACE (JS) : la ligne se fond et se grise, sans faire sauter la
   page. `point-sortant` = état désactivé animé ; `point-flash` = confirmation brève. */
tr.point-sortant > td { opacity: .4; transition: opacity var(--dur) var(--ease-out); }
tr.point-sortant strong { text-decoration: line-through; }
.point-desactive-tag { display: inline-flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
@keyframes ox-point-flash { from { background: var(--gold-50); } to { background: transparent; } }
tr.point-flash > td { animation: ox-point-flash .9s var(--ease-out); }
/* Bloc d'actions « Main humaine » (document) : le <details> reste sobre ; ses
   deux formulaires (désactiver / annoter) s'empilent avec un peu d'air. */
.main-humaine > summary { cursor: pointer; }
.main-humaine-corps { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-2); }
.form-note textarea { width: 100%; max-width: 44ch; }
.ligne-actions { display: inline-flex; gap: var(--space-2); }
/* Actions main-humaine sur une LIGNE d'incohérence/alerte (tableau de bord du deal) :
   « Écarter » + tiroir « Trancher » côte à côte, alignés à droite (colonne num). Le
   tiroir « Trancher » ouvre le champ note sous la ligne d'actions, sans la casser. */
.main-humaine-ligne { display: inline-flex; }
.main-humaine-ligne .ligne-actions { align-items: flex-start; flex-wrap: wrap; }
.main-humaine-ligne-tiroir { text-align: left; }
.main-humaine-ligne-tiroir > summary { cursor: pointer; }
.lien-trancher {
  color: var(--color-brand); font-size: var(--fs-body-sm);
  text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px;
}
.lien-trancher:hover { text-decoration-style: solid; }
.main-humaine-ligne-tiroir[open] > summary { margin-bottom: var(--space-2); }
.main-humaine-ligne-tiroir .form-note { display: flex; flex-direction: column; gap: var(--space-1); }
/* REVUE PAR POINTS (#07 lot 3) : écran de validation opt-in de la fiche document.
   Une ligne DÉJÀ validée (acquis) est signalée par un liseré vert à gauche + un fond
   très léger ; les selects/notes tiennent dans leur cellule ; le rappel de la
   proposition IA (revue-ia) et la méta (revue-meta) restent discrets (jamais de
   couleur en dur — tokens sémantiques ; AUCUN thème sombre n'est implémenté à ce jour,
   mais l'absence de couleur en dur rendrait son ajout futur facile). */
tr.point-acquis > td { background: var(--success-100); }
tr.point-acquis > td:first-child { box-shadow: inset 3px 0 0 0 var(--success-600); }
#revue select.sm { max-width: 100%; }
#revue textarea { width: 100%; max-width: 100%; }
.revue-ia { font-size: var(--fs-caption); margin-top: 2px; }
.revue-meta { font-size: var(--fs-caption); margin: 2px 0; }
/* AUTOSAVE de la revue (#07 lot 4) : chaque geste s'enregistre au fil de l'eau, un visuel
   rassure. Bandeau d'état global COLLANT en tête de revue (sous la topbar) + pastille par
   ligne. Aucune couleur en dur — tokens sémantiques (pas de thème sombre implémenté
   à ce jour). */
.revue-bandeau {
  position: sticky; top: var(--topbar-h); z-index: 5;
  display: flex; align-items: center; gap: var(--space-2);
  margin: 0 0 var(--space-4); padding: var(--space-2) var(--space-5);
  font-size: var(--fs-body-sm); border-radius: var(--radius-sm);
}
.revue-bandeau.ok { background: var(--success-100); color: var(--success-600); }
.revue-bandeau.enregistrement { background: var(--info-100); color: var(--blue-700); }
.revue-bandeau.echec { background: var(--danger-100); color: var(--danger-600); cursor: pointer; }
/* Pastille d'état par ligne, à côté du contrôle modifié (1re cellule « Valider »). */
.revue-etat { display: inline-block; margin-top: 2px; font-size: var(--fs-caption); white-space: nowrap; }
.revue-etat.ok { color: var(--success-600); }
.revue-etat.en-cours { color: var(--text-muted); }
.revue-etat.echec {
  color: var(--danger-600); cursor: pointer;
  text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px;
}
/* Ligne dont un enregistrement a ÉCHOUÉ : liseré + fond danger (prime le vert « acquis »,
   défini juste au-dessus, car l'échec est plus important à signaler). */
tr.revue-echec > td { background: var(--danger-100); }
tr.revue-echec > td:first-child { box-shadow: inset 3px 0 0 0 var(--danger-600); }
/* Arbitrage d'un fait (tdb) — ligne de candidat RETENU mise en avant (la valeur qui
   fait foi doit sauter aux yeux) : liseré doré à gauche + fond très léger. */
tr.ligne-retenue > td { background: var(--gold-50); }
tr.ligne-retenue > td:first-child { box-shadow: inset 3px 0 0 0 var(--gold-500); }
/* Actions d'un candidat (Retenir / Écarter) : côte à côte, repli propre en étroit. */
.actions-candidat { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: flex-end; }
.col-actions-candidat { text-align: right; white-space: nowrap; }
/* Panneau « Points désactivés » replié en bas de la page document. */
.points-desactives > summary { cursor: pointer; padding: var(--space-3) var(--space-5); font-size: var(--fs-body-sm); }
/* Panneau « Documents hors champ » replié en bas de la page analyse du deal, et
   lignes hors champ grisées : sorti du champ ≠ supprimé (réversible, tracé). */
.documents-hors-champ > summary { cursor: pointer; padding: var(--space-3) var(--space-5); font-size: var(--fs-body-sm); }
.ligne-hors-champ td { opacity: .72; }
/* Documents compartimentés PAR RUBRIQUE (#40) : chaque section est un <details>
   repliable. Le <summary> aligne le titre à gauche et le méta (compteur, coût,
   pastille, bouton « Analyser la rubrique ») à droite, repli propre en étroit. */
.rubrique-docs { border-top: var(--border-hairline) solid var(--border-subtle); }
.rubrique-docs:first-of-type { border-top: none; }
.rubrique-docs > summary {
  cursor: pointer; list-style: none;
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  align-items: center; justify-content: space-between;
  padding: var(--space-3) var(--space-5);
}
.rubrique-docs > summary::-webkit-details-marker { display: none; }
.rubrique-titre { font-weight: 600; }
.rubrique-meta { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
/* Colonne de cases à cocher (sélection d'analyse depuis « Documents ») : étroite. */
.col-cocher { width: 1%; white-space: nowrap; text-align: center; }

/* ============================================================
   CONFORMITÉ (mission #36) — page unifiée DD + AM + Pièces, flags R/O/V
   Réutilise les pastilles existantes (.pastille ok/ko/attention/neutre) ;
   ici seulement la MISE EN PAGE (récap par phase, sections, liseré de flag).
   ============================================================ */
/* Mini-récap des deux phases côte à côte (Due diligence | Gestion). */
.conf-phases-recap {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4); margin-bottom: var(--space-5);
}
.conf-recap { margin-bottom: 0; }
.conf-recap-flags { display: inline-flex; gap: var(--space-2); margin: 0 0 var(--space-2); }
/* Une section de conformité dans un panneau de phase (titre h3 + table). */
.conf-section { padding: 0 var(--space-5) var(--space-4); }
.conf-section-titre {
  font-size: var(--fs-body-sm); font-weight: var(--fw-semibold);
  color: var(--text-muted); margin: var(--space-4) 0 var(--space-2);
}
/* Liseré de flag en tête de ligne : lecture tricolore d'un coup d'œil, sans
   couleur en dur (dérivée des mêmes tokens que les pastilles). */
.conf-flag-rouge  > td:first-child { box-shadow: inset 3px 0 0 var(--danger-600); }
.conf-flag-orange > td:first-child { box-shadow: inset 3px 0 0 var(--warning-600); }
.conf-flag-vert   > td:first-child { box-shadow: inset 3px 0 0 var(--success-600); }
.conf-flag-neutre > td:first-child { box-shadow: inset 3px 0 0 var(--neutral-300); }

/* Vue par actif de la Couverture (§3bis) : rappel du périmètre en vue par actif,
   ventilation par actif (puces cliquables) en vue globale multi-actifs. Mise en
   page seule — les compteurs réutilisent les pastilles ok/ko/attention (tokens). */
.conf-perimetre { margin: 0 0 var(--space-4); color: var(--text-secondary); }
.vent-actifs {
  display: flex; flex-wrap: wrap; gap: var(--space-3); margin: 0 0 var(--space-5);
}
.vent-actif {
  display: inline-flex; align-items: center; gap: var(--space-2);
  border: var(--border-hairline) solid var(--border-default);
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-3);
  background: var(--white); color: var(--text-secondary); text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.vent-actif:hover { border-color: var(--border-brand); background: var(--blue-50); }
.vent-actif-nom { font-size: var(--fs-body-sm); font-weight: var(--fw-medium); }

/* Bloc « Pièces de la couverture » de la fiche document (lot A, vue inverse) : un
   groupe par rubrique (badge neutre + chips des items liés). Mise en page seule. */
.doc-couverture-groupe {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2);
  margin: var(--space-2) 0;
}

/* ── Lot B — gestes humains de la couverture (chips retirer, lier, flag cliquable) ──
   Tout en tokens brand (aucune couleur en dur), zéro JS (details/summary natifs). */

/* Chip d'une pièce liée + croix « retirer » (Couverture et fiche document) : la croix
   suit le chip, discrète, rouge au survol. Le petit <form> POST reste en ligne. */
.chip-piece { display: inline-flex; align-items: center; gap: 1px; }
.chip-retirer-forme { display: inline-flex; margin: 0; }
.chip-retirer {
  background: none; border: 0; padding: 0 3px; cursor: pointer; line-height: 1;
  color: var(--text-muted); font-size: var(--fs-body); border-radius: var(--radius-sm);
}
.chip-retirer:hover { color: var(--danger-600); }

/* Geste « Lier un document » / « Ajouter une pièce » : <details> discret sous les chips,
   un <select> (documents de l'opération ou lignes de la couverture) + bouton. */
.lier-piece { margin-top: var(--space-2); }
.lier-piece > summary {
  cursor: pointer; color: var(--text-muted); font-size: var(--fs-body-sm); user-select: none;
}
.lier-piece > summary:hover { color: var(--color-brand); }
.lier-piece-forme {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-top: var(--space-2);
}
.lier-piece-forme select { max-width: 100%; }

/* FLAG CLIQUABLE (§3ter) : la pastille tricolore devient un menu <details> qui pose le
   statut d'un clic. Le panneau est en position ABSOLUE pour ne pas casser la ligne du
   tableau ; la cellule porteuse (`td.cellule-flag`) repasse en overflow visible — sans
   quoi `table.fixe td { overflow: hidden }` (ellipse) le rognerait. Le panneau peut être
   partiellement masqué si la ligne est tout en bas d'une table longue défilable
   (.table-scroll) : cas de bord assumé (v1), la majorité des lignes l'ouvrent en clair. */
table.fixe td.cellule-flag { overflow: visible; }
/* Progressive enhancement : tant qu'un menu de flag est OUVERT dans un tableau
   défilable, on laisse le conteneur déborder pour que le panneau ne soit pas rogné au
   bord bas d'une table longue. `:has()` non supporté (vieux navigateur) → repli propre
   sur le cas de bord documenté ci-dessus (la règle est ignorée). */
.table-scroll:has(.flag-menu[open]) { overflow: visible; }
.flag-menu { position: relative; display: inline-block; }
.flag-menu > summary { cursor: pointer; list-style: none; user-select: none; }
.flag-menu > summary::-webkit-details-marker { display: none; }
.flag-menu > summary::marker { content: ""; }
.flag-menu-panneau {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 20;
  min-width: 12rem; padding: var(--space-2);
  background: var(--white); border: var(--border-hairline) solid var(--border-default);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 2px;
}
.flag-menu-tete { margin: 0 0 var(--space-1); font-size: var(--fs-caption); }
.flag-menu-forme { margin: 0; }
.flag-menu-choix {
  display: block; width: 100%; text-align: left; font: inherit;
  background: none; border: 0; padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm); cursor: pointer;
}
.flag-menu-choix:hover { background: var(--paper-alt); }

/* Bandeau « écart de zone » (vue Étape) : le dossier SharePoint n'est pas à
   l'emplacement attendu (racine / Archives) — alerte discrète + bouton de
   rattrapage « Déplacer maintenant » (cycle-deal §3.6). */
.ecart-zone {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  background: var(--gold-50); border: 1px solid var(--border-gold);
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-3);
  margin: var(--space-3) 0;
}
.ecart-zone p { margin: 0; }

/* ── Cycle de vie de l'opération (vue Étape, circuit de validation lot 3) ─────── */

/* Frise du cycle : les 5 étapes résidentes en ligne, points reliés par un trait.
   États : faite (or plein), courante (accent doré, cerclé), à venir (neutre).
   Pur flex + ::after pour le trait ; wrap propre en étroit. */
.frise-etapes {
  list-style: none; margin: 0 0 var(--space-5); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  /* `overflow: hidden` (2026-08-29) : le trait `::after` de chaque étape (ci-dessous)
     s'étire de 100% de sa PROPRE largeur vers la droite pour rejoindre l'étape
     suivante — correct sur une ligne, mais le dernier élément d'une ligne repliée
     (mobile étroit) n'a rien à sa droite et le trait continue de déborder du
     document (mesuré : le débordement de la topbar le masquait jusqu'ici). Contient
     ce débord décoratif sans rien retirer au contenu (points/labels restent dans
     leur propre ligne, jamais plus larges que le conteneur). */
  overflow: hidden;
}
.frise-etape {
  position: relative; flex: 1 1 120px; min-width: 110px;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--space-1); padding-top: var(--space-4);
}
.frise-point {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--white); border: 2px solid var(--neutral-300);
}
/* Trait reliant chaque point au suivant (sauf le dernier). */
.frise-etape::after {
  content: ''; position: absolute; top: calc(var(--space-4) + 6px); left: 50%;
  width: 100%; height: 2px; background: var(--neutral-300); z-index: 0;
}
.frise-etape:last-child::after { display: none; }
.frise-point { position: relative; z-index: 1; }
.frise-label { font-size: var(--fs-caption); color: var(--text-muted); }
.frise-sous { font-size: 11px; }
/* Étape FAITE : point et trait en or. */
.frise-faite .frise-point { background: var(--ox-gold); border-color: var(--ox-gold); }
.frise-faite::after { background: var(--ox-gold); }
.frise-faite .frise-label { color: var(--color-brand); }
/* Étape COURANTE : point cerclé d'or, label fort. */
.frise-courante .frise-point {
  background: var(--white); border-color: var(--ox-gold);
  box-shadow: 0 0 0 4px var(--gold-50);
}
.frise-courante .frise-label { color: var(--color-brand); font-weight: var(--fw-semibold); }
/* Opération abandonnée : toute la frise en neutre (aucune courante). */
.frise-abandonnee .frise-point { background: var(--white); border-color: var(--neutral-300); }
.frise-abandonnee .frise-etape::after { background: var(--neutral-300); }
.frise-abandon-note { margin: 0 0 var(--space-4); }

/* Variante COMPACTE (lot 5) : frise réduite en tête du tableau de bord du deal.
   Points plus petits, moins d'air, labels resserrés (le libellé complet reste en
   `title` sur chaque étape). Même composant, même source (deals/_frise_etapes.html). */
.frise-etapes.compacte { margin: 0 0 var(--space-4); gap: var(--space-1) var(--space-3); }
.frise-etapes.compacte .frise-etape { flex-basis: 90px; min-width: 78px; padding-top: var(--space-3); }
.frise-etapes.compacte .frise-point { width: 10px; height: 10px; }
.frise-etapes.compacte .frise-etape::after { top: calc(var(--space-3) + 4px); }
.frise-etapes.compacte .frise-label { font-size: 11px; }
.frise-etapes.compacte .frise-sous { font-size: 10px; }

/* Panneau « Passage d'étape » : en-tête, boutons de préparation. */
.passage-entete { margin: 0 0 var(--space-4); }
.passage-boutons { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* Prérequis : liste de cases cliquables (POST cocher/décocher). */
.prerequis-liste { list-style: none; margin: 0 0 var(--space-5); padding: 0;
  display: flex; flex-direction: column; gap: var(--space-2); }
.prerequis-item { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2); }
.prerequis-case {
  display: inline-flex; align-items: center; gap: var(--space-2);
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
  font: inherit; color: var(--text-primary);
}
span.prerequis-case { cursor: default; }
.prerequis-marque {
  flex: none; width: 18px; height: 18px; border-radius: var(--radius-sm);
  border: 2px solid var(--neutral-300); background: var(--white);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: var(--fw-semibold); line-height: 1; color: var(--white);
}
.prerequis-case.coche .prerequis-marque {
  background: var(--success-600); border-color: var(--success-600);
}
.prerequis-trace { font-size: var(--fs-caption); }

/* Deux cartes de validation côte à côte (responsable / valideur). */
.cartes-validation {
  display: flex; flex-wrap: wrap; gap: var(--space-4); margin: var(--space-5) 0;
}
.carte-validation {
  flex: 1 1 220px; border: var(--border-hairline) solid var(--border-default);
  border-radius: var(--radius-md); padding: var(--space-4); background: var(--white);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.carte-validee { background: var(--gold-50); border-color: var(--ox-gold); }
.carte-role { font-weight: var(--fw-semibold); }
.carte-etat { margin: 0; color: var(--success-600); font-weight: var(--fw-medium); }
/* Bouton de validation grisé (désactivé pour qui n'est pas la bonne personne). */
.carte-validation .btn[disabled], .btn[disabled] {
  opacity: .5; cursor: not-allowed; pointer-events: none;
}

/* Form de refus + champs de demande. */
.form-demande .champ, .form-refus { margin: var(--space-3) 0; display: flex;
  flex-direction: column; gap: var(--space-2); max-width: 480px; }
.form-refus textarea, .form-demande textarea { width: 100%; }

/* Historique des passages : liste compacte. */
.historique-validations { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--space-2); }
.historique-item { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
/* Repli de l'historique : 2 entrées visibles, le reste derrière la flèche (details
   natif — le marqueur triangle du summary EST la flèche déplier/replier, aucun JS). */
.historique-plus > summary {
  cursor: pointer; color: var(--text-muted); font-size: var(--fs-body-sm);
  margin-top: var(--space-2); user-select: none;
}
.historique-plus > summary:hover { color: var(--color-brand); }
.historique-plus[open] > summary { margin-bottom: var(--space-2); }

/* ============================================================
   NOMBRES ET TABLEAUX — contrat typographique unique (lot 4)
   Trois règles, dans l'ordre de priorité :
     1. un nombre est ALIGNÉ À DROITE et en chasse fixe ;
     2. un nombre ne se TRONQUE jamais ;
     3. le SIGNE se lit par la FORME, pas seulement par la couleur.
   Ce bloc AJOUTE ; il ne réécrit rien du socle (contrastes, focus, topbar).
   ============================================================ */

/* ---- 1. Alignement : .num vaut aussi dans un conteneur FLEX ----
   `text-align` n'a AUCUN effet sur un conteneur flex : .cl-cellule restait donc
   aligné à gauche là où son jumeau .fait-val (justify-content: flex-end) était
   correct. Deux composants pour la même chose, un seul aligné. */
td.num > .cl-cellule,
th.num > .cl-cellule,
td.num > .fait-val { justify-content: flex-end; }
/* Un bloc de prose logé dans une cellule numérique (la <details> « Citation »
   d'un candidat) reprend la lecture normale : .num porte white-space: nowrap. */
td.num details, td.num blockquote { white-space: normal; text-align: left; }

/* ---- 2. Intégrité : un nombre déborde plutôt que d'être coupé ----
   `table.fixe td { overflow: hidden; text-overflow: ellipsis }` coupe à l'ellipse.
   Un titre coupé se voit ; « 12 500… » reste un nombre PLAUSIBLE, donc dangereux.
   Les colonnes numériques sont exemptées de la coupe. */
table.fixe td.num, table.fixe th.num { overflow: visible; text-overflow: clip; }

/* ---- 3. Écart : le composant .delta rendu utilisable EN CELLULE ----
   .delta (plus haut) est un inline-flex : dans un <td class="num">, il faut le
   pousser à droite lui-même — `text-align: right` ne l'y met pas. Le « = » de
   l'écart nul reste neutre (ni vert ni rouge) : zéro n'est pas une tendance. */
td.num > .delta { justify-content: flex-end; width: 100%; }
.delta .delta-pct { font-weight: var(--fw-regular); color: inherit; opacity: .75; }
.delta.egal { color: var(--text-muted); }

/* ---- 4. Repérage de ligne sur les tables larges ----
   Le survol était MORT là où il sert : `tbody tr:hover` peint le fond du <tr>,
   `tr.attention > td` peint celui des <td> PAR-DESSUS — donc sur les lignes en
   écart, précisément celles qu'on lit, le survol ne produisait aucun retour.
   On repasse le survol sur les <td> pour qu'il gagne, et on compose la teinte
   sur les lignes de statut. */
tbody tr:hover > td, tbody tr:hover > th { background: var(--blue-50); }
tbody tr.attention > th { background: var(--warning-100); }
tbody tr.attention:hover > td,
tbody tr.attention:hover > th { background: color-mix(in srgb, var(--warning-100) 70%, var(--blue-50)); }
tbody tr.total:hover > td, tbody tr.total:hover > th { background: var(--paper-alt); }
tbody tr.point-sortant:hover > td { background: var(--paper); }
/* Zébrure optionnelle (tables larges) : posée par le gabarit, jamais d'office. */
.table-zebra tbody tr:nth-child(even) > td,
.table-zebra tbody tr:nth-child(even) > th { background: color-mix(in srgb, var(--paper-alt) 55%, transparent); }
.table-zebra tbody tr:nth-child(even):hover > td,
.table-zebra tbody tr:nth-child(even):hover > th { background: var(--blue-50); }

/* ---- 5. Table LARGE et LONGUE : en-tête et 1re colonne figés ----
   PIÈGE, vérifié : .table-scroll pose `overflow-x: auto`, ce qui en fait un
   conteneur de défilement des DEUX axes. Un `position: sticky; top: var(--topbar-h)`
   posé DEDANS (.table-sticky) mesure alors son `top` par rapport à ce conteneur,
   dont la hauteur suit le contenu et qui ne défile jamais verticalement : le
   sticky est un NO-OP. Le correctif est de borner la HAUTEUR du conteneur et de
   coller l'en-tête à son propre `top: 0`. */
.table-figee {
  max-height: calc(100vh - var(--topbar-h) - 10rem);
  overflow: auto; -webkit-overflow-scrolling: touch;
  margin-bottom: var(--space-6);
}
.table-figee > table { margin: 0; }
.table-figee > table > thead th {
  position: sticky; top: 0; z-index: 5;
  background: var(--paper);
  box-shadow: 0 1px 0 var(--border-default);
  border-bottom: 0;
}
/* Première colonne figée (libellé de poste / de catégorie) : sans elle, à la 17e
   colonne d'un BP à 15 ans on ne sait plus quelle ligne on lit. */
.table-figee.fige-colonne > table > * > tr > *:first-child {
  position: sticky; left: 0; z-index: 4;
  background: var(--paper); box-shadow: 1px 0 0 var(--border-subtle);
}
.table-figee.fige-colonne > table > thead > tr > th:first-child { z-index: 6; }
.table-figee.fige-colonne > table > tbody > tr.total > td:first-child,
.table-figee.fige-colonne > table > tbody > tr.groupe > td:first-child { background: var(--paper-alt); }
/* Le panneau ne doit pas rogner la gouttière du conteneur figé. */
.panneau > .table-figee { margin: 0; }
.panneau > .table-figee > table th:first-child,
.panneau > .table-figee > table td:first-child { padding-left: var(--space-5); }
.panneau > .table-figee > table th:last-child,
.panneau > .table-figee > table td:last-child { padding-right: var(--space-5); }

/* ---- 6. En-tête de LIGNE (accessibilité) ----
   `<th scope="row">` associe la ligne à son libellé pour un lecteur d'écran : sans
   lui, une table de chiffres se lit comme une suite de nombres sans sujet. Mais le
   style global de `th` (petites capitales, muted, nowrap) est celui d'un en-tête de
   COLONNE — appliqué à un nom de locataire il défigure la table. On le ramène donc
   au rendu d'une cellule ordinaire : la sémantique change, pas l'apparence. */
tbody th[scope="row"] {
  text-transform: none; letter-spacing: normal; white-space: normal;
  color: var(--text-primary); font-size: inherit; font-weight: var(--fw-medium);
  border-bottom: var(--border-hairline) solid var(--border-subtle);
}
tbody tr.total th[scope="row"] {
  font-weight: var(--fw-semibold);
  border-top: var(--border-thick) solid var(--border-default);
  background: var(--paper-alt);
}

/* ---- 7. Légende de tableau (accessibilité) ----
   <caption> nomme le tableau pour un lecteur d'écran ; à l'écran il double le
   titre du panneau, on le rend donc DISCRET plutôt que de le masquer (un
   `display: none` le retirerait AUSSI de l'arbre d'accessibilité). */
table > caption {
  caption-side: top; text-align: left;
  padding: 0 0 var(--space-2) 0;
  color: var(--text-muted); font-size: var(--fs-micro);
  letter-spacing: var(--ls-caps); text-transform: uppercase;
  font-weight: var(--fw-semibold);
}
.panneau > .table-figee > table > caption,
.panneau > .table-scroll > table > caption { padding-left: var(--space-5); }

/* ============================================================
   IMPRESSION — feuille absente du design system jusqu'ici.
   Une feuille de business plan qu'on ne peut pas poser sur la
   table du comité n'existe pas.
   ============================================================ */
@media print {
  @page { size: A4 landscape; margin: 12mm 10mm; }

  /* La coquille disparaît ; seul le contenu s'imprime. */
  .topbar, .nav-main, .nav-user, .onglets, .onglets-deal, .sommaire,
  .page-actions, .form-pied, .zone-danger, .chips, .fil-ariane,
  .actions-candidat, .edit-inline, button, .btn { display: none !important; }

  body { background: #fff; color: #000; font-size: 9.5pt; }
  main, .page, main.large, .page.large { max-width: none; padding: 0; margin: 0; }
  .avec-sommaire { display: block; }        /* la grille 210px|1fr saute */

  /* Les conteneurs de défilement RENDENT TOUT : sinon les colonnes années du BP
     sont purement ABSENTES de la feuille (coupées à la largeur de l'écran). */
  .table-scroll, .table-figee, .panneau {
    overflow: visible !important; max-height: none !important;
  }
  .table-figee > table > thead th,
  .table-figee.fige-colonne > table > * > tr > *:first-child {
    position: static; box-shadow: none;
  }

  /* Les fonds de statut doivent survivre : les navigateurs les suppriment par
     défaut, or ils PORTENT l'information (ligne en écart, ligne de total). */
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }

  /* Une table ne se coupe pas n'importe où, et son en-tête se répète. */
  table { page-break-inside: auto; width: 100%; }
  thead { display: table-header-group; }
  tfoot { display: table-footer-group; }
  tr, .kpi, .card, .panneau { page-break-inside: avoid; }
  h1, h2, h3 { page-break-after: avoid; }
  .panneau { border: 1px solid #999; box-shadow: none; }
  table > caption { color: #000; }

  /* Les <details> repliés à l'écran s'ouvrent sur le papier (sinon ils sortent
     vides : la dette et la situation initiale en sont pleines). */
  details { display: block; }
  details > summary { list-style: none; font-weight: var(--fw-semibold); }
  details:not([open]) > *:not(summary) { display: revert; }

  /* Un lien imprimé sans sa cible est un cul-de-sac ; on la donne. */
  a[href^="http"]::after, a[href^="/"]::after { content: " (" attr(href) ")"; font-size: 8pt; color: #555; }
  a[href^="#"]::after { content: ""; }

  /* Chiffres : chasse fixe et alignement conservés sur le papier. */
  .num, .cl-verite, .fait-verite, .kpi-valeur { font-variant-numeric: tabular-nums; }
  .delta, .delta .fleche { color: #000; }
}
