/* ═══════════════════════════════════════════════════════════════
   Griot — Design System v2 « Institut »   (S5.1, 2026-07-28)
   ───────────────────────────────────────────────────────────────
   Canon : Diag/GRIOT_DESIGN_SOT_v2.md §2 (tokens/composants) + §5
           (contraintes dures) · Diag/S5_FRAMES_RATIFICATION_2026-07-28.md
           §2 (le canon des 7 frames) · §4/§11 (ce qui ne se code pas).

   Ce fichier NE REMPLACE PAS style.css tant que les pages n'ont pas
   migré (S5.2 → S5.4). Il est autonome : reset + tokens + composants.
   Une page charge l'un OU l'autre, jamais les deux.

   Les frames Stitch sont ILLUSTRATIVES (verbatim opérateur 2026-07-28) —
   ce fichier les suit par la FONCTION, pas au pixel. Les deux écarts
   assumés sont documentés à la section « Or : deux valeurs, pas une ».
   ═══════════════════════════════════════════════════════════════ */

/* ── Reset ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; }
img, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; }

/* ═══════════════════════════════════════════════════════════════
   TOKENS
   ═══════════════════════════════════════════════════════════════ */
:root {
  /* ── Surfaces ─────────────────────────────────────────────── */
  --ice-paper:      #EEF2F5;   /* fond de page (SoT §2) */
  --surface:        #FFFFFF;   /* cartes, tables */
  --surface-sunk:   #F4F7F9;   /* en-tête de table, rails */

  /* ── Encres ───────────────────────────────────────────────────
     ★ DÉRIVATION 2026-07-28 (décision opérateur : « dériver — garder la
     grammaire, décaler les 2 copies »). Mesure déclenchante, prise sur
     cgdev.org en direct : `--ink-display` valait #0B4C5B et `--gold`
     #FFB52C — **les hexadécimaux exacts de cgdev** (80 et 39 occurrences
     sur leur page d'accueil), repris en avril 2026 et jamais rouverts
     (EXECUTION_PLAN_2026-04-10 §« CGD aesthetic palette »). Pire : leur
     couleur réellement dominante est #006970 (2 157 occurrences) — on
     avait donc copié leur teal SECONDAIRE et manqué leur signature.
     La palette n'était ni fidèle ni originale.
     `--ink` #14343F et `--ice-paper` #EEF2F5 ne sont PAS des copies
     (cgdev : #1A272A et #F3F6F7) — ils restent inchangés.             */
  --ink:            #14343F;   /* Deep Teal Ink — texte, titres  13,2:1 /blanc */
  --ink-display:    #0E3F55;   /* Griot Ink Teal — display      11,3:1 /blanc
                                  ex-#0B4C5B (= cgdev). Même famille, plus
                                  profond et plus bleu : la parenté
                                  institutionnelle reste, la copie part. */
  --ink-muted:      #526A74;   /* captions, labels                5,7:1 /blanc · 5,1:1 /ice */

  /* ── Ocre : DEUX valeurs, pas une ─────────────────────────────
     Le split n'est pas un contournement de l'accent — il est
     STRUCTUREL : tout accent chaud assez lumineux pour servir de filet
     échoue le 4,5:1 du texte. Changer de teinte ne le supprime pas,
     seul un accent sombre le ferait — et ce ne serait plus un accent.
       --gold      graphique seulement (filets, barres, donut, le O)
       --gold-ink  TOUT texte ocre                   5,8:1 /blanc ✓ AA
     ex-#FFB52C / #9A6A00. L'ocre est plus chaud et plus profond que
     l'ambre cgdev, et la marge AA du texte passe de 4,73 à 5,78.
     ⚠ Ne PAS dériver vers la terracotta / le cuivre : c'était la
     proposition B, écartée par l'opérateur le 2026-07-25.             */
  --gold:           #E0921A;
  --gold-ink:       #8F5A0E;
  --gold-rail:      #F6E2C4;

  /* ── Interactif ───────────────────────────────────────────────
     Clear Teal #2D99B5 mesuré à 3,31:1 sur blanc : il PASSE le 3:1
     non-textuel (traits, remplissages, focus) et ÉCHOUE le 4,5:1 du
     texte. D'où : liens en --ink-display, Clear Teal pour le trait,
     le survol et les surfaces.                                      */
  --teal-live:      #2D99B5;
  --teal-live-deep: #1E7C96;   /* survol de lien       4,5:1 /blanc ✓ */
  --teal-wash:      #E4F1F6;   /* fond de chip/badge */

  /* ── Traits ───────────────────────────────────────────────── */
  --hairline:       #D9E2E7;   /* Soft Blue-Gray (SoT §2) */
  --hairline-soft:  #E8EDF0;

  /* ── Donut / séries ───────────────────────────────────────── */
  --serie-1:        #0E3F55;
  --serie-2:        #2D99B5;
  --serie-3:        #E0921A;
  --serie-4:        #C8D5DC;

  /* ── Typographie ──────────────────────────────────────────────
     Figtree = candidat nommé SoT §2 (« sans géométrique humaniste »).
     Mono tabular pour TOUTE donnée — sans exception, vérifié sur les
     7 frames.

     ★ LES FACES SONT DÉCLARÉES DANS `fonts.css`, PAS ICI — c'est le point
     de bascule unique, et sa procédure de remplacement y est écrite. Ne
     changer une police qu'à partir de là.

     ⚠ « … Variable » EN PREMIER : ces faces portent l'axe wght complet.
     Une famille livrée en graisse 400 seule fait SYNTHÉTISER 500/600/700
     par le navigateur — faux gras mesuré le 2026-07-28 (`document.fonts`
     ne contenait que des faces 400). Le nom non-variable reste en repli
     pour une page pas encore migrée.                                     */
  --font-ui:   'Figtree Variable', 'Figtree', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-data: 'JetBrains Mono Variable', 'JetBrains Mono', 'SFMono-Regular', Consolas, monospace;

  --text-2xs:  0.6875rem;  /* 11px — stamps, labels de colonne */
  --text-xs:   0.75rem;    /* 12px */
  --text-sm:   0.875rem;   /* 14px */
  --text-base: 1rem;       /* 16px */
  --text-lg:   1.125rem;   /* 18px */
  --text-xl:   1.375rem;   /* 22px */
  --text-2xl:  1.75rem;    /* 28px */
  --text-3xl:  2.25rem;    /* 36px — valeur du metric band */
  --text-4xl:  3.25rem;    /* 52px — hero */

  --tracking-caps:  0.09em;
  --tracking-tight: -0.02em;

  --w-regular:  400;
  --w-medium:   500;
  --w-semibold: 600;
  --w-bold:     700;

  /* ── Espacement (base 4px) ────────────────────────────────── */
  --space-1:  0.25rem;  --space-2:  0.5rem;   --space-3: 0.75rem;
  --space-4:  1rem;     --space-5:  1.25rem;  --space-6: 1.5rem;
  --space-8:  2rem;     --space-10: 2.5rem;   --space-12: 3rem;
  --space-16: 4rem;     --space-20: 5rem;

  /* ── Formes ───────────────────────────────────────────────── */
  --radius-card:  10px;   /* SoT §2 : cartes radius ~10px */
  --radius-pill:  999px;
  --radius-sm:    4px;
  --shadow-card:  0 1px 2px rgba(20, 52, 63, 0.04),
                  0 4px 16px rgba(20, 52, 63, 0.05);

  /* ── Grille ───────────────────────────────────────────────── */
  --measure:      1180px;  /* largeur de planche */
  --measure-prose: 640px;
}

/* ═══════════════════════════════════════════════════════════════
   BASE
   ═══════════════════════════════════════════════════════════════ */
body {
  background-color: var(--ice-paper);
  /* Texture pointillée discrète (SoT §2) — CSS pur, aucun asset. */
  background-image: radial-gradient(circle, rgba(20, 52, 63, 0.055) 1px, transparent 1px);
  background-size: 22px 22px;
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0; font-weight: var(--w-bold); letter-spacing: var(--tracking-tight); }
p { margin: 0; }

a { color: var(--ink-display); text-decoration-color: var(--teal-live); text-underline-offset: 3px; }
a:hover { color: var(--teal-live-deep); }

/* Anneau de focus unique et visible sur fond clair — 3:1 garanti. */
:where(a, button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--teal-live-deep);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.layout      { width: 100%; max-width: var(--measure); margin-inline: auto; padding-inline: var(--space-6); }
.prose       { max-width: var(--measure-prose); }
.stack-page  { display: flex; flex-direction: column; gap: var(--space-12); padding-block: var(--space-12) var(--space-16); }

/* Toute donnée est en mono tabular. Une seule règle, appliquée partout. */
.data,
.metric-value, .metric-count, .metric-stamp,
.evi-table td, .evi-table th,
.badge-sources, .pill-status,
.donut-legend, .bar-row, .plate-note, .site-foot-v2 .foot-stamp {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

.u-caps {
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.u-mute { color: var(--ink-muted); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════
   HEADER  (composant site-header-v2.js)
   ═══════════════════════════════════════════════════════════════ */
.site-header-v2 {
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
  position: sticky; top: 0; z-index: 40;
}
.site-header-v2 .header-inner {
  display: flex; align-items: center; gap: var(--space-6);
  min-height: 72px;
}

/* Le wordmark est le seul endroit du système qui a droit à un traitement
   propre : partout ailleurs la typo suit l'échelle. Il héritait jusqu'ici
   de l'UI en 700 — c'est-à-dire qu'il ne décidait rien. Traitement retenu,
   volontairement sobre et entièrement réversible : graisse 800 (disponible
   depuis le passage aux faces variables) + approche resserrée, pour que les
   cinq lettres se lisent comme UNE marque et non comme un mot.
   ⚠ Ne pas pousser plus loin sans arbitrage : un wordmark dessiné est un
   travail d'identité, pas un réglage CSS. */
.wordmark-v2 {
  font-family: var(--font-ui);
  font-size: 1.75rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--ink-display);
  text-decoration: none;
  flex: none;
}
/* Le O en ocre — décoratif : le mot entier reste lisible sans la couleur,
   et l'aria-label du lien porte « Griot » pour un lecteur d'écran. */
.wordmark-v2 .wm-o { color: var(--gold); }

.primary-nav-v2 { display: flex; align-items: center; gap: var(--space-6); flex: 1 1 auto; }
.primary-nav-v2 a {
  color: var(--ink); font-size: var(--text-sm); font-weight: var(--w-medium);
  text-decoration: none; padding-block: var(--space-2);
  border-bottom: 2px solid transparent;
}
.primary-nav-v2 a:hover { color: var(--ink-display); border-bottom-color: var(--hairline); }
.primary-nav-v2 a.is-active { color: var(--ink-display); font-weight: var(--w-semibold); border-bottom-color: var(--gold); }

.search-pill {
  display: flex; align-items: center; gap: var(--space-2);
  background: var(--surface-sunk); border: 1px solid var(--hairline);
  border-radius: var(--radius-pill); padding: var(--space-2) var(--space-4);
  min-width: 240px;
}
.search-pill svg { flex: none; color: var(--ink-muted); }
.search-pill input {
  border: 0; background: transparent; outline: none; width: 100%;
  font-size: var(--text-sm); color: var(--ink);
}
.search-pill input::placeholder { color: var(--ink-muted); }
.search-pill:focus-within { border-color: var(--teal-live); }

/* ── COUTURE RÉSERVÉE — emplacement header droit ────────────────
   Décision opérateur 2026-07-28 (S5_FRAMES_RATIFICATION §11) :
   réserver la place d'un futur « Sign In », VIDE en S5.1. Rien n'est
   construit ici. La largeur minimale évite d'avoir à refaire la mise
   en page le jour venu. NE RIEN Y METTRE sans cadrage explicite.   */
.header-slot-reserved { flex: none; min-width: 96px; min-height: 36px; }

/* ═══════════════════════════════════════════════════════════════
   KICKER — filet or court + titre. En tête de chaque carte/section.
   ═══════════════════════════════════════════════════════════════ */
.kicker { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-5); }
.kicker::before {
  content: ''; flex: none; width: 40px; height: 3px;
  background: var(--gold); border-radius: 2px;
}
.kicker > * { margin: 0; }
.kicker h2, .kicker h3 { font-size: var(--text-xl); color: var(--ink-display); }

/* Variante « sur-titre » : filet au-dessus, label capitales, puis titre. */
.kicker-stack { margin-bottom: var(--space-6); }
.kicker-stack::before {
  content: ''; display: block; width: 40px; height: 3px;
  background: var(--gold); border-radius: 2px; margin-bottom: var(--space-4);
}

/* ═══════════════════════════════════════════════════════════════
   CARTE
   ═══════════════════════════════════════════════════════════════ */
.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-8);
}
.card-flush { padding: 0; overflow: hidden; }
.card-flush > .kicker,
.card-flush > .card-head { padding: var(--space-8) var(--space-8) 0; }

/* ═══════════════════════════════════════════════════════════════
   METRIC BAND — le composant le plus stable des 7 frames.
   Valeur $ or mono · « Volume · Confirmed + Executed » · compteurs
   neutres · filet · « COMPUTED SERVER-SIDE · AS OF … UTC ».
   ═══════════════════════════════════════════════════════════════ */
.metric-band { background: var(--surface); border: 1px solid var(--hairline);
               border-radius: var(--radius-card); box-shadow: var(--shadow-card); }

.metric-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  padding: var(--space-8) var(--space-8) var(--space-6);
}
.metric-cell { padding-inline: var(--space-6); border-left: 1px solid var(--hairline); }
.metric-cell:first-child { padding-left: 0; border-left: 0; }

.metric-value {
  display: block;
  font-size: var(--text-3xl); font-weight: var(--w-semibold);
  color: var(--gold-ink); line-height: 1.1;
}
.metric-count {
  display: block;
  font-size: var(--text-2xl); font-weight: var(--w-medium);
  color: var(--ink); line-height: 1.15;
}
.metric-label {
  display: block; margin-top: var(--space-2);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); font-weight: var(--w-semibold); color: var(--ink);
}
.metric-sub { display: block; font-size: var(--text-xs); color: var(--ink-muted); }

.metric-foot {
  border-top: 1px solid var(--hairline);
  padding: var(--space-4) var(--space-8);
  display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
}
.metric-stamp {
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
}

/* ═══════════════════════════════════════════════════════════════
   EVIDENCE TABLE
   Date · Deal · Country · Sector · Amount · Status · Sources · →
   ═══════════════════════════════════════════════════════════════ */
/* `position: relative` n'est pas décoratif ici : la table peut être plus large
   que le conteneur (c'est le principe du défilement horizontal), et un enfant
   en `position: absolute` — notre <caption> visuellement masqué — se
   positionnerait alors par rapport au bloc conteneur initial, tout au bord
   droit de la table. Mesuré en tablette le 2026-07-28 : le document passait à
   857px pour une fenêtre de 753px, soit un défilement horizontal de PAGE alors
   que seule la table devait défiler. Ancrer le conteneur contient l'absolu. */
.evi-wrap { width: 100%; overflow-x: auto; position: relative; }
.evi-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }

.evi-table thead th {
  background: var(--surface-sunk);
  text-align: left; white-space: nowrap;
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); font-weight: var(--w-semibold); color: var(--ink-muted);
  padding: var(--space-3) var(--space-4);
  border-block: 1px solid var(--hairline);
}
.evi-table tbody td {
  padding: var(--space-4);
  border-bottom: 1px solid var(--hairline-soft);
  vertical-align: middle;
  color: var(--ink);
}
.evi-table tbody tr:last-child td { border-bottom: 0; }
.evi-table tbody tr:hover { background: var(--surface-sunk); }

/* ⚠ Le sélecteur PORTE le `td` — même défaut de spécificité que `.evi-deal`
   ci-dessous, resté celui-là non corrigé en S5.2 et rattrapé ici (S5.3,
   mesuré à l'écran) : `.evi-date` seul pèse (0,1,0) et perdait contre le
   `.evi-table tbody td` (0,1,1) qui pose `color: var(--ink)`. La date
   s'affichait donc à 13,19:1 au lieu des 5,72:1 attendus — pas un défaut
   de contraste, mais une hiérarchie visuelle perdue : la date pesait
   autant que le nom du deal. Le correctif profite aussi à la home, qui
   utilise la même table. */
.evi-table td.evi-date,
.evi-date   { white-space: nowrap; color: var(--ink-muted); }
/* ⚠ Le sélecteur PORTE le `td` — corrigé en S5.2, 2026-07-28.
   `.evi-deal` seul pèse (0,1,0) et perdait contre le `.evi-table td` (0,1,1)
   de la règle « toute donnée en mono » : le nom du deal restait en
   JetBrains Mono malgré cette déclaration. Le défaut était invisible sur la
   page témoin, dont les noms tiennent en un mot ; il saute aux yeux sur la
   home, où « Acumen Resilient Agriculture Fund (ARAF) » se brisait en quatre
   lignes de chasse fixe. Le nom d'un deal est du TEXTE, pas de la donnée
   tabulaire — c'était bien l'intention, seule la spécificité manquait. */
.evi-table td.evi-deal,
.evi-table td.evi-deal a { font-family: var(--font-ui); font-weight: var(--w-medium); }
/* Pas de largeur imposée sur `Deal` — vérifié plutôt que supposé. Un
   `width: 30%` a été essayé puis RETIRÉ : mesuré à 1280px de fenêtre, la
   colonne fait 339px AVEC comme SANS la règle — la disposition auto lui
   donne déjà toute la marge disponible, la contrainte ne servait à rien.
   Le resserrement qui avait motivé l'essai (lignes de 119px) venait d'un
   panneau de prévisualisation à 929px, pas de la page : à largeur réelle
   les lignes plafonnent à 76px. Ne pas réintroduire sans mesure. */
.evi-deal a { color: var(--ink-display); text-decoration: none; }
.evi-deal a:hover { text-decoration: underline; }
.evi-amount { text-align: right; white-space: nowrap; font-weight: var(--w-medium); }
.evi-open   { text-align: right; width: 44px; }

.evi-open a,
.evi-open button {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--radius-sm);
  color: var(--ink-muted); text-decoration: none;
  background: none; border: 0; cursor: pointer; font: inherit;
}
.evi-open a:hover,
.evi-open button:not([disabled]):hover { color: var(--ink-display); background: var(--teal-wash); }
/* Affordance présente, tiroir pas encore câblé (D8 → S5.3). Désactivée
   plutôt que morte : hors tabulation, et le curseur ne promet rien. */
.evi-open button[disabled] { opacity: 0.45; cursor: default; }

/* Footnote d'évidence — sous CHAQUE table (SoT §2). */
.evi-footnote {
  padding: var(--space-4) var(--space-4) 0;
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
  font-family: var(--font-data);
}

/* ═══════════════════════════════════════════════════════════════
   PILLS STATUT — C+E SEULEMENT.
   EXECUTED plein · CONFIRMED contour (D5 ratifié 2026-07-28).
   Aucune autre valeur ne doit exister sur une surface monétaire :
   c'est un INVARIANT PERMANENT (§11 statut A), pas un différé.
   ═══════════════════════════════════════════════════════════════ */
.pill-status {
  display: inline-block; white-space: nowrap;
  padding: 3px var(--space-3); border-radius: var(--radius-sm);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); font-weight: var(--w-semibold);
  border: 1px solid transparent;
}
.pill-status.is-executed  { background: var(--ink-display); color: #fff; }
.pill-status.is-confirmed { background: transparent; color: var(--ink-display); border-color: var(--ink-display); }

/* ═══════════════════════════════════════════════════════════════
   BADGE CORROBORATION — « N SOURCES » = COUNT(DISTINCT domain).
   JAMAIS le compte brut d'URLs (invariant permanent §11 statut A).
   D6 ratifié : pill en liste/profil · cercle chiffré en table dense.
   ═══════════════════════════════════════════════════════════════ */
.badge-sources {
  display: inline-flex; align-items: center; gap: var(--space-2);
  background: var(--teal-wash); color: var(--ink-display);
  padding: 3px var(--space-3); border-radius: var(--radius-sm);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); font-weight: var(--w-semibold);
  white-space: nowrap;
}
.badge-sources::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--teal-live); flex: none;
}

.badge-sources-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--teal-wash); color: var(--ink-display);
  font-size: var(--text-xs); font-weight: var(--w-semibold);
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════════
   DONUT + légende 2 colonnes
   ═══════════════════════════════════════════════════════════════ */
.donut-wrap { display: flex; flex-direction: column; align-items: center; gap: var(--space-6); }
.donut { position: relative; width: 200px; height: 200px; flex: none; }
.donut svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.donut-center {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; pointer-events: none;
}
.donut-center .u-caps { margin-bottom: 2px; }
.donut-total {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-lg); font-weight: var(--w-semibold); color: var(--ink);
}

.donut-legend {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-6); width: 100%;
  font-size: var(--text-xs);
}
.donut-legend li { display: flex; align-items: center; gap: var(--space-2); list-style: none; }
.donut-legend { margin: 0; padding: 0; }
.donut-swatch { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.donut-legend .lg-label { color: var(--ink); font-family: var(--font-ui); }
.donut-legend .lg-pct   { margin-left: auto; color: var(--ink-muted); }

/* ═══════════════════════════════════════════════════════════════
   BARRES sur rails pâles — % à droite.
   Utilisé par « Sector Composition » et, D7 ratifié, par le
   « Geographic Distribution » du profil secteur : POURCENTAGES SEULS,
   jamais le montant exact.
   ═══════════════════════════════════════════════════════════════ */
.bar-list { display: flex; flex-direction: column; gap: var(--space-4); margin: 0; padding: 0; list-style: none; }
.bar-row .bar-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-4); margin-bottom: var(--space-2);
}
.bar-row .bar-label { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--ink); }
.bar-row .bar-pct   { font-size: var(--text-xs); font-weight: var(--w-semibold); color: var(--gold-ink); }
.bar-rail {
  /* ⚠ `display: block` est PORTEUR depuis le 2026-07-30 : le rail et son
     remplissage sont des `<span>` et non des `<div>`, parce qu'un `<div>` est
     invalide dans un `<button>` (contenu phrasé) et que les barres cliquables
     sont enveloppées dans un bouton. Un span reste `inline` par défaut, où
     `height` ne s'applique pas — sans cette ligne la barre disparaît. */
  display: block;
  height: 8px; border-radius: var(--radius-pill);
  background: var(--hairline-soft); overflow: hidden;
}
/* L'or plein ne fait que 1,77:1 sur son rail : insuffisant pour une marque
   graphique porteuse de sens (WCAG 1.4.11, seuil 3:1). Le bord en --gold-ink
   donne à la marque une frontière mesurée à 4,01:1 contre le rail — la barre
   reste perceptible sans dépendre du remplissage. */
.bar-fill {
  display: block;                 /* même raison que `.bar-rail` ci-dessus */
  height: 100%; border-radius: var(--radius-pill);
  background: var(--gold);
  box-shadow: inset 0 0 0 1px var(--gold-ink);
}
/* Ligne hors-classement (« Continental ») : remplissage neutre ET bord neutre.
   Un remplissage gris cerclé d'or se relit comme une barre or à petite taille —
   la marque doit être neutre de bout en bout pour se distinguer du classement. */
.bar-fill.is-aside {
  background: var(--serie-4);
  box-shadow: inset 0 0 0 1px var(--ink-muted);
}

/* ═══════════════════════════════════════════════════════════════
   NOTE DE PLANCHE
   ═══════════════════════════════════════════════════════════════ */
.plate-note {
  display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
  border-top: 1px solid var(--hairline);
  margin-top: var(--space-6); padding-top: var(--space-4);
  font-size: var(--text-2xs); color: var(--ink-muted);
}
.plate-note .pn-asof { text-transform: uppercase; letter-spacing: var(--tracking-caps); }

/* ═══════════════════════════════════════════════════════════════
   BOUTONS · CHIPS · TUILES
   ═══════════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-6); border-radius: var(--radius-pill);
  font-size: var(--text-sm); font-weight: var(--w-semibold);
  text-decoration: none; border: 1px solid transparent; cursor: pointer;
}
.btn-primary { background: var(--teal-live-deep); color: #fff; }
.btn-primary:hover { background: var(--ink-display); color: #fff; }
.btn-quiet { background: var(--surface); color: var(--ink-display); border-color: var(--hairline); }
.btn-quiet:hover { border-color: var(--teal-live); background: var(--teal-wash); }

.chip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--hairline);
  font-size: var(--text-xs); color: var(--ink);
}
.chip.is-on { background: var(--teal-wash); border-color: var(--teal-live); color: var(--ink-display); font-weight: var(--w-semibold); }

.tile-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-6); }
.tile {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  padding: var(--space-6);
}
.tile:hover { border-color: var(--teal-live); }
.tile h3 { font-size: var(--text-lg); color: var(--ink-display); margin-bottom: var(--space-2); }
.tile p  { font-size: var(--text-sm); color: var(--ink-muted); }
.tile-icon {
  width: 40px; height: 40px; border-radius: var(--radius-sm);
  background: var(--teal-wash); color: var(--ink-display);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--space-4);
}

/* ═══════════════════════════════════════════════════════════════
   HERO
   ═══════════════════════════════════════════════════════════════ */
.hero h1 { font-size: var(--text-4xl); line-height: 1.08; color: var(--ink-display); max-width: 16ch; }
.hero .hero-lede { margin-top: var(--space-5); font-size: var(--text-lg); color: var(--ink); max-width: 52ch; }
.hero .hero-proof { margin-top: var(--space-3); font-size: var(--text-sm); color: var(--ink-muted); }
.hero .btn { margin-top: var(--space-8); }

/* ═══════════════════════════════════════════════════════════════
   FOOTER  (composant site-footer-v2.js)
   SoT §3 : scope line C+E + as-of + data range. Aucun autre lien —
   les 4 pages moat restantes sont DIFFÉRÉES au gate post-Phase-10
   (§11 statut B), pas interdites.
   ═══════════════════════════════════════════════════════════════ */
.site-foot-v2 {
  border-top: 1px solid var(--hairline);
  background: var(--surface);
  margin-top: var(--space-20);
  padding-block: var(--space-12);
}
.site-foot-v2 .foot-inner { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); text-align: center; }
.site-foot-v2 .foot-scope { font-size: var(--text-sm); color: var(--ink-muted); }
.site-foot-v2 .foot-stamp {
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
}

/* ── COUTURE RÉSERVÉE — bloc pied de page ───────────────────────
   Décision opérateur 2026-07-28 : réserver la place de la future
   newsletter, VIDE en S5.1. Rien n'est collecté aujourd'hui, donc
   aucune obligation légale n'est déclenchée. Le jour où un email est
   collecté, la Privacy Policy devient OBLIGATOIRE (hébergement UE) —
   elle est autorisée depuis le 2026-07-28 (§11 statut C).           */
.foot-slot-reserved { width: 100%; max-width: 420px; min-height: 56px; }

/* ═══════════════════════════════════════════════════════════════
   METRIC BAND — cellule drillable  (S5.2)
   ───────────────────────────────────────────────────────────────
   Décision opérateur 2026-07-28 à l'ouverture de S5.2 : le drill des
   anciennes cartes KPI (`setupKpiDrills`, dans AUCUNE frame) est PORTÉ
   sur le metric band plutôt que supprimé. Il ouvre le panneau
   d'évidence — la promesse « tout chiffre se descend jusqu'à sa source ».

   L'indice est TOUJOURS visible, jamais révélé au survol seul : sur une
   surface tactile un affordance en `:hover` n'existe pas.
   ═══════════════════════════════════════════════════════════════ */
.metric-cell.is-drill { cursor: pointer; border-radius: var(--radius-sm); }
.metric-cell.is-drill:hover { background: var(--surface-sunk); }

.metric-drill-hint {
  display: block; margin-top: var(--space-2);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); font-weight: var(--w-semibold);
  color: var(--teal-live-deep);
}
/* ⚠ CETTE RÈGLE EST PORTEUSE, pas cosmétique — ne pas la retirer.
   `--teal-live-deep` mesure 4,80:1 sur `--surface` (✓ AA) mais 4,46:1 sur
   `--surface-sunk` (✗). Les deux changements sont donc COUPLÉS : dès que le
   fond de la cellule passe au creux, l'indice passe à `--ink-display`.
   Vérifié dans l'état de survol réel le 2026-07-28 : 10,49:1. Découpler les
   deux ferait échouer l'indice au survol, silencieusement. */
.metric-cell.is-drill:hover .metric-drill-hint { color: var(--ink-display); }

/* ═══════════════════════════════════════════════════════════════
   PANNEAU D'ÉVIDENCE — habillage v2  (S5.2)
   ───────────────────────────────────────────────────────────────
   `components/evidence-panel.js` est INCHANGÉ : il fait déjà le travail
   difficile (piège de focus, restitution du focus à l'ouvrant, Échap,
   parsing d'URL, badge F5). Il portait en revanche des classes définies
   uniquement dans `style.css` — sur une page v2, le panneau se serait
   ouvert SANS mise en page du tout. C'est un habillage, pas un fork.

   ⚠ Ce panneau est la liste d'évidence d'un AGRÉGAT. Le tiroir par
   DEAL (l'affordance `→` en fin de ligne) est D8, câblé en S5.3 :
   les deux ne doivent pas être confondus.
   ═══════════════════════════════════════════════════════════════ */
.evidence-backdrop {
  position: fixed; inset: 0; display: none;
  background: rgba(20, 52, 63, 0.45);
  z-index: 50;
}
.evidence-backdrop.is-open { display: block; }

.evidence-panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: 480px; max-width: 100vw;
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--hairline);
  box-shadow: -8px 0 32px rgba(20, 52, 63, 0.14);
  z-index: 60; overflow-y: auto;
  transform: translateX(100%);
  transition: transform 220ms ease;
}
.evidence-panel.is-open { transform: translateX(0); }

.evidence-panel__header {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
}
.evidence-panel__title { font-weight: var(--w-semibold); color: var(--ink-display); }
.evidence-panel__count {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-xs); color: var(--ink-muted);
}
.evidence-panel__close {
  background: none; border: 0; cursor: pointer;
  font-size: var(--text-xl); line-height: 1;
  color: var(--ink-muted); padding: var(--space-1);
  border-radius: var(--radius-sm);
}
.evidence-panel__close:hover { color: var(--ink-display); background: var(--teal-wash); }

.evidence-panel__body {
  flex: 1; display: flex; flex-direction: column; gap: var(--space-4);
  padding: var(--space-5) var(--space-6) var(--space-8);
}

.evidence-event {
  padding: var(--space-4);
  background: var(--surface-sunk);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
}
.evidence-event__name {
  font-size: var(--text-sm); font-weight: var(--w-semibold);
  color: var(--ink-display); margin-bottom: var(--space-2);
}
.evidence-event__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.evidence-event__amount {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-sm); font-weight: var(--w-semibold);
  color: var(--gold-ink);
}
.evidence-event__date {
  font-family: var(--font-data);
  font-size: var(--text-xs); color: var(--ink-muted);
}
.evidence-event__description { font-size: var(--text-sm); color: var(--ink); margin-bottom: var(--space-3); }
.evidence-event__source { font-size: var(--text-xs); color: var(--ink-muted); margin-bottom: var(--space-2); }
.evidence-event__urls { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.evidence-event__urls a {
  display: block; font-size: var(--text-xs); color: var(--ink-display);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Badges du panneau — portée limitée à `.evidence-panel` pour ne pas
   ouvrir un second vocabulaire de badges dans le système. La grammaire
   D5 est respectée : EXECUTED plein, CONFIRMED contour. Les statuts hors
   C+E (drill « tous statuts ») sont NEUTRES — ni or ni teal plein : un
   statut hors C+E ne doit jamais emprunter l'habit d'un statut C+E. */
.evidence-panel .badge {
  display: inline-block; padding: 2px var(--space-2);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  font-family: var(--font-data);
  font-size: var(--text-2xs); font-weight: var(--w-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
}
.evidence-panel .badge-green { background: var(--ink-display); color: #fff; }          /* Executed */
.evidence-panel .badge-blue  { background: transparent; color: var(--ink-display); border-color: var(--ink-display); } /* Confirmed */
.evidence-panel .badge-amber,
.evidence-panel .badge-gray  { background: var(--surface); color: var(--ink-muted); border-color: var(--hairline); }
/* Le badge de corroboration porte sa propre classe : sans cette règle il
   partagerait l'habit neutre des statuts et se lirait comme un statut. */
.evidence-panel .evidence-event__sources {
  background: var(--teal-wash); color: var(--ink-display); border-color: transparent;
}

/* ═══════════════════════════════════════════════════════════════
   EXPLORER — barre de filtres · onglets · breakdown · matrice
   (S5.3, 2026-07-29)
   ───────────────────────────────────────────────────────────────
   D2 : barre de CHIPS comme primitive (pas la phrase-requête), avec
   `Copy link / Reset` et le bandeau des 4 métriques ÉTIQUETÉ dans la
   même carte que les filtres — le chiffre reste collé au slice qui le
   produit.

   ⚠ COMBIEN DE CHIPS, ET POURQUOI SI PEU — mesuré le 2026-07-29 sur
   l'API live, à re-mesurer avant d'en ajouter une :

     `olap.js` déclare 12 dimensions. Deux tests les réduisent à 4.

     1. FIABILITÉ (couverture sur les 1 999 deals C+E) — `structure` est
        remplie à 100 % mais vaut `Direct` dans 88 % des cas (elle ne
        discrimine rien) ; `concessionality` 25,4 % ; `geo_scope` 23,3 % ;
        `materiality_tier` 3,7 % ; `event_kind` 0,4 % (champ Phase 10, pas
        encore alimenté). Côté investisseur, `investor_type` est rempli à
        100 % mais **44,7 % valent `Other`**, et `capital_origin` 39,9 %.
     2. FILTRABILITÉ SERVEUR — `capital_types`, `deal_types`, `regions`
        sont **acceptés sans erreur et IGNORÉS** par
        /api/intelligence/query : le total revient à 1 999 inchangé. Même
        piège que le `signal_status` apparié. Les exposer imposerait un
        filtre CLIENT, qui casserait « le bandeau est un agrégat serveur ».

   ⇒ Intersection fiable ∧ filtrable-serveur = **country · sector ·
     instrument · flow_type**, plus les scalaires montant/dates. Une chip
     de plus exige de repasser les DEUX tests.
   ═══════════════════════════════════════════════════════════════ */

.exp-filters {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-5) var(--space-8);
}
.exp-filters__lead { flex: none; margin-right: var(--space-1); }
.exp-dims { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.exp-actions { display: flex; gap: var(--space-2); margin-left: auto; }

/* Chip de DIMENSION — ouvre un menu. `position: relative` ancre le menu. */
/* Le wrap porte le repère de positionnement du menu : le menu est un FRÈRE
   du bouton (un <button> ne peut pas contenir de contrôles interactifs —
   D-S5-CHIP-MENU-NESTED-IN-BUTTON). */
.chip-wrap { position: relative; display: inline-flex; }
.chip-dim {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--hairline);
  color: var(--ink); font-size: var(--text-xs); font-weight: var(--w-medium);
  cursor: pointer;
}
.chip-dim:hover { border-color: var(--teal-live); color: var(--ink-display); }
.chip-dim[aria-expanded="true"] { border-color: var(--teal-live); background: var(--teal-wash); color: var(--ink-display); }
.chip-dim .caret { font-size: 9px; opacity: .6; }
/* Compteur de sélection. Fond `--ink-display` : le blanc y contraste à
   11,3:1 — l'ocre plein n'aurait pas tenu sur un si petit disque. */
.chip-dim .n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px;
  background: var(--ink-display); color: #fff;
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: 10px; font-weight: var(--w-semibold);
}

/* Menu déroulant d'une dimension. */
.chip-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 30;
  min-width: 240px; max-width: 340px; max-height: 340px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  padding: var(--space-2); cursor: default;
}
.chip-dim[aria-expanded="false"] + .chip-menu { display: none; }
.chip-menu label {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2); border-radius: var(--radius-sm);
  font-size: var(--text-sm); font-weight: var(--w-regular); color: var(--ink);
  cursor: pointer;
}
.chip-menu label:hover { background: var(--surface-sunk); }
.chip-menu input { accent-color: var(--teal-live-deep); flex: none; }
.chip-menu .menu-note {
  padding: var(--space-2); font-size: var(--text-2xs); color: var(--ink-muted);
  border-top: 1px solid var(--hairline-soft); margin-top: var(--space-1);
}
.chip-menu input[type="date"],
.chip-menu input[type="number"] {
  width: 100%; padding: var(--space-2);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  font-family: var(--font-data); font-size: var(--text-xs); color: var(--ink);
  background: var(--surface);
}

/* Chip de filtre ACTIF — retirable. */
.chip-active {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--teal-wash); border: 1px solid var(--teal-live);
  color: var(--ink-display); font-size: var(--text-xs); font-weight: var(--w-semibold);
}
.chip-active .x {
  background: none; border: 0; cursor: pointer; color: inherit;
  line-height: 1; padding: 0 2px; font-size: var(--text-sm); opacity: .7;
}
.chip-active .x:hover { opacity: 1; }
.exp-active {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  padding: 0 var(--space-8) var(--space-5);
}
.exp-active:empty { display: none; }

.btn-xs {
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-pill);
  font-size: var(--text-xs); font-weight: var(--w-semibold); cursor: pointer;
  border: 1px solid var(--hairline); background: var(--surface); color: var(--ink-display);
  /* À 375px, « Export CSV » et « Copy link » se cassaient en deux lignes
     et déformaient la rangée d'actions. Un libellé de bouton ne se coupe pas. */
  white-space: nowrap;
}
.btn-xs:hover { border-color: var(--teal-live); background: var(--teal-wash); }
.btn-xs:disabled { opacity: .45; cursor: default; }
.btn-xs:disabled:hover { border-color: var(--hairline); background: var(--surface); }

/* ── BANDEAU DU SLICE — « fiche de résultat » (V3, ratifié 2026-07-30)
   ───────────────────────────────────────────────────────────────
   Retour opérateur : « La barre principale ressemble trop à celle de la
   home. » C'était structurel — les deux pages rendaient `metric-band` à
   l'identique, alors qu'elles ne disent pas la même chose : la home
   affiche L'ÉTAT DU CORPUS (une manchette, qui doit dominer sa page),
   l'Explorer LE RÉSULTAT D'UNE REQUÊTE, qui change à chaque clic.

   Trois traitements ont été rendus sur données réelles ; celui-ci est
   retenu. Le volume est isolé derrière le filet ocre vertical — la même
   marque que le kicker du système, réutilisée pour dire « voici la
   mesure » — et les compteurs l'accompagnent en retrait. C'est le seul
   des trois qui hiérarchise explicitement la valeur monétaire C+E face
   aux compteurs, distinction que S5.2 a passé du temps à rendre lisible
   sur la home et qu'une ligne de chiffres égaux aurait aplatie. */
.slice-band {
  border-top: 1px solid var(--hairline);
  background: var(--surface-sunk);
  padding: var(--space-6) var(--space-8);
  display: flex; flex-wrap: wrap; gap: var(--space-6) var(--space-8);
}
.slice-lead {
  flex: none;
  border-left: 3px solid var(--gold);
  padding-left: var(--space-4);
}
.slice-rest {
  flex: 1 1 auto;
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: var(--space-4) var(--space-8);
}
.slice-k {
  display: block; margin-bottom: 2px;
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
}
.slice-v {
  display: block;
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-lg); font-weight: var(--w-medium); color: var(--ink);
  line-height: 1.15;
}
.slice-lead .slice-v {
  font-size: var(--text-2xl); font-weight: var(--w-semibold); color: var(--gold-ink);
  line-height: 1.1;
}
.slice-foot {
  width: 100%;
  border-top: 1px solid var(--hairline);
  padding-top: var(--space-3);
  display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
  font-family: var(--font-data);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
}

/* ── Onglets (D3 ratifié : LIST / BREAKDOWN / MATRIX, LIST par défaut).
   MAP est ABSENT, pas désactivé : il partage le blocage GeoJSON de la
   planche twin (`D-S5-TWIN-MAP-DEFERRED`, re-éval 2026-09-15). Un onglet
   grisé serait une affordance morte sur une page publique. ───────── */
.exp-tabs {
  display: flex; gap: var(--space-1);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--space-6);
  overflow-x: auto;
}
.exp-tabs button {
  flex: none; background: none; border: 0; cursor: pointer;
  padding: var(--space-3) var(--space-5); margin-bottom: -1px;
  font-size: var(--text-xs); font-weight: var(--w-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  color: var(--ink-muted); border-bottom: 2px solid transparent;
}
.exp-tabs button:hover { color: var(--ink-display); }
.exp-tabs button[aria-selected="true"] { color: var(--ink-display); border-bottom-color: var(--gold); }
.exp-panel[hidden] { display: none; }

/* ── BREAKDOWN — réutilise `.bar-list` du système. Deux colonnes de
   classements ; la ligne hors-classement « Continental » porte
   `.bar-fill.is-aside` (remplissage ET bord neutres). ────────────── */
.bd-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--space-8);
}
.bd-aside {
  margin-top: var(--space-4); padding-top: var(--space-4);
  border-top: 1px dashed var(--hairline);
}
.bd-total {
  margin-top: var(--space-3);
  font-family: var(--font-data); font-size: var(--text-2xs);
  color: var(--ink-muted); text-transform: uppercase; letter-spacing: var(--tracking-caps);
}

/* ── MATRICE — habillage clair du heatmap de `charts.js`.
   Les cellules reçoivent leur fond en style inline (rgba calculé) ; ici
   on ne pose que la grille, les en-têtes collants et les états. ──── */
.chart-heatmap-wrap {
  overflow: auto; max-height: 560px;
  border: 1px solid var(--hairline); border-radius: var(--radius-card);
  background: var(--surface);
}
.chart-heatmap-grid {
  display: grid;
  grid-template-columns: 180px repeat(var(--cols, 17), minmax(66px, 1fr));
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: 11px; line-height: 1.1;
}
.chart-heatmap-cell {
  display: flex; align-items: center; justify-content: center;
  min-height: 30px; padding: 6px 4px; text-align: center;
  color: var(--ink);
  border-right: 1px solid var(--hairline-soft);
  border-bottom: 1px solid var(--hairline-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chart-heatmap-cell--corner {
  position: sticky; top: 0; left: 0; z-index: 3;
  background: var(--surface-sunk); color: var(--ink-muted);
  font-family: var(--font-ui); font-size: var(--text-2xs); font-weight: var(--w-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  justify-content: flex-start; padding-left: var(--space-4);
  border-right-color: var(--hairline); border-bottom-color: var(--hairline);
}
.chart-heatmap-cell--col-head {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface-sunk); color: var(--ink);
  font-family: var(--font-ui); font-size: var(--text-2xs); font-weight: var(--w-medium);
  border-bottom-color: var(--hairline);
}
.chart-heatmap-cell--row-head {
  position: sticky; left: 0; z-index: 2;
  background: var(--surface-sunk); color: var(--ink);
  font-family: var(--font-ui); font-size: var(--text-xs);
  justify-content: flex-start; padding-left: var(--space-4);
  border-right-color: var(--hairline);
}
.chart-heatmap-cell--data[role="button"] { cursor: pointer; outline: 1px solid transparent; outline-offset: -1px; }
.chart-heatmap-cell--data[role="button"]:hover { outline: 2px solid var(--teal-live-deep); }
.chart-heatmap-cell--data[role="button"]:focus-visible { outline: 2px solid var(--teal-live-deep); }
.chart-heatmap-cell--empty { color: var(--ink-muted); background: var(--surface-sunk); }

.chart-empty {
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-12) var(--space-4); margin: 0;
  color: var(--ink-muted); font-size: var(--text-sm); text-align: center;
}

/* ── Toast « lien copié » ───────────────────────────────────────── */
.exp-toast {
  position: fixed; bottom: var(--space-8); left: 50%;
  transform: translateX(-50%) translateY(8px);
  background: var(--ink-display); color: #fff;
  padding: var(--space-3) var(--space-6); border-radius: var(--radius-pill);
  font-size: var(--text-sm); box-shadow: var(--shadow-card);
  opacity: 0; pointer-events: none; z-index: 70;
  transition: opacity .18s ease, transform .18s ease;
  max-width: min(90vw, 460px); text-align: center;
}
.exp-toast.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ═══════════════════════════════════════════════════════════════
   TIROIR DEAL — D8, variante V2 « lede + preuve » (S5.3)
   ───────────────────────────────────────────────────────────────
   Ratifié par l'opérateur le 2026-07-29 après revue des trois frames.
   Ordre : montant + statut + badge · LEDE (la description en base) ·
   investisseurs · attributs en grille 3 colonnes · preuve.

   ⚠ Il RÉUTILISE le shell `.evidence-panel` — même conteneur, même
   piège de focus, même backdrop, même restitution du focus à l'ouvrant.
   Seul le gabarit interne diffère. Ne pas créer un second panneau
   flottant : ce sont deux CONTENUS, pas deux composants.
   Le panneau d'AGRÉGAT reste `EvidencePanel.open()` ; le tiroir par
   DEAL est `EvidencePanel.openDeal()`.

   ⚠ « N SOURCES » affiche un COMPTE de domaines distincts, jamais une
   liste : mesuré le 2026-07-29, `corroboration_domains` vaut jusqu'à 10
   alors que `all_sources` n'expose qu'UNE entrée et que `mentions[]` ne
   porte aucune URL. Le tiroir le DIT (`.deal-caveat`) plutôt que de
   laisser croire à dix liens qu'il ne peut pas montrer.
   ═══════════════════════════════════════════════════════════════ */
.deal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); }
.deal-head h2 { font-size: var(--text-lg); color: var(--ink-display); }
.deal-sub {
  margin-top: var(--space-1);
  font-family: var(--font-data); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--ink-muted);
}
.deal-money { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-3); }
.deal-money .amt {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-2xl); font-weight: var(--w-semibold); color: var(--gold-ink);
}
.deal-money .orig { font-family: var(--font-data); font-size: var(--text-xs); color: var(--ink-muted); }
.deal-lede { font-size: var(--text-sm); line-height: 1.6; color: var(--ink); }

.deal-section-title {
  padding-top: var(--space-4); border-top: 1px solid var(--hairline-soft);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); font-weight: var(--w-semibold); color: var(--ink-muted);
  margin-bottom: var(--space-3);
}
.deal-investors { font-size: var(--text-sm); color: var(--ink); line-height: 1.6; }

.deal-attrs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3) var(--space-4); margin: 0; }
.deal-attrs dt {
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted); margin-bottom: 2px;
}
.deal-attrs dd {
  margin: 0; font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-xs); color: var(--ink); overflow-wrap: anywhere;
}
.deal-source { display: block; font-size: var(--text-xs); color: var(--ink-display); overflow-wrap: anywhere; }
.deal-caveat {
  margin-top: var(--space-2);
  font-family: var(--font-data); font-size: var(--text-2xs); color: var(--ink-muted);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
}

/* ═══════════════════════════════════════════════════════════════
   PROFILS — pays · secteur · investisseur   (S5.4, 2026-07-30)
   ───────────────────────────────────────────────────────────────
   Les trois pages de profil ont DEUX modes dans un même document :

     · INDEX   (aucun slug)  → la liste navigable de la dimension
     · PROFIL  (?name=/?id=) → la fiche d'une valeur

   C'est la structure d'origine, conservée : elle tient l'URL propre
   (`/country/kenya` réécrit par `_redirects`) sans dupliquer un
   fichier par mode. Ce qui change ici, c'est uniquement la peau — les
   417 lignes de CSS sombre en ligne des trois pages sont REMPLACÉES
   par les composants ci-dessous, comme S5.2 et S5.3 l'ont fait pour la
   home et l'Explorer.

   ⚠ Rien de neuf n'est inventé quand le système a déjà la primitive :
   `.card` · `.kicker` · `.kicker-stack` · `.metric-band` · `.bar-list`
   · `.donut-*` · `.evi-table` · `.pill-status` · `.badge-sources[-dot]`
   · `.chip` · `.chart-empty` servent tels quels. Cette section n'ajoute
   que ce qui n'existait pas : fil d'Ariane, grilles d'index et de
   widgets, bloc narratif, et le bouton transparent d'une barre
   cliquable.
   ═══════════════════════════════════════════════════════════════ */

/* ── Fil d'Ariane ───────────────────────────────────────────────
   Séparateurs en `::after` générés : ils sont décoratifs et ne
   doivent pas être lus par un lecteur d'écran, qui annonce déjà la
   liste de liens de la navigation `aria-label="Breadcrumb"`. */
.crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  font-size: var(--text-xs); color: var(--ink-muted);
}
.crumbs a { color: var(--ink-muted); text-decoration: none; }
.crumbs a:hover { color: var(--ink-display); text-decoration: underline; }
.crumbs > *:not(:last-child)::after {
  content: '›'; margin-left: var(--space-2); color: var(--hairline);
}
.crumbs [aria-current="page"] { color: var(--ink); font-weight: var(--w-medium); }

/* ── En-tête de fiche ───────────────────────────────────────────
   Le titre et les attributs d'identité sur la même ligne de base :
   sur un profil, « qui c'est » et « de quel type » se lisent ensemble. */
.prof-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-4); }
.prof-title h1 { font-size: var(--text-3xl); color: var(--ink-display); }
.chip-set { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* Un attribut CURÉ n'est pas un filtre actif : il se distingue de
   `.chip.is-on` (teal) par l'ocre, la seule autre marque du système. */
.chip.is-curated {
  background: var(--gold-rail); border-color: var(--gold);
  color: var(--gold-ink); font-weight: var(--w-semibold);
}

/* ── Bloc narratif ──────────────────────────────────────────────
   Servi par /api/intelligence/<dim>/<val>/narrative. Filet ocre à
   gauche — même marque que `.slice-lead` de l'Explorer : « voici la
   lecture », par opposition aux planches chiffrées. */
.narrative {
  border-left: 3px solid var(--gold);
  background: var(--surface);
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
  box-shadow: var(--shadow-card);
  padding: var(--space-6) var(--space-8);
}
.narrative h2 { font-size: var(--text-xl); color: var(--ink-display); }
.narrative .nr-body {
  margin-top: var(--space-3); font-size: var(--text-base);
  color: var(--ink); max-width: 78ch;
}
/* Repli : ~5 lignes. `-webkit-line-clamp` reste le seul mécanisme
   largement supporté ; il dégrade proprement (texte entier visible)
   là où il ne l'est pas, ce qui est le bon sens de dégradation. */
.narrative .nr-body.is-clamped {
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden;
}
.narrative .nr-toggle {
  margin-top: var(--space-3);
  background: none; border: 0; padding: 0; cursor: pointer;
  font-size: var(--text-xs); font-weight: var(--w-semibold);
  color: var(--teal-live-deep);
}
.narrative .nr-toggle:hover { color: var(--ink-display); text-decoration: underline; }
.narrative .nr-facts {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  margin: var(--space-5) 0 0; padding: 0; list-style: none;
}
.narrative .nr-facts li {
  background: var(--surface-sunk); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs); color: var(--ink);
}

/* ── Grille de widgets ──────────────────────────────────────────
   `auto-fit` + `minmax` : ajouter ou retirer une planche ne casse pas
   la mise en page, elle se recompose. 340px est le point où une barre
   avec son libellé et son pourcentage tient sans se briser. */
.wg-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: var(--space-6); }
.wg-wide { grid-column: 1 / -1; }

/* ⚠ CETTE RÈGLE EST PORTEUSE, pas cosmétique — ne pas la retirer.
   Une piste `1fr` vaut `minmax(auto, 1fr)`, et ce `auto` prend pour
   MINIMUM la largeur min-content de la carte. Une carte qui contient une
   table dense a donc un plancher que la piste ne peut pas descendre, et
   c'est la PAGE qui déborde — pas la table.
   Mesuré le 2026-07-30 à 375px sur le profil pays : la carte « Peer
   comparison » a un min-content de 398px, la grille n'en offrait que 327 ;
   le document passait à 421px pour une fenêtre de 375. Les quatre autres
   cartes tenaient (183-250px), donc le défaut ne se voyait que sur une
   page portant une table — et pas du tout tant que la table n'avait pas
   fini de charger, ce qui l'a rendu invisible au premier contrôle.
   `min-width: 0` autorise la piste à descendre sous le min-content ;
   l'`overflow-x: auto` de `.evi-wrap` reprend alors son rôle et c'est la
   TABLE qui défile, ce qui est exactement l'intention du composant. */
.wg-grid > * { min-width: 0; }
.wg-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: var(--space-3);
  margin-bottom: var(--space-5);
}
.wg-head h3 { font-size: var(--text-lg); color: var(--ink-display); }
.wg-meta {
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
  font-family: var(--font-data);
}

/* Bouton transparent enveloppant une barre cliquable.
   ⚠ Il remplace le `style="all:unset"` en ligne de l'Explorer : `all:unset`
   supprime AUSSI le comportement de focus par défaut du bouton dans certains
   moteurs, et un `outline` posé après ne se rattache à rien de visible.
   Ici on ne remet à zéro que ce qu'il faut, et on garde l'anneau du système. */
.bar-pick {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; padding: 0; color: inherit; font: inherit;
  border-radius: var(--radius-sm);
}
.bar-pick:hover .bar-label { color: var(--ink-display); text-decoration: underline; }

/* Note sous une planche — dit l'échelle ET le dénominateur. */
/* Une note vide ne laisse aucun espace mort : les pages posent un `<p>` de
   note même quand elle n'a rien à dire (index pays sans valeur hors taxonomie),
   et sans cette règle il restait ~28px de marge et un filet au-dessus de rien. */
.wg-note:empty { display: none; }
.wg-note {
  margin-top: var(--space-4); padding-top: var(--space-3);
  border-top: 1px solid var(--hairline-soft);
  font-family: var(--font-data); font-size: var(--text-2xs);
  color: var(--ink-muted); text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
}

/* ── Grille d'index ─────────────────────────────────────────────
   La carte d'index porte 3 informations et pas une de plus : le nom,
   le NOMBRE de deals (tous statuts) et le VOLUME (C+E). Les deux
   grandeurs n'ont pas la même portée — d'où deux traitements
   typographiques distincts, et le libellé qui le dit sous la carte. */
.idx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--space-4); }
.idx-card {
  display: flex; flex-direction: column; gap: var(--space-1);
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  padding: var(--space-5); text-decoration: none; color: inherit;
}
.idx-card:hover { border-color: var(--teal-live); }
.idx-name { font-size: var(--text-base); font-weight: var(--w-semibold); color: var(--ink-display); }
.idx-type {
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  font-size: var(--text-2xs); color: var(--ink-muted);
}
.idx-stat {
  margin-top: var(--space-2);
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-xl); font-weight: var(--w-semibold); color: var(--ink);
  line-height: 1.1;
}
.idx-sub {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-xs); color: var(--ink-muted);
}
.idx-sub .idx-vol { color: var(--gold-ink); font-weight: var(--w-semibold); }

/* Contrôles de l'index investisseurs (2 700+ entrées : sans recherche
   ni pagination, la page est inutilisable). */
.idx-controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  margin-bottom: var(--space-6);
}
.idx-controls input[type="search"],
.idx-controls select {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius-pill); padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm); color: var(--ink); min-width: 200px;
}
.idx-controls input[type="search"]:focus-within,
.idx-controls input[type="search"]:focus,
.idx-controls select:focus { border-color: var(--teal-live); }
.pager {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  margin-top: var(--space-6);
}
.pager .pg-info {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--text-xs); color: var(--ink-muted);
}

/* ── État d'erreur de chargement ───────────────────────────────── */
.load-error {
  max-width: 560px; margin-inline: auto; text-align: center;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  padding: var(--space-10) var(--space-8);
}
.load-error h2 { font-size: var(--text-xl); color: var(--ink-display); margin-bottom: var(--space-3); }
.load-error p { color: var(--ink-muted); font-size: var(--text-sm); }
.load-error .btn { margin-top: var(--space-6); }

/* ── Bandeau d'avertissement (entité dépréciée, couverture partielle)
   Ocre pâle + filet : la même marque que le kicker, en surface.
   Le texte est en `--ink`, jamais en ocre — `--gold` échoue le 4,5:1. */
.notice {
  border: 1px solid var(--gold);
  border-left-width: 3px;
  background: var(--gold-rail);
  border-radius: var(--radius-sm);
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-sm); color: var(--ink);
}
.notice strong { color: var(--gold-ink); }
.notice a { color: var(--ink-display); }

/* ═══════════════════════════════════════════════════════════════
   RESPONSIVE
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .metric-cell { border-left: 0; padding-inline: 0; padding-block: var(--space-3); }
  .metric-row  { gap: var(--space-2); }
  .donut-legend { grid-template-columns: 1fr; }
}

@media (max-width: 768px) {
  :root { --text-4xl: 2.25rem; --text-3xl: 1.875rem; }
  .site-header-v2 .header-inner { flex-wrap: wrap; gap: var(--space-3); min-height: 0; padding-block: var(--space-3); }
  .primary-nav-v2 { order: 3; width: 100%; overflow-x: auto; gap: var(--space-5); }
  .search-pill { min-width: 0; flex: 1 1 auto; }
  .card { padding: var(--space-6); }
  .metric-row, .metric-foot { padding-inline: var(--space-6); }

  /* Explorer — les paddings de la carte de filtres suivent ceux du
     metric band, sinon chips et chiffres ne s'alignent plus. */
  .exp-filters { padding-inline: var(--space-6); }
  .exp-active  { padding-inline: var(--space-6); }
  .exp-actions { margin-left: 0; width: 100%; }
  /* Le menu d'une chip proche du bord droit déborderait : à cette largeur
     il s'ancre à droite plutôt qu'à gauche. */
  .chip-menu { left: auto; right: 0; min-width: min(280px, calc(100vw - var(--space-12))); }
  .deal-attrs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chart-heatmap-grid { grid-template-columns: 130px repeat(var(--cols, 17), minmax(58px, 1fr)); }

  /* Profils — les paddings suivent ceux de `.card`, sinon un bloc
     narratif à filet ne s'aligne plus sur les planches voisines. */
  .narrative { padding: var(--space-5) var(--space-6); }
  .load-error { padding: var(--space-8) var(--space-6); }
  /* `minmax(340px, …)` ne se replie pas seul sous 340px + gouttières :
     `auto-fit` garde une colonne, mais la piste garde son minimum et
     déborde. Mesuré à 375px — d'où la colonne unique explicite.
     ⚠ `minmax(0, 1fr)` et non `1fr` : voir la note de `.wg-grid > *`. */
  .wg-grid { grid-template-columns: minmax(0, 1fr); }
  .idx-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .idx-controls input[type="search"],
  .idx-controls select { min-width: 0; flex: 1 1 160px; }
}

@media (max-width: 480px) {
  /* Le tiroir occupe toute la largeur : à 375px, 480px de panneau
     déborderaient de la fenêtre. `max-width: 100vw` était déjà posé sur
     `.evidence-panel` ; ici on ramène la grille d'attributs à une colonne
     pour que les valeurs mono ne se coupent pas. */
  .deal-attrs { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ═══════════════════════════════════════════════════════════════
   SOMMAIRE DE PROFIL — revue 2026-08-06, ledger M7
   Barre d'ancres collante sous le header (72px). Les cibles portent
   un scroll-margin pour ne pas disparaître sous les deux bandeaux.
   ═══════════════════════════════════════════════════════════════ */
.profile-toc {
  position: sticky; top: 72px; z-index: 30;
  display: flex; flex-wrap: wrap; gap: var(--space-5);
  align-items: center;
  background: var(--ice-paper);
  border-bottom: 1px solid var(--hairline);
  padding: var(--space-2) 0 var(--space-3);
  margin-bottom: var(--space-6);
}
.profile-toc a {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  text-decoration: none;
  letter-spacing: 0.02em;
}
.profile-toc a:hover,
.profile-toc a:focus-visible { color: var(--teal-live-deep); text-decoration: underline; text-underline-offset: 3px; }
#profile-mode, #narrative, #widgets, #deals { scroll-margin-top: 128px; }

/* ═══════════════════════════════════════════════════════════════
   SKELETONS — revue 2026-08-06, ledger M26
   État de chargement : barres animées à la place d'un « Loading… » nu.
   Le fallback d'ÉCHEC reste textuel et explicite (bandUnavailable,
   listMessage, showLoadError) — un squelette qui ne se remplit jamais
   serait un état dégradé silencieux.
   ⚠ prefers-reduced-motion coupe l'animation (règle globale en fin de
   fichier) : les barres restent visibles, statiques.
   ═══════════════════════════════════════════════════════════════ */
.skeleton-bars { display: grid; gap: 10px; padding: var(--space-3) 0; }
.skeleton-bars span {
  display: block; height: 12px; border-radius: 6px;
  background: linear-gradient(90deg, var(--surface-sunk) 25%, var(--hairline-soft) 50%, var(--surface-sunk) 75%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s linear infinite;
}
.skeleton-bars span:nth-child(1) { width: 82%; }
.skeleton-bars span:nth-child(2) { width: 64%; }
.skeleton-bars span:nth-child(3) { width: 73%; }
@keyframes skeleton-shimmer { to { background-position: -200% 0; } }

/* Filtre de menu long (Explorer, revue passe 2 — ledger M43) */
.chip-menu .menu-filter {
  width: calc(100% - 2 * var(--space-3));
  margin: var(--space-2) var(--space-3);
  padding: 6px 10px;
  font-size: var(--text-sm);
  font-family: var(--font-ui);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 8px;
}
.chip-menu .menu-filter:focus { outline: none; border-color: var(--teal-live); }
