/* ==========================================================================
   NORYVA — feuille de style
   Le site est une scene unique : une couche .stage fixe porte les objets 3D,
   les sections .act defilent par-dessus et pilotent la camera.
   ========================================================================== */
@import url("../fonts/fonts.css");

/* ==========================================================================
   `hidden` CACHE. UNE FOIS, POUR TOUT LE SITE.
   --------------------------------------------------------------------------
   La règle du navigateur est `[hidden]{display:none}`, de spécificité 0,1,0 :
   n'importe quelle classe qui pose un `display` la bat, et n'importe quel
   identifiant l'écrase. Ce dépôt le sait — VINGT règles écrites à la main
   réparent le cas au coup par coup, chacune avec son commentaire « display:flex
   bat [hidden] ». Vingt réparations veut dire que le défaut revient à chaque
   composant neuf, et deux étaient passées à travers :

     · `#cartCount` avait bien son correctif, mais SOUS PORTÉE — `.pg-cart
       #cartCount[hidden]` ne s'applique pas à l'en-tête du site. Une pastille
       violette vide était donc posée sur le bouton « Panier » de chaque page,
       dans les sept langues : une notification qui annonce un panier plein
       alors qu'il est vide. Vérifié à la capture.
     · `.cmd-etape` n'en avait aucun. Les cinq étapes du tunnel de commande —
       panier, e-mail, adresse, facturation, récapitulatif — s'affichaient
       TOUTES EN MÊME TEMPS, 2 454 px de formulaire et cinq boutons
       « Continuer » sur un téléphone. `tests/commande.js` passait ses 58
       contrôles : il lit la PROPRIÉTÉ `hidden`, qui vaut bien `true`. La
       propriété disait vrai, la page montrait autre chose.

   Une vingt-et-unième rustine aurait réparé ces deux-là et laissé le
   vingt-deuxième arriver. `!important` est ici la pratique recommandée pour
   cet attribut précis, et il est sans risque dans ce dépôt : les vingt règles
   `[hidden]` existantes posent toutes `display:none`, aucune ne cherche à
   AFFICHER un élément marqué caché. Elles deviennent redondantes ; elles ne
   deviennent pas fausses.
   ========================================================================== */
[hidden]{display:none !important}

:root{
  /* --- identite de marque -------------------------------------------- */
  --night:#08070a;
  --night-2:#0d0c11;
  --ink:#f6f4f1;
  --muted:rgba(246,244,241,.56);
  --faint:rgba(246,244,241,.30);
  --line:rgba(246,244,241,.11);
  --gold:#c4985c;
  --gold-lt:#e9ca9a;
  --plasma:#8b4ad6;
  /* LE VERT DE WHATSAPP, ET SEULEMENT POUR WHATSAPP.
     Il n'appartient pas à NORYVA : c'est la couleur d'un tiers, et c'est
     précisément ce qui le rend utile — un visiteur reconnaît le canal avant de
     lire le mot. Il ne sert donc qu'aux deux points d'entrée WhatsApp (la
     pastille flottante et le bouton de l'acte « contact ») : en bordure, en
     icône et en lueur, jamais en aplat de fond. Un bouton entièrement vert
     dans cette page ferait le même effet qu'un autocollant sur une vitrine.
     --wa-clair sert au survol et aux états actifs : le vert de marque sur un
     fond presque noir passe 4,5:1 en icône, mais s'éteint dès qu'on l'éclaire
     moins. */
  --wa:#25d366;
  --wa-clair:#5ce89a;
  /* Les deux glyphes sont des MASQUES, pas des images : aucune requête, aucune
     couleur figée, et ils suivent la couleur du texte quand on le leur
     demande. Tracé officiel de la bulle WhatsApp, et une enveloppe pour
     l'e-mail. */
  --ico-wa:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12.04 2C6.58 2 2.13 6.45 2.13 11.91c0 1.75.46 3.46 1.32 4.96L2 22l5.25-1.38a9.9 9.9 0 0 0 4.79 1.22h.01c5.46 0 9.91-4.45 9.91-9.91C21.96 6.45 17.5 2 12.04 2Zm0 18.02h-.01a8.2 8.2 0 0 1-4.19-1.15l-.3-.18-3.12.82.83-3.04-.2-.31a8.17 8.17 0 0 1-1.26-4.37c0-4.54 3.7-8.23 8.25-8.23a8.2 8.2 0 0 1 8.24 8.24c0 4.54-3.7 8.22-8.24 8.22Zm4.52-6.16c-.25-.12-1.47-.72-1.69-.81-.23-.08-.39-.12-.56.13-.16.25-.64.8-.79.97-.14.16-.29.19-.54.06-.25-.12-1.05-.39-1.99-1.23-.74-.66-1.23-1.47-1.38-1.72-.14-.25-.01-.38.11-.5.11-.11.25-.29.37-.44.13-.15.17-.25.25-.42.08-.16.04-.31-.02-.44-.06-.12-.56-1.35-.77-1.85-.2-.48-.4-.42-.56-.43h-.47c-.16 0-.42.06-.64.31-.22.25-.84.82-.84 2s.86 2.32.98 2.48c.12.16 1.69 2.58 4.1 3.62.57.25 1.02.39 1.37.5.58.18 1.1.16 1.51.1.46-.07 1.47-.6 1.68-1.18.21-.58.21-1.08.14-1.18-.06-.11-.22-.17-.47-.29Z'/></svg>");
  --ico-mail:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M3 5.5h18c.55 0 1 .45 1 1v11c0 .55-.45 1-1 1H3c-.55 0-1-.45-1-1v-11c0-.55.45-1 1-1Zm1.6 2L12 12.6l7.4-5.1H4.6ZM20 9.3l-7.43 5.12a1 1 0 0 1-1.14 0L4 9.3v7.2h16V9.3Z'/></svg>");
  /* accent courant : pilote par le JS selon la reference affichee */
  --accent:#8b4ad6;
  /* MÊME TEINTE, PLUS LISIBLE — et uniquement pour du TEXTE.
     Le plasma de marque affiche 3,87 de contraste sur le fond du site : sous
     le seuil de 4,5, et il porte justement les libellés les plus petits, en
     10 px très espacés, qui se lisent déjà plus fins que leur taille. La
     teinte décorative NE CHANGE PAS — halos, brume, liserés, bagues du
     produit gardent exactement le plasma d'origine. Seule l'encre s'éclaircit,
     à teinte constante : 5,41 de contraste. */
  --accent-txt:#a06bde;
  --ease:cubic-bezier(.22,1,.36,1);
  --nav:68px;
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--night);color:var(--ink);
  font:400 16px/1.65 Inter,system-ui,-apple-system,"Segoe UI",sans-serif;
  overflow-x:hidden;-webkit-font-smoothing:antialiased;
}
img{display:block;max-width:100%;height:auto}
a{color:inherit;text-decoration:none}
h1,h2,h3{margin:0;font-family:Outfit,Inter,sans-serif;font-weight:200;line-height:1.02;
  letter-spacing:.005em}
p{margin:0}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}

.mono{font-family:"JetBrains Mono",ui-monospace,monospace;font-size:10px;
  letter-spacing:.2em;text-transform:uppercase;line-height:1.6}
.gold{color:var(--gold-lt)}
.acc{color:var(--accent-txt)}

/* ==========================================================================
   1. ATMOSPHERE — brume, lumiere volumetrique, grain
   ========================================================================== */
.stage{position:fixed;inset:0;z-index:1;overflow:hidden;perspective:1500px;
  perspective-origin:50% 46%;pointer-events:none}
.atmos{position:absolute;inset:0}
/* ATMOSPHÈRE — POURQUOI IL N'Y A PLUS UN SEUL `filter:blur()` ICI.
   Mesuré sur le site complet, à l'arrêt, sans la moindre interaction :
   1,2 image/s, 9,39 s de CPU en 6 s de temps réel, dont 0,06 s de JavaScript.
   Le script ne faisait rien. Tout partait dans la rasterisation.

   La cause : cinq calques flous, ~5 mégapixels au total, avec des rayons de
   48 a 90 px, deux d'entre eux en `mix-blend-mode:screen`. Un flou de 90 px
   est une convolution enorme, et un blend force le compositeur a relire le
   fond. Le tout etant anime a chaque image, la scene entiere etait
   re-rasterisee en permanence — y compris quand la page ne bougeait pas.

   Ce qui les remplace ne coute RIEN : un degrade radial est DEJA flou. Le
   flouter n'ajoutait presque rien a l'ecran et coutait tout au GPU. On elargit
   donc les butees du degrade, et on obtient la meme brume.
   PRODUIT > MARQUE > EFFETS D'ENVIRONNEMENT : c'est ce budget-la qu'on rend
   au produit, sous forme de resolution. */
/* `will-change` A ÉTÉ RETIRÉ, ET C'EST UN GAIN, PAS UNE PERTE.
   Il promeut l'élément en calque de composition DÉFINITIF : trois disques de
   88 vw gardés en mémoire graphique et remontés à chaque image, du premier au
   dernier écran, même quand plus rien ne les déplace. C'est exactement le
   genre de calque qui fait chauffer une machine sans rien apporter à l'image.
   Depuis que la dérive ne joue plus que dans les quatre sections où la scène
   est le sujet, la promotion permanente n'a plus aucune justification : le
   navigateur promeut tout seul, le temps du mouvement, et libère ensuite. */
/* ==========================================================================
   LE FOND ENTRE ET SORT EN FONDU, IL NE SE COUPE PAS.
   --------------------------------------------------------------------------
   Ces couches sont retirées de la composition (`display:none`) hors des actes
   où la scène est le sujet — c'est le gain de performance, et il ne bouge pas.
   Ce qui change, c'est le PASSAGE : sans transition, le fond violet et
   éclairé disparaissait en une image et l'on sentait le changement de bloc.
   La transition ne coûte que pendant le fondu, puisque au repos la couche
   n'est plus composée du tout. */
.fog,.beam,#penGlow,#scene{transition:opacity .52s var(--ease, cubic-bezier(.4,0,.2,1))}
@media (prefers-reduced-motion:reduce){
  /* Choix du visiteur : pas d'animation. La coupure nette redevient la règle,
     et elle est ici la bonne réponse. */
  .fog,.beam,#penGlow,#scene{transition:none}
}
.fog{position:absolute;border-radius:50%}
/* bloom principal : derriere le produit, cote droit */
.fog-1{width:88vw;height:88vw;right:-22vw;top:-22vw;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--accent) 62%,transparent) 0%,
    color-mix(in srgb,var(--accent) 26%,transparent) 34%,
    color-mix(in srgb,var(--accent) 7%,transparent) 62%,transparent 88%);
  opacity:.34}
.fog-2{width:84vw;height:84vw;left:-28vw;bottom:-30vw;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--accent) 40%,transparent) 0%,
    color-mix(in srgb,var(--accent) 17%,transparent) 38%,
    color-mix(in srgb,var(--accent) 5%,transparent) 66%,transparent 90%);
  opacity:.28}
.fog-3{width:150vw;height:64vw;left:-25vw;top:26%;
  background:radial-gradient(closest-side,
    rgba(255,248,236,.11) 0%,rgba(255,248,236,.05) 40%,
    rgba(255,248,236,.015) 68%,transparent 90%);
  opacity:.46}
/* Le faisceau : le flou ne servait qu'a adoucir ses bords LATERAUX — le
   degrade s'occupait deja du haut vers le bas. Un masque horizontal fait
   exactement le meme travail pour une fraction du cout. `screen` sur un fond
   quasi noir revient a une composition alpha ordinaire : on le retire. */
.beam{position:absolute;left:50%;top:-30vh;width:52vw;height:150vh;
  transform:translateX(-50%) rotate(9deg);
  background:linear-gradient(to bottom,
    color-mix(in srgb,var(--accent) 46%,transparent) 0%,
    color-mix(in srgb,var(--accent) 18%,transparent) 34%,transparent 68%);
  -webkit-mask-image:linear-gradient(to right,transparent 0%,#000 26%,#000 74%,transparent 100%);
  mask-image:linear-gradient(to right,transparent 0%,#000 26%,#000 74%,transparent 100%);
  opacity:.46}
#dust{position:absolute;inset:0;opacity:.55}
/* SANS 3D. Quand la machine rasterise au processeur, la scene n'est pas
   construite du tout — ou elle est demontee apres quelques images. Le canvas
   ne doit alors plus occuper l'ecran : les rendus photorealistes approuves,
   deja presents dans les sections, portent le produit seuls. */
.vp-sans-3d #scene{display:none}
/* L'OBJET DE REPLI. Meme place, meme echelle, meme respiration que la scene
   qu'il remplace. Detoure, sur fond transparent : ce n'est pas une photo
   posee dans la page, c'est le produit dans la composition. Seules l'opacite
   et la translation bougent — le compositeur n'a rien a repeindre.

   PLUS DE `drop-shadow`. Il y en avait un : 70 px de flou applique a la
   silhouette d'une image de 619 x 1122, sur un calque qui se translate et se
   fond a chaque image. Mesure sur trois traversees completes de la page,
   a 1440 :
       avec drop-shadow(0 40px 70px) .... 19 images > 50 ms, pire 133 ms
       avec drop-shadow(0 16px 24px) .... 10 images > 50 ms, pire 100 ms
       sans ombre ........................ 7 images > 50 ms, pire  83 ms
   Le temps de tâches, lui, ne bouge pas : ce flou ne coute rien au fil
   principal, il coute a la RASTERISATION — c'est-a-dire exactement ce que le
   visiteur ressent comme un accroc. Et sur un fond quasiment noir, une ombre
   noire a 55 % ne se voit pas : la comparaison des deux captures est
   indiscernable. On a donc paye douze accrocs pour rien. */
/* LE PRODUIT SE RAPPROCHE DE SON TEXTE.
   À 7vw du bord droit, il restait 450 px de vide entre la colonne de lecture
   et l'objet à 1440 : le nom, le prix et le bouton d'un côté, le produit de
   l'autre, et rien pour dire que les deux parlent de la même chose. */
/* LE VISUEL DE REPLI SUIT LE MÊME DÉCALAGE QUE LA SCÈNE 3D.
   Le stylo doré arrivait à hauteur de la ligne de confiance (« Déjà plus de
   10 000 clients… ») et la frôlait. La caméra 3D a reculé de 1,6 unité vers la
   gauche (voir CAM dans vp-scene.js) ; sans ce changement-ci, la version SANS
   WebGL — celle que voit une machine sans GPU, et celle que capturent les
   essais — serait restée à l'ancienne place. Deux vérités pour un même écran,
   c'est exactement ce qu'on ne veut pas d'un repli. */
.still{position:absolute;right:9.5vw;top:50%;height:min(78vh,760px);width:auto;
  opacity:0;pointer-events:none;z-index:2;
  transform:translate3d(0,-50%,0)}
@media (max-width:1100px){
  /* SOUS 1100 px, LE VISUEL PASSE DERRIÈRE LE TEXTE — il ne peut donc pas
     rester à pleine opacité. À 0,9 il était aussi présent que la colonne de
     lecture qui le recouvre : les puces des axes étudiés, le repli « Détail
     scientifique » et le nom de la référence se lisaient PAR-DESSUS un flacon
     net, et le résultat n'est ni lisible ni présentable. Il devient une
     toile de fond — c'est le rôle qu'il tient à cette largeur, et le seul
     qu'il puisse tenir. */
  .still{right:50%;transform:translate3d(50%,-50%,0);height:min(52vh,460px);opacity:.34}
}
@media (max-width:700px){
  /* Plus la colonne est étroite, plus le texte occupe la même surface que le
     visuel : à 390 px ils se superposent entièrement. */
  .still{opacity:.22;height:min(46vh,400px)}
}

/* ET CE QUI PREND SA PLACE. Retirer la scene laissait la moitie droite de la
   section « Anatomie » vide, et ses deux visuels d'etat relegues sous le
   texte : le geste disparaissait ET la composition avec lui. Les rendus
   approuves remontent donc a la place qu'occupait la 3D — meme colonne, meme
   hauteur, meme respiration. Rien n'est redessine, rien n'est deplace quand
   la 3D est la. */
@media (min-width:1100px){
  /* `.col` borne le texte a 430 px — c'est ce qui donne sa mesure de lecture
     a la colonne. Ici la meme boite doit accueillir DEUX colonnes : on la
     libere, et on redonne les 430 px a la seule colonne de texte. */
  .vp-sans-3d #system .hold{display:grid;max-width:min(1180px,92vw);
    grid-template-columns:minmax(0,430px) minmax(0,1fr);
    column-gap:clamp(24px,5vw,72px);align-content:center}
  .vp-sans-3d #system .hold > .eyebrow{grid-column:1;grid-row:1}
  .vp-sans-3d #system .hold > h2{grid-column:1;grid-row:2}
  .vp-sans-3d #system .hold > .steps{grid-column:1;grid-row:3}
  .vp-sans-3d #system .hold > .states{grid-column:2;grid-row:1 / span 3;
    align-self:center;margin:0;gap:20px}
  .vp-sans-3d #system .hold > .shot{grid-column:2;grid-row:4;margin-top:16px}
  .vp-sans-3d #system .hold > .shot--wide{grid-column:1 / -1;grid-row:5;
    width:100%;margin:32px 0 0}
  /* La sequence prend la colonne de droite, sous les etats. Elle etait ECRITE
     HORS DU `.hold` — trois `</div>` la sortaient de la colonne — et retombait
     donc par-dessus la liste des temps : « La fiole » se lisait au travers de
     « Fiole, cartouche, stylo ». Le balisage est corrige ; il ne restait qu'a
     lui donner sa place dans la grille de repli. */
  .vp-sans-3d #system .hold > .seq{grid-column:2;grid-row:4;margin-top:26px}
}
/* La section durait 520vh pour donner a la scene le temps de se demonter au
   fil du scroll. Sans scene, ce sont cinq ecrans a traverser pour rien. */
/* SANS 3D, LA MISE EN SCENE N'A PLUS DE SUJET.
   Empiler onze temps qu'aucune image n'accompagne ferait traverser cinq
   ecrans pour lire onze paragraphes. La liste redevient donc une liste : tout
   est visible d'un coup, et la section retrouve une hauteur de lecture. */
.vp-sans-3d #system{min-height:130vh}
/* Sans 3D, la liste des onze temps se deroule PAR-DESSUS le rendu fixe : sur
   un telephone, le texte passait devant le stylo et se lisait mal. L'image
   recule derriere lui — elle reste la, elle cesse d'etre un obstacle. */
/* 0,22 et non 0,34 : sur un écran de 390 px le rendu passe DERRIÈRE le titre
   et la proposition de valeur, et à un tiers d'opacité il les concurrence. Il
   reste dans la composition ; il cesse d'être un fond de texte. */
@media (max-width:900px){ .vp-sans-3d .still{opacity:.22} }
.vp-sans-3d .steps{height:auto;overflow:visible;-webkit-mask-image:none;mask-image:none}
.vp-sans-3d .steps-piste{transform:none;gap:22px}
/* Sans 3D, la liste est une LISTE : tout se lit d'un coup. `.on` et `.pres`
   continuent d'etre poses par le rendu — ils pilotent la mise en lumiere de
   la piece dans la scene — et leurs opacites, declarees plus bas dans le
   fichier a specificite egale, reprenaient le dessus : deux temps sur six
   s'affichaient a 40 % sans qu'aucun mouvement ne l'explique. */
.vp-sans-3d .step,.vp-sans-3d .step.pres,.vp-sans-3d .step.on{opacity:1}
.vp-sans-3d .seq{display:grid;animation:none}
/* Le grain couvrait tout l'ecran en `mix-blend-mode:overlay` : un melange
   plein cadre a refaire des que quoi que ce soit bouge derriere. En alpha
   simple, avec un bruit plus sombre et une opacite plus basse, il tient le
   meme role de texture pour un cout de composition ordinaire. */
.grain{position:fixed;inset:0;z-index:40;pointer-events:none;opacity:.16;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3'/></filter><rect width='180' height='180' filter='url(%23n)' opacity='.5'/></svg>")}
.vign{position:fixed;inset:0;z-index:2;pointer-events:none;
  background:radial-gradient(130% 96% at 50% 44%,transparent 54%,rgba(0,0,0,.62) 100%)}

/* ==========================================================================
   2. OBJETS DE LA SCENE
   ========================================================================== */
#scene{position:absolute;inset:0;width:100%;height:100%;display:block}
/* Pas de `will-change` : ces rendus de repli ne bougent QUE sur les machines
   sans carte graphique, c'est-à-dire précisément celles où un calque promu en
   permanence coûte le plus cher. Le navigateur promeut le temps du mouvement. */
.obj{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  pointer-events:none}
#penGlow{width:min(64vw,780px);height:min(64vw,780px);border-radius:50%;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--accent) 78%,transparent) 0%,
    color-mix(in srgb,var(--accent) 32%,transparent) 32%,
    color-mix(in srgb,var(--accent) 9%,transparent) 60%,transparent 86%);}

/* ==========================================================================
   3. INTERFACE FIXE
   ========================================================================== */
/* ==========================================================================
   `body > header`, ET PAS `header` — LA BARRE DU SITE, PAS TOUS LES EN-TÊTES
   --------------------------------------------------------------------------
   Cette règle visait l'élément `header` tout court. Elle s'appliquait donc à
   TOUT `<header>` de la page, y compris celui que porte chaque carte d'avis
   (`.rv-card > header`, l'étoile et la pastille « achat vérifié »).
   Conséquence, invisible tant que la grille d'avis restait vide : à la
   première carte affichée, son en-tête devenait `position:fixed; top:0` et
   ses étoiles allaient se poser SUR le bouton MENU, sa pastille par-dessus
   « ACCÈS PRO ». Relevé au rendu, une carte à 20 124 px du haut et ses
   étoiles à 22 px.
   La barre du site est le seul `header` enfant direct de `body` : c'est donc
   ce qu'on écrit. Un sélecteur d'élément nu, dans une feuille partagée par
   toutes les pages, finit toujours par attraper quelque chose d'autre.
   ========================================================================== */
body > header{position:fixed;top:0;left:0;right:0;height:var(--nav);z-index:30;
  display:flex;align-items:center;justify-content:space-between;
  padding:0 clamp(18px,3.4vw,44px)}
/* UN VOILE, PAS UN BANDEAU — ET SEULEMENT UNE FOIS QUE ÇA A DÉFILÉ.
   Le texte des pages de document passait sous une barre entièrement
   transparente et s'y mélangeait. Un fond plein aurait réglé la lisibilité en
   ajoutant une bande à toutes les pages, hero compris : ce n'est pas ce qui a
   été validé. Un dégradé du fond de page vers le transparent, posé DERRIÈRE
   les boutons, suffit — il éteint ce qui passe dessous sans dessiner de
   limite. `html.defile` est posé par la boucle au-delà de 24 px : dans le
   premier écran, le voile n'existe pas.
   `pointer-events:none` : le voile ne doit rien intercepter. Pas de
   `backdrop-filter` — reflouter un fond qui défile coûte une image entière,
   c'est la même raison qu'ailleurs sur ce site. */
body > header::before{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to bottom,
    color-mix(in srgb,var(--night) 92%,transparent) 0%,
    color-mix(in srgb,var(--night) 74%,transparent) 58%,
    transparent 100%);
  opacity:0;transition:opacity .3s var(--ease);pointer-events:none}
html.defile body > header::before{opacity:1}
@media (prefers-reduced-motion:reduce){ body > header::before{transition:none} }
.lockup{position:absolute;left:50%;transform:translateX(-50%);display:flex;
  align-items:center;gap:11px}
.lockup svg{width:26px;height:26px}
.lockup b{font-family:Outfit;font-weight:300;font-size:15px;letter-spacing:.36em;
  text-transform:uppercase;padding-left:.36em}
/* Le nom se compose d'un seul mot, dans l'or de la marque — comme le logo
   officiel. Le style à deux teintes de l'ancienne marque n'a plus d'objet. */
@media (max-width:1100px){
  /* CENTRER EN ABSOLU NE MARCHE QUE S'IL RESTE DE LA PLACE AU CENTRE. Sous
     1100 px, le groupe de droite (langue, panier, acces pro) franchit deja le
     milieu : la marque, centree par-dessus, retombait SUR le panier. On la
     remet dans le flux — elle prend sa place au lieu de la voler. */
  .lockup{position:static;transform:none}
}
.lockup b{color:var(--gold-lt)}
.lockup b i{font-style:normal;color:var(--gold)}
.btn{display:inline-flex;align-items:center;gap:10px;border:1px solid var(--line);
  border-radius:999px;padding:11px 22px;transition:.4s var(--ease);
  font-family:"JetBrains Mono";font-size:10px;letter-spacing:.2em;text-transform:uppercase}
.btn:hover{background:var(--ink);color:var(--night);border-color:var(--ink)}
.btn-acc{border-color:color-mix(in srgb,var(--accent) 60%,transparent);
  background:color-mix(in srgb,var(--accent) 15%,transparent)}
.btn-acc:hover{background:var(--accent);border-color:var(--accent);color:#fff}
#bar{position:fixed;top:0;left:0;height:2px;width:0;z-index:35;
  background:linear-gradient(90deg,transparent,var(--accent));box-shadow:0 0 16px var(--accent)}

/* pastilles de reference, colonne de droite */
/* ---- MENU ----------------------------------------------------------------
   Trois colonnes : ce qu'on vend, ce qu'on peut vérifier, ce qu'on peut faire.
   Fond OPAQUE et non flouté : un `backdrop-filter` plein écran se recalcule à
   chaque image tant que le menu est ouvert, pour un rendu indiscernable sur un
   fond déjà presque noir. */
#menuOverlay{position:fixed;inset:0;z-index:38;background:rgba(7,6,10,.985);
  display:grid;place-items:center;padding:calc(var(--nav) + 20px) 5vw 30px;
  overflow:auto;animation:swapIn .28s var(--ease) both}
#menuOverlay[hidden]{display:none}
.mo-in{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(26px,5vw,80px);width:min(1080px,100%)}
.mo-col{display:grid;align-content:start;gap:2px}
.mo-t{font-size:10px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--accent-txt);margin:0 0 14px}
.mo-col a,.mo-col button{display:flex;align-items:center;min-height:52px;
  font-family:Outfit,system-ui,sans-serif;font-weight:200;
  font-size:clamp(22px,3.1vw,34px);letter-spacing:.01em;color:var(--ink);
  opacity:.72;background:none;border:0;padding:0;cursor:pointer;text-align:left;
  transition:opacity .25s var(--ease)}
.mo-col a:hover,.mo-col button:hover,
.mo-col a:focus-visible,.mo-col button:focus-visible{opacity:1}
.mo-col .menu-pro{margin-top:16px;font-family:"JetBrains Mono";font-size:12px;
  letter-spacing:.2em;text-transform:uppercase;min-height:48px;padding:0 24px;
  border:1px solid var(--line);border-radius:999px;justify-content:center;
  opacity:1}
@media (max-width:760px){
  #menuOverlay{place-items:start center}
  .mo-in{grid-template-columns:1fr;gap:26px}
  .mo-col a,.mo-col button{font-size:24px;min-height:48px}
}

#dots{position:fixed;right:clamp(12px,2vw,26px);top:50%;transform:translateY(-50%);
  z-index:30;display:grid;gap:12px}
#dots button{width:34px;height:34px;border-radius:50%;border:1px solid var(--line);
  display:grid;place-items:center;transition:.45s var(--ease);opacity:0}
#dots button i{width:5px;height:5px;border-radius:50%;background:var(--faint);
  transition:.45s var(--ease)}
#dots.on button{opacity:1}
/* LE HALO DE LA PASTILLE ACTIVE N'A PLUS D'ARÊTE DURE.
   C'était une ombre d'ÉCARTEMENT PUR — quatre pixels, flou zéro : son
   contour est alors une frontière nette, et une frontière nette sur un
   cercle de trente-quatre pixels se lit comme un polygone dès qu'on
   l'agrandit. Un pixel de flou suffit à l'effacer : à taille réelle
   l'anneau est identique, et il n'a plus de marche. Mesuré au pixel : le
   rond lui-même et son filet étaient déjà lisses, c'est ce halo qui
   portait l'aspect crénelé. */
#dots button.sel{border-color:var(--accent);
  box-shadow:0 0 1px 4px color-mix(in srgb,var(--accent) 16%,transparent)}
#dots button.sel i{background:var(--accent);width:8px;height:8px}

/* ==========================================================================
   4. CONTENU
   ========================================================================== */
.content{position:relative;z-index:3}
.act{position:relative;min-height:100vh;padding:0 clamp(20px,5vw,90px)}
/* le bloc de texte reste tenu pendant toute la traversee de l'acte :
   la camera bouge, le cadrage du texte ne bouge pas. */
.hold{position:sticky;top:0;min-height:100vh;display:flex;flex-direction:column;
  justify-content:center;padding:12vh 0}
/* section longue (tableau + tuiles) : on laisse le flux normal */
.hold--flow{position:static;min-height:auto;padding:18vh 0}
#acquire .hold{padding:8vh 0}
.act--tall{min-height:230vh}
/* Onze temps d'anatomie (voir ANATOMIE dans vp-scene.js), un demi-ecran
   chacun, plus un ecran pour l'entree et la sortie de l'acte. La hauteur
   est DEDUITE du nombre de temps : ajouter une piece a expliquer allonge
   la section d'autant, et rien d'autre n'est a toucher. */
/* 650vh -> 400vh -> 220vh.
   La séquence du stylo comptait dix-sept plans de caméra et un démontage
   complet ; il en reste six et un seul geste, sur deux temps. Garder la
   hauteur d'avant, c'est faire défiler quatre écrans sur une chorégraphie qui
   n'existe plus — et repousser d'autant le moment où le visiteur voit un
   produit qu'il peut acheter. Le passage tient maintenant en deux écrans :
   « à quoi ça sert » et « est-ce simple », rien d'autre. */
/* 220vh POUR DEUX TEMPS, ET C'EST UN CHOIX DE FLUIDITÉ, PAS DE BAVARDAGE.
   Raccourcir l'acte à 170vh ne retire aucun contenu : il compresse le même
   mouvement de caméra sur un tiers de défilement en moins. `tests/jank.js` l'a
   vu immédiatement — l'approche du stylo passait de 42 à 23 unités de recul en
   six images au lieu de neuf, et deux d'entre elles sautaient de cinq unités
   quand leurs voisines en faisaient une demie. Une présentation « plus courte »
   qui saccade est plus longue à regarder qu'une présentation fluide. */
/* L'ACTE DU PLAN LARGE NE DURE PLUS QU'UN ÉCRAN. Il en faisait un et demi, et
   le relevé de texte le montrait sans appel : de 0,75 à 2,00 écran, la même
   surface lisible, les mêmes dix blocs, rien qui entre ni qui sorte. Ce n'est
   pas un vide de contenu, c'est un vide de MOUVEMENT — le visiteur descend et
   la page ne lui répond pas. L'approche du stylo se joue maintenant sur la
   distance qu'elle mérite. */
/* 150vh, PAS 110. Le bloc collé fait un écran de haut : dans une section de
   110vh il n'est réellement épinglé que sur les dix premiers pour cent, et il
   remonte hors du champ pendant tout le reste — mesuré, le titre était coupé
   par l'en-tête dès 40 % de la section. À 150vh il tient un demi-écran de
   lecture, et c'est aussi la place dont la caméra a besoin pour aller des trois
   stylos aux fioles sans raccord sec. */
#system{min-height:150vh}
/* LE COFFRET : trois temps — fermé, ouverture, stylo dedans. Il a été essayé
   DANS le chemin d'achat, entre les couleurs et les prix, à 170vh : tout ce
   qu'il prenait, le visiteur le payait avant de voir un tarif. Il est
   redescendu après les offres, là où il ne coûte plus rien — il peut donc
   reprendre la durée qui lui va. */
/* L'ACTE DU STYLO PORTE UNE OFFRE, DONC PLUS DE CONTENU : le nom, une phrase,
   trois faits, deux boutons. Le bloc collé fait un écran de haut et centre son
   contenu ; passé cette hauteur il déborde des DEUX côtés et l'accroche passe
   derrière l'en-tête fixe. On lui donne la barre en rembourrage haut. */
#system .hold{justify-content:center;padding:calc(var(--nav) + 2vh) 0 3vh}
/* Les trois faits : une liste, pas des cartes. Quatre encadrés à la file
   feraient un tableau comparatif, et il n'y a rien à comparer. */
.faits{list-style:none;margin:26px 0 0;padding:0;display:grid;gap:11px}
.faits li{position:relative;padding-left:18px;color:var(--muted);
  font-size:clamp(13.5px,1.05vw,15px);line-height:1.55;max-width:40ch}
.faits li::before{content:"";position:absolute;left:0;top:.62em;width:6px;height:1px;
  background:color-mix(in srgb,var(--gold) 70%,transparent)}
/* UN TIRET DEVANT UNE LISTE D'UN SEUL ÉLÉMENT N'EST PLUS UNE PUCE.
   Une puce sépare des éléments entre eux ; seule, elle ne sépare rien et se
   lit comme un tiret oublié devant la phrase. Le propriétaire l'a relevé.
   La règle ne vaut que pour l'élément unique : dès qu'il y en a deux, la
   liste redevient une liste et retrouve ses tirets. */
.faits li:only-child{padding-left:0}
.faits li:only-child::before{display:none}
/* TROIS AFFIRMATIONS COURTES NE SE LISENT PAS COMME TROIS EXPLICATIONS.
   La liste par défaut est grise, fine et large — juste pour des phrases qui
   expliquent. Ici ce sont trois arguments de deux ou trois mots : ils prennent
   la couleur du texte principal et se resserrent, pour qu'on les lise d'un
   seul coup d'œil au lieu de les parcourir. */
.faits--court{gap:7px;margin-top:22px}
.faits--court li{color:var(--ink);font-size:clamp(15px,1.25vw,17px);
  line-height:1.45;max-width:none}
.faits--court li::before{top:.66em;width:9px;
  background:color-mix(in srgb,var(--gold) 88%,transparent)}
/* Le pied de page sépare les molécules des deux accès de format : un filet
   discret, pas un titre de plus. */
.fsep{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}

#range{min-height:340vh}
/* 210 vh LAISSAIENT UNE DEMI-PAGE VIDE À LA FIN, ET C'ÉTAIT MESURABLE.
   Relevé à 1440 en balayant la section : passé le premier écran et demi, le
   coffret a commencé sa sortie — il rétrécit et monte — pendant que la
   colonne de texte, elle, reste collée. Le visiteur a donc devant lui un
   texte en haut à gauche, un petit coffret en haut à droite, et la moitié
   basse de l'écran vide. Le propriétaire l'a relevé : « une grande zone
   vide ». La séquence ne demande pas cette longueur ; c'est la longueur qui
   fabriquait le vide. */
#pack{min-height:172vh}
/* ==========================================================================
   SUR TÉLÉPHONE, DEUX ÉCRANS DE COFFRET FONT UN ÉCRAN DE VIDE
   --------------------------------------------------------------------------
   Les 210 vh servent à dérouler la séquence du coffret : entrée, ouverture,
   présentation. Au 1440 le coffret occupe la moitié droite pendant tout ce
   temps et il y a quelque chose à regarder. Au 390, la colonne de texte prend
   toute la largeur, le coffret passe derrière elle et la seconde moitié de la
   section est un écran noir — mesuré à 91 % de la page. La séquence tient
   très bien en un écran et demi : elle est simplement jouée plus vite, et
   c'est le sens du réglage `stage()` qui la borne, pas la hauteur du bloc.
   Même raisonnement pour l'acte final et pour la respiration des blocs
   collés : ce qui aère une composition large étire une colonne étroite. */
@media (max-width:899px){
  #pack{min-height:150vh}
  .hold{padding:7vh 0}
}
.col{max-width:430px}
.eyebrow{color:var(--accent-txt);margin-bottom:20px}
/* LE BANDEAU DU HERO RÉSERVE DEUX LIGNES, MÊME QUAND IL N'EN OCCUPE QU'UNE.
   Il nomme quatre références et il est écrit dans une police chargée : tant
   qu'elle n'est pas là, les métriques de repli décident du nombre de lignes.
   À mille vingt-quatre points de large, il passait d'une ligne à deux au
   moment où la police arrivait — et le titre, le paragraphe et les boutons
   descendaient d'un cran. Mesuré : 0,059 de décalage, sur un budget de 0,1.
   Deux lignes réservées, et l'arrivée de la police ne déplace plus rien. */
#hero .eyebrow{min-height:2.4em}
h1{font-size:clamp(40px,5.6vw,88px);font-weight:200;letter-spacing:-.012em;text-wrap:balance}
h2{font-size:clamp(34px,4.6vw,72px)}
h3{font-size:clamp(24px,2.5vw,38px);font-weight:300}
.lead{margin-top:22px;color:var(--muted);font-size:clamp(15px,1.25vw,18px);max-width:42ch}
.lead b{color:var(--ink);font-weight:500}
.lead--lead{color:var(--ink);font-size:clamp(17px,1.5vw,21px);margin-top:26px}
.cta-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:38px}
/* ==========================================================================
   DEUX CANAUX DE CONTACT, LISIBLES AVANT D'ÊTRE CLIQUÉS
   --------------------------------------------------------------------------
   Deux boutons côte à côte se lisent comme « le principal et l'autre ». Ici ce
   ne sont pas deux versions d'une même action : ce sont deux INTENTIONS. Elles
   ont donc chacune leur colonne, et chaque colonne s'ouvre par la question à
   laquelle elle répond — une ligne mono, du même corps que les intitulés du
   site, puis le bouton, puis le micro-texte qui précise le régime de réponse.
   Sous 640 px les deux colonnes s'empilent : à cette largeur, deux colonnes
   de boutons donnent deux boutons trop étroits pour leur libellé.
   ========================================================================== */
.cta-canaux{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:26px 22px;margin-top:34px}
@media (max-width:640px){ .cta-canaux{grid-template-columns:1fr;gap:22px} }
.cta-canal{display:flex;flex-direction:column;align-items:flex-start;gap:10px}
.cta-q{margin:0;font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--faint)}
.cta-micro{margin:0;font-size:12px;color:var(--muted);line-height:1.4}
/* L'ICÔNE EST DESSINÉE DANS LA FEUILLE DE STYLE, PAS DANS LE BOUTON.
   Le moteur de traduction remplace le CONTENU des éléments `data-i18n` : une
   icône posée à l'intérieur disparaîtrait au premier changement de langue.
   Un masque en `::before` survit à la traduction, ne coûte aucune requête, et
   prend la couleur qu'on lui donne. */
.btn-wa::before,.btn-mail::before{content:"";width:16px;height:16px;flex:none;
  background:currentColor;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain}
.btn-wa::before{-webkit-mask-image:var(--ico-wa);mask-image:var(--ico-wa);
  background:var(--wa)}
.btn-wa:hover::before,.btn-wa:focus-visible::before{background:var(--wa-clair)}
.btn-mail::before{-webkit-mask-image:var(--ico-mail);mask-image:var(--ico-mail)}
/* Le canal rapide porte le vert de WhatsApp sur sa bordure — reconnaissable
   au premier coup d'oeil — sans devenir un bouton vert : le fond reste celui
   de la marque, et c'est la marque qui tient la page. */
.btn-wa{border-color:color-mix(in srgb,var(--wa) 52%,transparent);
  background:color-mix(in srgb,var(--wa) 12%,transparent)}
.btn-wa:hover,.btn-wa:focus-visible{background:color-mix(in srgb,var(--wa) 22%,transparent);
  border-color:var(--wa);color:var(--ink)}
.cta-row--mid{margin:26px 0 6px}
/* Les deux liens de vérification sous les boutons d'offre : disponibles, et
   visiblement secondaires. Ce ne sont pas des décisions d'achat. */
.hero-liens{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-top:16px;
  font-family:"JetBrains Mono";font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
/* 40 px : c'est le plancher de cible du dépôt, et il vaut aussi pour un
   lien discret — un lien qu'on rate au doigt n'est pas discret, il est raté. */
.hero-liens a{color:var(--muted);border-bottom:1px solid var(--line);
  padding-bottom:3px;min-height:40px;display:inline-flex;align-items:center}
.hero-liens a:hover{color:var(--ink);border-bottom-color:var(--ink)}

/* hero */
#hero{min-height:112vh}
#hero .col{max-width:none}
#hero h1{max-width:12ch}
#hero .lead{max-width:48ch}
#hero .tagline{margin-top:22px}
.tagline{margin-top:26px;color:var(--gold-lt);font-family:"JetBrains Mono";
  font-size:10px;letter-spacing:.34em;text-transform:uppercase}
/* L'INVITE À DÉFILER A ÉTÉ RETIRÉE, ET SON STYLE AVEC.
   `.scrollcue` — le trait animé et le mot « Défiler » sous le hero — ne
   correspond plus à aucun élément : un écran qui demande simplement de
   continuer à défiler ne sert ni le désir, ni la compréhension, ni l'achat.
   La boutique commence à l'écran suivant et se présente toute seule. */
/* bandeau de repères du hero : quatre faits, aucune promesse */
.trust{list-style:none;margin:34px 0 0;padding:0;display:grid;gap:1px;
  grid-template-columns:repeat(auto-fit,minmax(132px,1fr));
  background:var(--line);border:1px solid var(--line);border-radius:14px;overflow:hidden;
  max-width:660px}
.trust li{background:rgba(12,11,16,.90);padding:15px 16px;
  display:grid;gap:4px}
.trust b{font-weight:400;font-size:13.5px}
.trust span{color:var(--muted);font-size:11.5px;line-height:1.5}

/* etapes du systeme
   ONZE TEMPS EMPILES, PAS UNE LISTE DE ONZE.
   La liste tenait tant qu'il y avait cinq etapes. A onze, elle depassait
   l'ecran : le visiteur lisait l'etape active au milieu d'un mur de texte
   grise, et sur mobile l'etape active pouvait etre hors champ. Les etapes
   occupent donc la MEME case : une seule est lisible a la fois, celle dont la
   camera parle. Le bloc garde une hauteur stable, ce qui evite en prime le
   decalage de mise en page a chaque changement. */
/* etapes du systeme — TROIS A L'ECRAN, PAS UNE.
   Une seule etape affichee laissait l'acte a 11 % de surface occupee : un
   titre et trois lignes sur neuf cents pixels de haut. Le visiteur y voyait
   une page vide, et il avait raison. La liste defile maintenant derriere une
   fenetre : l'etape expliquee est nette, la precedente sort par le haut, la
   suivante entre par le bas. Il y a toujours quelque chose qui entre ou qui
   sort, sans une ligne de texte de plus. */
.steps{position:relative;margin-top:30px;height:270px;overflow:hidden;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 15%,#000 76%,transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0,#000 15%,#000 76%,transparent 100%)}
.steps-piste{display:grid;gap:22px;
  transform:translate3d(0,calc(var(--etape,0) * -1px),0);
  transition:transform .42s var(--ease)}
.step{display:grid;grid-template-columns:34px 1fr;gap:18px;
  opacity:.18;transition:opacity .42s var(--ease)}
.step.pres{opacity:.40}
.step.on{opacity:1}
.step b{font-family:"JetBrains Mono";font-size:10px;letter-spacing:.16em;color:var(--accent-txt)}
.step p{color:var(--muted);font-size:14px;margin-top:5px}
/* LE DERNIER TEMPS PORTE L'ACTION.
   L'anatomie se terminait sur une description ; le visiteur qui venait de
   comprendre l'offre n'avait rien a cliquer et repartait chercher. Le lien
   herite de l'opacite de son temps : invisible tant que le temps n'est pas
   lu, il ne capte donc pas le clic avant d'etre lisible. */
.step-cta-row{display:flex;gap:18px;flex-wrap:wrap}
.step-cta{display:inline-flex;align-items:center;min-height:40px;
  margin-top:8px;font-family:"JetBrains Mono";
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--accent-txt);text-decoration:none;
  border-bottom:1px solid var(--line);padding-bottom:4px;
  transition:border-color .3s var(--ease)}
.step:not(.on) .step-cta{pointer-events:none}
.step-cta:hover{border-bottom-color:var(--accent-txt)}

/* le systeme en quatre temps : fiole, cartouche, insertion, stylo pret.
   Masque par defaut ; il ne prend la place des etapes qu'a son temps. */
/* `display:none` et non `visibility:hidden` : masquee par visibilite, la
   sequence garderait sa hauteur en permanence — quatre lignes de reserve sous
   les etapes, sur un ecran de telephone deja tenu. Elle ne prend donc sa place
   qu'a son temps, et l'animation d'entree remplace la transition. */
.seq{display:none;gap:14px;margin-top:30px;list-style:none;padding:0}
.seq.on{display:grid;animation:swapIn .3s var(--ease) both}
/* Le titre ET le corps dans UNE seule cellule.
   Ils etaient trois enfants directs d'une grille a deux colonnes : le corps du
   texte repartait donc a la ligne suivante, dans la colonne du numero — large
   de 26 px. Il s'affichait un mot par ligne. Une grille compte ses enfants,
   pas ses intentions. */
.seq li{display:grid;grid-template-columns:26px minmax(0,1fr);gap:16px;
  align-items:start}
.seq-n{font-family:"JetBrains Mono";font-size:10px;letter-spacing:.16em;
  color:var(--accent-txt);border:1px solid var(--line);border-radius:50%;
  width:26px;height:26px;display:grid;place-items:center}
.seq strong{display:block;font-size:14px}
.seq em{display:block;color:var(--muted);font-size:13px;font-style:normal;margin-top:3px}

/* echange de contenu dans la fiche : animation CSS a etat final garanti
   (un fondu pilote par tween peut rester bloque si l'echange est relance) */
@keyframes swapIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.swap{animation:swapIn .5s var(--ease) both}

/* fiche produit */
/* ---- cadre de lecture de la fiche ----------------------------------------
   `#sheetCol` est colle en haut de l'ecran. Sa hauteur est donc EXACTEMENT un
   ecran : tout ce qui depasserait serait definitivement hors du pli, puisque
   le bloc ne bouge plus. Le contenu, lui, monte a l'interieur pendant le
   temps de lecture du chapitre — c'est `--lect` qui le pilote, ecrit par le
   rendu a chaque image. */
#sheetCol{height:100vh;min-height:100vh;justify-content:flex-start;
  padding:0;overflow:hidden;position:sticky;top:0}
/* ---- LE PRODUIT SE CLIQUE, ET S'ACHÈTE ----------------------------------
   Calque sur la moitié qui porte la fiole, actif uniquement pendant le
   chapitre des références. `[hidden]` est REDÉCLARÉ : la règle du navigateur
   est un sélecteur d'attribut nu, un `display:grid` porté par un `#id` la bat
   toujours — le calque serait resté visible, et cliquable, sur toute la page. */
/* LA CARTE RESPIRE AVEC LE BOUTON FLOTTANT, ET L'ÉCART EST MESURÉ.
   Elle est centrée dans la moitié droite et collée au bas de l'écran : à
   1440, son bord droit arrivait à une trentaine de pixels de la pastille
   WhatsApp, et les deux se lisaient comme un seul amas. La zone réserve donc
   une gouttière à droite — la carte glisse vers la gauche, le bouton flottant
   ne bouge pas d'un pixel.
   CETTE GOUTTIÈRE A ÉTÉ UN `clamp(24px, 7vw, 132px)`, ET C'ÉTAIT FAUX.
   Une largeur en pourcentage d'écran ne peut pas connaître la largeur d'un
   bouton dont le libellé change avec la langue. Mesuré à 1024 px : la pastille
   allait de 853 à 1003 px, la carte jusqu'à 952 — 99 px de recouvrement. Le
   réglage tombait juste à 1440 et nulle part ailleurs ; c'est pourquoi il
   avait l'air correct.
   La gouttière vaut maintenant l'écart du bord (`--vc-gap`), plus la largeur
   RÉELLE de la pastille (`--vc-l`, écrite par vp-contact.js après mesure),
   plus l'air qu'il leur faut entre elles. Le repli de 150 px couvre le cas —
   théorique — où le script n'aurait pas encore mesuré : il vaut mieux trop
   d'air qu'un recouvrement. */
#produitZone{position:fixed;z-index:4;top:var(--nav);bottom:0;right:0;
  width:min(50%,760px);display:grid;align-content:end;justify-items:center;
  /* L'AIR ENTRE LA CARTE ET LA PASTILLE A ÉTÉ RECALCULÉ APRÈS LE RESSERREMENT.
     La carte est passée de 182 à 140 px de haut. Collée au bas de la zone,
     elle est donc DESCENDUE de quarante pixels — et elle est entrée dans la
     bande verticale de la pastille flottante, qui jusque-là passait au-dessus
     d'elle. Relevé par tests/layout.js à 940 px : 15 px entre les deux, sous
     le seuil de 16. Ce n'est pas la largeur qui a changé, c'est la hauteur ;
     la correction est quand même ici, parce que c'est la seule dimension
     qu'on puisse rendre sans regrandir la carte. */
  padding-right:calc(var(--vc-gap) + var(--vc-l,150px) + clamp(22px,2.6vw,44px));
  padding-bottom:clamp(22px,6vh,64px)}
#produitZone[hidden]{display:none}
/* Le lien couvre toute la zone, SOUS la carte : on peut cliquer la fiole
   elle-même, mais un clic sur « Ajouter » ne navigue pas. */
#produitLien{position:absolute;inset:0;z-index:0;cursor:pointer}
/* LE RAYON EST CELUI D'UNE CARTE, PAS CELUI D'UN ONGLET.
   À 18 px sur une carte de 385 px de large, l'arc est si court qu'il se lit
   comme un angle légèrement adouci : le propriétaire l'a relevé sur capture —
   « bordure irrégulière, forme cassée ». Le coin contient d'ailleurs des
   pastilles entièrement rondes, ce qui accentue la rupture. Le rayon passe
   donc à 26 px : l'arc devient assez long pour se lire comme une courbe
   continue, la carte garde exactement sa taille, sa position, son fond et son
   contenu. Rien d'autre ne bouge, et cela ne coûte pas une image par seconde. */
/* ELLE EST COMPACTE, ET C'EST UNE MESURE, PAS UN GOÛT.
   Relevé par le propriétaire : la carte touchait la fiole. Mesuré à 1440, le
   bord haut de la carte arrivait à une vingtaine de pixels du bas du flacon —
   les deux se lisaient comme un seul bloc, et la carte, haute de 182 px,
   mangeait le tiers bas du produit qu'elle est censée vendre.
   Tout est resserré d'un cran : les marges intérieures, le nom, les pastilles
   et les deux boutons. Rien n'est retiré — le nom, la concentration, le prix,
   le choix de dosage et les deux appels à l'action sont tous là — et les
   boutons gardent une cible tactile de 40 px, le minimum au doigt. La carte
   rétrécit donc vers le HAUT, puisqu'elle reste collée au bas de la zone :
   c'est cet espace-là qui devient la respiration autour de la fiole. */
.pz-carte{position:relative;z-index:1;display:grid;justify-items:center;gap:2px;
  padding:11px 16px 12px;border-radius:20px;border:1px solid var(--line);
  background:rgba(11,10,15,.90);max-width:min(330px,100%);min-width:0;
  transform:translateY(8px);opacity:0;transition:.4s var(--ease)}
#produitZone:not([hidden]) .pz-carte{transform:none;opacity:1}
.pz-carte b{font-size:16px;font-weight:500;letter-spacing:.01em;line-height:1.2}
.pz-meta{font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);line-height:1.3}
/* LE CHOIX DE CONCENTRATION, DANS LA CARTE QUI VEND.
   Mêmes pastilles que la boutique — `.bt-mg` / `.bt-mgb`, définies une seule
   fois dans vp-page.css — pour que le geste soit le même partout. Elles sont
   centrées comme le reste de la carte, et la carte ne s'élargit pas pour
   elles : deux à cinq pastilles de deux chiffres tiennent dans sa largeur.
   `display:flex` bat `[hidden]` : sans la règle qui suit, une référence à
   concentration unique afficherait un groupe vide. */
.pz-mg{margin-top:1px;display:flex;justify-content:center}
.pz-mg[hidden]{display:none}
/* DANS LA CARTE, LES PASTILLES SONT PLUS SERRÉES QU'AILLEURS.
   Retatrutide en porte cinq. À la largeur de la carte, elles passaient sur
   deux rangs et lui rendaient les 35 px qu'on venait de lui retirer : la
   référence la plus riche du catalogue était aussi celle dont la carte
   touchait le plus la fiole. Resserrées, les cinq tiennent sur un rang. */
.pz-mg .bt-mg{justify-content:center;gap:4px;margin:0}
.pz-mg .bt-mgb{padding:4px 8px;font-size:10.5px;min-height:0}
@media (pointer:coarse){ .pz-mg .bt-mgb{min-height:34px;padding:7px 9px;font-size:11px} }
/* Le prix de la variante allumée n'est pas toujours arrêté. La carte le DIT,
   elle ne reprend jamais celui d'une voisine. */
/* 11 px, pas 10,5 : c'est le plancher de lisibilité que `tests/layout.js`
   fait respecter partout dans le dépôt, et il ne connaît pas d'exception pour
   les blocs masqués — à juste titre, un bloc masqué finit par s'afficher. */
.pz-note{margin:1px 0 0;font-family:"JetBrains Mono";font-size:11px;
  letter-spacing:.04em;color:var(--gold-lt);text-align:center;max-width:26ch;
  line-height:1.35}
.pz-note[hidden]{display:none}
/* LES DEUX APPELS RESTENT SUR UN RANG.
   À la largeur resserrée, ils passaient l'un sous l'autre et rendaient à la
   carte les trente pixels qu'on venait de lui retirer — la carte remontait
   alors jusqu'à toucher la fiole, c'est-à-dire exactement le défaut à
   corriger. `nowrap` et un pas de lettre plus court les gardent côte à côte ;
   la cible tactile reste à 40 px de haut. */
/* LE RETOUR À LA LIGNE EST AUTORISÉ, MAIS IL N'ARRIVE QUE S'IL LE FAUT.
   `nowrap` empêchait la carte de RÉTRÉCIR : sa largeur minimale devenait celle
   des deux boutons côte à côte, elle débordait de sa gouttière, et à 940 px
   elle recouvrait la pastille de contact de 3 px — relevé par tests/layout.js.
   Avec `wrap` et une largeur bornée au conteneur, les deux boutons restent sur
   un rang partout où il y a la place — c'est le cas dès 1024 — et se replient
   là où il n'y en a pas, au lieu de pousser la carte hors de son cadre. */
.pz-actions{display:flex;gap:8px;margin-top:7px;flex-wrap:wrap;
  justify-content:center}
/* 11 px, PAS 10 : c'est le plancher de lisibilité que `tests/layout.js` fait
   respecter partout dans le dépôt, et resserrer une carte n'est pas une raison
   d'y déroger — un appel à l'action qu'on ne lit pas ne sert à rien. Ce sont
   le pas de lettre et les marges intérieures qui absorbent la différence. */
.pz-actions .btn{min-height:40px;padding:9px 11px;font-size:11px;
  letter-spacing:.04em;white-space:nowrap}
.pz-actions .btn[hidden]{display:none}
/* Pas de carte flottante sur téléphone : la fiche couvre le produit, il n'y a
   rien à cliquer dessous. L'achat est alors DANS la fiche, sous le nom. */
@media (max-width:900px){ #produitZone{display:none} }

/* ---- L'ACHAT, SOUS LE NOM DE LA RÉFÉRENCE ------------------------------- */
/* Le résumé fait partie du bloc d'achat, pas de la fiche qui défile. */
/* MÊME RAISON QUE LE BLOC D'ACHAT, ET C'ÉTAIT LA VRAIE SOURCE DU SAUT.
   Ce résumé vient du catalogue et CHANGE à chaque référence : mesuré aux
   quatre, il fait deux lignes pour GHK-Cu et IGF-1 LR3, trois pour Retatrutide
   et BPC-157. Vingt-deux pixels d'écart, et toute la fiche descendait d'autant
   au moment où l'on passe d'une référence à la suivante — 0,112 de décalage
   cumulé sur un budget de 0,1, à lui seul. Trois lignes sont donc réservées,
   la hauteur du plus long : un résumé court laisse un peu d'air, aucun ne
   déplace ce qui le suit. */
/* ==========================================================================
   LES AXES ÉTUDIÉS — LE TROISIÈME ÉLÉMENT DE LA COLONNE, ET IL SE LIT SEUL
   --------------------------------------------------------------------------
   Il y avait ici un BLOC D'ACHAT — concentration, pureté, prix — et sa place
   était réservée par une `min-height` de 204 px pour qu'il n'y ait pas de
   saut quand le catalogue arrivait. Tout ce bloc est monté dans la carte
   posée sur le produit : à gauche on comprend, à droite on achète.
   Ce qui prend sa place répond à la seule question que le visiteur se pose en
   arrivant sur une molécule qu'il ne connaît pas. Une liste, quatre lignes au
   plus, pas de pastilles : une pastille se survole, une liste se LIT, et
   c'est de lecture qu'il s'agit ici.
   LA RÉSERVE DE HAUTEUR RESTE, pour la même raison qu'avant : la liste vient
   d'un fichier chargé après le premier rendu, et sans réserve tout ce qui la
   suit descendrait sous les yeux du visiteur. Quatre lignes plus le titre. */
/* ==========================================================================
   LE BLOC D'ACHAT DE LA FICHE N'EXISTE QUE LÀ OÙ IL N'Y A PAS DE « DROITE »
   --------------------------------------------------------------------------
   `#produitZone` — la carte posée sur le produit — est masquée en dessous de
   900 px : sur téléphone la fiche couvre le produit, il n'y a rien à cliquer
   dessous. Ce bloc est son COMPLÉMENT EXACT, masqué au-dessus du même seuil.
   Les deux ne sont donc jamais visibles ensemble : un seul endroit où l'on
   achète, sur tous les écrans, et la règle « à gauche on comprend, à droite
   on achète » reste entière partout où il y a une droite.
   Sans lui, une fiole ne serait ni choisissable ni achetable depuis l'accueil
   sur téléphone : la bande boutique des fioles a disparu quand les huit
   références sont entrées dans le récit. */
.sheet-buy{display:none}
@media (max-width:900px){
  /* LA PLACE EST RÉSERVÉE AVANT QUE LE CATALOGUE N'ARRIVE.
     Le bloc est rempli après le premier rendu : vide il ne prenait rien,
     rempli il prenait 280 px, et TOUT ce qui le suit dans la fiche descendait
     d'autant sous les yeux du visiteur. Mesuré sans réserve : 0,1025 de
     décalage cumulé au 390, deux fois le budget entier de la page, et
     `tests/layout.js` refuse à juste titre. La réserve est accordée sur le
     bloc le PLUS HAUT — Retatrutide, cinq concentrations sur deux rangs —
     sans quoi passer d'une référence à l'autre ferait sauter la fiche. */
  .sheet-buy{display:grid;gap:10px;flex:none;margin-top:14px;padding-top:14px;
    border-top:1px solid var(--line);position:relative;z-index:1;
    background:var(--night);padding-bottom:14px;min-height:300px}
  .sb-prix{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
  .sb-prix b{font-size:24px;font-weight:500;letter-spacing:.01em}
  .sb-prix span{font-family:"JetBrains Mono";font-size:11px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--muted)}
  .sb-prix[hidden]{display:none}
  .sb-mg-t{font-size:10px;letter-spacing:.2em;text-transform:uppercase;
    color:var(--faint);margin:0}
  .sb-mg-note{font-family:"JetBrains Mono";font-size:11px;letter-spacing:.06em;
    color:var(--gold-lt);margin:0}
  .sb-actions{display:flex;gap:10px;flex-wrap:wrap}
  .sb-actions .btn{min-height:46px}
  .sb-note{font-family:"JetBrains Mono";font-size:11px;letter-spacing:.06em;
    color:var(--faint);line-height:1.5}
}
/* ---- « CE QUE C'EST », SOUS LE NOM -------------------------------------
   Le bloc occupe la place qu'occupaient la concentration et le prix. Sa
   réserve de hauteur ne change pas : c'est la même zone, au même endroit,
   avec un autre contenu — passer d'une référence à l'autre ne doit toujours
   pas faire sauter la fiche. */
/* Dans le flux, il n'a plus de hauteur à réserver pour lui-même : ce qui le
   suit le suit vraiment, et un changement de référence ne peut plus faire
   sauter un bloc épinglé. La réserve reste mesurée par `tests/layout.js`. */
.sheet-quoi{margin-top:14px;padding-top:14px;
  border-top:1px solid var(--line)}
.sheet-quoi[hidden]{display:none}
.quoi-clair{margin:0 0 7px;color:var(--ink);
  font-size:clamp(14.5px,1.6vw,16.5px);line-height:1.45;max-width:44ch}
.quoi-clair[hidden]{display:none}
.quoi-def{margin:12px 0 0;color:var(--muted);font-size:13.5px;line-height:1.55;
  max-width:46ch}
.quoi-axes{margin-top:12px}
.quoi-axes[hidden]{display:none}
.axes-h{font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--faint);margin:0 0 9px;font-weight:400}
.axes{list-style:none;margin:0;padding:0;display:grid;gap:6px;max-width:44ch}
/* La puce est dessinée, pas héritée : un `list-style` ne se colore pas, et un
   point gris au milieu d'une colonne sombre disparaît. */
.axes li{position:relative;padding-left:16px;color:var(--ink);
  font-size:clamp(13.5px,1.45vw,15px);line-height:1.5}
.axes li::before{content:"";position:absolute;left:0;top:.62em;
  width:5px;height:5px;border-radius:50%;
  background:var(--accent-txt)}

/* LA PASTILLE DE PURETÉ. Or, compacte, lisible d'un coup d'œil — c'est une
   preuve, elle doit se voir ; ce n'est pas une promesse, elle ne prend pas la
   place du prix. Elle n'existe dans le DOM que si le certificat porte une
   valeur : aucune règle ici ne peut la faire apparaître à vide. */
.pur{display:inline-flex;align-items:baseline;gap:7px;padding:4px 10px;
  border:1px solid color-mix(in srgb,var(--gold) 38%,var(--line));border-radius:999px;
  background:color-mix(in srgb,var(--gold) 7%,transparent);width:fit-content}
.pur b{font-family:"JetBrains Mono";font-size:11.5px;letter-spacing:.1em;color:var(--gold-lt)}
.pur i{font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.14em;
  text-transform:uppercase;font-style:normal;color:var(--faint)}
.bt-carte .pur{margin-top:2px}

/* ---- LA CARTE D'EN-TÊTE SE TOUCHE --------------------------------------- */
.sheet-tete{padding:10vh 0 0;flex:none;display:block;text-decoration:none;
  position:relative;color:inherit}
.sheet-tete h2{margin-top:6px}
.tete-fleche{position:absolute;right:0;bottom:2px;font-size:20px;
  color:var(--accent-txt);opacity:0;transition:.35s var(--ease)}
.tete-lien .tete-fleche{opacity:.75}
.tete-lien:hover .tete-fleche,.tete-lien:focus-visible .tete-fleche{
  opacity:1;transform:translateX(4px)}
.tete-lien:hover h2{color:var(--accent-txt)}
.sheet-vue{flex:1;min-height:0;overflow:hidden;display:flex;
  padding:18px 0 4vh;align-items:flex-start}
.sheet-def{width:100%;transform:translate3d(0,0,0);will-change:transform}
/* Repere de lecture : trois points qui s'effacent quand le bas est atteint. */
.sheet-plus{position:absolute;left:0;bottom:2.2vh;display:flex;justify-content:center;
  width:100%;pointer-events:none;opacity:0;transition:opacity .25s var(--ease)}
.sheet-plus span{width:22px;height:3px;border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--accent-txt),transparent)}
@media (prefers-reduced-motion:reduce){ .sheet-plus{transition:none} }

.sheet{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:16px;overflow:hidden;max-width:520px;margin-top:34px}
.sheet section{background:rgba(11,10,15,.95);padding:22px 24px}
.sheet h3, .sheet h4{margin:0 0 9px;font-family:"JetBrains Mono";font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--faint);font-weight:400}
.sheet p{font-size:14px;color:var(--muted)}
/* Domaines de recherche : des DOMAINES D'ETUDE, jamais des indications.
   Ils sont donc traites comme des mots-cles, pas comme des benefices. */
.chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:11px}
/* 11 px, pas 10. Le plancher de lisibilité du dépôt vaut aussi pour les
   domaines de recherche : ils étaient relevés « sous 11 px » par l'audit de
   mise en page depuis leur création, et un bloc `@media (pointer: coarse)` les
   rattrapait sur téléphone — donc jamais sur l'écran où on les lit le plus. */
.chips span{font-family:"JetBrains Mono";font-size:11px;letter-spacing:.10em;
  text-transform:uppercase;color:var(--muted);border:1px solid var(--line);
  border-radius:999px;padding:5px 10px;line-height:1}
/* Fiches techniques : deux colonnes, et un champ non renseigne le DIT. */
.specs{display:grid;grid-template-columns:auto minmax(0,1fr);gap:6px 16px;margin-top:10px}
.specs dt{font-family:"JetBrains Mono";font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);opacity:.75;align-self:baseline}
.specs dd{margin:0;font-size:13.5px;color:var(--ink)}
.specs dd.vide{color:var(--muted);opacity:.62;font-style:italic}

/* ---- fiole ou stylo : deux objets, deux achats -----------------------------
   Deux cartes cote a cote sur grand ecran, empilees sur telephone. Tout le
   contenu vient du catalogue ; un champ non renseigne le DIT. */
.sys{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
  gap:16px;margin:22px 0 26px}
.sys-carte{border:1px solid var(--line);border-radius:14px;padding:22px 22px 18px;
  background:rgba(255,255,255,.02)}
.sys-carte h3{margin:6px 0 10px;font-size:19px;font-weight:400}
.sys-carte > p{color:var(--muted);font-size:14px;line-height:1.6}
.sys-carte .specs{margin-top:14px}
.sys-carte--pen{border-color:rgba(196,152,92,.34)}
/* ==========================================================================
   « FIOLE OU STYLO » OCCUPAIT LE QUART GAUCHE D'UN ÉCRAN DE 1440
   --------------------------------------------------------------------------
   L'acte « Offres » n'a pas de scène 3D — il ne porte pas `data-3d`. Sa
   colonne de texte, elle, gardait la largeur des actes qui EN ONT une : 430 px
   calés à gauche, la moitié droite laissée au décor. Résultat mesuré : les
   deux cartes s'empilaient l'une sous l'autre sur 851 px de haut, dans le
   quart gauche, et 940 px de large ne portaient rien.
   La colonne s'ouvre donc ici, et elle seule. Le TEXTE garde sa largeur de
   lecture — un titre et un chapô ne se lisent pas sur 1 300 px — mais la
   comparaison des deux formats, qui est une composition et non un paragraphe,
   prend toute la place : deux cartes côte à côte, la hauteur du bloc divisée
   par deux, et un défilement qui avance au lieu de descendre dans le vide.
   ========================================================================== */
/* LES DEUX FORMATS, À DROITE DU TEXTE.
   Une fiole et un stylo, pris aux rendus de repli déjà produits — aucun
   nouveau modèle, aucune nouvelle animation permanente. Ils ENTRENT quand
   l'acte arrive : opacité et translation, deux propriétés que le compositeur
   traite sans repeindre, jouées UNE fois. La respiration qui suit est une
   translation de quelques pixels, coupée dès que l'acte quitte l'écran et
   supprimée en mouvement réduit — voir `#acqVue` dans vp.js. */
/* LA COMPOSITION RESPIRE, ET ELLE RÉPOND AU SURVOL.
   Le flacon occupait 44 % de la largeur du cadre : à côté d'un stylo qui n'en
   prend que 26, il écrasait l'ensemble et sortait du cadre par le haut. Il
   passe à 38 %, le stylo à 28 : les deux objets tiennent dans le même cadre et
   l'espace entre eux redevient lisible.
   `pointer-events` était coupé sur tout le cadre — c'est ce qui rendait toute
   interaction impossible. Il est rétabli SUR LES OBJETS uniquement : le cadre
   lui-même ne capte rien et ne gêne aucun clic derrière lui. */
.acq-vue{margin:0;position:relative;justify-self:center;align-self:center;
  width:min(430px,100%);aspect-ratio:1/.92;pointer-events:none}
.acq-obj{position:absolute;bottom:0;height:auto;filter:drop-shadow(0 26px 44px rgba(0,0,0,.55));
  opacity:0;transition:opacity .8s var(--ease),transform .9s var(--ease),filter .45s var(--ease)}
.acq-obj--fiole{left:3%;width:38%;transform:translateY(26px) rotate(-3deg)}
.acq-obj--stylo{right:0;width:28%;transform:translateY(34px) rotate(9deg)}
.acq-vue.on .acq-obj--fiole{opacity:1;transform:translateY(0) rotate(-3deg)}
.acq-vue.on .acq-obj--stylo{opacity:1;transform:translateY(0) rotate(9deg);transition-delay:.14s}

/* ==========================================================================
   MICRO-INTERACTION PREMIUM — UNE ÉLÉVATION, PAS UN GADGET.
   --------------------------------------------------------------------------
   Trois choses seulement, et c'est volontaire : l'objet MONTE de quelques
   pixels, son ombre portée s'allonge comme celle d'un objet qu'on soulève, et
   une lueur très faible passe dessus. Pas de rotation, pas de rebond, pas de
   changement d'échelle : un produit qui gigote au passage de la souris cesse
   d'être un produit et devient une animation.

   `@media (hover:hover)` : sur un écran tactile il n'y a pas de survol, et un
   état de survol collé au premier appui est le pire des deux mondes. Le
   mouvement d'apparition, lui, existe déjà sur mobile — c'est l'équivalent
   naturel demandé, et il ne coûte rien de plus.

   `transform` et `filter` seulement : ni l'un ni l'autre ne déclenche de
   calcul de mise en page. */
.acq-obj{pointer-events:auto;cursor:default}
@media (hover:hover) and (pointer:fine){
  .acq-vue.on .acq-obj--fiole:hover{
    transform:translateY(-9px) rotate(-3deg);
    filter:drop-shadow(0 38px 56px rgba(0,0,0,.62)) drop-shadow(0 0 26px rgba(168,140,255,.28));
    animation-play-state:paused}
  .acq-vue.on .acq-obj--stylo:hover{
    transform:translateY(-9px) rotate(9deg);
    filter:drop-shadow(0 38px 56px rgba(0,0,0,.62)) drop-shadow(0 0 26px rgba(232,200,140,.30));
    animation-play-state:paused}
}
@media (prefers-reduced-motion:reduce){
  .acq-vue.on .acq-obj--fiole:hover,.acq-vue.on .acq-obj--stylo:hover{transform:none}
}
@media (prefers-reduced-motion:no-preference){
  .acq-vue.on .acq-obj--fiole{animation:acqFlot 9s var(--ease) 1.1s infinite}
  .acq-vue.on .acq-obj--stylo{animation:acqFlot 11s var(--ease) 1.5s infinite reverse}
}
@keyframes acqFlot{
  0%,100%{translate:0 0}
  50%{translate:0 -9px}
}
@media (max-width:999px){
  .acq-vue{width:min(320px,86%);margin:26px auto 0}
}
/* SANS CARTE GRAPHIQUE, LA PLACE EST DÉJÀ PRISE.
   Les rendus de repli de la scène — le flacon détouré — traversent cet acte :
   c'est la composition validée, et elle occupe exactement cette moitié droite.
   Y superposer la composition ci-dessus donnerait DEUX flacons dans le même
   quart d'écran. Elle ne sert donc que là où la scène 3D s'efface : sur les
   machines qui l'ont, `#acquire` ne porte pas `data-3d`, le canevas y est
   masqué, et la moitié droite est réellement vide. */
.vp-sans-3d .acq-vue{display:none}
@media (min-width:1000px){
  #acquire .hold.col{max-width:none}
  #acquire .acq-tete{display:grid;grid-template-columns:minmax(0,430px) minmax(0,1fr);
    gap:clamp(28px,5vw,80px);align-items:center;max-width:1180px}
  #acquire .acq-txt > .eyebrow,
  #acquire .acq-txt > h2,
  #acquire .acq-txt > .lead,
  #acquire .acq-txt > .cta-row,
  #acquire .hold.col > .acq-foot{max-width:430px}
  /* `auto-fit` sur 1 180 px ouvrirait QUATRE pistes de 280 et laisserait les
     deux cartes serrées à gauche : le défaut qu'on corrige, en plus étroit.
     Deux colonnes, écrites. */
  #acquire .sys{grid-template-columns:1fr 1fr;max-width:1180px;gap:22px}
}
/* ==========================================================================
   ACTE « ENTRER EN CONTACT » — LE PRODUIT OCCUPE LA MOITIÉ QUI ÉTAIT VIDE.
   --------------------------------------------------------------------------
   Même grille que `#acquire` : texte à gauche, objet à droite, une seule
   image, déjà produite et déjà en cache. Sous 1000 px la colonne redevient
   unique et l'objet passe dessous, plus petit — sur un téléphone, un stylo
   pleine largeur volerait la place des deux boutons, qui sont l'objet de la
   section.
   L'APPARITION SUIT LE MÊME OBSERVATEUR que la composition des offres
   (`vp.js`, `acqVue`) : une classe, aucune boucle, aucune image de rendu. */
/* LE CADRE EST DIMENSIONNÉ PAR SA HAUTEUR, PAS PAR SA LARGEUR.
   Réglé en largeur, l'objet — très allongé — dépassait par le haut et sortait
   du cadre : c'est ce qu'on voyait au premier rendu. On borne donc la hauteur,
   et la largeur suit le rapport du rendu. */
.cta-vue{margin:0;position:relative;justify-self:center;align-self:center;
  width:min(300px,100%);height:clamp(280px,42vh,420px);pointer-events:none}
.cta-obj{position:absolute;bottom:0;right:14%;height:100%;width:auto;max-width:none;
  filter:drop-shadow(0 26px 44px rgba(0,0,0,.55));
  opacity:0;transform:translateY(30px) rotate(7deg);
  transition:opacity .8s var(--ease),transform .9s var(--ease),filter .45s var(--ease);
  pointer-events:auto}
.cta-vue.on .cta-obj{opacity:1;transform:translateY(0) rotate(7deg)}
@media (prefers-reduced-motion:no-preference){
  .cta-vue.on .cta-obj{animation:acqFlot 10s var(--ease) 1.2s infinite}
}
@media (hover:hover) and (pointer:fine){
  .cta-vue.on .cta-obj:hover{transform:translateY(-9px) rotate(7deg);
    filter:drop-shadow(0 38px 56px rgba(0,0,0,.62)) drop-shadow(0 0 26px rgba(232,200,140,.30));
    animation-play-state:paused}
}
@media (min-width:1000px){
  #cta .hold.col{max-width:none}
  #cta .cta-tete{display:grid;grid-template-columns:minmax(0,560px) minmax(0,1fr);
    gap:clamp(28px,5vw,80px);align-items:center;max-width:1180px}
  #cta .cta-txt > .eyebrow,#cta .cta-txt > h2,
  #cta .cta-txt > .lead,#cta .cta-txt > .cta-row,
  #cta .cta-txt > .cta-canaux{max-width:560px}
}
@media (max-width:999px){
  .cta-vue{width:min(190px,60%);height:clamp(200px,30vh,280px);margin:30px auto 0}
}

/* passerelle fiole -> stylo, posee sur la fiche produit */
/* 11,5 px et non 10,5 : sous onze pixels, un lien ne se lit pas a bout de
   bras — l'audit de mise en page le refuse, et il a raison. */
.cross{display:inline-flex;align-items:center;gap:8px;margin-top:10px;
  font-family:"JetBrains Mono";font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent-txt);text-decoration:none;
  border-bottom:1px solid rgba(255,255,255,.16);padding-bottom:4px;min-height:40px}
.cross::after{content:"→";font-family:inherit}
.cross:hover,.cross:focus-visible{color:var(--ink);border-color:var(--accent-txt)}
#pAcq{display:flex;flex-direction:column;align-items:flex-start;gap:4px}
.sheet-add{margin-top:10px}

/* ---- approfondir : le detail s'ouvre a la demande -------------------------
   Une lecture au defilement ne peut pas etre plus courte que son contenu :
   tout ce qu'on ajoute a la fiche allonge mecaniquement le chapitre. Ce bloc
   est la reponse — l'essentiel d'emblee, le detail sur un geste. */
.fiche-plus{margin-top:14px}
.fiche-plus > summary{list-style:none;cursor:pointer;display:inline-flex;
  align-items:center;gap:9px;font-family:"JetBrains Mono";font-size:11.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  border:1px solid var(--line);border-radius:999px;padding:10px 16px;
  min-height:40px;box-sizing:border-box;transition:color .25s var(--ease),border-color .25s var(--ease)}
.fiche-plus > summary::-webkit-details-marker{display:none}
.fiche-plus > summary::after{content:"";width:7px;height:7px;flex:none;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .25s var(--ease)}
.fiche-plus[open] > summary::after{transform:translateY(1px) rotate(-135deg)}
.fiche-plus > summary:hover,.fiche-plus > summary:focus-visible{color:var(--ink);border-color:var(--accent-txt)}
.fiche-plus .sheet{margin-top:12px}
/* Fiche depliee : le cadre redevient un bloc qui se lit normalement. Le
   contenu n'est plus pilote par la position de page — il a sa propre barre. */
#sheetCol.fiche-ouverte .sheet-vue{overflow-y:auto;overscroll-behavior:contain}
#sheetCol.fiche-ouverte .sheet-def{transform:none}
@media (prefers-reduced-motion:reduce){
  .fiche-plus > summary,.fiche-plus > summary::after{transition:none}
}
.sheet strong{color:var(--ink);font-weight:500}

/* niveau de preuve */
.evid{display:flex;align-items:center;gap:10px;margin-top:12px}
.evid i{flex:1;height:3px;border-radius:2px;background:rgba(255,255,255,.10)}
.evid i.f{background:var(--accent)}
.evid b{font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--accent-txt)}

/* grilles diverses */
.grid3{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));
  margin-top:40px;max-width:900px}
.tile{border:1px solid var(--line);border-radius:14px;padding:24px 22px;
  background:linear-gradient(180deg,rgba(255,255,255,.035),rgba(255,255,255,.008))}
.tile h4{margin:0 0 8px;font-family:Outfit;font-weight:300;font-size:19px}
.tile p{font-size:13px;color:var(--muted)}
.tile .mono{color:var(--accent-txt);margin-bottom:14px}

/* tableau de lot / COA */
/* Le tableau de certificat défile DANS SA BOÎTE. Sa largeur dépend de la
   longueur des trois en-têtes, donc de la langue : ce qui tient en français
   pousse la page en allemand. Une seule règle règle les sept langues, et
   celles qu'on ajoutera. */
.coa-wrap{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}
.coa{width:100%;max-width:760px;margin-top:34px;border-collapse:collapse;font-size:13.5px}
.coa th,.coa td{white-space:nowrap}
@media (min-width:640px){ .coa th,.coa td{white-space:normal} }
.coa th,.coa td{text-align:left;padding:15px 14px;border-bottom:1px solid var(--line)}
.coa th{font-family:"JetBrains Mono";font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--faint);font-weight:400}
.coa td:last-child{color:var(--faint);font-family:"JetBrains Mono";font-size:11px}

/* footer */
/* `body > footer`, POUR LA MÊME RAISON QUE L'EN-TÊTE.
   Le pied de page du site est un enfant direct de `body`. Écrite sur l'élément
   nu, cette règle habillait aussi le pied de CHAQUE carte d'avis — la ligne
   « prénom · date » recevait 70 px de rembourrage et le fond plein du site,
   ce qui donnait un rectangle noir de 77 px au bas de chaque témoignage. Même
   défaut, même correction : on nomme l'élément qu'on vise. */
body > footer{position:relative;z-index:3;border-top:1px solid var(--line);
  padding:70px clamp(20px,5vw,90px) 46px;background:var(--night)}
.fgrid{display:grid;gap:34px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  max-width:1100px}
body > footer p,body > footer li{color:var(--muted);font-size:13px}
body > footer ul{margin:0;padding:0;list-style:none;display:grid;gap:8px}
.legal{margin-top:52px;padding-top:26px;border-top:1px solid var(--line);
  color:var(--faint);font-size:11.5px;max-width:780px;line-height:1.75}

/* ==========================================================================
   5. MODE REVUE — balise tout ce qui doit passer au contrôle juridique
   ========================================================================== */
/* LA PASTILLE EST UN OUTIL DE TRAVAIL, PAS UN ÉLÉMENT DE LA BOUTIQUE.
   Elle était visible pour tout le monde, en bas à droite de chaque page, et
   elle révèle les annotations internes posées en `data-review` — parmi elles,
   sur l'accueil : « Preuve — à étayer par des documents réels »,
   « Laboratoire tiers — à confirmer ». Sur un site dont toute la promesse
   repose sur la preuve, montrer à un client que la preuve est « à étayer »
   travaille contre le reste de la page.
   L'outil ne change pas d'un octet : c'est son EXPOSITION qui change. Il
   s'ouvre par `?revue=1`, se retient d'une visite à l'autre, et se referme par
   `?revue=0` — voir `vp-contact.js`. */
#review{display:none}
body.revue-outil #review{
  position:fixed;right:clamp(12px,2vw,24px);bottom:clamp(12px,2vw,24px);z-index:36;
  display:flex;align-items:center;gap:9px;border:1px solid var(--line);border-radius:999px;
  padding:9px 15px;background:rgba(11,10,15,.93);
  font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.16em;text-transform:uppercase}
#review i{width:7px;height:7px;border-radius:50%;background:var(--faint);transition:.3s}
body.review #review i{background:#ffb43c;box-shadow:0 0 10px #ffb43c}
body.review [data-review]{outline:1px dashed rgba(255,180,60,.62);outline-offset:7px;
  border-radius:3px}
body.review [data-review]::after{content:attr(data-review);position:absolute;
  left:0;top:100%;margin-top:9px;z-index:39;
  font:400 9px/1 "JetBrains Mono";letter-spacing:.13em;text-transform:uppercase;
  color:#100c04;background:#ffb43c;padding:5px 7px;border-radius:3px;white-space:nowrap}
[data-review]{position:relative}

/* ==========================================================================
   6. RESPONSIVE
   ========================================================================== */
@media (max-width:900px){
  /* le texte reste tenu, mais compacte pour tenir dans un ecran */
  .hold{padding:9vh 0}
  .hold--flow{padding:13vh 0}
  /* dans la gamme : produit en haut, fiche calee en bas */
  /* Sur telephone le cadre garde sa hauteur d'ecran ; c'est la fenetre interne
     qui se resserre, pas la fiche qui deborde. */
  #range .hold{justify-content:flex-start}
  .sheet-tete{padding:8vh 0 0}
  .sheet-vue{padding:14px 0 3vh}
  .steps{margin-top:22px;height:236px}
  .steps-piste{gap:18px}
  .step p{font-size:13px}
  .lead{margin-top:20px}
  .cta-row{margin-top:26px}
  /* LE NOM ET LES AXES NE SE LISENT PAS À TRAVERS UN FLACON.
     Sur téléphone, le rendu de repli passe DERRIÈRE la fiche — c'est voulu,
     le produit reste dans la composition — mais il passait aussi derrière le
     texte, à 34 % d'opacité : le capuchon tombait en plein milieu. Un fond
     opaque sur l'identité et sur les axes étudiés, et rien d'autre : le reste
     de la fiche garde sa transparence. Le bloc d'achat, lui, n'est plus dans
     cette colonne — il vit dans la carte posée sur le produit. */
  /* SEUL LE NOM EST ÉPINGLÉ, DONC SEUL LE NOM A BESOIN D'UN FOND.
     Le bloc « Ce que c'est » portait ce fond opaque parce qu'il ne bougeait
     pas et devait masquer ce qui défilait dessous. Il défile maintenant avec
     le reste : un fond opaque ne masquerait plus rien, il ferait seulement
     une bande qui glisse sur le texte. */
  .sheet-tete{position:relative;z-index:1;background:var(--night)}
  #dots{top:auto;bottom:14px;left:50%;right:auto;transform:translateX(-50%);
    grid-auto-flow:column;gap:9px}
  /* LES PASTILLES NE SE POSENT PLUS SUR LE TEXTE.
     Barre flottante au centre bas, elles tombaient au milieu d'un paragraphe
     de la fiche : on lisait « DECOUVRIR LE STYLO » avec trois ronds dedans.
     Un fond opaque les detache et les designe comme une commande. Il n'existe
     que quand elles sont visibles, sinon c'est une pilule vide qui flotte. */
  #dots.on{background:rgba(11,10,15,.88);border:1px solid var(--line);
    border-radius:999px;padding:6px 10px}
  #dots button{width:28px;height:28px}
  /* La fleche de l'en-tete devient une cible : sur telephone, la fiole est
     derriere la fiche, et c'est le seul endroit ou l'on peut toucher le
     produit. Une fleche nue ne se lit pas comme un bouton. */
  .tete-fleche{width:34px;height:34px;border:1px solid var(--line);
    border-radius:50%;display:grid;place-items:center;font-size:15px;
    bottom:4px;right:0}
  .sheet section{padding:17px 19px}
  .sheet p{font-size:13px}
  #penSeq{width:min(52vw,240px);height:56vh}
  .vial{width:clamp(78px,20vw,130px)}
  #vialRow{gap:clamp(30px,10vw,70px)}
  #packRow img{width:min(70vw,340px)}
  .act{padding:12vh 22px}
  #dots{right:10px}
}
@media (max-width:760px){
  /* Le mot-symbole était masqué sur petit écran pour laisser la place au CTA :
     le monogramme suffisait. Depuis que le monogramme officiel manque et que
     plus aucun N n'est dessiné, cette règle laissait un en-tête SANS MARQUE
     sur mobile — 26 px de rien. On ne le masque donc que si le monogramme
     officiel est réellement là. */
  html:not(.vp-logo-official) .lockup b{display:inline}
  html.vp-logo-official .lockup b{display:none}
  /* Le monogramme seul mesure 26 px de haut : c'est une belle marque et une
     mauvaise cible. Le lien qui l'entoure doit rester saisissable au doigt
     sans que le dessin grossisse — on agrandit la zone, pas le logo. */
  .lockup{min-width:44px;min-height:44px;justify-content:center}
  /* CENTRER EN ABSOLU NE MARCHE QUE S'IL RESTE DE LA PLACE AU CENTRE.
     À 390 px, le bouton MENU et le groupe de droite se touchent déjà : la
     marque, centrée par-dessus, retombait SUR le panier. On la remet donc
     dans le flux — elle prend sa place au lieu de la voler — et on resserre
     les boutons juste assez pour que les trois tiennent. */
  body > header{gap:8px}
  .btn{padding:9px 12px}
  /* À 390 px il reste 354 px utiles. MENU (61) et la marque (44) en prennent
     105 ; le groupe de droite en demandait 306. Quelque chose devait céder, et
     un bouton coupé au bord de l'écran est pire qu'un bouton dans le menu :
     « Accès pro » y rejoint les autres entrées, à une frappe. Le panier et la
     langue restent visibles — ce sont eux qu'on cherche en cours de lecture. */
  body > header .btn-acc{display:none}
  .btn{padding:9px 15px;font-size:9px}
}
@media (max-width:640px){
  .stage{perspective:900px}
  #penRow img{width:52px}
  h1{font-size:clamp(40px,11vw,64px)}
}

/* ==========================================================================
   7. MOUVEMENT REDUIT
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  .grain,.beam{display:none}
  *{transition-duration:.01ms !important}
  /* Les etapes et la sequence entrent par une animation, pas une transition :
     la regle ci-dessus ne les touche pas, et elles continuaient de glisser.
     Elles apparaissent, sans deplacement. */
  .step,.seq.on,.swap{animation-duration:.01ms !important}
  .steps-piste{transition:none}
}

/* ==========================================================================
   8. ACQUISITION — achat ponctuel / réapprovisionnement
   Volontairement sobre : deux options, pas de compte à rebours, pas de
   pastille « économisez ». L'abonnement doit rassurer, pas pousser.
   ========================================================================== */
.acq{display:grid;gap:10px;margin-top:26px;max-width:440px}
.acq-card{position:relative;display:grid;gap:6px;padding:18px 22px;cursor:pointer;
  border:1px solid var(--line);border-radius:16px;
  background:linear-gradient(180deg,rgba(255,255,255,.035),rgba(255,255,255,.008));
  transition:border-color .4s var(--ease),background .4s var(--ease)}
.acq-card:hover{border-color:rgba(246,244,241,.24)}
.acq-card input{position:absolute;opacity:0;pointer-events:none}
.acq-card:has(input:checked){border-color:color-mix(in srgb,var(--accent) 62%,transparent);
  background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 12%,transparent),rgba(255,255,255,.01))}
.acq-card input:focus-visible + .acq-head{outline:2px solid var(--accent);outline-offset:4px}
.acq-head{display:flex;justify-content:space-between;align-items:baseline;gap:16px}
.acq-head b{font-family:Outfit;font-weight:300;font-size:20px}
.acq-head em{font-style:normal;font-family:Outfit;font-weight:300;font-size:20px;
  color:var(--ink);font-variant-numeric:tabular-nums}
.acq-sub{color:var(--muted);font-size:13.5px}
.acq-iv{display:flex;gap:7px;flex-wrap:wrap;margin-top:5px}
.acq-iv .iv{border:1px solid var(--line);border-radius:999px;padding:7px 14px;
  font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);transition:.35s var(--ease)}
.acq-iv .iv.on{border-color:var(--accent);color:var(--ink);
  background:color-mix(in srgb,var(--accent) 18%,transparent)}
.acq-promise{color:var(--faint);font-size:12.5px;line-height:1.65;margin-top:4px;
  padding-top:12px;border-top:1px solid var(--line)}
.acq-go{justify-self:start;margin-top:6px}
.acq-go[disabled]{opacity:.42;cursor:not-allowed}
.acq-note{color:var(--faint);font-size:12px;line-height:1.6;max-width:42ch}
.acq--closed{border:1px solid var(--line);border-radius:16px;padding:26px 24px;
  display:grid;gap:12px;justify-items:start;
  background:linear-gradient(180deg,rgba(255,255,255,.03),rgba(255,255,255,.006))}
.acq--closed .mono{color:var(--accent-txt)}
.acq-foot{margin-top:26px;font-size:13px;color:var(--muted)}
.acq-foot a{border-bottom:1px solid var(--line);padding-bottom:2px}
.acq-foot a:hover{border-color:var(--accent);color:var(--ink)}

/* ==========================================================================
   9. MENTIONS RÉGLEMENTAIRES
   Elles ne sont pas décoratives : leur présence est décidée par le statut du
   SKU, et elles apparaissent partout où une décision d'achat se prend.
   ========================================================================== */
.warn{display:grid;gap:5px;border-radius:12px;padding:14px 16px;margin-bottom:10px;
  border:1px solid rgba(255,180,60,.30);background:rgba(255,180,60,.07)}
.warn b{font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.18em;
  text-transform:uppercase;color:#ffc978;font-weight:400}
.warn span{color:var(--muted);font-size:12.5px;line-height:1.6}
.warn--info{border-color:var(--line);background:rgba(255,255,255,.03)}
.warn--info b{color:var(--faint)}
#heroWarn .warn{max-width:520px}

/* ==========================================================================
   10. TRUST CENTER
   Un dossier, pas une page de réassurance. Ce qui manque est affiché comme
   manquant : c'est ce qui rendra crédible ce qui sera présent.
   ========================================================================== */
#trustDlg{border:1px solid var(--line);border-radius:22px;background:#0a090d;color:var(--ink);
  padding:0;width:min(1000px,calc(100vw - 28px));max-height:min(88vh,900px);overflow:hidden}
#trustDlg::backdrop{background:rgba(4,4,7,.93)}
.tc{display:grid;grid-template-columns:236px 1fr;max-height:inherit}
.tc-side{border-right:1px solid var(--line);padding:26px 20px;display:flex;flex-direction:column;
  gap:20px;background:linear-gradient(180deg,rgba(255,255,255,.028),transparent)}
.tc-side h3{font-size:26px}
.tc-side .mono{color:var(--accent-txt)}
#tcNav{display:grid;gap:2px}
#tcNav button{text-align:left;padding:10px 12px;border-radius:10px;display:grid;gap:3px;
  transition:.3s var(--ease);font-size:14px}
#tcNav button em{font-style:normal;color:var(--faint);font-size:10.5px;line-height:1.4}
#tcNav button:hover{background:rgba(255,255,255,.04)}
#tcNav button.on{background:color-mix(in srgb,var(--accent) 14%,transparent);
  box-shadow:inset 2px 0 0 var(--accent)}
.tc-main{overflow-y:auto;padding:26px 30px 40px;scroll-behavior:smooth}
.tc-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;
  margin-bottom:22px}
.tc-head h2{font-size:clamp(26px,3vw,40px)}
.tc-sec{padding-top:26px;margin-top:26px;border-top:1px solid var(--line)}
.tc-sec:first-of-type{border-top:0;margin-top:0;padding-top:0}
.tc-sec h4{margin:0 0 14px;font-family:"JetBrains Mono";font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--faint);font-weight:400}
.tc-dl{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:12px;overflow:hidden;grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
.tc-dl > div{background:rgba(10,9,13,.92);padding:14px 16px}
.tc-dl dt{color:var(--faint);font-size:11px;margin-bottom:5px}
.tc-dl dd{margin:0;font-size:14.5px}
.tc-empty{color:rgba(255,180,60,.72);font-family:"JetBrains Mono";font-size:11.5px}
.tc-note{margin-top:12px;color:var(--muted);font-size:12.5px;line-height:1.65;max-width:62ch}
.tc-docs{list-style:none;margin:0;padding:0;display:grid;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:12px;overflow:hidden}
.tc-docs li{background:rgba(10,9,13,.92);padding:13px 16px;display:flex;
  justify-content:space-between;align-items:center;gap:12px;font-size:14px}
.tc-docs em{font-style:normal;color:rgba(255,180,60,.72);font-family:"JetBrains Mono";font-size:10px;
  letter-spacing:.14em;text-transform:uppercase}
.tc-tab{width:100%;border-collapse:collapse;font-size:13.5px}
.tc-tab th,.tc-tab td{text-align:left;padding:12px 14px;border-bottom:1px solid var(--line)}
.tc-tab th{font-family:"JetBrains Mono";font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--faint);font-weight:400}
.tc-trace{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.tc-trace li{display:flex;justify-content:space-between;gap:14px;padding:12px 0;
  border-bottom:1px solid var(--line);font-size:14px}
.tc-trace b{font-weight:400}
.tc-qr{display:flex;align-items:center;gap:16px;margin-top:16px;padding:14px;
  border:1px solid var(--line);border-radius:12px;position:relative}
.tc-qr svg{width:88px;height:88px;color:rgba(246,244,241,.34);flex:0 0 auto}
.tc-qr span{color:var(--faint);font-size:11.5px;line-height:1.5}
.tc-close{position:absolute;top:16px;right:20px;font-size:24px;line-height:1;color:var(--muted);
  z-index:2}
.tc-close:hover{color:var(--ink)}
@media (max-width:820px){
  .tc{grid-template-columns:1fr}
  .tc-side{border-right:0;border-bottom:1px solid var(--line);padding:20px}
  #tcNav{grid-auto-flow:column;overflow-x:auto;gap:6px}
  #tcNav button em{display:none}
  .tc-main{padding:20px}
}

/* ==========================================================================
   11. SOCIAL PROOF — emplacements
   Les tuiles sont hachurées et étiquetées : impossible de les confondre avec
   un contenu réel, y compris sur une capture d'écran.
   ========================================================================== */
.ugc{margin-top:64px}
.ugc-head{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  flex-wrap:wrap;margin-bottom:22px}
.ugc-head h3{font-size:clamp(22px,2.4vw,32px)}
.pill-demo{font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:#ffb43c;border:1px solid rgba(255,180,60,.34);
  background:rgba(255,180,60,.08);border-radius:999px;padding:6px 12px}
.ugc-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));
  grid-auto-rows:150px}
.ugc-tile{margin:0;border:1px dashed rgba(255,180,60,.26);border-radius:14px;
  display:grid;place-content:center;gap:7px;padding:18px;text-align:center;
  background-image:repeating-linear-gradient(135deg,rgba(255,255,255,.028) 0 8px,
    transparent 8px 16px)}
.ugc-tile > span:first-child{font-family:"JetBrains Mono";font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--faint)}
.ugc-tile--wide{grid-column:span 2}
.ugc-tile--v{grid-row:span 2}
.ugc-tile--card{place-content:start;text-align:left;gap:8px}
.ugc-tile--card b{font-weight:400;font-size:15px}
.ugc-tile--card em{font-style:normal;color:var(--muted);font-size:12px;line-height:1.55}
.ugc-stars{color:rgba(255,180,60,.4);letter-spacing:.22em;font-size:15px}
.ugc-note{margin-top:16px;color:var(--faint);font-size:12.5px;line-height:1.7;max-width:62ch}
@media (max-width:700px){ .ugc-tile--wide,.ugc-tile--v{grid-column:auto;grid-row:auto} }

/* ==========================================================================
   12. PANIER — tiroir
   DOM pur : il s'ouvre en une image, sans toucher à la scène 3D.
   ========================================================================== */
/* L'ENCART SOLVANT — DISCRET, PREMIUM, ET IL SE FERME.
   Une bordure dorée fine, pas un bandeau : la proposition doit se remarquer
   sans concurrencer le bouton « Passer commande », qui reste la seule action
   accentuée du tiroir. */
.cart-up{padding:0 clamp(16px,3vw,22px)}
.cart-up[hidden]{display:none}
.up-in{position:relative;border:1px solid color-mix(in srgb,var(--gold) 34%,var(--line));
  border-radius:14px;padding:14px 40px 14px 16px;margin:4px 0 10px;
  background:linear-gradient(150deg,color-mix(in srgb,var(--gold) 6%,transparent),transparent 70%)}
.up-t{margin:0 0 3px;font-size:14px;color:var(--ink)}
.up-s{margin:0 0 10px;font-family:"JetBrains Mono";font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint)}
.up-go{width:100%;min-height:44px}
.up-x{position:absolute;top:6px;right:6px;width:30px;height:30px;line-height:1;
  font-size:19px;color:var(--faint);background:none;border:0;cursor:pointer}
.up-x:hover{color:var(--ink)}
#cartScrim{position:fixed;inset:0;z-index:44;background:rgba(4,4,7,.62);
  opacity:0;visibility:hidden;transition:.42s var(--ease)}
#cartDrawer.on ~ #cartScrim,#cartScrim.on{opacity:1;visibility:visible}
#cartDrawer{position:fixed;top:0;right:0;bottom:0;z-index:45;width:min(430px,100vw);
  background:#0a090d;border-left:1px solid var(--line);display:flex;flex-direction:column;
  transform:translateX(102%);transition:transform .48s var(--ease)}
#cartDrawer.on{transform:none;box-shadow:-30px 0 80px rgba(0,0,0,.6)}
.cart-head{display:flex;justify-content:space-between;align-items:center;gap:12px;
  padding:22px 22px 16px;border-bottom:1px solid var(--line)}
.cart-head h3{font-size:22px}
#cartBody{flex:1;overflow-y:auto;padding:18px 22px}
.cart-empty{color:var(--muted);font-size:14px;padding:30px 0}
/* LA COLONNE DU MILIEU DOIT POUVOIR RÉTRÉCIR — SINON C'EST LE PRIX QUI SORT.
   `1fr` vaut `minmax(auto,1fr)` : la colonne ne descend jamais sous le
   MIN-CONTENT de ce qu'elle porte, et ce qu'elle porte est la mention
   réglementaire, en mono espacée. Mesuré à 390 px : min-content de 151 px en
   français, 181 en allemand, pour 124 px disponibles. La grille dépassait donc
   la largeur du tiroir, et ce qui sortait était la DERNIÈRE colonne — le
   compteur de quantité et le prix. « 89 € » finissait coupé au bord de
   l'écran, au moment précis où le visiteur décide.
   `minmax(0,1fr)` rend le rétrécissement possible. Rien ne change dès qu'il y
   a de la place : à 430 px et au-delà, la répartition est identique au pixel.
   Et on ne touche PAS au plancher tactile de 44 px du compteur — c'est lui qui
   rend les boutons atteignables au doigt, il n'a pas à céder pour que du texte
   tienne. */
.cart-line{display:grid;grid-template-columns:56px minmax(0,1fr) auto;gap:14px;
  padding:16px 0;border-bottom:1px solid var(--line)}
.cart-thumb{width:56px;height:74px;border-radius:9px;border:1px solid var(--line);
  display:grid;place-items:center;background:linear-gradient(160deg,
    color-mix(in srgb,var(--accent) 22%,transparent),rgba(255,255,255,.02))}
.cart-thumb span{font-family:Outfit;font-weight:300;font-size:15px;color:var(--ink)}
/* La photo occupe la vignette sans être rognée : une fiole coupée en deux
   dans un panier n'est pas une photo de produit. */
.cart-thumb img{width:100%;height:100%;object-fit:contain;display:block}
.cart-info b{font-weight:400;font-size:15px;display:block}
.cart-info p{color:var(--muted);font-size:12px;margin-top:4px;display:flex;gap:8px;
  align-items:center;flex-wrap:wrap}
/* LA MENTION DANS LE PANIER N'EST PLUS UN FEU ORANGE.
   Elle disait la bonne chose dans la mauvaise couleur : un orange d'alerte, à
   côté d'un prix, sur chaque ligne. Le texte ne change pas — « réservé à la
   recherche » reste écrit, sur chaque référence concernée — mais il est rendu
   comme une MENTION et non comme un incident. C'est le même parti que la
   fiche : la règle ne bouge pas, sa hiérarchie visuelle oui. */
.cart-warn{color:var(--faint);border:1px solid var(--line);border-radius:999px;
  padding:2px 7px;font-family:"JetBrains Mono";font-size:8.5px;letter-spacing:.12em;
  text-transform:uppercase}
.cart-mode{display:inline-flex;margin-top:9px;border:1px solid var(--line);border-radius:999px;
  overflow:hidden}
/* « UNE FOIS » OU « ABONNEMENT » — LE CHOIX QUI DÉCIDE DU MONTANT, À 9 PX.
   Relevé dans Chrome sur les quatre largeurs, tactile comme pointeur fin :
   9 px, en capitales, avec 0,13 em d'interlettrage. Le plancher de 11 px que
   le dépôt s'est fixé pour les écrans tactiles ne couvrait pas ce sélecteur —
   il a été appliqué règle par règle au fil des passes, et celle-ci est passée
   entre les mailles.
   Ce n'est pas une étiquette décorative : c'est la commande qui fait basculer
   la ligne entre un achat ponctuel et un réapprovisionnement à −10 %. La
   rendre illisible, c'est rendre l'économie invisible au moment exact où elle
   se décide. 11 px partout, et l'interlettrage se resserre pour que les deux
   boutons tiennent dans la colonne à 390 px. */
.cart-mode button{padding:6px 11px;font-family:"JetBrains Mono";font-size:11px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);transition:.3s var(--ease)}
.cart-mode button.on{background:color-mix(in srgb,var(--accent) 24%,transparent);color:var(--ink)}
.cart-iv{margin-top:8px;background:rgba(255,255,255,.04);border:1px solid var(--line);
  color:var(--ink);border-radius:8px;padding:6px 9px;font:inherit;font-size:12px}
.cart-right{text-align:right;display:grid;gap:8px;align-content:start}
.cart-qty{display:inline-flex;align-items:center;gap:10px;border:1px solid var(--line);
  border-radius:999px;padding:4px 10px;justify-self:end}
.cart-qty button{width:18px;color:var(--muted);font-size:15px;line-height:1}
.cart-qty button:hover{color:var(--ink)}
.cart-right b{font-weight:400;font-size:15px}
.cart-save{font-style:normal;color:#5fd6a4;font-size:11.5px;font-family:"JetBrains Mono"}
#cartFoot{border-top:1px solid var(--line);padding:18px 22px 22px;display:grid;gap:14px}
.cart-promo{display:flex;gap:8px}
.cart-promo input{flex:1;background:rgba(255,255,255,.04);border:1px solid var(--line);
  border-radius:10px;padding:11px 13px;color:var(--ink);font:inherit;font-size:13px}
.cart-promo input::placeholder{color:var(--faint)}
.cart-tot{margin:0;display:grid;gap:8px;font-size:13.5px}
.cart-tot > div{display:flex;justify-content:space-between;gap:12px}
.cart-tot dt{color:var(--muted)} .cart-tot dd{margin:0}
.cart-tot-save dd{color:#5fd6a4}
.cart-tot-final{padding-top:10px;border-top:1px solid var(--line);font-size:17px}
.cart-tot-final dt{color:var(--ink)}
.cart-go{width:100%;justify-content:center}
.cart-go[disabled]{opacity:.45;cursor:not-allowed}
.cart-note{color:var(--faint);font-size:11.5px;line-height:1.6}
#cartBtn{position:relative}
#cartCount{position:absolute;top:-5px;right:-5px;min-width:17px;height:17px;border-radius:999px;
  background:var(--accent);color:#fff;font-family:"JetBrains Mono";font-size:9px;
  display:grid;place-items:center;padding:0 4px}
/* SOUS 430 px, LE TIROIR EST COLLÉ AUX DEUX BORDS — ET CHAQUE PIXEL COMPTE.
   Au-dessus, il fait 430 px de large au milieu d'un écran plus grand : la
   marge de 22 px et la gouttière de 14 px sont celles qui ont été validées, et
   elles ne bougent pas. En dessous, le tiroir EST l'écran, et ces 36 px sont
   exactement ce qui manque à la mention réglementaire pour tenir sans se
   couper. On rend donc 16 px de marge et 8 px de gouttière à la colonne du
   texte — 145 px au lieu de 124 — sans toucher ni au plancher tactile de 44 px
   du compteur, ni à la largeur du visuel produit, ni à rien au-dessus de
   429 px. */
@media (max-width:429px){
  #cartBody{padding:18px 16px}
  .cart-line{gap:10px}
}
@media (prefers-reduced-motion:reduce){ #cartDrawer{transition:none} }

/* ============ CAPTURE E-MAIL ============ */
.cap{border:1px solid var(--line);border-radius:14px;padding:22px 22px 18px;
  background:rgba(255,255,255,.02);max-width:680px}
.cap .eyebrow{margin-bottom:8px}
.cap-offer{font-size:17px;line-height:1.5;margin-bottom:14px;color:var(--ink)}
.cap-offer--plain{color:var(--muted)}
.cap-terms{font-size:12px;color:var(--faint);margin:-8px 0 14px}
.cap-row{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}
.cap-field{display:flex;flex-direction:column;gap:5px;flex:1 1 190px;min-width:0}
.cap-lab{font:500 10.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint)}
.cap input[type=email],.cap input[type=text],.cap select{
  background:rgba(255,255,255,.04);border:1px solid var(--line);border-radius:9px;
  color:var(--ink);padding:11px 12px;font:400 14px/1.2 inherit;width:100%;
  transition:border-color .2s,background .2s}
.cap input:focus,.cap select:focus{outline:none;border-color:var(--gold);
  background:rgba(255,255,255,.06)}
.cap select{appearance:none;cursor:pointer}
.cap-go{flex:0 0 auto;padding:11px 22px}
.cap-consent{display:flex;gap:10px;align-items:flex-start;margin-top:14px;
  font-size:12.5px;line-height:1.55;color:var(--muted);cursor:pointer}
.cap-consent input{margin-top:2px;accent-color:var(--gold);flex:0 0 auto}
.cap-legal{font-size:11.5px;line-height:1.6;color:var(--faint);margin-top:10px}
.cap-legal a{color:var(--muted);text-decoration:underline}
.cap-msg{font-size:12.5px;line-height:1.55;color:var(--gold);margin-top:10px;min-height:1em}
.cap--done{border-color:rgba(196,152,92,.4)}
.cap--done .cap-row,.cap--done .cap-consent{opacity:.45}

#capModal{position:fixed;inset:0;z-index:60;display:grid;place-items:center;
  background:rgba(4,4,6,.88);opacity:0;transition:opacity .28s}
#capModal.on{opacity:1}
.cap-box{position:relative;width:min(560px,calc(100vw - 32px));background:var(--night-2);
  border:1px solid var(--line);border-radius:18px;padding:8px}
.cap-box .cap{border:0;background:none;padding:26px 24px 20px}
.cap-x{position:absolute;top:10px;right:12px;background:none;border:0;color:var(--faint);
  font-size:26px;line-height:1;cursor:pointer;padding:4px 8px}
.cap-x:hover{color:var(--ink)}
@media (max-width:560px){ .cap-go{width:100%} }
@media (prefers-reduced-motion:reduce){ #capModal{transition:none} }

/* ============ SÉLECTEUR DE LANGUE ============
   UN `<select>` NATIF NE TENAIT QU'À DEUX LANGUES. À sept, il liste quatre
   alphabets dans une fenêtre dessinée par le système d'exploitation, et sur
   mobile il ouvre une roulette plein écran qui n'appartient pas à la marque.

   Le bouton reste minuscule — le code de la langue, deux signes — pour ne pas
   pousser le panier et l'accès pro hors de l'en-tête. La liste, elle, affiche
   les noms NATURELS en entier : personne ne cherche « ru », on cherche
   « Русский ». Elle s'ancre au bord DROIT du bouton et ne peut donc pas
   déborder de l'écran, quelle que soit la longueur des noms. */
.lang{position:relative;display:inline-flex}
.lang-b{gap:6px;padding:11px 13px;min-width:52px;justify-content:center}
/* 11 px, pas 10 : c'est le plancher de lisibilité que le reste du site
   respecte déjà, et le code de langue est le seul repère qui dit au visiteur
   dans quelle langue il se trouve. */
.lang-b .lang-code{font-family:"JetBrains Mono";font-size:11px;letter-spacing:.14em}
/* Le chinois n'a pas d'espacement de capitales : appliqué à un idéogramme, le
   suivi le décale sur la droite de son propre cadre et le bouton paraît de
   travers. */
:root[lang="zh-CN"] .lang-b .lang-code{letter-spacing:0;font-size:12px;
  font-family:inherit}
.lang-v{opacity:.55;transition:transform .2s}
.lang-b[aria-expanded="true"] .lang-v{transform:rotate(180deg)}
.lang-menu{position:absolute;top:calc(100% + 8px);inset-inline-end:0;z-index:60;
  margin:0;padding:6px;list-style:none;min-width:168px;
  background:#0d0c11;border:1px solid var(--line);border-radius:14px;
  box-shadow:0 18px 44px rgba(0,0,0,.55)}
.lang-menu li{margin:0}
.lang-menu button{display:block;width:100%;text-align:start;background:none;border:0;
  color:var(--ink);font-size:13.5px;line-height:1.25;padding:10px 12px;border-radius:9px;
  cursor:pointer;white-space:nowrap}
.lang-menu button:hover{background:rgba(255,255,255,.06)}
.lang-menu button:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.lang-menu [aria-selected="true"]{color:var(--gold-lt)}
.lang-menu [aria-selected="true"]::after{content:"·";margin-inline-start:8px;color:var(--gold)}
@media (max-width:420px){
  /* Sur un téléphone de 390 px, l'en-tête est déjà plein. La liste s'aligne
     toujours sur le bord droit du bouton, mais on la borne à la largeur
     disponible pour qu'aucun nom ne pousse la page horizontalement. */
  .lang-menu{min-width:150px;max-width:calc(100vw - 24px)}
}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* ============ ÉCRITURE DE DROITE À GAUCHE ============
   L'arabe ne se traite pas en retournant la page. Ce qui change, ce sont les
   axes de LECTURE : le tiroir arrive du côté opposé, les alignements de texte
   suivent le sens d'écriture, la barre de progression avance vers la gauche.
   Ce qui NE CHANGE PAS : la scène 3D et les chiffres. Un produit ne se
   reflète pas parce que la langue s'écrit dans l'autre sens, et un dosage lu
   à l'envers serait une faute. */
[dir="rtl"] .coa th,[dir="rtl"] .coa td,
[dir="rtl"] .tc-tab th,[dir="rtl"] .tc-tab td,
[dir="rtl"] #tcNav button,[dir="rtl"] .ugc-tile--card{text-align:right}
[dir="rtl"] .cart-right{text-align:left}
[dir="rtl"] .tc-side{border-right:0;border-left:1px solid var(--line)}
[dir="rtl"] .tc-close{right:auto;left:20px}
[dir="rtl"] #cartDrawer{right:auto;left:0;border-left:0;border-right:1px solid var(--line);
  transform:translateX(-100%)}
[dir="rtl"] #cartDrawer.on{transform:none;box-shadow:30px 0 80px rgba(0,0,0,.6)}
[dir="rtl"] #cartCount{right:auto;left:-5px}
[dir="rtl"] #bar{left:auto;right:0}
[dir="rtl"] #dots{right:auto;left:clamp(12px,2vw,26px)}
[dir="rtl"] #review{right:auto;left:clamp(12px,2vw,24px)}
[dir="rtl"] .cap-x{right:auto;left:12px}
[dir="rtl"] .lockup b{padding-left:0;padding-right:.36em}
/* La scène et les mesures restent dans le sens de lecture latin. */
[dir="rtl"] .stage,[dir="rtl"] .num,[dir="rtl"] .mono{direction:ltr}
[dir="rtl"] .mono{text-align:right}
@media (max-width:820px){
  [dir="rtl"] #dots{left:50%;right:auto}
}

/* ============ COMPRÉHENSION / SCIENCE ============ */
.lead--cat{font-size:clamp(16px,1.5vw,19px);color:var(--gold-lt);
  letter-spacing:.005em;margin-bottom:6px}
.btn-ghost{opacity:.72}

/* PLUS DE GRANDE BULLE GRISE AUTOUR DE LA COUCHE PÉDAGOGIQUE.
   Ce bloc portait un fond blanc translucide et un contour arrondi sur toute sa
   hauteur — c'est-à-dire une zone grise géante, plus claire que la page,
   posée par-dessus le fond noir. Vu à l'écran, ce n'était pas un cadre : ça
   ressemblait à un panneau collé sur le site, et sa moitié droite vide
   accentuait encore l'impression.
   Le texte se lit tout aussi bien sans caisson — c'est du texte long, sur un
   fond déjà sombre et régulier. On garde uniquement le retrait qui l'aligne
   sur la colonne de lecture. Les petites cartes internes (`.edu-split`)
   gardent leur contour : elles, elles séparent deux idées côte à côte. */
.edu{padding:clamp(22px,3vw,34px) 0;margin:34px 0 40px}
.edu h3{font-size:clamp(21px,2.2vw,27px);margin-bottom:14px;letter-spacing:-.01em}
.edu .edu-h2{margin-top:34px}
.edu-p{font-size:15px;line-height:1.72;color:var(--muted);margin-bottom:13px;max-width:74ch}
.edu-tabs{display:flex;gap:8px;margin:16px 0 18px}
.edu-tabs button{background:rgba(255,255,255,.04);border:1px solid var(--line);
  color:var(--muted);border-radius:999px;padding:9px 18px;cursor:pointer;
  font:500 11.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.1em;
  text-transform:uppercase;transition:color .2s,border-color .2s,background .2s}
.edu-tabs button[aria-selected=true]{color:var(--night);background:var(--gold-lt);
  border-color:var(--gold-lt)}
.edu-det{border-top:1px solid var(--line);padding:14px 0}
.edu-det summary{cursor:pointer;font-weight:500;font-size:15px;color:var(--ink);
  list-style:none;display:flex;justify-content:space-between;align-items:center;gap:14px}
.edu-det summary::after{content:"+";color:var(--gold);font-size:19px;line-height:1}
.edu-det[open] summary::after{content:"–"}
.edu-det p{margin-top:11px}
.edu-split{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:30px}
.edu-split>div{border:1px solid var(--line);border-radius:12px;padding:18px}
.edu-split b{display:block;font-size:15px;margin-bottom:8px;color:var(--gold-lt)}
.edu-split p{font-size:13.5px;line-height:1.65;color:var(--muted)}
.edu-limit{margin-top:10px;padding-top:10px;border-top:1px solid var(--line);
  color:var(--faint)!important;font-size:12.5px!important}
@media (max-width:760px){ .edu-split{grid-template-columns:1fr} }

/* --- niveau de preuve --- */
.ev{border:1px solid var(--line);border-radius:12px;padding:18px;margin-bottom:24px}
.ev-scale{display:flex;gap:5px;margin-bottom:12px}
.ev-scale i{flex:1;height:5px;border-radius:3px;background:rgba(246,244,241,.10)}
.ev-scale i.on{background:var(--gold)}
.ev-label{font-size:16px;color:var(--gold-lt)}
.ev-means{font-size:13px;line-height:1.6;color:var(--muted);margin-top:7px}
.ev-src{font-size:11.5px;color:var(--faint);margin-top:10px;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.06em}
.ev-none{color:#e9ca9a}

/* --- fiche scientifique --- */
.sc-areas{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:22px}
.sc-areas span{border:1px solid var(--line);border-radius:999px;padding:6px 13px;
  font-size:11.5px;color:var(--muted)}
.sc-sec{border-top:1px solid var(--line);padding:18px 0}
.sc-sec h4{font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--faint);margin-bottom:9px;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.sc-sec p{font-size:14.5px;line-height:1.72;color:var(--muted);max-width:72ch}
.sc-sec--limit h4{color:#e9ca9a}
.sc-note{font-size:12px!important;color:var(--faint)!important;margin-top:8px}
.sc-empty{font-size:13.5px;line-height:1.7;color:var(--faint);
  border-left:2px solid var(--line);padding-left:14px}
.sc-refs{list-style:none;display:grid;gap:18px}
.ref a{color:var(--ink);font-size:15px;line-height:1.5;text-decoration:underline;
  text-underline-offset:3px;text-decoration-color:var(--line)}
.ref a:hover{text-decoration-color:var(--gold)}
.ref-meta{font-size:11.5px;color:var(--faint);margin-top:6px;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.ref-reg{font-size:12.5px;color:#e9ca9a;margin-top:8px;
  border-left:2px solid rgba(233,202,154,.4);padding-left:10px}
.ref-reg--appr{color:#5fd6a4;border-left-color:rgba(95,214,164,.5)}
.ref-sum{font-size:13.5px;line-height:1.65;color:var(--muted);margin-top:8px}
.ref-lim{font-size:12.5px;line-height:1.6;color:var(--faint);margin-top:6px}
.ref--negative{border-left:2px solid rgba(255,143,107,.45);padding-left:14px}
.ref--mixed{border-left:2px solid rgba(233,202,154,.4);padding-left:14px}

#sciDlg{border:0;padding:0;background:transparent;max-width:none;max-height:none;
  width:100vw;height:100dvh}
/* PAS DE FLOU D'ARRIÈRE-PLAN SUR UN MODAL PLEIN ÉCRAN.
   Mesuré : ouvrir le Science Center coûtait 2,6 s de processeur et le fermer
   3,4 s. Un `backdrop-filter` refloute TOUT le viewport à chaque image tant
   que le dialogue est ouvert — et le Science Center est justement une section
   où le visiteur reste. C'est le même défaut que les cinq calques flous de
   l'atmosphère, simplement caché derrière un modal.
   Sur une page déjà presque noire, un voile opaque sombre donne exactement la
   même lecture : le fond recule, le modal ressort. Pour zéro coût. */
#sciDlg::backdrop{background:rgba(4,4,6,.93)}
#sciNav{display:grid;gap:5px;margin:22px 0}
#sciNav button{background:none;border:0;color:var(--muted);text-align:left;
  padding:9px 12px;border-radius:9px;cursor:pointer;font-size:13.5px;
  transition:background .2s,color .2s}
#sciNav button:hover{background:rgba(255,255,255,.05);color:var(--ink)}
#sciNav button.on{background:rgba(196,152,92,.14);color:var(--gold-lt)}
#sciBody{padding:clamp(20px,3vw,38px)}
[dir="rtl"] #sciNav button{text-align:right}

/* ==========================================================================
   VISUELS PRODUIT PHOTORÉALISTES
   Ils passent AVANT la 3D temps réel. Une image ne recalcule ni le verre, ni
   la réfraction, ni les reflets à chaque image : c'est le même écran, en plus
   beau, pour une fraction du GPU.
   ========================================================================== */
.shot{position:relative;display:block;margin:0;z-index:3}
.shot picture{display:block}
.shot img{display:block;width:100%;height:auto;border-radius:3px}
/* La 3D était derrière un canvas plein écran ; ces visuels vivent DANS le flux,
   donc ils ont besoin de leur propre place dans la colonne. */
.act .shot{width:min(46vw,620px)}
.act--tall .shot{width:min(42vw,560px)}
.shot-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;
  width:min(46vw,620px)}
.shot-grid .shot{width:100%}
.shot figcaption,.shot-cap{margin-top:9px;font-family:"JetBrains Mono";
  font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--faint)}

/* Emplacement réservé : il occupe la place réelle du visuel et nomme le
   fichier attendu. Volontairement sobre — ce n'est pas une erreur, c'est une
   pièce en attente. */
.shot-reserved{display:flex;flex-direction:column;justify-content:center;gap:7px;
  aspect-ratio:4/5;padding:20px;border:1px dashed var(--line);border-radius:3px;
  background:linear-gradient(160deg,rgba(139,74,214,.05),rgba(255,255,255,.012))}
.shot-reserved b{font-size:13px;font-weight:500;color:var(--ink)}
.shot-reserved span{font-size:10px;letter-spacing:.04em;color:var(--faint);
  word-break:break-all}
.shot-reserved em{font-style:normal;font-family:"JetBrains Mono";font-size:9px;
  letter-spacing:.18em;text-transform:uppercase;color:var(--gold)}

@media (max-width:900px){
  .act .shot,.act--tall .shot,.shot-grid{width:min(92vw,560px)}
}

/* Le texte et le visuel approuvé côte à côte. La 3D occupait tout le fond de
   l'écran ; ces visuels vivent dans le flux, donc l'acte devient une vraie
   mise en page à deux colonnes. */
/* `.hold` est une colonne ; il faut donc explicitement repasser en RANGÉE,
   sinon le visuel se retrouve sous le texte au lieu d'être à côté. */
.hold--split{position:sticky;top:0;min-height:100vh;display:flex;
  flex-direction:row;align-items:center;justify-content:space-between;
  gap:clamp(24px,5vw,72px);padding:12vh 0}
.hold--split > .col{flex:0 1 430px;max-width:430px}
/* le hero ouvre sa colonne de texte : #hero .col la libère, on la reborne */
#hero .hold--split > .col{max-width:560px}
.shot-stack{display:flex;flex-direction:column;gap:12px;
  width:min(46vw,620px);flex:0 0 auto}
.shot-stack .shot,.shot-stack .shot-grid{width:100%}
/* Bascule à 1100 px, pas à 900. À 1024 la mise en page à deux colonnes tenait
   « techniquement » — 430 px de texte plus 620 px de visuel — mais chaque mot
   traduit changeait la hauteur de la colonne étranglée, et c'est là que se
   concentrait le décalage cumulé de la page. Au-dessous de 1100, on empile :
   plus lisible, et plus stable. */
@media (max-width:1100px){
  .hold--split{flex-direction:column;align-items:stretch;justify-content:center;
    gap:24px;min-height:auto;padding:9vh 0;position:static}
  .hold--split > .col{flex:1 1 auto;max-width:none}
  .shot-stack{width:100%}
}
.shot--wide{width:min(92vw,1100px);margin:0 auto 40px}

/* ==========================================================================
   ACCESSIBILITÉ TACTILE ET LISIBILITÉ — écrans à doigt
   Mesuré sur 390 px : huit cibles sous 40 px et six textes sous 11 px. Un
   bouton de 30 px se rate une fois sur trois ; un texte de 9 px ne se lit pas
   à bout de bras. Ces règles ne s'appliquent qu'aux pointeurs GROSSIERS —
   sur un écran piloté à la souris, les mêmes tailles sont confortables et il
   n'y a aucune raison de gonfler l'interface.
   ========================================================================== */
@media (pointer: coarse){
  .btn,.iv,button,select,input[type="submit"],input[type="text"],input[type="email"]{min-height:44px}
  /* Les puces de navigation restent visuellement fines : c'est leur ZONE
     TOUCHABLE qu'on agrandit, avec un pseudo-élément transparent. Grossir la
     puce elle-même abîmerait le repère ; l'agrandir sous le doigt, non. */
  #dots button{position:relative}
  #dots button::after{content:"";position:absolute;inset:-14px}
  /* Même principe pour les pastilles de finition, et pour la même raison :
     elles portent déjà leur cible de 44 px en pseudo-élément. La règle
     générale ci-dessus les étirait à 30 x 44 — trois ovales à la place de
     trois ronds, et une couleur qu'on juge sur une forme déformée. */
  .bt-sw{min-height:0}
  .cart-qty button{min-width:44px}
  .shot-reserved span,.shot-reserved em{font-size:11px}
  .btn,.iv{padding-top:11px;padding-bottom:11px}
  body > header .btn,#menuBtn{min-width:44px}
  .lockup{min-height:44px;display:inline-flex;align-items:center}
  /* Les libellés en petite chasse mono descendaient à 9 px : lisibles sur un
     écran de bureau à 50 cm, pas dans une main. */
  .mono,.eyebrow,.tagline,.btn,.acq-note,.cart-note{font-size:11px}
  /* ==========================================================================
     « AJOUTER AU PANIER » TENAIT SUR DEUX LIGNES, ET C'EST L'ESPACEMENT QUI
     PAYAIT LE PRIX DE LA LARGEUR
     --------------------------------------------------------------------------
     Dans une carte de boutique à 390 px, la colonne de texte fait 172 px. Le
     libellé le plus long du site — dix-sept caractères — mesurait 180 px avec
     l'interlettrage de bureau : il passait à la ligne, le bouton doublait de
     hauteur (60 px au lieu de 44) et venait toucher le bouton secondaire
     dessous.
     On ne réduit NI le corps (onze pixels est le plancher de lisibilité que
     `tests/pages.js` fait respecter), NI la cible tactile (44 px). On réduit
     l'INTERLETTRAGE, qui est un choix typographique de large écran : à cette
     taille il n'ajoute pas d'élégance, il ajoute de la largeur. Le libellé
     tient alors sur une ligne, et le bouton retrouve sa hauteur normale. */
  .btn{letter-spacing:.12em;padding-left:14px;padding-right:14px}
  .sheet h3, .sheet h4,.tc-tab th{font-size:11.5px}
  #dots{font-size:11px}
}

/* Le bloc de boutons du hero change de hauteur quand la langue change : trois
   boutons anglais tiennent sur deux lignes là où le français en prend trois.
   Tout ce qui suit se déplaçait alors — c'est le plus gros décalage mesuré de
   la page. Réserver la hauteur le supprime, sans rien figer d'autre. */
.cta-row{min-height:96px;align-content:flex-start}
@media (max-width:900px){ .cta-row{min-height:0} }

/* Les deux états du stylo, côte à côte. Ils sont volontairement de MÊME
   taille : montrer l'état ouvert plus grand que l'état vendu inverserait la
   hiérarchie du produit. */
.states{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;
  margin:40px 0 24px}
.states .shot{width:100%}
@media (max-width:760px){ .states{grid-template-columns:1fr} }
.shot-grid--six{grid-template-columns:repeat(3,1fr)}
@media (max-width:520px){ .shot-grid--six{grid-template-columns:repeat(2,1fr)} }
@media (pointer: coarse){
  /* Les derniers libellés sous 11 px : mentions réglementaires et étiquettes
     d'emplacement. Une mention qu'on ne peut pas lire ne remplit pas son rôle. */
  .warn b,.warn span,.tc-note,.acq-promise,.shot figcaption,.shot-cap,
  label,.field label,.hint,.note,body > footer small{font-size:11px}
  /* TOUS les champs, pas seulement ceux qu'on avait listés : un champ oublié
     est un champ qu'on rate au doigt. */
  input:not([type="hidden"]),textarea{min-height:44px}
}
/* Un bloc en flux normal qui se scinde en deux colonnes : il ne colle pas, il
   ne force pas 100vh, mais il garde ses deux colonnes. */
.hold--flow.hold--split{position:static;min-height:auto;align-items:flex-start}
@media (pointer: coarse){
  /* Derniers libellés relevés sous 11 px, un par un. Une mention réglementaire
     ou une étiquette de champ qu'on ne peut pas lire ne remplit pas son rôle. */
  .pill-demo,.cap-lab,.iv,.evid b,.tc-tab th,.tc-tab td,#review span,
  .sheet .mono,p.mono,.shot-cap,.brand-sub{font-size:11px}
}
@media (pointer: coarse){
  /* Les trois derniers : légendes des vignettes de réception, signature
     secondaire de la marque, et le sélecteur de langue — dont la hauteur
     venait de son habillage, pas de la balise. */
  .ugc-tile > span:first-child,#tcNav button em{font-size:11px}
  p[data-brand="secondarySignature"],.tagline{font-size:11px}
  #langSwitch,.lang-b,.lang-menu button,.sw select{min-height:44px;height:auto}
}

.brand-sub{color:var(--faint);margin-top:8px;font-size:10.5px}
@media (pointer: coarse){ .brand-sub{font-size:11px} }

/* ==========================================================================
   POINT DE CONTACT UNIQUE — un bouton, pas une pile

   Chaque canal posait auparavant son propre bouton flottant dans le même coin.
   Avec la pastille « mode revue » qui s'y trouvait déjà, cela faisait une
   colonne de trois. Une pile de boutons ne se lit pas : le visiteur ne choisit
   plus, il évite.

   Un seul objet, donc, posé AU-DESSUS de la pastille de revue (qui reste un
   outil de relecture, pas un point de contact client). Selon ce qui est
   réellement disponible : rien, un bouton d'action directe, ou un bouton qui
   ouvre le choix — voir vp-contact.js.

   z-index 39 : au-dessus de la pastille (36), SOUS le voile du panier (44) et
   la popup e-mail (60). Il ne peut donc jamais passer par-dessus une
   sollicitation en cours — et quand l'une s'ouvre, il s'efface (.vc--hide).
   ========================================================================== */
:root{
  --vc-gap:clamp(12px,2vw,24px);
  /* RIEN À DÉGAGER QUAND IL N'Y A RIEN. La pastille de revue n'est plus
     publique : le point de contact descend donc au bas de l'écran pour le
     visiteur ordinaire, et ne remonte que lorsque l'outil est ouvert.
     46 px = hauteur réelle de #review (padding 9px x2 + ligne 9,5px arrondie)
     plus la respiration. */
  --vc-clear:var(--vc-gap);
}
body.revue-outil{ --vc-clear:calc(var(--vc-gap) + 46px) }
/* LA BARRE D'ACHAT COLLÉE PASSE AVANT LE POINT DE CONTACT.
   67 px de barre plus la respiration : le bouton flottant monte au-dessus
   plutôt que de recouvrir « Ajouter au panier ». La barre n'existe qu'en
   dessous de 820 px et seulement quand le bloc d'achat est sorti de l'écran —
   le décalage suit exactement, ni avant ni après. */
body.barre-achat{ --vc-clear:calc(var(--vc-gap) + 77px) }
body.revue-outil.barre-achat{ --vc-clear:calc(var(--vc-gap) + 77px + 46px) }
.vc{
  position:fixed;right:var(--vc-gap);bottom:var(--vc-clear);z-index:39;
  display:flex;flex-direction:column;align-items:flex-end;gap:10px;
  transition:opacity .3s var(--ease),transform .42s var(--ease);
}
.vc--hide{opacity:0;transform:translateY(8px) scale(.96);pointer-events:none}
/* LA PASTILLE CÈDE LE PASSAGE À UN BOUTON — deux raisons, deux classes.
   `--hide` dit qu'une AUTRE sollicitation a la parole (popup, tiroir) ; celle-ci
   dit qu'un bouton occupe sa bande. Les confondre reviendrait à ce que la
   fermeture d'un tiroir ramène la pastille sur un « Ajouter au panier ». */
.vc--cede{opacity:0;transform:translateY(8px) scale(.96);pointer-events:none}

.vc-fab,.vc-item{
  display:inline-flex;align-items:center;gap:10px;cursor:pointer;
  height:52px;padding:0 20px 0 17px;border-radius:999px;
  border:1px solid var(--line);
  background:linear-gradient(150deg,rgba(19,16,24,.96),rgba(11,10,15,.96));
  color:var(--ink);
  box-shadow:0 14px 40px rgba(0,0,0,.55),0 0 0 1px rgba(0,0,0,.35);
  /* PAS DE `backdrop-filter` SUR UN ÉLÉMENT FIXE.
     Il refloute son arrière-plan À CHAQUE IMAGE tant que la page défile —
     c'est-à-dire tout le temps. Le fond du bouton est déjà opaque à 96 % :
     le flou ne se voyait pas, il se payait. Même défaut, même correction que
     le `::backdrop` du Science Center et l'ombre portée du produit. */
  transition:transform .42s var(--ease),border-color .42s var(--ease),
             box-shadow .42s var(--ease),opacity .3s var(--ease);
}
.vc-fab:hover,.vc-fab:focus-visible,.vc-item:hover,.vc-item:focus-visible{transform:translateY(-2px)}
.vc-i{width:21px;height:21px;flex:0 0 auto}
/* 11 px, et pas 10,5 : c'est le plancher de lisibilité que `tests/pages.js`
   fait respecter partout ailleurs. Le libellé était sous ce plancher, et il ne
   se voyait pas tant que le canal WhatsApp n'était pas activé — personne ne
   lisait un bouton qui n'existait pas. */
.vc-t{font-family:"JetBrains Mono";font-size:11px;letter-spacing:.17em;
  text-transform:uppercase;white-space:nowrap;color:var(--muted)}
.vc-fab:hover .vc-t,.vc-fab:focus-visible .vc-t,
.vc-item:hover .vc-t,.vc-item:focus-visible .vc-t{color:var(--ink)}

/* Chaque canal garde son identité : le vert pour WhatsApp, plasma pour le
   conseiller, bronze pour le reste.
   LE VERT EST REVENU, ET LA RAISON A CHANGÉ. Il avait été écarté au motif que
   la forme de la bulle suffit à reconnaître le canal et qu'un aplat vert
   casserait la page. Le premier point était faux à l'usage : sur un fond
   presque noir, une bulle bronze de 21 px ne se lit pas comme WhatsApp — elle
   se lit comme « une icône ». Le second reste vrai, et il est tenu : le vert
   ne touche QUE l'icône, la bordure et la lueur de survol. Le corps du bouton
   garde le dégradé sombre de la marque. */
.vc-gold{border-color:color-mix(in srgb,var(--gold) 40%,var(--line))}
.vc-gold .vc-i{color:var(--gold-lt)}
.vc-gold:hover,.vc-gold:focus-visible{
  border-color:color-mix(in srgb,var(--gold-lt) 72%,transparent);
  box-shadow:0 16px 46px rgba(0,0,0,.6),0 0 24px color-mix(in srgb,var(--gold) 30%,transparent)}
.vc-vert{border-color:color-mix(in srgb,var(--wa) 46%,var(--line))}
.vc-vert .vc-i{color:var(--wa)}
.vc-vert:hover,.vc-vert:focus-visible{
  border-color:color-mix(in srgb,var(--wa) 82%,transparent);
  box-shadow:0 16px 46px rgba(0,0,0,.6),0 0 26px color-mix(in srgb,var(--wa) 34%,transparent)}
.vc-vert:hover .vc-i,.vc-vert:focus-visible .vc-i{color:var(--wa-clair)}
.vc-plasma{border-color:color-mix(in srgb,var(--plasma) 44%,var(--line))}
.vc-plasma .vc-i{color:var(--accent-txt)}
.vc-plasma:hover,.vc-plasma:focus-visible{
  border-color:color-mix(in srgb,var(--accent-txt) 76%,transparent);
  box-shadow:0 16px 46px rgba(0,0,0,.6),0 0 26px color-mix(in srgb,var(--plasma) 40%,transparent)}
.vc-fab--hub{border-color:color-mix(in srgb,var(--gold) 34%,var(--line))}
.vc-fab--hub .vc-i{color:var(--gold-lt)}

.vc-menu{display:flex;flex-direction:column;align-items:flex-end;gap:10px;
  opacity:0;transform:translateY(10px);transition:.34s var(--ease)}
.vc-menu.on{opacity:1;transform:none}
/* `display:flex` ci-dessus écrase la règle par défaut du navigateur pour
   l'attribut `hidden` (un sélecteur de classe l'emporte sur `[hidden]`) : sans
   cette ligne, les deux canaux restaient VISIBLES au repos — exactement la pile
   de boutons qu'on voulait supprimer. Trouvé par le parcours visiteur réel. */
.vc-menu[hidden]{display:none}

@media (max-width:560px){
  /* Le libellé disparaît : un bouton-pilule de 130 px sur un écran de 390 px
     mange le tiers de la ligne. Le glyphe suffit — l'aria-label porte le sens.
     Les ENTRÉES DE MENU gardent leur libellé : c'est un choix, il doit se lire. */
  .vc-fab{width:52px;padding:0;justify-content:center;gap:0}
  .vc-fab > .vc-t{display:none}
}
[dir="rtl"] .vc{right:auto;left:var(--vc-gap);align-items:flex-start}
[dir="rtl"] .vc-menu{align-items:flex-start}
@media (prefers-reduced-motion:reduce){
  .vc,.vc-fab,.vc-item,.vc-menu{transition:opacity .2s linear}
  .vc-fab:hover,.vc-item:hover,.vc-fab:focus-visible,.vc-item:focus-visible{transform:none}
}

/* --- le panneau ----------------------------------------------------------
   Tiroir à droite sur grand écran, feuille en bas sur mobile. z-index 46 :
   au-dessus du tiroir panier (45) parce qu'il s'ouvre PAR-DESSUS lui, mais
   toujours sous la popup e-mail (60), qui reste prioritaire. */
.sa-panel{
  position:fixed;right:0;bottom:0;top:0;z-index:46;width:min(420px,100vw);
  display:flex;flex-direction:column;
  background:#0a090d;border-left:1px solid var(--line);
  transform:translateX(102%);transition:transform .46s var(--ease);

}
.sa-panel.on{transform:none;box-shadow:-30px 0 80px rgba(0,0,0,.6)}
.sa-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;
  padding:20px 20px 14px;border-bottom:1px solid var(--line)}
.sa-head h3{font-size:19px;margin:0}
.sa-bot{margin:5px 0 0;font-family:"JetBrains Mono";font-size:9.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--faint)}
.sa-x{background:none;border:0;color:var(--faint);font-size:26px;line-height:1;
  cursor:pointer;padding:0 4px}
.sa-x:hover{color:var(--ink)}

.sa-fil{flex:1;overflow-y:auto;padding:18px 20px;display:flex;flex-direction:column;gap:12px}
.sa-msg{max-width:88%}
.sa-msg p{margin:0;font-size:14px;line-height:1.62;border-radius:14px;padding:11px 14px}
.sa-msg--bot p{background:rgba(255,255,255,.045);border:1px solid var(--line);color:var(--ink)}
.sa-msg--moi{align-self:flex-end}
.sa-msg--moi p{background:color-mix(in srgb,var(--plasma) 22%,transparent);
  border:1px solid color-mix(in srgb,var(--plasma) 40%,transparent)}
.sa-msg--wait p{color:var(--faint)}
.sa-cta{margin-top:9px;width:100%;padding:11px 14px;border-radius:11px;cursor:pointer;
  border:1px solid color-mix(in srgb,var(--gold) 52%,transparent);
  background:color-mix(in srgb,var(--gold) 13%,transparent);color:var(--ink);
  font-family:"JetBrains Mono";font-size:10px;letter-spacing:.15em;text-transform:uppercase}
.sa-cta:hover{background:var(--gold);color:var(--night)}
.sa-cta--human{border-color:var(--line);background:rgba(255,255,255,.04)}

.sa-form{display:flex;gap:9px;padding:14px 20px 18px;border-top:1px solid var(--line)}
.sa-in{flex:1;min-height:44px;padding:11px 13px;border-radius:11px;font-size:14px;
  background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--ink)}
.sa-in:focus{outline:2px solid color-mix(in srgb,var(--accent-txt) 60%,transparent);outline-offset:1px}
.sa-go{min-height:44px;padding:0 16px;border-radius:11px;cursor:pointer;
  border:1px solid var(--line);background:rgba(255,255,255,.06);color:var(--ink);
  font-family:"JetBrains Mono";font-size:10px;letter-spacing:.14em;text-transform:uppercase}
.sa-go:hover{background:var(--ink);color:var(--night)}

@media (max-width:560px){
  /* Feuille basse : un tiroir latéral de 420 px sur un écran de 390 px est un
     plein écran qui s'annonce mal. */
  .sa-panel{top:auto;left:0;width:100vw;height:min(82vh,640px);
    border-left:0;border-top:1px solid var(--line);border-radius:18px 18px 0 0;
    transform:translateY(102%)}
}
[dir="rtl"] .sa-panel{right:auto;left:0;border-left:0;border-right:1px solid var(--line);
  transform:translateX(-102%)}
@media (prefers-reduced-motion:reduce){
  .sa-panel{transition:none}
}

/* Lien vers la page produit, depuis la fiche du parcours. Discret mais toujours
   présent : c'est la seule sortie utile d'un chapitre qui n'a rien à vendre. */
.sheet-more{display:inline-flex;align-items:center;gap:7px;margin-top:12px;
  font-family:"JetBrains Mono";font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--gold-lt);border-bottom:1px solid color-mix(in srgb,var(--gold) 40%,transparent);
  padding-bottom:3px;transition:.3s var(--ease)}
.sheet-more:hover{color:var(--ink);border-bottom-color:var(--ink)}

/* Section preuves de l'accueil : titres intermédiaires entre les deux
   composants, assez distincts pour se repérer sans concurrencer le H2. */
.proof-h{margin:48px 0 18px;font-size:clamp(15px,2vw,17px);
  font-family:"JetBrains Mono";font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--faint);font-weight:400}

/* ==========================================================================
   BANDE DOCUMENT — insérée entre deux chapitres de la scène.

   Elle ne pilote pas la caméra et n'est pas épinglée : on y lit normalement,
   au-dessus de la scène fixe, sur un fond opaque qui rend le texte confortable
   après un long parcours en 3D.
   ========================================================================== */
/* PLUS DE TRAIT, PLUS DE COUPURE.
   La bande était un rectangle opaque bordé d'un filet d'un pixel en haut et en
   bas. Posée entre deux chapitres de la scène, elle produisait exactement ce
   qu'on voyait au passage stylo -> fiole : une LIGNE HORIZONTALE, puis un autre
   univers. Le fond noir de la bande et le noir de la scène sont pourtant la
   même couleur — c'est le filet, et la franchise du bord, qui faisaient la
   coupure.
   Le fond NAÎT donc du noir de la scène et y RETOURNE : un dégradé vertical,
   transparent aux extrémités, opaque partout où il y a du texte. La zone de
   fondu est plus courte que le rembourrage de `.doc-in`, donc aucune ligne de
   texte ne se lit sur un fond en cours de disparition.
   DEUX BANDES QUI SE SUIVENT NE SE FONDENT PAS ENTRE ELLES : « Choisissez
   votre peptide » et « Vous préférez le format fiole ? » sont collées, et deux
   fondus dos à dos rouvriraient une couture au milieu. Elles forment une seule
   surface continue, qui apparaît au début de la première et disparaît à la fin
   de la seconde. */
/* LE FONDU DES BANDES RÉDACTIONNELLES EST CE QUI EFFACE LA COUTURE.
   Il valait 56 à 110 px : sur un écran de 900, la bande passait du noir plein
   au transparent en un huitième de hauteur, et l'oeil lisait une LIGNE. Le
   propriétaire l'a relevé — « une zone très noire, puis une zone grise/violette
   presque instantanément ». Le dégradé est donc étiré à 120–260 px : la même
   couleur, la même mécanique, servie sur une distance où le regard ne peut
   plus situer le changement. Rien n'est ajouté — c'est le même `linear-gradient`
   qu'avant, avec une borne différente, donc zéro coût de rendu
   supplémentaire. */
.doc-band{position:relative;z-index:3;
  --fondu:clamp(120px,17vw,260px);
  background:linear-gradient(to bottom,
    transparent 0, var(--night) var(--fondu),
    var(--night) calc(100% - var(--fondu)), transparent 100%)}
.doc-band:has(+ .doc-band){
  background:linear-gradient(to bottom,
    transparent 0, var(--night) var(--fondu), var(--night) 100%)}
.doc-band + .doc-band{
  background:linear-gradient(to bottom,
    var(--night) 0, var(--night) calc(100% - var(--fondu)), transparent 100%)}
.doc-band + .doc-band:has(+ .doc-band){background:var(--night)}
/* LE TÉMOIN DE SORTIE — la zone du bas où le fond redevient transparent.
   Il n'a ni fond, ni bord, ni contenu : il ne sert qu'à dire au script qu'on
   entre dans le dégradé de fin de bande, pour que la scène soit déjà rendue
   derrière au moment où celui-ci commence à la découvrir. Posé en absolu, il
   ne mesure rien et ne déplace rien. Créé par vp.js, décrit ici.
   SA HAUTEUR EST CELLE DU DÉGRADÉ, ET ZÉRO AILLEURS. `--fondu` n'existe que
   sur `.doc-band`. Les autres zones sobres — l'acte « certificat » — n'ont pas
   de dégradé de fin : leur témoin est une ligne sans épaisseur, et la scène
   revient quand leur bas entre dans l'écran, ni avant ni après. Sans le repli
   à 0, la déclaration serait invalide sur ces zones-là et la hauteur
   retomberait sur le contenu — c'est-à-dire sur rien de prévisible. */
.doc-sortie{position:absolute;left:0;right:0;bottom:0;height:var(--fondu,0px);
  pointer-events:none}
.doc-in{max-width:1180px;margin:0 auto;padding:clamp(64px,10vw,120px) clamp(20px,5vw,44px)}
/* ==========================================================================
   LES DEUX BANDES BOUTIQUE : L'EN-TÊTE PRENAIT UN TIERS D'ÉCRAN POUR RIEN
   --------------------------------------------------------------------------
   Titre, chapô et grille étaient empilés dans une seule colonne de lecture.
   Mesuré au 1440 : 354 px avant la première fiole, dont la moitié droite —
   750 px de large — entièrement vide. Le visiteur payait un écran de
   défilement pour arriver aux produits, et le vide donnait à la bande l'air
   d'attendre quelque chose qui ne venait pas.
   Le chapô monte donc À CÔTÉ du titre, aligné sur sa dernière ligne : c'est la
   place qu'il occupait déjà en largeur, il ne la prend plus en hauteur. Rien
   n'est retiré, rien n'est ajouté — la même copy, deux fois moins d'écran
   avant la grille, et un défilement qui avance.
   Les deux bandes bougent ensemble : ce sont les mêmes composants côte à côte,
   et n'en corriger qu'une créerait un décalage visible entre les deux. */
@media (min-width:1000px){
  #stylos .doc-in,#fioles .doc-in{
    display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);
    grid-template-areas:"e e" "t l" "g g";
    column-gap:clamp(32px,4vw,64px);align-items:end;
    padding-top:clamp(52px,6.5vw,84px)}
  #stylos .doc-in > .eyebrow,#fioles .doc-in > .eyebrow{grid-area:e}
  #stylos .doc-in > h2,#fioles .doc-in > h2{grid-area:t;margin-bottom:0}
  #stylos .doc-in > .lead,#fioles .doc-in > .lead{grid-area:l;margin:0 0 8px;max-width:none}
  #stylos .doc-in > .boutique,#fioles .doc-in > .boutique{grid-area:g}
}
.doc-in > h2{font-size:clamp(28px,5vw,52px);line-height:1.06;letter-spacing:-.02em;margin:0 0 20px}
.doc-in > .lead{max-width:58ch;color:var(--muted);font-size:clamp(15.5px,1.9vw,18px);line-height:1.65}

/* ==========================================================================
   CONTRÔLE D'ÂGE 21+

   Une seule surface, tenue au-dessus de tout, et le reste de la page rendu
   INERTE derrière — pas caché : rendu, indexable, mais hors d'atteinte tant
   que la question n'a pas de réponse. Le voile est épais parce qu'un contrôle
   d'accès qu'on peut lire à travers n'en est pas un ; il n'est pas opaque
   parce que le visiteur doit voir où il arrive.
   ========================================================================== */
.vp-age-bloque, .vp-age-bloque body{overflow:hidden}
/* PAS DE `backdrop-filter` ICI NON PLUS — ET C'ÉTAIT LE PIRE ENDROIT DU SITE.
   Cette règle floutait TOUT le viewport, à chaque image, au moment précis où
   la page est la plus chargée : premier chargement, polices en cours, scène 3D
   en construction. Un flou d'arrière-plan plein écran oblige le compositeur à
   relire et à reflouter la surface entière chaque fois que quoi que ce soit
   bouge derrière — et derrière, il y avait un canevas WebGL animé.
   Le projet avait déjà pris cette décision pour l'en-tête collant (voir plus
   haut, « Fond OPAQUE plutôt qu'un flou d'arrière-plan ») ; la porte 21+ y
   avait échappé. Le voile est maintenant simplement plus dense : à 97 %, le
   contenu passe dessous et disparaît, ce qui est exactement l'effet recherché,
   pour zéro rasterisation.
   La scène, elle, ne démarre plus derrière la question : voir vp-age.js. */
.age-ecran{position:fixed;inset:0;z-index:9000;display:grid;place-items:center;
  padding:clamp(18px,5vw,40px);
  background:color-mix(in srgb,var(--night) 97%,transparent);
  opacity:0;transition:opacity .42s var(--ease)}
.age-ecran.on{opacity:1}
.age-boite{width:min(440px,100%);text-align:center;
  border:1px solid color-mix(in srgb,var(--gold) 22%,var(--line));
  border-radius:26px;padding:clamp(28px,5vw,42px) clamp(22px,4vw,38px);
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--gold) 5%,rgba(255,255,255,.035)),
    rgba(255,255,255,.012));
  box-shadow:0 30px 90px rgba(0,0,0,.55)}
.age-marque{display:flex;align-items:center;justify-content:center;gap:10px;
  margin:0 0 22px}
.age-marque b{font-size:13px;letter-spacing:.34em;font-weight:400;color:var(--gold-lt)}
.age-logo{fill:var(--gold)}
.age-boite h2{font-size:clamp(23px,3.4vw,31px);font-weight:300;line-height:1.16;
  letter-spacing:-.01em;margin:0 0 16px;text-wrap:balance}
.age-note{color:var(--muted);font-size:13.5px;line-height:1.6;margin:0 auto;
  max-width:36ch}
.age-act{display:flex;flex-direction:column;gap:11px;margin-top:26px}
.age-act .btn{width:100%;justify-content:center}
/* Une sortie n'est pas un échec à corriger : pas de bouton pour revenir en
   arrière, pas de « êtes-vous sûr ». On l'a dit une fois. */
.age-boite--sortie h2{color:var(--muted)}
@media (min-width: 520px){ .age-act{flex-direction:row} }
@media (prefers-reduced-motion: reduce){ .age-ecran{transition:none} }

/* ==========================================================================
   MICRO-DÉMONSTRATION DU STYLO — dans la moitié basse de l'acte « format stylo »

   ELLE N'AJOUTE PAS DE HAUTEUR. `.hold` est collante et occupe le premier
   écran de l'acte, qui en fait un et demi. Le bloc qui la suit se place donc
   dans le demi-écran restant — celui qui était vide. Sa hauteur est PLAFONNÉE
   à cette place : si le texte devait déborder, c'est la vidéo qui rétrécit,
   jamais la page qui s'allonge.
   ========================================================================== */
/* La course de la colonne collante de l'acte « format stylo » : un écran, pas
   l'acte entier. Voir le commentaire dans index.html. */
.hold-piste{min-height:100vh}

.film{position:relative;display:grid;gap:clamp(18px,3vw,40px);align-items:center;
  max-height:50vh;padding:0 0 4vh;isolation:isolate}
@media (min-width:900px){ .film{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)} }
/* ==========================================================================
   LA VIDÉO N'EST PAS UN LECTEUR POSÉ SUR LE SITE
   --------------------------------------------------------------------------
   Elle en avait tout l'air : un rectangle 16/9, contour net, fond plus sombre
   que la page, coins arrondis — un widget collé au milieu d'une composition.
   Le fond de la vidéo est pourtant EXACTEMENT celui de la page (le dégradé
   `fondPage()` du banc reprend --night) : la rupture ne venait pas de
   l'image, elle venait du CADRE qu'on avait mis autour.

   On retire donc le cadre et on fond les bords. Le contour disparaît, la
   surface prend la couleur du site, et un masque éteint progressivement les
   quatre bords sur une trentaine de pixels — la vidéo n'a plus d'arête, elle
   émerge du fond. Un halo très doux, aux couleurs de l'accent, la relie à
   l'atmosphère de la section au lieu de l'en détacher.

   CE QUI NE CHANGE PAS : le rapport 16/9 réserve toujours la place avant
   l'arrivée du fichier, donc rien ne saute au chargement ; et l'image reste
   entière, aucune lisibilité n'est sacrifiée au fondu — le masque ne mord que
   sur les bords, où il n'y a que du noir. */
/* ==========================================================================
   LA VIDÉO N'A PLUS DE BORD — ELLE SE FOND DANS LE FOND
   --------------------------------------------------------------------------
   Le masque précédent était un dégradé radial à 120 % de la boîte : son
   dégradé commençait donc AU-DELÀ du cadre, et ne masquait rien. Vérifié à
   l'image : un rectangle noir à coins arrondis, contour net sur les quatre
   côtés, posé par-dessus la composition — exactement ce qu'on voulait éviter.
   Le masque est maintenant l'INTERSECTION de deux dégradés linéaires, un par
   axe : les quatre bords s'éteignent progressivement dans le fond de la page.
   Aucun filtre, aucun flou, aucune couche supplémentaire — un masque est une
   opération de composition statique, elle ne se recalcule pas au défilement. */
/* UN AXE PAR ÉLÉMENT, ET PAS DEUX MASQUES SUR LE MÊME.
   Le premier essai posait deux dégradés sur la vidéo et demandait leur
   intersection (`mask-composite`). Vérifié à l'image : la vidéo disparaissait
   entièrement — les deux modèles, le préfixé et le standard, ne composent pas
   dans le même ordre, et le résultat est vide. Deux éléments imbriqués portant
   chacun UN masque se multiplient naturellement : le cadre éteint le haut et
   le bas, la vidéo éteint la gauche et la droite. Aucune ambiguïté, aucun
   préfixe à accorder. */
.film-fig{margin:0;position:relative;border-radius:0;overflow:visible;
  border:0;background:transparent;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 14%,#000 84%,transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 14%,#000 84%,transparent 100%);
  aspect-ratio:16/9}
/* Un souffle de lumière derrière l'image, pour que le bord fondu ne se lise
   pas comme un manque. Il est SOUS la vidéo (`z-index:-1`) et ne coûte qu'un
   dégradé peint une fois. */
.film-fig::after{content:"";position:absolute;inset:-16% -10%;pointer-events:none;
  border-radius:50%;z-index:-1;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--accent) 17%,transparent) 0%,
    color-mix(in srgb,var(--accent) 6%,transparent) 55%,transparent 84%);
  opacity:.62}
.film-v{display:block;width:100%;height:100%;object-fit:cover;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 17%,#000 83%,transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 17%,#000 83%,transparent 100%)}
/* Le bouton n'apparaît qu'en mouvement réduit ou si la lecture automatique est
   refusée : il est posé au centre, sur l'affiche. */
.film-play{position:absolute;inset:50% auto auto 50%;transform:translate(-50%,-50%);
  border:1px solid var(--line);border-radius:999px;background:#0c0a10;
  color:var(--ink);font-family:"JetBrains Mono";font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;padding:12px 22px;cursor:pointer}
/* LE DERNIER `backdrop-filter` DU SITE EST PARTI D'ICI.
   Il floutait le fond d'un bouton posé SUR UNE VIDÉO : le navigateur refloute
   donc la zone à chaque image décodée, tant que le bouton est affiché. Le fond
   passe de 72 % à opaque — sur une affiche sombre, l'écart ne se voit pas — et
   le coût disparaît entièrement. */
.film-play:hover{background:var(--ink);color:var(--night)}
.film-txt{max-width:430px}
.film-txt h3{font-size:clamp(22px,3.1vw,34px);line-height:1.06;margin:.35em 0 .5em;
  letter-spacing:-.01em}
.film-lead{color:var(--ink);font-size:14.5px;line-height:1.55;margin:0 0 12px}
/* L'ARGUMENT PASSE DEVANT, LA MENTION RESTE DERRIÈRE.
   Les deux étaient au même gris et à la même taille : le visiteur lisait
   d'abord ce que la vidéo ne montre pas. La phrase qui vend est donc à la
   taille d'un argument, la mention réglementaire à celle d'une mention — elle
   reste parfaitement lisible, elle ne parle simplement plus à la place du
   produit. */
.film-claim{color:var(--ink);font-size:clamp(17px,1.5vw,20px);line-height:1.3;
  margin:0 0 10px;letter-spacing:-.01em}
.film-note{color:var(--faint);font-size:13.5px;line-height:1.5;margin:0 0 12px}
/* LE DÉTAIL TECHNIQUE, REPLIÉ. Il réutilise la pastille « approfondir » de la
   fiche produit : même geste, même objet visuel, aucun composant de plus. */
.film-plus{margin:0 0 18px}
.film-plus p{color:var(--faint);font-size:13px;line-height:1.5;margin:10px 0 0}
@media (pointer:coarse){ .film-note{font-size:12.5px} }
.film-cta{align-self:start}
@media (max-width:899px){
  /* SOUS 900 px : LA COLONNE PREND SA HAUTEUR NATURELLE, ET LA DÉMONSTRATION
     S'INSTALLE DANS LA PLACE AINSI RENDUE.

     C'est le vrai réglage, trouvé en mesurant plutôt qu'en supposant. `.hold`
     réserve UN ÉCRAN ENTIER : utile au 1440, où la colonne est centrée en face
     des trois stylos ; absurde sur un téléphone, où elle contient un titre,
     une phrase, trois faits et deux boutons, et laisse le bas vide. C'est ce
     vide — et lui seul — qui empêchait la vidéo de tenir dans l'acte.

     Deux essais ont été écartés en chemin, et ils méritent d'être nommés :
     poser le texte SUR l'image, qui ne laissait que quatre-vingts pixels de
     vidéo visible ; et masquer la liste de faits, qui retirait du contenu pour
     régler un problème de rembourrage. Ni l'un ni l'autre n'était nécessaire.
     Les trois faits restent, le texte reste sous l'image, et l'acte garde
     exactement sa hauteur d'un écran et demi. */
  #system .hold{min-height:auto;padding-bottom:3vh}
  #system .hold-piste{min-height:auto}
  /* VIDÉO ET TEXTE FORMENT UNE SEULE CARTE.
     Sans elle, le texte se lisait par-dessus les trois stylos de la scène 3D,
     encore à l'écran derrière lui à cette hauteur sur un téléphone — la même
     faute que celle corrigée sur la colonne des fioles : rien ne doit passer
     derrière un texte. La carte porte son propre fond, et la scène redevient
     ce qu'elle est ici : un décor. */
  /* FOND OPAQUE, PAS UN FLOU D'ARRIÈRE-PLAN.
     Le premier jet posait `backdrop-filter: blur(3px)` — et `tests/layout.js`
     l'a refusé, à raison : c'est précisément le genre de calque flou qui
     faisait tourner la rasterisation en permanence et ramer les machines
     modestes. Une couleur pleine cache la scène aussi bien, et ne coûte rien.
     Elle reprend le haut du dégradé peint DANS la vidéo, pour que le bord de
     l'image ne se voie pas contre la carte. */
  /* SUR TÉLÉPHONE LA CARTE RESTE, MAIS ELLE S'ADOUCIT.
     Le contour plein et le fond franc étaient là pour cacher les trois stylos
     de la scène derrière le texte : c'est toujours nécessaire, et une couleur
     pleine reste la façon la moins chère de le faire. Ce qui change, c'est
     que le fond est celui de la page et le contour presque effacé — la carte
     protège la lecture sans se présenter comme un lecteur vidéo posé là. */
  .film{gap:0;border:1px solid color-mix(in srgb,var(--line) 55%,transparent);
    border-radius:18px;overflow:hidden;background:#0a0910}
  .film-fig{border:0;border-radius:0}
  .film-fig::after{display:none}
  /* Le masque radial n'a plus lieu d'être quand l'image est bord à bord dans
     une carte : il éteindrait les coins de la carte elle-même. Seul le bas se
     fond, vers le texte qui suit. */
  .film-v{-webkit-mask-image:linear-gradient(to bottom,#000 78%,transparent 100%);
    mask-image:linear-gradient(to bottom,#000 78%,transparent 100%)}
  .film-txt{padding:16px 16px 18px}
  .film-txt h3{font-size:21px;line-height:1.1;margin:.25em 0 .45em}
  .film-lead{font-size:13px;margin-bottom:10px}
  .film-claim{font-size:16px;margin-bottom:8px}
  .film-note{font-size:12px;margin-bottom:10px}
  .film-plus{margin-bottom:14px}
  .film-plus p{font-size:12px}
}
/* Mouvement réduit : rien ne démarre tout seul. L'affiche reste, le bouton
   apparaît, et c'est le visiteur qui décide. */
@media (prefers-reduced-motion:reduce){ .film-play{display:block} }

/* ==========================================================================
   PREUVE TRUSTPILOT — une ligne dans le premier écran, pas un encart

   Le réflexe est de poser le bloc blanc de la plateforme. Sur un hero sombre,
   il se lit comme une publicité collée par-dessus le site : le visiteur voit
   d'abord qu'on lui montre un logo, pas qu'on lui montre une preuve. Ici, la
   preuve emprunte la typographie du site — la note en gros, les étoiles à
   l'échelle, le nom de la plateforme en petites capitales — et reste une
   ligne. Elle ne pousse rien, elle ne crie pas, et elle est cliquable.
   ========================================================================== */
.hero-trust{margin-top:18px;min-height:22px}
/* ==========================================================================
   LA PREUVE OUVRE LE PREMIER ÉCRAN
   --------------------------------------------------------------------------
   Le bloc était une ligne discrète sous les boutons. Il est maintenant la
   PREMIÈRE chose lue, au-dessus du titre : il doit donc se tenir seul, être
   reconnaissable d'un coup d'œil, et ne pas voler la vedette à la promesse
   qui le suit. D'où la mesure : une pastille cerclée, pas un encart plein ;
   la note en chiffres clairs, le reste en petites capitales.
   `.tp-slot` n'a AUCUNE hauteur réservée : sans note réelle le module ne rend
   rien, et la page doit alors commencer par son titre exactement comme avant —
   pas par un vide de vingt pixels qui trahirait un bloc absent.
   ========================================================================== */
/* EN HAUT, AU CENTRE, ET SANS RIEN POUSSER.
   La bande est ABSOLUE dans le hero : elle ne participe pas au flux, donc
   elle n'ajoute pas un pixel à la hauteur de la page et ne déplace pas le
   titre d'un cheveu — ce qui est exactement ce qu'on demande d'une preuve
   posée dans le premier écran. `pointer-events` est rendu au seul lien : la
   bande traverse toute la largeur et n'a aucune raison d'intercepter un clic
   destiné à la scène. */
/* LA BANDE CENTRALE EST UNE PYRAMIDE, PAS UNE LIGNE.
   Elle empile, sur un même axe et dans l'ordre de lecture, la pastille
   Trustpilot puis la ligne des clients — le monogramme du bandeau les
   surmonte et ferme la figure par le haut. `column` au lieu de `row` : c'est
   tout le changement de structure, et il tient en un mot parce que la bande
   était déjà centrée et déjà absolue.
   Elle ne pousse rien, et sans contenu elle n'occupe aucune place. */
.tp-haut{position:absolute;top:calc(var(--nav) + 10px);left:0;right:0;z-index:6;
  display:flex;flex-direction:column;justify-content:flex-start;align-items:center;
  gap:10px;pointer-events:none;padding:0 16px}
@media (max-width:520px){ .tp-haut{gap:8px;top:calc(var(--nav) + 8px)} }
.tp-haut .tp,.tp-haut .tp-origin{pointer-events:auto}
.tp-haut #heroOrigin[hidden]{display:none}
.tp-slot{display:block}
/* 44 px de haut au doigt : c'est un LIEN, et `tests/layout.js` refuse une
   cible tactile plus petite. Le rembourrage vertical est du vide utile — il ne
   change rien à l'apparence de la ligne, il la rend atteignable. */
.tp{display:inline-flex;align-items:center;gap:10px;color:var(--faint);
  font-size:13px;line-height:1;padding:6px 0;min-height:24px;
  transition:color .25s var(--ease)}
@media (pointer:coarse){ .tp{min-height:44px;padding:10px 0} }
.tp:hover{color:var(--ink)}
/* En tête de hero, la preuve se pose dans une pastille : elle se distingue du
   texte courant sans devenir une bannière publicitaire. */
.tp-slot .tp{gap:14px;padding:10px 20px;border:1px solid var(--line);
  border-radius:999px;background:rgba(255,255,255,.045)}
.tp-slot .tp:hover{border-color:color-mix(in srgb,var(--gold) 42%,transparent)}
@media (pointer:coarse){ .tp-slot .tp{padding:11px 16px} }
/* Dans l'acte des offres la pastille s'aligne à gauche, sur la colonne de
   texte : centrée, elle flotterait au milieu d'un bloc ferré à gauche. Vide,
   elle ne prend aucune place — pas de marge fantôme sous les boutons. */
/* LA LIGNE DES CLIENTS, CENTRÉE SOUS LE MONOGRAMME.
   Une ligne, une seule, dans la chasse mono du site : elle doit se lire comme
   une mention de marque, pas comme une bannière. Elle est centrée sur le logo
   parce que c'est la marque qu'elle qualifie — et elle reste au-dessus du
   titre sans jamais le toucher, la bande étant en position absolue.
   ELLE NE DOIT PAS ATTEINDRE LE PRODUIT : `max-width` la tient dans la moitié
   centrale de l'écran, là où le stylo n'entre jamais. */
.soc-haut{margin:0}
.soc-haut[hidden]{display:none}
/* ELLE ÉTAIT TROP DISCRÈTE, ET C'EST LA SEULE PREUVE CHIFFRÉE DU PREMIER
   ÉCRAN. Onze pixels en `--muted`, soit un gris à mi-chemin du fond : la
   phrase existait, elle ne se lisait pas. Trois réglages, et aucun de plus :
   la taille passe à 13 px, la couleur à 88 % de l'encre — donc au niveau du
   texte courant, pas au niveau d'un titre — et la graisse à 500 pour tenir
   l'interlettrage large sans se diluer. Le chiffre lui-même est mis en relief
   par `<b>` côté rendu ; le reste de la phrase garde sa chasse mono, qui est
   celle des mentions de marque partout ailleurs sur le site. */
.soc-l{display:inline-block;max-width:min(86vw,620px);
  color:color-mix(in srgb,var(--ink) 88%,transparent);
  font-family:"JetBrains Mono";font-size:13px;font-weight:500;letter-spacing:.12em;
  text-transform:uppercase;line-height:1.5;text-align:center}
.soc-l b{font-weight:700;color:var(--ink)}
/* ONZE PIXELS EST LE PLANCHER que `tests/layout.js` fait respecter partout sur
   écran tactile : à 390 px la ligne descend à 12 px avec un interlettrage
   resserré, ce qui la garde sur deux lignes — c'est la largeur qu'on rend,
   pas la taille du texte. */
@media (max-width:520px){ .soc-l{font-size:12px;letter-spacing:.05em;max-width:90vw} }
/* LA PROMESSE, SOUS LE CHIFFRE — plus basse d'un cran dans la hiérarchie.
   Elle est en chasse de TEXTE, pas en mono : la mono dit « mention de
   marque », et cette ligne-ci est une phrase qui se lit. Un cran plus petite
   et un cran plus discrète que le chiffre qu'elle prolonge — l'ordre de
   lecture doit rester logo, note, chiffre, promesse, sans qu'aucune des deux
   dernières ne vole la place du titre qui suit. */
.soc-p{display:block;margin-top:5px;max-width:min(88vw,52ch);
  color:var(--muted);font-size:13px;line-height:1.45;text-align:center;
  letter-spacing:0;text-transform:none;
  /* ELLE PASSE DEVANT LE STYLO SUR TÉLÉPHONE, ET LE STYLO NE BOUGERA PAS.
     Sur un écran de 390 px la bande de preuve descend jusqu'au capuchon du
     rendu 3D : la deuxième ligne se lit alors sur un fond doré clair. La
     position du stylo est gelée, la bande est en absolu — reste à rendre le
     texte lisible là où il tombe. Une ombre portée sombre coûte zéro image
     par seconde, ne se voit pas sur le fond noir, et suffit exactement là où
     il faut. Pas de `backdrop-filter` : il reflouterait son arrière-plan à
     chaque image de défilement, et c'est précisément ce qu'on a retiré
     partout ailleurs. */
  text-shadow:0 1px 12px rgba(11,10,15,.92), 0 0 4px rgba(11,10,15,.85)}
@media (max-width:520px){ .soc-p{font-size:12px;max-width:92vw;margin-top:4px} }
/* LA PASTILLE, DEUXIÈME ÉTAGE DE LA PYRAMIDE.
   Elle a occupé la colonne éditoriale, ferrée à gauche au-dessus de « Huit
   références ». Elle revient sur l'axe du monogramme : une preuve de jugement
   appartient à la MARQUE, pas au paragraphe qu'elle côtoie, et posée à gauche
   elle ouvrait une deuxième colonne de preuve en face de la première.
   Elle reste une pastille cerclée — pas une bannière — et son libellé long
   (« Voir notre profil Trustpilot ») reste retiré du rendu : il double la
   largeur pour ne rien ajouter, le lien porte déjà la phrase dans son nom
   accessible. Vide, elle ne prend aucune place. */
.tp-slot--pyr{margin:0}
.tp-slot--pyr:empty{display:none}
.tp-slot--pyr .tp{gap:12px;padding:8px 16px}
.tp-slot--pyr .tp-nom{font-size:15px}
.tp-slot--pyr .tp-star{width:18px;height:18px}
.tp-slot--pyr .tp-note b{font-size:16px}
@media (max-width:520px){
  .tp-slot--pyr .tp{padding:7px 12px;gap:9px}
  .tp-slot--pyr .tp-nom{font-size:13px}
  .tp-slot--pyr .tp-star{width:15px;height:15px}
}
/* LE RENVOI DE LA SECTION « AVIS CLIENTS », SUR LA LIGNE DU TITRE.
   Il a d'abord été un encadré posé sous le titre, avec une phrase. Il coûtait
   99 px de parcours et `tests/composition.js` l'a refusé : le plafond de
   27 écrans est la promesse de ne pas rallonger la visite, et une promesse ne
   se relève pas pour loger ce qu'on vient d'ajouter. Le renvoi va donc là où
   il y avait du VIDE — à droite du titre « Avis clients », qui est une petite
   étiquette mono seule sur sa ligne. Même marque, même vert, mêmes étoiles,
   pour le prix de la différence de hauteur entre une étiquette et une pilule.
   Sous 720 px la pilule passe à la ligne : la colonne est trop étroite pour
   les deux, et la section n'est plus comptée par le plafond de bureau. */
/* LA NOTE PASSE SOUS LE TITRE, ET ELLE GRANDIT.
   Elle était posée à DROITE du titre, sur la même ligne : c'était la place la
   moins chère en hauteur quand la section n'avait pas d'avis à montrer. Elle
   en a maintenant trois, et le propriétaire veut l'ordre de lecture d'une
   vraie section Trustpilot — le titre, puis la note, puis les avis. La ligne
   devient donc une colonne, et la pastille passe de 14 à 17 px : c'est la
   première chose qu'on lit après le titre, elle ne peut pas être la plus
   petite. */
.proof-tete{display:flex;flex-direction:column;align-items:flex-start;gap:14px;
  margin-bottom:clamp(20px,2.4vw,30px)}
.proof-tete .proof-h{margin-bottom:0}
/* LE TITRE DE LA BANDE DES AVIS EST UN TITRE, PAS UNE ÉTIQUETTE.
   `.proof-h` est un intertitre en mono de 11 px : il convient à « Sources et
   publications » ou « Questions fréquentes », qui séparent des blocs. La bande
   des avis, elle, doit CASSER le rythme de la page — c'est la demande, et
   c'est ce que fait déjà l'inversion claire des cartes. Un titre de 11 px
   au-dessus de trois cartes lumineuses annulait la moitié de l'effet.
   La règle ne vaut QUE pour ce titre-là : les autres `.proof-h` ne bougent
   pas d'un pixel. */
.proof-h--grand{font-family:inherit;font-size:clamp(28px,4.4vw,52px);
  letter-spacing:-.015em;text-transform:none;color:var(--ink);
  line-height:1.04;margin:48px 0 4px;font-weight:400;max-width:18ch}
.tp-renvoi-slot{display:flex;align-items:center}
.tp-renvoi-slot:empty{display:none}
.tp--renvoi{gap:14px;padding:10px 20px;border:1px solid var(--line);
  border-radius:999px;background:rgba(255,255,255,.055);
  transition:border-color .25s var(--ease),color .25s var(--ease)}
.tp--renvoi:hover{border-color:color-mix(in srgb,var(--gold) 42%,transparent)}
.tp--renvoi .tp-nom{font-size:17px}
.tp--renvoi .tp-star{width:20px;height:20px}
.tp--renvoi .tp-note b{font-size:19px}
.tp--renvoi .tp-glyphe{width:20px;height:20px}
/* « Voir notre profil » accompagne la marque partout où elle paraît sans
   note : en tête de hero, à l'ouverture des offres, sur la ligne des avis.
   C'est le libellé qui rend la pastille cliquable pour l'oeil. */
.tp-voir{color:var(--muted);font-size:12px;white-space:nowrap}
.tp:hover .tp-voir,.tp:focus-visible .tp-voir{color:var(--ink)}
@media (max-width:720px){ .tp--renvoi .tp-voir{display:none} }
/* ==========================================================================
   LA PREUVE SE LIT EN MOINS D'UNE SECONDE, OU ELLE NE SERT À RIEN
   --------------------------------------------------------------------------
   Elle était habillée aux couleurs du site : étoile dorée, nom en petites
   capitales très espacées, corps 10,5 px. Résultat, à l'arrivée sur la page,
   on voyait une mention discrète de plus — pas le sceau d'un tiers. Une
   preuve empruntée doit se reconnaître comme empruntée : c'est justement ce
   qui la rend crédible. On reprend donc le vert de la plateforme (#00b67a),
   ses étoiles en BOÎTES pleines avec l'étoile évidée en blanc, et son nom
   écrit comme un nom, pas comme une étiquette.
   Le vert n'apparaît nulle part ailleurs sur le site : il ne peut donc pas
   être pris pour une couleur NORYVA.
   ========================================================================== */
.tp-mark{display:inline-flex;align-items:center;gap:7px;white-space:nowrap}
.tp-nom{font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--ink)}
.tp-glyphe{width:18px;height:18px;fill:#00b67a;flex:none}
.tp-note{display:inline-flex;align-items:baseline;gap:3px;white-space:nowrap}
.tp-note b{color:var(--ink);font-size:17px;font-weight:600;letter-spacing:.01em}
.tp-sur{color:var(--muted);font-size:12.5px}
/* Le point médian qui articule « note » et « plateforme ». Discret : il
   sépare, il ne ponctue pas. */
.tp-sep{color:var(--faint);font-size:13px;line-height:1;opacity:.7}
.tp-txt{white-space:nowrap}
.tp-txt b{color:var(--ink);font-size:15px;font-weight:600}
@media (pointer:coarse){ .tp-mark{font-size:11px} }
/* Sous 420 px la pastille tient encore sur une ligne : on resserre les
   espacements plutôt que de laisser la note passer à la ligne toute seule. */
@media (max-width:420px){
  .tp-slot .tp{gap:10px;padding:9px 14px}
  .tp-nom{font-size:14px}
  .tp-glyphe{width:15px;height:15px}
  .tp-note b{font-size:15px}
}
/* LES ÉTOILES SONT DES BOÎTES REMPLIES AU PRORATA, pas des demi-caractères :
   4,2 doit se voir comme 4,2 — quatre pleines et une remplie au cinquième —
   et non comme 4,5 arrondi vers le haut. Le remplissage est posé en `width`
   par le module, à partir de la note réelle. */
/* LES ÉTOILES SONT DES BOÎTES, COMME CHEZ TRUSTPILOT — c'est la forme qu'on
   reconnaît de loin, et elle porte une information de plus que cinq étoiles
   nues : la boîte remplie au prorata dit 4,2 sans arrondir à 4,5. */
.tp-stars{display:inline-flex;gap:3px}
.tp-star{position:relative;width:21px;height:21px;display:inline-block;
  overflow:hidden;border-radius:2px;background:#4b4b55}
.tp-star i{position:absolute;inset:0;display:block;background:#00b67a}
.tp-star::after{content:"";position:absolute;inset:0;background:#fff;
  clip-path:polygon(50% 9%,61% 38%,92% 38%,67% 57%,77% 88%,50% 69%,23% 88%,33% 57%,8% 38%,39% 38%)}
@media (max-width:520px){ .tp-star{width:17px;height:17px} }

/* La mention d'origine, quand elle est documentée : une puce discrète à côté
   de la preuve Trustpilot, pas un drapeau. Elle partage la ligne — deux
   preuves valent mieux qu'une bannière. */
.hero-trust{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px}
.tp-origin{display:inline-flex;align-items:center;gap:8px;color:var(--faint);
  font-family:"JetBrains Mono";font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;border:1px solid var(--line);border-radius:999px;
  padding:7px 14px}
@media (pointer:coarse){ .tp-origin{font-size:11px} }

/* ==========================================================================
   CALCULATEUR — L'ASSISTANT, UNE QUESTION À LA FOIS
   ========================================================================== */
.cal-fil{display:flex;gap:8px;list-style:none;margin:0 0 22px;padding:0}
.cal-fil-i{width:26px;height:26px;border-radius:50%;border:1px solid var(--line);
  display:grid;place-items:center;font-family:"JetBrains Mono";font-size:11px;color:var(--faint)}
.cal-fil-i.on{border-color:var(--accent-txt);color:var(--accent-txt)}
.cal-fil-i.fait{border-color:var(--muted);color:var(--muted)}
/* UNE QUESTION PAR ÉCRAN, ET DE L'AIR AUTOUR. L'espacement est le seul outil
   qui distingue un écran premium d'un formulaire : il ne coûte rien et il se
   voit avant le premier mot. */
.cal-etape{border:0;padding:0;margin:0;display:flex;flex-direction:column;gap:22px}
.cal-etape > legend{padding:0;font-size:clamp(21px,2.6vw,28px);line-height:1.22;
  font-weight:200;color:var(--ink);margin-bottom:2px;letter-spacing:-.015em;max-width:22ch}
.cal-etape > legend:focus-visible{outline:2px solid var(--accent-txt);outline-offset:4px}
/* Le focus PROGRAMMÉ ne dessine rien : voir `versEtape` dans
   vp-calculateur.js. L'anneau revient à la première touche du clavier. */
.cal-etape > legend[data-focus-doux]:focus-visible{outline:none}
.cal-aide{margin:0;color:var(--faint);font-size:13px;line-height:1.6;max-width:60ch}
.cal-q{display:flex;flex-direction:column;gap:10px;padding:16px 0;
  border-bottom:1px solid var(--line)}
.cal-q:last-of-type{border-bottom:0}
.cal-q-t{margin:0;color:var(--ink);font-size:15px;line-height:1.5}
/* DEUX RÉPONSES, DEUX CARTES : un bouton radio de 18 px et son libellé
   demandent de viser ; une carte entière se touche. */
.cal-choix{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}
/* LES CARTES SONT CALMES, ET LA SÉLECTION EST UN HALO — PAS UN CADRE.
   Elles portaient une bordure pleine à la couleur d'accent : deux rectangles
   cerclés, côte à côte, sur un fond sombre. Vu de loin, ce n'est plus un choix
   premium, c'est un formulaire. Ce qui distingue la carte retenue est
   maintenant une bordure à peine plus claire et une lueur très basse — l'œil
   la trouve immédiatement, et rien ne crie. */
.cal-carte{display:flex;flex-direction:column;gap:7px;text-align:left;cursor:pointer;
  border:1px solid var(--line);border-radius:18px;padding:20px 22px;min-height:74px;
  background:rgba(255,255,255,.012);color:var(--ink);
  transition:border-color .35s var(--ease),background .35s var(--ease),box-shadow .35s var(--ease)}
.cal-carte b{font-weight:400;font-size:16px;letter-spacing:-.005em}
.cal-carte span{color:var(--faint);font-size:13px;line-height:1.6}
.cal-carte:hover{border-color:color-mix(in srgb,var(--accent) 32%,var(--line))}
.cal-carte.on{border-color:color-mix(in srgb,var(--accent) 55%,transparent);
  background:color-mix(in srgb,var(--accent) 7%,transparent);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 18%,transparent),
             0 12px 40px -22px var(--accent)}
.cal-carte:focus-visible{outline:2px solid var(--accent-txt);outline-offset:2px}
/* ==========================================================================
   SUR TÉLÉPHONE, LE CALCULATEUR DOIT MONTRER SA QUESTION, PAS SA NOTICE
   --------------------------------------------------------------------------
   Relevé à 390 px : l'accroche de la page occupe 106 px sur quatre lignes,
   puis 112 px de vide, puis la frise d'étapes à 465 px, puis la question à
   513. Les deux réponses commencent à 541 et la seconde sort de l'écran. Le
   visiteur voit donc un titre et un paragraphe qui EXPLIQUENT l'outil, là où
   il suffirait de le lui MONTRER — une question, deux cartes, et il a compris.

   Rien n'est retiré, rien n'est réécrit : l'accroche se resserre, l'air entre
   les deux sections se réduit, et les cartes cessent d'être des pavés. La
   description des réponses passe de `--faint` (30 %) à `--muted` (56 %) : à
   13 px sur un écran tenu à bout de bras, 30 % d'opacité n'est pas une nuance
   de gris, c'est du texte qu'on ne lit pas.
   Au-dessus de 700 px, rien ne change. */
@media (max-width:700px){
  /* LES MENTIONS RESTENT, LEUR BOÎTE PART.
     « Réservé à la recherche » et « Aucune autorisation de mise sur le marché »
     sont obligatoires et ne bougent pas d'un mot. Mais dans la colonne étroite
     du panier, et avec le plancher de 11 px des écrans tactiles, chacune se
     replie sur trois ou quatre lignes À L'INTÉRIEUR d'une pastille arrondie :
     260 px de haut par ligne de panier, davantage que le nom, la
     concentration, le prix et la quantité réunis. Sur un panier de deux
     références, le client voit un produit et demi.
     Une pastille de quatre lignes n'est plus une pastille, c'est un encadré
     qui a l'air cassé. On retire donc la BOÎTE, pas le texte : les mentions
     redeviennent de la phrase, séparées par un point médian, à la même taille
     et à la même place. */
  .cart-warn{border:0;padding:0;border-radius:0;line-height:1.5}
  .cart-warn + .cart-warn::before{content:"· ";color:var(--line)}
  /* Et elles COULENT. En boîte souple, chaque mention est un élément qui
     commence sa propre ligne : la seconde ne peut jamais finir la ligne de la
     première, et deux mentions courtes occupent quatre lignes. En flux
     ordinaire, elles se replient comme une phrase. */
  .cart-info p{display:block}
  /* L'ESPACE QUE LA BOÎTE SOUPLE DONNAIT, IL FAUT LE RENDRE.
     `gap:8px` séparait la concentration de la première mention ; en flux
     ordinaire il n'y a plus que l'espace de la chaîne, et « 50 mg » et
     « RÉSERVÉ À LA RECHERCHE » se touchent — la même soudure que celle
     trouvée sur l'accroche, au même endroit du raisonnement. */
  .cart-info p .cart-warn{margin-left:6px}
  /* ET ELLES SE COUPENT PLUTÔT QUE DE SORTIR.
     La colonne du milieu peut désormais rétrécir — c'est ce qui empêche le
     prix d'être coupé au bord de l'écran. Mais un mot plus large que la
     colonne, lui, ne rétrécit pas : « ARZNEIMITTELRECHTLICHE » fait 176 px à
     11 px en mono espacée, pour 145 px disponibles à 390. Sans cette règle il
     débordait de 56 px en allemand, 36 en russe, 26 en français — mesuré — et
     partait vers la colonne du prix.
     `anywhere` ne coupe QUE lorsqu'il n'y a pas d'autre solution, et il compte
     dans le calcul de la largeur minimale, ce que `break-word` ne fait pas.
     Une mention réglementaire coupée en deux se lit ; une mention qui passe
     sur le prix, non. */
  .cart-info p{overflow-wrap:anywhere}
  .pg .pg-lead{font-size:15px;line-height:1.62}
  .cal-carte{padding:15px 17px;min-height:0;border-radius:15px}
  .cal-carte span{color:var(--muted);font-size:13px}
  .cal-choix{gap:10px}
  .cal-garde{margin-top:16px}
}

/* LE BOUTON EST DISCRET, ET C'EST VOULU : sur un écran qui ne pose qu'une
   question, il n'a personne à convaincre — il n'a qu'à être trouvable. */
.cal-nav{display:flex;gap:12px;flex-wrap:wrap;margin-top:14px}
.cal-nav .btn{min-height:48px;padding-inline:26px}
.cal-nav .btn-acc{background:color-mix(in srgb,var(--accent) 12%,transparent);
  border-color:color-mix(in srgb,var(--accent) 45%,transparent)}
.cal-nav .btn-acc:hover{background:var(--accent);border-color:var(--accent);color:#fff}
@media (max-width:520px){
  .cal-nav{flex-direction:column-reverse}
  .cal-nav .btn{width:100%;justify-content:center}
}

/* ==========================================================================
   TÉLÉPHONE — CE QUI RESTAIT SOUS LE PLANCHER, ET LES CIBLES TROP FINES

   Le dépôt s'est fixé un PLANCHER DE 11 px sur écran tactile, appliqué
   sélecteur par sélecteur au fil des passes. Un relevé sur les dix-neuf pages
   à 390, 430 et 768 px en a trouvé deux qui n'y étaient jamais passés — les
   étiquettes des fiches techniques et l'en-tête du tableau de lot — et deux
   familles de liens dont la zone tactile fait seize pixels de haut.

   RIEN N'EST REDESSINÉ ICI. La typographie desktop ne bouge pas, les tailles
   ne bougent pas au-dessus du plancher, et aucune cible ne grossit
   visuellement : c'est la zone touchable qui s'étend.
   ========================================================================== */
@media (pointer: coarse){
  /* Étiquettes des fiches techniques et en-tête du tableau de lot : 10 px.
     Ce sont précisément les libellés qu'on lit pour VÉRIFIER une donnée —
     format, pureté, concentration — c'est-à-dire ceux qu'il faut pouvoir lire
     sans zoomer. */
  .specs dt,.coa th{font-size:11px}

  /* LES LIENS DE PIED DE PAGE ET LES SOURCES.
     Seize pixels de haut : au doigt, c'est un lien qu'on rate une fois sur
     deux — et en pied de page se trouvent le contact, les mentions et les
     accès. La ligne monte à 44 px sans que le texte bouge : c'est la BOÎTE qui
     grandit, pas la typographie. L'écart entre les lignes est repris d'autant,
     pour que le pied de page garde sa hauteur. */
  body > footer ul{gap:0}
  body > footer ul a{display:inline-flex;align-items:center;min-height:44px}
}

/* ==========================================================================
   LE RAPPEL DE L'OFFRE DE BIENVENUE

   Une fenêtre fermée emporte l'offre avec elle : le visiteur qui la referme
   par réflexe n'a plus aucun moyen d'y revenir. Ce rappel reste donc en bas
   d'écran — minuscule, discret, et il n'ouvre RIEN de lui-même : il attend un
   clic. Il disparaît définitivement dès que le visiteur s'inscrit ou commande.
   ========================================================================== */
.cap-teaser{position:fixed;left:16px;bottom:16px;z-index:34;
  border:1px solid color-mix(in srgb,var(--accent) 45%,transparent);
  background:color-mix(in srgb,var(--night) 92%,var(--accent));
  color:var(--ink);border-radius:999px;padding:11px 18px;cursor:pointer;
  font-family:"JetBrains Mono";font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  box-shadow:0 10px 30px rgba(0,0,0,.45);
  opacity:0;transform:translateY(10px);transition:.45s var(--ease);
  max-width:calc(100vw - 32px);text-align:left;line-height:1.4}
.cap-teaser.on{opacity:1;transform:none}
.cap-teaser:hover,.cap-teaser:focus-visible{border-color:var(--accent-txt)}
.cap-teaser:focus-visible{outline:2px solid var(--accent-txt);outline-offset:3px}
@media (pointer: coarse){
  /* 44 px de haut au doigt, et à GAUCHE : le bouton WhatsApp occupe déjà le
     coin bas-droit, et deux pastilles superposées valent un clic perdu. */
  .cap-teaser{min-height:44px;display:inline-flex;align-items:center;font-size:11px}
}
@media (max-width:430px){
  .cap-teaser{left:12px;right:auto;bottom:calc(12px + env(safe-area-inset-bottom,0px));
    padding:11px 15px;letter-spacing:.1em}
}

/* La première lecture d'une référence, sur la page d'accueil : trois lignes
   simples entre la phrase claire et les axes étudiés. Même trame que les axes
   — ce sont deux listes de la même famille, l'une en français de tous les
   jours, l'autre dans le vocabulaire de la recherche. */
.quoi-points{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:6px}
.quoi-points li{color:var(--ink);font-size:14px;line-height:1.55;
  padding-left:16px;position:relative}
.quoi-points li::before{content:"";position:absolute;left:0;top:.62em;
  width:6px;height:6px;border-radius:50%;background:var(--accent-txt)}
/* Le repli de la définition exacte : discret, et il ne doit surtout pas
   ressembler à un bouton d'action — c'est une note de bas de page qui s'ouvre. */
.quoi-plus{margin-top:12px}
.quoi-plus > summary{cursor:pointer;list-style:none;color:var(--faint);
  font-family:"JetBrains Mono";font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;padding:8px 0;min-height:40px;display:flex;align-items:center}
.quoi-plus > summary::-webkit-details-marker{display:none}
.quoi-plus > summary::after{content:"+";margin-left:8px;font-size:14px}
.quoi-plus[open] > summary::after{content:"–"}
.quoi-plus > summary:hover,.quoi-plus > summary:focus-visible{color:var(--accent-txt)}
.quoi-plus .quoi-def{margin:0}

/* LA MENTION D'USAGE, EN UNE LIGNE.
   Elle remplace un encadré d'alerte de cent pixels posé à hauteur du prix. La
   mention est la même, au mot près ; ce qui change est sa taille au moment où
   le visiteur décide — un pavé rouge à cet endroit dit « ne m'achetez pas ».
   Le texte complet vit dans le repli « Fiche technique et limites ». */
.warn-line{margin:0;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline;
  color:var(--muted);font-size:13px;line-height:1.55}
.warn-line b{font-family:"JetBrains Mono";font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--faint);font-weight:400}
@media (pointer: coarse){ .warn-line b{font-size:11px} }

/* ==========================================================================
   L'ACCROCHE PASSE SUR LE STYLO — ET IL FAUT QU'ELLE SE LISE
   --------------------------------------------------------------------------
   Au 1440 et au 768, la colonne de texte tient dans la moitié gauche : le
   stylo occupe la droite, rien ne se croise. Sous 700 px la colonne prend
   toute la largeur, et le stylo — noir laqué, anneau doré, reflets — passe
   DERRIÈRE le titre. Le texte reste blanc, mais son contraste change d'une
   lettre à l'autre : « simple » tombait précisément sur l'anneau.
   La capture le montre ; aucune mesure de boîte ne pouvait le voir.

   CE QU'ON NE FAIT PAS : redessiner le hero, déplacer la caméra, changer une
   ligne de texte. Le stylo reste où il est, à la taille où il est.
   CE QU'ON FAIT : poser un voile local DERRIÈRE la colonne de texte, assez
   dense sous les lettres pour rendre le contraste régulier, et transparent
   partout ailleurs — le stylo reste entier, sa pointe et son capuchon
   au-dessus du texte ne sont pas touchés.
   Il n'existe qu'en dessous de 700 px, c'est-à-dire exactement là où le
   croisement a lieu. */
@media (max-width:700px){
  #hero .hold.col{position:relative}
  #hero .hold.col::before{
    content:"";position:absolute;z-index:-1;pointer-events:none;
    left:-22px;right:-22px;top:200px;bottom:0;
    background:linear-gradient(180deg,
      transparent 0%,
      rgba(8,7,10,.55) 12%,
      rgba(8,7,10,.72) 30%,
      rgba(8,7,10,.72) 62%,
      rgba(8,7,10,.38) 82%,
      transparent 100%);
  }
}

/* LES RETOURS À LA LIGNE ÉCRITS À LA MAIN SONT POUR LE GRAND ÉCRAN.
   L'accroche du hero porte deux `<br>` : ils règlent la respiration au 1440,
   où chaque ligne tient. À 390 px la colonne est deux fois plus étroite, les
   lignes se replient d'elles-mêmes, et le retour forcé laisse un mot seul en
   fin de ligne — « … pensée pour aller » puis, à la ligne, « à l'essentiel
   sans effort. » On les neutralise au lieu de réécrire la phrase : le texte
   est le même, c'est sa coupure qui redevient celle du navigateur.

   ET L'ESPACE ? ELLE EST DANS LA CHAÎNE, PAS ICI.
   Un `<br>` ne porte aucun caractère : c'est le retour lui-même qui sépare les
   deux mots. Le masquer les recollait — « … Plus de simplicité.Une nouvelle
   technologie pensée pour allerà l'essentiel ». Deux soudures, sur le premier
   écran, dans six langues sur sept, et invisibles à la lecture du code
   puisque la chaîne, elle, était juste.
   Aucune valeur de `display` ne répare cela : dans Blink, seul `none` retire
   le retour, et `none` ne rend pas d'espace. La réparation est donc dans
   `i18n/*.json`, où chaque `<br>` de cette accroche est désormais précédé
   d'une espace ordinaire. Au grand écran elle tombe en fin de ligne et
   disparaît — rendu identique au pixel près, vérifié. Sous 700 px elle reste,
   et les mots se séparent. Le chinois en est exclu : il ne sépare pas ses
   mots par des espaces, et en ajouter une y serait la faute.
   `tests/rendu.js` monte la garde. */
@media (max-width:700px){
  .lead--lead br{display:none}
  .lead--lead br + *{margin-left:0}
}
