/* Bertrande. LE CHAMP GRADUE.
   Trois couches, une regle chacune, et rien d'autre :
     1. le CHAMP    : une trame graduee fixe couvre la fenetre, le contenu glisse dessus ;
     2. l'ENCRE     : tout ce qui NOMME une donnee (bandeau de site, en-tete de colonne)
                      est reserve en blanc dans un pave d'encre pleine ;
     3. la COTE     : tout ce qui EST une donnee reste nu sur le champ, et chaque nombre
                      d'une colonne chiffree porte sous lui sa position sur l'echelle
                      reelle de toutes les valeurs publiees du meme parametre.
   Aucun trait de ce fichier n'est decoratif : la trame est une graduation, la barre
   d'en-tete est une couverture comptee, la cote est une valeur publiee.
   Clair et sombre tenus tous les deux, l'utilisateur systeme decide. */

:root{
  /* Le pas de la graduation. Tout espacement du fichier en est un multiple
     entier : la regularite se VOIT au lieu de se supposer. */
  --pas:8px;        /* graduation mineure */
  --pas-fort:64px;  /* graduation majeure : 8 mineures */
  --r:.125rem;      /* un seul rayon, et il ne sert qu'aux controles manipules */
  /* Six tailles, pas vingt et une. */
  --t1:.6875rem; --t2:.8125rem; --t3:.9375rem; --t4:1rem; --t5:1.1875rem; --t6:1.5rem;
  /* Couleurs. Chaque couple encre / fond est calcule par tests/lint_couleurs.py sur le
     fond REEL de l'element, et le lint echoue sous le seuil. --grid et --grid-major sont
     des hex PLEINS et non des alphas : la couleur composite sous une graduation est donc
     connue exactement, et le contraste du texte qui la traverse se calcule. */
  --bg:#faf9f6; --fg:#16171a; --muted:#585a55; --faint:#616259;
  --line:#a49f91; --line-strong:#96907f; --card:#ffffff;
  --grid:#eeebe1; --grid-major:#e5e1d3;
  /* Sur papier clair, l'aurore est une chaleur, pas une lueur : elle reste au
     seuil du visible pour ne pas laver le texte. */
  --aurore:rgba(18,86,107,.15); --aurore-2:rgba(122,92,46,.10);
  /* L'echelle des cotes. Elle porte du sens, donc elle vise 3:1 et non le seuil
     des filets : sans la piste, le tiret n'a plus d'etendue. */
  --track:#807a69;
  --accent:#7a5c2e; --accent-soft:#f2ead9;
  /* L'accent editorial et l'encre qui porte de la donnee sont deux choses. */
  --data:#12566b;
  --up:#8a2f22; --down:#0f5d63; --warn:#7a4f0f;
  /* Le pave d'encre. Surface de contraste maximal : bandeau de site, releve,
     en-tete de tableau. En sombre il s'inverse, la regle ne change pas. */
  --ink:#16171a; --ink-fg:#faf9f6; --ink-dim:#a9a79c; --ink-line:#4e5054;
  --mono:ui-monospace,SFMono-Regular,"SF Mono","Cascadia Mono",Menlo,Consolas,
    "DejaVu Sans Mono","Liberation Mono",monospace;
  --sans:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}
:root:not([data-theme="light"]){}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --bg:#0d0e0f; --fg:#e6e8e6; --muted:#9aa09c; --faint:#8b918d;
    --line:#565e60; --line-strong:#5a615f; --card:#15181a;
    --grid:#161a1b; --grid-major:#1e2325;
  --aurore:rgba(87,201,187,.15); --aurore-2:rgba(217,177,105,.09);
  --aurore:rgba(87,201,187,.15); --aurore-2:rgba(217,177,105,.09);
    --track:#6a7370;
    --accent:#d9b169; --accent-soft:#241d10;
    --data:#57c9bb;
    --up:#ef8b72; --down:#4fcbba; --warn:#e0a63a;
    --ink:#e6e8e6; --ink-fg:#0d0e0f; --ink-dim:#4d5150; --ink-line:#9aa09b;
  }
}
:root[data-theme="dark"]{
  --bg:#0d0e0f; --fg:#e6e8e6; --muted:#9aa09c; --faint:#8b918d;
  --line:#565e60; --line-strong:#5a615f; --card:#15181a;
  --grid:#161a1b; --grid-major:#1e2325;
  --track:#6a7370;
  --accent:#d9b169; --accent-soft:#241d10;
  --data:#57c9bb;
  --up:#ef8b72; --down:#4fcbba; --warn:#e0a63a;
  --ink:#e6e8e6; --ink-fg:#0d0e0f; --ink-dim:#4d5150; --ink-line:#9aa09b;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
/* Le site entier en chasse fixe. Un registre est une sortie d'appareil, pas
   un magazine, et la chasse fixe le dit sans avoir a l'ecrire.
   La pile est celle du SYSTEME, jamais « Courier New » nomme : cette police-la
   n'est installee que sur une partie des machines, elle y est fine et pauvre a
   l'ecran, et ailleurs elle retombe sur autre chose. Nommer la famille rendrait
   le resultat different sur chaque poste ; demander « la meilleure chasse fixe
   d'ici » le rend bon partout. Verifie sur ce serveur : « Courier New » y
   retombe deja sur Liberation Mono.
   La mesure passe en ch et non en rem : une ligne se lit a environ 68 signes,
   et en chasse fixe cette regle se calcule exactement. */
body{margin:0;background:var(--bg);color:var(--fg);font:15.5px/1.62 var(--mono);
  -webkit-font-smoothing:antialiased;letter-spacing:-.005em}

/* ============================================================
   COUCHE 1. LE CHAMP GRADUE
   Filets d'un pixel tous les 8 px, renforces tous les 64 px, peints par quatre
   degrades sur un pseudo-element en position fixe. Il NE DEFILE PAS : le contenu
   glisse dessus comme un trace sur l'ecran d'un appareil. Cout : 0 octet d'actif,
   0 requete, 0 image, 0 JS, et aucune repeinture au defilement puisque la couche
   est composee une fois.
   ============================================================ */
/* L'AURORE. Un halo radial qui descend du bord haut, sous la trame graduee.
   Le principe est emprunte aux fonds de 2026 ; la couleur vient de notre propre
   palette, ou --data est deja l'encre qui porte de la donnee. Un indigo jurerait
   avec un accent chaud.
   Elle est PEINTE SOUS LA TRAME, jamais par-dessus : la graduation reste
   l'element de tete, l'aurore ne fait que lui donner de la profondeur. Et elle
   s'arrete haut, la ou le texte courant ne passe pas encore, pour que le
   contraste calcule sur --bg reste vrai la ou il compte. Le composite au point
   le plus dense est verifie par tests/lint_couleurs.py. docs/15 D83. */
body::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-color:var(--bg);
  background-image:
    repeating-linear-gradient(90deg,var(--grid-major) 0 1px,transparent 1px var(--pas-fort)),
    repeating-linear-gradient(180deg,var(--grid-major) 0 1px,transparent 1px var(--pas-fort)),
    repeating-linear-gradient(90deg,var(--grid) 0 1px,transparent 1px var(--pas)),
    repeating-linear-gradient(180deg,var(--grid) 0 1px,transparent 1px var(--pas)),
    /* Deux halos, l'un centre et l'autre decale, pour que la lumiere ne soit pas
       symetrique : une symetrie parfaite se lit comme un gabarit.
       Le centre est pose SOUS la bande d'encre, qui couvre les deux cents
       premiers pixels : plus haut, le halo etait a son plus dense la ou personne
       ne le voyait. Mesure a la pipette, a 210 px du haut : #0f1415 avec un
       centre a -12 %, #1b2b28 avec celui-ci. */
    radial-gradient(110% 60% at 50% 20%,var(--aurore) 0%,transparent 62%),
    radial-gradient(65% 40% at 84% 14%,var(--aurore-2) 0%,transparent 70%)}

/* Le filet lumineux, pose sous la bande d'encre. Il ne recouvre aucun texte,
   donc il ne coute rien au contraste, et c'est lui qui donne l'heure : un halo
   qui teinte le fond est bride par la lisibilite, une ligne ne l'est pas. */
.readout::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;
  background:linear-gradient(90deg,transparent 0%,var(--data) 22%,var(--accent) 52%,
    var(--data) 74%,transparent 100%);opacity:.75}
.readout{position:relative}

.wrap{max-width:64rem;margin:0 auto;padding:0 1.25rem}
.skip{position:absolute;left:-9999px}
.skip:focus{left:1rem;top:1rem;background:var(--card);color:var(--fg);padding:.85rem 1rem;
  z-index:60;min-height:44px;display:flex;align-items:center;
  border:2px solid var(--accent);border-radius:0}
a{color:var(--accent);text-underline-offset:.18em}
a:focus-visible,button:focus-visible,summary:focus-visible,input:focus-visible,
[tabindex]:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
/* Chrome rend focalisable au clavier tout conteneur qui defile SANS enfant
   focalisable : deux tableaux du site sont dans ce cas au pouce (le tarif
   conditionnel d'une fiche, la table des niveaux de source). Sans cette regle
   ils heritent du contour par defaut, invisible sur fond sombre. Le defaut est
   anterieur a cette passe, il est repare ici. */
.scroll:focus{outline:3px solid var(--accent);outline-offset:-3px}
/* Une ancre doit s'arreter SOUS le bandeau colle. Mesure : 105,0 px de 390 a
   1920 px, sur les six pages testees ; 7rem (112 px) laisse la marge. */
:target,tbody tr:target{scroll-margin-top:7rem}

/* ============================================================
   COUCHE 2. L'ENCRE : LE BANDEAU DE SITE
   Ce qui nomme est reserve en blanc dans l'encre. C'est la meme regle que pour
   l'en-tete de tableau plus bas, ce qui en fait un systeme et non un decor.
   ============================================================ */
header.site{background:var(--ink);color:var(--ink-fg);position:sticky;top:0;z-index:20}
.bar{display:flex;align-items:center;gap:1rem;min-height:3rem;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:.6rem;text-decoration:none;color:var(--ink-fg);
  font:700 var(--t3)/1 var(--mono);letter-spacing:.02em;min-height:44px}
.brand-name{text-transform:uppercase;letter-spacing:.1em}
.brand-mark{width:1.5rem;height:1.5rem;color:var(--ink-fg);flex:none}
/* Le pave d'encre inverse le logo : sans cela, ses barres interieures, peintes en
   var(--bg), disparaitraient sur un carre de la meme couleur. Le rayon tombe a zero,
   en CSS pour ne pas toucher au gabarit ; Safari < 15 l'ignore et reste arrondi. */
.brand-mark rect{rx:0}
.brand-mark g rect,.brand-mark circle{fill:var(--ink)}
.brand-mark path{stroke:var(--ink-fg)}
.kbtn{display:inline-flex;align-items:center;gap:.45rem;background:transparent;
  color:var(--ink-fg);border:1px solid var(--ink-line);border-radius:0;padding:.5rem .7rem;
  font:600 var(--t1)/1 var(--mono);text-transform:uppercase;letter-spacing:.1em;
  cursor:pointer;margin-left:auto;min-height:44px}
/* Sans JavaScript ce bouton n'ouvre rien : la feuille actuelle le rendait visible
   quand meme, parce que display:inline-flex bat [hidden] de la feuille du navigateur. */
.kbtn[hidden]{display:none}
.kbtn:hover{background:var(--ink-fg);color:var(--ink)}
.kbtn:hover kbd{color:var(--ink);border-color:var(--ink)}
.kbtn:focus-visible{outline-color:var(--ink-fg)}
kbd{font:var(--t1)/1 var(--mono);background:transparent;border:1px solid var(--ink-line);
  border-radius:0;padding:.1em .35em;color:var(--ink-dim)}

/* La reglette d'onglets prend sa propre ligne sans toucher au gabarit : elle reste
   dans .bar, mais sa base de flex vaut 100 %. Elle ne replie JAMAIS (une seconde
   rangee d'un ou deux onglets, filets compris, se lit comme un defaut) : elle defile
   partout ou elle ne tient pas. */
/* La navigation, a DEUX NIVEAUX depuis le 02/09/2026.
   Elle etait une reglette unique de douze onglets qui defilait horizontalement,
   prevue pour 888 px de contenu. Douze entrees aux libelles longs la faisaient
   deborder a toutes les tailles, et le degrade de bord cachait la moitie des
   pages : une navigation dont on ne voit pas les entrees n'est pas une
   navigation, c'est une liste.
   Le premier niveau porte les quatre choses qu'un visiteur fait en arrivant :
   voir les donnees, obtenir une reponse, verifier un prix, savoir ce qui a
   bouge. Le second porte le reste, groupe et nomme, en plus petit. La hierarchie
   est dans la taille et dans le poids, pas dans un menu qui se deplie : rien ici
   ne depend d'un script. */
/* min-width:0 n'est pas cosmetique, c'est ce qui empeche le site entier de
   deborder. Ce nav est un item flex de .bar. Avant la refonte du 02/09 il portait
   lui-meme overflow-x:auto, ce qui mettait sa taille minimale automatique a zero.
   En descendant ce overflow vers .navrow, j'ai emporte la protection sans la
   remplacer : sa taille minimale est redevenue sa largeur min-content, soit les
   890 px de la rangee la plus large, et ce nombre est devenu le plancher du
   DOCUMENT. Mesure : scrollWidth 890 pour clientWidth 412, tout le site rendu a
   46 % de sa taille, et les onglets de droite peints hors du pave d'encre, en
   blanc sur blanc. Ne pas retirer. */
header nav{display:flex;flex-direction:row;align-items:stretch;flex:1 0 100%;order:2;
  margin:0;gap:0;min-width:0;
  border-top:1px solid var(--ink-line);margin-inline:-1.25rem;padding-inline:1.25rem}
/* UNE SEULE RANGEE, plus une porte. Mesure du 02/09/2026 a 412 px, hauteur de
   l'en-tete et premier pixel de contenu :
     deux rangees, debordement corrige   128 px   contenu a 302   5 liens sur 12 hors ecran
     deux rangees a 13 px                130 px   contenu a 304   6 sur 8 hors ecran
     une rangee plus porte               105 px   contenu a 279   AUCUN hors ecran
   Douze onglets dans 412 px est une erreur de categorie : un site de mille pages
   ne s'indexe pas dans une reglette.

   La porte est un <details> NATIF : elle s'ouvre sans script, verifie scripts
   desactives. Son panneau est en position:absolute et RECOUVRE au lieu de
   pousser, donc le haut du contenu ne bouge pas d'un pixel, porte ouverte ou
   fermee. Le test du 26/08, qui interdit de repousser le contenu sous la ligne
   de flottaison, est donc tenu dans son intention et pas seulement dans sa
   lettre. */
/* position:relative a ete RETIRE de cette regle le 03/09/2026, et ne doit pas
   revenir. overflow-x:auto fait calculer overflow-y en auto (CSS Overflow 3 :
   un axe non visible transforme le visible de l'autre axe en auto), donc cette
   boite ROGNE sur 44 px de haut. Tant qu'elle etait aussi positionnee, elle
   etait le bloc conteneur du panneau absolu de la porte : le panneau, pose a
   top:100%, tombait exactement sur le bord bas du rognage. Mesure du
   03/09/2026 : rectangle 984 x 459 px annonce par getBoundingClientRect,
   intersection reelle avec la zone visible 984 x 0 px, 0 pixel repeint sous
   y=105, 0 des 8 liens atteignable par elementFromPoint, a 412 comme a 1920 px.
   La porte est maintenant SOEUR de cette rangee, donc plus aucun descendant
   absolu ici ; position:relative n'aurait plus d'effet, mais le retirer ferme
   le piege pour de bon. */
header .navrow{display:flex;flex-wrap:nowrap;align-items:stretch;gap:0;min-width:0;
  flex:1 1 auto;overflow-x:auto;overflow-y:visible;scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch;scrollbar-width:none}
header .navrow::-webkit-scrollbar{display:none}

/* L'indice de debordement est un FOND, jamais un masque. Un mask-image touche
   l'alpha du TEXTE : il peut faire tomber n'importe quel couple a 1:1 sans que
   lint_couleurs.py s'en apercoive, puisque le lint compare des jetons et non des
   pixels. Mesure du 02/09 : « What moved » finissait a 379,7 px sous un fondu
   commence a 349,6, alpha 0,01, contraste 1,02:1. C'etait le « MOVE » ampute de
   la capture, sur une rangee qui ne defilait meme pas. */
header nav{position:relative}
/* Depuis le 03/09/2026 cet indice est un ITEM de la rangee <nav>, glisse entre la
   reglette et la porte par order:0 contre order:1 et une marge negative qui le
   remet a cheval sur les 25,6 derniers pixels de la reglette. Il etait absolu au
   bord droit de <nav> ; ce bord est desormais celui de la PORTE, et le degrade
   tombait donc sur le mot MORE. Mesure du 03/09 a 412 px, en ligne : le sommet
   de la porte etait couvert par le degrade, et a 320 px la porte etait meme
   entierement hors ecran (x 339 a 403 pour une fenetre de 320). Si <nav> revenait
   un jour a flex-direction:column, cet item deviendrait une bande de 25,6 px de
   haut : les deux regles vont ensemble. */
header nav::after{content:"";order:0;flex:0 0 1.6rem;margin-left:-1.6rem;
  position:relative;z-index:1;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--ink) 78%)}
@media (min-width:64rem){ header nav::after{display:none} }

header .navrow a{color:var(--ink-fg);font:700 var(--t2)/1 var(--mono);
  text-transform:uppercase;letter-spacing:.09em;text-decoration:none;
  display:flex;align-items:center;min-height:44px;
  padding:0 .85rem;border-left:1px solid var(--ink-line);white-space:nowrap}
header .navrow > a:first-child{border-left:0;padding-left:0}
header .navrow a:hover{background:var(--ink-line);color:var(--ink-fg)}
/* La specificite, et non l'ordre. « header .navrow.second a » pesait (0,2,2) et
   battait « header nav a[aria-current] » qui pese (0,1,3) : l'onglet de la page
   courante recevait son fond clair et GARDAIT sa couleur claire. Clair sur clair,
   1,00:1, litteralement invisible sur quatre pages et 2,29:1 sur huit autres.
   C'etait le pave gris pale de la capture. Le lint validait --ink sur --ink-fg a
   17:1 pendant que la feuille ne l'appliquait nulle part : un lint de jetons ne
   voit pas une regle qui perd en cascade. */
header .navrow a[aria-current="page"]{background:var(--ink-fg);color:var(--ink)}
header .navrow a:focus-visible{outline-color:var(--ink-fg);outline-offset:-3px}

/* La porte. Le triangle natif est retire : il ajoute un signe a une barre ou
   chaque pixel compte, et le mot « More » suffit a dire ce qu'il fait. */
/* La porte est SOEUR de la rangee qui defile, jamais dedans : c'est la cause du
   defaut, pas son symptome. position:static est ici la declaration porteuse :
   elle laisse <nav> (position:relative, overflow visible) etre le bloc conteneur
   du panneau. La rendre relative renfermerait le panneau dans une boite de
   80 px, la rendre statique DANS la rangee ramenerait le rognage. */
.navmore{order:1;flex:0 0 auto;margin-left:0;position:static}
.navmore > summary{list-style:none;cursor:pointer;color:var(--ink-fg);
  font:700 var(--t2)/1 var(--mono);text-transform:uppercase;letter-spacing:.09em;
  display:flex;align-items:center;min-height:44px;padding:0 .85rem;
  border-left:1px solid var(--ink-line);white-space:nowrap}
.navmore > summary::-webkit-details-marker{display:none}
.navmore > summary:hover{background:var(--ink-line)}
.navmore > summary:focus-visible{outline:2px solid var(--ink-fg);outline-offset:-3px}
.navmore[open] > summary{background:var(--ink-fg);color:var(--ink)}
/* La borne de hauteur n'est pas un confort. Le panneau pend d'un bandeau COLLE,
   donc il reste pose a y=105 quoi qu'on fasse defiler : ses 459 px de haut ne
   tiennent pas dans une fenetre courte, et rien ne ramene le bas sous les yeux.
   Mesure du 03/09/2026, tabulation depuis la porte, nombre de liens qui prennent
   le focus HORS de l'ecran, sans la borne :
     412 x 900   0 sur 8        740 x 360 (telephone couche)   4 sur 8
     360 x 480   2 sur 8        320 x 256 (le point de reflow WCAG 1.4.10,
                                soit 1280 x 1024 a 400 % de zoom)   6 sur 8
   Le navigateur fait defiler la page jusqu'a 1531 px pour tenter d'amener le
   lien, sans jamais le bouger : la page saute ET le lien reste invisible. Un
   focus pose sur ce qu'on ne voit pas fait tomber WCAG 2.4.7 et 2.4.11.
   Avec la borne : 0 sur 8 hors de vue aux sept formats testes, et a 412 x 900 le
   panneau mesure scrollHeight 458 pour clientHeight 458, donc aucune barre
   n'apparait et le rendu courant ne bouge pas d'un pixel. 7rem est deja la
   constante d'en-tete du site ; dvh double vh pour la barre mobile qui se retire. */
.navpanel{position:absolute;left:0;right:0;top:100%;z-index:30;
  max-height:calc(100vh - 7rem);max-height:calc(100dvh - 7rem);
  overflow-y:auto;overscroll-behavior:contain;
  background:var(--ink);border-top:1px solid var(--ink-line);
  box-shadow:0 12px 28px rgba(0,0,0,.35);
  padding:.6rem 1.25rem 1rem;display:grid;gap:0}
.navpanel a{display:flex;align-items:center;min-height:44px;
  color:var(--ink-fg);text-decoration:none;border-left:0;padding:0;
  font:600 var(--t3)/1.3 var(--mono);text-transform:none;letter-spacing:.01em;
  white-space:normal}
.navpanel a:hover{color:var(--ink-fg);text-decoration:underline;background:none}
.navpanel a[aria-current="page"]{background:none;color:var(--ink-fg);text-decoration:underline}
/* L'etiquette de groupe est un <p>, pas un <span> pale : elle se lit comme un
   titre et non comme un lien desactive. Trois <span class=navlab> etaient
   annonces role=none par le navigateur, donc le groupement n'existait pour
   personne, et le proprietaire les avait comptes parmi les onglets. */
.navpanel .navlab{margin:.9rem 0 .2rem;color:var(--ink-dim);
  font:700 var(--t2)/1 var(--mono);text-transform:uppercase;letter-spacing:.12em}
.navpanel .navlab:first-child{margin-top:.2rem}

header nav a:focus-visible{outline-color:var(--ink-fg);outline-offset:-3px}

/* Meme derogation pour les deux elements qu'elle avait oublies. Sur le pave
   d'encre, l'anneau accent rend 1,63:1 en sombre : il n'existe pas. L'offset
   negatif le rentre dans le pave au lieu de le poser a cheval. */
.brand:focus-visible,th.sortable:focus-visible{outline-color:var(--ink-fg);
  outline-offset:-3px}

/* ============================================================
   LE RELEVE. Quatre faits dates, sous le bandeau, sur toutes les pages.
   Chacun porte SON unite : « 626 services » a cote de « 15 141 parameters held
   back » sans les noms se lirait « ils publient 4 % de ce qu'ils ont ».
   Il replie, il ne defile pas : un conteneur a defilement sans enfant focalisable
   ajouterait un arret de tabulation muet sur 660 pages.
   ============================================================ */
.readout{background:var(--ink);color:var(--ink-fg);border-top:1px solid var(--ink-line);
  border-bottom:3px solid var(--ink)}
.readout ul{display:flex;flex-wrap:wrap;gap:0;margin:0;padding:.7rem 0 .85rem;list-style:none}
.readout li{flex:1 1 12rem;min-width:0;padding:0 1.1rem;border-left:1px solid var(--ink-line)}
.readout li:first-child{border-left:0;padding-left:0}
.readout .k{display:block;font:600 var(--t1)/1.3 var(--mono);text-transform:uppercase;
  letter-spacing:.14em;color:var(--ink-dim)}
.readout .v{display:block;font:700 var(--t6)/1.05 var(--mono);letter-spacing:-.025em;
  font-variant-numeric:tabular-nums;margin:.3rem 0 .2rem;color:var(--ink-fg)}
.readout .u{display:block;font:var(--t1)/1.4 var(--mono);color:var(--ink-dim)}
.readout li.stamp .v{font:400 var(--t2)/1.5 var(--mono);letter-spacing:0;margin-top:.45rem}

/* ============================================================
   TYPOGRAPHIE. La chasse fixe porte tout ce qui est un FAIT : titres, chiffres,
   dates, empreintes, en-tetes, libelles. La prose courante reste en sans : elle
   se lit sur 111 signes par ligne au lieu de 104, et c'est le seul choix de cette
   direction dont la duree de vie serait courte.
   ============================================================ */
main.wrap{padding-bottom:2rem}
h1{font:700 clamp(1.75rem,4.4vw,2.5rem)/1.08 var(--mono);letter-spacing:-.035em;
  margin:1.5rem 0 .8rem;padding-top:.9rem;border-top:3px solid var(--fg);position:relative;
  /* Le titre non plus ne se bride pas a une mesure. text-wrap:balance suffit a
     equilibrer ses lignes quand il en faut plusieurs, sans lui interdire la
     largeur quand une seule ligne tient. */
  max-width:none;overflow-wrap:anywhere;text-wrap:balance}
/* La regle de titre porte sa propre graduation : le titre est pose sur une echelle,
   comme la legende d'un cadran. */
h1::before{content:"";position:absolute;left:0;top:3px;height:6px;width:min(100%,18ch);
  background:repeating-linear-gradient(90deg,var(--line-strong) 0 1px,transparent 1px 8px)}
h2{font:700 var(--t3)/1.35 var(--mono);text-transform:uppercase;letter-spacing:.08em;
  margin:2.3rem 0 .85rem;padding-bottom:.45rem;border-bottom:2px solid var(--line-strong);
  position:relative;overflow-wrap:anywhere}
h2::after{content:"";position:absolute;left:0;bottom:-2px;width:4ch;height:2px;
  background:var(--accent)}
h3{font:700 var(--t2)/1.4 var(--mono);text-transform:uppercase;letter-spacing:.1em;
  color:var(--muted);margin:1.9rem 0 .5rem}
/* Le texte prend la largeur de sa colonne. Il ne se bride plus a une mesure
   de lecture : la colonne est deja bornee par .wrap, et un paragraphe qui
   s'arrete au tiers de la page pendant que le reste est vide se lit comme un
   defaut, pas comme un choix. Regle de Paul, valable sur tous ses projets et
   rappelee deux fois : ce qui peut prendre la pleine largeur la prend. */
p{margin:0 0 1rem;max-width:none}
/* Le chapeau ouvre la page : il a droit a plus de souffle que le corps, sans
   franchir la limite de lecture. Au-dela d'environ 75 signes en chasse fixe,
   l'oeil rate la ligne suivante en revenant a la marge. Le corps reste a 68. */
.lede{font-size:var(--t4);line-height:1.65;color:var(--muted);max-width:none}
.crumb{font:600 var(--t1)/1.4 var(--mono);color:var(--faint);margin:1.25rem 0 0;
  text-transform:uppercase;letter-spacing:.12em}
.crumb a{color:var(--faint);display:inline-block;padding:.6rem 0}

/* ============================================================
   BLOCS DE DONNEE. Ils sont OPAQUES : ils passent devant le champ, qui s'interrompt
   derriere eux. Quatre equerres de cadrage disent « encadre = mesure », et c'est le
   meme signe partout. Huit degrades, quatre coins : les compter est le minimum sur
   un site dont l'argument est l'exactitude.
   ============================================================ */
.answer,figure.chart{position:relative;background-color:var(--card);
  border:1px solid var(--line-strong);border-radius:0;
  background-image:
    linear-gradient(var(--accent),var(--accent)),linear-gradient(var(--accent),var(--accent)),
    linear-gradient(var(--accent),var(--accent)),linear-gradient(var(--accent),var(--accent)),
    linear-gradient(var(--accent),var(--accent)),linear-gradient(var(--accent),var(--accent)),
    linear-gradient(var(--accent),var(--accent)),linear-gradient(var(--accent),var(--accent));
  background-size:12px 2px,2px 12px,12px 2px,2px 12px,12px 2px,2px 12px,12px 2px,2px 12px;
  background-position:0 0,0 0,100% 0,100% 0,0 100%,0 100%,100% 100%,100% 100%;
  background-repeat:no-repeat}
.answer{padding:1.35rem 1.4rem;margin:1.4rem 0 1.75rem}
.answer p{font:var(--t4)/1.62 var(--mono);margin:0;max-width:none;color:var(--fg)}
.scope{margin:.9rem 0 0;padding-top:.9rem;border-top:1px solid var(--line);
  font-size:var(--t3);color:var(--muted);max-width:none}
.figures{display:flex;flex-wrap:wrap;gap:0;margin-top:1.25rem;padding-top:1.15rem;
  border-top:1px solid var(--line-strong)}
.figure{flex:1 1 12rem;min-width:0;padding:0 1.25rem;border-left:1px solid var(--line)}
.figure:first-child{padding-left:0;border-left:0}
.figure .k{display:block;font:600 var(--t1)/1.3 var(--mono);text-transform:uppercase;
  letter-spacing:.13em;color:var(--faint)}
/* Le chiffre est la valeur affichee d'un appareil : chasse fixe, chiffres de largeur
   egale, aucun crenage qui ferait danser une colonne de nombres. */
.figure .v{display:block;font:700 2rem/1.05 var(--mono);letter-spacing:-.04em;
  font-variant-numeric:tabular-nums;margin:.35rem 0 .3rem;overflow-wrap:anywhere}
.figure .u{display:block;font-size:var(--t1);line-height:1.4;color:var(--muted);
  padding-top:.4rem;
  background:repeating-linear-gradient(90deg,var(--line-strong) 0 1px,transparent 1px 8px)
    left top / 100% 4px no-repeat}

/* Les prix deja publies pour une date a venir : une liste reglee, pas des puces. */
ul.annonces{list-style:none;margin:.9rem 0 1rem;padding:0;border-top:1px solid var(--line)}
ul.annonces li{display:flex;flex-wrap:wrap;gap:.15rem .9rem;align-items:baseline;
  padding:.55rem 0;border-bottom:1px solid var(--line);font:var(--t2)/1.5 var(--mono)}
ul.annonces .k{flex:1 1 14rem;font-weight:700}
ul.annonces .from{color:var(--muted);text-decoration:line-through}
ul.annonces .to{color:var(--data);font-weight:700}
ul.annonces .when{color:var(--faint)}

/* ============================================================
   COUCHE 2 (suite). L'ENCRE : L'EN-TETE DE TABLEAU
   La meme regle qu'en haut de page. L'en-tete dit le nom, l'unite, la couverture
   comptee, la barre de couverture et les bornes reelles de l'echelle. Le corps ne
   dit que des valeurs.
   ============================================================ */
.scroll{overflow-x:auto;margin:1.1rem 0 1.5rem;background:var(--card);
  border:1px solid var(--line-strong);border-radius:0;position:relative;
  -webkit-overflow-scrolling:touch;scrollbar-width:thin;
  scrollbar-color:var(--line-strong) transparent}
.scroll::-webkit-scrollbar{height:.5rem}
.scroll::-webkit-scrollbar-thumb{background:var(--line-strong)}
table{border-collapse:collapse;width:100%;font-size:var(--t2);
  font-variant-numeric:tabular-nums}
th,td{text-align:left;padding:.55rem .75rem;border-bottom:1px solid var(--line);
  border-right:1px solid var(--line);white-space:nowrap;vertical-align:top}
tr>th:last-child,tr>td:last-child{border-right:0}
/* Les colonnes de bord touchaient le filet du conteneur, ce qui donne au
   tableau un air de capture d'ecran mal recadree. Elles prennent le meme
   retrait que les gouttieres interieures, ni plus ni moins. */
tr>th:first-child,tr>td:first-child{padding-left:1.1rem}
tr>th:last-child,tr>td:last-child{padding-right:1.1rem}
thead th,tfoot th{background:var(--ink);color:var(--ink-fg);vertical-align:bottom;
  font:700 var(--t1)/1.3 var(--mono);text-transform:uppercase;letter-spacing:.11em;
  border-bottom:0;border-right:1px solid var(--ink-line);padding-top:.7rem;padding-bottom:.65rem}
tfoot th{vertical-align:top;border-top:3px solid var(--ink);border-bottom:0}
thead th .u,tfoot th .u{display:block;font:400 var(--t1)/1.35 var(--mono);
  text-transform:none;letter-spacing:0;color:var(--ink-dim)}
th.num{text-align:right}
td.num{text-align:right;font-family:var(--mono)}
tbody tr:last-child td{border-bottom:0}
td.wrap-cell{white-space:normal;min-width:7rem;overflow-wrap:anywhere}
/* Une valeur qui est une LISTE se lit comme une liste. Rendue en une chaine
   sans retour a la ligne, elle etirait sa colonne a plus de deux mille pixels
   et chassait hors de l'ecran toutes les autres valeurs de la meme colonne,
   alignees a droite. Une cellule ne doit jamais pouvoir faire cela a ses
   voisines : d'ou la largeur maximale, en plus du retour a la ligne. */
td.liste-cell{white-space:normal;max-width:34rem;min-width:12rem;padding-top:.45rem;
  padding-bottom:.45rem}
ul.jetons{display:flex;flex-wrap:wrap;gap:.25rem .3rem;list-style:none;margin:0;padding:0}
ul.jetons li{font:var(--t1)/1.5 var(--mono);color:var(--muted);background:var(--bg);
  border:1px solid var(--line);padding:.12rem .38rem;white-space:nowrap}
@media (max-width:52rem){ td.liste-cell{max-width:22rem;min-width:11rem} }
@media print{ ul.jetons li{border-color:#000;color:#000} }
td:first-child.wrap-cell,th:first-child{min-width:13rem}

/* La barre de couverture. Deux rectangles accoles, traces en SVG DANS le HTML servi :
   la CSP du site est style-src 'self', un attribut style= serait bloque en silence.
   Elle ne dit rien de neuf, elle montre le compte ecrit juste au-dessus. */
th.num .cov{display:block;width:100%;height:3px;margin-top:.45rem}
th.num .cov .t{fill:var(--ink-line)}
th.num .cov .f{fill:var(--ink-fg)}
/* Les bornes de l'echelle, sans lesquelles la cote serait une decoration. */
th.num .ax{display:flex;justify-content:space-between;align-items:center;gap:.35rem;
  margin-top:.5rem;font:400 var(--t1)/1 var(--mono);color:var(--ink-dim);
  text-transform:none;letter-spacing:0}
th.num .ax::before{content:"";flex:1;height:2px;background:var(--ink-line);order:1}
th.num .ax i{font-style:normal;white-space:nowrap}
th.num .ax i:first-of-type{order:0}
th.num .ax i:last-of-type{order:2}

/* La premiere colonne reste sous l'oeil pendant qu'on fait defiler les prix. */
table td:first-child,table th:first-child{position:sticky;left:0;z-index:1;
  background:var(--card);box-shadow:1px 0 0 var(--line)}
thead th:first-child,tfoot th:first-child{background:var(--ink);z-index:2;
  box-shadow:1px 0 0 var(--ink-line)}
/* Le survol est un CURSEUR de lecture : un trait vif a gauche de la ligne, comme le
   repere d'un enregistreur. */
/* La cible n'est pas le lien de 17 px de haut, c'est la cellule entiere : 208 x 40 px
   au minimum. Aucune hauteur de ligne n'est payee, la cellule etait deja la. La cellule
   est deja position:sticky, donc positionnee : l'incrustation se cale dessus. */
/* La cible tapable est la CELLULE, pas le mot. La regle etait calee sur
   td:first-child : sur les six pages de classement, ou la premiere colonne porte
   le rang et le lien la deuxieme, elle ne mordait jamais et la cible mesurait
   14 px. Elle vise desormais le premier lien de toute cellule de texte. */
td.wrap-cell{position:relative}
td.wrap-cell>a:first-child::after{content:"";position:absolute;inset:0}
td:first-child.wrap-cell .lvl,td:first-child.wrap-cell .sub{position:relative;z-index:1}
tbody tr:hover td{background:var(--accent-soft)}
tbody tr:hover td:first-child{background:var(--accent-soft);
  box-shadow:inset 3px 0 0 var(--data),1px 0 0 var(--line)}
tbody tr:target td{background:var(--accent-soft);box-shadow:inset 0 -2px 0 var(--accent)}
tbody tr:target td:first-child{background:var(--accent-soft);
  box-shadow:inset 3px 0 0 var(--accent),1px 0 0 var(--line)}

/* ============================================================
   COUCHE 3. LA COTE. La signature du site.
   Sous chaque nombre d'une colonne chiffree court une piste de 2 px, et un tiret de
   3 x 8 px y marque la position de CETTE valeur parmi TOUTES les valeurs publiees du
   meme parametre. Les deux colonnes de prix partagent une seule echelle : sans cela
   5,00 $ d'entree se poserait plus a droite que 25,00 $ de sortie.
   La position vient d'une classe posee a la generation, jamais d'un attribut style :
   la CSP servie est style-src 'self', un style en ligne serait bloque et le tiret
   retomberait a une position fausse, ce qui serait un fait produit.
   Le tiret se loge dans le remplissage bas que la cellule avait deja : la ligne ne
   grandit pas. Il ne remplace jamais le nombre, il le situe.
   ============================================================ */
td.num.f{position:relative}
td.num.f::before{content:"";position:absolute;left:.75rem;right:.75rem;bottom:4px;
  height:2px;background:var(--track)}
td.num.f::after{content:"";position:absolute;bottom:1px;height:8px;width:3px;
  background:var(--data);left:calc(.75rem + (100% - 1.5rem - 3px) * var(--p) / 100)}
/* Une valeur nulle n'a pas de place sur une echelle logarithmique. Elle prend un carre
   plein, detache de la piste : c'est un fait different, pas un minimum. */
td.num.f0::before{left:1.35rem}
td.num.f0::after{left:.3rem;width:6px;height:6px;bottom:2px;background:var(--fg)}
.p0{--p:0}.p1{--p:1}.p2{--p:2}.p3{--p:3}.p4{--p:4}.p5{--p:5}.p6{--p:6}.p7{--p:7}
.p8{--p:8}.p9{--p:9}.p10{--p:10}.p11{--p:11}.p12{--p:12}.p13{--p:13}.p14{--p:14}
.p15{--p:15}.p16{--p:16}.p17{--p:17}.p18{--p:18}.p19{--p:19}.p20{--p:20}.p21{--p:21}
.p22{--p:22}.p23{--p:23}.p24{--p:24}.p25{--p:25}.p26{--p:26}.p27{--p:27}.p28{--p:28}
.p29{--p:29}.p30{--p:30}.p31{--p:31}.p32{--p:32}.p33{--p:33}.p34{--p:34}.p35{--p:35}
.p36{--p:36}.p37{--p:37}.p38{--p:38}.p39{--p:39}.p40{--p:40}.p41{--p:41}.p42{--p:42}
.p43{--p:43}.p44{--p:44}.p45{--p:45}.p46{--p:46}.p47{--p:47}.p48{--p:48}.p49{--p:49}
.p50{--p:50}.p51{--p:51}.p52{--p:52}.p53{--p:53}.p54{--p:54}.p55{--p:55}.p56{--p:56}
.p57{--p:57}.p58{--p:58}.p59{--p:59}.p60{--p:60}.p61{--p:61}.p62{--p:62}.p63{--p:63}
.p64{--p:64}.p65{--p:65}.p66{--p:66}.p67{--p:67}.p68{--p:68}.p69{--p:69}.p70{--p:70}
.p71{--p:71}.p72{--p:72}.p73{--p:73}.p74{--p:74}.p75{--p:75}.p76{--p:76}.p77{--p:77}
.p78{--p:78}.p79{--p:79}.p80{--p:80}.p81{--p:81}.p82{--p:82}.p83{--p:83}.p84{--p:84}
.p85{--p:85}.p86{--p:86}.p87{--p:87}.p88{--p:88}.p89{--p:89}.p90{--p:90}.p91{--p:91}
.p92{--p:92}.p93{--p:93}.p94{--p:94}.p95{--p:95}.p96{--p:96}.p97{--p:97}.p98{--p:98}
.p99{--p:99}.p100{--p:100}

/* Deux mesures, une seule raison de les separer : la prose se lit sur 44 rem, une
   grille de sept colonnes a besoin de 1 139 px. Le tableau sort donc de la colonne
   de lecture sans jamais depasser la fenetre. */
@media (min-width:64rem){
  /* Tout ce qui appartient au TABLEAU partage sa largeur : les puces de filtre
     qui le commandent, la grille de vendeurs qui compte ses lignes, la barre de
     filtre et le tableau lui-meme. La page n'a plus que deux mesures, celle du
     texte et celle de la donnee, au lieu de quatre bords droits qui ne
     s'accordaient sur rien. */
  .scroll[data-table],.tablebar,.caps,.grid.hubs{
    /* 100% vaut ici la largeur utile de .wrap ; (100vw - 100%) / 2 est donc la
       gouttiere gauche. On repart du bord du texte et on va chercher la fenetre
       a droite, en gardant 3rem de marge. */
    width:min(calc(100vw - (100vw - 100%) / 2 - 3rem),100rem);
    margin-left:0}
}

/* Marqueurs */
.lvl{display:inline-block;font:700 var(--t1)/1 var(--mono);padding:.28rem .42rem;
  border-radius:0;background:var(--accent-soft);color:var(--accent);letter-spacing:.06em;
  border:1px solid var(--accent);text-transform:uppercase}
.lvl.cond{background:transparent;color:var(--faint);border-color:var(--line-strong);
  font-weight:400;cursor:help}
.date{font:var(--t1)/1.35 var(--mono);color:var(--muted);letter-spacing:.04em;
  white-space:nowrap}
.checked{font:var(--t1)/1.35 var(--mono);color:var(--faint)}
abbr.stale{color:var(--warn);font-weight:700;cursor:help;text-decoration:none;
  border-bottom:2px dotted var(--warn)}
.up{color:var(--up)} .down{color:var(--down)}
/* La preuve quitte le gris. Elle passe de --faint a --data : sur ce site, l'empreinte
   n'est pas une note de bas de page, c'est le produit. */
code.hash{font:var(--t1)/1 var(--mono);color:var(--data);background:transparent;
  border:0;border-bottom:1px dotted var(--track);padding:0 0 .2em;letter-spacing:.06em;
  cursor:help}
.sub{display:none;font:var(--t1)/1.4 var(--mono);color:var(--muted);margin-top:.2rem}
td.wrap-cell .sub{display:none}

/* Encarts */
.note{background:transparent;border-left:4px solid var(--accent);padding:.9rem 0 .9rem 1.1rem;
  margin:1.25rem 0;font-size:var(--t3);border-radius:0}
.note p{margin:0 0 .6rem;max-width:none}
.note p:last-child{margin-bottom:0}
.note-strong{border-left-color:var(--up);background:transparent;border-top:0;border-right:0;
  border-bottom:0}
.note-strong p:last-child{color:var(--muted);font-size:var(--t3)}
details.fold{background:transparent;border-left:4px solid var(--accent);border-radius:0;
  margin:1.1rem 0;padding:.7rem 0 .7rem 1.1rem}
details.fold summary{cursor:pointer;font:700 var(--t1)/1 var(--mono);text-transform:uppercase;
  letter-spacing:.12em;color:var(--accent);list-style:none;min-height:44px;display:flex;
  align-items:center}
details.fold summary::-webkit-details-marker{display:none}
details.fold summary::before{content:"\25B8";margin-right:.5rem;transition:transform .12s}
details.fold[open] summary::before{transform:rotate(90deg)}
details.fold p{margin:.6rem 0 0;font-size:var(--t3)}

/* ============================================================
   LE BLOC DE COMPARAISON
   02/09/2026. La page /en/compare/ faisait 53 392 px a 412 px, soit 58 ecrans de
   telephone, 175 tableaux et UNE seule ancre sur 202 ko : aucun lien profond,
   aucun retour arriere, aucun sommaire. Elle est le differenciateur du site,
   donc elle ne perd pas un octet : elle se replie.

   Ce qui se replie, ce sont les VENDEURS. Le nom du modele, l'ecart, la fenetre
   d'observation et les niveaux de source restent toujours peints. Aucune figure
   sans sa date : c'est la regle publiee par /llms.txt, pas une preference de
   dessin. Le <h2> vit DANS le <summary>, donc la page garde ses 176 titres pour
   la navigation par titres d'un lecteur d'ecran, et le nom du modele est
   toujours rendu, donc Ctrl+F aboutit sans dependre de beforematch.

   Piege mesure et evite : marquer les 175 tableaux data-table SANS le pli porte
   la page de 53 392 a 146 657 px, plus 175 %, parce qu'une carte coute 196 px la
   ligne contre 44 en tableau. La doctrine des cartes ne change pas ; c'est le
   nombre de tableaux VISIBLES qui change. */
details.modele{border-top:1px solid var(--line-strong)}
details.modele:last-of-type{border-bottom:1px solid var(--line-strong)}
details.modele>summary{display:flex;flex-wrap:wrap;align-items:baseline;gap:.15rem .8rem;
  min-height:44px;padding:.5rem 0;cursor:pointer;list-style:none}
details.modele>summary::-webkit-details-marker{display:none}
/* Le chevron est decoratif : sans le texte alternatif vide, les 176 noms
   accessibles commencaient par « ▸ » et le nom MUTAIT a l'ouverture, alors que
   l'etat est deja porte par aria-expanded. */
details.modele>summary::before{content:"\25B8" / "";color:var(--accent);
  align-self:center;flex:none;transition:transform .12s}
details.modele[open]>summary::before{transform:rotate(90deg)}
details.modele>summary h2{flex:1 1 13rem;margin:0;padding:0;border:0;
  font:700 var(--t3)/1.4 var(--mono);text-transform:none;letter-spacing:-.01em;
  overflow-wrap:anywhere}
/* Le repere de 4ch de h2::after survit au border:0 et se poserait sous les
   quatre premiers caracteres de 176 titres, ou il se lit comme un souligne
   casse. */
details.modele>summary h2::after{display:none}
/* Le facteur reste NU, sans pastille d'encre : sur ce site, ce qui NOMME une
   donnee est reserve en blanc dans l'encre, ce qui EST une donnee reste nu.
   Mettre ce chip en encre pleine serait la premiere fois que l'encre porte une
   valeur, et cela romprait le systeme. */
details.modele .ec{font:700 var(--t2)/1.4 var(--mono);color:var(--fg);
  font-variant-numeric:tabular-nums}
details.modele .ec.plat,details.modele .ec.nul{font-weight:400;color:var(--muted)}
details.modele .ec.inp{font-weight:400;color:var(--warn)}
details.modele .fk{font:400 var(--t2)/1.4 var(--mono);color:var(--fg);
  font-variant-numeric:tabular-nums}
details.modele .win,details.modele .lv{font:400 var(--t2)/1.4 var(--mono);color:var(--fg)}
details.modele .nv{font:400 var(--t2)/1.4 var(--mono);color:var(--muted)}
details.modele>p{margin:.6rem 0 .8rem}
details.modele:target>summary{outline:3px solid var(--accent);outline-offset:2px}
/* Mesure : dans un tiers de carte, meta-llama/llama-3.2-1b-instruct se coupe en
   quatre lignes et etire ses deux voisines a 139 px. */
@media screen and (max-width:52rem){
  details.modele .blocs tbody td.wrap-cell[data-label]{flex:1 1 100%}
}

/* Courbe d'evolution. Aucun JS : le trace est du SVG inline. */
figure.chart{margin:1.25rem 0;padding:1.15rem}
.spark{width:100%;height:auto;display:block;overflow:visible}
.spark .line{fill:none;stroke:var(--data);stroke-width:2;stroke-linejoin:round}
.spark .area{fill:var(--data);opacity:.12;stroke:none}
.spark .dots circle{fill:var(--data)}
figure.chart figcaption{font-size:var(--t2);color:var(--muted);margin-top:.85rem;
  max-width:none;line-height:1.5}

/* Le simulateur de cout. Le formulaire ouvre la page : il est ce que le lecteur
   vient regler, et il arrive rempli d'un profil deja calcule. */
form.simul{border:1px solid var(--line-strong);border-left:3px solid var(--data);
  background:var(--card);padding:1.1rem 1.2rem;margin:1.5rem 0}
form.simul .simul-quoi{margin:0 0 1rem;font-size:var(--t3);color:var(--muted)}
.simul-champs{display:grid;gap:.9rem 1.2rem;
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
form.simul label{display:block;font:600 var(--t1)/1.4 var(--mono);text-transform:uppercase;
  letter-spacing:.06em;color:var(--faint);margin:0 0 .3rem}
form.simul input{width:100%;font:16px/1.4 var(--mono);padding:.55rem .7rem;
  border:2px solid var(--line-strong);border-radius:0;background:var(--bg);
  color:var(--fg);min-height:44px}
form.simul input:focus,form.simul button:focus-visible{outline:3px solid var(--accent);
  outline-offset:1px}
form.simul button{margin-top:1rem;min-height:44px;padding:.5rem 1.2rem;cursor:pointer;
  font:600 var(--t3) var(--mono);background:var(--ink);color:var(--ink-fg);
  border:2px solid var(--ink);border-radius:0}
form.simul .fine{margin:.9rem 0 0;font-size:var(--t1);color:var(--muted)}
/* La formule est affichee pour etre refaite, pas pour decorer. */
pre.formule{background:var(--card);border:1px solid var(--line);padding:.9rem 1.1rem;
  overflow-x:auto;font:var(--t2)/1.6 var(--mono);color:var(--fg);margin:1rem 0}
td.rang{color:var(--faint)}

/* Le formulaire d'inscription. Il vit en bas de page, apres la reponse, jamais
   au-dessus d'elle et jamais en flottant : docs/17 §1. */
form.souscrire{border:1px solid var(--line-strong);border-left:3px solid var(--data);
  background:var(--card);padding:1.1rem 1.2rem;margin:1.25rem 0;max-width:none}
form.souscrire label{display:block;font:600 var(--t1)/1.4 var(--mono);text-transform:uppercase;
  letter-spacing:.06em;color:var(--faint);margin:.7rem 0 .3rem}
form.souscrire label:first-of-type{margin-top:0}
form.souscrire input[type=email],form.souscrire select{width:100%;max-width:26rem;
  font:16px/1.4 var(--mono);padding:.55rem .7rem;border:2px solid var(--line-strong);
  border-radius:0;background:var(--bg);color:var(--fg);min-height:44px}
form.souscrire input:focus,form.souscrire select:focus,form.souscrire button:focus-visible{
  outline:3px solid var(--accent);outline-offset:1px}
form.souscrire button{margin-top:1rem;min-height:44px;padding:.5rem 1.2rem;cursor:pointer;
  font:600 var(--t3) var(--mono);background:var(--ink);color:var(--ink-fg);
  border:2px solid var(--ink);border-radius:0}
form.souscrire button:hover{background:var(--bg);color:var(--fg)}
form.souscrire .fine{margin:.9rem 0 0;font-size:var(--t1);color:var(--muted);max-width:none}
/* Le pot de miel. Il doit rester dans le flux pour qu'un robot le remplisse,
   donc jamais display:none, mais hors de portee de l'oeil et du clavier. */
form.souscrire .pot{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

pre.sample{background:var(--card);border:1px solid var(--line);border-radius:0;
  padding:1rem 1.1rem;overflow-x:auto;font:var(--t2)/1.55 var(--mono);color:var(--muted);
  white-space:pre-wrap;word-break:break-word;max-width:100%}

/* Listes de services : des filets, pas des cartes. */
.grid{display:grid;gap:0;grid-template-columns:repeat(auto-fill,minmax(17rem,1fr));
  margin:1.25rem 0;padding:0;list-style:none;border-top:2px solid var(--line-strong);
  border-left:1px solid var(--line)}
.grid li{border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  background:var(--card);border-radius:0}
.grid a{display:block;padding:.85rem 1rem;text-decoration:none;color:var(--fg);min-height:44px}
.grid a:hover{background:var(--accent-soft)}
.grid .n{display:block;font:700 var(--t3)/1.35 var(--sans);margin-bottom:.25rem}
.grid .m{display:block;font:var(--t1)/1.4 var(--mono);color:var(--faint);
  text-transform:uppercase;letter-spacing:.06em}
.grid.hubs{grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));margin:1.1rem 0 1.4rem}
.grid.hubs .n{font-size:var(--t4)}

/* Frise des mises a disposition recentes : un registre d'entrees reglees, pas un
   bandeau de cartes. La date passe devant le nom, c'est elle le fait. */
ol.frise{list-style:none;display:flex;gap:0;overflow-x:auto;margin:1.1rem 0 1.5rem;padding:0;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;
  border-top:2px solid var(--line-strong);border-bottom:1px solid var(--line)}
ol.frise li{flex:none;scroll-snap-align:start;min-width:12rem;background:transparent;
  border:0;border-left:1px solid var(--line);border-radius:0}
ol.frise li:first-child{border-left:0}
ol.frise li::before{display:none}
ol.frise a{display:flex;flex-direction:column;gap:.3rem;padding:.8rem .9rem;
  text-decoration:none;color:var(--fg);min-height:44px}
ol.frise a:hover{background:var(--accent-soft)}
ol.frise .d{order:-1;font:var(--t1)/1.3 var(--mono);color:var(--data);
  letter-spacing:.06em;text-transform:uppercase}
ol.frise .n{font:700 var(--t3)/1.35 var(--sans)}

/* Filtres par capacite. Les chiffres sont ceux de la source, pas des estimations. */
.caps{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center;margin:1.1rem 0}
.caplabel{width:100%;margin-bottom:.15rem;font:600 var(--t1)/1.4 var(--mono);
  text-transform:uppercase;letter-spacing:.13em;color:var(--faint)}
.cap{display:inline-flex;align-items:center;gap:.4rem;background:var(--card);
  color:var(--muted);border:1px solid var(--line-strong);border-radius:0;
  padding:.4rem .8rem;font:600 var(--t1)/1 var(--mono);text-transform:uppercase;
  letter-spacing:.08em;cursor:pointer;min-height:44px}
.cap:hover{color:var(--fg);border-color:var(--accent)}
.cap[aria-pressed="true"]{background:var(--accent-soft);color:var(--accent);
  border-color:var(--accent)}
.cap .n{font:var(--t1) var(--mono);color:var(--faint)}
.cap[aria-pressed="true"] .n{color:var(--accent)}

/* Recherche interne et barre de filtre */
.searchbox{margin:1.5rem 0 .5rem}
.searchbox label,.tablebar label{display:block;font:600 var(--t1)/1.4 var(--mono);
  text-transform:uppercase;letter-spacing:.13em;color:var(--faint);margin-bottom:.4rem}
.searchbox input{width:100%;max-width:32rem;font:var(--t4)/1.4 var(--mono);padding:.75rem .9rem;
  border:2px solid var(--line-strong);border-radius:0;background:var(--card);color:var(--fg);
  min-height:44px}
.searchbox input:focus{outline:3px solid var(--accent);outline-offset:1px;
  border-color:var(--accent)}
.searchcount,.tablecount{font:var(--t2) var(--mono);color:var(--muted);margin:.35rem 0 0;
  min-height:1.2em}
.tablebar{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;margin:0 0 .75rem;
  padding:.6rem .9rem;border:1px solid var(--line);background:var(--card)}
.tablebar label{margin-bottom:0}
.tablebar input{flex:1 1 16rem;max-width:26rem;font:var(--t3) var(--mono);padding:.55rem .7rem;
  border:2px solid var(--line-strong);border-radius:0;background:var(--card);color:var(--fg);
  min-height:44px}
.tablebar input:focus{outline:3px solid var(--accent);outline-offset:1px}

/* Tri de colonne */
th.sortable{cursor:pointer;user-select:none;position:relative;padding-right:1.3rem}
th.sortable:hover{color:var(--ink-fg)}
/* L'indicateur de tri s'aligne sur le LIBELLE, pas sur le centre de la cellule.
   Les en-tetes chiffres portent trois lignes (nom, unite, couverture) et les
   en-tetes de texte une seule : ancre en haut, la fleche de « Service » flottait
   trois lignes au-dessus de son mot. Le libelle etant cale en bas
   (vertical-align:bottom), l'ancre l'est aussi. */
th.sortable::after{content:"\2195";position:absolute;right:.4rem;top:auto;bottom:.6rem;
  font-size:.75rem;line-height:1;opacity:.55;color:var(--ink-dim);font-weight:400}
tfoot th.sortable::after{bottom:auto;top:.6rem}
th.sortable[aria-sort="ascending"]::after,
th.sortable[aria-sort="descending"]::after{opacity:1;color:var(--ink-fg);font-size:.65rem}
th.sortable[aria-sort="ascending"]::after{content:"\25B2"}
th.sortable[aria-sort="descending"]::after{content:"\25BC"}

/* Palette de commande */
html.palette-ouverte{overflow:hidden}
.palette{position:fixed;inset:0;z-index:50;display:flex;align-items:flex-start;
  justify-content:center;padding:8vh 1rem 1rem}
.palette[hidden]{display:none}
.palette-fond{position:absolute;inset:0;background:rgba(0,0,0,.55)}
.palette-boite{position:relative;width:min(40rem,100%);background:var(--card);
  border:2px solid var(--line-strong);border-radius:var(--r);overflow:hidden}
.palette-champ{width:100%;border:0;border-bottom:2px solid var(--line);background:transparent;
  color:var(--fg);font:var(--t4) var(--mono);padding:1rem 1.1rem}
.palette-champ:focus{outline:none}
.palette-liste{list-style:none;margin:0;padding:.35rem;max-height:52vh;overflow-y:auto}
.palette-liste li{border-radius:0}
.palette-liste li.on{background:var(--accent-soft)}
.palette-liste a{display:flex;justify-content:space-between;gap:1rem;align-items:baseline;
  padding:.6rem .75rem;text-decoration:none;color:var(--fg);min-height:44px}
.palette-liste .n{font-size:var(--t3)}
.palette-liste .m{font:var(--t1) var(--mono);color:var(--muted);flex:none}
.palette-pied{margin:0;padding:.55rem 1.1rem;border-top:1px solid var(--line);
  font:var(--t1) var(--mono);color:var(--faint);display:flex;gap:.4rem;align-items:center;
  flex-wrap:wrap}
.palette-pied kbd{border-color:var(--line-strong);color:var(--muted)}

/* Pied */
footer.site{border-top:3px solid var(--fg);margin-top:4rem;padding:2rem 0 3rem;
  font-size:var(--t3);color:var(--muted)}
.foot-lead{max-width:none}
footer nav{display:flex;gap:0 1.4rem;flex-wrap:wrap;margin:1rem 0}
footer nav a{font:600 var(--t1)/1 var(--mono);text-transform:uppercase;letter-spacing:.11em;
  min-height:44px;display:flex;align-items:center}
.foot-note{font:var(--t1)/1.6 var(--mono);color:var(--faint);max-width:none}

.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ============================================================
   MOBILE. Un site de donnees denses n'a pas le droit d'etre penible au pouce.
   Rien n'est masque : ce qui existe sur grand ecran existe ici, autrement dispose.
   ============================================================ */
@media (max-width:52rem){
  .wrap{padding:0 1rem}
  header nav{margin-inline:-1rem;padding-inline:1rem}
  /* Le panneau se cale sur <nav> : son rembourrage doit suivre celui de .wrap,
     sinon ses liens ne sont plus alignes sur les onglets a 4 px pres. */
  .navpanel{padding-inline:1rem}
  p,.lede,ul,.note p,.foot-lead,.foot-note,figure.chart figcaption,.answer p,.scope{
    max-width:none}
  h1{max-width:none}
  /* Le releve tenait sur trois lignes par chiffre : le nom en capitales de 11 px,
     la valeur, puis la glose. Quatre chiffres coutaient ainsi la moitie du
     premier ecran d'un telephone. Il devient une phrase par ligne.
     La declaration font sur le <li> est indispensable : sans elle, le corps de
     15,5 px du body impose un interligne de 25,1 px a une ligne de 13 px, ce qui
     reprend 24 px de ce qu'on vient de gagner. Elle supprime aussi le dernier
     11 px du bandeau, celui du tampon de fraicheur.
     NE PAS masquer .u : sur le tampon, .u ne porte pas une glose mais l'HEURE.
     Le texte passerait de « SOURCES READ 2 September 2026 16:16 UTC » a la date
     seule, alors que le site relit ses sources plusieurs fois par jour. Le
     tampon de fraicheur est la preuve du site, pas sa decoration. */
  .readout ul{display:block;padding:.35rem 0 .45rem}
  .readout li{display:block;padding:.15rem 0;border-left:0;
    border-top:1px solid var(--ink-line);font:400 var(--t2)/1.5 var(--mono)}
  .readout li:first-child{border-top:0}
  .readout .k,.readout .v,.readout .u,.readout li.stamp .v{display:inline;margin:0;
    letter-spacing:0}
  .readout .k{font:600 var(--t2)/1.5 var(--mono);letter-spacing:.04em}
  .readout .k::after{content:" "}
  .readout .v,.readout li.stamp .v{font:700 var(--t2)/1.5 var(--mono)}
  .readout .u{font:400 var(--t2)/1.5 var(--mono)}
  .readout .u::before{content:" "}
  th,td{padding:.55rem .6rem;font-size:var(--t2)}
  .figures{gap:0}
  .figure{flex:1 1 8.5rem;padding:0 .8rem}
  .figure .v{font-size:var(--t6)}
  .grid{grid-template-columns:1fr}
  .grid.hubs{grid-template-columns:1fr 1fr}
  .grid.hubs a{padding:.65rem .7rem}
  .answer{padding:1.1rem}
  h2{margin-top:2rem}
  .tablebar input{flex:1 1 100%}
  /* Le vendeur passe sous le nom : une colonne de moins, donc un prix visible sans
     avoir a deviner qu'il faut faire defiler. */
  .col-seller{display:none}
  td.wrap-cell .sub{display:block}
  /* Au doigt, ces deux-la ne sont que du texte : ils ne doivent pas trouer la
     cible du lien qui les entoure. Au bureau ils gardent leur infobulle. */
  td.wrap-cell .sub,td.wrap-cell .lvl{pointer-events:none}
  /* Une cible parfaitement couverte reste trop petite si la ligne fait 35 px.
     Le plancher de 44 px est celui du doigt, il ne se negocie pas ; mesure sur
     /en/compare/, quatre lignes sur vingt tombaient dessous par leur seule
     hauteur, l'incrustation etant deja complete. */
  tbody td{height:44px}
}

@media (max-width:34rem){
  .kbtn kbd{display:none}
  .bar .kbtn span.lbl{display:none}
  .palette-pied{display:none}
  .palette{padding:0}
  .palette-boite{width:100%;height:100%;border-radius:0;border:0;display:flex;
    flex-direction:column}
  .palette-liste{max-height:none;flex:1}
  .palette-champ{padding:1.1rem 1rem;font-size:16px} /* 16px evite le zoom iOS */
  .palette-liste a{padding:.8rem .75rem}
  .tablebar input{font-size:16px}
  .searchbox input{font-size:16px}
  th,td{padding:.5rem .5rem;font-size:var(--t1)}
  footer nav{gap:0 1.1rem}
}

/* ============================================================
   LA CARTE DE RELEVE. Sous 52rem, le tableau qui defile cede la place a une
   carte par ligne. Ce n'est pas un repli : c'est la meme regle appliquee plus
   loin. Dans un tableau, le nom d'une valeur est en haut de la colonne et le
   pave d'encre le porte une fois ; dans une carte, il est CONTRE la valeur, et
   le pave d'encre le porte a chaque fois. La couche 2 gagne du terrain, elle
   n'en cede pas.

   Un seul HTML pour les deux formes. Le contenu n'est ecrit qu'une fois : le nom
   de chaque valeur vient de son propre attribut data-label, pas d'une copie du
   tableau. Cout mesure sur /en/ai/, 633 lignes et 3 798 cellules etiquetees :
   +1 149 octets comprimes pour les etiquettes, +749 pour les roles, soit +8,7 %
   de la page la plus lourde du site.

   La bascule est en CSS. Sans JavaScript, la page arrive deja en cartes.

   Ecran seulement : a l'impression, la page A4 fait 49,6rem et passerait sous le
   seuil sans que personne l'ait demande. Le papier garde le vrai tableau.
   ============================================================ */
@media screen and (max-width:52rem){

  /* -- 1. le conteneur cesse de defiler --------------------------------- */
  .blocs{overflow:visible;border:0;background:transparent;margin:1rem 0 1.5rem}
  .blocs table{display:block;border-collapse:separate;border-spacing:0;
    font-size:var(--t2);table-layout:auto}
  .blocs thead,.blocs tbody,.blocs tfoot{display:block}

  /* -- 2. LA REGLETTE. L'en-tete reste, et reste entier ------------------
     Il porte trois choses qu'aucune carte ne peut porter : l'unite, la
     couverture comptee, et les deux bouts de l'echelle sur laquelle chaque cote
     se lit. Les masquer rendrait la cote decorative. Il devient donc un bloc
     d'encre en tete de liste, une colonne par ligne, et chaque nom reste la
     commande de tri, a 44 px. */
  .blocs thead tr,.blocs tfoot tr{display:flex;flex-wrap:wrap;background:var(--ink)}
  .blocs thead th,.blocs tfoot th{display:block;flex:1 1 auto;
    min-width:0;min-height:44px;border:0;border-top:1px solid var(--ink-line);
    white-space:normal;padding:.4rem .7rem;text-align:left;position:relative;
    vertical-align:baseline}
  .blocs thead th.num,.blocs tfoot th.num{flex:1 1 44%;text-align:left}
  .blocs thead th+th,.blocs tfoot th+th{border-left:1px solid var(--ink-line)}
  /* Nom, unite et couverture tiennent sur une ligne au lieu de trois. */
  .blocs thead th .u,.blocs tfoot th .u{display:inline}
  /* Le generateur ecrit « Context<span class=u>tokens</span> » SANS espace : sur
     une seule ligne, « CONTEXTtokens·454 » est un mot insecable de 126 px dans une
     boite de 121,6, et la pastille debordait de 8,5 px a 320 px. Un espace
     genere rend la coupure possible. Un espace de largeur NULLE ferait
     l'affaire a l'oeil mais collerait les mots dans le nom accessible : Chrome
     rendait « INTELLIGENCE INDEX<ZWSP>/ 100 ». Un vrai espace coupe la ligne ET
     separe les mots. Le separateur est un filet et non un caractere : un point
     median serait lu a voix haute par-dessus le nom de la colonne. */
  .blocs thead th .u::before,.blocs tfoot th .u::before{content:" "}
  .blocs thead th .u+.u,.blocs tfoot th .u+.u{padding-left:.4rem;
    border-left:1px solid var(--ink-line)}
  .blocs thead th .cov,.blocs tfoot th .cov{margin-top:.35rem}
  .blocs thead th .ax,.blocs tfoot th .ax{margin-top:.35rem}
  /* La fleche de tri est calee en haut a droite de la pastille ; sans la reserve
     de droite, elle se posait SUR « 601 of 633 held ». Le remplissage de base de
     th.sortable est ecrase par celui de la pastille : il faut le redonner. */
  .blocs thead th.sortable,.blocs tfoot th.sortable{padding-right:1.6rem}
  .blocs thead th.sortable::after,.blocs tfoot th.sortable::after{top:.4rem;
    bottom:auto;right:.5rem}

  /* -- 3. LA CARTE ------------------------------------------------------ */
  .blocs tbody{display:grid;gap:var(--pas)}
  /* Flex et non grid, pour une raison mesurable : une carte a un nombre IMPAIR
     de valeurs une fois sur deux, et une grille laisse alors une case vide,
     peinte en filet, qui se lit comme une donnee manquante. En flex, la derniere
     cellule d'une ligne s'etale et la case vide n'existe pas. Les filets
     interieurs sont les gouttieres : un pixel exact, jamais deux bordures qui
     se doublent. */
  .blocs tbody tr{display:flex;flex-wrap:wrap;
    gap:1px;background:var(--line);border:1px solid var(--line-strong);
    position:relative}
  /* Le [hidden] de la feuille du navigateur PERD contre un display d'auteur.
     Sans cette ligne, le filtre de ui.js cesserait de masquer quoi que ce soit
     et le compteur mentirait. Meme piege que .kbtn[hidden] plus haut. */
  .blocs tbody tr[hidden]{display:none}
  .blocs tbody td{display:block;position:relative;background:var(--card);
    border:0;box-shadow:none;white-space:normal;overflow-wrap:anywhere;
    flex:1 1 42%;min-width:0;max-width:none;height:auto;text-align:left;
    padding:.35rem .6rem .4rem;font-size:var(--t2);vertical-align:baseline}
  .blocs tbody td.num{text-align:left;font-variant-numeric:tabular-nums}

  /* La tete de carte : la cellule d'identite est la seule sans data-label.
     Elle n'a pas de bande : son nom, c'est la ligne entiere. */
  .blocs tbody td:not([data-label]){flex:1 1 100%;font-size:var(--t3);
    line-height:1.4;padding:.5rem .7rem;min-height:44px}
  .blocs tbody td:not([data-label]) a{font-weight:700}
  /* Le vendeur revient comme colonne nommee, donc son doublon sous le nom s'en
     va : un fait, un endroit, et cet endroit porte son nom. */
  .blocs tbody td.col-seller{display:block}
  .blocs tbody td .sub{display:none}

  /* -- 4. LA BANDE D'ENCRE. Ce qui nomme la valeur, contre la valeur ---- */
  .blocs tbody td[data-label]::before{content:attr(data-label);
    display:block;position:static;inset:auto;width:auto;height:auto;
    margin:-.35rem -.6rem .35rem;padding:.2rem .6rem;
    background:var(--ink);color:var(--ink-fg);border:0;
    font:700 var(--t1)/1.4 var(--mono);text-transform:uppercase;
    letter-spacing:.09em;white-space:normal}
  /* Texte alternatif vide : l'etiquette sort de l'arbre d'accessibilite. Le
     lecteur d'ecran tient deja le nom par l'en-tete de colonne, qui n'a pas
     bouge ; sans cela il l'entendrait deux fois. Declaration separee a dessein :
     un moteur qui ignore la syntaxe « / » jette la declaration entiere et garde
     la precedente, donc l'etiquette reste visible partout. */
  .blocs tbody td[data-label]::before{content:attr(data-label) / ""}
  /* Une cellule vide ne porte aucun fait : sa bande ne nommerait rien. */
  .blocs tbody td[data-label]:empty{display:none}

  /* -- 5. LA COTE. Elle survit telle quelle, cellule par cellule --------
     ::before est passe a l'etiquette, donc ::after porte desormais la piste ET
     le tiret, en deux couches de fond. La position en pourcentage place le
     tiret de 3 px a (largeur - 3px) x p / 100 : exactement le calcul du grand
     ecran, sans attribut style, donc sans rien qui heurte la CSP. */
  .blocs tbody td.num.f::after{content:"";display:block;position:static;
    width:auto;height:7px;margin:.3rem 0 0;background-color:transparent;
    background-image:linear-gradient(var(--data),var(--data)),
                     linear-gradient(var(--track),var(--track));
    background-size:3px 7px,100% 2px;
    background-position:calc(var(--p) * 1%) bottom,left bottom;
    background-repeat:no-repeat}
  /* Zero reste hors de l'echelle, comme sur grand ecran. */
  .blocs tbody td.num.f0::after{
    background-image:linear-gradient(var(--fg),var(--fg)),
                     linear-gradient(var(--track),var(--track));
    background-size:6px 6px,calc(100% - 10px) 2px;
    background-position:left bottom,right bottom}

  /* -- 6. LE RANG. Un classement se lit dans l'ordre ---------------------
     Bande d'encre en tete de carte : 1, 2, 3 descendent le long de la page. Pas
     de position absolue, donc rien ne peut recouvrir le titre. */
  .blocs tbody td.rang{flex:1 1 100%;display:flex;align-items:baseline;
    gap:.6rem;background:var(--ink);color:var(--ink-fg);
    font:700 var(--t4)/1.3 var(--mono);padding:.3rem .7rem;min-height:2.1rem}
  .blocs tbody td.rang::before{margin:0;padding:0;background:transparent;
    color:var(--ink-dim);font:700 var(--t1)/1.9 var(--mono);flex:none}

  /* -- 6 bis. LA PAIRE. Sur /en/announced/, deux prix se comparent ligne a
     ligne : c'est le sens meme de la page. A trois colonnes, ils tombaient dans
     deux lignes differentes et deux colonnes differentes, ce qui defait la
     comparaison. La cellule qui PRECEDE la paire finit donc sa ligne, et la
     paire ouvre la suivante : elle reste soudee quel que soit le nombre de
     colonnes optionnelles qui la precedent, et ce tableau en a deux.
     Si :has() manque, la paire peut se couper : chaque prix garde alors sa
     bande d'encre, donc rien n'est perdu ni confondu, seule la comparaison
     demande un aller-retour du regard. C'est un confort, pas un fait.
     La cellule qui precede prend 56 % et non 100 % : assez large pour qu'aucune
     moitie de paire (46 %) ne puisse s'y joindre, assez etroit pour garder un
     voisin a sa gauche. Une ligne entiere aurait ete gaspillee pour rien. */
  .blocs tbody td.paire{flex-basis:46%}
  .blocs tbody td:not(.paire):has(+td.paire){flex-basis:56%}

  /* -- 7. Les valeurs qui sont des LISTES prennent la carte entiere ----- */
  .blocs tbody td.liste-cell{flex:1 1 100%;max-width:none;min-width:0}
  .blocs tbody td.liste-cell ul.jetons{margin-top:.1rem}

  /* Le survol et l'ancre gardent leur repere, cale sur la carte. */
  .blocs tbody tr:hover td,.blocs tbody tr:target td{background:var(--accent-soft)}
  .blocs tbody tr:target{box-shadow:inset 3px 0 0 var(--accent)}
  .blocs tbody tr:hover td:first-child{box-shadow:none}
}

/* Trois colonnes des 22rem. Le seuil est mesure, pas choisi : sur /en/ai/ a
   390 px, la carte passe de 225 a 179 px et le nombre de chiffres nommes vus en
   trois ecrans passe de 2/3/5 a 3/4/8, sans un pixel de debordement. En dessous
   de 22rem la troisieme colonne casse les etiquettes longues : on reste a deux. */
@media screen and (min-width:22rem) and (max-width:52rem){
  .blocs tbody td{flex-basis:28%}
}

/* Le survol n'existe pas au doigt : on ne cache rien derriere. */
@media (hover:none){
  th.sortable::after{opacity:.8}
  th.sortable{padding-right:1.6rem}
}

/* ============================================================
   PREFERENCES SYSTEME
   La trame fixe sous un contenu qui defile EST un mouvement relatif : c'est
   exactement ce que ce reglage existe pour supprimer. Elle devient absolue, donc
   solidaire du document, et plus rien ne glisse.
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;scroll-behavior:auto !important}
  body{position:relative}
  body::before{position:absolute;height:100%;min-height:100vh}
}
/* Sous contraste renforce ou couleurs imposees, la trame et les equerres disparaissent :
   elles sont un reperage, jamais une information. */
@media (prefers-contrast:more){
  body::before{background-image:none}
}
@media (forced-colors:active){
  body::before{background-image:none}
  .answer,figure.chart{background-image:none}
  td.num.f::before,td.num.f::after{forced-color-adjust:none}
  /* En contraste impose, le fond du panneau est force a Canvas et son ombre
     portee est supprimee : il recouvre alors une page elle aussi Canvas sans
     qu'aucune limite ne le dise sur trois de ses cotes, seul le filet du haut
     survit. Mesure du 03/09/2026 : fond rgb(255,255,255), box-shadow none.
     Un panneau qui recouvre doit se voir recouvrir. */
  .navpanel{border:1px solid CanvasText}
}

/* ============================================================
   IMPRESSION. Les jetons sont redefinis, les regles ne sont pas rapiecees.
   L'encre devient du blanc borde de noir : la plupart des navigateurs impriment
   sans les fonds, et un en-tete de colonne reserve en blanc disparaitrait.
   ============================================================ */
@media print{
  :root,:root[data-theme="dark"],:root:not([data-theme="light"]){
    --bg:#fff; --fg:#000; --muted:#333; --faint:#444; --line:#999; --line-strong:#666;
    --card:#fff; --grid:#fff; --grid-major:#fff; --track:#666;
    --accent:#000; --accent-soft:#fff; --data:#000; --up:#000; --down:#000; --warn:#000;
    --ink:#fff; --ink-fg:#000; --ink-dim:#333; --ink-line:#000;
  }
  body::before{display:none}
  header.site,.readout,footer.site nav,.kbtn,.tablebar,.caps,.palette,.skip{display:none}
  body{background:#fff;color:#000;font-size:10pt}
  .wrap{max-width:none;padding:0}
  a{color:#000;text-decoration:underline}
  .scroll{overflow:visible;border:1px solid #000}
  .answer,figure.chart{background-image:none;border:1px solid #000}
  thead th,tfoot th{background:#fff;color:#000;border-bottom:2px solid #000}
  table td:first-child,table th:first-child{position:static;box-shadow:none;min-width:0}
  /* Sur le papier, une cellule qui refuse de se couper pousse les colonnes de
     provenance hors de la feuille. Mesure sur /en/announced/ en A4 : 1 205 px de
     tableau pour 717 px utiles, soit trois colonnes perdues dont Source. */
  th,td{white-space:normal;overflow-wrap:anywhere;padding:.25rem .4rem;font-size:8pt}
  td.wrap-cell,td:first-child.wrap-cell{min-width:0}
  table{table-layout:auto}
  /* L'URL de la source, invisible a l'ecran, doit figurer sur le papier : une
     impression sans provenance n'est plus une preuve. Et la premiere colonne perd sa
     largeur minimale, faute de quoi les colonnes de provenance tombent hors feuille. */
  main a[href^="http"]::after{content:" (" attr(href) ")";font-size:8pt;word-break:break-all}
  .print-ok thead{display:table-header-group}
  tr{page-break-inside:avoid}
  td.num.f::before,td.num.f::after{display:none}
/* Le papier ne se replie pas. Sans cette regle, /en/compare/ s'imprime en 9
   pages de noms sans une seule date, la ou la page servie en rend 51 avec 479
   dates : une impression sans provenance n'est plus une preuve, comme dit plus
   haut dans ce meme bloc. Limite honnete : ::details-content est recent ; un
   moteur qui l'ignore n'imprimera que les sommaires, et c'est precisement
   pourquoi la mise en garde d'appariement reste HORS du pli quoi qu'il arrive.
   Essai elimine avec sa mesure : details>*{display:block} ne restitue rien, le
   masquage du pli ne passe pas par display. */
details.modele>summary{list-style:none}
details::details-content{content-visibility:visible;display:block}
}

/* Le pays de l'entite juridique, sur la vignette d'un vendeur. Il vient APRES
   le nombre de services et se lit d'un coup d'oeil, mais il ne doit pas prendre
   le pas sur le nom du vendeur : c'est une precision, pas un titre. */
.hubs .pays{display:block;font-size:.82em;letter-spacing:.02em;color:var(--data)}
.hubs .pays.plus{color:var(--muted);font-size:.76em}

/* Le selecteur. « not measured » ne doit ni disparaitre ni crier : c'est une
   information, pas une erreur, et la cacher reviendrait a laisser croire que
   nous savons ce que nous ne savons pas. */
.unk{color:var(--faint);font-style:italic;font-size:.88em}
[data-reglages] label{display:inline-flex;align-items:center;gap:.4rem;
  font-size:.86em;color:var(--muted);margin-right:1rem}
[data-reglages] input[type=number]{width:6rem}
[data-besoins] .cap.on{border-color:var(--accent);color:var(--fg)}
