@font-face{font-family:'Archivo';src:url('/fonts/archivo-latin-wght.woff2') format('woff2');font-weight:100 900;font-style:normal;font-display:swap;}@font-face{font-family:'Space Grotesk';src:url('/fonts/space-grotesk-latin-wght.woff2') format('woff2');font-weight:300 700;font-style:normal;font-display:swap;}:root{color-scheme:dark;--primary:#10CEF2;--accent:#3EC875;--danger:#ED9BA6;--bg:#1A1A1A;--surface:#2C2C2C;--text:#FFFFFF;--muted:#B1B1B1;--font-heading:'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;--font-body:'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif}:root[data-theme="nuit"]{color-scheme:light;--primary:#0A7A90;--accent:#096E38;--danger:#B01F32;--bg:#EFEFEF;--surface:#FFFFFF;--text:#1A1A1A;--muted:#5E5E5E;--font-heading:'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;--font-body:'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif}/* ═══════════════════════════════════════════════════════════════════════════
   VeVePreda/veve-sites — themes/vitrine/theme.css
   « Vitrine Froide » — LE CSS DE LA MAQUETTE, PORTÉ TEL QUEL
   ═══════════════════════════════════════════════════════════════════════════

   ⭐⭐⭐ CE FICHIER N'EST PLUS UNE RÉÉCRITURE, C'EST UN PORTAGE.
   Six versions précédentes retrouvaient l'INTENTION de la maquette et en
   perdaient les VALEURS — d'où « ça y ressemble mais ce n'est pas ça », sept
   fois de suite. Un comparateur écrit après coup a chiffré l'écart :
   **18,3 % des classes de la maquette existaient dans les gabarits.**
   ⭐ Un défaut qui revient sept fois n'est pas une étourderie, c'est un
   contrôle absent. Celui-ci s'appelle `comparer.js` : il liste les classes de
   chaque écran de la maquette et les confronte à celles que le gabarit émet.

   647 règles + 55 blocs @media/@keyframes/@container, extraits de
   `maquette-veveprice.html`, châssis de prévisualisation écarté.
   ⛔ NE PAS LE RÉÉCRIRE À LA MAIN — le RÉGÉNÉRER depuis la maquette.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  /* ⚠️ `--grain` ÉTAIT POSÉ PAR DU JAVASCRIPT dans la maquette
     (`documentElement.style.setProperty`). En production il n'y a pas ce
     script : le grain aurait simplement disparu, sans erreur, et les aplats
     auraient perdu l'épaisseur qui les distingue d'un dégradé numérique.
     ⭐ Cuit en data-URI : zéro requête, zéro script, et il ne peut plus
     dépendre de l'exécution d'un fichier. */
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.028'/%3E%3C/svg%3E");

  /* ─── LES GRIS VeVe ────────────────────────────────────────────────────── */
  --nuit:      #1A1A1A;
  /* --surface : fourni par le manifeste */   /* VeVe, verbatim */
  --surface-2: #383838;   /* VeVe, verbatim */
  --surface-3: #444444;

  --rule:      #3A3A3A;
  --rule-2:    #4E4E4E;
  --rule-int:  #8F8F8F;   /* bordure de champ · 3,01:1 */
  /* --text : fourni par le manifeste */   /*  9,74:1 */
  --text-2:    #CACACA;   /*  5,94:1 — VeVe, verbatim */
  /* --muted : fourni par le manifeste */   /*  4,54:1 — plancher */

  /* ─── LE PANNEAU OS — la signature éditoriale ──────────────────────────────
     ⭐ Passé du blanc pur au BONE `#EEEDE8`. Le blanc pur est un défaut de
     fabrique : c'est ce qu'on obtient quand on n'a rien choisi. Un os cassé
     tire vers le chaud, se détache du gris VeVe sans l'agresser, et c'est
     exactement le panneau des planches .SWOOSH. */
  --carte:     #EEEDE8;
  --carte-2:   #E4E3DD;
  --carte-ink: #1A1A1A;   /* 13,53:1 */
  --carte-ink-2:#5E5E5E;  /*  5,04:1 */
  --carte-lien:#0A6F84;   /*  4,51:1 — corrigé après mesure sur l'os */
  --carte-rule:#D5D4CD;

  /* ─── CYAN — la couleur du site ────────────────────────────────────────── */
  --cyan:      #10CEF2;   /* 5,16:1 · texte ET aplat, sans retouche */
  --cyan-fonce:#0A8FA9;
  --cyan-1v:   #10CEF21F;

  /* ─── PRIX ─── sur des CHIFFRES uniquement ─────────────────────────────── */
  --up:        #3EC875;   /* vert VeVe éclairci · 4,51:1 */
  --down:      #ED9BA6;   /* rouge VeVe éclairci · 4,56:1 */
  --up-1v:     #3EC8751F;
  --down-1v:   #ED9BA61F;

  /* ─── MONNAIES ─────────────────────────────────────────────────────────────
     ⭐ Deux marques distinctes, imposées par Preda et justes :
       gems = DIAMANT plein, cyan
       OMI  = ROND CREUX, rouge
     Elles ne se confondent ni par la forme, ni par le remplissage, ni par la
     couleur. Une fiche affiche les deux côte à côte : c'est le seul endroit du
     site où deux devises coexistent, il fallait qu'elles soient illisibles
     l'une pour l'autre. */
  --gems:      #10CEF2;
  --omi:       #E36777;   /* rouge VeVe éclairci à 3,00:1 — c'est un TRAIT */

  /* ─── RARETÉ — code VeVe, sur des FACETTES ─────────────────────────────────
     `-a` face éclairée (fond sombre) · `-b` face d'ombre · `-ink` fond clair.
     Les teintes sont celles de la planche ; seule la luminosité bouge, et
     seulement du minimum nécessaire pour atteindre 3:1. */
  --r-common-a:  #0EBA52; --r-common-b:  #086C30; --r-common-ink:  #0B9542;
  --r-uncommon-a:#D157FC; --r-uncommon-b:#762692; --r-uncommon-ink:#C540F4;
  --r-rare-a:    #1F91FB; --r-rare-b:    #004B91; --r-rare-ink:    #007FF5;
  --r-ultra-a:   #ED8E00; --r-ultra-b:   #895200; --r-ultra-ink:   #BB7000;
  --r-secret-a:  #E36777; --r-secret-b:  #7D1623; --r-secret-ink:  #D7263D;
  --r-proof-a:   #CACACA; --r-proof-b:   #757575; --r-proof-ink:   #818181;

  /* ─── ACCÈS ─── ⚠️ LE VIOLET EST MORT, LE CYAN LE REMPLACE.
     Décision de Preda : le cyan est la couleur du site, elle doit porter aussi
     l'accès. ⭐ Conséquence à assumer : l'accès ne se distingue plus par la
     TEINTE, il se distingue par le TRAITEMENT — bordure en pointillé, cadenas,
     et jamais d'aplat. Un signal peut se porter par autre chose qu'une couleur,
     mais il faut alors que le traitement soit tenu partout, sans exception. */
  --lock:      #10CEF2;
  --lock-pur:  #10CEF2;
  --lock-1v:   #10CEF224;

  /* ─── SECTION — 5 ambiances, toutes de la planche VeVe ─────────────────── */
  --sect-a:    #10CEF2;
  --sect-pur:  #10CEF2;
  --sect-sur:  #1A1A1A;
  --sect-fonce:#0A8FA9;
  --sect-1v:   #10CEF21F;

  /* ─── TYPO ─────────────────────────────────────────────────────────────── */
  /* ⭐ ARCHIVO remplace Outfit — c'est la fonte de la référence « SIGN UP FOR
     EARLY ACCESS » : grotesque à chasse variable, terminaisons plates,
     contreformes carrées, très lourde en display. Elle est VARIABLE sur deux
     axes (largeur 75→125, graisse 400→900), donc UNE famille couvre le titre
     monumental ET l'interface. Deux fontes au total sur le site. */
  --geo:'Archivo',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --tech:'Space Grotesk',ui-monospace,'SF Mono','Cascadia Mono',monospace;
  --sans:'Archivo',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --t-3xs:9px; --t-2xs:10px; --t-xs:11px; --t-sm:12.5px; --t-md:14.5px; --t-lg:16.5px;
  --t-xl:clamp(20px,2.2vw,25px); --t-2xl:clamp(26px,3.6vw,38px);
  --t-3xl:clamp(32px,5vw,52px); --t-4xl:clamp(34px,5.4vw,58px);

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:36px; --s7:56px; --s8:88px;
  /* ⭐ RAYONS SERRÉS — le geste .SWOOSH. Les CONTENEURS sont presque
     carrés (0 à 4 px), les COMMANDES restent des pilules. C'est exactement
     la répartition des planches : blocs à angle droit, bouton JOIN en pilule.
     ⛔ Tout arrondir donne un site « application » ; tout carrer donne un site
     « brutaliste illisible ». La règle est : ce qui CONTIENT est carré, ce
     qu'on CLIQUE est rond. */
  --r-doc:0; --r-sm:2px; --r-md:3px; --r-lg:4px; --r-full:999px;
  --tap:44px;--i-lune:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z'/%3E%3C/svg%3E");--i-soleil:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='4.2'/%3E%3Cpath d='M12 2.6v2.2M12 19.2v2.2M2.6 12h2.2M19.2 12h2.2M5.3 5.3l1.6 1.6M17.1 17.1l1.6 1.6M18.7 5.3l-1.6 1.6M6.9 17.1l-1.6 1.6'/%3E%3C/svg%3E");        /* cible confortable — navigation, boutons pleins */
  --tap-min:36px;    /* plancher tactile : WCAG 2.1 AA exige 24 px (2.5.8),
                        donc 32 px était CONFORME. ⭐ « Conforme » et
                        « confortable » ne sont pas le même seuil, et c'est le
                        second qui décide si on réussit du premier coup. */
  /* Trois intentions d'interlettrage, pas dix-sept. */
  --ls-titre:-.03em;   /* affiche : les capitales larges se resserrent */
  --ls-etiq:.11em;     /* étiquette technique en capitales */
  --ls-etiq-l:.16em;   /* étiquette isolée, qui doit se lire comme un tampon */
  /* ═══ LA FOCALE — la deuxième grammaire du site, après la couleur ═══
     ⭐ Une seule idée : CE QUI EST NET EST CE QUI COMPTE. Le flou n'est pas
     un effet, c'est un rang. Trois plans, jamais quatre, et un objet ne
     change jamais de plan en cours de route.
     ⛔ Ne pas s'en servir pour « faire joli sur un fond » : un flou qui ne
     dit pas de distance est du bruit qui coûte une couche de composition. */
  --foc-net:0px;        /* plan de mise au point — le sujet */
  --foc-proche:2.5px;   /* juste devant/derrière — contexte lisible */
  --foc-loin:7px;       /* hors focale — présence sans lecture */
  --foc-mur:9px;        /* le mur payant : on voit qu'il y a, pas quoi */
  --foc-fond:26px;      /* fond diffus d'une vignette — plus aucun détail */
  --foc-verre:18px;     /* verre de l'en-tête — la page passe DERRIÈRE */

  --survol:#FFFFFF1A; --voile-haut:#FFFFFF1F; --voile-bas:#00000073; /* voile de survol — s'inverse en thème jour */
  --sh-1:0 1px 2px #00000073; --sh-2:0 10px 26px -10px #000000CC,0 2px 8px #00000080;
  --sh-3:0 26px 64px -18px #000000E6,0 6px 18px #0000009E;
  --lueur:0 0 0 1px color-mix(in srgb,var(--sect-pur) 30%,transparent),
          0 10px 34px -12px color-mix(in srgb,var(--sect-pur) 38%,transparent);

  --d-fast:130ms; --d-base:240ms; --d-slow:440ms;
  --e-out:cubic-bezier(.22,1,.36,1); --e-soft:cubic-bezier(.4,0,.2,1);
  --e-rebond:cubic-bezier(.34,1.56,.64,1);

  /* ⛔⛔ REINJECTE LE 31/07/2026 — CES CINQ VARIABLES AVAIENT DISPARU EN PROD.
     En « portant le CSS de la maquette tel quel », j'ai ecarte ce que j'appelais
     son chassis. Le chassis, c'etait les fondations : `body`, `header.site`,
     `nav.main`, `footer.site` et les variables qu'elles consomment. Resultat en
     ligne : corps en serif (aucune regle ne lisait --font-body), en-tete sans
     style, et TOUTES les pages du moteur (blog, mentions, raretes, 404) en HTML
     brut — pas seulement l'accueil.
     ⭐ Une variable non definie ne casse rien : la declaration qui la lit est
     simplement ignoree. C'est le defaut par repli, en version invisible. */
  --vp-s2:color-mix(in srgb,var(--surface) 88%,var(--text));
  --vp-rule:color-mix(in srgb,var(--text) 14%,transparent);
  --vp-rule-2:color-mix(in srgb,var(--text) 26%,transparent);
  --vp-ink-2:color-mix(in srgb,var(--text) 78%,var(--bg));
  --vp-survol:color-mix(in srgb,var(--text) 8%,transparent);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SOCLE DU MOTEUR — LE CONTRAT DE CLASSES QUE TOUTES LES PAGES EMETTENT
   ═══════════════════════════════════════════════════════════════════════════
   ⛔⛔ SECTION PERDUE PUIS RETABLIE LE 31/07/2026.
   `body html header.site .brand nav.main footer.site .card .grid .item .up
   .down .searchbox .chart .legal .post .prose th td .gate` ne sont PAS
   specifiques a l'accueil : le moteur les emet sur chaque page de chaque site.
   Les avoir retirees a laisse le blog, les mentions legales, les raretes et la
   404 SANS AUCUN STYLE en production, sans qu'un seul build echoue.
   ⭐ Mon comparateur notait 92,9 % pendant ce temps : il verifiait que la
   classe etait dans le GABARIT, jamais qu'une REGLE existait pour elle. Il
   controlait le mauvais cote du contrat.
   ⛔ NE PAS SUPPRIMER CETTE SECTION en croyant qu'elle fait doublon avec la
   maquette : les selecteurs deja couverts par la maquette en ont ete retires,
   il ne reste ici que ce qu'elle ne porte pas.
   ═══════════════════════════════════════════════════════════════════════════ */

html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--text);
  font-family:var(--font-body);line-height:1.6;font-size:16px;
  /* Le grain : papier photographique tiré. Il casse les bandes des dégradés et
     donne au gris une épaisseur qu'un aplat numérique n'a jamais. On ne le voit
     pas ; on sent son absence. Data-URI, donc zéro requête. */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.028'/%3E%3C/svg%3E");}

/* ⛔ Un thème doit désarmer TOUT mouvement d'un coup, en tête de feuille.
   Une préférence d'accessibilité traitée règle par règle finit toujours par
   oublier la règle ajoutée demain. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}
header.site{position:sticky;top:0;z-index:10;
  background:color-mix(in srgb,var(--bg) 86%,transparent);
  backdrop-filter:blur(var(--foc-verre));-webkit-backdrop-filter:blur(var(--foc-verre));
  border-bottom:1px solid var(--vp-rule)}
header.site::after{content:"";position:absolute;left:0;right:0;bottom:-3px;height:3px;
  background:linear-gradient(90deg,var(--primary),transparent 62%)}
header.site .wrap{display:flex;align-items:center;gap:var(--s5);min-height:64px;flex-wrap:wrap}
.brand{font-family:var(--font-heading);font-weight:800;font-size:19px;
  text-transform:uppercase;letter-spacing:.01em;line-height:1;color:var(--text)}
.brand span{color:var(--primary)}
nav.main{display:flex;gap:2px;margin-left:auto;flex-wrap:wrap}
nav.main a{font-family:var(--font-heading);font-size:14px;font-weight:500;color:var(--muted);
  padding:0 13px;min-height:var(--tap);display:inline-flex;align-items:center;
  border-radius:var(--r-full);transition:color var(--d-fast),background var(--d-fast)}
nav.main a:hover, nav.main a:focus-visible{color:var(--text);background:var(--vp-survol);text-decoration:none}
nav.main a[aria-current]{color:var(--primary);background:color-mix(in srgb,var(--primary) 12%,transparent)}
/* 🔴🔴 `margin-top:var(--s8)` RETIRÉ LE 06/08/2026 — 88 px de vide en bas de
   CHAQUE page, signalés plusieurs fois par Preda.
   ⭐⭐⭐ LA CORRECTION ÉTAIT DÉJÀ ÉCRITE, ET ELLE NE S'APPLIQUAIT PAS.
   Le footer porte `class="site site-f"`. `.site-f` (l. 510) déclare
   `margin-top:0` — mais `.site-f` pèse (0,1,0) et `footer.site` pèse (0,1,1) :
   l'ancienne règle GAGNE, quel que soit l'ordre des lignes. Quelqu'un a donc
   écrit le correctif, l'a vu dans le fichier, et l'espace est resté.
   ⭐⭐ « EST-CE LÀ ? » ET « EST-CE CE QUI GAGNE ? » SONT DEUX QUESTIONS.
   ⚠️ ET CE N'EST PAS UN CAS ISOLÉ : `header.site` (l. 205) contre `.site-h`
   (l. 411), `nav.main` contre `.nav__liens`, `footer.site` contre `.site-f` —
   une STRATE ENTIÈRE de l'ancien thème habille encore les mêmes éléments que
   le vocabulaire de la maquette. On retire ici la seule déclaration qui faisait
   un dégât visible ; la strate, elle, se traite en entier, pas au coup par coup.
   ⛔ Ne pas « re-corriger » en remontant `.site-f` plus bas dans le fichier :
   l'ordre ne bat pas la spécificité, et on croirait avoir compris. */
footer.site{border-top:1px solid var(--vp-rule);padding:var(--s6) 0;
  color:var(--muted);font-size:14px}
.card{background:var(--surface);border:1px solid var(--vp-rule);
  border-radius:var(--r-lg);padding:var(--s5);box-shadow:var(--sh-1)}
.grid{display:grid;gap:var(--s3);grid-template-columns:repeat(auto-fill,minmax(196px,1fr))}
.item{display:block;background:var(--surface);border:1px solid var(--vp-rule);
  border-radius:var(--r-lg);padding:var(--s4);color:var(--text);overflow:hidden;
  transition:border-color var(--d-fast),transform var(--d-base) var(--e-out),
             box-shadow var(--d-base) var(--e-soft)}
.item:hover{border-color:var(--primary);text-decoration:none;
  transform:translateY(-2px);box-shadow:var(--sh-2)}
.item .n{font-family:var(--font-heading);font-weight:600;font-size:14.5px;
  line-height:1.3;margin-bottom:3px;letter-spacing:-.01em}
.item .s{font-size:12.5px;color:var(--muted)}
.item .f{margin-top:var(--s3);font-family:var(--font-heading);
  font-size:21px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.stat .k{font-family:var(--font-heading);font-size:10px;color:var(--muted);
  text-transform:uppercase;letter-spacing:var(--ls-etiq)}
.stat .v{font-family:var(--font-heading);font-size:clamp(24px,3vw,34px);font-weight:700;
  font-variant-numeric:tabular-nums;letter-spacing:-.03em;line-height:1;margin-top:6px}
th, td{text-align:left;padding:11px var(--s2);border-bottom:1px solid var(--vp-rule)}
td.num, th.num{text-align:right;font-variant-numeric:tabular-nums;
  font-family:var(--font-heading);font-weight:600}
.up{color:var(--accent)}
.down{color:var(--danger)}
.searchbox{width:100%;min-height:var(--tap);padding:0 var(--s4);
  border-radius:var(--r-md);border:1px solid var(--vp-rule-2);
  background:var(--surface);color:var(--text);font-size:16px;font-family:var(--font-body);
  transition:border-color var(--d-fast),box-shadow var(--d-fast)}
.searchbox:focus{outline:0;border-color:var(--primary);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 22%,transparent)}
.searchbox::placeholder{color:var(--muted)}
.chart{width:100%;height:auto;margin:var(--s2) 0 var(--s1)}
.chart .line{stroke:var(--primary);stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.chart .area{fill:color-mix(in srgb,var(--primary) 15%,transparent);stroke:none}
.chart .grid{stroke:var(--vp-rule);stroke-width:1}
.chart .axis{fill:var(--muted);font-size:10px;font-family:var(--font-heading);
  letter-spacing:var(--ls-etiq)}
.post, .legal{max-width:72ch}
.legal h2{font-size:19px;text-transform:none;letter-spacing:-.01em;margin:var(--s5) 0 var(--s2)}
.legal p{margin:0 0 var(--s3)}
.legal strong{font-weight:600}
.prose ul, .prose ol{margin:0 0 var(--s4) 20px}
.prose li{margin-bottom:6px}
.prose code{background:var(--vp-s2);padding:1px 6px;border-radius:var(--r-sm);
  font-family:var(--font-heading);font-size:15px}
.prose blockquote{margin:var(--s4) 0;padding:var(--s2) 0 var(--s2) var(--s4);
  border-left:2px solid var(--primary);color:var(--vp-ink-2)}
[data-gate], .gate{position:relative;isolation:isolate}
[data-gate] .gate__flou, .gate__flou{filter:blur(var(--foc-mur)) saturate(.42);
  opacity:.34;pointer-events:none;user-select:none}
.gate__voile{position:absolute;inset:0;display:grid;place-items:center;text-align:center;
  padding:var(--s5) var(--s4);z-index:3;
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--bg) 30%,transparent),
    color-mix(in srgb,var(--bg) 97%,transparent) 62%)}

/* ─── 13 · MOBILE ────────────────────────────────────────────────────────── */
@media (max-width:640px){
  .wrap{padding:0 var(--s4)}
  header.site .wrap{min-height:auto;padding-top:10px;padding-bottom:10px;gap:10px}
  nav.main{margin-left:0;width:100%}
  thead th{position:static}
  th.hide,td.hide{display:none}
  h1{font-size:clamp(26px,8vw,40px)}
  /* ⭐ Sur un téléphone, une pièce décorative ne décore plus : elle occupe la
     place du contenu. La ligne de partage n'est pas « image / pas image », elle
     est « ILLUSTRATION / SUJET » — une vignette de fiche EST le contenu.
     🔴 LOT 161 · 24/08/2026 — il y avait ICI `  .decor,.banniere,` : un
     sélecteur pendant, virgule finale, AUCUN bloc. Le navigateur jette la règle
     (mesuré : lightningcss, « Unexpected end of input », ligne 305) — sans une
     erreur, sans un log, sans un build rouge. ⭐ ET LA RÈGLE N'A PAS ÉTÉ
     RÉPARÉE ICI : elle existe déjà, complète, plus bas
     (`@media (max-width:640px){ .decor,.banniere{display:none!important} }`).
     La réécrire aurait posé un DOUBLON. Le geste juste était de la RETIRER. */
}

@media (max-width:820px){
  .plaque__champ{right:calc(50% - 50vw);left:calc(50% - 50vw);height:34%}
  .plaque__piece{display:none}
  .plaque__os{margin-top:74px;padding:var(--s5);max-width:none}
}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}

[data-theme="jour"]{
  --nuit:#EFEFEF; --surface:#FFFFFF; --surface-2:#E7E7E7; --surface-3:#D9D9D9;
  --rule:#E2E2E2; --rule-2:#C6C6C6; --rule-int:#767676;
  /* --text : fourni par le manifeste */ --text-2:#3D3D3D; --muted:#5E5E5E;
  --cyan:#08687A; --cyan-fonce:#054E5C; --cyan-1v:#10CEF23D;
  --up:#096E38; --down:#B01F32; --up-1v:#096E3814; --down-1v:#B01F3214;
  /* ⭐⭐ LE THÈME JOUR N'EST PLUS TERNE — et la correction n'est pas
     « éclaircir », c'est SÉPARER DEUX USAGES.
     Mesuré : sur un fond clair, les couleurs VeVe vives échouent en TEXTE
     (le cyan tombe à 1,38:1, le jaune à 1,26:1) — ça, c'est physique, on ne
     peut rien y faire. MAIS elles réussissent parfaitement en APLAT, avec
     l'encre sombre par-dessus (cyan 9,23:1, jaune 10,06:1).
     ⭐ Or ce qui donne l'impression de couleur à une page, ce ne sont PAS les
     mots colorés : ce sont les BOUTONS, les pastilles actives, les badges,
     les bandeaux. Je les avais tous assombris « par sécurité » — d'où le gris.
     Ici : `--*-pur` reprend les valeurs de la NUIT à l'octet près, `--*-a`
     reste assombri pour le texte, et les voiles passent de 1F à 33. */
  --gems:#0B859D; --omi:#B01F32;
  --carte:#EEEDE8; --carte-2:#E4E3DD; --carte-lien:#0A6F84; --carte-rule:#D5D4CD;
  --r-common-a:#0B8D3F; --r-common-b:#075E2A; --r-common-ink:#0B9542;
  --r-uncommon-a:#A62BD4; --r-uncommon-b:#6B1E85; --r-uncommon-ink:#C540F4;
  --r-rare-a:#0069C9; --r-rare-b:#00447F; --r-rare-ink:#007FF5;
  --r-ultra-a:#AF6A00; --r-ultra-b:#8A5300; --r-ultra-ink:#BB7000;
  --r-secret-a:#C02236; --r-secret-b:#7D1623; --r-secret-ink:#D7263D;
  --r-proof-a:#7A7A7A; --r-proof-b:#5E5E5E; --r-proof-ink:#818181;
  --lock:#08687A; --lock-pur:#10CEF2; --lock-1v:#10CEF233;
  /* ⚠️ EN MODE JOUR L'APLAT DEVIENT LE CYAN FONCÉ, PAS LE CYAN VIF.
     Un `#10CEF2` en aplat sur une page presque blanche est fluorescent : il
     passe le contraste (9,23:1) et il est laid. `--sect-pur` bascule donc en
     `#0A6F84` avec du texte blanc — 5,07:1, et ça respire. */
  --sect-a:#08687A; --sect-pur:#10CEF2; --sect-sur:#1A1A1A; --sect-fonce:#0A8FA9; --sect-1v:#10CEF233;
  --survol:#0000000F; --voile-haut:#FFFFFF80; --voile-bas:#0000002E; /* pendant jour : voile SOMBRE, sinon invisible */
  --sh-1:0 1px 2px #0000001A; --sh-2:0 10px 26px -10px #00000026,0 2px 8px #00000014;
  --sh-3:0 26px 64px -18px #00000033,0 6px 18px #0000001A;
}

/* ═══ LE PONT AVEC LE MANIFESTE ═══════════════════════════════════════════
   ⭐⭐ Le bloc ci-dessus vient de la maquette VERBATIM. Mais il ne doit pas
   FIGER la palette : `identity.palette` est la source de vérité du réseau, et
   un thème qui l'ignore casse la règle centrale du dépôt — « le manifeste
   décide, le code obéit ».
   On mappe donc les ALIAS de la maquette sur les variables que Base.astro
   injecte. ⚠️ Jamais `--surface: var(--surface)` : une auto-référence rend la
   propriété invalide, et la couleur disparaît sans un mot.
   ⚠️ ORDRE : ce bloc doit venir APRÈS l'import, sinon il serait écrasé. */
:root{
  --nuit:     var(--bg);
  --sect-a:   var(--primary);
  --sect-pur: var(--primary);
  --sect-sur: var(--bg);
  --up:       var(--accent);
  --down:     var(--danger);
  --gems:     var(--primary);
  --lock:     var(--primary);
}

[data-sect="collectibles"]{--sect-a:#6BB6FC;--sect-pur:#0082FA;--sect-sur:#1A1A1A;--sect-fonce:#004B91;--sect-1v:#0082FA24}
[data-sect="comics"] {--sect-a:#3EC875;--sect-pur:#0EBA52;--sect-sur:#1A1A1A;--sect-fonce:#086C30;--sect-1v:#0EBA5224}
[data-sect="cotes"] {--sect-a:#ED9BA6;--sect-pur:#D7263D;--sect-sur:#FFFFFF;--sect-fonce:#8E1926;--sect-1v:#D7263D26}
[data-sect="analyse"] {--sect-a:#10CEF2;--sect-pur:#10CEF2;--sect-sur:#1A1A1A;--sect-fonce:#0A8FA9;--sect-1v:#10CEF21F}
[data-sect="collectibles"]{--sect-a:#005FB5;--sect-pur:#0082FA;--sect-sur:#1A1A1A;--sect-fonce:#0060B7;--sect-1v:#0082FA33}
[data-sect="comics"] {--sect-a:#096E38;--sect-pur:#0EBA52;--sect-sur:#1A1A1A;--sect-fonce:#097039;--sect-1v:#0EBA5233}
[data-sect="cotes"] {--sect-a:#B72034;--sect-pur:#D7263D;--sect-sur:#FFFFFF;--sect-fonce:#8E1926;--sect-1v:#D7263D2E}
[data-sect="analyse"] {--sect-a:#08687A;--sect-pur:#10CEF2;--sect-sur:#1A1A1A;--sect-fonce:#0A8FA9;--sect-1v:#10CEF233}
:root{--nuit: #1A1A1A; --surface: #2C2C2C; --surface-2: #383838; --surface-3: #444444; --rule: #3A3A3A; --rule-2: #4E4E4E; --rule-int: #8F8F8F; --text: #FFFFFF; --text-2: #CACACA; --muted: #B1B1B1; --carte: #EEEDE8; --carte-2: #E4E3DD; --carte-ink: #1A1A1A; --carte-ink-2:#5E5E5E; --carte-lien:#0A6F84; --carte-rule:#D5D4CD; --cyan: #10CEF2; --cyan-fonce:#0A8FA9; --cyan-1v: #10CEF21F; --up: #3EC875; --down: #ED9BA6; --up-1v: #3EC8751F; --down-1v: #ED9BA61F; --gems: #10CEF2; --omi: #E36777; --r-common-a: #0EBA52; --r-common-b: #086C30; --r-common-ink: #0B9542; --r-uncommon-a:#D157FC; --r-uncommon-b:#762692; --r-uncommon-ink:#C540F4; --r-rare-a: #1F91FB; --r-rare-b: #004B91; --r-rare-ink: #007FF5; --r-ultra-a: #ED8E00; --r-ultra-b: #895200; --r-ultra-ink: #BB7000; --r-secret-a: #E36777; --r-secret-b: #7D1623; --r-secret-ink: #D7263D; --r-proof-a: #CACACA; --r-proof-b: #757575; --r-proof-ink: #818181; --lock: #10CEF2; --lock-pur: #10CEF2; --lock-1v: #10CEF224; --sect-a: #10CEF2; --sect-pur: #10CEF2; --sect-sur: #1A1A1A; --sect-fonce:#0A8FA9; --sect-1v: #10CEF21F; --geo:'Archivo',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif; --tech:'Space Grotesk',ui-monospace,'SF Mono','Cascadia Mono',monospace; --sans:'Archivo',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif; --t-3xs:9px; --t-2xs:10px; --t-xs:11px; --t-sm:12.5px; --t-md:14.5px; --t-lg:16.5px; --t-xl:clamp(20px,2.2vw,25px); --t-2xl:clamp(26px,3.6vw,38px); --t-3xl:clamp(32px,5vw,52px); --t-4xl:clamp(34px,5.4vw,58px); --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:36px; --s7:56px; --s8:88px; --r-doc:0; --r-sm:2px; --r-md:3px; --r-lg:4px; --r-full:999px; --tap:44px; --tap-min:36px; --ls-titre:-.03em; --ls-etiq:.11em; --ls-etiq-l:.16em; --foc-net:0px; --foc-proche:2.5px; --foc-loin:7px; --foc-mur:9px; --foc-fond:26px; --foc-verre:18px; --survol:#FFFFFF1A; --voile-haut:#FFFFFF1F; --voile-bas:#00000073; --sh-1:0 1px 2px #00000073; --sh-2:0 10px 26px -10px #000000CC,0 2px 8px #00000080; --sh-3:0 26px 64px -18px #000000E6,0 6px 18px #0000009E; --lueur:0 0 0 1px color-mix(in srgb,var(--sect-pur) 30%,transparent), 0 10px 34px -12px color-mix(in srgb,var(--sect-pur) 38%,transparent); --d-fast:130ms; --d-base:240ms; --d-slow:440ms; --e-out:cubic-bezier(.22,1,.36,1); --e-soft:cubic-bezier(.4,0,.2,1); --e-rebond:cubic-bezier(.34,1.56,.64,1);}
[data-theme="jour"]{--nuit:#EFEFEF; --surface:#FFFFFF; --surface-2:#E7E7E7; --surface-3:#D9D9D9; --rule:#E2E2E2; --rule-2:#C6C6C6; --rule-int:#767676; --text:#1A1A1A; --text-2:#3D3D3D; --muted:#5E5E5E; --cyan:#08687A; --cyan-fonce:#054E5C; --cyan-1v:#10CEF23D; --up:#096E38; --down:#B01F32; --up-1v:#096E3814; --down-1v:#B01F3214; --gems:#0B859D; --omi:#B01F32; --carte:#EEEDE8; --carte-2:#E4E3DD; --carte-lien:#0A6F84; --carte-rule:#D5D4CD; --r-common-a:#0B8D3F; --r-common-b:#075E2A; --r-common-ink:#0B9542; --r-uncommon-a:#A62BD4; --r-uncommon-b:#6B1E85; --r-uncommon-ink:#C540F4; --r-rare-a:#0069C9; --r-rare-b:#00447F; --r-rare-ink:#007FF5; --r-ultra-a:#AF6A00; --r-ultra-b:#8A5300; --r-ultra-ink:#BB7000; --r-secret-a:#C02236; --r-secret-b:#7D1623; --r-secret-ink:#D7263D; --r-proof-a:#7A7A7A; --r-proof-b:#5E5E5E; --r-proof-ink:#818181; --lock:#08687A; --lock-pur:#10CEF2; --lock-1v:#10CEF233; --sect-a:#08687A; --sect-pur:#10CEF2; --sect-sur:#1A1A1A; --sect-fonce:#0A8FA9; --sect-1v:#10CEF233; --survol:#0000000F; --voile-haut:#FFFFFF80; --voile-bas:#0000002E; --sh-1:0 1px 2px #0000001A; --sh-2:0 10px 26px -10px #00000026,0 2px 8px #00000014; --sh-3:0 26px 64px -18px #00000033,0 6px 18px #0000001A;}
[data-sect="collectibles"]{--sect-a:#6BB6FC;--sect-pur:#0082FA;--sect-sur:#1A1A1A;--sect-fonce:#004B91;--sect-1v:#0082FA24}
[data-sect="comics"]{--sect-a:#3EC875;--sect-pur:#0EBA52;--sect-sur:#1A1A1A;--sect-fonce:#086C30;--sect-1v:#0EBA5224}
[data-sect="cotes"]{--sect-a:#ED9BA6;--sect-pur:#D7263D;--sect-sur:#FFFFFF;--sect-fonce:#8E1926;--sect-1v:#D7263D26}
[data-sect="analyse"]{--sect-a:#10CEF2;--sect-pur:#10CEF2;--sect-sur:#1A1A1A;--sect-fonce:#0A8FA9;--sect-1v:#10CEF21F}
[data-theme="jour"] [data-sect="collectibles"]{--sect-a:#005FB5;--sect-pur:#0082FA;--sect-sur:#1A1A1A;--sect-fonce:#0060B7;--sect-1v:#0082FA33}
[data-theme="jour"] [data-sect="comics"]{--sect-a:#096E38;--sect-pur:#0EBA52;--sect-sur:#1A1A1A;--sect-fonce:#097039;--sect-1v:#0EBA5233}
[data-theme="jour"] [data-sect="cotes"]{--sect-a:#B72034;--sect-pur:#D7263D;--sect-sur:#FFFFFF;--sect-fonce:#8E1926;--sect-1v:#D7263D2E}
[data-theme="jour"] [data-sect="analyse"]{--sect-a:#08687A;--sect-pur:#10CEF2;--sect-sur:#1A1A1A;--sect-fonce:#0A8FA9;--sect-1v:#10CEF233}
[data-sect]{--cyan:var(--sect-a);--cyan-fonce:var(--sect-fonce);--cyan-1v:var(--sect-1v)}
[data-leger] .socle__fond,[data-leger] .socle__voile,[data-leger] .grain, [data-leger] .decor,[data-leger] 
[data-leger] .socle__net{filter:none!important;transform:none!important}
[data-leger] .site-h,[data-leger] .deplie__m,[data-leger] .tuile__rar, [data-leger] .tuile__off,[data-leger] .socle__fav{backdrop-filter:none!important}
[data-leger] .carte,[data-leger] .panneau,[data-leger] .stat,[data-leger] .tbl-hote, [data-leger] .graph-hote,[data-leger] .col-carte{box-shadow:none!important}
[data-leger] *{animation:none!important;transition:none!important;will-change:auto!important}
.decor, 
.banniere{display:none!important}
[data-leger] .banniere__l img{filter:none!important}
*,*::before,*::after{box-sizing:border-box}
.grain{position:fixed;inset:0;pointer-events:none;z-index:9999;opacity:.03;mix-blend-mode:overlay; background-image:var(--grain);background-size:160px 160px}
.carte,.panneau,.stat,.tbl-hote,.graph-hote,.tarif,.barre-f,.col-carte,.mur,.sceau{box-shadow:inset 0 1px 0 #FFFFFF0F, var(--sh-1)}
[data-theme="jour"] .carte,[data-theme="jour"] .panneau,[data-theme="jour"] .stat, [data-theme="jour"] .tbl-hote,[data-theme="jour"] .graph-hote,[data-theme="jour"] .tarif, [data-theme="jour"] .barre-f,[data-theme="jour"] .col-carte,[data-theme="jour"] .mur, [data-theme="jour"] .sceau{box-shadow:inset 0 1px 0 #FFFFFF, var(--sh-1)}
main::after{content:"";position:absolute;inset:-10% -20% auto;height:520px;pointer-events:none;z-index:0; background:radial-gradient(58% 100% at 50% 0%, color-mix(in srgb,var(--sect-pur) 13%,transparent), transparent 68%); filter:blur(30px)}
[data-theme="jour"] main::after{display:none}
main[data-sect="collectibles"]::after,main[data-sect="comics"]::after{background:repeating-linear-gradient(90deg,var(--rule) 0 1px,transparent 1px 118px), repeating-linear-gradient(0deg,var(--rule) 0 1px,transparent 1px 118px); filter:none;opacity:.6;height:420px;inset:0 0 auto; mask-image:linear-gradient(180deg,#000 0%,transparent 88%)}
[data-theme="jour"] main::before{background: repeating-linear-gradient(90deg,var(--rule) 0 1px,transparent 1px 120px), repeating-linear-gradient(0deg,var(--rule) 0 1px,transparent 1px 120px); mask-image:linear-gradient(180deg,#000 0%,transparent 92%);height:340px}
img{max-width:100%;display:block}
button{font:inherit;color:inherit}
a{color:var(--sect-a);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:3px}
:focus-visible{outline:2px solid var(--sect-a);outline-offset:2px;border-radius:var(--r-sm)}
/* ⛔⛔ `max-width:1220px` RETIRE D'ICI LE 01/08/2026 — ET C'EST LA VRAIE
   CORRECTION, pas celle du 31/07. Le lot 26 avait neutralise ce plafond plus
   bas par un second `.wrap{max-width:none}` : deux declarations pour la meme
   mesure, la seconde annulant la premiere. Ca marchait pour l'en-tete (dont le
   `.wrap` est un ENFANT) et ca cassait le contenu — parce que `<main>` PORTE
   lui-meme la classe :
       body > main   -> (0,0,2)  max-width:var(--cadre-max)  1520px
       .wrap         -> (0,1,0)  max-width:none              <- GAGNE
   `main` n'avait donc plus AUCUN plafond pendant que l'en-tete gardait 1520 :
   la page etait plus LARGE que son en-tete, l'inverse exact du defaut qu'on
   croyait avoir repare.
   ⭐⭐ MEME LECON QU'IL Y A DEUX JOURS, DANS L'AUTRE SENS : ajouter une
   contrainte sans retirer celle qu'elle remplace laisse les deux en vigueur.
   Le 31/07 la plus SERREE gagnait ; ici c'est la plus SPECIFIQUE. On ne
   negocie plus entre deux regles : il n'en reste qu'une, le cadre. */
.wrap{margin:0 auto;padding:0 24px}
.site-h{position:sticky;top:0;z-index:60;background:color-mix(in srgb,var(--nuit) 90%,transparent); backdrop-filter:blur(var(--foc-verre));-webkit-backdrop-filter:blur(var(--foc-verre)); border-bottom:1px solid var(--rule)}
.site-h::after{content:"";position:absolute;inset:auto 0 -3px;height:3px; background:linear-gradient(90deg,var(--sect-pur),color-mix(in srgb,var(--sect-pur) 30%,transparent) 68%,transparent); z-index:2}
.site-h__in{display:flex;align-items:center;gap:var(--s4);height:64px}
.marque{display:flex;align-items:center;gap:11px;color:var(--text)}
.marque:hover{text-decoration:none}
.logo{width:32px;height:32px;flex:0 0 32px;display:grid;place-items:center;border-radius:9px; background:linear-gradient(135deg,var(--sect-a),var(--sect-fonce));font-family:var(--geo); font-size:13px;font-weight:700;letter-spacing:-.04em;color:var(--sect-sur)}
.logo--sm{width:24px;height:24px;flex:0 0 24px;font-size:10px;border-radius:7px}
.logo--xl{width:56px;height:56px;flex:0 0 56px;font-size:22px;border-radius:15px}
.marque__t{font-family:var(--geo);font-size:19px;font-weight:800;line-height:1; text-transform:uppercase;letter-spacing:.01em;font-stretch:106%}
.marque__t em{font-style:normal;color:var(--sect-a)}
.marque__t small{display:block;font-family:var(--tech);font-size:8.5px;letter-spacing:.16em; text-transform:uppercase;color:var(--muted);margin-top:4px;font-weight:500}
.nav{display:flex;align-items:center;gap:2px;margin-left:auto}
.nav a{font-family:var(--geo);font-size:14px;font-weight:500;color:var(--text-2);padding:8px 13px; min-height:var(--tap);display:inline-flex;align-items:center;gap:7px;border-radius:var(--r-full); transition:color var(--d-fast),background var(--d-fast)}
.nav a:hover{color:var(--text);background:var(--sect-1v);text-decoration:none}
.nav a[aria-current]{color:var(--sect-a);background:var(--sect-1v)}
.nav a svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.7;opacity:.85}
.h-outils{display:flex;align-items:center;gap:6px;margin-left:8px}
.icone-b{width:var(--tap);height:var(--tap);display:grid;place-items:center;background:transparent; border:1px solid transparent;border-radius:var(--r-md);color:var(--muted);cursor:pointer;position:relative;transition:all var(--d-fast)}
.icone-b:hover{color:var(--sect-a);background:var(--sect-1v)}
.icone-b svg{width:19px;height:19px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.icone-b__n{position:absolute;top:6px;right:5px;min-width:16px;height:16px;padding:0 4px;border-radius:var(--r-full); background:var(--sect-pur);color:var(--sect-sur);font-family:var(--tech);font-size:9.5px;font-weight:700; display:grid;place-items:center;line-height:1}
.h-rech{display:flex;align-items:center;gap:9px;min-width:240px;background:var(--surface-2); border:1px solid var(--rule-2);padding:0 7px 0 13px;height:38px;color:var(--muted);cursor:pointer; border-radius:var(--r-full);transition:all var(--d-base) var(--e-soft)}
.h-rech:hover{border-color:var(--sect-a);color:var(--text-2);box-shadow:var(--lueur)}
.h-rech svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.9;flex:0 0 16px}
.h-rech span{font-size:var(--t-sm);flex:1 1 auto;min-width:0;text-align:left; overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.h-rech .kbd{flex:0 0 auto}
.h-rech svg{flex:0 0 16px}

/* ═══════════════════════════════════════════════════════════════════════════
   LES DEUX COMMANDES QUI ARRIVENT DANS L'EN-TETE (Preda, 06/08/2026)
   ═══════════════════════════════════════════════════════════════════════════
   ⛔ CES QUATRE CLASSES SONT EMISES PAR `Base.astro`, DONC PAR LES 15 SITES —
   mais SEULEMENT quand le manifeste declare `langues_dans: compte`. Aujourd'hui
   veveprice, et lui seul. `encyclopedie` n'a donc rien a habiller, et c'est
   voulu : une regle ecrite pour un site qui ne l'emet pas est une regle morte,
   et une classe emise sans regle coute plus cher qu'une classe absente — elle a
   l'air d'etre la. Le jour ou vevewiki bascule, ces regles se recopient LA-BAS,
   elles ne se generalisent pas ici. */

/* 🌐 LE GLOBE — l'acces discret aux langues, depliable SANS JavaScript.
   ⭐ `<details>` et non un bouton : les liens hreflang restent dans le DOM
   meme replies, donc Google continue de decouvrir /fr/, /es/, /de/. C'est la
   seule forme qui satisfait a la fois « discret » et « indexable ». */
.globe{position:relative;flex:0 0 auto}
.globe>summary{display:inline-flex;align-items:center;gap:6px;height:38px;padding:0 10px;
  background:var(--surface-2);border:1px solid var(--rule-2);border-radius:var(--r-full);
  color:var(--muted);font-size:var(--t-sm);cursor:pointer;list-style:none;
  transition:all var(--d-base) var(--e-soft)}
/* ⚠️ LES DEUX FAMILLES DE MARQUEURS. Le triangle de `<details>` s'efface par
   `list-style:none` chez les uns et par `::-webkit-details-marker` chez les
   autres. N'en ecrire qu'une laisse un chevron sur la moitie des navigateurs —
   invisible depuis la machine de celui qui code. */
.globe>summary::-webkit-details-marker{display:none}
.globe>summary::marker{content:''}
.globe>summary:hover{border-color:var(--sect-a);color:var(--text-2);box-shadow:var(--lueur)}
.globe>summary:focus-visible{outline:var(--foc-proche) solid var(--sect-pur);outline-offset:2px}
.globe>summary svg{width:16px;height:16px;flex:0 0 16px}
.globe[open]>summary{border-color:var(--sect-a);color:var(--text)}
/* 🔴 LOT 111 — LE MENU DE LANGUE ETAIT LE SEUL PANNEAU SUR FOND CLAIR.
   Il portait `background:var(--carte)` — #EEEDE8, la couleur du PAPIER des
   fiches — quand les deux autres panneaux de l'en-tete (`.deplie__m`,
   l'avatar) sont sur `--surface-2`. En theme nuit il s'ouvrait donc en blanc
   cassé au milieu d'un en-tete sombre, avec un texte `--text-2` clair PAR
   DESSUS : illisible autant que deplace.
   ⭐ `--carte` n'est pas une surface d'interface, c'est la matiere d'un
   contenu. Un menu n'est pas un contenu. */
.globe__m{position:absolute;top:calc(100% + 6px);right:0;z-index:60;display:flex;flex-direction:column;
  min-width:150px;padding:6px;background:var(--surface-2);border:1px solid var(--rule-2);
  border-radius:var(--r-lg);box-shadow:var(--sh-3)}
/* 🌍 LOT 139 — LE MENU N'HABILLAIT QUE DES `<a>`, ET LE SÉLECTEUR DE LANGUE
   D'INTERFACE EST FAIT DE `<button>`. ⛔ Ce n'est pas un caprice de balise : la
   page est un fichier pré-généré derrière un cache partagé, un `<a href="?lang=fr">`
   n'y est lu par personne et empoisonnerait le cache s'il l'était (cf.
   `src/socle/55-langue.js`). ⭐ Les deux sélecteurs se ressemblent donc à
   l'écran parce qu'ils portent la même règle — pas parce que quelqu'un a
   recopié douze déclarations. `.globe__m button` REMET À ZÉRO ce qu'un agent
   utilisateur met sur un bouton (fond, bordure, police, alignement) : sans
   `font:inherit` et `text-align:left`, les quatre langues s'afficheraient
   centrées en police système au milieu d'un menu qui ne l'est pas. */
.globe__m a,.globe__m button{padding:8px 12px;border-radius:var(--r-sm);color:var(--text-2);font-size:var(--t-sm);white-space:nowrap}
.globe__m button{display:block;width:100%;text-align:left;background:none;border:0;cursor:pointer;font-family:inherit;line-height:inherit}
.globe__m a:hover,.globe__m button:hover{background:var(--survol);color:var(--sect-a);text-decoration:none}
.globe__m a[aria-current="true"],.globe__m button[aria-current="true"]{color:var(--sect-a);font-weight:600}
.globe__m button:focus-visible{outline:var(--foc-proche) solid var(--sect-pur);outline-offset:-2px}

/* ⭐⭐ L'APPEL A L'INSCRIPTION. Un seul bouton plein, la connexion en retrait :
   deux appels a l'action de meme poids n'en font aucun. */
.h-cta{display:inline-flex;align-items:center;gap:10px;flex:0 0 auto;margin-left:2px}
/* 🔴🔴 LOT 111 — LE TEXTE DU BOUTON « S'INSCRIRE » DEVENAIT ILLISIBLE
   SELON LA PAGE, ET C'EST MESURABLE.
   `.btn--principal` peint `--sect-sur` sur un degrade `--sect-pur` →
   `--sect-fonce`. Ces trois variables sont REDEFINIES par section :
       general     encre #1A1A1A sur #0A8FA9  →  4,6:1   (limite)
       comics      encre #1A1A1A sur #086C30  →  2,7:1   ⛔ ECHEC
       collectibles encre #1A1A1A sur #004B91 →  2,3:1   ⛔ ECHEC
   Autrement dit : le bouton etait lisible sur l'accueil et ne l'etait plus sur
   une fiche de comic. Personne ne compare deux pages cote a cote, donc le
   defaut ne ressemblait pas a un defaut — juste a « pas tres visible ».
   ⭐⭐⭐ L'EN-TETE N'EST PAS DU CONTENU : il est identique sur les 8 484
   pages, il n'a aucune raison de changer de palette avec la section. En le
   detachant de `--sect-*` on corrige le contraste ET on retire une source de
   variation que personne n'avait demandee.
   ⭐ `--cyan` / `--nuit` s'INVERSENT ensemble avec le theme : en nuit,
   encre sombre sur cyan vif (5,0:1) ; en jour, encre claire sur cyan profond
   (7,5:1). Une seule regle tient les deux, sans valeur en dur. */
.h-cta .btn--principal{ background:linear-gradient(100deg,var(--cyan),var(--cyan-fonce));
  color:var(--nuit); }
.h-cta .btn--principal:hover{ box-shadow:var(--lueur); }
.h-cta__b{color:var(--text-2);font-size:var(--t-sm);white-space:nowrap}
.h-cta__b:hover{color:var(--sect-a)}

.kbd{font-family:var(--tech);font-size:10px;padding:3px 6px;border-radius:5px;background:var(--nuit); border:1px solid var(--rule-2);color:var(--muted)}
.deplie{position:relative}
.deplie__b{display:flex;align-items:center;gap:7px;height:38px;padding:0 12px;background:transparent; border:1px solid var(--rule-2);border-radius:var(--r-full);color:var(--text-2);cursor:pointer; font-family:var(--geo);font-size:13px;font-weight:500;transition:all var(--d-fast);min-height:38px}
.deplie__b:hover,.deplie__b[aria-expanded="true"]{border-color:var(--sect-a);color:var(--sect-a);background:var(--sect-1v)}
.deplie__b svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2.4;transition:transform var(--d-base) var(--e-out)}
.deplie__b[aria-expanded="true"] svg:last-child{transform:rotate(180deg)}
.deplie__m{position:absolute;top:calc(100% + 8px);right:0;min-width:210px;z-index:80;background:var(--surface-2); border:1px solid var(--rule-2);box-shadow:var(--sh-3);padding:6px;display:grid;gap:1px;border-radius:var(--r-lg)}
.deplie__m a,.deplie__m button{display:flex;align-items:center;gap:11px;padding:9px 11px;min-height:42px; color:var(--text-2);font-size:var(--t-sm);background:none;border:0;width:100%;text-align:left;cursor:pointer; border-radius:var(--r-md);transition:all var(--d-fast)}
.deplie__m a:hover,.deplie__m button:hover{background:var(--sect-1v);color:var(--sect-a);text-decoration:none}
.deplie__m a[aria-current]{color:var(--sect-a)}
.deplie__m a[aria-current]::after{content:"";margin-left:auto;width:6px;height:6px;border-radius:50%;background:var(--sect-a)}
.deplie__m hr{border:0;height:1px;background:var(--rule);margin:5px 0}
.deplie__code{font-family:var(--tech);font-size:10px;color:var(--muted);background:var(--nuit); border-radius:var(--r-sm);padding:3px 6px;min-width:32px;text-align:center}
.deplie__m svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.7;flex:0 0 16px}
.deplie__m{transition:opacity var(--d-base) var(--e-out),transform var(--d-base) var(--e-out)}
.deplie__m{opacity:0;transform:translateY(-8px) scale(.98)}
/* 🔴🔴🔴 LOT 111 — LA LIGNE QUI MANQUAIT, ET QUI RENDAIT LE MENU INVISIBLE.
   La declaration du dessus est un ETAT DE DEPART d'animation. Son etat
   d'ARRIVEE n'a jamais ete ecrit : rien, nulle part dans cette feuille, ne
   remettait `opacity:1` sur `.deplie__m`. Le JavaScript retirait bien
   `hidden`, le menu passait bien en `display:grid`, il occupait sa place et
   repondait au clavier — et il etait TRANSPARENT.
   ⭐⭐⭐ C'EST POURQUOI LE BOUTON « NE FAISAIT RIEN » : il faisait tout, sauf
   se montrer. Aucun banc ne pouvait le voir — le HTML est juste, le script est
   juste, la structure est juste. Un element transparent passe tous les
   controles de structure.
   ⭐⭐ ON SE LIE A `[hidden]`, PAS A `aria-expanded`. C'est le MEME attribut
   qui gouverne `display` : une seule source pour l'affichage et pour
   l'opacite. Se lier a `aria-expanded` aurait fabrique un second juge, et
   deux juges pour un affichage finissent par ne pas repondre pareil (la
   lecon du lot 103, sur ce meme en-tete).
   ⛔ NE PAS SUPPRIMER LES DEUX LIGNES DU DESSUS « puisqu'elles ne servaient a
   rien » : elles servent, maintenant. C'est l'ouverture en fondu. */
.deplie__m:not([hidden]){opacity:1;transform:none}
/* ⛔ `margin-top` RETIRE LE 03/08/2026 (lot 45, Preda) : « le contenu doit
   toucher le pied de page ». Il valait `var(--s8)` = 88 px de vide entre la
   derniere ligne et le filet du pied — sur une page courte (/legal/, une fiche
   sans articles lies) ce blanc etait la moitie de ce qu'on voyait en bas.
   ⭐ LE PIED GARDE SON `padding` INTERNE : le texte ne colle pas au filet, il
   respire A L'INTERIEUR du pied. Ce qu'on retire est l'ecart ENTRE les deux
   blocs, pas l'air autour du texte — deux choses que « l'ecart en bas de
   page » designe indistinctement et qui ne se corrigent pas au meme endroit.
   ⚠️ `main` n'a deja aucun `padding-bottom` (l. 460 : `var(--s7) 0 0`) : cette
   marge etait le SEUL ecart, il n'y en a pas un second a chercher.
   ⚠️ vitrine SEULEMENT — `.site-f` n'existe dans aucun autre theme, vevewiki
   (encyclopedie) n'est pas touche. */
.site-f{margin-top:0;padding:var(--s7) 0;color:var(--muted);font-size:var(--t-sm); border-top:1px solid var(--rule);background:var(--surface)}
.site-f__cols{display:grid;gap:var(--s6);grid-template-columns:1.5fr 1fr 1fr 1fr;margin-bottom:var(--s6)}
.site-f h2{margin:0 0 12px;font-family:var(--tech);font-size:var(--t-xs);color:var(--text-2); text-transform:uppercase;letter-spacing:.11em;font-weight:600}
.site-f ul{list-style:none;margin:0;padding:0;display:grid;gap:8px}
.site-f a{color:var(--text-2)}
.f-legal{border-top:1px solid var(--rule);padding-top:var(--s4);font-size:var(--t-xs);line-height:1.8}
/* 🔴 `padding-bottom` AJOUTÉ LE 06/08/2026 — ET C'EST LA VRAIE DEMANDE.
   Le lot 87 a retiré les 88 px de marge du footer : l'espace a disparu, mais
   ce n'était pas ça qu'il fallait. Preda voulait l'espace, avec LE FOND DE LA
   PAGE dedans — pas la bande noire du `body`.
   ⭐⭐⭐ UNE MARGE MONTRE CE QU'IL Y A DERRIÈRE, UN PADDING MONTRE L'ÉLÉMENT.
   La marge du footer laissait voir `body{background:#0E0E0E}`, c'est-à-dire le
   noir hors cadre. Le même espace posé en padding sur `main` est PEINT par le
   fond du cadre (`body > main{background:var(--bg)}`), et le fond de la page
   touche donc le footer sans discontinuité.
   ⛔ Ne pas le rendre au footer sous forme de marge « puisque c'était là
   avant » : on remettrait la bande noire, et le symptôme avec. */
main{padding:var(--s7) 0 var(--s8);display:block;position:relative}
/* 🔴🔴 LOT 161 — MESURÉ LE 24/08/2026 : LA RÈGLE CI-DESSUS N'A JAMAIS PEINT.
   `Base.astro` émet `<main class="wrap">`. Une CLASSE (0,1,0) bat un ÉLÉMENT
   (0,0,1) quel que soit l'ordre, et `.wrap{padding:0 24px}` est un RACCOURCI :
   il remet padding-top ET padding-bottom à ZÉRO. Mesuré sur la feuille servie
   en production, à 1280 px comme à 390 px : `padding-bottom` valait **0**.
   ⭐ Le commentaire du 06/08 juste au-dessus décrit une INTENTION, pas un
   résultat : la correction a changé `main` sans voir que le gabarit posait
   `class="wrap"` sur ce même `<main>`.
   ⭐⭐⭐ « EST-CE ÉCRIT ? » ET « EST-CE CE QUI GAGNE ? » SONT DEUX QUESTIONS.
   Le remède monte la spécificité à (0,1,1) et RESTE UN PADDING SUR `main` —
   l'interdit du 06/08 tient : ⛔ jamais en `margin-top` sur `.site-f`, qui
   laisserait revoir la bande noire du `body`. `.wrap` garde gauche/droite.
   🔬 Contrôlé par `outils/cascade-resolue.mjs`, banc `test_feuille.mjs`. */
main.wrap{padding-top:var(--s7);padding-bottom:var(--s8)}
/* ② MÊME SIGNATURE, SENS INVERSE : `.site-f{padding:var(--s7) 0}` (0,1,0) est
   battu par `footer.site{padding:var(--s6) 0}` (0,1,1) de la feuille du
   manifeste — le pied rendait 36 px au lieu des 56 écrits. */
footer.site.site-f{padding:var(--s7) 0}
main::before{content:"";position:absolute;inset:0 0 auto;height:240px;pointer-events:none;z-index:0; background:linear-gradient(180deg,var(--sect-1v),transparent)}
main>*{position:relative;z-index:1}
h1,h2,h3{font-family:var(--geo);font-weight:600;margin:0;letter-spacing:-.028em}
h1{font-size:var(--t-2xl);line-height:1.13}
.h-page{font-size:var(--t-3xl);line-height:1.08;font-weight:700;letter-spacing:-.035em}
h2{font-size:var(--t-xl);line-height:1.2}
h3{font-size:var(--t-lg)}
.lead{color:var(--text-2);font-size:var(--t-lg);line-height:1.68;margin:var(--s4) 0 0;max-width:60ch}
.muted{color:var(--muted)}
.num{font-family:var(--tech);font-variant-numeric:tabular-nums;font-weight:600}
.etiq{font-family:var(--tech);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em; color:var(--muted);font-weight:500;line-height:1.4}
.etiq--bleu{color:var(--sect-a)}
.sect-t{display:flex;align-items:center;gap:var(--s4);margin:var(--s7) 0 var(--s5)}
/* ═══════════════════════════════════════════════════════════════════════════
   🔴🔴 LOT 139 — UN TITRE DE SECTION N'EST PAS UN TITRE DE PAGE
   ═══════════════════════════════════════════════════════════════════════════
   Preda, 11/08 : « les titres de sections de /collections/ sont trop gros ».
   Mesuré : ils font **96 px**. Il avait le chiffre exact, et il vient d'ici.

   `.mono-t` (0,1,0) vaut `clamp(38px,7.2vw,96px)` — c'est le format du TITRE
   DE PAGE, et les `<h2>` de section portent la MÊME classe que les `<h1>`
   (35 émetteurs). Le format de section existe pourtant : `.sect-t--gd h2`,
   `clamp(28px,4.4vw,54px)`. Il gagne parce qu'il pèse (0,1,1).
   ⇒ Un `<div class="sect-t">` SANS `--gd` ne gagne rien, et son `<h2>` retombe
   sur les 96 px du titre de page.

   ⭐⭐⭐ RETIRER UN MODIFICATEUR NE REND PAS L'ÉLÉMENT « NEUTRE », IL LE REND À
   LA RÈGLE DE BASE — et la règle de base était le format du TITRE DE PAGE.
   Le lot qui a retiré `--gd` d'`Orientation.astro` a cru revenir au format
   ordinaire ; il a promu trois `<h2>` au rang de `<h1>`. *Un défaut par
   OMISSION de classe ne se lit dans aucun diff : il n'y a rien à lire.*

   🔬 MESURÉ sur `dist/` (147 pages) AVANT : **3 `h2.mono-t` dans un `.sect-t`
   seul** (les 3 rayons de `/collections/`, à 96 px) contre **10** correctement
   à 54 px dans un `.sect-t--gd`. APRÈS : 0 à 96 px.
   ⚠️ L'échantillon ne contient ni `Dashboard.astro` (page membre) ni
   `AVenir.astro` (rendu conditionnel) — ils émettent le MÊME `.sect-t` nu dans
   la source. C'est pourquoi le remède est ici, dans la feuille, et non un
   `--gd` ajouté à `Orientation.astro` : une correction chez UN appelant laisse
   les autres, et c'est exactement la faute que le lot 139 vient de payer avec
   `CarteSet.astro`.
   ⛔ `--gd` garde ses propres règles (marges, `max-width:16ch`, alignement) :
   il reste un variant d'ESPACEMENT, il cesse d'être le seul porteur de la
   taille. Les deux tailles sont désormais identiques — une seule peau. */
.sect-t h2{flex:0 0 auto;
  font-family:var(--geo);font-weight:800;font-stretch:108%;
  text-transform:uppercase;letter-spacing:-.03em;line-height:.92;
  font-size:clamp(28px,4.4vw,54px)}
.sect-t--gd{margin:var(--s8) 0 var(--s5);align-items:flex-end}
.sect-t--gd h2{font-family:var(--geo);font-weight:800;font-stretch:108%; text-transform:uppercase;letter-spacing:-.03em;line-height:.92; font-size:clamp(28px,4.4vw,54px);max-width:16ch}
.sect-t--gd::after{display:none}
.sect-t--gd .etiq,.sect-t--gd a{margin-bottom:6px}
/* 🔴 LOT 206 (V7, Preda 26/08) — LE COMPTEUR N'EST PLUS COLLE AU TITRE.
   « MES FAVORIS 2 », « LES SUJETS 4 » : dans un `.sect-t--gd`, `::after` est
   eteint (pas de filet), donc l'etiq — `order:3` — atterrissait a `gap` du
   titre et rendait comme une faute de frappe. Le remede est celui que les
   `.sect-t` nus appliquent deja : le compteur part au bord droit. ⛔ Seule
   l'`.etiq` bouge — le lien « voir tout → » d'un titre reste pres du titre,
   c'est un chemin, pas un comptage. */
.sect-t--gd .etiq{margin-left:auto}
.sect-t::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--rule-2),transparent 80%)}
.sect-t a,.sect-t .etiq{order:3;flex:0 0 auto}
.sect-t a{font-family:var(--geo);font-size:var(--t-sm);font-weight:500;color:var(--muted)}
.sect-t a:hover{color:var(--sect-a)}
.gems-m{width:12px;height:12px;flex:0 0 12px;display:inline-block;vertical-align:-1.5px;color:var(--gems)}
.gems-m--g{width:22px;height:22px;flex:0 0 22px}
.gems-m svg{width:100%;height:100%;display:block}
.omi-m{width:12px;height:12px;flex:0 0 12px;display:inline-block;border:2px solid var(--omi); border-radius:50%;vertical-align:-1.5px;box-sizing:border-box}
.omi-m--g{width:22px;height:22px;flex:0 0 22px;border-width:2.8px}
.forme{width:14px;height:14px;flex:0 0 14px;display:inline-block;color:var(--c-a)}
.forme svg{width:100%;height:100%;display:block;fill:none;stroke:currentColor; stroke-width:2.1;stroke-linejoin:round;stroke-linecap:round}
.forme--g{width:22px;height:22px;flex:0 0 22px}
.forme--g svg{stroke-width:1.8}
.forme--xl{width:44px;height:44px;flex:0 0 44px}
.forme--xl svg{stroke-width:1.4}
.rar--sur-blanc .forme{color:var(--c-ink)}
.rar{display:inline-flex;align-items:center;gap:7px;font-family:var(--tech);font-size:var(--t-xs); font-weight:500;letter-spacing:.06em;color:var(--text-2);white-space:nowrap;line-height:1;text-transform:uppercase}
.rar--common{--c-a:var(--r-common-a);--c-b:var(--r-common-b);--c-ink:var(--r-common-ink)}
.rar--uncommon{--c-a:var(--r-uncommon-a);--c-b:var(--r-uncommon-b);--c-ink:var(--r-uncommon-ink)}
.rar--rare{--c-a:var(--r-rare-a);--c-b:var(--r-rare-b);--c-ink:var(--r-rare-ink)}
.rar--ultra{--c-a:var(--r-ultra-a);--c-b:var(--r-ultra-b);--c-ink:var(--r-ultra-ink)}
.rar--secret{--c-a:var(--r-secret-a);--c-b:var(--r-secret-b);--c-ink:var(--r-secret-ink)}
.rar--proof{--c-a:var(--r-proof-a);--c-b:var(--r-proof-b);--c-ink:var(--r-proof-ink)}
.rar--pilule{padding:5px 11px 5px 8px;border-radius:var(--r-full); background:var(--surface-2);border:1px solid var(--rule-2);color:var(--text); transition:background var(--d-base),border-color var(--d-base)}
.rar--pilule:hover,.rar--pilule:focus-visible{background:color-mix(in srgb,var(--c-a) 16%,transparent); border-color:color-mix(in srgb,var(--c-a) 52%,transparent)}
.rar--sur-blanc{color:var(--carte-ink-2)}
.carte:hover .rar--secret .forme,.rar--secret:hover .forme{animation:pulse-pli 700ms var(--e-out)}
.delta{display:inline-flex;align-items:center;gap:4px;font-family:var(--tech); font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--t-sm);white-space:nowrap;line-height:1.2}
.delta--up{color:var(--up)}
.delta--down{color:var(--down)}
.delta--flat{color:var(--muted)}
.delta svg{width:9px;height:9px;fill:currentColor;flex:0 0 9px}
.delta--plein{padding:4px 9px;border-radius:var(--r-full);background:var(--surface-2)}
.delta--plein.delta--up{background:var(--up-1v)}
.delta--plein.delta--down{background:var(--down-1v)}
.delta__k{font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;opacity:.72;margin-right:2px;font-weight:500}
.delta--sur-blanc.delta--up{color:#0A7A3E}
.delta--sur-blanc.delta--down{color:#B01F32}
.socle{position:relative;aspect-ratio:4/5;overflow:hidden;isolation:isolate; background:linear-gradient(178deg, var(--surface-3), var(--surface) 70%)}
.socle__fond{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0; filter:blur(var(--foc-fond)) saturate(1.45) brightness(.5);transform:scale(1.3); opacity:0;transition:opacity var(--d-slow) var(--e-soft)}
.socle__fond.ok{opacity:1}
.socle__voile{position:absolute;inset:0;z-index:1;pointer-events:none; background:radial-gradient(78% 52% at 50% 6%, var(--voile-haut), transparent 64%), radial-gradient(120% 78% at 50% 108%, var(--voile-bas), transparent 62%)}
.socle__net{width:100%;height:100%;object-fit:contain;opacity:0;position:relative;z-index:2; transform:scale(1.06); transition:transform var(--d-slow) var(--e-out),opacity var(--d-base) var(--e-soft); filter:drop-shadow(0 10px 14px #00000059)}
.socle__net.ok{opacity:1}
.socle--comic .socle__net{transform:none}
.socle::after{content:"";position:absolute;left:50%;bottom:7%;width:50%;height:4.5%; transform:translateX(-50%);border-radius:50%;background:#000;filter:blur(10px);opacity:.6;z-index:1}
.socle::before{content:"";position:absolute;inset:0;z-index:0; background:linear-gradient(100deg,transparent 20%,#FFFFFF12 42%,transparent 64%); background-size:220% 100%;animation:scintille 1.7s linear infinite}
.socle__ext{position:absolute;left:0;right:0;bottom:0;z-index:4;padding:5px 7px; display:flex;align-items:center;justify-content:space-between;gap:8px; font-family:var(--tech);font-size:8.5px;letter-spacing:.05em; background:linear-gradient(to top,#000000CC,transparent);pointer-events:none}
.socle__ext b{display:block;font-size:10px;font-weight:700;font-variant-numeric:tabular-nums; letter-spacing:-.01em;color:#FFFFFFE6}
/* ⭐ `.b` n'avait aucune regle : la maquette ne stylait que `.h`, et `.b`
   vivait du defaut. Ca MARCHE, mais ca ne se relit pas — le jour ou quelqu'un
   change la direction du conteneur, l'un des deux bouge et pas l'autre.
   Une paire se declare en paire. */
.socle__ext .b{text-align:left}
.socle__ext .h{text-align:right}
.socle__ext i{font-style:normal;color:#FFFFFF80;display:block;font-size:var(--t-3xs);letter-spacing:.1em}
.socle__droit{position:absolute;left:0;right:0;bottom:0;z-index:4;padding:3px 6px; font-family:var(--tech);font-size:var(--t-3xs);letter-spacing:.06em;color:#FFFFFFB3; background:linear-gradient(to top,#000000A6,transparent);pointer-events:none;text-align:right}
.socle--carre{aspect-ratio:1/1}
.socle__fav{position:absolute;top:8px;right:8px;z-index:3;width:32px;height:32px;display:grid;place-items:center; background:#000000A6;backdrop-filter:blur(8px);border:1px solid var(--rule-2);border-radius:var(--r-full); cursor:pointer;color:var(--text-2);opacity:0;transition:all var(--d-base) var(--e-out)}
.socle__fav svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8}
/* ❤️ LOT 126 — `.carte-h` : l'enveloppe qui rend le cœur possible sur une carte.
   `.carte` EST un <a> ; un <button> dedans est du HTML invalide. Le bouton est
   donc un FRÈRE du lien, et cette enveloppe est le seul ancrage `relative`.
   ⚠️ `display:flex` + `flex:1` sur l'enfant : l'enveloppe devient l'élément de
   grille et la carte l'occupe entièrement — la grille ne voit pas la différence. */
.carte-h{position:relative;display:flex;min-width:0}
.carte-h>.carte{flex:1 1 auto;min-width:0}
/* 🔴 LE SURVOL SUIT L'ENVELOPPE. Sans `.carte-h:hover`, le cœur resterait à
   `opacity:0` sur les cartes : il n'est plus un descendant de `.carte`. */
.carte:hover .socle__fav,.carte-h:hover .socle__fav,.socle__fav:focus-visible,.socle__fav[aria-pressed="true"]{opacity:1}
.socle__fav:hover,.socle__fav[aria-pressed="true"]{color:var(--sect-a);border-color:var(--sect-a)}
.socle__fav[aria-pressed="true"] svg{fill:var(--sect-a)}
/* 🔴 LOT 206 (V8, capture Preda 26/08) — SUR /favoris/, LE CŒUR DESCEND EN
   BAS À DROITE. Sur cette page chaque cœur est ALLUMÉ en permanence
   (aria-pressed vrai ⇒ opacity:1) : posé en haut à droite il recouvrait le
   HAUT de la couverture — le ruban « ANIMATED » de l'œuvre tronqué en
   « (( ANIMA… » sur sa capture. Le bas du socle n'est occupé que par le
   reflet, jamais par le sujet de l'œuvre. (1,1,0) bat le (0,1,0) du haut.
   ⛔ Ailleurs, rien ne change : le cœur n'apparaît qu'au survol, en haut. */
#fav-l .socle__fav{top:auto;bottom:8px}
.socle__coin{position:absolute;top:8px;left:8px;z-index:3}
.grille{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fill,minmax(196px,1fr))}
.grille--ligne{grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);grid-template-columns:none}
.carte{display:flex;flex-direction:column;background:var(--surface);border-radius:var(--r-lg);overflow:hidden; color:var(--text);box-shadow:var(--sh-1);position:relative;isolation:isolate;border:1px solid var(--rule); transition:transform var(--d-base) var(--e-out),box-shadow var(--d-base),border-color var(--d-base)}
.carte:hover{transform:translateY(-4px);box-shadow:var(--sh-2);border-color:var(--rule-2);text-decoration:none}
.carte:hover .socle__net{transform:scale(1.12) translateY(-3px);filter:drop-shadow(0 16px 18px #00000073)}
.carte:hover .socle--comic .socle__net{transform:scale(1.05) translateY(-3px)}
.carte:hover .socle::after{opacity:.7;width:54%}
.carte:hover .socle__fond{filter:blur(24px) saturate(1.6) brightness(.58)}
.cartouche{background:var(--carte);color:var(--carte-ink);padding:10px 12px 11px; display:flex;flex-direction:column;gap:6px;margin-top:auto}
/* 158-A : hauteur FIXE (pas min-height) + etiq sur 1 ligne = grille regulière.
   Le pourquoi et les mesures vivent dans CarteSet.astro — ce fichier est SERVI. */
.cartouche__n{font-family:var(--geo);font-size:var(--t-sm);font-weight:600;line-height:1.3;letter-spacing:-.015em; display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;height:2.6em}
.cartouche .etiq{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.cartouche__l{display:flex;align-items:center;justify-content:space-between;gap:8px; padding-top:7px;border-top:1px solid var(--carte-rule)}
.cartouche__s{font-family:var(--tech);font-size:10px;color:var(--carte-ink-2);overflow:hidden; text-overflow:ellipsis;white-space:nowrap}
.prix{font-family:var(--tech);font-size:var(--t-md);font-weight:700;font-variant-numeric:tabular-nums; line-height:1;letter-spacing:-.02em;display:inline-flex;align-items:center;gap:5px}
.prix__u{font-size:9.5px;font-weight:500;opacity:.6;letter-spacing:.06em;text-transform:uppercase}
.spark{width:100%;height:26px;display:block;overflow:visible}
.spark path.l{fill:none;stroke:var(--muted);stroke-width:1.6;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke}
.spark.up path.l{stroke:var(--up)}
.spark.down path.l{stroke:var(--down)}
.spark path.a{stroke:none;fill:url(#gU)}
.spark.down path.a{fill:url(#gD)}
.stats{display:grid;gap:var(--s3);grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
.stat{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-md);padding:13px 16px;position:relative}
.stat__v{font-family:var(--tech);font-size:var(--t-xl);font-weight:700;font-variant-numeric:tabular-nums; margin-top:5px;line-height:1.1;display:flex;align-items:baseline;gap:5px;flex-wrap:wrap;letter-spacing:-.02em}
.stat--bleu{border-color:color-mix(in srgb,var(--sect-pur) 40%,transparent);background:var(--sect-1v)}
.tbl-hote{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);overflow-x:auto;overflow-y:hidden;box-shadow:var(--sh-1)}
table{width:100%;border-collapse:collapse;font-size:var(--t-sm)}
thead th{text-align:left;padding:11px 15px;background:var(--surface-2);font-family:var(--tech); font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:500; border-bottom:1px solid var(--rule);white-space:nowrap}
thead th.tri{cursor:pointer;user-select:none;transition:color var(--d-fast)}
thead th.tri:hover,thead th.tri[aria-sort]{color:var(--sect-a)}
thead th.tri::after{content:"↕";margin-left:5px;opacity:.4;font-size:9px}
thead th.tri[aria-sort="descending"]::after{content:"↓";opacity:1}
thead th.tri[aria-sort="ascending"]::after{content:"↑";opacity:1}
tbody td{padding:9px 15px;border-bottom:1px solid var(--rule);vertical-align:middle}
tbody tr{transition:background var(--d-fast) var(--e-soft)}
tbody tr:hover{background:var(--sect-1v)}
tbody tr:last-child td{border-bottom:0}
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
.tbl-obj{display:flex;align-items:center;gap:11px;min-width:0}
.tbl-obj .socle{width:30px;height:45px;flex:0 0 30px;aspect-ratio:auto;border-radius:var(--r-sm)}
.tbl-obj .socle::after,.tbl-obj .socle__droit,.tbl-obj .socle__ext,.tbl-obj .socle__voile{display:none}
.tbl-obj .socle .socle__fond{filter:blur(7px) saturate(1.4) brightness(.6);transform:scale(1.4)}
.tbl-obj .socle .socle__net{filter:none}
.tbl-obj__n{font-family:var(--geo);font-weight:500;color:var(--text);display:block;overflow:hidden; text-overflow:ellipsis;white-space:nowrap;max-width:34ch}
.tbl-obj__s{font-family:var(--tech);font-size:10px;color:var(--muted);overflow:hidden; text-overflow:ellipsis;white-space:nowrap;display:block;max-width:34ch}
.rang{font-family:var(--tech);color:var(--muted);width:1%;padding-right:0!important;font-variant-numeric:tabular-nums}
/* 🖼️ LOT 155-C — LA COUVERTURE A REMPLACE LE RANG DANS LA PREMIERE COLONNE
   (Preda : « vignette moyenne, 48 px »). 48x72 = le ratio 2:3 des couvertures
   VeVe, le meme que les tuiles (400x600).
   ⛔ LA LARGEUR EST POSEE SUR LA CELLULE, PAS SEULEMENT SUR L'IMAGE : avec
   `loading="lazy"`, l'image n'a aucune taille tant qu'elle n'est pas arrivee —
   la colonne se recalerait image par image et le tableau sauterait pendant tout
   le chargement. Les attributs `width`/`height` du `<img>` disent le ratio, ce
   `width` dit la colonne : il faut les deux.
   ⭐ `line-height:0` sur la cellule : sans lui, la ligne du tableau garde
   l'interligne du texte SOUS l'image, et chaque ligne grandit de 4 px pour
   rien. */
.vign{width:1%;padding-right:0!important;line-height:0}
.vign__i{display:block;width:48px;height:72px;object-fit:cover;border-radius:3px;background:var(--rule-2)}
.vign__v{display:grid;place-items:center;width:48px;height:72px;color:var(--rule-2)}
.vign__v svg{width:24px;height:24px}
.ticker{border-block:1px solid var(--rule);background:var(--surface);overflow:hidden;position:relative; mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent)}
.ticker__piste{display:flex;gap:var(--s5);padding:11px 0;width:max-content;animation:defile 48s linear infinite}
.ticker:hover .ticker__piste,.ticker:focus-within .ticker__piste{animation-play-state:paused}
.tick{display:inline-flex;align-items:center;gap:8px;font-size:var(--t-sm);white-space:nowrap;color:var(--text-2)}
.tick:hover{text-decoration:none;color:var(--sect-a)}
.tick b{font-family:var(--geo);font-weight:500;color:var(--text)}
.graph-hote{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg); padding:18px 18px 14px;box-shadow:var(--sh-1);position:relative}
.graph-tete{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s4)}
.plages{display:flex;gap:2px;padding:3px;background:var(--surface-2);border-radius:var(--r-full)}
.plages button{min-height:var(--tap-min);border:0;background:transparent;color:var(--muted);cursor:pointer;font-family:var(--tech); font-size:11px;padding:6px 11px;border-radius:var(--r-full);min-height:var(--tap-min);transition:all var(--d-fast);font-weight:500}
.plages button:hover{color:var(--text)}
.plages button[aria-pressed="true"]{background:var(--sect-pur);color:var(--sect-sur);font-weight:700}
/* 🔴🔴 LOT 132 — LE CADENAS DES DURÉES VERROUILLÉES.
   Preda, 10/08 : « n'oublie pas un cadenas et une infobulle disant quel grade
   débloque quoi ».
   ⭐⭐ L'INFOBULLE EST DANS LE HTML (`title="Crevette l'ouvre"`, posé par
   `Cadran.astro`) et le CADENAS EST ICI, en CSS. Ce partage n'est pas un
   caprice : le dessin est le même sur les cinq boutons de 3 000 fiches. En SVG
   dans le gabarit il pèserait 5 × 3 000 fois ; en `mask` il pèse UNE fois, dans
   une feuille déjà mise en cache. C'est le calcul du sprite du lot 127, à plus
   petite échelle.
   ⛔ PAS UN GLYPHE (« 🔒 ») : il dépend d'une fonte à symboles que le thème ne
   charge pas, et il se copie dans le presse-papier avec le libellé. Payé une
   fois sur le bouton jour/nuit (lot 18).
   ⚠️ `currentColor` VIA `background-color` + `mask` : un `background-image` en
   data-URI garderait la couleur écrite dans le SVG et ignorerait `--lock`, donc
   le thème jour. Le masque, lui, ne donne que la FORME.
   ⭐ Le cadenas s'en va AVEC `data-verrou` : c'est le script qui retire
   l'attribut quand le serveur a reconnu un droit — un seul juge, un seul geste,
   et rien à synchroniser entre le dessin et l'état. */
.plages button[data-verrou]{color:var(--lock);padding-right:8px}
.plages button[data-verrou]::after{
  content:"";display:inline-block;width:9px;height:9px;margin-left:5px;vertical-align:-1px;
  background-color:currentColor;
  -webkit-mask:var(--cadenas-m) center/contain no-repeat;
          mask:var(--cadenas-m) center/contain no-repeat; }
/* ⚠️ LA FORME VIT DANS UNE VARIABLE, et pas en double dans la règle : le jour
   où un second contrôle verrouillé arrive, il la réutilise au lieu d'en
   recopier une — c'est la divergence des deux gabarits de tuiles, en CSS. */
:root{ --cadenas-m:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round"><rect x="4.5" y="10.5" width="15" height="10" rx="2"/><path d="M8 10.5V7.8a4 4 0 0 1 8 0v2.7"/></svg>'); }
.series{display:flex;gap:var(--s3);flex-wrap:wrap}
.serie-b{display:inline-flex;align-items:center;gap:7px;background:none;border:0;cursor:pointer; font-family:var(--tech);font-size:11px;color:var(--muted);padding:5px 2px;min-height:var(--tap-min);transition:color var(--d-fast)}
.serie-b:hover{color:var(--text)}
.serie-b[aria-pressed="true"]{color:var(--text)}
.serie-b i{width:14px;height:3px;border-radius:2px;background:var(--muted);flex:0 0 14px;transition:background var(--d-fast)}
.serie-b[aria-pressed="true"] i{background:var(--c,var(--sect-pur))}
.serie-b--pointille[aria-pressed="true"] i{background:repeating-linear-gradient(90deg,var(--c,var(--muted)) 0 4px,transparent 4px 7px)}
.graph{width:100%;height:auto;display:block;overflow:visible;cursor:crosshair}
.graph .grille-l{stroke:var(--rule);stroke-width:1}
.graph .axe{fill:var(--muted);font-size:9.5px;font-family:var(--tech)}
.graph .axe--d{fill:var(--muted);opacity:.75}
.graph .aire{fill:url(#gAire);stroke:none}
.graph .ligne{fill:none;stroke:var(--sect-pur);stroke-width:2.2;stroke-linejoin:round;stroke-linecap:round; stroke-dasharray:var(--len,2600);animation:trace 1.4s var(--e-out) both}
.graph .ligne-offres{fill:none;stroke:var(--muted);stroke-width:1.6;stroke-dasharray:4 3;opacity:.9}
.graph .pt-haut,.graph .pt-bas{r:4;stroke:var(--surface);stroke-width:2}
.graph .pt-haut{fill:var(--up)}
.graph .pt-bas{fill:var(--down)}
.graph .cadran{stroke:var(--text);stroke-width:1;stroke-dasharray:2 3;opacity:0;transition:opacity var(--d-fast)}
.graph .cadran-pt{fill:var(--sect-pur);stroke:var(--surface);stroke-width:2;r:5;opacity:0;transition:opacity var(--d-fast)}
.graph-hote:hover .cadran,.graph-hote:hover .cadran-pt, .graph-hote:focus-within .cadran,.graph-hote:focus-within .cadran-pt{opacity:1}
.info-bulle{position:absolute;pointer-events:none;z-index:5;background:var(--surface-2); border:1px solid var(--rule-2);border-radius:var(--r-md);padding:9px 12px;box-shadow:var(--sh-2); font-family:var(--tech);font-size:11px;line-height:1.6;opacity:0;transition:opacity var(--d-fast);white-space:nowrap}
.graph-hote:hover .info-bulle{opacity:1}
.info-bulle b{color:var(--text);font-weight:700}
.info-bulle .j{color:var(--muted);display:block;margin-bottom:4px;font-size:10px}
.graph-pied{display:flex;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;margin-top:12px}
.extremes{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3);margin-top:var(--s4)}
.extreme{position:relative;overflow:hidden;border-radius:var(--r-lg);padding:16px 18px; border:1px solid color-mix(in srgb,var(--c) 34%,transparent); background:linear-gradient(115deg,color-mix(in srgb,var(--c) 13%,transparent),transparent 72%)}
.extreme--h{--c:var(--up)}
.extreme--b{--c:var(--down)}
.extreme::before{content:"";position:absolute;inset:0 auto 0 0;width:3px;background:var(--c)}
.extreme__k{font-family:var(--tech);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em; color:var(--c);font-weight:600;display:flex;align-items:center;gap:6px}
.extreme__v{font-family:var(--tech);font-size:var(--t-2xl);font-weight:700;font-variant-numeric:tabular-nums; line-height:1;margin-top:8px;letter-spacing:-.03em;display:flex;align-items:center;gap:8px}
.extreme__d{font-family:var(--tech);font-size:11px;color:var(--muted);margin-top:8px}
.extreme__e{font-family:var(--tech);font-size:11px;color:var(--c);font-weight:600;margin-top:2px}
.verrou{position:relative;isolation:isolate;border-radius:var(--r-lg);overflow:hidden}
.verrou__fond{filter:blur(var(--foc-mur)) saturate(.42);opacity:.34;pointer-events:none;user-select:none}
.verrou__prof{position:absolute;inset:0;z-index:1;pointer-events:none}
.verrou__prof i{position:absolute;left:0;right:0;display:block}
.verrou__prof i:nth-child(1){top:0;height:46%;backdrop-filter:blur(1px); -webkit-backdrop-filter:blur(1px);mask-image:linear-gradient(180deg,transparent,#000)}
.verrou__prof i:nth-child(2){top:34%;height:40%;backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);mask-image:linear-gradient(180deg,transparent,#000 60%)}
.verrou__prof i:nth-child(3){top:62%;bottom:0;backdrop-filter:blur(7px); -webkit-backdrop-filter:blur(7px);mask-image:linear-gradient(180deg,transparent,#000 45%)}
[data-leger] .verrou__prof{display:none}
.verrou__voile{position:absolute;inset:0;display:grid;place-items:center;text-align:center;padding:var(--s5) var(--s4); background:linear-gradient(180deg,#1A1A1A4D,#1A1A1AF7 62%)}
[data-theme="jour"] .verrou__voile{background:linear-gradient(180deg,#F5F5F54D,#F5F5F5F7 62%)}
.verrou__in{max-width:46ch;display:grid;gap:var(--s3);justify-items:center;position:relative;z-index:2}
.verrou__t{font-family:var(--geo);font-size:var(--t-lg);font-weight:600;color:var(--text);letter-spacing:-.02em}
.verrou__d{font-size:var(--t-sm);color:var(--text-2);line-height:1.6}
.verrou__d b{color:var(--sect-a);font-family:var(--tech);font-weight:700}
.cadenas{width:42px;height:42px;display:grid;place-items:center;border-radius:var(--r-full); background:var(--lock-1v);border:1px solid color-mix(in srgb,var(--lock) 44%,transparent);color:var(--lock)}
.cadenas svg{width:19px;height:19px;stroke:currentColor;fill:none;stroke-width:1.7}
.sceau{position:relative;border:1px solid var(--rule);border-radius:var(--r-lg);background:var(--surface); padding:var(--s6) var(--s5);text-align:center;overflow:hidden}
.sceau::before{content:"";position:absolute;inset:0;opacity:.6; background:radial-gradient(72% 90% at 50% 0%, var(--lock-1v), transparent 70%)}
.sceau__in{position:relative;z-index:2;display:grid;gap:var(--s3);justify-items:center;max-width:46ch;margin:0 auto}
/* ═══════════════════════════════════════════════════════════════════════════
   LA BARRE D'ACCES PREND LA COULEUR DE SA SECTION — 03/08/2026, lot 45, Preda
   ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐ AUCUNE COULEUR N'EST INVENTEE ICI, ET C'EST TOUT LE POINT. Le mecanisme
   existe depuis le lot 43 : l'attribut `data-sect` est pose sur la balise body
   (Base.astro l. 354) et
   chaque section redefinit `--sect-a` / `--sect-1v` un peu plus haut dans ce
   fichier. La barre lisait `--lock` et `--text-2` — deux valeurs FIXES — donc
   elle sortait cyan sur le Marche, qui est rouge. On remplace des constantes
   par les variables que le corps de page pose deja.
   ⭐ `--sect-a` et non `--sect-pur` : `a` est la teinte ACCESSIBLE de la
   section (la variante sombre en theme jour, claire en theme nuit). C'est
   celle que `.etiq--bleu` emploie depuis toujours pour du TEXTE — mettre du
   `--sect-pur` sur du 12,5 px donnerait un contraste que WCAG refuse.
   ⛔ LE CADENAS EST RECOLORE ICI, PAS DANS `.cadenas`. La regle generique
   (l. 649) habille aussi le sceau de <Gate>, ou la couleur `--lock` DIT
   « contenu reserve ». La reperer globalement effacerait ce signal partout
   pour corriger un composant. Selecteur a deux niveaux = specificite (0,2,0),
   il gagne sur (0,1,0) quel que soit l'ordre des regles. */
.barre-acces{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap;padding:15px 18px; border:1px solid color-mix(in srgb,var(--sect-a) 38%,transparent);border-radius:var(--r-lg); background:var(--sect-1v);margin-bottom:var(--s5)}
.barre-acces p{margin:0;font-size:var(--t-sm);color:var(--sect-a);flex:1;min-width:220px}
.barre-acces .cadenas{background:var(--sect-1v);border-color:color-mix(in srgb,var(--sect-a) 44%,transparent);color:var(--sect-a)}
.modules{display:grid;gap:var(--s3);grid-template-columns:repeat(auto-fill,minmax(232px,1fr))}
.module{display:flex;gap:12px;align-items:flex-start;padding:15px;border-radius:var(--r-md); border:1px dashed color-mix(in srgb,var(--lock) 40%,transparent);background:var(--lock-1v); transition:border-color var(--d-fast),transform var(--d-base) var(--e-out)}
.module:hover{border-color:var(--lock);transform:translateY(-2px);text-decoration:none}
.module__i{width:32px;height:32px;flex:0 0 32px;display:grid;place-items:center;border-radius:var(--r-sm); background:color-mix(in srgb,var(--lock) 18%,transparent);color:var(--lock)}
.module__i svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.8}
.module__n{font-family:var(--geo);font-weight:600;font-size:var(--t-sm);color:var(--text)}
.module__d{font-size:var(--t-xs);color:var(--muted);line-height:1.5;margin-top:3px}
/* 🔴 LOT 165 — `.module__c` = LE CONTENU, `.module__x` = le chevron.
   Cinq emetteurs sur six s'en servaient comme conteneur ; la regle du chevron
   (`flex:0 0 auto`) les empechait de retrecir et cassait `/analytics/` en
   production. ⛔ Ne pas rendre `.module__c` au chevron. ⛔ Ne pas retirer
   `min-width:0` : sans lui le debordement revient sur un mot long.
   📄 Le detail mesure vit dans `src/components/pages/Analytics.astro`. */
.module__c{display:flex;flex-direction:column;align-items:flex-start;min-width:0;flex:1 1 auto}
.module__c > .etiq{margin-top:6px}
.module__x{margin-left:auto;color:var(--lock);flex:0 0 auto}
.module__x svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2}
/* 🔴 LOT 104 — LE TABLEAU DE BORD DE L'ACCUEIL (bloc membre).
   ⭐ Il occupe la place du `hero`, donc il en reprend le rythme vertical — pas
   son decor. Le hero a un champ noir, un panneau os et une piece qui deborde ;
   un tableau de bord n'a rien a mettre en scene, il presente.
   ⛔ AUCUN `display` ICI. Le bloc est rendu avec `hidden` et c'est la regle en
   ligne du <head> qui l'ouvre — une regle d'affichage posee dans cette feuille
   arriverait avec le CSS externe, donc PARFOIS apres la premiere peinture, et
   le clignotement reviendrait de temps en temps. Pire qu'a chaque fois : on
   cesserait de savoir le reproduire. */
/* ⛔ LOT 134 — `.tableau-bord` A ETE RETIREE : son unique emetteur (le bloc
   membre de l'accueil, lot 104) est parti avec le lot 134. Deux regles qui ne
   peuvent plus matcher aucun element ne changent rien a l'ecran et se relisent
   comme une intention encore vivante. */

/* 🔴 LOT 104 — LE MODULE ANNONCE MAIS PAS CONSTRUIT.
   ⭐ Il est ATTENUE, jamais barre ni grise a l'illisible : Preda a choisi de
   les montrer, et un module qu'on montre doit rester lisible. Le contraste du
   nom ne bouge donc pas — seule la bordure recule.
   ⛔ AUCUN `pointer-events:none` ICI : ces cartes ne sont pas cliquables (ce
   sont des `<div>`), et desarmer une interaction inexistante donnerait a
   croire, au prochain lecteur, qu'elle existait. */
.module--attente{border-style:dotted;opacity:.86}
.module--attente .module__i{background:color-mix(in srgb,var(--lock) 10%,transparent)}
.module--ouvert{border-style:solid;border-color:var(--rule);background:var(--surface)}
.module--ouvert .module__i{background:var(--sect-1v);color:var(--sect-a)}
.module--ouvert .module__x{color:var(--sect-a)}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:var(--tap); padding:0 20px;border-radius:var(--r-full);font-family:var(--geo);font-size:var(--t-sm);font-weight:600; cursor:pointer;border:1px solid transparent;letter-spacing:-.01em;position:relative; transition:transform var(--d-fast) var(--e-rebond),background var(--d-base),color var(--d-base), border-color var(--d-base),box-shadow var(--d-base)}
.btn:hover{text-decoration:none;transform:translateY(-1px)}
.btn:active{transform:none}
.btn--principal{background:linear-gradient(100deg,var(--sect-pur),var(--sect-fonce));color:var(--sect-sur)}
.btn--principal:hover{box-shadow:var(--lueur)}
.btn--verrou{background:transparent;border-color:var(--lock);color:var(--lock);border-width:1.5px}
.btn--verrou:hover{background:var(--lock);color:var(--sect-sur);box-shadow:var(--lueur)}
.btn--fantome{background:transparent;border-color:var(--rule-int);color:var(--text-2)}
.btn--fantome:hover{border-color:var(--sect-a);color:var(--sect-a);background:var(--sect-1v)}
.btn--danger{background:transparent;border-color:color-mix(in srgb,var(--down) 50%,transparent);color:var(--down)}
.btn--danger:hover{background:var(--down-1v);border-color:var(--down)}
.btn--sm{min-height:36px;padding:0 14px;font-size:var(--t-xs)}
.btn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2.2;flex:0 0 15px}
.champ{display:grid;gap:6px}
.champ input,.champ select,.champ textarea{width:100%;min-height:var(--tap);padding:11px 14px; background:var(--surface-2);border:1px solid var(--rule-int);color:var(--text);font:inherit; font-size:var(--t-md);border-radius:var(--r-md);transition:border-color var(--d-fast),box-shadow var(--d-fast)}
.champ input:focus,.champ select:focus{border-color:var(--sect-a);outline:none;box-shadow:0 0 0 3px var(--sect-1v)}
.champ input::placeholder{color:var(--muted)}
/* ═══════════════════════════════════════════════════════════════════════════
   🔴🔴🔴 LOT 204 — UNE CASE À COCHER N'EST PAS UN CHAMP DE SAISIE
   ═══════════════════════════════════════════════════════════════════════════
   MESURÉ SUR SA CAPTURE DU 26/08 : dans « Mon tableau de bord », les sept cases
   flottaient en escalier au milieu de la largeur, libellés collés à l'extrême
   droite. On ne savait plus quelle case allait avec quel libellé.
   LA CAUSE : la règle juste au-dessus vise `.champ input` SANS EXCEPTION. Elle
   est écrite pour un `<input type="text">` qui doit prendre toute la largeur ;
   appliquée à une `checkbox`, elle en fait une barre de 100 % de large avec
   14 px de rembourrage. Le navigateur dessine alors la coche quelque part au
   milieu de cette barre — d'où l'escalier.
   ⭐⭐ ET LE DÉFAUT EXISTAIT DEPUIS LE LOT 160-A, sur le bloc e-mails. Il n'y
   avait qu'UNE case, donc personne ne l'a jamais remarqué : une case seule mal
   placée ressemble à un choix de mise en page. C'est en en mettant sept côte à
   côte au lot 202 que le défaut est devenu lisible. ⛔ Ce n'est pas le lot 202
   qui l'a créé, c'est lui qui l'a RÉVÉLÉ — corriger ici corrige les DEUX.
   ⭐⭐⭐ LA LEÇON, ET ELLE EST PLUS GRANDE QUE CES DEUX BLOCS : `.champ` décrit
   un RÔLE (« ce conteneur porte des champs de saisie pleine largeur »), et on
   l'a recopiée comme un conteneur générique. Une classe recopiée sans lire ce
   qu'elle fait à ses ENFANTS, c'est un défaut recopié. Troisième fois dans ce
   projet — `.rang` sur les prix de la caisse est la même faute, le même jour.
   ⛔ ON CORRIGE DANS LE THÈME, PAS DANS LES PAGES. Deux pages réparées à la
   main laisseraient la troisième cassée, et le prochain `class="panneau champ"`
   naîtrait cassé. Ici, l'exception vaut pour tout usage futur.
   ⚠️ `min-height:0` autant que `width:auto` : `--tap` vaut 44 px (la cible
   tactile), et une case de 44 px de HAUT désaligne son libellé même une fois
   sa largeur rendue. Les trois déclarations de la règle du dessus se défont,
   pas seulement la plus visible.
   🔬 `test:feuille` §204-A résout la cascade sur la feuille SERVIE et lit qui
   GAGNE sur une `checkbox` dans un `.champ` — pas « la règle est écrite »,
   mais « la règle gagne ». Retirer la ligne ci-dessous doit rendre `exit 1`. */
.champ input[type="checkbox"],.champ input[type="radio"]{width:auto;min-height:0;padding:0}

/* ═══════════════════════════════════════════════════════════════════════════
   🔴🔴 LOT 204 — LA GRILLE DES PRIX DE LA CAISSE, ET LA MÊME FAUTE QUE CI-DESSUS
   ═══════════════════════════════════════════════════════════════════════════
   MESURÉ SUR SA CAPTURE DU 26/08 : « $6.00 / mois » entassé sur trois lignes
   dans un DISQUE bleu de la taille d'un jeton. Six boutons, six pastilles
   rondes illisibles.
   LA CAUSE : `CaisseAchat.astro` employait `<div class="rang">` comme conteneur
   de ligne. `.rang` est la colonne de RANG d'un tableau — `width:1%`, c'est-à-
   dire « prends la place minimale ». Écrasé à 1 %, un `.btn` (`inline-flex`,
   `border-radius:var(--r-full)`) casse son texte en trois lignes ; une pilule
   aussi haute que large est un cercle. ⛔ LE BOUTON N'EST PAS COUPABLE : sur
   `/offre/` les MÊMES `.btn btn--principal btn--sm` sont corrects. La
   différence est le CONTENEUR — donc on ne touche pas à `.btn`.
   ⚠️ ET `#caisse-choix` N'AVAIT AUCUNE RÈGLE : la grille des prix n'était
   peinte nulle part. Un conteneur non peint hérite de ce qu'il trouve, et ce
   qu'il avait trouvé était `.rang`.
   ⭐ LA FORME EST L'ARBITRAGE DE PREDA (26/08) : une LIGNE PAR PALIER, le nom
   à gauche, les deux durées à droite. `flex-wrap` laisse les boutons descendre
   sur un téléphone plutôt que d'écraser le nom — c'est exactement le défaut
   qu'on répare, on ne le réintroduit pas au format étroit.
   ⚠️ `min-width:0` sur le nom : sans lui, un nom de palier long refuse de
   rétrécir et repousse les boutons hors de la carte. C'est la même règle que
   `.item{min-width:0}` que `test:feuille` surveille déjà — un enfant non
   plafonné casse une grille.
   ⭐ `white-space:nowrap` est PORTÉ ICI, pas sur `.btn` : « 36 $ / mois » ne
   doit jamais se couper, mais un bouton d'article long a le droit de le faire.
   🔬 `test:feuille` §204-B exige ces règles dès que `offer.url` existe au
   manifeste — la MÊME condition qui décide d'afficher la caisse. Sur un site
   sans caisse, le contrôle est SANS OBJET, pas indécidable. */
#caisse-choix{display:grid;gap:0}
.caisse-rangee{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s3);padding:var(--s3) 0;border-top:1px solid var(--rule-int)}
.caisse-rangee:first-child{border-top:0;padding-top:0}
.caisse-rangee>strong{flex:1 1 auto;min-width:0}
#caisse-choix .btn{flex:0 0 auto;white-space:nowrap}
.champ--sm input,.champ--sm select{min-height:36px;padding:7px 11px;font-size:var(--t-sm)}
.champ__aide{font-size:var(--t-xs);color:var(--muted);line-height:1.5}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden; clip:rect(0 0 0 0);white-space:nowrap;border:0}
.puce{display:inline-flex;align-items:center;gap:7px;min-height:36px;padding:0 13px;border-radius:var(--r-full); border:1px solid var(--rule-2);background:var(--surface);color:var(--text-2);font-family:var(--geo); font-size:var(--t-sm);font-weight:500;cursor:pointer;transition:all var(--d-fast)}
.puce:hover{border-color:var(--sect-a);color:var(--text)}
.puce[aria-pressed="true"]{background:var(--sect-pur);border-color:var(--sect-pur);color:var(--sect-sur);font-weight:600}
.puce svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2.2}
.puce--rar[aria-pressed="true"]{background:color-mix(in srgb,var(--c-a) 18%,transparent); border-color:color-mix(in srgb,var(--c-a) 62%,transparent);color:var(--text);font-weight:600}
.puce--rar[aria-pressed="true"] .forme{color:var(--c-a)}
.puce__x{margin-left:2px;opacity:.7}
.filtres{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.sep-v{width:1px;height:22px;background:var(--rule);margin:0 3px}
.tag{display:inline-flex;align-items:center;min-height:var(--tap-min);padding:0 12px;border-radius:var(--r-full); background:var(--surface-2);border:1px solid var(--rule);color:var(--text-2);font-size:var(--t-sm);transition:all var(--d-fast)}
.tag:hover{border-color:var(--sect-a);color:var(--sect-a);text-decoration:none}
.tag b{font-family:var(--tech);font-weight:600;color:var(--muted);margin-left:7px;font-variant-numeric:tabular-nums}
.evitement{position:absolute;left:0;top:0;z-index:60;width:1px;height:1px;overflow:hidden; clip-path:inset(50%);white-space:nowrap; background:var(--sect-pur);color:var(--sect-sur);border-radius:var(--r-md); font-family:var(--tech);font-size:var(--t-sm);letter-spacing:.06em; padding:10px var(--s4);text-decoration:none;box-shadow:var(--sh-2)}
.evitement:focus-visible{width:auto;height:auto;clip-path:none; outline:2px solid var(--text);outline-offset:2px}
.barre-f{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg); padding:12px 14px;display:grid;gap:12px}
.barre-f__l{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.barre-f__t{font-family:var(--tech);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em; color:var(--muted);min-width:66px}
.f-onglets{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.f-b{display:inline-flex;align-items:center;gap:7px;min-height:36px;padding:0 13px; border-radius:var(--r-full);border:1px solid var(--rule-2);background:var(--surface-2); color:var(--text-2);font-family:var(--geo);font-size:var(--t-sm);font-weight:500;cursor:pointer; transition:all var(--d-fast)}
.f-b:hover{border-color:var(--sect-a);color:var(--text)}
.f-b[aria-expanded="true"]{background:var(--sect-1v);border-color:var(--sect-a);color:var(--sect-a)}
.f-b svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2.4; transition:transform var(--d-base) var(--e-out)}
.f-b[aria-expanded="true"] svg:last-child{transform:rotate(180deg)}
.f-b .cpt-f{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px; border-radius:var(--r-full);background:var(--sect-pur);color:var(--sect-sur); font-family:var(--tech);font-size:10px;font-weight:700}
.f-panneau{padding:var(--s4) var(--s4) var(--s3);margin-top:12px;border-radius:var(--r-md); background:var(--surface-2);border:1px solid var(--rule-2)}
.f-panneau__t{font-family:var(--tech);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em; color:var(--muted);margin-bottom:12px;display:flex;align-items:center;gap:10px}
.f-panneau__t::after{content:"";flex:1;height:1px;background:var(--rule)}
.tiroir__c{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end}
/* 🔴🔴 LE PANNEAU DE FILTRES ETAIT INVISIBLE EN PERMANENCE (01/08/2026).
   La maquette ecrit :
       @media (prefers-reduced-motion: no-preference){
         .f-panneau{transition:opacity …,transform …}
         @starting-style{ .f-panneau{opacity:0;transform:translateY(-6px)} }
       }
   `@starting-style` decrit l'etat de DEPART d'une transition — l'apparence de
   l'element juste avant qu'il apparaisse. LES DEUX at-rules ont ete aplaties
   en portant ce lot : `opacity:0` est passe de « pendant un dixieme de
   seconde » a « pour toujours ». Le panneau s'ouvrait, POUSSAIT le contenu
   (d'ou le grand vide sous FILTRES) et ne se voyait pas.
   ⭐⭐ `cascade-aplatie.mjs` NE POUVAIT PAS L'ATTRAPER, et c'est ce qui compte
   ici. Il cherche une regle presente A LA FOIS a la racine et sous une
   at-rule : il detecte la RECOPIE. Ici l'at-rule a ete REMPLACEE par son
   contenu — il ne reste aucun doublon a comparer. C'est l'autre moitie de la
   meme famille, et l'outil posait deja la bonne question sans y repondre en
   entier : « quelle FRACTION de sa famille j'attrape ? ».
   ➡️ Le pendant statique vit dans `outils/css-mort.mjs` : un `opacity:0` pose
   a la racine que rien ne ramene au-dessus de zero rend l'element
   DEFINITIVEMENT invisible — et ca, ca se mesure sans navigateur. */
@media (prefers-reduced-motion: no-preference){
  .f-panneau{transition:opacity var(--d-base) var(--e-out),transform var(--d-base) var(--e-out)}
  @starting-style{ .f-panneau{opacity:0;transform:translateY(-6px)} }
}
.seg-p{display:inline-flex;padding:3px;background:var(--surface-2);border-radius:var(--r-full); border:1px solid var(--rule-2);gap:2px}
.seg-p button{border:0;background:transparent;color:var(--muted);cursor:pointer; padding:0 15px;min-height:var(--tap-min);border-radius:var(--r-full);font-family:var(--geo); font-size:var(--t-sm);font-weight:600;display:inline-flex;align-items:center;gap:7px; transition:all var(--d-fast)}
.seg-p button:hover{color:var(--text)}
.seg-p button[aria-pressed="true"]{background:var(--sect-pur);color:var(--sect-sur)}
.seg-p button svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2}
.cols-l{display:grid;gap:5px;grid-template-columns:repeat(auto-fill,minmax(178px,1fr))}
.cols-l label{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:var(--r-sm); background:var(--surface);border:1px solid var(--rule);cursor:pointer;font-size:var(--t-sm); min-height:40px;transition:border-color var(--d-fast)}
.cols-l label:hover{border-color:var(--sect-a)}
.cols-l input{width:16px;height:16px;accent-color:var(--sect-pur);flex:0 0 16px}
.cols-l label[data-verrou]{opacity:.55;cursor:default}
.actifs{display:flex;flex-wrap:wrap;gap:7px;align-items:center;padding-top:12px;border-top:1px solid var(--rule)}
.jeton{display:inline-flex;align-items:center;gap:7px;padding:5px 8px 5px 11px;border-radius:var(--r-full); background:var(--sect-1v);border:1px solid color-mix(in srgb,var(--sect-pur) 40%,transparent); color:var(--sect-a);font-family:var(--tech);font-size:11px}
.jeton button{background:none;border:0;color:inherit;cursor:pointer;display:grid;place-items:center; width:18px;height:18px;border-radius:50%;opacity:.8}
.jeton button:hover{opacity:1;background:var(--survol)}
.jeton svg{width:10px;height:10px;stroke:currentColor;fill:none;stroke-width:2.6}
.crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:var(--t-sm);color:var(--muted);margin-bottom:var(--s4)}
.crumbs a{color:var(--muted)}
.crumbs a:hover{color:var(--sect-a)}
.crumbs span[aria-current]{color:var(--text-2)}
.avertis{display:flex;gap:12px;align-items:flex-start;padding:14px 17px;border-radius:var(--r-md); border:1px solid color-mix(in srgb,var(--down) 34%,transparent);border-left-width:3px; background:var(--down-1v);font-size:var(--t-sm);line-height:1.55;color:var(--text-2)}
.avertis b{color:var(--down);font-weight:600}
.avertis svg{width:17px;height:17px;flex:0 0 17px;margin-top:2px;stroke:var(--down);fill:none;stroke-width:1.9}
.alerte{display:inline-grid;place-items:center;width:16px;height:16px;border-radius:var(--r-full); background:var(--down);color:#1A1A1A;font-family:var(--tech);font-size:10px;font-weight:700; vertical-align:middle;margin-left:5px;cursor:help;line-height:1}
.fiche{display:grid;gap:var(--s6);grid-template-columns:minmax(0,300px) minmax(0,1fr);align-items:start}
.fiche__viz{position:sticky;top:88px;display:grid;gap:var(--s4)}
.fiche__socle{border-radius:var(--r-lg);overflow:hidden;border:1px solid var(--rule);box-shadow:var(--sh-2)}
.murs{display:grid;grid-template-columns:1fr auto 1fr;gap:var(--s6);margin-top:var(--s5); padding:var(--s5) 0;border-block:1px solid var(--rule);align-items:start}
.murs__sep{width:1px;background:var(--rule);align-self:stretch}
.mur__k{display:flex;align-items:center;gap:9px;font-family:var(--tech);font-size:var(--t-xs); text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:500}
.mur__v{font-family:var(--tech);font-size:var(--t-4xl);font-weight:700;line-height:.95; font-variant-numeric:tabular-nums;letter-spacing:-.045em;margin-top:14px;display:flex;align-items:baseline;gap:10px}
.mur__u{font-family:var(--tech);font-size:var(--t-sm);color:var(--muted);letter-spacing:.1em;text-transform:uppercase;font-weight:500}
.mur__eq{font-family:var(--tech);font-size:var(--t-sm);color:var(--text-2);margin-top:10px}
.mur__d{display:flex;gap:7px;flex-wrap:wrap;margin-top:16px}
.jauge{display:grid;gap:12px;margin-top:var(--s6)}
.jauge__b{position:relative;height:5px;background:var(--surface-2)}
.jauge__r{position:absolute;inset:0;background:linear-gradient(90deg,var(--down),var(--muted) 50%,var(--up));opacity:.5}
.jauge__c{position:absolute;top:50%;width:3px;height:18px;background:var(--text); transform:translate(-50%,-50%);box-shadow:0 0 0 2px var(--nuit)}
.jauge__l{display:grid;grid-template-columns:1fr auto 1fr;gap:var(--s4);align-items:start}
.jauge__e{display:grid;gap:5px}
.jauge__e--d{text-align:right;justify-items:end}
.jauge__e--c{text-align:center;justify-items:center}
.jauge__k{font-family:var(--tech);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.1em; color:var(--muted);display:flex;align-items:center;gap:6px}
.jauge__v{font-family:var(--tech);font-size:var(--t-lg);font-weight:700;font-variant-numeric:tabular-nums; letter-spacing:-.02em;display:flex;align-items:center;gap:7px}
.jauge__v--h{color:var(--up)}
.jauge__v--b{color:var(--down)}
.jauge__d{font-family:var(--tech);font-size:10px;color:var(--muted)}
dl.fiche-tbl{display:grid;grid-template-columns:auto 1fr;gap:0;margin:0;font-size:var(--t-sm)}
dl.fiche-tbl dt{padding:10px 15px 10px 0;border-bottom:1px solid var(--rule);white-space:nowrap;color:var(--muted)}
dl.fiche-tbl dd{padding:10px 0;margin:0;border-bottom:1px solid var(--rule);text-align:right; font-variant-numeric:tabular-nums;color:var(--text-2)}
dl.fiche-tbl dt:last-of-type,dl.fiche-tbl dd:last-of-type{border-bottom:0}
/* 🔴 LOT 132 — LE FILET ENTRE LES BLOCS. Preda, 10/08 : « dans les fiches il
   manque des lignes séparatrices dans la colonne gauche (entre tirage et
   éditions par exemple) ».
   ⭐ MESURÉ, ET IL DÉSIGNAIT EXACTEMENT LA JOINTURE : « tirage » est la
   DERNIÈRE ligne du bloc ① et « édition » la PREMIÈRE du bloc ②. La règle
   au-dessus retire le filet du dernier couple de CHAQUE `<dl>` — ce qui est
   juste pour le dernier bloc et faux pour les deux autres : `.fiche__viz` les
   sépare d'un `gap`, donc d'un blanc, et deux tableaux collés par un blanc se
   lisent comme un seul tableau à trou.
   ⛔ ON NE RÉTABLIT PAS `border-bottom` SUR `:last-of-type` : ça poserait aussi
   un filet sous la DERNIÈRE ligne de la colonne, un trait qui ne sépare de
   rien. Le filet appartient à la jointure, donc au bloc SUIVANT.
   ⚠️ `+` et non `~` : seuls deux `<dl>` VOISINS forment une jointure. Avec `~`,
   un troisième bloc en hériterait même séparé par autre chose.
   ⭐ `padding-top` sur les deux premières cellules du bloc suivant : sans lui le
   filet colle au texte, et un séparateur collé se lit comme un soulignement. */
dl.fiche-tbl + dl.fiche-tbl{border-top:1px solid var(--rule);padding-top:2px}
.holders{display:grid;gap:1px}
.holder{display:flex;align-items:center;gap:12px;padding:9px 0;border-bottom:1px solid var(--rule)}
.holder:last-child{border-bottom:0}
.holder__r{font-family:var(--tech);color:var(--muted);width:18px;flex:0 0 18px;font-variant-numeric:tabular-nums}
.holder__a{width:32px;height:32px;flex:0 0 32px;border-radius:var(--r-full);background:var(--surface-3); display:grid;place-items:center;color:var(--muted)}
.holder__a svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.7}
.holder__n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--t-sm)}
.holder__v{font-family:var(--tech);font-variant-numeric:tabular-nums;font-weight:700}
.holder__p{font-family:var(--tech);font-size:10px;color:var(--muted);margin-left:6px}
.onglets-m{display:flex;gap:0;border-bottom:1px solid var(--rule);margin-bottom:var(--s4);overflow-x:auto}
.onglets-m button{border:0;background:none;color:var(--muted);cursor:pointer;padding:12px 16px; font-family:var(--geo);font-size:var(--t-sm);font-weight:500;white-space:nowrap;border-bottom:2px solid transparent; margin-bottom:-1px;min-height:var(--tap);transition:all var(--d-fast);display:inline-flex;align-items:center;gap:8px}
.onglets-m button:hover{color:var(--text)}
.onglets-m button[aria-selected="true"]{color:var(--sect-a);border-bottom-color:var(--sect-pur)}
.onglets-m svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2}
.onglets-m .cpt{font-family:var(--tech);font-size:10.5px;color:var(--muted);background:var(--surface-2);padding:2px 7px;border-radius:var(--r-full)}
.rail{display:flex;gap:var(--s3);overflow-x:auto;padding-bottom:11px;scroll-snap-type:x mandatory; scrollbar-width:thin;scrollbar-color:var(--rule-2) transparent}
.rail>*{scroll-snap-align:start;flex:0 0 auto}
.rail::-webkit-scrollbar{height:5px}
.rail::-webkit-scrollbar-thumb{background:var(--rule-2);border-radius:99px}
.col-carte{width:216px;background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg); overflow:hidden;box-shadow:var(--sh-1);color:var(--text);transition:transform var(--d-base) var(--e-out),box-shadow var(--d-base)}
.col-carte:hover{transform:translateY(-4px);box-shadow:var(--sh-2);text-decoration:none}
.col-carte__pile{display:flex;gap:3px;padding:11px 11px 0}
.col-carte__pile .socle{flex:1;border-radius:var(--r-sm)}
.col-carte__pile .socle::after,.col-carte__pile .socle__droit,.col-carte__pile .socle__ext{display:none}
.col-carte__pile .socle .socle__fond{filter:blur(13px) saturate(1.45) brightness(.52);transform:scale(1.35)}
.col-carte:hover .socle__net,.carte:hover .col-carte__pile .socle__net{transform:none}
/* 🔴🔴 LOT 139 — `.onglets` (LA BARRE DU BAS) A ÉTÉ RETIRÉE, PAS MASQUÉE.
   Décision de Preda du 11/08/2026 : « je ne veux pas la barre du bas sous
   640 px, je veux juste celui qui s'ouvre quand on clique sur le bouton ».
   ⭐⭐ ELLE N'ÉTAIT VISIBLE QUE SOUS 640 px (`display:none` ici, `grid` dans le
   @media) : la masquer sous 640 px, c'était la supprimer. On a donc retiré
   l'ÉMETTEUR aussi (`Base.astro`) plutôt que de laisser un balisage que
   personne ne peint — *une règle sans émetteur et un émetteur sans règle sont
   la même dette vue des deux côtés.*
   ⭐⭐⭐ ET ELLE EMPORTE DEUX AUTRES DÉFAUTS AVEC ELLE :
     ① un SECOND repère `<nav aria-label="Main navigation">`, homonyme de celui
        de l'en-tête — deux repères indiscernables au lecteur d'écran ;
     ② `.onglets a{font-size:9.5px}`, la plus petite police du site, sur la
        navigation principale du téléphone (MOB‑2 de l'audit du 10/08).
   ⛔ AVANT DE LA RETIRER, LES AUTRES CHEMINS ONT ÉTÉ COMPTÉS — et MESURÉS, pas
   supposés : sous 640 px il reste le tiroir pour le menu, et l'avatar `.globe`
   pour `/compte/`, visibles aux 30 largeurs balayées. `test:affichage` §3 bis
   et §3 quater le vérifient à chaque passage ; le §3 quinquies fabrique la
   panne pour prouver qu'ils savent encore rougir.
   ⚠️ La règle d'origine documentait ici une fuite hors d'at-rule (une version
   large recopiée sans condition, qui affichait la barre sur un écran de
   2560 px). La leçon vaut toujours pour la feuille entière, elle vit désormais
   dans `test:affichage` — *un commentaire ne peut pas rougir.* */
.deux-col{display:grid;gap:var(--s6);grid-template-columns:1fr 1fr}
.avec-aside{display:grid;gap:var(--s6);grid-template-columns:minmax(0,1fr) 300px;align-items:start}
.panneau{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);padding:var(--s5);box-shadow:var(--sh-1)}
.centre{max-width:470px;margin:0 auto}
.tarifs{display:grid;gap:var(--s4);grid-template-columns:repeat(4,1fr)}
.tarif{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);padding:var(--s5) var(--s4); display:grid;gap:var(--s3);align-content:start;position:relative}
.tarif--phare{border-color:var(--lock-pur);background:var(--lock-1v)}
/* ⛔⛔ IL Y AVAIT `content:"LE PLUS CHOISI"` ICI — du francais en dur dans une
   feuille de style, servi tel quel sur les pages anglaise, espagnole et
   allemande. ⭐⭐ DU TEXTE DANS DU CSS NE SERA JAMAIS TRADUIT : aucun controle
   i18n ne lit les feuilles de style, et `test:langues` mesure la couverture
   editoriale, pas le contenu d'un `content:`.
   Le gabarit fournit desormais la chaine traduite via `data-phare`. */
.tarif--phare::before{content:attr(data-phare);position:absolute;top:0;left:50%;transform:translate(-50%,-50%); background:var(--lock-pur);color:#FFFFFF;font-family:var(--tech);font-size:9px;letter-spacing:.12em; padding:4px 11px;border-radius:var(--r-full);font-weight:700;white-space:nowrap}
.tarif__p{font-family:var(--tech);font-size:var(--t-2xl);font-weight:700;font-variant-numeric:tabular-nums; line-height:1;letter-spacing:-.03em}
.tarif ul{list-style:none;margin:0;padding:0;display:grid;gap:9px;font-size:var(--t-sm)}
.tarif li{display:flex;gap:9px;align-items:flex-start;color:var(--text-2)}
.tarif li svg{width:14px;height:14px;flex:0 0 14px;margin-top:4px;stroke:var(--sect-a);fill:none;stroke-width:2.6}
.tarif li[data-non]{color:var(--muted)}
.tarif li[data-non] svg{stroke:var(--rule-2)}
.tarif__b{font-family:var(--geo);font-size:var(--t-lg);font-weight:700;display:flex;align-items:center;gap:8px}
.prose{max-width:70ch;font-size:var(--t-lg);line-height:1.75;color:var(--text-2)}
.prose h2{margin:var(--s6) 0 var(--s3);color:var(--text)}
.prose p{margin:0 0 var(--s4)}
.prose a{text-decoration:underline}
.prose figure{margin:var(--s5) 0}
.prose figcaption{font-family:var(--tech);font-size:var(--t-xs);color:var(--muted);margin-top:9px}
.editorial{position:relative}
.editorial::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;opacity:.55; background:repeating-linear-gradient(90deg,var(--rule) 0 1px,transparent 1px 132px), repeating-linear-gradient(0deg,var(--rule) 0 1px,transparent 1px 132px); mask-image:linear-gradient(180deg,#000 0%,#000 62%,transparent 100%)}
.editorial>*{position:relative;z-index:1}
.mono-t{font-family:var(--geo);font-weight:800;font-stretch:108%;text-transform:uppercase; font-size:clamp(38px,7.2vw,96px);line-height:.92;letter-spacing:-.028em;margin:0; font-variation-settings:'wdth' 108,'wght' 800}
.mono-t em{font-style:normal;color:var(--sect-a)}
.respire{max-width:56ch;line-height:1.62;font-size:var(--t-lg);color:var(--text-2)}
.num-s{font-family:var(--tech);font-size:var(--t-xs);letter-spacing:.16em;color:var(--sect-a); font-weight:600;display:block;margin-bottom:12px}
.banniere{position:relative;height:220px;overflow:hidden;isolation:isolate; display:flex;gap:3px;margin-bottom:calc(var(--s6)*-1)}
.banniere__l{flex:1;position:relative;overflow:hidden; clip-path:polygon(14% 0,100% 0,86% 100%,0 100%);margin:0 -3.5%}
.banniere__l:first-child{clip-path:polygon(0 0,100% 0,86% 100%,0 100%);margin-left:0}
.banniere__l:last-child{clip-path:polygon(14% 0,100% 0,100% 100%,0 100%);margin-right:0}
.banniere__l img{width:100%;height:100%;object-fit:cover;object-position:center 28%; opacity:0;transition:opacity var(--d-slow) var(--e-soft);transform:scale(1.12)}
.banniere__l img.ok{opacity:1}
.banniere__l:nth-child(3n+2) img{filter:grayscale(1) brightness(.5)}
.banniere__l:nth-child(3n) img{filter:grayscale(.85) brightness(.42)}
.banniere__l:nth-child(3n+1) img{filter:saturate(1.15) brightness(.72)}
.banniere::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none; background:linear-gradient(180deg,#00000059 0%,transparent 26%, color-mix(in srgb,var(--nuit) 72%,transparent) 74%, var(--nuit) 100%)}
.banniere__txt{position:absolute;inset:auto 0 0;z-index:4;padding:0 24px var(--s5)}
.tete-p{display:flex;align-items:center;gap:var(--s5);flex-wrap:wrap}
.tete-p__viz{flex:0 0 auto;display:flex;gap:5px}
/* 🔴 LOT 206 (V9) — LE CADRE. « Sans légende, sans cadre, sans lien » :
   le filet rattache la pile au langage des cartes du site ; la légende et le
   lien resteraient mensongers sur un décor `aria-hidden`. À juger sur sa
   prochaine capture — c'est un remède de rendu, pas de circuit. */
.tete-p__viz .socle{width:74px;border-radius:var(--r-md);border:1px solid var(--rule-2)}
.tete-p__viz .socle:nth-child(2){width:56px;opacity:.82}
.tete-p__viz .socle:nth-child(3){width:44px;opacity:.6}
.tete-p__viz .socle::after,.tete-p__viz .socle__droit,.tete-p__viz .socle__ext{display:none}
.fiche__socle .socle__ext{display:none}
.faq{display:grid;gap:2px}
.faq details{background:var(--surface);border:1px solid var(--rule);overflow:hidden}
.faq details[open]{border-color:var(--sect-a)}
.faq summary{cursor:pointer;list-style:none;padding:17px 20px;display:flex;align-items:center; gap:var(--s4);font-family:var(--geo);font-weight:600;font-size:var(--t-md);min-height:var(--tap)}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";margin-left:auto;font-family:var(--tech);font-size:19px; color:var(--sect-a);transition:transform var(--d-base) var(--e-out);line-height:1}
.faq details[open] summary::after{transform:rotate(45deg)}
.faq summary:hover{background:var(--sect-1v)}
.faq__n{font-family:var(--tech);font-size:var(--t-xs);color:var(--muted);letter-spacing:.12em;flex:0 0 auto}
.faq__c{padding:0 20px 19px 20px;color:var(--text-2);font-size:var(--t-sm);line-height:1.68;max-width:76ch}

/* 🔴 LOT 161 · 24/08/2026 — DOUZE LIGNES RETIRÉES ICI : trois séries d'étapes
   `0% / 22% / 78% / 100%` posées À LA RACINE de la feuille, sans leur
   `@keyframes` autour (mesuré : lightningcss, 12 × « Invalid empty selector »).
   Elles étaient MORTES, et sans conséquence : les vraies enveloppes
   `@keyframes vp-trav-loin|moyen|pres` existent plus bas et portent exactement
   les mêmes étapes. Un doublon amputé, pas une animation perdue. */

.compa{width:100%;border-collapse:collapse;font-size:var(--t-sm)}
.compa th,.compa td{padding:9px 10px;border-bottom:1px solid var(--rule);text-align:center}
.compa th:first-child,.compa td:first-child{text-align:left;color:var(--text-2)}
.compa thead th{font-family:var(--tech);font-size:var(--t-xs);text-transform:uppercase; letter-spacing:.09em;color:var(--muted);border-bottom-color:var(--rule-2)}
.compa thead th b{display:block;font-family:var(--geo);font-size:var(--t-md);color:var(--text); font-weight:700;letter-spacing:-.02em;margin-bottom:3px}
.compa td svg{width:14px;height:14px;stroke-width:2.6;fill:none;stroke:var(--sect-a)}
.compa td[data-non] svg{stroke:var(--rule-2)}
.compa .num{font-size:var(--t-sm)}
.compa tbody tr:last-child td{border-bottom:0}
.tuiles{display:grid;gap:var(--s3);grid-template-columns:repeat(auto-fill,minmax(178px,1fr))}
.tuile{position:relative;display:flex;flex-direction:column;background:var(--surface); border:1px solid var(--rule);border-radius:var(--r-lg);overflow:hidden;color:var(--text); transition:transform var(--d-base) var(--e-out),border-color var(--d-base)}
.tuile:hover{transform:translateY(-3px);border-color:var(--sect-a);text-decoration:none}
.tuile__hd{position:absolute;top:7px;left:7px;right:7px;z-index:4;display:flex; align-items:flex-start;justify-content:space-between;gap:6px;pointer-events:none}
.tuile__rar{display:inline-flex;align-items:center;gap:5px;padding:3px 7px;border-radius:var(--r-full); background:#000000A6;backdrop-filter:blur(6px);font-family:var(--tech);font-size:9px; letter-spacing:.08em;text-transform:uppercase;color:var(--text);min-width:0;overflow:hidden}
.tuile__off{display:inline-flex;align-items:center;gap:4px;padding:3px 7px;border-radius:var(--r-full); background:#000000A6;backdrop-filter:blur(6px);font-family:var(--tech);font-size:9.5px;color:var(--text-2);flex:0 0 auto;white-space:nowrap}   /* 155-C ③ : « N Offres » ne se casse plus en deux */
.tuile__b{padding:9px 11px 11px;display:grid;gap:6px}
/* 155-C ③ : `height` et NON `min-height` — un plancher n'est pas une égalité. Le
   raisonnement complet est dans Market.astro, au-dessus du pilote. ⛔ CE FICHIER EST
   SERVI COMMENTAIRES COMPRIS (mesuré le 18/08) : on y met le repère, pas la preuve. */
.tuile__n{font-family:var(--geo);font-weight:600;font-size:var(--t-sm);line-height:1.28; display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;height:2.56em}
.tuile__s{font-family:var(--tech);font-size:9.5px;color:var(--muted);overflow:hidden; text-overflow:ellipsis;white-space:nowrap}
.tuile__p{display:flex;align-items:center;justify-content:space-between;gap:8px; padding-top:8px;border-top:1px solid var(--rule)}
.dissout{position:relative}
.dissout__px{position:absolute;inset:0;pointer-events:none;z-index:5}
.dissout__px i{position:absolute;display:block;background:var(--fond-px,var(--nuit))}
.bloc{position:relative;display:grid;isolation:isolate}
.bloc__champ{position:absolute;inset:0;background:var(--surface);overflow:hidden}
.bloc__champ--noir{background:#0E0E0E}
/* 🔴 LOT 206 (M2, capture mobile 26/08) — LA UNE DU BLOG S'EMPILE SUR MOBILE.
   La carte vedette gardait ses 340px et sa cover absolue à droite (56%) : à
   390px il restait un grand champ noir vide entre la date et le titre. Les
   styles quittent le gabarit (ils étaient EN LIGNE, donc ingagnables par une
   media query) pour ces classes ; sous 640px la cover devient une bande en
   flux au-dessus du texte, et la hauteur suit le contenu. */
.bloc--une{margin-top:var(--s5);min-height:340px;text-decoration:none}
.bloc--une__viz{position:absolute;inset:0 0 0 auto;width:56%;overflow:hidden}
.bloc--une__viz img{width:100%;height:100%;object-fit:cover;opacity:.9}
.bloc--une__viz::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,#0E0E0E 6%,transparent 52%)}
@media (max-width:640px){
  .bloc--une{min-height:0}
  .bloc--une__viz{position:relative;inset:auto;width:100%;aspect-ratio:16/7}
  .bloc--une__viz::after{background:linear-gradient(0deg,#0E0E0E 10%,transparent 60%)}
}
[data-theme="jour"] .bloc__champ--noir{background:#1A1A1A}
.bloc__os{background:var(--carte);color:var(--carte-ink);padding:var(--s6) var(--s6) var(--s5); position:relative;z-index:2;max-width:640px}
.bloc__os .mono-t{color:var(--carte-ink)}
.bloc__os p{color:var(--carte-ink-2)}
.bloc__os .num-s{color:var(--carte-lien)}
.ref{position:absolute;z-index:6;font-family:var(--tech);font-size:9.5px;letter-spacing:.13em; text-transform:uppercase;color:var(--muted);line-height:1.7;white-space:pre-line}
.ref--tg{top:16px;left:18px}
.ref--td{top:16px;right:18px;text-align:right}
.ref--bg{bottom:16px;left:18px}
.ref--bd{bottom:16px;right:18px;text-align:right}
.ref b{color:var(--sect-a);font-weight:600}
.marq{display:flex;align-items:flex-start;gap:12px}
.marq i{width:26px;height:26px;flex:0 0 26px;background:var(--sect-pur);display:block}
.marq i[data-b]{background:var(--r-rare-a)}
.marq span{font-family:var(--tech);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase; color:var(--text-2);line-height:1.7}
.hero{position:relative;min-height:600px;display:grid;align-items:center;margin-bottom:var(--s8)}
.hero__champ{position:absolute;top:0;bottom:104px;left:26%;right:calc(50% - 50vw); background:#0E0E0E;z-index:0}
[data-theme="jour"] .hero__champ{background:#1A1A1A}
.hero__ref{position:absolute;z-index:4;font-family:var(--tech);font-size:9.5px;letter-spacing:.13em; text-transform:uppercase;color:#8E8E8E;line-height:1.7;white-space:pre-line}
.hero__ref.ref--tg{top:22px;left:calc(26% + 24px)}
.hero__ref.ref--bd{bottom:126px;right:24px;text-align:right}
.hero__ref b{color:var(--sect-a);font-weight:600}
.hero__piece{position:absolute;right:2%;top:-52px;bottom:36px;width:38%;z-index:2; display:block;pointer-events:none}
.hero__piece img{width:100%;height:100%;object-fit:contain;opacity:0; filter:drop-shadow(0 34px 44px #000000D9);transition:opacity 700ms var(--e-soft)}
.hero__piece img.ok{opacity:1}
.hero__os{position:relative;z-index:3;background:var(--carte);color:var(--carte-ink); padding:var(--s7);max-width:600px;margin-top:120px;box-shadow:var(--sh-3)}
.hero__os .mono-t{color:var(--carte-ink);font-size:clamp(42px,8vw,104px)}
.hero__rech{width:100%;max-width:400px;height:56px;border-radius:0;padding-left:18px; margin-top:var(--s6);background:transparent;border-color:var(--carte-ink);border-width:1.5px; color:var(--carte-ink-2)}
.hero__rech .kbd{background:var(--carte-2);border-color:var(--carte-rule);color:var(--carte-ink-2)}
.decor{position:absolute;inset:0;pointer-events:none;z-index:2;overflow:hidden}
.decor img{position:absolute;object-fit:contain;filter:drop-shadow(0 22px 30px #000000BF); opacity:0;transition:opacity var(--d-slow) var(--e-soft)}
.decor img.ok{opacity:1}
.decor img:nth-child(1){filter:blur(var(--foc-net)) drop-shadow(0 22px 30px #000000BF)}
.decor img:nth-child(2),.decor img:nth-child(4){filter:blur(var(--foc-proche)) brightness(.8)}
.decor img:nth-child(3),.decor img:nth-child(5){filter:blur(var(--foc-loin)) brightness(.62)}
.damier{background-image: linear-gradient(45deg,var(--surface-2) 25%,transparent 25%,transparent 75%,var(--surface-2) 75%), linear-gradient(45deg,var(--surface-2) 25%,transparent 25%,transparent 75%,var(--surface-2) 75%); background-size:44px 44px;background-position:0 0,22px 22px;opacity:.5}
.boites{display:grid;gap:2px;grid-template-columns:repeat(12,1fr);grid-auto-rows:118px}
.boite{position:relative;overflow:hidden;background:var(--surface);border:1px solid var(--rule); display:flex;flex-direction:column;justify-content:space-between;gap:var(--s3); padding:var(--s4);color:var(--text); transition:transform var(--d-base) var(--e-out),border-color var(--d-base)}
.boite:hover{text-decoration:none;border-color:var(--sect-a);transform:translateY(-3px);z-index:4}
.boite__t{font-family:var(--geo);font-weight:700;text-transform:uppercase;letter-spacing:-.035em; line-height:.92;font-size:clamp(19px,2.3vw,32px);position:relative;z-index:3}
.boite__d{font-size:var(--t-sm);color:var(--text-2);margin-top:9px;max-width:34ch;position:relative;z-index:3}
.boite__n{font-family:var(--tech);font-size:var(--t-xs);letter-spacing:.16em;color:var(--sect-a); font-weight:600;position:relative;z-index:3;flex:0 0 auto}
.boite__bas{position:relative;z-index:3;display:grid;gap:9px}
.boite__viz{position:absolute;right:-5%;bottom:-12%;width:48%;z-index:1;pointer-events:none; transform:rotate(-4deg);transform-origin:bottom right; filter:drop-shadow(0 22px 30px #000000B3); transition:transform var(--d-slow) var(--e-out)}
.boite:hover .boite__viz{transform:rotate(-6deg) scale(1.05)}
.boite__viz img{width:100%;height:auto;object-fit:contain;border-radius:var(--r-sm)}
.boite__bas{max-width:58%}
.boite--large .boite__bas{max-width:64%}
.boite::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none; background:linear-gradient(90deg,var(--surface) 40%,color-mix(in srgb,var(--surface) 55%,transparent) 62%,transparent 82%)}
.boite--os{background:var(--carte);color:var(--carte-ink);border-color:var(--carte-rule)}
.boite--os .boite__d{color:var(--carte-ink-2)}
.boite--os .boite__n{color:var(--carte-lien)}
.boite--os::after{background:linear-gradient(90deg,var(--carte) 40%,color-mix(in srgb,var(--carte) 55%,transparent) 62%,transparent 82%)}
.boite--sect{background:linear-gradient(120deg,var(--sect-pur),var(--sect-fonce));color:var(--sect-sur);border-color:transparent}
.boite--sect .boite__d{color:var(--sect-sur);opacity:.82}
.boite--sect .boite__n{color:var(--sect-sur);opacity:.7}
.boite--sect::after{display:none}
.boite--damier::after{display:none}
.grille>*{transition:opacity var(--d-slow) var(--e-out),transform var(--d-slow) var(--e-out); transition-delay:calc(var(--i,0)*40ms)}
/* 🔴🔴 LOT 111 — MEME FAMILLE, ET CELUI-CI N'ETAIT DANS AUCUNE REMONTEE.
   `.grille>*` partait a `opacity:0` A LA RACINE, et ce qui la rouvre —
   l'animation `monte` portee par `.revele` — vit dans
   `@media (prefers-reduced-motion: no-preference)`. Pour qui a active
   « reduire les animations » dans son systeme, l'etat de depart s'appliquait
   et rien ne l'annulait : LES CARTES DE L'ACCUEIL, DES SETS ET DU MARKET
   ETAIENT INVISIBLES. Le site etait vide pour ces gens, et ils croyaient a
   une panne.
   ⭐⭐⭐ L'ETAT DE DEPART DOIT VIVRE SOUS LA MEME CONDITION QUE L'ANIMATION
   QUI LE LEVE. Ecrits sous deux conditions differentes, ils se separent le
   jour ou l'une des deux ne s'applique pas — et ce jour-la, personne dans
   l'equipe n'est concerne, donc personne ne le voit. */
/* 🔴🔴🔴 LOT 111 — L'ETAT DE REPOS CHANGE DE SELECTEUR, ET C'EST LE POINT.
   Il etait sur `.grille>*` ; ce qui le leve — l'animation `monte` — est sur
   `.revele`, et vit sous `@media (prefers-reduced-motion: no-preference)`.
   Deux selecteurs differents, deux conditions differentes : pour qui a demande
   de reduire les animations, l'etat de repos s'appliquait et RIEN ne le levait.
   LES CARTES DE L'ACCUEIL, DES SETS ET DU MARKET ETAIENT INVISIBLES. Le site
   etait vide pour ces gens, et ils croyaient a une panne.
   ⛔ Personne dans l'equipe n'a ce reglage, donc personne ne l'a vu, donc ce
   defaut n'est dans aucune remontee de Preda. Il a ete trouve par le banc.
   ⭐⭐⭐ LA REPARATION N'EST PAS D'AJOUTER UNE REGLE, C'EST DE POSER L'ETAT DE
   REPOS SUR L'ELEMENT QUI SERA REVELE. `.grille>*` etait un PROXY pour « les
   cartes » ; `.revele` est le vrai marqueur, celui qui porte l'animation.
   Un etat de depart et son animation sur le meme selecteur ne peuvent plus se
   separer — c'est structurel, pas une regle de plus a se rappeler.
   ⭐ `.grille>*` garde la transition et l'echelonnement (`--i`) : c'est la
   grille qui decide de l'ORDRE, l'element qui decide de son ETAT.
   ⭐⭐ Et la moitie `reduce` copie l'idiome de `.flottantes img` (l. 1550),
   deja present dix lignes plus bas. Deux façons de resoudre le meme probleme
   dans une meme feuille, c'est une de trop. */
.revele{opacity:0;transform:translateY(10px)}
@media (prefers-reduced-motion: reduce){ .revele{opacity:1;transform:none} }
@media (max-width:640px){ .decor,  .banniere{display:none!important} }
@media (prefers-reduced-motion: no-preference){ .carte,.col-carte,.tarif,.module{will-change:transform} }
@media (prefers-reduced-motion: reduce){ *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important; transition-duration:.001ms!important;scroll-behavior:auto!important} .ticker__piste{animation:none!important} }
@media (max-width:640px){ .wrap{padding:0 16px} }
/* 🔴 LOT 118 — LA RÈGLE `.nav__liens` À 1040 px A ÉTÉ RETIRÉE D'ICI.
   Elle existait TROIS fois dans cette feuille (l. 1191, l. 1773, et la
   nouvelle). Trois copies d'un seuil qui doit coïncider avec celui du bouton
   de menu, dans un fichier de 2 300 lignes : c'est la configuration exacte qui
   a produit le trou 641–1040 px du lot 111.
   ⭐⭐⭐ ET C'EST LE POINT : j'allais en ajouter une QUATRIÈME sous un
   commentaire disant « ne séparez jamais ces deux lignes ». *Écrire la règle
   et laisser vivre ses contre-exemples, c'est fabriquer l'avertissement qu'on
   citera en le contredisant.* Elle vit désormais en un seul endroit, avec le
   bouton, à la fin de ce fichier — cherchez « LE MENU DEVIENT UN TIROIR ». */
/* ⛔ SUR ETROIT ON NE RETIRE PAS L'APPEL A L'ACTION, ON RETIRE CE QUI L'ENTOURE.
   Le lien « Se connecter » et le code de langue s'effacent ; le bouton reste.
   ⚠️ `display` n'est PAS declare a la racine pour ces deux selecteurs — sinon
   `cascade-aplatie.mjs` aurait raison de crier : une regle d'ecran etroit
   recopiee a la racine gagne partout, et c'est la panne du 31/07. */
@media (max-width:640px){ .h-cta__b{display:none} .globe>summary span{display:none} }
@media (max-width:900px){ .h-rech span,.h-rech .kbd{display:none} .h-rech{min-width:0;width:var(--tap);height:var(--tap);justify-content:center;padding:0;border-color:transparent;background:transparent} }
@media (max-width:820px){ .site-f__cols{grid-template-columns:1fr 1fr} }
@media (max-width:520px){ .site-f__cols{grid-template-columns:1fr} }
@media (max-width:640px){ main.wrap{padding-top:var(--s5)} }
@media (max-width:640px){ .sect-t--gd h2{font-size:clamp(26px,8vw,40px)} }
@keyframes pulse-pli{0%{transform:none}45%{transform:translateY(-3px) scale(1.14)}100%{transform:none}}
@keyframes scintille{to{background-position:-220% 0}}
@media (max-width:520px){ .grille{grid-template-columns:repeat(2,1fr);gap:var(--s3)} }
@media (max-width:700px){ .grille--ligne{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:10px} .grille--ligne>*{flex:0 0 156px;scroll-snap-align:start} }
@media (max-width:1000px){ .c-5{display:none} }
@media (max-width:940px){ .c-4{display:none} }
@media (max-width:760px){ .c-3{display:none} }
@media (max-width:580px){ .c-2{display:none} thead th,tbody td{padding-left:11px;padding-right:11px} .tbl-obj__n,.tbl-obj__s{max-width:19ch} }
@keyframes defile{to{transform:translateX(-50%)}}
@media (prefers-reduced-motion: reduce){ .ticker{overflow-x:auto;scroll-snap-type:x proximity} .ticker__piste{width:auto} .tick{scroll-snap-align:start} }
@keyframes trace{from{stroke-dashoffset:var(--len,2600)}to{stroke-dashoffset:0}}
@media (max-width:560px){ .extremes{grid-template-columns:1fr} }
@supports not (backdrop-filter:blur(1px)){ .verrou__prof{display:none} }
@media (max-width:900px){ .fiche{grid-template-columns:1fr;gap:var(--s5)} }
@media (max-width:900px){ .fiche__viz{position:static;max-width:250px;margin:0 auto} }
@media (max-width:700px){ .murs{grid-template-columns:1fr;gap:var(--s5)} .murs__sep{display:none} }
@media (max-width:560px){ .jauge__l{grid-template-columns:1fr 1fr;gap:var(--s3)} .jauge__e--c{grid-column:1/-1;order:3;justify-items:center;padding-top:8px;border-top:1px solid var(--rule)} }
@media (max-width:640px){ .stats{grid-template-columns:repeat(2,1fr)} .site-h__in{height:56px;gap:10px} }
/* 🔴 LOT 206 (M1, captures mobile du 26/08) — L'ACCROCHE NE SE CLIPPE PLUS.
   A ~390px, « TRAQUEZ CE QUE VOUS AIMEZ » se pliait en 3 lignes de 8,5px dans
   un en-tete fige a 56px : la troisieme ligne etait COUPEE par le bord — une
   devise illisible vaut moins que pas de devise. Sous 640px elle se tait ;
   au-dessus, rien ne change, c'est la ou Preda la voulait (lot 74). ⛔ Ne pas
   agrandir l'en-tete a la place : 56px est le prix d'un ecran de 390px. */
@media (max-width:640px){ .marque__t small{display:none} }
@media (max-width:840px){ .deux-col{grid-template-columns:1fr} }
@media (max-width:900px){ .avec-aside{grid-template-columns:1fr} }
@media (max-width:1040px){ .tarifs{grid-template-columns:repeat(2,1fr)} }
@media (max-width:600px){ .tarifs{grid-template-columns:1fr} }
@media (max-width:640px){ .mono-t{font-size:clamp(32px,9.4vw,50px)} }
@media (max-width:640px){ .banniere{height:150px} }
/* 🔴 LOT 206 (V9 + capture mobile 26/08) — SOUS 560px LA PILE SE TAIT EN
   ENTIER. L'ancienne règle ne gardait que la première vignette : une cover
   seule, sans cadre ni légende, flottait sous l'intro — « orpheline », le mot
   de Preda. Une pile décorative se montre à trois ou pas du tout. */
@media (max-width:560px){ .tete-p__viz{display:none} }
@media (prefers-reduced-motion: no-preference){    }
@media (prefers-reduced-motion: reduce){  }

@media (max-width:900px){  }
@media (max-width:700px){  }
@media (max-width:520px){ .tuiles{grid-template-columns:repeat(2,1fr);gap:9px} }
@media (max-width:820px){ .hero{min-height:0;display:block;padding-top:var(--s5)} }
@media (max-width:820px){ .hero__champ{left:0;right:calc(50% - 50vw);bottom:0;top:0} }
@media (max-width:820px){ .hero__ref{display:none} }
@media (max-width:820px){ .hero__piece{position:relative;inset:auto;width:58%; height:260px;margin:0 auto var(--s5);right:auto;top:auto} }
@media (max-width:820px){ .hero__os{margin-top:0;padding:var(--s5);max-width:none} }
@media (prefers-reduced-motion: no-preference){ .decor img{animation:flotte 9s ease-in-out infinite alternate} .decor img:nth-child(2){animation-duration:11s;animation-delay:-3s} .decor img:nth-child(3){animation-duration:13s;animation-delay:-6s} .decor img:nth-child(4){animation-duration:10s;animation-delay:-1.5s} .decor img:nth-child(5){animation-duration:12s;animation-delay:-4s} }
@keyframes flotte{from{transform:translateY(-8px)}to{transform:translateY(8px)}}
@media (max-width:820px){ .decor img:nth-child(n+4){display:none} }
@media (max-width:900px){ .boites{grid-template-columns:repeat(6,1fr);grid-auto-rows:112px} }
@media (max-width:560px){ .boites{grid-template-columns:repeat(2,1fr);grid-auto-rows:104px;gap:8px} }
@media (prefers-reduced-motion: no-preference){ .revele{animation:monte linear both;animation-timeline:view();animation-range:entry 0% entry 40%} }
@keyframes monte{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ═══════════════════════════════════════════════════════════════════════════
   CLASSES ÉMISES PAR LES GABARITS ET QUE RIEN N'HABILLAIT — 31/07/2026
   ═══════════════════════════════════════════════════════════════════════════
   ⛔⛔ Ces classes sortaient du moteur depuis le premier jour SANS AUCUNE
   RÈGLE, ni dans la maquette ni dans aucun thème. Conséquences vues en ligne :
   la page Articles servait UNE carte de 220 px au milieu du vide, et les
   paliers s'empilaient en pleine largeur au lieu de former une grille.
   ⭐⭐ MON COMPARATEUR LES COMPTAIT COMME « PRÉSENTES » : elles étaient bien
   dans le gabarit. Il vérifiait le mauvais côté du contrat — une classe émise
   sans règle est exactement aussi cassée qu'une classe absente, et elle coûte
   plus cher parce qu'elle a l'air d'être là.
   ⛔ Avant d'ajouter une classe dans un gabarit : lui écrire sa règle, ou ne
   pas l'ajouter. `node outils/css-mort.mjs` refuse désormais l'oubli.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── La grille d'articles (Articles, accueil éditorial) ─────────────────── */
/* ⭐ `auto-fill` et non `auto-fit` : avec UN seul article, `auto-fit` fait
   s'étirer la carte sur toute la largeur — un article de 1 180 px de large.
   `auto-fill` garde les colonnes vides et la carte conserve sa taille. C'est
   exactement le cas du site aujourd'hui : le blog n'a qu'un article. */
.cartes{display:grid;gap:var(--s4);
  grid-template-columns:repeat(auto-fill,minmax(clamp(240px,26vw,300px),1fr));
  margin:var(--s5) 0}
.cartes .item{display:flex;flex-direction:column;gap:var(--s2)}
.cover{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:var(--r-md);
  background:var(--vp-s2);display:block}
/* Un article sans visuel ne laisse pas un trou : la carte se referme. */
.cover:not([src]),.cover[src=""]{display:none}

/* ─── La grille de séries (accueil, Collections) ─────────────────────────── */
.grille--series{display:grid;gap:var(--s4);
  grid-template-columns:repeat(auto-fill,minmax(clamp(190px,20vw,240px),1fr))}

/* ─── La fiche : le socle et son repli ───────────────────────────────────── */
.socle--fiche{aspect-ratio:4/5;width:100%;border-radius:var(--r-lg);overflow:hidden;
  position:relative;display:grid;place-items:center;background:var(--vp-s2)}
/* La gemme n'est PAS une image manquante : c'est la marque explicite qu'aucun
   visuel n'existe pour cette pièce. Elle doit se lire comme un choix. */
.socle__gemme{display:grid;place-items:center;width:46%;color:var(--vp-rule-2)}
.socle__gemme svg{width:100%;height:auto}
.fiche__txt{display:flex;flex-direction:column;gap:var(--s3);min-width:0}

/* ─── Le Marché : le bouton de vue ───────────────────────────────────────── */
.v-b{display:inline-flex;align-items:center;gap:6px;min-height:var(--tap-min);
  padding:0 12px;border:1px solid var(--vp-rule);border-radius:var(--r-full);
  background:none;color:var(--muted);font-family:var(--font-heading);
  font-size:12.5px;font-weight:500;cursor:pointer;
  transition:color var(--d-fast),border-color var(--d-fast),background var(--d-fast)}
.v-b:hover,.v-b:focus-visible{color:var(--text);background:var(--vp-survol)}
.v-b[aria-pressed="true"]{color:var(--primary);border-color:var(--primary);
  background:color-mix(in srgb,var(--primary) 12%,transparent)}

/* ─── Repris du lot 1, supprimées à tort le 31/07 ─────────────────────────
   ⛔ Je les avais classées « noms v3 abandonnés » DE MÉMOIRE. Offre.astro et
   Movers.astro les émettent toujours. ⭐ On ne décide pas qu'un sélecteur est
   mort en se souvenant : on le demande aux gabarits. */
.f-g{position:relative}
.f-g>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:7px;
  min-height:var(--tap-min);padding:0 13px;border-radius:var(--r-full);
  border:1px solid var(--vp-rule-2);background:transparent;color:var(--muted);
  font-family:var(--font-heading);font-size:13px;font-weight:600}
.f-g>summary::-webkit-details-marker{display:none}
.f-g>summary::after{content:"▾";font-size:10px}
.f-g[open]>summary{border-color:var(--primary);color:var(--primary);
  background:color-mix(in srgb,var(--primary) 12%,transparent)}
.f-p{position:absolute;z-index:20;top:calc(100% + 6px);left:0;min-width:230px;
  max-height:min(58vh,380px);overflow:auto;
  background:var(--surface);border:1px solid var(--vp-rule-2);
  border-radius:var(--r-lg);box-shadow:var(--sh-2);padding:var(--s3);
  display:grid;gap:2px}
.f-p label{display:flex;align-items:center;gap:9px;min-height:var(--tap-min);
  padding:0 var(--s2);border-radius:var(--r-md);font-size:13.5px;cursor:pointer}
.f-p label:hover{background:var(--vp-survol)}
.f-raz{min-height:var(--tap-min);padding:0 13px;border:0;background:transparent;
  color:var(--muted);cursor:pointer;font-family:var(--font-heading);font-size:13px;
  text-decoration:underline;text-underline-offset:3px}
.f-cpt{margin:var(--s3) 0 0;font-family:var(--font-heading);font-size:11px;
  font-weight:600;letter-spacing:var(--ls-etiq);text-transform:uppercase;color:var(--muted)}
.f-vide{padding:var(--s6) 0;text-align:center;color:var(--muted)}
.promesses{list-style:none;padding:0;margin:0;display:grid;gap:var(--s3);max-width:70ch}
.promesses li{position:relative;padding-left:26px;font-size:15px;line-height:1.55}
.promesses li::before{content:"—";position:absolute;left:0;top:0;
  color:var(--primary);font-weight:700}

/* ═══════════════════════════════════════════════════════════════════════════
   LE BOUTON JOUR / NUIT — 31/07/2026
   ═══════════════════════════════════════════════════════════════════════════
   ⛔⛔ `vitrine` N'AVAIT AUCUNE REGLE POUR `.bascule`. Le moteur emet
   `<button class="bascule"></button>` — un bouton VIDE, que le theme devait
   habiller. Sans regle : un tiret gris de 8 px entre la recherche et les
   langues. Aucune erreur, aucun build rouge — la classe emise sans regle,
   exactement le defaut que ce projet paie depuis le lot 12.
   ⭐ `encyclopedie` l'habillait (4 regles) : le bouton MARCHAIT sur vevewiki
   et pas sur veveprice. « Corrige sur un site » n'est pas « corrige ».

   ⭐⭐ ICONE EN MASQUE SVG, PAS EN GLYPHE. `encyclopedie` utilise
   `content:"☾"` / `content:"☀"`. C'est court et lisible, mais ces deux
   caracteres sont HORS du sous-ensemble latin d'Archivo : ils partent dans la
   pile de repli, et sur une machine qui n'a pas de fonte a symboles ils
   sortent en CARRE VIDE — sans erreur, la encore. Un masque SVG ne depend
   d'aucune fonte, herite de `currentColor`, et pese moins qu'une requete. */
.bascule{
  width:var(--tap-min);height:var(--tap-min);flex:0 0 auto;cursor:pointer;
  display:inline-grid;place-items:center;padding:0;
  border:1px solid var(--rule);border-radius:var(--r-md);
  background:var(--surface-2);color:var(--text-2);
  transition:border-color var(--d-fast) var(--e-soft),color var(--d-fast) var(--e-soft),
             background var(--d-fast) var(--e-soft);
}
.bascule::before{
  content:"";width:16px;height:16px;background:currentColor;
  /* lune — l'action proposee quand on est en JOUR */
  -webkit-mask:var(--i-lune) center/16px 16px no-repeat;
          mask:var(--i-lune) center/16px 16px no-repeat;
}
:root[data-theme="nuit"] .bascule::before{
  /* soleil — l'action proposee quand on est en NUIT.
     ⭐ Le bouton montre TOUJOURS ce vers quoi il emmene, jamais l'etat
     courant : un bouton qui affiche l'etat se lit comme un interrupteur
     deja actionne, et on clique dans le mauvais sens une fois sur deux. */
  -webkit-mask:var(--i-soleil) center/16px 16px no-repeat;
          mask:var(--i-soleil) center/16px 16px no-repeat;
}
.bascule:hover{border-color:var(--sect-pur);color:var(--text);background:var(--surface-3)}
.bascule:focus-visible{outline:var(--foc-proche) solid var(--sect-pur);outline-offset:2px}

/* Les langues au pied de page (identity.langues_dans: pied). */
.f-langues{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.f-langues .etiq{width:100%;color:var(--muted)}
.f-langues .tag[aria-current]{
  border-color:var(--sect-pur);color:var(--text);background:var(--sect-1v);font-weight:600;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LE CADRE — le contenu décollé des bords  (31/07/2026)
   ═══════════════════════════════════════════════════════════════════════════
   ⭐ Demande de Preda : « j'aimerais que les pages soient décollées sur chaque
   côté, je trouve que ça donne plus d'identité au site ». C'est aussi ce que
   la maquette montre depuis toujours — son `.vp` est un panneau posé sur un
   vide plus sombre, et c'est ce vide qui fait le cadre.

   ⭐⭐ ET CE CADRE PORTE DEUX CHOSES QU'ON AVAIT PERDUES EN PORTANT LE CSS.
   Dans la maquette, `.vp` est `position:relative` et vit dans un
   `.mk-frame{overflow:hidden}`. Le thème n'avait ni l'un ni l'autre :
     · sans bloc de positionnement, `.hero__champ{right:calc(50% - 50vw)}`
       se calcule contre un ancêtre imprévu ;
     · sans rognage, ce qui déborde à droite POUSSE LA PAGE et crée la barre
       de défilement horizontale.
   On avait vu la 3ᵉ chose que `.vp` portait (le `container-name`, corrigé au
   lot 15) et manqué les deux autres. ⭐ Un élément supprimé emporte TOUT ce
   qu'il portait, pas seulement ce pour quoi on le connaissait.
   ⚠️ `overflow-x:clip` et non `hidden` : `hidden` crée un contexte de
   défilement qui casse `position:sticky` à l'intérieur. `clip` rogne sans
   rien rendre défilable. */
:root{ --cadre-max:1520px; --cadre-marge:var(--s5); }
body{ background:#0E0E0E; }
body > header.site,
body > main,
body > footer.site{
  max-width:var(--cadre-max);
  margin-inline:auto;
  background:var(--bg);
}
/* ⛔ On ne rogne QUE `main`. Rogner l'en-tête tuerait tout menu déroulant
   qui en sort (le menu du compte de la maquette). */
body > main{ position:relative; overflow-x:clip; }
body > header.site{ margin-top:var(--cadre-marge); }
body > footer.site{ margin-bottom:var(--cadre-marge); }
@media (max-width:900px){
  /* Sur mobile le cadre mange de la largeur utile pour rien : on le retire. */
  :root{ --cadre-marge:0px; }
  body > header.site, body > main, body > footer.site{ max-width:none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   [hidden] — CE QUE LE MOTEUR CACHE DOIT RESTER CACHÉ  (31/07/2026)
   ═══════════════════════════════════════════════════════════════════════════
   🔴 LE THÈME N'AVAIT AUCUNE RÈGLE POUR `[hidden]`. La feuille du navigateur
   dit `[hidden]{display:none}` — une règle de spécificité (0,1,0) qu'une
   simple classe (0,1,0) déclarée APRÈS écrase. Neuf classes du thème posent
   un `display:` et gagnaient donc contre l'attribut :
     .tuiles .socle__fond .socle__gemme .socle__ext .hero__piece
     .logo .cadenas .col-carte__pile .tete-p__viz
   VISIBLE EN PRODUCTION : /movers/ affichait LE TABLEAU **ET** LA GRILLE en
   même temps — la bascule Tableau/Tuiles pose bien `hidden`, le CSS l'ignorait.
   ⭐⭐ Aucune erreur, aucun build rouge : le moteur avait raison, le thème
   aussi, et c'est la CASCADE entre les deux qui donnait le mauvais résultat.
   Encore « est-ce là ? » contre « est-ce ce qui gagne ? ».
   ⭐ `!important` est ici le bon outil, pas un raccourci : `hidden` est une
   intention du DOM, elle ne se négocie pas avec une règle de présentation. */
[hidden]{ display:none !important; }

/* Les compteurs sous les quatre boîtes : ils étaient collés au bloc. */
.boites + .stats{ margin-top:var(--s5); }

/* ⛔⛔ `.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,var(--geo));font-weight:700;
  font-size:var(--t-lg);line-height:1.3;letter-spacing:var(--ls-titre);
  color:var(--text);margin:0 0 6px;
}
.item .s{
  display:block;font-family:var(--tech);font-size:var(--t-2xs);
  letter-spacing:var(--ls-etiq);text-transform:uppercase;color:var(--muted);
}
.item .lead{font-size:var(--t-sm);margin:10px 0 0;color:var(--text-2)}
.item:hover .n{color:var(--sect-a)}

/* ═══════════════════════════════════════════════════════════════════════════
   L'EN-TÊTE PORTAIT DEUX HABILLAGES (31/07/2026)
   ═══════════════════════════════════════════════════════════════════════════
   Le moteur emet `<header class="site site-h">` — une classe pour le socle
   generique (`header.site`, que servent aurora et encyclopedie) et une pour la
   maquette (`.site-h`). Les DEUX s'appliquaient :
     · deux `background` en color-mix empiles (l'un sur --bg, l'autre --nuit) ;
     · deux `backdrop-filter:blur()` l'un sur l'autre ;
     · deux `z-index` (10 et 60) ;
     · et surtout `header.site .wrap{flex-wrap:wrap}` contre
       `.site-h__in{display:flex;height:64px}` — d'ou l'en-tete qui passait sur
       DEUX lignes et debordait du cadre.
   ⭐⭐ AUCUNE DES DEUX REGLES N'EST FAUSSE. C'est leur SOMME qui l'est. Une
   classe de compatibilite laissee en place « au cas ou » n'est pas neutre :
   elle habille. Meme famille que `[hidden]` du lot 19 — le defaut ne vit dans
   aucun des deux fichiers, il vit entre eux.
   ⛔ On ne retire pas `site` du gabarit : aurora et encyclopedie en dependent,
   et `css-mort` exige `header.site` dans le socle de CHAQUE theme. On
   NEUTRALISE la couche generique ici, ou l'on sait qu'elle fait double emploi.
   Specificite (0,2,1) : gagne sur `header.site` (0,1,1) comme sur `.site-h`. */
header.site.site-h{
  background:color-mix(in srgb,var(--nuit) 90%,transparent);
  z-index:60;
}
header.site.site-h .wrap{
  flex-wrap:nowrap;      /* ⛔ c'est CE `wrap` qui cassait l'en-tete en deux */
  min-height:0;
  gap:var(--s4);
}

/* ⛔⛔ LA PAGE ETAIT PLUS ETROITE QUE SON EN-TETE (31/07/2026).
   Le cadre du lot 19 pose `--cadre-max:1520px` sur l'en-tete, le contenu et le
   pied. Mais `.wrap` — le conteneur interne, herite du socle du moteur —
   plafonne a 1220px. L'en-tete DESSINE donc son fond sur 1520 pendant que le
   contenu vit dans 1220 : 150 px de vide de chaque cote, et une barre
   superieure visiblement plus large que la page.
   ⭐ DEUX PLAFONDS SUR LE MEME AXE, ET AUCUN DES DEUX N'EST FAUX. 1220 etait
   le bon chiffre AVANT le cadre ; 1520 est le bon depuis. Ajouter une
   contrainte sans retirer celle qu'elle remplace laisse les deux en vigueur —
   et c'est la plus SERREE qui gagne, en silence.
   ⛔⛔ 01/08/2026 — CETTE NEUTRALISATION EST SUPPRIMEE, PAS CORRIGEE.
   Elle produisait le defaut INVERSE : `<main class="wrap">` PORTE la classe,
   donc `.wrap{max-width:none}` (0,1,0) battait `body > main` (0,0,2) et le
   contenu n'avait plus de cadre du tout. Le plafond de 1220 est desormais
   retire A LA SOURCE (voir plus haut). Une seule declaration, plus de duel. */

/* ⛔ `.flat` — LA VARIATION NULLE N'AVAIT AUCUNE REGLE (31/07/2026).
   Le tableau ecrit `class:list={['n', … : 'flat']}` : `up` est vert, `down`
   est rose, et `flat` ne recevait RIEN. Un « 0,0 % » sortait donc dans la
   couleur du texte courant, c'est-a-dire aussi affirme qu'une vraie hausse.
   ⭐ L'absence de mouvement est une information, mais c'est la MOINS
   importante des trois : elle doit se lire sans attirer l'oeil. */
.flat, td.flat .num, td.flat{ color:var(--muted); }

/* ═══════════════════════════════════════════════════════════════════════════
   ⑮ L'INSCRIPTION — champ de profondeur + formulaire.        LOT 42, 03/08/2026
   ═══════════════════════════════════════════════════════════════════════════
   ⛔ CE BLOC N'EXISTE QUE DANS `vitrine`, ET C'EST DÉLIBÉRÉ.
   `panneau`, `champ`, `etiq`, `logo`, `centre`, `respire` ont ZÉRO règle dans
   `encyclopedie` et `aurora` — mesuré le 03/08, pas supposé. Porter le décor
   dans les trois thèmes reviendrait à réclamer à l'encyclopédie le vocabulaire
   de la vitrine : c'est le grief exact des 172 lignes du 31/07.
   ⭐ Le contrat tient dans l'autre sens : les classes `inscr__*` ci-dessous ont
   TOUTES une règle ici. Une classe émise sans règle coûte plus cher qu'une
   classe absente — elle a l'air d'être là.

   ⚠️ LA MAQUETTE ÉCRIVAIT `@container vp (max-width:700px)`. Repris tel quel,
   ce serait une règle MORTE : aucun `container-name: vp` n'est déclaré nulle
   part dans ce dépôt (vérifié sur les 3 thèmes et sur Base.astro). Elle aurait
   eu l'air présente et n'aurait jamais rien coupé. → `@media`. */

/* ── LE CHAMP DE PROFONDEUR ───────────────────────────────────────────────
   ⭐ DEUX LOIS D'OPTIQUE, PAS DES RÉGLAGES DÉCORATIFS : la vitesse est
   proportionnelle à la taille (parallaxe) et le flou à la distance à la
   focale. C'est ce couple qui fait lire « profondeur » au lieu d'« animation ».
   ⚠️ `position:fixed` et pas `absolute` : le champ doit occuper la FENÊTRE. Un
   `absolute` reste prisonnier du premier ancêtre positionné, et il y en a
   toujours un — la maquette a payé ce défaut, les pièces traversaient un
   couloir de 470 px au lieu de la page. */
.flottantes{ position:fixed; inset:0; pointer-events:none; z-index:0; overflow:hidden; }
.flottantes img{ position:absolute; object-fit:contain; opacity:0; will-change:transform,opacity; }

/* Plan LOIN — petit, flou léger, sombre, très lent : il dérive à peine. */
.flottantes img[data-p="1"]{ filter:blur(var(--foc-proche)) brightness(.42); z-index:1; }
/* Plan MOYEN — net : c'est le plan de mise au point. */
.flottantes img[data-p="2"]{ filter:blur(var(--foc-net)) brightness(.86)
  drop-shadow(0 16px 22px #000000B3); z-index:2; }
/* Plan PRÈS — grand et très flou. Il est HORS focale, donc il passe devant sans
   jamais capter l'oeil : c'est ce qui empêche le décor de voler la vedette au
   formulaire. */
.flottantes img[data-p="3"]{ filter:blur(var(--foc-loin)) brightness(.6); z-index:3; }

/* ⚠️ AUCUNE ANIMATION NE CHANGE L'ÉCHELLE. Une pièce qui grandit sur place
   ressemble à un zoom d'appareil photo — un mouvement de CAMÉRA, que l'oeil lit
   comme un défaut de rendu. Seul le déplacement porte le mouvement.
   ⭐ `.ok` n'est posé que par `onload` : une image qui n'est jamais arrivée ne
   s'anime pas, elle reste à `opacity:0`. Le décor ne clignote pas en attendant
   le réseau. */
@media (prefers-reduced-motion: no-preference){
  .flottantes img.ok[data-p="1"]{ animation:vp-trav-loin  var(--dur) linear var(--dl) infinite both; }
  .flottantes img.ok[data-p="2"]{ animation:vp-trav-moyen var(--dur) linear var(--dl) infinite both; }
  .flottantes img.ok[data-p="3"]{ animation:vp-trav-pres  var(--dur) linear var(--dl) infinite both; }
}
/* ⭐ Qui refuse le mouvement garde la profondeur : les pièces restent posées,
   simplement immobiles. Retirer le décor entier punirait le réglage. */
@media (prefers-reduced-motion: reduce){ .flottantes img.ok{ opacity:.35; } }

@keyframes vp-trav-loin{
  0%{ opacity:0; transform:translate3d(0,34px,0) rotate(-3deg); }
  22%{ opacity:.55; } 78%{ opacity:.55; }
  100%{ opacity:0; transform:translate3d(-26px,-34px,0) rotate(3deg); }
}
@keyframes vp-trav-moyen{
  0%{ opacity:0; transform:translate3d(0,72px,0) rotate(4deg); }
  18%{ opacity:1; } 82%{ opacity:1; }
  100%{ opacity:0; transform:translate3d(-58px,-72px,0) rotate(-4deg); }
}
@keyframes vp-trav-pres{
  0%{ opacity:0; transform:translate3d(0,150px,0) rotate(-6deg); }
  14%{ opacity:.5; } 86%{ opacity:.5; }
  100%{ opacity:0; transform:translate3d(-120px,-150px,0) rotate(6deg); }
}

/* Sous 900 px le plan PRÈS mange l'écran ; sous 700 px il n'y a plus de marge
   latérale du tout et le décor passerait derrière le formulaire au lieu
   d'autour. On le retire, on ne le rétrécit pas. */
@media (max-width:900px){ .flottantes img[data-p="3"]{ display:none; } }
@media (max-width:700px){ .flottantes{ display:none; } }

/* ── LE FORMULAIRE ────────────────────────────────────────────────────────── */
.inscr__tete{ text-align:center; display:grid; gap:12px; justify-items:center; }
/* ⛔ PAS `mono-t` ICI. Ce titre-là fait `clamp(38px,7.2vw,96px)` : sur un
   panneau de 470 px, « Créer un compte » passerait à la ligne au milieu du
   mot. La maquette pose d'ailleurs `font-size:var(--t-xl)` en dur au même
   endroit — elle avait vu le même mur. */
.inscr__h1{ font-family:var(--geo); font-size:var(--t-xl); font-weight:800;
  letter-spacing:-.02em; line-height:1.15; margin:0; }

/* ⚠️ Le bandeau d'avertissement emprunte la couleur du CADENAS, pas celle de
   l'erreur : rien n'est cassé, la fonction n'est pas encore ouverte. Un rouge
   ici ferait croire à une panne du site. */
.inscr__avis{ margin:var(--s4) 0 0; padding:12px 14px; border-radius:var(--r-md);
  background:var(--lock-1v); border:1px solid var(--lock);
  font-size:var(--t-sm); line-height:1.55; color:var(--text-2); }
.inscr__avis b{ color:var(--text); }

.inscr__form{ display:grid; gap:var(--s3); margin-top:var(--s5); }

.inscr__cgu{ display:flex; gap:10px; align-items:flex-start; margin-top:5px;
  font-size:var(--t-sm); line-height:1.5; color:var(--text-2); }
/* ⭐ 16 px et pas plus : au-delà, une case à cocher cesse d'avoir l'air d'une
   case. `accent-color` suffit — repeindre une case avec un pseudo-élément lui
   fait perdre son comportement clavier. */
.inscr__cgu input{ width:16px; height:16px; margin-top:3px; flex:0 0 16px;
  accent-color:var(--sect-pur); }
.inscr__cgu a{ color:var(--sect-a); }

.inscr__valider{ width:100%; margin-top:var(--s2); }

.inscr__filet{ height:1px; background:var(--rule); margin:var(--s5) 0; }
.inscr__pied{ text-align:center; font-size:var(--t-sm); color:var(--muted); margin:0; }
.inscr__pied a{ color:var(--sect-a); }

/* ── CE QUE LE COMPTE OUVRE ───────────────────────────────────────────────── */
.inscr__ouvre{ margin-top:var(--s4); padding:var(--s4); }
.inscr__liste{ list-style:none; padding:0; margin:12px 0 0; display:grid; gap:9px;
  font-size:var(--t-sm); color:var(--text-2); }
.inscr__liste li{ display:flex; gap:10px; align-items:flex-start; }
.inscr__oui{ color:var(--sect-a); flex:0 0 auto; }
.inscr__clos{ flex:0 0 auto; }
/* ⭐ LA LIGNE VERROUILLÉE EST GRISE, PAS BARRÉE. Barrer dirait « supprimé » ;
   gris dit « existe, ailleurs ». C'est toute la différence entre frustrer et
   vendre. */
.inscr__non{ color:var(--muted); }
.inscr__paliers{ margin:var(--s4) 0 0; }

/* ═══════════════════════════════════════════════════════════════════════════
   ⑯ LA CELLULE À DEUX LIGNES — le Marché VeVe / StackR.  LOT 43, 03/08/2026
   ═══════════════════════════════════════════════════════════════════════════
   ⭐ `.m2` empile deux valeurs DANS une cellule : ligne du haut = VeVe, ligne
   du bas = StackR. Le tableau garde donc UN `<tr>` par pièce — ce qui compte,
   parce que tout le filtrage et le compteur de résultats comptent des `<tr>`.

   ⛔ CE BLOC N'EXISTE QUE DANS `vitrine`, comme le décor du lot 42. Les pages
   de prix n'existent que sur un site à `data_modules` non vide, et le seul
   aujourd'hui porte ce thème. Le jour où un site de prix prend `aurora`, ces
   règles devront y être portées — c'est écrit ici pour qu'on le sache. */
.m2{ display:grid; gap:2px; }
.m2__a{ line-height:1.25; }
/* ⭐ LA SECONDE LIGNE EST PLUS PETITE ET PLUS PÂLE, ET C'EST DE L'INFORMATION.
   Deux lignes de même poids se liraient comme deux pièces différentes ; une
   hiérarchie dit « même objet, second marché ». */
.m2__b{ font-size:var(--t-xs); color:var(--muted); line-height:1.25; }

/* ⭐⭐ LE TIRET EN ATTENTE SE DISTINGUE DU TIRET « RIEN ».
   Un « — » qui veut dire « aucune offre » et un « — » qui veut dire « pas
   encore collecté » sont l'inverse l'un de l'autre. Le second est donc
   souligné en pointillés : on voit qu'il y a quelque chose à savoir, et le
   `title` le dit au survol comme au clavier.
   ⚠️ `text-decoration` et pas une couleur : une couleur seule serait invisible
   pour un daltonien, et sur une colonne de chiffres elle passerait pour un
   état de marché. */
[data-attente]{ text-decoration:underline dotted currentColor; text-underline-offset:3px;
  cursor:help; opacity:.75; }

/* La colonne des liens n'a pas à être aussi large que le nom d'une pièce. */
.tbl-hote td .m2__a, .tbl-hote td .m2__b{ white-space:nowrap; }

/* ═══════════════════════════════════════════════════════════════════════════
   ⑰ LES MODULES DU GRAND LIVRE — Analytics.               LOT 44, 03/08/2026
   ═══════════════════════════════════════════════════════════════════════════
   ⭐ `.led__hote` est le conteneur que le script remplit après réponse de
   `/api/analytics/`. Il porte une règle parce qu'il est ÉMIS : une classe
   émise sans règle coûte plus cher qu'une classe absente — elle a l'air d'être
   là. C'est le contrat gabarit ↔ thème, et il vaut aussi pour trois lignes.

   ⚠️ `min-height` et pas `height` : le bloc contient successivement « chargement »,
   puis un cadenas, puis un tableau de douze lignes. Une hauteur fixe ferait
   sauter la page à chaque réponse d'API — et sur quatre modules qui répondent
   dans un ordre imprévisible, la page danserait sous le curseur. */
.led__hote{ min-height:44px; display:grid; align-content:start; gap:var(--s3); }
/* Les tableaux servis par l'API n'ont pas de largeur imposée : ils tiennent la
   colonne de leur panneau, et débordent en défilement plutôt qu'en écrasant
   les colonnes de chiffres. */
.led__hote .tbl-hote{ overflow-x:auto; }
.led__hote code{ font-family:var(--tech); font-size:var(--t-xs); color:var(--text-2); }


/* ═══════════════════════════════════════════════════════════════════════════
   LOT 68 — 05/08/2026 · retours de Preda sur veveprice
   ═══════════════════════════════════════════════════════════════════════════
   ⛔ TOUT CE QUI SUIT EST EN FIN DE FICHIER, ET C'EST VOLONTAIRE. À
   spécificité égale, c'est l'ordre de source qui tranche : écrites plus haut,
   la moitié de ces règles auraient été « là » sans jamais « gagner ». C'est le
   défaut le plus cher de ce thème, il a déjà coûté trois sessions.
   ⭐ Aucune classe neuve inventée : on habille des sélecteurs que les gabarits
   émettent, ou on étend un vocabulaire déjà porté par le thème.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────────────────
   1. UNE COULEUR PAR PAGE  — « la ligne du header doit prendre celle de la page »
   ───────────────────────────────────────────────────────────────────────────
   Le mécanisme existait déjà et il est intact : `Base.astro` pose
   `data-sect` sur <body>, `.site-h::after` (l. 412) peint la ligne de 3 px
   avec `--sect-pur`, et `[data-sect]{--cyan:var(--sect-a)}` (l. 373) fait
   suivre tout ce qui consommait le cyan. On n'ajoute donc QUE des palettes.
   ⚠️ CINQ VARIABLES PAR SECTION, JAMAIS QUATRE :
     --sect-a     la couleur du TEXTE et des liens  → doit passer 4,5:1 sur le fond
     --sect-pur   la couleur PLEINE (ligne du header, pastilles, segments actifs)
     --sect-sur   l'encre POSÉE SUR `--sect-pur`    → doit passer 4,5:1 sur elle
     --sect-fonce le bas des dégradés
     --sect-1v    le voile (fond des états actifs)
   ⭐ `--sect-a` et `--sect-pur` DIFFÈRENT en thème jour, et ce n'est pas une
   coquetterie : une couleur assez vive pour une ligne de 3 px est illisible en
   texte de 14 px. La même distinction existe déjà pour le cyan (l. 327-329) ;
   la reproduire ici évite de repayer la leçon cinq fois. */
[data-sect="tableau"]  {--sect-a:#10CEF2;--sect-pur:#10CEF2;--sect-sur:#1A1A1A;--sect-fonce:#0A8FA9;--sect-1v:#10CEF21F}
[data-sect="blog"]     {--sect-a:#ED8E00;--sect-pur:#ED8E00;--sect-sur:#1A1A1A;--sect-fonce:#895200;--sect-1v:#ED8E0024}
[data-sect="sets"]     {--sect-a:#6BB6FC;--sect-pur:#0082FA;--sect-sur:#1A1A1A;--sect-fonce:#004B91;--sect-1v:#0082FA24}
[data-sect="offre"]    {--sect-a:#E3B341;--sect-pur:#D4A017;--sect-sur:#1A1A1A;--sect-fonce:#8A6608;--sect-1v:#D4A01726}
[data-sect="analytics"]{--sect-a:#C08BF8;--sect-pur:#A855F7;--sect-sur:#FFFFFF;--sect-fonce:#6B21A8;--sect-1v:#A855F726}
/* Thème jour : `--sect-a` s'assombrit, `--sect-pur` ne bouge pas. */
[data-theme="jour"] [data-sect="tableau"]  {--sect-a:#08687A;--sect-pur:#10CEF2;--sect-sur:#1A1A1A;--sect-fonce:#0A8FA9;--sect-1v:#10CEF233}
[data-theme="jour"] [data-sect="blog"]     {--sect-a:#8A5300;--sect-pur:#ED8E00;--sect-sur:#1A1A1A;--sect-fonce:#895200;--sect-1v:#ED8E0033}
[data-theme="jour"] [data-sect="sets"]     {--sect-a:#005FB5;--sect-pur:#0082FA;--sect-sur:#1A1A1A;--sect-fonce:#0060B7;--sect-1v:#0082FA33}
[data-theme="jour"] [data-sect="offre"]    {--sect-a:#6F5200;--sect-pur:#D4A017;--sect-sur:#1A1A1A;--sect-fonce:#8A6608;--sect-1v:#D4A01733}
[data-theme="jour"] [data-sect="analytics"]{--sect-a:#6B21A8;--sect-pur:#A855F7;--sect-sur:#FFFFFF;--sect-fonce:#6B21A8;--sect-1v:#A855F733}

/* ───────────────────────────────────────────────────────────────────────────
   2. LE CONTENU DESCEND JUSQU'AU PIED DE PAGE
   ───────────────────────────────────────────────────────────────────────────
   Sur une page courte (une fiche sans historique, un blog à un article, un
   filtre qui ne rend rien), le pied de page remontait au milieu de l'écran et
   laissait un bandeau de fond nu en dessous. Ce n'est pas un espacement à
   régler : c'est que rien ne disait au contenu d'occuper la hauteur restante.
   ⭐ `100dvh` et non `100vh` : sur mobile, `vh` compte la barre d'adresse
   rétractée, donc `100vh` fabrique un débordement d'une soixantaine de pixels
   qu'on ne voit que sur un vrai téléphone. `dvh` suit la barre.
   ⚠️ `flex:1 0 auto` sur `main` seulement. Les autres enfants de <body> gardent
   leur hauteur naturelle ; `flex-shrink:0` empêche l'en-tête et le pied d'être
   comprimés quand le contenu déborde vraiment. */
body{ min-height:100dvh; display:flex; flex-direction:column; }
body > header.site, body > footer.site{ flex:0 0 auto; }
body > main{ flex:1 0 auto; }

/* ───────────────────────────────────────────────────────────────────────────
   3. LE DÉPLIANT DE NAVIGATION  (voir le commentaire de src/layouts/Base.astro)
   ───────────────────────────────────────────────────────────────────────────
   ⭐ LE MÊME SEUIL QUE `.nav__liens`, ÉCRIT JUSTE EN DESSOUS. Deux seuils qui
   doivent coïncider et qui vivent à 400 lignes d'écart finissent par diverger —
   c'est exactement ce qui a créé le trou 641-1040 qu'on répare ici. */
/* 🔴🔴 LOT 111 — L'ACCORDEON EST VISIBLE A TOUTE LARGEUR, ET IL EST A GAUCHE.
   Demande de Preda (09/08) : « quelle que soit la resolution, un symbole
   accordeon dans le header, tout a gauche avant le logo ».
   ⭐⭐⭐ ET CA SUPPRIME UN INTERVALLE MORTEL. Avant : au-dessus de 1040 px le
   depliant etait `display:none` et la nav complete s'affichait ; en dessous,
   la nav disparaissait et le depliant prenait le relais — SAUF qu'il etait
   transparent (voir l. 512). Sous 1040 px, il ne restait donc AUCUN chemin
   visible vers le Market, les Sets ou l'Abonnement. Une largeur de fenetre
   suffisait a rendre la moitie du site inatteignable, et rien ne le disait.
   ⛔ ON NE GARDE PAS DEUX MENUS. Le depliant portait DEJA la liste entiere ;
   l'afficher partout ne double pas la navigation, il lui donne un seul point
   d'entree stable. Les deux lisent `menuComplet` — meme source, aucune
   divergence possible.
   ⚠️ `.nav__liens` garde son seuil : au-dessus de 1040 px les liens rapides
   restent, l'accordeon est un RACCOURCI vers la liste complete, pas un
   remplacant. */
/* 🔴 LOT 118 — LES TROIS RÈGLES QUI ÉTAIENT ICI ONT DÉMÉNAGÉ EN FIN DE
   FICHIER, ensemble : `.nav__deplie{display:block}`, le seuil `.nav__liens`,
   et l'ancrage à gauche du panneau. Le panneau est devenu un TIROIR
   (`position:fixed`), donc `.nav__deplie .deplie__m{left:0}` n'a plus d'objet
   — un enfant positionné en `fixed` ne s'ancre plus sur son parent.
   ⛔ Laisser cette règle ici aurait été pire qu'inutile : elle porte un
   `min-width:min(260px,78vw)` qui aurait combattu la largeur du tiroir, avec
   une spécificité PLUS FORTE (deux classes contre une). *« Est-ce là ? » et
   « est-ce ce qui gagne ? » sont deux questions* — et une règle qu'on croit
   morte parce qu'on a déplacé son voisin est toujours vivante. */
/* ⛔ Sous 420 px, le libelle « Menu » part et le bouton devient une pastille
   de la meme famille que la recherche et le globe — pas une quatrieme forme. */
@media (max-width:420px){
  .nav__deplie .deplie__b > span{ display:none; }
  .nav__deplie .deplie__b{ width:38px; padding:0; justify-content:center; }
}

/* ───────────────────────────────────────────────────────────────────────────
   4. LES CASES D'ARTICLE DU BLOG RESPIRENT
   ───────────────────────────────────────────────────────────────────────────
   ⛔ `.boites` GARDE SON `gap:2px`, et il le doit : sur l'accueil c'est une
   MOSAÏQUE — quatre surfaces jointives qui forment un seul bloc. Élargir le
   gap là-bas déferait le dessin de la maquette.
   ⭐ Le blog n'est pas une mosaïque, c'est une LISTE de cartes : même grille,
   autre intention, donc une variante et pas une retouche. */
.boites--blog{ gap:var(--s4); grid-auto-rows:136px; }
@media (max-width:560px){ .boites--blog{ gap:var(--s3); } }
/* 🔴 LOT 206 (M2, capture mobile 26/08) — SOUS 560px UNE CARTE D'ARTICLE SUIT
   SON CONTENU. Les empans de grille des cartes du blog sont EN LIGNE dans le
   gabarit (mode vitrine comme mode dégradé) : à 390px, « span 6 / row span 2 »
   donnait ~280px de haut pour un titre et une date — le grand champ vide de
   sa capture. Un style en ligne ne se plie qu'à `!important` — précédent
   assumé du thème : `.decor,.banniere` à 640px. Le desktop ne change pas. */
@media (max-width:560px){ .boites--blog>.boite{grid-column:1/-1!important;grid-row:auto!important;min-height:136px} }

/* ───────────────────────────────────────────────────────────────────────────
   5. ACCUEIL — L'ESPACE ENTRE « À L'AFFICHE » ET LES DEUX COLONNES
   ───────────────────────────────────────────────────────────────────────────
   Les deux titres de `.deux-col` portent `margin-top:0` (sinon ils se
   décalaient l'un de l'autre), si bien que le bloc se collait à la grille du
   dessus : `.sect-t--gd` donnait son `var(--s8)` à tous les autres titres et à
   aucun de ceux-là. L'espace appartient donc au BLOC, pas à son titre. */
.grille + .deux-col{ margin-top:var(--s8); }

/* ───────────────────────────────────────────────────────────────────────────
   6. ACCUEIL — « HAUSSES » ET « BAISSES » DÉSAXÉES SELON LA LANGUE
   ───────────────────────────────────────────────────────────────────────────
   🔴 Signalé par Preda, et invisible en français. « Plus fortes hausses » tient
   sur une ligne, « Größte Kursrückgänge (7 Tage) » sur deux : la grille de
   droite démarrait un titre plus bas que celle de gauche. Le défaut n'est donc
   pas dans la mise en page — il est dans le fait qu'elle dépende de la
   LONGUEUR D'UNE TRADUCTION.
   ⭐⭐ `subgrid` répond exactement à ça : les deux sections partagent les
   RANGÉES de leur parent, donc les deux titres occupent la même hauteur et les
   deux grilles commencent à la même ligne — quelle que soit la langue.
   ⚠️ REPLI SILENCIEUX ET SÛR : là où `subgrid` manque, la déclaration entière
   est invalide et ignorée, on retombe sur le rendu d'aujourd'hui. Aucune page
   ne casse, elle se désaxe comme avant. */
.deux-col{ grid-template-rows:auto 1fr; align-items:start; }
.deux-col > section{ grid-row:span 2; display:grid; grid-template-rows:subgrid; gap:var(--s5); }
.deux-col > section > .sect-t{ align-self:end; }
@media (max-width:840px){
  /* En une colonne il n'y a plus rien à aligner : on rend la main. */
  .deux-col{ grid-template-rows:none; }
  .deux-col > section{ grid-row:auto; grid-template-rows:none; }
}

/* ───────────────────────────────────────────────────────────────────────────
   7. LA BARRE DE FILTRES — panneaux, tri, et le compteur qui ne mentait plus
   ───────────────────────────────────────────────────────────────────────────
   ⭐ `.f-b[aria-expanded="true"]` était DÉJÀ habillé (l. 740) et ne s'allumait
   jamais : le gabarit employait `<details><summary class="f-b">`, or un
   `<summary>` n'a pas d'attribut `aria-expanded` — il l'expose à l'arbre
   d'accessibilité, pas au DOM, donc le sélecteur d'attribut ne le voit pas.
   Le bouton du groupe ouvert restait gris. Corrigé côté gabarit (vrais
   `<button aria-expanded>`), rien à changer ici.
   Ce qui suit n'ajoute que ce que la maquette montre et que le thème n'avait
   pas : la rangée du tri, et le repli du panneau sur petit écran. */
.barre-f__tri{ display:flex; align-items:center; gap:8px; margin-left:auto; }
.barre-f__tri label{ font-family:var(--tech); font-size:var(--t-xs); text-transform:uppercase;
  letter-spacing:.1em; color:var(--muted); }
.f-panneau .tiroir__c{ gap:12px; }
.f-panneau .champ .etiq{ display:block; margin-bottom:5px; }
@media (max-width:560px){
  .barre-f__tri{ margin-left:0; width:100%; }
  .f-panneau .tiroir__c > *{ flex:1 1 140px; }
}
/* Les jetons « actifs » n'ont pas à border la barre quand il n'y en a aucun. */
.actifs:empty{ display:none; }

/* ───────────────────────────────────────────────────────────────────────────
   8. LES DEUX LIENS DU MARCHÉ, SUR UNE SEULE LIGNE, SÉPARÉS PAR UNE BARRE
   ───────────────────────────────────────────────────────────────────────────
   Demande de Preda. Ce sont deux BOUTONS, donc ils portent une cible tactile
   et un état désactivé lisible — un lien « en attente de collecte » ne doit pas
   avoir l'air cliquable. */
.liens-2{ display:inline-flex; align-items:center; gap:7px; white-space:nowrap; }
.liens-2__sep{ color:var(--rule-int); user-select:none; }
.lien-b{ display:inline-flex; align-items:center; justify-content:center; min-height:var(--tap-min);
  padding:0 11px; border-radius:var(--r-full); border:1px solid var(--rule-2);
  background:var(--surface-2); color:var(--text-2); font-family:var(--geo);
  font-size:var(--t-xs); font-weight:600; transition:all var(--d-fast); }
.lien-b:hover{ border-color:var(--sect-a); color:var(--sect-a); background:var(--sect-1v); text-decoration:none; }
/* ⭐ `[data-attente]` porte DÉJÀ le sens « pas encore collecté » partout dans
   ce site : on l'habille au lieu d'inventer une classe `--off`. Un seul mot
   pour une seule idée, sinon les deux divergent. */
.lien-b[data-attente]{ opacity:.5; cursor:help; border-style:dashed; }
.lien-b[data-attente]:hover{ border-color:var(--rule-2); color:var(--text-2); background:var(--surface-2); }

/* ───────────────────────────────────────────────────────────────────────────
   9. LA COURBE 7 j EST DEVENUE UNE COLONNE À PART ENTIÈRE
   ───────────────────────────────────────────────────────────────────────────
   Elle n'est plus l'appendice muet du pourcentage : elle EST la colonne « 7 j ».
   Elle porte donc un en-tête visible et une largeur tenue. */
.col-courbe{ width:104px; }
.col-courbe .spark{ display:block; }


/* ═══════════════════════════════════════════════════════════════════════════
   LOT 71 — 05/08/2026 · deuxième passe de retours sur veveprice
   ═══════════════════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────────────────
   1. 🔴🔴 LA BANDE DE L'EN-TÊTE N'ÉTAIT PAS ROUGE SUR LE MARCHÉ
   ───────────────────────────────────────────────────────────────────────────
   Preda : « la bande colorée du header n'est pas rouge dans le Market ».
   Et il avait raison contre trois vérifications qui disaient le contraire :
   `<body data-sect="cotes">` était bien émis, `[data-sect="cotes"]` posait bien
   `--sect-pur:#D7263D`, et `.site-h::after` (l. 412) lisait bien `--sect-pur`.

   ⭐⭐⭐ CE QUI MANQUAIT : IL Y A **DEUX** RÈGLES `::after` SUR CET ÉLÉMENT.
       header.site::after   (l. 209)  →  var(--primary)   spécificité (0,1,2)
       .site-h::after       (l. 412)  →  var(--sect-pur)  spécificité (0,1,1)
   Le socle générique GAGNE — un type de plus dans le sélecteur — et il peint la
   bande avec `--primary`, la couleur du manifeste, donc CYAN sur toutes les
   pages. La règle « juste » était écrite, chargée, et perdait.
   ⛔ Et c'est la TROISIÈME fois que ce double habillage frappe ce même élément :
   le 31/07 on avait neutralisé son `background`, son `z-index` et son `.wrap`
   (bloc `header.site.site-h` plus haut) — et laissé son `::after`.
   ⭐⭐ ON NE CORRIGE PAS UN DOUBLE HABILLAGE UNE PROPRIÉTÉ À LA FOIS. Le jour où
   on en neutralise une, on liste TOUT ce que la couche générique déclare sur ce
   sélecteur, pseudo-éléments compris — sinon on revient trois fois.
   ⭐ Spécificité (0,2,2) : gagne sur les deux, sans `!important`. */
header.site.site-h::after{
  background:linear-gradient(90deg,var(--sect-pur),
             color-mix(in srgb,var(--sect-pur) 30%,transparent) 68%,transparent);
}

/* ───────────────────────────────────────────────────────────────────────────
   2. L'EN-TÊTE NE SUIT PLUS LE DÉFILEMENT (demande de Preda)
   ───────────────────────────────────────────────────────────────────────────
   ⚠️ `position:relative` et NON `static` : la bande de 3 px est un
   `::after` en `position:absolute`. En `static`, elle n'aurait plus d'ancêtre
   positionné et irait se caler sur le bloc conteneur initial — c'est-à-dire
   une barre de 3 px flottant en haut du document, visible sur toutes les pages.
   ⛔ Le piège classique de « je retire juste le sticky ». */
header.site, header.site.site-h{ position:relative; top:auto; }

/* ───────────────────────────────────────────────────────────────────────────
   3. 🔴🔴 L'EN-TÊTE ÉTAIT PLUS ÉTROIT QUE LA PAGE — ET C'EST MOI QUI L'AI FAIT
   ───────────────────────────────────────────────────────────────────────────
   Le lot 70 a posé `body{display:flex;flex-direction:column}` pour que le
   contenu descende jusqu'au pied de page. Effet de bord que je n'avais pas vu :
   **un élément flex ne rétrécit jamais sous sa largeur min-content.** Le
   `<main>` qui contient le tableau du Marché (dix colonnes) réclamait donc plus
   que la largeur de la fenêtre, il l'obtenait, et l'en-tête — lui, sans contenu
   large — restait à la largeur de la fenêtre. D'où une barre du haut visiblement
   plus étroite que la page, et une page qui « s'agrandit » en vue Tuiles.
   ⭐⭐ `min-width:auto` EST LE DÉFAUT DES ÉLÉMENTS FLEX, et c'est une protection :
   elle empêche d'écraser un contenu illisible. Elle devient un piège dès que le
   contenu a le droit de défiler tout seul — ce qui est le cas d'un tableau.
   ➡️ `min-width:0` sur les enfants directs de <body> + la table qui défile DANS
   sa carte (`.tbl-hote{overflow-x:auto}`, corrigé plus haut). Le tableau reste
   entièrement atteignable, la page ne s'élargit plus.
   ⭐ La leçon : `display:flex` sur <body> n'est pas un réglage de mise en page,
   c'est un changement de modèle de dimensionnement pour TOUS ses enfants. */
body > *{ min-width:0; }

/* ───────────────────────────────────────────────────────────────────────────
   🔴🔴🔴 LOT 72 — LA VRAIE CAUSE, ET ELLE EXPLIQUE SIX SYMPTÔMES D'UN COUP
   ───────────────────────────────────────────────────────────────────────────
   Preda, trois fois de suite : « le header n'a pas la même taille que le
   contenu », « aucune page n'a la même largeur », « quand je retire une
   colonne dans le filtre, la largeur de la page diminue », « exploite la
   largeur maximale », « le fond du contenu doit descendre jusqu'au footer ».
   J'ai traité ça comme cinq problèmes. C'EN EST UN SEUL.

   ⭐⭐⭐ `margin-inline:auto` SUR UN ÉLÉMENT FLEX DÉSACTIVE L'ÉTIREMENT.
   Spécification Flexbox, §9.4 : un élément s'étire à la taille de sa ligne
   « si `align-self:stretch`, si sa taille transversale calculée vaut `auto`,
   **et si AUCUNE de ses marges transversales ne vaut `auto`** ».
   Or `body > header.site, body > main, body > footer.site` portent
   `margin-inline:auto` depuis le lot 19 — c'était le bon outil quand <body>
   était un bloc. Le lot 70 a mis <body> en `display:flex`, et cette marge est
   devenue un interrupteur : chaque bande se dimensionne désormais sur SON
   PROPRE CONTENU (`fit-content`), puis se centre.
   D'où, mécaniquement :
     · l'en-tête = largeur de sa barre (marque + menu + outils)   → plus étroit
     · le <main> = largeur de son contenu le plus large           → variable
     · une colonne masquée = un tableau plus étroit = UNE PAGE PLUS ÉTROITE
     · le fond de `main` ne couvre plus toute la largeur, le fond de <body>
       (#0E0E0E) apparaît sur les côtés — d'où « le fond ne descend pas »
     · et rien n'« exploite la largeur maximale », puisque plus personne ne la
       demande.
   ⭐⭐ MON CORRECTIF DU LOT 71 (`min-width:0`) A ENLEVÉ LA BORNE BASSE ET LAISSÉ
   LE VRAI DÉFAUT INTACT. Il empêchait la page de s'élargir ; il ne lui rendait
   pas sa largeur. Traiter un symptôme au lieu de la cause déplace le bug.
   ➡️ On redonne une taille transversale EXPLICITE. `width:100%` n'est pas
   `auto`, donc l'étirement n'est plus nécessaire : la bande fait la largeur du
   <body>, `max-width` la plafonne à 1520 px, et les marges auto la centrent —
   ce qui laisse le vide sur les bords, exactement comme la maquette.
   ⚠️ `box-sizing:border-box` est posé sur `*` (l. 382) : `width:100%` cohabite
   donc avec le padding sans déborder. */
body > header.site,
body > main,
body > footer.site{ width:100%; }

/* Le fond du contenu couvre toute la hauteur restante — pas seulement celle de
   ce qu'il contient. `flex:1 0 auto` le fait grandir ; encore faut-il qu'il
   soit peint : `background:var(--bg)` est déjà posé plus haut par la règle du
   cadre, on ne fait ici que garantir qu'aucune page courte ne laisse voir le
   fond de <body> entre le contenu et le pied. */
body > main{ background:var(--bg); }


/* ───────────────────────────────────────────────────────────────────────────
   4. 🔴 TOUTES LES PAGES N'AVAIENT PAS LA MÊME LARGEUR
   ───────────────────────────────────────────────────────────────────────────
   Mesuré : `Base.astro` rend `<main class="wrap">` (padding 0 24px), et
   `Home.astro` remet DEUX `<div class="wrap">` à l'intérieur. L'accueil avait
   donc **48 px de marge** là où le Marché, les Sets, Plans et Analytics en
   avaient 24. Les blocs de l'accueil étaient 48 px plus étroits de chaque côté
   que partout ailleurs — assez pour se voir, trop peu pour qu'on sache dire
   pourquoi.
   ⭐ Le `.wrap` interne de l'accueil n'est PAS une erreur : il existe pour que
   le bandeau animé puisse sortir de la colonne et courir d'un bord à l'autre.
   Ce qu'il ne doit pas faire, c'est ajouter une SECONDE fois le padding.
   ⛔ On ne le retire donc pas du gabarit — on rend l'imbrication inoffensive,
   ici, pour tout le réseau et pour toutes les pages à venir. */
.wrap .wrap{ padding-left:0; padding-right:0; }

/* ───────────────────────────────────────────────────────────────────────────
   5. LE BANDEAU ANIMÉ COLLAIT AUX COMPTEURS
   ───────────────────────────────────────────────────────────────────────────
   Il touche les bords de l'écran par construction (il est hors de `.wrap`),
   donc rien ne le séparait verticalement de ce qui l'entoure. */
.ticker{ margin-block:var(--s6); }
@media (max-width:640px){ .ticker{ margin-block:var(--s5); } }

/* ───────────────────────────────────────────────────────────────────────────
   6. 🔴 LA PAGE « PLANS » RESTAIT CYAN
   ───────────────────────────────────────────────────────────────────────────
   Preda : « la couleur dans Plans n'est pas respectée, la majeure partie des
   cases sont cyan ». Cause : `[data-sect]` remappait `--cyan`, `--cyan-fonce`
   et `--cyan-1v` (l. 373) — mais **pas `--lock`**. Or c'est `--lock` qui peint
   le palier mis en avant (`.tarif--phare`), les modules réservés (`.module`),
   le cadenas, le sceau et le bouton verrou : l'essentiel de cette page.
   ⭐⭐ UN JETON DE COULEUR QUI ÉCHAPPE AU REMAPPAGE EST UNE COULEUR QUI NE
   CHANGERA JAMAIS, et rien ne le dit : la page « prend » sa couleur partout où
   on regarde d'abord (la bande, les liens, les étiquettes) et la garde là où
   elle occupe le plus de surface.
   ⚠️ Conséquence assumée sur les autres pages : le cadenas et les blocs
   « réservé aux membres » prennent désormais la couleur de leur page. C'est
   cohérent avec « une couleur par page » — et `--lock` gardait de toute façon
   le cyan du site, pas une sémantique propre (il vaut `var(--primary)` dans le
   socle, l. 352).
   ✅ ARBITRAGE PREDA, 26/08/2026 (train 205→209) : « le verrou SUIT LA PAGE »
   — la conséquence ci-dessus n'est plus une conséquence, c'est la règle
   choisie. ⛔ Un audit qui resignale « le cadenas n'est pas magenta » a une
   observation juste et un verdict faux : c'est voulu, et c'est daté. */
[data-sect]{
  --lock:     var(--sect-a);
  --lock-pur: var(--sect-pur);
  --lock-1v:  var(--sect-1v);
}

/* ───────────────────────────────────────────────────────────────────────────
   7. LA VUE TUILES NE DOIT PAS POUVOIR ÉLARGIR LA PAGE
   ───────────────────────────────────────────────────────────────────────────
   Ceinture et bretelles avec le `min-width:0` du §3 : une grille dont les
   colonnes ont un minimum en pixels réclame ce minimum × le nombre de colonnes
   dès que la largeur disponible devient indéfinie. */
.tuiles{ min-width:0; }
.tuile__n, .tuile__s{ overflow-wrap:anywhere; }

/* ═══════════════════════════════════════════════════════════════════════════
   LOT 101 — L'EMPLACEMENT D'UNE COTE FERMÉE
   ═══════════════════════════════════════════════════════════════════════════
   ⭐ Le composant `<Cote>` rend un tiret. Ces règles ne CACHENT rien — il n'y
   a rien à cacher, le montant n'est plus dans le HTML : elles disent
   simplement que ce tiret est un emplacement réservé, et non une donnée
   manquante. La distinction est éditoriale et elle compte : le site doit avoir
   l'air de retenir un chiffre, pas d'en avoir perdu un.
   ⚠️ `font-variant-numeric` et `font-family` héritent volontairement de
   `.prix` / `.num` : quand le chiffre arrive par JavaScript, il ne doit pas
   changer de fonte ni décaler la ligne. Un remplissage qui fait sauter la mise
   en page se lit comme un défaut, même quand tout marche. */
.cote{ display:inline-flex; align-items:center; font:inherit; color:var(--muted);
       letter-spacing:inherit; }
.cote__v{ font-variant-numeric:tabular-nums; }
/* ⭐ Une fois la cote reçue, l'emplacement redevient du texte courant : c'est
   `[data-ouverte]` que le script pose, jamais une classe — un attribut se teste
   sans lire de CSS, et les trois thèmes honorent déjà ce genre de crochet. */
.cote[data-ouverte]{ color:inherit; }
/* 🔴🔴 LOT 112 — LE CADENAS DU TIRET (demande Preda, 10/08).
   Un « — » nu est ambigu PAR CONSTRUCTION : ailleurs sur ce site il veut dire
   « la donnée n'existe pas » (un tirage inconnu, aucune offre). Le même signe
   pour « je n'ai pas » et pour « je ne montre pas » enseigne au visiteur que
   le site est INCOMPLET alors qu'il est FERMÉ — deux causes opposées derrière
   un seul signe, la confusion que ce projet paie le plus souvent.
   ⭐⭐ IL DISPARAÎT QUAND LA VALEUR ARRIVE, et c'est la moitié qui compte :
   `CoteScript` pose `data-ouverte="1"` au retour de `/api/cote/`. Sans cette
   seconde règle, un membre verrait son prix AVEC un cadenas à côté — la porte
   ouverte et le verrou toujours dessiné.
   ⛔ `[data-ouverte]`, jamais une classe : un attribut se teste des deux côtés
   (thème et script) sans qu'aucun n'ait à connaître le vocabulaire de l'autre.
   ⚠️ Pas d'`opacity` de repos ici : `test:opacite` (lot 111) refuserait un
   état de départ sans releveur, et il aurait raison — `display` suffit. */
.cote__l{ display:inline-flex; align-items:center; margin-left:5px; color:var(--lock); }
.cote__l svg{ width:11px; height:11px; flex:0 0 11px; }
.cote[data-ouverte] .cote__l{ display:none; }
/* ⛔ PAS DE CURSEUR `help` NI DE SOULIGNÉ POINTILLÉ sur l'emplacement fermé :
   le `title` suffit, et un ornement d'interactivité sur un élément qui ne
   répond à aucun clic est un mensonge d'interface. */

/* La courbe SANS ÉCHELLE — arbitrage Preda du 07/08 : « les graphes sans
   échelle restent publics ». Elle n'a pas d'axe des ordonnées, donc elle
   récupère l'espace que `.graph` réservait à gauche pour les graduations. */
.graph--muet .axe{ opacity:.75; }

/* ═══════════════════════════════════════════════════════════════════════════
   LOT 103 — LA RECHERCHE EN BOUTON
   ═══════════════════════════════════════════════════════════════════════════
   ⭐ Un MODIFICATEUR, pas une seconde règle : `.h-rech` garde son fond, sa
   bordure, son survol et son focus. `--b` ne fait que retirer ce qui la faisait
   ressembler à un champ de saisie — la largeur minimale et le libellé.
   ⛔ NE PAS remplacer `.h-rech` : elle sert encore ailleurs (l'accueil a sa
   propre entrée `hero__rech` qui hérite de la même base), et deux classes
   concurrentes pour un même objet divergent au premier ajustement. */
/* 🔴 LOT 111 — IL CHANGEAIT DE NATURE SELON LA LARGEUR.
   `.h-rech--b` en faisait une pastille de 38 px bordee ; la regle d'ecran
   etroit (l. 1120) lui retirait sa bordure ET son fond et la portait a 44 px.
   Resultat : une pastille au-dessus de 900 px, une icone nue en dessous —
   deux objets differents pour une meme commande, a cote de deux VRAIES
   pastilles (le globe, le menu) qui, elles, ne bougeaient pas.
   ⭐ Ce n'est pas un gout : c'est la seule commande de l'en-tete dont la forme
   ne survivait pas au redimensionnement. On la fige. */
/* ═══════════════════════════════════════════════════════════════════════════
   🔴🔴🔴 LOT 161 (24/08/2026) — LE CARRÉ DU LOT 139 N'A JAMAIS PEINT
   ═══════════════════════════════════════════════════════════════════════════
   Le lot 139 (11/08) a écrit `border-radius:var(--r-md)` sur `.h-rech--b`, à la
   demande de Preda, avec quarante lignes pour expliquer le choix du rayon et la
   taille qui l'accompagne. MESURÉ le 24/08 sur la feuille SERVIE en production :

       nav.main a  { border-radius: var(--r-full) }   spécificité (0,1,2)  ← GAGNE
       .h-rech--b  { border-radius: var(--r-md)   }   spécificité (0,1,0)

   ⇒ Le bouton est **rond** en ligne depuis le 11 août. C'est ce que Preda a vu
   sur sa capture (« un rond gris identique au bouton de compte »), et il avait
   raison : ce n'était pas un souvenir approximatif, c'était l'écran.

   ⭐⭐⭐ TROISIÈME FOIS LE MÊME DÉFAUT DANS CETTE SEULE JOURNÉE — après les 88 px
   du pied de page et les 56 px de la barre grise. La signature est toujours la
   même : une règle écrite, commentée, défendue, et BATTUE EN SPÉCIFICITÉ par
   une règle plus ancienne que personne ne relit. « Est-ce écrit ? » et « est-ce
   ce qui gagne ? » sont deux questions, et le dépôt ne posait que la première.
   🔬 Il pose la seconde depuis ce lot : `outils/cascade-resolue.mjs` la calcule,
   `test:feuille` la surveille.

   ⭐ ARBITRAGE DE PREDA, 24/08, sur trois formes montrées côte à côte : **on
   garde le rond**. Le carré mort part donc — il ne peint rien, il ne peut que
   faire croire au prochain lecteur qu'il y a un carré quelque part.
   ⛔ NE PAS « restaurer » `--r-md` en montant la spécificité : ce serait
   ressusciter un choix explicitement abandonné. Si le carré revient un jour, il
   reviendra sur une demande datée, pas sur la lecture de ce commentaire.

   ⚠️ CE QUI RESTE DU LOT 139, ET QUI EST TOUJOURS VRAI : la TAILLE. `.h-rech--b`
   prend `--tap-min` (36 px) comme `.bascule`, au lieu des 38 px d'avant — les
   deux boutons de l'en-tête ont le même gabarit, et c'est ce que l'œil lit.
   ⚠️ 36 px reste sous les 44 px de cible tactile recommandés — vrai de
   `.bascule` depuis toujours. Écrit comme non réglé plutôt que tu : ça se
   tranche dans l'audit WCAG, qui n'a jamais été fait (SUIVI).
   ⭐ Un seul chiffre pour revenir en arrière : `--tap-min` → `38px`. */
.h-rech--b{ min-width:0; width:var(--tap-min); height:var(--tap-min); padding:0;
  justify-content:center; background:var(--surface-2);
  border:1px solid var(--rule-2); }
/* ⚠️ CE BLOC RESTE, ET IL N'EST PAS REDONDANT. `.h-rech` (la base) se
   déshabille sous 900 px — `min-width:0`, fond et bordure retirés, taille
   portée à `--tap`. Sans cette reprise, le bouton changerait de nature à
   900 px : c'est exactement la panne que le lot 111 a fermée, et elle
   reviendrait par la porte de la base. */
@media (max-width:900px){
  .h-rech--b{ width:var(--tap-min); height:var(--tap-min); background:var(--surface-2);
    border-color:var(--rule-2); }
}
/* La loupe reprend la taille des autres pictogrammes de l'en-tête (le globe,
   l'avatar), pour que les boutons aient le même poids visuel. */
.h-rech--b svg{ width:17px; height:17px; }

/* ═══════════════════════════════════════════════════════════════════════════
   LOT 113 — LE RAYON, LA PAGINATION, « À VENIR », L'ORIENTATION
   ═══════════════════════════════════════════════════════════════════════════
   ⛔ AUCUN `opacity:0` ICI. `test:opacite` (lot 111) refuserait un état de
   repos sans releveur, et il aurait raison : ces blocs n'ont pas d'animation
   d'entrée, donc rien qui doive partir de l'invisible.
   ⭐ Ces classes ne vivent que sur veveprice : les pages qui les portent sont
   derrière `priceEnabled()`, et vevewiki ne l'active pas. */

/* ── LE RAYON ────────────────────────────────────────────────────────────── */
.rayon{ list-style:none; margin:var(--s5) 0 0; padding:0; display:grid; gap:2px; }
/* 🔴 LOT 139 — UNE COLONNE DE PLUS : les extrêmes. ⚠️ Elle est `auto`, donc
   elle ne prend RIEN quand la ligne n'en émet pas — et 94 % des lignes n'en
   émettent pas (18 212 pièces sur 19 412 n'ont pas de fiche, donc pas de cote
   en réserve). Une colonne `auto` vide se replie sur zéro ; une colonne `1fr`
   aurait creusé un blanc sur toutes les autres lignes. */
/* 🔴🔴🔴 LOT 201 — UNE SIXIÈME COLONNE : le plancher (`.rayon__p`).
   ⛔ ELLE S'AJOUTE DANS LE MÊME LOT QUE SON ÉMETTEUR, et ce n'est pas de la
   discipline de façade. Cette grille nomme SIX colonnes pour six enfants ; un
   septième enfant ne déborde pas en largeur, il se REPLIE SUR UNE LIGNE
   SUPPLÉMENTAIRE et fait grandir toutes les lignes du rayon d'un coup. C'est
   `regle-enfant-non-plafonne-casse-une-grille`, et elle ne se voit pas sur une
   ligne isolée — elle se voit sur 20.
   ⭐ `auto`, comme la colonne des extrêmes juste après, et pour la même
   raison : 18 212 pièces sur 19 412 n'ont pas de fiche, donc n'émettent ni
   plancher ni extrêmes. Une colonne `auto` vide se replie sur zéro ; une
   colonne `1fr` aurait creusé un blanc sur 94 % des lignes.
   🐛 ET ELLE PASSE DE CINQ À SEPT, PAS À SIX — parce que la mesure a trouvé
   un défaut qui était DÉJÀ LÀ, indépendant de ce lot. Compté sur le HTML
   servi de `/collectibles/` : 15 lignes émettent 6 enfants et 5 en émettent
   7 (celles qui portent `.rayon__e`, la mention d'édition). Avec cinq
   colonnes, ces 5 lignes-là débordaient déjà sur une SECONDE RANGÉE et
   grandissaient d'un cran, une sur quatre. Personne ne l'avait nommé : une
   ligne un peu plus haute au milieu de vingt ne ressemble pas à une faute,
   elle ressemble à du texte long.
   ⭐ Sept `auto` coûtent zéro : celles que la ligne n'alimente pas se replient
   sur zéro, exactement comme la colonne des extrêmes le fait depuis le lot
   139. ⛔ Ne pas les poser aurait laissé mon plancher accusé d'un repli qu'il
   n'a pas causé — et c'est la seule raison pour laquelle ce chiffre est écrit
   ici plutôt que dans une note. */
.rayon__c{ display:grid; grid-template-columns:minmax(0,2fr) minmax(0,1.4fr) auto auto auto auto auto;
  align-items:center; gap:var(--s4); padding:11px 14px; min-height:var(--tap);
  background:var(--surface); border:1px solid var(--rule); border-radius:var(--r-md);
  color:var(--text-2); transition:border-color var(--d-fast),background var(--d-fast); }
.rayon__c:hover{ border-color:var(--sect-a); background:var(--sect-1v); text-decoration:none; }
/* ⭐⭐ LA LIGNE SANS FICHE N'EST PAS UN LIEN DÉSACTIVÉ, C'EST UN <div>. Un lien
   mort se copie, se partage et s'indexe ; un élément qui n'est pas un lien ne
   fait rien de tout ça. Le style le DIT aussi : pas de survol, pas de curseur
   de main, une mention explicite. */
.rayon__c--muet{ background:transparent; border-style:dashed; color:var(--muted); }
.rayon__c--muet:hover{ border-color:var(--rule); background:transparent; }
.rayon__n{ font-weight:600; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rayon__c--muet .rayon__n{ color:var(--text-2); font-weight:500; }
.rayon__s{ font-size:var(--t-sm); color:var(--muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rayon__e{ font-size:var(--t-xs); color:var(--muted); }
.rayon__t{ font-family:var(--tech); font-size:var(--t-xs); color:var(--muted); font-variant-numeric:tabular-nums; }
.rayon__x{ font-size:var(--t-2xs); letter-spacing:var(--ls-etiq); text-transform:uppercase; color:var(--muted); }
/* 🔴🔴 LOT 139 — LES EXTRÊMES SUR UNE LIGNE DE RAYON : `.rayon__ext`.
   ⛔ ON NE RÉUTILISE PAS `.socle__ext`, ET CE N'EST PAS UN CAPRICE DE NOM :
   celui-ci est `position:absolute; inset auto 0 0 0` avec un dégradé noir — il
   est fait pour se poser SUR une image de vignette. Sur une ligne de liste il
   n'y a pas d'image, donc pas de bloc conteneur : il irait se coller au coin
   bas-gauche du premier ancêtre positionné, exactement le mécanisme qui a
   coûté le tiroir de 64 pixels au début de ce même lot.
   ⭐ Même contenu (`.b`/`.h`/`i`/`b`), même vocabulaire, autre géométrie.
   ⚠️ `.rayon__c` gagne une colonne AVEC cette règle, dans le même lot : une
   classe émise sans règle est un « posé jamais lu », une règle sans émetteur
   est une des ~10 classes mortes qu'on traîne déjà. Le contrat va dans les
   deux sens. */
.rayon__ext{ display:flex; align-items:center; gap:var(--s3); font-family:var(--tech);
  font-size:var(--t-2xs); letter-spacing:.05em; color:var(--muted);
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.rayon__ext i{ font-style:normal; display:block; font-size:var(--t-3xs);
  letter-spacing:.1em; color:var(--muted); }
.rayon__ext b{ display:block; font-weight:700; color:var(--text-2); }
.rayon__ext .b{ text-align:left; }
.rayon__ext .h{ text-align:right; }
/* ⭐ Le cadenas du `<Cote>` reste lisible dans une ligne : il hérite de la
   taille du texte, il ne la fixe pas. */
.rayon__ext .cote{ display:inline-flex; align-items:center; gap:3px; }
/* 🔴 LOT 201 — LE PLANCHER DE LA LIGNE. ⭐ Il est en `--text`, pas en
   `--muted` : c'est le seul chiffre de la ligne que le visiteur cherche
   vraiment, et les extrêmes juste à côté sont volontairement plus discrets.
   Un plancher au même gris que son ATL ne se distinguerait pas de lui.
   ⚠️ `tabular-nums` : sans lui, la colonne des prix danse d'une ligne à
   l'autre parce que le `1` est plus étroit que le `8` — sur 20 lignes
   empilées, c'est le défaut qu'on voit sans savoir le nommer.
   ⭐ Même `display:inline-flex` sur `.cote` que dans `.rayon__ext` : le
   cadenas et le tiret doivent rester sur la même ligne de base. */
.rayon__p{ font-family:var(--tech); font-size:var(--t-sm); font-weight:700;
  color:var(--text); font-variant-numeric:tabular-nums; white-space:nowrap; }
.rayon__p.cote{ display:inline-flex; align-items:center; gap:3px; }
@media (max-width:760px){
  .rayon__c{ grid-template-columns:1fr auto; row-gap:4px; }
  .rayon__s{ grid-column:1/-1; }
}

/* ── LA PAGINATION ───────────────────────────────────────────────────────── */
.pagin{ display:flex; flex-wrap:wrap; gap:6px; align-items:center; justify-content:center;
  margin:var(--s6) 0 var(--s5); }
.pagin__b{ display:inline-flex; align-items:center; justify-content:center;
  min-width:var(--tap-min); min-height:var(--tap-min); padding:0 10px;
  border:1px solid var(--rule-2); border-radius:var(--r-md); color:var(--text-2);
  font-family:var(--tech); font-size:var(--t-sm); font-variant-numeric:tabular-nums; }
.pagin__b:hover{ border-color:var(--sect-a); color:var(--sect-a); text-decoration:none; }
.pagin__b--ici{ background:var(--sect-1v); border-color:var(--sect-a); color:var(--sect-a); font-weight:600; }
.pagin__e{ color:var(--muted); padding:0 2px; }

/* ── « À VENIR » ─────────────────────────────────────────────────────────── */
/* ⛔ Aucun style d'« état vide » : le composant NE REND RIEN quand il n'a rien.
   Un cadre vide ressemble à une panne, et VeVe n'annonce qu'à quelques jours. */
.avenir{ margin:var(--s5) 0; }
.avenir__l{ list-style:none; margin:var(--s4) 0 0; padding:0; display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr)); gap:var(--s3); }
/* 🔴 LOT 132 — LES CARTES « À VENIR » DEVIENNENT DES LIENS (celles qui ont une
   fiche). Preda, 10/08 : « améliore l'aspect des cartes À venir, elles devraient
   aussi mener à des fiches ».
   ⭐ LE `<li>` N'EST PLUS LA CARTE : il enveloppe un `<a>` ou un `<div>` selon
   que le drop a une fiche ou non. `.avenir__l` est un `flex` ; sans cette
   règle, chaque `<li>` deviendrait une boîte à sa propre largeur et la rangée
   se disloquerait. `display:contents` fait disparaître le `<li>` de la mise en
   page SANS le retirer du DOM — la liste reste une liste pour un lecteur
   d'écran, et le flex continue de voir les cartes comme ses enfants directs.
   ⚠️ Safari a longtemps retiré de l'arbre d'accessibilité les `<li>` mis en
   `display:contents`. Le `role="listitem"` explicite le rattrape — il est posé
   dans `AVenir.astro`, parce qu'un rôle est du BALISAGE. Cette règle-ci ne fait
   que de la mise en page, et les deux moitiés se tiennent : retirer l'une sans
   l'autre rend une liste que le CSS aplatit et que personne ne rattrape. */
.avenir__l > li{ display:contents; }
/* ⭐ L'ÉTAT LIEN : la carte cliquable se distingue au survol et au clavier.
   ⛔ Elle ne se distingue PAS au repos par une couleur : une rangée où deux
   cartes sur sept sont bleues laisserait croire que les cinq autres sont
   désactivées, alors qu'elles annoncent la même chose. La différence se révèle
   au geste, pas au coup d'œil. */
.avenir__c--lien{ cursor:pointer; transition:border-color var(--d-fast), transform var(--d-base) var(--e-out); }
.avenir__c--lien:hover{ border-color:var(--sect-a); transform:translateY(-1px); text-decoration:none; }
.avenir__c--lien:focus-visible{ outline:var(--foc-proche) solid var(--sect-pur); outline-offset:2px; }
/* ═══════════════════════════════════════════════════════════════════════════
   🔴 LOT 158 — LA PILULE DEVIENT UNE BANDE (demande Preda, 21/08 : « les
   cartes dans À venir présentées d'une plus belle façon », variante D validée
   sur maquette).
   ⭐⭐ ET LE RAYON EN PILULE ÉTAIT UN DÉFAUT DE GRAMMAIRE, PAS DE GOÛT. La
   règle de la maison est écrite vingt lignes sous `--r-full` : *ce qui
   CONTIENT est carré, ce qu'on CLIQUE est rond.* Cette carte CONTIENT — et
   elle ne se clique même pas la plupart du temps : mesuré le 21/08 sur la
   production, **0 des 3 drops annoncés a une fiche**, donc zéro carte
   cliquable. Un contenant dessiné en bouton promettait un clic qui n'existe
   pas. ⇒ `--r-lg`, comme tout ce qui contient.
   ⭐ LE VISUEL PASSE DE 34 px À 76 × 104. Une couverture de comic réduite à
   une pastille ronde de 34 px ne montre rien : c'est le seul élément de la
   carte qui donne envie, il était le plus petit. Le format suit celui du
   catalogue (2:3), en plus court.
   ⛔ LE FILET CYAN EST À GAUCHE, PAS UN APLAT. Le lot 132 avait déjà tranché
   la question voisine et son argument tient ici : une carte qui se colore au
   repos laisse croire que ses voisines sont désactivées. Le filet marque la
   section, pas un état — il est posé sur les TROIS cartes, pas sur certaines.
   ⛔ ET LA GRILLE REMPLACE LE `flex-wrap`. Une rangée de pilules se répartit
   au petit bonheur des longueurs de titre ; `auto-fill` donne des colonnes de
   largeur égale et une seule colonne sous 320 px. `min()` dans le `minmax`
   évite le débordement horizontal sur un téléphone de 360 px — un `minmax`
   nu à 320 px déborde dès que la page a du padding. */
.avenir__c{ display:flex; gap:var(--s3); min-width:0; overflow:hidden;
  background:var(--surface-2); border:1px solid var(--rule-2);
  border-left:3px solid var(--sect-a); border-radius:var(--r-lg);
  font-size:var(--t-sm); color:var(--text-2); }
/* ⭐ `align-self:stretch` sans `height` : les cartes d'une même rangée sont
   étirées à la plus haute par la grille, et l'image suit au lieu de laisser
   une bande morte sous elle. `min-height` fixe le plancher quand la carte est
   seule sur sa rangée. */
.avenir__b{ display:flex; flex-direction:column; gap:5px; min-width:0; flex:1;
  padding:var(--s3) var(--s3) var(--s3) 0; }
/* ⛔ Un drop sans couverture ne réserve pas la place de l'image (règle du lot
   118), mais son texte ne doit pas coller au filet : le padding gauche revient
   quand le bloc est le premier enfant. */
.avenir__c > .avenir__b:first-child{ padding-left:var(--s3); }
.avenir__j{ font-family:var(--tech); font-size:var(--t-xs); letter-spacing:var(--ls-etiq);
  text-transform:uppercase; color:var(--sect-a); }
.avenir__n{ font-family:var(--geo); font-size:var(--t-md); font-weight:700;
  line-height:1.3; color:var(--text); overflow-wrap:anywhere; }
/* ⭐ `margin-top:auto` pousse les compteurs en bas de la carte : deux cartes
   côte à côte alignent leurs pastilles même quand l'une a un titre sur deux
   lignes et l'autre sur une. ⛔ `:empty` — un drop d'une seule pièce et d'une
   seule rareté n'émet aucun compteur, et un conteneur vide laisserait un
   `gap` de 5 px qui décale le titre sans rien afficher — et c'est `AVenir.astro`
   qui s'en charge, en n'ÉMETTANT pas le conteneur. ⛔ Pas de `:empty` ici : il
   n'aurait jamais mordu, Astro laisse les blancs de l'indentation à
   l'intérieur et `:empty` refuse un nœud de texte, fût-il fait d'espaces. */
.avenir__m{ margin-top:auto; display:flex; flex-wrap:wrap; gap:6px; padding-top:2px; }
.avenir__s, .avenir__r{ font-family:var(--tech); font-size:var(--t-2xs);
  letter-spacing:var(--ls-etiq); text-transform:uppercase; border-radius:var(--r-sm);
  padding:3px 7px; background:var(--surface-3); color:var(--text-2); }
.avenir__s{ background:var(--sect-1v); color:var(--sect-a); }

/* ── L'ORIENTATION ───────────────────────────────────────────────────────── */
.orient{ margin:var(--s6) 0; }
.orient__t{ margin-left:auto; font-family:var(--tech); font-size:var(--t-sm); color:var(--sect-a); white-space:nowrap; }
.orient .sect-t{ display:flex; align-items:baseline; gap:var(--s4); }

/* ═══ LOT 114 — LA BASCULE MOIS/ANNÉE, LE COMPARATIF, LE CHOIX DE LANGUE ═══
   ⛔ AUCUN `opacity:0` : `test:opacite` (lot 111) refuserait un état de repos
   sans releveur. Ces blocs n'ont pas d'animation d'entrée. */
/* 🔴 LOT 132 — `justify-content:center`. Preda, 10/08 : « dans les paliers, les
   boutons à l'année ou au mois devraient être centrés au milieu ».
   ⭐ Ils étaient collés à gauche par DÉFAUT, pas par décision : `display:flex`
   sans `justify-content` vaut `flex-start`. La grille de tarifs, elle, est
   centrée sur la largeur du contenu — la bascule qui la commande partait donc
   du bord gauche pendant que ce qu'elle pilote occupait toute la largeur.
   ⛔ Pas `margin:auto` sur les boutons : ça les écarterait l'un de l'autre au
   lieu de centrer le groupe, et la bascule cesserait de se lire comme UN
   contrôle à deux positions. */
.bascule-p{ display:flex; align-items:center; justify-content:center; gap:6px; margin:var(--s5) 0 var(--s4); flex-wrap:wrap; }
.bascule-p__b{ min-height:var(--tap-min); padding:0 16px; border:1px solid var(--rule-2);
  border-radius:var(--r-full); background:transparent; color:var(--text-2); cursor:pointer;
  font-family:var(--geo); font-size:var(--t-sm); font-weight:500; transition:all var(--d-fast); }
.bascule-p__b:hover{ border-color:var(--sect-a); color:var(--sect-a); }
.bascule-p__b[aria-pressed="true"]{ background:var(--sect-1v); border-color:var(--sect-a); color:var(--sect-a); font-weight:600; }
.bascule-p__g{ font-family:var(--tech); font-size:var(--t-xs); color:var(--sect-a); margin-left:6px; }

/* ⭐ `overflow-x` sur un CONTENEUR, jamais sur la table : une table qui défile
   d'elle-même perd son en-tête collant et son accessibilité au clavier. */
.compa-t__h{ overflow-x:auto; margin:var(--s4) 0 var(--s5); }
.compa-t{ width:100%; border-collapse:collapse; font-size:var(--t-sm); }
.compa-t th, .compa-t td{ padding:11px 13px; border-bottom:1px solid var(--rule); text-align:center; }
.compa-t thead th{ font-family:var(--geo); color:var(--text); white-space:nowrap;
  border-bottom:1px solid var(--rule-2); }
.compa-t tbody th{ text-align:left; font-weight:600; color:var(--text); min-width:200px; }
.compa-t__d{ display:block; font-weight:400; font-size:var(--t-xs); color:var(--muted); margin-top:3px; }
.compa-t__phare{ background:var(--sect-1v); }
.compa-t tbody tr:hover{ background:var(--survol); }

.lang-choix{ display:flex; gap:6px; margin:0 0 var(--s3); }
.lang-choix a{ min-height:28px; min-width:32px; display:inline-flex; align-items:center;
  justify-content:center; padding:0 8px; border-radius:var(--r-sm); font-family:var(--tech);
  font-size:var(--t-xs); color:var(--muted); }
.lang-choix a:hover{ color:var(--sect-a); background:var(--survol); text-decoration:none; }
.lang-choix a[aria-current="true"]{ color:var(--sect-a); background:var(--sect-1v); font-weight:600; }

/* ═══ LOT 115 — LE FAVORI, ET CE QUI PASSAIT DEVANT LE FLOU ═══════════════
   🔴🔴 `.socle__fav` PART À `opacity:0` ET NE SE RELÈVE QU'AU SURVOL
   (l. 665-667, écrit au lot 15 pour un composant qui n'existait pas).
   Sur un téléphone il n'y a pas de survol : le bouton n'existerait pas.
   ⭐ La variante `--fiche` est visible d'emblée et vit dans le flux, pas en
   surimpression : la fiche n'a pas de vignette sur laquelle se poser.
   ⛔ ELLE NE TOUCHE PAS `.socle__fav` : sur les cartes, l'apparition au survol
   est voulue (le cœur ne doit pas encombrer une grille de 20 vignettes). */
/* 🔴 LOT 139 — LE BOUTON FAVORIS DE LA FICHE : ICÔNE ET TEXTE CENTRÉS, CÔTE À
   CÔTE (demande Preda, 11/08). La variante héritait `display:grid` +
   `place-items:center` de `.socle__fav`, mais avec `width:auto` et
   `grid-auto-flow:column` les DEUX colonnes s'étiraient sur toute la largeur
   disponible : l'icône partait à gauche, le libellé à droite, et le « centré »
   du parent ne centrait que le CONTENU de chaque colonne, pas les colonnes
   entre elles. ⭐⭐ *`place-items` centre dans la piste ; `place-content` centre
   les pistes.* Les deux se lisent pareil et ne font pas la même chose — c'est
   la troisième fois que ce dépôt paie cette confusion (`.stats`, `.pagin`).
   ⛔ Et `justify-items:center` n'aurait rien réglé : c'est encore le contenu. */
/* ❤️ LE BOUTON FAVORI DE LA FICHE — REECRIT EN FLEX AU LOT 171 (21/08/2026)
   Demande de Preda, point `x` de l'audit du 14/08, ses mots :
   « icone + texte du bouton Favoris centres cote a cote ».

   ⛔ CE QU'IL Y AVAIT AVANT, ET POURQUOI ON NE L'A PAS RAFISTOLE.
   La variante heritait de `.socle__fav{display:grid;place-items:center;
   width:32px;height:32px}` et la corrigeait morceau par morceau :
   `width:auto`, `grid-auto-flow:column`, `justify-content`, `align-content`,
   `align-items`, plus un `min-height` qui devait battre le `height:32px`
   herite. SIX declarations pour obtenir « deux choses cote a cote, centrees »,
   et chacune ne vaut que si les cinq autres tiennent.
   ⭐⭐⭐ *Un centrage obtenu par accumulation de correctifs n'est pas centre :
   il est en equilibre.* `inline-flex` le dit en trois mots, et `place-items`
   herite devient sans effet (justify-items ne s'applique pas en flex,
   align-items:center est de toute facon ce qu'on veut).
   ⭐ `height:auto` est ECRIT, pas deduit : sans lui, le `height:32px` de la
   base continue de lutter contre `min-height`, et le resultat depend de
   l'ordre des regles. */
.socle__fav--fiche{ position:static; opacity:1;
  display:inline-flex; flex-flow:row nowrap;
  align-items:center; justify-content:center; gap:8px;
  width:auto; height:auto; min-height:var(--tap-min);
  padding:0 14px; background:transparent;
  backdrop-filter:none; border-color:var(--rule-2); margin-bottom:var(--s3); }
/* ⭐ `flex:0 0 auto` sur les deux enfants : sans lui, le texte peut ecraser
   l'icone quand le libelle est long (l'allemand « Zu den Favoriten hinzufugen »
   fait 28 caracteres contre 19 en francais). */
.socle__fav--fiche::after{ content:attr(data-l); flex:0 0 auto;
  font-family:var(--geo); font-size:var(--t-sm); line-height:1; }
.socle__fav--fiche svg{ flex:0 0 auto; width:16px; height:16px; }

/* 🔴 LES ILLUSTRATIONS PASSAIENT DEVANT LE FLOU (demande Preda).
   `.flottantes` est `position:fixed; z-index:0` : elle crée son propre
   contexte d'empilement, mais le formulaire au-dessus n'avait AUCUN `z-index`
   — donc `z-index:auto`, donc peint dans la même couche, et l'ordre du DOM
   décidait seul. Un `img` en `position:absolute` y gagnait par endroits.
   ⭐ On ne descend PAS `.flottantes` en `z-index:-1` : sur un élément `fixed`,
   ça la ferait passer derrière le fond du `<body>` et disparaître entièrement.
   ⇒ C'est le CONTENU qu'on remonte, explicitement. */
.centre{ position:relative; z-index:1; }
.flottantes{ z-index:0; }

/* ═══ LOT 115b — LA RECHERCHE DE MARQUE ET L'ESPACE DES SÉRIES ════════════ */
/* ⭐ Le champ reprend la géométrie des autres champs de la barre de filtres :
   une commande qui a sa propre forme se lit comme un objet d'une autre nature. */
.champ-f{ width:100%; max-width:280px; min-height:var(--tap-min); margin:0 0 var(--s3);
  padding:0 12px; background:var(--surface-2); border:1px solid var(--rule-2);
  border-radius:var(--r-md); color:var(--text); font-family:var(--sans); font-size:var(--t-sm); }
.champ-f:focus-visible{ outline:var(--foc-proche) solid var(--sect-pur); outline-offset:2px;
  border-color:var(--sect-a); }
.champ-f::placeholder{ color:var(--muted); }

/* 🔴 L'ESPACE ENTRE « items / tirage / offres » ET LES CARTES.
   ⛔ Posé sur la GRILLE, pas sur `.stats` : `.stats` sert aussi sur la fiche,
   et lui donner une marge la déplacerait sur des pages qui n'ont rien demandé.
   *Une règle élargie peut emporter ce qu'elle étendait.* */
.grille--apres-stats{ margin-top:var(--s6); }

/* ⛔ Le témoin qui remplace la barre de filtres pour un visiteur : il DIT ce
   qui manque et pourquoi, il ne fait pas semblant d'être une commande. */
.filtres-mur{ margin:var(--s4) 0 var(--s5); padding:11px 14px; border:1px dashed var(--rule-2);
  border-radius:var(--r-md); color:var(--muted); }

/* ═══════════════════════════════════════════════════════════════════════════
   LOT 118 — LES VISUELS DES SETS ET DES DROPS À VENIR
   ═══════════════════════════════════════════════════════════════════════════
   Preda, 10/08 : « pas de visuel pour les sets, ni de visuel pour Coming up ».

   🔴🔴 LOT 131 — `.col-carte__v` A ÉTÉ RETIRÉE, ET SON DÉPART EST LA MOITIÉ
   VISIBLE D'UNE CORRECTION PLUS PROFONDE. Elle habillait l'image PLATE que
   `/collections/` posait sur un set, pendant que `/sets/` rendait le même set
   en pile de trois vignettes (`.col-carte__pile`). Preda a vu l'écart avant
   nous. Les deux pages passent désormais par `CarteSet.astro`.
   ⭐⭐ ET LE COMMENTAIRE QUI ÉTAIT ICI DISAIT LE CONTRAIRE : « ces deux règles
   sont émises, et elles le restent ». Elle ne l'est plus. Une règle CSS qu'on
   laisse derrière son dernier émetteur rejoint les ~13 classes jamais émises
   qu'on traîne — et son commentaire, lui, continue d'affirmer qu'elle sert.
   ⛔ Retirer le gabarit sans retirer la règle, c'est fabriquer la dette au
   moment même où on croit la rembourser.
   ⚠️ `.col-carte__n` et `.col-carte__c` étaient l'inverse : ÉMISES par
   `Orientation.astro` et habillées par AUCUNE règle, dans aucun des trois
   thèmes — des éléments nus depuis le lot 118. Elles disparaissent avec lui.
   Le contrat vaut dans les deux sens ; ce lot paie les deux. */

.avenir__v{ display:block; width:76px; flex:0 0 76px; min-height:104px;
  align-self:stretch; object-fit:cover; }
/* ⭐ `flex:0 0 76px` : `.avenir__c` est un conteneur flex, et une image sans
   base fixe s'y écrase ou s'y étire selon le voisinage. `width` seul ne suffit
   pas dans un flex — c'est `flex-basis` qui décide.
   ⚠️ LOT 158 — ce commentaire disait « 34px » APRÈS que la règle soit passée à
   76 : un commentaire qui garde l'ancien chiffre se cite plus tard comme une
   mesure. Il se corrige dans le même geste que la règle, jamais après. */

/* ═══════════════════════════════════════════════════════════════════════════
   🔴🔴 LOT 118 — LE MENU DEVIENT UN TIROIR, ET LE BOUTON SE TAIT QUAND LA
   NAVIGATION EST DÉJÀ LÀ
   ═══════════════════════════════════════════════════════════════════════════
   Preda, 10/08 : « le bouton menu accordéon ne doit être visible que quand le
   menu du header n'est pas dispo » et « il doit s'ouvrir en drawer menu
   gauche ».

   ⭐⭐⭐ LE SEUIL EST ÉCRIT UNE FOIS, ET LES DEUX RÈGLES SONT VOISINES.
   `.nav__liens{display:none}` bascule à 1040 px ; le bouton doit apparaître
   EXACTEMENT là. Le lot 111 avait payé le contraire : deux seuils qui devaient
   coïncider vivaient à 400 lignes d'écart, et l'intervalle 641–1040 px n'avait
   AUCUN accès visible au menu — les liens existaient, le bouton répondait,
   l'écran ne montrait rien. ⛔ Ne jamais séparer ces deux lignes.
   ⚠️ `test:menu` (lot 118) lit la feuille et échoue si les deux seuils
   divergent : un commentaire qui dit « ne les séparez pas » ne peut pas
   rougir, et *un avertissement qu'on ne peut pas faire rougir finit lu sans
   être suivi.*

   ⛔ CE N'EST PAS UNE RÉGRESSION DU LOT 111. Ce lot-là avait rendu le bouton
   visible partout POUR RÉPARER LE TROU ci-dessus, pas parce que le doublon
   était souhaitable. Le trou est fermé par le seuil commun ; au-dessus de
   1040 px les six liens sont là, et un second chemin vers les mêmes six liens
   n'apporte rien qu'un doublon à maintenir. */
.nav__deplie{ display:none; margin-right:var(--s3); }
@media (max-width:1040px){ .nav__liens{ display:none; } .nav__deplie{ display:block; } }

/* ── LE TIROIR ─────────────────────────────────────────────────────────────
   ⭐ `position:fixed` et non `absolute` : un panneau absolu est ancré à
   `.deplie{position:relative}` et se ferait rogner par le `overflow` de
   l'en-tête. Un tiroir sort du flux de la page, sinon ce n'est pas un tiroir.
   ⛔ `left:0` et `translateX(-100%)` À LA FERMETURE, pas `display:none` : on
   veut un GLISSEMENT. Mais `[hidden]` reste le seul juge de l'existence —
   c'est lui qui retire le panneau de l'ordre de tabulation. Sans ça on tabule
   dans six liens qu'on ne voit pas, et le lot 111 l'a déjà payé.
   ⚠️ LA TRANSITION NE PORTE PAS SUR `display`. Un panneau à `display:none` ne
   s'anime pas ; c'est `transform` et `opacity` qui bougent, et `[hidden]` qui
   décide. C'est déjà le dispositif de `.deplie__m` depuis le lot 111. */
.deplie__m{ position:fixed; inset:0 auto 0 0; top:0; right:auto; bottom:0; left:0;
  width:min(310px, 84vw); min-width:0; max-width:none; z-index:120;
  border-radius:0; border:0; border-right:1px solid var(--rule-2);
  padding:calc(var(--s6) + 8px) var(--s3) var(--s3);
  align-content:start; overflow-y:auto; overscroll-behavior:contain;
  transform:translateX(-100%); }
.deplie__m:not([hidden]){ transform:none; }

/* 🔴 LE VOILE. Sans lui, le tiroir se pose sur un texte qui reste lisible et
   cliquable : on croit avoir cliqué à côté d'un lien alors qu'on a cliqué
   DANS la page, derrière le panneau.
   ⭐ Il est porté par le `<body>` et non par un élément en plus : un nœud
   ajouté par JavaScript n'existerait pas sans JavaScript, et le tiroir ne
   s'ouvre justement que par JavaScript — mais un voile orphelin resterait
   affiché si le script échouait entre les deux gestes.
   ⚠️ `pointer-events` bascule avec l'opacité : un voile transparent qui garde
   ses évènements intercepte tous les clics de la page, en silence. C'est
   exactement la panne de l'élément transparent du lot 111, vue de l'autre
   côté. */
body::after{ content:""; position:fixed; inset:0; z-index:110; background:rgba(0,0,0,.52);
  opacity:0; pointer-events:none; transition:opacity var(--d-base) var(--e-out); }
body[data-tiroir]::after{ opacity:1; pointer-events:auto; }
/* ⛔ On ne bloque PAS le défilement du document (`overflow:hidden` sur body) :
   sur iOS ça fait sauter la page en haut à la fermeture, et l'utilisateur perd
   sa place dans une liste de 835 pages. Le voile suffit à empêcher les clics. */

/* ── 🔳 LE CODE QR DE L'ÉCRAN D'ACHAT (lot 201) ───────────────────────────── */
/* ⭐⭐⭐ LE CADRE BLANC N'EST PAS DÉCORATIF, IL EST FONCTIONNEL. Ce site a un
   thème sombre. Un code QR a besoin d'une marge claire de quatre modules
   (« quiet zone ») pour que le décodeur trouve ses bords — le SVG la porte
   déjà — mais il a AUSSI besoin que cette marge ne soit pas noyée dans un fond
   noir. `padding` + `background` blancs sont ce qui rend le code lisible sur
   une page sombre, pas ce qui le rend joli.
   ⛔ Et surtout : ⛔ AUCUN `filter: invert()` en thème sombre. Un QR inversé
   (modules clairs sur fond sombre) EST lisible par certains décodeurs et pas
   par d'autres — c'est exactement le genre de « marche chez moi » qui coûte un
   paiement perdu.
   ⚠️ `max-width` en pourcentage ET une largeur fixe sur le SVG : sur un
   téléphone étroit, un carré de 200 px déborderait la colonne. */
.caisse-qr{ margin:var(--s4) 0 0; }
.caisse-qr svg{ display:block; width:200px; max-width:100%; height:auto;
  padding:8px; background:#fff; border-radius:var(--r-md); }
.caisse-qr .etiq{ margin:8px 0 0; max-width:38ch; }

/* ═══════════════════════════════════════════════════════════════════════════
   📏 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}