/* =====================================================================
   Denichor — socle fonctionnel commun aux six variations.

   Ce fichier ne porte AUCUNE opinion visuelle : ni couleur de marque, ni
   échelle typographique, ni ombre, ni rayon. Il porte seulement :
     1. les polices, servies en local (aucun CDN, aucun blocage de rendu) ;
     2. une remise à zéro moderne ;
     3. les utilitaires d'accessibilité ;
     4. la géométrie du moteur d'explication (le projecteur, la voix) ;
     5. la règle de mouvement réduit.

   Chaque variation habille ensuite les classes `dnG-*` à sa manière.
   Si une couleur de marque apparaît ici, c'est un défaut.
   ===================================================================== */

/* ---------- 1. Les polices, en local ---------- */

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('polices/fraunces-normal.woff2') format('woff2-variations');
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url('polices/fraunces-italic.woff2') format('woff2-variations');
}
@font-face {
  font-family: 'General Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('polices/general-sans-400.woff2') format('woff2');
}
@font-face {
  font-family: 'General Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('polices/general-sans-500.woff2') format('woff2');
}
@font-face {
  font-family: 'General Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('polices/general-sans-600.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('polices/jetbrains-400.woff2') format('woff2');
}

/* ---------- 2. Remise à zéro ---------- */

*, *::before, *::after { box-sizing: border-box; }

/* `hidden` doit gagner sur toute regle d'affichage. Sans cela, un panneau
   masque reapparait des qu'une variation lui donne un `display`. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-synthesis-weight: none;
  overflow-x: clip;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ul, ol {
  margin: 0;
  padding: 0;
}

/* LE REFUS DU GRAS SE TIENT AUSSI CONTRE LE NAVIGATEUR.

   Les six variations refusent la graisse 700. Le navigateur, lui, rend
   `h1`…`h6`, `b` et `strong` à 700 par défaut : un titre sur lequel
   personne n'a pensé à écrire une graisse arrive donc en gras, et le refus
   fuit par la porte de service. Mesuré sur v2 : « Opportunités » et
   « Console de réglage », les deux titres de l'écran principal, rendus à
   700 alors que la variation entière est bâtie sur 300 et 500.

   `inherit` plutôt qu'une valeur : le socle ne choisit pas la graisse des
   variations, il empêche seulement le navigateur de la choisir à leur
   place. Chaque système garde la main, et une règle de classe existante
   continue de gagner. */
h1, h2, h3, h4, h5, h6, b, strong { font-weight: inherit; }

ul, ol { list-style: none; }

img, svg, video, canvas, picture {
  display: block;
  max-width: 100%;
}

img { height: auto; }

button, input, select, textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

a { color: inherit; text-decoration: none; }

table { border-collapse: collapse; border-spacing: 0; width: 100%; }

/* Les chiffres s'alignent sur la virgule partout où on les compare. */
.dn-num, td.dn-num, .dn-tab td, .dn-tab th {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* ---------- 3. Accessibilité ---------- */

.dn-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Le lien d'évitement : premier élément tabulable de chaque page. */
.dn-evite {
  position: fixed;
  top: 0; left: 50%;
  transform: translate3d(-50%, -120%, 0);
  z-index: 9999;
  padding: 12px 22px;
  transition: transform 180ms cubic-bezier(.2,.7,.2,1);
}
.dn-evite:focus-visible { transform: translate3d(-50%, 12px, 0); }

/* Aucune cible tactile sous 44 px : la règle est ici, pas dans chaque page.
   Elle s'applique sur un vrai pointeur grossier ET au format téléphone :
   une règle qui ne se déclenche que sur un appareil tactile ne peut pas
   être vérifiée par la recette, donc elle ne peut pas être prouvée. */
@media (pointer: coarse), (max-width: 699px) {
  /* ET `min-height` NE FAIT RIEN SUR UNE BOÎTE `inline`.

     La règle était écrite, présente dans le style calculé, et sans le moindre
     effet : un juré d'intégration a mesuré 1 054 contrôles sous 44 px sur les
     114 écrans à 390 px, dont 200 liens « ouvrir sur Vinted » à 13×16 px dans
     le mur de preuve — un douzième de la surface minimale. `getComputedStyle`
     répondait bien `min-height: 44px` sur chacun.

     Une hauteur minimale ne s'applique qu'à une boîte de bloc. `display:
     inline-block` la rend effective sans changer le flux du texte, et
     `min-width` couvre l'autre axe : le bouton de navigation de v3 mesurait
     25×44, conforme sur une dimension et pas sur l'autre.

     Leçon écrite au protocole : une déclaration n'est pas une mesure. La
     recette compare désormais des rectangles rendus, pas des feuilles. */
  a, button, [role='button'], [role='tab'], input[type='checkbox'], input[type='radio'], summary {
    display: inline-block;
    min-height: 44px;
    min-width: 44px;
  }
  /* Ceux qui portent déjà une disposition la gardent : `inline-block` ne doit
     pas casser une grille ni un `flex` posé par une variation. */
  a:where([class*='grille'], [class*='rang'], [class*='carte'], [class*='ligne'],
    [class*='fiche'], [class*='lot'], [class*='brique'], [class*='tuile'],
    [class*='vignette'], [class*='case'], [class*='pave']),
  button:where([class*='grille'], [class*='rang'], [class*='carte'], [class*='ligne'],
    [class*='fiche'], [class*='lot'], [class*='brique'], [class*='tuile'],
    [class*='vignette'], [class*='case'], [class*='pave']) {
    display: revert;
  }
  /* LE LIEN DANS UNE PHRASE NE PEUT PAS DEVENIR UNE BOÎTE DE 44 PX.

     Après la correction ci-dessus, il restait 201 cibles trop petites sur
     v1/produit, toutes de la même espèce : `.lien-texte`, un lien DANS une
     phrase. Le passer en `inline-block` l'empêcherait de se couper en fin de
     ligne, et casserait la justification de tout le paragraphe pour gagner
     une zone de frappe. Le remède serait pire que le mal.

     Sur une boîte `inline`, un rembourrage vertical agrandit la zone de
     frappe SANS toucher à la hauteur de la ligne : 17 px de texte deviennent
     45 px de cible, et le paragraphe ne bouge pas d'un pixel. La marge
     négative annule le débordement de peinture. */
  a.lien-texte, a:not([class]) {
    display: revert;
    min-height: 0;
    min-width: 0;
    padding-block: 14px;
    margin-block: -14px;
  }
  .dn-tactile-libre { min-height: 0; min-width: 0; }
}

/* ---------- 4. Le moteur d'explication : géométrie seulement ---------- */

.dnG {
  position: fixed;
  inset: 0;
  z-index: 9000;
  pointer-events: none;
}
.dnG[data-phase='ouvert'] { pointer-events: auto; }

/* ET LE VOILE RECOUVRAIT LES COMMANDES DU GUIDE.

   Mesure, guide ouvert : sur l'ecran des opportunites de trois variations,
   `document.elementFromPoint` au centre d'une pastille rend `div.dnG__voile`.
   Le voile est la couche qui assombrit la page ; il passait au-dessus de la
   voix, donc au-dessus du rail d'etapes et des commandes. Les cinq pastilles
   etaient inatteignables, avec la bonne taille et le bon nom.

   Aucune couche n'avait de rang declare : elles se rangeaient par l'ordre du
   DOM, que chaque variation pouvait defaire. Les rangs sont donc poses ici,
   une fois : le voile dessous, le trou et le halo au milieu, la voix dessus. */
.dnG__voile {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  transition: opacity 260ms cubic-bezier(.2,.7,.2,1);
}
.dnG[data-phase='ouvert'] .dnG__voile,
.dnG[data-phase='bilan'] .dnG__voile { opacity: 1; }

/* Le trou : un rectangle positionné en `transform`, jamais en `top/left`. */
.dnG__trou,
.dnG__halo {
  position: absolute;
  top: 0; left: 0;
  width: 0; height: 0;
  z-index: 2;
  pointer-events: none;
  will-change: transform, width, height;
  transition:
    transform 420ms cubic-bezier(.16,.84,.24,1),
    width 420ms cubic-bezier(.16,.84,.24,1),
    height 420ms cubic-bezier(.16,.84,.24,1),
    opacity 220ms linear;
}
.dnG[data-sanscible] .dnG__trou,
.dnG[data-sanscible] .dnG__halo { opacity: 0; }

.dnG__voix {
  position: absolute;
  top: 0; left: 0;
  width: min(360px, calc(100vw - 32px));
  z-index: 3;
  pointer-events: auto;
  will-change: transform;
  transition: transform 420ms cubic-bezier(.16,.84,.24,1), opacity 220ms linear;
  opacity: 0;
}
.dnG[data-phase='ouvert'] .dnG__voix { opacity: 1; }

/* Sur téléphone la voix se pose en bas et libère la moitié haute pour la cible. */
.dnG[data-format='telephone'] .dnG__voix,
.dnG__voix[data-pose='bas'] {
  top: auto;
  bottom: 0;
  left: 0;
  width: 100%;
  transform: none !important;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.dnG__rail { display: flex; gap: 6px; }

/* UN PAS DE TROIS PIXELS DE HAUT NE SE TOUCHE PAS.

   Mesuré, guide ouvert : `.dnG__pas` fait 60 par 3 px et le test de contact
   rend 0 sur 4 aux deux planchers — 24 px comme 44. C'est un onglet cliquable,
   `role="tab"`, nommé « Étape 1 sur 5 », et il était inatteignable à la souris
   comme au doigt. Cinq par guide, sur les six variations, sur chaque écran.

   La garde des cibles ne le voyait pas : elle mesure ce qui est VISIBLE, et le
   guide est fermé au repos. Une garde qui ne regarde que l'état par défaut ne
   prouve rien sur ce qui s'ouvre.

   Le trait garde ses trois pixels — c'est une jauge, elle doit rester fine —
   et sa zone de contact est étendue par un pseudo-élément qui ne se voit pas.
   La boîte ne bouge donc pas d'un pixel, et le rail ne grossit pas. */
/* ET LA ZONE DE CONTACT VIVAIT SUR `::after`, QUE LES VARIATIONS EMPLOIENT
   POUR LEUR TRAIT.

   Mesure, guide ouvert et choregraphie posee : quatre variations sur six
   atteignent leurs cinq pastilles aux quatre points cardinaux. v4 en atteint
   deux sur quatre — elle redefinit `::after` pour dessiner son trait de deux
   pixels, ce qui EFFACE la zone de contact du socle. v2 n'en atteint aucun.

   La zone vit donc sur `::before`, que rien ne redefinit, et le rail ne rogne
   plus ce qui depasse. Le trait garde ses trois pixels : la boite dessinee ne
   bouge pas d'un pixel, et le rail ne grossit pas. */
/* J'AI ESSAYE DE DONNER AU RAIL SON PROPRE RANG, ET C'EST PIRE.

   `.dnG__rail, .dnG__pieds, .dnG__bilan { position: relative; z-index: 3 }`
   creait un contexte d'empilement de plus : v1, qui atteignait ses cinq
   pastilles, n'en atteignait plus aucune. La regle est retiree, et l'echec est
   ecrit ici plutot que dissimule. */
.dnG__rail { overflow: visible; }
.dnG__pas { flex: 1 1 auto; position: relative; }
.dnG__pas::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 24px;
  transform: translateY(-50%);
  z-index: 1;
}
@media (pointer: coarse), (max-width: 699px) {
  .dnG__pas::before { height: 44px; }
}

.dnG__pieds { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.dnG__nav { display: flex; align-items: center; gap: 8px; }

.dnG__bilan {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate3d(-50%, -50%, 0);
  width: min(520px, calc(100vw - 32px));
  max-height: min(78vh, 620px);
  overflow: auto;
  pointer-events: auto;
}
.dnG[data-format='telephone'] .dnG__bilan {
  left: 0;
  top: auto;
  bottom: 0;
  transform: none;
  width: 100%;
  max-height: 82vh;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* L'élément visé est remonté au-dessus du voile, sans le déplacer d'un pixel. */
[data-dnG-vise] {
  position: relative;
  z-index: 9010;
}

/* ---------- 5. Mouvement réduit ---------- */

/* MESURÉ, ET C'EST UN PIÈGE À RETENIR.

   Ce bloc écrivait `transition-duration: 1ms`. Une transition d'une
   milliseconde reste une TRANSITION : le navigateur en crée l'objet, et cet
   objet, tant qu'il n'a pas avancé d'une image, impose sa première valeur
   PAR-DESSUS tout le reste — y compris un style en ligne. Une animation en
   cours bat toutes les déclarations CSS, c'est sa nature.

   Conséquence constatée sur `compte.html` : la scène posait proprement
   `opacity: 1` en ligne sur sa phrase de bilan, le calculé restait à 0, et la
   phrase « 1 compteur touche le plafond de ton plan » n'existait pour
   personne — précisément pour l'utilisateur qui a demandé moins de mouvement.

   `transition: none` ne crée aucun objet. Il n'y a plus rien qui puisse se
   figer sur une première image, donc plus rien qui puisse effacer un état
   final correctement posé. On coupe la transition, jamais le résultat. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* Le même effet, demandé explicitement par l'utilisateur ou par ?statique=1.
   L'état final reste PROPRE : on coupe la transition, jamais le résultat. */
html[data-mouvement='reduit'] *,
html[data-mouvement='reduit'] *::before,
html[data-mouvement='reduit'] *::after {
  animation-duration: 1ms !important;
  animation-iteration-count: 1 !important;
  transition: none !important;
}


/* =====================================================================
   AUCUNE MARQUE DE GRAPHIQUE NE SE PEINT EN NOIR PAR DÉFAUT

   Une forme SVG sans `fill` déclaré se remplit de `#000000` : c'est le
   défaut du moteur, pas une décision de design. Mesuré sur la matrice
   prix contre vitesse du Radar, posée sur la surface de nuit : les
   bulles des prix RÉELLEMENT OBSERVÉS sortaient à 1,11:1 sur le fond
   sombre. Les données observées étaient invisibles sur l'écran qui
   existe pour les montrer, parce que le repeint de nuit avait couvert
   `.g-ded` et `.g-inc` et oublié `.g-obs`.

   La doctrine dit déjà tout : l'encre est ce qui a été observé, l'or ce
   qu'on en déduit, le hachuré ce qu'on ne sait pas — et chacune de ces
   trois classes porte déjà sa `color`. Il suffit que le remplissage la
   suive. Les marques qui veulent autre chose (`.g-obs.g-courbe`,
   `.g-obs.g-corps`…) le déclarent avec deux classes et gagnent.

   Écrit dans le socle, donc vrai pour les six variations, y compris
   pour les graphiques que personne n'a encore dessinés.
   ===================================================================== */

/* `:where()` et non `svg .g-obs`. La première écriture pesait (0,1,1) et
   battait donc les règles d'une variation qui déclare sa doctrine à une
   seule classe. Mesuré : v6-mur écrit `.g-obs`, `.g-ded` et `.g-inc` en
   (0,1,0) — mon repli les écrasait toutes les trois. L'or de la déduction
   disparaissait, et pire, `.g-inc { fill: none }` était écrasé : la marque
   qui dit « on ne sait pas » se remplissait comme une donnée observée.
   Un défaut d'honnêteté introduit par une réparation d'honnêteté.

   `:where()` a une spécificité nulle : la règle vaut (0,1,0) mais perd
   contre toute déclaration locale par l'ordre de cascade, puisque le socle
   est chargé avant la feuille de la variation. Un repli doit céder devant
   ce qu'il complète — sinon ce n'est pas un repli, c'est une prise de
   pouvoir. */
:where(svg) .g-obs,
:where(svg) .g-ded,
:where(svg) .g-inc { fill: currentColor; }

/* =====================================================================
   LES DEUX ÉTATS QUE PERSONNE NE DESSINAIT

   Le squelette de chargement et le bandeau hors-ligne, posés ici parce
   qu'ils appartiennent aux six variations. Le socle donne la GÉOMÉTRIE et
   le MOUVEMENT ; chaque variation les habille avec ses jetons, ou les
   laisse tels quels — ils empruntent `currentColor` et se fondent.
   ===================================================================== */

/* ---------- Le squelette ---------- */

.dn-os { display: block; }
.dn-os__ligne {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor 10%, transparent);
}
.dn-os__ligne--simple { gap: 16px; }
.dn-os__ligne--pile { flex-direction: column; align-items: stretch; gap: 8px; }
.dn-os__col { display: flex; flex-direction: column; gap: 6px; flex: 1 1 0; min-width: 0; }
.dn-os__col--fin { align-items: flex-end; flex: none; }

/* Le bloc ne clignote pas : une lueur le TRAVERSE. Un clignotement dit
   « attends » ; un balayage dit « ça arrive », et il ne fatigue pas l'œil
   d'un utilisateur qui ouvre l'application quinze fois par jour. */
.dn-os__bloc {
  display: block;
  border-radius: 3px;
  background: color-mix(in srgb, currentColor 9%, transparent);
  position: relative;
  overflow: hidden;
  flex: none;
}
.dn-os__bloc::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translate3d(-100%, 0, 0);
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, currentColor 7%, transparent) 50%,
    transparent 100%);
  animation: dn-os-passe 1400ms linear infinite;
}
@keyframes dn-os-passe { to { transform: translate3d(100%, 0, 0); } }

/* ---------- Le bandeau hors-ligne ---------- */

/* Le bandeau s'ancre AU-DESSUS de la navigation basse. Mesuré à 390 px :
   posé à 16 px du bas, il couvrait 46 des 62 px de la rampe et recouvrait
   entièrement la barre de panier. Annoncer la panne en mangeant la
   navigation, c'est ajouter une panne à la panne.

   `--dn-bas-libre` est la prise que chaque variation redéfinit avec la
   hauteur de sa propre rampe : le socle ne connaît pas la rampe, mais il
   lui laisse une place. */
.dn-hors {
  position: fixed;
  left: 50%;
  bottom: calc(var(--dn-bas-libre, 16px) + 16px);
  z-index: 9020;
  max-width: min(560px, calc(100vw - 32px));
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor 28%, transparent);
  border-radius: 10px;
  background: Canvas;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .14);
  font-size: 13px;
  line-height: 1.5;
  transform: translate3d(-50%, 140%, 0);
  opacity: 0;
  transition: transform 320ms cubic-bezier(.16, .84, .24, 1), opacity 320ms;
}
.dn-hors[data-ici='oui'] { transform: translate3d(-50%, 0, 0); opacity: 1; }

/* La pastille est un anneau creux, pas un point plein : elle dit « le lien
   est rompu », là où un point plein dirait « un état est actif ». */
.dn-hors__p {
  flex: none;
  width: 10px;
  height: 10px;
  margin-top: 4px;
  border: 2px solid currentColor;
  border-radius: 50%;
  opacity: .55;
}
.dn-hors__t { min-width: 0; }

/* La phrase qui accompagne le squelette : elle dit ce qui se passe, elle
   ne remplace aucun contenu existant. Elle disparaît avec lui. */
.dn-os__dit { padding: 16px 16px 0; font-size: 13px; }

/* La ligne d'une DÉFINITION, dans le centre de guides.

   Sans couleur ni graisse propre : la variation l'habille par ses jetons,
   comme le reste de ce socle. Le seul réglage posé ici est la mesure de
   lecture — une définition qu'on lit sur cent caractères de large n'est
   pas une définition, c'est un mur. */
.g-def {
  max-width: 68ch;
  line-height: 1.55;
  margin: 0 0 .5em;
}
.g-def:last-child { margin-bottom: 0; }

/* =====================================================================
   UN REFUS QUI N'EMPÊCHE RIEN N'EST PAS UN REFUS

   Le bandeau hors-ligne annonçait trois actions suspendues et posait
   `aria-disabled="true"` sur les gestes concernés. Un juré d'intégration a
   fait ce que je n'avais pas fait : il a CLIQUÉ. Résultat mesuré sur 33
   écrans, un bouton « refusé » reçoit et exécute quand même le clic —
   `aria-disabled` est une annonce pour les aides techniques, jamais une
   serrure. Aucune feuille ne posait `pointer-events: none`.

   Pire, la moitié des variations ne le rendait même pas visible : deux
   d'entre elles stylent `.b[aria-disabled]`, mais l'une emploie `.cmd`, et
   trois n'ont aucune règle. Le bandeau affirmait en mots ce que
   l'interface démentait en gestes — un défaut d'honnêteté introduit par une
   réparation d'honnêteté.

   La règle vit ici, dans le socle, parce qu'elle doit valoir partout sans
   dépendre du nom qu'une variation donne à ses boutons.
   ===================================================================== */
/* ET UN REFUS NE SE DIT PAS EN EFFAÇANT LE TEXTE QUI L'EXPLIQUE.

   `opacity: .5` était le signal visuel de ce refus. Mesuré par un juré
   d'intégration le 31 juillet, sur le fond réel : l'encre secondaire, déjà
   à 65 % d'alpha, tombe à **2,09:1** une fois l'élément à demi transparent
   — pour un plancher de 4,5:1 qui ne se négocie pas. Or c'est ce texte qui
   porte l'instruction : « cette action a besoin du serveur ». Le produit
   effaçait la phrase qui dit pourquoi il refuse.

   Le refus se dit donc autrement, et de trois façons qui ne coûtent aucun
   contraste : le geste est bloqué (`pointer-events`), le curseur l'annonce,
   et le bord devient un trait interrompu — la convention du « pas
   maintenant » sur du papier. `aria-disabled` continue de le dire aux aides
   techniques, et `title` porte la raison.

   Correction de sûreté : elle vaut pour les six variations. */
[aria-disabled='true'] {
  pointer-events: none;
  cursor: not-allowed;
  border-style: dashed;
}
/* Un conteneur désactivé ne doit pas rendre son contenu inatteignable au
   clavier : le focus reste possible, seul le geste est refusé. */
[aria-disabled='true']:focus-visible { pointer-events: auto; }

/* =====================================================================
   L'INVITATION À L'EXPLICATION — géométrie seulement

   Elle existe parce qu'un juré revendeur a chronométré ce que coûtait
   l'ancienne façon : un voile plein écran à 1,1 s, quinze fois par jour.
   Celle-ci ne prend RIEN : pas de voile, pas de défilement, aucun élément
   de la page touché.

   TROIS MESURES ONT CORRIGÉ CE QUE SON PREMIER COMMENTAIRE PROMETTAIT.
   Il annonçait « une bande de 44 px, sous l'en-tête ». Mesuré : **53 px à
   1 512 et 200 px à 390**, soit **24 % d'un écran de téléphone**, posée en
   BAS. Un commentaire qui annonce un chiffre sans l'avoir mesuré est un
   mensonge de plus, et celui-là a survécu à deux tours de jury.

   Elle est donc bornée à deux lignes, son texte se coupe proprement, et ses
   boutons tiennent 44 px à toutes les tailles — pas seulement au doigt.

   ET ELLE APPARTIENT À LA VARIATION. Elle était blanche plate avec un rayon
   de 8 px : un aplat sur la variation qui refuse l'aplat, un rayon sur celle
   qui refuse le rayon. Le seul élément présent sur les dix-neuf écrans était
   le seul à contredire leur doctrine. Elle se lie maintenant aux jetons, et
   ne retombe sur une valeur neutre que si la variation n'en propose pas.
   ===================================================================== */
.dnG-invite {
  position: fixed;
  left: 50%;
  bottom: calc(var(--dn-bas-libre, 16px) + 16px);
  transform: translateX(-50%);
  z-index: 8500;
  display: flex;
  align-items: center;
  gap: 12px;
  max-height: 96px;
  max-width: min(92vw, 640px);
  padding: 8px 12px;
  border: 1px solid var(--filet-porteur, currentColor);
  /* UN CONTRAT EXPLICITE, PAS UNE DEVINETTE. Le socle ignore comment chaque
     variation nomme ses jetons — l'une dit `--papier`, l'autre `--plaque`,
     une troisieme `--feuille` ; l'une nomme son rayon `--a-champ`, une autre
     `--a-puce`. Deviner, c'est retomber au hasard sur une valeur neutre et
     poser un aplat blanc a rayon de huit sur la variation qui refuse les
     deux. Chaque variation DECLARE donc ce que l'invitation doit porter. */
  border-radius: var(--dn-invite-rayon, 2px);
  background: var(--dn-invite-fond, Canvas);
  color: var(--dn-invite-encre, CanvasText);
  font-size: 13px;
  line-height: 1.35;
}
.dnG-invite__t {
  flex: 1 1 auto;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.dnG-invite__b {
  flex: 0 0 auto;
  /* 44 px SANS CONDITION. La version d'avant ne les donnait qu'au doigt : au
     clavier et à la souris, la sortie faisait 32 px de haut. */
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--dn-invite-filet, currentColor);
  border-radius: var(--dn-invite-rayon, 2px);
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.dnG-invite__b:hover { background: var(--lisiere, transparent); }
@media (max-width: 699px) {
  /* Sur téléphone la bande reste sur UNE ligne de texte : deux lignes plus
     deux boutons empilés faisaient 200 px, soit le quart de l'écran, posés
     par-dessus les chiffres qu'on venait d'ouvrir. */
  .dnG-invite { max-height: 60px; gap: 8px; padding: 6px 8px; }
  .dnG-invite__t { -webkit-line-clamp: 2; font-size: 12px; }
  .dnG-invite__b { padding: 0 8px; }
}

/* L'AVEU D'UNE DÉCISION QUI NE S'EXÉCUTE PAS.

   Il se pose AU-DESSUS de la décision qu'il conteste, jamais en dessous : un
   lecteur qui parcourt en diagonale lit la recommandation avant l'avertissement
   si l'ordre est inverse. Sans couleur propre — chaque variation l'habille par
   ses jetons — et sans rouge : ce n'est pas une erreur, c'est une mesure qui ne
   passe pas la règle du produit. */
.dn-aveu-dj {
  max-width: 74ch;
  margin: 0 0 var(--dn-aveu-marge, 16px);
  padding: 10px 12px;
  border-left: 3px solid currentColor;
  font-size: 13px;
  line-height: 1.5;
}

/* LA VÉRITÉ DES FRAIS, POSÉE SOUS LE TITRE DES ÉCRANS DE DÉCISION.

   Le socle ne porte aucune opinion visuelle : cette règle ne fixe donc que la
   GÉOMÉTRIE et emprunte ses couleurs aux jetons de la variation qui l'accueille.
   Un filet à gauche pour la distinguer du corps de texte, et rien d'autre. */
.dn-verite-frais {
  max-width: 78ch;
  margin-block: 12px 0;
  padding-inline-start: 12px;
  border-inline-start: 2px solid currentColor;
  font-size: 13px;
  line-height: 1.55;
  /* PAS D'OPACITÉ SUR UN TEXTE QUI PORTE UN AVERTISSEMENT.

     `opacity: .82` sur 13 px mesurait 4,36:1 et 4,41:1 selon la variation,
     sous le seuil de 4,5:1. Une nuance se porte par la couleur du jeton, que
     chaque variation a mesurée, jamais par un voile qui divise tout. */
}
.dn-verite-frais b { font-weight: inherit; }
/* LE REPLI EST FAIT A LA MAIN : LA CHARTE REFUSE LE `<details>` NATIF.

   Trois manifestes publient ce refus, et le controleur porte la regle — mais
   il lit la source, et ce repli-ci etait CONSTRUIT a l'execution par le
   noyau : trente ecrans affichaient le triangle du navigateur pendant que
   l'instrument rendait vert. Un bouton, une region qu'il commande, et le
   clavier qui marche parce qu'un bouton EST focusable. */
.dn-verite-frais__t {
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: start;
}
/* LE LIBELLE DU REPLI NE SE COUPE PAS EN DEUX.

   Vu a l'oeil sur `v1-…-produit-1512.png` : « …il peut etre negatif. Qui /
   paie quoi » — trois mots casses au bout d'une phrase d'avertissement, ce qui
   les fait lire comme la suite de la phrase plutot que comme le geste qu'ils
   commandent. Un libelle de commande tient sur une ligne ou passe entier a la
   suivante ; il ne se partage pas. */
.dn-verite-frais__plus {
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
}
.dn-verite-frais__t[aria-expanded='true'] .dn-verite-frais__plus { display: none; }
.dn-verite-frais p { margin-top: 4px; }
/* Sur l'ordinateur la place ne manque pas : le repli s'ouvre d'office et le
   titre redevient la première phrase du paragraphe. */
@media (min-width: 700px) {
  .dn-verite-frais__t { min-height: 0; display: block; }
  .dn-verite-frais > p { display: inline; }
  /* LA SOUDURE, TROISIEME FOIS — ET LA DERNIERE, PARCE QU'ON CESSE DE COMPTER
     LES JOINTS.

     Cette regle passait tous les `<p>` en `inline` et n'espacait QU'UN joint,
     celui d'apres le titre. Tant qu'il n'y avait qu'un paragraphe, ca marchait.
     Le tour 7 en a ajoute deux — le chiffre sorti du repli, puis la variante
     nue — et les joints non espaces sont revenus : « …dans Reglages.Sur
     Vinted » et « …peut etre negatif.Acheter », mesures 19 fois sur 19 et
     visibles a l'oeil sur cinq captures.

     Deux fois j'ai repare UN joint. On espace donc TOUS les paragraphes qui
     se suivent, quel que soit leur nombre : la regle ne depend plus de la
     structure, elle depend de la seule chose qui compte — deux blocs de
     phrase colles l'un a l'autre sur une meme ligne. */
  /* ET UN JOINT QUI N'EXISTE PAS NE SE SOUDE PAS.

     `.dn-verite-frais__t + p::before` visait le paragraphe qui suit le
     bouton. Or la règle six lignes plus haut met ce bouton en
     `display: block` : les deux ne sont JAMAIS sur la même ligne, mesuré
     `memeLigne:false` sur 18 blocs sur 18. La fine n'y soudait donc rien —
     elle ouvrait une ligne, et deux jurés ont mesuré le même retrait de
     2,72 px en tête du paragraphe d'argent, sur seize blocs sur dix-huit.

     Une espace insécable en tête de ligne ne se supprime pas : c'est
     exactement pour cela qu'on l'avait choisie. Le bord gauche du bloc
     devenait irrégulier au milieu d'un paragraphe, sur les écrans où l'on
     demande sa confiance au lecteur.

     Réparer un joint deux fois de suite apprend à compter les joints ;
     le troisième apprend à vérifier qu'il y en a un. */
  .dn-verite-frais > p + p::before {
    /* UNE ESPACE ORDINAIRE SE FAIT MANGER, ET J'AI MIS TROIS TOURS A LE VOIR.

       `content: ' '` produit une espace COLLAPSIBLE. En tête d'une boîte
       en ligne qui suit un saut de ligne dans la source, le navigateur la
       supprime — la règle existe, elle est appliquée, et elle ne pose rien.

       Pire : elle est INVISIBLE aux deux mesures ordinaires. `textContent`
       ne voit pas le contenu généré ; `innerText` insère un `\n\n` entre
       deux `<p>` même en `display: inline`. Ma vérification annonçait donc
       « 0 soudure sur 108 rendus » pendant qu'un juré mesurait 18 blocs
       soudés sur 18, à 1512 comme à 834, avec un écart de 0,00 px entre les
       deux runs de texte.

       La seule mesure qui pouvait voir : la GÉOMÉTRIE. Deux mots sur la même
       ligne, à zéro pixel l'un de l'autre, sont collés — quoi qu'en disent
       les deux représentations textuelles.

       Une espace insécable ne se fait pas manger. */
    content: '\00a0';
  }
}

/* Le repli d'un panneau au téléphone : géométrie seulement, les couleurs
   viennent de la variation qui l'accueille. */
.dn-replie-tel__t {
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: inherit;
  text-align: start;
}
.dn-replie-tel__t::after {
  content: '▾';
  margin-left: auto;
  transition: transform 180ms cubic-bezier(.2,.7,.2,1);
}
.dn-replie-tel__t[aria-expanded='true']::after { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .dn-replie-tel__t::after { transition: none; }
}

/* ---------- LES TROIS ÉTATS : VIDE, ERREUR, QUOTA ----------

   Le socle ne porte aucune opinion visuelle : cette règle ne fixe que la
   GÉOMÉTRIE et emprunte ses couleurs aux jetons de la variation d'accueil.
   Chaque `systeme.css` habille ensuite `.dn-etat--vide`, `--erreur` et
   `--quota` à sa manière — un état qui aurait l'air pareil sur les six ne
   serait pas un état, ce serait un encart. */
.dn-etat {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 24px;
  border: 1px solid currentColor;
  border-radius: 10px;
  max-width: 72ch;
}
.dn-etat__t { font-size: 17px; line-height: 1.3; }
.dn-etat__c { font-size: 14px; line-height: 1.55; }
.dn-etat__p { font-size: 13px; line-height: 1.5; opacity: .82; }
/* Le filet de gauche dit lequel des trois on regarde, sans couleur : la
   couleur appartient aux variations, la forme au socle. */
.dn-etat--vide { border-inline-start-width: 3px; }
.dn-etat--erreur { border-inline-start-width: 3px; border-style: solid dashed dashed solid; }
.dn-etat--quota { border-inline-start-width: 3px; border-style: solid; border-top-style: dashed; }
@media (max-width: 699px) {
  .dn-etat { padding: 16px; }
}

/* Le repère « tu es ici » du ruban des marchés : une forme, jamais une
   couleur de valeur. Le socle ne fixe que la géométrie du trait ; sa teinte
   vient de `currentColor`, donc du système d'accueil. */
.g-ici { stroke: currentColor; stroke-width: 1.5; opacity: .72; }

/* ---------- LA VIDÉO DE FOND ----------

   Le socle ne fixe que la géométrie et la garantie de lisibilité : une boucle
   posée derrière du texte doit être voilée, sinon elle vole le contraste que
   le reste du produit défend. Chaque variation choisit son voile et son
   opacité — c'est là que le parti pris se joue. */
.dn-fond-video {
  position: absolute;
  inset: 0 0 auto 0;
  width: 100%;
  height: 100%;
  /* UNE BOUCLE PLUS HAUTE QUE LA FENETRE EST UN PLEIN ECRAN.

     `SOURCES.md` promet « jamais en plein écran ». Mesuré aux trois formats,
     la boucle de v6 occupait **117 %, 111 % et 178 %** de la fenêtre : elle
     n'était pas un fond, elle était le fond de tout. La promesse n'était pas
     tenue, et le registre ne donnait qu'une seule géométrie — celle de 1512 —
     en la présentant comme LA géométrie.

     Une boucle ne dépasse donc jamais 82 % de la hauteur visible. Au-delà,
     l'hôte garde sa couleur : le média accompagne une scène, il ne la
     remplace pas. Les cinq autres étaient déjà sous cette limite ; seule v6
     bouge, et c'est celle qui débordait. */
  max-height: 82vh;
  object-fit: cover;
  z-index: 0;
  pointer-events: none;
}
/* Le contenu passe devant, toujours : une vidéo de fond qui recouvre son
   propre texte est un décor, pas un média. */
/* PAS D'ENCRE TRANSPARENTE AU-DESSUS D'UNE BOUCLE.

   Une encre à 60 ou 64 % laisse passer plus d'un tiers du fond. Sur du papier
   uni, la nuance est jolie et le contraste tient. Sur une image — même voilée
   — le fond n'est plus uniforme, et la même encre tombe à 2,30:1, 2,44:1,
   2,55:1. Mesuré sur les six hôtes, une fois l'alpha enfin composée dans le
   calcul au lieu d'être ignorée.

   Le socle interdit donc l'alpha sur le texte posé au-dessus d'une boucle :
   la nuance se porte par la COULEUR du jeton, que chaque variation a mesurée,
   jamais par un voile qui divise tout. C'est la même règle que celle déjà
   posée sur la vérité des frais, étendue à son vrai périmètre. */
.dn-fond-hote,
.dn-fond-hote * { opacity: 1; }
/* `rgb(from …)` retire l'alpha SANS toucher a la teinte : l'or reste l'or, le
   gris reste gris, et seule la transparence part. Un `color-mix` a 100 % ne
   ferait rien du tout — il recopierait l'alpha avec le reste, ce que j'ai
   ecrit d'abord. */
.dn-fond-hote :is(p, span, b, i, em, strong, h1, h2, h3, h4, li, dt, dd, td, th, a, button, label) {
  color: rgb(from currentColor r g b);
}

.dn-fond-hote { position: relative; isolation: isolate; }
.dn-fond-hote > *:not(.dn-fond-video):not(.dn-fond-voile) { position: relative; z-index: 2; }
.dn-fond-voile { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  /* Le poster reste, la boucle ne part pas : le noyau ne pose alors aucune
     source, et cette règle empêche toute reprise par le navigateur. */
  .dn-fond-video { animation: none !important; }
}

/* Le chiffre du coût réel : même famille que la mécanique qu'il suit, mais il
   porte un nombre, donc il se détache d'un cran. */
.dn-verite-frais__chiffre {
  margin: var(--e2, 8px) 0 0;
  font-size: .8125rem;
  line-height: 1.5;
}

/* La cale du séparateur de milliers : elle ne remplace pas la fine, elle
   l'épaissit. Sa largeur est posée EN LIGNE par le noyau, mesurée dans la
   fonte exacte de l'élément — une valeur en `em` réparait une variation et
   en dégradait une autre, parce que les polices ne donnent pas la même
   largeur à U+202F. */
.dn-cale-mille { display: inline-block; width: 0; }

/* La version nue de la vérité des frais : l'avertissement et le chiffre, sans
   le repli — les écrans qui l'affichent expliquent déjà la mécanique. */
.dn-verite-frais--nue { display: block; }
.dn-verite-frais__avert { margin: 0; }
.dn-verite-frais--nue .dn-verite-frais__chiffre { margin-top: var(--e2, 8px); }


/* ---------- LE FLOU D'ARRIÈRE-PLAN NE SERT QU'UNE FOIS DÉFILÉ ----------

   Un `backdrop-filter` oblige le navigateur à composer TOUT ce qui se trouve
   derrière avant de peindre l'élément. Mesuré sur v1/aujourdhui : l'estrade
   couvre 76 000 px² au-dessus du pli, et l'écran met 603 ms entre la fin de
   ses scripts et son premier pixel — contre 121 ms sur v5 et -145 ms sur v6,
   qui n'ont aucun élément filtré au-dessus du pli.

   Or en haut de page, il n'y a RIEN derrière une barre fixe : le flou ne
   montre rien, il coûte. Il n'a de sens que lorsque du contenu passe dessous.

   Le socle éteint donc le flou tant que la page n'a pas défilé, et
   `DN.noyau` pose `data-defile="oui"` au premier pixel de défilement. Ce
   n'est pas un compromis visuel : à zéro de défilement, les deux rendus sont
   identiques au pixel près, puisqu'il n'y a rien à flouter. */
/* UNE LISTE DE NOMS DE CLASSES N'EST PAS UNE REGLE, C'EST UN INVENTAIRE.

   Premier jet : cinq sélecteurs nommés, ceux que j'avais vus. Un juré a
   mesuré ce qui restait : **32 éléments filtrés au-dessus du pli à défilement
   zéro**, sur neuf classes différentes — `traverse`, `rampe`, `barre`,
   `reglette`, `passerelle`, `hors__tete`, `outils`, `ee-hors__tete`,
   `ee-regie`. Et `[class*='assise']`, que j'avais écrit, ne correspondait à
   aucun élément filtré : j'avais deviné.

   Le raisonnement ne porte pas sur des noms. Il porte sur un fait : **à
   défilement zéro, il n'y a rien derrière une barre fixe**. Il vaut donc pour
   TOUT élément, connu ou non, présent ou à venir.

   Une exception, et une seule : les voiles de la couche d'explication, qui
   couvrent la page ENTIÈRE — derrière eux il y a du contenu dès le premier
   pixel, et leur flou fait son travail. */
html:not([data-defile='oui']) *:not(.dnG):not(.dnG *) {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* TROIS GRAS AU PLUS, SINON LE GRAS NE DIT PLUS RIEN.

   Deux jurés ont mesuré la même chose au tour 9 : la phrase du coût alignait
   onze montants dont neuf distincts, et `emphases: []` — pas un gras, pas un
   corps différent. Le lecteur devait trier tout seul entre le prix affiché,
   la part fixe, la protection, le port, la revente et ce qui reste.

   Ne portent la marque que les deux nombres qui décident : ce que l'achat
   coûte VRAIMENT, et ce qui resterait ou serait perdu. La graisse reste sous
   700 comme la charte l'impose ; c'est le poids relatif qui parle, pas le
   noir.

   ET LE SELECTEUR PORTE DEUX CLASSES, PARCE QUE `.dn-verite-frais b` EXISTE.
   Le bloc pose `.dn-verite-frais b { font-weight: inherit }` vingt lignes plus
   haut — 0-1-1 contre 0-1-0. La regle courte etait parsee, l'element la
   matchait, et le poids calcule restait 400. Une sonde ecrite pour trouver la
   concurrente a repondu « aucune » : c'est la LECTURE DU FICHIER qui l'a
   donnee. Un instrument neuf ne se croit pas sur parole non plus. */
.dn-verite-frais .dn-verite-frais__cle { font-weight: 600; }

/* UNE PERTE NE SE DISTINGUE PAS D'UN GAIN PAR LA SEULE COULEUR.

   Un juré novice a mesuré que « tu perdrais 35,20 € » et « il te resterait
   6,80 € » se composaient au pixel près à l'identique. Le soulignement tient
   en niveaux de gris, ne coûte pas un pixel de hauteur, et ne dépend d'aucun
   jeton de variation — chaque système garde la main sur la couleur s'il veut
   en ajouter une. */
.dn-verite-frais .dn-verite-frais__perte {
  /* ET LE SOULIGNE APPARTIENT A LA COMMANDE.

     Le montant de la perte etait souligne a 2 px, le repli « Qui paie quoi »
     a 1 px, meme decalage de 3 px : deux epaisseurs du meme trait. Un jure du
     tour 11 a clique sur le montant.

     Sur le web, un mot souligne veut dire « clique ici » — c'est la
     convention la plus ancienne du support, et elle appartient a la couche de
     la commande. Une perte n'est pas un geste : c'est un chiffre qui fait
     mal, et il doit se voir sans emprunter le vocabulaire d'un bouton.

     Un lavis de surligneur ne dit « cliquable » nulle part, tient en niveaux
     de gris, ne coute pas un pixel de hauteur et laisse chaque variation
     libre d'y poser sa propre teinte. */
  background: rgba(23, 19, 12, .07);
  box-shadow: 0 0 0 2px rgba(23, 19, 12, .07);
  border-radius: 2px;
}

/* CE BLOC A ETE RETIRE : IL DOUBLAIT CELUI DE LA SECTION 3.

   Ecrit au tour 15 pour poser un plancher tactile de 44 px au telephone, sans
   avoir lu que la section 3 de ce meme fichier le pose depuis un tour
   precedent — avec plus de soin : `display: inline-block` pour rendre la
   hauteur minimale effective, une liste de classes de disposition qui gardent
   leur `display`, et l'echappatoire `.dn-tactile-libre`.

   Troisieme fois de la session que j'ajoute un mecanisme a cote d'un mecanisme
   existant faute de l'avoir lu : apres `?etat=` contre `etats.js`, apres
   `DN.etats` contre `?faim=`. La regle est simple et je l'ecris ici pour la
   troisieme fois : LIRE LE FICHIER AVANT D'Y AJOUTER.

   Ce qui restait a reparer apres la section 3 tenait en trois cas nommes, tous
   traites a leur place : la pince de v4 qui interceptait fermee, les pastilles
   de regie de v6 sous le plancher, et `.lot__titre` de v1 a 38 px. */

/* =====================================================================
   CE QUI SE LIT SANS SE VOIR

   Une légende de table, un format attendu, le nom d'une région : des
   phrases que l'œil n'a pas besoin de lire parce que la mise en page les
   dit autrement, et qu'un lecteur d'écran doit entendre.

   `display: none` les ferait disparaître des deux côtés. La technique qui
   marche : une boîte d'un pixel, découpée, hors du flux — visible pour
   l'arbre d'accessibilité, invisible à l'écran, et sans effet sur la mise
   en page.

   Elle redevient visible au foyer clavier : un lien d'évitement masqué
   qu'on ne voit jamais est un lien qu'on ne peut pas suivre.
   ===================================================================== */
.dn-lu-seulement {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.dn-lu-seulement:focus-visible {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  clip-path: none;
  white-space: normal;
}

/* CE QUI MANQUE SE LIT COMME UNE PHRASE, PAS COMME UN RÉSIDU.

   La passe `direCeQuiManque` écrit une ligne dans les hôtes de donnée qui
   s'effondrent à zéro. Elle lui pose aussi la classe `leg` des variations qui
   en ont une — mais trois variations sur six n'en ont pas, et la phrase y
   serait rendue en corps de texte plein, plus lourde que la donnée absente.

   Cette règle est le filet : elle ne pose que ce qui manque partout, en
   laissant `--dim` là où le jeton existe. `--dim` mesure 7,94:1 sur v2, au-delà
   du seuil renforcé — une phrase qui explique une absence est le seul contenu
   de sa boîte, elle doit se lire sans effort. */
.dn-manque {
  margin: 0;
  font-size: .8125rem;
  line-height: 1.35;
  color: var(--dim, currentColor);
}
