
:root{
  color-scheme:light dark;
  --bg:oklch(0.985 0.004 210);
  --surface:oklch(1 0 0);
  --surface-2:oklch(0.972 0.005 210);
  --accent:oklch(0.906 0.008 215);
  --accent-hover:oklch(0.872 0.010 215);
  --line:oklch(0.906 0.008 215);
  --line-soft:oklch(0.945 0.006 215);
  --ink:oklch(0.24 0.018 220);
  --ink-2:oklch(0.40 0.018 220);
  --mut:oklch(0.475 0.017 220);
  --brand:oklch(0.44 0.078 205);
  --brand-ink:oklch(0.33 0.075 205);
  --brand-wash:oklch(0.955 0.017 205);
  --up:oklch(0.505 0.132 155);
  --up-wash:oklch(0.945 0.045 155);
  --down:oklch(0.525 0.185 26);
  --down-wash:oklch(0.955 0.035 26);
  --warn:oklch(0.60 0.13 75);
  --warn-wash:oklch(0.962 0.045 85);
  /* --r-sm était consommé par .tip, .crange input[type=date] et .crange button
     sans avoir jamais été déclaré : les trois border-radius étaient invalides et
     retombaient à 0. Champs et boutons se posent à 4 px (échelle Carbon), les
     surfaces flottantes à 8. */
  --r-sm:8px; --r-fld:4px; --r:10px; --r-lg:14px;
  --shadow:0 1px 2px oklch(0.24 0.018 220/.05), 0 1px 3px oklch(0.24 0.018 220/.04);
  --pad:clamp(14px,2.2vw,20px);
  --ease:cubic-bezier(.22,1,.36,1);
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme=light]){
    --bg:oklch(0.178 0.014 222);
    --surface:oklch(0.216 0.016 222);
    --surface-2:oklch(0.247 0.017 222);
    --accent:oklch(0.315 0.018 222);
    --accent-hover:oklch(0.352 0.019 222);
    --line:oklch(0.315 0.018 222);
    --line-soft:oklch(0.272 0.016 222);
    --ink:oklch(0.945 0.008 220);
    --ink-2:oklch(0.83 0.012 220);
    --mut:oklch(0.715 0.017 220);
    --brand:oklch(0.76 0.075 200);
    --brand-ink:oklch(0.85 0.06 200);
    --brand-wash:oklch(0.30 0.035 205);
    --up:oklch(0.78 0.105 158);
    --up-wash:oklch(0.30 0.055 158);
    --down:oklch(0.74 0.115 26);
    --down-wash:oklch(0.30 0.06 27);
    --warn:oklch(0.79 0.12 82);
    --warn-wash:oklch(0.32 0.05 82);
    --shadow:0 1px 2px oklch(0 0 0/.30), 0 1px 3px oklch(0 0 0/.22);
  }
}
:root[data-theme=dark]{
  --bg:oklch(0.178 0.014 222); --surface:oklch(0.216 0.016 222);
  --surface-2:oklch(0.247 0.017 222);
  --accent:oklch(0.315 0.018 222); --accent-hover:oklch(0.352 0.019 222);
  --line:oklch(0.315 0.018 222);
  --line-soft:oklch(0.272 0.016 222); --ink:oklch(0.945 0.008 220);
  --ink-2:oklch(0.83 0.012 220); --mut:oklch(0.715 0.017 220);
  --brand:oklch(0.76 0.075 200); --brand-ink:oklch(0.85 0.06 200);
  --brand-wash:oklch(0.30 0.035 205);
  --up:oklch(0.78 0.105 158); --up-wash:oklch(0.30 0.055 158);
  --down:oklch(0.74 0.115 26); --down-wash:oklch(0.30 0.06 27);
  --warn:oklch(0.79 0.12 82); --warn-wash:oklch(0.32 0.05 82);
  --shadow:0 1px 2px oklch(0 0 0/.30), 0 1px 3px oklch(0 0 0/.22);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);
 font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
 font-size:14px;line-height:20px;letter-spacing:.16px;font-variant-numeric:tabular-nums;
 -webkit-font-smoothing:antialiased}
a{color:var(--brand-ink)}
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:4px}
.skip{position:absolute;left:-9999px;top:0;background:var(--surface);color:var(--ink);
 padding:10px 14px;border-radius:0 0 var(--r) 0;z-index:60}
.skip:focus{left:0}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
 clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- header ---------- */
.top{position:sticky;top:0;z-index:30;background:color-mix(in oklab,var(--bg) 88%,transparent);
 -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.top-in{max-width:var(--page-w);margin:0 auto;padding:10px var(--page-pad);
 display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:9px;color:var(--brand);text-decoration:none;flex:0 0 auto}
.brand-txt{display:flex;flex-direction:column;line-height:1.05}
.brand-txt b{font-size:19px;font-weight:640;letter-spacing:-.025em;color:var(--ink)}
.brand-txt i{font-style:normal;font-size:11px;color:var(--mut);letter-spacing:.02em}
.top-meta{margin-inline-start:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap;
 font-size:12.5px;color:var(--mut)}
.pill{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);
 background:var(--surface);border-radius:99px;padding:3px 10px;font-size:12.5px;color:var(--ink-2)}
.pill .dot{width:7px;height:7px;border-radius:50%;background:var(--up)}
.pill.stale{border-color:color-mix(in oklab,var(--warn) 45%,var(--line));
 background:var(--warn-wash);color:var(--ink)}
.pill.stale .dot{background:var(--warn)}
/* Horodatage du rafraîchissement : même gabarit que les autres pastilles, mais
   teinté marque — c'est l'information qu'on vient vérifier en premier. */
.pill.fresh{border-color:color-mix(in oklab,var(--brand) 32%,var(--line));
 color:var(--brand-ink);background:color-mix(in oklab,var(--brand) 6%,transparent);
 font-variant-numeric:tabular-nums}
.pill.fresh .i-clock{width:13px;height:13px;flex:0 0 auto;opacity:.85}
.brand+em{font-style:normal;font-size:12px;color:var(--mut);align-self:center}
.langs{display:flex;gap:2px;align-items:center}
.lang{font-size:12px;color:var(--mut);text-decoration:none;padding:3px 7px;border-radius:99px;
 border:1px solid transparent;white-space:nowrap}
.lang:hover{color:var(--ink);background:var(--surface-2)}
.lang.on{color:var(--brand-ink);border-color:var(--line);background:var(--surface)}
.iconbtn{border:1px solid var(--line);background:var(--surface);color:var(--ink-2);
 border-radius:99px;width:32px;height:32px;display:grid;place-items:center;cursor:pointer;
 transition:background .18s var(--ease),color .18s var(--ease)}
.iconbtn:hover{background:var(--surface-2);color:var(--ink)}
.iconbtn svg{width:16px;height:16px}
:root[data-theme=dark] .i-sun,.i-moon{display:none}
:root[data-theme=dark] .i-moon{display:block}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .i-sun{display:none}
 :root:not([data-theme=light]) .i-moon{display:block}}

/* ---------- tabs ---------- */
.tabs{display:flex;gap:2px;overflow-x:auto;scrollbar-width:none;
 border-top:1px solid var(--line-soft);background:var(--bg)}
.tabs::-webkit-scrollbar{display:none}
.tabs-in{max-width:var(--page-w);margin:0 auto;padding:0 var(--page-pad);display:flex;gap:2px}
.tab{appearance:none;border:0;background:none;color:var(--mut);cursor:pointer;
 text-decoration:none;display:inline-block;
 padding:11px 14px;font:inherit;font-size:14px;font-weight:520;white-space:nowrap;
 border-bottom:2px solid transparent;transition:color .18s var(--ease),border-color .18s var(--ease)}
.tab:hover{color:var(--ink)}
.tab[aria-current]{color:var(--brand-ink);border-bottom-color:var(--brand)}
/* Césure entre le volet marché et le volet change : un trait, pas un titre —
   la barre reste une seule ligne scrollable sur mobile. */
.tabsep{flex:0 0 auto;align-self:center;width:1px;height:16px;
 margin-inline:10px 8px;background:var(--line)}

/* ---------- panneau de navigation ----------
   Header + panneau gauche (motif Carbon) : le header porte les liens SYSTÈME
   (langue, thème, fraîcheur) à droite, le panneau porte les liens PRODUIT à
   gauche. Ce que la barre d'onglets ne pouvait pas faire : nommer ses groupes.

   Le panneau se replie, parce qu'il prend 256 px sur un écran de sélection à
   seize colonnes. Un seul mécanisme à toutes les largeurs — le même bouton
   ouvre et ferme ; au-dessus de 1056 px il pousse le contenu, en dessous il
   recouvre. L'état est mémorisé. */
:root{--nav-w:256px;--rail-w:48px;--top-h:48px;
 /* Largeur du contenu, lue par l'en-tête, les onglets, le contenu et le pied :
    quatre valeurs séparées finissaient toujours par se désaligner d'un pixel. */
 --page-w:1180px;--page-pad:clamp(12px,2.5vw,24px)}
/* Le bouton commande la barre latérale : il se tient AU-DESSUS d'elle, dans sa
   propre colonne, et n'en bouge plus. Posé dans le flux de l'en-tête, il suivait
   le bloc centré à `max-width:1180px` et flottait à 150 px de la barre qu'il
   replie. `position:fixed` le sort du rembourrage de `body` — c'est le seul
   moyen d'atteindre la colonne du rail, que ce rembourrage réserve justement. */
.navbtn{position:fixed;inset-block-start:0;inset-inline-start:0;z-index:31;
 width:var(--rail-w);height:var(--top-h);display:grid;place-items:center;
 border:0;background:none;color:var(--ink-2);cursor:pointer}
.navbtn:hover{background:var(--surface-2);color:var(--ink)}
.navbtn svg{width:21px;height:21px}
/* Au-dessus de 1056 px, le bouton se loge dans le rembourrage que `body` réserve
   déjà au rail. En dessous il n'y a plus de rembourrage : sans cette réserve,
   le bouton fixe recouvrirait le logo. */
@media (max-width:1055.98px){.top-in{padding-inline-start:calc(var(--rail-w) + 4px)}}
/* Le chevron pousse vers l'extérieur quand le panneau est ouvert, vers
   l'intérieur quand il est replié — et se retourne de lui-même en arabe. */
.navbtn .chev{transition:transform .18s var(--ease);transform-origin:15.5px 12px}
:root[data-nav=full] .navbtn .chev{transform:scaleX(-1)}
[dir=rtl] .navbtn .chev{transform:scaleX(-1)}
[dir=rtl]:root[data-nav=full] .navbtn .chev{transform:none}
@media (prefers-reduced-motion:reduce){.navbtn .chev{transition:none}}

.side{position:fixed;inset-block:var(--top-h) 0;inset-inline-start:0;z-index:25;
 width:var(--nav-w);background:var(--surface);border-inline-end:1px solid var(--line);
 overflow-y:auto;overscroll-behavior:contain;padding:var(--s-nav,12px) 0;
 transition:transform .18s var(--ease)}
.side ul{list-style:none;margin:0;padding:0}
.side a{display:flex;align-items:center;gap:12px;padding:10px 16px;font-size:14px;
 letter-spacing:.16px;color:var(--ink-2);text-decoration:none;
 border-inline-start:3px solid transparent;white-space:nowrap}
.side a svg{width:20px;height:20px;flex:0 0 auto}
.side a:hover{background:var(--surface-2);color:var(--ink)}
.side a[aria-current]{background:var(--brand-wash);color:var(--brand-ink);
 font-weight:600;border-inline-start-color:var(--brand)}
.side-grp{padding:14px 16px 4px;font-size:11.5px;font-weight:600;letter-spacing:.06em;
 text-transform:uppercase;color:var(--mut)}
.side-grp:first-child{padding-top:4px}

/* ---------- rail : la navigation en 48 px ----------
   Le libellé sort de l'oeil mais reste dans le DOM — c'est le nom accessible du
   lien. L'infobulle le reprend telle quelle, au survol ET au focus clavier :
   une navigation en icônes qu'on ne peut lire qu'à la souris n'est pas navigable. */
/* overflow visible en rail : un conteneur qui defile decoupe l'infobulle, et
   elle est posee HORS du panneau de 48 px. Les neuf entrees tiennent sans
   defilement — c'est ce qui rend le compromis acceptable. */
:root[data-nav=rail] .side{width:var(--rail-w);overflow:visible}
:root[data-nav=rail] .side a{justify-content:center;padding:10px 0;gap:0;
 border-inline-start-width:2px}
:root[data-nav=rail] .side-l{position:absolute;width:1px;height:1px;padding:0;
 margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* La ligne de groupe devient un filet : à 48 px un intitulé ne tient pas, mais la
   coupure entre le volet marché et le volet change doit rester lisible. */
:root[data-nav=rail] .side-grp{height:0;padding:0;margin:8px 12px;overflow:hidden;
 border-top:1px solid var(--line)}
:root[data-nav=rail] .side-grp:first-child{margin-top:0;border-top:0}
/* Infobulle : posée par le conteneur, jamais par title= — un title met une seconde
   à paraître et ne se déclenche pas au clavier. */
:root[data-nav=rail] .side a{position:relative}
:root[data-nav=rail] .side a::after{content:attr(data-lbl);position:absolute;
 inset-inline-start:calc(100% + 8px);top:50%;transform:translateY(-50%);
 background:var(--ink);color:var(--bg);font-size:12.5px;letter-spacing:.16px;
 padding:5px 10px;border-radius:var(--r-fld);white-space:nowrap;pointer-events:none;
 opacity:0;visibility:hidden;transition:opacity .1s var(--ease);z-index:40}
:root[data-nav=rail] .side a:hover::after,
:root[data-nav=rail] .side a:focus-visible::after{opacity:1;visibility:visible}
@media (prefers-reduced-motion:reduce){:root[data-nav=rail] .side a::after{transition:none}}
.side-veil{position:fixed;inset:var(--top-h) 0 0;z-index:24;
 background:oklch(0.24 0.018 220/.45)}

/* Replié : le panneau sort du flux, le contenu récupère toute la largeur. */
:root[data-nav=off] .side{transform:translateX(calc(-1 * var(--nav-w)))}
:root[dir=rtl][data-nav=off] .side{transform:translateX(var(--nav-w))}
@media (max-width:1055.98px){:root[data-nav=rail] .side{width:var(--nav-w)}}
@media (min-width:1056px){.side-veil{display:none}}
/* Sous 1056 px le panneau recouvre : il part replié et le voile le ferme. */
@media (max-width:1055.98px){
  .side{transform:translateX(calc(-1 * var(--nav-w)));box-shadow:var(--shadow)}
  :root[dir=rtl] .side{transform:translateX(var(--nav-w))}
  /* `full` et non `on` : le JS n'a jamais écrit `on`, il pose off/rail/full.
     La feuille attendait un état que rien ne produisait — le tiroir restait
     donc à -256 px, invisible, et le voile masqué : le menu ne s'ouvrait pas
     du tout sous 1056 px. */
  :root[data-nav=full] .side{transform:none}
  :root:not([data-nav=full]) .side-veil{display:none}
}
@media (prefers-reduced-motion:reduce){.side{transition:none}}

/* ---------- breadcrumb ---------- */
.crumb{display:flex;gap:8px;align-items:center;font-size:12.5px;color:var(--mut);
 margin:0 0 16px}
.crumb a{color:var(--mut);text-decoration:none}
.crumb a:hover{color:var(--brand-ink);text-decoration:underline}

/* ---------- shell ---------- */
/* ⚠ `main.wrap`, jamais `.wrap` seul : le nom sert AUSSI de modificateur de
   cellule (`td.wrap`, plus bas). Non borné, le gabarit de page posait ses
   30/72 px de marge dans chaque cellule qui portait la classe — invisible dans
   un tableau `.dense`, qui redéclare le padding, et une rangée de 121 px de
   haut partout ailleurs. Un nom, deux emplois : on borne celui qui a un
   élément propre. */
main.wrap{max-width:var(--page-w);margin:0 auto;
 padding:clamp(18px,3vw,30px) var(--page-pad) 72px}
.panel[hidden]{display:none}
section{margin:0 0 clamp(24px,3.4vw,40px)}
h2{font-size:20px;line-height:28px;font-weight:400;letter-spacing:0;
 margin:0 0 4px;color:var(--ink)}
h3{font-size:14px;line-height:18px;font-weight:600;letter-spacing:.16px;
 margin:0 0 8px;color:var(--ink)}
.sub{font-size:14px;line-height:20px;letter-spacing:.16px;color:var(--ink-2);
 margin:0 0 16px}
.head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
 flex-wrap:wrap;margin-bottom:12px}
.head .sub{margin:0}

/* ---------- hero ---------- */
.hero{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
 box-shadow:var(--shadow);overflow:hidden}
.hero-top{display:flex;flex-wrap:wrap;gap:clamp(16px,3vw,40px);
 padding:var(--pad) var(--pad) 6px;align-items:flex-end}
.hero-main{flex:1 1 240px;min-width:0}
.hero-k{font-size:12px;color:var(--mut);letter-spacing:.02em}
.hero-v{font-size:clamp(30px,5.2vw,42px);font-weight:660;letter-spacing:-.03em;
 line-height:1.05;margin:2px 0 4px}
.hero-d{font-size:14px;font-weight:560;white-space:nowrap}
.hero-side{display:flex;gap:clamp(16px,3vw,32px);flex-wrap:wrap;padding-bottom:4px}
.stat .k{font-size:11.5px;color:var(--mut)}
.stat .v{font-size:17px;font-weight:600;letter-spacing:-.02em}
.stat .d{font-size:12.5px}
.chart{display:block;width:100%;height:auto}
.chart .ln{fill:none;stroke:var(--brand);stroke-width:1.6;vector-effect:non-scaling-stroke}
/* le dégradé porte un identifiant par graphique : la règle ne fixe que le trait,
   sinon elle écraserait l'attribut fill et tous les graphiques partageraient un id */
.chart .ar{stroke:none}
.chart .gr{stroke:var(--line-soft);stroke-width:1;vector-effect:non-scaling-stroke}
.chart .pt{fill:var(--brand)}
.chart-x{display:flex;justify-content:space-between;padding:0 var(--pad) 12px;
 font-size:11.5px;color:var(--mut)}

/* ---------- carte de la cote : l'aire dit le poids, la couleur la séance ----
   Pavés positionnés en pourcentages : la carte se redimensionne sans qu'aucun
   calcul ne soit refait au chargement. `aspect-ratio` lui garde une forme
   lisible, et le rapport s'aplatit sur mobile où la largeur commande. */
/* Plus large que haute : la carte ne doit pas pousser le reste de la page sous
   la ligne de flottaison. Les tuiles y perdent en hauteur, d'où une étiquette
   plus grande pour compenser — mieux vaut vingt noms lisibles que cinquante
   qu'on devine. */
.hm{position:relative;width:100%;aspect-ratio:64/21;border-radius:var(--r-sm);
 overflow:hidden;background:var(--line)}
@media (max-width:1055.98px){.hm{aspect-ratio:16/9}}
@media (max-width:720px){.hm{aspect-ratio:3/4}}
.hm-t{position:absolute;display:flex;flex-direction:column;align-items:center;
 justify-content:center;gap:1px;overflow:hidden;text-decoration:none;
 color:var(--ink);outline:1px solid var(--bg);outline-offset:-1px;
 font-size:13.5px;line-height:1.15;padding:1px}
.hm-t b{font-weight:640;letter-spacing:-.01em;max-width:100%;overflow:hidden;
 text-overflow:ellipsis;white-space:nowrap}
.hm-t i{font-style:normal;font-size:12px;color:var(--ink-2)}
/* La tuile se mesure elle-même : une étiquette tronquée en « SOT… » vaut moins
   que pas d'étiquette du tout, et le seuil ne peut pas se calculer au rendu —
   la carte est en 16/9 sur écran large et en 4/5 sur téléphone. */
/* Carte des secteurs : une douzaine de pavés au lieu de soixante-dix-sept, donc
   plus plate et le nom en toutes lettres — un libellé de secteur ne s'abrège
   pas comme un mnémonique. */
.hm-ix{aspect-ratio:64/13}
@media (max-width:1055.98px){.hm-ix{aspect-ratio:16/7}}
@media (max-width:720px){.hm-ix{aspect-ratio:3/4}}
.hm-ix .hm-t{font-size:13px;padding:2px 4px}
.hm-ix .hm-t b{white-space:normal;text-align:center;line-height:1.15;
 display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}

.hm-t{container-type:size}
@container (max-height:36px){.hm-t i{display:none}}
@container (max-width:60px){.hm-t i{display:none}}
@container (max-height:20px){.hm-t b{display:none}}
@container (max-width:40px){.hm-t b{display:none}}
.hm-t:hover,.hm-t:focus-visible{outline:2px solid var(--brand);outline-offset:-2px;
 z-index:2}
/* Pas d'échange : hachures. Le gris seul disait « stable » pour une valeur dont
   on ne sait rien de la séance. */
.hm-x{background-image:repeating-linear-gradient(45deg,transparent 0 4px,
 color-mix(in oklab,var(--mut) 22%,transparent) 4px 5px)}
.hm-x b,.hm-x i{color:var(--mut)}
.hm-leg{display:flex;align-items:center;justify-content:center;gap:2px;
 margin-top:10px;font-size:11.5px;color:var(--mut)}
.hm-leg span{display:inline-flex;align-items:center;gap:5px}
.hm-leg i{width:26px;height:11px;border-radius:2px;display:inline-block}

/* ---------- graphiques interactifs : survol daté, bornes, export ---------- */
.ichart{position:relative}
.ichart .cxl{stroke:var(--brand);stroke-width:1;stroke-dasharray:3 3;
 vector-effect:non-scaling-stroke;opacity:.55}
.ichart .cxd{fill:var(--surface);stroke:var(--brand);stroke-width:2;
 vector-effect:non-scaling-stroke}
.ichart .cx{transition:opacity .12s ease-out;pointer-events:none}
.ichart .chart{touch-action:pan-y}
/* Détachements de dividende : le repère doit se lire sans jamais concurrencer
   la courbe — trait ténu, fanion à l'axe, et le titre natif porte le montant. */
.dvm line{stroke:var(--mut);stroke-width:1;stroke-dasharray:2 4;opacity:.45;
 vector-effect:non-scaling-stroke}
.dvm path{fill:var(--mut);opacity:.75}
.dvm:hover line,.dvm:focus line{opacity:.9;stroke:var(--brand)}
.dvm:hover path,.dvm:focus path{fill:var(--brand);opacity:1}
.tip{position:absolute;top:8px;z-index:2;pointer-events:none;
 background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
 box-shadow:var(--shadow);padding:6px 10px;font-size:12.5px;line-height:1.45;
 white-space:nowrap;transform:translateX(-50%)}
.tip b{font-size:14px;letter-spacing:-.01em}
.tip .tip-d{color:var(--mut);font-size:11.5px}
.crange{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
 padding:0 var(--pad) 12px;font-size:12.5px;color:var(--mut)}
.crange label{display:inline-flex;align-items:center;gap:6px}
.crange input[type=date]{font:inherit;color:var(--ink);background:var(--surface);
 border:1px solid var(--line);border-radius:var(--r-fld);padding:4px 8px;
 min-height:32px;color-scheme:light dark}
.crange button{font:inherit;color:var(--ink);background:var(--surface);cursor:pointer;
 border:1px solid var(--line);border-radius:var(--r-fld);padding:5px 12px;min-height:32px}
.crange button:hover{border-color:var(--brand);color:var(--brand)}
.crange .cr-x{font-weight:600}
.crange .cr-n{margin-inline-start:auto;font-variant-numeric:tabular-nums}
.crange .cr-n[data-empty]{color:var(--down)}
@media (max-width:720px){
 .crange{font-size:12px;gap:6px}
 .crange .cr-n{margin-inline-start:0;flex-basis:100%}
}
@media (prefers-reduced-motion:reduce){.ichart .cx{transition:none}}

/* ---------- surfaces ---------- */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
 box-shadow:var(--shadow)}
.card-pad{padding:var(--pad)}
.split{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(310px,1fr))}
.split.wide{grid-template-columns:repeat(auto-fit,minmax(480px,1fr))}
.scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* En-tête collant : `overflow-x:auto` fait calculer `overflow-y:auto`, donc
   .scroll DEVIENT le port de défilement du th{position:sticky;top:0}. Sans
   hauteur, ce port ne défile jamais et l'en-tête ne colle à rien : mesuré sur
   cotes.html, le <th> était à −647 px après 900 px de défilement de page.
   .scroll-y borne la hauteur, ce qui rend le port réel et l'en-tête effectif.
   Réservé aux tableaux longs — ailleurs, un défilement imbriqué serait pire
   que le mal. */
.scroll-y{max-block-size:calc(100dvh - 15rem);min-block-size:22rem;overflow-y:auto}
@supports not (height:100dvh){.scroll-y{max-block-size:calc(100vh - 15rem)}}

/* ---------- barres de défilement ----------
   La barre native de Windows est épaisse et grise : dans une liste de valeurs
   haute de dix lignes, elle pèse plus que son contenu. On la ramène à un trait
   qui suit les couleurs du thème, sans la faire disparaître — une barre
   invisible ne dit plus qu'il y a quelque chose à faire défiler.
   Les deux syntaxes coexistent : la standard (Firefox) et celle de WebKit. */
.scroll,.cmp-sugg{scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.scroll::-webkit-scrollbar,.cmp-sugg::-webkit-scrollbar{width:10px;height:10px}
.scroll::-webkit-scrollbar-track,.cmp-sugg::-webkit-scrollbar-track{background:transparent}
.scroll::-webkit-scrollbar-thumb,.cmp-sugg::-webkit-scrollbar-thumb{
 background:var(--line);border-radius:99px;border:3px solid var(--surface)}
.scroll:hover::-webkit-scrollbar-thumb,.cmp-sugg:hover::-webkit-scrollbar-thumb{
 background:color-mix(in oklab,var(--mut) 55%,transparent)}
.scroll::-webkit-scrollbar-thumb:hover,.cmp-sugg::-webkit-scrollbar-thumb:hover{
 background:var(--mut)}
.scroll::-webkit-scrollbar-corner,.cmp-sugg::-webkit-scrollbar-corner{background:transparent}

/* ---------- stat row (no card grid) ---------- */
.statrow{display:flex;flex-wrap:wrap;gap:0;background:var(--surface);border:1px solid var(--line);
 border-radius:var(--r-lg);box-shadow:var(--shadow);overflow:hidden}
.statrow>div{flex:1 1 170px;padding:14px var(--pad);border-inline-end:1px solid var(--line-soft)}
.statrow>div:last-child{border-inline-end:0}
.statrow .k{font-size:11.5px;color:var(--mut)}
.statrow .v{font-size:clamp(19px,2.6vw,23px);font-weight:640;letter-spacing:-.025em;margin:1px 0}
.statrow .d{font-size:12.5px;color:var(--mut)}

/* ---------- tables ---------- */
table{width:100%;border-collapse:collapse;font-size:14px}
caption{text-align:start;font-size:12.5px;color:var(--mut);padding:0 0 8px}
/* Le filet bas est une ombre interne et non un border-bottom : sur un th
   collant, Chrome laisse la bordure au fil du tableau et elle disparaît dès que
   l'en-tête décolle. */
th{text-align:start;font-size:12px;line-height:16px;font-weight:600;color:var(--ink);
 letter-spacing:.32px;height:32px;padding:0 10px;
 box-shadow:inset 0 -1px 0 var(--line);
 white-space:nowrap;position:sticky;top:0;background:var(--accent);z-index:1}
th.s:hover{background:var(--accent-hover)}
td{height:32px;padding:6px 10px;line-height:20px;
 border-bottom:1px solid var(--line-soft);white-space:nowrap}
table.prose td{white-space:normal}
/* Colonne de texte long (intitulé d'une publication) : elle se replie au lieu
   d'obliger à faire défiler le tableau — sur un téléphone c'est la seule
   colonne qu'on vient lire. */
td.wrap{white-space:normal;min-width:20ch;max-width:70ch;line-height:1.35}
/* Tableau de lecture, pas de chiffres : beaucoup de lignes courtes, donc moins
   d'air que dans les tableaux de cotes. */
/* Marque d'une date rectifiée : discrète, mais visible et survolable. */
abbr.fix{margin-inline-start:6px;font-size:11px;color:var(--mut);
 border-bottom:1px dotted var(--mut);cursor:help;text-decoration:none;white-space:nowrap}
table.dense td{padding:5px 10px}
table.dense th{padding:6px 10px}
table.prose td:first-child{width:26%;font-weight:520;vertical-align:top}
tbody tr:last-child td{border-bottom:0}
tbody tr{transition:background .14s var(--ease)}
tbody tr:hover{background:var(--surface-2)}
.num{text-align:end;font-variant-numeric:tabular-nums}
.tk{font-weight:600}
.nm{color:var(--mut);font-size:12.5px;font-weight:400;margin-inline-start:7px}
th.s{cursor:pointer;user-select:none}
th.s:hover{color:var(--ink)}
th.s::after{content:"";opacity:.28;margin-inline-start:5px;font-size:10px}
th.s[aria-sort=ascending]::after{content:"▲";opacity:.85}
th.s[aria-sort=descending]::after{content:"▼";opacity:.85}
.up{color:var(--up)}.down{color:var(--down)}.flat{color:var(--mut)}
.chip{display:inline-block;padding:1px 7px;border-radius:var(--r-fld);font-size:11.5px;
 font-weight:600;white-space:nowrap;
 background:var(--brand-wash);color:var(--brand-ink)}
.chip.up{background:var(--up-wash);color:var(--up)}
.chip.down{background:var(--down-wash);color:var(--down)}
/* Familles de nature des publications. Trois teintes, pas vingt-neuf : coder
   chaque nature ferait un nuancier, pas une aide à la lecture. Le reste garde
   la pastille neutre. Aucune ne réutilise --up/--down : une nature n'est ni une
   hausse ni une baisse. */
.chip.nat{font-weight:500;background:var(--surface-2);color:var(--ink-2);
 border:1px solid var(--line-soft)}
.chip.nat.fam-cotation{background:var(--warn-wash);color:var(--ink);
 border-color:color-mix(in oklab,var(--warn) 45%,var(--line))}
.chip.nat.fam-comptes{background:var(--brand-wash);color:var(--brand-ink);
 border-color:color-mix(in oklab,var(--brand) 30%,var(--line))}
.chip.nat.fam-capital{background:var(--accent);color:var(--ink);border-color:var(--line)}

/* ---------- comparateur : habillage replié ---------- */
.cmp-more{margin-top:6px}
.cmp-more>summary{display:flex;align-items:center;gap:8px;cursor:pointer;
 list-style:none;width:max-content;padding:5px 11px;border:1px solid var(--line);
 border-radius:var(--r-fld);background:var(--surface);font-size:12.5px;
 color:var(--ink-2);min-height:32px}
.cmp-more>summary::-webkit-details-marker{display:none}
.cmp-more>summary::before{content:"";width:0;height:0;flex:0 0 auto;
 border-inline-start:5px solid currentColor;border-block:4px solid transparent;
 transition:transform .14s var(--ease)}
[dir=rtl] .cmp-more>summary::before{transform:scaleX(-1)}
.cmp-more[open]>summary::before{transform:rotate(90deg)}
[dir=rtl] .cmp-more[open]>summary::before{transform:scaleX(-1) rotate(-90deg)}
.cmp-more>summary:hover{border-color:var(--brand);color:var(--ink)}
.cmp-more>summary .sm-t{font-weight:600}
.cmp-more[open]>summary{margin-bottom:6px}
@media (prefers-reduced-motion:reduce){.cmp-more>summary::before{transition:none}}

/* ---------- rail d'ancres d'une fiche ----------
   Collant sous la barre d'onglets. Horizontal et non en colonne : il se miroite
   seul en arabe, tient sous 672 px, et ne touche pas à la grille de la page.
   scroll-padding-top empêche l'ancre d'atterrir sous le chrome collant. */
.rail{position:sticky;top:var(--rail-top,0);z-index:20;display:flex;gap:2px;
 overflow-x:auto;scrollbar-width:none;margin:0 0 clamp(24px,3.4vw,40px);
 padding:6px 0;background:color-mix(in oklab,var(--bg) 92%,transparent);
 -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-bottom:1px solid var(--line-soft)}
.rail::-webkit-scrollbar{display:none}
.rail a{flex:0 0 auto;padding:6px 12px;border-radius:var(--r-fld);
 font-size:12.5px;color:var(--mut);text-decoration:none;white-space:nowrap;
 transition:background .14s var(--ease),color .14s var(--ease)}
.rail a:hover{background:var(--surface-2);color:var(--ink)}
@media (prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}

/* ---------- ratios d'une fiche : quatre groupes, une médiane ---------- */
/* Une rangée de groupe est un en-tête de portée, pas une ligne de données :
   elle porte scope=colgroup et se distingue par la couche, pas par une couleur. */
table.ratios tr.grp-row th{position:static;height:32px;text-align:start;
 background:var(--surface-2);color:var(--mut);font-size:11.5px;font-weight:600;
 letter-spacing:.06em;text-transform:uppercase;padding:0 10px;
 box-shadow:inset 0 -1px 0 var(--line)}
table.ratios tr.grp-row:first-child th{box-shadow:inset 0 -1px 0 var(--line)}
table.ratios td:first-child{width:46%}
table.ratios td:nth-child(2){font-weight:600;color:var(--ink)}
/* La colonne de comparaison reste en retrait : c'est un repère, pas la donnée
   de la ligne. Le chevron dit le sens, jamais la couleur — « au-dessus de la
   médiane » n'est ni une hausse ni une bonne nouvelle en soi. */
table.ratios td:last-child{width:26%;color:var(--mut)}
table.ratios .ecart{font-size:10px;opacity:.75;margin-inline-end:2px}
table.ratios thead th{height:auto;padding-bottom:4px;background:none;
 box-shadow:none;font-size:11.5px;color:var(--mut);text-transform:none;letter-spacing:.02em}
/* La sparkline se cale sur la ligne du texte : a 22 px elle imposait une
   rangee de 35 px la ou l'en-tete en fait 32, ce que Carbon interdit
   (l'en-tete et le corps ont la meme taille de rangee). Le viewBox
   redimensionne, le trace n'est pas deforme. */
.spark{width:74px;height:20px;display:block}

/* ---------- diverging bars (the beam) ---------- */
.beam{display:grid;gap:1px}
.dv{display:grid;grid-template-columns:minmax(96px,1.1fr) minmax(120px,3fr) 64px;
 gap:12px;align-items:center;padding:4px 0}
.dv-l{font-size:13px;color:var(--ink-2);overflow:hidden;text-overflow:ellipsis}
.dv-t{position:relative;height:16px}
.dv-t::before{content:"";position:absolute;left:50%;top:-2px;bottom:-2px;width:1px;
 background:var(--line)}
.dv-t i{position:absolute;top:3px;height:10px;border-radius:2px;display:block;
 animation:grow .5s var(--ease) both}
.dv-t i.up{left:50%;background:var(--up)}
.dv-t i.down{right:50%;background:var(--down)}
.dv-t.mag::before{left:0}
.dv-t.mag i{left:0;background:var(--brand);transform-origin:left}
.dv-v{font-size:12.5px;text-align:end}
@keyframes grow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.dv-t i.up{transform-origin:left}
.dv-t i.down{transform-origin:right}

/* ---------- feeds ---------- */
.feed{list-style:none;margin:0;padding:0}
.feed li{display:flex;gap:10px;align-items:baseline;padding:9px var(--pad);
 border-bottom:1px solid var(--line-soft)}
.feed li:last-child{border-bottom:0}
.feed .dt{color:var(--mut);font-size:12px;flex:0 0 auto;min-width:38px}
.feed a{color:var(--ink);text-decoration:none;text-decoration-color:var(--line)}
.feed a:hover{color:var(--brand-ink);text-decoration:underline}
.feed .tks{flex:0 0 auto}

/* ---------- listes de prose ---------- */
/* Même mesure de lecture que les paragraphes : sans cela, dans une même carte,
   la prose s'arrêtait à 589 px pendant que les puces couraient sur 1 070 —
   deux longueurs de ligne pour un seul texte, et une carte à moitié vide. */
.bullets{margin:10px 0 0;padding-inline-start:20px;color:var(--mut);font-size:13.5px;
 line-height:1.65}
.bullets li{margin-bottom:7px}
.bullets li b{color:var(--ink-2)}
.card-pad p.sub+p.sub{margin-top:10px}
/* Le texte occupe la largeur qu'on lui donne. La mesure de lecture de 78ch
   laissait, dans une carte de 1 132 px, cinq cents pixels de vide à sa droite :
   un paragraphe qui s'arrête au tiers d'un cadre se lit comme un défaut
   d'alignement, pas comme une colonne. Tableaux et graphiques, eux, gardent
   leur cadre — c'est le texte seul qui s'étirait mal. */

/* ---------- notice ---------- */
.notice{display:flex;gap:11px;align-items:flex-start;padding:12px 14px;border-radius:var(--r);
 border:1px solid color-mix(in oklab,var(--warn) 40%,var(--line));background:var(--warn-wash);
 font-size:13.5px;margin-bottom:18px}
.notice b{font-weight:620}
.notice svg{flex:0 0 auto;width:17px;height:17px;color:var(--warn);margin-top:1px}

/* ---------- filter ---------- */
.filter{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:12px}
.filter input,.filter select{font:inherit;font-size:13.5px;color:var(--ink);
 background:var(--surface);border:1px solid var(--line);border-radius:99px;padding:7px 13px}
.filter input{min-width:190px}
.filter input::placeholder{color:var(--mut)}
.count{font-size:12.5px;color:var(--mut)}
/* Jeux de colonnes : trois familles qui s'échangent, le reste du tableau ne
   bouge pas. Un seul contrôle segmenté, pas un menu — les trois options se
   lisent d'un coup et l'active se voit sans l'ouvrir. */
.views{display:inline-flex;border:1px solid var(--line);border-radius:var(--r-fld);
 overflow:hidden;background:var(--surface)}
.views button{font:inherit;font-size:12.5px;color:var(--mut);background:none;border:0;
 padding:6px 12px;min-height:32px;cursor:pointer;white-space:nowrap;
 border-inline-end:1px solid var(--line);transition:background .14s var(--ease)}
.views button:last-child{border-inline-end:0}
.views button:hover{background:var(--surface-2);color:var(--ink)}
.views button[aria-pressed=true]{background:var(--brand);color:oklch(1 0 0);font-weight:600}
:root[data-theme=dark] .views button[aria-pressed=true]{color:oklch(0.178 0.014 222)}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .views button[aria-pressed=true]{
 color:oklch(0.178 0.014 222)}}

/* Rangée de familles : elle se cale SOUS elle-même dans le port de défilement,
   donc la seconde rangée d'en-têtes doit descendre d'autant. 32 px = la hauteur
   d'une rangée. */
tr.grps th{height:32px;top:0;z-index:3;background:var(--surface-2);color:var(--mut);
 font-size:11.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
 text-align:center;box-shadow:inset 0 -1px 0 var(--line)}
tr.grps th:first-child{text-align:start}
tr.grps+tr th{top:32px;z-index:2}
th.grp[data-g]{border-inline-start:1px solid var(--line)}
/* Le score est l'argument du site : il ne peut pas finir hors écran. Il se fige
   au bord de fin du port de défilement, comme la colonne d'identité se fige au
   bord de début. Un filet le détache du reste. */
td.sc,th.sc{position:sticky;inset-inline-end:0;z-index:2;
 box-shadow:inset 1px 0 0 var(--line)}
td.sc{background:var(--surface)}
th.sc{background:var(--accent);z-index:4}
tr.grps th:last-child{position:sticky;inset-inline-end:0;z-index:5;
 background:var(--surface-2);box-shadow:inset 1px 0 0 var(--line)}
tbody tr:hover td.sc{background:var(--surface-2)}
td.sc b,th.sc{color:var(--ink)}
/* La raison sociale ne pousse pas la table : elle se tronque proprement. */
td .nm{display:inline-block;max-width:26ch;overflow:hidden;text-overflow:ellipsis;
 vertical-align:bottom}

/* ---------- comparateur ----------
   Palette d'identité d'Okabe-Ito : six teintes conçues pour rester distinctes
   en vision dichromate. Un premier essai en teintes régulièrement espacées
   confondait la troisième et la sixième — deux violets voisins — alors que la
   couleur ne dit rien ici sinon « c'est cette valeur-là ». Les teintes sont
   éclaircies en sombre, l'écart entre elles est conservé. */
:root{--c1:oklch(52% .12 250);--c2:oklch(72% .14 75);--c3:oklch(58% .12 165);
 --c4:oklch(60% .11 350);--c5:oklch(55% .16 45);--c6:oklch(68% .10 235)}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
 --c1:oklch(70% .13 250);--c2:oklch(82% .14 75);--c3:oklch(72% .13 165);
 --c4:oklch(74% .11 350);--c5:oklch(70% .16 45);--c6:oklch(80% .10 235)}}
:root[data-theme=dark]{--c1:oklch(70% .13 250);--c2:oklch(82% .14 75);
 --c3:oklch(72% .13 165);--c4:oklch(74% .11 350);--c5:oklch(70% .16 45);
 --c6:oklch(80% .10 235)}
.cmp-bar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:12px}
.cmp-bar .seg{display:inline-flex;border:1px solid var(--line);border-radius:99px;
 overflow:hidden;background:var(--surface)}
.cmp-bar .seg button{font:inherit;font-size:12.5px;color:var(--mut);background:none;
 border:0;padding:6px 11px;cursor:pointer;white-space:nowrap}
.cmp-bar .cmp-x,.cmp-all{white-space:nowrap;font:inherit;font-size:12.5px;color:var(--ink);
 background:var(--surface);border:1px solid var(--line);border-radius:99px;
 padding:6px 13px;cursor:pointer}
.cmp-bar .cmp-x:hover,.cmp-all:hover:not(:disabled){border-color:var(--brand)}
.cmp-all:disabled{opacity:.4;cursor:default}
.cmp-ost{font-size:12px;color:var(--mut);margin-top:6px}
.cmp-ost b{color:var(--ink-2);font-weight:600}
.cmp-bar .seg button[aria-pressed=true]{background:var(--brand);color:oklch(1 0 0)}
/* Deux colonnes, deux rangées : les en-têtes en haut, la liste et le graphique
   dessous. `display:contents` fait entrer les quatre blocs dans la même grille,
   si bien que la rangée des en-têtes prend la hauteur du plus grand et que la
   liste et le graphique démarrent au même endroit — sans hauteur écrite en dur,
   qui aurait cédé à la première traduction plus longue.
   ⚠️ Remplissage par COLONNES : en rangées, la liste se plaçait à côté de son
   propre en-tête. Les quatre blocs arrivent dans l'ordre en-tête gauche, liste,
   en-tête droit, graphique — soit exactement deux colonnes de deux. */
/* Plus de grille à deux colonnes : le choix des valeurs tient sur une barre, et
   le graphique prend toute la largeur — c'est lui qu'on vient regarder. */
.cmp-pick{display:block}
.cmp-col{display:block}
/* Les deux en-têtes n'ont pas le même nombre de rangées : les répartir sur la
   hauteur commune les fait se répondre, plutôt que de coller les plus courtes
   en bas de leur bande. */
.cmp-hd{display:flex;flex-direction:column;justify-content:space-between;gap:8px}
/* Un enfant de grille garde par défaut la largeur de son contenu : sans ce
   min-width:0, les raisons sociales longues élargissaient toute la page sur
   téléphone (490 px de large pour 375 px de fenêtre). */
.cmp-pick>*{min-width:0}
@media (max-width:720px){
  /* Une seule colonne : les blocs reprennent leur ordre naturel, et le
     graphique passe devant — personne ne veut faire défiler soixante cases à
     cocher pour voir la courbe. */
  .cmp-saisie{flex:1 1 100%}
  /* Le tracé garderait sinon son rapport 1000:320, soit 91 px de haut sur un
     téléphone : illisible. `preserveAspectRatio=none` lui permet d'être étiré. */
  .cmp-chart{height:240px}
  /* Le groupe de boutons ne peut pas se replier dans une pastille unique : il
     débordait, et « 3 ans » comme « Tout » étaient rognés. Sous 720 px, chaque
     bouton devient sa propre pastille et la ligne se replie. */
  .cmp-bar .seg{flex-wrap:wrap;gap:6px;border:0;background:none;overflow:visible}
  .cmp-bar .seg button{border:1px solid var(--line);border-radius:99px;
   background:var(--surface)}
  .cmp-bar .seg button[aria-pressed=true]{border-color:var(--brand)}
}
/* La liste occupe toute la rangée : elle finit donc exactement où finit la
   carte du graphique, au lieu de s'arrêter cent pixels plus haut.
   ⚠️ Elle est posée en absolu dans son cadre, sinon ses 77 lignes dictent la
   hauteur de la rangée — le graphique se retrouvait étiré sur 2 100 px. C'est
   donc le graphique qui commande, et la liste s'y ajuste. */
/* Le choix des valeurs : UN champ. Les jetons vivent dans la boîte de saisie,
   comme les destinataires d'un courriel — la sélection et l'ajout ne sont plus
   deux rangées mais un seul objet, qui se comporte comme un champ de texte. */
.cmp-champ{position:relative;display:flex;flex-wrap:wrap;align-items:center;gap:6px;
 padding:7px 8px;border:1px solid var(--line);border-radius:var(--r-sm);
 background:var(--surface);cursor:text;transition:border-color .15s var(--ease)}
.cmp-champ:focus-within{border-color:var(--brand);
 box-shadow:0 0 0 3px color-mix(in oklab,var(--brand) 14%,transparent)}
.cmp-jetons{display:contents}
.cmp-jeton{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:12.5px;
 padding:3px 4px 3px 8px;border:0;border-radius:99px;cursor:pointer;
 background:var(--surface-2);color:var(--ink)}
.cmp-jeton i{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
.cmp-jeton b{font-weight:600;letter-spacing:-.01em}
/* La croix ne s'affiche qu'au survol : douze jetons portant chacun leur croix
   font un mur de bruit, alors que la cible reste le jeton entier. */
.cmp-jeton span{width:14px;text-align:center;color:var(--mut);font-size:14px;
 line-height:1;opacity:0;transition:opacity .12s var(--ease)}
.cmp-jeton:hover,.cmp-jeton:focus-visible{background:color-mix(in oklab,var(--down) 12%,var(--surface-2));
 color:var(--down)}
.cmp-jeton:hover span,.cmp-jeton:focus-visible span{opacity:1;color:var(--down)}
.cmp-champ .cmp-q{flex:1 1 12ch;min-width:12ch;border:0;background:none;padding:3px 2px;
 font:inherit;font-size:13px;color:var(--ink);outline:none}
.cmp-champ .cmp-q::placeholder{color:var(--mut)}
/* Vider : discret, et seulement quand il y a quelque chose à vider. */
.cmp-clear{border:0;background:none;color:var(--mut);font-size:16px;line-height:1;
 cursor:pointer;padding:2px 4px;border-radius:var(--r-fld);margin-inline-start:auto}
.cmp-clear:hover{color:var(--down);background:var(--surface-2)}
.cmp-champ.vide .cmp-clear{display:none}
.cmp-sugg{position:absolute;z-index:20;inset-inline:0;top:calc(100% + 4px);margin:0;
 padding:4px;list-style:none;max-height:300px;overflow:auto;background:var(--surface);
 border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--shadow)}
.cmp-sugg li{display:flex;gap:8px;align-items:baseline;padding:6px 8px;border-radius:8px;
 cursor:pointer;font-size:13px}
.cmp-sugg li:hover,.cmp-sugg li[aria-selected=true]{background:var(--surface-2)}
.cmp-sugg li b{font-weight:600;min-width:6ch}
.cmp-sugg li span{color:var(--mut);font-size:12px;overflow:hidden;
 text-overflow:ellipsis;white-space:nowrap}
/* Un secteur n'est pas une valeur : il ajoute une poignée de courbes d'un coup,
   et se distingue donc de ce qui n'en ajoute qu'une. */
.cmp-sug-sec b{color:var(--brand)}
.cmp-sug-sec{border-bottom:1px solid transparent}
/* Le pied du graphique : base de calcul, export, et rien d'autre. */
.cmp-pied{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}
.cmp-pied .cmp-trn{margin:0;flex:1 1 auto}
.cmp-chart{width:100%;height:auto;display:block;direction:ltr;touch-action:pan-y}
.cmp-wrap{position:relative;display:grid;grid-template-columns:1fr auto;gap:8px}
/* Chaque graduation est posée à la hauteur exacte de sa ligne de grille : une
   colonne en `space-between` les répartissait sur toute la boîte, décalées de
   la marge interne du tracé. */
.cmp-y{position:relative;font-size:11px;color:var(--mut);
 font-variant-numeric:tabular-nums;min-width:5ch}
.cmp-y span{position:absolute;inset-inline-end:0;transform:translateY(-50%);
 white-space:nowrap}
/* L'axe des dates suit le tracé, donc l'ordre chronologique de gauche à droite,
   y compris en RTL. Chaque date reste isolée pour que l'arabe s'y écrive dans
   son propre sens sans réordonner la ligne. */
.cmp-dates{display:flex;justify-content:space-between;font-size:11px;color:var(--mut);
 margin-top:4px;direction:ltr}
.cmp-dates span{unicode-bidi:isolate}
.cmp-leg{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;font-size:12.5px}
.cmp-l{display:inline-flex;gap:6px;align-items:center;font:inherit;font-size:12.5px;
 color:var(--ink);background:none;border:1px solid transparent;border-radius:99px;
 padding:3px 9px;cursor:pointer}
.cmp-l:hover{background:var(--surface-2)}
.cmp-l[aria-pressed=true]{border-color:var(--line);background:var(--surface-2)}
.cmp-clear{font:inherit;font-size:15px;line-height:1;color:var(--mut);
 background:var(--surface);border:1px solid var(--line);border-radius:99px;
 padding:5px 11px;cursor:pointer}
.cmp-clear:hover{color:var(--down);border-color:var(--down)}
.cmp-l i,.cmp-d{width:10px;height:10px;border-radius:3px;display:inline-block}
.cmp-d{margin-inline-end:7px;vertical-align:-1px}
.cmp-lv{color:var(--mut);font-variant-numeric:tabular-nums}
.cmp-tip{position:absolute;top:6px;transform:translateX(-50%);pointer-events:none;
 background:var(--surface);border:1px solid var(--line);border-radius:10px;padding:7px 10px;
 font-size:12px;box-shadow:0 6px 20px rgba(0,0,0,.13);white-space:nowrap;z-index:3}
.cmp-tip i{width:9px;height:9px;border-radius:2px;display:inline-block;margin-inline-end:5px}
.cmp-tip .tip-d{color:var(--mut);margin-bottom:3px}
.cmp-note{font-size:12px;color:var(--mut);margin-top:6px}
.cmp-bar2{margin-top:-4px}
.cmp-bar2 .lbl{font-size:12px;color:var(--mut)}
.cmp-bar .seg-mm button,.cmp-bar .seg-outils button{min-width:38px;text-align:center}
.cmp-wipe{font:inherit;font-size:12.5px;color:var(--mut);background:none;border:0;
 padding:6px 8px;cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.cmp-wipe:hover{color:var(--down)}
.cmp-dess .dr{stroke:var(--brand);stroke-width:1.6;vector-effect:non-scaling-stroke}
.cmp-dess .dr-tmp{stroke-dasharray:4 3;opacity:.7}
.cmp-dess .dr-fib{stroke-width:1;opacity:.6}
.cmp-chart .il{font-size:10px;fill:var(--mut)}
.cmp-tip .up{color:var(--up)} .cmp-tip .down{color:var(--down)}
.cmp-grid .gr{stroke:var(--line-soft);stroke-width:1;vector-effect:non-scaling-stroke}
.cmp-grid .gr0{stroke:var(--mut);stroke-width:1;vector-effect:non-scaling-stroke;opacity:.55}
.cmp-cx{stroke:var(--brand);stroke-width:1;stroke-dasharray:3 3;
 vector-effect:non-scaling-stroke;opacity:0}
table.corr th{font-weight:560}
table.corr td[data-c]{font-weight:600}

/* ---------- pagination ----------
   La page porte ses 2 500 lignes ; sans cette règle le navigateur les met
   toutes en page avant que le script de fin de document n'en cache 2 480, et
   le tableau se réajuste sous les yeux pendant une à deux secondes. La règle
   ne s'applique que si le script du <head> a posé `js` : sans JavaScript, le
   tableau reste entier et lisible, faute de pagination pour le parcourir.
   Le seuil suit `data-page="20"` — l'autotest vérifie qu'ils ne divergent pas. */
html.js table.pg-init tbody tr:nth-child(n+21){display:none}

/* ---------- pagination ---------- */
.pager{display:flex;gap:8px;align-items:center;justify-content:flex-end;
 margin-top:10px;font-size:12.5px;color:var(--mut)}
.pager button{font:inherit;font-size:15px;line-height:1;color:var(--ink);
 background:var(--surface);border:1px solid var(--line);border-radius:99px;
 padding:5px 12px;cursor:pointer}
.pager button:hover:not(:disabled){border-color:var(--brand)}
.pager button:disabled{opacity:.35;cursor:default}
.pager .pg-info{min-width:11ch;text-align:center;font-variant-numeric:tabular-nums}
.pager select{font:inherit;font-size:12.5px;color:var(--ink);background:var(--surface);
 border:1px solid var(--line);border-radius:99px;padding:4px 9px}
/* Les flèches suivent le sens de lecture : en RTL, « précédent » pointe à droite. */
[dir=rtl] .pager button{transform:scaleX(-1)}

/* ---------- footer ---------- */
footer{max-width:var(--page-w);margin:0 auto;padding:26px var(--page-pad) 44px;
 border-top:1px solid var(--line);color:var(--mut);font-size:12.5px;line-height:1.65}
footer a{color:var(--mut)}

/* ---------- arabe, sens de lecture inversé ----------
   La mise en page se retourne d'elle-même grâce aux propriétés logiques
   (text-align:start/end, margin-inline, inset-inline). Deux exceptions :
   les courbes, où le temps va toujours de gauche à droite, et les nombres,
   qu'il faut isoler pour que « -1,05 % » ne soit pas réordonné par l'algorithme
   bidirectionnel. */
[dir=rtl] .chart,[dir=rtl] .spark,[dir=rtl] .dv-t{direction:ltr}
[dir=rtl] .num,[dir=rtl] .hero-v,[dir=rtl] .kpi-value,[dir=rtl] .statrow .v,
[dir=rtl] .stat .v,[dir=rtl] .dv-v,[dir=rtl] .dt{unicode-bidi:plaintext}
[dir=rtl] .tk{unicode-bidi:isolate}
[dir=rtl] .crumb span[aria-hidden]{transform:scaleX(-1);display:inline-block}
[dir=rtl] .skip{left:auto;right:-9999px}
[dir=rtl] .skip:focus{right:0}
[dir=rtl] .bullets{padding-inline-start:20px}

/* ---------- mobile ----------
   Les tableaux de données sont larges par nature. Plutôt que de tout comprimer,
   on hiérarchise : les colonnes marquées .opt disparaissent sous 720 px, la
   première colonne reste figée pendant le défilement horizontal, et une ombre
   au bord droit signale qu'il reste du contenu — sans cet indice, personne ne
   découvre le défilement. */
@media (max-width:720px){
  .scroll table td:first-child,
  .scroll table th:first-child{position:sticky;inset-inline-start:0;z-index:2;
    background:var(--surface);box-shadow:1px 0 0 var(--line-soft)}
  .scroll tbody tr:hover td:first-child{background:var(--surface-2)}
  .scroll{background-image:
      linear-gradient(to right,var(--surface),transparent 12px),
      linear-gradient(to left,var(--surface),transparent 12px),
      linear-gradient(to right,oklch(0.5 0 0/.10),transparent 10px),
      linear-gradient(to left,oklch(0.5 0 0/.10),transparent 10px);
    background-position:left center,right center,left center,right center;
    background-repeat:no-repeat;background-size:24px 100%,24px 100%,10px 100%,10px 100%;
    background-attachment:local,local,scroll,scroll}
  table{font-size:13.5px}
  td,th{padding:7px 8px}
  .nm{display:block;margin-inline-start:0;font-size:11.5px}
  .spark{width:56px}
  /* En dernier et qualifié : .nm{display:block} ci-dessus l'emporterait sinon sur
     les cellules qui portent les deux classes. */
  td.opt,th.opt,span.opt,.opt{display:none}
}
@media (max-width:640px){
  .dv{grid-template-columns:minmax(82px,1fr) minmax(70px,2fr) 58px;gap:8px}
  .statrow>div{flex:1 1 50%;border-bottom:1px solid var(--line-soft)}
  .hero-top{gap:14px}
  .hero-side{gap:16px}
  .stat .v{font-size:15px}
  .filter input,.filter select{flex:1 1 100%;min-width:0}
  .feed li{flex-wrap:wrap;gap:6px}
  .feed li a{flex:1 1 100%}
  .top-in{gap:8px;padding:9px 12px}
  .top-meta{width:100%;margin-inline-start:0;font-size:11.5px;gap:6px}
  .brand-txt b{font-size:17px}
  footer{font-size:11.5px}
}
@media (max-width:420px){
  .statrow>div{flex:1 1 100%}
  .dv{grid-template-columns:minmax(72px,1fr) minmax(50px,1.4fr) 52px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}
@media print{
  .top,.tabs,.iconbtn{display:none}
  .panel[hidden]{display:block!important}
  body{background:#fff}
  .card,.hero,.statrow{break-inside:avoid;box-shadow:none}
}

/* ---------- decalage du contenu par le panneau ----------
   Le decalage est pose sur le CONTENEUR, pas sur chaque bloc.

   Premiere version : `margin-inline-start` sur `.wrap` et `footer>*`. Elle
   ecrasait le `margin:0 auto` de ces blocs, donc le contenu se collait au rail
   pendant que l'en-tete, lui, restait centre — mesure sur un ecran de 2560 px :
   en-tete a 683 du bord, contenu a 48, pied a 755. Trois alignements pour une
   meme page, et un vide de 1332 px a droite du tableau.

   `padding-inline-start` sur `body` decale l'en-tete, le contenu et le pied
   ensemble ; chacun garde son `margin:0 auto` et se recentre dans la largeur
   restante. Le panneau est en `position:fixed` : il se loge exactement dans le
   rembourrage. */
@media (min-width:1056px){
  body{padding-inline-start:var(--nav-w);
   transition:padding-inline-start .18s var(--ease)}
  :root[data-nav=rail] body{padding-inline-start:var(--rail-w)}
  :root[data-nav=off] body{padding-inline-start:0}
}
@media (prefers-reduced-motion:reduce){body{transition:none}}
