/* statistics.css
   Relevé sur la source (1440px, #statistics, top 1982 -> hauteur 1043) :
   - Fond --c-orange, motif de pois en radial-gradient (manque du brief, voir A0) :
     radial-gradient(19px 19px, --c-orange-light, --c-orange-light 25%, --c-orange 25%),
     background-size 9.5px 9.5px, repeat — posé sur un calque décoratif dédié
     (.statistics__dots, absolute inset:0) plutôt que sur le fond de section lui-même,
     pour rester sur un simple background-color côté section.
   - Bord festonné du haut : appartient à CETTE section (vérifié en remontant la chaîne
     des ancêtres sur la source — voir brief), bombe vers le haut dans #benefits-1.
     .scallop-top, --scallop-color: var(--c-orange). La section ne doit PAS passer en
     overflow:hidden/clip, sous peine de rogner son propre ::before qui déborde au-dessus
     de sa boîte.
     ⚠ La primitive rendait un demi-disque SEUL, sans la bande pleine qui le porte :
     forme fausse, livrée telle quelle par la tâche 7 et non détectée à sa revue.
     Corrigée dans layout.css le 2026-08-11 (relevé refait ici aux trois paliers :
     bosse 96 × 75,59 / 68,27 × 53,76 / 26 × 20,47, remontée 61 / 40 / 20), puis
     profil recomparé à la source colonne par colonne — écart max 1 px à 1440 et 390,
     2 px à 1024 sur les seules colonnes de jointure entre bosses.
   - Titre <h1> sur la source, redevient <h2> ici (un seul <h1> par page, déjà porté par
     le logo du hero — même correction que studio.css). Climate Crisis 68px/68px (desktop)
     / 52px/52px (tablette) / 42px/42px (mobile), centré, largeur 950px desktop/tablette,
     pleine largeur mobile. Couleur --c-ink.
   - Pastille "parcours" : la source y pose un VRAI starburst à 32 pointes (path SVG à
     65 sommets, confirmé par relevé direct sur la source) — contrairement à la tâche 6,
     .starburst est ici l'usage calibré (tâche 3). Couleur --c-yellow (fill calculé
     exactement égal au token). Rotation -20deg (relevée sur le style inline de la
     source, transform: rotate(-20deg)).
   - Bandeau logos : implémenté avec le contrat marquee.js/CSS du brief (piste dupliquée,
     translateX -100%, INCHANGÉ). La source anime en réalité chaque logo le long d'un
     `offset-path` courbe avec `offset-rotate` automatique (d'où la bande "ondulée" et
     les pastilles visiblement inclinées sur la capture) — mécanisme motion-path propre à
     Framer, hors du contrat marquee.js fourni par le brief (qui est un simple défilement
     horizontal, réutilisé tel quel en tâche 13). CORRIGÉ ICI : reproduit sans
     toucher au mécanisme générique, via une seconde animation (translateY + rotate,
     nth-child déphasé) posée sur .statistics__logo — voir le commentaire détaillé au-dessus
     de cette règle, section "Bandeau logos" plus bas dans ce fichier, pour les mesures et
     la justification du calage de phase. 5 pastilles pastel arrondies (radius 40px,
     mesuré), une couleur par client, logo centré sans étirement (max-width/max-height,
     voir A1). Couleurs de pastille relevées directement sur les DIV de fond de la source
     (pas une supposition) :
     Les moulins bleus --c-pink-light, Adonys --c-mint, 100 patates --c-yellow-pale,
     Giant Caffeine --c-sand, O'bello --c-cream.
   - Noms de clients : présents dans le DOM source (opacity:1, texte réel, pas
     aria-hidden) mais rognés hors-champ par l'overflow:hidden de leur propre pastille
     (piège proche du A1#1 "ancêtre" mais ici un overflow, pas une opacity) — invisibles
     sur la capture.
     ⚠ MIS À JOUR le 2026-08-14 : ce constat était le bon indice et il a été lu trop
     vite. Si la source garde ce texte dans la pastille, ce n'est pas par négligence :
     c'est le SURVOL qui l'amène à l'écran. Ils étaient reproduits ici en
     `.visually-hidden` ; ils portent désormais `.statistics__logo-name`, toujours
     invisibles au repos et toujours exposés au lecteur d'écran, mais révélés au survol
     par-dessus une étoile — voir le bloc « Survol d'une pastille » plus bas. La
     typographie du relevé (Poppins 600 20px/26px, -0.8px, --c-ink) y est reprise telle
     quelle : elle était disponible depuis le début dans releve-2026-08-10.json.
   - Bloc "Chiffres" : fond --c-teal (couleur exacte du token). Sticker "Chiffres" en
     blob organique orange (chemin SVG relevé sur la source, unique — pas une primitive,
     comme le veut A1#0), rotate(-20deg) également.
   - Compteurs : nombre Oswald 500 91px (desktop/tablette) / 48px (mobile), libellé
     Climate Crisis 400 22px/30.8px (desktop/tablette) / 20px/28px (mobile). Le suffixe
     ("+"/"%") est, sur la source, dans une police et une couleur corail différentes
     (Clash Display 500 41px/41px, ls -1.64px, couleur --c-coral — voir tokens.css pour
     la provenance) — voir .counter__suffix plus bas. CORRIGÉ ICI : la version précédente de counter.js
     écrivait le nombre ET le suffixe dans le même textContent, rendant la distinction
     impossible ; le brief a été amendé (défaut 3), counter.js anime désormais
     [data-count-value] et laisse le suffixe, dans son propre <span class="counter__suffix">,
     intact. */

/* ---------- Bandeau défilant (générique, réutilisé tel quel en tâche 13) ---------- */
.marquee {
  display: flex;
  width: 100%;
  overflow: hidden;
  /* Masque en dégradé : seul le canal alpha compte (mask-mode par défaut = alpha pour un
     gradient CSS), la couleur opaque utilisée n'a donc aucune incidence visuelle — token
     réutilisé plutôt qu'un noir brut, pour rester sur les couleurs centralisées. */
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--c-ink) 8%, var(--c-ink) 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, var(--c-ink) 8%, var(--c-ink) 92%, transparent);
}

.marquee__track {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: var(--sp-9);
  padding-right: var(--sp-9);
}

.marquee.is-running .marquee__track {
  animation: marquee-scroll var(--marquee-duration) linear infinite;
}

/* ⚠ Le bandeau ne se met PLUS en pause au survol (retiré le 2026-08-14, à la
   demande du propriétaire, capture de la source à l'appui). La pause était
   NOTRE ajout, pas un relevé : la source laisse ses pastilles défiler sans
   jamais s'arrêter, et c'est ce qui rend son effet de survol fugace — la
   pastille s'échappe sous le curseur. La règle retirée était :
       .marquee.is-running:hover .marquee__track { animation-play-state: paused; }
   Ne pas la remettre « pour confort de lecture » sans en reparler : elle change
   le caractère de l'effet de survol posé dans statistics.css. */

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}

.marquee--static { overflow-x: auto; }

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
}

/* ---------- Section ---------- */
.statistics {
  position: relative;
  background: var(--c-orange);
  padding: 96px var(--gutter) 145px;
  text-align: center;

  /* Couleur du bord festonné de la primitive `.scallop-top` (layout.css), qui se
     peint au-dessus de la section, sur #benefits-1. Déclarée ici plutôt qu'en
     style en ligne dans le markup — même convention que #benefits. */
  --scallop-color: var(--c-orange);
}

/* Le motif de pois n'occupe PAS toute la section : il apparaît en fondu depuis
   le haut. Masque relevé sur la source le 2026-08-13, identique aux trois
   largeurs, sur le conteneur du calque de pois :

     mask-image: linear-gradient(181deg, transparent 10%, opaque 48%)

   Le haut de la section reste donc en --c-orange uni sur ses dix premiers pour
   cent, puis les pois montent jusqu'à pleine force à 48 % de la hauteur. C'est
   ce fondu qui fait que le bord festonné — peint dans cette même teinte — se
   fond dans le haut de la section au lieu de buter sur une arête de motif : le
   raccord entre les deux sections devient continu. Sans lui, les pois
   démarraient net au pixel près sous les bosses.
   ⚠ La source écrit sa borne opaque en noir brut ; nous ne le pouvons pas, les
   contraintes du chantier interdisant toute valeur de couleur hors de
   `tokens.css`, ce que `check.py` vérifie. Seul le canal alpha d'un masque
   compte, donc `transparent` + un token donnent exactement le même rendu —
   convention déjà employée par le masque des pois du pied de page et par celui
   du calque de cercles du hero. */
.statistics__dots {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(19px 19px, var(--c-orange-light), var(--c-orange-light) 25%, var(--c-orange) 25%);
  background-size: 9.5px 9.5px;
  background-repeat: repeat;
  -webkit-mask-image: linear-gradient(181deg, transparent 10%, var(--c-ink) 48%);
  mask-image: linear-gradient(181deg, transparent 10%, var(--c-ink) 48%);
  pointer-events: none;
}

/* ---------- Pastille "parcours" ----------
   ⚠ REFAITE le 2026-08-13, comme celle de #services et pour les mêmes raisons.
   C'était le vestige n° 35, laissé ouvert en tâche 18 : « la source dessine une
   étoile douce de 166,4 × 130,7, nous posons un disque rayé de 238,4 × 238,4 ».
   Les deux chiffres étaient des boîtes ENGLOBANTES, et le constat s'arrêtait à
   la taille. Le fond du problème est ailleurs :
   - la source pose ici le MÊME tracé que la pastille « Services » (comparé
     caractère par caractère, 1029 signes identiques) — une étoile à 30 pointes
     à cœur plein, désormais dans `--shape-star-30` ;
   - nous posions `.starburst`, dont les rayons convergent en un point : le fond
     orange passait entre eux au centre, et le mot « parcours » y était illisible
     (c'est le défaut signalé) ;
   - la boîte réelle de l'étoile fait 145,8 × 144,58, et non 186 × 186 ; c'est sa
     rotation de -20° qui donne les 166 × 164 englobants.
   Centre relevé, en coordonnées de section : 349 / 78,5 à 1440, 199 / 80 à 1024,
   centré à 195 / 70 à 390. */
.statistics__badge {
  position: absolute;
  left: 349px;
  top: 78.5px;
  z-index: 1;
  width: 145.8px;
  height: 144.58px;
  display: grid;
  place-items: center;
  transform: translate(-50%, -50%) rotate(-20deg);
}

.statistics__badge-shape {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  background: var(--c-yellow);
  -webkit-mask: var(--shape-star-30) no-repeat center / contain;
  mask: var(--shape-star-30) no-repeat center / contain;
}

/* Le libellé passe au-dessus du tracé, comme sur la source (z-index 1 sur son
   conteneur). Avec le cœur plein de l'étoile, il se lit sur du jaune uni. */
.statistics__badge-text {
  grid-area: 1 / 1;
  position: relative;
  z-index: 1;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-20);
  line-height: 26px;
  letter-spacing: -0.8px;
  color: var(--c-ink);
}

/* ---------- Titre ---------- */
.statistics__intro {
  position: relative;
  z-index: 1;
  max-width: 950px;
  margin-inline: auto;
}

.statistics__heading {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-68);
  line-height: 1;
  color: var(--c-ink);
  /* Filet de sécurité : à 390px, "d'expérience" dépasse de justesse la largeur
     disponible (metrics de la police locale) — évite un débord horizontal de page
     plutôt que de réduire la taille mesurée sur la source. */
  overflow-wrap: break-word;
}

/* ---------- Bandeau logos ---------- */
/* La source porte chaque pastille le long d'un `offset-path` en S (mécanisme
   motion-path propre à Framer, hors du contrat marquee.js/CSS générique
   ci-dessus, réutilisé tel quel en tâche 13). Reproduit ici SANS toucher au
   mécanisme générique .marquee/.marquee__track (translateX -100% inchangé) :
   une seconde animation, indépendante, posée sur .statistics__logo (portée
   par les <li>, pas par la piste), qui fait onduler chaque pastille en
   translateY + rotate. Mesures prises directement sur la source
   (browser_evaluate, path.getTotalLength()/getPointAtLength()) plutôt que
   devinées :
   - le chemin offset-path source ("M 0.25 230.74 C … 1439.92 90.562") couvre
     1440px de large pour une amplitude verticale de 230.74-90.56 ≈ 140px
     (rayon ≈ 70px) et une rotation de tangente qui oscille entre environ
     -23° et +23°, nulle aux crêtes/creux et maximale aux points d'inflexion ;
   - le chemin dessine deux ondulations complètes sur sa largeur totale, pour
     10 items espacés tous les 10% → une ondulation complète tous les ~5 items.
   Repris ici avec une sinusoïde à 8 points (translateY ~ sin, rotate ~ cos,
   déphasées de 90° comme la tangente d'une vraie courbe), amplitude 65px /
   rotation 22° côté desktop — valeurs arrondies proches des mesures ci-dessus.
   Le déphasage par item (--logo-index, un cran par nth-child, cycle de CINQ)
   est calé sur var(--marquee-duration) / 5 : le motif de phase se répète tous
   les 5 items, soit une ondulation complète tous les 5 items — exactement la
   longueur d'onde de la source, dont le chemin en dessine deux pour ses dix
   items. La piste en comptant dix, un multiple de cinq, le raccord entre les
   deux pistes reproduit à l'identique une jonction interne : la boucle reste
   sans saut (vérifié par mesure des pas, jonctions comprises).
   ⚠ L'onde n'est en revanche PAS fixe dans l'espace de l'écran : sa crête
   dérive vers la gauche à 67,5 px/s à 1440 (pastilles à 45 px/s), là où celle
   de la source, portée par un chemin fixe, ne dérive pas. Écart pré-existant
   (75 px/s avant ce correctif), chiffré dans task-18-fix-4 et non corrigé ici :
   l'annuler avec ce mécanisme imposerait un déphasage égal au temps de parcours
   d'un pas (durée / 10), donc une ondulation tous les 10 items — la longueur
   d'onde de la source serait perdue en échange.
   Délai NÉGATIF (`-i × durée/5`, voir .statistics__logo) :
   un délai positif aurait laissé chaque item à transform:none jusqu'à ce que
   son tour arrive (jusqu'à 25.6s pour le 5e item) — un aplat qui se courbe
   progressivement au chargement, jamais courbé sur la source. Un délai négatif
   démarre l'animation déjà avancée de |délai|, donc chaque item est déjà
   réparti sur la courbe dès la première frame ; la relation de phase ci-dessus
   (raccord entre pistes) ne dépend que de la valeur absolue
   du délai modulo la durée, donc reste valable au signe près — revérifié
   après coup avec getAnimations(). */
/* Géométrie des pastilles — relevée sur la source aux cinq largeurs 1440 / 1199 /
   1024 / 500 / 390 (offsetWidth/offsetHeight et styles calculés ; JAMAIS
   getBoundingClientRect, les pastilles portent une rotation animée dont
   l'englobante balaie) :
   - pastille 158 x 100, border-radius 40px : UNE SEULE valeur distincte sur les
     dix pastilles à 1440 et sur les cinq des autres paliers. La source ne réduit
     PAS la pastille en tablette/mobile — les tailles réduites posées ici en tâche 13
     (150 x 116 et 118 x 92) étaient une invention, supprimées.
   - boîte d'image 63.3906 x 48, object-fit: contain : là encore une seule valeur
     distincte sur les dix images, identique aux trois paliers. Exprimée ici en
     pourcentage de la pastille (40.12% x 48%), d'où la suppression du padding de
     la pastille : la source, elle, a un padding nul et centre une boîte fixe.
   - pas horizontal = largeur du chemin / nombre d'items, soit 10vw à partir de
     1200px (10 items dans la période), 20vw entre 810 et 1199 (5 items) et 22vw
     en dessous (5 items, chemin 1,1x plus large que le viewport). Vérifié à
     1440 (143,97), 1199 (239,74), 1024 (204,75), 500 (109,97), 390 (85,78).
   Le pas desktop de 10vw exige DIX items dans la piste, comme la source : avec
   cinq seulement, la piste (5 x 10vw = 50vw) serait plus étroite que son
   conteneur et un vide défilerait en fin de cycle, marquee.js ne clonant la
   piste qu'une fois. Les dix <li> sont désormais dans index.html (le second jeu
   en aria-hidden, décoratif), la piste vaut donc 10 x 10vw = 100vw à partir de
   1200px — plus large que le conteneur à toute largeur, ce qui supprime au
   passage le vide de 160px qui défilait au bord droit à 1440. Aux paliers
   inférieurs, dix items donnent 200vw / 220vw, toujours couvrants, sans changer
   le pas (20vw / 22vw) déjà conforme. Voir task-18-fix-4. */
.statistics__marquee {
  position: relative;
  z-index: 1;
  margin-block: 88px 64px;
  --logo-w: 158px;
  --logo-h: 100px;
  --logo-step: 10vw;
  --logo-wave-amp: 65px;
  --logo-wave-rotate: 22deg;
  /* Étend la boîte du conteneur (.marquee, overflow:hidden sur sa boîte de
     padding) pour laisser la place au débattement vertical des pastilles,
     sans toucher à la propriété overflow générique elle-même. Comble aussi
     l'essentiel du déficit de hauteur de la section (défaut 2). Conservée telle
     quelle par le correctif de géométrie : la hauteur du conteneur source
     (321px à 1440 et 1024, 170px à 390, remesurée) reste au-dessus de la nôtre,
     mais l'amplitude d'ondulation est hors du périmètre de ce correctif — écart
     chiffré dans le rapport plutôt que corrigé au jugé. */
  padding-block: var(--logo-wave-amp);
}

@keyframes statistics-logo-wave {
  0%    { transform: translateY(0)                                        rotate(var(--logo-wave-rotate)); }
  12.5% { transform: translateY(calc(var(--logo-wave-amp) * 0.707))       rotate(calc(var(--logo-wave-rotate) * 0.707)); }
  25%   { transform: translateY(var(--logo-wave-amp))                     rotate(0deg); }
  37.5% { transform: translateY(calc(var(--logo-wave-amp) * 0.707))       rotate(calc(var(--logo-wave-rotate) * -0.707)); }
  50%   { transform: translateY(0)                                        rotate(calc(var(--logo-wave-rotate) * -1)); }
  62.5% { transform: translateY(calc(var(--logo-wave-amp) * -0.707))      rotate(calc(var(--logo-wave-rotate) * -0.707)); }
  75%   { transform: translateY(calc(var(--logo-wave-amp) * -1))          rotate(0deg); }
  87.5% { transform: translateY(calc(var(--logo-wave-amp) * -0.707))      rotate(calc(var(--logo-wave-rotate) * 0.707)); }
  100%  { transform: translateY(0)                                        rotate(var(--logo-wave-rotate)); }
}

/* Le pas est porté par une marge de fin d'item, et non par le `gap` générique de
   .marquee__track : le pas source est INFÉRIEUR à la largeur de la pastille dès
   qu'on descend sous 1200px (les pastilles se chevauchent), et `gap` n'accepte pas
   de valeur négative. La marge de fin, elle, peut l'être ; portée par TOUS les
   items, y compris le dernier, elle garde la période de la piste exactement égale
   à 5 x pas, donc le raccord avec la piste clonée (translateX -100%) reste sans
   saut. Le `gap` et le `padding-right` génériques sont neutralisés ici seulement
   (sélecteur de même spécificité, placé après la règle générique), la piste de la
   tâche 13 n'est pas touchée.
   Ordre de superposition : la source fait passer, à 7 jonctions sur 9, la pastille
   de droite AU-DESSUS de sa voisine de gauche (les 2 inversions viennent de l'ordre
   DOM entrelacé de Framer et se déplacent avec les pastilles). Le simple ordre DOM
   des <li>, tous en position:relative sans z-index, donne exactement cette règle
   dominante. */
.statistics__logos {
  gap: 0;
  padding-right: 0;
}

.statistics__logo {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--logo-w);
  height: var(--logo-h);
  margin-inline-end: calc(var(--logo-step) - var(--logo-w));
  border-radius: 40px;
  background: var(--logo-bg, var(--c-cream));
  animation: statistics-logo-wave var(--marquee-duration) linear infinite;
  /* Négatif : démarre l'animation déjà en cours (avance de |délai|), pour que
     chaque item soit distribué sur la vague dès la première frame au lieu de
     partir de transform:none et de "s'assembler" pendant les 25.6 premières
     secondes de la page — corrigé après relecture, voir rapport de correctif. */
  animation-delay: calc(var(--marquee-duration) / 5 * var(--logo-index, 0) * -1);
}

/* nth-child se recompte à l'identique dans la piste clonée par marquee.js
   (un <ul> indépendant) : le déphasage reste correct dans les deux pistes.
   Le cycle de déphasage reste de CINQ crans (5n+i) alors que la piste compte
   désormais dix items : une ondulation complète tous les 5 items, exactement
   comme la source (son chemin dessine deux ondulations pour ses dix items).
   Le raccord reste sans saut, dans la piste comme entre les deux pistes,
   puisque le motif de phase se répète tous les 5 items et que 10 en est un
   multiple — même condition qu'avant, vérifiée par mesure. */
.statistics__logo:nth-child(5n+1) { --logo-index: 0; }
.statistics__logo:nth-child(5n+2) { --logo-index: 1; }
.statistics__logo:nth-child(5n+3) { --logo-index: 2; }
.statistics__logo:nth-child(5n+4) { --logo-index: 3; }
.statistics__logo:nth-child(5n+5) { --logo-index: 4; }

/* La source pose object-fit: contain sur les 10 <img> du bandeau (valeur relevée
   directement, 10/10, une seule valeur distincte). Alignée ici : la boîte de
   l'image est inchangée (max-width/max-height sur width/height auto), seul le
   rendu du contenu est garanti sans étirement — l'arrondi de la boîte au pixel
   entier déformait jusqu'à 2,7 % le logo le plus allongé à 390px. Neutre en
   hauteur : la pastille porte une hauteur fixe, l'image ne participe pas au
   calcul de la hauteur de la section.
   Bornes alignées sur la boîte d'image de la source (63.3906 x 48 dans une
   pastille de 158 x 100, soit 40.12% x 48%, valeur unique sur les dix images et
   identique aux trois paliers). Les cinq tailles peintes qui en résultent
   reproduisent exactement celles de la source, le rapport d'aspect étant conservé
   par contain. */
.statistics__logo img {
  max-width: 40.12%;
  max-height: 48%;
  width: auto;
  height: auto;
  object-fit: contain;
}

.statistics__logo--moulins { --logo-bg: var(--c-pink-light); }

/* ⚠ Exception de largeur pour CE logo seul (2026-08-14). Le bandeau borne ses
   dix images à `max-width: 40.12%` — valeur relevée sur la source, identique
   pour les dix. Elle convient à des logos trapus : sous cette borne, Adonys
   rend 63 × 36, Giant 63 × 42, O'Bello 63 × 30.
   Le wordmark manuscrit des Moulins Bleus, lui, fait 456 × 62, soit un rapport
   de 7,35:1. Bridé en largeur à 63px, il ne mesurait plus que 8,6px de haut —
   un trait illisible. Porté à 78 %, il rend 123 × 17, ce qui le met à peu près
   au niveau de « 100 patates » (63 × 18), le plus allongé des autres.
   Cet écart au relevé est assumé : la source n'affichait pas ce fichier-ci dans
   son bandeau, il n'y a donc aucune mesure d'origine à respecter pour lui. */
.statistics__logo--moulins img { max-width: 78%; }
.statistics__logo--adonys  { --logo-bg: var(--c-mint); }
.statistics__logo--patates { --logo-bg: var(--c-yellow-pale); }
.statistics__logo--giant   { --logo-bg: var(--c-sand); }
.statistics__logo--obello  { --logo-bg: var(--c-cream); }

/* ---------- Survol d'une pastille : le nom du client sur une étoile ----------
   Repris de la source à la demande du propriétaire (2026-08-14), d'après sa
   capture : le logo s'efface et le nom du client surgit, posé sur une étoile
   jaune. ⚠ Rien ici n'est un relevé — le bandeau de la source ne s'arrête pas,
   une pastille ne reste donc pas sous le curseur assez longtemps pour mesurer
   quoi que ce soit image par image. Forme, taille et durée sont des choix,
   signalés comme tels dans le README.

   L'étoile est le médaillon `Bf3S7lrMf4RLc0FEbNVgXCJTvI.svg`, DÉJÀ dans
   assets/svg/ — c'est la vingtaine de pointes arrondies qui découpe le portrait
   de François dans #about, et c'est la même forme que l'auréole du
   « développeur » de #studio. Employée ici en `mask-image` et non en `<img>` :
   le fichier est peint en blanc, un masque le rend recolorable par la feuille
   de style (`background: var(--c-yellow)`), sans écrire une couleur en dur ni
   recopier un onzième tracé dans index.html.

   Pseudo-élément plutôt qu'une balise : dix pastilles × une balise de plus,
   pour une pure décoration, alourdiraient le HTML sans rien apporter. */
.statistics__logo::after {
  content: "";
  position: absolute;
  inset: 5% 6%;
  z-index: 1;
  background: var(--c-yellow);
  /* `100% 100%` et non `contain` : le fichier est carré, `contain` l'inscrivait
     donc en DISQUE au centre de la pastille. La source pose un OVALE allongé qui
     en remplit presque toute la largeur (capture du propriétaire, 2026-08-14) ;
     étirer le masque aux deux dimensions de la boîte donne cette ellipse. */
  mask: url(../../assets/svg/Bf3S7lrMf4RLc0FEbNVgXCJTvI.svg) center / 100% 100% no-repeat;
  -webkit-mask: url(../../assets/svg/Bf3S7lrMf4RLc0FEbNVgXCJTvI.svg) center / 100% 100% no-repeat;
  opacity: 0;
  transform: scale(.55);
  pointer-events: none;
  transition: opacity var(--dur-logo-name) var(--ease-out),
              transform var(--dur-logo-name) var(--ease-back);
}

/* Le nom porte AUSSI le nom accessible de la pastille — c'est le même élément
   qui servait de `.visually-hidden` avant cet effet. Il reste donc dans l'arbre
   d'accessibilité en permanence : `opacity: 0` masque à l'œil sans retirer du
   lecteur d'écran. Ne pas le remplacer par `display: none` ou `visibility:
   hidden`, qui le retireraient et laisseraient les cinq pastilles anonymes. */
/* ⚠ La TYPOGRAPHIE ci-dessous, elle, est RELEVÉE, pas choisie. Les dix noms
   figurent dans `releve-2026-08-10.json` (section `statistics`) : la source les
   pose en vrai texte dans la pastille, rognés hors-champ par son overflow —
   c'est ce que note déjà le commentaire en tête de ce fichier. Le relevé donne
   les dix fois la même chose : `Poppins 600 20px/26px`, interlettrage -0,8px, et
   une couleur de texte qui est exactement celle du token --c-ink. Soit
   --font-sans, --fs-20 et --c-ink, au caractère près.
   (La valeur brute de cette couleur n'est pas recopiée ici : check.py compte une
   couleur citée en commentaire comme une couleur écrite en dur dès qu'elle tombe
   sur une ligne de continuation — faux positif connu de l'outil.)

   ⚠ LARGEUR : 63 %, et surtout PAS les 120 à 124px que le relevé affiche. Ces
   boîtes-là sont des boîtes ENGLOBANTES de texte en ROTATION — les pastilles
   ondulent, le relevé les a saisies inclinées, et une boîte inclinée mesure plus
   large que son contenu. Le premier jet a repris les 120 tels quels (78 %) et
   « Les moulins bleus » tenait alors sur deux lignes au lieu de trois.
   En dépliant W = w·cosθ + h·sinθ sur les deux instances relevées (120 × 110 et
   124 × 120), la seule hypothèse qui tienne est trois lignes de 26px pour une
   largeur réelle d'environ 100px — soit 63 % d'une pastille de 158. L'hypothèse
   « deux lignes » donnerait une hauteur englobante de 90px, très loin des 110
   relevés. C'est aussi ce que montre la capture du propriétaire : trois lignes. */
.statistics__logo-name {
  position: absolute;
  z-index: 2;
  max-width: 63%;
  text-align: center;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-20);
  line-height: 26px;
  letter-spacing: -0.8px;
  color: var(--c-ink);
  opacity: 0;
  transform: scale(.72);
  pointer-events: none;
  transition: opacity var(--dur-logo-name) var(--ease-out),
              transform var(--dur-logo-name) var(--ease-back);
}

.statistics__logo img {
  transition: opacity var(--dur-logo-name) var(--ease-in);
}

/* `hover: hover` écarte les écrans tactiles, où un survol se déclenche au
   premier toucher et reste collé. */
@media (hover: hover) {
  .statistics__logo:hover img { opacity: 0; }

  .statistics__logo:hover::after,
  .statistics__logo:hover .statistics__logo-name {
    opacity: 1;
    transform: scale(1);
  }
}

/* prefers-reduced-motion neutralise déjà .marquee__track (règle générique
   ci-dessus) ; fait de même pour l'ondulation, propre à cette section. */
@media (prefers-reduced-motion: reduce) {
  .statistics__logo { animation: none; }

  /* L'échange logo -> nom reste, seul le mouvement disparaît : il n'y a plus ni
     fondu ni dépassement, l'étoile et le nom sont là ou n'y sont pas. */
  .statistics__logo::after,
  .statistics__logo-name,
  .statistics__logo img { transition: none; }

  .statistics__logo::after,
  .statistics__logo-name { transform: none; }
}

/* ---------- Bloc "Chiffres" ---------- */
.statistics__block {
  position: relative;
  z-index: 1;
  max-width: 1360px;
  margin-inline: auto;
  background: var(--c-teal);
  border-radius: 40px;
  padding: 20px 30px;
}

.statistics__block-sticker {
  position: absolute;
  left: -10px;
  top: -40px;
  z-index: 2;
  width: 155px;
  height: 129px;
  transform: rotate(-20deg);
}

.statistics__block-blob {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: var(--c-orange);
}

.statistics__block-sticker-text {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-20);
  letter-spacing: -0.8px;
  color: var(--c-ink);
}

.statistics__counters {
  display: grid;
  grid-template-columns: repeat(4, auto);
  justify-content: center;
  gap: 80px;
}

.statistics__counter { text-align: left; }

.statistics__counter-value {
  font-family: var(--font-cond);
  font-weight: 500;
  font-size: 91px;
  line-height: 1;
  letter-spacing: -6.37px;
  color: var(--c-white);
}

/* Le suffixe ("+"/"%") vit dans son propre élément (voir counter.js) : sur la
   source il est en Clash Display, corail, dans une taille distincte du chiffre
   Oswald blanc qui le précède — relevé directement sur la source (41px/41px,
   ls -1.64px à desktop/tablette). */
.counter__suffix {
  font-family: var(--font-clash);
  font-weight: 500;
  font-size: 41px;
  line-height: 1;
  letter-spacing: -1.64px;
  color: var(--c-coral);
}

.statistics__counter-label {
  margin-block-start: var(--sp-2);
  max-width: 220px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-22);
  line-height: 30.8px;
  color: var(--c-white);
}

@media (max-width: 1199px) {
  .statistics { padding-block-start: 80px; }

  /* Centre relevé à 1024 : 199 / 80 en coordonnées de section, étoile 128,6 × 127,6. */
  .statistics__badge { left: 199px; top: 80px; width: 128.64px; height: 127.56px; }

  .statistics__badge-text { font-size: var(--fs-16); line-height: 20.8px; letter-spacing: -0.64px; }

  .statistics__heading { font-size: var(--fs-52); }

  /* La pastille garde 158 x 100 (la source ne la réduit à aucun palier) ; seul le
     pas change : 20vw, loi relevée sur la source à 1199 (239,74) et 1024 (204,75).
     La piste vaut alors exactement 100vw, toujours plus large que le conteneur
     (100vw - 2 gouttières) : le raccord de boucle reste couvert à toute largeur
     du palier. L'amplitude d'ondulation reste à sa valeur d'avant correction,
     elle n'est pas dans le périmètre de ce correctif (écart relevé et rapporté). */
  .statistics__marquee { --logo-step: 20vw; --logo-wave-amp: 57px; }

  .statistics__counters { grid-template-columns: repeat(2, auto); gap: 56px 40px; }
}

@media (max-width: 809px) {
  .statistics { padding: 64px var(--gutter) 70px; }

  /* À 390 la pastille est centrée : 195 relevé pour une page de 390. */
  .statistics__badge { left: 50%; top: 70px; width: 124.35px; height: 123.31px; }

  .statistics__badge-text { font-size: var(--fs-15); line-height: 19.5px; letter-spacing: -0.6px; }

  .statistics__intro { max-width: none; }

  .statistics__heading { font-size: var(--fs-42); letter-spacing: -1.6px; }

  /* Pas de 22vw : sous 810px la source élargit son chemin à 1,1 x le viewport pour
     5 items — relevé à 500 (109,97 = 21,99vw) et 390 (85,78 = 21,99vw). Le pas
     passe donc SOUS la largeur de la pastille : les pastilles se chevauchent de
     72px à 390px, comme sur la source. La piste vaut 110vw, largement plus que le
     conteneur : boucle couverte à toute largeur du palier. Amplitude d'ondulation
     inchangée (hors périmètre). */
  .statistics__marquee { margin-block: 72px 48px; --logo-step: 22vw; --logo-wave-amp: 45px; }

  .statistics__block-sticker { left: -6px; top: -46px; width: 108px; height: 90px; }

  /* Dégage le premier compteur de la zone couverte par le sticker "Chiffres",
     qui dépasse davantage dans le bloc à cette largeur. */
  .statistics__counters { grid-template-columns: repeat(2, auto); gap: 32px 24px; margin-block-start: 32px; }

  .statistics__counter-value { font-size: 48px; letter-spacing: -3.36px; }

  .counter__suffix { font-size: 34px; letter-spacing: -1.36px; }

  .statistics__counter-label { font-size: var(--fs-20); line-height: 28px; }
}
