:root{color-scheme:light;--primary:#3366cc;--accent:#7a5f10;--danger:#b32424;--bg:#ffffff;--surface:#f8f9fa;--text:#202122;--muted:#666b71;--font-heading:Georgia, 'Times New Roman', serif;--font-body:system-ui, -apple-system, Segoe UI, Roboto, sans-serif}:root[data-theme="nuit"]{color-scheme:dark;--primary:#6699ff;--accent:#e2c65c;--danger:#e0555b;--bg:#0c0d10;--surface:#16181d;--text:#e7e9ee;--muted:#9aa0ab;--font-heading:Georgia, 'Times New Roman', serif;--font-body:system-ui, -apple-system, Segoe UI, Roboto, sans-serif}/* =============================================================================
   THÈME  ENCYCLOPEDIE  —  vevewiki
   VeVePreda/veve-sites — themes/encyclopedie/theme.css
   -----------------------------------------------------------------------------
   ⛔ NE PAS MODIFIER `themes/aurora/theme.css` POUR VEVEWIKI.
   aurora n'est pas « sombre par sa palette », il est sombre PAR SA STRUCTURE :
   il code en dur des filets et des fonds en BLANC SEMI-TRANSPARENT
   (#ffffff14, #ffffff12, #ffffff10). Sur un fond blanc, un filet blanc à 8 %
   d'opacité n'est pas « discret », il est ABSENT — la page perd toutes ses
   séparations sans qu'aucun build ne s'en plaigne. D'où un fichier séparé.
   Corollaire : ce thème n'utilise aucune couleur en alpha-blanc.

   CONTRAT AVEC LE MOTEUR (src/layouts/Base.astro, ligne 86) — le moteur
   n'émet QUE ces neuf variables, depuis `identity.palette` du manifeste :
       --primary --accent --danger --bg --surface --text --muted
       --font-heading --font-body
   ⚠️ `--primary` est câblé sur la couleur des LIENS (`a{color:var(--primary)}`).
   La palette jour met donc le BLEU DE LIEN dans `primary`, pas l'or : l'or du
   logo à #d4af37 sur blanc ne fait que 2,10:1, il est illisible en texte. L'or
   vit dans `accent`, et sert de DÉCOR (filets, puces, cadres) — jamais de
   texte fin. Voir la table de contraste en fin de fichier.

   Tous les autres jetons sont déclarés ICI et non au manifeste : un thème est
   propre à un site, il a le droit d'avoir son vocabulaire. Ce qui doit rester
   au manifeste, c'est ce que le MOTEUR lit (les neuf ci-dessus) et ce que
   d'autres modules relisent (`figures.mjs` lit `identity.palette`).
   ============================================================================= */

:root{
  /* --- Structure ---
     ⚠️ Pas d'alias décoratif : on écrit var(--bg) et var(--surface), jamais un
     --paper qui les double. Un jeton qui en aliase un autre sans être utilisé
     fait croire à un vocabulaire canonique qui n'existe pas — et le prochain
     lecteur écrit la moitié du fichier avec le mauvais nom. */
  --shell-2:#eaecf0;      /* séparateur de bloc            */
  --th-bg:#f2f4f6;        /* en-tête de tableau            */
  --rule:#c8ccd1;         /* filet fin                     */
  --rule-strong:#a2a9b1;  /* bordure de cadre, de tableau  */

  /* --- Encre : mesurée sur --bg ET sur --surface ET sur --shell-2 ---
     `text` (#202122) et `muted` (#666b71) viennent du manifeste ; seul le
     niveau intermédiaire est propre au thème. */
  --ink-soft:#54595d;      /* 7,09:1 blanc / 6,72:1 surface / 6,30:1 shell-2 */
  --ink-faint:var(--muted);/* #666b71 — 5,38:1 / 5,10:1 / 4,54:1 */

  /* --- Or : DEUX rôles, DEUX valeurs, et un seul est du texte ---
     Le texte doré est `accent` (#7a5f10, 6,05:1), fourni par le manifeste.
     `--gold` ci-dessous est l'or DE MARQUE, réservé au décor : filets, puces,
     cadres. À 2,10:1 sur blanc il ne peut porter aucun caractère. */
  --gold:#d4af37;
  --gold-wash:#fdf8e8;
  --gold-hair:#e6dcb8;

  --link-visited:#795cb2;  /* 5,27:1 — savoir ce qu'on a déjà lu */
  --tap:44px;              /* cible tactile minimale             */
}

/* =============================================================================
   THÈME NUIT — `data-theme="nuit"` posé par Base.astro AVANT la peinture
   -----------------------------------------------------------------------------
   ⚠️⚠️ LE MANIFESTE NE SUFFIT PAS. Il retourne les 7 couleurs du moteur
   (`bg`, `text`, `primary`…), mais TOUS les jetons déclarés ici — filets, fonds
   de bloc, encre intermédiaire, or de décor — sont écrits en dur pour le fond
   clair. Sans ce bloc, la nuit sortirait avec des filets #c8ccd1 sur de
   l'anthracite : des traits plus CLAIRS que le texte, sur une page sombre.
   ⭐ La règle, valable pour les 13 sites à venir : un thème bascule si — et
   seulement si — CHAQUE valeur en dur qu'il déclare a son pendant nuit.
   ============================================================================= */
:root[data-theme="nuit"]{
  --shell-2:#1e2127;      /* séparateur                      */
  --th-bg:#1a1d22;        /* en-tête de tableau              */
  --rule:#2a2d34;         /* filet fin — 1,41:1, décor pur   */
  --rule-strong:#3a3f47;

  --ink-soft:#b0b6c0;     /* 9,53:1 sur bg · 8,71:1 sur surface */
  /* --ink-faint suit `muted` du manifeste : #9aa0ab, 7,39:1 */

  --gold:#d4af37;         /* ⭐ l'or BRUT devient lisible la nuit : 9,24:1.
                             C'est l'inverse exact du jour, où il tombe à 2,10:1
                             et ne peut porter aucun caractère. */
  --gold-wash:#211d12;
  --gold-hair:#4a3f1e;

  --link-visited:#a397db; /* 7,41:1 — #795cb2 n'y ferait que 2,4:1 */
}

/* =============================================================================
   1. SOCLE
   ============================================================================= */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--text);font-family:var(--font-body);
  line-height:1.65;font-size:16px}

a{color:var(--primary);text-decoration:none}
a:hover{text-decoration:underline}
/* Un lien visité n'est pas un détail sur une encyclopédie : savoir ce qu'on a
   déjà lu est la moitié de la navigation dans un glossaire de 87 entrées.
   ⚠️ Restreint au CONTENU : dans une navigation, un lien visité grisé donne
   l'impression d'un menu à moitié désactivé. */
main a:visited{color:var(--link-visited)}
main nav a:visited,.crumbs a:visited,a.tag:visited{color:var(--primary)}

/* Le focus clavier n'était pas stylé : à la tabulation on ne savait pas où on
   était. Le contour est posé sur tout ce qui prend le focus, y compris les
   `summary` (sections pliables) et les champs. */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
summary:focus-visible,[tabindex]:focus-visible{
  outline:2px solid var(--primary);outline-offset:2px;border-radius:2px}
main:focus{outline:none}   /* main[tabindex=-1] reçoit le focus du lien d'évitement */

.wrap{max-width:1080px;margin:0 auto;padding:0 20px}
.hide{display:none}

/* =============================================================================
   2. EN-TÊTE / NAVIGATION / PIED
   ============================================================================= */
header.site{border-bottom:1px solid var(--rule);position:sticky;top:0;
  background:var(--bg);z-index:10}
/* `sticky` positionne déjà l'élément : les enfants absolus s'y accrochent. */
/* Le filet doré sous l'en-tête : le seul endroit où l'or est franc. Il tient le
   rôle que jouait la lueur dorée du fond sombre. */
header.site::after{content:"";display:block;height:2px;
  background:linear-gradient(90deg,var(--gold) 0%,var(--gold-hair) 58%,transparent 100%)}
header.site .wrap{display:flex;align-items:center;gap:18px;min-height:56px;flex-wrap:wrap}

.brand{font-family:var(--font-heading);font-weight:400;font-size:20px;
  color:var(--text);letter-spacing:-.01em;display:inline-flex;align-items:center;gap:9px}
.brand:hover{text-decoration:none}
/* Emplacement du logo (PNG à fournir). Tant que le fichier n'est pas là, rien
   ne s'affiche — pas de cadre en pointillés en production. */
.brand img{width:30px;height:30px;flex:0 0 auto;vertical-align:middle}
.brand span{color:var(--accent)}   /* prêt pour « VeVe<span>Wiki</span> » */

nav.main{display:flex;gap:4px;margin-left:auto;flex-wrap:wrap;align-items:center}
nav.main a{color:var(--primary);font-size:14.5px;padding:9px;border-radius:3px;
  min-height:var(--tap);display:inline-flex;align-items:center}
nav.main a:hover{background:var(--surface);text-decoration:none}
nav.main a[aria-current]{color:var(--text);font-weight:600;
  box-shadow:inset 0 -2.5px 0 var(--gold)}

/* --- Bascule jour / nuit ---------------------------------------------------
   Un bouton sans libellé : le glyphe dit l'ACTION à venir (lune = passer en
   nuit), et `aria-label` porte le texte pour qui ne voit pas le glyphe.
   ⚠️ Rendu uniquement si le manifeste déclare `palette_nuit` : un interrupteur
   qui n'allume rien est pire qu'une absence d'interrupteur. */
.bascule{width:34px;height:34px;flex:0 0 auto;cursor:pointer;
  border:1px solid var(--rule-strong);border-radius:2px;background:var(--surface);
  color:var(--ink-soft);font-size:15px;line-height:1;padding:0;margin-left:6px}
.bascule::before{content:"☾"}
:root[data-theme="nuit"] .bascule::before{content:"☀"}
.bascule:hover{border-color:var(--gold);color:var(--text)}

footer.site{border-top:1px solid var(--rule);background:var(--surface);
  margin-top:44px;padding:20px 0 30px;font-size:12.5px;color:var(--ink-faint)}
/* ⚠️ UN SEUL NIVEAU DANS LE PIED. « Site indépendant, non affilié » et « ceci
   n'est pas un conseil » sont des mentions obligatoires : elles doivent être
   ATTEIGNABLES, pas visibles de loin. Elles sortaient plus grosses et plus
   sombres que les liens légaux — donc c'est elles que l'œil attrapait en bas
   de chaque page.
   ⚠️ Le `!important` n'est pas un caprice : `Base.astro` écrit
   `style="font-size:13px"` EN LIGNE sur la dernière ligne, et un style en ligne
   bat n'importe quelle feuille. Le retirer demanderait de toucher un fichier qui
   sert les 15 sites — pour trois caractères. À supprimer le jour où l'on ouvrira
   `Base.astro` (lot 2). */
footer.site p{margin:0 0 7px;font-size:12.5px!important;color:var(--ink-faint);
  line-height:1.7}

/* ═══════════════════════════════════════════════════════════════════════════
   🦶🔴🔴 LOT 139 — LES QUATRE COLONNES DU PIED, CÔTÉ `encyclopedie`
   ═══════════════════════════════════════════════════════════════════════════
   ⛔ CE N'EST PAS UNE COPIE DE `vitrine`, ET IL NE FAUT PAS QUE ÇA LE DEVIENNE.
   Mesuré le 11/08/2026 : `Base.astro` émettait DÉJÀ `class="site-f__cols"` sur
   les 263 pages de vevewiki, et ce fichier ne portait AUCUNE règle de ce nom
   (`grep` = 0). Une classe émise que personne ne peint est le symétrique exact
   d'une règle que personne n'émet — et les DEUX vivaient dans ce pied en même
   temps, sur les deux sites. *Un contrôle qui part du CSS voit la seconde et
   jamais la première.*

   ⭐⭐ LES VALEURS SONT CELLES DE CE THÈME, PAS CELLES DE L'AUTRE. `vitrine`
   est un thème de vitrine : il donne `1.5fr` à la première colonne et de
   grands écarts. `encyclopedie` est un thème d'encyclopédie — corps à 12,5 px,
   `--ink-faint`, filets fins. Recopier la grille de `vitrine` aurait donné à
   vevewiki un pied deux fois plus haut que son contenu. ⇒ quatre colonnes
   ÉGALES, écarts serrés.

   ⚠️ `footer.site p` ci-dessus force `font-size:12.5px!important` : les
   colonnes sont faites de `<li>`, pas de `<p>`, donc elles y échappent. On
   redit la taille ici plutôt que d'élargir le sélecteur — élargir ferait
   remonter le `!important` sur des éléments qui n'en ont pas besoin, et un
   `!important` qu'on étend est un `!important` qu'on ne retirera plus.
   ⛔ Les deux reprises responsive sont celles de `vitrine` (820 px puis
   520 px) : les seuils du réseau sont une échelle DÉCLARÉE depuis ce lot
   (`engine/lib/seuils.mjs`), pas un chiffre qu'on choisit par thème. */
footer.site .site-f__cols{display:grid;gap:22px;grid-template-columns:repeat(4,1fr);
  margin-bottom:22px}
footer.site .site-f__cols h2{margin:0 0 9px;font-size:11.5px;color:var(--text);
  text-transform:uppercase;letter-spacing:.09em;font-weight:600}
footer.site .site-f__cols ul{list-style:none;margin:0;padding:0;display:grid;gap:6px;
  font-size:12.5px;line-height:1.6;color:var(--ink-faint)}
footer.site .site-f__cols a{color:var(--ink-faint);border-bottom:1px solid transparent}
footer.site .site-f__cols a:hover,footer.site .site-f__cols a:focus-visible{
  color:var(--text);border-bottom-color:var(--rule-strong)}
/* ⭐ Le filet du bas SÉPARE les colonnes des mentions. Il était posé sur un
   `<p>` qui était lui-même un ÉLÉMENT DE GRILLE : le trait passait donc au
   milieu d'une colonne. Sorti de la grille, il fait enfin ce qu'il annonce. */
footer.site .f-legal{border-top:1px solid var(--rule);padding-top:14px}
@media (max-width:820px){ footer.site .site-f__cols{grid-template-columns:1fr 1fr} }
@media (max-width:520px){ footer.site .site-f__cols{grid-template-columns:1fr} }

/* -----------------------------------------------------------------------------
   ⚠️⚠️ SURCHARGES À SPÉCIFICITÉ RENFORCÉE — LIRE AVANT DE SIMPLIFIER
   Base.astro contient un TROISIÈME bloc <style> (ligne 147) injecté APRÈS ce
   fichier, qui code en dur des règles pour .langbar / .legal-links / .crumbs /
   .saut / #langsuggest — dont `background:#ffffff14`, invisible sur blanc.
   Ordre réel : vars (145) → CE FICHIER (146) → bloc en dur (147).
   À spécificité égale, c'est le bloc en dur qui gagne. Les sélecteurs ci-dessous
   sont donc VOLONTAIREMENT plus spécifiques. ⛔ Ne pas les « nettoyer » :
   l'indicateur de langue courante redeviendrait invisible, sans erreur de build.
   ----------------------------------------------------------------------------- */
nav.main .langbar{display:flex;gap:4px;margin-left:8px}
nav.main .langbar a{font-size:12.5px;color:var(--ink-faint);padding:0 7px;
  border-radius:2px;min-height:30px;min-width:30px;border:1px solid transparent}
nav.main .langbar a[aria-current]{background:var(--surface);color:var(--text);
  border-color:var(--rule-strong);font-weight:600;box-shadow:none}

footer.site .legal-links{margin:0 0 10px;font-size:12.5px;line-height:1.9;
  color:var(--ink-faint)}
footer.site .legal-links a{color:var(--ink-faint);border-bottom:1px solid transparent}
footer.site .legal-links a:hover,footer.site .legal-links a:focus-visible{
  color:var(--text);border-bottom-color:var(--rule-strong)}

main .crumbs{font-size:12.5px;color:var(--ink-faint);margin:14px 0 2px}
main .crumbs a{color:var(--primary);display:inline-block;padding:3px 0;min-height:24px}

/* Le lien d'évitement existe déjà côté moteur (WCAG 2.4.1). Il utilisait
   `border:1px solid var(--primary)` sur `var(--surface)` : correct de jour dès
   lors que primary est le bleu et non l'or. On renforce juste le contraste. */
body .saut{background:var(--bg);color:var(--primary);border:2px solid var(--primary);
  border-radius:0 0 4px 0}

main #langsuggest{background:var(--gold-wash);border:1px solid var(--rule-strong);
  border-left:3px solid var(--gold);border-radius:0;padding:11px 14px}
main #langsuggest button{color:var(--ink-faint)}

/* -----------------------------------------------------------------------------
   ⚠️⚠️ L'ANCRE DOIT ATTERRIR SOUS L'EN-TÊTE, PAS DESSOUS AU SENS PROPRE
   L'en-tête est COLLANT. Sans `scroll-margin-top`, le navigateur amène la cible
   à y = 0 — c'est-à-dire EXACTEMENT derrière l'en-tête, qui la recouvre. Le
   lecteur clique « Floor Price », la page bouge, et il ne voit pas le terme :
   le symptôme est rigoureusement le même que celui d'une ancre absente.
   ⭐ Poser des ancres sans cette règle, c'est livrer un correctif qui a l'air
   d'un correctif. Hauteurs réelles : 56 + 2 px de filet au bureau ; 50 (titre)
   + 44 (rubriques) + 3 px sur mobile, où l'en-tête porte DEUX lignes.
   ----------------------------------------------------------------------------- */
:target{scroll-margin-top:72px}
.term,.milestone,.item[id],.fiche,h2[id],h3[id]{scroll-margin-top:72px}

/* Et une fois arrivé, on doit VOIR lequel c'est. Une page de 87 définitions se
   ressemble d'une ligne à l'autre : sans marque, il faut relire pour trouver ce
   qu'on cherchait déjà. Le repère s'efface au premier clic ailleurs — il aide,
   il ne décore pas. */
.term:target,.milestone:target{
  background:var(--gold-wash);box-shadow:inset 3px 0 0 var(--gold);
  padding-left:11px;margin-left:-14px;border-radius:0 2px 2px 0}
/* ⚠️ L'annuaire est une GRILLE : une marge négative y ferait déborder la
   cellule sur sa voisine. Le repère est donc posé sans toucher à la boîte. */
.item[id]:target{background:var(--gold-wash);box-shadow:inset 3px 0 0 var(--gold)}
.term:target dt,.milestone:target .what,.item[id]:target .n{font-weight:700}

/* =============================================================================
   3. TITRES & TEXTE COURANT
   ============================================================================= */
h1{font-family:var(--font-heading);font-size:clamp(25px,4vw,33px);line-height:1.2;
  margin:6px 0 8px;font-weight:400;padding-bottom:9px;
  border-bottom:1px solid var(--rule-strong)}
h2{font-family:var(--font-heading);font-size:clamp(19px,3vw,22px);margin:30px 0 10px;
  font-weight:400;padding-bottom:5px;border-bottom:1px solid var(--rule)}
h3{font-family:var(--font-heading);font-size:17.5px;margin:22px 0 7px;font-weight:400}

/* 68ch : sur .wrap (1080 px) la ligne dépassait 90 caractères, très au-delà de
   la plage confortable (65–75). Une mesure trop longue fait perdre la ligne au
   retour à la marge — c'est une fatigue, pas un défaut visible. */
main p,main li{max-width:68ch}
main{padding:0 0 20px}

.lead{color:var(--ink-soft);margin:0 0 24px;font-size:16.5px;max-width:68ch}
.muted{color:var(--ink-faint)}
.prose p,.post p{font-size:16px;line-height:1.72}
.prose h2,.post h2{max-width:68ch}
.prose blockquote{margin:0 0 14px;padding:9px 14px;border-left:3px solid var(--gold);
  background:var(--gold-wash);color:var(--ink-soft);font-size:14.5px}
.prose code,.post code{background:var(--surface);border:1px solid var(--rule);
  border-radius:2px;padding:1px 4px;font-size:14px}

/* La devise, traduite par langue (clé `devise` du manifeste). Filets haut/bas :
   la seule ornementation du site, et elle reste en or lisible. */
.devise{display:inline-block;font-family:var(--font-heading);font-style:italic;
  font-size:14.5px;color:var(--accent);border-top:1px solid var(--gold-hair);
  border-bottom:1px solid var(--gold-hair);padding:5px 0;margin:0 0 18px}

/* =============================================================================
   4. BLOCS GÉNÉRIQUES — cartes, grilles, statistiques, étiquettes
   Densité assumée : filets 1 px et fonds gris très clairs. Pas d'ombre, pas de
   coin arrondi à 12 px : un wiki n'est pas un tableau de bord.
   ============================================================================= */
.card{background:var(--surface);border:1px solid var(--rule);border-radius:0;padding:15px}

.grid{display:grid;gap:1px;background:var(--rule);border:1px solid var(--rule);
  grid-template-columns:repeat(auto-fill,minmax(230px,1fr))}
.item{display:block;background:var(--bg);border:0;border-radius:0;padding:13px 14px;
  color:var(--text);min-height:var(--tap)}
.item:hover{background:var(--surface);text-decoration:none}
.item .n{font-family:var(--font-heading);font-size:15.5px;font-weight:400;
  color:var(--primary);margin-bottom:3px}
.item .s{font-size:12px;color:var(--ink-faint);line-height:1.45}
.item .f{margin-top:9px;font-size:17px;font-weight:500;color:var(--text)}
.item .f.muted{color:var(--ink-faint)}

.tag{display:inline-block;font-size:11.5px;padding:2px 7px;border-radius:2px;
  background:var(--surface);border:1px solid var(--rule);color:var(--ink-soft);
  margin-right:5px}
a.tag:hover{border-color:var(--rule-strong);text-decoration:none}

.stats{display:grid;gap:1px;background:var(--rule);border:1px solid var(--rule);
  grid-template-columns:repeat(auto-fit,minmax(125px,1fr));margin:18px 0}
.stat{background:var(--bg);border:0;border-radius:0;padding:11px 13px}
.stat .k{font-size:10.5px;color:var(--ink-faint);text-transform:uppercase;
  letter-spacing:.06em}
.stat .v{font-family:var(--font-heading);font-size:20px;font-weight:400;
  font-variant-numeric:tabular-nums;margin-top:2px}

.up{color:var(--accent)}
.down{color:var(--danger)}

.alerte,.avertis{border:1px solid var(--rule-strong);border-left:3px solid var(--gold);
  background:var(--gold-wash);padding:10px 13px;margin:0 0 16px;font-size:14px;
  color:var(--ink-soft);max-width:68ch}
.alerte b,.avertis b{color:var(--text)}

/* =============================================================================
   5. TABLEAUX
   ============================================================================= */
table{width:100%;border-collapse:collapse;font-size:14.5px;
  border:1px solid var(--rule-strong)}
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--rule);
  vertical-align:top}
th{background:var(--th-bg);color:var(--ink-soft);font-weight:600;font-size:12.5px;
  text-transform:none;letter-spacing:0}
tbody tr:last-child td{border-bottom:0}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}

/* =============================================================================
   6. PAGES ÉDITORIALES  (engine/lib/editorial*.mjs — le cœur de vevewiki)
   ============================================================================= */

/* --- Glossaire & sigles : une liste de définitions, pas des cartes --- */
.glossary{margin:16px 0 0}
.glossary .term{padding:12px 0;border-top:1px solid var(--shell-2);max-width:none}
.glossary .term:first-child{border-top:1px solid var(--rule-strong)}
.glossary .term dt,.glossary .term>b,.glossary .term .n{
  font-family:var(--font-heading);font-size:15.5px;font-weight:400}
.glossary .term .s,.glossary .term dd{margin:3px 0 0;font-size:14px;
  color:var(--text);max-width:68ch}
.glossary .term .sources,.glossary .term .muted{font-size:11.5px;color:var(--ink-faint)}

/* Le sigle : cadre doré, TEXTE en or lisible. Le cadre porte la couleur vive,
   pas les lettres — c'est la règle qui vaut partout dans ce fichier. */
.glossary .tag,.term .tag{font-family:var(--font-body);font-size:10.5px;
  font-weight:700;letter-spacing:.06em;color:var(--accent);
  border:1px solid var(--gold);background:var(--gold-wash)}

/* --- Chronologie : une frise, pas une liste --- */
/* ⚠️ `<ol class="timeline">` : sans `list-style:none`, les numéros du navigateur
   (1. 2. 3.) s'ajoutent aux puces dorées de la frise — deux repères pour la même
   chose. Et `padding-left` doit écraser le retrait par défaut de 40 px, sinon le
   filet vertical et le texte ne sont plus alignés. */
.timeline{margin:16px 0 0;padding-left:15px;border-left:2px solid var(--shell-2);
  list-style:none}
.milestone{position:relative;padding:0 0 15px;max-width:none}
.milestone::before{content:"";position:absolute;left:-21px;top:6px;width:7px;height:7px;
  border-radius:50%;background:var(--gold);border:1.5px solid var(--bg)}
.milestone .when{font-size:11.5px;color:var(--ink-faint);
  font-variant-numeric:tabular-nums}
.milestone .what{font-family:var(--font-heading);font-size:15px;line-height:1.35;
  margin-top:2px;max-width:68ch}
.milestone .tag{margin-left:6px}

/* --- Fiche (marque, créateur, entrée détaillée) --- */
.fiche{margin:16px 0 0}
.reperes{display:grid;gap:1px;background:var(--rule);
  border:1px solid var(--rule-strong);
  grid-template-columns:repeat(auto-fit,minmax(110px,1fr));margin:0 0 18px}
.reperes>*{background:var(--bg);padding:9px 11px;text-align:center}
.chiffres{display:grid;gap:1px;background:var(--gold-hair);
  grid-template-columns:repeat(auto-fit,minmax(90px,1fr));
  border-top:1px solid var(--gold-hair);margin-top:9px}
.chiffres>*{background:var(--gold-wash);padding:8px 4px;text-align:center;font-size:11px;
  color:var(--ink-soft)}
.chiffres b{display:block;font-family:var(--font-heading);font-size:16px;
  color:var(--text);font-weight:400}

.counters{font-size:12.5px;color:var(--ink-faint);margin:0 0 14px}
.sources{font-size:12.5px;color:var(--ink-faint);line-height:1.75}
.sources a{color:var(--primary)}
.notes{font-size:13.5px;color:var(--ink-soft);max-width:68ch}
.voisines{margin:22px 0 0;padding-top:14px;border-top:1px solid var(--rule);
  font-size:13.5px}
.socials{display:flex;gap:7px;flex-wrap:wrap;margin:10px 0 0}
.annuaire-group{margin:22px 0 0}
.latest-wrap{margin:22px 0 0}
.latest{margin:0}

/* --- Cartes d'ARTICLES : elles respirent, contrairement aux grilles denses ---
   Une grille de rubriques est un index : on la balaie, les filets de 1 px
   suffisent. Une liste d'articles se REGARDE une carte à la fois — d'où de
   vraies gouttières et une bordure par carte.

   ⚠️ CORRIGÉ LE 30/07 : la règle s'écrivait `.latest-wrap .grid`, un sélecteur
   de POSITION. Il ne valait donc que pour le bloc « articles » de l'accueil —
   et `/blog/`, qui est LA page où l'on parcourt les articles, gardait la grille
   dense. Le style suivait l'endroit au lieu de suivre la nature de la chose.
   ⭐ Une classe explicite (`cartes`) dit ce que c'est, et se pose partout où
   c'en est. */
.grid.cartes{gap:14px;background:none;border:0;
  grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}
.grid.cartes .item{border:1px solid var(--rule);padding:0;overflow:hidden;
  display:flex;flex-direction:column}
.grid.cartes .item:hover{border-color:var(--rule-strong);background:var(--surface)}
.grid.cartes .item .n,
.grid.cartes .item .s,
.grid.cartes .item .f,
.grid.cartes .item > p{padding-left:13px;padding-right:13px}
.grid.cartes .item .n{padding-top:12px;font-size:16px}
.grid.cartes .item > p:last-child{padding-bottom:12px;margin-bottom:0}
.grid.cartes .item .f{padding-bottom:12px;margin-top:auto}

/* La couverture : rendue SEULEMENT si l'article en déclare une. Pas de cadre
   gris par défaut — une image absente ne doit pas devenir un trou visible.
   ⚠️ La colonne `cover` du Sheet est vide pour les 13 articles : rien ne
   s'affichera tant qu'elle ne sera pas remplie. */
.grid.cartes .item .cover{display:block;width:100%;aspect-ratio:16/9;
  object-fit:cover;background:var(--surface);border-bottom:1px solid var(--rule);
  margin:0 0 2px}

/* ⚠️⚠️ DÉFAUT QUE J'AI CRÉÉ, VU EN PRODUCTION : `.lien-ancre` n'est pas
   seulement le petit lien discret à côté d'un titre. Dans la chronologie, c'est
   la balise qui entoure **LA DATE ELLE-MÊME** :
       <div class="when"><a class="lien-ancre" href="#j-…">{r.date}</a>
   Un `opacity:0` global a donc rendu les 41 dates invisibles. La frise
   paraissait sans dates, et sans repère de lecture.
   ⭐ La leçon : une classe nommée d'après son RÔLE SUPPOSÉ (« le lien d'ancre »)
   peut recouvrir deux usages. On style le rôle DANS SON CONTEXTE, jamais la
   classe seule. */
h2 .lien-ancre,h3 .lien-ancre{color:var(--ink-faint);text-decoration:none;
  opacity:0;padding:0 6px;font-weight:400}
h2:hover .lien-ancre,h3:hover .lien-ancre,
h2 .lien-ancre:focus-visible,h3 .lien-ancre:focus-visible{opacity:1}
/* Dans la frise, l'ancre EST la date : pleinement visible, et cliquable. */
.milestone .when .lien-ancre{color:var(--ink-faint);text-decoration:none;opacity:1}
.milestone .when .lien-ancre:hover{color:var(--primary);text-decoration:underline}

/* --- Pages légales (LegalPage.astro : `.legal`, corps injecté en HTML) ---
   Obligatoires et lues rarement, mais lues en entier quand elles le sont :
   même mesure de ligne que le reste, aucune fantaisie. */
.legal{max-width:68ch;font-size:15px}
.legal h2{font-size:19px;margin:26px 0 8px}
.legal ul,.legal ol{padding-left:22px}
.legal table{font-size:13.5px;margin:12px 0}

/* --- RECHERCHE (features.search: internal, index éditorial) ---------------
   La liste de résultats est en flux NORMAL, pas en survol absolu : sur mobile
   un menu flottant se fait recouvrir par le clavier virtuel, et l'utilisateur
   ne voit jamais ses résultats. Elle pousse le contenu, c'est voulu. */
.searchwrap{margin:0 0 26px;max-width:520px}
.searchbox{width:100%;height:var(--tap);padding:0 12px;font-size:15px;
  border:1px solid var(--rule-strong);border-radius:2px;background:var(--bg);
  color:var(--text);font-family:var(--font-body)}
.searchbox::placeholder{color:var(--ink-faint)}
.searchhint{margin:5px 2px 0;font-size:11.5px;color:var(--ink-faint)}

.results:not(:empty){border:1px solid var(--rule-strong);border-top:0;
  background:var(--bg);margin-top:-1px}
.result{display:flex;align-items:baseline;gap:10px;padding:9px 12px;
  min-height:var(--tap);border-top:1px solid var(--shell-2);text-decoration:none}
.result:first-child{border-top:0}
.result:hover,.result:focus-visible{background:var(--surface);text-decoration:none}
.result .rn{font-family:var(--font-heading);font-size:14.5px;color:var(--primary);
  flex:1;min-width:0}
/* Le TYPE de chaque résultat, à droite. Sans lui, « Floor Price » du glossaire
   et l'article « Ce qu'est vraiment un prix plancher » sont indiscernables :
   deux lignes, deux destinations, aucun moyen de choisir. */
.result .rt{font-size:10.5px;color:var(--ink-faint);text-transform:uppercase;
  letter-spacing:.05em;white-space:nowrap;flex:0 0 auto}
.searchvide{margin:0;padding:11px 12px;font-size:13px;color:var(--ink-faint)}

/* =============================================================================
   7. FIGURES / GRAPHIQUES
   ⚠️ Les figures générées côté serveur (engine/lib/figures.mjs) relisent
   `identity.palette` et portent leur propre cartouche : elles suivront la
   palette jour d'elles-mêmes. Ici on ne traite que le SVG inline.
   ============================================================================= */
.chart{width:100%;height:auto;margin:8px 0 4px}
.chart .line{stroke:var(--primary);stroke-width:2;stroke-linejoin:round;
  stroke-linecap:round}
.chart .area{fill:color-mix(in srgb,var(--primary) 12%,transparent);stroke:none}
/* ⚠️ COLLISION DE NOMS PRÉSENTE DANS LE MOTEUR, pas introduite ici : `.grid`
   sert à la fois de grille de mise en page (§4) et de quadrillage de graphique.
   Sans les annulations ci-dessous, le quadrillage d'un graphique hérite
   `display:grid`, `background` et `border` — et disparaît du tracé. */
.chart .grid{stroke:var(--rule);stroke-width:1;display:initial;background:none;
  border:0;gap:0}
.chart .axis{fill:var(--ink-faint);font-size:11px}

/* =============================================================================
   8. MOBILE — vevewiki est lu au pouce avant d'être lu au clavier
   ============================================================================= */
@media (max-width:640px){
  body{font-size:15.5px}
  .wrap{padding:0 16px}

  /* ⚠️⚠️ TROIS DÉFAUTS MOBILES CONSTATÉS EN PRODUCTION LE 30/07, UNE SEULE CAUSE.
     `.brand{flex:1}` donne au titre une base de 0 : la ligne calcule donc
     « 0 % + 100 % = 100 %, ça tient », la nav NE PASSE PAS à la ligne, et le
     titre déborde par-dessus « Glossaire ». Comme la nav se retrouve coincée à
     côté du titre, tout son contenu part dans le défilement horizontal — d'où
     le sélecteur de langue invisible tant qu'on ne fait pas glisser la barre.
     ⭐ La leçon : `flex:1` n'est pas « prends la place restante », c'est
     « base 0, puis grandis ». Pour forcer un retour à la ligne il faut une
     base réelle : `flex:0 0 100%`. */
  header.site .wrap{min-height:50px;gap:0;position:relative;flex-wrap:wrap}
  .brand{font-size:17px;flex:1 1 auto;min-width:0;max-width:calc(100% - 158px);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;
    line-height:50px}

  /* Le sélecteur de langue SORT du défilement : il vit sur la ligne du titre,
     toujours visible. Enterré dans la barre qui défile, il n'existait que pour
     qui pense à faire glisser une barre horizontale — c'est-à-dire personne. */
  nav.main .langbar{position:absolute;top:10px;right:0;margin:0;gap:3px;z-index:5}
  /* Une pastille encadrée, pas un mot gris posé sur du blanc : sur la ligne du
     titre, sans fond ni bordure, elle se lisait « blanc sur blanc ». */
  nav.main .langbar a{font-size:11.5px;min-width:28px;padding:0 5px;min-height:30px;
    color:var(--ink-soft);background:var(--surface);
    border:1px solid var(--rule);border-radius:2px}
  nav.main .langbar a[aria-current]{background:var(--bg);color:var(--text);
    border-color:var(--gold);font-weight:700}

  /* ⚠️⚠️ LE MASQUE A ÉTÉ RETIRÉ — il effaçait le sélecteur de langue.
     J'avais posé `mask-image` sur `nav.main` pour faire un dégradé à droite. Or
     `.langbar` est un ENFANT de `nav.main` : un masque s'applique à tout le
     sous-arbre, et la langbar était placée pile dans la zone transparente du
     dégradé. Résultat : des boutons présents, cliquables, et **invisibles**.
     ⭐ Deux corrections posées le même jour se sont annulées : le repère de
     défilement a effacé ce qu'il devait rendre atteignable. Le dégradé vit
     maintenant sur un pseudo-élément de l'EN-TÊTE, qui n'est pas le conteneur
     de défilement — il ne peut donc plus rien masquer de son contenu. */
  nav.main{flex:0 0 100%;width:100%;gap:0;margin-left:0;overflow-x:auto;
    -ms-overflow-style:none;scrollbar-width:none;
    border-top:1px solid var(--shell-2);flex-wrap:nowrap;padding-right:26px}
  header.site::before{content:"";position:absolute;right:0;bottom:2px;
    width:30px;height:44px;pointer-events:none;z-index:3;
    background:linear-gradient(90deg,transparent,var(--bg) 78%)}
  nav.main::-webkit-scrollbar{display:none}
  nav.main a{font-size:13.5px;padding:0 10px;white-space:nowrap}

  /* En-tête à deux lignes sur mobile : 50 (titre) + 44 (rubriques) + filets. */
  :target,.term,.milestone,.item[id],.fiche,h2[id],h3[id]{scroll-margin-top:108px}
  h1{font-size:23px}
  .grid,.stats{grid-template-columns:1fr}
  .reperes,.chiffres{grid-template-columns:1fr 1fr}
  main p,main li,.lead,.notes,.milestone .what{max-width:none}
  table{font-size:13.5px}
  th,td{padding:7px 8px}
}

/* =============================================================================
   9. IMPRESSION & MOUVEMENT RÉDUIT
   Un article d'encyclopédie s'imprime et se convertit en PDF. Sans l'adresse
   des liens externes, un article imprimé n'est plus sourçable — or « toute
   info porte un lien » est la règle du site.
   ============================================================================= */
@media print{
  header.site,footer.site .legal-links,nav.main,.saut,#langsuggest,.lien-ancre{display:none}
  body{background:#fff;color:#000;font-size:11pt}
  a{color:#000;text-decoration:underline}
  main a[href^="http"]::after{content:" (" attr(href) ")";font-size:8.5pt;color:#444;
    word-break:break-all}
  .card,.item,table,.alerte,.avertis{break-inside:avoid}
  h1,h2,h3{break-after:avoid}
  details{display:block!important}
}
@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important;scroll-behavior:auto!important}
}

/* =============================================================================
   CONTRASTES — mesurés, pas estimés. Seuil WCAG AA = 4,5:1 (texte courant).
   -----------------------------------------------------------------------------
     rôle              couleur    sur #ffffff   sur #f8f9fa   sur #eaecf0
     texte courant     #202122      16,13:1       15,40:1       15,00:1   AAA
     texte secondaire  #54595d       7,09:1        6,72:1        6,30:1   AAA
     méta / dates      #666b71       5,38:1        5,10:1        4,54:1   AA
     lien              #3366cc       5,37:1        5,09:1        4,54:1   AA
     lien visité       #795cb2       5,27:1           —             —     AA
     or — texte        #7a5f10       6,05:1        5,49:1           —     AA
     danger            #b32424       6,57:1           —             —     AA
     or — DÉCOR SEUL   #d4af37       2,10:1  ⛔ INTERDIT EN TEXTE
   -----------------------------------------------------------------------------
   ⚠️ LA PAIRE LA PLUS JUSTE : lien #3366cc sur le séparateur #eaecf0 —
   4,54:1 pour un seuil de 4,50. Aucune marge. Si `--shell-2` s'éclaircit d'un
   cran, les liens posés dessus deviennent non conformes et RIEN ne le signale.
   Ne pas éclaircir --shell-2 sans remesurer.
   ⚠️ Le gris de méta de Wikipédia, #72777d, a été écarté : il passe sur blanc
   (4,52:1) mais ÉCHOUE sur --surface (4,28:1) — or les méta vivent justement
   dans les encadrés gris. Un contraste se valide contre le fond RÉEL du bloc,
   jamais contre le blanc.
   ============================================================================= */

/* ⛔⛔ `hidden` EST UNE INTENTION DU DOM, ELLE NE SE NEGOCIE PAS (31/07/2026).
   La feuille du navigateur dit `[hidden]{display:none}` — specificite (0,1,0).
   N'IMPORTE QUELLE classe de ce theme qui pose un `display:` la vaut et,
   declaree plus tard, la GAGNE : l'element reste VISIBLE alors que le moteur
   l'a cache. Vu en production sur veveprice (/movers/ affichait le tableau ET
   la grille) ; ce theme avait le meme trou, sans qu'on l'ait encore rencontre.
   ⭐ Corrige AVANT le symptome, parce que le controle l'a trouve — c'est la
   premiere fois aujourd'hui que l'ordre est dans ce sens-la. */
[hidden]{ display:none !important; }

/* ⛔⛔ `.n` ET `.s` N'AVAIENT AUCUNE REGLE — DANS LES TROIS THEMES (31/07/2026).
   Ce sont le TITRE et la LIGNE SECONDAIRE des cartes generiques du moteur :
   la liste des articles, les resultats de recherche, les listes d'entrees.
   Sans regle, l'article sortait en texte nu dans une boite — « un probleme de
   design, pas de contenu » (Preda). J'avais conclu l'inverse la veille : la
   page etait vide, j'ai cru que le CONTENU manquait alors que c'est
   l'HABILLAGE qui manquait. ⭐ Une page pauvre ne dit pas d'elle-meme laquelle
   des deux moities manque.
   ⭐ Les listes de `css-mort.mjs` ne les contenaient pas : le socle y est ECRIT
   A LA MAIN, donc il ne couvre que ce qu'on a pense a y mettre. Corrige. */
.item .n{
  display:block;font-family:var(--font-heading,system-ui);font-weight:700;
  font-size:1.05rem;line-height:1.3;
  color:var(--text);margin:0 0 6px;
}
.item .s{
  display:block;font-family:var(--font-body,system-ui);font-size:.72rem;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);
}
.item .lead{font-size:.9rem;margin:10px 0 0;color:var(--muted)}
.item:hover .n{color:var(--primary)}

/* ⭐ `.flat` : la variation NULLE. `up` est vert, `down` est rouge, et `flat`
   ne recevait rien — un « 0,0 % » sortait donc aussi affirme qu'une vraie
   hausse. L'absence de mouvement est une information, mais la moins
   importante des trois : elle doit se lire sans attirer l'oeil. */
.flat{ color:var(--muted); }

/* ═══════════════════════════════════════════════════════════════════════════
   📏 LOT 203, POINT `ag` — UNE SÉRIE NE DÉFORME PLUS SA CARTE
   ═══════════════════════════════════════════════════════════════════════════
   🔴 CE QUE PREDA A DEMANDÉ, AVEC SES MOTS : « il faut juste tronquer
   l'affichage, et quand on passe le curseur dessus on voit dans une infobulle
   le nom complet — le but est que ça ne déforme pas les tuiles ».
   ⭐⭐⭐ LE BUT EST « NE PAS DÉFORMER », PAS UN NOMBRE DE CARACTÈRES. Sa
   première formulation donnait 13 ; sa raison donne le critère. Couper à 13
   aurait tronqué « Spider-Man '94 » (14 caractères) dans une colonne qui en
   tient 34, et l'aurait tronqué pareil sur un écran deux fois plus large.

   ⛔ ET LA COUPE RESTE ICI, PAS AU SERVEUR. Une chaîne tronquée à la source ne
   peut plus rien dire au survol, et elle serait coupée identiquement partout.
   `text-overflow` coupe à la place RÉELLE et laisse le texte entier dans le
   document — c'est ce qui rend l'infobulle possible.

   🔴🔴 `[data-serie]` ET JAMAIS `.item .s` NU. Cette classe porte AUSSI des
   dates d'article, des rôles et des notes éditoriales (`BlogIndex`, `BlogTag`,
   `Editorial`). Leur imposer une ligne unique tronquerait des textes qui ont le
   droit de respirer — et un correctif global sur une classe partagée avait déjà
   coûté 764 titres à ce projet.

   ⭐ `max-width` en `ch` et non en pixels : la borne suit la taille de police
   du lecteur. `34ch` est la valeur que `.tbl-obj__s` emploie depuis le lot 139,
   reprise ici pour que les deux familles coupent au même endroit.
   ⚠️ `min-width:0` sur le PARENT : sans lui, un enfant qui refuse de rétrécir
   élargit la carte au lieu d'être coupé, et l'`ellipsis` ne se déclenche
   jamais. C'est le défaut qu'on croit corriger en ajoutant `overflow:hidden`
   à l'enfant, alors qu'il se règle chez le parent. */
.item{ min-width:0; }
.item .s[data-serie]{
  display:block; max-width:34ch;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.item .n[title]{
  display:block; max-width:34ch;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.legal-links{margin:0 0 10px;font-size:12.5px;line-height:1.9;color:var(--muted)}.legal-links a{color:var(--muted);text-decoration:none;border-bottom:1px solid transparent}.legal-links a:hover,.legal-links a:focus-visible{color:var(--text);border-bottom-color:var(--muted)}.langbar{display:flex;gap:6px;margin-left:12px}.langbar a{font-size:13px;color:var(--muted);padding:2px 6px;border-radius:6px;min-height:24px;min-width:24px;display:inline-flex;align-items:center;justify-content:center}.langbar a[aria-current]{background:#ffffff14;color:var(--text)}.crumbs a{display:inline-block;padding:3px 0;min-height:24px}.legal-links a{display:inline-block;padding:3px 0;min-height:24px}.saut{position:absolute;left:-9999px;top:0;z-index:100;background:var(--surface);color:var(--text);border:1px solid var(--primary);border-radius:0 0 8px 0;padding:10px 16px;text-decoration:none}.saut:focus{left:0}#langsuggest{display:none;background:var(--surface);border:1px solid var(--primary);border-radius:10px;padding:10px 14px;margin:14px 0;font-size:14px}#langsuggest a{font-weight:500}#langsuggest button{background:none;border:0;color:var(--muted);cursor:pointer;font-size:13px;text-decoration:underline}.globe__sugg{border-top:1px solid var(--rule);margin-top:6px;padding-top:8px;max-width:230px}.globe__sugg p{margin:0 0 7px;font-size:12.5px;line-height:1.45;color:var(--text-2);white-space:normal}.globe__sugg span{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.globe__sugg button{padding:5px 10px;border-radius:6px;font-size:12.5px;cursor:pointer;min-height:30px;white-space:nowrap}.globe__sugg button:first-child{background:var(--primary);color:var(--surface);border:0;font-weight:600}.globe__sugg button:last-child{background:none;border:0;color:var(--muted);text-decoration:underline}