@charset "utf-8";
/* ==========================================================================
   VAPE ADDICT — Design system « FR-157 »
   Nommé d'après le vrai n° de lot des étiquettes : FR157-0435-…
   Palette échantillonnée sur 14 étiquettes produits réelles. Zéro couleur inventée.
   ========================================================================== */

/* ---------- 1. TOKENS ---------- */
:root {
  /* Couleurs — voir audit.md §8 */
  --ink:        #0B0B0C;   /* contour du logo graffiti — jamais #000 */
  --ink-70:     #4A4A4E;
  --ink-45:     #86868C;
  --ink-20:     #C9C7C2;
  --rule:       #DAD7D0;
  --paper:      #F1EEE8;   /* fond d'étiquette — jamais #FFF */
  --paper-pure: #FBFAF7;
  --vermillon:  #D9461A;   /* teinte dominante des étiquettes + picto -18 */
  --vermillon-d:#B03713;
  --cyan:       #0891A8;   /* segment frais / ice */
  --ambre:      #C09018;

  /* Typo */
  --display: 'Big Shoulders Display', 'Arial Narrow', sans-serif;
  --text:    'Archivo', system-ui, sans-serif;
  --mono:    'Space Mono', ui-monospace, monospace;

  /* Échelle fluide.
     --t-mega est calibrée pour que « E-LIQUIDES » (la ligne la plus longue du H1)
     tienne sur UNE ligne dans sa colonne, à toutes les largeurs. Au-delà de ~7vw
     elle se scinde en « E- / LIQUIDES ». Mesuré, pas estimé. */
  --t-mega:  clamp(2.6rem, 6.6vw, 7rem);
  --t-xxl:   clamp(2.6rem, 8vw,  7rem);
  --t-xl:    clamp(2rem,   5vw,  3.8rem);
  --t-l:     clamp(1.4rem, 2.6vw, 2rem);
  --t-body:  clamp(1rem,   1.05vw, 1.125rem);
  --t-s:     0.875rem;
  --t-xs:    0.75rem;

  /* Espacements */
  --s1: 0.5rem;  --s2: 1rem;   --s3: 1.5rem; --s4: 2rem;
  --s5: 3rem;    --s6: 4.5rem; --s7: 7rem;   --s8: 10rem;
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --maxw: 1560px;

  /* Hauteur réelle du header collant et de la barre d'action mobile.
     Ces deux valeurs étaient recopiées à la main (« 68px ») dans quatre règles :
     le panneau de nav, sa hauteur max, la nav catégories collante et le padding
     bas du body. Le header mesure en fait 70 px (68 de min-height + 2 du filet),
     et la barre 58 (56 + 2) : les quatre règles étaient donc fausses de 2 px.
     Repli codé ici, valeur exacte mesurée au runtime par app.js → syncShell(). */
  --hdr-h:  70px;
  --dock-h: 58px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --border: 2px solid var(--ink);
}

/* ---------- 2. RESET ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--text);
  font-size: var(--t-body);
  line-height: 1.55;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video, svg { display: block; max-width: 100%; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }   /* ol aussi : sinon le fil d'Ariane affiche « 1. Accueil » */

/* Le header est collant : sans cette marge, toute cible d'ancre (le lien
   d'évitement « #main » en tête, les retours de la boutique) atterrit SOUS le
   header et le premier titre reste caché. `:where` garde la spécificité à 0. */
:where([id]) { scroll-margin-top: calc(var(--hdr-h) + var(--s2)); }

:focus-visible {
  outline: 3px solid var(--vermillon);
  outline-offset: 3px;
}
::selection { background: var(--vermillon); color: var(--paper-pure); }

.skip-link {
  position: absolute; top: -100px; left: var(--gutter); z-index: 999;
  background: var(--ink); color: var(--paper-pure);
  padding: var(--s2) var(--s3); font-family: var(--mono); font-size: var(--t-xs);
  text-transform: uppercase; letter-spacing: .1em; text-decoration: none;
}
.skip-link:focus { top: var(--s2); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- 3. TYPO ---------- */
.display {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  line-height: 0.86;
  letter-spacing: -0.005em;
  font-stretch: condensed;
}
.mono {
  font-family: var(--mono);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: .12em;
}
.kicker {
  font-family: var(--mono); font-size: var(--t-xs);
  text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-45);
  display: flex; align-items: baseline; gap: var(--s2);
}
.kicker::before {
  content: attr(data-num);
  color: var(--vermillon); font-weight: 700;
}
.lead { font-size: var(--t-l); line-height: 1.35; max-width: 42ch; }
.prose p + p { margin-top: var(--s2); }
.prose a { color: var(--vermillon); text-underline-offset: 3px; }

/* Mot géant en outline qui déborde */
.outline-word {
  font-family: var(--display); font-weight: 900; text-transform: uppercase;
  font-size: clamp(5rem, 22vw, 20rem); line-height: .78;
  color: transparent;
  -webkit-text-stroke: 2px var(--ink-20);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}
.outline-word--verm { -webkit-text-stroke-color: rgba(255,255,255,.32); }

/* ---------- 4. GRILLE / SHELL ---------- */
.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--s7); }
.rule { border-top: var(--border); }

/* Grille éditoriale asymétrique — jamais tout centré */
.grid-edit {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--s6) var(--s5);
  align-items: start;
}
@media (max-width: 900px) { .grid-edit { grid-template-columns: 1fr; gap: var(--s4); } }

/* ---------- 5. BOUTONS ---------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; text-decoration: none;
  padding: 1.05rem 1.6rem;
  border: var(--border);
  background: var(--ink); color: var(--paper-pure);
  box-shadow: 6px 6px 0 var(--vermillon);           /* ombre dure décalée */
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), background .2s;
}
.btn:hover { transform: translate(3px, 3px); box-shadow: 3px 3px 0 var(--vermillon); }
.btn:active { transform: translate(6px, 6px); box-shadow: 0 0 0 var(--vermillon); }
.btn--ghost { background: transparent; color: var(--ink); box-shadow: 6px 6px 0 var(--ink-20); }
.btn--ghost:hover { background: var(--ink); color: var(--paper-pure); box-shadow: 3px 3px 0 var(--ink-20); }
.btn--verm { background: var(--vermillon); border-color: var(--ink); box-shadow: 6px 6px 0 var(--ink); }
.btn--verm:hover { box-shadow: 3px 3px 0 var(--ink); }
.btn__arrow { transition: transform .25s var(--ease); }
.btn:hover .btn__arrow { transform: translateX(4px); }

/* ---------- 6. HEADER ---------- */
.hdr {
  position: sticky; top: 0; z-index: 90;
  background: var(--paper);
  border-bottom: var(--border);
}
.hdr__in {
  max-width: var(--maxw); margin-inline: auto;
  padding: 0 var(--gutter);
  display: flex; align-items: center; justify-content: space-between;
  min-height: 68px; gap: var(--s3);
}
.hdr__logo { display: flex; align-items: center; gap: var(--s2); text-decoration: none; flex-shrink: 0; }
.hdr__logo img { width: 118px; height: auto; }
.hdr__nav { display: flex; align-items: center; gap: var(--s1); }
.hdr__link {
  font-family: var(--mono); font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: .1em; text-decoration: none; padding: .6rem .75rem;
  position: relative; white-space: nowrap;
}
.hdr__link::after {
  content: ''; position: absolute; left: .75rem; right: .75rem; bottom: .35rem;
  height: 2px; background: var(--vermillon);
  transform: scaleX(0); transform-origin: left; transition: transform .3s var(--ease);
}
.hdr__link:hover::after, .hdr__link[aria-current="page"]::after { transform: scaleX(1); }
.hdr__cta { margin-left: var(--s2); padding: .75rem 1.1rem; box-shadow: 4px 4px 0 var(--vermillon); }
.hdr__burger { display: none; padding: .6rem; border: var(--border); }
.hdr__burger svg { width: 20px; height: 20px; }

/* Bascule burger — 1040 px, et non 880.
   MESURÉ, pas choisi : la nav dépliée (logo 118 + 5 liens + panier + CTA) occupe
   949 px, plus deux gouttières de 4vw. Elle ne tient donc qu'à partir de ~1032 px.
   Entre 881 et 1032 px, le header débordait — le panier et le bouton « Commander »
   sortaient de l'écran, invisiblement, parce que `body { overflow-x: hidden }`
   rognait la preuve. Tablette en paysage et fenêtre de portable réduite : la
   plage la plus fréquentée du site.
   Le même seuil pilote la barre d'action basse : un seul point de bascule, donc
   aucune bande où le panier n'est joignable ni en haut ni en bas. */
@media (max-width: 1040px) {
  .hdr__burger { display: block; }
  .hdr__nav {
    position: fixed; inset: var(--hdr-h) 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--paper); border-bottom: var(--border);
    padding: var(--s2) var(--gutter) var(--s4);
    transform: translateY(-120%); transition: transform .4s var(--ease);
    /* on retranche aussi la barre basse : sans ça, le dernier lien du menu
       ouvert se glisse dessous et devient incliquable sur petit écran. */
    max-height: calc(100dvh - var(--hdr-h) - var(--dock-h)); overflow-y: auto;
  }
  .hdr__nav[data-open="true"] { transform: translateY(0); }
  .hdr__link { padding: 1rem 0; border-bottom: 1px solid var(--rule); font-size: var(--t-s); }
  .hdr__link::after { left: 0; right: 0; bottom: 0; }
  .hdr__cta { margin: var(--s3) 0 0; justify-content: center; }
}

/* ---------- 7. HERO ACCUEIL ---------- */
.hero {
  position: relative;
  min-height: min(92svh, 900px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  align-items: center;
  gap: var(--s5);
  max-width: var(--maxw); margin-inline: auto;
  padding: var(--s6) var(--gutter) var(--s7);
  isolation: isolate;
}
.hero__media {
  position: relative;
  aspect-ratio: 4 / 5;
  border: var(--border);
  overflow: hidden;
  background: var(--paper-pure);
}
.hero__media video, .hero__media img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.94) contrast(1.06);   /* traitement photo unifié */
}
.hero__cap {
  position: absolute; left: 0; bottom: 0; right: 0;
  background: var(--ink); color: var(--paper-pure);
  padding: .55rem .75rem;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: .08em;
  display: flex; justify-content: space-between; gap: var(--s2);
}
.hero__cap span:last-child { color: var(--vermillon); }

.hero__title { margin-bottom: var(--s4); }
.hero__title .ln { display: block; overflow: hidden; }
/* État de base : VISIBLE, sans transform.
   Le H1 ne doit JAMAIS dépendre d'une animation pour exister. Une animation
   peut ne jamais démarrer (onglet en arrière-plan, page non visible, moteur
   sans compositing) : avec `fill: backwards`, le titre resterait alors figé
   hors du cadre, donc invisible. Constaté en conditions réelles, pas supposé.
   L'animation n'est donc activée que par JS (data-anim), qui la retire aussi
   si elle n'a pas joué au bout de 2,5 s. Voir app.js → heroTitle(). */
.hero__title .ln > span {
  display: block;
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: var(--t-mega); line-height: .84; letter-spacing: -0.01em;
  transform: none;
}
.hero__title[data-anim] .ln > span { animation: rise .95s var(--ease) backwards; }
.hero__title[data-anim] .ln:nth-child(2) > span { animation-delay: .1s; }
.hero__title[data-anim] .ln:nth-child(3) > span { animation-delay: .2s; }
.hero__title em { font-style: normal; color: var(--vermillon); }
@keyframes rise { from { transform: translateY(105%); } to { transform: none; } }

.hero__kicker { margin-bottom: var(--s3); }
.hero__sub { max-width: 40ch; color: var(--ink-70); margin-bottom: var(--s4); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s3); }

.hero__scroll {
  position: absolute; left: var(--gutter); bottom: var(--s3);
  display: flex; align-items: center; gap: var(--s2);
  font-family: var(--mono); font-size: 0.66rem; text-transform: uppercase;
  letter-spacing: .14em; color: var(--ink-45);
}
.hero__scroll i {
  display: block; width: 1px; height: 34px; background: var(--ink-20);
  position: relative; overflow: hidden;
}
.hero__scroll i::after {
  content: ''; position: absolute; inset: 0; background: var(--vermillon);
  animation: scrollpulse 1.8s var(--ease) infinite;
}
@keyframes scrollpulse {
  0% { transform: translateY(-100%); } 60%,100% { transform: translateY(100%); }
}

@media (max-width: 980px) {
  .hero { grid-template-columns: 1fr; min-height: auto; padding-block: var(--s5) var(--s6); }
  /* La vidéo est en 4:5. On garde ce ratio sur mobile : en 4:3, le `cover`
     recadrait et coupait le bécher en haut et en bas. */
  .hero__media { aspect-ratio: 4 / 5; order: 2; }
  .hero__scroll { display: none; }
}

/* ---------- 8. MARQUEE ---------- */
.marquee {
  border-block: var(--border);
  background: var(--ink); color: var(--paper-pure);
  overflow: hidden; padding-block: .85rem;
  display: flex; gap: 0;
}
.marquee__track {
  display: flex; flex-shrink: 0; gap: var(--s4); padding-right: var(--s4);
  animation: slide 42s linear infinite;
  will-change: transform;
}
.marquee span {
  font-family: var(--mono); font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: .16em; white-space: nowrap;
  display: flex; align-items: center; gap: var(--s4);
}
.marquee span::after { content: '◆'; color: var(--vermillon); font-size: .6em; }
@keyframes slide { to { transform: translateX(-100%); } }
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
  .marquee { justify-content: flex-start; }
}

/* ---------- 9. STATS ---------- */
.stats {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-bottom: var(--border);
}
.stats__i {
  padding: var(--s5) var(--s3);
  border-left: var(--border);
  display: flex; flex-direction: column; gap: .35rem;
}
.stats__i:first-child { border-left: 0; }
.stats__n {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(2.6rem, 6vw, 5.2rem); line-height: .85;
}
.stats__n em { font-style: normal; color: var(--vermillon); }
.stats__l { font-family: var(--mono); font-size: var(--t-xs); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-45); }
@media (max-width: 760px) {
  .stats { grid-template-columns: 1fr 1fr; }
  .stats__i { padding: var(--s4) var(--s2); }
  .stats__i:nth-child(odd) { border-left: 0; }
  .stats__i:nth-child(n+3) { border-top: var(--border); }
}

/* ---------- 10. CARTES GAMME (numérotées) ---------- */
.range { display: grid; grid-template-columns: repeat(3, 1fr); border-top: var(--border); }
.range__c {
  border-left: var(--border);
  padding: var(--s5) var(--s4) var(--s6);
  display: flex; flex-direction: column; gap: var(--s3);
  position: relative;
  transition: background .3s var(--ease);
}
.range__c:first-child { border-left: 0; }
.range__c:hover { background: var(--paper-pure); }
.range__n {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--vermillon); font-weight: 700;
  letter-spacing: .14em;
}
.range__t {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: var(--t-xl); line-height: .9;
}
.range__spec {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-45);
  letter-spacing: .06em; line-height: 1.9;
  border-top: 1px solid var(--rule); padding-top: var(--s2);
}
.range__spec b { color: var(--ink); font-weight: 700; }
.range__p {
  font-family: var(--display); font-weight: 800; font-size: clamp(2.2rem, 4vw, 3.4rem);
  line-height: 1; margin-top: auto;
}
.range__p sup { font-family: var(--mono); font-size: .28em; vertical-align: super; letter-spacing: 0; }
@media (max-width: 900px) {
  .range { grid-template-columns: 1fr; }
  .range__c { border-left: 0; border-top: var(--border); }
  .range__c:first-child { border-top: 0; }
}

/* ---------- 11. BANDE FULL-BLEED ---------- */
.bleed {
  position: relative; overflow: hidden;
  background: var(--ink); color: var(--paper-pure);
  padding-block: var(--s7);
  border-block: var(--border);
}
.bleed--verm { background: var(--vermillon); color: var(--paper-pure); }
.bleed__word {
  position: absolute; left: -3vw; bottom: -3%;
  opacity: .5;
}
.bleed .wrap { position: relative; z-index: 1; }
.bleed .kicker { color: rgba(255,255,255,.62); }
.bleed .kicker::before { color: var(--vermillon); }
.bleed--verm .kicker { color: rgba(255,255,255,.8); }
.bleed--verm .kicker::before { color: var(--ink); }
.bleed h2 {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: var(--t-xxl); line-height: .88; margin: var(--s3) 0 var(--s4);
}
.bleed p { color: rgba(255,255,255,.78); max-width: 52ch; }
.bleed--verm p { color: rgba(255,255,255,.92); }

/* ---------- 12. SPLIT ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; min-height: 78svh; border-bottom: var(--border); }
.split__media { position: relative; overflow: hidden; border-right: var(--border); background: var(--ink); }
.split__media img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.94) contrast(1.06); }

/* Variante « document » : quand l'image EST une pièce à lire (une étiquette), on
   ne la rogne pas. `cover` la zoomait à outrance dans un panneau paysage et la
   rendait illisible. `contain` sur fond papier, avec de la marge : c'est un
   document posé sur une table, pas une photo d'ambiance. */
.split__media--doc {
  background: var(--paper-pure);
  display: grid; place-items: center;
  padding: clamp(1.5rem, 3.5vw, 3.5rem);
  padding-bottom: clamp(3rem, 5vw, 4.5rem);
}
.split__media--doc img {
  width: 100%; height: 100%;
  object-fit: contain;
  filter: saturate(.94) contrast(1.05);
}
.split__media--doc figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--ink); color: var(--paper-pure);
  padding: .6rem .9rem;
  font-size: .66rem; letter-spacing: .1em;
}
.split__body { padding: var(--s7) var(--gutter); display: flex; flex-direction: column; justify-content: center; }
.split__body h1, .split__body h2 {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: var(--t-xxl); line-height: .88; margin: var(--s3) 0 var(--s4);
}
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; min-height: auto; }
  .split__media { border-right: 0; border-bottom: var(--border); aspect-ratio: 4/3; }
  .split__body { padding-block: var(--s5); }
}

/* ---------- 13. FICHE TECHNIQUE (spec-sheet) ---------- */
.spec { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: var(--t-s); }
.spec caption { text-align: left; padding-bottom: var(--s2); color: var(--ink-45); font-size: var(--t-xs); letter-spacing: .12em; text-transform: uppercase; }
.spec th, .spec td { text-align: left; padding: .85rem .9rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
.spec thead th {
  border-bottom: var(--border); font-size: var(--t-xs); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-45); font-weight: 700;
}
.spec tbody tr:hover { background: var(--paper-pure); }
.spec a { color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--vermillon); }
.spec a:hover { background: var(--vermillon); color: var(--paper-pure); border-color: var(--ink); }
.spec__scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tag {
  display: inline-block; font-family: var(--mono); font-size: 0.66rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em;
  padding: .2rem .45rem; border: 1px solid currentColor;
}
.tag--ok { color: var(--ink-45); }
.tag--ko { color: var(--vermillon); background: var(--vermillon); color: var(--paper-pure); border-color: var(--vermillon); }

/* ---------- 14. FAQ ---------- */
.faq details {
  border-top: 1px solid var(--rule);
}
.faq details:last-of-type { border-bottom: 1px solid var(--rule); }
.faq summary {
  cursor: pointer; list-style: none;
  padding: var(--s3) 0; padding-right: var(--s4);
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: var(--t-l); line-height: 1.05;
  position: relative;
  transition: color .2s;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+'; position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  font-family: var(--mono); font-size: 1.4rem; color: var(--vermillon);
  transition: transform .3s var(--ease);
}
.faq details[open] summary::after { transform: translateY(-50%) rotate(45deg); }
.faq summary:hover { color: var(--vermillon); }
.faq details > div { padding-bottom: var(--s3); max-width: 62ch; color: var(--ink-70); }

/* ---------- 15. FOOTER ---------- */
.ftr { background: var(--ink); color: var(--paper-pure); padding-top: var(--s6); }
.ftr__warn {
  background: var(--vermillon); color: #fff;
  padding: var(--s2) var(--gutter);
  font-family: var(--mono); font-size: var(--t-xs); letter-spacing: .06em;
  display: flex; align-items: center; justify-content: center; gap: var(--s2);
  text-align: center; text-transform: uppercase; border-bottom: var(--border);
}
.ftr__grid {
  max-width: var(--maxw); margin-inline: auto; padding: 0 var(--gutter) var(--s5);
  display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: var(--s5) var(--s4);
}
.ftr h3 {
  font-family: var(--mono); font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: .14em; color: var(--vermillon); margin-bottom: var(--s2); font-weight: 700;
}
.ftr a { color: rgba(255,255,255,.72); text-decoration: none; }
.ftr a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.ftr li { padding: .28rem 0; font-size: var(--t-s); }
.ftr__logo img { width: 150px; filter: invert(1) brightness(2); margin-bottom: var(--s2); }
.ftr__addr { font-size: var(--t-s); color: rgba(255,255,255,.66); font-style: normal; line-height: 1.8; }
.ftr__addr a { color: rgba(255,255,255,.9); }
.ftr__18 {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border: 2px solid var(--vermillon); color: var(--vermillon);
  border-radius: 50%;
  font-family: var(--display); font-weight: 800; font-size: 1.15rem;
  margin-bottom: var(--s2);
}
.ftr__bot {
  border-top: 1px solid rgba(255,255,255,.14);
  padding: var(--s3) var(--gutter);
  max-width: var(--maxw); margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s3); justify-content: space-between;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: .06em;
  color: rgba(255,255,255,.44); text-transform: uppercase;
}
@media (max-width: 900px) { .ftr__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .ftr__grid { grid-template-columns: 1fr; } }

/* ---------- 16. POPUP D'ARRIVÉE (contrôle d'âge) — CSP art. L3513-5 ----------
   Une VRAIE popup : une carte posée sur le site, pas une prise d'otage plein
   écran. Le site reste visible derrière, flouté — on voit où l'on est arrivé,
   et la carte se lit comme une carte. */
.agegate {
  position: fixed; inset: 0; z-index: 999;
  display: grid; place-items: center;
  padding: var(--gutter);
  background: rgba(11, 11, 12, .62);
  backdrop-filter: blur(7px) saturate(.8);
  -webkit-backdrop-filter: blur(7px) saturate(.8);
  animation: gateIn .35s var(--ease) both;
}
.agegate[hidden] { display: none; }
@keyframes gateIn { from { opacity: 0; } to { opacity: 1; } }

.agegate__box {
  width: 100%; max-width: 620px;
  max-height: calc(100dvh - 2 * var(--gutter));
  overflow-y: auto;
  background: var(--ink);
  border: 2px solid var(--ink);
  box-shadow: 14px 14px 0 var(--vermillon);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  animation: gateCard .45s var(--ease) both;
}
@keyframes gateCard {
  from { opacity: 0; transform: translateY(18px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .agegate, .agegate__box { animation: none; }
}

.agegate__logo { width: 168px; filter: invert(1) brightness(2); margin-bottom: var(--s3); }
.agegate h1 {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(1.9rem, 5vw, 3rem); line-height: .92; color: var(--paper-pure);
  margin-bottom: var(--s2);
}
.agegate h1 em { font-style: normal; color: var(--vermillon); }
.agegate p { color: rgba(255,255,255,.66); font-size: var(--t-s); margin-bottom: var(--s3); max-width: 46ch; }
.agegate__act { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.agegate__no {
  font-family: var(--mono); font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: .12em; color: rgba(255,255,255,.5);
  padding: .5rem 0; text-decoration: underline; text-underline-offset: 4px;
}
.agegate__no:hover { color: #fff; }
.agegate__legal {
  margin-top: var(--s3); padding-top: var(--s2);
  border-top: 1px solid rgba(255,255,255,.16);
  font-family: var(--mono); font-size: 0.64rem; line-height: 1.7;
  color: rgba(255,255,255,.38); letter-spacing: .03em;
}
body[data-locked="true"] { overflow: hidden; }

/* ---------- 17. GRAIN CINÉMA ----------
   Implémenté en pseudo-élément, avec le bruit en data-URI, et SANS mix-blend-mode.

   La première version était un <svg> plein écran en `mix-blend-mode: multiply`.
   Elle FAISAIT DISPARAÎTRE TOUTES LES IMAGES DE LA PAGE — les 95 visuels produits
   compris. Isolé et prouvé au rendu : le même test avec/sans le calque de fusion
   donne 0 image / 4 images. Un effet décoratif qui gomme la marchandise n'a aucune
   valeur. Aucun mix-blend-mode plein écran sur ce site, jamais. */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 200;
  pointer-events: none;
  opacity: .055;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media (prefers-reduced-motion: reduce) { body::after { opacity: .035; } }
@media (prefers-reduced-motion: reduce) { .grain { opacity: .18; } }

/* ---------- 18. BREADCRUMB ---------- */
.crumb {
  border-bottom: 1px solid var(--rule);
  padding-block: var(--s2);
  font-family: var(--mono); font-size: var(--t-xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-45);
}
.crumb ol { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.crumb a { text-decoration: none; }
.crumb a:hover { color: var(--vermillon); }
.crumb li + li::before { content: '/'; margin-right: .5rem; color: var(--ink-20); }
.crumb [aria-current] { color: var(--ink); }

/* ---------- 19. HERO « CARTE DE VISITE » (contact) ---------- */
.card-hero {
  padding-block: var(--s7) var(--s6);
  border-bottom: var(--border);
}
.card-hero__data {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(2.6rem, 9vw, 8.5rem); line-height: .9;
  text-decoration: none; display: inline-block;
  letter-spacing: -0.01em;
  transition: color .25s var(--ease);
}
.card-hero__data:hover { color: var(--vermillon); }
.card-hero__meta {
  margin-top: var(--s5);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s4); border-top: var(--border); padding-top: var(--s4);
}
.card-hero__meta dt { font-family: var(--mono); font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .12em; color: var(--ink-45); margin-bottom: .4rem; }
.card-hero__meta dd { font-size: var(--t-s); line-height: 1.7; }
.card-hero__meta a { color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--vermillon); }

/* ---------- 20. DOCUMENT (mentions, CGV) ---------- */
.doc { max-width: 74ch; padding-block: var(--s6) var(--s7); }
.doc h1 {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: var(--t-xxl); line-height: .9; margin-bottom: var(--s2);
}
.doc h2 {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: var(--t-l); line-height: 1.05;
  margin: var(--s5) 0 var(--s2); padding-top: var(--s3);
  border-top: 1px solid var(--rule);
}
.doc p, .doc li { color: var(--ink-70); }
.doc p + p, .doc ul { margin-top: var(--s2); }
.doc li { padding-left: 1.2rem; position: relative; }
.doc li::before { content: '—'; position: absolute; left: 0; color: var(--vermillon); }
.doc dl { margin-top: var(--s2); font-family: var(--mono); font-size: var(--t-s); }
.doc dt { color: var(--ink-45); font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .1em; margin-top: var(--s2); }
.doc dd { color: var(--ink); }
.doc a { color: var(--vermillon); }
.doc__note {
  border-left: 4px solid var(--vermillon); background: var(--paper-pure);
  padding: var(--s3); margin-top: var(--s4); font-size: var(--t-s);
}

/* ---------- 21. REVEAL ----------
   Même règle que pour le H1 : l'état de base est VISIBLE. On ne masque que si
   le JS a confirmé qu'il peut animer (page réellement visible, IntersectionObserver
   disponible). Sinon un contenu caché par CSS en attendant une animation qui ne
   vient jamais reste invisible pour de bon. */
[data-reveal] { opacity: 1; transform: none; }
[data-reveal].will-reveal { opacity: 0; transform: translateY(28px); }
[data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-reveal].will-reveal { opacity: 1; transform: none; transition: none; }
  .hero__title .ln > span { transform: none; animation: none; }
  .hero__scroll i::after { animation: none; }
}

/* ---------- 22. MOBILE ≤ 480 px (couche dédiée) ---------- */
@media (max-width: 480px) {
  :root { --s7: 4rem; --s6: 3rem; }
  .btn { width: 100%; justify-content: center; box-shadow: 4px 4px 0 var(--vermillon); }
  .btn--ghost { box-shadow: 4px 4px 0 var(--ink-20); }
  .hero__actions { flex-direction: column; }
  .hero__actions .btn { width: 100%; }
  .agegate__act { flex-direction: column; align-items: stretch; }
  .agegate__act .btn { width: 100%; }
  .agegate__no { text-align: center; }
  .lead { font-size: 1.125rem; }
  .outline-word { font-size: clamp(4rem, 30vw, 8rem); }
  .ftr__warn { font-size: 0.66rem; text-align: left; }
}
@media (pointer: coarse) {
  .hdr__link, .ftr a, .crumb a { min-height: 44px; display: inline-flex; align-items: center; }
  .faq summary { min-height: 44px; display: flex; align-items: center; }
}

/* ---------- 23. NAVIGATION CATÉGORIES DE LA BOUTIQUE ----------
   Notre nav remplace celle d'Ecwid (masquée) : elle n'expose que les
   9 vraies catégories, pas les 40 fausses catégories « FDS ». */
.catnav {
  display: flex; flex-wrap: wrap; gap: 0;
  border-top: var(--border); border-left: var(--border);
}
.catnav__b {
  flex: 1 1 auto;
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em;
  padding: 1rem 1.2rem; white-space: nowrap;
  border-right: var(--border); border-bottom: var(--border);
  background: var(--paper); color: var(--ink);
  transition: background .2s var(--ease), color .2s var(--ease);
}
.catnav__b:hover { background: var(--ink); color: var(--paper-pure); }
.catnav__b[aria-current="true"] { background: var(--vermillon); color: #fff; }
@media (max-width: 640px) {
  .catnav { border-left: 0; }
  .catnav__b { flex: 1 1 50%; border-left: var(--border); border-right: 0; padding: .9rem .6rem; font-size: .66rem; }
}

/* ---------- 24. CONTENEUR DE LA BOUTIQUE ECWID ---------- */
.store {
  border-bottom: var(--border);
  padding-block: var(--s5) var(--s7);
  min-height: 60svh;
}
.store__note {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--ink-45);
  letter-spacing: .08em; text-transform: uppercase;
  padding-block: var(--s2); border-top: 1px solid var(--rule); margin-top: var(--s4);
}
.store__note b { color: var(--vermillon); }

/* ---------- 25. BANDEAU SPEC (en-tête de page interne) ---------- */
.spechead {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  border-top: var(--border); border-left: var(--border);
}
.spechead__i {
  border-right: var(--border); border-bottom: var(--border);
  padding: var(--s3);
}
.spechead__k { font-family: var(--mono); font-size: .66rem; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-45); display: block; margin-bottom: .3rem; }
.spechead__v { font-family: var(--display); font-weight: 800; text-transform: uppercase; font-size: 1.5rem; line-height: 1; }
.spechead__v em { font-style: normal; color: var(--vermillon); }

/* ==========================================================================
   COUCHE CONVERSION — rendre l'achat facile et rassurant.
   Jamais désirable par la promesse : aucune imagerie de vapotage, aucun
   « plaisir », aucune incitation. Uniquement des faits et de l'ergonomie.
   (Code de la santé publique, art. L3513-4.)
   ========================================================================== */

/* ---------- 26. PANIER (header, toutes les pages) ---------- */
.cart {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; text-decoration: none;
  padding: .7rem .9rem;
  border: var(--border);
  background: var(--paper);
  white-space: nowrap;
  transition: background .2s var(--ease), color .2s var(--ease), box-shadow .2s var(--ease);
}
.cart:hover { background: var(--ink); color: var(--paper-pure); }
.cart svg { width: 16px; height: 16px; flex: none; }
.cart__n {
  display: inline-grid; place-items: center;
  min-width: 20px; height: 20px; padding: 0 .25rem;
  background: var(--ink-20); color: var(--ink);
  font-size: .68rem; line-height: 1;
}
.cart__t { color: var(--ink-45); font-weight: 400; letter-spacing: .06em; }
.cart:hover .cart__t { color: rgba(255,255,255,.7); }
/* Panier non vide : il se signale. */
.cart[data-count]:not([data-count="0"]) {
  border-color: var(--vermillon);
  box-shadow: 4px 4px 0 var(--vermillon);
}
.cart[data-count]:not([data-count="0"]) .cart__n { background: var(--vermillon); color: #fff; }
.cart[data-count]:not([data-count="0"]) .cart__t { color: var(--vermillon); }

/* ---------- 27. BARRE DE RÉASSURANCE ---------- */
.trust {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: var(--border); border-bottom: var(--border);
  background: var(--paper-pure);
}
.trust__i {
  display: flex; align-items: flex-start; gap: .7rem;
  padding: 1.1rem var(--s3);
  border-left: 1px solid var(--rule);
}
.trust__i:first-child { border-left: 0; }
.trust__i svg { width: 18px; height: 18px; flex: none; margin-top: 2px; color: var(--vermillon); }
.trust__t { font-family: var(--mono); font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; display: block; }
.trust__d { font-size: .78rem; color: var(--ink-45); line-height: 1.4; }
@media (max-width: 900px) {
  .trust { grid-template-columns: 1fr 1fr; }
  .trust__i:nth-child(odd) { border-left: 0; }
  .trust__i:nth-child(n+3) { border-top: 1px solid var(--rule); }
}
@media (max-width: 480px) {
  .trust { grid-template-columns: 1fr; }
  .trust__i { border-left: 0; border-top: 1px solid var(--rule); padding: .9rem var(--gutter); }
  .trust__i:first-child { border-top: 0; }
}

/* ---------- 28. PORTAIL DES SAVEURS (accueil) ---------- */
.gate { display: grid; grid-template-columns: repeat(4, 1fr); border-top: var(--border); border-left: var(--border); }
.gate__c {
  border-right: var(--border); border-bottom: var(--border);
  padding: var(--s4) var(--s3) var(--s5);
  text-decoration: none;
  display: flex; flex-direction: column; gap: .4rem;
  position: relative; overflow: hidden;
  min-height: 148px;
  transition: background .25s var(--ease), color .25s var(--ease);
}
.gate__c:hover { background: var(--vermillon); color: #fff; }
.gate__n { font-family: var(--mono); font-size: .66rem; letter-spacing: .14em; color: var(--ink-45); }
.gate__c:hover .gate__n { color: rgba(255,255,255,.75); }
.gate__t {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(1.5rem, 2.4vw, 2.1rem); line-height: .95; margin-top: auto;
}
.gate__go {
  font-family: var(--mono); font-size: .66rem; letter-spacing: .1em;
  opacity: 0; transform: translateX(-6px);
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.gate__c:hover .gate__go { opacity: 1; transform: none; }
@media (max-width: 900px) { .gate { grid-template-columns: 1fr 1fr; } }
@media (max-width: 480px) { .gate__c { min-height: 110px; padding: var(--s3) var(--s2) var(--s4); } }

/* ---------- 29. NAV CATÉGORIES COLLANTE (boutique) ---------- */
.catnav--sticky {
  position: sticky; top: var(--hdr-h); z-index: 60;
  background: var(--paper);
}
@media (max-width: 1040px) { .catnav--sticky { position: static; } }

/* ---------- 30. BARRE D'ACTION MOBILE ----------
   Sur mobile, le bouton d'achat doit rester sous le pouce. */
.dock { display: none; }
@media (max-width: 1040px) {
  .dock {
    display: flex; gap: 0;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 95;
    border-top: var(--border);
    background: var(--paper);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .dock__a {
    flex: 1; display: flex; align-items: center; justify-content: center; gap: .5rem;
    min-height: 56px;
    font-family: var(--mono); font-size: .72rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .1em; text-decoration: none;
  }
  .dock__a--main { background: var(--ink); color: var(--paper-pure); }
  .dock__a--cart { border-left: var(--border); background: var(--paper); }
  .dock__a--cart[data-count]:not([data-count="0"]) { background: var(--vermillon); color: #fff; }
  .dock__a svg { width: 16px; height: 16px; }
  /* La barre mesure 58 px (56 + filet) et grandit encore de la hauteur de la
     zone sûre sur iPhone à encoche. Avec l'ancien `56px` fixe, elle recouvrait
     en permanence la dernière ligne du pied de page — SIREN et mentions. */
  body { padding-bottom: calc(var(--dock-h) + env(safe-area-inset-bottom)); }
  /* le panier du header laisse la place au burger : il vit dans la barre basse,
     sous le pouce. Les deux bascules partagent le même seuil, donc il y a
     toujours exactement UN panier visible, jamais zéro. */
  .hdr .cart { display: none; }
}

/* ---------- 31. POPUP D'ARRIVÉE — les arguments dans l'age gate ----------
   On ne montre PAS deux modales d'affilée : le contrôle d'âge est déjà
   obligatoire à l'arrivée (CSP art. L3513-5), les arguments s'y greffent.
   Aucun champ e-mail : une newsletter pour des produits du vapotage est une
   publicité au sens de l'art. L3513-4, et elle est interdite. Décidé avec le
   client, tracé dans le README. */
.agegate__box {
  max-height: calc(100dvh - 2 * var(--gutter));
  overflow-y: auto;
}
.agegate__facts {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  margin-top: var(--s4);
  background: rgba(255, 255, 255, .14);   /* les filets de la grille */
  border: 1px solid rgba(255, 255, 255, .14);
}
.agegate__facts li {
  display: flex; align-items: flex-start; gap: .65rem;
  padding: .9rem 1rem;
  background: var(--ink);
}
.agegate__facts svg { width: 17px; height: 17px; flex: none; margin-top: 2px; color: var(--vermillon); }
.agegate__facts b {
  display: block;
  font-family: var(--mono); font-size: .7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--paper-pure);
}
.agegate__facts span { font-size: .76rem; color: rgba(255, 255, 255, .55); line-height: 1.4; }
@media (max-width: 560px) {
  .agegate__facts { grid-template-columns: 1fr; }
  .agegate__facts li { padding: .75rem .9rem; }
  .agegate__logo { width: 150px; margin-bottom: var(--s3); }
}

/* ---------- 32. PREUVES D'ORIGINE ----------
   « Made in France » est le mot le plus galvaudé du commerce. On ne le clame pas :
   on pose les pièces, chacune vérifiable par le lecteur — jusqu'au lien vers le
   registre de l'État. La confiance se donne, elle ne se réclame pas. */
.proof {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: var(--border); border-left: var(--border);
}
.proof__c {
  border-right: var(--border); border-bottom: var(--border);
  padding: var(--s4) var(--s3) var(--s4);
  display: flex; flex-direction: column; gap: var(--s2);
  background: var(--paper);
  transition: background .25s var(--ease);
}
.proof__c:hover { background: var(--paper-pure); }
.proof__n {
  font-family: var(--mono); font-size: .64rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--vermillon); font-weight: 700;
}
.proof__t {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(1.6rem, 2.6vw, 2.2rem); line-height: .95;
}
.proof__d { font-size: var(--t-s); color: var(--ink-70); line-height: 1.55; }
.proof__d strong { color: var(--ink); }
.proof__l {
  margin-top: auto; padding-top: var(--s2);
  font-family: var(--mono); font-size: .66rem; letter-spacing: .08em;
  text-transform: uppercase; text-decoration: none;
  color: var(--ink); border-top: 1px solid var(--rule);
  transition: color .2s var(--ease);
}
.proof__l:hover { color: var(--vermillon); }
@media (max-width: 1000px) { .proof { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px)  { .proof { grid-template-columns: 1fr; border-left: 0; }
                             .proof__c { border-left: var(--border); } }

/* ==========================================================================
   33. COUCHE RESPONSIVE — corrections mesurées
   Chaque règle ci-dessous répond à un défaut constaté au rendu, à une largeur
   donnée. Aucune n'est préventive.
   ========================================================================== */

/* ---------- 33.1 REGISTRES EN FICHES SOUS 640 px ----------
   Les tableaux (registre FDS 38 lignes × 4 colonnes, fiche technique de
   fabrication) mesurent 434 px de large. Sous 430 px, ils imposaient un
   défilement latéral — et la colonne « Document », celle qui porte le lien de
   téléchargement, tombait hors écran. L'action était donc hors de portée
   exactement là où elle compte le plus.

   Sous 640 px, chaque ligne devient une fiche : la préparation en titre, les
   autres colonnes en paires libellé/valeur. On ne perd rien du registre — on
   le tourne de 90°. Les libellés sont repris des `<th scope="col">` par
   app.js → stackTables(), qui pose alors `data-stack`. Sans JS, l'attribut
   n'existe pas et l'on retombe sur le tableau à défilement : dégradation
   propre, jamais d'écran vide. */
@media (max-width: 640px) {
  .spec__scroll[data-stack] { overflow-x: visible; }

  [data-stack] .spec,
  [data-stack] .spec tbody,
  [data-stack] .spec tr,
  [data-stack] .spec th,
  [data-stack] .spec td { display: block; width: auto; }

  [data-stack] .spec thead {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  [data-stack] .spec caption { display: block; }

  [data-stack] .spec tbody tr {
    border: var(--border);
    margin-top: -2px;                      /* filets fusionnés, comme la grille produits */
    padding: var(--s2);
    background: var(--paper);
  }
  [data-stack] .spec tbody tr:hover { background: var(--paper); }

  [data-stack] .spec tbody th[scope="row"] {
    padding: 0 0 .55rem;
    border-bottom: 1px solid var(--rule);
    font-family: var(--display); font-weight: 800; text-transform: uppercase;
    font-size: 1.3rem; line-height: 1.05; letter-spacing: -0.005em;
  }
  [data-stack] .spec tbody td {
    padding: .55rem 0 0; border-bottom: 0;
    display: grid; grid-template-columns: 6.5rem minmax(0, 1fr);
    gap: var(--s2); align-items: baseline;
    /* sans ça, le badge de statut et le lien de téléchargement deviennent des
       items de grille étirés : le cadre du `.tag` s'allongeait sur toute la
       colonne — on lisait un champ de saisie vide — et le filet vermillon du
       lien courait sous le vide à droite du texte. */
    justify-items: start;
  }
  [data-stack] .spec tbody td::before {
    content: attr(data-col);
    font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
    color: var(--ink-45);
  }
  /* le lien de téléchargement redevient une vraie cible, pleine largeur */
  [data-stack] .spec tbody td a {
    display: inline-flex; align-items: center; min-height: 44px;
  }
}

/* ---------- 33.2 CIBLES TACTILES ----------
   Mesuré au doigt, pas au curseur : ces éléments tombaient entre 16 et 38 px de
   haut alors que la cible minimale utilisable est 44. */
.proof__l {
  display: flex; align-items: center; min-height: 44px;
}
.hdr__logo { min-height: 44px; }
/* Le téléphone de la page contact est un lien tel: — la cible d'appel du site.
   Mesuré à 37 px de haut : l'interligne de 0,9 écrase la boîte sous le glyphe. */
.card-hero__data { min-height: 44px; }
.agegate__no {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px;
}
@media (pointer: coarse) {
  .card-hero__meta a,
  .doc a,
  .prose a,
  .store__note a { display: inline-block; padding-block: .35rem; }
}

/* ---------- 33.3 PLANCHER TYPOGRAPHIQUE MOBILE ----------
   Le système descend jusqu'à 0,64 rem (10,2 px) — lisible sur un 27 pouces à
   50 cm, illisible sur un téléphone tenu à bout de bras. Sous 480 px, rien ne
   passe sous 0,72 rem (11,5 px). Le rythme du mono est conservé : on ne change
   que la taille, jamais la graisse ni l'interlettrage. */
@media (max-width: 480px) {
  .proof__n,
  .proof__l,
  .gate__n,
  .gate__go,
  .spechead__k,
  .hero__cap,
  .ftr__bot,
  .tag,
  .cart__n,
  .split__media--doc figcaption,
  figcaption.mono { font-size: 0.72rem; }
  .catnav__b { font-size: 0.72rem; }
  /* Le bandeau nicotine est une mention légale permanente (CSP art. L3513-4) :
     c'est la ligne du site qui a le moins le droit d'être illisible. La couche
     mobile §22 le descendait à 0,66 rem — 10,56 px sur téléphone. Il remonte au
     plancher comme le reste. Cette règle vient APRÈS §22 à dessein : même
     spécificité, c'est l'ordre qui tranche. */
  .ftr__warn { font-size: 0.72rem; }
}

/* Le portail des saveurs passe à deux colonnes de 159 px sous 900 px. À 320 px,
   « Les Gourmands » et « Les Classiques » mesuraient 131 et 128 px de rendu dans
   une boîte de 125 : les deux se faisaient rogner. Le plancher de `--t-l` ne
   descendait pas assez bas pour ces deux libellés. */
@media (max-width: 360px) {
  .gate__t { font-size: 1.3rem; }
}

/* ---------- 33.4 TITRES DES BANDES PLEINE LARGEUR ----------
   `--t-xxl` vaut 8vw : elle est calibrée sur la largeur de la FENÊTRE. Or les
   h2 des quatre bandes `.bleed` vivent dans la colonne de 5/12 d'une
   `.grid-edit` — jamais en pleine largeur. Au-dessus de 900 px, où la grille
   passe à deux colonnes, le titre gardait donc une échelle pleine largeur dans
   une demi-colonne. Débordement mesuré à TOUTES les largeurs de bureau :
   394 px de texte dans 373 de colonne à 1024, 539 dans 532 à 1440. Les groupes
   « <<&nbsp;fabricant&nbsp;>> », « un document&nbsp;? » sont insécables — c'est
   l'espace fine française, on ne la supprime pas — donc rien ne pouvait se
   replier.

   On échelonne sur la COLONNE (unité `cqi`) et non sur la fenêtre. Sous 901 px
   la grille est déjà sur une colonne et l'échelle d'origine tient : on n'y
   touche pas. La règle est portée par `.bleed .grid-edit` uniquement, jamais
   par `.bleed` seul : sans conteneur déclaré, `cqi` retomberait sur le viewport
   et donnerait l'inverse de l'effet voulu. */
@media (min-width: 901px) {
  .bleed .grid-edit > * { container-type: inline-size; }
  .bleed .grid-edit h2 { font-size: clamp(2.6rem, 17cqi, 7rem); }
}

/* ---------- 33.5 FLÈCHE NON ORPHELINE ----------
   « Vérifier sur annuaire-entreprises.data.gouv.fr → » laissait la flèche seule
   sur sa ligne à 320-390 px. L'espace insécable est posé dans le HTML ; ici on
   garantit que l'URL, elle, a le droit de se couper. */
.proof__l { overflow-wrap: anywhere; }
