/* ==================================================================
   cockpit.css — feuille d'écran du COCKPIT (#799).
   ------------------------------------------------------------------
   POURQUOI CE FICHIER EXISTE. Le cockpit n'avait pas de feuille propre :
   sa composition vivait pour partie dans `optifisc.css` (partagée par les
   22 écrans) et pour partie dans un `style=` en dur sur la grille du
   héros. La migration vers « Cockpit 29 pouces.dc.html » (#799) déplace
   deux blocs — l'en-tête et la carte de seuil — et ces règles n'ont RIEN
   à faire dans la feuille partagée : elles ne décrivent qu'un écran.

   CE QU'IL NE CONTIENT PAS, ET C'EST DÉLIBÉRÉ :
     · aucune valeur de design nouvelle — tout passe par les jetons de
       `optifisc-tokens.css`, source canonique unique (CLAUDE.md §Front) ;
     · aucune redéfinition de jeton — `tokens:audit` la refuserait, et le
       cockpit n'a aucune raison d'être la première exception ;
     · aucune palette sémantique : les teintes du héros (positif/négatif)
       restent celles de `optifisc.css`, on ne les recopie pas.

   LES RUPTURES SONT CELLES DU SOCLE (#765/#793) — 1600 / 1180 / 561 /
   560 — et pas des seuils inventés pour cet écran. Les quatre corps du
   `h1` (42 → 38 → 34 → 28) sont déjà portés par `--of-display-l` : le
   lot 4 de #799 n'a donc rien à recalculer sur le titre.
   ================================================================== */

/* ==================================================================
   §1 — L'EN-TÊTE (#799 lot 1)

   La maquette pose trois choses que la production n'avait pas : le titre
   et les actions sur UN MÊME RANG (le titre à gauche, ce qu'on peut en
   faire à droite), puis une ligne de contexte soulignée d'un filet qui
   sépare l'en-tête du contenu.

   La ligne de contexte n'est pas décorative : elle porte le lien ENTRANT
   vers « Situation détaillée » que DA-19 réclame pour cet écran. Depuis
   #765 lot B, cette vue ne s'atteint plus que par la sidebar — un seul
   chemin, et il disparaît sous 561 px. Ce lien est le second.
   ================================================================== */

.ck-entete-rang{
  display:flex; flex-wrap:wrap; gap:16px;
  align-items:flex-end; justify-content:space-between;
}
/* La colonne de titre garde sa mesure de lecture ; elle absorbe le
   reliquat pour que les actions restent collées au bord droit. */
.ck-entete-titre{ flex:1 1 24rem; min-width:min(100%,20rem) }
.ck-entete-actions{ margin:0; display:flex; gap:8px; align-items:center }

/* Ligne de contexte + FILET. Le filet appartient à l'en-tête, pas à la
   première carte : c'est lui qui dit « ici finit le cadrage, là commence
   la lecture ». */
/* `.page-head .ck-contexte` et non `.ck-contexte` : à spécificité 0-1-0, la
   règle perdait contre `.page-head p` (optifisc.css:2536) et le filet gardait
   sa borne de 76ch. Même piège que `.card.hero .bd` (#806, #828) — une règle
   d'écran qui vise un élément déjà stylé par le socle doit le dire. */
.page-head .ck-contexte{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:6px 12px;
  margin:16px 0 0; padding-bottom:14px;
  border-bottom:1px solid var(--of-line-300);
  font-size:13px; line-height:18px;
  /* `.page-head p` borne à 76ch (optifisc.css:2536) — juste pour une phrase
     d'intention, faux pour un FILET : il s'arrêtait au milieu de la page et se
     lisait comme une règle de tableau tronquée, pas comme une séparation. */
  max-width:none;
}
.ck-contexte-lien{ font-weight:650; color:var(--of-petrol-800) }
.ck-contexte-sens{ color:var(--of-ink-550) }
/* L'état d'URL, en mono, poussé à droite : `?vue=` est le SEUL état
   partageable de cet écran (DA-21) et il se lit rarement dans la barre
   d'adresse. Il vit DANS le panneau cockpit — il ne peut donc pas mentir
   sur la vue affichée. */
.ck-contexte-etat{
  margin-left:auto; font-family:var(--of-font-data);
  font-size:11px; color:var(--of-ink-550);
}
@media (max-width:560px){
  /* Sur téléphone la ligne passe en deux rangs : `margin-left:auto` ne
     pousse plus rien quand il n'y a plus de place à pousser. */
  .ck-contexte-etat{ margin-left:0 }
}

/* ==================================================================
   §1 bis — LA COMPOSITION EN BANDES (#847 lot 1)

   La maquette ne met RIEN à côté du patrimoine net : la carte de seuil
   tient toute la largeur, et le reste s'organise en BANDES de deux
   colonnes ÉGALES sous elle.

   ⚠️ Pourquoi ce n'est pas `.ck-grid` retouché mais une grille neuve :
   `.ck-grid` (optifisc.css:2111-2132) pose une colonne de lecture + un
   RAIL de 400 px, collant et défilant. Ce sont deux modèles différents,
   pas deux réglages du même. Les garder tous deux vivants aurait donné
   deux grammaires de composition pour un seul écran — et c'est
   exactement le défaut que #626 avait corrigé en son temps.

   ⚠️ ÉCART AVEC LA SPEC, TRANCHÉ (Thomas, 04/08, #847).
   `SPEC_Cockpit_29_pouces.md` §1 décrit 790 / 1fr / 342, et le squelette
   de chargement de la maquette les dessine. Mais l'état NOMINAL de la
   même maquette ne les dessine pas. Le squelette est un artefact : il est
   recopié à l'identique dans « Cockpit tablette », où 790 + 342 +
   gouttières ne tiennent pas dans 1024 px. L'état nominal fait foi.
   ⚠️ Conséquence pour le lot 5 : le squelette de chargement doit suivre
   CETTE géométrie. Un squelette en trois colonnes suivi d'un contenu en
   bandes, c'est le saut de mise en page que la SPEC §5 interdit — et il
   serait alors de NOTRE fait, plus de celui de la maquette.

   La rupture est celle du socle (1180), pas un seuil inventé.
   ================================================================== */

.ck-bandes{ display:grid; gap:var(--of-gap) }
.ck-bande{ display:grid; gap:var(--of-gap) }
/* `align-content:start` : une colonne courte ne s'étire pas pour
   rattraper sa voisine. Sans lui, une carte isolée se dilate et prend le
   rang d'une carte pleine — la hauteur devient un signal qu'elle ne
   porte pas. */
/* ⚠️ `grid-template-columns:minmax(0,1fr)` — ET C'EST UN CORRECTIF, PAS UN ORNEMENT.
   Sans piste EXPLICITE, `.ck-col` place ses cartes dans une colonne implicite
   dimensionnée `auto`, donc au moins au min-content de la plus large d'entre
   elles. `#kpis` porte huit tuiles en `repeat(4,1fr)` : son min-content vaut
   681 px. Résultat mesuré le 06/08 en DOM authentifié, à 1180 · 1300 · 1440 ·
   1600 px : la boîte de la colonne faisait bien 449/509/579/635 px, mais TOUTES
   ses cartes en faisaient 681 — elles débordaient dans la gouttière et par-dessus
   la colonne de droite. Le banc ne pouvait pas le voir : `largeurs-verif` mesure
   le débordement de la PAGE, et la page, elle, ne débordait pas.
   `min-width:0` seul ne suffit pas — il autorise la colonne à rétrécir, il
   n'empêche pas sa piste interne de grandir. */
.ck-col{
  display:grid; grid-template-columns:minmax(0,1fr);
  gap:var(--of-gap); align-content:start; min-width:0;
}

@media (min-width:1180px){
  .ck-bande{ grid-template-columns:repeat(2,minmax(0,1fr)); align-items:start }
}

/* La marge haute des cartes est portée par `.mt` (socle). Dans une
   colonne de grille, elle DOUBLE la gouttière sur la première carte de
   chaque colonne — le décalage se voit d'autant plus que les deux
   colonnes commencent au même niveau. La gouttière de la grille suffit. */
.ck-col > .mt:first-child{ margin-top:0 }

/* — LES TROIS REPLIS DE COLONNE ÉTROITE, REPORTÉS DEPUIS `.ck-rail` —
   Ce ne sont pas des règles cosmétiques et elles ne se perdent pas avec
   le rail : #626 (recette du lot D) les a écrites parce que trois blocs
   conçus pour 1 136 px avaient déménagé dans une colonne de 400 px SANS
   règle scopée. Le rail fiscal — le bloc signature — y affichait trois
   cellules laiton de ~89 px de contenu utile. Et le défaut ne se voyait
   pas : leurs replis étaient conditionnés au VIEWPORT (820/760 px), donc
   jamais déclenchés sur l'écran de 2 507 px qui a motivé l'issue.
   Le repli suit le CONTENEUR, pas la fenêtre. La colonne fait désormais
   la moitié de la largeur utile et non 400 px fixes — la règle vaut donc
   d'autant plus qu'elle protège aussi le palier 1180-1400. */
.ck-col .rail-grid{ grid-template-columns:1fr }
.ck-col .compl{ grid-template-columns:1fr; gap:14px; justify-items:start }
.ck-col .src-row{ grid-template-columns:minmax(90px,auto) 1fr auto; gap:8px }
/* ⚠️ NE PAS « CORRIGER » les 12 px dont `.src-row.action` dépasse sa carte :
   ils sont voulus. `optifisc.css:1023` lui pose `margin:-4px -6px` et
   `width:calc(100% + 12px)` pour que le fond de survol morde sur la gouttière
   de la carte au lieu de s'arrêter au ras du texte. Un détecteur de débordement
   naïf les compte comme une faute ; ce n'en est pas une, et la trace est écrite
   ici pour que le prochain passage ne les rabote pas. */

/* ==================================================================
   §1 ter — LES TROIS SOUS-ZONES (#847 lot 1)

   Composition assurance & pension, patrimoine net global, cap/dis.
   La SPEC §3 point 7 est explicite sur le traitement : « trois cartes de
   sous-zone, délimitées par FOND ET FILET, pas par une ombre — elles ne
   concurrencent pas les cartes de rang 1 ». C'est la seule chose qui les
   tient à leur rang, et c'est pour ça qu'aucune ombre n'apparaît ici.

   Rayon 14 (`--of-radius-md`) et non 18 : `DESIGN_TOKENS.md` §6 pose
   « nested card : au moins 4 px de moins que son parent » — 18 − 4 = 14.
   Le jeton existe, on ne recalcule rien.
   ================================================================== */

.ck-souszones{ display:grid; gap:var(--of-gap) }
@media (min-width:900px){
  .ck-souszones{ grid-template-columns:repeat(3,minmax(0,1fr)) }
}
.ck-souszone{
  padding:var(--of-pad);
  background:var(--of-surface-100);
  border-radius:var(--of-radius-md);
  /* Filet SEUL, jamais d'ombre — cf. ci-dessus. `--of-line-200` est le
     filet faible des surfaces de carte (optifisc-tokens.css:425). */
  box-shadow:inset 0 0 0 1px var(--of-line-200);
  min-width:0;
}
/* Titre de sous-zone : 13/650, la mesure de la maquette. La graisse 650
   est le palier intermédiaire de Manrope variable — c'est elle qui donne
   sa présence au titre sans le faire passer en gras. */
.ck-souszone-t{
  margin:0 0 10px; font-size:13px; line-height:18px;
  font-weight:650; color:var(--of-ink-650);
}
/* La note de la sous-zone porte la RÉSERVE (plafond fiscal, cascade,
   écart de contrôle). Elle n'est pas décorative : c'est elle qui empêche
   de lire un montant sans sa méthode. */
.ck-souszone-n{
  margin:10px 0 0; font-size:12px; line-height:17px;
  color:var(--of-ink-550); max-width:none;
}
.ck-souszone-n:empty{ display:none }

/* — LES DEUX BLOCS QUI CHANGENT DE FOND, ET C'EST TOUT CE QU'ILS CHANGENT —
   `.h-compo` (optifisc.css:614-616) était écrit POUR LE HÉROS : encre
   `rgba(255,255,255,.85)`, valeur en blanc plein. Sur `--of-surface-100`
   c'est illisible. On ne redéclare pas la notion — la fonte de données,
   les chiffres tabulaires et la graisse restent celles du socle — on
   corrige la SEULE chose qui dépendait du fond : l'encre.
   C'est la même règle que `.hero .h-evo .of-nul` en §3, dans l'autre sens. */
.ck-souszone .h-compo{ margin:0; color:var(--of-ink-650) }
.ck-souszone .h-compo .hc-v{ color:var(--of-ink-950) }
/* Une ligne par avoir : « libellé … montant », le montant poussé à droite.
   La maquette les empile, elle ne les met pas bout à bout séparés d'un
   point médian — deux avoirs de nature différente ne se lisent pas comme
   une énumération. `.hc-sep` devient donc sans emploi ici. */
.ck-souszone .hc-l{
  display:flex; justify-content:space-between; align-items:baseline;
  gap:12px; margin:0 0 4px;
}
.ck-souszone .hc-l:last-child{ margin-bottom:0 }
.ck-souszone .hc-k{ font-family:var(--of-font-ui) }

/* Le montant du net global : même corps que les autres chiffres de
   sous-zone, pas celui d'un héros. Il peut être NÉGATIF — c'est un net
   après passifs — et il n'y a donc aucune teinte de signe ici : la
   couleur ne porte jamais une valeur à elle seule, la cascade dessous
   dit d'où vient le résultat. */
.ck-souszone .h-global-v{
  font-family:var(--of-font-data); font-variant-numeric:tabular-nums;
  font-size:22px; line-height:28px; font-weight:600; color:var(--of-ink-950);
}

/* L'écart de contrôle : il ne s'affiche QUE s'il est servi ET non nul
   (cf. `renderHero`). Quand il parle, il dit qu'une addition ne se
   referme pas — il porte donc l'encre d'alerte du socle, pas une teinte
   inventée pour l'occasion. */
.ck-ecart{ display:block; margin-top:6px; font-weight:650; color:var(--of-negative-700) }

/* ==================================================================
   §2 — LA CARTE DE SEUIL, PLEINE LARGEUR (#799 lot 2)

   AVANT : `grid-template-columns:1.4fr 1fr` en dur dans le HTML — le
   héros à gauche, les quatre tuiles serrées à droite sur deux rangs de
   deux. Le chiffre premier de l'écran partageait donc son rang avec
   quatre chiffres de second rang, et la grille était écrite dans le
   balisage, hors de portée de toute rupture responsive.

   APRÈS : la carte de seuil prend toute la colonne de lecture, les
   tuiles descendent en dessous sur quatre colonnes. C'est la composition
   de la maquette, et elle a une conséquence de FOND : le montant n'est
   plus en concurrence visuelle avec autre chose.

   ⚠️ CE QUI A CHANGÉ AU LOT 1 DE #847. La carte de seuil était pleine
   largeur DE SA COLONNE ; elle est désormais pleine largeur DE LA PAGE —
   plus rien n'est posé à côté d'elle. C'est la bande 0. Les quatre tuiles
   la suivent dans la colonne de lecture, elles ne partagent plus son rang.
   ================================================================== */

.ck-seuil{ display:grid; gap:var(--of-gap) }

/* Les quatre tuiles, en quatre colonnes comme la maquette.
   ⚠️ Le sélecteur ne peut plus être `.ck-grid .ck-seuil .kpis` : les
   tuiles ont quitté `.ck-seuil` (elles vivent dans la colonne de lecture)
   et `.ck-grid` n'existe plus sur cet écran. Il reste `.ck-grid .kpis`
   dans `optifisc.css:634` — désormais SANS EFFET ici faute d'ancêtre, ce
   qui est le comportement voulu : cette règle compensait une colonne de
   359 px qui n'existe plus. Elle n'est pas retirée depuis cette feuille,
   c'est le périmètre de #828 (classes mortes), pas celui-ci. */
/* #847 lot 2 (C1) — DEUX RANGS TITRÉS, quatre tuiles chacun.
   Le titre de rang n'est pas un ornement : sans lui, huit tuiles alignées se
   lisent comme un inventaire plat, et le lecteur cherche pourquoi le cash
   apparaît deux fois. Il apparaît deux fois parce qu'on le regarde sous deux
   angles — par nature, puis par rôle — et le rang le dit. */
.ck-kpis{ display:grid; gap:var(--of-gap) }
.ck-kpi-rang-t{
  margin:0 0 8px; font-size:13px; line-height:18px; font-weight:650;
  color:var(--of-ink-650);
}
.ck-kpi-rang-n{
  font-weight:400; font-size:12px; color:var(--of-ink-550);
  /* La note explique la DÉCOUPE servie ; elle n'est pas au même rang que le
     titre, sinon les deux se lisent comme un seul intitulé long. */
}
/* #887 §3 — LA TUILE-SQUELETTE EST LA TUILE RÉELLE, SON TEXTE EN MOINS.
   ═══════════════════════════════════════════════════════════════════════
   #847 lot 5 (G3) lui avait donné les classes de la tuile réelle et des
   hauteurs en `em` : il restait 47,7 px d'écart à 1920 px, parce qu'une hauteur
   en `em` réserve UNE ligne là où le texte réel en prend deux — et parce que
   `.of-figure` est le GRID ITEM de `.kpis` (`display:grid` sur le même élément,
   cf. `OF.ui.kpi` : `classes:'kpi'` pose les deux classes sur un seul `<div>`).
   Ses trois lignes s'étirent donc pour remplir la hauteur du rang, imposée par
   la tuile la plus haute. Réserver « une ligne » n'avait aucune chance.

   Le squelette porte désormais le VRAI libellé et le VRAI sous-texte (constantes
   de `cockpit.js`, `KPI_RANGS`), rendus invisibles. Le texte fait la géométrie ;
   on ne la recopie plus, on la laisse se produire. Aucune hauteur en dur ici :
   c'est ce qui garantit que le squelette suive le socle quand celui-ci bouge.

   ⚠️ `color:transparent` ET PAS `visibility:hidden` : `visibility` retire la
   boîte du calcul de ligne dans certains moteurs, et c'est cette boîte qu'on
   veut. Les rangs portent `aria-hidden` (cf. `kpisSquelette`), le texte n'est
   donc ni lu ni annoncé.
   ⚠️ `.ck-kpi-rang-n` repose une couleur : sans le sélecteur descendant, la
   note du titre resterait lisible sous son propre shimmer. */
/* ⚠️ `min-height:80px` — c'est la valeur que le socle donne à `.skeleton`
   (optifisc.css), calibrée pour une CARTE entière. Sur une ligne de texte, elle
   fait un pavé de 80 px là où le rendu tiendra en 14. On la neutralise ici. */
.ck-kpi-skel > *,
.ck-kpi-rang-t.skeleton{ min-height:0; border-radius:var(--of-radius-xs) }
.ck-kpi-skel > *,
.ck-kpi-skel > * *,
.ck-kpi-rang-t.skeleton,
.ck-kpi-rang-t.skeleton *{ color:transparent }
/* LE RYTHME DE LARGEURS DE #847 (62 / 78 / 88 %) EST TENU PAR LE FOND, PAS PAR
   LA BOÎTE. Une bande pleine largeur se lit comme un bloc plutôt que comme une
   ligne en attente — mais rétrécir la BOÎTE ferait retourner à la ligne le texte
   qui porte la géométrie. Mesuré : `width:62%` sur `.eyebrow` remettait 35 px
   d'écart à 1920 px et 68 px à 1440 px, soit plus que le défaut d'origine.
   La boîte reste donc pleine largeur, et c'est le dégradé qui s'arrête.
   ⚠️ Aucune couleur nouvelle : `--of-line-200` est le fond que le socle donne
   déjà à `.skeleton`, servi ici en image pour pouvoir le borner. */
.ck-kpi-skel > *,
.ck-kpi-rang-t.skeleton{ background-color:transparent; background-repeat:no-repeat }
.ck-kpi-skel > *,
.ck-kpi-rang-t.skeleton{ background-image:linear-gradient(var(--of-line-200),var(--of-line-200)) }
.ck-kpi-skel .eyebrow{ background-size:62% 100% }
.ck-kpi-skel .of-figure-v{ background-size:78% 100% }
.ck-kpi-skel .of-figure-sub{ background-size:88% 100% }
.ck-kpi-rang-t.skeleton{ background-size:22rem 100% }

/* ⚠️ `minmax(0,1fr)` ET NON `1fr`. `1fr` vaut `minmax(auto,1fr)` : la piste ne
   peut pas descendre sous le min-content de la tuile (~165 px), et c'est cette
   somme — 4 × 165 + gouttières = 681 px — qui débordait la colonne de lecture
   entre 1180 et 1600 px (voir §1 bis). */
.ck-kpi-rang .kpis{ grid-template-columns:repeat(4,minmax(0,1fr)) }
/* — LE REPLI SUIT LE CONTENEUR, PAS LA FENÊTRE, et il faut le traduire en
   media queries parce que la page n'a pas de requête de conteneur.
   Mesuré : la colonne de lecture vaut 449 px à 1180, 579 à 1440, 635 à 1600,
   685 à 1700 et 763 à 1920. Quatre tuiles demandent ~700 px pour que le montant
   tienne sur sa ligne. Elles se replient donc par DEUX dans toute la bande où la
   page est en deux colonnes sans être assez large — c'est exactement le défaut
   que #626 avait relevé sur le rail fiscal : un repli conditionné au viewport
   n'était jamais déclenché sur un grand écran. */
@media (min-width:1180px) and (max-width:1699px){
  .ck-col .ck-kpi-rang .kpis{ grid-template-columns:repeat(2,minmax(0,1fr)) }
  /* Trois sous-zones dans 449 px font 140 px de contenu utile : le titre
     « Composition assurance & pension » y tient sur quatre lignes. Deux
     colonnes jusqu'à 1400, une seule en dessous. */
  .ck-col .ck-souszones{ grid-template-columns:repeat(2,minmax(0,1fr)) }
}
@media (min-width:1180px) and (max-width:1399px){
  .ck-col .ck-souszones{ grid-template-columns:minmax(0,1fr) }
}
/* Sous 1180 la page est en une seule colonne : les tuiles gardent quatre
   colonnes jusqu'à 900, puis se replient par deux. */
@media (max-width:899px){
  .ck-kpi-rang .kpis{ grid-template-columns:repeat(2,minmax(0,1fr)) }
}
@media (max-width:560px){
  .ck-kpi-rang .kpis{ grid-template-columns:minmax(0,1fr) }
}

/* Le montant : mono 44 px, la mesure de la maquette. Sans cette règle il
   suivait `clamp(38px,6vw,54px)` (optifisc.css:611) — calibré pour une
   colonne de 1,4fr, il tapait le plafond de 54 px dès que la carte a pris
   toute la largeur. Un chiffre plus GROS n'est pas un chiffre mieux lu :
   c'est 44 px qui a été dessiné à côté d'une mention d'évolution. */
.ck-seuil .hero .big{ font-size:clamp(32px,4.4vw,44px); line-height:48px }
@media (max-width:560px){
  .ck-seuil .hero .big{ font-size:32px; line-height:38px }
}

/* Le rang du chiffre : montant à gauche, évolution à droite, alignés sur
   leur ligne de base basse. `flex-wrap` plutôt qu'une grille — sous
   561 px l'évolution passe simplement dessous, elle ne se comprime pas. */
.hero-chiffre{
  display:flex; flex-wrap:wrap; gap:12px 28px;
  align-items:flex-end; justify-content:space-between;
}
.hero-chiffre-g{ min-width:0 }

/* ==================================================================
   §2 bis — L'EN-TÊTE DE LA CARTE DE SEUIL ET SA COURBE (#847 lot 2)
   ================================================================== */

.ck-seuil-hd{
  display:flex; flex-wrap:wrap; gap:10px 18px;
  align-items:center; justify-content:space-between;
  margin-bottom:14px;
}
/* Titre serif sur fond pétrole. Le corps (22 px) est celui de la maquette pour
   un titre de carte de rang 1 ; l'encre est le blanc du héros, pas un jeton
   d'encre — aucun jeton n'est calibré pour ce fond (même convention que
   `.h-evo-r` en §3). */
.ck-seuil-hd h2{
  margin:0; font-family:var(--of-font-display);
  font-size:22px; line-height:28px; font-weight:400; color:var(--of-white);
}
/* Le sélecteur de période sur fond sombre.
   ⚠️ `.of-periode-btn` (optifisc.css:1538-1540) est calibré pour un fond CLAIR :
   fond blanc, encre `--of-ink-650`, et l'état pressé en pétrole plein. Posé tel
   quel sur le héros, il donnait six pastilles BLANCHES dont une seule lisible —
   celle qui portait `aria-pressed`, parce qu'elle seule redéfinissait son encre.
   Mesuré sur capture avant livraison, pas déduit.
   On ne redéclare ni la géométrie ni le rayon : seulement les trois propriétés
   qui dépendent du fond, et l'inversion de l'état pressé (sur fond sombre, c'est
   le CLAIR qui marque la sélection). */
.ck-seuil-per{ margin-bottom:0 }
/* ⚠️ 23/08/2026 (#973 · #971) — L'ENCRE EST PASSÉE AU JETON.
   `rgba(255,255,255,.82)` était la recopie littérale de `--of-sur-sombre-courant` :
   une valeur de design redéclarée dans une feuille d'écran, ce que la source unique
   de jetons interdit. Remplacée par le renvoi, à valeur RIGOUREUSEMENT identique.

   ═══ 24/08/2026 (#973 §5, Q4) — ET LA BORDURE SUIT, PAR ARBITRAGE ═══
   Elle restait en dur à `rgba(255,255,255,.28)`, faute d'un rang correspondant :
   le seul jeton de filet sur fond sombre (`--of-sur-sombre-filet`) vaut `.14`, soit
   la MOITIÉ. La SPEC avait réservé la question — « .28 bordure : appelle-moi plutôt
   que d'inventer un cinquième rang » — et Thomas a tranché : RATTACHER au jeton
   existant, ne pas créer de cinquième rang.

   ⚠️ CE N'EST DONC PAS UN CHANGEMENT NEUTRE, et c'est dit. Le filet du sélecteur
   passe de `.28` à `.14` : il s'éclaircit de moitié. C'est un arbitrage VISUEL rendu,
   pas un ménage de jetons à pixel constant — la ligne du dessus, elle, ne bougeait
   pas d'un iota. La contrepartie est acquise : plus aucune valeur de design ne vit
   hors de `optifisc-tokens.css` sur cette carte. */
.ck-seuil-per .of-periode-btn{
  background:transparent; border-color:var(--of-sur-sombre-filet);
  color:var(--of-sur-sombre-courant);
}
.ck-seuil-per .of-periode-btn[aria-pressed="true"]{
  background:var(--of-white); border-color:var(--of-white);
  color:var(--of-petrol-800); font-weight:650;
}
.ck-seuil-per .of-periode-btn:focus-visible{
  outline:2px solid var(--of-white); outline-offset:2px;
}

/* #973 §2 · §6 — LES DEUX CONTRÔLES DE CADRAGE ONT ÉTÉ RETIRÉS, leurs règles
   avec eux (`.ck-seuil-cadrage`, `.ck-seuil-apports`). Sur une courbe de net
   GLOBAL, « Distinguer les apports » soustrairait des apports financiers d'une
   variation qui contient une revalorisation immobilière et un amortissement de
   crédit : le contrôle serait faux, pas seulement inutile. Le motif complet est
   dans `serieSeuil()` (`cockpit.js`). */

/* La courbe : hauteur réservée pour qu'un changement de période ne fasse pas
   sauter la carte. C'est la même exigence que le squelette du lot 5 — une
   mesure qui arrive ne doit pas déplacer ce qui est déjà lu. */
.h-courbe{ margin-top:16px; min-height:150px }
.h-courbe svg{ display:block; width:100%; height:auto }
/* L'absence de courbe se DIT, elle ne se cache pas (#575) : la carte porte
   maintenant un axe et un sélecteur de période, un vide muet s'y lirait comme
   un contrôle cassé.
   ⚠️ Elle NE réserve PAS les 150 px de la courbe. Une mesure absente n'occupe
   pas la place d'une mesure — c'est la règle déjà appliquée à `.h-spark:empty`
   au §2, et la carte de seuil est l'endroit où une bande vide de 900 px de long
   se voit le plus. La phrase se cale à gauche, sous le montant : centrée dans
   un grand vide, elle se lisait comme une erreur système. */
.h-courbe:has(.h-courbe-nul){ min-height:0 }
.h-courbe-nul{
  margin:0; padding:10px 0 2px;
  font-size:13px; line-height:19px; color:var(--of-sur-sombre-70);
}

/* ==================================================================
   #973 §4 — LE SURVOL DATÉ DE LA COURBE, SUR FOND PÉTROLE

   L'infobulle réemploie `.evo-tip` (`optifisc.css`) : fond encre, texte blanc,
   anti-débordement piloté par `placerInfobulle()`. Elle est déjà lisible sur
   n'importe quel fond — rien à redéclarer, et surtout rien à re-teinter.

   Le CROSSHAIR et le POINT ACTIF, eux, ne peuvent pas être réemployés tels
   quels : `.evo-cross` et `.evo-pt` sont calibrés pour la carte « Évolution »,
   qui est sur fond BLANC (`--of-ink-550`, `--of-petrol-800`, contour blanc). Sur
   le héros pétrole, un trait d'encre sombre sur fond sombre ne se voit pas.
   On redéfinit donc les DEUX SEULES propriétés qui dépendent du fond, avec les
   jetons prévus pour ça (`--of-sur-sombre-*`), et rien d'autre : ni la
   géométrie, ni le pointillé, ni les rayons. Même convention que `.ck-seuil-per`
   au §2 bis — on ne recopie pas un composant, on l'adapte à son fond.
   ⚠️ Aucune couleur en dur : `DataVizPontTeintesTest` balaie ce fichier. */
.h-courbe-chart{ position:relative }
.h-courbe-svg{ display:block; width:100%; height:auto; touch-action:pan-y }
.h-courbe-svg:focus-visible{ outline:2px solid var(--of-white); outline-offset:2px }
.h-courbe-cross{
  stroke:var(--of-sur-sombre-70); stroke-width:1; stroke-dasharray:3 3;
}
.h-courbe-pt{
  fill:var(--of-white); stroke:var(--of-petrol-800); stroke-width:1.5;
}

/* #973 — la note d'écart entre la photo et la série. Même encre que l'état
   d'absence de la courbe (`--of-sur-sombre-70`, calibrée pour le fond pétrole) :
   c'est une réserve sur le chiffre, pas une alerte — elle se lit, elle n'arrête
   pas la lecture. Elle ne réserve aucune hauteur : muette, elle n'existe pas. */
.h-courbe-note{
  margin:8px 0 0; padding:0;
  font-size:12.5px; line-height:18px; color:var(--of-sur-sombre-70);
}
.h-courbe-note[hidden]{ display:none }
.h-courbe-note .h-courbe-note-v{ font-variant-numeric:tabular-nums; font-weight:650 }

/* La sparkline (#359) réserve 56 px de haut EN PERMANENCE (optifisc.css:1594),
   qu'elle ait ou non une série à tracer — et elle n'en a pas dès que la vue
   d'ensemble rend moins de deux points mesurés, ou des points sans
   `net_financier` (cockpit.js, `renderHeroSparkline`). Tant que la carte était
   étroite, la bande vide passait pour de la respiration ; pleine largeur, c'est
   un pied de carte creux de 900 px de long.
   Elle est DÉCORATIVE : rien n'est perdu à ne pas la réserver. Une mesure
   absente n'occupe pas la place d'une mesure (#575). */
.h-spark:empty{ display:none }

/* ==================================================================
   §3 — LA MENTION D'ÉVOLUTION, EN DEUX LIGNES

   La maquette écrit la valeur PUIS sa raison, l'une sous l'autre. Ce
   n'est pas une préférence de mise en page : c'est ce qui rend lisible le
   cas dégradé — « évolution non renseignée » sur la première ligne, la
   cause sur la seconde. Une cause qu'on met entre parenthèses à la suite
   d'un chiffre ne se lit pas ; une cause seule sur sa ligne, si.

   Le cas dégradé est le SEUL que la maquette montre, et c'est délibéré
   (#575) : un zéro à la place d'une mesure absente serait un mensonge, et
   il aurait exactement la même allure qu'une mesure.
   ================================================================== */

.h-evo{
  display:flex; flex-direction:column; gap:2px;
  max-width:34ch; text-align:left;
}
/* La valeur reprend la fonte de données du héros ; la teinte de signe
   (`.delta.pos` / `.delta.neg`) reste celle de `optifisc.css` — on ne
   redéclare pas une couleur sémantique dans une feuille d'écran. */
.h-evo .h-evo-v{ font-size:16px }
.h-evo .h-evo-r{
  font-size:13px; line-height:19px;
  /* Le commentaire d'ici disait « pas de jeton d'encre sur fond sombre ». Il était
     FAUX : `--of-sur-sombre-70` existe depuis la refonte de la sidebar, et son propre
     commentaire le destine à l'« eyebrow/mention sur héros sombre » — soit exactement
     ce rang-ci. Quatre sites recopiaient sa valeur à la main. */
  color:var(--of-sur-sombre-70);
}
/* ⚠️ `.h-evo-w` A ÉTÉ RETIRÉE LE 23/08/2026 (#973 · #971), ET SON ABSENCE SE
   RACONTE. Elle habillait « la mention qui SÉPARE les deux fenêtres de la carte » :
   le delta portait une fenêtre fixée par le back, la courbe une fenêtre choisie par
   le lecteur, et cette réserve nommait la disjonction faute de pouvoir la supprimer.
   `e74f339` l'a supprimée — le delta lit `overview.variation`, sur la période
   demandée. Plus aucun site du front n'émet la classe (vérifié sur tout le dépôt) :
   la règle survivait à sa raison d'être, et elle recopiait au passage un cinquième
   blanc en dur qu'aucun jeton ne couvre. Une règle morte n'est pas neutre — elle
   invite à réemployer une notion qui n'existe plus. */
/* ⚠️ `.hero .h-evo .of-nul` A ÉTÉ RETIRÉE LE 23/08/2026 (#973 unité A), ET SON
   ABSENCE SE RACONTE — même motif que `.h-evo-w` juste au-dessus. Elle habillait
   la mention d'absence du delta, seul `.of-nul` que `#h-delta` ait jamais émis.
   La variation absente passe désormais par `OF.ui.etats.nonChiffrable()` →
   `.of-nc`, dont le rang sur héros sombre est déjà posé (`optifisc.css`,
   `.hero .of-nc`, 6,84:1 mesuré, `7c39741`) : plus aucun chemin du front ne
   produit un `.of-nul` dans `.h-evo` (vérifié sur tout le dépôt).
   Ce qu'elle apportait de propre au socle se réduisait à `font-size:15px` — la
   teinte, elle, était DÉJÀ celle de `.hero .of-nul` (`optifisc.css`), donc
   redite. Une règle morte n'est pas neutre : elle invite à réemployer « non
   renseigné » là où la SPEC demande « non chiffrable », c'est-à-dire à rouvrir
   exactement l'unité qu'on vient de fermer. */

/* ==================================================================
   §4 — IMPRESSION

   `SPEC_EXPORT.md` §142 est explicite : il n'existe AUCUN export serveur
   pour la vue cockpit, et l'assistant « Exporter » de la maquette produit
   cette vue par la feuille d'impression EXISTANTE. On la reprend, on ne
   la réinvente pas.

   Ce qui disparaît du papier : la ligne de contexte (un lien ne se clique
   pas sur une feuille) et les actions. Le filet part avec elle — sur
   papier c'est l'en-tête de document (#609) qui sépare.
   ================================================================== */

/* ==================================================================
   §4 bis — « MEILLEURE ACTION DU MOIS » (#847 lot 3, D1)

   Panneau SABLE. C'est la deuxième zone laiton de l'écran, et elle est
   ARBITRÉE : la liste fermée du §7.8 de la fiche de parité nommait « rail
   fiscal, aperçu fiscal, cascade » ; Thomas l'a ouverte d'une entrée le
   04/08 (#847). L'écart est donc assumé et daté, pas silencieux.

   ⚠️ SANS MOTIF DE GRAIN. La maquette pose `ofGrain`, un MOTIF SVG (élément
   `pattern`) à 3,5-5 % d'opacité. La garde de #767 compte les motifs au même
   titre que les dégradés hors `of-chart.js` : le poser ici ferait rougir
   `of-chart-verif.mjs`. Il entrera avec l'arbitrage de #795 — qui doit
   donc couvrir une TROISIÈME famille, la texture, en plus de la dataviz
   et de la marque. Une atténuation de 3,5 % n'est pas une information :
   son absence ne coûte rien, sa contrebande coûterait une garde.
   ================================================================== */

.ck-bna{
  padding:var(--of-pad);
  background:var(--of-fiscal-wash);
  border-radius:var(--of-radius-lg);
  box-shadow:inset 0 0 0 1px var(--of-fiscal-line);
}
.ck-bna-hd{ margin-bottom:12px }
.ck-bna .card-title{ color:var(--of-fiscal-750) }
/* Le libellé, puis le montant : deux rangs, jamais côte à côte. Un montant
   accolé à son libellé sur une seule ligne se lit comme une ligne de tableau ;
   ici c'est le chiffre qui porte, et le libellé le qualifie. */
.ck-bna-k{
  margin:0; font-size:12px; line-height:17px; font-weight:650;
  letter-spacing:.04em; text-transform:uppercase; color:var(--of-fiscal-650);
}
.ck-bna-v{
  margin:2px 0 14px; font-family:var(--of-font-data);
  font-variant-numeric:tabular-nums; font-size:26px; line-height:32px;
  font-weight:600; color:var(--of-ink-950);
}
.ck-bna-v2{
  margin:2px 0 14px; font-family:var(--of-font-data);
  font-variant-numeric:tabular-nums; font-size:18px; line-height:24px;
  font-weight:600; color:var(--of-ink-950);
}
.ck-bna-n{
  font-family:var(--of-font-ui); font-size:12px; font-weight:400;
  color:var(--of-ink-550);
}
/* La règle de répartition. Elle est écrite parce que « pourquoi pas au prorata
   des cibles ? » est une question que le lecteur se pose, et que ce panneau est
   le seul endroit du produit qui puisse y répondre. */
.ck-bna-r{
  margin:0; padding-top:12px; border-top:1px solid var(--of-fiscal-line);
  font-size:12px; line-height:18px; color:var(--of-ink-650); max-width:none;
}
/* Le bandeau de sous-provisionnement : un avertissement de CONSÉQUENCE, pas une
   note. Il ne s'affiche que si le serveur le dit. */
.ck-bna-alerte{
  margin:12px 0 0; padding:10px 12px;
  border-radius:var(--of-radius-bloc);
  background:var(--of-fiscal-100); color:var(--of-fiscal-750);
  font-size:12px; line-height:18px; max-width:none;
}
.ck-bna-cta{ margin:14px 0 0; display:flex; flex-wrap:wrap; gap:8px }

/* ==================================================================
   §4 ter — LE COMPTEUR DE CARTE (#847 lot 4)

   La maquette pose une pastille chiffrée à droite de quatre titres de
   carte : combien de cours à rafraîchir, combien de pièces, combien
   d'obligations ouvertes. Ce n'est pas un ornement — c'est ce qui permet
   de décider s'il faut lire la carte sans la lire.

   ⚠️ RAYON : `--of-radius-pilule`, pas le 999 littéral de la maquette
   (même valeur, mais le jeton existe et la source canonique est unique).
   ================================================================== */

.ck-compteur{
  flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  min-width:24px; height:22px; padding:0 8px;
  border-radius:var(--of-radius-pilule);
  background:var(--of-surface-100); color:var(--of-ink-650);
  font-family:var(--of-font-data); font-variant-numeric:tabular-nums;
  font-size:12px; font-weight:600;
}
.ck-compteur:empty{ display:none }

/* ==================================================================
   §4 quater — LE DUO « COURS À RAFRAÎCHIR » / « DOCUMENTS & PREUVES »
   (#847 lot 4, E2 et E3)

   Deux colonnes égales dès que la place existe, une seule en dessous.
   La rupture est celle du socle (1180) : sous elle la page est déjà en
   une colonne, y garder deux cartes côte à côte casserait la mesure de
   lecture des libellés d'instrument.
   ================================================================== */

.ck-duo{ display:grid; gap:var(--of-gap) }
@media (min-width:1180px){
  .ck-duo{ grid-template-columns:repeat(2,minmax(0,1fr)); align-items:start }
}
/* Dans une colonne de bande, la place est déjà divisée par deux : le duo
   repasse en pile pour ne pas produire deux colonnes de 340 px. */
@media (min-width:1180px) and (max-width:1599px){
  .ck-col .ck-duo{ grid-template-columns:1fr }
}

/* — E2 : la liste des cours périmés — */
.ck-cours-l{ list-style:none; margin:0; padding:0; display:grid; gap:10px }
.ck-cours{
  padding:12px 13px;
  border-radius:var(--of-radius-bloc);
  background:var(--of-surface-100);
}
.ck-cours-n{ margin:0; font-size:13px; line-height:19px; font-weight:650; color:var(--of-ink-950) }
.ck-cours-m{
  margin:2px 0 0; font-size:11px; line-height:16px; color:var(--of-ink-550);
}
.ck-cours-a{ margin:10px 0 0 }
.ck-cours-nok{ font-size:11px; line-height:16px; color:var(--of-ink-550) }
.ck-cours-plus{ margin:10px 0 0; font-size:12px; font-weight:650 }
/* La note de méthode : c'est elle qui empêche de lire « périmé » comme un
   jugement du front. Elle nomme le champ serveur, en mono, parce qu'un nom
   de champ est une référence, pas une phrase. */
.ck-cours-note{
  margin:12px 0 0; font-size:11px; line-height:16px; color:var(--of-ink-550);
  max-width:none;
}

/* — E3 : les trois dernières pièces — */
.ck-docs-l{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px }
.ck-doc{
  display:flex; flex-direction:column; gap:1px; min-width:0;
  padding:9px 10px; border-radius:var(--of-radius-sm);
  text-decoration:none;
}
.ck-doc-t{
  font-size:13px; line-height:18px; font-weight:600; color:var(--of-ink-950);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* L'état d'indexation est ÉCRIT et NON COLORISÉ (cf. le balisage) : trois
   états d'un cycle de vie ne sont ni bons ni mauvais, et une pastille de
   couleur y ferait lire un problème. */
.ck-doc-m{ font-size:11px; line-height:16px; color:var(--of-ink-550) }
.ck-docs-f{
  margin:12px 0 0; padding-top:12px; border-top:1px solid var(--of-line-200);
  font-size:12px; font-weight:650;
}

/* ==================================================================
   §4 quinquies — « OBLIGATIONS DÉCLARATIVES » (#847 lot 3, D2)

   Une ligne par obligation millésimée, son état écrit, et l'action à
   droite quand il y en a une.

   ⚠️ LE TON N'EST PAS LA SEULE INFORMATION. Chaque ligne porte son état
   en toutes lettres — « À déclarer », « Justifiée · preuve liée »,
   « Déclarée sans pièce », « Couverte · attestation PCC ». La teinte
   double le mot, elle ne le remplace jamais.
   ================================================================== */

.ck-obl-l{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px }
.ck-obl{
  display:grid; grid-template-columns:minmax(0,1fr) auto;
  align-items:center; gap:10px;
  padding:11px 12px; border-radius:var(--of-radius-bloc);
  background:var(--of-surface-100);
}
/* Ouverte : laiton — c'est une obligation fiscale non réglée, et le laiton
   est la surface du registre fiscal (liste fermée du §7.8, entrée « rail
   fiscal » : cette carte est le prolongement du rail, pas une surface neuve). */
.ck-obl.warn{ background:var(--of-fiscal-100) }
.ck-obl.warn .ck-obl-n,.ck-obl.warn .ck-obl-s{ color:var(--of-fiscal-750) }
.ck-obl.ok{ background:var(--of-positive-100) }
.ck-obl.ok .ck-obl-n,.ck-obl.ok .ck-obl-s{ color:var(--of-positive-700) }
.ck-obl-t{ min-width:0; display:flex; flex-direction:column; gap:3px }
.ck-obl-n{ font-size:12px; line-height:17px; font-weight:650; color:var(--of-ink-950) }
.ck-obl-s{ font-size:11px; line-height:16px; color:var(--of-ink-550) }
.ck-obl-act{
  flex:0 0 auto; height:30px; padding:0 11px; border:0;
  border-radius:var(--of-radius-sm);
  background:var(--of-white); color:var(--of-fiscal-750);
  font:inherit; font-size:11px; font-weight:650; white-space:nowrap; cursor:pointer;
}
.ck-obl-act:disabled{ opacity:.6; cursor:default }
.ck-obl-act:focus-visible{ outline:2px solid var(--of-teal-650); outline-offset:2px }
/* L'écart n° 1, dit à l'écran. */
.ck-obl-n2{
  margin:12px 0 0; font-size:11px; line-height:16px; color:var(--of-ink-550);
  max-width:none;
}

/* ==================================================================
   §4 sexies — « PREUVE & TRAÇABILITÉ » (#847 lot 4, E5)

   La carte pétrole, et la seule de l'écran. Elle ne compte pas des
   chiffres de patrimoine : elle compte des ÉCRITURES et leur couverture
   documentaire, ce qui est une autre nature — d'où une autre surface.

   ⚠️ AUCUN DÉGRADÉ, AUCUN MOTIF. La maquette pose deux vagues SVG en
   fond ; la garde de #767 compte les dégradés hors `of-chart.js`, et
   #795 n'a pas encore ouvert le tiroir « texture ». Aplat pétrole en
   attendant : l'information est intacte, seule l'ornementation manque.
   ================================================================== */

.ck-preuve{
  padding:var(--of-pad);
  border-radius:var(--of-radius-lg);
  background:var(--of-ocean-950);
}
.ck-preuve .card-title{ color:var(--of-white) }
.ck-preuve-s{
  margin:8px 0 0; font-size:13px; line-height:20px; color:var(--of-sur-marine);
  max-width:none;
}
.ck-preuve-c{
  margin:14px 0 0; font-size:13px; line-height:20px; color:var(--of-sur-marine);
}
.ck-preuve-n{ font-size:20px; line-height:26px; font-weight:600; color:var(--of-white) }
.ck-preuve-x{ display:block; font-size:12px; line-height:17px; color:var(--of-sur-marine-faible) }
.ck-preuve-t{ margin:8px 0 0; font-size:12px; line-height:17px; color:var(--of-sur-marine) }
.ck-preuve-t b{ color:var(--of-white) }
.ck-preuve-a{ margin:14px 0 0 }
/* Le bouton sur fond marine : on ne redéclare que ce qui dépend du fond —
   même convention que `.ck-seuil-per` au §2 bis. */
.ck-preuve-a .btn{
  background:var(--of-aqua-500); border-color:var(--of-aqua-500); color:var(--of-ocean-950);
}
.ck-preuve-a .btn:focus-visible{ outline:2px solid var(--of-white); outline-offset:2px }

/* ==================================================================
   §4 septies — « DIVERGENCES OUVERTES » (#847 lot 4, E4)

   Une notion, sa cause en une ligne, et la NATURE de l'écart à droite.
   Le chip qualifie la nature, jamais la gravité : « attendu » ne veut pas
   dire bénin, il veut dire qu'on sait pourquoi.
   ================================================================== */

.ck-diverg{ margin-top:16px; padding-top:14px; border-top:1px solid var(--of-line-200) }
.ck-diverg-t{
  margin:0 0 8px; font:var(--of-eyebrow-s); letter-spacing:.10em;
  text-transform:uppercase; color:var(--of-ink-550);
}
.ck-diverg-l{ list-style:none; margin:0; padding:0 }
.ck-diverg-i{
  display:grid; grid-template-columns:minmax(0,1fr) auto;
  align-items:baseline; gap:14px;
  padding:10px 4px; border-radius:var(--of-radius-sm); text-decoration:none;
  box-shadow:inset 0 -1px 0 0 var(--of-line-300);
}
.ck-diverg-l li:last-child .ck-diverg-i{ box-shadow:none }
.ck-diverg-k{ min-width:0; display:flex; flex-direction:column; gap:2px }
.ck-diverg-k b{ font-size:12px; line-height:17px; font-weight:650; color:var(--of-ink-950) }
.ck-diverg-k span{ font-size:11px; line-height:16px; color:var(--of-ink-550) }
.ck-diverg-c{ font-size:12px; font-weight:650; white-space:nowrap; color:var(--of-ink-650) }
.ck-diverg-c.warn{ color:var(--of-fiscal-750) }
.ck-diverg-c.bad{ color:var(--of-negative-700) }

/* ==================================================================
   §4 octies — LE CONTRÔLE D'ADDITION DE L'ALLOCATION (#847 lot 4, F3)

   « Total reçu » et « Somme des lignes » ne se ressemblent pas, et c'est
   le but : le premier est un chiffre de rang 1 (il fait foi), le second
   est une phrase de contrôle. Les mettre au même corps ferait deux
   totaux concurrents — exactement ce que ce bloc existe pour empêcher.
   ================================================================== */

.alloc-controle{
  margin-top:16px; padding-top:14px; border-top:1px solid var(--of-line-200);
}
.alloc-ctrl-k{
  margin:0; font:var(--of-eyebrow-s); letter-spacing:.10em;
  text-transform:uppercase; color:var(--of-ink-550);
}
.alloc-ctrl-v{
  margin:3px 0 0; font-family:var(--of-font-data); font-variant-numeric:tabular-nums;
  font-size:20px; line-height:26px; font-weight:600; color:var(--of-ink-950);
}
.alloc-ctrl-s{ margin:4px 0 0; font-size:12px; line-height:17px; color:var(--of-ink-650) }
.alloc-ctrl-r{
  margin:10px 0 0; font-size:12px; line-height:17px; color:var(--of-ink-550);
  max-width:none;
}
.alloc-ctrl-r b{ color:var(--of-ink-650); font-weight:650 }

/* ==================================================================
   §4 nonies — LE PIED DU RAIL FISCAL (#847 lot 5, G5)
   ================================================================== */

.rail-foot{
  margin:14px 0 0; padding-top:13px;
  border-top:1px solid var(--of-fiscal-line);
  font-size:12px; line-height:17px; color:var(--of-fiscal-750);
  max-width:none;
}
.rail-foot:empty{ display:none }
/* La provenance des badges de rappel (#847 lot 3, D2). Elle vit juste
   au-dessus d'eux et pas en note de pied : une réserve qu'on lit APRÈS
   la donnée qu'elle qualifie arrive trop tard. */
.rail-badges-k{
  margin:16px 0 0; font:var(--of-eyebrow-s); letter-spacing:.10em;
  text-transform:uppercase; color:var(--of-fiscal-750);
  max-width:none;
}
.rail-badges-k:empty{ display:none }
/* La communication de paiement TOB : une donnée à copier. Elle se
   sélectionne d'un geste — sur un virement, retaper une communication
   structurée est le moyen le plus courant de se tromper. */
.rail-comm{ user-select:all; word-break:break-word }

/* ==================================================================
   §4 decies — L'ÉTAT D'ERREUR (#847 lot 5, G2)

   L'endpoint et l'heure en mono, la consigne de non-action, deux recours.
   ================================================================== */

.ck-err-tech{
  display:block; margin-top:6px;
  font-size:11px; line-height:16px; color:var(--of-ink-550);
}
.ck-err-c{ display:block; margin-top:6px; font-size:13px; line-height:19px }
.ck-err-a{ display:flex; flex-wrap:wrap; gap:8px; margin-top:12px }

/* ==================================================================
   §4 undecies — LA GRAMMAIRE DES SURVOLS (#847 lot 4, I3)

   La maquette relève 79 survols et UNE SEULE grammaire :
     · fond clair            → `--of-surface-100` ;
     · élément cliquable de rang 1 → l'anneau passe en teal ;
     · et surtout : AUCUN survol ne DÉPLACE, n'AGRANDIT ni n'OMBRE.

   C'est cette dernière clause qui donne sa sobriété à la page, et c'est
   la seule qu'on ne remarque qu'en son absence : un écran dont chaque
   ligne se soulève au passage de la souris est un écran qui frétille.
   Les règles ci-dessous ne valent que pour les blocs livrés par cette
   issue — étendre la grammaire aux composants du socle appartient à
   `optifisc.css`, hors du périmètre de ce chantier.
   ================================================================== */

.ck-doc:hover,
.ck-diverg-i:hover{ background:var(--of-surface-100); text-decoration:none }
.ck-doc:focus-visible,
.ck-diverg-i:focus-visible{ outline:2px solid var(--of-teal-650); outline-offset:-2px }
.ck-obl-act:hover{ background:var(--of-fiscal-100) }
.ck-preuve-a .btn:hover{ background:var(--of-white) }
/* Aucune de ces règles ne touche `transform`, `box-shadow` ni `scale` :
   c'est volontaire et c'est la clause qui compte. */

/* ==================================================================
   §5 — LE MOUVEMENT (#847 lot 2, I1 et I2)

   La maquette nomme QUATRE animations ; la production n'en avait
   l'équivalent que d'une (`rise`, .5 s, l'entrée des cartes). Les trois
   autres manquaient, et le shimmer existant était une BALAYEUSE
   (`translateX`) là où la maquette pose une PULSATION D'OPACITÉ.

   Ce qui se joue n'est pas décoratif : un squelette qui balaie suggère
   un chargement qui progresse, une pulsation dit « en attente ». Sur un
   écran où l'attente peut durer (18 endpoints), la seconde est honnête
   et la première promet une progression que rien ne mesure.

   `ofSeDepose` et `ofSOuvre` n'entrent PAS encore : elles animent les
   bandeaux d'état et le panneau de jalon, qui arrivent aux lots 4 et 5.
   Poser une animation que rien ne déclenche serait le pendant CSS d'un
   point d'entrée mort — on les posera avec leur porteur.
   ================================================================== */

@keyframes ofShimmer{ 0%{ opacity:.55 } 50%{ opacity:1 } 100%{ opacity:.55 } }

/* La pulsation ÉCHELONNÉE. Cinq délais, ceux de la maquette. En phase,
   une grille de squelettes bat comme un seul bloc et se lit comme un
   écran figé ; décalée, elle se lit comme un chargement. C'est trois
   lignes de CSS, et c'est la différence entre « ça rame » et « ça
   charge ». */
.ck-bandes .skeleton{ animation:ofShimmer 1.4s ease-in-out infinite }
.ck-bandes .skeleton:nth-child(2){ animation-delay:.1s }
.ck-bandes .skeleton:nth-child(3){ animation-delay:.15s }
.ck-bandes .skeleton:nth-child(4){ animation-delay:.2s }
.ck-bandes .skeleton:nth-child(5){ animation-delay:.3s }

/* L'entrée des cartes raccourcit : `rise` (socle) dure .5 s, la maquette
   pose .3 s. Sur un écran de cette densité, une entrée d'une demi-seconde
   se remarque, et ce qui se remarque à chaque visite finit par agacer.
   ⚠️ SEULE LA DURÉE CHANGE, PAS LA COURBE — et c'est un arbitrage, pas
   une omission. La maquette écrit `cubic-bezier(.2,.7,.3,1)`, valeur que
   porte déjà `--of-ease-ouvre`. Mais le dépôt nomme ses deux courbes par
   le GESTE : « ouvre » pour ce qui s'étend, « émerge » pour ce qui monte.
   Une carte qui entre en `translateY` monte — elle ne s'étend pas. La
   coïncidence numérique avec « ouvre » ne fait pas d'elle une ouverture,
   et employer le mauvais verbe rendrait la règle invérifiable sur le nom.
   `.fade` garde donc `--of-ease-emerge` du socle. C'est le même
   raisonnement que `--of-dataviz-gold-500`, distinct de `--of-solar-500`
   malgré une valeur identique (SPEC §4). Écart avec la maquette : assumé
   et signalé, pas silencieux. */
.ck-bandes .fade{ animation-duration:.3s }

@media (prefers-reduced-motion:reduce){
  /* Le socle neutralise déjà `.fade` et `.skeleton::after`. On étend à la
     pulsation, qui est une animation d'OPACITÉ et non de transformation —
     donc invisible aux règles écrites pour le mouvement. */
  .ck-bandes .skeleton{ animation:none }
  .ck-bandes .fade{ animation:none }
}

/* ==================================================================
   §5 ter — EN-TÊTE DE LA SITUATION DÉTAILLÉE (#805)
   ------------------------------------------------------------------
   Ces règles vivaient en attributs `style` dans `cockpit.html`, dont un
   `font-size:1.35rem` : la source canonique unique de jetons est une barre
   de qualité du dépôt, et c'était l'un des derniers sites à l'enfreindre
   dans les `.html`. Aucune valeur nouvelle n'est introduite ici — le titre
   prend `--of-display-l` par `.page-head h1`, qui existe déjà et qui
   décroît seul aux quatre largeurs.
   ================================================================== */

.sit-head{
  margin-top:0;
  display:flex;flex-wrap:wrap;gap:12px;
  justify-content:space-between;align-items:flex-end;
}
.sit-head-titre{min-width:min(100%,20rem);flex:1 1 24rem}
.sit-head-action{display:flex;flex-direction:column;gap:6px;align-items:flex-end}

/* La phrase d'intention : elle dit ce que l'écran NE fait pas (« rien ne s'y
   exécute »). C'est une promesse de non-action, elle se lit avant les chiffres. */
.sit-intention{margin:4px 0 0;color:var(--of-ink-650);max-width:52ch}

/* ==================================================================
   §5 bis — FRISE DES JALONS DU GLIDEPATH (#536)
   ------------------------------------------------------------------
   Trois pas : dernier jalon franchi · palier en vigueur · prochain jalon.
   Elle vit en tête de la carte « Poches », au-dessus du tableau réel/cible :
   la question qu'elle répond (« où j'en suis dans le plan ? ») précède
   celle du tableau (« et de combien je m'en écarte ? »).

   Le pas COURANT est le seul à porter l'encre pleine et un fond : sur une
   frise, ce qui n'est pas maintenant doit se lire comme tel du premier
   coup d'œil, sans avoir à lire les années. Le passé et le futur partagent
   la même encre secondaire — les distinguer par la couleur ferait du passé
   une réussite et du futur une menace, ce qu'aucun des deux n'est.
   ================================================================== */

.glide-frise{
  list-style:none;margin:0 0 14px;padding:0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;
}
.gf-etape{
  display:flex;flex-direction:column;gap:2px;
  padding:8px 10px;border-radius:var(--of-radius-md);
  border:1px solid var(--of-line-300);
}
.gf-an{font:var(--of-caption);font-family:var(--of-font-data);color:var(--of-ink-650)}
.gf-lib{font-size:.9rem;line-height:1.25;color:var(--of-ink-950)}
.gf-note{font:var(--of-caption);color:var(--of-ink-650)}

/* Passé et futur : en retrait, à égalité. */
.gf-passe,.gf-futur{background:transparent}
.gf-passe .gf-lib,.gf-futur .gf-lib{color:var(--of-ink-650)}

/* Le pas courant, et lui seul, est plein. */
.gf-courant{background:var(--of-surface-100);border-color:var(--of-ink-550)}
.gf-courant .gf-an{color:var(--of-ink-950);font-weight:600}
.gf-courant .gf-lib{font-weight:600}

/* Sous 640 px la frise passe en pile : trois colonnes de 100 px coupent les
   libellés de jalon au milieu d'un mot, et un jalon tronqué ne se lit pas. */
@media (max-width:640px){
  .glide-frise{grid-template-columns:1fr}
}

/* ==================================================================
   §6 — IMPRESSION
   ================================================================== */

@media print{
  .ck-contexte{ display:none }
  /* #847 lots 3-5 — CE QUI SORT SUR PAPIER, ET CE QUI N'EN SORT PAS.
     Les commandes disparaissent (on ne saisit pas un cours sur une feuille) ;
     la carte pétrole passe en encre sur blanc — un aplat sombre pleine largeur
     vide une cartouche et rend son texte illisible en niveaux de gris.
     ⚠️ La communication de TOB porte le numéro de registre national : elle
     porte `no-print` à la source (voir `renderRailFiscal`), pas ici — c'est une
     règle de donnée, elle ne doit pas dépendre d'une feuille d'écran. */
  .ck-cours-a,.ck-obl-act,.ck-preuve-a{ display:none }
  .ck-preuve{ background:var(--of-white); box-shadow:var(--of-surface-carte) }
  .ck-preuve .card-title,.ck-preuve-n,.ck-preuve-t b{ color:var(--of-ink-950) }
  .ck-preuve-s,.ck-preuve-c,.ck-preuve-t,.ck-preuve-x{ color:var(--of-ink-650) }
  .ck-duo{ display:block }
  .ck-duo > *{ break-inside:avoid }
  /* Les bandes s'impriment en une colonne : deux colonnes sur A4 coupent
     une carte sur deux en bas de page. */
  .ck-bande{ display:block }
  .ck-col > *{ break-inside:avoid }
  .ck-entete-rang{ display:block }
  /* Le montant reprend un corps de document : 44 px sur une feuille A4
     mangent le quart de la première page. */
  .ck-seuil .hero .big{ font-size:28px; line-height:32px }
  .hero-chiffre{ display:block }
  .h-evo{ max-width:none; margin-top:6px }
}

/* ==================================================================
   §5 quater — ACCUSÉ DE RÉCEPTION D'UNE ÉCRITURE (#847 G4)
   ------------------------------------------------------------------
   La saisie d'un cours écrit RÉELLEMENT en base, puis recharge tout
   l'écran. Son message de statut vivait DANS le formulaire — que le
   rechargement détruit : il ne servait donc que les erreurs, jamais
   les succès. Une écriture sur une donnée patrimoniale sans accusé,
   c'est l'utilisateur qui doit deviner si son geste a porté ; et le
   réflexe, devant un écran qui n'a rien dit, est de recommencer.

   Il est posé en tête de `main`, hors de tout ce que `render()`
   réécrit — c'est ce qui le fait survivre au rechargement.

   Aucune couleur nouvelle : c'est le `.banner.info` du socle. Le ✓
   porte le succès, pas une teinte de plus.
   ================================================================== */

.ck-accuse{ margin: 0 0 14px; }
.ck-accuse[hidden]{ display: none; }

/* Il n'entre pas à l'impression : un accusé de réception est l'écho d'un
   geste qu'on vient de faire, pas un fait du patrimoine. */
@media print{ .ck-accuse{ display: none } }

/* ==================================================================
   §6 — CE QUI N'EXISTAIT QU'AU SURVOL (#887 §7)
   ------------------------------------------------------------------
   `GRAMMAIRE_DE_LECTURE.md` §4.3 : « le survol précise, il n'informe
   pas ». Cinq informations NÉCESSAIRES vivaient dans un attribut
   `title=` : la provenance et l'état des trous d'une source de
   complétude, la cible en euros d'une poche, le motif d'exclusion d'un
   élément hors poches, la définition de la cible du glidepath.

   Un `title` est invisible au clavier, À L'IMPRESSION, et sur tout
   appareil sans survol — soit précisément les trois situations où l'on
   vérifie une addition. La leçon était déjà écrite dans ce fichier,
   pour la cascade du net global (#847) ; elle n'avait pas été appliquée
   à ces cinq-là.

   Aucune couleur, aucune taille nouvelle ici : ces lignes reprennent
   `.of-perimetre`, `.de-src` et `.of-nul` du socle — la grammaire de la
   « ligne de confiance ». Le seul travail de cette feuille est de leur
   faire une PLACE dans des grilles qui n'en avaient pas.
   ================================================================== */

/* Ligne de confiance d'une source de complétude : provenance + trous.
   `.src-row` est une grille de trois colonnes serrées (libellé, jauge,
   pourcentage) ; la ligne prend donc un rang à elle, sur toute la
   largeur, plutôt que d'écraser la jauge. */
.ck-src-conf{
  grid-column:1 / -1;
  display:flex; flex-wrap:wrap; align-items:center; gap:8px;
  margin-top:2px;
}
/* `.src-row` centre ses trois colonnes ; avec un second rang, l'alignement
   vertical se fait en tête de rang, pas au milieu de l'ensemble. */
.src-row{ align-items:start }
.src-row .track{ margin-top:5px }

/* La cible en euros d'une poche : le second terme de la comparaison, au
   même rang que le réel et l'écart. Encre atténuée — c'est un repère,
   pas le chiffre que l'on suit. */
.pocket .pv .pcible{ color:var(--of-ink-550); font-weight:400 }

/* Le motif d'exclusion d'un élément hors poches. Il vit SOUS la ligne de
   légende (qui est une grille pleine), décalé sous le libellé — la
   pastille et le libellé occupent les 24 premiers pixels. */
.alloc-legend .ck-hors-motif{
  display:block; margin:-2px 0 6px 24px;
  font-size:11.5px; line-height:1.45; color:var(--of-ink-550);
}

/* ==================================================================
   §N — #344 · LA SOURCE D'INCERTITUDE DE LA PROJECTION

   Le rejeu historique (`/api/patrimoine/rejeu`) et la distribution
   Monte-Carlo (`/api/patrimoine/monte-carlo`) se lisent SOUS les
   commandes de projection, au-dessus de la courbe qu'ils annotent.

   AUCUNE VALEUR DE DESIGN NOUVELLE ICI. Les trois chiffres de la
   distribution réemploient `.ov-stats` / `.ov-stat` du socle, la
   saisie de la cible réemploie `.ov-proj-lab` / `.ov-proj-sel`, et
   les notes réemploient `.sit-note`. Le seul travail de ce bloc est
   de donner une PLACE — et surtout, de donner la PREMIÈRE place à la
   phrase de périmètre fiscal.

   ⚠️ POURQUOI LA PHRASE FISCALE EST EN TÊTE, ET PAS EN NOTE DE BAS DE
   PAGE. Le moteur ne rejoue AUCUN des six rails fiscaux belges : ni
   TOB, ni plus-values, ni Reynders, ni précompte mobilier, ni taxe
   comptes-titres, ni taxe sur les primes. Le biais va donc toujours
   dans le MÊME sens — il surestime. Une mise en garde placée après le
   chiffre se lit après le chiffre, ou jamais : la composition est ici
   une propriété de justesse, pas de goût.
   ================================================================== */

.ov-incert{ margin-top:12px }

/* Le périmètre fiscal : un encart en retrait, filet laiton — le laiton
   est déjà la couleur du fiscal dans ce dépôt (`--of-fiscal-*`), on ne
   lui en invente pas une seconde. Il ne crie pas : il précède. */
.ov-incert-fiscal{
  margin:0 0 10px;
  padding:9px 12px;
  border-left:3px solid var(--of-fiscal-650);
  background:var(--of-fiscal-wash);
  border-radius:var(--of-radius-sm);
  font-size:12.5px; line-height:1.5; color:var(--of-ink-950);
}

/* #979 — LE MILLÉSIME FISCAL SUPPOSÉ CONSTANT. Même encre fiscale que le
   périmètre au-dessus — c'est la même famille de réserve —, mais un filet
   PLEIN au lieu du wash : elle porte une hypothèse datée, pas une liste
   d'exclusions. Elle vient JUSTE APRÈS le périmètre et AVANT le chiffre.

   ⚠️ ELLE DOIT SURVIVRE À L'IMPRESSION, et c'est un critère de #979, pas
   une préférence : « une réserve qui ne s'imprime pas n'existe pas ».
   Le texte survit de lui-même ; le FILET, lui, disparaîtrait — les
   navigateurs suppriment fonds et bordures colorés par défaut. Sans lui,
   la réserve se fond dans le corps de texte d'un rapport qu'on transmet,
   et cesse d'être lue comme une réserve. D'où `print-color-adjust`, la
   même réponse que `.etat-pill` et les aires de graphe du dépôt. */
.ov-incert-millesime{
  margin:0 0 10px;
  padding:9px 12px;
  border-left:3px solid var(--of-fiscal-650);
  border-radius:var(--of-radius-sm);
  font-size:12.5px; line-height:1.5; color:var(--of-ink-950);
}
.ov-incert-millesime .hint{ display:block; margin-top:4px }

@media print{
  .ov-incert-fiscal,.ov-incert-millesime{
    print-color-adjust:exact; -webkit-print-color-adjust:exact;
    /* Jamais coupée entre deux pages : une réserve dont on ne lit que la
       première moitié est pire qu'une réserve absente. */
    break-inside:avoid; page-break-inside:avoid;
  }
}

/* L'année sur laquelle porte le chiffre. Discrète, mais AVANT lui. */
.ov-incert-terme{
  margin:0 0 8px;
  font-family:var(--of-font-data); font-size:12px; color:var(--of-ink-650);
}
.ov-incert-terme b{ color:var(--of-ink-950); font-weight:600 }

.ov-incert-chiffres{ margin-bottom:8px }

/* La cible saisie : même gabarit compact que la barre de projection. */
.ov-incert-cible{
  display:flex; flex-wrap:wrap; align-items:center; gap:8px;
  margin:10px 0 6px;
}
.ov-incert-cible .ov-proj-sel{ max-width:180px }
.ov-incert-proba{
  margin:0 0 8px;
  font-size:12.5px; line-height:1.5; color:var(--of-ink-950);
}
.ov-incert-proba b{ font-family:var(--of-font-data); font-variant-numeric:tabular-nums }

@media (max-width:640px){
  /* En colonne étroite, le champ prend son rang : coupé, un montant à
     six chiffres devenait illisible pendant la frappe. */
  .ov-incert-cible .ov-proj-sel{ max-width:100%; flex:1 1 100% }
}

/* ══════════════════════════════════════════════════════════════════════
   #976 (#975 question 3) — « PRODUITS DÉTENUS ».

   Une ligne par produit, sa variation sur la fenêtre, sa sparkline. La carte
   vit en bande 0, pleine largeur, sous le héros (le motif du placement est
   dans `cockpit.html`, au-dessus de `#produits-card`).

   ⚠️ AUCUNE VALEUR DE COULEUR N'EST DÉCLARÉE ICI. Tout passe par les jetons
   de `optifisc-tokens.css` — c'est la source canonique unique, et
   `scripts/parite/audit-tokens.mjs` la garde mécaniquement. La géométrie de
   la sparkline (120 × 34) est celle de `CHARTE_DATAVIZ.md` §6 ; elle est
   passée en OPTIONS à `OFChart.aireHtml`, pas écrite en CSS, pour qu'il n'y
   ait qu'un endroit où elle se lise.
   ══════════════════════════════════════════════════════════════════════ */

/* La ligne de couverture : trois faits sur un rang, au rang des mentions.
   Elle est PERMANENTE et s'imprime — un état « partiel » qui ne survit pas au
   papier laisse croire à une carte complète (`CHARTE_DATAVIZ.md` §4.6). */
.prod-couverture{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px 14px;
  margin:0 0 10px;
  font-size:12.5px; line-height:1.5; color:var(--of-ink-650);
}
.prod-couv-n{ color:var(--of-ink-950); font-weight:600 }
.prod-couv-f{ font-family:var(--of-font-data); font-variant-numeric:tabular-nums }
.prod-couv-s{ font-family:var(--of-font-data); font-variant-numeric:tabular-nums }

/* Le tableau reprend `.decl-table` du socle — pas une seconde grammaire de
   table (#592). Ce qui s'ajoute lui est propre : quatre colonnes dont deux
   portent de la prose (les motifs de refus, servis mot pour mot), donc des
   largeurs bornées, sinon une phrase de trois lignes étire tout le tableau. */
.prod-table{ font-size:13px; table-layout:fixed; min-width:640px }
.prod-table th, .prod-table td{ vertical-align:top; overflow-wrap:anywhere }
.prod-table thead th{ white-space:normal }

/* Les QUATRE largeurs, posées une fois. `table-layout:fixed` les rend
   effectives : sans lui, la colonne de nom absorbe tout et les trois colonnes
   de mesure se réduisent à leur contenu le plus court. `min-width` sur la table
   est ce qui déclenche le défilement DANS `.of-table-wrap` en colonne étroite,
   plutôt qu'un écrasement illisible. */
/* ⚠️ Les sélecteurs sont préfixés par `.prod-table` — `.decl-table th,td` du
   socle pose `text-align:left` à specificité 0,2,0 : une classe seule (0,1,0)
   ne le déplacerait pas, quel que soit l'ordre des feuilles. */
.prod-table th.prod-c-nom{ width:34% }
.prod-table th.prod-c-val{ width:18%; text-align:right }
.prod-table th.prod-c-var{ width:24%; text-align:right }
.prod-table th.prod-c-tend{ width:24% }
/* Les deux colonnes de MESURE s'alignent à droite, comme tout chiffre du dépôt :
   c'est ce qui rend une colonne de montants comparable d'un coup d'œil. La
   colonne « Tendance » reste à gauche — elle porte un tracé et de la prose. */
.prod-table td.prod-valeur, .prod-table td.prod-variation{ text-align:right }
.prod-nom-t{ display:block; font-weight:600; color:var(--of-ink-950); line-height:1.35 }
.prod-sous, .prod-isin{ display:block }
.prod-isin{ font-family:var(--of-font-data) }

/* LA NATURE — critère de fermeture : les quatre se lisent DISTINCTEMENT.
   Le MOT porte l'information (« Coté », « Solde », « Manuel », « Passif ») ;
   la pastille ne fait que la rendre repérable en balayage. La distinction ne
   repose donc jamais sur la seule couleur — c'est la règle P8 du socle, et
   c'est aussi ce qui la rend lisible à l'impression en noir et blanc. */
.prod-nature{
  display:inline-block; margin-top:3px;
  padding:1px 7px;
  border:1px solid var(--of-line-300); border-radius:var(--of-radius-pilule);
  font-family:var(--of-font-data); font-size:10.5px; letter-spacing:.03em;
  text-transform:uppercase; color:var(--of-ink-650);
  background:var(--of-surface-100);
}
/* Coté : la seule nature dont la valeur suit un COURS. Teal, la teinte de la
   série mesurée dans tout le produit. */
.prod-nature.is-cote{ color:var(--of-teal-650); border-color:var(--of-teal-650); background:var(--of-teal-100) }
/* Solde : connu par relevé. Neutre, plein — c'est le cas le plus fréquent. */
.prod-nature.is-balance_only{ background:var(--of-surface-200) }
/* Manuel : saisi à la main. Trait interrompu, le vocabulaire du « non mesuré
   ici » déjà employé par la trame des courbes reportées (#767). */
.prod-nature.is-manuel{ border-style:dashed }
/* Passif : la seule nature dont la valeur est NÉGATIVE. */
.prod-nature.is-passif{ color:var(--of-negative-700); border-color:var(--of-negative-550); background:var(--of-negative-100) }

/* Une ligne de passif : le montant est négatif, et ça se voit sans lire le
   signe. La teinte NE PORTE PAS SEULE — le signe « − » est dans le texte du
   montant (`OF.eur`) et le mot « Passif » dans la pastille. */
.prod-ligne.est-passif .prod-valeur .num{ color:var(--of-negative-700) }

.prod-valeur .num{ font-family:var(--of-font-data); font-variant-numeric:tabular-nums; font-weight:600 }
.prod-valeur .of-figure-sub{ display:block; margin-top:2px; white-space:normal }

.prod-variation{ white-space:normal }
.prod-var-e, .prod-var-p{ display:block }
.prod-var-p{ margin-top:2px }
.prod-variation .of-figure-sub{ display:block; margin-top:2px; text-align:right }
.prod-var-nc{ display:block }

/* L'APPEL DE NOTE. La cause est écrite en entier sous le tableau (une fois par
   cause distincte) ; ici, seul son numéro. Il porte la phrase complète en
   `title` pour qui survole, mais l'infobulle n'est JAMAIS le seul porteur —
   c'est précisément ce que `CHARTE_DATAVIZ.md` §4.6 interdit. */
.prod-ref{ text-decoration:none; font-family:var(--of-font-data) }
.prod-ref sup{ font-size:10px; padding-left:2px }

/* LES CAUSES, sous le tableau : le texte SERVI, entier, imprimable. Rang de
   mention — elles expliquent, elles n'alertent pas. */
.prod-causes{ margin-top:12px }
.prod-causes-t{
  margin:0 0 6px; font-family:var(--of-font-ui); font-size:11.5px;
  letter-spacing:.04em; text-transform:uppercase; color:var(--of-ink-550); font-weight:600;
}
.prod-causes-l{ margin:0; padding-left:20px; font-size:12.5px; line-height:1.5; color:var(--of-ink-650) }
.prod-causes-l li{ margin-bottom:5px }
.prod-causes-l li:last-child{ margin-bottom:0 }

.prod-tendance{ }
/* La sparkline : sans axe, elle prend la largeur de sa cellule et sa hauteur
   fixe. `preserveAspectRatio="none"` est passé en option au composant — la
   hauteur est donc la seule contrainte à poser ici. */
.prod-spark{ color:var(--of-teal-650) }
.prod-spark .ofc-aire-svg{ height:34px }
.prod-tendance .ofc-note{ margin-top:4px; font-size:11.5px }

/* LES MARQUEURS DE BOUT DE TRAIT. Disque plein = point MESURÉ, anneau creux =
   point REPORTÉ ou DÉRIVÉ. C'est ce qui fait qu'« un trait qui finit sur un
   report ne dit pas la même chose qu'un trait sur mesure » se voit à l'œil,
   et pas seulement dans la note sous le tracé. */
.prod-pt{ fill:currentColor; stroke:none }
.prod-pt.est-report{ fill:var(--of-white); stroke:currentColor; stroke-width:1.4 }

/* La cellule sans tracé : la mention de refus prend la place du trait, elle ne
   la laisse pas vide. Un vide se lit comme un rendu cassé. */
.prod-sans-trait{ display:inline-block }
.prod-tendance .of-nc-motif{ display:block; margin-top:4px; white-space:normal }

.prod-plus{ margin:10px 0 0 }

/* La note de méthode et la source, SERVIES et rendues mot pour mot. Rang de
   mention, en pied de carte : elle porte l'avertissement « ces valeurs ne
   s'additionnent pas », qui doit survivre à l'impression. */
.prod-methode{ margin-top:12px; font-size:12px; line-height:1.5 }

/* Sous 640 px, la table atteint son `min-width` et défile DANS
   `.of-table-wrap` — la grammaire de débordement du dépôt (#559 L3). Le `body`,
   lui, ne défile jamais horizontalement (mesuré à 412 px). */

@media print{
  /* Le tableau ne défile pas au papier (`.of-table-wrap{overflow:visible}` du
     socle) et les lignes ne se coupent pas en deux pages. */
  .prod-ligne{ break-inside:avoid; page-break-inside:avoid }
}

/* ==================================================================
   §N — « APPORTS & MARCHÉ » (#972, 25/08/2026)

   L'identité à quatre termes, sa mention de périmètre, ses réserves et
   son renvoi vers « Performance réelle ». Rendue par
   `apports-marche.js`, consommée par `situation.js` (carte « Évolution
   du patrimoine financier », panneau « Patrimoine ») et par
   `cockpit.js` (infobulle de « Patrimoine — vue d'ensemble »).

   POURQUOI DANS CETTE FEUILLE ET PAS DANS `situation.css`. Les deux
   consommateurs vivent dans le MÊME document — `cockpit.html` absorbe
   la situation détaillée depuis #380/#392. Écrire ces règles deux fois,
   une par feuille d'écran, serait deux rédactions vivantes d'un même
   composant (#592) ; les écrire dans la feuille SOCLE les servirait aux
   21 écrans qui n'en ont pas l'usage (le sens de la marche fermé par
   #763). Elles décrivent un composant d'UN écran : elles vivent dans la
   feuille de cet écran.

   AUCUNE VALEUR DE DESIGN NOUVELLE : tout passe par les jetons de
   `optifisc-tokens.css`, source canonique unique.
   ================================================================== */

/* La bascule de vue « Valeur » / « Apports & marché » emprunte la famille
   `.evo-modes .evo-classes`, qui est celle des bascules de courbe du dépôt —
   et qui DISPARAÎT à l'impression, comme tout ce qui sert à agir.
   ⚠️ C'est précisément pourquoi `.apm-perimetre` existe et s'imprime : sur le
   papier, plus aucun contrôle ne dit LAQUELLE des deux vues on regarde. La
   phrase de périmètre le dit, en toutes lettres, écran et papier. */
.apm-perimetre{
  margin:0 0 10px; font-size:12.5px; line-height:1.5; color:var(--of-ink-650);
}
.apm-perimetre strong{ color:var(--of-ink-950) }

/* L'identité : quatre lignes libellé → montant, le total détaché par un filet.
   `tabular-nums` sur les montants : quatre nombres qui doivent s'additionner à
   l'œil doivent s'aligner à la colonne près. */
.apm-identite{
  margin:0 0 12px; padding:12px 14px;
  background:var(--of-surface-100); border:1px solid var(--of-line-200);
  border-radius:var(--of-radius-md);
}
.apm-l{
  display:flex; align-items:baseline; justify-content:space-between; gap:16px;
  padding:4px 0;
}
.apm-l dt{ font-size:12.5px; color:var(--of-ink-650) }
.apm-l dd{ margin:0; font-family:var(--of-font-data); font-variant-numeric:tabular-nums; font-size:13.5px }
.apm-total{
  margin-top:4px; padding-top:8px; border-top:1px solid var(--of-line-300);
}
.apm-total dt{ color:var(--of-ink-950); font-weight:600 }
.apm-total dd{ font-weight:600 }

.apm-reserves{ margin:0 0 10px }
.apm-note{ margin:8px 0 0; font-size:12px; line-height:1.5; color:var(--of-ink-550) }

/* La ligne de décomposition dans une infobulle datée : elle nomme son périmètre
   AVANT ses quatre termes, sinon un chiffre « marché » lu sur une carte globale
   passerait pour la performance du patrimoine entier. */
.apm-tip-perimetre{ font-size:10.5px; letter-spacing:.06em; text-transform:uppercase }

@media print{
  /* Le bloc ne se coupe pas en deux pages : quatre termes qui doivent
     s'additionner et dont deux sont sur la feuille suivante n'attestent rien.
     Les réserves suivent leur chiffre, jamais l'inverse. */
  .apm-identite,.apm-reserves{ break-inside:avoid; page-break-inside:avoid }
  .apm-identite{ background:none; border:1px solid var(--of-print-filet-decor) }
}
