/* ==========================================================================
   ExEuropa — feuille de styles
   --------------------------------------------------------------------------
   Organisation :
     1. Jetons de conception et thèmes
     2. Base et typographie
     3. Décor animé
     4. En-tête et navigation
     5. Composants (boutons, cartes, badges, formulaires)
     6. Accueil : hero, statistiques
     7. Carte : le cœur du site
     8. Rail de couches et tableau de bord
     9. Actualités
    10. Forum
    11. Fiches pays et frises
    12. Pages diverses, pied de page, utilitaires
   ========================================================================== */

/* ==========================================================================
   1. Jetons de conception
   ========================================================================== */

:root {
  /* Rayons — resserrés pour un trait plus net */
  --r-xs: 5px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 24px;
  --r-full: 999px;

  /* Espacements */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px;  --sp-6: 32px;  --sp-7: 48px;  --sp-8: 64px;
  --sp-9: 96px;
  /* L'écart entre deux blocs de premier rang : assez pour qu'ils se lisent
     comme deux sujets, assez peu pour qu'on ne croie pas la page finie. */
  --flow: clamp(44px, 5vw, 76px);
  --flow-tight: clamp(26px, 3vw, 40px);

  /* Typographie.
     Les titres passent en linéale à graisse légère et interlettrage resserré :
     l'empattement est conservé pour les dates et les citations, où il apporte
     une note éditoriale sans alourdir la page. */
  --font-sans: system-ui, -apple-system, "Segoe UI Variable Display", "Segoe UI",
               Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: var(--font-sans);
  --font-serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  --fs-xs: 0.74rem;
  --fs-sm: 0.83rem;
  --fs-base: 0.94rem;
  --fs-md: 1.02rem;
  --fs-lg: 1.18rem;
  --fs-xl: 1.5rem;
  --fs-2xl: clamp(1.6rem, 2.6vw, 2rem);
  --fs-3xl: clamp(2rem, 4.4vw, 3.3rem);

  /* Graisses et interlettrages des titres */
  --w-display: 300;
  --w-title: 500;
  --ls-display: -0.035em;
  --ls-title: -0.02em;

  /* Transitions */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-fast: 140ms;
  --t: 260ms;
  --t-slow: 520ms;

  --maxw: 1560px;
}

/* -- Thème sombre (par défaut) ---------------------------------------------
 *
 * `:root` seul, sans attribut, est le cas du visiteur qui n'a rien choisi :
 * le sombre lui est servi, et la requête de média plus bas lui rend le clair
 * si son système le demande. Le gabarit n'écrit plus `data-theme` dans la
 * balise `<html>` — il l'écrivait en dur, et sans script le site restait
 * sombre quelle que soit la préférence de la machine.
 */
:root,
[data-theme="dark"] {
  color-scheme: dark;

  --bg: #070912;
  --bg-2: #0b0f1c;
  --surface: rgba(20, 26, 44, 0.72);
  --surface-solid: #121728;
  --surface-2: rgba(28, 35, 58, 0.66);
  --border: rgba(148, 166, 214, 0.16);
  --border-strong: rgba(148, 166, 214, 0.32);

  --text: #e8ecf8;
  --text-2: #a9b4d0;
  --text-3: #6f7c9d;

  /* La couronne d'étoiles, en masque : le fond de page et le pied de page la
     reprennent, et une chaîne de deux mille caractères recopiée quatre fois
     finit par diverger. */
  --crown: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><g fill='black'><path d='M100,17 102.02,23.22 108.56,23.22 103.27,27.06 105.29,33.28 100,29.44 94.71,33.28 96.73,27.06 91.44,23.22 97.98,23.22Z'/><path d='M137,26.91 139.02,33.13 145.56,33.13 140.27,36.98 142.29,43.2 137,39.35 131.71,43.2 133.73,36.98 128.44,33.13 134.98,33.13Z'/><path d='M164.09,54 166.11,60.22 172.65,60.22 167.36,64.06 169.38,70.28 164.09,66.44 158.8,70.28 160.82,64.06 155.53,60.22 162.07,60.22Z'/><path d='M174,91 176.02,97.22 182.56,97.22 177.27,101.06 179.29,107.28 174,103.44 168.71,107.28 170.73,101.06 165.44,97.22 171.98,97.22Z'/><path d='M164.09,128 166.11,134.22 172.65,134.22 167.36,138.06 169.38,144.28 164.09,140.44 158.8,144.28 160.82,138.06 155.53,134.22 162.07,134.22Z'/><path d='M137,155.09 139.02,161.3 145.56,161.3 140.27,165.15 142.29,171.37 137,167.52 131.71,171.37 133.73,165.15 128.44,161.3 134.98,161.3Z'/><path d='M100,165 102.02,171.22 108.56,171.22 103.27,175.06 105.29,181.28 100,177.44 94.71,181.28 96.73,175.06 91.44,171.22 97.98,171.22Z'/><path d='M63,155.09 65.02,161.3 71.56,161.3 66.27,165.15 68.29,171.37 63,167.52 57.71,171.37 59.73,165.15 54.44,161.3 60.98,161.3Z'/><path d='M35.91,128 37.93,134.22 44.47,134.22 39.18,138.06 41.2,144.28 35.91,140.44 30.62,144.28 32.64,138.06 27.35,134.22 33.89,134.22Z'/><path d='M26,91 28.02,97.22 34.56,97.22 29.27,101.06 31.29,107.28 26,103.44 20.71,107.28 22.73,101.06 17.44,97.22 23.98,97.22Z'/><path d='M35.91,54 37.93,60.22 44.47,60.22 39.18,64.06 41.2,70.28 35.91,66.44 30.62,70.28 32.64,64.06 27.35,60.22 33.89,60.22Z'/><path d='M63,26.91 65.02,33.13 71.56,33.13 66.27,36.98 68.29,43.2 63,39.35 57.71,43.2 59.73,36.98 54.44,33.13 60.98,33.13Z'/></g></svg>");
  --brand-1: #6f7dff;
  --brand-2: #22d3ee;
  --brand-3: #f5c451;
  --accent: #f472b6;

  /* Deux voix, deux couleurs.
     On ouvre un débat quand le sujet pose une question : bleu-vert, ouvert,
     il attend une réponse de quelqu'un d'autre. On écrit une tribune quand le
     sujet fait affirmer quelque chose : ambre, ferme, elle n'attend rien.
     La couleur du bouton se retrouve sur la page où il mène — c'est à cela
     qu'on sait, en arrivant, dans lequel des deux on vient d'entrer. */
  --voice-ask: #22d3ee;
  --voice-say: #f0a63c;
  --voice-ink: #0b1020;

  --success: #34d399;
  --warning: #fbbf24;
  --danger: #f87171;

  /* Carte */
  --sea-1: #050912;
  --sea-2: #0a1730;
  --land-1: #33406b;
  --land-2: #232c4d;
  --land-context: #1a1f3550;
  --map-stroke: rgba(178, 196, 240, 0.45);
  --map-stroke-strong: rgba(214, 228, 255, 0.85);
  --map-shadow: #000814;
  --map-label: rgba(226, 233, 255, 0.97);
  --map-label-halo: rgba(6, 9, 18, 0.96);
  --graticule: rgba(130, 152, 205, 0.26);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow: 0 8px 24px -14px rgba(0, 0, 0, 0.7);
  --shadow-lg: 0 24px 56px -32px rgba(0, 0, 0, 0.85);
  --glow: 0 0 0 1px rgba(111, 125, 255, 0.28), 0 10px 32px -14px rgba(111, 125, 255, 0.35);

  --aurora-1: rgba(96, 112, 220, 0.16);
  --aurora-2: rgba(34, 190, 210, 0.09);
  --grid-line: rgba(148, 166, 214, 0.055);
  /* Palette des graphiques.

     Huit teintes d'étiquette, pas de jugement : une part « détenue à
     l'étranger » n'est ni rouge ni verte, elle est de la couleur de son rang.
     Le site a déjà des couleurs de sens — le rouge d'une alerte, le vert d'une
     confirmation — et les employer sur une mesure ferait lire un avis là où il
     n'y a qu'un chiffre. Les luminances sont proches, pour qu'aucune ne domine
     et qu'elles restent distinctes une fois converties en gris. */
  --chart-1: #6f7dff;
  --chart-2: #22d3ee;
  --chart-3: #f5c451;
  --chart-4: #f472b6;
  --chart-5: #7ee787;
  --chart-6: #c792ea;
  --chart-7: #ff9f6b;
  --chart-8: #8fa3c8;
  --chart-grid: rgba(148, 166, 214, 0.14);
  --chart-ink: rgba(148, 166, 214, 0.72);
}

/* -- Thème clair ------------------------------------------------------------ */
[data-theme="light"] {
  color-scheme: light;

  --bg: #f6f4ee;
  --bg-2: #efece3;
  --surface: rgba(255, 255, 255, 0.82);
  --surface-solid: #ffffff;
  --surface-2: rgba(255, 255, 255, 0.62);
  --border: rgba(28, 38, 66, 0.13);
  --border-strong: rgba(28, 38, 66, 0.26);

  --text: #14192a;
  --text-2: #4a5474;
  --text-3: #7a849e;

  --brand-1: #3b4ee0;
  --brand-2: #0e9ab4;
  --brand-3: #b7841c;
  --accent: #d9407f;

  /* Sur fond clair, les deux voix doivent tenir en texte comme en fond : le
     cyan et l'ambre du thème sombre y passeraient pour de la décoration. */
  --voice-ask: #0e8ea8;
  --voice-say: #b46a05;
  --voice-ink: #ffffff;

  --success: #12855f;
  --warning: #a96a06;
  --danger: #cc3b3b;

  --sea-1: #d7e3f4;
  --sea-2: #bccfea;
  --land-1: #fdfcf8;
  --land-2: #eae3d2;
  --land-context: #ded8c850;
  --map-stroke: rgba(40, 54, 92, 0.45);
  --map-stroke-strong: rgba(20, 30, 58, 0.8);
  --map-shadow: #7a8299;
  --map-label: rgba(16, 22, 42, 0.98);
  --map-label-halo: rgba(255, 255, 255, 0.96);
  --graticule: rgba(48, 68, 120, 0.24);

  --shadow-sm: 0 1px 2px rgba(28, 38, 66, 0.07);
  --shadow: 0 10px 26px -18px rgba(28, 38, 66, 0.26);
  --shadow-lg: 0 26px 56px -36px rgba(28, 38, 66, 0.34);
  --glow: 0 0 0 1px rgba(59, 78, 224, 0.2), 0 10px 30px -16px rgba(59, 78, 224, 0.26);

  --aurora-1: rgba(59, 78, 224, 0.075);
  --aurora-2: rgba(14, 154, 180, 0.055);
  --grid-line: rgba(50, 70, 120, 0.05);
  --chart-1: #3b4ee0;
  --chart-2: #0e8ea8;
  --chart-3: #a97a10;
  --chart-4: #c43d7e;
  --chart-5: #2f8f52;
  --chart-6: #7b52c4;
  --chart-7: #c35a24;
  --chart-8: #5c6b8a;
  --chart-grid: rgba(28, 38, 66, 0.12);
  --chart-ink: rgba(28, 38, 66, 0.62);
}

/* -- Thème clair, servi sans qu'on l'ait demandé ---------------------------
 *
 * Le même que ci-dessus, pour le visiteur qui n'a rien choisi et dont le
 * système demande le clair. Sans ce bloc, il n'y a que le script pour le lui
 * donner — et sans script, personne.
 *
 * `:not([data-theme])` est ce qui rend la chose sûre : dès qu'un choix est
 * posé, cette règle ne s'applique plus, et un lecteur qui a demandé le sombre
 * sur un téléphone en clair garde le sombre.
 *
 * **Les deux listes doivent rester identiques**, déclaration pour
 * déclaration. Une palette recopiée dérive — c'est déjà arrivé ici, entre la
 * feuille de style et les couleurs de la barre du navigateur. `smoke.php` les
 * compare désormais et échoue si elles s'écartent : cette copie n'est donc
 * pas une promesse mais une vérification.
 */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    color-scheme: light;

    --bg: #f6f4ee;
    --bg-2: #efece3;
    --surface: rgba(255, 255, 255, 0.82);
    --surface-solid: #ffffff;
    --surface-2: rgba(255, 255, 255, 0.62);
    --border: rgba(28, 38, 66, 0.13);
    --border-strong: rgba(28, 38, 66, 0.26);

    --text: #14192a;
    --text-2: #4a5474;
    --text-3: #7a849e;

    --brand-1: #3b4ee0;
    --brand-2: #0e9ab4;
    --brand-3: #b7841c;
    --accent: #d9407f;

    --voice-ask: #0e8ea8;
    --voice-say: #b46a05;
    --voice-ink: #ffffff;

    --success: #12855f;
    --warning: #a96a06;
    --danger: #cc3b3b;

    --sea-1: #d7e3f4;
    --sea-2: #bccfea;
    --land-1: #fdfcf8;
    --land-2: #eae3d2;
    --land-context: #ded8c850;
    --map-stroke: rgba(40, 54, 92, 0.45);
    --map-stroke-strong: rgba(20, 30, 58, 0.8);
    --map-shadow: #7a8299;
    --map-label: rgba(16, 22, 42, 0.98);
    --map-label-halo: rgba(255, 255, 255, 0.96);
    --graticule: rgba(48, 68, 120, 0.24);

    --shadow-sm: 0 1px 2px rgba(28, 38, 66, 0.07);
    --shadow: 0 10px 26px -18px rgba(28, 38, 66, 0.26);
    --shadow-lg: 0 26px 56px -36px rgba(28, 38, 66, 0.34);
    --glow: 0 0 0 1px rgba(59, 78, 224, 0.2), 0 10px 30px -16px rgba(59, 78, 224, 0.26);

    --aurora-1: rgba(59, 78, 224, 0.075);
    --aurora-2: rgba(14, 154, 180, 0.055);
    --grid-line: rgba(50, 70, 120, 0.05);
    --chart-1: #3b4ee0;
    --chart-2: #0e8ea8;
    --chart-3: #a97a10;
    --chart-4: #c43d7e;
    --chart-5: #2f8f52;
    --chart-6: #7b52c4;
    --chart-7: #c35a24;
    --chart-8: #5c6b8a;
    --chart-grid: rgba(28, 38, 66, 0.12);
    --chart-ink: rgba(28, 38, 66, 0.62);
  }
}

/* ==========================================================================
   2. Base
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scrollbar-color: var(--border-strong) transparent;
  /* L'en-tête est collé en haut : sans cette marge, une ancre amène sa cible
     sous lui, et le lecteur atterrit quelques lignes trop bas sans savoir
     pourquoi. `scroll-padding` sur le port de défilement plutôt que
     `scroll-margin` sur chaque cible : il n'y a qu'un en-tête, et il n'a pas à
     être redit à chaque titre. La hauteur est mesurée, pas devinée. */
  scroll-padding-top: calc(var(--head-h, 64px) + 12px);
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  transition: background-color var(--t-slow) var(--ease), color var(--t-slow) var(--ease);
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--w-title);
  line-height: 1.15;
  letter-spacing: var(--ls-title);
  margin: 0 0 var(--sp-3);
  text-wrap: balance;
}
h1 {
  font-size: var(--fs-3xl);
  font-weight: var(--w-display);
  letter-spacing: var(--ls-display);
  line-height: 1.06;
}
h2 {
  font-size: var(--fs-2xl);
  font-weight: 400;
  letter-spacing: -0.028em;
}
h3 { font-size: var(--fs-lg); }

p { margin: 0 0 var(--sp-4); text-wrap: pretty; }

a { color: inherit; text-decoration: none; }
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

img, svg { max-width: 100%; }
ul, ol { margin: 0; padding: 0; list-style: none; }

/* L'attribut hidden doit l'emporter sur les display: grid / flex des
   composants ; sans cela, masquer un bloc depuis le script reste sans effet. */
[hidden] { display: none !important; }

::selection { background: var(--brand-1); color: #fff; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: -100px; left: var(--sp-4);
  z-index: 200;
  padding: var(--sp-3) var(--sp-4);
  background: var(--brand-1); color: #fff;
  border-radius: var(--r-sm);
  transition: top var(--t) var(--ease);
}
.skip-link:focus { top: var(--sp-4); }

.muted { color: var(--text-2); }
/* Le contenu passe devant le pied de page, et non l'inverse.

   Les deux doivent monter au-dessus du décor `.aurora`, qui est fixe et couvre
   la fenêtre : chacun portait donc `z-index: 1`. À rang égal, c'est l'ordre du
   document qui tranche, et le pied de page vient après — il recouvrait tout ce
   qui déborde du contenu vers le bas. Une liste de pays ouverte en fin de
   formulaire (l'inscription, une nouvelle discussion) passait dessous : elle a
   beau demander `z-index: 60`, ce rang ne vaut qu'à l'intérieur de `.main`,
   qui est un contexte d'empilement à lui seul. C'est le rang de `.main` qu'il
   fallait relever, pas celui de la liste. */
.main { position: relative; z-index: 2; }

/* ==========================================================================
   3. Décor animé
   ========================================================================== */

/* Décor de fond volontairement discret : une nappe lumineuse très diffuse en
   haut de page, une seconde presque effacée en bas, et une trame fine sous un
   masque doux. Aucune couleur saturée ne vient concurrencer la carte. */
.aurora {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.aurora__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(140px);
  will-change: transform;
}
.aurora__blob--1 {
  width: 74vw; height: 46vw;
  top: -22vw; left: -6vw;
  background: var(--aurora-1);
  animation: drift1 60s var(--ease) infinite alternate;
}
.aurora__blob--2 {
  width: 52vw; height: 40vw;
  top: 38vh; right: -18vw;
  background: var(--aurora-2);
  animation: drift2 78s var(--ease) infinite alternate;
}
.aurora__blob--3 { display: none; }

.aurora__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 120px 120px;
  mask-image: radial-gradient(ellipse 80% 55% at 50% 0%, #000 0%, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse 80% 55% at 50% 0%, #000 0%, transparent 72%);
}

@keyframes drift1 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(5vw, 4vh, 0) scale(1.08); }
}
@keyframes drift2 {
  from { transform: translate3d(0, 0, 0) scale(1.05); }
  to   { transform: translate3d(-4vw, -5vh, 0) scale(0.96); }
}

/* ==========================================================================
   4. En-tête
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 90;
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  background: color-mix(in oklab, var(--bg) 76%, transparent);
  border-bottom: 1px solid var(--border);
}
.site-header__inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--sp-3) var(--sp-5);
  display: flex;
  align-items: center;
  gap: var(--sp-5);
}

.brand { display: flex; align-items: center; gap: var(--sp-3); flex-shrink: 0; }
.brand__mark { display: grid; place-items: center; }
.brand__star {
  /* Le repère de l'emblème est passé de 40 à 64 : sans ce centre, les étoiles
     tournaient autour d'un point qui n'existe plus. */
  transform-origin: 32px 32px;
  animation: twinkle 4s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.18s);
}
@keyframes twinkle {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 1; }
}
.brand__text { display: flex; flex-direction: column; line-height: 1.1; }
.brand__text strong {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 500;
  letter-spacing: -0.03em;
}
.brand__accent {
  background: linear-gradient(100deg, var(--brand-1), var(--brand-2) 60%, var(--brand-3));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.brand__text small { font-size: 0.66rem; color: var(--text-3); letter-spacing: 0.09em; text-transform: uppercase; }

.nav { flex: 1; min-width: 0; }
.nav__list { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.nav__link {
  position: relative;
  display: block;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: var(--sp-3); right: var(--sp-3); bottom: 3px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--brand-1), var(--brand-2));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t) var(--ease-out);
}
.nav__link:hover { color: var(--text); background: var(--surface-2); }
.nav__link:hover::after,
.nav__link.is-active::after { transform: scaleX(1); }
.nav__link.is-active { color: var(--text); }

.site-header__tools { display: flex; align-items: center; gap: var(--sp-2); }

.search { position: relative; display: flex; align-items: center; }
.search input {
  width: 190px;
  padding: 8px 34px 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  transition: width var(--t) var(--ease-out), border-color var(--t-fast), background var(--t-fast);
}
.search input:focus { width: 260px; border-color: var(--brand-1); background: var(--surface-solid); outline: none; }
.search button {
  position: absolute; right: 6px;
  display: grid; place-items: center;
  width: 26px; height: 26px;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--text-3);
  cursor: pointer;
  transition: color var(--t-fast);
}
.search button:hover { color: var(--brand-2); }
.search__results {
  position: absolute;
  top: calc(100% + 8px); left: 0; right: 0;
  min-width: 280px;
  background: var(--surface-solid);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  z-index: 20;
  animation: pop var(--t) var(--ease-out);
}
.search__results a {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-sm);
  border-bottom: 1px solid var(--border);
}
.search__results a:last-child { border-bottom: 0; }
.search__results a:hover { background: var(--surface-2); }
.search__results .group-title {
  padding: var(--sp-2) var(--sp-3) 2px;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-3);
}
.search__results .empty { padding: var(--sp-3); font-size: var(--fs-sm); color: var(--text-3); }

.btn-icon {
  display: grid; place-items: center;
  width: 36px; height: 36px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text-2);
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast), transform var(--t-fast) var(--ease-spring);
}
.btn-icon:hover { color: var(--text); border-color: var(--border-strong); transform: translateY(-1px); }
.lang-code { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em; }

/* Le bouton de thème, trois positions.
 *
 * L'icône montre désormais l'état **courant** et non l'action à venir : à deux
 * états, « le soleil mène au clair » se devine ; à trois, la position suivante
 * ne se devine plus, et une icône qui annonce une action laisse ignorer d'où
 * l'on part. Le libellé dit la même chose en toutes lettres.
 *
 * Le mode automatique est l'absence d'attribut : c'est lui que sert `:root`
 * quand ni `[data-theme="dark"]` ni `[data-theme="light"]` ne s'appliquent. */
.theme-toggle { position: relative; overflow: hidden; }
.theme-toggle svg { position: absolute; transition: transform var(--t-slow) var(--ease-spring), opacity var(--t) var(--ease); }

/* Rangées hors champ par défaut ; celle de l'état courant redescend. */
.theme-toggle__auto,
.theme-toggle__sun,
.theme-toggle__moon { transform: translateY(28px) rotate(-40deg); opacity: 0; }

:root:not([data-theme]) .theme-toggle__auto { transform: translateY(0) rotate(0); opacity: 1; }
[data-theme="dark"] .theme-toggle__moon { transform: translateY(0) rotate(0); opacity: 1; }
[data-theme="light"] .theme-toggle__sun { transform: translateY(0) rotate(0); opacity: 1; }

.dropdown { position: relative; }
.dropdown__menu {
  position: absolute;
  top: calc(100% + 8px); left: 0;
  min-width: 190px;
  padding: 6px;
  background: var(--surface-solid);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  z-index: 30;
  animation: pop var(--t) var(--ease-out);
}
.dropdown__menu--right { left: auto; right: 0; }
.dropdown__item {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%;
  padding: 8px 10px;
  border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  font: inherit; font-size: var(--fs-sm);
  text-align: left; cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.dropdown__item:hover { background: var(--surface-2); color: var(--text); }
.dropdown__item.is-active { color: var(--brand-2); font-weight: 600; }
.dropdown__code {
  display: inline-grid; place-items: center;
  min-width: 26px; padding: 1px 5px;
  border-radius: var(--r-xs);
  background: var(--surface-2);
  font-size: 0.65rem; font-weight: 700; letter-spacing: 0.05em;
}
.dropdown__form { margin: 0; }

@keyframes pop {
  from { opacity: 0; transform: translateY(-6px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.avatar-btn {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 4px 10px 4px 4px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text-2);
  cursor: pointer; font: inherit; font-size: var(--fs-sm);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.avatar-btn:hover { border-color: var(--border-strong); color: var(--text); }
.avatar { border-radius: 50%; display: block; }
.avatar-btn__name { max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Les trois traits font quatorze pixels de haut dans une case de trente-six :
   `place-items: center`, hérité de `.btn-icon`, ne centre rien ici — en boîte
   souple, c'est `justify-content` qui tient l'axe principal, et sa valeur par
   défaut plaquait la pile en haut. */
.nav-toggle {
  display: none;
  flex-direction: column;
  align-items: center; justify-content: center;
  gap: 4px;
}
.nav-toggle span {
  display: block; width: 16px; height: 2px;
  background: currentColor; border-radius: 2px;
  transition: transform var(--t) var(--ease), opacity var(--t);
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Le menu vit dans l'en-tête, qui est collé : ouvert, il reste à l'écran
   pendant que la page continue de défiler dessous. Le doigt posé sur le menu
   faisait donc glisser le site derrière lui — on croyait toucher le menu, on
   déplaçait la page.

   Deux règles, et il en faut deux. `overscroll-behavior: contain` retient le
   geste **quand le menu a lui-même de quoi défiler** ; il ne fait rien sur un
   panneau qui tient à l'écran, où le navigateur transmet le geste au parent
   sans même le commencer. C'est la classe `.is-nav-open` posée sur `html` qui
   traite ce cas-là, en figeant la page tant que le menu est ouvert. */
.mobile-nav {
  border-top: 1px solid var(--border);
  padding: var(--sp-3) var(--sp-5) var(--sp-5);
  animation: slideDown var(--t) var(--ease-out);
  /* Onze rubriques, « À propos » et l'inscription : sur un téléphone couché,
     la liste dépasse. `dvh` et non `vh` — la barre d'adresse d'un navigateur
     mobile se rétracte, et `vh` la compte toujours présente. */
  max-height: calc(100dvh - 4.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.mobile-nav ul { display: grid; gap: 2px; }
.mobile-nav a {
  display: block;
  padding: var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--fs-md);
}
.mobile-nav a:hover { background: var(--surface-2); color: var(--text); }
@keyframes slideDown {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* La page ne bouge plus tant que le menu est ouvert.

   **`overflow: hidden` sur `html` ne convient pas ici**, et c'est mesuré :
   `body` porte `overflow-x: hidden` pour empêcher les débordements latéraux,
   ce qui en fait un conteneur de défilement candidat. Figer `html` fait alors
   passer le défilement de l'un à l'autre — la page saute de plusieurs
   centaines de pixels à l'ouverture, l'en-tête collé décroche et le menu
   lui-même sort de l'écran.

   D'où le procédé classique : le corps est sorti du flux et remonté de la
   hauteur déjà défilée. Rien ne bouge à l'œil, rien ne défile sous le doigt,
   et la fermeture rend la position exacte — c'est le script qui la retient,
   puisque `position: fixed` la perd. */
html.is-nav-open body {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overscroll-behavior: none;
}

/* ==========================================================================
   5. Composants
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: 11px 22px;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  font: inherit; font-size: var(--fs-sm); font-weight: 600;
  cursor: pointer;
  transition: transform var(--t-fast) var(--ease-spring), box-shadow var(--t) var(--ease),
              background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn--primary {
  background: linear-gradient(100deg, var(--brand-1), var(--brand-2));
  color: #fff;
  box-shadow: 0 8px 24px -10px color-mix(in oklab, var(--brand-1) 80%, transparent);
}
.btn--primary:hover { box-shadow: 0 14px 34px -12px color-mix(in oklab, var(--brand-1) 85%, transparent); }
.btn--ghost {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text);
}
.btn--ghost:hover { border-color: var(--brand-1); color: var(--brand-2); }
.btn--sm { padding: 7px 14px; font-size: var(--fs-xs); }
.btn--block { width: 100%; }

/* Les deux voix, en bouton. Pleins tous les deux et de teintes franchement
   différentes : c'est la couleur qui doit porter la distinction, pas la
   hiérarchie plein/creux — l'une n'est pas plus importante que l'autre, elles
   ne font simplement pas la même chose. */
.btn--ask, .btn--say { color: var(--voice-ink); border-color: transparent; }
.btn--ask { background: var(--voice-ask); }
.btn--say { background: var(--voice-say); }
.btn--ask:hover { box-shadow: 0 12px 28px -12px var(--voice-ask); }
.btn--say:hover { box-shadow: 0 12px 28px -12px var(--voice-say); }

/* Le bouton qui porte le geste de la page respire. Une onde d'ombre, et non
   un déplacement : un bouton qui bouge se manque au clic, et la page en
   compte d'autres qui ne doivent pas se disputer le regard. L'ombre au repos
   du bouton principal reste dessous — la pulsation s'y ajoute, elle ne la
   remplace pas.

   Rien à prévoir pour qui demande moins d'animation : la règle globale de
   `prefers-reduced-motion` arrête toute animation de la feuille. */
@keyframes btn-pulse {
  0%   { box-shadow: 0 8px 24px -10px color-mix(in oklab, var(--brand-1) 80%, transparent),
                     0 0 0 0 color-mix(in oklab, var(--brand-1) 45%, transparent); }
  70%  { box-shadow: 0 8px 24px -10px color-mix(in oklab, var(--brand-1) 80%, transparent),
                     0 0 0 12px color-mix(in oklab, var(--brand-1) 0%, transparent); }
  100% { box-shadow: 0 8px 24px -10px color-mix(in oklab, var(--brand-1) 80%, transparent),
                     0 0 0 0 color-mix(in oklab, var(--brand-1) 0%, transparent); }
}
.btn--pulse { animation: btn-pulse 2.6s var(--ease-out) infinite; }
/* Au survol, l'onde s'efface : la main est déjà dessus, l'appel a porté. */
.btn--pulse:hover { animation: none; }

.card {
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: var(--shadow);
}
.card h3 { margin-bottom: var(--sp-2); }
.card--glow { position: relative; overflow: hidden; }
.card--glow::before {
  content: "";
  position: absolute;
  inset: -60% -20% auto -20%;
  height: 200px;
  background: radial-gradient(ellipse at 50% 0%, var(--aurora-1), transparent 70%);
  pointer-events: none;
}

.tag, .chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px;
  border-radius: var(--r-full);
  font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: 0.01em;
  background: color-mix(in oklab, var(--chip, var(--brand-1)) 18%, transparent);
  color: color-mix(in oklab, var(--chip, var(--brand-1)) 88%, var(--text));
  border: 1px solid color-mix(in oklab, var(--chip, var(--brand-1)) 32%, transparent);
}
.chip {
  transition: transform var(--t-fast) var(--ease-spring), background var(--t-fast);
}
.chip:hover { transform: translateY(-2px); background: color-mix(in oklab, var(--chip) 30%, transparent); }
.chip__count {
  padding: 0 5px;
  border-radius: var(--r-full);
  background: color-mix(in oklab, var(--chip) 30%, transparent);
  font-size: 0.65rem;
}
.topic-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-5); }

.badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: var(--r-full);
  font-size: 0.66rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  vertical-align: middle;
}
.badge--pin { background: color-mix(in oklab, var(--brand-3) 22%, transparent); color: var(--brand-3); }
.badge--lock { background: color-mix(in oklab, var(--danger) 20%, transparent); color: var(--danger); }
.badge--demo { background: color-mix(in oklab, var(--warning) 20%, transparent); color: var(--warning); }

/* Formulaires */
.field { margin-bottom: var(--sp-4); }
.field label { display: block; margin-bottom: 6px; font-size: var(--fs-sm); font-weight: 600; }
.field .hint { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--text-3); }
.field .error { margin: 6px 0 0; font-size: var(--fs-xs); color: var(--danger); }

.input, .select, .textarea {
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text);
  font: inherit; font-size: var(--fs-base);
  transition: border-color var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
}
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--brand-1);
  background: var(--surface-solid);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand-1) 22%, transparent);
  outline: none;
}
.textarea { min-height: 170px; resize: vertical; line-height: 1.7; font-family: var(--font-sans); }
.field--invalid .input, .field--invalid .textarea { border-color: var(--danger); }

/* Montrer ce qu'on tape.
 *
 * Un mot de passe de douze signes se saisit mal en aveugle, et le formulaire
 * en demande deux fois le même : sans ce bouton, la seule façon de comprendre
 * un refus de concordance est de tout retaper. Le champ garde donc son masque
 * par défaut — c'est ce qu'on attend d'un mot de passe — et le dévoile sur
 * demande explicite.
 *
 * `secret` et non `reveal` : `.reveal` est l'animation d'entrée des blocs.
 */
.secret { position: relative; display: block; }
.secret .input { padding-right: 46px; }
.secret__eye {
  position: absolute;
  top: 50%; right: 5px;
  transform: translateY(-50%);
  display: grid; place-items: center;
  width: 34px; height: 34px;
  padding: 0;
  border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-3);
  cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast);
}
.secret__eye:hover { color: var(--text-1); background: color-mix(in oklab, var(--text-1) 8%, transparent); }
.secret__eye:focus-visible { outline: 2px solid var(--brand-1); outline-offset: 1px; }
/* L'œil ouvert invite à montrer ; l'œil barré, à masquer. Ce que dessine
   l'icône est donc l'action proposée, pas l'état courant. */
.secret__eye .secret__shut { display: none; }
.secret__eye[aria-pressed="true"] { color: var(--brand-2); }
.secret__eye[aria-pressed="true"] .secret__open { display: none; }
.secret__eye[aria-pressed="true"] .secret__shut { display: block; }
/* Sans script, le bouton ne peut rien : il ne doit pas s'afficher. */
.no-js .secret__eye { display: none; }
.no-js .secret .input { padding-right: 14px; }

.checkbox { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); cursor: pointer; }
.checkbox input { width: 16px; height: 16px; accent-color: var(--brand-1); }

.form-error {
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--danger) 14%, transparent);
  border: 1px solid color-mix(in oklab, var(--danger) 34%, transparent);
  color: var(--danger);
  font-size: var(--fs-sm);
}

/* Ce qui s'est bien passé, dit du même geste que ce qui a échoué : même cadre,
   même place, une autre couleur. La confirmation d'un envoi n'est pas une
   erreur, et n'a pas à en emprunter l'apparence. */
.form-note {
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--brand-2) 12%, transparent);
  border: 1px solid color-mix(in oklab, var(--brand-2) 30%, transparent);
  color: var(--text);
  font-size: var(--fs-sm);
}

/* Le renvoi du lien de confirmation, sous le formulaire de connexion : un
   second formulaire dans le même cadre doit se lire comme un recours, pas
   comme une alternative. */
.auth-resend {
  margin: var(--sp-4) 0;
  padding: var(--sp-4);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
  background: color-mix(in oklab, var(--surface) 50%, transparent);
}
.auth-resend .field { margin-bottom: var(--sp-3); }

.flash-stack {
  position: fixed;
  top: 76px; right: var(--sp-5);
  z-index: 120;
  display: grid; gap: var(--sp-2);
  max-width: 380px;
}
.flash {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--surface-solid);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm);
  animation: flashIn var(--t-slow) var(--ease-spring);
}
.flash__icon { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.flash--success .flash__icon { background: var(--success); box-shadow: 0 0 12px var(--success); }
.flash--error .flash__icon { background: var(--danger); box-shadow: 0 0 12px var(--danger); }
@keyframes flashIn {
  from { opacity: 0; transform: translateX(30px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Révélation au défilement */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 55ms);
}
.reveal.is-visible { opacity: 1; transform: none; }
.no-js .reveal { opacity: 1; transform: none; }

/* ==========================================================================
   6. Accueil : hero et statistiques
   ========================================================================== */

.hero {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--sp-8) var(--sp-5) var(--sp-6);
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: var(--sp-7);
  align-items: end;
}
.hero__kicker {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-4);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
}
.hero__kicker::before {
  content: "";
  width: 26px; height: 1px;
  background: linear-gradient(90deg, var(--brand-1), transparent);
}
.hero__title {
  margin-bottom: var(--sp-4);
  color: var(--text);
}
.hero__lead {
  max-width: 58ch;
  color: var(--text-2);
  font-size: var(--fs-md);
  line-height: 1.72;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }

.stat-strip {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3);
}
.stat {
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: transform var(--t) var(--ease-out), border-color var(--t-fast);
}
.stat:hover { transform: translateY(-2px); border-color: var(--border-strong); }
.stat__value {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 300;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.stat__label {
  display: block;
  margin-top: 2px;
  font-size: 0.7rem;
  letter-spacing: 0.03em;
  color: var(--text-3);
}

/* Sections génériques */
/* Le rythme vertical vient de la marge, jamais du rembourrage.
   Deux sections voisines additionnaient leurs deux rembourrages de soixante-
   quatre pixels : l'écart réel valait le double de celui qu'on croyait poser,
   et toute tentative de le régler l'aggravait. */
.section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--sp-5);
}

.main > .section + .section,
.main > .page-head + .section,
.main > .section + .page-head { margin-top: var(--flow); }

/* Une page qui s'ouvre sur une section, sans titre au-dessus, n'a plus rien
   qui la décolle de l'en-tête du site : le rembourrage est parti avec le
   reste, et il faut le lui rendre en marge. L'en-tête de page porte déjà le
   sien. */
.main > .section:first-child { margin-top: var(--sp-7); }
.main > .page-head:first-child { margin-top: 0; }
.main > *:last-child { margin-bottom: var(--sp-8); }
.section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-3);
  margin-bottom: var(--sp-5);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.section__head h2 { margin: 0; }
.section__link {
  font-size: var(--fs-sm); font-weight: 600; color: var(--brand-2);
  transition: gap var(--t-fast), opacity var(--t-fast);
}
.section__link:hover { opacity: 0.75; }
.section--split {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 0.9fr);
  gap: var(--sp-6);
  align-items: start;
}
.split__aside { display: grid; gap: var(--sp-4); position: sticky; top: 84px; }

/* ==========================================================================
   7. La carte
   ========================================================================== */

.map-section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--sp-5) var(--sp-7);
}
.map-layout {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr) 370px;
  gap: var(--sp-4);
  align-items: stretch;
  /* Une seule hauteur pour les trois colonnes, donc un seul bas.
     Les deux colonnes latérales sont collantes et plafonnées à la fenêtre
     depuis toujours ; la carte, elle, prenait la hauteur de son contenu et
     changeait donc de bas selon qu'une légende s'affichait ou non. Elles
     partagent désormais la même expression, et le trio s'aligne. */
  --map-col-h: calc(100vh - 110px);
}

.mapwrap {
  position: relative;
  height: var(--map-col-h, auto);
  max-height: var(--map-col-h, none);
  /* Colonne souple : la scène prend ce qui reste une fois la légende et
     l'invite servies. Sans cela, le bas du bloc montait de cent pixels dès
     qu'aucune couche n'était active — la légende disparaissant avec elles — et
     la carte cessait de s'aligner sur les colonnes qui l'encadrent. */
  display: flex; flex-direction: column;
  height: 100%;
  border-radius: var(--r-xl);
  border: 1px solid var(--border);
  background:
    radial-gradient(ellipse 120% 90% at 50% -10%, color-mix(in oklab, var(--brand-1) 12%, transparent), transparent 65%),
    linear-gradient(180deg, var(--sea-1), var(--sea-2));
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.mapwrap__stage {
  position: relative;
  /* `min-height: 0` autorise la scène à descendre sous la hauteur naturelle du
     tracé : sans lui, un enfant de colonne souple ne se réduit jamais. */
  flex: 1 1 auto; min-height: 0;
  touch-action: none;
  cursor: grab;
}
.mapwrap__stage.is-panning { cursor: grabbing; }

.map {
  display: block;
  width: 100%;
  height: auto;
  /* Le tracé remplit la scène, quelle qu'en soit la hauteur ; le `viewBox` et
     `preserveAspectRatio` s'occupent de ne pas le déformer. La borne est celle
     du bloc, plus celle du tracé : deux plafonds concurrents s'annulaient mal. */
  height: 100%;
  transition: transform 420ms var(--ease-out);
  will-change: transform;
}
.map.is-instant { transition: none; }

.map__sea { pointer-events: none; }

.graticule {
  fill: none;
  stroke: var(--graticule);
  /* Un demi-point dans un repère de mille unités rendu sur sept cent
     cinquante pixels donne un trait de trois dixièmes de pixel : le lissage
     l'efface, et la bascule du quadrillage n'avait plus rien à montrer. */
  stroke-width: 1.5;
  pointer-events: none;
}
.graticule--parallel { stroke-dasharray: 5 8; }
[data-map-graticule][hidden] { display: none; }

.sea-label {
  fill: var(--map-label);
  opacity: 0.42;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: calc(11px * var(--w, 1));
  letter-spacing: 0.14em;
  text-anchor: middle;
  pointer-events: none;
  user-select: none;
}

.map__halo {
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--t) var(--ease), cx 380ms var(--ease-out), cy 380ms var(--ease-out);
}
.map__halo.is-on { opacity: 1; }

/* -- Pays ------------------------------------------------------------------ */
.country {
  fill: url(#landGrad);
  stroke: var(--map-stroke);
  stroke-width: 0.55;
  stroke-linejoin: round;
  cursor: pointer;
  transition: fill 260ms var(--ease), stroke 200ms var(--ease),
              stroke-width 200ms var(--ease), opacity 260ms var(--ease);
}
.country--context {
  fill: var(--land-context);
  stroke: var(--map-stroke);
  stroke-width: 0.35;
  opacity: 0.55;
  cursor: default;
  pointer-events: none;
}
.country-link { outline: none; }

.country:hover,
.country.is-hover {
  fill: url(#hoverGrad);
  stroke: var(--map-stroke-strong);
  stroke-width: 1.1;
}
.country.is-selected {
  fill: url(#hoverGrad);
  stroke: var(--brand-3);
  stroke-width: 1.5;
  filter: url(#softGlow);
}
/* Le focus se marque sur le tracé du pays, jamais par un rectangle autour de sa
   boîte englobante : sur une forme géographique, ce cadre est illisible.
   Chrome dessine son anneau sur :focus (et non :focus-visible) pour les formes
   SVG focalisables — il faut donc neutraliser les deux. */
.country-link:focus,
.country:focus,
.micro__hit:focus,
.country-link:focus-visible,
.country:focus-visible,
.micro__hit:focus-visible { outline: none; }

/* Indicateur de focus au clavier, conservé pour l'accessibilité. */
.country-link:focus-visible .country,
.country:focus-visible {
  stroke: var(--brand-2);
  stroke-width: 2;
  filter: url(#softGlow);
}
.micro__hit:focus-visible ~ .micro__dot,
.micro:focus-within .micro__dot {
  stroke: var(--brand-2);
  stroke-width: 1.6;
}
/* Estompage des pays non concernés lorsqu'une couche filtre la carte */
.map--filtered .country:not(.is-match):not(.country--context) {
  opacity: 0.24;
  fill: var(--land-2);
}

/* États de couche : la teinte est injectée par le script */
/* Trois états, trois aspects : teinte pleine, teinte pâle, trame oblique.
   L'opacité ne suffisait pas — deux pâleurs voisines de la même couleur ne se
   distinguent ni sur la carte ni dans la légende. */
.country.layer-in      { fill: var(--layer-fill, url(#landGrad)); }
.country.layer-partial { fill: var(--layer-fill, url(#landGrad)); }
.country.layer-pending { fill: var(--layer-fill, url(#landGrad)); }

.map__hatch-bg { fill: var(--hatch-bg, transparent); }
.map__hatch-fg { stroke: var(--hatch-fg, currentColor); }
.country.layer-hatched { fill: var(--layer-fill, url(#landGrad)); }

/* Couche « familles politiques » : l'opacité traduit l'écart entre la première
   et la deuxième famille du pays. Un pays franchement dominé ressort net, un
   pays disputé apparaît atténué. */
.country.layer-composition { opacity: var(--layer-opacity, 1); }

.map__hint.is-highlight {
  color: var(--brand-2);
  font-weight: 600;
}

/* -- Micro-États ----------------------------------------------------------- */
.micro__dot {
  fill: var(--brand-3);
  stroke: var(--map-shadow);
  stroke-width: 0.9;
  transition: r var(--t) var(--ease-spring), fill var(--t);
}
.micro__hit { fill: transparent; cursor: pointer; }
.micro:hover .micro__dot,
.micro.is-selected .micro__dot { r: 6.4; fill: var(--brand-2); }

/* -- Étiquettes ------------------------------------------------------------ */
.country-label {
  fill: var(--map-label);
  font-family: var(--font-sans);
  /* Le plancher comptait plus que le plafond : la moitié des noms tombaient à
     cinq pixels de haut à l'écran, ce qui n'est plus de la lecture. */
  font-size: clamp(8px, calc(5.4px + var(--area) / 1750 * 1px), 16px);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-anchor: middle;
  paint-order: stroke;
  stroke: var(--map-label-halo);
  stroke-width: 3.2px;
  stroke-linejoin: round;
  pointer-events: none;
  user-select: none;
  transition: opacity var(--t) var(--ease);
}
[data-map-labels][hidden] { display: none; }

.capital circle { fill: var(--brand-3); stroke: var(--map-label-halo); stroke-width: 0.6; }
.capital text {
  fill: var(--map-label);
  font-size: 7.6px;
  font-weight: 600;
  paint-order: stroke;
  stroke: var(--map-label-halo);
  stroke-width: 2.6px;
}
[data-map-capitals][hidden] { display: none; }

/* -- Pastilles d'actualité -------------------------------------------------- */
.pulse { pointer-events: none; }
.pulse__core { fill: var(--accent); }
.pulse__ring {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  opacity: 0;
  /* Sans transform-box, une transformation CSS sur un élément SVG s'applique
     autour du centre du viewBox : les anneaux dériveraient dans l'océan. */
  transform-box: fill-box;
  transform-origin: center;
  animation: pulseRing 3.4s var(--ease-out) infinite;
  animation-delay: var(--d, 0s);
}
@keyframes pulseRing {
  0%   { opacity: 0.85; transform: scale(0.4); }
  70%  { opacity: 0;    transform: scale(2.4); }
  100% { opacity: 0;    transform: scale(2.4); }
}
[data-map-pulses][hidden] { display: none; }

/* -- Réseaux et flux -------------------------------------------------------- */
.netline {
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  opacity: 0;
  animation: fadeIn 420ms var(--ease-out) forwards;
  filter: drop-shadow(0 0 3px currentColor);
}
.netline--gas { stroke: #f59e0b; color: #f59e0b; }
.netline--oil { stroke: #a16207; color: #a16207; }
.netline--power { stroke: #3b82f6; color: #3b82f6; }
.netline--active { stroke-dasharray: 6 5; animation: fadeIn 420ms var(--ease-out) forwards, dash 2.4s linear infinite; }
.netline--reduced { stroke-dasharray: 3 6; opacity: 0.75; }
.netline--offline { stroke-dasharray: 1 6; opacity: 0.5; }
.netline--planned { stroke-dasharray: 2 8; opacity: 0.6; }
@keyframes dash { to { stroke-dashoffset: -44; } }
@keyframes fadeIn { to { opacity: 1; } }

.netpoint {
  fill: var(--brand-2);
  stroke: var(--map-label-halo);
  stroke-width: 0.7;
  opacity: 0;
  animation: popIn 420ms var(--ease-spring) forwards;
  animation-delay: calc(var(--i, 0) * 22ms);
}
.netpoint--heritage { fill: var(--brand-3); }
.netpoint--heritage.era-christianity { fill: #a78bfa; }
.netpoint--heritage.era-judaism { fill: #38bdf8; }
.netpoint--heritage.era-humanism { fill: #34d399; }
@keyframes popIn { to { opacity: 1; } }

.flowarc {
  fill: none;
  stroke: var(--accent);
  stroke-linecap: round;
  opacity: 0;
  stroke-dasharray: 5 7;
  animation: fadeIn 500ms var(--ease-out) forwards, dash 2.8s linear infinite;
  filter: drop-shadow(0 0 4px var(--accent));
}
.flowarc--newslink { stroke: color-mix(in oklab, var(--accent) 70%, var(--brand-1)); }
.flowarc--reduced { opacity: 0.55; }

/* -- Contrôles et infobulle -------------------------------------------------- */
.map__controls {
  position: absolute;
  top: var(--sp-4); right: var(--sp-4);
  display: grid; gap: 4px;
  z-index: 5;
}
.map-btn {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--surface-solid) 82%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text-2);
  font-size: var(--fs-sm); font-weight: 700;
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast), transform var(--t-fast) var(--ease-spring);
}
.map-btn:hover { color: var(--brand-2); border-color: var(--brand-1); transform: scale(1.08); }
.map-btn[aria-pressed="true"] { color: var(--brand-3); border-color: color-mix(in oklab, var(--brand-3) 50%, transparent); }

.map__hint {
  margin: 0;
  padding: var(--sp-2) var(--sp-4) var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--text-3);
  text-align: center;
}

.map__tooltip {
  position: absolute;
  z-index: 8;
  padding: 8px 12px;
  min-width: 130px;
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--surface-solid) 94%, transparent);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-xs);
  pointer-events: none;
  transform: translate(-50%, -130%);
  animation: pop 160ms var(--ease-out);
}
.map__tooltip strong { display: block; font-size: var(--fs-sm); font-weight: 600; letter-spacing: -0.01em; }
.map__tooltip .tt-line { color: var(--text-3); display: block; }
.map__tooltip .tt-layer { color: var(--brand-2); display: block; margin-top: 3px; }

/* La légende se pose sous la carte, elle ne la recouvre plus.
 *
 * En surimpression au coin sud-ouest, elle mangeait la péninsule Ibérique et le
 * Maghreb — précisément la zone qu'une couche « appartenances » ou « flux »
 * donne à lire. Sur un écran large la place est libre : la carte ne descend pas
 * jusqu'au bas des colonnes qui l'encadrent. Elle devient donc une bande, et
 * ses blocs se rangent en ligne au lieu de s'empiler dans 250 pixels. */
.map__legend {
  position: static;
  max-width: none;
  padding: var(--sp-4) var(--sp-5);
  border: 0; border-top: 1px solid var(--border);
  border-radius: 0;
  background: color-mix(in oklab, var(--surface-solid) 72%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: none;
  font-size: var(--fs-xs);
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: var(--sp-4) var(--sp-5);
  /* Pas d'animation d'apparition : elle servait à faire surgir un encart posé
     sur la carte. Une bande en flux n'a rien à faire surgir — et un élément
     dont l'aspect au repos dépend d'une animation menée à son terme se
     retrouve figé sur sa première image partout où les animations ne tournent
     pas, onglet en arrière-plan compris. */
}
.map__legend h4 { margin: 0 0 6px; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-3); }
.map__legend + .map__legend { display: none; }
.legend-row { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.legend-swatch { width: 14px; height: 10px; border-radius: 3px; flex-shrink: 0; border: 1px solid var(--border); }
.legend-line { width: 16px; height: 2px; border-radius: 2px; flex-shrink: 0; }
.legend-scale { height: 10px; border-radius: 4px; margin: 4px 0; }
.legend-scale__labels { display: flex; justify-content: space-between; color: var(--text-3); }

/* Un bloc par couche active, côte à côte, séparés d'un filet vertical. */
.legend-block { flex: 0 1 auto; min-width: 160px; max-width: 280px; }
.legend-block + .legend-block {
  padding-left: var(--sp-5);
  border-left: 1px solid var(--border);
}

/* ==========================================================================
   8. Rail de couches et tableau de bord
   ========================================================================== */

.layer-rail {
  position: sticky; top: 84px;
  max-height: var(--map-col-h, calc(100vh - 110px));
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  overflow: hidden;
}
.layer-rail__head { padding: var(--sp-4); border-bottom: 1px solid var(--border); }
.layer-rail__head h3 { margin: 0 0 2px; font-size: var(--fs-md); }
.layer-rail__head p { margin: 0; font-size: var(--fs-xs); color: var(--text-3); }
.layer-rail__body { flex: 1; overflow-y: auto; padding: var(--sp-2); }
.layer-rail__more {
  display: block; padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs); font-weight: 600; color: var(--brand-2);
}
/* Le pied du rail est devenu un bouton : il lui faut les mises à zéro d'usage. */
.layer-rail__clear {
  width: 100%; text-align: left;
  background: none; border: 0; border-top: 1px solid var(--border);
  font-family: inherit; cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast);
}
.layer-rail__clear:hover { color: var(--text); background: var(--surface-2); }

.layer-group { border-radius: var(--r-sm); margin-bottom: 2px; }
.layer-group > summary {
  display: flex; align-items: center; justify-content: space-between;
  padding: 9px 10px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-2);
  cursor: pointer;
  list-style: none;
  transition: background var(--t-fast), color var(--t-fast);
}
.layer-group > summary::-webkit-details-marker { display: none; }
.layer-group > summary::before {
  content: "▸";
  margin-right: 7px;
  font-size: 0.7em;
  color: var(--text-3);
  transition: transform var(--t) var(--ease);
}
.layer-group[open] > summary::before { transform: rotate(90deg); }
.layer-group > summary:hover { background: var(--surface-2); color: var(--text); }
.layer-group__count {
  padding: 0 6px; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-3);
  font-size: 0.65rem;
}
.layer-group__note { margin: 2px 10px 8px 34px; font-size: 0.68rem; color: var(--text-3); }
.layer-group--single { padding-top: var(--sp-2); margin-top: var(--sp-2); border-top: 1px solid var(--border); }

.layer-list { padding: 2px 0 6px; }
.layer-item {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px 7px 12px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.layer-item:hover { background: var(--surface-2); color: var(--text); }
.layer-item input { position: absolute; opacity: 0; pointer-events: none; }
.layer-item__swatch {
  width: 16px; height: 16px; flex-shrink: 0;
  border-radius: 5px;
  background: linear-gradient(135deg, var(--c1), var(--c2));
  opacity: 0.42;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease-spring), box-shadow var(--t);
}
.layer-item input:checked ~ .layer-item__swatch {
  opacity: 1;
  transform: scale(1.14);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--c1) 40%, transparent), inset 0 0 0 1px rgba(255,255,255,0.3);
}
.layer-item input:checked ~ .layer-item__label { color: var(--text); font-weight: 600; }
.layer-item input:focus-visible ~ .layer-item__swatch { outline: 2px solid var(--brand-2); outline-offset: 2px; }
.layer-item__label { line-height: 1.3; }

/* -- Tableau de bord -------------------------------------------------------- */
.dashboard {
  position: sticky; top: 84px;
  max-height: var(--map-col-h, calc(100vh - 110px));
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  overflow: hidden;
  box-shadow: var(--shadow);
}
.dashboard__empty {
  display: grid; place-items: center; gap: var(--sp-4);
  padding: var(--sp-8) var(--sp-5);
  text-align: center;
  color: var(--text-3);
  min-height: 320px;
}
.dashboard__empty-art { color: var(--brand-1); opacity: 0.5; }
.dashboard__star {
  transform-origin: 60px 60px;
  animation: twinkle 5s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.22s);
}
.dashboard__empty p { margin: 0; font-size: var(--fs-sm); max-width: 26ch; }

.dashboard__panel { overflow-y: auto; animation: panelIn 420ms var(--ease-out); }
@keyframes panelIn {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: none; }
}

.dpanel__head {
  position: sticky; top: 0; z-index: 2;
  padding: var(--sp-4);
  background: linear-gradient(160deg,
    color-mix(in oklab, var(--brand-1) 22%, var(--surface-solid)),
    var(--surface-solid));
  border-bottom: 1px solid var(--border);
}
.dpanel__flag { font-size: 2rem; line-height: 1; }
.dpanel__title { display: flex; align-items: center; gap: var(--sp-3); }
.dpanel__title h3 { margin: 0; font-size: var(--fs-lg); }
.dpanel__title small { display: block; font-size: var(--fs-xs); color: var(--text-3); font-family: var(--font-sans); }
.dpanel__close {
  position: absolute; top: 10px; right: 10px;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--surface-2); color: var(--text-2);
  cursor: pointer; font-size: 1rem; line-height: 1;
  transition: color var(--t-fast), transform var(--t-fast) var(--ease-spring);
}
.dpanel__close:hover { color: var(--danger); transform: rotate(90deg); }

.dpanel__body { padding: var(--sp-4); display: grid; gap: var(--sp-5); }
.dpanel__section > h4 {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-sans);
  font-size: 0.68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.11em;
  color: var(--text-3);
}
.dpanel__summary { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--text-2); }

.kv-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
.kv {
  padding: 9px 11px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.kv dt { font-size: 0.66rem; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.06em; }
.kv dd { margin: 2px 0 0; font-size: var(--fs-sm); font-weight: 600; font-variant-numeric: tabular-nums; }

.pill-list { display: grid; gap: 5px; }
.pill {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: 7px 11px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: var(--fs-xs);
}
.pill__label { display: flex; align-items: center; gap: 7px; font-weight: 600; }
.pill__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.pill--in .pill__dot { background: var(--success); box-shadow: 0 0 8px var(--success); }
.pill--out .pill__dot { background: var(--text-3); }
.pill--partial .pill__dot { background: var(--warning); box-shadow: 0 0 8px var(--warning); }
.pill--pending .pill__dot { background: var(--brand-2); box-shadow: 0 0 8px var(--brand-2); }
.pill__detail { color: var(--text-3); }

.party-bar {
  display: flex; height: 12px;
  border-radius: var(--r-full);
  overflow: hidden;
  border: 1px solid var(--border);
  margin-bottom: var(--sp-3);
}
.party-bar span {
  display: block; height: 100%;
  transform-origin: left;
  animation: growX 700ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 60ms);
}
@keyframes growX { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.party-list { display: grid; gap: 4px; }
.party-row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto auto;
  align-items: center; gap: 8px;
  font-size: var(--fs-xs);
  padding: 3px 0;
}
.party-row__dot { width: 10px; height: 10px; border-radius: 3px; }
.party-row__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.party-row__share { color: var(--text-3); font-variant-numeric: tabular-nums; }
.party-row__seats { font-weight: 700; font-variant-numeric: tabular-nums; }

.dpanel__list { display: grid; gap: 2px; }
.dpanel__item {
  display: block;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  transition: background var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
}
.dpanel__item:hover { background: var(--surface-2); border-color: var(--border); transform: translateX(3px); }
.dpanel__item strong { display: block; font-size: var(--fs-sm); font-weight: 600; line-height: 1.35; }
.dpanel__item small { color: var(--text-3); font-size: 0.68rem; }

.dpanel__mini-timeline { display: grid; gap: 3px; }
.mini-event {
  display: grid; grid-template-columns: 62px minmax(0, 1fr);
  gap: var(--sp-2); align-items: baseline;
  font-size: var(--fs-xs);
  padding: 3px 0;
  border-left: 2px solid var(--border);
  padding-left: var(--sp-3);
  margin-left: 4px;
  transition: border-color var(--t-fast);
}
.mini-event:hover { border-color: var(--brand-2); }
.mini-event time { color: var(--brand-3); font-variant-numeric: tabular-nums; font-weight: 700; }

.dpanel__actions { display: grid; gap: 6px; padding: var(--sp-4); border-top: 1px solid var(--border); }

.mini-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); margin: var(--sp-4) 0; }
.mini-stats dt { font-size: var(--fs-xs); color: var(--text-3); }
.mini-stats dd { margin: 0; font-size: var(--fs-lg); font-weight: 300; letter-spacing: -0.025em; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   9. Actualités
   ========================================================================== */

.news-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--sp-4);
}
.news-card {
  position: relative;
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  overflow: hidden;
  transition: transform var(--t) var(--ease-out), border-color var(--t-fast), box-shadow var(--t);
}
.news-card::after {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(600px circle at var(--mx, 50%) var(--my, 0%),
              color-mix(in oklab, var(--brand-1) 12%, transparent), transparent 42%);
  opacity: 0; transition: opacity var(--t) var(--ease);
  pointer-events: none;
}
.news-card:hover { transform: translateY(-5px); border-color: var(--border-strong); box-shadow: var(--shadow-lg); }
.news-card:hover::after { opacity: 1; }
.news-card--featured { grid-column: span 2; }
.news-card--featured .news-card__title { font-size: var(--fs-xl); }

.news-card__head {
  --row-h: 20px;
  display: flex; align-items: center; align-content: flex-start; flex-wrap: wrap;
  gap: var(--sp-2);
  height: calc(2 * var(--row-h) + 6px);
  overflow: hidden;
}
.news-card__head > * {
  display: inline-flex; align-items: center;
  height: var(--row-h); line-height: 1;
}
.news-card__scope {
  font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-3);
}
.news-card__scope--european { color: var(--brand-2); }

/* L'explication accompagne l'étiquette sur la page d'un article, et nulle part
   ailleurs : sur une vignette, elle prendrait plus de place que le titre. Elle
   se lit comme une glose — même ligne, ton plus bas — et non comme un second
   intitulé qui entrerait en concurrence avec le premier. */
.article__scope-help {
  font-size: var(--fs-xs);
  color: var(--text-3);
  font-style: italic;
}
.news-card__date { margin-left: auto; font-size: var(--fs-xs); color: var(--text-3); }
.news-card__title {
  --lh: 21px;
  margin: 0; font-size: var(--fs-md); line-height: var(--lh);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
  height: calc(3 * var(--lh));
}
.news-card__link:hover .news-card__title { color: var(--brand-2); }
.news-card__summary {
  --lh: 21px;
  margin: 0; font-size: var(--fs-sm); color: var(--text-2); line-height: var(--lh);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(3 * var(--lh));
}
.news-card__meta { margin: 0; font-size: var(--fs-xs); color: var(--text-3); }

/* En bas à droite de la vignette. `margin-top: auto` la pousse au bas de la
   colonne quelle que soit la hauteur du titre — sans quoi elle flotterait
   sous le résumé, à une hauteur différente d'une carte à l'autre, et la
   grille perdrait sa ligne de base. */
/* Une seule ligne au pied de la vignette : les pays à gauche, ce qui s'est dit
   à droite. `margin-top: auto` est porté par la rangée, plus par ses deux
   contenus — sinon chacun se calerait au bas de son côté, et deux drapeaux qui
   passent à la ligne décaleraient la mention de commentaires. */
.news-card__foot {
  margin-top: auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
}
.news-card__foot .flag-row { margin-top: 0; }

.news-card__comments {
  /* Poussée à droite d'elle-même : sans drapeau en face, `space-between`
     laisserait la mention à gauche. */
  margin-left: auto;
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  color: var(--text-3);
  text-decoration: none;
  display: inline-flex; align-items: center; gap: 5px;
}
/* La bulle est dessinée, non écrite : une émoji varierait d'un système à
   l'autre, et un caractère typographique ne se colorerait pas avec le texte. */
.news-card__comments::before {
  content: "";
  width: 12px; height: 11px;
  border: 1.5px solid currentColor;
  border-radius: 3px 3px 3px 0;
  opacity: 0.7;
}
.news-card__comments:hover { color: var(--brand-2); text-decoration: underline; }

.flag-row { display: flex; flex-wrap: wrap; gap: 5px; margin-top: auto; }
.flag-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px;
  border-radius: var(--r-full);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 0.66rem; font-weight: 600;
  color: var(--text-2);
  transition: border-color var(--t-fast), color var(--t-fast), transform var(--t-fast) var(--ease-spring);
}
.flag-pill:hover { border-color: var(--brand-1); color: var(--brand-2); transform: translateY(-2px); }
.flag-pill__flag { font-size: 0.85rem; line-height: 1; }
.flag-row__more { font-size: 0.66rem; color: var(--text-3); align-self: center; }

/* Le bloc de filtres est un outil, pas un contenu : il précède ce qu'on est
   venu lire et ne doit pas lui disputer la place. D'où des commandes moins
   hautes que celles d'un formulaire qu'on remplit — on ne saisit ici qu'un mot
   ou deux —, un gouttière et une marge resserrées, et un seuil de repli plus
   bas, qui laisse tenir trois commandes de front là où deux se partageaient la
   largeur. */
.news-filters {
  /* `stretch` plutôt que `center` : chaque commande prend la hauteur de la plus
     haute de sa ligne. Un `input`, un `select` et un bouton peint ne calculent
     pas la même hauteur pour un même texte, et fixer un nombre les alignerait
     jusqu'au jour où la police change. */
  display: flex; flex-wrap: wrap; align-items: stretch;
  gap: var(--sp-2);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.news-filters .select, .news-filters .input, .news-filters .fsel
  { width: auto; min-width: 132px; flex: 1 1 132px; }
/* `.fsel__btn` n'est pas un `.select` : le sélecteur de pays est un bouton
   peint, et l'oublier ici le laisserait quatre pixels plus haut que ses
   voisins — assez pour que la ligne paraisse de travers. */
/* `line-height` explicite : à hauteur de police égale, un `select` calcule sa
   ligne autrement qu'un `input` — trois pixels d'écart, invisibles isolément,
   très visibles quand les deux se touchent. */
.news-filters .input,
.news-filters .select,
.news-filters .fsel__btn { padding: 7px 11px; font-size: var(--fs-sm); line-height: 1.5; }
/* Le sélecteur de pays est un `div` qui porte un bouton : l'étirement s'arrête
   au `div` si le bouton ne le suit pas. */
.news-filters .fsel__btn { height: 100%; }

/* Le compte des résultats, sous les commandes qui l'ont produit. */
.news-count {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-sm); color: var(--text-3);
}
.news-filters .btn { padding: 7px var(--sp-4); font-size: var(--fs-sm); }

/* Deux colonnes : la lecture au centre, ce qui l'entoure à droite — le même
   partage que sur une pétition ou un événement d'histoire.

   `.article` gardait `max-width: 820px; margin: 0 auto`, ce qui suffisait tant
   qu'il était seul. Dans une grille, la marge automatique le centrerait dans sa
   colonne et laisserait un vide entre le texte et la colonne latérale : la
   largeur devient donc un maximum, sans centrage. */
.article__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-6);
  align-items: start;
}
.article { max-width: 820px; }

/* Collée pendant la lecture : « À lire aussi » sert au moment où l'on hésite,
   pas une fois qu'on est arrivé au bas. Le décalage suit la hauteur réelle de
   l'en-tête, mesurée par le script. */
.article__side {
  position: sticky;
  top: calc(var(--header-h, 64px) + var(--sp-4));
  display: grid;
  gap: var(--sp-4);
}
.article__side-title { font-size: var(--fs-md); margin-bottom: var(--sp-3); }

/* Les cartes s'empilent : dans une colonne de 340 pixels, une grille de
   vignettes les réduirait à des timbres. */
.article__related { display: grid; gap: var(--sp-3); }
.article__head { margin-bottom: var(--sp-5); }
.article__title { margin-bottom: var(--sp-3); }
.article__meta {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  font-size: var(--fs-sm); color: var(--text-3);
  padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.article__lead { font-size: var(--fs-md); color: var(--text-2); }
.article__body { font-size: var(--fs-md); line-height: 1.8; }
.article__body p { margin-bottom: var(--sp-4); }
.notice {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px dashed var(--border-strong);
  background: var(--surface-2);
  font-size: var(--fs-xs);
  color: var(--text-3);
  margin-bottom: var(--sp-5);
}

/* ==========================================================================
   10. Forum
   ========================================================================== */

/* -- Blocs de discussion ----------------------------------------------------- */

.tcard-list { display: grid; gap: var(--sp-3); }
.tcard-list--grid { grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); }

.tcard {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  overflow: hidden;
  transition: transform var(--t) var(--ease-out), border-color var(--t-fast), box-shadow var(--t);
}
.tcard::before {
  content: "";
  position: absolute; inset: 0 auto 0 0; width: 2px;
  background: linear-gradient(180deg, var(--rail), transparent 70%);
  opacity: 0.85;
}
.tcard:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}
.tcard__link { display: block; }

.tcard__top {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 var(--sp-2);
  font-size: 0.7rem;
  color: var(--text-3);
}
.tcard__flag { font-size: 0.85rem; }
.tcard__cat { color: color-mix(in oklab, var(--rail) 75%, var(--text-2)); font-weight: 600; }
.tcard__origin {
  padding: 1px 7px;
  border-radius: var(--r-full);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.tcard__time { margin-left: auto; }

.tcard__title {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.32;
}
.tcard:hover .tcard__title { color: var(--brand-2); }

/* Résumé automatique : signalé comme tel, jamais confondu avec un message. */
.tcard__summary {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-2);
}
.tcard__ai {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 7px;
  border-radius: var(--r-full);
  background: color-mix(in oklab, var(--brand-2) 14%, transparent);
  border: 1px solid color-mix(in oklab, var(--brand-2) 30%, transparent);
  color: var(--brand-2);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  vertical-align: 1px;
  cursor: help;
}

.tcard__foot {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.tcard__count { white-space: nowrap; }
.tcard__join {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 600;
  color: var(--brand-2);
  white-space: nowrap;
  transition: gap var(--t-fast) var(--ease);
}
.tcard:hover .tcard__join { gap: 9px; }

.avatar-stack { display: inline-flex; }
.avatar-stack img,
.avatar-stack .avatar-link {
  border-radius: 50%;
  border: 2px solid var(--surface-solid);
  margin-left: -8px;
}
.avatar-stack img { display: block; border: 0; margin: 0; border-radius: 50%; }
.avatar-stack > :first-child { margin-left: 0; }

/**
 * L'avatar d'un membre mène à son profil. C'est le seul chemin depuis que
 * l'annuaire a été retiré : il doit donc se voir cliquable, sans pour autant
 * prendre le pas sur le texte qu'il accompagne.
 */
.avatar-link {
  display: inline-block; flex-shrink: 0;
  border-radius: 50%;
  line-height: 0;
  transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast);
}
.avatar-link:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--brand-1) 55%, transparent);
}
.avatar-link:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 2px;
}

.thread-summary {
  margin: var(--sp-3) 0 var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: var(--fs-sm);
  line-height: 1.65;
  color: var(--text-2);
}
.thread-summary__date { color: var(--text-3); font-size: var(--fs-xs); }

/* -- Profils de membre --------------------------------------------------------- */

.member-head { display: flex; gap: var(--sp-4); align-items: flex-start; }
.member-head__avatar { border-radius: 50%; border: 1px solid var(--border); flex-shrink: 0; }
.member-head h1 { font-size: var(--fs-2xl); margin-bottom: 4px; }
.member-head__handle { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); color: var(--text-3); }
.member-head__handle a { color: var(--brand-2); }
.member-head__bio { margin: 0; color: var(--text-2); max-width: 60ch; }

.member-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: var(--sp-4); }
.member-card {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast),
              box-shadow var(--t-fast);
}
.member-card:hover {
  transform: translateY(-2px);
  border-color: var(--brand-1);
  box-shadow: var(--shadow);
}
.member-card__top { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.member-card img { border-radius: 50%; border: 1px solid var(--border); flex-shrink: 0; }
.member-card__body { display: grid; min-width: 0; }
.member-card__name { font-weight: 600; font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; }
.member-card__meta { font-size: 0.68rem; color: var(--text-3); }
.member-card__bio {
  font-size: var(--fs-sm); color: var(--text-2); line-height: 1.5;
}
.member-card__last {
  display: grid; gap: 2px;
  margin-top: auto;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm); color: var(--text-2);
}
.member-card__label {
  font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-3);
}

.member-petitions { display: grid; gap: var(--sp-3); margin-top: var(--sp-2); }
.member-petitions li { display: grid; gap: 2px; font-size: var(--fs-sm); }
.member-petitions__meta { font-size: 0.68rem; color: var(--text-3); }

.member-posts { display: grid; gap: var(--sp-4); }
.member-post {
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.member-post__thread {
  display: block; margin-bottom: var(--sp-2);
  font-size: var(--fs-xs); font-weight: 600; color: var(--brand-2);
}
.member-post__meta { margin: var(--sp-2) 0 0; font-size: var(--fs-xs); color: var(--text-3); }

/* -- Orientation politique estimée ---------------------------------------------- */

.politics__head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.politics__head h3 { margin: 0; flex: 1; font-size: var(--fs-md); }
.badge--private {
  background: color-mix(in oklab, var(--text-3) 22%, transparent);
  color: var(--text-2);
}

.politics__family {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-sm);
}
.politics__dot { width: 10px; height: 10px; border-radius: 3px; }
.politics__confidence { color: var(--text-3); font-size: var(--fs-xs); }

/* Boussole à deux axes : économique en abscisse, européen en ordonnée. */
.compass {
  position: relative;
  aspect-ratio: 1;
  width: 100%;
  max-width: 230px;
  margin: 0 auto var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background:
    linear-gradient(var(--grid-line) 1px, transparent 1px) 0 0 / 25% 25%,
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px) 0 0 / 25% 25%,
    var(--surface-2);
}
.compass__axis { position: absolute; background: var(--border-strong); }
.compass__axis--h { left: 0; right: 0; top: 50%; height: 1px; }
.compass__axis--v { top: 0; bottom: 0; left: 50%; width: 1px; }
.compass__point {
  position: absolute;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  background: var(--c, var(--brand-1));
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--c, var(--brand-1)) 25%, transparent);
  animation: popIn 500ms var(--ease-spring) both;
}
.compass__label {
  position: absolute;
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}
.compass__label--top { top: 5px; left: 50%; transform: translateX(-50%); }
.compass__label--bottom { bottom: 5px; left: 50%; transform: translateX(-50%); }
.compass__label--left { left: 6px; top: 50%; transform: translateY(-50%) rotate(-90deg); transform-origin: left center; }
.compass__label--right { right: 6px; top: 50%; transform: translateY(-50%) rotate(90deg); transform-origin: right center; }

.politics__summary { margin: 0 0 var(--sp-3); font-size: var(--fs-sm); color: var(--text-2); }
.politics__meta { margin: 0 0 var(--sp-2); font-size: var(--fs-xs); color: var(--text-3); }
.politics__disclaimer {
  margin: 0;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: 0.68rem;
  line-height: 1.55;
  color: var(--text-3);
}

.rule { border: 0; border-top: 1px solid var(--border); margin: var(--sp-5) 0 var(--sp-4); }
.fieldset { border: 0; padding: 0; margin-bottom: var(--sp-4); }
.fieldset legend { padding: 0; margin-bottom: 6px; font-size: var(--fs-sm); font-weight: 600; }
.fieldset .checkbox { margin-bottom: 4px; }
.fieldset[disabled], .fieldset.is-disabled { opacity: 0.45; }

/* -- Indicateurs de communauté ------------------------------------------------ */

/* Les six indicateurs tiennent sur une seule ligne : ils se lisent d'un coup
   d'œil, et les répartir sur deux rangs en ferait deux groupes qu'on
   comparerait l'un à l'autre sans raison.
   `minmax(0, 1fr)` et non une largeur plancher : à six, un plancher de cent
   trente pixels replierait la ligne bien avant que la requête de média ne
   s'en charge, et sans qu'on sache pourquoi.

   Six est un maximum, pas un acquis : la vue tait ceux qui n'ont rien à dire —
   un site qui ouvre n'a ni discussion ni membre — et pose le compte réel dans
   `--kpi-*`. Six colonnes pour deux cartes laisseraient quatre trous. Les
   valeurs de repli servent au cas où le style se lit sans la vue. */
.kpi-strip {
  display: grid;
  grid-template-columns: repeat(var(--kpi-wide, 6), minmax(0, 1fr));
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}
@media (max-width: 1000px) {
  .kpi-strip { grid-template-columns: repeat(var(--kpi-mid, 3), minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .kpi-strip { grid-template-columns: repeat(var(--kpi-narrow, 2), minmax(0, 1fr)); }
}
/* Un indicateur porte une amorce colorée : quatre encadrés gris alignés se
   lisent comme un tableau, et un tableau ne se regarde pas. La couleur tourne
   avec le rang pour que la rangée forme une progression plutôt qu'une répétition. */
.kpi {
  position: relative;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
}
.kpi::before {
  content: '';
  position: absolute; top: 0; left: 0; width: 34px; height: 2px;
  background: var(--brand-2);
  border-radius: 0 0 2px 0;
}
.kpi:nth-child(2n)::before   { background: var(--brand-1); }
.kpi:nth-child(3n)::before   { background: var(--brand-3); }
.kpi__value {
  display: block;
  font-size: var(--fs-xl);
  font-weight: 300;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.kpi__label { display: block; margin-top: 2px; font-size: 0.7rem; color: var(--text-3); }

.section__hook {
  max-width: 68ch;
  margin: calc(var(--sp-3) * -1) 0 var(--sp-5);
  color: var(--text-2);
}

/* -- Pétitions citoyennes ----------------------------------------------------- */

.page-head__actions {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-top: var(--sp-4);
}

/* Jauge de progression : une seule variable, --p, porte le remplissage. */
.gauge {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: var(--surface-3, var(--surface-2));
  border: 1px solid var(--border);
  overflow: hidden;
}
.gauge--lg { height: 12px; }
.gauge__fill {
  display: block;
  height: 100%;
  width: var(--p, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--brand-1), var(--brand-2));
  transform-origin: left center;
  animation: gaugeIn 900ms var(--ease-out) both;
}
@keyframes gaugeIn { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.pcard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--sp-4);
}
.pcard {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast),
              box-shadow var(--t-fast);
}
.pcard:hover { transform: translateY(-2px); border-color: var(--brand-1); box-shadow: var(--shadow); }
.pcard.is-closed { opacity: 0.72; }
.pcard__link { display: grid; gap: var(--sp-2); color: inherit; }
/* Même règle que sur les tribunes : les rangées qui précèdent un titre ont une
   hauteur posée, sans quoi une étiquette de plus décale le titre d'un rang et
   la grille se lit de travers. */
.pcard__meta {
  --row-h: 22px;
  display: flex; flex-wrap: wrap; align-items: center; align-content: flex-start;
  gap: var(--sp-2);
  font-size: 0.7rem; color: var(--text-3);
  height: calc(2 * var(--row-h) + 6px);
  overflow: hidden;
}
.pcard__meta > * {
  display: inline-flex; align-items: center;
  height: var(--row-h); line-height: 1;
}
.pcard__kind {
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.62rem; letter-spacing: 0.07em; text-transform: uppercase;
  border: 1px solid var(--border);
}
.pcard__kind--eci {
  color: var(--brand-1);
  border-color: color-mix(in oklab, var(--brand-1) 45%, transparent);
  background: color-mix(in oklab, var(--brand-1) 12%, transparent);
}
.pcard__title {
  --lh: 25px;
  font-size: var(--fs-lg); line-height: var(--lh);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  height: calc(2 * var(--lh));
}
.pcard__summary {
  --lh: 21px;
  font-size: var(--fs-sm); color: var(--text-2); line-height: var(--lh);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(3 * var(--lh));
}
.pcard__progress { margin-top: auto; display: grid; gap: var(--sp-2); }
.pcard__numbers { display: flex; align-items: baseline; gap: 6px; font-size: var(--fs-sm); }
.pcard__numbers strong { font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }
.pcard__numbers span { color: var(--text-3); }
.pcard__foot { display: flex; flex-wrap: wrap; gap: 6px; }
.pcard__chip {
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.66rem;
  color: var(--text-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.pcard__chip--time { color: var(--text-2); }
.pcard__chip--closed { opacity: 0.8; }
.pcard__actions { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.pcard__origin { font-size: 0.72rem; color: var(--text-3); }
.pcard__origin:hover { color: var(--brand-2); }

/* Page d'une pétition */
/* Le même gabarit sur une pétition et sur un débat : à gauche ce qu'on lit et
   ce qu'on écrit, à droite ce qu'on en fait. Les deux pages posent la même
   question au lecteur arrivé au bout, et il n'y a pas de raison qu'elles la
   posent différemment. */
.petition__layout,
.thread__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-6);
  align-items: start;
}
.thread { max-width: 1240px; }
.petition__head h1 { font-size: var(--fs-2xl); line-height: 1.15; margin-bottom: var(--sp-3); }
.petition__summary { font-size: var(--fs-md); color: var(--text-2); max-width: 62ch; }

/* Le préambule d'une initiative enregistrée. Encadré et coloré : ce n'est pas
   un paragraphe de plus, c'est un avertissement de portée — signer ici ne vaut
   pas signer là-bas, et le lecteur doit l'apprendre avant de cliquer.

   Il n'est pas alarmant pour autant : rien ne va mal, il y a seulement deux
   gestes distincts et un seul qui compte devant la Commission. */
.petition__preamble {
  margin: var(--sp-4) 0 0;
  padding: var(--sp-4);
  border: 1px solid var(--brand-2);
  border-left: 3px solid var(--brand-2);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--brand-2) 6%, var(--surface));
}
.petition__preamble p { margin: 0; }
.petition__preamble p + p { margin-top: var(--sp-3); }
.petition__preamble-lead { font-weight: 600; }
.petition__preamble-where { font-weight: 600; color: var(--brand-1); }
.petition__preamble-role { font-size: var(--fs-sm); color: var(--text-2); }

/* Le renvoi au registre après avoir soutenu ici. Encadré : c'est la suite du
   geste, pas une proposition parmi d'autres — on vient d'arriver dessus par
   une ancre, et il doit se distinguer de ce qui l'entoure. */
.counter__handoff {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-3);
  border: 1px solid var(--brand-2);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--brand-2) 6%, var(--surface));
  scroll-margin-top: calc(var(--header-h, 64px) + var(--sp-4));
}
.counter__handoff-lead { margin: 0 0 var(--sp-3); font-size: var(--fs-sm); }

/* Les co-auteurs, dans la passerelle de dépôt. Séparés de ce qui précède : ce
   sont les seuls réglages que l'auteur ne partage pas, et la ligne le dit. */
.pfiling__editors {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.pfiling__editors h4 { margin: 0 0 4px; font-size: var(--fs-sm); }
.pfiling__editor-list { list-style: none; margin: var(--sp-3) 0; padding: 0; display: grid; gap: 6px; }
.pfiling__editor-list li {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-sm);
}
.pfiling__editor-list form { margin: 0; }
.pfiling__editor-add { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.pfiling__editor-add .input { max-width: 220px; }
/* Le renvoi vers la procédure, au pied du compteur. Discret et souligné : ce
   n'est pas une action de la page, c'est une note de bas de page qui mène
   dehors — et deux boutons de même forme se liraient comme deux façons de
   faire la même chose. */
.counter__procedure {
  display: block; margin-top: var(--sp-2);
  font-size: var(--fs-sm); color: var(--text-3);
  text-align: center; text-decoration: none;
}
.counter__procedure:hover { color: var(--brand-1); text-decoration: underline; }

/* La case à cocher qui commande le bouton. Encadrée et rapprochée de lui :
   elle n'est pas une option de plus dans le formulaire, c'est la condition du
   geste — et le bouton reste inerte tant qu'elle n'est pas lue. */
.counter__understand {
  margin: var(--sp-3) 0;
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: var(--fs-sm);
  line-height: 1.5;
}
.petition__meta {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  margin-top: var(--sp-3);
  font-size: var(--fs-sm); color: var(--text-3);
}
.petition__demand {
  margin: var(--sp-5) 0;
  padding: var(--sp-5);
  border-left: 3px solid var(--brand-1);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: var(--surface-2);
}
.petition__demand h2 {
  font-size: 0.72rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-3); margin-bottom: var(--sp-2);
}
.petition__demand p { font-size: var(--fs-md); line-height: 1.6; }
.petition__basis { margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--text-3); }
.petition__basis-label { font-weight: 600; color: var(--text-2); }
/* L'appel au bas du texte. Un titre, pas un paragraphe : c'est la phrase qui
   ferme l'exposé, et elle doit arrêter l'œil de qui vient de finir de lire. */
.petition__cta {
  margin-top: var(--sp-5);
  padding: var(--sp-4) var(--sp-5);
  border-left: 3px solid var(--brand-1);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: color-mix(in srgb, var(--brand-1) 6%, var(--surface));
  font-size: var(--fs-lg); line-height: 1.4; font-weight: 600;
}
.petition__cta a { color: inherit; text-decoration: none; }
.petition__cta a:hover { color: var(--brand-1); text-decoration: underline; }

.petition__outcome {
  margin-top: var(--sp-6);
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
/* -------------------------------------------------- lancer une pétition ---
   Ce que le site apporte, dit avant le formulaire et non après. Le bloc a
   volontairement l'allure d'un encart et non d'une carte de plus : il se lit
   d'abord, puis on l'oublie pour écrire. */
.pnew-pitch {
  margin: var(--sp-4) 0 var(--sp-5);
  padding: var(--sp-5);
  border: 1px solid var(--brand-2);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--brand-2) 5%, var(--surface));
}
.pnew-pitch h2 { font-size: var(--fs-md); margin-bottom: var(--sp-3); }
.pnew-pitch__list { display: grid; gap: var(--sp-3); }
.pnew-pitch__list li {
  font-size: var(--fs-sm); color: var(--text-2); line-height: 1.6; max-width: 74ch;
}
.pnew-pitch__list strong { color: var(--text-1); }
/* La limite se lit après la promesse, et pas sur le même ton : ce n'est pas
   un argument de plus, c'est ce que le site ne fera pas. */
.pnew-pitch__caveat {
  margin-top: var(--sp-4); padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm); color: var(--text-3); max-width: 74ch; line-height: 1.6;
}

/* Les dispositions relevées pendant la frappe. Elles s'ouvrent sous le champ
   qu'elles servent : plus loin, on ne ferait pas le lien. */
.pnew-suggest {
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px dashed var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.pnew-suggest__label { font-size: var(--fs-sm); font-weight: 600; margin-bottom: var(--sp-2); }
.pnew-suggest__list { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.pnew-suggest__list li { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.pnew-suggest__pick {
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text-1);
  padding: 3px 9px; font-size: var(--fs-sm); font-family: inherit;
  cursor: pointer; text-align: left;
}
.pnew-suggest__pick:hover { border-color: var(--brand-1); color: var(--brand-1); }
.pnew-suggest__why { font-size: 0.72rem; color: var(--text-3); }

/* Ce qui vient après la publication : une suite d'étapes, donc numérotée. */
.pnew-after { display: grid; gap: var(--sp-2); padding-left: 1.2em; list-style: decimal; }
.pnew-after li { font-size: var(--fs-sm); color: var(--text-2); line-height: 1.6; max-width: 74ch; }

/* Le compteur, épinglé le long de la lecture */
/* La colonne n'est plus collée : elle porte désormais les tribunes en réponse
   et les autres campagnes, donc plus d'une hauteur d'écran. Une colonne collée
   plus haute que la fenêtre a son bas hors d'atteinte — ce qu'on gagne en haut,
   on le perd en bas. Le compteur ouvre la colonne, il est vu d'emblée. */
/* `minmax(0, 1fr)` et non `1fr` : la piste implicite d'une grille vaut au
   moins le min-content de ses éléments, et une carte de tribune en réclame
   bien plus que la colonne n'en offre. Sans cette borne basse, les blocs
   débordaient de cent quarante pixels et la page prenait une barre
   horizontale. */
.petition__side,
.thread__side { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); align-content: start; }
.petition__side > *,
.thread__side > * { min-width: 0; }
/* Une carte dans 340 pixels : une colonne, jamais deux. Et l'écart entre les
   blocs vient de la colonne elle-même — la marge que ces sections portaient
   pour respirer au fil du texte s'y ajouterait deux fois. */
.petition__side .tribcard-grid,
.thread__side .tribcard-grid,
.tribune__side .tribcard-grid { grid-template-columns: minmax(0, 1fr); }
.petition__side .tribcard-grid > *,
.thread__side .tribcard-grid > *,
.tribune__side .tribcard-grid > * { min-width: 0; }
.petition__related h2,
.petition__side .reactions h2,
.thread__side .reactions h2,
.tribune__side .reactions h2 { font-size: var(--fs-md); }

/* Les autres campagnes : une ligne par campagne, mais une ligne qui dit où
   elle en est. Un nombre de soutiens seul ne se compare à rien — trois mille
   est beaucoup à cinq mille, presque rien à un million. La jauge donne
   l'échelle d'un coup d'œil, et c'est elle qui fait choisir. */
.prel { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }
.prel__item {
  display: grid; gap: 6px;
  padding: var(--sp-3);
  border: 1px solid transparent; border-radius: var(--r-md);
  color: inherit;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.prel__item:hover { border-color: var(--border); background: var(--surface-2); }
.prel__head { display: flex; align-items: baseline; gap: 8px; }
/* Le drapeau ne doit ni grandir ni pousser le titre : c'est une marque de
   portée, pas une image. */
.prel__flag { flex: 0 0 auto; line-height: 0; }
.prel__title {
  font-size: var(--fs-sm); font-weight: 600; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.prel__item:hover .prel__title { color: var(--brand-1); }
.prel__meta {
  font-size: 0.68rem; color: var(--text-3);
  display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap;
}
.prel__meta strong { color: var(--text-2); font-variant-numeric: tabular-nums; }
.prel__sep { opacity: 0.5; }
.petition__side .reactions,
.thread__side .reactions,
.tribune__side .reactions { margin-top: 0; }
.petition__side .reactions .section__head,
.thread__side .reactions .section__head,
.tribune__side .reactions .section__head { flex-wrap: wrap; gap: var(--sp-2); }
/* Dans une colonne de trois cent quarante pixels, les gestes s'empilent : deux
   moitiés y feraient deux boutons illisibles. */
.petition__side .reactions__actions,
.thread__side .reactions__actions,
.tribune__side .reactions__actions { grid-template-columns: minmax(0, 1fr); }
/* Le renvoi vers la pétition devient une carte de colonne, et non plus une
   bande large : les deux blocs qui l'entourent en sont, il détonnerait. */
.thread__side .thread-petition { display: grid; gap: var(--sp-3); }
.counter {
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  display: grid; gap: var(--sp-3);
}
.counter__value { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.counter__value strong {
  font-size: 2.1rem; font-weight: 300; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.counter__value span { color: var(--text-3); font-size: var(--fs-sm); }
.counter__target { font-size: var(--fs-sm); color: var(--text-2); }
.counter__facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--sp-3); }
.counter__facts li {
  padding: var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
}
.counter__fact-value { display: block; font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }
.counter__fact-label { display: block; margin-top: 2px; font-size: 0.66rem; color: var(--text-3); }
.counter__form { display: grid; gap: var(--sp-3); }
.counter__legal { font-size: 0.68rem; color: var(--text-3); line-height: 1.5; }
.counter__hook, .counter__signed, .counter__closed { font-size: var(--fs-sm); color: var(--text-2); }
.counter__signed { color: var(--brand-2); font-weight: 600; }
.counter__withdraw { text-align: center; }
.link-button {
  background: none; border: 0; padding: 0;
  color: var(--text-3); font: inherit; font-size: 0.72rem;
  text-decoration: underline; cursor: pointer;
}
.link-button:hover { color: var(--text); }

/* Seuils nationaux */
/* Les deux cartes de bas d'exposé — les seuils, les signataires — ont la même
   forme parce qu'elles disent la même chose sous deux angles : où en est la
   campagne. Elles se suivaient à quelques pixels l'une de l'autre et se
   lisaient comme un seul bloc coupé en deux ; l'écart les sépare. */
.petition__panel {
  padding: var(--sp-5);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--surface);
  margin-top: var(--sp-6);
}
.petition__panel > h2 { font-size: var(--fs-md); margin-bottom: 4px; }
.thresholds h2 { font-size: var(--fs-md); margin-bottom: 4px; }
/* Vingt-sept pays en une colonne faisaient huit cents pixels de haut : on ne
   lisait plus une carte de l'Europe, on faisait défiler une liste. En colonnes
   qui se replient selon la place, les mêmes vingt-sept tiennent en sept lignes
   et se comparent d'un regard — c'est à cela que sert ce bloc. */
.thresholds__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-3);
}
/* Le drapeau, le nom et le compte sur une seule ligne, la barre dessous :
   trois rangées par pays devenaient deux, et la hauteur avec. */
.threshold {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr) auto;
  grid-template-areas: "flag name num" "bar bar bar";
  align-items: baseline;
  gap: 3px var(--sp-2);
  font-size: 0.72rem;
}
.threshold__flag { grid-area: flag; }
.threshold__name {
  grid-area: name; color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.threshold__num { grid-area: num; color: var(--text-3); font-variant-numeric: tabular-nums; }
.threshold__bar {
  grid-area: bar;
  height: 4px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  overflow: hidden;
}
.threshold__bar > span {
  display: block; height: 100%; width: var(--p, 0%);
  background: var(--text-3);
}
.threshold.is-reached .threshold__bar > span { background: var(--brand-1); }
.threshold.is-reached .threshold__name { color: var(--text); font-weight: 600; }

/* Signataires */
/* Les signataires : des visages alignés, et rien d'autre. Une grille en
   colonnes verticales étirait le bloc sur des écrans entiers ; en rang qui
   se replie, cent soutiens tiennent en quatre lignes et se lisent d'un coup
   d'œil — ce qu'on veut d'eux, c'est le nombre et les visages. */
.signers { display: grid; gap: var(--sp-3); margin-top: var(--sp-3); }
/* La pagination des visages se range au bas et à droite de sa carte : centrée,
   elle prenait la place d'un titre sous une rangée d'avatars alignés à gauche,
   et paraissait annoncer autre chose que ce qu'elle tourne. */
.petition__signers .pagination { justify-content: flex-end; margin-top: var(--sp-4); }
.signers--faces { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.signer { display: flex; gap: var(--sp-3); align-items: flex-start; }
.signers--faces .signer { display: block; }
.signer__avatar { border-radius: 50%; border: 1px solid var(--border); flex-shrink: 0; }
.signers--faces .avatar-link { display: block; border-radius: 50%; }
.signers--faces .avatar-link:hover .signer__avatar { border-color: var(--brand-1); }
.signer__avatar--anon {
  width: 40px; height: 40px; display: block;
  border-radius: 50%; border: 1px dashed var(--border);
  background: var(--surface-2);
}
.signer__name { font-size: var(--fs-sm); font-weight: 600; }
.signer__name--anon { color: var(--text-3); font-weight: 400; }
.signer__comment { margin-top: 2px; font-size: var(--fs-sm); color: var(--text-2); line-height: 1.5; }

/* Le passage du débat à la pétition */
.thread-petition {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-4);
  margin: var(--sp-6) 0;
  padding: var(--sp-5);
  border: 1px solid color-mix(in oklab, var(--brand-1) 35%, var(--border));
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 140% at 0% 0%, color-mix(in oklab, var(--brand-1) 10%, transparent), transparent 60%),
    var(--surface);
}
.thread-petition h3 { font-size: var(--fs-md); margin-bottom: 2px; }
.thread-petition p { font-size: var(--fs-sm); color: var(--text-2); max-width: 52ch; }
.thread-petition--exists { display: grid; gap: 4px; color: inherit; }
.thread-petition--exists:hover { border-color: var(--brand-1); }
.thread-petition__label {
  font-size: 0.64rem; letter-spacing: 0.09em; text-transform: uppercase; color: var(--brand-1);
}
.thread-petition__count { font-size: var(--fs-sm); color: var(--text-3); }

/* Conditions officielles de l'initiative citoyenne européenne */
.eci {
  margin-top: var(--sp-7);
  padding: var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  background: var(--surface);
}
.eci__head h2 { font-size: var(--fs-xl); margin-bottom: var(--sp-2); }
.eci__head p { color: var(--text-2); max-width: 70ch; }
.eci__figures {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--sp-3);
  margin: var(--sp-5) 0;
}
.eci__figure {
  padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
}
.eci__value {
  display: block;
  font-size: var(--fs-xl); font-weight: 300; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.eci__caption { display: block; margin-top: 4px; font-size: 0.7rem; color: var(--text-3); }
.eci__steps { display: grid; gap: var(--sp-4); counter-reset: eci; }
.eci__step { display: flex; gap: var(--sp-4); align-items: flex-start; }
.eci__step-n {
  flex-shrink: 0;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid color-mix(in oklab, var(--brand-1) 45%, var(--border));
  color: var(--brand-1);
  font-size: 0.8rem;
}
.eci__step h3 { font-size: var(--fs-md); margin-bottom: 2px; }
.eci__step p { font-size: var(--fs-sm); color: var(--text-2); max-width: 68ch; }
.eci__thresholds { margin-top: var(--sp-5); }
.eci__thresholds summary { cursor: pointer; font-size: var(--fs-sm); color: var(--text-2); }
.eci__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}
.eci__grid li {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px;
  border: 1px solid var(--border); border-radius: var(--r-sm, 8px);
  background: var(--surface-2);
  font-size: 0.74rem;
}
.eci__grid-name { flex: 1; color: var(--text-2); min-width: 0; }
.eci__grid-value { font-variant-numeric: tabular-nums; color: var(--text); }
.eci__disclaimer {
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm); color: var(--text-3); line-height: 1.6;
}

/* Choix du type de pétition */
.radio-card { display: flex; gap: var(--sp-3); align-items: flex-start; cursor: pointer; }
.radio-card + .radio-card { margin-top: var(--sp-3); }
.radio-card span { display: grid; gap: 2px; }
.radio-card strong { font-size: var(--fs-sm); }
.radio-card em { font-style: normal; font-size: 0.75rem; color: var(--text-3); line-height: 1.5; }

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-4); }
.textarea--sm { min-height: 90px; }

/* -- Tribunes ----------------------------------------------------------------- */

.tribcard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--sp-4);
}
.tribcard-grid--tight { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--sp-3); }

.tribcard {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast),
              box-shadow var(--t-fast);
}
.tribcard:hover { transform: translateY(-2px); border-color: var(--brand-1); box-shadow: var(--shadow); }
.tribcard__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: 0.7rem; color: var(--text-3);
}
.tribcard__kind {
  padding: 2px 8px; border-radius: 999px;
  font-size: 0.62rem; letter-spacing: 0.07em; text-transform: uppercase;
  border: 1px solid var(--border);
}
.tribcard__kind--declaration {
  color: var(--brand-3, var(--brand-1));
  border-color: color-mix(in oklab, var(--brand-3, var(--brand-1)) 45%, transparent);
  background: color-mix(in oklab, var(--brand-3, var(--brand-1)) 12%, transparent);
}
.tribcard__kind--relay {
  color: var(--brand-2);
  border-color: color-mix(in oklab, var(--brand-2) 45%, transparent);
  background: color-mix(in oklab, var(--brand-2) 12%, transparent);
}
/* Des rangées de même hauteur d'un bloc à l'autre : sans elles, une ligne de
   provenance présente ici et absente là décalait les titres, et la grille se
   lisait de travers. Chaque rangée est bornée au nombre de lignes qu'elle
   occupe, et remplie jusque-là quand elle en occupe moins.

   Interlignes en pixels et hauteurs exactement multiples : avec un interligne
   relatif, l'arrondi du navigateur ne tombe pas au même endroit selon le
   nombre de lignes réellement posées, et il reste un pixel d'écart. */
/* Deux rangs d'étiquettes, toujours.
 *
 * Le nombre d'étiquettes varie — forme, thème, portée, ancienneté — et selon
 * qu'« il y a trois jours » tenait ou non sur la première ligne, le titre
 * descendait d'un rang. La hauteur est donc posée, et chaque étiquette porte la
 * sienne : déduite d'un rembourrage, elle aurait changé à la première retouche
 * de police. */
.tribcard__meta {
  --row-h: 22px;
  align-content: flex-start;
  height: calc(2 * var(--row-h) + 6px);
  overflow: hidden;
}
.tribcard__meta > * {
  display: inline-flex; align-items: center;
  height: var(--row-h); line-height: 1;
}
.tribcard__source {
  --lh: 18px;
  font-size: 0.72rem; line-height: var(--lh); color: var(--text-3);
  padding-left: var(--sp-3);
  border-left: 2px solid var(--border);
  height: var(--lh);
  /* La coupure se voit : sans les points de suspension, un titre tronqué par
     le débordement se lit comme un titre court. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tribcard__source a { color: inherit; text-decoration: none; }
.tribcard__source a:hover { color: var(--brand-2); text-decoration: underline; }
/* Rien à annoncer : la barre de provenance s'efface, la place reste. */
.tribcard__source.is-empty { border-left-color: transparent; }
.tribcard__source strong { color: var(--text-2); font-weight: 500; }
.tribcard__link { display: grid; gap: var(--sp-2); color: inherit; }
.tribcard__title {
  --lh: 25px;
  font-size: var(--fs-lg); line-height: var(--lh);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  height: calc(2 * var(--lh));
}
.tribcard__standfirst {
  --lh: 21px;
  font-size: var(--fs-sm); color: var(--text-2); line-height: var(--lh);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(3 * var(--lh));
}
.tribcard__media {
  position: relative; display: block;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-2);
}
.tribcard__media img { display: block; width: 100%; height: auto; aspect-ratio: 16/9; object-fit: cover; }
.tribcard__media-blank {
  display: grid; place-items: center;
  width: 100%; aspect-ratio: 16/9;
  color: color-mix(in oklab, var(--c, var(--text-3)) 70%, white);
  background:
    radial-gradient(80% 120% at 50% 0%, color-mix(in oklab, var(--c, var(--brand-1)) 26%, transparent), transparent 72%),
    linear-gradient(135deg, var(--surface-2), var(--surface));
}
.tribcard__provider {
  position: absolute; left: 8px; bottom: 8px;
  padding: 2px 8px; border-radius: 999px;
  background: var(--c, var(--text-3)); color: #fff;
  z-index: 1;
  font-size: 0.6rem; letter-spacing: 0.06em; text-transform: uppercase;
}
.tribcard__foot {
  margin-top: auto; padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  font-size: 0.72rem; color: var(--text-3);
}
.tribcard__author { display: inline-flex; align-items: center; gap: 7px; color: var(--text-2); }
.tribcard__author img { border-radius: 50%; border: 1px solid var(--border); }
.tribcard__counts { display: inline-flex; gap: var(--sp-3); font-variant-numeric: tabular-nums; }

/* Page d'une tribune */
.tribune__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--sp-6);
  align-items: start;
}
/* Plus collante : la colonne porte désormais les tribunes en réponse, et
   dépasse la hauteur d'une fenêtre — collée, son bas devient hors d'atteinte.
   Même raison que sur une pétition. */
.tribune__side {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4); align-content: start;
}
.tribune__side > * { min-width: 0; }
.tribune__head h1 { font-size: var(--fs-2xl); line-height: 1.15; margin-bottom: var(--sp-3); }
.tribune__standfirst { font-size: var(--fs-md); color: var(--text-2); max-width: 62ch; }
.tribune__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4);
  margin-top: var(--sp-4);
  font-size: var(--fs-sm); color: var(--text-3);
}
.tribune__author { display: inline-flex; align-items: center; gap: 8px; }
.tribune__author img { border-radius: 50%; border: 1px solid var(--border); }
.tribune__source {
  display: grid; gap: 2px;
  margin-bottom: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-left: 3px solid var(--brand-2);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: var(--surface-2);
  color: inherit;
}
.tribune__source:hover { background: var(--surface); }
.tribune__source-label {
  font-size: 0.64rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--brand-2);
}
.tribune__source-host { font-size: 0.72rem; color: var(--text-3); }
.tribune__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-6) 0; }
.tribune__like-form { display: inline; }
.tribune__card-author { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.tribune__card-author img { border-radius: 50%; border: 1px solid var(--border); }
.tribune__card-author div { display: grid; }
.tribune__card-author .muted { font-size: 0.72rem; }

.reactions { margin-top: var(--sp-7); }
/* Les façons de prolonger, sous le titre du bloc et avant ce qui a déjà été
   écrit : on choisit d'écrire, puis on regarde ce qui existe — l'inverse
   ferait passer la liste pour la réponse à l'invitation.

   Chaque bouton porte sous lui la ligne qui dit ce qu'il fait. Sans elle, deux
   boutons voisins menaient à deux endroits que rien ne distinguait, et le
   lecteur choisissait au hasard entre un débat et une tribune. */
.reactions__actions {
  display: grid; gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}
/* Deux façons de prolonger : deux moitiés de la largeur, à égalité. Une
   seule : une carte qui ne s'étire pas jusqu'au bout — un bouton large comme
   la page se lit comme une bannière, pas comme un choix. */
.reactions__actions--2 { grid-template-columns: 1fr 1fr; }
.reactions__actions--1 { grid-template-columns: minmax(0, 420px); }

/* Chaque geste dans sa carte, sa raison au-dessus et son bouton dessous : on
   lit pourquoi avant de lire où l'on va. Le filet du haut porte la couleur de
   la voix, si bien que la carte se reconnaît avant même d'être lue. */
.reactions__action {
  display: grid; gap: var(--sp-3); align-content: space-between;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-top: 3px solid var(--voice-c, var(--border));
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.reactions__action--ask { --voice-c: var(--voice-ask); }
.reactions__action--say { --voice-c: var(--voice-say); }
.reactions__action .btn { justify-self: start; }
.reactions__hint {
  margin: 0;
  font-size: var(--fs-sm); color: var(--text-2); line-height: 1.5;
}

@media (max-width: 620px) {
  .reactions__actions--2 { grid-template-columns: 1fr; }
}
.reactions__empty {
  padding: var(--sp-4);
  border: 1px dashed var(--border); border-radius: var(--r-md);
  font-size: var(--fs-sm); color: var(--text-3);
}

/* -- Médias hébergés ailleurs -------------------------------------------------- */

.embed { margin: var(--sp-5) 0; }
.embed__caption { margin-top: var(--sp-2); font-size: 0.76rem; color: var(--text-3); }

.embed__player {
  position: relative;
  border-radius: var(--r-lg); overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.embed__facade {
  position: relative; display: block; width: 100%; padding: 0;
  border: 0; background: none; cursor: pointer;
  color: inherit; font: inherit;
}
.embed__thumb { display: block; width: 100%; height: auto; aspect-ratio: 16/9; object-fit: cover; }
.embed__thumb--blank {
  display: block; width: 100%; aspect-ratio: 16/9;
  background:
    radial-gradient(80% 120% at 50% 0%, color-mix(in oklab, var(--brand) 30%, transparent), transparent 70%),
    linear-gradient(135deg, var(--surface-2), var(--surface));
}
.embed__play {
  position: absolute; inset: 0; margin: auto;
  width: 62px; height: 62px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--brand, var(--brand-1)); color: #fff;
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.6);
  transition: transform var(--t-fast) var(--ease-out);
}
.embed__facade:hover .embed__play { transform: scale(1.08); }
.embed__cta {
  position: absolute; left: 12px; bottom: 12px;
  padding: 4px 10px; border-radius: 999px;
  background: rgba(0, 0, 0, 0.62); color: #fff;
  font-size: 0.72rem;
}
.embed__frame { display: block; width: 100%; aspect-ratio: 16/9; border: 0; }
.embed__player.is-playing { background: #000; }
.embed__consent { margin-top: 6px; font-size: 0.7rem; color: var(--text-3); }

.embed__image { display: block; width: 100%; height: auto; border-radius: var(--r-lg); }

.embed__quote {
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand, var(--brand-1));
  border-radius: 0 var(--r-lg) var(--r-lg) 0;
  background: var(--surface-2);
}
.embed__quote p { font-size: var(--fs-sm); line-height: 1.65; color: var(--text-2); }
.embed__quote p + p { margin-top: var(--sp-2); }
.embed__quote-head { display: flex; align-items: center; gap: 8px; margin-bottom: var(--sp-3); }
.embed__quote footer { margin-top: var(--sp-3); font-size: 0.74rem; }
.embed__author { font-size: 0.76rem; color: var(--text-3); }

.embed__mark {
  padding: 2px 8px; border-radius: 999px;
  background: var(--c, var(--text-3)); color: #fff;
  font-size: 0.6rem; letter-spacing: 0.06em; text-transform: uppercase;
  white-space: nowrap;
}
.embed__link, .embed__pending {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
  color: inherit; font-size: var(--fs-sm);
}
.embed__link:hover, .embed__pending:hover { border-color: var(--brand-1); }
.embed__link-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.embed__host { font-size: 0.7rem; color: var(--text-3); white-space: nowrap; }

/* Champs de média du formulaire */
.embed-field {
  display: grid; gap: 6px;
  padding: var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
}
.embed-field + .embed-field { margin-top: var(--sp-2); }
.embed-field__detected { font-size: 0.72rem; color: var(--brand-2); }
.embed-field__detected.is-error { color: var(--danger, #e5484d); }
.input--sm { padding: 7px 10px; font-size: 0.8rem; }
.textarea--tall { min-height: 320px; }

@media (max-width: 980px) {
  .tribune__layout { grid-template-columns: 1fr; }
}

/* -- Langues et traduction ---------------------------------------------------- */

.reading-picker {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-6);
  margin-bottom: var(--sp-6);
  border: 1px solid color-mix(in oklab, var(--brand-1) 30%, var(--border));
  border-radius: var(--r-xl);
  background:
    radial-gradient(120% 140% at 0% 0%, color-mix(in oklab, var(--brand-1) 9%, transparent), transparent 60%),
    var(--surface);
}
.reading-picker h2 { font-size: var(--fs-lg); margin-bottom: 4px; }
.reading-picker p { font-size: var(--fs-sm); color: var(--text-2); max-width: 56ch; }
.reading-picker p + p { margin-top: 4px; }
.reading-picker__form { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }
.reading-picker__form .select { min-width: 240px; }

.lang-list { display: grid; gap: 2px; margin-top: var(--sp-4); }
.lang-row {
  display: grid;
  grid-template-columns: 28px minmax(150px, 280px) 96px minmax(80px, 1fr) 82px auto;
  align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.lang-row:hover { background: var(--surface-2); }
.lang-row.is-reading {
  border-color: color-mix(in oklab, var(--brand-1) 45%, transparent);
  background: color-mix(in oklab, var(--brand-1) 8%, transparent);
}
.lang-row__rank {
  font-size: 0.72rem; color: var(--text-3);
  font-variant-numeric: tabular-nums; text-align: right;
}
.lang-row__names { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; }
.lang-row__names strong { font-size: var(--fs-sm); }
.lang-row__en { font-size: 0.72rem; color: var(--text-3); }
.lang-row__ui {
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 0.6rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--brand-2);
  border: 1px solid color-mix(in oklab, var(--brand-2) 40%, transparent);
}
.lang-row__flags {
  display: flex; align-items: center; gap: 3px;
  white-space: nowrap; overflow: hidden;
}
.lang-row__more {
  font-size: 0.62rem; font-weight: 700; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.lang-row__bar {
  height: 5px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  overflow: hidden;
}
.lang-row__bar > span {
  display: block; height: 100%; width: var(--p, 0%);
  background: linear-gradient(90deg, var(--brand-1), var(--brand-2));
}
.lang-row__pop {
  font-size: 0.74rem; color: var(--text-2);
  font-variant-numeric: tabular-nums; text-align: right;
}
.lang-row__action { justify-self: end; }

.notice-block {
  padding: var(--sp-5) var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.notice-block h2 { font-size: var(--fs-md); margin-bottom: var(--sp-3); }
.notice-block p { font-size: var(--fs-sm); color: var(--text-2); max-width: 76ch; line-height: 1.65; }
.notice-block p + p { margin-top: var(--sp-3); }

/* Marqueur de traduction : discret, mais jamais absent. */
.tmark {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: var(--sp-2);
  font-size: 0.72rem;
}
.tmark--title { margin: var(--sp-2) 0 var(--sp-3); }
.tmark__badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  color: var(--brand-2);
  border: 1px solid color-mix(in oklab, var(--brand-2) 40%, transparent);
  background: color-mix(in oklab, var(--brand-2) 10%, transparent);
  font-size: 0.62rem; letter-spacing: 0.06em; text-transform: uppercase;
}
.tmark__from { color: var(--text-3); }
.tmark__original-title { font-style: italic; }

/* -- Traduction : les deux textes, un seul visible ---------------------------
   Chaque bloc portait son propre repli « Voir l'original » : sur un fil de
   trente messages, cela faisait trente déplis. La bascule est désormais
   unique et en tête de page ; ici, il ne reste qu'à marquer l'original quand
   c'est lui qu'on affiche, pour qu'on sache lequel des deux on lit. */

/* Le filet ne vaut que pour un bloc : sur un titre ou un chapeau, `.tr__source`
   est un `span` en ligne, et un bord gauche y ferait une barre au milieu d'une
   phrase. */
div.tr__source {
  border-left: 2px solid var(--brand-2);
  padding-left: var(--sp-4);
}

/* Sur une liste, l'interrupteur précède la grille : il vaut pour tout ce qui
   suit, et le poser sous les cartes l'aurait rendu introuvable. */
.tribcard-grid, .pcard-grid, .tcard-list { margin-top: var(--sp-3); }

/* La bascule n'avait aucune marge, et `inline-flex` la posait sur une ligne de
   texte : elle mordait de six pixels sur l'encart qui la précède et touchait
   la grille qui la suit. Un interrupteur collé à ce qu'il commande se lit
   comme un titre de la liste, pas comme une commande.
   `flex` plutôt qu'`inline-flex` — la boîte cesse de dépendre d'une ligne de
   texte —, avec `fit-content` pour qu'elle ne s'étende pas d'un bord à
   l'autre, et de l'air des deux côtés, plus large en dessous. */
.tswitch {
  display: flex; width: fit-content;
  align-items: center; gap: var(--sp-3);
  flex-wrap: wrap;
  margin: var(--sp-3) 0 var(--sp-5);
  font-size: var(--fs-xs); color: var(--text-3);
}
/* Sauf dans la barre d'actions d'un fil : elle n'y est plus un bloc mais un
   élément d'une rangée, et ces marges y écarteraient le bandeau entier. */
.tbar__actions .tswitch { margin: 0; }
.tswitch__btn {
  padding: 4px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font: inherit; cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.tswitch__btn:hover { border-color: var(--brand-2); color: var(--brand-2); }
/* Enfoncé : c'est l'original qui est à l'écran, et cela doit se voir sans
   avoir à relire le libellé. */
.tswitch__btn[aria-pressed="true"] {
  border-color: var(--brand-2);
  background: color-mix(in oklab, var(--brand-2) 12%, transparent);
  color: var(--brand-2);
}

/* Bandeau de langue en tête d'une discussion étrangère */
.tbar {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-3);
  margin: var(--sp-4) 0;
  padding: var(--sp-3) var(--sp-4);
  border: 1px dashed var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.tbar__text { font-size: var(--fs-sm); color: var(--text-2); margin: 0; }
/* Les deux actions forment un groupe : la bascule et le lien vers le choix de
   langue répondent à la même question, et les écarteler aux deux bouts du
   bandeau les faisait lire comme trois éléments sans rapport. */
.tbar__actions {
  display: flex; align-items: center; gap: var(--sp-4);
  flex-wrap: wrap;
}
.tbar__link { font-size: 0.74rem; color: var(--text-3); white-space: nowrap; }
.tbar__link:hover { color: var(--brand-2); }

/* Le menu de langue s'est élargi : ancré à gauche il déborderait de la fenêtre. */
.dropdown__menu--lang { min-width: 250px; left: auto; right: 0; }
.dropdown__title {
  padding: var(--sp-2) var(--sp-3) 4px;
  font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-3);
}
.dropdown__note { padding: 0 var(--sp-3) var(--sp-2); font-size: 0.74rem; color: var(--text-2); }
.dropdown__sep { margin: var(--sp-2) 0; border: 0; border-top: 1px solid var(--border); }
.dropdown__item--more { color: var(--brand-2); font-size: 0.78rem; }

@media (max-width: 760px) {
  .lang-row {
    grid-template-columns: 24px minmax(0, 1fr) auto;
    grid-template-areas: "rank names names" ". bar pop" ". flags action";
    row-gap: 6px;
  }
  .lang-row__rank { grid-area: rank; }
  .lang-row__names { grid-area: names; }
  .lang-row__bar { grid-area: bar; }
  .lang-row__pop { grid-area: pop; }
  .lang-row__flags { grid-area: flags; }
  .lang-row__action { grid-area: action; }
}

/* -- Partage ------------------------------------------------------------------ */

.share {
  margin: var(--sp-6) 0;
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.share--inline { padding: var(--sp-3); background: transparent; border: 0; margin: var(--sp-3) 0; }
/* En tête de colonne latérale : exactement le gabarit des cartes qui la
   suivent, sans quoi le premier bloc de la colonne paraîtrait détaché. */
.share--aside {
  margin: 0;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: var(--shadow);
}
.share--aside .share__actions { gap: 6px; }
.share--aside .share__btn { padding: 5px 10px; font-size: 0.72rem; }
/* La note de bas de bloc tient sur deux lignes dans une colonne étroite : on
   la réduit plutôt que de la laisser pousser le reste vers le bas. */
.share__label {
  font-size: 0.68rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-3); margin-bottom: var(--sp-3);
}
.share__actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.share__btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 0.75rem; font-family: inherit;
  cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.share__btn:hover { color: var(--text); border-color: var(--brand-1); transform: translateY(-1px); }
.share__btn.is-done { color: var(--brand-2); border-color: var(--brand-2); }
.share__btn.is-failed, .btn.is-failed { color: var(--text-3); border-color: var(--text-3); }
.share__dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--c, var(--text-3));
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--c, var(--text-3)) 20%, transparent);
}
.share__masto { display: inline-block; }
.share__masto > summary { list-style: none; }
.share__masto > summary::-webkit-details-marker { display: none; }
.share__masto-form { display: flex; gap: 6px; margin-top: 8px; }
.share__masto-form .input { max-width: 190px; padding: 6px 10px; font-size: 0.78rem; }

/* -- Trousse de relais -------------------------------------------------------- */

.kit {
  margin: var(--sp-6) 0;
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
}
.kit__head h2 { font-size: var(--fs-lg); margin-bottom: 2px; }
.kit__head p { font-size: var(--fs-sm); color: var(--text-2); max-width: 66ch; }
.kit__blocks { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); }
.kit__block {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
}
.kit__block-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.kit__block-head h3 { font-size: 0.72rem; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-3); }
.kit__text {
  margin: 0; padding: var(--sp-4);
  font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", Menlo, monospace;
  font-size: 0.76rem; line-height: 1.6; color: var(--text-2);
  white-space: pre-wrap; word-break: break-word;
  max-height: 190px; overflow-y: auto;
}
.kit__mail {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-4);
  margin-top: var(--sp-4); padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.kit__mail h3 { font-size: var(--fs-md); }

@media (max-width: 900px) {
  .petition__layout, .thread__layout { grid-template-columns: 1fr; }
  /* Sous neuf cents pixels, une colonne de 340 ne tient plus : elle passe
     sous l'article, et cesse d'être collée — une colonne empilée qui suit le
     défilement recouvrirait ce qu'on lit. */
  .article__layout { grid-template-columns: 1fr; }
  .article__side { position: static; }
  .article { max-width: none; }
}

/* -- Accroches ---------------------------------------------------------------- */

.cta {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-5);
  margin-top: var(--sp-7);
  padding: var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  background: var(--surface);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  overflow: hidden;
}
/* Le halo couvre exactement le bloc, quelle qu'en soit la hauteur.
   Il avait une hauteur fixe de 240 px placée en pourcentage de celle du
   bloc : dès qu'un titre passait sur deux lignes, le bloc s'allongeait, le
   halo s'arrêtait net en cours de route et laissait une bande franche en bas.
   Avec `inset: 0`, le dégradé s'éteint à l'intérieur du bloc et ne peut plus
   finir sur une arête. */
.cta::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 90% 150% at 22% 0%,
                              var(--cta-glow, var(--aurora-1)), transparent 72%);
  pointer-events: none;
}
.cta--forum { --cta-glow: color-mix(in oklab, var(--brand-1) 22%, transparent); }
.cta--news  { --cta-glow: color-mix(in oklab, var(--accent) 16%, transparent); }
.cta--map   { --cta-glow: color-mix(in oklab, var(--brand-2) 18%, transparent); }

.cta__text { position: relative; max-width: 60ch; }
.cta__title { margin: 0 0 6px; font-size: var(--fs-lg); font-weight: 500; }
.cta__lead { margin: 0; color: var(--text-2); font-size: var(--fs-sm); }
.cta__actions { position: relative; display: flex; flex-wrap: wrap; gap: var(--sp-3); }

.chip.is-on { color: #fff; background: var(--brand-1); border-color: var(--brand-1); }

.empty-state .btn { margin-top: var(--sp-3); }

.thread-list { display: grid; gap: var(--sp-2); }
.thread-row {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast), background var(--t-fast);
}
.thread-row:hover { transform: translateX(4px); border-color: var(--border-strong); }
.thread-row__rail {
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px;
  background: linear-gradient(180deg, var(--rail), transparent);
}
.thread-row__score {
  display: grid; place-items: center;
  min-width: 38px; padding: 4px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-weight: 500;
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
  color: var(--brand-2);
}
.thread-row__title { margin: 0 0 2px; font-size: var(--fs-md); font-family: var(--font-sans); font-weight: 600; }
.thread-row__title a:hover { color: var(--brand-2); }
.thread-row__meta { margin: 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: var(--fs-xs); color: var(--text-3); }
.thread-row__cat { color: color-mix(in oklab, var(--rail) 80%, var(--text)); font-weight: 600; }
.thread-row__flag { font-size: 0.95rem; }
.thread-row__counts { display: flex; gap: var(--sp-3); text-align: center; }
.count strong { display: block; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.count small { font-size: 0.6rem; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.06em; }
.count--muted strong { color: var(--text-3); }

.cat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--sp-3); }
.cat-card {
  position: relative;
  display: block;
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: transform var(--t) var(--ease-out), border-color var(--t-fast);
}
.cat-card::before {
  content: "";
  position: absolute; inset: 0 auto 0 0; width: 4px;
  background: linear-gradient(180deg, var(--rail, var(--brand-1)), transparent);
}
.cat-card:hover { transform: translateY(-4px); border-color: var(--border-strong); }
.cat-card h3 { margin: 0 0 4px; font-size: var(--fs-md); font-family: var(--font-sans); }
.cat-card p { margin: 0 0 var(--sp-3); font-size: var(--fs-xs); color: var(--text-3); }
.cat-card__counts { font-size: var(--fs-xs); color: var(--text-3); }

.post {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  gap: var(--sp-4);
  padding: var(--sp-5) 0;
  border-bottom: 1px solid var(--border);
}
.post:last-child { border-bottom: 0; }
/* Le message d'ouverture porte la question dont tout le reste dépend : il se
   distingue sur toute sa surface et non par une seule étiquette. Un fond, un
   filet de la couleur du forum sur son bord, et le texte un cran plus grand —
   on doit voir d'où part le fil sans avoir à lire l'étiquette. */
.post--first {
  padding: var(--sp-5);
  margin-bottom: var(--sp-3);
  border: 1px solid color-mix(in srgb, var(--voice-ask) 35%, var(--border));
  border-left: 3px solid var(--voice-ask);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--voice-ask) 6%, var(--surface));
}
.post--first .post__body { font-size: var(--fs-md); }
.post__side { display: grid; justify-items: center; align-content: start; gap: 4px; }
.post__avatar { border-radius: 50%; border: 1px solid var(--border); }
.post__author {
  font-size: 0.68rem; font-weight: 600; text-align: center; line-height: 1.2;
  /* Deux lignes au plus : un nom long ne doit pas allonger la colonne. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
/* Drapeau et réputation tiennent sur une ligne : deux valeurs de deux
   caractères n'ont pas besoin de deux rangs. */
.post__id {
  display: flex; align-items: center; gap: 5px;
  margin: 0; font-size: 0.66rem; color: var(--text-3);
}
.post__rep { font-variant-numeric: tabular-nums; cursor: help; }

.vote { display: flex; flex-direction: column; align-items: center; gap: 2px; margin-top: 4px; }
/* Le vote à l'horizontale dans la colonne d'un message : empilé, il ajoutait
   soixante pixels à une colonne déjà plus haute que bien des messages. */
.vote--row { flex-direction: row; gap: 1px; margin-top: 2px; }
.vote--row button { width: 22px; height: 20px; }
.vote button {
  width: 26px; height: 22px;
  display: grid; place-items: center;
  border: 1px solid transparent; border-radius: var(--r-xs);
  background: transparent; color: var(--text-3);
  cursor: pointer; font-size: 0.8rem; line-height: 1;
  transition: color var(--t-fast), background var(--t-fast), transform var(--t-fast) var(--ease-spring);
}
.vote button:hover { background: var(--surface-2); transform: scale(1.15); }
.vote button.is-active { color: var(--brand-2); }
.vote button.is-active[data-vote="-1"] { color: var(--danger); }
/* Le pouce est plein une fois le vote donné : le seul changement de couleur se
   perdait sur un dessin au trait de quinze pixels. */
.vote button.is-active .vote__thumb { fill: currentColor; fill-opacity: 0.18; }
.vote button:disabled { cursor: default; opacity: 0.55; }
.vote button:disabled:hover { background: transparent; transform: none; }
.vote__score { font-size: var(--fs-sm); font-weight: 700; font-variant-numeric: tabular-nums; }

.post__header { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: baseline; margin-bottom: var(--sp-2); font-size: var(--fs-xs); color: var(--text-3); }
.post__body { color: var(--text); line-height: 1.75; }
.post__body p { margin: 0 0 var(--sp-3); }
.post__body p:last-child { margin-bottom: 0; }
.post__body blockquote {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  border-left: 3px solid var(--brand-1);
  background: var(--surface-2);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--text-2);
}
.post__body ul { list-style: disc; padding-left: 1.3em; margin: 0 0 var(--sp-3); }
.post__body li { margin-bottom: 4px; }
.post__body code {
  padding: 1px 5px; border-radius: var(--r-xs);
  background: var(--surface-2); border: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 0.88em;
}
.post__body a { color: var(--brand-2); text-decoration: underline; text-underline-offset: 2px; }

/* -- Commentaires sous un article ------------------------------------------- */

.comments { margin-top: var(--sp-6); }

.comments__panel {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  overflow: hidden;
}
.comments__summary {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4);
  list-style: none;
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-2);
  transition: background var(--t-fast), color var(--t-fast);
}
.comments__summary::-webkit-details-marker { display: none; }
.comments__summary:hover { background: var(--surface-2); color: var(--text); }
.comments__icon { display: grid; place-items: center; color: var(--brand-2); }
.comments__label { flex: 1; }
.comments__chevron {
  display: grid; place-items: center;
  color: var(--text-3);
  transition: transform var(--t) var(--ease);
}
.comments__panel[open] .comments__chevron { transform: rotate(180deg); }
.comments__panel[open] .comments__summary { border-bottom: 1px solid var(--border); }

.comments__body { padding: var(--sp-4); }
.comments__notice { margin: 0; font-size: var(--fs-sm); color: var(--text-3); }
.comments__notice a { color: var(--brand-2); font-weight: 500; }
.comments__thread-link {
  margin: var(--sp-4) 0 0;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
}
.comments__thread-link a { color: var(--brand-2); }

.comment-list { display: grid; gap: var(--sp-4); margin-bottom: var(--sp-5); }
.comment {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: start;
}
.comment__avatar { border-radius: 50%; border: 1px solid var(--border); flex-shrink: 0; }
.comment__meta {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  margin: 0 0 4px;
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.comment__meta strong { color: var(--text); font-weight: 600; font-size: var(--fs-sm); }
.comment__body { font-size: var(--fs-sm); line-height: 1.7; color: var(--text-2); }
.comment__body p { margin: 0 0 var(--sp-2); }
.comment__body p:last-child { margin-bottom: 0; }
.comment__body blockquote {
  margin: 0 0 var(--sp-2);
  padding: 2px var(--sp-3);
  border-left: 2px solid var(--border-strong);
  color: var(--text-3);
}
.comment__body ul { list-style: disc; padding-left: 1.2em; margin: 0 0 var(--sp-2); }
.comment__body code {
  padding: 1px 4px; border-radius: var(--r-xs);
  background: var(--surface-2); border: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 0.88em;
}
.comment__body a { color: var(--brand-2); text-decoration: underline; text-underline-offset: 2px; }

.vote--inline { flex-direction: row; align-items: center; gap: 4px; margin: 0; }
.vote--inline .vote__score { font-size: var(--fs-xs); min-width: 14px; text-align: center; }
.vote--inline button { width: 22px; height: 20px; font-size: 0.68rem; }

.comment-form {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: start;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.comment-form__field { display: grid; gap: var(--sp-2); }
.comment-form__actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
}
.comment-form__actions .hint { margin: 0; font-size: 0.7rem; color: var(--text-3); }
.textarea--compact { min-height: 84px; font-size: var(--fs-sm); }

.thread-source {
  display: block;
  margin-bottom: var(--sp-5);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-left: 2px solid var(--brand-2);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  transition: border-color var(--t-fast), transform var(--t-fast);
}
.thread-source:hover { border-color: var(--border-strong); transform: translateX(2px); }
.thread-source__label {
  display: block;
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-3);
}
.thread-source strong { font-size: var(--fs-sm); font-weight: 500; }

.reply-box {
  margin-top: var(--sp-6);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.reply-box h3 { margin-top: 0; }

.thread-header {
  padding-bottom: var(--sp-4);
  margin-bottom: var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.thread-header h1 { font-size: clamp(1.6rem, 3.4vw, 2.4rem); }
.thread-header__meta { display: flex; flex-wrap: wrap; gap: var(--sp-3); font-size: var(--fs-sm); color: var(--text-3); }

/* ==========================================================================
   11. Pays et frises
   ========================================================================== */

/* La silhouette a rejoint la carte d'identité : le héros n'a plus de seconde
   colonne et laisse le résumé respirer sur toute la largeur. */
.country-hero {
  position: relative;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--sp-7) var(--sp-5) var(--sp-5);
}
/* Plus de pastille autour du drapeau : il est passé à gauche du nom, dans le
   titre, et l'encadrer l'aurait fait lire comme une étiquette. Le jour où le
   dessin manque, `flag--code` porte son propre cadre — c'est là qu'est la
   règle, et il n'y a pas lieu de la redire ici. */
.country-hero h1 { margin-bottom: var(--sp-2); }
.country-hero__official {
  font-size: var(--fs-sm);
  color: var(--text-3);
  margin-bottom: var(--sp-4);
}
.country-hero__summary { font-size: var(--fs-md); color: var(--text-2); max-width: 66ch; }

.country-shape {
  display: grid; place-items: center;
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.country-shape svg { width: 100%; height: auto; max-height: 260px; }

/* Dans la carte d'identité : la carte porte déjà le cadre, la silhouette n'a
   plus qu'à poser le fond qui la détache du reste de la fiche. */
.country-shape--card {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-4);
  background: var(--surface-2);
  border-radius: var(--r-md);
}
.country-shape--card svg { max-height: 170px; }
.country-shape .shape {
  fill: url(#hoverGrad);
  stroke: var(--map-stroke-strong);
  stroke-width: 1.1;
  filter: url(#softGlow);
  transform-box: fill-box;
  transform-origin: center;
  animation: shapeIn 900ms var(--ease-out) both;
}
@keyframes shapeIn {
  from { opacity: 0; transform: scale(0.9); }
  to   { opacity: 1; transform: none; }
}

.country-grid {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--sp-5) var(--sp-8);
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: start;
}
.country-aside { display: grid; gap: var(--sp-4); position: sticky; top: 84px; }

.prose { font-size: var(--fs-md); line-height: 1.8; color: var(--text-2); }
.prose p { margin-bottom: var(--sp-4); }
.prose > h2, .prose > h3 { color: var(--text); margin-top: var(--sp-6); }

.timeline { position: relative; padding-left: var(--sp-6); }
.timeline::before {
  content: "";
  position: absolute; left: 7px; top: 8px; bottom: 8px;
  width: 2px;
  background: linear-gradient(180deg, var(--brand-1), var(--brand-2) 45%, var(--brand-3));
  opacity: 0.5;
  border-radius: 2px;
}
.tl-item { position: relative; padding-bottom: var(--sp-5); }
.tl-item::before {
  content: "";
  position: absolute;
  left: calc(var(--sp-6) * -1 + 2px);
  top: 7px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--brand-1);
  transition: transform var(--t) var(--ease-spring), border-color var(--t), box-shadow var(--t);
}
.tl-item:hover::before { transform: scale(1.4); border-color: var(--brand-2); box-shadow: 0 0 14px var(--brand-2); }
.tl-item--major::before { border-color: var(--brand-3); background: var(--brand-3); box-shadow: 0 0 12px var(--brand-3); }
.tl-item__year {
  font-family: var(--font-serif);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
  color: var(--brand-3);
}
.tl-item__era {
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-3);
  transition: color var(--t-fast);
}
.tl-item__era:hover { color: var(--brand-2); }

/* Le titre de tranche porte la période longue qui la recouvre : la liste et
   les bandes de l'axe se répondent alors, au lieu de vivre côte à côte. */
.era-block__period {
  padding: 1px 8px;
  border-radius: var(--r-full);
  font-size: 0.66rem;
  color: var(--text-2);
  background: color-mix(in oklab, var(--c) 20%, transparent);
  border: 1px solid color-mix(in oklab, var(--c) 45%, transparent);
  white-space: nowrap;
}
.era-block__title h2 {
  font-family: var(--font-serif);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tl-item h3 { margin: 2px 0 4px; font-size: var(--fs-md); font-family: var(--font-sans); }
.tl-item p { margin: 0; font-size: var(--fs-sm); color: var(--text-2); }

.era-block { margin-bottom: var(--sp-7); }
.era-block__title {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.era-block__title::after {
  content: ""; flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--border-strong), transparent);
}

.country-index { display: grid; gap: var(--sp-6); }
.country-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: var(--sp-3); }
.country-card {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast), box-shadow var(--t);
}
.country-card:hover { transform: translateY(-3px); border-color: var(--brand-1); box-shadow: var(--shadow); }
.country-card__flag { font-size: 1.6rem; line-height: 1; }

/* Le nom et la mesure sur deux lignes, toujours.

   Ils étaient tous deux en ligne, et se suivaient donc dans le même flux : la
   carte tenait sur une ligne tant que « nom + population + sièges + dépêches »
   passait dans les 176 pixels utiles. C'était vrai par chance, pas par
   construction. Mesuré : l'Allemagne débordait de cinq pixels en français, et
   la carte suivante n'avait qu'un pixel de marge. Sept cartes cassaient en
   allemand, cinq en espagnol et en italien, deux en anglais — le « ● » final
   tombait seul sur une seconde ligne, et toute la rangée grandissait avec lui.

   Élargir la grille aurait demandé de la caler sur « Bosnien und Herzegowina »,
   qui réclame 222 pixels contre 176 : une colonne perdue partout pour un cas.
   Le nom seul, lui, tient dans les cinq langues — 158 pixels au pire. Deux
   lignes fixes valent donc mieux qu'une ligne qui dépend de la longueur des
   mots. */
.country-card > span:last-child { min-width: 0; }
.country-card__name {
  display: block;
  font-weight: 600;
  font-size: var(--fs-sm);
  /* Un nom composé ne doit pas dépasser du cadre s'il grandit encore. */
  overflow-wrap: anywhere;
}
.country-card__meta { display: block; font-size: 0.66rem; color: var(--text-3); }

.heritage-list { display: grid; gap: 4px; }
.heritage-item {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm);
  padding: 4px 0;
}
.heritage-item__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.era-antiquity    { background: #d97706; }
.era-christianity { background: #a78bfa; }
.era-judaism      { background: #38bdf8; }
.era-humanism     { background: #34d399; }

/* ==========================================================================
   12. Divers
   ========================================================================== */

.page-head {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--sp-8) var(--sp-5) 0;
}
/* Un titre de page et la première section sont le même sujet : l'écart y est
   plus court qu'entre deux sections. */
.main > .page-head + .section { margin-top: var(--flow-tight); }
.page-head p { max-width: 74ch; color: var(--text-2); font-size: var(--fs-md); }

.auth-wrap {
  max-width: 460px;
  margin: var(--sp-8) auto;
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}
.auth-wrap h1 { font-size: var(--fs-2xl); }
.auth-wrap .muted { margin-bottom: var(--sp-5); }
.auth-alt { margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--border); font-size: var(--fs-sm); text-align: center; }
.auth-alt a { color: var(--brand-2); font-weight: 600; }

.pagination { display: flex; align-items: center; justify-content: center; gap: var(--sp-3); margin-top: var(--sp-6); flex-wrap: wrap; }
.pagination__list { display: flex; gap: 3px; }
.pagination__list a, .pagination__list span {
  display: grid; place-items: center;
  min-width: 34px; height: 34px; padding: 0 8px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  border: 1px solid transparent;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.pagination__list a:hover { background: var(--surface-2); border-color: var(--border); }
.pagination__list .is-current { background: var(--brand-1); color: #fff; font-weight: 700; }
.pagination__step { font-size: var(--fs-sm); color: var(--brand-2); font-weight: 600; }
.pagination__step.is-disabled { color: var(--text-3); opacity: 0.5; }
.pagination__gap { color: var(--text-3); }

.empty-state {
  padding: var(--sp-8) var(--sp-5);
  text-align: center;
  color: var(--text-3);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
}

.error-page {
  max-width: 700px;
  margin: var(--sp-9) auto;
  padding: 0 var(--sp-5);
  text-align: center;
}
.error-page__code {
  font-family: var(--font-display);
  font-weight: 200;
  letter-spacing: -0.05em;
  font-size: clamp(4.5rem, 15vw, 8.5rem);
  line-height: 0.9;
  background: linear-gradient(120deg, var(--brand-1), var(--brand-2), var(--brand-3));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  opacity: 0.85;
}

.site-footer {
  position: relative; z-index: 1;
  margin-top: var(--sp-9);
  background: color-mix(in oklab, var(--bg-2) 80%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  overflow: hidden;
}

/* Le filet du haut porte les trois couleurs de la marque plutôt qu'un gris.
   C'est la même amorce colorée que sous un titre de section : le pied de page
   n'est pas un appendice, c'est la dernière section. */
.site-footer::before {
  content: '';
  position: absolute; inset: 0 0 auto; height: 2px;
  background: linear-gradient(90deg,
      var(--brand-1) 0, var(--brand-2) 34%, var(--brand-3) 62%,
      color-mix(in oklab, var(--brand-3) 30%, transparent) 82%,
      transparent 100%);
}

/* La couronne déborde par le bas à droite : on n'en voit qu'un arc, franc,
   plutôt que douze étoiles rognées qui passeraient pour un accident. */
.site-footer::after {
  content: '';
  position: absolute;
  right: -196px; bottom: -214px;
  width: 460px; height: 460px;
  pointer-events: none;
  background: linear-gradient(150deg, var(--brand-1), var(--brand-2) 55%, var(--brand-3));
  opacity: 0.06;
  -webkit-mask-image: var(--crown);
          mask-image: var(--crown);
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
:root[data-theme="light"] .site-footer::after { opacity: 0.085; }
.site-footer__inner, .site-footer__bar { position: relative; z-index: 1; }
/* Trois colonnes, pas quatre. L'identité et les sources tiennent à gauche, où
   l'œil commence ; les sections se dédoublent au centre plutôt que de faire une
   file deux fois plus haute que ses voisines. */
.site-footer__inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--sp-7) var(--sp-5) var(--sp-5);
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1.5fr) minmax(0, 1fr);
  gap: var(--sp-6) var(--sp-7);
  /* Les trois colonnes commencent sur la même ligne. Alignées par le bas, leurs
     titres se retrouvaient à trois hauteurs différentes — « ExEuropa », puis
     « Le site » sept pixels plus bas, puis « Sections » trente de plus — et
     l'on ne voyait pas qu'il s'agissait de trois rubriques de même rang. Le
     bas reste inégal, mais c'est là que ça se voit le moins. */
  align-items: start;
}
.site-footer__brand { display: grid; gap: var(--sp-3); }
.site-footer__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3) var(--sp-5);
}

/* Ce que le site couvre, en trois nombres. Ils se lisent d'un coup d'œil et
   n'ont pas besoin de phrase. */
.site-footer__figures {
  list-style: none; margin: var(--sp-2) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
}
.site-footer__figures li {
  position: relative;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--surface) 55%, transparent);
  overflow: hidden;
}
/* Un filet de couleur par nombre : trois teintes de la marque, qui distinguent
   les trois mesures sans avoir à les encadrer davantage. */
.site-footer__figures li::before {
  content: '';
  position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--fig, var(--brand-2));
}
.site-footer__figures strong {
  display: block;
  font-size: var(--fs-lg); font-weight: 500; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text-1);
}
.site-footer__figures span { font-size: var(--fs-xs); color: var(--text-3); }
.site-footer h2 { font-size: var(--fs-sm); font-family: var(--font-sans); text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-3); }
.site-footer__brand strong { font-size: var(--fs-lg); font-weight: 500; letter-spacing: -0.03em; }
.site-footer p { font-size: var(--fs-sm); color: var(--text-2); }
.site-footer__note { font-size: var(--fs-xs); color: var(--text-3); }
/* `align-content` et non `align-items` : sans lui, la colonne de trois liens
   étire ses lignes à la hauteur de celle qui en a quatre, et les deux listes
   cessent d'être alignées l'une sur l'autre. */
.site-footer__nav ul {
  display: grid; gap: 6px; align-content: start;
  list-style: none; margin: 0; padding: 0;
}
.site-footer__nav > ul, .site-footer__cols { margin-top: var(--sp-3); }
.site-footer__nav a { font-size: var(--fs-sm); color: var(--text-2); transition: color var(--t-fast); }
.site-footer__nav a:hover { color: var(--brand-2); }
.site-footer__bar {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--sp-3) var(--sp-5) var(--sp-5);
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-3);
  font-size: var(--fs-xs); color: var(--text-3);
  border-top: 1px solid var(--border);
}
.site-footer__langs { display: flex; gap: var(--sp-3); }

@media (max-width: 860px) {
  .site-footer__inner { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
}
.site-footer__langs a { transition: color var(--t-fast); }
.site-footer__langs a:hover, .site-footer__langs a.is-active { color: var(--brand-2); }

/* ==========================================================================
   Adaptation aux petits écrans
   ========================================================================== */

@media (max-width: 1400px) {
  .map-layout { grid-template-columns: 224px minmax(0, 1fr) 330px; }
}

@media (max-width: 1200px) {
  .map-layout { grid-template-columns: minmax(0, 1fr) 320px; }
  .layer-rail {
    grid-column: 1 / -1;
    position: static;
    max-height: none;
    order: 3;
  }
  .layer-rail__body { max-height: 300px; }
  .hero { grid-template-columns: 1fr; gap: var(--sp-5); }
  .country-hero { grid-template-columns: 1fr; }
  .country-grid { grid-template-columns: 1fr; }
  .country-aside { position: static; }
  .section--split { grid-template-columns: 1fr; }
  .split__aside { position: static; }
  .site-footer__inner { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 960px) {
  .nav { display: none; }
  .nav-toggle { display: flex; }
  .search input { width: 130px; }
  .search input:focus { width: 190px; }
  .avatar-btn__name { display: none; }
  .hide-sm { display: none; }

  .map-layout { grid-template-columns: 1fr; }
  .dashboard {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    top: auto;
    max-height: 74vh;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    z-index: 80;
    transform: translateY(100%);
    transition: transform var(--t-slow) var(--ease-out);
    box-shadow: var(--shadow-lg);
  }
  .dashboard.is-open { transform: translateY(0); }
  .dashboard__empty { display: none; }
  /* Le panneau retient le défilement. En feuille posée sur la page, il flotte
     au-dessus d'elle : arrivé au bas de la fiche d'un pays, le doigt continuait
     sur l'article en dessous, qui défilait sous une feuille immobile — on
     croyait avoir cassé quelque chose. Sur un écran large, la colonne est à
     côté de la carte et non par-dessus : là, reprendre la page est le bon
     comportement, et la règle ne s'y applique pas.

     Posé sur les deux : le panneau défile, mais la feuille elle-même reçoit
     le geste quand il commence sur l'en-tête collé ou sur les boutons du bas. */
  .dashboard, .dashboard__panel { overscroll-behavior: contain; }
  .news-card--featured { grid-column: span 1; }
  .news-card--featured .news-card__title { font-size: var(--fs-md); }
}

@media (max-width: 720px) {
  :root { --sp-5: 16px; --sp-7: 32px; --sp-8: 40px; --sp-9: 56px; }
  .site-header__inner { padding: var(--sp-2) var(--sp-4); gap: var(--sp-2); }
  .brand__text small { display: none; }

  /* Le menu de langue est ancré au bord droit de son bouton. Sur un écran
     large ce bouton est loin à droite et le menu tombe dans la fenêtre ; sur
     mobile il suit la marque, à 142 pixels du bord — 250 pixels de menu
     partaient alors 44 pixels hors de l'écran, à gauche.
     Aucun ancrage sur le bouton ne tient à toutes les largeurs : à gauche il
     déborderait à droite sur les écrans les plus étroits. Le menu s'ancre
     donc sur la fenêtre. `fixed` se résout ici contre l'en-tête, qui porte un
     `backdrop-filter` et sert donc de bloc conteneur — mais l'en-tête occupe
     toute la largeur et se colle en haut : le résultat est le même, et il ne
     dépend pas de la position du bouton. */
  .dropdown__menu--lang {
    position: fixed;
    top: calc(var(--head-h, 60px) + 6px);
    left: var(--sp-4); right: var(--sp-4);
    min-width: 0; width: auto;
  }
  .search { display: none; }
  .stat-strip { grid-template-columns: repeat(2, 1fr); }
  .thread-row { grid-template-columns: auto minmax(0, 1fr); }
  .thread-row__counts { display: none; }
  .post { grid-template-columns: 48px minmax(0, 1fr); gap: var(--sp-3); }
  .site-footer__inner { grid-template-columns: 1fr; }

  /* Les trois nombres se lisent ensemble ou ne se lisent pas : ils disent une
     couverture, et c'est leur voisinage qui la donne à voir. À 434 pixels il
     s'en fallait de neuf pour que la troisième carte tienne — elle passait à
     la ligne, seule, et perdait la comparaison. Trois parts égales de ce qui
     reste, `min-width: 0` pour qu'une part puisse être plus étroite que son
     texte, et la légende se replie sur deux lignes plutôt que de déborder. */
  .site-footer__figures { flex-wrap: nowrap; gap: var(--sp-2); }
  .site-footer__figures li {
    flex: 1 1 0; min-width: 0;
    padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  }
  /* La carte masque ce qui dépasse : sans césure, l'allemand
     « Lesesprachen » se ferait couper en silence sous 300 pixels. */
  .site-footer__figures span { line-height: 1.3; overflow-wrap: break-word; }

  .flash-stack { left: var(--sp-4); right: var(--sp-4); max-width: none; }
  .kv-grid { grid-template-columns: 1fr; }
  /* Empilés, les trois blocs n'ont plus de bas commun à tenir. */
  .map-layout { --map-col-h: auto; }
  .mapwrap { height: auto; max-height: none; }
  .map { max-height: 70vh; }

  /* En colonne étroite les blocs s'empilent : côte à côte, ils tiendraient
     sur trois mots chacun. Et la légende n'a plus de bornes : trois couches
     lui font dépasser trois cents pixels, et chaque case cochée pousse tout
     ce qui la suit vers le bas. Elle défile donc dans son propre cadre — la
     page garde sa hauteur, et cocher une couche ne déplace plus rien.
     `nowrap` n'est pas décoratif : en colonne, un `wrap` hérité range ce qui
     dépasse la hauteur dans une seconde colonne, à côté. Avec une hauteur
     bornée, la légende se mettait à déborder en largeur — texte coupé et
     barre horizontale — au lieu de défiler. */
  .map__legend {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: var(--sp-3);
    max-height: 34vh;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .legend-block { max-width: none; }
  .legend-block + .legend-block {
    padding-left: 0; border-left: 0;
    padding-top: var(--sp-3); border-top: 1px solid var(--border);
  }
}

/* ==========================================================================
   Histoire : axe de densité, contexte, comparaison
   ========================================================================== */

/* -- L'axe du temps --------------------------------------------------------- */

.tlaxis { margin-bottom: var(--sp-6); }
.tlaxis__chart {
  position: relative;
  height: 120px;
  margin-top: var(--sp-3);
  border-bottom: 1px solid var(--border-strong);
}
.tlaxis__bar {
  position: absolute;
  bottom: 0;
  height: var(--h);
  min-width: 2px;
  border-radius: 2px 2px 0 0;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--brand-1) 85%, transparent),
    color-mix(in oklab, var(--brand-1) 25%, transparent));
  transition: background var(--t-fast), transform var(--t-fast) var(--ease-spring);
  transform-origin: bottom;
}
.tlaxis__bar.has-major {
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--brand-3) 90%, transparent),
    color-mix(in oklab, var(--brand-3) 20%, transparent));
}
.tlaxis__bar:hover, .tlaxis__bar:focus-visible {
  transform: scaleY(1.06);
  background: var(--brand-2);
}

/* Les bandes de période s'empilent par couloir : sans cela, la Renaissance
   recouvrirait les Réformes, qui se chevauchent réellement. */
.tlaxis__periods { position: relative; height: 66px; margin-top: 3px; }
.tlaxis__period {
  position: absolute;
  top: calc(var(--lane) * 21px);
  height: 18px;
  display: flex; align-items: center;
  padding: 0 6px;
  overflow: hidden;
  white-space: nowrap;
  border-radius: var(--r-xs);
  font-size: 0.64rem;
  letter-spacing: 0.02em;
  color: var(--text-2);
  background: color-mix(in oklab, var(--c) 22%, transparent);
  border: 1px solid color-mix(in oklab, var(--c) 45%, transparent);
  transition: background var(--t-fast), color var(--t-fast);
}
.tlaxis__period:hover { background: color-mix(in oklab, var(--c) 45%, transparent); color: var(--text); }

.tlaxis__scale {
  display: flex; justify-content: space-between;
  margin-top: var(--sp-2);
  font-family: var(--font-serif);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
}

.input--year { max-width: 110px; font-variant-numeric: tabular-nums; }

/* -- Les cartes d'événement ------------------------------------------------- */

.tl-item__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); margin: 0; }
.tl-item__kind {
  padding: 1px 7px;
  border-radius: var(--r-full);
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--k, var(--text-3));
  border: 1px solid color-mix(in oklab, var(--k, var(--border-strong)) 45%, transparent);
}
.tl-item__country { font-size: var(--fs-xs); color: var(--text-3); }
/* Deux pays co-titulaires d'un même fait : le point les sépare sans les
   hiérarchiser, là où une virgule ferait du second une précision du premier. */
.tl-item__and { margin: 0 3px; opacity: .6; }
.tl-item__foot { margin-top: 6px !important; font-size: var(--fs-xs); }

/* Chaque nature a sa couleur : la frise se lit alors aussi par thème, et pas
   seulement de gauche à droite. */
.tl-item--treaty      { --k: var(--brand-2); }
.tl-item--battle      { --k: var(--danger); }
.tl-item--text        { --k: var(--brand-3); }
.tl-item--institution { --k: var(--brand-1); }
.tl-item--person      { --k: var(--accent); }
.tl-item--discovery   { --k: var(--success); }
.tl-item--schism      { --k: #a78bfa; }
.tl-item--disaster    { --k: var(--warning); }
.tl-item[class*="tl-item--"]:not(.tl-item--major)::before { border-color: var(--k, var(--brand-1)); }

/* -- La page d'un événement ------------------------------------------------- */

.hevent__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--sp-6);
  align-items: start;
}
.hevent__side { display: grid; gap: var(--sp-4); position: sticky; top: 88px; }
.hevent__head { margin-bottom: var(--sp-4); }
.hevent__date { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3); margin: 0; }
.hevent__year {
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-variant-numeric: tabular-nums;
  color: var(--brand-3);
}
.hevent__place { margin: 4px 0 0; font-size: var(--fs-sm); color: var(--text-3); }

.hchain { margin: var(--sp-6) 0; }
.hchain__side + .hchain__side { margin-top: var(--sp-4); }
.hchain__label {
  margin: 0 0 6px;
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-3);
}
.hchain ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.hchain__item {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  padding: 8px 10px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: var(--fs-sm);
}
.hchain__relation {
  font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--brand-2);
}
.hchain__year { font-family: var(--font-serif); color: var(--text-3); font-variant-numeric: tabular-nums; }
.hchain__note { flex: 1 1 100%; font-size: var(--fs-xs); color: var(--text-3); }

.hmeanwhile { margin: var(--sp-6) 0; }
.hmeanwhile__list { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: 5px; }
.hmeanwhile__list li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm);
}
.hmeanwhile__gap {
  min-width: 62px;
  font-family: var(--font-serif);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.hmeanwhile__gap.is-before { color: var(--brand-1); }
.hmeanwhile__gap.is-after  { color: var(--brand-2); }
.hmeanwhile__gap.is-same   { color: var(--brand-3); }
.hmeanwhile__country { font-size: var(--fs-xs); color: var(--text-3); }

.hperiods { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.hperiods li {
  display: grid; gap: 2px;
  padding-left: 10px;
  border-left: 3px solid var(--c, var(--brand-1));
}
.hperiods__range {
  font-family: var(--font-serif); font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs); color: var(--text-3);
}
.hperiods__summary { font-size: var(--fs-xs); color: var(--text-2); line-height: 1.55; }

/* -- Deux pays, une échelle -------------------------------------------------- */

/* Les deux colonnes partagent les mêmes lignes : l'alignement est porté par la
   grille elle-même, donc exact, et rien ne se recouvre puisque chaque tranche
   prend la hauteur qu'il lui faut. */
.hcompare { margin-top: var(--sp-4); }
.hcompare__head,
.hcompare__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 132px minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
}
.hcompare__head { margin-bottom: var(--sp-3); }
.hcompare__head h2 {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  margin: 0; font-size: var(--fs-lg);
}
.hcompare__head h2:last-child { text-align: left; }

.hcompare__row { padding: var(--sp-3) 0; border-top: 1px solid var(--border); }
.hcompare__gutter {
  display: grid; gap: 2px; justify-items: center; text-align: center;
  padding: 4px 6px;
  border-radius: var(--r-sm);
  border-top: 3px solid var(--c);
  background: var(--surface-2);
}
.hcompare__slice {
  font-family: var(--font-serif); font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs); color: var(--brand-3);
  line-height: 1.35;
}
.hcompare__period { font-size: 0.62rem; color: var(--text-3); line-height: 1.3; }

.hcompare__side { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.hcompare__event a {
  display: grid; gap: 1px;
  padding: 5px 8px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  font-size: var(--fs-sm);
  transition: background var(--t-fast), border-color var(--t-fast);
}
.hcompare__event a:hover { background: var(--surface-2); border-color: var(--border); }
.hcompare__event.is-major a { border-left: 2px solid var(--brand-3); border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.hcompare__year {
  font-family: var(--font-serif); font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs); color: var(--brand-3);
}
.hcompare__title { color: var(--text-2); line-height: 1.4; }

/* ==========================================================================
   Modération et signalement
   ========================================================================== */

.mod-role {
  padding: 10px 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: var(--fs-sm);
  color: var(--text-2);
}
.mod-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--sp-4) 0; }

.mod-queue { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.mod-item {
  display: grid; gap: var(--sp-3);
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface);
  border-left: 3px solid var(--border-strong);
}
.mod-item--reported { border-left-color: var(--danger); }
.mod-item--held     { border-left-color: var(--warning); }
.mod-item--flagged  { border-left-color: var(--brand-2); }

.notice--warning {
  border-color: color-mix(in oklab, var(--warning) 45%, transparent);
  color: var(--warning);
}

.trust { display: grid; gap: 4px; margin: 0 0 var(--sp-3); text-align: left; }
.trust__level {
  font-family: var(--font-serif);
  font-size: var(--fs-md);
  color: var(--brand-3);
}

.mod-item__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3);
  font-size: var(--fs-xs); color: var(--text-3);
}
.mod-item__origin { font-weight: 600; color: var(--text-2); }
.mod-item__type { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.62rem; }
.mod-item__status { padding: 1px 7px; border-radius: var(--r-full); border: 1px solid var(--border-strong); }
.mod-item__status.is-hidden     { color: var(--danger);  border-color: var(--danger); }
.mod-item__status.is-pending    { color: var(--warning); border-color: var(--warning); }
.mod-item__status.is-published  { color: var(--success); border-color: var(--success); }
.mod-item__status.is-restricted { color: var(--danger);  border-color: var(--danger); }

.mod-item__body { display: grid; gap: 6px; }
.mod-item__title { margin: 0; font-size: var(--fs-md); }
.mod-item__excerpt {
  margin: 0;
  padding: 8px 12px;
  border-left: 2px solid var(--border-strong);
  font-size: var(--fs-sm);
  color: var(--text-2);
  white-space: pre-wrap;
  word-break: break-word;
}
.mod-item__author { margin: 0; font-size: var(--fs-xs); color: var(--text-3); }

.mod-item__signals { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 5px; }
.mod-signal {
  padding: 2px 8px;
  border-radius: var(--r-full);
  font-size: 0.66rem;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
}
.mod-signal--weight { color: var(--text); border-color: var(--border-strong); }
.mod-signal--reason { color: var(--danger); border-color: color-mix(in oklab, var(--danger) 45%, transparent); }
.mod-signal--spam   { color: var(--warning); border-color: color-mix(in oklab, var(--warning) 45%, transparent); }

.mod-item__actions { display: flex; flex-wrap: wrap; gap: 6px; }
.mod-item__actions form { margin: 0; }

.mod-log { margin-top: var(--sp-7); }
.mod-log__list { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: 4px; }
.mod-log__list li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-2);
}
.mod-log__action { font-weight: 600; color: var(--text); }
.mod-log__action--hide, .mod-log__action--restrict { color: var(--danger); }
.mod-log__action--restore, .mod-log__action--publish { color: var(--success); }
.mod-log__target { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-3); }
.mod-log__list time { margin-left: auto; font-size: var(--fs-xs); color: var(--text-3); }

/* Le signalement reste discret jusqu'au survol : présent, mais sans inviter
   au clic réflexe. */
.report-link {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 6px;
  font-size: var(--fs-xs);
  color: var(--text-3);
  opacity: 0.55;
  transition: opacity var(--t-fast), color var(--t-fast);
}
.report-link:hover, .report-link:focus-visible { opacity: 1; color: var(--danger); }
.comment:hover .report-link, .post:hover .report-link { opacity: 0.85; }

.btn--danger {
  color: var(--danger);
  border-color: color-mix(in oklab, var(--danger) 50%, transparent);
  background: color-mix(in oklab, var(--danger) 10%, transparent);
}
.btn--danger:hover {
  color: #fff;
  background: var(--danger);
  border-color: var(--danger);
}

/* ==========================================================================
   Champ-piège
   ==========================================================================
   Il doit rester dans le flux du document — un `display: none` serait ignoré
   par les automates les plus courants, qui savent le détecter. On l'écarte
   donc visuellement sans le retirer, et `aria-hidden` le soustrait aux
   lecteurs d'écran.
   ========================================================================== */

.hp-field {
  position: absolute !important;
  left: -9999px !important;
  top: auto !important;
  width: 1px !important; height: 1px !important;
  overflow: hidden !important;
}

@media (max-width: 900px) {
  .hevent__layout { grid-template-columns: 1fr; }
  .hevent__side { position: static; }
  .hcompare__head, .hcompare__row { grid-template-columns: minmax(0, 1fr) 74px minmax(0, 1fr); gap: var(--sp-2); }
  .hcompare__title { font-size: var(--fs-xs); }
  .tlaxis__chart { height: 90px; }
  .mod-log__list time { margin-left: 0; }
}

/* ==========================================================================
   Programmes politiques
   ========================================================================== */

/* -- La liste ---------------------------------------------------------------- */

.prog-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--sp-4); }
.prog-card {
  display: grid; gap: var(--sp-3); align-content: start;
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow);
  transition: transform var(--t) var(--ease), border-color var(--t);
}
.prog-card:hover { transform: translateY(-3px); border-color: var(--border-strong); }
/* Un programme officiel se distingue au premier regard : le lecteur doit
   savoir s'il lit une formation politique ou un citoyen. */
.prog-card--official { border-left: 3px solid var(--brand-3); }

.prog-card__head {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin: 0; font-size: var(--fs-xs); color: var(--text-3);
}
.prog-card__kind {
  padding: 1px 8px; border-radius: var(--r-full);
  border: 1px solid var(--border-strong);
  text-transform: uppercase; letter-spacing: 0.07em; font-size: 0.6rem;
}
.prog-card__draft { color: var(--warning); }
.prog-card h2 { margin: 0; font-size: var(--fs-md); line-height: 1.3; }

/* Des rangées de même hauteur d'une carte à l'autre.
 *
 * Sans elles, un titre sur deux lignes ou une présentation plus longue
 * décalait les pastilles de thème et le pied de la carte, et la grille se
 * lisait de travers. Chaque rangée est donc bornée par le nombre de lignes
 * qu'elle occupe, et remplie jusqu'à ce nombre quand elle en occupe moins.
 *
 * C'est ce qui a motivé une présentation de longueur régulière : la borne ne
 * coupe presque rien quand tous les textes font la même taille. */
.prog-card__head { min-height: calc(var(--fs-xs) * 1.6); }
.prog-card__title h3 {
  /* Interligne en pixels et hauteur exactement double : un titre d'une ligne
     et un titre de deux occupent alors la même boîte. Avec un interligne
     relatif, l'arrondi du navigateur laissait un pixel d'écart, et ce pixel
     désalignait toute la suite de la carte. */
  --lh: 21px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: var(--lh); height: calc(2 * var(--lh));
}
.prog-card__summary {
  margin: 0; font-size: var(--fs-sm); color: var(--text-2); line-height: 1.6;
  --lines: 9;
  display: -webkit-box; -webkit-line-clamp: var(--lines); -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(var(--fs-sm) * 1.6 * var(--lines));
}
/* Deux rangées de pastilles, toujours : au-delà, le « +N » prend le relais.
   Une hauteur fixe ici aligne aussi le pied de toutes les cartes. */
.prog-card__themes {
  --chip-h: 20px;
  height: calc(2 * var(--chip-h) + 4px);
  overflow: hidden;
}

/* Dix crans, un par chapitre : la complétude se lit sans chiffre. */
.prog-card__gauge { position: relative; display: flex; gap: 3px; }
.prog-card__tick {
  flex: 1; height: 5px; border-radius: 3px;
  background: color-mix(in oklab, var(--c) 22%, transparent);
}
.prog-card__ticks-done {
  position: absolute; inset: 0 auto 0 0;
  width: calc(var(--n) / var(--t) * 100%);
  border-radius: 3px;
  background: linear-gradient(90deg, var(--brand-1), var(--brand-2));
  opacity: 0.75;
  pointer-events: none;
}

.prog-card__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  margin: 0; font-size: var(--fs-xs); color: var(--text-3);
}
.prog-card__avatar { border-radius: 50%; }
.prog-card__flags { color: var(--warning); }

.prog__group {
  padding: 1px 8px; border-radius: var(--r-full);
  font-size: 0.66rem; font-weight: 600;
  color: var(--c); border: 1px solid color-mix(in oklab, var(--c) 55%, transparent);
  background: color-mix(in oklab, var(--c) 14%, transparent);
}

/* -- La page d'un programme --------------------------------------------------- */

/* L'en-tête ouvre la colonne de gauche : le haut de la colonne de droite se
   trouve alors à la hauteur du titre, et non sous le résumé. */
.prog__head { margin-bottom: var(--sp-2); }
.prog__head h1 { margin-bottom: var(--sp-3); }
.prog__summary { font-size: var(--fs-md); color: var(--text-2); max-width: 68ch; line-height: 1.7; }
.prog__by {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--text-3);
}
.prog__by img { border-radius: 50%; }

.prog__layout {
  display: grid; grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-6); align-items: start;
}
/* La colonne suit le lecteur, et le menu des thèmes en occupe le haut : c'est
   ce qui rend la navigation disponible pendant toute la lecture. Elle défile
   sur elle-même quand elle dépasse l'écran — sinon le bas de la colonne, où
   vivent la boussole et les programmes proches, deviendrait inatteignable. */
.prog__side {
  display: grid; gap: var(--sp-4); align-content: start;
  /* La colonne fait la largeur de sa piste, jamais celle de son contenu : une
     seule adresse insécable — un identifiant Mastodon, par exemple — suffirait
     sinon à élargir toutes les cartes, et le défilement vertical rognerait
     alors leur bord droit. */
  grid-template-columns: minmax(0, 1fr);
  position: sticky; top: calc(var(--head-h, 64px) + 12px);
  max-height: calc(100vh - var(--head-h, 64px) - 28px);
  /* `overflow-y: auto` seul rendrait l'axe horizontal défilant à son tour :
     posé explicitement, il coupe au lieu d'ouvrir une barre inutile. */
  overflow-x: hidden;
  /* Pas d'`overscroll-behavior: contain` : arrivé au bas de la colonne, le
     défilement doit reprendre la page. L'enfermer ici donnerait l'impression
     d'une page bloquée dès que le pointeur passe à droite. */
  overflow-y: auto;
  scrollbar-width: thin;
  padding-right: 2px;
}
.prog__main { display: grid; gap: var(--sp-5); }
.prog__gauge-label { margin: 0 0 6px; font-size: var(--fs-sm); color: var(--text-2); }

/* -- Un chapitre --------------------------------------------------------------- */

.pchapter {
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--c);
  background: var(--surface);
}
/* Un chapitre vide reste affiché : ce qu'un programme ne dit pas se lit aussi. */
.pchapter--empty { background: transparent; border-left-color: color-mix(in oklab, var(--c) 30%, transparent); }
.pchapter--empty .pchapter__head h2 { color: var(--text-3); }

.pchapter__head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.pchapter__head h2 { margin: 0; font-size: var(--fs-lg); }
.pchapter__meta { font-size: var(--fs-xs); color: var(--text-3); }
.pchapter__title { margin: 0 0 var(--sp-3); font-size: var(--fs-md); color: var(--text); }
.pchapter__body { font-size: var(--fs-base); }

.pchapter__edit, .pchapter__talk { margin-top: var(--sp-4); }
.pchapter__edit > summary, .pchapter__talk > summary {
  cursor: pointer; font-size: var(--fs-sm); color: var(--text-2);
  padding: 6px 0; list-style: none;
}
.pchapter__edit > summary::-webkit-details-marker,
.pchapter__talk > summary::-webkit-details-marker { display: none; }
.pchapter__edit > summary::before, .pchapter__talk > summary::before { content: "› "; color: var(--brand-2); }
.pchapter__edit[open] > summary::before, .pchapter__talk[open] > summary::before { content: "⌄ "; }
.pchapter__edit > summary:hover, .pchapter__talk > summary:hover { color: var(--brand-2); }
.pchapter__edit form { margin-top: var(--sp-3); }

/* -- Annotations ---------------------------------------------------------------- */

.pchapter__flags, .pflags { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: grid; gap: var(--sp-3); }
.pflag {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-3);
  background: var(--surface-2);
  font-size: var(--fs-sm);
  scroll-margin-top: 90px;
}
.pflag--info     { border-left-color: var(--brand-2); }
.pflag--caution  { border-left-color: var(--warning); }
.pflag--blocking { border-left-color: var(--danger); }
/* Écartée, jamais effacée : une objection supprimée est une objection suspecte. */
.pflag.is-dismissed { opacity: 0.55; }
.pflag.is-dismissed .pflag__label { text-decoration: line-through; }

.pflag__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  margin: 0 0 4px; font-size: 0.66rem; color: var(--text-3);
}
.pflag__kind { text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-2); }
.pflag__severity { padding: 0 7px; border-radius: var(--r-full); border: 1px solid var(--border-strong); }
.pflag--caution  .pflag__severity { color: var(--warning); border-color: var(--warning); }
.pflag--blocking .pflag__severity { color: var(--danger);  border-color: var(--danger); }
.pflag__label { margin: 0; font-weight: 600; color: var(--text); }
.pflag__detail { margin: 4px 0 0; color: var(--text-2); line-height: 1.6; }
.pflag__ref { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--brand-3); font-family: var(--font-serif); }
.pflag__excerpt {
  margin: var(--sp-2) 0 0; padding: 4px 10px;
  border-left: 2px solid var(--border-strong);
  font-size: var(--fs-xs); color: var(--text-3); font-style: italic;
}
.pflag__dismissed { margin: var(--sp-2) 0 0; font-size: var(--fs-xs); color: var(--text-3); }
.pflag__dismiss { margin-top: var(--sp-2); }
.pflag__dismiss summary { cursor: pointer; font-size: var(--fs-xs); color: var(--text-3); }
.pflag__dismiss summary:hover { color: var(--danger); }
.pflag__dismiss form { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.pflag__dismiss .input { flex: 1 1 220px; }

.pannots { margin-top: var(--sp-6); }
.pannots__add { margin-top: var(--sp-4); }
.pannots__add > summary { cursor: pointer; font-size: var(--fs-sm); color: var(--text-2); }
.pannots__add form { margin-top: var(--sp-3); }

/* -- Colonne : voisins et co-auteurs -------------------------------------------- */

.pneighbours { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-3); }
.pneighbours li { display: grid; gap: 2px; padding-left: 10px; border-left: 2px solid var(--border-strong); }
.pneighbours__score { font-size: var(--fs-xs); color: var(--brand-2); }
.pneighbours__terms { font-size: 0.66rem; color: var(--text-3); line-height: 1.4; }
.pneighbours__compare { font-size: var(--fs-xs); }

.peditors { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-2); }
.peditors li { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.peditors li img { border-radius: 50%; }
.peditors li form { margin-left: auto; }
.peditors__add { display: flex; gap: 6px; margin-top: var(--sp-3); }
.peditors__add .input { flex: 1; }

/* -- Comparaison ---------------------------------------------------------------- */

.pcompare { margin-top: var(--sp-4); }
.pcompare__head, .pcompare__row {
  display: grid; grid-template-columns: minmax(0, 1fr) 150px minmax(0, 1fr);
  gap: var(--sp-4); align-items: start;
}
.pcompare__head { margin-bottom: var(--sp-3); }
.pcompare__head h2 { margin: 0; font-size: var(--fs-md); display: grid; gap: 2px; }
.pcompare__head h2 .muted { font-size: var(--fs-xs); }

.pcompare__row { padding: var(--sp-4) 0; border-top: 1px solid var(--border); }
.pcompare__gutter {
  display: grid; gap: 3px; justify-items: center; text-align: center;
  padding: 6px; border-radius: var(--r-sm);
  border-top: 3px solid var(--c);
  background: var(--surface-2);
}
.pcompare__topic { font-size: var(--fs-sm); color: var(--text); }
.pcompare__score { font-family: var(--font-serif); font-size: var(--fs-md); color: var(--brand-2); }
.pcompare__shared { font-size: 0.62rem; color: var(--text-3); line-height: 1.35; }

.pcompare__cell { font-size: var(--fs-sm); color: var(--text-2); }
.pcompare__cell.is-empty { opacity: 0.5; }
.pcompare__title { margin: 0 0 6px; font-weight: 600; color: var(--text); }
/* Le texte comparé est borné : au-delà, on ouvre le chapitre. */
.pcompare__text { max-height: 260px; overflow: hidden; position: relative; line-height: 1.6; }
.pcompare__text::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 60px;
  background: linear-gradient(180deg, transparent, var(--bg));
  pointer-events: none;
}
.pcompare__text p { margin-bottom: var(--sp-3); }
.pcompare__link { margin: 6px 0 0; font-size: var(--fs-xs); }
.pcompare__silence { margin: 0; font-style: italic; font-size: var(--fs-sm); color: var(--text-3); }

@media (max-width: 980px) {
  .prog__layout { grid-template-columns: 1fr; }
  .pcompare__head, .pcompare__row { grid-template-columns: minmax(0, 1fr) 96px minmax(0, 1fr); gap: var(--sp-2); }
  .pcompare__text { max-height: 180px; }
}

/* -- Thèmes trouvés ------------------------------------------------------------ */

/* La pastille grandit avec la place que le thème occupe : la hiérarchie se lit
   avant qu'on ait lu un seul libellé. */
.ptheme-bar { margin-top: var(--sp-5); }
.ptheme-bar__label {
  margin: 0 0 var(--sp-2);
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-3);
}
.ptheme-bar__list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.ptheme {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 4px 12px;
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  color: var(--text);
  border: 1px solid color-mix(in oklab, var(--c) 55%, transparent);
  background: linear-gradient(90deg,
              color-mix(in oklab, var(--c) 26%, transparent) var(--w),
              color-mix(in oklab, var(--c) 8%, transparent) var(--w));
  transition: border-color var(--t-fast), transform var(--t-fast);
}
.ptheme:hover { border-color: var(--c); transform: translateY(-1px); }
.ptheme__count { font-size: 0.66rem; color: var(--text-3); font-variant-numeric: tabular-nums; }

.ptheme-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 4px 12px;
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  color: var(--text-2);
  border: 1px solid var(--border);
  background: var(--surface-2);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.ptheme-chip:hover { color: var(--text); border-color: color-mix(in oklab, var(--c) 60%, transparent); }
.ptheme-chip.is-on {
  color: var(--text);
  border-color: var(--c);
  background: color-mix(in oklab, var(--c) 22%, transparent);
}
.ptheme-chip__count { font-size: 0.66rem; color: var(--text-3); font-variant-numeric: tabular-nums; }
.pthemes { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }

/* -- Qui parle de quoi ---------------------------------------------------------- */

.pfinder {
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  margin-bottom: var(--sp-5);
}
.pfinder h2 { margin: 0 0 4px; font-size: var(--fs-lg); }
.pfinder__form { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.pfinder__form .input { flex: 1 1 260px; }

.ppassage-list { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: grid; gap: var(--sp-3); }
.ppassage {
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  border-left: 3px solid var(--c);
  background: var(--surface);
}
.ppassage__who {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin: 0 0 6px; font-size: var(--fs-xs); color: var(--text-3);
}
.ppassage__who img { border-radius: 50%; }
.ppassage__kind, .ppassage__theme {
  padding: 1px 8px; border-radius: var(--r-full);
  border: 1px solid var(--border-strong);
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.06em;
}
.ppassage__theme { color: var(--c); border-color: color-mix(in oklab, var(--c) 55%, transparent); }
.ppassage__title { margin: 0 0 6px; font-size: var(--fs-md); }
.ppassage__from { font-size: var(--fs-xs); color: var(--text-3); margin-left: 6px; }
.ppassage__excerpt {
  margin: 0; font-size: var(--fs-sm); color: var(--text-2); line-height: 1.7;
  padding-left: 10px; border-left: 2px solid var(--border);
}

/* -- Sommaire et parties -------------------------------------------------------- */

.ptoc {
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.ptoc__label {
  margin: 0 0 var(--sp-2);
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-3);
}
.ptoc ol { margin: 0; padding-left: var(--sp-4); display: grid; gap: 4px; }
.ptoc li { font-size: var(--fs-sm); }
.ptoc__theme { font-size: 0.62rem; color: var(--c); margin-left: 6px; }

.pchapter__theme {
  padding: 1px 8px; border-radius: var(--r-full);
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--c); border: 1px solid color-mix(in oklab, var(--c) 50%, transparent);
}
.pchapter__theme--side { color: var(--text-3); border-color: var(--border); text-transform: none; }
/* Le point signale un thème reconnu plutôt que choisi : la nuance compte pour
   qui lit une comparaison. */
.pchapter__auto { opacity: 0.7; }
.pchapter__tools { display: flex; align-items: flex-start; gap: var(--sp-3); margin-top: var(--sp-4); }
.pchapter__tools .pchapter__edit { flex: 1; margin-top: 0; }
.pchapter__move { display: flex; gap: 4px; }
.pchapter__move button { font-size: var(--fs-md); padding: 0 6px; }
.pchapter__move button[disabled] { opacity: 0.3; cursor: default; }
.pchapter--add { border-left-color: var(--brand-2); background: var(--surface-2); }
.pchapter--add h2 { font-size: var(--fs-lg); margin: 0 0 4px; }

.psection-form { margin-top: var(--sp-3); }

.prog-card__themes {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: 4px;
}
.prog-card__themes li {
  /* Hauteur posée, pas déduite d'un rembourrage : c'est elle qui fixe celle de
     la rangée, et une rangée dont la hauteur dépend d'un padding se déplace au
     premier changement de police. */
  height: var(--chip-h); line-height: calc(var(--chip-h) - 2px);
  padding: 0 8px; border-radius: var(--r-full);
  font-size: 0.62rem; color: var(--c);
  border: 1px solid color-mix(in oklab, var(--c) 45%, transparent);
}
.prog-card__themes-more { color: var(--text-3) !important; border-color: var(--border) !important; }

.pcompare__part + .pcompare__part { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px dashed var(--border); }
.pcompare__title a { color: var(--text); }

/* -- Menu des thèmes ------------------------------------------------------------ */

/* Il colle sous l'en-tête : sur un programme de dix parties, la navigation doit
   rester à portée sans qu'on remonte. */
.pmenu {
  /* Le menu ne colle plus de lui-même : c'est la colonne qui suit le lecteur,
     et deux collants imbriqués se disputeraient le même bord. */
  z-index: 4;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  /* Opaque, sans flou d'arrière-plan : le menu passe devant le texte du
     programme pendant qu'on descend, et un fond translucide y laissait lire
     deux phrases superposées. Le flou ne rattrape rien — il n'est pas rendu
     partout, et là où il l'est le résultat reste illisible. */
  background: var(--surface-solid);
  box-shadow: var(--shadow-lg, var(--shadow));
}
.pmenu__label {
  margin: 0 0 6px;
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-3);
}
.pmenu__list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 5px; }
.pmenu__cell { flex: 1 1 auto; }
.pmenu__item { flex: 1 1 auto; }
.pmenu__item {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 4px 11px;
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  color: var(--text-2);
  border: 1px solid color-mix(in oklab, var(--c) 40%, transparent);
  background: color-mix(in oklab, var(--c) 10%, transparent);
  transition: color var(--t-fast), background var(--t-fast), border-color var(--t-fast);
}
.pmenu__item:hover, .pmenu__item:focus-visible {
  color: var(--text);
  background: color-mix(in oklab, var(--c) 26%, transparent);
  border-color: var(--c);
}
.pmenu__count { font-size: 0.66rem; color: var(--text-3); font-variant-numeric: tabular-nums; }
.pmenu__actions { display: flex; gap: var(--sp-3); margin-top: 8px; }
.pmenu__actions .link-button { font-size: var(--fs-xs); }

/* -- Un thème : le pli, puis ce qui l'entoure ------------------------------------- */

/* Chaque thème est un objet distinct, séparé du suivant par du vide plutôt que
   par un trait : c'est l'espace qui fait lire une page comme une suite de
   blocs, pas la multiplication des bordures. */
.pgroup { margin-bottom: var(--sp-6); }

.ptheme-block {
  border-radius: var(--r-lg);
  border: 1px solid color-mix(in oklab, var(--c) 30%, var(--border));
  background: var(--surface);
  box-shadow: var(--shadow);
  /* Pas de `overflow: hidden` : il empêcherait le titre de rester collé en
     haut de l'écran pendant qu'on lit le thème. Les coins sont donc arrondis
     sur le titre lui-même. */
}

/* Le titre porte la couleur du thème et reste collé en haut pendant la
   lecture : sur un chapitre de six mille signes, on oublie sinon dans quel
   thème on se trouve. Le fond est un mélange faible — il identifie sans
   écraser — et le texte garde son contraste dans les deux thèmes clair et
   sombre, d'où `--text` et non une couleur posée en dur. */
.ptheme-block__head {
  /* Collé exactement sous l'en-tête du site, sans un pixel d'écart : la
     hauteur vient de `--head-h`, mesurée au chargement. Devinée, elle laissait
     une bande où le texte défilait à découvert. */
  position: sticky; top: var(--head-h, 64px); z-index: 3;
  display: grid; gap: 8px;
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  cursor: pointer;
  list-style: none;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  border-left: 5px solid var(--c);
  background: linear-gradient(
    to right,
    color-mix(in oklab, var(--c) 22%, var(--surface-solid)),
    color-mix(in oklab, var(--c) 8%, var(--surface-solid))
  );
  transition: padding var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.ptheme-block__head::-webkit-details-marker { display: none; }
details:not([open]) > .ptheme-block__head { border-radius: var(--r-lg); }
.ptheme-block__head:hover {
  background: linear-gradient(
    to right,
    color-mix(in oklab, var(--c) 32%, var(--surface-solid)),
    color-mix(in oklab, var(--c) 14%, var(--surface-solid))
  );
}
.ptheme-block__top {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3);
}

/* Grand tant qu'il est à sa place, discret dès qu'il monte se coller : un
   titre de deux centimètres bloqué en haut de l'écran mangerait la lecture
   qu'il est censé accompagner. */
.ptheme-block__name {
  font-size: clamp(1.55rem, 3.2vw, 2.2rem);
  font-weight: 600; color: var(--text);
  letter-spacing: var(--ls-title); line-height: 1.15;
  transition: font-size var(--t) var(--ease);
}
.ptheme-block__meta { font-size: var(--fs-xs); color: var(--text-2); }
.ptheme-block__chevron {
  margin-left: auto; color: var(--text-2);
  transition: transform var(--t) var(--ease);
}
details[open] > .ptheme-block__head .ptheme-block__chevron { transform: rotate(180deg); }

/* La ligne de résumé : elle porte tout le travail du repli. Un bloc fermé qui
   n'annonce rien fait déplier au hasard, et le repli n'a servi à rien. */
.ptheme-block__digest {
  font-size: var(--fs-md); color: var(--text-2); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* L'état collé, posé par `initProgrammeThemes()`. */
.ptheme-block__head.is-stuck {
  padding: 10px var(--sp-5);
  border-radius: 0;
  box-shadow: 0 10px 24px -18px rgba(0, 0, 0, 0.7);
}
/* Le titre collé fait plafond : le texte disparaît en l'atteignant au lieu de
   passer derrière et de continuer plus haut. L'en-tête du site est translucide
   — c'est son parti pris partout ailleurs — et laissait donc lire les lignes
   qui montaient sous lui ; ce cache opaque se glisse entre les deux, sous
   l'en-tête et au-dessus du texte. */
.ptheme-block__head.is-stuck::before {
  content: '';
  position: absolute;
  left: -5px; right: 0;          /* jusqu'au bord de la barre de couleur */
  top: calc(-1 * var(--head-h, 64px));
  height: var(--head-h, 64px);
  background: var(--bg);
  pointer-events: none;
}
.ptheme-block__head.is-stuck .ptheme-block__name { font-size: var(--fs-md); }
.ptheme-block__head.is-stuck .ptheme-block__digest { display: none; }

.ptheme-block__body { padding: var(--sp-5); display: grid; gap: var(--sp-4); }

/* Le préambule : ce qu'on voit avant de lire. */
.ptheme-block__embeds { display: grid; gap: var(--sp-3); }
.ptheme-block__embed { position: relative; }
.ptheme-block__unembed { position: absolute; top: 6px; right: 10px; }
.ptheme-block__unembed .link-button { font-size: var(--fs-xs); }
.ptheme-block__add-embed > summary {
  cursor: pointer; font-size: var(--fs-sm); color: var(--text-3); padding: 4px 0;
}
.ptheme-block__add-embed > summary:hover { color: var(--brand-2); }
.ptheme-block__add-embed form { margin-top: var(--sp-3); }

/* Un thème abordé par des parties dont il n'est pas le sujet principal. */
.ptheme-block__mentions {
  margin: 0; padding: 0 0 var(--sp-2);
  font-size: var(--fs-sm); color: var(--text-3);
  display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
}
.ptheme-block__mentions a { color: var(--text-2); }
.ptheme-block__mentions a:not(:last-child)::after { content: ','; color: var(--text-3); }

/* Dans un bloc de thème, la partie n'a plus besoin de son propre cadre. */
.ptheme-block .pchapter {
  padding: 0 0 var(--sp-4);
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  /* En plus de la marge globale : le titre du thème restera collé au-dessus
     d'elle, et occupe cette hauteur-là. */
  scroll-margin-top: 48px;
}
.ptheme-block .pchapter:last-of-type { border-bottom: 0; padding-bottom: 0; }
.ptheme-block .pchapter__head h3 { margin: 0; font-size: var(--fs-lg); }

/* -- Hors du pli : contrôles et discussion ---------------------------------------- */

/* Même largeur que le thème : ces deux bandes lui appartiennent, un décalage
   les ferait passer pour un ajout de second rang. */
.ptheme-foot { display: grid; gap: 3px; margin-top: 3px; }
.pstrip {
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  border-left: 5px solid color-mix(in oklab, var(--c) 45%, var(--border));
  background: var(--surface-2);
}
.pstrip > summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 10px var(--sp-4);
  cursor: pointer;
  font-size: var(--fs-sm); color: var(--text-2);
  list-style: none;
}
.pstrip > summary::-webkit-details-marker { display: none; }
.pstrip > summary:hover { color: var(--text); }
.pstrip[open] > summary { border-bottom: 1px solid var(--border); }
.pstrip__hint { font-size: var(--fs-xs); color: var(--text-3); font-style: italic; }
.pstrip .pchapter__flags,
.pstrip .comment-list,
.pstrip .comment-form,
.pstrip .comments__notice { margin: var(--sp-4); }

/* Chaque contrôle s'ouvre pour lui-même : l'intitulé suffit à savoir si l'on
   veut lire ce qu'il suppose, et six annotations dépliées prendraient plus de
   place que le chapitre qu'elles accompagnent. */
.pflag--fold { padding: 0; }
.pflag--fold > details > summary {
  cursor: pointer; list-style: none;
  padding: 10px var(--sp-4);
}
.pflag--fold > details > summary::-webkit-details-marker { display: none; }
.pflag--fold > details > summary:hover { background: var(--surface); }
.pflag--fold .pflag__summary .pflag__label { margin-bottom: 0; }
.pflag--fold .pflag__body { padding: 0 var(--sp-4) var(--sp-4); }
.pflag--fold > details[open] > summary { border-bottom: 1px dashed var(--border); }

/* Le point d'information : gris, discret, jamais alarmant. Un contrôle de
   faisabilité n'est pas un avertissement. */
.i-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; flex: 0 0 16px;
  border-radius: 50%;
  border: 1px solid var(--text-3);
  color: var(--text-3);
  font-size: 0.62rem; font-weight: 700; font-style: italic;
  line-height: 1;
}
.pchapter__note {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--text-3); text-decoration: none;
  font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
}
.pchapter__note:hover { color: var(--text-2); }
.pchapter__note:hover .i-dot { border-color: var(--text-2); color: var(--text-2); }

.comment__about { font-size: var(--fs-xs); color: var(--text-3); }

@media (max-width: 980px) {
  /* En colonne unique, la colonne de droite se disperse : `display: contents`
     rend ses cartes au fil de la page, et le menu des thèmes remonte en tête.
     Renvoyé en bas avec le reste, il n'aurait plus servi à rien — on n'ouvre
     pas un sommaire après avoir lu. */
  .prog__side { display: contents; }
  .prog__side > * { order: 2; }
  .prog__side > .pmenu { order: 0; position: sticky; top: var(--head-h, 64px); }
  .prog__main { order: 1; }

  /* Le titre du thème ne colle plus : sur un écran étroit, il mangerait le
     quart de la hauteur disponible. */
  .ptheme-block__head { position: static; }
  .ptheme-block__name { font-size: clamp(1.35rem, 6vw, 1.8rem); }
  /* Le titre ne colle plus : la marge globale suffit. */
  .ptheme-block .pchapter { scroll-margin-top: 0; }
}

/* ==========================================================================
   Accessibilité : mouvement réduit et impression
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .aurora__blob { animation: none; }
}

@media print {
  .aurora, .site-header, .site-footer, .map__controls, .layer-rail,
  .dashboard, .reply-box, .pagination { display: none !important; }
  body { background: #fff; color: #000; }
  .reveal { opacity: 1; transform: none; }
}

/* -- Où écrire quoi : tribune, débat ou programme --------------------------------- */

.wwrite {
  margin-top: var(--sp-6);
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: var(--surface);
}
.wwrite__title {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-md); font-weight: 500;
  letter-spacing: var(--ls-title);
}
.wwrite__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.wwrite__item {
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-2);
}
/* La surface courante n'est pas un lien : on y est déjà. */
.wwrite__item.is-current { border-color: var(--brand-1); background: var(--surface-solid); }
.wwrite__name {
  display: inline-block; font-weight: 500; color: var(--text);
  text-decoration: none;
}
a.wwrite__name:hover, a.wwrite__name:focus-visible { color: var(--brand-2); text-decoration: underline; }
.wwrite__here {
  margin-left: 6px;
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--brand-2);
}
.wwrite__what { margin: 6px 0 0; font-size: var(--fs-sm); color: var(--text-2); }
.wwrite__when { margin: 6px 0 0; font-size: var(--fs-xs); color: var(--text-3); font-style: italic; }
.wwrite__note { margin: var(--sp-4) 0 0; font-size: var(--fs-xs); color: var(--text-3); }

/* -- Les thèmes propres à un programme -------------------------------------------- */

.pthemes {
  margin-bottom: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px dashed var(--border-strong);
  background: var(--surface-2);
}
.pthemes > summary {
  cursor: pointer; font-size: var(--fs-sm); color: var(--text-2); padding: 2px 0;
}
.pthemes > summary:hover { color: var(--brand-2); }
.pthemes .hint { margin: var(--sp-3) 0 0; }
.pthemes__list {
  list-style: none; margin: var(--sp-3) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
}
.pthemes__item {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--c) 45%, transparent);
  background: color-mix(in oklab, var(--c) 12%, transparent);
  font-size: var(--fs-sm);
}
.pthemes__item form { display: inline; }
.pthemes__item .link-button { font-size: var(--fs-xs); color: var(--text-3); }
.pthemes__add { display: flex; gap: var(--sp-3); margin-top: var(--sp-3); flex-wrap: wrap; }
.pthemes__add .input { flex: 1 1 220px; }

/* Le porteur nommé et l'origine de la présentation. */
.prog__org { margin: 4px 0 0; color: var(--text-2); font-size: var(--fs-md); }
.prog__summary-src {
  margin: 4px 0 0;
  font-size: var(--fs-xs); color: var(--text-3); font-style: italic;
}

/* Un thème abordé par des parties dont il n'est pas le sujet principal. */
.ptheme-block__mentions {
  margin: 0; padding: var(--sp-3) 0 0;
  font-size: var(--fs-sm); color: var(--text-3);
  display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
}
.ptheme-block__mentions a { color: var(--text-2); }
.ptheme-block__mentions a:not(:last-child)::after { content: ','; color: var(--text-3); }

/* -- Le menu des thèmes, unique ---------------------------------------------------- */

.pmenu__cell { position: relative; display: flex; align-items: stretch; }
.pmenu__item {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 10px 7px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm); text-decoration: none;
  color: var(--text-2);
  border: 1px solid color-mix(in oklab, var(--c) 40%, transparent);
  background:
    /* La barre de poids, sous la pastille : elle dit la place que le thème
       occupe dans le programme, ce que le compteur de parties ne dit pas. */
    linear-gradient(to right, var(--c) var(--w, 0%), transparent var(--w, 0%))
      bottom left / 100% 3px no-repeat,
    color-mix(in oklab, var(--c) 10%, transparent);
  transition: color var(--t-fast), background-color var(--t-fast), border-color var(--t-fast);
}
.pmenu__item:hover, .pmenu__item:focus-visible {
  color: var(--text);
  background-color: color-mix(in oklab, var(--c) 26%, transparent);
  border-color: var(--c);
}
.pmenu__name { font-weight: 500; }
.pmenu__count { font-size: 0.66rem; color: var(--text-3); font-variant-numeric: tabular-nums; }
/* Le renvoi vers les autres programmes du même thème : présent, pas encombrant. */
.pmenu__elsewhere {
  align-self: center; margin-left: 2px; padding: 0 4px;
  font-size: 0.7rem; color: var(--text-3); text-decoration: none;
}
.pmenu__elsewhere:hover { color: var(--brand-2); }
.pmenu__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: baseline; margin-top: 10px; }
.pmenu__actions .link-button { font-size: var(--fs-xs); }
.pmenu__hint { font-size: var(--fs-xs); color: var(--text-3); font-style: italic; }

/* -- La boussole : radar et jauge --------------------------------------------------- */

.pcompass__radar { width: 100%; height: auto; margin: var(--sp-3) 0; overflow: visible; }
.pcompass__ring { fill: none; stroke: var(--border); stroke-width: 1; }
.pcompass__ring.is-origin { stroke: var(--border-strong); stroke-dasharray: 3 3; }
.pcompass__spoke { stroke: var(--border); stroke-width: 1; }
.pcompass__shape {
  fill: color-mix(in oklab, var(--brand-1) 30%, transparent);
  stroke: var(--brand-1); stroke-width: 2; stroke-linejoin: round;
}
.pcompass__axis { fill: var(--text-2); font-size: 11px; }

.pcompass__legend { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: grid; gap: 6px; }
.pcompass__row { display: grid; grid-template-columns: 5.5rem 1fr; gap: 8px; align-items: center; }
.pcompass__name { font-size: var(--fs-xs); color: var(--text-2); }
.pcompass__pole { grid-column: 2; font-size: var(--fs-xs); color: var(--text-3); }
.pcompass__bar {
  grid-column: 2; position: relative; height: 6px;
  border-radius: 3px; background: var(--surface-2);
}
/* L'origine au milieu : un score négatif part vers la gauche, un positif vers
   la droite. Une barre qui remplirait toujours depuis la gauche ferait passer
   « intervention publique » pour un petit « marché ». */
.pcompass__bar::before {
  content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px;
  width: 1px; background: var(--border-strong);
}
.pcompass__fill {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: var(--v, 0%);
  border-radius: 3px;
  background: var(--brand-1);
}
.pcompass__fill.is-minus { left: auto; right: 50%; background: var(--brand-2); }

.pcompass__gauge { margin-top: var(--sp-4); text-align: center; }
.pcompass__gauge svg { width: 160px; max-width: 100%; height: auto; }
.pcompass__gauge-track {
  fill: none; stroke: var(--surface-2); stroke-width: 10; stroke-linecap: round;
}
.pcompass__gauge-fill {
  fill: none; stroke: var(--brand-1); stroke-width: 10; stroke-linecap: round;
  stroke-dasharray: var(--p, 0) 201;
}
.pcompass__needle { stroke: var(--text); stroke-width: 2; stroke-linecap: round; }
.pcompass__pin { fill: var(--text); }
.pcompass__gauge-value { fill: var(--text); font-size: 15px; font-weight: 600; }
.pcompass__gauge-label { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--text-3); }

.pcompass__terms { margin-top: var(--sp-4); }
.pcompass__terms > summary { cursor: pointer; font-size: var(--fs-sm); color: var(--text-3); }
.pcompass__terms > summary:hover { color: var(--brand-2); }
.pcompass__words { display: flex; flex-wrap: wrap; gap: 5px; margin: var(--sp-3) 0 0; }
.pcompass__words span {
  padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface-2);
  font-size: var(--fs-xs); color: var(--text-2);
}
.pcompass__caveat { margin: var(--sp-4) 0 0; font-size: var(--fs-xs); color: var(--text-3); }
.pcompass__consent { margin-top: var(--sp-4); }
.pcompass__buttons { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }

/* -- Emblème, adhésion, réseaux de l'auteur ---------------------------------------- */

.prog__title { display: flex; align-items: flex-start; gap: var(--sp-4); }
.prog__logo {
  flex: 0 0 auto;
  width: 64px; height: 64px;
  object-fit: contain;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 6px;
}

/* L'adhésion : le geste que la page attend du lecteur convaincu. */
.pjoin { text-align: center; }
.pjoin__count { margin: 0 0 var(--sp-3); display: grid; gap: 2px; }
.pjoin__count strong {
  font-size: var(--fs-2xl); font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--brand-2);
}
.pjoin__count span { font-size: var(--fs-xs); color: var(--text-3); }
.pjoin .hint { margin-top: var(--sp-3); text-align: left; }
.pjoin__private {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-xs); color: var(--text-3); text-align: left;
}

/* Les réseaux : des liens, rien de chargé depuis les plateformes. */
.plinks__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.plinks__item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  border: 1px solid color-mix(in oklab, var(--c) 40%, transparent);
  background: color-mix(in oklab, var(--c) 9%, transparent);
}
.plinks__item > a {
  display: flex; align-items: baseline; gap: 8px; flex: 1 1 auto;
  min-width: 0; text-decoration: none; color: var(--text);
}
.plinks__item > a:hover .plinks__handle { color: var(--brand-2); }
.plinks__net { flex: 0 0 auto; font-size: var(--fs-sm); font-weight: 500; }
.plinks__handle {
  /* `min-width: 0` sur le lien ne suffit pas : c'est cet élément-ci qui doit
     accepter de descendre sous la largeur de son texte pour que les points de
     suspension apparaissent. */
  flex: 0 1 auto; min-width: 0;
  font-size: var(--fs-xs); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.plinks__item form { display: flex; }
.plinks__item .link-button { font-size: var(--fs-md); color: var(--text-3); line-height: 1; }
.plinks__add { margin-top: var(--sp-3); }
.plinks__add > summary { cursor: pointer; font-size: var(--fs-sm); color: var(--text-3); }
.plinks__add > summary:hover { color: var(--brand-2); }

.plogo__preview {
  width: 64px; height: 64px; object-fit: contain;
  border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--surface-2); padding: 6px;
}
.plogo form { margin-top: var(--sp-3); }

@media (max-width: 720px) {
  .prog__title { gap: var(--sp-3); }
  .prog__logo { width: 48px; height: 48px; }
}
.prog__org-tag {
  display: inline-block; margin-right: 6px;
  padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--border-strong);
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-3); vertical-align: 2px;
}

/* Emblème et auteur sur la fiche d'un programme. */
.prog-card__title { display: flex; align-items: flex-start; gap: var(--sp-3); }
.prog-card__title h3 { margin: 0; }
.prog-card__logo {
  flex: 0 0 auto; width: 40px; height: 40px; object-fit: contain;
  border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface-2); padding: 3px;
}
.prog-card__author { display: inline-flex; align-items: center; gap: 5px; color: inherit; text-decoration: none; }
.prog-card__author:hover { color: var(--brand-2); }
.pchapter__author { color: var(--text-3); text-decoration: none; }
.pchapter__author:hover { color: var(--brand-2); text-decoration: underline; }
/* L'emblème dessiné se distingue d'un logo déposé : il n'a pas de cadre. */
.prog__logo--drawn { border-color: transparent; background: transparent; padding: 0; }

/* Les programmes d'un membre, sur sa page. */
.mprog-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.mprog {
  display: flex; align-items: flex-start; gap: var(--sp-4);
  padding: var(--sp-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: var(--surface);
}
.mprog__logo {
  flex: 0 0 auto; width: 44px; height: 44px; object-fit: contain;
  border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface-2); padding: 3px;
}
.mprog__main { min-width: 0; }
.mprog__title { margin: 0; font-weight: 500; }
.mprog__title a { color: var(--text); text-decoration: none; }
.mprog__title a:hover { color: var(--brand-2); }
.mprog__org { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--text-2); }
.mprog__meta { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--text-3); }

/* -- La passerelle vers le dépôt officiel ----------------------------------------- */

.pfiling { margin-top: var(--sp-6); }
.pfiling__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3);
  margin-bottom: var(--sp-2);
}
.pfiling__head h2 { margin: 0; font-size: var(--fs-lg); }
.pfiling__route {
  padding: 2px 10px; border-radius: var(--r-full);
  border: 1px solid var(--brand-1);
  font-size: var(--fs-xs); color: var(--brand-2);
}
.pfiling__filed { margin-top: var(--sp-4); }

.pfiling__steps { list-style: none; margin: var(--sp-5) 0 0; padding: 0; display: grid; gap: var(--sp-4); }
.pfiling__step { display: flex; align-items: flex-start; gap: var(--sp-3); }
/* Trois états, trois marques. Rien d'alarmant : une condition qui manque
   n'est pas une faute, c'est une étape. */
.pfiling__mark {
  flex: 0 0 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%; border: 1px solid var(--border-strong);
  font-size: 0.7rem; color: var(--text-3);
}
.is-done .pfiling__mark { border-color: var(--success); color: var(--success); }
.is-info .pfiling__mark { font-style: italic; }
.pfiling__what { margin: 0; font-weight: 500; font-size: var(--fs-sm); }
.is-done .pfiling__what { color: var(--text); }
.pfiling__detail {
  margin-left: 6px; padding: 1px 8px; border-radius: var(--r-full);
  border: 1px solid var(--border); font-size: var(--fs-xs); color: var(--text-3);
  font-weight: 400; font-variant-numeric: tabular-nums;
}
.pfiling__why { margin: 3px 0 0; font-size: var(--fs-sm); color: var(--text-2); }
.pfiling__ref { margin: 3px 0 0; font-size: var(--fs-xs); color: var(--text-3); font-style: italic; }

.pfiling__dossier { margin-top: var(--sp-5); }
.pfiling__dossier > summary { cursor: pointer; font-size: var(--fs-sm); color: var(--text-2); }
.pfiling__dossier > summary:hover { color: var(--brand-2); }
.pfiling__fields { margin: var(--sp-4) 0 0; display: grid; gap: var(--sp-3); }
.pfiling__field {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.pfiling__field dt {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-3);
}
.pfiling__field dd {
  margin: 4px 0 0; display: flex; align-items: baseline; gap: var(--sp-3);
  font-size: var(--fs-sm); color: var(--text);
}
.pfiling__value { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.pfiling__field .link-button { flex: 0 0 auto; font-size: var(--fs-xs); }

.pfiling__actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4);
  margin-top: var(--sp-5);
}
.pfiling__count { font-size: var(--fs-sm); color: var(--text-2); }
.pfiling__owner {
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px dashed var(--border-strong);
  display: grid; gap: var(--sp-4);
}
.pfiling__caveat { margin: var(--sp-4) 0 0; font-size: var(--fs-xs); color: var(--text-3); }

/* -- Le sujet : un pays, ou l'Europe ---------------------------------------------- */

.scope {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 8px; border-radius: var(--r-full);
  border: 1px solid var(--border);
  font-size: 0.68rem; color: var(--text-3);
  text-decoration: none; white-space: nowrap;
}
a.scope:hover { color: var(--text); border-color: var(--border-strong); }
/* Le sujet européen se distingue du sujet national : c'est la différence qu'on
   veut voir, et un simple drapeau absent ne la disait pas. */
.scope--europe {
  color: var(--brand-2);
  border-color: color-mix(in oklab, var(--brand-1) 40%, transparent);
  background: color-mix(in oklab, var(--brand-1) 10%, transparent);
}

/* -- Encarts de littérature -------------------------------------------------------- */

.litbox {
  margin: var(--sp-5) 0 0;
  padding: var(--sp-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand-3, var(--brand-1));
  background:
    radial-gradient(120% 140% at 0% 0%,
      color-mix(in oklab, var(--brand-3, var(--brand-1)) 9%, transparent), transparent 62%),
    var(--surface);
}
.litbox__label {
  margin: 0 0 var(--sp-3);
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--text-3);
}
.litbox__quote {
  margin: 0; padding: 0; border: 0;
  font-size: var(--fs-lg); line-height: 1.55;
  font-style: italic; color: var(--text);
  /* Les guillemets font partie de la citation, pas du texte : ils sont posés
     ici pour que la copie du passage n'en emporte pas. */
  quotes: '«\00a0' '\00a0»';
}
.litbox__quote::before { content: open-quote; color: var(--text-3); }
.litbox__quote::after  { content: close-quote; color: var(--text-3); }

/* La mention de traduction se lit sans se disputer la place avec le texte :
   elle dit qui parle, elle n'est pas ce qu'on vient lire. */
.litbox__rendered,
.qaside__rendered {
  margin: var(--sp-3) 0 0;
  padding-top: var(--sp-2);
  border-top: 1px dashed var(--border);
  font-size: var(--fs-xs); color: var(--text-3);
  font-style: italic;
}
.qaside__rendered { margin-top: var(--sp-2); }

.litbox__original { margin-top: var(--sp-3); }
.litbox__original > summary { cursor: pointer; font-size: var(--fs-xs); color: var(--text-3); }
.litbox__original > summary:hover { color: var(--brand-2); }
.litbox__original p {
  margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--text-2); font-style: italic;
}

.litbox__cite {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  margin-top: var(--sp-4); font-size: var(--fs-sm); color: var(--text-2);
}
.litbox__author { font-weight: 600; color: var(--text); }
.litbox__work { font-style: italic; }
.litbox__year { color: var(--text-3); font-variant-numeric: tabular-nums; }
.litbox__pd {
  padding: 1px 8px; border-radius: var(--r-full);
  border: 1px solid var(--border); font-size: 0.62rem; color: var(--text-3);
  cursor: help;
}
.litbox__note { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--text-2); }
.litbox__source { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--text-3); }

/* La tranche repliée au bord gauche de l'axe : ce qui précède les sources
   continues, compté et atteignable, sans manger la moitié de la largeur. */
.tlaxis__folded {
  position: absolute; left: 0; bottom: 0;
  display: grid; place-items: center;
  width: 18px; height: 100%;
  border-right: 1px dashed var(--border-strong);
  color: var(--text-3); text-decoration: none;
  font-size: var(--fs-sm); line-height: 1;
}
.tlaxis__folded:hover { color: var(--brand-2); background: var(--surface-2); }

/* -- Un passage de littérature en colonne ----------------------------------------- */

.qaside {
  margin: 0;
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand-3, var(--brand-1));
  background:
    radial-gradient(120% 140% at 0% 0%,
      color-mix(in oklab, var(--brand-3, var(--brand-1)) 8%, transparent), transparent 60%),
    var(--surface);
}
.qaside__label {
  margin: 0 0 var(--sp-3);
  font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--text-3);
}
.qaside__quote {
  margin: 0; padding: 0; border: 0;
  font-size: var(--fs-sm); line-height: 1.6;
  font-style: italic; color: var(--text);
  quotes: '«\00a0' '\00a0»';
}
.qaside__quote::before { content: open-quote; color: var(--text-3); }
.qaside__quote::after  { content: close-quote; color: var(--text-3); }
.qaside__cite {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
  margin-top: var(--sp-3); font-size: var(--fs-xs);
}
.qaside__author { font-weight: 600; color: var(--text); }
.qaside__year { color: var(--text-3); font-variant-numeric: tabular-nums; }
.qaside__work {
  margin: 2px 0 0; font-size: var(--fs-xs); color: var(--text-3);
  font-style: italic;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: help;
}

/* ==========================================================================
   Écran cathodique
   ==========================================================================

   Un voile, pas un filtre. Trois couches très faibles posées par-dessus la
   page : des lignes de balayage, un très léger halo aux angles, et une trame
   de masque d'ombre. Rien qui touche au texte lui-même — un flou de phosphore
   sur des caractères de treize pixels les rendrait illisibles, et l'effet
   n'aurait alors coûté que la lecture.

   Le voile ne reçoit aucun clic (`pointer-events: none`), ne s'imprime pas, et
   disparaît pour qui demande moins de mouvement ou plus de contraste : un
   décor n'a pas à s'imposer à qui l'a refusé.

   Le voile n'a pas d'interrupteur : c'est un parti pris, pas une option, et
   une préférence qu'on n'a pas prévue de changer n'a pas besoin d'un bouton.
   Il s'efface là où il gênerait, et cela suffit. */

body::after {
  content: '';
  position: fixed; inset: 0;
  z-index: 9999;
  pointer-events: none;

  background:
    /* Lignes de balayage : une claire, une sombre, toutes les trois lignes. */
    repeating-linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0.025) 0px,
      rgba(255, 255, 255, 0.025) 1px,
      rgba(0, 0, 0, 0.035) 1px,
      rgba(0, 0, 0, 0.035) 3px
    ),
    /* Masque d'ombre : la trame verticale des tubes à fentes. */
    repeating-linear-gradient(
      to right,
      rgba(255, 0, 60, 0.014) 0px,
      rgba(0, 255, 120, 0.014) 1px,
      rgba(60, 90, 255, 0.014) 2px,
      transparent 3px
    ),
    /* Halo d'angle : le verre bombé assombrissait les bords. */
    radial-gradient(120% 100% at 50% 50%,
      transparent 58%, rgba(0, 0, 0, 0.10) 100%);
}

/* Sur fond clair, le masque d'ombre vire au sale : seules les lignes de
   balayage et le halo restent, deux fois plus discrets. */
:root[data-theme="light"] body::after {
  background:
    repeating-linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.018) 0px,
      rgba(0, 0, 0, 0.018) 1px,
      transparent 1px,
      transparent 3px
    ),
    radial-gradient(120% 100% at 50% 50%,
      transparent 62%, rgba(40, 30, 20, 0.06) 100%);
}

@media (prefers-reduced-motion: reduce), (prefers-contrast: more), print {
  body::after { display: none; }
}

/* ==========================================================================
   Politique : formations, partis, portée nationale ou européenne
   ========================================================================== */

/* -- Les formations d'un pays, repliées ------------------------------------ */

.country-parties {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: var(--sp-3);
}

.cparty {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}
.cparty[open] { border-color: var(--border-strong); }

.cparty__head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) 64px auto;
  align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  list-style: none;
}
.cparty__head::-webkit-details-marker { display: none; }
.cparty__head:hover { background: var(--surface-2); }

.cparty__flag { font-size: 1.1rem; }
.cparty__name { font-weight: 600; font-size: var(--fs-sm); }

/* La barre d'un pays reprend les couleurs du Parlement : deux échelles
   différentes, une seule légende, et la comparaison se fait à l'œil. */
.cparty__bar {
  display: flex; height: 8px; border-radius: 4px; overflow: hidden;
  background: var(--surface-2);
}
.cparty__bar > span { display: block; height: 100%; }

.cparty__seats {
  font-size: var(--fs-xs); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.cparty__list {
  list-style: none; margin: 0;
  padding: 0 var(--sp-4) var(--sp-3);
  border-top: 1px solid var(--border);
}
.cparty__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto 28px;
  align-items: center; gap: var(--sp-2);
  padding: 6px 0;
}
.cparty__row + .cparty__row { border-top: 1px solid var(--border); }

.cparty__link {
  display: flex; align-items: center; gap: var(--sp-2);
  min-width: 0; color: inherit; text-decoration: none;
}
.cparty__link:hover .cparty__abbr { color: var(--brand-2); }
.cparty__emblem { border-radius: 5px; flex: 0 0 auto; }
.cparty__abbr { font-weight: 600; font-size: var(--fs-xs); white-space: nowrap; }
.cparty__full {
  font-size: 0.68rem; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}

.cparty__group {
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.02em;
  padding: 2px 7px; border-radius: var(--r-pill);
  color: var(--g); border: 1px solid color-mix(in oklab, var(--g) 45%, transparent);
  background: color-mix(in oklab, var(--g) 12%, transparent);
  white-space: nowrap;
}
.cparty__n {
  font-size: var(--fs-xs); color: var(--text-3); text-align: right;
  font-variant-numeric: tabular-nums;
}

/* -- La page d'une formation ----------------------------------------------- */

.party-head {
  display: flex; align-items: center; gap: var(--sp-5);
  margin: var(--sp-4) 0 var(--sp-3);
}
.party-head__text { min-width: 0; }
.party-head__text h1 { margin: 2px 0; }
.party-head__country a {
  font-size: var(--fs-sm); color: var(--text-2); text-decoration: none;
}
.party-head__country a:hover { color: var(--brand-2); }
.party-head__abbr {
  margin: 0; font-size: var(--fs-sm); color: var(--text-3); font-weight: 600;
}
.party-head__group {
  margin: var(--sp-2) 0 0; font-size: var(--fs-sm);
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
}
.party-head__dot {
  width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
}

.party-grid {
  display: grid;
  /* Trois cent quarante, comme les autres colonnes latérales du site : la
     liste des formations voisines y tient ses sigles sans les couper. */
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-6);
  align-items: start;
}
/* La piste explicite, et non `auto` : une grille dont la colonne se dimensionne
   sur son contenu s'élargit au-delà de la place qu'on lui a donnée, et la
   colonne latérale débordait alors de trente-six pixels sur la droite. Le même
   piège que sur la page d'un programme, et le même remède. */
.party-side {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4); min-width: 0;
}
.party-side > * { min-width: 0; }

.party-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--sp-4); margin: 0 0 var(--sp-3);
}
.party-figures dt { font-size: var(--fs-xs); color: var(--text-3); }
.party-figures dd {
  margin: 2px 0 0; font-size: var(--fs-xl); font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.pgroup-block + .pgroup-block { margin-top: var(--sp-3); }
.pgroup-block__head {
  display: flex; align-items: center; gap: 7px;
  margin: 0 0 4px; font-size: var(--fs-xs);
}
.pgroup-block__head .muted { margin-left: auto; }
.pgroup-block__list {
  display: flex; flex-wrap: wrap; gap: 5px;
  list-style: none; margin: 0; padding: 0;
}
.pgroup-block__list li { font-size: 0.68rem; }
.pgroup-block__list a { color: var(--text-2); text-decoration: none; }
.pgroup-block__list a:hover { color: var(--brand-2); }
.pgroup-block__list .is-current { font-weight: 700; color: var(--text); }

/* -- National ou Europe ----------------------------------------------------- */

.scope-tabs__bar {
  display: flex; gap: var(--sp-2);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-4);
}
.scope-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 14px;
  background: none; border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  font: inherit; font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-3); cursor: pointer;
  transition: color var(--t) var(--ease), border-color var(--t) var(--ease);
}
.scope-tab:hover { color: var(--text); }
.scope-tab.is-active { color: var(--text); border-bottom-color: var(--brand-2); }
.scope-tab__count {
  font-size: 0.62rem; font-weight: 700;
  padding: 1px 6px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.scope-tab.is-active .scope-tab__count {
  background: color-mix(in oklab, var(--brand-2) 18%, transparent);
  color: var(--brand-2);
}

.proposals { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.proposal { padding-left: var(--sp-4); border-left: 2px solid var(--border); }
.proposal__title { margin: 5px 0 4px; font-size: var(--fs-md); }
.proposal__body { margin: 0; font-size: var(--fs-sm); color: var(--text-2); }
.proposal__source { font-size: var(--fs-xs); }

.party-sync { margin-top: var(--sp-4); }

/* Quand rien n'a été relevé, l'onglet ne montre pas un vide : il montre où le
   programme se trouve. L'emblème à gauche dit de qui il s'agit — la formation
   pour le national, le groupe européen pour l'Europe — et évite de confondre
   les deux. */
.elsewhere {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.elsewhere__emblem {
  width: 64px; height: 64px;
  border-radius: 14px;
  object-fit: contain;
  background: #fff;
  border: 1px solid var(--border);
}
.elsewhere__text { min-width: 0; }
.elsewhere__text p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-2);
  text-wrap: pretty;
}
.elsewhere__link {
  margin-top: var(--sp-3);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

@media (max-width: 560px) {
  .elsewhere { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 900px) {
  .party-grid { grid-template-columns: minmax(0, 1fr); }
  .party-head { gap: var(--sp-4); }
  .cparty__head { grid-template-columns: auto minmax(0, 1fr) auto; }
  .cparty__bar { display: none; }
}

/* -- L'hémicycle ------------------------------------------------------------
   Le dessin et sa légende côte à côte : l'un se lit en couleurs, l'autre en
   chiffres, et les chercher sur deux écrans différents annulerait le gain. */

.hemi-card {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(262px, 0.7fr);
  gap: clamp(var(--sp-5), 4vw, var(--sp-7));
  align-items: center;
  padding: clamp(var(--sp-5), 3vw, var(--sp-7));
}

.hemi { position: relative; margin: 0; min-width: 0; }
.hemi__svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Un siège survolé nomme son groupe, et les autres s'effacent : sept cent
   vingt cercles ne se distinguent qu'en en éteignant sept cent. */
.hemi__seat { transition: opacity var(--t) var(--ease); }
.hemi-card.is-focusing .hemi__seat { opacity: 0.16; }
.hemi-card.is-focusing .hemi__seat.is-lit { opacity: 1; }

/* Le décompte occupe le creux de l'arc, pas la place d'un siège. */
.hemi__core {
  position: absolute;
  left: 50%; bottom: 2%;
  transform: translateX(-50%);
  display: grid; justify-items: center; gap: 1px;
  text-align: center; pointer-events: none;
}
.hemi__total {
  font-size: clamp(2rem, 4.4vw, 2.9rem); line-height: 1;
  font-weight: 700; font-variant-numeric: tabular-nums;
}
.hemi__label {
  font-size: var(--fs-xs); color: var(--text-3);
  text-transform: lowercase; letter-spacing: 0.06em;
}
.hemi__majority {
  margin-top: 5px;
  font-size: var(--fs-xs); color: var(--text-3);
  padding: 2px 10px; border-radius: var(--r-pill);
  border: 1px dashed var(--border-strong);
}

/* Le choix de la législature, dans l'en-tête de la section. `margin-left: auto`
   le pousse à droite, du côté où l'on va chercher une commande, sans lui
   donner une ligne à lui : il commande l'hémicycle, il doit rester à sa
   hauteur. */
.hemi-terms {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-left: auto;
  font-size: var(--fs-sm);
}
.hemi-terms label { color: var(--text-3); }
.hemi-terms .select { width: auto; padding: 6px 10px; font-size: var(--fs-sm); }
.hemi-terms .btn { padding: 6px var(--sp-3); font-size: var(--fs-sm); }
/* Le bouton n'a plus d'utilité quand le script envoie le formulaire tout seul,
   mais il reste dans le document : c'est lui qui sert sans JavaScript. Le site
   marque l'absence de script par `no-js` sur la racine, retiré au démarrage —
   d'où la négation, et non une classe `js` qui n'existe pas. */
html:not(.no-js) .hemi-terms .btn { display: none; }
@media (max-width: 720px) {
  .hemi-terms { margin-left: 0; width: 100%; }
  .hemi-terms .select { flex: 1 1 auto; }
}

.hemi-legend { display: grid; gap: 2px; min-width: 0; }

.glegend {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr) 44px 52px;
  align-items: center; gap: var(--sp-3);
  padding: 5px var(--sp-3);
  border-radius: var(--r-sm);
  cursor: default;
  transition: background var(--t) var(--ease);
}
.glegend:hover { background: var(--surface-2); }
.glegend__dot { width: 12px; height: 12px; border-radius: 3px; }
.glegend__name { min-width: 0; display: grid; }
.glegend__name strong { font-size: var(--fs-sm); }
.glegend__full {
  font-size: 0.68rem; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.glegend__seats {
  text-align: right; font-weight: 700; font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
.glegend__share {
  text-align: right; font-size: var(--fs-xs); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* -- La respiration de la page ---------------------------------------------
   Trois blocs de nature différente — un dessin, une grille de pays, une liste
   de programmes. L'écart se règle ici par la marge seule : les sections
   portaient déjà soixante-quatre pixels de rembourrage haut et bas, et ajouter
   une marge par-dessus doublait ce qu'on croyait ajuster. */

.section__lead {
  margin: calc(var(--sp-3) * -1) 0 var(--sp-5);
  max-width: 62ch;
  font-size: var(--fs-sm); color: var(--text-2);
}

@media (max-width: 1000px) {
  .hemi-card { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  .hemi { max-width: 560px; margin: 0 auto; }
}


/* ==========================================================================
   Vocabulaire graphique commun
   ==========================================================================

   Deux marques, posées en CSS et non dans les gabarits : elles s'appliquent
   donc à toutes les pages à la fois, et une page nouvelle les reçoit sans
   qu'on y pense. C'est la condition pour qu'une identité tienne — celle qu'on
   doit se rappeler d'ajouter finit toujours par manquer quelque part. */

/* -- Le filigrane de l'en-tête de page --------------------------------------
   La couronne de l'emblème, très pâle, en haut à droite. Un repère de marque,
   pas une illustration : elle ne dit rien du contenu et n'a donc pas à se
   faire remarquer. */

.page-head { position: relative; overflow: hidden; }
.page-head::after {
  content: '';
  position: absolute;
  /* La couronne déborde du coin : on n'en voit qu'un arc, franc, plutôt que
     des étoiles rognées sur deux bords qui passeraient pour un accident. */
  top: -108px; right: -108px;
  width: 320px; height: 320px;
  pointer-events: none;
  background: linear-gradient(150deg, var(--brand-1), var(--brand-2) 55%, var(--brand-3));
  opacity: 0.09;
  -webkit-mask-image: var(--crown);
          mask-image: var(--crown);
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
:root[data-theme="light"] .page-head::after { opacity: 0.13; }

/* Le filigrane ne doit jamais passer devant ce qu'on lit. */
.page-head > * { position: relative; z-index: 1; }

/* -- Le trait d'un titre de section -----------------------------------------
   Le filet gris disait seulement « ici s'arrête le titre ». Une amorce colorée
   sur la longueur d'un mot en fait un début plutôt qu'une fin, et le même
   geste se retrouve d'une section à l'autre. */

.section__head {
  position: relative;
  border-bottom: none;
}
.section__head::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg,
      var(--voice, var(--brand-2)) 0, var(--voice, var(--brand-2)) 46px,
      var(--border) 46px, var(--border) 42%,
      transparent 100%);
}

/* La voix d'une page. Le forum et ses fils posent des questions ; les tribunes
   affirment. La teinte suit le lecteur du bouton jusqu'à la page, et de la
   page jusqu'au bouton qui publie. */
.page-forum, .page-thread, .page-forum-new { --voice: var(--voice-ask); }
.page-tribunes, .page-tribune, .page-tribune-new { --voice: var(--voice-say); }
/* Le bouton qui publie prend la couleur de la voix : on est parti d'un bouton
   coloré, on arrive sur une page de cette couleur, on publie du même bouton.
   La règle s'arrête à `.main` — l'en-tête porte « Créer un compte », qui n'a
   rien à voir avec la voix de la page et virait à l'ambre sur les tribunes. */
.page-forum .main .btn--primary,
.page-thread .main .btn--primary,
.page-forum-new .main .btn--primary,
.page-tribunes .main .btn--primary,
.page-tribune .main .btn--primary,
.page-tribune-new .main .btn--primary {
  background: var(--voice);
  color: var(--voice-ink);
}

/* Un état vide se voit comme un état, pas comme une page cassée. */
.empty-state::before {
  content: '';
  display: block;
  width: 46px; height: 46px;
  margin: 0 auto var(--sp-4);
  border-radius: 50%;
  border: 2px dashed var(--border-strong);
  opacity: 0.7;
}

@media (prefers-reduced-motion: reduce) {
  .page-head::after { opacity: 0.05; }
}

/* -- La demande de consentement ---------------------------------------------
   Elle se pose au bas de l'écran et ne barre pas la page : un accord obtenu en
   empêchant de lire n'est pas un accord libre. Les deux boutons ont le même
   poids visuel — refuser doit coûter le même geste qu'accepter. */

.consent {
  position: fixed;
  left: 50%; bottom: var(--sp-4);
  transform: translateX(-50%);
  z-index: 9000;
  width: min(920px, calc(100vw - var(--sp-5) * 2));
  background: var(--surface-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}

.consent__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; gap: var(--sp-5);
  padding: var(--sp-4) var(--sp-5);
}

.consent__title { margin: 0 0 4px; font-weight: 700; font-size: var(--fs-md); }
.consent__body {
  margin: 0; font-size: var(--fs-sm); color: var(--text-2);
  max-width: 68ch;
}
.consent__body a { color: var(--brand-2); }

.consent__actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.consent__actions form { margin: 0; }
/* Même largeur pour les deux : l'œil compte les pixels avant de lire. */
.consent__btn { min-width: 132px; justify-content: center; }

@media (max-width: 720px) {
  .consent__inner { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
  .consent__actions { display: grid; grid-template-columns: 1fr 1fr; }
  .consent__btn { min-width: 0; width: 100%; }
}

/* L'état courant, sur la page des mentions légales. */
.consent-state {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.consent-state__text { font-size: var(--fs-sm); margin: 0; }
.consent-state form { margin: 0; }

/* Les deux issues du consentement ont le même poids : même taille, même
   graisse, même contour. Seul le mot change. */
.consent__btn { min-width: 132px; justify-content: center; font-weight: 600; }
.consent__btn:hover { border-color: var(--brand-1); color: var(--text); }

/* -- Vos données : les deux droits, dans le compte -------------------------- */

.rights { display: grid; gap: var(--sp-5); margin-top: var(--sp-4); }
.rights__item { padding-left: var(--sp-4); border-left: 2px solid var(--border); }
.rights__item--danger { border-left-color: color-mix(in oklab, var(--danger, #e5484d) 55%, transparent); }
.rights__label { margin: 0 0 2px; font-weight: 600; font-size: var(--fs-sm); }
.rights__item .hint { margin: 0 0 var(--sp-3); }

/* L'effacement se replie : il ne doit pas se déclencher d'un clic distrait,
   mais rester à un clic de distance pour qui le cherche. */
.rights__confirm > summary {
  cursor: pointer; font-size: var(--fs-sm); font-weight: 600;
  color: var(--danger, #e5484d);
}
.rights__form { display: grid; gap: var(--sp-3); margin-top: var(--sp-3); max-width: 360px; }

/* -- Le titre d'une carte ---------------------------------------------------
   La classe existait dans les gabarits sans règle qui lui corresponde : un
   `h2` posé dans une carte héritait donc de la taille des titres de section,
   trente-deux pixels, et « Les autres formations — France » tenait sur trois
   lignes dans une colonne de deux cent quarante. Un titre de carte annonce un
   bloc, pas une partie de la page. */

.card__title {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-lg);
  line-height: 1.3;
}

/* Dans une colonne latérale, il descend encore d'un cran : ce qui s'y trouve
   accompagne la lecture, il ne l'ouvre pas. */
.party-side .card__title,
.split__aside .card__title { font-size: var(--fs-md); }

/* -- Les drapeaux -----------------------------------------------------------
   Dessinés plutôt qu'écrits en émoji : Windows ne compose pas les indicateurs
   régionaux et affichait « FR » là où un téléphone montre un drapeau. */

.flag {
  display: inline-block;
  vertical-align: -0.16em;
  border-radius: 2px;
  /* Un liseré très léger, sans quoi les drapeaux à bande blanche — Pologne,
     Malte, Chypre — se fondent dans le fond et paraissent tronqués. */
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--text) 16%, transparent);
  flex: 0 0 auto;
}

/* Le repli, pour un pays qu'on ne dessine pas : le code en pastille, ce que le
   système faisait, en assumé. */
.flag--code {
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--fh, 14px); min-width: calc(var(--fh, 14px) * 1.5);
  padding: 0 3px; border-radius: 2px;
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: calc(var(--fh, 14px) * 0.62); font-weight: 700;
  letter-spacing: 0.02em; color: var(--text-3);
  vertical-align: -0.16em;
}

/* -- Une liste de pays, avec ses drapeaux ------------------------------------
   Le `<select>` natif reste dans le document — il porte la valeur, il répond
   au clavier, il fonctionne sans JavaScript — mais il est rendu transparent
   et posé par-dessus le bouton peint. L'un se voit, l'autre s'utilise. */

.fsel { position: relative; width: 100%; min-width: 0; }


/* Le `<select>` reste dans le document — il porte la valeur et part avec le
   formulaire — mais il cesse de se voir et de se cliquer : c'est la liste
   peinte qui s'ouvre, sinon les drapeaux n'apparaîtraient qu'une fois choisis.
   Il n'est pas retiré du flux d'accessibilité pour autant : sur les appareils
   tactiles, rien n'est remplacé et il reste seul en scène. */
.fsel > select {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* Les mesures sont celles du `<select>` natif, relevées sur l'élément plutôt
   que devinées : quatre pixels de hauteur et deux de rayon d'écart suffisent à
   faire dépareiller une barre de filtres. */
.fsel__btn {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  font: inherit; font-size: var(--fs-base); color: var(--text);
  text-align: left;
}
.fsel__btn:hover { border-color: var(--border-strong); }
.fsel__btn:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; }
.fsel.is-open .fsel__btn { border-color: var(--brand-1); }
.fsel.is-open .fsel__btn::after { transform: rotate(-135deg) translate(-4px, 2px); }

.fsel__btn::after {
  content: ''; margin-left: auto;
  width: 7px; height: 7px;
  border-right: 1.6px solid var(--text-3);
  border-bottom: 1.6px solid var(--text-3);
  transform: rotate(45deg) translate(-2px, -2px);
}
.fsel__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* La place d'un drapeau absent — « tous les pays », « portée européenne » —
   pour que les intitulés restent alignés. */
.fsel__nowhere { display: inline-block; width: 21px; height: 14px; flex: 0 0 auto; }

/* Un signe à la place d'un drapeau — le planisphère de « hors d'Europe ».
   Même emprise que le drapeau, pour que la colonne des intitulés ne bouge pas.
   Ce n'est pas un drapeau : ne pas ranger ce sélecteur avec eux, la règle qui
   les aligne pose `font-size: 0` et effacerait le signe. */
.fsel__glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 21px; height: 14px; flex: 0 0 auto;
  font-size: 15px; line-height: 1;
}

/* La liste déroulée : c'est elle qui montre les drapeaux, ce qu'un menu natif
   ne sait pas faire. */
.fsel__list {
  position: absolute; z-index: 60;
  top: calc(100% + 4px); left: 0; right: 0;
  max-height: 320px; overflow-y: auto;
  padding: 5px;
  background: var(--surface-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}

.fsel__opt {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%;
  padding: 7px 9px;
  border: none; border-radius: var(--r-sm);
  background: none;
  font: inherit; font-size: var(--fs-sm); color: var(--text);
  text-align: left; cursor: pointer;
}
.fsel__opt:hover, .fsel__opt:focus-visible { background: var(--surface-2); outline: none; }
.fsel__opt:focus-visible { box-shadow: inset 0 0 0 2px var(--brand-2); }
.fsel__opt.is-on { font-weight: 700; }
/* La ligne choisie porte un point : la graisse seule se remarque mal dans une
   liste où l'on cherche déjà un drapeau. */
.fsel__opt.is-on::after {
  content: ''; margin-left: auto;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--brand-2);
}

@media (max-width: 720px) {
  .fsel__btn { padding: 9px var(--sp-3); }
}

/* Au doigt, les cibles s'agrandissent et la liste prend la hauteur qu'elle
   peut : une rangée de vingt-huit pixels se rate une fois sur trois. */
@media (pointer: coarse) {
  .fsel__opt { padding: 11px 10px; font-size: var(--fs-base); }
  .fsel__list { max-height: min(60vh, 420px); }
}

/* Le bouton de langue porte son drapeau à côté du code : le code nomme, le
   drapeau se repère.

   « À côté » n'allait pas de soi : `.btn-icon` est une grille, et une grille
   sans piste déclarée range ses éléments en colonne. Le drapeau se posait donc
   au-dessus du code, dans le tiers haut de la case, et le code sous lui. Il
   faut une boîte souple en ligne pour les mettre côte à côte, et centrer sur
   les deux axes pour que l'ensemble tienne au milieu des trente-six pixels. */
.btn-icon--lang {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: auto; gap: 5px;
  padding: 0 9px;
}
/* Le dessin décide de la hauteur de sa boîte : en ligne, il garderait le
   talon de la ligne de base et retomberait deux pixels sous le code. */
.btn-icon--lang .flag { display: block; }
.btn-icon--lang .lang-code { line-height: 1; }
.dropdown__item .flag { margin-right: 2px; }

/* -- Les enveloppes de drapeau ----------------------------------------------
   Chacune portait un corps et un interligne taillés pour un émoji — un glyphe
   de texte, qui se posait sur une ligne de base. Le dessin qui l'a remplacé
   n'en a pas besoin, mais la boîte, elle, restait haute de vingt-sept pixels
   pour un drapeau de quatorze : le centrage du parent alignait donc la boîte,
   pas le drapeau, et le nom du pays paraissait remonté de six pixels.

   Une seule règle les remet toutes d'aplomb : la boîte épouse le dessin.

   **Elle ne vise que des drapeaux.** Le mot « flag » désigne deux choses dans
   ce code — le drapeau d'un pays et l'annotation de faisabilité d'un programme
   — et deux sélecteurs de la seconde famille s'étaient glissés ici :
   `.pchapter__flags`, qui est la liste des annotations d'un chapitre, et
   `.prog-card__flags`, qui en est le compteur sur une carte.

   Les dégâts étaient à la mesure de la règle. `line-height: 0` était hérité par
   tout le contenu des annotations, dont les lignes se sont posées les unes sur
   les autres ; `display: inline-flex` remplaçait la grille, si bien que des
   blocs faits pour s'empiler se rangeaient côte à côte ; et `font-size: 0`
   rendait « 11 annotations » présent dans la page et invisible à l'écran.

   Un nom qui veut dire deux choses finit par les confondre : au premier
   sélecteur ajouté ici sans y regarder de près. */

.country-card__flag, .country-hero__flag, .cparty__flag, .flag-pill__flag,
.lang-row__flags, .thread-row__flag,
.threshold__flag, .dpanel__flag, .tcard__flag, .qaside__flag {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 0; line-height: 0;
}

/* Le drapeau seul, hors enveloppe : dans une phrase, il garde son calage sur
   la ligne de base. Dans une boîte souple, `vertical-align` est ignoré et
   c'est `align-items` qui décide — ce qui est le comportement voulu. */
.flag { vertical-align: -0.16em; }

/* L'ère de la construction européenne porte son drapeau : la vignette devient
   souple pour l'aligner sur le texte. */
.tl-item__era { display: inline-flex; align-items: center; gap: 5px; }

/* Le lien vers le site d'une formation, dans la liste d'un pays. */
.cparty__site {
  display: inline-flex; align-items: center;
  color: var(--text-3);
  transition: color var(--t-fast);
}
.cparty__site:hover { color: var(--brand-2); }

/* ---------------------------------------------------------------------------
   Résultats de recherche
   ---------------------------------------------------------------------------
   Une même forme pour cinq sortes de contenus : pétition, tribune, événement,
   formation, message. Elles n'ont ni la même structure ni les mêmes attributs,
   et les distinguer visuellement reviendrait à demander au lecteur d'apprendre
   cinq gabarits pour lire une seule page. Le titre de section suffit à dire ce
   qu'on regarde ; la vignette dit seulement de quoi il retourne.
   --------------------------------------------------------------------------- */

.search-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}

.search-hit {
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color .18s ease;
}
.search-hit:hover { border-color: var(--border-strong); }

.search-hit__title {
  display: inline-block;
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
}
.search-hit__title:hover { text-decoration: underline; }

.search-hit__excerpt {
  margin: 6px 0 0;
  color: var(--text-2);
  font-size: var(--fs-sm);
  /* Trois lignes : au-delà, l'extrait cesse d'aider à choisir et devient le
     texte lui-même, qu'on lira sur sa page. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.search-hit__meta {
  margin: 8px 0 0;
  font-size: var(--fs-xs);
  color: var(--text-3);
}

/* Les formations n'ont ni extrait ni date : une ligne leur suffit, et une
   grille de cartes hautes pour un nom propre serait du vide encadré. */
.search-list--inline {
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.search-hit--inline {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--sp-3) var(--sp-4);
}
.search-hit--inline .search-hit__meta { margin: 0; }
.search-hit__flag {
  flex: 0 0 auto;
  width: 22px;
  line-height: 0;
}
.search-hit__flag svg { width: 22px; height: auto; border-radius: 2px; }

/* ===========================================================================
   Administration, sécurité du compte
   ---------------------------------------------------------------------------
   Deux pages qui ne ressemblent à rien d'autre sur le site : des tableaux
   denses, où l'on cherche une ligne parmi des centaines. Le reste des pages
   cherche à se lire ; celles-ci cherchent à se parcourir.
   =========================================================================== */

.admin-stats {
  list-style: none;
  margin: 0 0 var(--sp-5);
  padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
}
.admin-stats li {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.admin-stats strong {
  display: block;
  font-size: var(--fs-lg); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.admin-stats span { font-size: var(--fs-xs); color: var(--text-3); }

.tabs {
  display: flex; flex-wrap: wrap; gap: 2px;
  margin-bottom: var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.tabs__link {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 2px solid transparent;
  color: var(--text-2);
  font-size: var(--fs-sm); font-weight: 600;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.tabs__link:hover { color: var(--text); }
.tabs__link.is-active { color: var(--brand-2); border-bottom-color: var(--brand-2); }

.admin-filters {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.admin-filters .input { max-width: 280px; }
.admin-filters .select { max-width: 220px; }

/* Le tableau déborde plutôt que de comprimer ses colonnes : une adresse
   électronique coupée en trois lignes ne se lit plus. */
.table-scroll { overflow-x: auto; }

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.admin-table th, .admin-table td {
  padding: var(--sp-3);
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}
.admin-table th {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-3); font-weight: 600;
  white-space: nowrap;
}
.admin-table tbody tr:hover { background: var(--surface-2); }
.admin-table .tabular { font-variant-numeric: tabular-nums; white-space: nowrap; }

.admin-actions { display: grid; gap: 6px; min-width: 220px; }
.inline-form { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.select--sm { padding: 6px 8px; font-size: 0.8rem; max-width: 150px; }

/* Un geste irréversible ne se présente pas comme les autres : il est replié,
   et son bloc porte la couleur du danger dès qu'on l'ouvre. */
.danger > summary {
  cursor: pointer;
  font-size: var(--fs-xs);
  color: var(--danger);
  padding: 4px 0;
}
.danger[open] {
  padding: var(--sp-3);
  border: 1px solid color-mix(in oklab, var(--danger) 40%, transparent);
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--danger) 6%, transparent);
}
.danger form { display: grid; gap: 6px; margin-top: var(--sp-2); }
.danger__label { display: grid; gap: 4px; font-size: var(--fs-xs); color: var(--text-2); }

/* -- Sécurité du compte ---------------------------------------------------- */

.auth-wrap--wide { max-width: 620px; }

.input--code {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 1.3rem;
  letter-spacing: 0.3em;
  text-align: center;
}

/* La clé se recopie à la main dans une application : elle doit être lisible
   caractère par caractère, et se sélectionner d'un seul geste. */
.totp-key {
  padding: var(--sp-4);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 1.05rem;
  letter-spacing: 0.12em;
  text-align: center;
  user-select: all;
  word-break: break-all;
}

.card--warn {
  border-color: color-mix(in oklab, var(--warning) 45%, transparent);
  background: color-mix(in oklab, var(--warning) 7%, transparent);
}

.code-list {
  list-style: none; margin: var(--sp-3) 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 6px;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.95rem;
  user-select: all;
}
.badge--ok {
  background: color-mix(in oklab, var(--success) 20%, transparent);
  color: var(--success);
}

@media (max-width: 720px) {
  .admin-filters .input, .admin-filters .select { max-width: none; width: 100%; }
  .admin-actions { min-width: 160px; }
}

/* Les sources d'une section légale : les textes qui fondent ce qui vient d'être
   dit. Discrètes — elles appuient le paragraphe, elles ne le concurrencent pas.
   Une par ligne : les titres officiels sont longs, et deux mis bout à bout se
   liraient comme un seul. */
.legal-sources {
  list-style: none;
  margin: calc(var(--sp-4) * -0.5) 0 0;
  padding: 0;
  display: grid;
  gap: 4px;
  font-size: var(--fs-sm);
}
.legal-sources a {
  color: var(--brand-2);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* -- Retour à la carte, sur petit écran --------------------------------------
   Le rail des couches passe sous la carte : on coche, et le résultat se peint
   au-dessus, hors de l'écran. Ce bouton ne paraît qu'une fois qu'au moins une
   couche est active — il attend qu'on ait fini de choisir, là où un retour
   automatique interdirait d'en cocher plusieurs.

   **Il vit dans le rail, et non flottant au-dessus.** Une première version le
   posait en `position: fixed` : sur téléphone, la liste des couches
   disparaissait par moments entièrement. Le rail porte un `backdrop-filter`,
   et poser une couche de composition de plus au-dessus d'une surface floutée
   suffit à ce que le repeint ne suive pas. Dans le flux du panneau, il ne
   compose rien.
   -------------------------------------------------------------------------- */

.map-back { display: none; }

@media (max-width: 960px) {
  .map-back {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    width: calc(100% - var(--sp-4));
    margin: 0 auto var(--sp-2);
    padding: 10px 14px;
    border: 1px solid color-mix(in oklab, var(--brand-2) 55%, transparent);
    border-radius: var(--r-sm);
    background: color-mix(in oklab, var(--brand-2) 12%, transparent);
    color: var(--text);
    font: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
  }
  .map-back[hidden] { display: none; }

  .map-back__count {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: var(--r-full);
    background: var(--brand-2);
    color: #fff;
    font-size: var(--fs-xs);
    font-variant-numeric: tabular-nums;
  }

  /* Le flou coûte cher à peindre, et c'est lui qui rendait la liste blanche
     lorsqu'un élément composité passait dessus. Sur téléphone, le panneau est
     posé sur le fond de la page : il n'a rien à flouter. */
  .layer-rail {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* == Statistiques ==========================================================
 *
 * Les graphiques sont du SVG rendu par PHP ; tout ce qui suit ne fait que
 * l'habiller et l'animer. Aucune règle ici n'est nécessaire à la lecture des
 * chiffres : une feuille de style qui ne se chargerait pas laisserait un
 * tableau de bord laid, jamais un tableau de bord faux.
 *
 * Toute animation est suspendue sous `prefers-reduced-motion` — un mouvement
 * qu'on n'a pas demandé peut rendre malade, et un tableau de bord n'a aucune
 * raison d'être la page qui l'impose.
 * ========================================================================= */

/* -- Tuiles ---------------------------------------------------------------- */

.stat-tiles {
  display: grid;
  /* `minmax(0, …)` et non `1fr` : une piste `1fr` vaut au moins le min-content
     de ses éléments, et un libellé long y imposait une barre horizontale. */
  grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
  gap: 14px;
  margin: 18px 0 28px;
}

.stat-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  padding: 16px 16px 42px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  overflow: hidden;
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}

a.stat-tile:hover,
a.stat-tile:focus-visible {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

.stat-tile__label {
  font-size: .82rem;
  color: var(--text-2);
  line-height: 1.3;
}

.stat-tile__value {
  font-size: clamp(1.35rem, 1.1rem + 1vw, 1.8rem);
  font-weight: 650;
  letter-spacing: -0.01em;
  /* Les chiffres ne doivent pas changer de largeur pendant que le compteur
     défile : sans cela, la tuile entière tremble à chaque image. */
  font-variant-numeric: tabular-nums;
}

.stat-tile__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  font-size: .76rem;
  color: var(--text-3);
}

.stat-tile__change {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  font-variant-numeric: tabular-nums;
  /* La flèche dit un sens, jamais un mérite : ni vert, ni rouge. Sur la dette
     publique, la couleur aurait tranché un débat que ce site n'a pas à
     trancher. */
  color: var(--text-2);
}

/* La moyenne de l'Union, sous le mouvement. Elle répond à la seule question
   qu'on se pose devant un chiffre national — est-ce beaucoup ? — et l'écart est
   ce qui se retient. Ni vert ni rouge : au-dessus de la moyenne n'est pas une
   faute, et en dessous n'est pas un mérite. */
.stat-tile__ref {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 5px;
  margin-top: 3px;
  font-size: .72rem;
  color: var(--text-3);
}

.stat-tile__ref strong { color: var(--text-2); font-variant-numeric: tabular-nums; font-weight: 600; }

/* L'année du repère, quand la comparaison ne porte pas sur celle du chiffre
   montré. Discrète, mais présente : deux millésimes comparés en silence
   vaudraient moins que pas de comparaison du tout. */
.stat-tile__ref-when { font-variant-numeric: tabular-nums; opacity: .8; }
.stat-tile__gap { font-variant-numeric: tabular-nums; }
.stat-tile__gap--over,
.stat-tile__gap--under { color: var(--text-3); }

.stat-tile__note {
  margin-top: 6px;
  font-size: .72rem;
  line-height: 1.45;
  color: var(--text-3);
}

.stat-tile__spark {
  position: absolute;
  inset: auto 0 0 0;
  width: 100%;
  height: 34px;
  opacity: .85;
}

.stat-tile__spark-line {
  fill: none;
  stroke: var(--chart-1);
  stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
}

.stat-tile__spark-area { fill: color-mix(in oklab, var(--chart-1) 14%, transparent); }

/* -- Courbes --------------------------------------------------------------- */

.stat-charts,
.stat-breaks {
  display: grid;
  gap: 18px;
  /* Une colonne par defaut : c'est la mise en page du téléphone, et celle qui
     sert de repli si aucune classe de compte n'est posée. */
  grid-template-columns: minmax(0, 1fr);
}

.stat-charts { margin-bottom: 28px; }

/* Le compte des colonnes est décidé en PHP par `Chart::columns()` : le moins de
   rangées possible, puis la rangée finale la moins vide. Six figures se rangent
   donc trois et trois, quatre se rangent deux et deux, et une seule ne s'étale
   plus sur toute la page. `auto-fit` faisait l'inverse — il donnait le nombre
   de colonnes que la fenêtre permettait, jamais celui que le contenu méritait,
   et deux familles voisines n'avaient pas le même rythme. */
@media (min-width: 720px) {
  .stat-grid--2, .stat-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1120px) {
  .stat-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Une figure seule garde une largeur de lecture : étirée sur seize cents
   pixels, une courbe de dix points devient une ligne d'horizon. */
.stat-grid--1 { max-width: 680px; }

.stat-chart {
  min-width: 0;
  margin: 0;
  padding: 14px 16px 10px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
}

.stat-chart__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}

.stat-chart__title { font-size: .92rem; font-weight: 600; }

.stat-chart__readout {
  font-size: .8rem;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  /* La lecture au survol occupe sa place même vide : sans cela, le titre saute
     d'un côté à l'autre dès que le pointeur entre dans le cadre. */
  min-height: 1.2em;
}

.stat-chart__svg { display: block; width: 100%; height: auto; overflow: visible; }
.stat-chart__svg:focus-visible { outline: 2px solid var(--brand-1); outline-offset: 4px; }

.stat-chart__grid { stroke: var(--chart-grid); stroke-width: 1; }
.stat-chart__grid--zero { stroke: var(--chart-ink); stroke-width: 1.2; }
.stat-chart__tick { fill: var(--text-3); font-size: 10px; font-variant-numeric: tabular-nums; }

.stat-chart__line {
  fill: none;
  stroke: var(--chart-1);
  stroke-width: 2.2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.stat-chart__ref {
  fill: none;
  stroke: var(--chart-8);
  stroke-width: 1.6;
  stroke-dasharray: 5 4;
  opacity: .85;
}

.stat-chart__area { fill: color-mix(in oklab, var(--chart-1) 12%, transparent); }

.stat-chart__surface { fill: transparent; pointer-events: all; }

.stat-chart__cursor line { stroke: var(--chart-ink); stroke-width: 1; stroke-dasharray: 3 3; }
.stat-chart__cursor circle { fill: var(--chart-1); stroke: var(--surface-solid); stroke-width: 2; }

.stat-chart__legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  margin: 4px 0 0;
  font-size: .74rem;
  color: var(--text-3);
}

.stat-chart__key { width: 16px; height: 0; border-top: 2px solid var(--chart-1); }
/* La même atténuation que le tracé qu'il annonce : à pleine opacité, le témoin
   paraissait d'un gris plus franc que la courbe. */
.stat-chart__key--ref { border-top-style: dashed; border-color: var(--chart-8); opacity: .85; }

/* Le tracé qui se dessine. `pathLength="1"` rend la longueur indépendante du
   nombre de points : la même règle sert trois points comme soixante-douze.

   **`.has-charts` est posé par le script, et lui seul.** Sans cette condition,
   l'état de départ — un tracé de longueur nulle — s'appliquait aussi aux pages
   où le script ne tourne pas, et les courbes y restaient invisibles pour
   toujours. Le SVG était complet, la feuille de style le cachait : exactement
   le défaut que le rendu côté serveur devait éviter. */
.has-charts .stat-chart__line,
.has-charts .stat-tile__spark-line {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.stat-chart.is-drawn .stat-chart__line {
  animation: stat-draw 1100ms cubic-bezier(.22, .8, .3, 1) forwards;
}

/*
 * Le repère européen **paraît** au lieu de se tracer, et c'est ce qui lui rend
 * ses tirets.
 *
 * Le tracé se fait en posant `stroke-dasharray: 1` — un tiret aussi long que le
 * chemin entier — puis en le décalant. Cette pose **écrasait** les « 5 4 » du
 * repère, qui finissait donc plein : sa légende le montrait en pointillés, la
 * courbe non, et rien ne le signalait puisqu'une ligne pleine est une ligne
 * valide. Mesuré : `stroke-dasharray` calculé à `1px` sur un tracé de 689.
 *
 * Le fondu ne touche pas au motif. Il convient d'ailleurs mieux : ce repère
 * n'est pas le sujet de la figure, il en est le fond de comparaison.
 */
.has-charts .stat-chart__ref { opacity: 0; }

.stat-chart.is-drawn .stat-chart__ref {
  animation: stat-fade-ref 700ms ease 400ms forwards;
}

@keyframes stat-fade-ref { to { opacity: .85; } }

.has-charts .stat-chart__area { opacity: 0; }
.stat-chart.is-drawn .stat-chart__area { animation: stat-fade 700ms ease 500ms forwards; }

@keyframes stat-draw { to { stroke-dashoffset: 0; } }
@keyframes stat-fade { to { opacity: 1; } }

/* La vignette d'une tuile se trace sans attendre d'être vue : elle est déjà
   dans le champ quand la tuile l'est. */
.has-charts .stat-tile__spark-line { animation: stat-draw 900ms ease-out 120ms forwards; }

/* -- Décompositions -------------------------------------------------------- */

.stat-break {
  min-width: 0;
  margin: 0;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
}

.stat-break__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.stat-break__title { font-size: .92rem; font-weight: 600; }

/* Ce que le tout pèse, et quand. Le centre de l'anneau porte désormais « 100 % »
   — c'est ce que l'anneau vaut —, et la mesure du tout se lit ici, en contexte,
   là où elle ne peut plus se confondre avec une part. */
.stat-break__meta {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: .76rem;
  color: var(--text-3);
}

.stat-break__whole { color: var(--text-2); font-variant-numeric: tabular-nums; }
.stat-break__period { font-size: .76rem; color: var(--text-3); }

/* L'anneau se cale en haut, pas au milieu : une légende de six postes le
   laissait flotter à mi-hauteur, loin de son titre, et l'œil devait redescendre
   pour trouver la première ligne qu'il explique. */
.stat-break__body {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 16px;
}

/* L'anneau suit la largeur de son cadre au lieu de rester à cent quarante
   pixels : dans une carte de cinq cents pixels il paraissait perdu, et une
   décomposition à trois parts — dont la légende est courte — laissait la moitié
   du cadre vide. Les bornes évitent les deux excès : illisible en dessous de
   cent soixante, écrasant la légende au-delà de deux cent quarante. */
.stat-break__ring {
  flex: 0 0 auto;
  width: clamp(155px, 37%, 215px);
  height: auto;
  aspect-ratio: 1;
}

.stat-break__track {
  fill: none;
  stroke: var(--chart-grid);
  stroke-width: 14;
}

.stat-break__arc {
  fill: none;
  stroke-width: 14;
  /* L'anneau part du haut : sans cette rotation, un `stroke-dashoffset` de zéro
     commencerait à trois heures. */
  transform: rotate(-90deg);
  transform-origin: 70px 70px;
  transition: opacity .18s ease;
}

/* Un arc de longueur nulle n'est visible qu'une fois animé : la même règle que
   pour les courbes s'applique, et pour la même raison. */
.has-charts .stat-break__arc { stroke-dasharray: 0 9999; }

.stat-break__arc.is-dimmed,
.stat-break__item.is-dimmed { opacity: .35; }

.stat-break__center { fill: var(--text); font-size: 15px; font-weight: 650; font-variant-numeric: tabular-nums; }
.stat-break__center-label { fill: var(--text-3); font-size: 9px; text-transform: uppercase; letter-spacing: .08em; }

/* Trois figures de front ne laissent pas la place à trois colonnes de chiffres.

   Mesuré sur la dette : le cadre fait 492 pixels, les trois en-têtes de colonne
   — « part du total », « montant », « % du PIB » — en prennent 222 à eux seuls,
   et il ne reste que **quarante et un** pixels au libellé. « Assurances et
   fonds de pension » y tient sur trois lignes.

   Ce ne sont pas les nombres qui serrent, ce sont les mots qui les coiffent :
   les pistes sont en `auto`, donc taillées sur leur plus large contenu, et le
   nom en `1fr` ne reçoit que ce qui reste. Les mêmes trois colonnes tiennent
   sans peine dans le budget, où quatre figures se rangent deux par deux et où
   le cadre fait 747 pixels — le nom y dispose de 257.

   La légende passe donc sous l'anneau quand les deux se rencontrent : trois de
   front, et des montants. Elle y prend la largeur entière.

   `flex-wrap: nowrap` en même temps que la colonne, faute de quoi le
   débordement se rangerait à côté plutôt que dessous — le piège est déjà
   consigné. */
.stat-grid--3 .stat-break__body:has(.stat-break__amount) {
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: center;
}

.stat-grid--3 .stat-break__body:has(.stat-break__amount) .stat-break__legend {
  width: 100%;
  flex: 0 0 auto;
}

/* La légende est la grille, et chaque ligne emprunte ses colonnes.

   Chaque ligne était sa propre grille : ses pistes `auto` se dimensionnaient
   donc sur son seul contenu, et l'en-tête — dont les mots sont plus larges que
   les nombres qu'il coiffe — ne tombait pas au-dessus de la bonne colonne.
   `subgrid` fait porter les pistes par la liste : toutes les lignes partagent
   alors les mêmes, en-tête compris.

   Le repli sans `subgrid` garde une grille par ligne — c'est l'état d'avant,
   lisible mais mal aligné — plutôt qu'une déclaration invalide qui écraserait
   la mise en page. */
.stat-break__legend {
  flex: 1 1 200px;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .8rem;
}


/* Les pistes de la légende : pastille, nom, puis les colonnes de chiffres.

   **Écrites une seule fois**, ici, et reprises par variable partout où elles
   servent — la ligne isolée, la légende en `subgrid`, la variante à montants.
   Elles l'étaient en quatre exemplaires, ce qui est la façon ordinaire dont
   deux copies d'une même règle finissent par dire deux choses.

   `min-content` et non `auto`, et c'est tout le sujet : une piste `auto` se
   taille sur son **plus large contenu**, or les mots d'en-tête sont plus larges
   que les nombres qu'ils coiffent. « PART DU TOTAL » réclamait ainsi 93 pixels
   pour des « 16,5 % » qui en demandent 42, et le nom — seul en `1fr` — ne
   recevait que ce qui restait. En `min-content`, ce sont les nombres qui fixent
   la piste : ils ne se coupent pas, l'espace qui les sépare de leur unité étant
   insécable, tandis que le titre se replie sur deux lignes. La colonne des
   intitulés récupère la différence.

   Le prix est une ligne d'en-tête un peu plus haute. Elle est en petites
   capitales de 0,68 rem : c'est le meilleur endroit de la figure où reprendre
   de la hauteur. */
.stat-break__legend {
  --break-cols: 10px minmax(0, 1fr) min-content min-content;
}

.stat-break__legend:has(.stat-break__amount) {
  --break-cols: 10px minmax(0, 1fr) min-content min-content min-content;
}

.stat-break__item {
  display: grid;
  grid-template-columns: var(--break-cols);
  align-items: center;
  gap: 4px 10px;
  padding: 3px 0;
  transition: opacity .18s ease;
}

/* La ligne d'en-tête : elle ne porte que les unités des deux colonnes de
   chiffres, et rien qui puisse se lire comme une part. */
.stat-break__item--head {
  padding-bottom: 5px;
  margin-bottom: 3px;
  border-bottom: 1px solid var(--border);
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-3);
  /* Le titre se replie maintenant sur deux ou trois lignes : à l'interligne du
     corps de texte, la ligne d'en-tête doublait de hauteur. Serré, il reprend
     l'essentiel — des petites capitales n'ont pas besoin du même air que de la
     prose. */
  line-height: 1.25;
}

/* L'en-tête ne porte que des mots : aucune de ses cellules ne se met en gras,
   quel que soit le rang de sa colonne. */
.stat-break__item--head .stat-break__cell--primary,
.stat-break__item--head .stat-break__cell--secondary { font-weight: 400; font-size: .68rem; }
.stat-break__item--head .stat-break__bar { background: none; }

.stat-break__swatch { width: 10px; height: 10px; border-radius: 3px; }
.stat-break__name { min-width: 0; color: var(--text-2); }

/* Les colonnes de chiffres partagent leur mise en forme ; ce qui les distingue
   est le rang, pas le nom. Sur la dépense la mesure est la part de PIB, sur la
   dette c'est la part du total — la classe d'identité sert la largeur, la
   classe de rang sert l'emphase. Les lier au nom aurait figé l'une des deux. */
/* Un nombre ne se coupe pas : « 571,6 Md€ » sur deux lignes ne se lit plus. */
.stat-break__value,
.stat-break__share,
.stat-break__amount {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Mais l'en-tête porte les **mêmes classes**, et il n'est pas un nombre.

   C'est ce qui rendait `min-content` sans effet sur les pistes : insécable,
   « PART DU TOTAL » valait sa largeur entière — 94 pixels — là où les « 16,5 % »
   qu'il coiffe en demandent 42. La piste se taillait sur le titre, et le nom,
   seul en `1fr`, ne recevait que le reste.

   Rendu sécable, le titre se replie sur deux lignes et ce sont les nombres qui
   fixent la colonne. La ligne d'en-tête grandit d'autant : elle est en petites
   capitales de 0,68 rem, c'est le meilleur endroit de la figure où reprendre de
   la hauteur. */
.stat-break__item--head .stat-break__value,
.stat-break__item--head .stat-break__share,
.stat-break__item--head .stat-break__amount { white-space: normal; }

.stat-break__cell--primary { font-weight: 600; color: var(--text); }
.stat-break__cell--secondary { font-size: .74rem; color: var(--text-3); }
.stat-break__amount.stat-break__cell--secondary { color: var(--text-2); }

.stat-break__share { min-width: 3.4em; }
/* Une décomposition signée porte une barre sous son nom : le nom et la valeur
   sur la première ligne, la barre sur la seconde. Sans placement explicite, la
   barre couvrant les colonnes 2 à -1 renvoyait la valeur à la ligne suivante,
   dans la colonne de la pastille — cinq pixels de large, texte débordé.
   Personne ne l'avait vu parce qu'une seule décomposition est signée. */
[data-chart="bars"] .stat-break__swatch { grid-row: 1; grid-column: 1; }
[data-chart="bars"] .stat-break__name   { grid-row: 1; grid-column: 2; }
[data-chart="bars"] .stat-break__value  { grid-row: 1; grid-column: 3 / -1; }
[data-chart="bars"] .stat-break__amount { grid-row: 1; grid-column: 3; }
[data-chart="bars"] .stat-break__bar    { grid-row: 2; grid-column: 2 / -1; margin-top: 3px; }

@supports (grid-template-columns: subgrid) {
  /* La liste porte les pistes, les lignes les empruntent : sans cela chaque
     ligne se dimensionnait sur son seul contenu, et l'en-tête ne tombait pas
     au-dessus de la bonne colonne. Le compte des pistes vient de la variable —
     une piste de plus quand la décomposition porte ses montants —, et c'est le
     partiel qui en décide en écrivant la colonne ou non. */
  .stat-break__legend {
    display: grid;
    grid-template-columns: var(--break-cols);
  }

  .stat-break__item {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
}


/* Une décomposition signée : des barres, jamais un anneau. */
.stat-break__bar {
  grid-column: 2 / -1;
  display: block;
  height: 6px;
  border-radius: 3px;
  background: var(--chart-grid);
  overflow: hidden;
}

.stat-break__bar-fill {
  display: block;
  width: var(--bar, 0%);
  height: 100%;
  border-radius: 3px;
}

.has-charts .stat-break__bar-fill { width: 0; }

.stat-break__bar-fill--neg { opacity: .55; }

.stat-break.is-drawn .stat-break__bar-fill {
  animation: stat-grow 720ms cubic-bezier(.22, .8, .3, 1) var(--bar-delay, 0ms) forwards;
}

.stat-break.is-drawn .stat-break__arc {
  animation: stat-arc 760ms cubic-bezier(.22, .8, .3, 1) var(--arc-delay, 0ms) forwards;
}

@keyframes stat-grow { to { width: var(--bar, 0%); } }
@keyframes stat-arc { to { stroke-dasharray: var(--arc-dash) var(--arc-gap); } }

.stat-break__note {
  margin: 10px 0 0;
  font-size: .74rem;
  line-height: 1.5;
  color: var(--text-3);
}

/* -- Classement ------------------------------------------------------------ */

.stat-rank {
  margin: 20px 0 28px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
}

.stat-rank__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.stat-rank__title { margin: 0; font-size: 1.05rem; }
.stat-rank__period { margin: 0; font-size: .82rem; color: var(--text-2); }

.stat-rank__scrub {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px 0 14px;
}

.stat-rank__play {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  line-height: 1;
}

.stat-rank__play.is-playing { background: var(--brand-1); color: #fff; border-color: transparent; }
.stat-rank__slider { flex: 1 1 auto; min-width: 0; accent-color: var(--brand-1); }

.stat-rank__bounds {
  display: none;
  gap: 8px;
  font-size: .72rem;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

@media (min-width: 620px) { .stat-rank__bounds { display: flex; } }

.stat-rank__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.stat-rank__row {
  display: grid;
  grid-template-columns: minmax(0, 9rem) minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  /* Le changement de rang glisse : la ligne est ramenée d'où elle venait par le
     script, puis relâchée. */
  transition: transform 520ms cubic-bezier(.22, .8, .3, 1);
}

.stat-rank__row.is-absent { opacity: .3; }

.stat-rank__link {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  font-size: .84rem;
}

.stat-rank__link:hover .stat-rank__name { text-decoration: underline; }
.stat-rank__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.stat-rank__track {
  height: 12px;
  border-radius: 6px;
  background: var(--chart-grid);
  overflow: hidden;
}

.stat-rank__bar {
  display: block;
  width: var(--bar, 0%);
  height: 100%;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--chart-1), var(--chart-2));
  transition: width 520ms cubic-bezier(.22, .8, .3, 1);
}

.stat-rank__value {
  font-size: .82rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* L'année d'un pays qui ne déclare pas la même que les autres. Muette quand
   elle est la commune : c'est l'exception qui doit se voir, pas la règle. */
.stat-rank__when {
  min-width: 3.2rem;
  text-align: right;
  font-size: .7rem;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Sur un téléphone, la barre passe sous le nom.

   Mesuré à 360 pixels d'écran : la barre en recevait **vingt-trois**. La grille
   d'une ligne est la même à toute largeur — 9 rem pour le nom, trois
   gouttières, la valeur, l'année — et ce qui reste après elles est ce que la
   barre obtient. Sur un écran large il reste huit cents pixels ; sur un
   téléphone, rien. Une barre de vingt-trois pixels ne compare plus rien : elle
   ne fait qu'occuper une place.

   S'y ajoutait une marge que personne n'avait demandée. `.stat-rank__when`
   réserve 3,2 rem pour aligner les années en colonne — utile là où l'espace
   abonde, mais la colonne est **vide sur presque toutes les lignes**, l'année
   ne s'écrivant que lorsqu'elle s'écarte de la commune. Cinquante et un pixels
   de blanc à droite des chiffres, sur un écran qui en compte trois cent
   soixante.

   Sur deux lignes, la barre reçoit la largeur entière — vingt-trois pixels
   deviennent près de trois cents — et l'année ne prend plus que ce qu'elle
   écrit. La liste grandit d'autant, ce qui est le bon échange : on vient y
   comparer des longueurs. */
@media (max-width: 620px) {
  .stat-rank__row {
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: 3px 8px;
    padding: 6px 0;
  }

  .stat-rank__link,
  .stat-rank__value,
  .stat-rank__when { grid-row: 1; }

  /* Plus de largeur réservée : l'année ne coûte que lorsqu'elle paraît. */
  .stat-rank__when { min-width: 0; }

  .stat-rank__track {
    grid-row: 2;
    grid-column: 1 / -1;
    height: 10px;
  }
}

/* Un pays sans chiffre à la période choisie reste dans la liste, en bas et en
   retrait : le faire disparaître ferait croire qu'il n'a jamais rien publié. */
.stat-rank__row.is-absent { opacity: .38; }
.stat-rank__row.is-absent .stat-rank__bar { background: var(--chart-grid); }

.stat-rank__ref { margin: 12px 0 0; font-size: .8rem; color: var(--text-2); }

/* -- Choix de l'indicateur ------------------------------------------------- */

/*
 * Le choix se met à côté du classement, pas au-dessus.
 *
 * Empilé, il faisait 392 pixels de haut pour vingt-neuf pastilles en six
 * rangées, et repoussait le premier pays à 814 — sous la ligne de flottaison.
 * En colonne, il ne coûte plus une seule ligne de hauteur et prend une largeur
 * que les rangées laissaient vide à 28 %.
 */
.stats-layout { display: grid; gap: 20px; align-items: start; }

.stats-layout__main { min-width: 0; }

/* Ce qui fait une colonne latérale, et rien de ce qu'elle contient. Deux pages
   la portent — le choix d'indicateur de l'index, le sommaire d'une page pays —
   et la règle est écrite une seule fois : deux copies finissent toujours par
   dire deux choses. */
.stats-rail { min-width: 0; margin-bottom: 8px; }

.stats-picker__box { min-width: 0; }

.stats-picker__body { display: grid; gap: 12px; }

.stats-picker__group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.stats-picker__legend {
  flex: 0 0 100%;
  margin-bottom: 4px;
  padding: 0;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--text-3);
}

.stats-picker__choice {
  display: inline-flex;
  padding: 5px 11px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  font-size: .8rem;
  cursor: pointer;
}

.stats-picker__choice input { position: absolute; opacity: 0; pointer-events: none; }
.stats-picker__choice:hover { border-color: var(--border-strong); }
.stats-picker__choice.is-active { background: var(--brand-1); border-color: transparent; color: #fff; }
.stats-picker__choice:focus-within { outline: 2px solid var(--brand-1); outline-offset: 2px; }

/* Le résumé du repli : il ne sert qu'en colonne étroite. */
.stats-picker__summary {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface-2);
  cursor: pointer;
  list-style: none;
}

.stats-picker__summary::-webkit-details-marker { display: none; }
.stats-picker__summary:hover { border-color: var(--border-strong); }
.stats-picker__summary:focus-visible { outline: 2px solid var(--brand-1); outline-offset: 2px; }

.stats-picker__summary-hint {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--text-3);
}

.stats-picker__summary-value {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .9rem;
  font-weight: 600;
}

/* La flèche, dessinée plutôt qu'écrite : elle tourne à l'ouverture. */
.stats-picker__summary::after {
  content: '';
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--text-3);
  border-bottom: 2px solid var(--text-3);
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s ease;
}

.stats-picker__box[open] > .stats-picker__summary { margin-bottom: 12px; }
.stats-picker__box[open] > .stats-picker__summary::after { transform: translateY(1px) rotate(-135deg); }

@media (min-width: 981px) {
  .stats-layout { grid-template-columns: minmax(0, 244px) minmax(0, 1fr); gap: 28px; }

  /*
   * Le rail suit le lecteur : le classement fait quarante-six lignes, et
   * remonter en haut pour changer d'indicateur était le prix de chaque
   * comparaison. Il déborde alors sa propre hauteur — d'où le défilement
   * interne, borné par `overscroll-behavior` pour qu'arrivé en bas il ne
   * pousse pas la page derrière lui.
   */
  .stats-rail {
    position: sticky;
    top: calc(var(--head-h, 64px) + 16px);
    max-height: calc(100vh - var(--head-h, 64px) - 32px);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    margin-bottom: 0;
    padding-right: 4px;
  }

  /* Le repli n'a plus lieu d'être : la colonne est déjà à côté du contenu. */
  .stats-picker__summary { display: none; }

  .stats-picker__body { gap: 16px; }

  .stats-picker__group { display: block; }

  .stats-picker__legend {
    margin-bottom: 6px;
    padding-left: 10px;
  }

  /* En rail, la pastille devient une ligne : c'est une liste, pas un nuage. */
  .stats-picker__choice {
    display: block;
    width: 100%;
    padding: 6px 10px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--text-2);
    line-height: 1.3;
  }

  .stats-picker__choice:hover { background: var(--surface-2); color: var(--text); }
  .stats-picker__choice.is-active { background: var(--brand-1); color: #fff; }
}

/* -- Pages ----------------------------------------------------------------- */

.stats-countries { margin-top: 28px; }
.stats-countries__lead { margin: 2px 0 12px; color: var(--text-2); font-size: .88rem; }

.stats-countries__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr));
  gap: 4px 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.stats-countries__link {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 0;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  font-size: .88rem;
}

.stats-countries__link:hover { text-decoration: underline; }

/* Six familles à la suite se lisaient comme une seule longue page : les titres
   avaient la taille d'un sous-titre et rien ne marquait la frontière. La règle
   est celle du site — un filet, un titre, une phrase — appliquée ici avec assez
   d'air pour qu'on voie où l'une finit et où l'autre commence. */
.stats-family { margin: 0 0 12px; padding-top: 34px; }
.stats-family + .stats-family { border-top: 1px solid var(--border); margin-top: 34px; }

.stats-family__head { margin-bottom: 18px; }

.stats-family__title {
  margin: 0 0 4px;
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  letter-spacing: -0.015em;
}

/* Le filet court sous le titre, et s'arrête : une barre pleine largeur aurait
   fait un tableau, pas un chapitre. */
.stats-family__title::after {
  content: "";
  display: block;
  width: 56px;
  height: 3px;
  margin-top: 8px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--chart-1), var(--chart-2));
}

.stats-family__lead { margin: 10px 0 0; color: var(--text-2); font-size: .94rem; }

.stats-note {
  margin: 0 0 18px;
  font-size: .82rem;
  line-height: 1.55;
  color: var(--text-3);
}

/* Le titre porte le drapeau : une boîte souple les cale l'un sur l'autre par
   leur milieu, ce que la ligne de base ne fait pas pour un dessin de trente
   pixels au milieu de lettres de quarante. */
/* Le drapeau reste à gauche du nom, quelle que soit la place : c'est le texte
   qui se replie à l'intérieur de sa propre boîte, pas le drapeau qui monte sur
   une ligne à lui. */
/* Un titre qui porte un drapeau : la fiche pays et sa page de statistiques.
   Une seule règle pour les deux — un dessin de trente pixels sur une ligne de
   quarante ne se cale pas sur la base des lettres, et la boîte souple les
   aligne par leur milieu. */
.stats-country__title,
.country-hero__title {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 14px;
}

.stats-country__title > span:last-child,
.country-hero__title > span:last-child { min-width: 0; }

.stats-country__title .stats-country__flag,
.country-hero__title .country-hero__flag { display: inline-flex; align-items: center; }

.stats-country__title .flag,
.country-hero__title .flag { vertical-align: 0; }

/* L'en-tête d'une page de pays : le titre à gauche, le partage en haut à
   droite — là où le site le pose partout ailleurs. En dessous de sept cents
   pixels les deux s'empilent, et le partage revient sous le titre plutôt que
   de le comprimer. */
.stats-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px 24px;
}

.stats-head__main { flex: 1 1 440px; min-width: 0; }

/* Le partage cède avant le titre : ses boutons se replient sur deux rangées
   plutôt que de repousser le drapeau à la ligne au-dessus du nom du pays. */
.stats-head__share { flex: 0 1 620px; min-width: 0; margin-top: 4px; }
/* La marge tombe — la carte est déjà calée par la grille de l'en-tête — mais
   **pas la garniture** : `share--aside` est un bloc comme ceux des autres
   pages, et le vider de son intérieur en ferait de nouveau un bloc nu. */
.stats-head__share .share { margin: 0; }

.stats-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .88rem;
}


.stats-jump a {
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-2);
  text-decoration: none;
  font-size: .8rem;
}

.stats-jump a:hover { border-color: var(--border-strong); color: var(--text); }

/* Le sommaire reste sous les yeux pendant les dix écrans qu'il commande.

   Il ne passe pas en colonne, contrairement au choix d'indicateur de l'index :
   là-bas le bloc était vertical et la largeur dormait, ici le sommaire fait
   trente-deux pixels et la bande de chiffres n'a pas un pixel de trop. Une
   colonne de 244 ramenait le contenu à 1 240, où six tuiles ne tenaient plus
   en rangée. Collé en haut, il ne coûte rien en largeur.

   **C'est l'enveloppe qui colle, et le rang qui défile.** Les deux flèches de
   bord doivent rester en place pendant que les pastilles passent dessous :
   posées dans le conteneur défilant, elles s'en iraient avec lui et
   désigneraient le vide. */
.stats-jump-wrap {
  position: sticky;
  top: var(--head-h, 64px);
  z-index: 5;
  /* Le fond est plein, et déborde la gouttière de la section : sans cela le
     contenu défilerait visiblement sous les pastilles. */
  margin: 0 -8px 8px;
  padding: 10px 8px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.stats-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  /* Reste le parent de position de ses pastilles : le script cherche celle qui
     est marquée par son `offsetLeft`, et le mesurer depuis l'enveloppe
     décalerait le calcul de la garniture. */
  position: relative;
}

/* Hors du téléphone, le rang ne défile pas : les flèches n'ont rien à annoncer.

   Cette règle est **avant** celle qui les allume, et non après : les deux ont la
   même spécificité, et c'est donc l'ordre qui tranche. Placée en dessous, elle
   les aurait éteintes jusque sur le téléphone — sans rien signaler, le défaut
   ayant déjà été payé une fois avec `subgrid`. */
.stats-jump__edge { display: none; }

/* Sur un téléphone, le rang défile au lieu de se replier.

   Mesuré : les six mots font 447 pixels, un écran de 360 en offre 328. Repliés,
   ils tiennent deux rangées — quatre-vingt-douze pixels collés en haut, sur une
   fenêtre qui en compte six cent quarante. En un seul rang qui défile, le
   sommaire en garde cinquante-trois et donne accès aux six.

   `overflow-x` rend l'autre axe défilant à son tour ; il n'y a rien à y
   déborder, le rang tenant sur une ligne. */
@media (max-width: 719px) {
  .stats-jump {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .stats-jump::-webkit-scrollbar { display: none; }

  /* Sans cela, une pastille se comprime au lieu de sortir du cadre. */
  .stats-jump a { flex: 0 0 auto; }

  /*
   * Les deux flèches de bord.
   *
   * La dernière pastille coupée par le bord dit déjà qu'il y a une suite, mais
   * elle le dit mal : rien ne distingue « coupée » de « serrée », et l'on ne
   * fait pas glisser une liste dont on ignore qu'elle glisse. Une flèche le
   * dit ; le dégradé qui la porte lui donne un fond lisible quand une pastille
   * passe dessous.
   *
   * Chacune ne paraît que s'il reste quelque chose de ce côté-là : montrées en
   * permanence, elles indiqueraient un mouvement impossible aux deux bouts. Ce
   * sont les classes posées par le script qui en décident — sans lui, aucune
   * n'apparaît, et le rang se fait glisser comme n'importe quel autre.
   */
  .stats-jump__edge {
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    width: 34px;
    pointer-events: none;
    opacity: 0;
    transition: opacity .18s ease;
  }

  .stats-jump__edge--start {
    left: 0;
    background: linear-gradient(90deg, var(--bg) 42%, transparent);
  }

  .stats-jump__edge--end {
    right: 0;
    background: linear-gradient(270deg, var(--bg) 42%, transparent);
  }

  .stats-jump-wrap.can-start .stats-jump__edge--start,
  .stats-jump-wrap.can-end .stats-jump__edge--end { opacity: 1; }

  /* Le chevron, dessiné plutôt qu'écrit : deux bords d'une boîte tournée, qui
     suivent la couleur du thème sans qu'aucune image ne soit à charger. */
  .stats-jump__edge::after {
    content: '';
    position: absolute;
    top: 50%;
    width: 7px;
    height: 7px;
    border-top: 2px solid var(--text-2);
    border-right: 2px solid var(--text-2);
  }

  .stats-jump__edge--start::after { left: 9px; transform: translateY(-50%) rotate(-135deg); }
  .stats-jump__edge--end::after { right: 9px; transform: translateY(-50%) rotate(45deg); }
}

/* La famille qu'on est en train de lire. Posée par le script : sans lui, le
   sommaire reste six liens qui mènent où ils disent, ce qui est tout ce qu'on
   lui demande. */
.stats-jump a.is-current {
  border-color: transparent;
  background: var(--brand-1);
  color: #fff;
}

/* Le saut d'ancre doit s'arrêter sous l'en-tête **et** sous le sommaire. La
   règle générale — `scroll-padding-top` sur `html` — ne connaît que le premier ;
   le second n'existe que sur cette page, et c'est donc à ses sections de
   déclarer ce qu'elles ont au-dessus d'elles. Le sommaire mesurant cinquante-
   trois pixels à toute largeur — c'est bien l'intérêt du rang unique —, la
   valeur ne dépend pas de l'écran. */
.stats-family { scroll-margin-top: 52px; }

/* La sortie de page. Deux noms de pays sans un mot pour dire ce qu'ils font là
   ne se comprennent pas : le bloc porte donc son titre, sa phrase, et le lien
   vers la liste complète. */
.stats-next {
  margin: 40px 0 0;
  padding-top: 26px;
  border-top: 1px solid var(--border);
}

.stats-next__title { margin: 0 0 4px; font-size: 1.05rem; }
.stats-next__lead { margin: 0 0 12px; color: var(--text-2); font-size: .86rem; }

.stats-next__links { display: flex; flex-wrap: wrap; gap: 10px; }

.stats-next__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: inherit;
  text-decoration: none;
  font-size: .86rem;
}

.stats-next__link:hover { border-color: var(--border-strong); }
.stats-next__link--all { background: var(--surface-2); }

.stat-source {
  margin-top: 26px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: .78rem;
  line-height: 1.6;
  color: var(--text-3);
}

.stat-source p { margin: 0 0 6px; }
.stat-source__caveat { max-width: 62ch; }

/* -- L'encart d'une fiche pays --------------------------------------------- */

.country-stats { margin: 26px 0; }

.stat-tile--compact { padding: 12px 12px 34px; }
.stat-tile--compact .stat-tile__value { font-size: 1.2rem; }

/* -- Mouvement : seulement si on ne l'a pas refusé ------------------------- */

@media (prefers-reduced-motion: reduce) {
  .stat-chart__line,
  .stat-chart__ref,
  .stat-tile__spark-line {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
    animation: none;
  }
  .stat-chart__area { opacity: 1; animation: none; }
  .stat-break__arc { stroke-dasharray: var(--arc-dash) var(--arc-gap); animation: none; }
  .stat-break__bar-fill { width: var(--bar, 0%); animation: none; }
  .stat-rank__row,
  .stat-rank__bar { transition: none; }
  a.stat-tile:hover,
  a.stat-tile:focus-visible { transform: none; }
}
