/* ══════════════════════════════════════════════════════════════════════════════
   Saṃsāra — feuille de STRUCTURE.
   Ici : la mise en page et les composants. Aucune couleur en dur — tout passe par des
   jetons (`var(--…)`). Les valeurs vivent dans themes/<id>.css, un fichier par thème,
   déclaré dans index.html par un <link data-theme>. Le contrat (jetons obligatoires,
   règles de performance) est vérifié par tests/test_contrat.py et tests/test_palette.py.

   RÈGLES DE PERFORMANCE (mesurées le 05/10/2026, tests/test_contrat.py les fait tenir) —
   pour CETTE feuille et css/bookmap.css. Depuis le 06/10/2026, une feuille de THÈME peut user
   de flou, de fusion ou d'animations infinies si elle tient son budget d'image, MESURÉ par
   tests/test_budget.js (voir le contrat) :
   · pas de `backdrop-filter` ailleurs qu'ici, et seulement via le jeton --verre : un thème
     choisit son verre, il ne pose pas de filtre sur un élément de son choix. Cinq surfaces
     floutées recalculées à chaque image du graphique = 167 ms par image (33 sans) ;
   · pas de `mix-blend-mode` ni de `filter: blur` : posés au-dessus du canvas, ils
     obligeaient à recomposer le graphique à chaque image (33 → 17 ms par image sans) ;
   · pas d'animation infinie : elle fait redessiner la page en continu, même au repos.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ─── 1. Jetons par défaut ─────────────────────────────────────────────────────
   Un thème DOIT définir le noyau (liste dans tests/test_contrat.py) ; le reste a une
   valeur par défaut ici, qu'il peut surcharger. */
:root {
  --font: 'Segoe UI Variable Text', 'Segoe UI Variable', -apple-system, BlinkMacSystemFont,
          'SF Pro Text', system-ui, 'Segoe UI', Roboto, sans-serif;
  --gutter: 13px;
  --gap: 11px;
  --r-bar: 999px;
  --r-panel: 32px;
  --r-card: 22px;
  --r-tile: 14px;

  /* Verre : aucun par défaut. Un thème qui en veut le déclare (data-verre) ET pose --verre. */
  --verre: none;
  --surface-ombre: none;
  --surface-reflet: none;
  --trame: none;
  --trame-opacite: 0.6;
  --grain: none;

  --capsule: var(--card-solid);
  --capsule-hover: var(--card-solid);
  --capsule-ombre: 0 1px 3px rgba(0,0,0,0.12);
  --pill: transparent;
  --pill-hover: var(--rail);
  /* Fond d'un élément qui porte du TEXTE (bouton actif, intervalle choisi, boutons du Grid
     Bot) : le dégradé de marque par défaut ; un thème dont le dégradé est trop clair pour
     son encre le redéfinit (tests/test_palette.py, contrôle 7, mesure chaque borne). */
  --brand-fond: var(--brand);
  --pill-actif: var(--brand-fond);
  --pill-actif-ink: #ffffff;
  --pill-actif-ombre: 0 3px 12px var(--accent-glow), inset 0 1px 0 rgba(255,255,255,0.35);
  --dot-anneau: var(--card-solid);
  --poignee: transparent;
  --poignee-hover: var(--rail);
  --card-hi: transparent;
  --card-reflet: none;
  --brand-ink: #ffffff;
  --forward: linear-gradient(135deg, var(--up), var(--up-ink));
  --modal-fond: var(--card-solid);
  --modal-ombre: 0 6px 20px -12px rgba(0,0,0,0.4);
  --selection: var(--accent-glow);
  --defil: var(--hairline);
  --defil-hover: var(--ink-3);
  --ombre-douce: 0 2px 8px rgba(0,0,0,0.15);

  --warn: #f0a50b;
  --warn-ink: #8a5a00;
  --warn-soft: rgba(240,165,11,0.16);

  /* Graphique (canvas). Lus par js/app.js à chaque changement de thème. */
  --chart-lueur: none;
  --chart-creux: none;
  --chart-surface: var(--chart-2);
  --grille: rgba(127,127,127,0.12);
  --reticule: var(--ink-3);
  --bulle: var(--card-solid);
  --filigrane: 0.05;
  --vol-alpha: 0.55;
  --bande-alpha: 0.08;
  --aura: 0;
  --ov-bb: var(--ink-3);
  --ov-vwap: var(--ov-ema100);
  --ov-sar: var(--accent);
  --ov-ichi-t: var(--ov-ema50);
  --ov-ichi-k: var(--ov-sma20);
  --s-rsi: var(--ov-ema200);
  --s-macd: var(--ov-ema20);
  --s-signal: var(--ov-ema100);
  --s-stoch-k: var(--ov-ema20);
  --s-stoch-d: var(--ov-ema100);
  --s-atr: var(--ov-sma20);
  --s-obv: var(--ov-ema100);
  --s-mfi: var(--ov-ema200);
  --s-wr: var(--ov-ema50);
  --s-cci: var(--ov-ema100);
  --s-adx: var(--ov-ema20);
  --s-equity: var(--ov-ema20);
  --sess-asie: rgba(255,152,0,0.75);
  --sess-europe: rgba(33,150,243,0.75);
  --sess-us: rgba(156,39,176,0.75);
  --sr-1: #ce93d8;
  --sr-2: #26c6da;
  --sr-3: #ffc107;
  --fib: #f0a50b;
  --vp: #64b4ff;
  --vp-poc: #ffc828;
}

/* ─── 2. Base ──────────────────────────────────────────────────────────────── */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { color-scheme: light; }
body {
  font-family: var(--font);
  font-size: 13px; line-height: 1.5;
  color: var(--ink-1);
  background: var(--fond);   /* pas de « fixed » : la page ne défile jamais, il ne servait à rien */
  display: flex; flex-direction: column; gap: var(--gap);
  height: 100vh;
  height: 100dvh;   /* mobile : 100vh inclut la barre d'URL, le bas passait sous le pli */
  overflow: hidden;
  padding: var(--gutter); padding-bottom: 46px;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}
/* Grain : une image fixe posée au-dessus de tout, composée une fois (pas recalculée). */
body::before {
  content: ''; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  background: var(--grain); background-size: 200px 200px; opacity: 0.028;
}
/* Trame de fond : ce que le verre (quand le thème en a) a à courber. */
.aero-grid {
  position: fixed; inset: -12%; z-index: -1; pointer-events: none;
  background-image: var(--trame);
  background-size: 38px 38px, 38px 38px, 190px 190px, 190px 190px;
  opacity: var(--trame-opacite);
}
::selection { background: var(--selection); }
:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--defil); border-radius: min(8px, var(--r-tile)); }
::-webkit-scrollbar-thumb:hover { background: var(--defil-hover); }
/* Le <svg> des filtres hyalite : caché sans display:none (Blink ignorerait ses filtres). */
.hyalite-filters { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Fins de ligne (revue du 14/10/2026, C8) : un nombre et ses milliers ou son unité, « : ; ? ! » »
   et leur mot, « « » et le sien, posés ensemble par Fmt.insecables (js/format.js), ne se coupent
   plus ; l'âge des infos du marché (« 25 min », « 1 h 31 »), réécrit chaque minute, non plus. */
.insec, [data-age-de] { white-space: nowrap; }

/* ─── 3. Les six surfaces ────────────────────────────────────────────────────── */
.header, .indicator-bar, .chart-container, .feed-panel, .strat-section, .reperes-section, .aero-taskbar {
  position: relative; overflow: hidden;
  background: var(--surface);
  box-shadow: var(--surface-ombre);
  -webkit-backdrop-filter: var(--verre); backdrop-filter: var(--verre);
}
/* hyalite écrit --hyalite sur les éléments qu'il attache (panneau, Grid Bot). La propriété
   est HÉRITÉE : ne la consommer que sur ces deux-là. */
.feed-panel, .strat-section, .reperes-section {
  -webkit-backdrop-filter: var(--hyalite, var(--verre)); backdrop-filter: var(--hyalite, var(--verre));
}
/* Le cadre du graphique n'est pas flouté : son anneau l'est (ci-dessous). Flouter toute la
   surface faisait recomposer 1404×632 px de flou à chaque image du canvas. */
.chart-container { -webkit-backdrop-filter: none; backdrop-filter: none; }
/* Arête : un anneau de 1,5 px au masque, dégradé fourni par le thème (none par défaut). */
.header::after, .indicator-bar::after, .chart-container::after,
.feed-panel::after, .strat-section::after, .reperes-section::after, .aero-taskbar::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  padding: 1.5px; z-index: 4;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  background: var(--surface-reflet);
}
/* Pendant un geste sur le graphique, le verre se suspend : il serait recalculé à chaque
   image du glissement. Sur un fond lisse, flou ou pas, la différence ne se lit pas. */
html.geste .header, html.geste .indicator-bar, html.geste .lg-ring::before, html.geste .lg-ring::after,
html.geste .lg-ring-cotes::before, html.geste .lg-ring-cotes::after,
html.geste .feed-panel, html.geste .strat-section, html.geste .reperes-section, html.geste .aero-taskbar {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}
/* Pendant un SURVOL du graphique (réticule redessiné à chaque image), seul l'anneau se
   suspend : c'est lui que chaque image du calque faisait recomposer (js/app.js, survol()). */
html.survol .lg-ring::before, html.survol .lg-ring::after,
html.survol .lg-ring-cotes::before, html.survol .lg-ring-cotes::after { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }

/* ─── 4. En-tête ────────────────────────────────────────────────────────────── */
.header {
  z-index: 100; flex-shrink: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 9px 16px; border-radius: var(--r-bar);
}
.header-left { display: flex; align-items: center; gap: 14px; min-width: 0; }
/* Sur bureau, le prix héros ne cède JAMAIS de place : ce sont les chiffres clés (.kpis) qui
   s'effacent, en entier, en partant de la fin (ajusterKpis). Sans cette règle, l'ajout de
   boutons à droite faisait déborder la variation 24 h par-dessus le premier chiffre clé. */
@media (min-width: 769px) { .header-left { flex-shrink: 0; } }
.header-right { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.header-orb {
  position: relative; flex-shrink: 0;
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 0;
  background: var(--orbe, var(--brand));
  box-shadow: var(--orbe-ombre, 0 2px 10px var(--accent-glow));
}
.header-left h1 {
  font-size: 20px; font-weight: 750; letter-spacing: -0.2px; white-space: nowrap;
  background: var(--brand); -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
/* Capsules : sélecteur de paire, boutons ronds, bouton « Choisir l'affichage ». */
.paire-btn, .theme-btn, .ind-dropdown-btn {
  background: var(--capsule); color: var(--ink-1);
  border: 1px solid transparent; border-radius: var(--r-bar);
  box-shadow: var(--capsule-ombre);
}
/* Le prix héros : la paire (sélecteur), le dernier prix, la variation 24 h — même requête,
   même seconde. C'est le premier chiffre que l'œil doit trouver. */
.hero-prix { display: flex; align-items: center; gap: 11px; min-width: 0; }
.paire-btn {
  display: inline-flex; align-items: center; gap: 3px; flex-shrink: 0;
  padding: 4px 7px 4px 11px; cursor: pointer; white-space: nowrap;
  font: inherit; font-size: 11.5px; font-weight: 750; letter-spacing: 0.3px;
}
.paire-btn svg { width: 14px; height: 14px; color: var(--ink-3); }
.paire-btn:hover { background: var(--capsule-hover); }
.price-badge {
  display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0;
  font-size: 23px; font-weight: 750; letter-spacing: -0.5px; line-height: 1;
  color: var(--ink-1); font-variant-numeric: tabular-nums; white-space: nowrap;
  text-shadow: var(--prix-lueur, none);
}
.price-badge.price-up::before, .price-badge.price-down::before {
  content: ''; width: 0; height: 0;
  border-left: 5px solid transparent; border-right: 5px solid transparent;
}
.price-badge.price-up::before { border-bottom: 8px solid var(--up); }
.price-badge.price-down::before { border-top: 8px solid var(--down); }
/* Gazette (structure « une ») : la place de la flèche est TOUJOURS réservée, vide quand le prix
   n'a pas bougé. Sans elle, à 375-390 px, chaque flèche poussait la variation 24 h sur une 2e
   ligne : l'en-tête grandissait de 23 px puis rapetissait, une à deux fois par seconde, et tout
   le dessous sautait sous le doigt (revue du 14/10, visuel-c-1). Même boîte que la flèche. */
:root[data-structure="une"] .price-badge:not(.price-up):not(.price-down)::before {
  content: ''; width: 0; height: 0;
  border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 8px solid transparent;
}
/* Éclair du prix : la couleur du sens, posée par une classe et retirée 450 ms plus tard (deux
   images par changement), sans transition — une animation de couleur repeignait le chiffre à
   chaque image : 70 % du CPU de la page au repos. */
.price-badge.eclair-hausse { color: var(--up-ink); }
.price-badge.eclair-baisse { color: var(--down-ink); }
.var24 {
  flex-shrink: 0; padding: 3px 9px; border-radius: var(--r-bar); white-space: nowrap;
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--rail); color: var(--ink-2);
}
.var24:empty { display: none; }
.var24.pos { background: var(--up-soft); color: var(--up-ink); }
.var24.neg { background: var(--down-soft); color: var(--down-ink); }
/* Aero (le seul thème clair sans structure) : le fond translucide de la pastille prenait le mauve
   de l'en-tête, « −2,26 % en 24 h » n'y tenait que 3,5:1 (3,4 en hausse) pour un texte de 10,5 px.
   Un fond opaque, l'encre à peine mêlée à --card-solid (sur qui l'encre tient 4,5:1, test_palette) :
   4,8 et 4,6:1. Les thèmes sombres gardent leur fond (6 à 12:1). Revue du 14/10, C32. */
:root:not([data-structure]) .var24.pos { background: light-dark(color-mix(in srgb, var(--up-ink) 6%, var(--card-solid)), var(--up-soft)); }
:root:not([data-structure]) .var24.neg { background: light-dark(color-mix(in srgb, var(--down-ink) 6%, var(--card-solid)), var(--down-soft)); }

/* Chiffres clés de la dernière publication (15 min). Ce qui ne tient pas en largeur est
   masqué en entier, en commençant par la fin (js : ajusterKpis) — jamais coupé à moitié. */
.kpis {
  flex: 1 1 auto; min-width: 0; height: 36px;
  display: flex; align-items: center; justify-content: flex-start;
  overflow: hidden; cursor: pointer;
}
.kpi {
  display: flex; flex-direction: column; justify-content: center; flex-shrink: 0;
  padding: 0 14px; line-height: 1.2; border-left: 1px solid var(--hairline);
}
.kpi:first-child { border-left: 0; padding-left: 4px; }
.kpi[hidden] { display: none; }
.kpi i {
  font-style: normal; font-size: 9px; font-weight: 700; letter-spacing: 0.7px;
  text-transform: uppercase; color: var(--ink-3);
}
.kpi b {
  font-size: 14px; font-weight: 700; letter-spacing: -0.2px; white-space: nowrap;
  color: var(--ink-1); font-variant-numeric: tabular-nums;
}
.kpi b.stat-pos { color: var(--up-ink); } .kpi b.stat-neg { color: var(--down-ink); }
.kpis:hover .kpi i { color: var(--ink-2); }
.kpi-age {
  flex-shrink: 0; margin-left: 6px; padding: 2px 8px; border-radius: var(--r-bar);
  font-size: 10px; font-weight: 650; white-space: nowrap;
  color: var(--ink-3); background: var(--rail);
}
.kpis.vieux .kpi-age { color: var(--warn-ink); background: var(--warn-soft); }
/* Au-delà du seuil, la pastille d'âge dit le mot : « en retard · 25 min » (la teinte seule ne se
   lisait pas). Le mot est écrit ici (contenu généré) : le texte de la pastille reste l'âge seul,
   que les structures habillent. Gare l'écrit déjà elle-même (« Retard · », themes/gare.css) et la
   Planche le marque de son △ (indice de révision) : pas deux fois, ni la case élargie. */
.kpi-age .age-retard { display: none; }
.kpis.vieux .kpi-age .age-retard { display: inline; }
.kpis.vieux .kpi-age .age-retard::before { content: 'en retard · '; }
[data-structure="tableau"] .kpis.vieux .kpi-age .age-retard,
[data-structure="planche"] .kpis.vieux .kpi-age .age-retard { display: none; }
/* Sur une autre paire que BTC/USDT, la bande dit qu'elle parle du bitcoin (js/app.js). */
.kpi-btc {
  flex-shrink: 0; margin-right: 4px; padding: 2px 8px; border-radius: var(--r-bar);
  font-size: 10px; font-weight: 700; white-space: nowrap; color: var(--ink-2); background: var(--rail);
}
/* Trace des dernières heures (js/chronique.js) : sur la ligne du libellé, dans la hauteur de
   la bande (36 px) — ni plus haute, ni beaucoup plus large. Statique : rien n'y bouge entre
   deux publications. Une ligne coupée est un trou de publication, jamais interpolé. */
.kpi-t { display: flex; align-items: center; gap: 5px; height: 11px; }
.kpi.sans-trace .chron-spark { display: none; }
.chron-spark { flex-shrink: 0; display: block; color: var(--ink-3); overflow: visible; }
.kpis:hover .chron-spark { color: var(--ink-2); }
.chron-spark .chron-ligne, .chron-fiche .chron-ligne { fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.chron-spark .chron-point, .chron-fiche .chron-point { fill: currentColor; }
#updated { font-size: 10px; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.theme-btn {
  cursor: pointer; font: inherit; font-weight: 600; color: var(--ink-2);
  transition: color .15s ease, background .15s ease;
}
.theme-btn.ico-btn {
  width: 34px; height: 34px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.theme-btn.ico-btn svg { width: 17px; height: 17px; display: block; }
.theme-btn:hover { color: var(--accent-2); background: var(--capsule-hover); }
.theme-btn:active { transform: scale(0.97); }
.theme-btn.ico-btn.on {
  color: var(--brand-ink); background: var(--brand-fond);
  box-shadow: 0 4px 14px var(--accent-glow), inset 0 1px 0 rgba(255,255,255,0.35);
}
/* Point « live » : une onde à chaque publication reçue (classe .ping posée par le JS),
   deux passages puis le calme. Pas d'animation infinie : elle redessinerait la page en
   continu, même au repos. */
.refresh-dot {
  position: relative; flex-shrink: 0;
  width: 10px; height: 10px; border-radius: 50%; background: var(--up);
  box-shadow: 0 0 0 3px var(--up-soft);
}
.refresh-dot::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%; background: inherit; opacity: 0;
}
.refresh-dot.ping::after { animation: onde 2.4s cubic-bezier(.2,.6,.3,1) 2; }
.refresh-dot.calme { box-shadow: none; }
.refresh-dot.calme::after { animation: none; }
@keyframes onde { from { transform: scale(1); opacity: 0.55; } to { transform: scale(3); opacity: 0; } }

/* Menus de l'en-tête : thèmes, paires */
.theme-menu, .paire-menu {
  position: fixed; z-index: 1200; display: none;
  min-width: 250px; padding: 8px;
  background: var(--card-solid); color: var(--ink-1);
  border: 1px solid var(--hairline); border-radius: min(18px, var(--r-panel));
  box-shadow: var(--card-shadow);
}
.theme-menu.open, .paire-menu.open { display: block; }
.paire-menu { min-width: 180px; }
.paire-menu label {
  display: flex; align-items: center; padding: 7px 10px; border-radius: min(12px, var(--r-tile)); cursor: pointer;
  font-size: 12.5px; font-weight: 650; font-variant-numeric: tabular-nums;
}
.paire-menu label:hover { background: var(--rail); }
.paire-menu label.active { background: var(--rail); color: var(--accent-2); }
.paire-menu label.active::after { content: '✓'; margin-left: auto; }
.theme-menu .cat-title, .paire-menu .cat-title {
  font-size: 9px; font-weight: 700; letter-spacing: 0.9px; text-transform: uppercase;
  color: var(--ink-3); padding: 4px 8px 6px;
}
.theme-item {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 7px 8px; border: 0; border-radius: min(12px, var(--r-tile)); background: transparent;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.theme-item:hover { background: var(--rail); }
.theme-item[aria-checked="true"] { background: var(--rail); }
.theme-item[aria-checked="true"] .theme-nom::after { content: '  ✓'; color: var(--accent-2); }
.theme-nom { font-size: 12.5px; font-weight: 650; }
.theme-mode { margin-left: auto; font-size: 10px; font-weight: 600; color: var(--ink-3); }
/* Aperçu : l'élément porte data-theme=<id>, il reçoit donc les VRAIS jetons du thème. */
.theme-apercu {
  position: relative; flex-shrink: 0; width: 46px; height: 30px; border-radius: 9px; overflow: hidden;
  background: var(--fond); box-shadow: inset 0 0 0 1px var(--hairline);
}
.theme-apercu i { position: absolute; display: block; }
.theme-apercu i:nth-child(1) { left: 5px; top: 6px; width: 24px; height: 18px; border-radius: 5px; background: var(--chart-2); }
.theme-apercu i:nth-child(2) { left: 9px; top: 9px; width: 4px; height: 10px; border-radius: 1px; background: var(--up); }
.theme-apercu i:nth-child(3) { left: 17px; top: 12px; width: 4px; height: 9px; border-radius: 1px; background: var(--down); }
.theme-apercu i:nth-child(4) { right: 5px; top: 7px; width: 10px; height: 16px; border-radius: 4px; background: var(--brand); }

/* ─── 5. Ruban d'outils ─────────────────────────────────────────────────────── */
.indicator-bar {
  z-index: 150; flex-shrink: 0;
  display: flex; align-items: center; gap: 2px; flex-wrap: nowrap;
  padding: 5px 12px; border-radius: var(--r-bar);
  overflow-x: auto; scrollbar-width: none;
  font-size: 11px;
}
.indicator-bar::-webkit-scrollbar { display: none; }
/* Ruban plus large que l'écran : un fondu à droite dit qu'il défile (classe posée par le JS). Quand
   « 1 j » tient dans le ruban, le fondu commence après lui, jamais dessus (revue du 14/10, C24) : au
   téléphone, avec un calque, le bouton passe en tête et « 1 j » finit près du bord, où le fondu le
   pâlissait. --fin-1j : où finit « 1 j » dans le ruban (ajusterRuban, js/app.js). */
.indicator-bar.deborde {
  -webkit-mask-image: linear-gradient(90deg, #000 max(calc(100% - 36px), var(--fin-1j, 0px)), transparent);
  mask-image: linear-gradient(90deg, #000 max(calc(100% - 36px), var(--fin-1j, 0px)), transparent);
}
/* Bureau 95 : pas de fondu, le bouton reste collé au bord droit. Une puce de la légende glissait
   dessous et n'en montrait qu'un carré de couleur, sans texte ; à sa droite, une lettre dépassait
   dans la marge du ruban (revue du 14/10, C24). Un voile plein de la couleur du fond, de chaque côté
   du bouton : à gauche, sur le bout trop court pour montrer un mot (--voile, ajusterRuban,
   js/app.js ; jamais sur un élément entier) ; à droite, sur la marge du ruban. Le relief est gardé. */
:root[data-structure="fenetres"] .indicator-bar.deborde > .ind-dropdown {
  box-shadow: inset 1px 0 var(--relief-3), inset 2px 0 var(--relief-1),
    calc(-1 * var(--voile, 0px)) 0 0 var(--surface), 6px 0 0 var(--surface);
}
/* « Choisir l'affichage » n'est jamais hors de vue en Complet, où le ruban
   défile : à 1440 px il était rogné au bord droit (x 1366–1490 pour 1427 px utiles) ; au
   téléphone, à trois écrans à droite. Au bureau, il est épinglé au bord droit du ruban (sticky),
   sur un fond plein qui recouvre en fondu ce qui défile dessous — le fondu du ruban est alors
   inutile ; au téléphone, il passe en tête, avant les intervalles. Bureau 95 l'épinglait déjà
   et la Planche le range sur la 1re rangée de sa nomenclature à partir de 1280 px : leurs
   règles, pas celles-ci (la Planche a les siennes plus bas, en dessous de 1280 px). */
@media (min-width: 769px) {
  :root[data-calques="1"]:not([data-structure="fenetres"]):not([data-structure="planche"]) .indicator-bar > .ind-dropdown {
    position: sticky; right: 0; z-index: 1; margin-left: auto;
  }
  :root[data-calques="1"]:not([data-structure="fenetres"]):not([data-structure="planche"]) .indicator-bar.deborde > .ind-dropdown {
    padding-left: 22px; background: linear-gradient(90deg, transparent, var(--card-solid) 18px);
    box-shadow: 12px 0 0 var(--card-solid);
  }
  :root[data-calques="1"]:not([data-structure="fenetres"]):not([data-structure="planche"]) .indicator-bar.deborde { -webkit-mask-image: none; mask-image: none; }
}
/* La Planche ne le range sur la 1re rangée de sa nomenclature qu'à partir de 1280 px : en dessous,
   sa nomenclature est une rangée qui défile, et le bouton était au bout, hors de l'écran. */
@media (min-width: 769px) and (max-width: 1279px) {
  :root[data-structure="planche"][data-calques="1"] .indicator-bar > .ind-dropdown {
    position: sticky; right: 0; z-index: 1; margin-left: auto;
  }
  :root[data-structure="planche"][data-calques="1"] .indicator-bar.deborde > .ind-dropdown {
    padding-left: 22px; background: linear-gradient(90deg, transparent, var(--card-solid) 18px);
    box-shadow: 12px 0 0 var(--card-solid);
  }
}
@media (max-width: 768px) {
  :root[data-calques="1"]:not([data-structure="fenetres"]) .indicator-bar > .ind-dropdown { order: -2; }
}
/* L'intervalle en tête du ruban, à toutes les largeurs : la légende des calques allumés (Complet)
   change de longueur, les intervalles gardent leur place ; la légende est suivie du bouton. Titres
   et `sep` sont des span frères : 1-2 « À l'écran » (la légende), 3-4 Intervalle. Si l'ordre des
   span du ruban change, réaligner ce sélecteur (la Planche, à partir de 1280 px, range le ruban
   par ses propres règles, plus précises). */
.indicator-bar > span:nth-of-type(3), .indicator-bar > span:nth-of-type(4),
.indicator-bar > label[id^="int_"] { order: -1; }
.indicator-bar .section-title {
  flex-shrink: 0;
  font-size: 9px; font-weight: 600; letter-spacing: 0.8px; text-transform: uppercase;
  color: var(--ink-3);
}
.indicator-bar .sep {
  flex-shrink: 0; width: 1px; height: 18px; margin: 0 4px;
  background: linear-gradient(180deg, transparent, var(--hairline), transparent);
}
.indicator-bar label {
  display: flex; align-items: center; gap: 4px; flex-shrink: 0;
  padding: 5px 10px; border: 1px solid transparent; border-radius: var(--r-bar);
  background: var(--pill); color: var(--ink-1);
  font-size: 11px; font-weight: 600; white-space: nowrap;
  cursor: pointer; user-select: none;
  transition: background .15s ease, color .15s ease;
}
.indicator-bar label:hover { background: var(--pill-hover); }
.indicator-bar label.active {
  background: var(--pill-actif); color: var(--pill-actif-ink); font-weight: 700;
  box-shadow: var(--pill-actif-ombre);
}
.indicator-bar input { display: none; }
.ind-label { color: inherit; font-weight: 600; display: inline-flex; align-items: center; }
/* Légende DANS la pastille : le point a la couleur exacte de la ligne tracée. */
.indicator-bar label[style*="--dot"] .ind-label::before {
  content: ''; flex-shrink: 0; width: 7px; height: 7px; margin-right: 6px; border-radius: 50%;
  background: var(--dot); box-shadow: 0 0 0 2px var(--dot-anneau);
}
/* La légende du Complet (majLegende, js/app.js) : une puce par calque allumé — sa couleur, son
   nom court, une croix (un clic le masque). Rien d'allumé : une phrase invite à choisir. */
.indicator-bar label.puce-calque { gap: 5px; }
.puce-calque .puce-x { font-size: 13px; line-height: 1; font-weight: 400; color: var(--ink-3); }
.puce-calque:hover .puce-x, .puce-calque:focus-visible .puce-x { color: var(--ink-1); }
.indicator-bar label.puce-calque:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.indicator-bar label.puce-plus { color: var(--accent-2); }
.indicator-bar label.legende-vide { background: transparent; border: 1px dashed var(--hairline); color: var(--ink-2); font-weight: 500; }

/* Bouton et panneau « Choisir l'affichage » (« Affichage » quand la place manque, jamais coupé) */
.ind-dropdown { display: inline-block; flex-shrink: 0; }
.aff-court { display: none; }
@media (max-width: 480px) { .aff-long { display: none; } .aff-court { display: inline; } }
.ind-dropdown-btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 13px 4px 10px; cursor: pointer; white-space: nowrap;
  font: inherit; font-size: 11px; font-weight: 600;
}
.ind-dropdown-btn svg { width: 13px; height: 13px; }
.ind-dropdown-btn:hover { background: var(--capsule-hover); }
.ind-dropdown-menu {
  display: none; position: fixed; z-index: 999;
  min-width: 270px; max-height: 60vh; overflow-y: auto; padding: 8px 0;
  background: var(--card-solid); color: var(--ink-1);
  border: 1px solid var(--hairline); border-radius: min(18px, var(--r-panel));
  box-shadow: var(--card-shadow);
}
.ind-dropdown-menu.open { display: block; }
.ind-dropdown-menu .cat-title {
  font-size: 9px; font-weight: 700; letter-spacing: 0.9px; text-transform: uppercase;
  color: var(--ink-3); padding: 8px 16px 3px;
}
.ind-dropdown-menu .cat-title:first-child { padding-top: 10px; }
.ind-dropdown-menu label {
  display: flex; align-items: center; gap: 8px; margin: 0 6px; padding: 5px 10px;
  border-radius: min(10px, var(--r-tile)); font-size: 12px; cursor: pointer; transition: background .15s;
}
.ind-dropdown-menu label:hover { background: var(--rail); }
.ind-dropdown-menu label input { margin: 0; accent-color: var(--accent); }
/* Une ligne : la case, le nom et sa phrase « C'est quoi ? », (Complet) l'importance, le « i ». */
.ind-dropdown-menu label.aff-ligne { align-items: flex-start; padding-top: 6px; padding-bottom: 6px; }
.ind-dropdown-menu label.aff-ligne input { margin-top: 2px; flex-shrink: 0; }
.aff-texte { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.aff-nom { font-weight: 600; }
.aff-quoi { font-size: 11px; line-height: 1.35; font-weight: 400; color: var(--ink-2); }
/* La légende des icônes (js/icones.js), sous « Ce que dit le graphique ». */
.aff-legende { display: flex; flex-wrap: wrap; gap: 3px 12px; margin: 2px 8px 6px; font-size: 11px; line-height: 1.35; color: var(--ink-2); }
.aff-legende[hidden] { display: none; }
.aff-leg { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.aff-leg .ico { width: 11px; height: 11px; flex: none; color: var(--ink-1); }
.ind-dropdown-menu label.aff-ligne:hover .aff-quoi { color: inherit; }
.ind-dropdown-menu label.aff-ligne .info-btn { flex-shrink: 0; margin-top: 1px; }
/* L'importance : une FORME et un MOT, jamais la couleur seule — disque plein « courant »,
   demi-disque « utile », anneau « spécialisé ». */
.aff-imp {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px; margin-top: 1px; padding: 1px 7px 1px 5px;
  border-radius: var(--r-bar); background: var(--rail); color: var(--ink-2);
  font-size: 9.5px; font-weight: 650; line-height: 15px; white-space: nowrap;
}
.aff-imp::before {
  content: ''; flex-shrink: 0; width: 8px; height: 8px; box-sizing: border-box; border-radius: 50%;
  border: 1.5px solid currentColor;
}
.aff-imp.imp-courant::before { background: currentColor; }
.aff-imp.imp-utile::before { background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
.aff-imp.imp-special::before { background: transparent; }
/* La tête du panneau : « Tout afficher », « Revenir au départ », « Mon écran », puis les préréglages. */
.aff-tete { padding: 6px 12px 4px; }
.aff-boutons, .aff-presets { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.aff-presets { margin-top: 7px; }
.aff-presets-titre { margin-right: 2px; font-size: 9px; font-weight: 700; letter-spacing: 0.9px; text-transform: uppercase; color: var(--ink-3); }
.aff-btn, .aff-preset {
  font: inherit; font-size: 11.5px; font-weight: 650; padding: 4px 11px; border-radius: var(--r-bar); cursor: pointer;
  color: var(--ink-1); background: var(--rail); border: 1px solid var(--hairline);
}
/* « Tout afficher » (.aff-tout) est une action, pas un état : il garde l'habit des autres .aff-btn.
   Rempli de l'accent (PR #29), il avait l'air enfoncé, ou plus allumé que l'affichage en cours
   (revue du 14/10, C14). Le fond plein reste au seul bouton enfoncé (aria-pressed). */
.aff-preset { font-size: 11px; font-weight: 600; color: var(--ink-2); background: transparent; }
.aff-preset[aria-pressed="true"] { color: var(--pill-actif-ink); background: var(--pill-actif); border-color: transparent; font-weight: 700; }
.aff-btn:hover, .aff-preset:hover, .aff-btn:focus-visible, .aff-preset:focus-visible { border-color: var(--accent); outline: none; }
.aff-tete ~ .ind-filtre { margin-top: 0; padding-top: 6px; }
/* « Mon écran » (plan du site, idée 9) : enfoncé quand l'affichage est exactement le sien. Sous les
   préréglages, le lien qui le garde, puis la phrase qui le confirme (pas de fenêtre). */
.aff-btn.aff-mon-ecran[aria-pressed="true"] { color: var(--pill-actif-ink); background: var(--pill-actif); border-color: transparent; }
/* Bureau 95 et son contraste (structure « fenetres ») : ces boutons ont le relief du thème, comme
   « Ajouter un palier » et les boutons des Légendes — gris, clair en haut, sombre en bas ; appuyé
   pendant le clic ; enfoncé quand il est l'affichage en cours. Ils étaient blancs et plats, à
   filet gris (revue du 14/10, M19). Pas de survol coloré en 1995 : le focus reste le pointillé. */
:root[data-structure="fenetres"] :is(.aff-btn, .aff-preset) { background: var(--surface); border-color: transparent; box-shadow: var(--releve); }
:root[data-structure="fenetres"] :is(.aff-btn, .aff-preset):active { box-shadow: var(--appuye); }
:root[data-structure="fenetres"] :is(.aff-btn, .aff-preset)[aria-pressed="true"] { background: var(--pill-actif); box-shadow: var(--enfonce-mince); }
.aff-garder, .aff-garde-dit { display: block; margin: 5px 0 0; padding: 3px 0; font: inherit; font-size: 11px; font-weight: 600; text-align: left; }
.aff-garder { color: var(--accent-2); background: none; border: 0; cursor: pointer; }
.aff-garder:hover, .aff-garder:focus-visible { text-decoration: underline; outline: none; }
.aff-garde-dit { color: var(--ink-2); }
@media (pointer: coarse) { .aff-garder { min-height: 40px; } }
/* « Réglages fins », repliés en bas du Complet : les réglages d'affichage (js/reglages.js). */
.aff-fins { margin: 10px 6px 2px; border-top: 1px solid var(--hairline); }
.aff-fins > summary {
  padding: 9px 10px 5px; cursor: pointer; font-size: 9px; font-weight: 700; letter-spacing: 0.9px;
  text-transform: uppercase; color: var(--ink-3);
}
.aff-fins > summary:hover, .aff-fins > summary:focus-visible { color: var(--ink-1); outline: none; }
.aff-fins-corps { padding: 0 10px 8px; font-size: 12px; line-height: 1.45; color: var(--ink-2); }
.aff-fins-corps .fiche-simple { margin: 4px 0 6px; font-size: 11.5px; color: var(--ink-2); }
.aff-fins-corps h4 { margin: 12px 0 4px; font-size: 10px; letter-spacing: 0.8px; text-transform: uppercase; color: var(--ink-3); }
.aff-fins-corps .fine { font-size: 10.5px; color: var(--ink-3); }
/* Ses <label> ne sont pas des lignes du panneau : ni leur boîte, ni leur survol. */
.ind-dropdown-menu .aff-fins label.reglage {
  display: flex; flex-direction: column; align-items: stretch; gap: 4px; margin: 8px 0; padding: 0;
  border-radius: 0; font-size: 12px; color: var(--ink-2); cursor: default; background: none;
}
.ind-dropdown-menu .aff-fins label.reglage:hover { background: none; color: var(--ink-2); }
.ind-dropdown-menu .aff-fins label.puce-case { display: inline-flex; gap: 4px; margin: 0; padding: 2px 8px; border-radius: var(--r-bar); font-size: 11.5px; }
.ind-dropdown-menu .aff-fins label.puce-case:hover { color: var(--ink-1); background: var(--rail); }
/* Une couche qui ne dessine rien sur la paire affichée : grisée, et elle dit pourquoi. */
.ind-dropdown-menu label.indispo { color: var(--ink-3); cursor: default; }
.ind-dropdown-menu label .ind-seul { font-size: 10px; font-weight: 600; color: var(--ink-3); white-space: nowrap; }
/* « Figures passées » (Complet) : un choix à trois états, sa phrase dessous, en petit. */
/* « Figures passées » (Complet) : cochée, le choix « validées seulement / toutes » sous sa phrase. */
.ind-passees select {
  align-self: flex-start; max-width: 100%; margin-top: 4px; padding: 2px 6px; border-radius: min(8px, var(--r-tile)); font: inherit; font-size: 11.5px;
  color: var(--ink-1); background: var(--rail); border: 1px solid var(--hairline);
}
@media (pointer: coarse) { .ind-passees select { min-height: 40px; } }
/* « Aide à la lecture » (Complet) : deux cases, séparées des calques par un filet — ce ne sont pas
   des indicateurs (ni importance ni fiche). */
.ind-dropdown-menu .aff-aide-titre { margin: 8px 6px 0; padding-top: 10px; border-top: 1px solid var(--hairline); }
/* « Outils » (plan du 13/10/2026, idée 7) : un bouton par outil — la calculette de risque —, juste
   avant les « Réglages fins », séparé par un filet ; carré dans les thèmes carrés (--r-bar). */
.aff-outils { display: flex; flex-wrap: wrap; align-items: center; gap: 5px 8px; margin: 10px 6px 0; padding: 10px 10px 2px; border-top: 1px solid var(--hairline); }
.aff-outils[hidden] { display: none; }
.aff-outils-titre { font-size: 9px; font-weight: 700; letter-spacing: 0.9px; text-transform: uppercase; color: var(--ink-3); }
.aff-outils .aff-btn { border-radius: var(--r-bar); }
@media (pointer: coarse) { .aff-outils .aff-btn { min-height: 40px; } }
/* L'aperçu du menu : ce que c'est et comment s'en servir, pour la ligne survolée ou touchée.
   Collé en bas du menu (qui défile), toujours visible. */
.ind-dropdown-menu { max-width: min(380px, calc(100vw - 16px)); }
.ind-dropdown-menu label[hidden], .ind-dropdown-menu .cat-title[hidden] { display: none; }
.ind-apercu {
  position: sticky; bottom: -8px; margin: 8px 0 -8px; padding: 9px 16px 11px;
  background: var(--card-solid); border-top: 1px solid var(--hairline);
  font-size: 11.5px; line-height: 1.45; color: var(--ink-2); white-space: normal;
  max-height: 42vh; overflow-y: auto;
}
.ind-apercu p { margin: 0 0 5px; }
.ind-apercu b { color: var(--ink-1); }
.ind-apercu .ind-apercu-titre { font-weight: 700; color: var(--ink-1); font-size: 12px; }
.ind-apercu .ind-apercu-vide { color: var(--ink-3); margin: 0; }
.ind-apercu .lien { padding: 0; font: inherit; font-size: 11px; font-weight: 600; color: var(--accent-2); background: none; border: 0; cursor: pointer; }
.ind-apercu .lien:hover { text-decoration: underline; }
.ind-filtre { position: sticky; top: -8px; z-index: 1; margin: -8px 0 2px; padding: 10px 10px 6px; background: var(--card-solid); }
.ind-filtre input {
  width: 100%; box-sizing: border-box; padding: 6px 10px; border-radius: var(--r-bar); font: inherit; font-size: 12px;
  color: var(--ink-1); background: var(--rail); border: 1px solid var(--hairline);
}
.ind-filtre input:focus { outline: none; border-color: var(--accent); }
.ind-aucun { margin: 6px 16px; font-size: 11.5px; color: var(--ink-3); }
/* Bureau : l'aperçu à droite de la liste, la liste garde toute sa hauteur. Le Complet est plus
   large (chaque ligne a sa phrase et son importance) ; le Lisible, plus court. */
@media (min-width: 769px) {
  .ind-dropdown-menu.open { display: grid; grid-template-columns: minmax(0, 1fr) 290px; align-items: start; }
  .ind-dropdown-menu { width: min(780px, calc(100vw - 16px)); max-width: min(780px, calc(100vw - 16px)); }
  .ind-apercu { position: sticky; top: 0; bottom: auto; margin: -8px 0 -8px; min-height: 100%; max-height: none; box-sizing: border-box;
    padding: 14px 16px; border-top: 0; border-left: 1px solid var(--hairline); }
}
/* Bureau 95, téléphone : l'aperçu collant, opaque, couvrait le relief de la fenêtre (une ombre
   intérieure) à gauche, à droite et en bas, et dépassait de 5 px sa marge de 3 px : le panneau
   n'avait plus de bord, la phrase du résumé dessous paraissait coupée. Il s'arrête au bas visible du
   panneau et porte le relief (revue du 14/10, C31). */
@media (max-width: 768px) {
  :root[data-structure="fenetres"] .ind-apercu { bottom: -3px; margin-bottom: -3px; box-shadow: var(--releve); }
}
.ind-compte {
  min-width: 16px; padding: 0 5px; border-radius: var(--r-bar); font-size: 10px; line-height: 16px; text-align: center;
  background: var(--accent); color: var(--card-solid);
}
.ind-compte[hidden] { display: none !important; }
/* Planche : le pied est compté au pixel (deux rangées) ; le compte y reste dans le menu, pas sur le bouton. */
.plan-pied .ind-compte { display: none !important; }
/* Planche, bureau : les noms du ruban (« Sur les bougies », « EMA 20 », « Stochastique », « 1 j »)
   sont plus longs que les abréviations d'avant ; les pastilles de la nomenclature sont resserrées
   pour qu'elle garde ses deux rangées (le thème lui compte ≈ 690 px à côté du cartouche). */
/* Planche : la « date de révision » (#updated) est l'heure de l'APPAREIL (js/format.js). Les
   feuilles Cyanotype et Diazo écrivent « UTC » en dur après elle : le fuseau de l'appareil, posé
   par js/structures.js dans data-fuseau, le remplace (sélecteur plus précis que celui du thème). */
html[data-structure="planche"] .plan-cartouche > #updated:not(:empty)::after { content: attr(data-fuseau); }
/* Planche : la police à chasse fixe (Overpass Mono) liait « ffi » et « fi » dans une seule case
   (« Aﬃchage », « ﬁchier ») ; une lettre par case, partout dans la page (revue du 14/10, C24). Le
   bouton « Affichage » s'élargit de 14 px : le ruban du téléphone a ses réglages serrés plus bas.
   Le canvas suit (ligaturesCanvas, js/app.js). */
html[data-structure="planche"] { font-variant-ligatures: none; }
/* Planche : la case « Ind. de révision » tient dans sa colonne, même quand la date de révision
   s'allonge (publication d'un autre jour : « 10/10 23:18 » au lieu de « 23:18 ») et resserre les
   colonnes. Son titre débordait de 7 px à 1024 px : le cartouche débordait, et ajusterKpis
   masquait le VIX pour lui faire place. Titre resserré, et rien ne déborde de la case. */
:root[data-structure="planche"] .plan-cartouche .kpi-age { padding-left: 5px; padding-right: 5px; min-width: 0; overflow: hidden; }
:root[data-structure="planche"] .plan-cartouche .kpi-age::before { letter-spacing: 0.06em; }
@media (min-width: 1280px) {
  :root[data-structure="planche"] .plan-pied .indicator-bar label { padding-left: 3px; padding-right: 3px; }
  :root[data-structure="planche"] .plan-pied .indicator-bar label[style*="--dot"] .ind-label::before { margin-right: 4px; }
  :root[data-structure="planche"] .plan-pied .indicator-bar .section-title { letter-spacing: 0.06em; }
  /* Les chiffres clés au format français sont plus larges (« +96,94 M $ ») : des cases un peu
     plus serrées rendent au ruban la place de ses deux rangées ; le fuseau passe sous l'heure,
     sa colonne garde la largeur de son titre (« Date de rév. »), quel que soit le fuseau. */
  :root[data-structure="planche"] .plan-cartouche .kpi,
  :root[data-structure="planche"] .plan-cartouche .kpi:first-child { padding-left: 5px; padding-right: 5px; }
  :root[data-structure="planche"] .plan-cartouche .kpi b { font-size: 12px; }
  :root[data-structure="planche"] .plan-cartouche > #updated { flex-direction: column; line-height: 1.1; }
  :root[data-structure="planche"] .plan-cartouche > #updated:not(:empty)::after { margin-left: 0; }
}
/* Planche, téléphone : les cinq colonnes égales coupaient « CVD 24H −118,98 M $ » (le « $ » sous la
   case voisine, 12 px de trop à 390, 18 à 360). Les colonnes suivent leur contenu : rien ne déborde,
   la grille reste dans la cartouche, la hauteur des rangées ne change pas (revue du 14/10, C26). */
@media (max-width: 768px) {
  :root[data-structure="planche"] .plan-cartouche > .kpis { grid-template-columns: repeat(5, minmax(min-content, auto)); }
}
/* Le décor de la barre du bas (« Format A0 · éch. 1:1 », « Information voyageurs · ») ne porte aucune
   valeur : là où il passait sur deux lignes, poussait « Saṃsāra » sous son icône et collait le point
   vivant à la paire, il s'efface (Planche sous 390 px, Gare sous 380 px ; revue du 14/10, C29). */
@media (max-width: 389px) { :root[data-structure="planche"] .aero-taskbar .plan-format { display: none; } }
@media (max-width: 379px) { :root[data-structure="tableau"] .aero-taskbar .gare-info { display: none; } }

/* ─── 6. Graphique ──────────────────────────────────────────────────────────── */
.main-area { display: flex; flex: 1; min-height: 0; gap: var(--gap); overflow: hidden; }
.chart-container {
  flex: 1; min-width: 0;
  --graphe-marge: 16px; padding: var(--graphe-marge); border-radius: var(--r-panel);
}
/* Anneau : même verre que les autres surfaces, sur la seule bande de bord (le padding), SOUS le
   canvas — en QUATRE bandes : haut et bas (.lg-ring::before / ::after), gauche et droite
   (.lg-ring-cotes). Un élément unique masqué à la bande gardait la boîte entière du conteneur :
   chaque image du canvas (réticule, étiquette du prix chaque seconde, bougies) y faisait
   recalculer le flou de 1 404 × 632 px — Aero au repos : 129 ms de CPU par seconde, 92 en bandes
   (page entière, rendu logiciel, mesuré le 07/10/2026). Chaque bande se prolonge de
   --anneau-fond (48 px ≈ 3 σ du flou) sous le canvas, masquée : le flou y lit le même fond que
   l'anneau d'un seul tenant (des bandes de 16 px seules floutaient moins, la trame
   transparaissait). Seuls les quatre coins diffèrent encore, de quelques niveaux sur ~200 px.
   Le canvas opaque couvre l'intérieur : seul le bord est flouté. */
.lg-ring, .lg-ring-cotes { position: absolute; inset: 0; z-index: 0; pointer-events: none; border-radius: inherit; --anneau-fond: 48px; }
.lg-ring::before, .lg-ring::after, .lg-ring-cotes::before, .lg-ring-cotes::after {
  content: ''; position: absolute;
  -webkit-backdrop-filter: var(--verre); backdrop-filter: var(--verre);
}
.lg-ring::before { left: 0; right: 0; top: 0; height: calc(var(--graphe-marge) + var(--anneau-fond));
  border-top-left-radius: inherit; border-top-right-radius: inherit;
  -webkit-mask: linear-gradient(#000 0 0) top / 100% var(--graphe-marge) no-repeat; mask: linear-gradient(#000 0 0) top / 100% var(--graphe-marge) no-repeat; }
.lg-ring::after { left: 0; right: 0; bottom: 0; height: calc(var(--graphe-marge) + var(--anneau-fond));
  border-bottom-left-radius: inherit; border-bottom-right-radius: inherit;
  -webkit-mask: linear-gradient(#000 0 0) bottom / 100% var(--graphe-marge) no-repeat; mask: linear-gradient(#000 0 0) bottom / 100% var(--graphe-marge) no-repeat; }
.lg-ring-cotes::before { left: 0; top: 0; bottom: 0; width: calc(var(--graphe-marge) + var(--anneau-fond));
  border-top-left-radius: inherit; border-bottom-left-radius: inherit;
  -webkit-mask: linear-gradient(#000 0 0) left center / var(--graphe-marge) calc(100% - 2 * var(--graphe-marge)) no-repeat;
  mask: linear-gradient(#000 0 0) left center / var(--graphe-marge) calc(100% - 2 * var(--graphe-marge)) no-repeat; }
.lg-ring-cotes::after { right: 0; top: 0; bottom: 0; width: calc(var(--graphe-marge) + var(--anneau-fond));
  border-top-right-radius: inherit; border-bottom-right-radius: inherit;
  -webkit-mask: linear-gradient(#000 0 0) right center / var(--graphe-marge) calc(100% - 2 * var(--graphe-marge)) no-repeat;
  mask: linear-gradient(#000 0 0) right center / var(--graphe-marge) calc(100% - 2 * var(--graphe-marge)) no-repeat; }
.chart-container canvas {
  position: relative; z-index: 1;
  display: block; width: 100%; height: 100%;
  border-radius: 6px;
  background: var(--chart-lueur), linear-gradient(160deg, var(--chart-1) 0%, var(--chart-2) 48%, var(--chart-3) 100%);
  box-shadow: var(--chart-creux);
  /* Le graphique gère lui-même pan et pincement : sans ceci le navigateur mobile lance son
     propre défilement en concurrence (pan saccadé, double-tap qui zoome la page). */
  touch-action: none;
}
/* Le calque (réticule, infobulles, étiquette du dernier prix) : posé sur le graphique, à la même
   taille (js/app.js, resizeCanvas), transparent et inerte au pointeur — les gestes restent au
   graphique. */
.chart-container canvas.calque {
  position: absolute; z-index: 2; pointer-events: none;
  background: none; box-shadow: none; border-radius: 0;
}

/* ─── 7. Panneau « Infos du marché » ──────────────────────────────────────── */
.feed-panel {
  z-index: 90; flex-shrink: 0;
  display: flex; width: 390px;
  border-radius: var(--r-panel);
  transition: width .3s cubic-bezier(0.4, 0, 0.2, 1);
}
.feed-panel.collapsed { width: 34px; }
.feed-panel-handle {
  position: relative; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  width: 34px; padding: 12px 0;
  writing-mode: vertical-rl; text-align: center; text-transform: uppercase;
  font-size: 9.5px; font-weight: 700; letter-spacing: 3px;
  color: var(--ink-2); background: var(--poignee);
  border-right: 1px solid var(--hairline);
  cursor: pointer; user-select: none;
  transition: color .2s ease, background .2s ease;
}
.feed-panel-handle::after {
  content: ''; position: absolute; left: 0; top: 22%; bottom: 22%; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--brand); opacity: 0.85;
}
.feed-panel-handle:hover { color: var(--accent-2); background: var(--poignee-hover); }
.feed-panel-body { flex: 1; overflow-y: auto; overflow-x: hidden; }
.feed-panel.collapsed .feed-panel-body { display: none; }
.feed { padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.loading { text-align: center; padding: 48px; color: var(--ink-2); }
.error {
  margin: 16px; padding: 40px; text-align: center;
  color: var(--down-ink); background: var(--down-soft); border-radius: min(18px, var(--r-card));
}

/* ─── 8. Cartes ─────────────────────────────────────────────────────────────── */
.demon-card {
  --teinte: var(--accent-2);
  position: relative; overflow: hidden;
  padding: 15px 16px 16px;
  background: var(--card); color: var(--ink-1);
  border: 1px solid var(--card-edge); border-radius: var(--r-card);
  box-shadow: var(--card-shadow), inset 0 1px 0 var(--card-hi);
}
.demon-card::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 42%;
  background: var(--card-reflet); pointer-events: none; z-index: 0;
}
/* Filet de couleur en tête de carte : l'identité de la carte, discrète. */
.demon-card::after {
  content: ''; position: absolute; top: 0; left: 22px; right: 22px; height: 2px;
  border-radius: 0 0 2px 2px; pointer-events: none; opacity: 0.7;
  background: linear-gradient(90deg, transparent, var(--teinte), transparent);
}
.demon-card > * { position: relative; z-index: 1; }
.carte-marche { --teinte: #0ea5c6; } .carte-macro { --teinte: #16a37a; }
.carte-ind { --teinte: #4f6cf0; }    .carte-micro { --teinte: #8b5cf6; }
.carte-liq { --teinte: #0891b2; }    .carte-flux { --teinte: #64748b; }
.carte-live { --teinte: #f59e0b; }   .carte-tape { --teinte: #0ea5e9; }
.carte-temps { --teinte: #7c8db5; }
.carte-horloges { --teinte: #7c8db5; } .carte-contre { --teinte: #16a37a; }
.demon-header { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; flex-wrap: nowrap; }
.demon-titres { min-width: 0; }
.demon-avatar { font-size: 28px; flex-shrink: 0; }
.avatar-orb {
  position: relative; flex-shrink: 0;
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 18px; font-weight: 700;
  background: var(--teinte);
  background: radial-gradient(circle at 32% 26%, color-mix(in srgb, var(--teinte) 30%, white) 0%,
              var(--teinte) 55%, color-mix(in srgb, var(--teinte) 70%, black) 100%);
  border: 1px solid rgba(255,255,255,0.85);
  box-shadow: 0 4px 12px rgba(30,45,110,0.22), inset 0 -3px 6px rgba(0,0,0,0.22),
              inset 0 2px 4px rgba(255,255,255,0.5);
}
.avatar-orb::after {
  content: ''; position: absolute; top: 2px; left: 6px; width: 20px; height: 9px; pointer-events: none;
  border-radius: 15px 15px 8px 8px / 12px 12px 4px 4px;
  background: linear-gradient(180deg, rgba(255,255,255,0.9) 0%, rgba(255,255,255,0.1) 100%);
}
.avatar-orb svg { position: relative; z-index: 1; width: 17px; height: 17px; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.25)); }
.demon-name { color: var(--ink-1); font-size: 14px; font-weight: 700; letter-spacing: -0.1px; }
.demon-role { font-size: 10.5px; color: var(--ink-3); line-height: 1.35; }
.demon-right { margin-left: auto; font-size: 10px; color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.demon-body { font-size: 12px; line-height: 1.5; color: var(--ink-1); }
/* Apparition au PREMIER rendu seulement (les cartes sont réécrites toutes les 60 s). */
@keyframes entree { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.demon-card.entree { animation: entree .55s cubic-bezier(.2,.7,.2,1) both; }
.demon-card.entree:nth-child(2) { animation-delay: .05s; } .demon-card.entree:nth-child(3) { animation-delay: .1s; }
.demon-card.entree:nth-child(4) { animation-delay: .15s; } .demon-card.entree:nth-child(5) { animation-delay: .2s; }
.demon-card.entree:nth-child(6) { animation-delay: .25s; } .demon-card.entree:nth-child(7) { animation-delay: .3s; }

/* Texte signé, pastilles, badges */
.stat-val { font-weight: 700; color: var(--accent); }
.stat-pos { color: var(--up-ink); font-weight: 700; }
.stat-neg { color: var(--down-ink); font-weight: 700; }
.badge {
  display: inline-block; white-space: nowrap;
  padding: 2px 8px; border-radius: var(--r-bar);
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.4px;
}
.badge-hausser { background: var(--up-soft); color: var(--up-ink); }
.badge-baissier { background: var(--down-soft); color: var(--down-ink); }
.chip {
  display: inline-flex; align-items: center; gap: 3px; white-space: nowrap;
  padding: 1px 8px; border-radius: var(--r-bar);
  font-size: 10.5px; font-weight: 650; background: var(--rail); color: var(--ink-2);
}
.chip.pos { background: var(--up-soft); color: var(--up-ink); }
.chip.neg { background: var(--down-soft); color: var(--down-ink); }
.lbl { font-size: 9.5px; font-weight: 700; letter-spacing: 0.7px; text-transform: uppercase; color: var(--ink-3); }
.mute { color: var(--ink-3); }
.fine { font-size: 10.5px; color: var(--ink-3); line-height: 1.45; }

/* Chiffre héros + tuiles */
.hero { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.hero-val { font-size: 26px; font-weight: 700; letter-spacing: -0.6px; color: var(--ink-1); line-height: 1.15; }
/* Le prix PUBLIÉ (carte « Fourchette des 24 h », Expert) : plus petit que le prix en direct de
   l'en-tête (23 px, 15 px au plus petit selon le thème) — il était le plus gros chiffre du
   panneau (26 px), deux prix contradictoires dont le plus vieux en plus grand. Son nom le précède. */
.hero.hero-publie .hero-val { font-size: 17px; letter-spacing: -0.3px; }
.hero.hero-publie .hero-lbl { font-size: 9.5px; font-weight: 700; letter-spacing: 0.7px; text-transform: uppercase; color: var(--ink-3); }
@media (max-width: 800px) { .hero.hero-publie .hero-val { font-size: 14px; } }
.tuiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.tuile { background: var(--rail); border-radius: var(--r-tile); padding: 8px 11px 9px; min-width: 0; }
.tuile .val { font-size: 17px; font-weight: 700; letter-spacing: -0.3px; color: var(--ink-1); line-height: 1.3; }
.tuile .sub { font-size: 10.5px; color: var(--ink-3); }
.bloc { margin-top: 13px; }
.bloc-titre { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.ligne { display: flex; align-items: center; flex-wrap: wrap; gap: 5px 8px; }

/* Position dans une plage (bas/haut 24 h, canal S/R) */
.track { margin-top: 8px; }
.track-rail { position: relative; height: 6px; border-radius: var(--r-bar); background: var(--rail); }
.track-fill {
  position: absolute; left: 0; top: 0; bottom: 0; border-radius: var(--r-bar); opacity: 0.55;
  background: var(--teinte);
  background: linear-gradient(90deg, color-mix(in srgb, var(--teinte) 15%, transparent), var(--teinte));
}
.track-dot {
  position: absolute; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
  background: var(--teinte); box-shadow: 0 0 0 2px var(--card-solid), 0 2px 6px rgba(0,0,0,0.25);
}
.track-legende { display: flex; justify-content: space-between; gap: 8px; font-size: 10.5px; color: var(--ink-3); margin-top: 5px; }
.track-legende b { color: var(--ink-1); font-weight: 650; }

/* Jauge RSI : zones 30 / 70 teintées, un point par RSI (6, 12, 24), de la couleur de sa ligne */
.rsi-meter { position: relative; flex: 1 1 70px; max-width: 130px; height: 5px; border-radius: var(--r-bar); background: var(--rail); margin: 0 4px; }
.rsi-zone { position: absolute; top: 0; bottom: 0; width: 30%; }
/* Les deux zones de la même teinte neutre : sous 30, ce n'est pas une « bonne nouvelle » (vert),
   ni au-dessus de 70 une mauvaise (rouge) — un RSI bas n'annonce aucun rebond. */
.rsi-zone.bas { left: 0; border-radius: var(--r-bar) 0 0 var(--r-bar); background: var(--warn-soft); }
.rsi-zone.haut { right: 0; border-radius: 0 var(--r-bar) var(--r-bar) 0; background: var(--warn-soft); }
.rsi-dot {
  position: absolute; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%;
  background: var(--accent-2); box-shadow: 0 0 0 2px var(--card-solid), 0 2px 6px rgba(0,0,0,0.2);
}
.tf-row + .tf-row { margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--hairline); }
.tf-tete { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.tf-nom {
  font-size: 10.5px; font-weight: 750; color: var(--ink-1); background: var(--rail);
  border-radius: min(7px, var(--r-tile)); padding: 1px 7px; min-width: 30px; text-align: center;
}
.tf-rsi { font-size: 11px; color: var(--ink-3); }
.tf-rsi b { color: var(--ink-1); font-size: 13px; }
.tf-tete .badge { margin-left: auto; }
.tf-row .track { margin-top: 9px; }
.tf-pied { margin-top: 6px; font-size: 10.5px; color: var(--ink-3); line-height: 1.45; }

/* Barre à deux segments (L/S, bids/asks) — 2 px de surface entre les segments */
.split { display: flex; gap: 2px; height: 8px; border-radius: var(--r-bar); overflow: hidden; margin-top: 6px; }
.split > span { display: block; height: 100%; }
.split-a { background: var(--up); }
.split-b { flex: 1; background: var(--down); }
.split-legende { display: flex; justify-content: space-between; gap: 8px; font-size: 10.5px; color: var(--ink-3); margin-top: 4px; }
.split-legende b { color: var(--ink-1); font-weight: 650; }

/* Barres divergentes (CVD) centrées sur zéro */
.dv-row { display: grid; grid-template-columns: 28px minmax(40px, 1fr) auto; align-items: center; gap: 8px; margin: 4px 0; }
.dv-lbl { font-size: 10.5px; font-weight: 700; color: var(--ink-3); }
.dv-bar { position: relative; height: 8px; background: var(--rail); border-radius: var(--r-bar); }
.dv-axe { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1px; background: var(--ink-3); opacity: 0.45; }
.dv-fill { position: absolute; top: 0; bottom: 0; }
/* Le CVD n'est ni « bien » ni « mal » : une seule teinte neutre, le côté de l'axe dit le signe (le
   vert et le rouge disent seulement « le prix monte / descend »). */
.dv-fill.pos { background: var(--ink-3); border-radius: 0 var(--r-bar) var(--r-bar) 0; }
.dv-fill.neg { background: var(--ink-3); border-radius: var(--r-bar) 0 0 var(--r-bar); }
.dv-val { font-size: 11px; font-weight: 650; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }

/* Mini-axe de prix (GEX) : put wall · zéro γ · spot · call wall */
.axe { position: relative; height: 56px; margin: 8px 2px 4px; }
.axe-rail { position: absolute; left: 0; right: 0; top: 27px; height: 2px; border-radius: 2px; background: var(--rail); }
.axe-pt { position: absolute; top: 0; bottom: 0; width: 0; }
.axe-pt i {
  position: absolute; top: 23px; left: -5px; width: 10px; height: 10px; border-radius: 50%;
  background: var(--ink-3); box-shadow: 0 0 0 2px var(--card-solid);
}
.axe-pt b {
  position: absolute; transform: translateX(-50%); white-space: nowrap;
  font-size: 10px; font-weight: 650; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.axe-pt b em { font-style: normal; color: var(--ink-3); font-weight: 600; margin-right: 3px; }
.axe-pt.haut b { top: 2px; } .axe-pt.bas b { bottom: 0; }
.axe-pt.spot i { width: 12px; height: 12px; left: -6px; top: 22px; background: var(--accent-2); }
.axe-pt.put i { background: var(--down); } .axe-pt.call i { background: var(--up); }
.axe-pt.zg i { border-radius: 2px; transform: rotate(45deg); background: var(--ink-2); }

/* Échelle des murs : asks au-dessus, mid, bids au-dessous — comme un carnet */
.ladder { display: flex; flex-direction: column; gap: 3px; margin-top: 8px; }
.lad-row { display: grid; grid-template-columns: 62px minmax(30px, 1fr) 64px; align-items: center; gap: 8px; font-size: 11px; font-variant-numeric: tabular-nums; }
.lad-px { color: var(--ink-1); font-weight: 650; }
.lad-bar { position: relative; height: 9px; }
.lad-bar span { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 0 4px 4px 0; opacity: 0.8; }
.lad-row.ask .lad-bar span { background: var(--down); }
.lad-row.bid .lad-bar span { background: var(--up); }
.lad-q { text-align: right; color: var(--ink-2); }
.lad-mid { display: flex; align-items: center; gap: 8px; font-size: 10px; color: var(--ink-3); margin: 3px 0; }
.lad-mid::before, .lad-mid::after { content: ''; flex: 1; height: 1px; background: var(--hairline); }

/* État du flux */
.etats { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.etat { font-size: 10.5px; font-weight: 650; padding: 2px 9px; border-radius: var(--r-bar); background: var(--up-soft); color: var(--up-ink); }
.etat.ko { background: var(--down-soft); color: var(--down-ink); }

/* Horloges : une ligne par instant affiché — nom, heure UTC, âge ; la panne nommée en clair. */
.horloge-ligne { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; padding: 3px 0; font-size: 11px; border-bottom: 1px solid var(--rail); }
.horloge-ligne:last-child { border-bottom: 0; }
.horloge-ligne .h-nom { flex: 1 1 140px; color: var(--ink-2); min-width: 0; }
.horloge-ligne .h-quand { font-variant-numeric: tabular-nums; color: var(--ink-1); font-weight: 600; }
.horloge-ligne .h-age { font-variant-numeric: tabular-nums; color: var(--ink-3); min-width: 72px; text-align: right; }
.horloge-ligne .h-src, .horloge-ligne .h-seuil { flex-basis: 100%; font-size: 10px; color: var(--ink-3); }
.horloge-ligne .h-panne { flex-basis: 100%; font-size: 10.5px; font-weight: 650; color: var(--down-ink); }
.horloge-ecart { font-size: 11px; font-weight: 650; color: var(--warn-ink); background: var(--warn-soft); border-radius: min(10px, var(--r-tile)); padding: 5px 10px; margin-bottom: 6px; }

/* Contre-expertise : ✓ retrouvé, ≈ cohérent (avec sa borne), ✗ différent (les deux valeurs). */
.age-banner.verif { color: var(--ink-2); background: var(--rail); }
.age-banner.verif::before { box-shadow: 0 0 0 4px var(--rail); }
.contre-compte { font-size: 10.5px; font-weight: 650; color: var(--up-ink); white-space: nowrap; }
.contre-compte.ko { color: var(--down-ink); }
.contre-groupe { margin-top: 6px; font-size: 11px; }
.contre-groupe summary { cursor: pointer; padding: 3px 0; color: var(--ink-1); }
.contre-ligne { display: flex; flex-wrap: wrap; gap: 1px 8px; padding: 2px 0 2px 4px; }
.contre-ligne .c-etat { width: 12px; font-weight: 700; color: var(--up-ink); }
.contre-ligne.e-approx .c-etat { color: var(--ink-2); }
.contre-ligne.e-diff .c-etat, .contre-ligne.e-source .c-etat, .contre-ligne.e-injoignable .c-etat { color: var(--down-ink); }
.contre-ligne .c-nom { flex: 1 1 130px; color: var(--ink-2); min-width: 0; }
.contre-ligne .c-val { font-variant-numeric: tabular-nums; color: var(--ink-1); }
.contre-ligne .c-note, .contre-raison .c-note { flex-basis: 100%; padding-left: 20px; font-size: 10px; color: var(--ink-3); }
.contre-raison { padding: 3px 0 3px 4px; color: var(--ink-2); line-height: 1.5; }
.contre-raison .c-note { display: block; padding-left: 0; font-weight: 650; }
.c-nature { font-style: normal; font-size: 9.5px; color: var(--ink-3); border: 1px solid var(--rail); border-radius: min(6px, var(--r-tile)); padding: 0 4px; }

/* Bandeau d'âge : au-delà de la cadence (15 min), la donnée est vieille et ça doit SE VOIR. */
.age-banner {
  display: flex !important; align-items: center; gap: 9px; margin: 0 0 8px;
  padding: 9px 13px; border-radius: min(16px, var(--r-card));
  font-size: 12px; font-weight: 650;
  color: var(--down-ink); background: var(--down-soft);
}
.age-banner::before {
  content: ''; flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%;
  background: currentColor; box-shadow: 0 0 0 4px var(--down-soft);
}
.age-banner.retard { color: var(--warn-ink); background: var(--warn-soft); }
.age-banner.retard::before { box-shadow: 0 0 0 4px var(--warn-soft); }

/* ─── 9. Modales (mobile, panneau ⚡) ───────────────────────────────────────── */
.modal {
  position: fixed; inset: 0; flex-direction: column; overflow: hidden;
  background: var(--modal-fond); color: var(--ink-1);
}
.modal-tete {
  display: flex; align-items: center; justify-content: space-between; padding: 12px 16px;
  background: var(--card); border-bottom: 1px solid var(--hairline); box-shadow: var(--modal-ombre);
}
.modal-titre {
  font-weight: 800; font-size: 17px; letter-spacing: -0.2px;
  background: var(--brand); -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.modal-titre span { -webkit-text-fill-color: var(--ink-3); color: var(--ink-3); font-size: 11px; font-weight: 600; }
.modal-titre #liveClock { display: block; margin-top: 1px; }
.modal-fermer {
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--card-solid); color: var(--ink-1);
  border: 1px solid var(--hairline); box-shadow: var(--ombre-douce);
}
.modal-fermer svg { width: 15px; height: 15px; }
/* En bas, la place de la barre des tâches (fixe, au-dessus de tout) : elle cachait la dernière
   ligne des modales « Infos du marché » et ⚡ au téléphone. */
.modal-corps { flex: 1; overflow-y: auto; padding: 14px 14px calc(44px + var(--gutter)); display: flex; flex-direction: column; gap: 12px; }
/* Les cartes ne se compriment JAMAIS dans la colonne : sinon elles sont rognées. */
.modal-corps > * { flex-shrink: 0; }

/* ─── 10. Grid Bot ──────────────────────────────────────────────────────────── */
/* « Sur le graphique » (Complet, téléphone) : le texte entier de chaque repère court du tracé, une
   ligne par repère, dans l'ordre du haut vers le bas ; toucher une ligne ouvre la bulle du repère. */
.reperes-section { flex-shrink: 0; position: relative; border-radius: var(--r-panel); }
.reperes-section[hidden] { display: none; }
.reperes-handle {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; min-height: 40px;
  padding: 0 14px; font: 700 13px/1.2 var(--font); color: var(--ink-1); text-align: left;
  background: none; border: 0; border-radius: inherit; cursor: pointer;
}
.reperes-textes { display: flex; flex-direction: column; gap: 1px; padding: 5px 0; min-width: 0; }
.reperes-resume { font-weight: 800; font-size: 13.5px; color: var(--ink-1); }
.reperes-resume:not([hidden]) + #reperesTitre { font-weight: 500; font-size: 11.5px; color: var(--ink-2); }
.reperes-resume[hidden] { display: none; }
.reperes-fleche { font-size: 14px; transition: transform .3s; }
.reperes-section:not(.collapsed) .reperes-fleche { transform: rotate(-90deg); }
/* La liste s'ouvre AU-DESSUS de sa barre, par-dessus le bas du graphique (placerMenu) : le tracé
   garde sa hauteur. Toucher une ligne la ferme et ouvre la bulle du repère. */
.reperes-liste {
  position: fixed; z-index: 999; box-sizing: border-box; list-style: none; margin: 0; padding: 4px 8px;
  max-height: 60vh; overflow-y: auto;
  background: var(--card-solid); color: var(--ink-1);
  border: 1px solid var(--hairline); border-radius: min(var(--r-card), 18px); box-shadow: var(--card-shadow);
}
.reperes-liste[hidden] { display: none; }
.reperes-liste li:first-child button { border-top: 0; }
.reperes-liste button {
  display: flex; gap: 9px; width: 100%; min-height: 40px; padding: 7px 6px; text-align: left;
  font: 500 13px/1.35 var(--font); color: var(--ink-1); background: none; border: 0;
  border-top: 1px solid var(--hairline); cursor: pointer;
}
/* Le repère choisi (aria-current) et celui que la bulle du graphique explique (.survole) : la ligne
   ressort, un filet d'accent à gauche, comme le repère ressort sur le tracé (surbrillanceCalque). */
.reperes-liste button[aria-current="true"], .reperes-liste button.survole {
  background: color-mix(in srgb, var(--accent-2) 12%, var(--card-solid)); border-radius: min(var(--r-tile), 8px);
  box-shadow: inset 3px 0 0 var(--accent-2);
}
.reperes-liste button:hover { background: color-mix(in srgb, var(--accent-2) 7%, transparent); border-radius: min(var(--r-tile), 8px); }
.reperes-trait { flex: 0 0 3px; align-self: stretch; border-radius: 2px; background: var(--trait, var(--ink-3)); }
/* L'icône de la famille d'une info (js/icones.js), la même que sur le graphique, dans sa couleur. */
.reperes-ico { flex: 0 0 13px; width: 13px; height: 13px; margin-top: 2px; }
/* « En résumé » (js/app.js, syntheseElement) : en tête de la liste, mis en valeur. La phrase en
   gras ; un trait de couleur par signal (hausse, baisse, neutre) que les mots disent aussi.
   La boîte est à l'encre neutre du thème (--ink-3), plus à son accent (revue du 14/10, C13) :
   l'accent est la baisse en Gazette et Codex, la hausse en Néon et Bureau 95, et « pas de sens
   net » s'affichait dans la couleur d'un sens. Seule la barre d'un résumé en hausse ou en baisse
   prend leur couleur (ci-dessous). */
.reperes-liste li.synthese {
  margin: 6px 0 8px; padding: 10px 12px 9px; border-radius: min(var(--r-tile), 10px);
  background: color-mix(in srgb, var(--ink-3) 9%, var(--card-solid)); border: 1px solid color-mix(in srgb, var(--ink-3) 35%, transparent);
  border-left: 4px solid var(--ink-3); color: var(--ink-1); font: 500 12.5px/1.4 var(--font);
}
.reperes-liste li.synthese.ton-hausse { border-left-color: var(--up-ink); }
.reperes-liste li.synthese.ton-baisse { border-left-color: var(--down-ink); }
.synthese p { margin: 0; }
.synthese-tete { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); }
.synthese-titre { margin-top: 3px !important; font-size: 14.5px; font-weight: 800; line-height: 1.3; }
.synthese-regle { margin-top: 2px !important; color: var(--ink-2); }
.synthese-sous { margin-top: 8px !important; font-size: 10.5px; font-weight: 700; color: var(--ink-2); }
.synthese-liste { list-style: none; margin: 3px 0 0; padding: 0; }
.synthese-liste li { position: relative; padding: 2px 0 2px 11px; }
.synthese-liste li::before { content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px; border-radius: min(var(--r-tile), 2px); background: var(--ink-3); }
.synthese-liste li.sens-haut::before { background: var(--up-ink); }
.synthese-liste li.sens-bas::before { background: var(--down-ink); }
.synthese-liste li.avec-ico { padding-left: 17px; }
.synthese-liste li.avec-ico::before { display: none; }
.synthese-liste li .ico { position: absolute; left: 0; top: 5px; width: 11px; height: 11px; color: var(--accent-2); }
.synthese-liste li.sens-neutre .ico { color: var(--ink-3); }
.synthese-liste li.sens-haut .ico { color: var(--up-ink); }
.synthese-liste li.sens-bas .ico { color: var(--down-ink); }
.synthese-avert { margin-top: 7px !important; font-size: 10.5px; color: var(--ink-3); }
/* Grand écran, avec « Le détail » : la liste en colonne à droite du graphique, toujours ouverte
   (majReperes y range la liste ; PARAM.guide.colonne et colonneL). */
.reperes-section.colonne { width: var(--colonne-l, 300px); display: flex; flex-direction: column; min-height: 0; }
.reperes-section.colonne .reperes-handle { flex-shrink: 0; }
.reperes-section.colonne .reperes-fleche { display: none; }
.reperes-section.colonne .reperes-liste {
  position: static; z-index: auto; flex: 1; min-height: 0; max-height: none; padding: 0 10px 8px;
  /* Sa hauteur vient de la colonne, jamais de son contenu : le résumé et les repères défilent
     au lieu d'allonger la colonne (une mise en page en colonne, Gare ou Planche, la grandirait). */
  contain: size;
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
.reperes-section.colonne .reperes-liste button { font-size: 12px; min-height: 34px; padding: 6px 4px; }
/* Fenêtre moyenne : la colonne repliée en onglet vertical, comme « Infos du marché ». */
.reperes-section.colonne.collapsed { width: 34px; }
.reperes-section.colonne.collapsed .reperes-handle {
  flex: 1; justify-content: center; padding: 12px 0; writing-mode: vertical-rl; text-transform: uppercase;
  font-size: 9.5px; letter-spacing: 3px; color: var(--ink-2); cursor: pointer;
}
.reperes-section.colonne:not(.collapsed) .reperes-handle { cursor: pointer; }
.strat-section {
  flex-shrink: 0; height: 28px;
  border-radius: var(--r-panel);
  transition: height .3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Ouvert : 46dvh s'adapte aux fenêtres courtes, le max garde le graphe utilisable. */
.strat-section:not(.collapsed) { height: 320px; height: min(46dvh, 320px); }
.strat-handle {
  display: flex; align-items: center; justify-content: space-between;
  height: 28px; padding: 0 18px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.3px; color: var(--ink-1);
  border-bottom: 1px solid var(--hairline);
  cursor: pointer; user-select: none;
}
.strat-handle:hover { color: var(--accent-2); }
.strat-handle-arrow { font-size: 14px; transition: transform .3s; }
.strat-section:not(.collapsed) .strat-handle-arrow { transform: rotate(90deg); }
.strat-body { height: calc(100% - 28px); overflow-y: auto; padding: 12px 18px; }
.strat-section.collapsed .strat-body { display: none; }
.strat-cols { display: flex; gap: 18px; height: 100%; }
/* Config sur 2 colonnes, lues par paires : (Capital|Niveaux) (Prix inf|Prix sup) (TP|SL) (Du|Au).
   L'ordre des params de gridParams() fait ces paires — ne pas déplacer gridLevels. Le `>` est
   obligatoire : avec `display: contents`, :first-child viserait les champs de #stratParams. */
.strat-col-config { flex: 0 0 460px; display: grid; grid-template-columns: 1fr 1fr; gap: 0 10px; align-content: start; }
.strat-col-config > .strat-row:first-child, .strat-col-config > .strat-help { grid-column: 1 / -1; }
#stratParams { display: contents; }
.strat-col-actions { flex: 0 0 130px; display: flex; flex-direction: column; gap: 5px; }
.strat-col-stats { flex: 1; min-width: 200px; font-size: 11px; }
.strat-section .strat-row { display: flex; align-items: center; margin-bottom: 6px; gap: 6px; }
.strat-section .strat-row label { min-width: 75px; font-size: 10px; font-weight: 600; color: var(--ink-3); }
.strat-section .strat-row select,
.strat-section .strat-row input[type="number"],
.strat-section .strat-row input[type="datetime-local"],
.strat-section input[type="datetime-local"] {
  flex: 1; padding: 4px 8px; font-size: 11px; font-family: var(--font);
  background: var(--card); color: var(--ink-1);
  border: 1px solid var(--hairline); border-radius: min(10px, var(--r-tile));
  transition: border-color .15s ease, box-shadow .15s ease;
}
.strat-section .strat-row select:focus, .strat-section .strat-row input:focus {
  outline: none; border-color: var(--accent-2); box-shadow: 0 0 0 3px var(--accent-glow);
}
.strat-btn {
  padding: 5px 10px; cursor: pointer;
  font-family: var(--font); font-size: 11px; font-weight: 700; letter-spacing: 0.2px;
  color: var(--brand-ink); background: var(--brand-fond);
  border: 1px solid transparent; border-radius: var(--r-bar);
  box-shadow: var(--capsule-ombre);
  transition: transform .1s ease, box-shadow .15s ease;
}
.strat-btn:hover { box-shadow: 0 4px 14px var(--accent-glow); }
.strat-btn:active { transform: scale(0.97); }
.strat-btn.secondary { background: var(--card); color: var(--ink-1); }
.strat-btn.forward { background: var(--forward); color: #fff; }
/* Grisé (revue du 14/10, C12) : « Comparer au témoin » quand le témoin est la stratégie choisie. */
.strat-btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.strat-section .strat-stats {
  padding: 10px 12px; line-height: 1.6; font-size: 11px;
  background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r-tile);
}
.strat-help { font-size: 10px; line-height: 1.45; color: var(--ink-3); margin: -2px 0 7px; }
.strat-help .strat-auto { color: var(--ink-1); margin-top: 3px; font-variant-numeric: tabular-nums; }
.strat-stats .verdict { font-weight: 700; margin-bottom: 5px; }
.strat-stats .strat-note { margin-top: 4px; color: var(--ink-2); font-size: 10px; }
.strat-section .strat-toggle {
  margin-top: 4px; text-align: center; cursor: pointer;
  font-size: 10px; font-weight: 650; color: var(--accent-2);
}
.strat-section input.auto-mode { opacity: 0.45; font-style: italic; }

/* ─── 11. Barre des tâches ──────────────────────────────────────────────────── */
.aero-taskbar {
  position: fixed; z-index: 2000;
  left: var(--gutter); right: var(--gutter); bottom: var(--gutter);
  height: 30px; padding: 0 16px; border-radius: var(--r-bar);
  display: flex; align-items: center; justify-content: space-between;
  font-size: 11px; font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.aero-taskbar .taskbar-left { display: flex; align-items: center; gap: 12px; }
.aero-taskbar .taskbar-right { display: flex; align-items: center; gap: 10px; }
.aero-taskbar .taskbar-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  box-shadow: 0 0 6px var(--up); transition: background .3s;
}

/* ─── 12. Mouvement : décoratif, donc coupé à la demande du système ───────────── */
@media (prefers-reduced-motion: reduce) {
  .refresh-dot.ping::after, .demon-card.entree { animation: none !important; }
  .feed-panel, .strat-section { transition: none; }
}

/* ─── 13. Petits écrans ─────────────────────────────────────────────────────────
   ⚠️ Ce bloc reste le DERNIER : il surcharge les règles .strat-* (même spécificité) ;
   placé avant elles, il était neutralisé par la cascade. */
@media (max-width: 800px) {
  :root { --gutter: 7px; --gap: 6px; }
  /* Coins plafonnés à 20 px, jamais plus ronds que le thème : Bureau 95, Cyanotype, Diazo, Gazette
     (--r-panel: 0) gardent leurs fenêtres carrées au téléphone (demande du 11/10/2026). */
  .chart-container { --graphe-marge: 11px; border-radius: min(var(--r-panel), 20px); }
  .header { padding: 6px 9px; gap: 6px; }
  /* L'orbe est DÉCORATIF, le badge porte de la donnée : c'est l'orbe qui cède. */
  .header-orb { display: none; }
  .header-left { gap: 6px; min-width: 0; flex: 1 1 auto; }
  .header-left h1 { font-size: 15px; }
  .header-right { gap: 6px; }
  #updated { display: none; }
  /* Les chiffres clés sont dans « Infos du marché » (bouton du panneau) : sur téléphone, la
     place va au prix. Sauf l'alerte : publication en retard, la pastille d'âge (« en retard ·
     25 min ») reste, seule de la bande, à côté du prix — panneau fermé, elle se voit. */
  .kpis { display: none; }
  :root[data-chiffres="1"] .header > .kpis.vieux { display: flex; flex: 0 0 auto; height: auto; }
  :root[data-chiffres="1"] .header > .kpis.vieux > :not(.kpi-age) { display: none; }
  :root[data-chiffres="1"] .header > .kpis.vieux > .kpi-age { margin-left: 0; }
  .hero-prix { gap: 7px; }
  .price-badge { font-size: 17px; gap: 6px; }
  .var24 { font-size: 10.5px; padding: 2px 7px; }
  .theme-btn.ico-btn { width: 30px; height: 30px; }
  .theme-btn.ico-btn svg { width: 15px; height: 15px; }
}
/* Entre 481 et 1100 px, le prix et les boutons occupent déjà la rangée (à 1024 px, il restait
   37 px à la bande) : la pastille passe sur une 2e rangée, sans rien prendre au prix — seule
   jusqu'à 800 px, après les boutons au-delà s'ils y sont passés (sous 481 px, elle est à côté
   du prix ; au-delà de 1100 px, dans la bande). */
@media (min-width: 481px) and (max-width: 1100px) {
  html[data-chiffres="1"]:not([data-structure]) .header:has(> .kpis.vieux) { flex-wrap: wrap; row-gap: 4px; }
  html[data-chiffres="1"]:not([data-structure]) .header > .kpis.vieux { order: 3; flex: 0 0 auto; height: auto; }
  html[data-chiffres="1"]:not([data-structure]) .header > .kpis.vieux > :not(.kpi-age) { display: none; }
  html[data-chiffres="1"]:not([data-structure]) .header > .kpis.vieux > .kpi-age { margin-left: 0; }
}
@media (min-width: 481px) and (max-width: 800px) {
  html[data-chiffres="1"]:not([data-structure]) .header:has(> .kpis.vieux) > .header-left { flex-basis: 0; }
  html[data-chiffres="1"]:not([data-structure]) .header > .kpis.vieux { flex-basis: 100%; }
}
/* Expert : la paire, le prix et neuf boutons ne tiennent pas toujours sur une rangée. Entre 481
   et 660 px, les boutons se posaient sur le prix ; dans les thèmes à structure, entre 801 et
   1000 px, les derniers sortaient de l'écran (Réglages, Légendes, Thème). Le bloc du prix garde
   sa largeur, et les boutons passent sur une 2e rangée, à droite, quand ils n'ont plus la place. */
@media (min-width: 481px) and (max-width: 800px) {
  html[data-chiffres="1"]:not([data-structure="fenetres"]) .header { flex-wrap: wrap; row-gap: 6px; }
  html[data-chiffres="1"]:not([data-structure="fenetres"]) .header > .header-left,
  html[data-chiffres="1"]:not([data-structure]) .header:has(> .kpis.vieux) > .header-left { flex: 1 0 auto; }
  html[data-chiffres="1"]:not([data-structure="fenetres"]) .header > .header-right { margin-left: auto; }
}
/* Fenêtres (Bureau 95) : l'en-tête garde UNE rangée (ses boutons sont dans la barre des tâches),
   mais entre 481 et 640 px, avec les chiffres du marché, le prix passait dessous. Le titre s'efface, comme sous 481 px (le
   nom reste dans la barre des tâches) : le prix et la variation 24 h gardent leur place. */
@media (min-width: 481px) and (max-width: 640px) {
  html[data-structure="fenetres"] .header-left h1 { display: none; }
}
@media (min-width: 801px) and (max-width: 1100px) {
  html[data-chiffres="1"][data-structure]:not([data-structure="fenetres"]) .header { flex-wrap: wrap; row-gap: 6px; }
  html[data-chiffres="1"][data-structure]:not([data-structure="fenetres"]) .header > .header-left { flex: 1 0 auto; }
  html[data-chiffres="1"][data-structure]:not([data-structure="fenetres"]) .header > .header-right { margin-left: auto; }
}
@media (max-width: 768px) {
  body { font-size: 12px; -webkit-tap-highlight-color: transparent; }
  /* Cibles tactiles : 20 px de haut étaient intappables au pouce. */
  .indicator-bar { padding: 4px 10px; gap: 4px; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
  .indicator-bar label { padding: 7px 11px; gap: 3px; }
  .indicator-bar label:active { transform: scale(0.94); }
  .indicator-bar .section-title { font-size: 8px; }
  .indicator-bar .sep { height: 18px; margin: 0 3px; }
  .ind-dropdown-btn { padding: 7px 10px; }
  .ind-dropdown-menu { min-width: 220px; width: min(440px, calc(100vw - 16px)); max-height: 72vh; font-size: 11px; }
  .ind-apercu { max-height: 30vh; }
  /* L'intervalle est en tête du ruban à toutes les largeurs (règle plus haut) : au pouce, il était
     à trois écrans à droite. (La paire est dans l'en-tête.) */

  .main-area { flex-direction: column; }
  .chart-container { height: 100%; }
  .feed-panel { display: none !important; }

  /* Grid Bot — colonnes empilées, cibles tactiles. */
  .strat-section { height: 36px; }
  .strat-section:not(.collapsed) { height: 330px; height: min(46dvh, 330px); }
  .strat-handle { height: 36px; padding: 0 14px; font-size: 13px; }
  .strat-body { height: calc(100% - 36px); padding: 8px 10px; }
  .strat-cols { flex-direction: column; gap: 8px; }
  .strat-col-config { display: block; flex: none; width: 100%; }
  .strat-col-actions { flex: none; width: 100%; flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .strat-col-actions .strat-btn { flex: 1; min-width: 80px; font-size: 10px; padding: 8px; }
  .strat-col-actions .strat-toggle { width: 100%; text-align: center; }
  .strat-col-stats { flex: none; width: 100%; min-width: unset; font-size: 10px; }
  .strat-section .strat-row { margin-bottom: 4px; }
  .strat-section .strat-row label { min-width: 55px; }
  .strat-section .strat-row select,
  .strat-section .strat-row input[type="number"],
  .strat-section .strat-row input[type="datetime-local"] { padding: 4px 5px; }
  .strat-section .strat-stats { font-size: 10px; line-height: 1.4; }

  .feed { padding: 10px; gap: 10px; word-break: break-word; overflow-wrap: break-word; }
  .demon-card { padding: 12px; }
  .demon-name { font-size: 13px; }
  .demon-body { font-size: 11px; }
  .hero-val { font-size: 24px; }
}
/* Sous 480 px : le mot-symbole cède (l'orbe et le <title> portent l'identité). */
@media (max-width: 480px) {
  .header-left h1 { display: none; }
  .header { padding: 6px; gap: 4px; }
  .header-left { gap: 4px; }
  .var24 { display: none; }
  .paire-btn { font-size: 10.5px; padding: 3px 5px 3px 8px; }
  /* Le prix et les huit boutons ne tiennent pas sur une ligne (à 390 px, les boutons se
     dessinaient sur le prix) : l'en-tête passe sur deux rangées, le prix d'abord. Bureau 95
     range ses boutons dans la barre des tâches : son en-tête tient sur une ligne. */
  html:not([data-structure="fenetres"]) .header { flex-wrap: wrap; row-gap: 6px; }
  html:not([data-structure="fenetres"]) .header-left { flex: 1 1 100%; }
  html:not([data-structure="fenetres"]) .header-right { flex: 1 1 100%; justify-content: space-between; }
  /* Expert : la pastille « en retard » se range à côté du prix, sur la 1re rangée (les boutons,
     à 100 %, restent sur la 2e) ; sans elle, le prix occupe la rangée comme avant. */
  html[data-chiffres="1"]:not([data-structure]) .header-left { flex: 1 1 auto; }
}
@media (max-width: 400px) {
  .price-badge { font-size: 15px; }
  .indicator-bar label { padding: 6px 9px; font-size: 10px; }
  .indicator-bar .section-title { display: none; }
  .aero-taskbar { height: 24px; padding: 0 8px; font-size: 10px; }
  .strat-section { height: 34px; }
  .strat-section:not(.collapsed) { height: 310px; height: min(46dvh, 310px); }
  .strat-handle { height: 34px; font-size: 12px; }
  .strat-body { height: calc(100% - 34px); }
  .strat-col-actions .strat-btn { font-size: 9px; padding: 6px; }
  .strat-section .strat-row label { min-width: 45px; font-size: 9px; }
}

/* Thème à structure : invisible tant que js/structures.js ne l'a pas posée (filet 2,5 s dans
   le script de tête). Évite d'afficher un instant la structure de base. */
html[data-structure-attendue]:not([data-structure-posee]) body { visibility: hidden; }
.theme-structure { font-size: 10px; font-weight: 600; color: var(--ink-3); }
/* Décor d'une structure (chantier().decor, js/structures.js) : muet ET inerte. Un titre de
   décor posé sur un vrai bouton ou une vraie valeur ne doit jamais intercepter le pointeur
   (tests/test_structures.js l'exige de tout [data-decor]). */
[data-decor] { pointer-events: none; }

/* ─── Un seul écran : trois attributs sur <html> (index.html, js/fiches.js, js/app.js) ───────────
   Le HTML est le même quels que soient les calques choisis : seul ce qui s'affiche change, jamais une
   valeur.
   - data-mode : le calque « Le détail » ('expert' allumé). .expert-seul / .debutant-seul le suivent
     (fiches, graphique). Éteint est le DÉFAUT de la feuille : sans attribut, ou avec une valeur
     inconnue, la page montre la version courte — jamais les deux variantes.
   - data-chiffres : le calque « Les chiffres du marché » ('1' allumé) : les chiffres de l'en-tête,
     l'En direct, le Grid Bot et les infos du marché chiffrées. .chiffres-seul / .sans-chiffres.
   - data-calques : '1' quand un calque de marché est allumé : le ruban montre sa légende. */
:where(html):not([data-mode="expert"]) .expert-seul,
[data-mode="expert"] .debutant-seul { display: none !important; }
:where(html):not([data-chiffres="1"]) .chiffres-seul,
[data-chiffres="1"] .sans-chiffres { display: none !important; }
:where(html):not([data-calques="1"]) .legende-seule { display: none !important; }
.info-btn {
  display: inline-flex; align-items: center; justify-content: center; vertical-align: 1px;
  width: 15px; height: 15px; margin-left: 5px; padding: 0;
  /* Rond (un signe, PR #47), mais carré dans un thème carré (--r-bar à 0 : Gazette, Planche) : un
     rond au bout de lignes toutes carrées détonnait (revue du 14/10, C30). Un thème aux coins
     arrondis, même petits (Néon, Codex, Gare), le garde rond. */
  border-radius: min(50%, var(--r-bar) * 1000);
  border: 1px solid var(--hairline); background: transparent; color: var(--ink-3);
  font: 700 9.5px/1 Georgia, 'Times New Roman', serif; font-style: italic; cursor: pointer;
  text-transform: none; letter-spacing: 0;
}
.info-btn:hover, .info-btn:focus-visible { color: var(--accent); border-color: var(--accent); outline: none; }
.lecture-courte {
  margin-top: 6px; padding: 5px 8px; border-radius: min(8px, var(--r-tile)); font-size: 11px; line-height: 1.4;
  color: var(--ink-2); background: var(--rail); border-left: 2px solid var(--accent);
}
/* Complet : la phrase en mots se lit à côté des chiffres, un cran plus discrète qu'eux (niveau
   « utile » : plus petite, sans fond) ; les chiffres restent ce qui se voit d'abord. */
html[data-chiffres="1"] .lecture-courte { margin-top: 5px; padding: 2px 0 2px 7px; font-size: 10.5px; background: transparent; }
/* Débutant, autre paire que BTCUSDT : les infos du marché parlent du bitcoin (js/app.js). */
.deb-btc {
  margin: 0 0 8px; padding: 6px 9px; border-radius: min(8px, var(--r-tile)); font-size: 11.5px; line-height: 1.4;
  color: var(--ink-1); background: var(--rail); border-left: 2px solid var(--warn);
}
/* Sans « Les chiffres du marché » : l'heure de la publication, dite une fois en tête des cartes
   (js/app.js renderFeedTo, revue du 14/10/2026, M7). En retard, le bandeau d'âge prend sa place. */
.pub-heure { margin: 0 0 8px; padding: 0 2px; font-size: 12px; font-weight: 650; line-height: 1.4; color: var(--ink-2); }
/* Gare, grand tableau (écran haut et large) : chaque bloc des infos du marché y est une colonne de
   330 px (themes/gare.css) ; l'heure de tête garde la largeur de son texte. */
@media (min-height: 1000px) and (min-width: 1200px) {
  :root[data-structure="tableau"] .feed > .pub-heure { flex: 0 0 auto; margin: 0; }
}
.glossaire-plus > summary { cursor: pointer; margin-top: 10px; font-size: 11.5px; font-weight: 700; color: var(--ink-2); }
.fiches-ligne { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 8px; font-size: 10.5px; color: var(--ink-3); }
.fiche-lien { white-space: nowrap; }
.fiche-pop {
  position: fixed; z-index: 1300; left: 50%; top: 12vh; transform: none;
  width: min(420px, calc(100vw - 24px)); max-height: 76vh; overflow-y: auto;
  padding: 12px 16px 14px; border-radius: min(16px, var(--r-panel));
  background: var(--card-solid); color: var(--ink-1);
  border: 1px solid var(--hairline); box-shadow: var(--card-shadow);
  font-size: 12.5px; line-height: 1.5;
}
.fiche-pop:not([style*="left"]) { left: calc(50% - min(210px, 50vw - 12px)); }
.fiche-pop[hidden] { display: none; }
.fiche-tete { display: flex; align-items: center; gap: 8px; }
/* Un long panneau (statistiques d'une figure, glossaire, calculette) défile : son titre et sa croix
   restent en haut, sur le fond du panneau. Il montait avec le texte : on ne savait plus de quelle
   figure il s'agissait, et Bureau 95 perdait sa barre de titre (revue du 14/10, M8). L'en-tête
   s'étend sur la marge haute du panneau (12 px), comme le filtre du panneau d'affichage. */
.fiche-tete { position: sticky; top: -12px; z-index: 1; margin-top: -12px; padding-top: 12px; background: var(--card-solid); }
/* Bureau 95 : la barre de titre (sa règle garde sa place et son fond) s'arrête sous le cadre de 3 px
   de la fenêtre, qu'elle redessine au-dessus d'elle : le texte qui défile n'y passe pas. */
:root[data-structure="fenetres"] .fiche-tete { top: 0; box-shadow: 0 -1px var(--surface), 0 -2px var(--relief-2), 0 -3px var(--relief-1); }
.fiche-titre { font-size: 14px; margin: 0; flex: 1; color: var(--ink-1); }
/* La croix suit le rayon du thème : à angles vifs dans un thème carré (Gazette : 6 px au survol). */
.fiche-fermer { font: inherit; font-size: 18px; line-height: 1; border: 0; background: none; color: var(--ink-3); cursor: pointer; padding: 2px 6px; border-radius: min(6px, var(--r-tile)); }
.fiche-fermer:hover { color: var(--ink-1); background: var(--rail); }
.fiche-nature { font-size: 9.5px; font-weight: 700; letter-spacing: 0.6px; text-transform: uppercase; padding: 2px 7px; border-radius: var(--r-bar); background: var(--rail); color: var(--ink-2); }
.fiche-nature.nature-convention, .fiche-nature.nature-seuil { background: var(--warn-soft, var(--rail)); color: var(--warn-ink, var(--ink-1)); }
.fiche-nature.nature-modèle { color: var(--accent-2); }
.fiche-simple { margin: 8px 0; color: var(--ink-1); }
/* Niveau 1 du Débutant : ce que c'est, une phrase en gras, un peu plus grande. */
.fiche-quoi { font-size: 13.5px; line-height: 1.45; }
/* Niveau 3 : « En savoir plus », replié en Débutant, ouvert en Expert (js/fiches.js). */
.fiche-plus { margin-top: 10px; }
.fiche-plus > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 600; color: var(--accent-2); padding: 3px 0;
}
.fiche-plus > summary::-webkit-details-marker { display: none; }
.fiche-plus > summary::after { content: '▸'; transition: transform .15s; }
.fiche-plus[open] > summary::after { transform: rotate(90deg); }
.fiche-plus > summary:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; border-radius: min(4px, var(--r-tile)); }
.fiche-valeur { margin: 6px 0; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.fiche-valeur b { color: var(--ink-1); }
.fiche-tf { font-size: 10px; font-weight: 700; color: var(--ink-3); }
.fiche-alerte { margin: 6px 0; padding: 6px 9px; border-radius: min(8px, var(--r-tile)); background: var(--warn-soft, var(--rail)); color: var(--ink-1); font-size: 11.5px; }
/* Bureau 95 contraste (le jumeau sombre) : le fond de l'alerte est le noir du panneau, « Trop peu
   de cas… » n'y était plus encadré ; un filet --warn l'entoure. Le jumeau clair garde sa case
   jaune, sans filet (revue du 14/10, C31). */
:root[data-structure="fenetres"] .fiche-alerte { box-shadow: inset 0 0 0 1px light-dark(transparent, var(--warn)); }
/* Courbe des dernières heures de publications : trous hachurés (aucune publication lue, ou
   champ absent du format d'alors) — un trou se voit, il n'est pas comblé. */
.fiche-chronique { margin: 8px 0 4px; }
.fiche-chronique-tete { font-size: 10px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--ink-3); }
.chron-fiche { display: block; width: 100%; height: 56px; margin: 4px 0 2px; color: var(--ink-2); background: var(--rail); border-radius: min(6px, var(--r-tile)); }
.chron-fiche .chron-trou { opacity: 0.55; }
.chron-fiche .chron-hachure { stroke: var(--ink-3); stroke-width: 1.5; }
.fiche-chronique-pied { font-size: 10.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.fiche-pop h4 { margin: 12px 0 4px; font-size: 10px; letter-spacing: 0.8px; text-transform: uppercase; color: var(--ink-3); }
.fiche-lectures { margin: 0; padding-left: 0; list-style: none; }
.fiche-lectures li { margin: 5px 0; color: var(--ink-2); }
.statut { display: inline-block; font-size: 9px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; padding: 1px 6px; border-radius: min(6px, var(--r-tile)); margin-right: 4px; background: var(--rail); color: var(--ink-2); }
.statut-débattu { background: var(--down-soft); color: var(--down-ink); }
.statut-convention { background: var(--warn-soft, var(--rail)); color: var(--warn-ink, var(--ink-1)); }
.statut-mesuré { background: var(--up-soft); color: var(--up-ink); }
.fiche-debat { margin: 10px 0; padding: 8px 10px; border-radius: min(10px, var(--r-tile)); border: 1px dashed var(--down-ink); color: var(--ink-2); font-size: 11.5px; }
.fiche-limites, .fiche-indice { color: var(--ink-2); font-size: 11.5px; }
.fiche-technique p { margin: 4px 0; color: var(--ink-1); font-size: 11.5px; }
.fiche-technique dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; margin: 6px 0; font-size: 11px; }
.fiche-technique dt { color: var(--ink-3); }
.fiche-technique dd { margin: 0; color: var(--ink-2); word-break: break-word; }
.fiche-pied { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--hairline); font-size: 10.5px; color: var(--ink-3); }
/* Calculette : « Un calcul, pas un conseil. » reste collé en bas du panneau, sur son fond, même
   quand les paliers le font défiler (Planche au téléphone : il était sous le pli). Il s'étend sur
   la marge basse du panneau (14 px ; 12 en Bureau 95, dont il redessine le bas du relief). Revue du
   14/10, C28. */
.calc ~ .fiche-pied { position: sticky; bottom: -14px; margin-bottom: -14px; padding-bottom: 14px; background: var(--card-solid); }
:root[data-structure="fenetres"] .calc ~ .fiche-pied { bottom: -12px; margin-bottom: -12px; padding-bottom: 12px; box-shadow: inset 0 -1px var(--relief-4), inset 0 -2px var(--relief-3); }
/* Statistiques détaillées d'une figure (js/stats-figures.js) : la cible en gros, puis les comptes. */
.stats-cible { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 8px 0 2px; }
.stats-etiquette { font-size: 10px; font-weight: 700; letter-spacing: 0.6px; text-transform: uppercase; color: var(--ink-3); width: 100%; }
.stats-prix { font-size: 19px; font-weight: 800; color: var(--ink-1); font-variant-numeric: tabular-nums; }
.stats-ou { font-size: 11.5px; color: var(--ink-3); }
.stats-note { width: 100%; margin: 0; font-size: 11.5px; color: var(--ink-2); }
.stats-comment { margin: 6px 0; font-size: 11.5px; color: var(--ink-2); }
.stats-phrase { margin: 6px 0 4px; color: var(--ink-1); }
.stats-barre { display: flex; gap: 2px; height: 10px; margin: 4px 0; border-radius: min(5px, var(--r-tile)); overflow: hidden; background: var(--rail); }
.stats-barre i { display: block; min-width: 3px; }
.stats-barre .ok { background: var(--up); } .stats-barre .ko { background: var(--down); } .stats-barre .neutre { background: var(--ink-3); }
.stats-barre .pale { opacity: 0.45; }
.stats-legende { margin: 2px 0 6px; font-size: 11px; color: var(--ink-2); display: flex; flex-wrap: wrap; gap: 2px 10px; font-variant-numeric: tabular-nums; }
.stats-legende .ok, .stats-marque.ok { color: var(--up-ink); } .stats-legende .ko, .stats-marque.ko { color: var(--down-ink); } .stats-legende .neutre, .stats-marque.neutre { color: var(--ink-3); }
.stats-table { display: grid; grid-template-columns: 1fr auto; gap: 3px 12px; margin: 4px 0; font-size: 12px; }
.stats-table dt { color: var(--ink-2); }
.stats-table dd { margin: 0; color: var(--ink-1); font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.stats-marque { display: inline-block; width: 1.1em; font-weight: 800; text-align: center; }
.stats-quand { color: var(--ink-1); font-variant-numeric: tabular-nums; }
/* Exemples passés d'une figure (plan du 13/10/2026, idée 4) : une bande qu'on fait défiler de côté
   (elle seule : la page et la bulle ne s'élargissent pas), une petite carte par cas, sans animation.
   Le prix de la figure à l'encre pleine, avant et après plus pâle ; la figure elle-même (ses points reliés,
   sa ligne de cou ou ses bornes) comme on la voit sur le graphique, à la couleur « attention » du
   thème (la seule qui ne se confond, dans aucun thème, ni avec le prix ni avec ✓ et ✗) ;
   le niveau franchi en pointillé quand la figure n'a pas de dessin ;
   l'objectif et l'invalidation aux couleurs de la barre des issues (✓ atteint, ✗ annulée). Carré
   dans les thèmes carrés (--r-tile) ; en Bureau 95, la carte est creusée comme un champ. */
.stats-exemples {
  display: flex; gap: 8px; max-width: 100%; margin: 4px 0 6px; padding: 2px 1px 6px;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
}
.stats-exemples:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.stats-exemple {
  flex: 0 0 140px; min-height: 40px; margin: 0; padding: 4px 4px 5px; scroll-snap-align: start;
  border-radius: min(8px, var(--r-tile)); background: var(--rail); box-shadow: var(--enfonce-mince, inset 0 0 0 1px var(--hairline));
}
.stats-exemple .ex-svg { display: block; width: 100%; height: auto; }
.stats-exemple figcaption { margin-top: 3px; font-size: 11px; line-height: 1.3; color: var(--ink-2); }
.ex-pendant { fill: var(--ink-3); fill-opacity: 0.12; }
.ex-avant, .ex-apres { fill: none; stroke: var(--ink-3); stroke-width: 1.1; stroke-linejoin: round; }
.ex-prix { fill: none; stroke: var(--ink-1); stroke-width: 1.5; stroke-linejoin: round; }
.ex-niveau { stroke: var(--ink-2); stroke-width: 1; stroke-dasharray: 2 2; }
.ex-objectif { stroke: var(--up-ink); stroke-width: 1.2; stroke-dasharray: 4 2; }
.ex-inval { stroke: var(--down-ink); stroke-width: 1.2; stroke-dasharray: 4 2; }
.ex-valide { fill: var(--ink-2); }
.ex-cou { stroke: var(--warn-ink); stroke-width: 1.3; }
.ex-cou.autre { stroke-width: 1; stroke-dasharray: 3 2; }
.ex-zig { fill: none; stroke: var(--warn-ink); stroke-width: 1.2; stroke-linejoin: round; }
.ex-point { fill: var(--warn-ink); }
.ex-issue { font-size: 11px; font-weight: 800; }
.ex-issue.ok { fill: var(--up-ink); } .ex-issue.ko { fill: var(--down-ink); } .ex-issue.neutre { fill: var(--ink-3); }
.glossaire { display: flex; flex-wrap: wrap; gap: 5px; }
/* Les touches du terminal, en une ligne sous le mode : un rappel, petit et gris. */
.fiche-touches { margin: 2px 0 8px; font-size: 11px; color: var(--ink-3); }
/* Sans souris (téléphone), pas de clavier : la ligne des touches se cache, comme sur la carte
   (js/bookmap.js ne les écrit que sous hover: hover). Revue du 14/10/2026, M17 : elle prenait 2 à
   3 lignes en tête des Légendes. */
@media (hover: none) { .fiche-touches { display: none; } }
.glossaire-item, .fiche-pop .lien {
  font: inherit; font-size: 11.5px; padding: 4px 9px; border-radius: var(--r-bar); cursor: pointer;
  border: 1px solid var(--hairline); background: var(--rail); color: var(--ink-1);
}
.fiche-pop .lien { padding: 1px 8px; }
.glossaire-item:hover, .fiche-pop .lien:hover { border-color: var(--accent); }
@media (max-width: 768px) {
  /* Au-dessus de la barre des tâches (fixe, au-dessus de tout) : elle cachait le bas de la fiche. */
  .fiche-pop { left: 8px !important; right: 8px; top: auto !important; bottom: calc(30px + 2 * var(--gutter) + 4px); width: auto; max-height: 70vh; }
  /* Planche : la cartouche est entre le graphique et la barre des tâches ; le panneau s'arrêtait au
     milieu de son bouton « Infos du marché » (la moitié basse des lettres dépassait). Il descend
     jusqu'à la barre des tâches et couvre la cartouche (revue du 14/10, C28). */
  :root[data-structure="planche"] .fiche-pop { bottom: calc(30px + var(--gutter) + 4px); }
}
@media (max-width: 400px) {
  /* La barre des tâches n'y a plus que 24 px de haut. */
  :root[data-structure="planche"] .fiche-pop { bottom: calc(24px + var(--gutter) + 4px); }
}

/* ─── Réglages d'affichage (js/reglages.js), dans les « Réglages fins » du panneau ─── */
.reglage { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; font-size: 12px; color: var(--ink-2); }
.reglage select, .ligne-reglage input {
  font: inherit; font-size: 12px; color: var(--ink-1); background: var(--rail);
  border: 1px solid var(--hairline); border-radius: min(8px, var(--r-tile)); padding: 4px 8px;
}
.ligne-reglage { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 3px; }
.ligne-reglage input { width: 64px; }
/* Calculette de risque (js/calculette.js), dans la bulle des légendes : les champs en haut (au
   téléphone, le clavier couvre le bas de la feuille), les résultats dessous. Un nom à gauche, le
   champ prend le reste ; 16 px au doigt (en dessous, le téléphone zoome sur le champ) et 40 px de
   haut ; les boutons sont ceux du glossaire, habillés par chaque thème. */
.calc-champs { margin: 6px 0 4px; }
.calc .calc-ligne { flex-wrap: nowrap; margin: 5px 0; }
.calc-nom { flex: 0 0 8.6em; color: var(--ink-2); font-size: 12px; }
.calc .calc-ligne input { flex: 1 1 auto; width: auto; min-width: 0; font-variant-numeric: tabular-nums; }
.calc-paliers { margin: 8px 0 0; padding: 0; border: 0; min-width: 0; }
.calc-legende { padding: 0; font-size: 10px; font-weight: 700; letter-spacing: 0.6px; text-transform: uppercase; color: var(--ink-3); }
.calc .calc-retirer { flex: 0 0 auto; }
.calc .calc-ajouter { margin: 4px 0 2px; }
.calc-resultats { margin-top: 8px; padding-top: 6px; border-top: 1px solid var(--hairline); }
.calc-message { margin: 4px 0; font-weight: 650; color: var(--ink-1); }
.calc-message.calc-attente { font-weight: 400; color: var(--ink-2); }
.calc-rappel { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-2); }
/* Revue du 14/10 (N3) : la ligne mesurée, sous le rappel, à son allure (un fait, pas une alerte). */
.calc-mesure { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-2); }
/* Revue du 14/10. C5 : une mise plus grande que le capital se dit en couleur d'alerte, comme
   l'écart d'horloge. N2 : ce que veut dire un nom de champ, en plus petit sous le nom (dans la
   légende des paliers, à sa suite, en casse ordinaire). M1 : l'écart du stop au prix moyen, sous
   son prix, sans élargir la colonne des valeurs. */
.calc-alerte { margin: 6px 0 0; padding: 5px 8px; font-size: 12px; font-weight: 650; color: var(--warn-ink); background: var(--warn-soft); border-radius: min(8px, var(--r-tile)); }
.calc-def { text-transform: none; letter-spacing: 0; font-weight: 400; }
.calc-nom .calc-def { display: block; font-size: 11px; line-height: 1.25; }
.calc-sous { display: block; font-size: 11px; font-weight: 400; color: var(--ink-2); }
@media (pointer: coarse) {
  .calc .calc-ligne input { font-size: 16px; min-height: 40px; }
  .calc .glossaire-item { min-height: 40px; }
}
.puces { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.puce-case {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: var(--r-bar);
  border: 1px solid var(--hairline); background: var(--rail); color: var(--ink-1); font-size: 11.5px; cursor: pointer;
}
.puce-case input { margin: 0; accent-color: var(--accent); }
.puce-case.indispo { opacity: 0.45; cursor: not-allowed; }

/* ─── Mode Débutant : l'écran calme ──────────────────────────────────────────────
   Le HTML est le même dans les deux modes ; ici, seulement ce qui se montre. En Débutant :
   le prix, sa variation 24 h (durée dite), une pastille « Infos du marché ▸ » à la place des
   chiffres clés, et les boutons utiles. Sans flou, sans animation infinie. */
.kpi-deb {
  flex-shrink: 0; display: inline-flex; align-items: center; padding: 4px 11px; border-radius: var(--r-bar);
  font-size: 11px; font-weight: 650; white-space: nowrap; color: var(--ink-2); background: var(--rail);
  cursor: pointer;
}
.kpi-deb:hover, .kpi-deb:focus-visible { color: var(--ink-1); outline: none; box-shadow: 0 0 0 1px var(--accent); }
.kpi-deb .deb-retard { display: none; }
.kpis.vieux .kpi-deb { color: var(--warn-ink); background: var(--warn-soft); }
.kpis.vieux .kpi-deb .deb-frais { display: none; }
.kpis.vieux .kpi-deb .deb-retard { display: inline; }
:where(html):not([data-chiffres="1"]) #cycle .kpi, :where(html):not([data-chiffres="1"]) #cycle .kpi-age { display: none; }
/* Épinglés (panneau « Infos du marché », js/app.js epingles) : ils restent dans l'en-tête sans
   « Les chiffres du marché », devant la pastille. Au téléphone, la bande ne garde qu'eux, sur sa
   propre ligne sous le prix (ce qui ne tient pas cède à droite, ajusterKpis). */
:where(html):not([data-chiffres="1"]) #cycle .kpi.epingle:not([hidden]) { display: flex; }
:where(html):not([data-chiffres="1"]) #cycle .kpi.epingle ~ .kpi-deb { margin-left: 10px; }
@media (max-width: 768px) {
  .header:has(> #cycle.a-epingles) { flex-wrap: wrap; row-gap: 6px; }
  .header > #cycle.a-epingles { display: flex; order: 9; flex: 1 0 100%; height: auto; min-width: 0; overflow: hidden; }
  #cycle.a-epingles > .kpi:not(.epingle), #cycle.a-epingles > .kpi-deb, #cycle.a-epingles > .kpi-btc,
  #cycle.a-epingles:not(.vieux) > .kpi-age { display: none; }
  #cycle.a-epingles > .kpi.epingle:not([hidden]) { display: flex; padding: 0 10px; }
  #cycle.a-epingles > .kpi.epingle:first-of-type { padding-left: 0; border-left: 0; }
}
/* Le choix des épinglés, en tête du panneau : les noms de l'en-tête, en pastilles à cocher. */
.epingles { margin: 0 0 10px; padding: 8px 10px; border-radius: 10px; background: var(--rail); }
.epingles-t { font-size: 11px; font-weight: 700; color: var(--ink-2); margin-bottom: 6px; }
.epingles-btns { display: flex; flex-wrap: wrap; gap: 5px; }
.epingle-btn {
  padding: 3px 9px; border-radius: var(--r-bar); border: 1px solid var(--hairline); background: transparent;
  font: inherit; font-size: 11px; font-weight: 650; color: var(--ink-2); cursor: pointer;
}
.epingle-btn[aria-pressed="true"] { color: var(--ink-1); border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.epingle-btn[aria-pressed="true"]::before { content: '✓ '; }
.epingle-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.epingles-quoi { margin-top: 6px; font-size: 10.5px; line-height: 1.35; color: var(--ink-3); }
:where(html):not([data-chiffres="1"]) .header-right > #updated { display: none; }
/* Les structures déplacent l'heure de publication hors de l'en-tête : en Débutant, son âge est
   dit par la pastille « Infos du marché » (infobulle) ; l'heure et ses étiquettes restent en
   Expert. La légende de la Gazette nomme les « bougies » : Expert aussi. */
:where(html):not([data-chiffres="1"]) #updated, :where(html):not([data-chiffres="1"]) .f95-pub, :where(html):not([data-chiffres="1"]) .gare-heure,
:where(html):not([data-chiffres="1"]) .gazette-edition, :where(html):not([data-chiffres="1"]) .gazette-legende { display: none !important; }
/* Planche (cyanotype, diazo) : les chiffres clés masqués, la case du cartouche garde son fond de
   case (sinon le trait clair de la grille paraît) et s'étend sous « date de rév. » (heure UTC masquée). */
:root:not([data-chiffres="1"]) .plan-cartouche > .kpis { grid-column: 1 / -1; display: flex; align-items: center; padding: 4px 9px; background: var(--plan-case); }
/* Sans les neuf cases, rien ne donne sa largeur au cartouche : les sources la donnent (sur une
   ligne), et la nomenclature, courte, part de la gauche. */
:root:not([data-chiffres="1"]) .plan-cartouche > .plan-sources { contain: none; white-space: nowrap; }
:root:not([data-calques="1"]) .plan-pied .indicator-bar > .ind-dropdown { margin-left: 0; }
:where(html):not([data-chiffres="1"]) .gazette-manchette { display: none; }
/* Les onglets des sous-graphiques sans place (dispositionGraphique, js/app.js) : posés sur le
   canvas, au-dessus du sélecteur de plage ; un clic en montre un à la place d'un autre. Ils
   défilent s'ils ne tiennent pas. Un élément HTML, pas un texte du graphique. */
.onglets-sous {
  position: absolute; z-index: 3; display: flex; align-items: center; gap: 4px; box-sizing: border-box;
  overflow-x: auto; scrollbar-width: none; white-space: nowrap; font-size: 10.5px; color: var(--ink-3);
}
.onglets-sous::-webkit-scrollbar { display: none; }
.onglets-sous[hidden] { display: none; }
.onglets-titre { flex-shrink: 0; margin-right: 2px; font-weight: 600; }
.onglet-sous {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 5px; min-height: 22px; padding: 2px 9px;
  font: inherit; font-size: 10.5px; font-weight: 650; color: var(--ink-1); cursor: pointer;
  background: var(--pill); border: 1px solid var(--hairline); border-radius: var(--r-bar);
}
.onglet-sous::before { content: ''; flex-shrink: 0; width: 6px; height: 6px; border-radius: 50%; background: var(--dot); }
.onglet-sous:hover, .onglet-sous:focus-visible { border-color: var(--accent); outline: none; }
/* La clé « ? » du Lisible, toujours là, dans un coin du tracé (js : astucePlacer) — un bouton, pas
   un texte du canvas ; la première fois, l'astuce à côté d'elle. Seule la clé prend le pointeur :
   un toucher sur l'astuce va au graphique (il la cache). */
.astuce-tap {
  position: absolute; z-index: 3; left: 20px; bottom: 60px;
  display: flex; align-items: center; gap: 6px; pointer-events: none;
}
.astuce-tap[hidden], .astuce-phrase[hidden] { display: none; }
/* Sous une bulle qui ne peut l'éviter (js : dessinerCalque), la clé s'efface sans quitter sa place :
   la bulle reste où elle est. Revue du 14/10 (C35). */
.astuce-tap.sous-bulle { visibility: hidden; }
.cle-aide {
  flex-shrink: 0; width: 28px; height: 28px; padding: 0; border-radius: min(50%, var(--r-bar)); pointer-events: auto; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; font-size: 14px; font-weight: 750; line-height: 1; color: var(--accent-2);
  background: var(--card-solid, var(--rail)); background-clip: padding-box; border: 0 solid transparent;
  box-shadow: inset 0 0 0 1px var(--hairline);
}
.cle-aide:hover, .cle-aide:focus-visible { color: var(--ink-1); box-shadow: inset 0 0 0 1px var(--accent); outline: none; }
/* Au doigt : une cible de 40 px, le rond dessiné garde ses 28 px (le bord transparent la porte). */
@media (pointer: coarse) { .cle-aide { width: 40px; height: 40px; border-width: 6px; } }
.astuce-phrase {
  padding: 5px 11px; border-radius: var(--r-bar); white-space: nowrap;
  font-size: 11.5px; font-weight: 600; color: var(--ink-1); background: var(--card-solid, var(--rail));
  border: 1px solid var(--hairline); box-shadow: var(--capsule-ombre);
}
/* Téléphone : la clé et l'astuce tiennent dans le tracé (à 360 px, 233 px entre la marge et la
   colonne des prix) — l'astuce passe sur deux lignes. */
@media (max-width: 480px) { .astuce-phrase { white-space: normal; max-width: 170px; border-radius: min(var(--r-tile), 12px); line-height: 1.3; } }
/* Le prix, sa variation et la pastille d'abord (la pastille ne rétrécit pas : elle n'a qu'un
   mot) ; les boutons à droite, et à la ligne quand ils ne tiennent plus. La barre d'outils
   passe aussi à la ligne plutôt que de défiler. */
:where(html):not([data-chiffres="1"]) .kpis { flex: 0 0 auto; order: 2; }
html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header { flex-wrap: wrap; row-gap: 6px; }
html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-right { order: 3; margin-left: auto; }
/* Néon (structure « hud ») sans « Les chiffres du marché » : la pastille est restée dans l'en-tête
   (js/structures.js), la bande de télémétrie n'aurait que son étiquette : elle se cache et rend sa
   rangée au graphique : 33 px au téléphone (23 au doigt : l'en-tête s'écarte de 10 px pour la zone
   de la pastille, plus bas), 51 à 1440 px (revue du 14/10, M20). Avec les chiffres, elle revient. */
:root[data-structure="hud"]:not([data-chiffres="1"]) .hud-bande { display: none; }
/* Néon : l'étiquette du dernier prix, sur le graphique (js/app.js, lireJetons), a les coins de ses
   boutons (--r-bar), et non plus ceux d'une pilule toute ronde (revue du 14/10, M20). */
:root[data-structure="hud"] { --prix-rayon: var(--r-bar); }
@media (max-width: 1100px) {
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header { column-gap: 8px; }
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-right { gap: 6px; }
}
:where(html):not([data-calques="1"]) .indicator-bar { flex-wrap: wrap; overflow-x: visible; row-gap: 4px; }
@media (max-width: 800px) {
  /* La pastille reste : c'est l'accès aux cartes du Débutant. */
  :where(html):not([data-chiffres="1"]) .kpis { display: flex; }
}
@media (max-width: 480px) {
  /* La variation 24 h répond à « ça monte ou ça baisse ? » : visible aussi sur téléphone. */
  :where(html):not([data-chiffres="1"]) .var24 { display: inline-flex; }
  /* Structure « fenêtres » (bureau95) : l'en-tête ne passe pas à la ligne (le bouton de mode y
     recouvrait la variation). Le bloc du prix passe, lui, sur deux rangées : la paire et le prix,
     puis la variation 24 h en entier ; le bouton de mode reste à droite. */
  html:not([data-chiffres="1"])[data-structure="fenetres"] .header-left { min-width: 0; }
  /* Tous thèmes : quand la variation ne tient plus à droite du prix (Gazette à 360 px), elle passe
     sous lui, entière — jamais coupée au bord de l'écran. */
  html:not([data-chiffres="1"]) .hero-prix { flex-wrap: wrap; row-gap: 4px; }
  html:not([data-chiffres="1"])[data-structure="fenetres"] .header-right { flex-shrink: 0; }
  :where(html):not([data-chiffres="1"]) .kpi-deb { padding: 4px 9px; font-size: 10.5px; }
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .kpis { order: 2; flex: 0 1 auto; }
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-right { order: 3; flex: 1 1 auto; justify-content: flex-end; gap: 4px; }
  /* La pastille et les boutons sur la 2e rangée : des boutons un peu plus petits (28 px). */
  :where(html):not([data-chiffres="1"]) .header-right .theme-btn.ico-btn { width: 28px; height: 28px; }
  /* La barre d'outils sur deux rangées au plus : sans son titre ni ses séparateurs. */
  :where(html):not([data-calques="1"]) .indicator-bar .section-title { display: none; }
  :where(html):not([data-calques="1"]) .indicator-bar .sep { display: none; }
}
@media (max-width: 400px) {
  :where(html):not([data-chiffres="1"]) .kpi-deb { padding: 3px 7px; font-size: 10px; }
  /* À 360 px, la flèche de la pastille « en retard · 25 min » cède aussi (2 px de trop). */
  :where(html):not([data-chiffres="1"]) .kpi-deb .deb-fleche { display: none; }
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-right { gap: 3px; }
  :where(html):not([data-chiffres="1"]) .header-right .theme-btn.ico-btn { width: 26px; height: 26px; }
  /* Avec les chiffres du marché : sept boutons et le voyant sur la 2e rangée. */
  html[data-chiffres="1"]:not([data-structure="fenetres"]) .header-right { gap: 4px; }
  :where(html)[data-chiffres="1"] .header-right .theme-btn.ico-btn { width: 28px; height: 28px; }
}
/* Cartes : un bloc réservé à l'Expert est enveloppé sans boîte (même mise en page qu'avant) ;
   en Débutant, une carte d'une seule tuile la montre en entier. */
.env-exp { display: contents; }
:where(html):not([data-chiffres="1"]) .tuiles.deb-une { grid-template-columns: minmax(0, 1fr); }

/* ─── Téléphone : l'en-tête et la barre tiennent en deux rangées, sans débord ──────────────
   Un rayon de pilule (999 px) sur un bloc de deux rangées rognait la paire au bord gauche et
   faisait une bulle : sur écran étroit, des coins de carte. */
@media (max-width: 1100px) {
  .header, .indicator-bar { border-radius: min(var(--r-bar), 22px); }
  /* Débutant : « Infos · en retard ▸ » (le mot « du marché » cède) ; l'en-tête tient sur une rangée. */
  :where(html):not([data-chiffres="1"]) .kpi-deb .deb-mot { display: none; }
}
/* Tablette : le nom (redit dans la barre du bas) cède avant que l'en-tête passe à la ligne —
   dès 1100 px quand la pastille s'allonge (« Infos · en retard · 25 min ▸ »). */
@media (max-width: 900px) { html:not([data-chiffres="1"]):not([data-structure]) .header-left h1 { display: none; } }
@media (max-width: 1100px) { html:not([data-chiffres="1"]):not([data-structure]) .header:has(> .kpis.vieux) .header-left h1 { display: none; } }
@media (max-width: 480px) {
  /* Débutant : 1re rangée, la paire, le prix et la variation ; 2e rangée, la pastille « Infos »
     (qui cède, en entier puis en points de suspension) et les boutons (qui ne passent jamais à
     une 3e rangée). */
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-left { order: 1; }
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .kpis { flex: 0 1 auto; min-width: 0; height: auto; }
  html:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-right { flex: 0 0 auto; flex-wrap: nowrap; margin-left: auto; }
  :where(html):not([data-chiffres="1"]) .kpi-deb { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  /* En retard, la pastille porte l'âge (« en retard · 25 min ») : « Infos · » cède, pour que
     les boutons restent sur la 2e rangée (le titre et le nom accessible disent « Infos du marché »). */
  :where(html):not([data-chiffres="1"]) .kpi-deb .deb-quoi { display: none; }
  /* La barre : les six intervalles et « Affichage » sur une seule rangée. Avec un calque aussi
     (revue du 14/10, C24) : le bouton passe en tête et la légende défile après « 1 j » ; les
     intervalles et le bouton gardent les mêmes réglages serrés (même poids de sélecteur), sinon
     « 1 j » finissait sous le fondu du bord ou hors du ruban. Les puces de la légende ne changent pas. */
  :where(html):not([data-calques="1"]) .indicator-bar { flex-wrap: nowrap; justify-content: space-between; }
  :where(html):not([data-calques="1"]) .indicator-bar, :where(html)[data-calques="1"] .indicator-bar { gap: 2px; padding: 4px 6px; }
  :where(html):not([data-calques="1"]) .indicator-bar label, :where(html)[data-calques="1"] .indicator-bar label:where([id^="int_"]) { padding: 7px 7px; }
  :where(html):not([data-calques="1"]) .ind-dropdown-btn, :where(html)[data-calques="1"] .ind-dropdown-btn { padding: 7px 9px; gap: 3px; }
}
@media (max-width: 400px) {
  :where(html):not([data-calques="1"]) .indicator-bar label, :where(html)[data-calques="1"] .indicator-bar label:where([id^="int_"]) { padding: 6px 5px; }
  :where(html):not([data-calques="1"]) .ind-dropdown-btn, :where(html)[data-calques="1"] .ind-dropdown-btn { padding: 6px 7px; }
  /* Gare : ses plaques de voie gardent leurs 36 px de large (des cibles au pouce) ; la place se
     gagne sur leurs marges, 1 px au lieu de 2 (revue du 14/10, C24 : à 360 px, le ruban débordait
     de 6 px dès le départ et « Affichage » passait sous le fondu). */
  :root[data-structure="tableau"] .indicator-bar label[id^="int_"] { margin: 0 1px; }
}

/* ─── Au doigt (pointer: coarse) : des cibles d'au moins 40 × 40 px ──────────────────────────────
   Le dessin ne change presque pas : un ::before transparent, centré, porte la zone de toucher à 40 px
   de côté au moins (inset négatif quand le bouton est plus petit, nul quand il est plus grand), et les
   marges écartent les voisins pour qu'aucune zone n'empiète sur une autre ni sur un bouton voisin
   (le bouton de mode, « + Indicateurs / Affichage » et Réglages relèvent d'autres chantiers : leurs
   voisins s'en écartent, eux ne changent pas). Entre deux boutons ronds, 42 px de centre à centre : le
   rendu au sous-pixel décale la zone de toucher de près d'un pixel. Les rangées s'écartent de 14 px
   (6 + 6 pour les zones des deux rangées, et 2 entre elles). Thèmes sans structure (aero,
   kala) : les structures rangent ces boutons ailleurs, leurs zones sont écrites plus bas (C25). */
@media (pointer: coarse) {
  html:not([data-structure]) .header .ico-btn:not(#reglagesBtn), html:not([data-structure]) .header .paire-btn,
  html:not([data-structure]) .indicator-bar label[id^="int_"] { position: relative; }
  html:not([data-structure]) .header .ico-btn:not(#reglagesBtn)::before, html:not([data-structure]) .header .paire-btn::before,
  html:not([data-structure]) .indicator-bar label[id^="int_"]::before,
  html:not([data-chiffres="1"]):not([data-structure]) .kpis::before {
    content: ''; position: absolute; inset: min(0px, calc(50% - 20px));
  }
  /* La pastille « Infos du marché » : sa zone est celle de la bande qui la porte (même action : un
     clic sur la bande ouvre les cartes) ; en Lisible, la bande ne montre qu'elle, rien n'en déborde.
     Vide (au chargement : largeur nulle, au bout de la rangée), elle n'a pas de zone : celle-ci
     déborderait à droite de l'en-tête. */
  html:not([data-chiffres="1"]):not([data-structure]) .kpis { position: relative; overflow: visible; min-height: 28px; }
  html:not([data-chiffres="1"]):not([data-structure]) .kpis:empty::before { display: none; }
  /* La paire : 28 px de haut (sa zone, 6 px au-dessus et au-dessous, tient dans la marge de l'en-tête). */
  html:not([data-structure]) .paire-btn { min-height: 28px; }
  html[data-mode]:not([data-structure]) .header { row-gap: 14px; }
  /* Les boutons ronds : 34 px, l'écart de la rangée (6 ou 10) et 1 px de marge de chaque côté. */
  html[data-mode]:not([data-structure]) .header-right > .ico-btn:not(#reglagesBtn) { margin: 0 1px; }
  /* Le voyant (un rond de 10 px, sans action au doigt) laisse le toucher à la zone voisine. */
  html:not([data-structure]) #dot { pointer-events: none; }
  /* Intervalles : 40 px de large et 32 de haut au moins (la zone déborde de 4 px dans la marge du
     ruban, qui la rognerait au-delà). */
  html:not([data-structure]) .indicator-bar label[id^="int_"] { min-width: 40px; min-height: 32px; justify-content: center; }
}
/* Le nom d'un bouton-icône, dit à l'appui du doigt (js/app.js) : une bulle inerte, 1,2 s. */
.nom-appui {
  position: fixed; z-index: 3000; pointer-events: none;
  padding: 4px 10px; border-radius: min(8px, var(--r-tile)); white-space: nowrap;
  font-size: 12px; font-weight: 650; color: var(--ink-1); background: var(--card-solid, var(--rail));
  border: 1px solid var(--hairline); box-shadow: var(--capsule-ombre);
}
.nom-appui[hidden] { display: none; }
@media (pointer: coarse) and (max-width: 768px) {
  /* 30 px, l'écart de 6 et 3 de marge. Le voyant, entre Légendes et Thème, ne prend pas de place. */
  html[data-mode]:not([data-structure]) .header-right > .ico-btn:not(#reglagesBtn) { margin: 0 3px; }
  html[data-mode]:not([data-structure]) .header-right > #dot { margin: 0 -5px; }
}
/* Téléphone, Complet : neuf boutons sur la 2e rangée — sans écart fixe, 5 px de marge de chaque côté
   des boutons ronds, et la place qui reste se partage entre eux (à 360 px, 16 px : 2 de plus entre
   deux voisins). */
@media (pointer: coarse) and (max-width: 480px) {
  html[data-mode]:not([data-structure]) .header-right { gap: 0; }
  html[data-mode]:not([data-structure]) .header-right > .ico-btn:not(#reglagesBtn) { margin: 0 5px; }
}
/* Téléphone, Lisible : la pastille, Réinitialiser, Carte, le bouton de mode, Légendes et le voyant
   tiennent sur la 2e rangée avec leurs zones (à 360 px, 332 px sur 334 : la pastille et le premier
   bouton sans écart, sa marge suffit) ; le Thème passe au bout de la 1re rangée, à droite du prix, qui
   lui laisse sa place (44 px). Boutons ronds de 28 px et 7 de marge. Les six intervalles et le menu :
   sans écart fixe, la place qui reste se partage entre eux (à 360 px, 7 px). */
@media (pointer: coarse) and (max-width: 480px) {
  html:not([data-chiffres="1"]):not([data-structure]) .header { column-gap: 0; }
  html:not([data-chiffres="1"]):not([data-structure]) .header-right > .ico-btn:not(#reglagesBtn) { width: 28px; height: 28px; margin: 0 7px; }
  /* Le voyant, désormais au bout de la rangée : 4 px à sa droite, pour que son onde (×3, js : ping)
     reste dans l'en-tête au lieu de le faire déborder. */
  html:not([data-chiffres="1"]):not([data-structure]) .header-right > #dot { margin: 0 4px 0 0; }
  html:not([data-chiffres="1"]):not([data-structure]) .header-left { padding-right: 44px; }
  html:not([data-chiffres="1"]):not([data-structure]) .header-right > #themeBtn { position: absolute; top: 6px; right: 6px; }
  html:not([data-calques="1"]):not([data-structure]) .indicator-bar { gap: 0; }
}
/* Téléphone de 400 px et moins, avec les chiffres du marché : les boutons des deux bouts rejoignent
   le bord de la rangée : les boutons ronds gardent plus de 41 px de centre à centre (à 360 px, 40 sans cela). */
@media (pointer: coarse) and (max-width: 400px) {
  html[data-chiffres="1"]:not([data-structure]) .header-right > #feedBtn.ico-btn { margin-left: 2px; }
  html[data-chiffres="1"]:not([data-structure]) .header-right > #themeBtn.ico-btn { margin-right: 2px; }
}

/* ─── Au doigt : les thèmes à structure et les panneaux (revue du 14/10, C25) ────────────────────
   Les zones de 40 × 40 px ci-dessus ne valaient que pour Aero, Aero nuit et Kāla. En Bureau 95, le
   thème par défaut, « 1 j » faisait 29 × 22 px ; ailleurs, des boutons ronds de 26 px à 29 px de
   centre à centre, la paire de 23 px, « Infos du marché » de 21 px. Même principe (un ::before
   transparent, centré, le dessin des boutons ne change pas), écrit structure par structure : en
   retirant seulement :not([data-structure]), les zones se chevauchaient et prenaient la cible du
   voisin (mesuré). Bureau 95 : au moins ses 32 × 34 px (ceux de sa barre des tâches) ; aller jusqu'à
   40 changerait son dessin. Dans l'en-tête et le ruban, seuls des écarts bougent : la marge de
   l'en-tête, l'écart entre ses rangées en Complet, la marge des boutons ronds et des intervalles. */
@media (pointer: coarse) {
  /* Dans les 11 thèmes : les boutons du panneau « Choisir l'affichage » à 40 px de haut (comme
     « Calculette de risque ») ; la croix des fiches, une zone de 40 × 40 px autour de son dessin.
     Bureau 95 : la croix (16 × 14) est au ras du haut et du bord droit de la fiche, qui défile ;
     centrée, sa zone dépassait de 7 px et la fiche défilait de côté : elle s'étend vers la gauche
     et vers le bas (33 × 34 au moins). */
  .aff-boutons .aff-btn, .aff-preset { min-height: 40px; }
  .fiche-fermer { position: relative; }
  .fiche-fermer::before { content: ''; position: absolute; inset: min(0px, calc(50% - 20px)); }
  :root[data-structure="fenetres"] .fiche-fermer::before { inset: -10px -4px -14px -13px; }
  /* Le voyant (sans action au doigt) : pendant son onde, il prenait le toucher de « Thème » (Néon). */
  :root[data-structure] #dot { pointer-events: none; }
}
@media (pointer: coarse) and (max-width: 480px) {
  /* La demi-zone : 20 px (40 × 40) ; Bureau 95, 16 × 17 (32 × 34). */
  :root[data-structure] { --zone-l: 20px; --zone-h: 20px; }
  :root[data-structure="fenetres"] { --zone-l: 16px; --zone-h: 17px; }
  :where(:root[data-structure]) :is(.header-right > .ico-btn:not(#reglagesBtn), .paire-btn, .indicator-bar label[id^="int_"]) { position: relative; }
  :root[data-structure] :is(.header-right > .ico-btn:not(#reglagesBtn), .paire-btn, .indicator-bar label[id^="int_"])::before {
    content: ''; position: absolute; inset: min(0px, calc(50% - var(--zone-h))) min(0px, calc(50% - var(--zone-l)));
  }
  /* Un intervalle : sa zone passe SOUS ses voisins. Là où le ruban n'a pas toute la place (Néon,
     Gazette et Planche à 360 px, en Lisible : il est presque plein), elle prend l'écart et ses 40 px
     de haut, jamais le bouton d'à côté. */
  :root[data-structure] .indicator-bar label[id^="int_"]::before { z-index: -1; }
  /* « Infos du marché » (Lisible) : la zone de la bande qui la porte, sous la pastille et les chiffres
     épinglés (même action). Avec des chiffres épinglés, la bande garde son rognage. Bureau 95 : la
     pastille est dans la barre d'état de la fenêtre, à 3 px de son bord. Néon : la pastille est dans
     l'en-tête (revue du 14/10, M20), sa zone y a ses 40 px. */
  :root[data-structure]:not([data-chiffres="1"]):not([data-structure="fenetres"]) #cycle:not(.a-epingles) { position: relative; overflow: visible; isolation: isolate; }
  :root[data-structure]:not([data-chiffres="1"]):not([data-structure="fenetres"]) #cycle:not(.a-epingles):not(:empty)::before {
    content: ''; position: absolute; inset: min(0px, calc(50% - 20px)); z-index: -1;
  }
  /* L'en-tête rogne ce qui le dépasse : 8 px au-dessus de la paire et sous les boutons ronds ; en
     Complet, les deux premiers boutons sont sous la paire : 16 px entre les rangées. Néon, Lisible : la
     pastille est sous la paire (revue du 14/10, M20), 16 px aussi. Bureau 95, Complet : 1 px de plus
     sous la paire. */
  :root:is([data-structure="hud"], [data-structure="codex"], [data-structure="tableau"], [data-structure="planche"]) .header { padding-top: 8px; padding-bottom: 8px; }
  :root[data-chiffres="1"]:is([data-structure="hud"], [data-structure="codex"], [data-structure="tableau"], [data-structure="planche"]) .header,
  :root[data-structure="hud"]:not([data-chiffres="1"]) .header { row-gap: 16px; }
  :root[data-structure="fenetres"] .header { padding-bottom: 6px; }
  /* Lisible : les boutons ronds à 42 px de centre à centre (la place est libre à leur gauche) ; en
     Néon, « Thème » s'écarte du coin arrondi de l'en-tête, qui rognait sa zone. */
  :root[data-structure]:not([data-chiffres="1"]):not([data-structure="fenetres"]) .header-right > .ico-btn:not(#reglagesBtn) { margin: 0 6.5px; }
  :root[data-structure="hud"] .header-right > #themeBtn.ico-btn:not(#reglagesBtn) { margin-right: 12px; }
  /* Les bandes : la zone de la pastille entre l'en-tête et le ruban (Codex, Gare), au-dessus de la
     barre du bas (Planche) ; Gazette : les boutons sous la manchette, le ruban sous la cote. */
  :root[data-structure="codex"] .codex-registre { padding-top: 4px; padding-bottom: 4px; }
  :root[data-structure="tableau"] .gare-tableau { padding-top: 4px; padding-bottom: 4px; }
  :root[data-structure="planche"]:not([data-chiffres="1"]) .plan-cartouche { padding-bottom: 3px; }
  :root[data-structure="une"] .gazette-folio { padding-top: 4px; }
  :root[data-structure="une"] .indicator-bar { margin-top: 0; }
  /* Le ruban défile, donc rogne : 40 px de haut à l'intérieur (34 en Bureau 95, Gare : déjà). */
  :root:is([data-structure="hud"], [data-structure="codex"], [data-structure="planche"]) .indicator-bar { padding-top: 6px; padding-bottom: 6px; }
  :root[data-structure="une"] .indicator-bar { padding-top: 7px; padding-bottom: 7px; }
  /* Les intervalles plus étroits que leur zone s'écartent d'autant (largeurs mesurées : Néon 28 px,
     Codex 22 à 36, Gare 36, Bureau 95 « 1 j » 28) ; Néon, Lisible : « 1 min » s'écarte du coin
     arrondi du ruban, et l'écart fixe cède la place à ces marges (à 360 px, « Affichage » sortait du
     ruban). Avec un calque, les six intervalles et « Affichage » tiennent encore dans le ruban (C24).
     Bureau 95 : les trois larges se touchent, « 1 j » s'écarte de « 4 h ». */
  :root[data-structure="hud"]:not([data-calques="1"]) .indicator-bar { gap: 0; }
  :root[data-structure="hud"]:not([data-calques="1"]) .indicator-bar #int_1m { margin-left: 3px; }
  :root[data-structure="hud"]:not([data-calques="1"]) .indicator-bar #int_5m { margin-left: 1px; }
  :root[data-structure="hud"] .indicator-bar :is(#int_1h, #int_4h, #int_1d) { margin: 0 6px; }
  :root[data-structure="codex"] .indicator-bar :is(#int_1m, #int_5m) { margin: 0 2px; }
  :root[data-structure="codex"] .indicator-bar :is(#int_1h, #int_4h) { margin: 0 8px; }
  :root[data-structure="codex"] .indicator-bar #int_1d { margin: 0 9.5px; }
  :root[data-structure="tableau"] .indicator-bar :is(#int_1h, #int_4h, #int_1d) { margin: 0 2px; }
  :root[data-structure="fenetres"] .indicator-bar :is(#int_5m, #int_15m) { margin-left: -1px; }
  :root[data-structure="fenetres"] .indicator-bar #int_1d { margin-left: 2px; }
}
/* Gazette (29 à 32 px) et Planche (30 px) : la place n'existe qu'au-delà de 380 px, ou en « Le détail »,
   où le ruban défile déjà (à 360 px, en Lisible, avec un calque, « 1 j » sortirait du ruban : C24). */
@media (pointer: coarse) and (min-width: 381px) and (max-width: 480px) {
  :root[data-structure="une"] .indicator-bar :is(#int_1h, #int_4h) { margin: 0 4px; }
  :root[data-structure="une"] .indicator-bar #int_1d { margin: 0 5.5px; }
  :root[data-structure="planche"] .indicator-bar :is(#int_1h, #int_4h, #int_1d) { margin: 0 5px; }
}
@media (pointer: coarse) and (max-width: 380px) {
  :root[data-mode="expert"][data-structure="une"] .indicator-bar :is(#int_1h, #int_4h) { margin: 0 4px; }
  :root[data-mode="expert"][data-structure="une"] .indicator-bar #int_1d { margin: 0 5.5px; }
  :root[data-mode="expert"][data-structure="planche"] .indicator-bar :is(#int_1h, #int_4h, #int_1d) { margin: 0 5px; }
}
