/* =====================================================================
   STELVOREN — SOCLE DES PAGES DE CONTENU
   Le lot « socle » du protocole d'intégration : ce que dix-huit écrans
   réutilisent, écrit une fois, avant les pages.

   Relevé Dev Mode du 21/09/2026, fichier Figma « Refonte »
   (Wiukeiz8DyfOof3a1OSaPR). Un nœud est cité devant chaque bloc : c'est
   lui qui fait foi, pas ce fichier.

   CE QUI N'EST PAS ICI. Les jetons (jetons.css), les composants du
   thème (composants.css), la fiche produit (fiche-produit.css). Le
   bouton `.stv-bouton` vit dans composants.css et sert tel quel : le
   bouton du bandeau showroom (156:10654) et le bouton d'envoi des
   formulaires (156:10581) SONT la variante secondaire et la variante
   primaire, aux mêmes valeurs. Rien n'est redessiné ici.

   RIEN N'EST FIGÉ. Aucun texte, aucun nombre d'éléments, aucune
   hauteur de bloc : les contenus de ces pages sont annoncés changeants
   (notes de Logan des 21/09 sur les guides, « À propos » et La marque).
   Pas de `:nth-child`, pas de compte de colonnes en dur, pas de
   hauteur qui suppose deux lignes de titre.

   LE PIÈGE DE SPÉCIFICITÉ s'applique partout ici — voir
   `piege-specificite-elementor.md`. Le kit est le 44301 ; il écrit sur
   `h1`…`h6`, `a`, `button` à 0,1,1 et sur `input` à 0,3,1. Chaque
   sélecteur de ce fichier qui vise un de ces éléments porte donc DEUX
   classes au moins, et le compte est justifié en commentaire là où il
   monte plus haut. Aucun `!important`.
   ================================================================== */


/* =====================================================================
   0. CE QUE LE THÈME PARENT IMPOSE, ET QU'ON LUI REPREND
   Relevé du 23/09, sur l'accueil : 28 liens sur 76 sortaient soulignés,
   dont les onze cartes de collection et les trois liens du hero.

   Hello Elementor écrit, dans `assets/css/theme.css` :

       .comments-area a, .page-content a { text-decoration: underline }

   `.page-content` est l'enveloppe que son modèle de page pose autour de
   TOUT le contenu : la règle atteint donc chaque lien d'une page, y
   compris ceux d'Elementor. Elle pèse 0,1,1 — une classe et un élément
   — là où un composant qui dit « pas de soulignement » n'écrit
   d'ordinaire qu'une classe, 0,1,0. Le composant perd, et l'ordre des
   fichiers n'y change rien : `reset.css` du parent remet pourtant
   `a { text-decoration: none }`, mais elle est chargée AVANT.

   On la reprend ici, au même compte, dans la dernière feuille chargée.
   Ce n'est pas une opinion sur le soulignement : c'est que la décision
   appartient au composant. Un lien de prose est souligné parce que
   `.stv-prose a` le dit (0,3,1), les coordonnées du pied parce que
   `.stv-pied .stv-pied__coordonnee` le dit (0,2,0), la mention RGPD
   parce que `.stv-mention__lien` le dit. Aucun des trois ne dépend de
   ce que le thème parent aura décidé pour tout le monde.
   ================================================================== */
.page-content a,
.comments-area a {
  text-decoration: none;
}


/* =====================================================================
   1. EN-TÊTE DE PAGE À FOND COLORÉ
   Nœuds 156:10630 / 156:10631 (La marque, crème, citation entre filets)
   et 156:9309 / 156:9310 (Pages légales, bleu clair, ligne de date).
   Troisième emploi : Nos marques (156:10324), le H1 et la grille des
   marques dans la même bande (`--contenu`, 05/10).

   UNE CLASSE, DEUX FONDS, TROIS GARNITURES. Le fond (crème ou bleu
   clair) et ce qui suit le H1 (rien, une citation entre deux filets,
   une ligne de date) sont des réglages, pas trois composants. La même
   classe sert dans un conteneur V4 d'Elementor (La marque, Nos
   marques) ET dans `page-legale.php`, modèle de page PHP des pages
   légales : c'est pour cela qu'elle ne suppose aucun balisage
   d'Elementor autour d'elle.

   Le rythme vertical diffère d'un écran à l'autre — 80 sur La marque,
   48 sur les pages légales — parce que la garniture diffère : une
   citation entre filets a besoin d'air, une date non. Il est donc porté
   par une variable que le modificateur règle.
   ================================================================== */

/*
   TROIS RÉPÉTITIONS — mesuré le 30/09 sur La marque, premier écran à poser
   l'en-tête sur un élément V4. Symptôme : `display: block` et 10 de marge
   intérieure en haut et en bas (257 de haut au lieu de 442) — l'atomique
   `.elementor .e-div-block-base` à 0,2,0, chargée après nous (§ 2). Le
   modificateur monte avec la classe, et les règles du § 11 aussi, sans quoi
   la répétition les ferait perdre. En PHP (pages légales) rien ne change :
   il n'y a pas d'atomique à battre, seulement un compte plus haut.
*/
.stv-entete-page.stv-entete-page.stv-entete-page {
  --stv-entete-page-fond: var(--stv-beige);
  --stv-entete-page-y: var(--stv-section-y);
  --stv-entete-page-ecart: var(--stv-espace-48);
  /* La citation : 32 à −1 % en desktop (156:10634), 20 à −0,5 % en mobile
     (156:8365) — aucun jeton ne fait ce couple, d'où deux variables que le
     § 11 règle. */
  --stv-entete-page-citation: var(--stv-taille-h3);
  --stv-entete-page-citation-interlettre: -0.01em;

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--stv-entete-page-ecart);
  padding: var(--stv-entete-page-y) var(--stv-page-gouttiere);
  background: var(--stv-entete-page-fond);
  text-align: center;
}

/* Le fond bleu clair des pages légales (156:9309) — même classe. */
.stv-entete-page--bleu.stv-entete-page--bleu.stv-entete-page--bleu {
  --stv-entete-page-fond: var(--stv-bleu-clair);
  --stv-entete-page-y: var(--stv-espace-48);
  --stv-entete-page-ecart: var(--stv-espace-16);
}

/*
   LE TITRE. Deux classes (0,2,0) devant `.elementor-kit-44301 h1`
   (0,1,1) : sans cela le H1 reprend la taille du Theme Style sur une
   page Elementor, et celle de style.css sur une page PHP — deux
   valeurs différentes pour le même dessin.

   `text-wrap: balance` plutôt qu'une largeur : un titre plus long que
   celui de la maquette doit se répartir, pas déborder ni se couper à
   une mesure devinée.
*/
/* DEUX SÉLECTEURS, UN SEUL CORPS (30/09) : posé par un widget Titre, le
   `stv-entete-page__titre` arrive sur l'enveloppe du widget — même parade
   que `stv-banniere__titre` (§ 2). En PHP, le premier sélecteur suffit. */
.stv-entete-page .stv-entete-page__titre,
.stv-entete-page .stv-entete-page__titre :where(h1, h2, p, .elementor-heading-title) {
  margin: 0;
  max-width: var(--stv-largeur-texte);
  font-family: var(--stv-police-titres);
  font-size: var(--stv-taille-hero);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: -0.01em;
  color: var(--stv-texte);
  text-wrap: balance;
}

/*
   LA CITATION (156:10634) : Outfit Medium 32, entre deux filets de 816
   de large. Les filets sont des bordures de la citation elle-même, pas
   deux éléments vides : un bloc éditorial ne doit pas exiger que le
   client pose des séparateurs à la main, et une citation absente ne
   doit pas laisser deux traits orphelins.
*/
.stv-entete-page .stv-entete-page__citation.stv-entete-page__citation {
  margin: 0;
  width: 100%;
  max-width: var(--stv-largeur-texte);
  padding: var(--stv-entete-page-ecart) 0;
  border-top: 1px solid var(--stv-filet-entete);
  border-bottom: 1px solid var(--stv-filet-entete);
  font-family: var(--stv-police-titres);
  font-size: var(--stv-entete-page-citation);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: var(--stv-entete-page-citation-interlettre);
  color: var(--stv-texte);
}

/*
   L'ÉCART RESTE ENTRE LE TITRE ET LA CITATION — corrigé le 30/09. Une règle
   `:has(.stv-entete-page__citation) { gap: 0 }` le retirait ici, au motif
   que la citation porte déjà ses marges : le H1 venait alors TOUCHER le
   premier filet. Le relevé Dev Mode de 156:10631 dit l'inverse — H1, 48,
   filet, 48, citation, 48, filet — soit exactement l'écart du bloc PLUS les
   marges intérieures de la citation. Rien à écrire : la règle est retirée.
   (Masquée jusqu'ici : l'en-tête n'avait jamais été monté avec sa citation.)
*/

/*
   LA LIGNE DE DATE (156:9312) : une icône de 16 et un texte Outfit
   Regular 16 anthracite, écart 6. Même dessin que le sur-titre à
   flèche des sections — c'est `stv-icone-surtitre` de composants.css
   qui peint la flèche en `currentColor`.

   La date est rendue par `get_the_modified_date()` dans
   `page-legale.php` : jamais saisie (décision 139.5).

   INTERLIGNE 1,25, pas 1,5 — relevé du 25/09. Le texte est en
   « leading normal » dans la maquette : sa boîte fait 20 pour un corps
   de 16 (156:9316) et 15 pour 12 en mobile (156:8205), soit 1,25 aux
   deux tailles. À 1,5 la ligne prenait 24 et l'en-tête 204 au lieu des
   200 dessinés.
*/
.stv-entete-page .stv-entete-page__meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--stv-espace-6);
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: 1.25;
  color: var(--stv-anthracite);
}

.stv-entete-page .stv-entete-page__meta svg {
  flex: 0 0 auto;
  width: var(--stv-espace-16);
  height: var(--stv-espace-16);
}

/*
   L'EN-TÊTE QUI PORTE LA PAGE — ajouté le 05/10 (Nos marques, 156:10324).
   La maquette pose le H1 ET la grille des marques dans la même bande
   crème, à 48 l'un de l'autre et à 80 des bords (1840 × 832). Le bloc qui
   suit le titre prend toute la largeur du contenu : l'en-tête centre ses
   enfants (`align-items: center`) et le resserrerait sinon sur sa largeur
   propre. Posé par un widget (le code court des marques), le
   `stv-entete-page__contenu` arrive sur l'enveloppe du widget — c'est elle
   qu'on étire. Le modificateur `--contenu` garde l'écart de 48 en mobile
   (156:7838 : H1 à 32 du haut, grille 48 plus bas), là où la citation de
   La marque le resserre à 24 (§ 11).
*/
.stv-entete-page .stv-entete-page__contenu {
  align-self: stretch;
  width: 100%;
}


/* =====================================================================
   2. BANNIÈRE PHOTO DE PAGE
   Nœuds 156:10509 (Espace pro, voile crème plat, texte centré),
   156:9485 (Notre histoire, voile crème latéral, texte à gauche),
   156:10917 (SAV, opaque en métadonnées, même famille).

   TROIS RÉGLAGES, PAS TROIS BLOCS : le voile (plat ou latéral), l'axe
   du texte (centré ou à gauche) et ce que la bannière contient après
   l'intro (rien, des puces, une carte). Le contenu est libre : la
   bannière est un conteneur, pas un gabarit de texte.

   Elle est PLEINE LARGEUR et le texte se pose dedans — à distinguer du
   bandeau (§ 3), où l'image est encadrée par la marge de la page.

   Ce n'est PAS le shortcode `[stelvoren_hero]` de l'accueil : pas de
   vidéo, pas de cale de hauteur de fenêtre, pas de voile en dégradé
   vertical. Une bannière photo sans vidéo est une classe V4.
   ================================================================== */

/*
   RELEVÉ DU 22/09 — L'ADVERSAIRE D'UNE ENVELOPPE POSÉE SUR UN ÉLÉMENT V4.

   Les enveloppes du socle arrivent sur une page Elementor par un élément
   atomique V4 (`e-div-block`), seul moyen de leur faire porter une
   classe : un conteneur V3 n'émet NI `_css_classes` NI `css_classes`
   dans le DOM (vérifié sur cette page, deux imports). Or l'atomique
   apporte `.elementor .e-div-block-base { display: block; padding: 10px }`
   — `base-desktop.css`, 0,2,0, chargée APRÈS la nôtre. Une classe seule
   (0,1,0) perd deux fois : sur le compte et sur l'ordre.

   D'où la classe RÉPÉTÉE TROIS FOIS (0,3,0) sur les enveloppes et sur
   leurs modificateurs. Les modificateurs montent avec elles : à 0,3,0
   pour `.stv-banniere` et 0,1,0 pour `.stv-banniere--lateral`, le voile
   latéral aurait cessé de gagner — un piège que la répétition crée si
   on ne la propage pas.

   CE QUI RESTE À FAIRE : `stv-split` a été monté et répété sur le SAV
   (22/09), `stv-entete-page` et `stv-bandeau` sur La marque (30/09). Reste
   `stv-callout` et ses modificateurs, jamais posés sur un élément V4 :
   même 0,2,0 à battre, même répétition, au premier écran qui le porte (le
   guide studio maison, 126) — en mesurant, pas à l'aveugle. La page
   styleguide ne peut pas le voir : elle rend le balisage en PHP, sans
   l'atomique d'Elementor.
*/
.stv-banniere.stv-banniere.stv-banniere {
  --stv-banniere-voile: var(--stv-voile-creme);
  --stv-banniere-titre: var(--stv-taille-hero);
  --stv-banniere-titre-interlettre: -0.01em;
  --stv-banniere-texte-ecart: var(--stv-espace-16);
  --stv-banniere-intro: var(--stv-taille-accroche);
  /* Deux réglages ajoutés le 15/10 (Notre histoire), neutres par défaut :
     la hauteur minimale (`--haute`) et la largeur du bloc titre + intro
     (`--lateral`). `auto` et `none` : rien ne bouge sur l'Espace pro ni
     sur le SAV. */
  --stv-banniere-hauteur-min: auto;
  --stv-banniere-texte-largeur: none;

  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-80);
  align-items: center;
  justify-content: center;
  min-height: var(--stv-banniere-hauteur-min);
  padding: var(--stv-section-y) var(--stv-page-gouttiere);
  isolation: isolate;
}

/*
   L'image en fond et le voile par-dessus, tous deux en couche
   inférieure : le contenu reste dans le flux, donc la bannière prend
   la hauteur de ce qu'on y met. Pas de hauteur fixe — la maquette en
   donne trois différentes (620 sur Notre histoire, 480 sur le SAV,
   1333 sur l'Espace pro) parce que le contenu diffère, pas parce que
   le bloc aurait trois tailles.
*/
.stv-banniere__image,
.stv-banniere::after {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.stv-banniere__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
   LA PHOTO POSÉE DEPUIS ELEMENTOR — relevé du 22/09. En PHP,
   `stv-banniere__image` est sur le `<img>` lui-même et la règle
   ci-dessus suffit. Dans une page Elementor, la classe arrive sur
   l'enveloppe du widget Image (même cause que pour le titre, plus
   haut) : l'enveloppe se met bien en couche inférieure, mais l'image
   dort au fond à sa taille naturelle. Les deux niveaux intermédiaires
   — `.elementor-widget-container` et l'éventuelle `<figure>` — sont
   donc étirés, et le `<img>` reçoit le `cover`. On garde le widget
   plutôt qu'un `<img>` écrit à la main : c'est lui qui apporte le
   `srcset` et le `sizes` de WordPress, donc le LCP du critère de fin.

   Deux répétitions de la classe (0,2,1 sur le `<img>`) : Elementor
   habille ses images par `.elementor-widget-image .elementor-image img`
   et par `.elementor-widget-image img`, jusqu'à 0,2,1 lui aussi, et il
   passe après nous.
*/
.stv-banniere__image.stv-banniere__image :where(.elementor-widget-container, figure) {
  width: 100%;
  height: 100%;
  margin: 0;
}

.stv-banniere__image.stv-banniere__image :where(img) {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.stv-banniere::after {
  content: "";
  background: var(--stv-banniere-voile);
}

/*
   VOILE LATÉRAL (156:9485) : crème opaque à gauche, presque transparent
   à droite — c'est lui qui rend le texte lisible sans assombrir la
   photo. Relevé exact : opaque jusqu'à 10,367 %, 0,8 à 40,245 %, 0,1 au
   bout.
*/
.stv-banniere--lateral.stv-banniere--lateral.stv-banniere--lateral {
  --stv-banniere-voile: var(--stv-voile-creme-lateral);
  /*
     LE TEXTE TIENT DANS LA PARTIE COUVERTE DU VOILE (156:9486 : bloc de
     672). À 1 840 il finit à 80 + 672 = 752, soit 41 % de la largeur —
     là où le voile vaut encore 0,8. Plus large, l'intro passerait sur la
     partie claire, où la photo n'est presque plus voilée. La borne
     appartient donc au voile, pas à la page. Sous 1024 le voile devient
     plat (§ 11) : la borne n'y gêne rien, le bloc est plus étroit qu'elle.
  */
  --stv-banniere-texte-largeur: 672px;
}

.stv-banniere--gauche.stv-banniere--gauche.stv-banniere--gauche {
  align-items: flex-start;
  text-align: left;
}

/*
   LA BANNIÈRE D'OUVERTURE (156:9485, 15/10) : 620 de haut au moins, le
   texte centré en hauteur dans la photo, 24 entre le titre et l'intro
   (156:9486). Une page de récit s'ouvre sur une image ; une page à
   formulaire (Espace pro, SAV) prend la hauteur de ce qu'elle porte.
   UN MINIMUM, PAS UNE HAUTEUR : un titre sur deux lignes ou une intro plus
   longue agrandissent la bannière au lieu de déborder. Sous 1024, non
   dessiné : la hauteur redevient celle du contenu (§ 11).
*/
.stv-banniere--haute.stv-banniere--haute.stv-banniere--haute {
  --stv-banniere-hauteur-min: 620px;
  --stv-banniere-texte-ecart: var(--stv-espace-24);
}

/*
   LE TITRE D'UNE PAGE À FORMULAIRE EST UN H2, PAS UN HERO (156:10512) :
   Outfit Medium 50 à -0,25px, soit `--stv-taille-h2` et son
   interlettrage de -0,005em — là où Notre histoire (156:9487) reste à
   62. Le § 2 annonçait déjà « c'est le poids de la page » ; voici le
   réglage qui le porte, au lieu d'une seconde classe de titre.
*/
.stv-banniere--titre-h2.stv-banniere--titre-h2.stv-banniere--titre-h2 {
  --stv-banniere-titre: var(--stv-taille-h2);
  --stv-banniere-titre-interlettre: -0.005em;
}

.stv-banniere__contenu.stv-banniere__contenu.stv-banniere__contenu {
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-24);
  align-items: inherit;
  /* `padding: 0` explicite : l'atomique V4 pose 10 sur tout e-div-block,
     et 10 de chaque côté, c'est 20 de moins pour les colonnes de champs
     — relevé du 22/09, la demi-rangée tombait à 274 au lieu de 284. */
  padding: 0;
  max-width: var(--stv-largeur-contenu);
}

/*
   Le sous-bloc titre + intro (156:10511) : écart de 16, pas de 24. Le
   contenu de la bannière a donc DEUX rythmes — 24 entre ses blocs, 16
   entre le titre et son intro — et c'est ce qui fait que les puces
   respirent sous l'intro sans que le titre s'en éloigne.
*/
.stv-banniere__texte.stv-banniere__texte.stv-banniere__texte {
  display: flex;
  flex-direction: column;
  gap: var(--stv-banniere-texte-ecart);
  align-items: inherit;
  max-width: var(--stv-banniere-texte-largeur);
  padding: 0;
}

/*
   LE TEXTE EST CENTRÉ LIGNE À LIGNE, À TOUTES LES LARGEURS (156:10511
   porte `text-center`). Le bloc était déjà centré dans la page par
   `align-items` ; ce sont les LIGNES qui restaient fer à gauche, et un
   titre ou une intro de plusieurs lignes fer à gauche sous un bloc
   centré se lit comme un défaut d'alignement.

   La variante `--gauche` (Notre histoire, 156:9485) est EXCLUE : elle
   est à gauche par décision, pas par défaut. L'exclusion est
   nécessaire et non décorative — une déclaration posée sur le
   descendant l'emporte sur l'héritage quel que soit le compte de la
   classe, donc `--gauche` aurait basculé au centre sans elle.
*/
.stv-banniere:not(.stv-banniere--gauche) .stv-banniere__texte {
  text-align: center;
}

/*
   Deux classes (0,2,0) devant le kit. Le H1 de la bannière est à 50 sur
   l'Espace pro (156:10512) et à 62 sur Notre histoire (156:9487) : ce
   n'est pas une incohérence, c'est le poids de la page — une page à
   formulaire annonce moins fort qu'une page d'histoire. La valeur par
   défaut est celle du H1 de page ; `--stv-banniere-titre` la règle.
*/
/*
   DEUX SÉLECTEURS, UN SEUL CORPS — RELEVÉ DU 22/09. Sur une page
   Elementor, `_css_classes` d'un widget V3 se pose sur l'ENVELOPPE du
   widget (`div.elementor-widget-heading`), pas sur le `<h1>` qu'elle
   contient : la règle habillait donc une boîte, et le titre gardait la
   taille que le kit donne à `h1` (62 au lieu de 50). Le second
   sélecteur descend au titre, en `:where()` pour ne rien ajouter au
   compte (0,2,0, devant le 0,1,1 de `.elementor-kit-44301 h1`).
*/
.stv-banniere .stv-banniere__titre,
.stv-banniere .stv-banniere__titre :where(h1, h2, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-banniere-titre);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: var(--stv-banniere-titre-interlettre);
  color: var(--stv-texte);
  text-wrap: balance;
}

.stv-banniere .stv-banniere__intro,
.stv-banniere .stv-banniere__intro :where(p) {
  margin: 0;
  max-width: var(--stv-largeur-texte);
  font-size: var(--stv-banniere-intro);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
}

/*
   LA BANNIÈRE SERRÉE DU SAV (156:10918) : écart de 8 sous le titre et
   intro à 16, là où l'Espace pro respire à 16 et 20.

   Ce n'est pas une incohérence du designer, c'est l'inverse : plus le
   titre est gros, plus l'intro s'efface. L'Espace pro porte un titre de
   50 et un argumentaire de trois lignes suivi de puces ; le SAV porte
   un titre de 62 et une seule phrase d'explication, qui doit rester
   sous lui sans lui disputer la place. Deux variables, pas une seconde
   classe de bannière.
*/
.stv-banniere--compacte.stv-banniere--compacte.stv-banniere--compacte {
  --stv-banniere-texte-ecart: var(--stv-espace-8);
  --stv-banniere-intro: var(--stv-taille-texte);
}


/* =====================================================================
   3. BANDEAU PHOTO À TEXTE CENTRÉ
   Nœuds 156:10650 / 156:10651 / bouton 156:10654 (La marque, showroom)
   et 156:9530 (guide studio maison, H1 + intro). Même famille que
   « Notre conviction » (156:9522).

   C'est le quatrième bloc « photo + voile + texte blanc » du site, avec
   Product CTA, les suggestions et la carte promo d'article : UN SEUL
   jeu de règles de voile, celui du jeton `--stv-voile-bandeau`, et un
   contraste à vérifier ≥ 4,5:1 sur chaque photo réelle.

   Le texte est ancré EN BAS de l'image, à 48 du bord (relevé 156:10652
   : sommet du bloc à 601 dans un conteneur de 800, bloc de 151 de
   haut). C'est une ancre, pas une position absolue : un titre sur deux
   lignes doit remonter, pas déborder.
   ================================================================== */

/*
   TROIS RÉPÉTITIONS — mesuré le 30/09 sur La marque, premier écran à poser
   le bandeau sur des éléments V4 : le bandeau, son cadre et son contenu
   sortaient en `display: block` avec 10 de marge intérieure (l'atomique à
   0,2,0, § 2) ; le titre restait au noir du kit, la photo à sa hauteur
   naturelle (1 680 × 1 120 dans un cadre de 720). Les règles du § 11
   montent avec eux.
*/
.stv-bandeau.stv-bandeau.stv-bandeau {
  display: flex;
  padding: var(--stv-section-y) var(--stv-page-gouttiere);
  background: var(--stv-blanc);
}

.stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
  /* 720 en desktop (156:10651), 480 sous 1024 (non dessiné), 428 en mobile
     (156:8382) : une variable que le § 11 règle. */
  --stv-bandeau-hauteur: 720px;

  position: relative;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  min-height: var(--stv-bandeau-hauteur);
  padding: var(--stv-espace-48);
  isolation: isolate;
}

.stv-bandeau__image,
.stv-bandeau__cadre::after {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.stv-bandeau__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
   LA PHOTO POSÉE DEPUIS ELEMENTOR (30/09) — même cause et même parade
   qu'au § 2 pour `stv-banniere__image` : la classe arrive sur l'enveloppe
   du widget Image V3, qui se met bien en couche inférieure, mais l'image y
   dormait à sa taille naturelle. On étire les niveaux intermédiaires et le
   `<img>` reçoit le `cover`. Le widget V3 plutôt que l'élément Image V4 :
   c'est lui qui sort le `srcset` et le `sizes` de WordPress (vérifié : les
   deux attributs sont là), et le SAV comme le Contact l'emploient déjà.
*/
.stv-bandeau__image.stv-bandeau__image :where(.elementor-widget-container, figure) {
  width: 100%;
  height: 100%;
  margin: 0;
}

.stv-bandeau__image.stv-bandeau__image :where(img) {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.stv-bandeau__cadre::after {
  content: "";
  background: var(--stv-voile-bandeau);
}

.stv-bandeau__contenu.stv-bandeau__contenu.stv-bandeau__contenu {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--stv-espace-48);
  padding: 0;
  max-width: var(--stv-largeur-contenu);
  text-align: center;
}

/*
   L'ÉCART DÉPEND DE CE QU'ON MET DESSOUS : 48 avant un bouton
   (156:10652), 24 avant une intro (156:9532). Un bouton se détache, un
   paragraphe se rattache.
*/
/* Quatre classes (0,4,0) : devant le contenu écrit à 0,3,0, et devant sa
   règle mobile du § 11, au même compte, plus bas dans le fichier. */
.stv-bandeau__contenu.stv-bandeau__contenu.stv-bandeau__contenu:has(.stv-bandeau__intro) {
  gap: var(--stv-espace-24);
}

/* Deux sélecteurs, un corps : le titre posé par un widget Titre (§ 2). */
.stv-bandeau .stv-bandeau__titre,
.stv-bandeau .stv-bandeau__titre :where(h1, h2, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-taille-h2);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: -0.005em;
  color: var(--stv-blanc);
  text-wrap: balance;
}

.stv-bandeau .stv-bandeau__intro,
.stv-bandeau .stv-bandeau__intro :where(p) {
  margin: 0;
  max-width: var(--stv-largeur-texte);
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-blanc);
}

/*
   LE TEXTE DU BANDEAU — `stv-bandeau__texte` (« Notre conviction »,
   156:9524, 15/10). Un paragraphe de plusieurs lignes sous un H2, et non
   l'intro d'un bandeau d'en-tête : 48 sous le titre et non 24 (l'écart du
   contenu, que le `:has(.stv-bandeau__intro)` ne touche pas), et une ligne
   plus longue que la colonne de lecture — 1 106 (156:9526), trois lignes à
   1 840 au lieu de cinq.

   UN TEXTE QUI MONTE CHANGE DE VOILE. Ancré à 48 du bas, ce bloc de 175
   (cinq lignes de plus en mobile) remonte bien au-dessus de la bande
   sombre où se pose un titre seul : c'est le cas du H1 centré des guides
   en mobile (05/10), et le voile « centré » des jetons, qui s'appuie dès
   le haut, y répond. Posé dès qu'un `__texte` est dans le cadre — rien à
   choisir dans l'éditeur. Le compte (0,4,1 avec le `:has()`) passe devant
   le voile du cadre, écrit à 0,1,1 ; il n'a rien à battre d'autre — la
   règle mobile du bandeau d'en-tête vise une autre page.
*/
.stv-bandeau .stv-bandeau__texte,
.stv-bandeau .stv-bandeau__texte :where(p) {
  margin: 0;
  max-width: 1106px;
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-blanc);
}

.stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre:has(.stv-bandeau__texte)::after {
  background: var(--stv-voile-bandeau-centre);
}

/*
   LE BANDEAU EN TÊTE DE PAGE — `stv-bandeau--tete` (pages conseils, 05/10 :
   156:9530 et 156:9727, mobile 156:8676). Le premier bloc de la page, qui
   porte le H1 et une intro. Trois réglages, pas un autre bloc :

   - la section respire moins : 48 sous l'en-tête du site, 32 avant le bloc
     suivant (l'encadré « L'essentiel », lui-même à 32 : 64 entre les deux) ;
     32 / 32 en mobile — là où le bandeau du showroom, au milieu d'une page,
     prend la marge de section (80 / 32) ;
   - le titre se borne à la colonne de lecture (820 dans la maquette, 816 :
     `--stv-largeur-texte`), sans quoi « Créer son espace Pilates à la
     maison : le guide complet » tiendrait sur une ligne de 1 250 ;
   - en mobile le cadre fait 420 (156:8677) et le texte s'y CENTRE en hauteur
     (156:8678 : 142 → 343 dans 32 → 452), là où le showroom l'ancre en bas.

   L'ancrage desktop reste celui du bandeau, à 48 du bas : c'est ce que
   dessine le guide pro (156:9729, texte de 562 à 720 dans une image qui
   finit à 768). Le guide maison (156:9532) le pose à 16 — même bloc de texte
   recopié à la même hauteur (594) dans un cadre remonté de 32 : coquille de
   recopie, pas un réglage. Écart assumé.

   Trois classes (0,3,0), comme le bandeau : un élément V4.
*/
.stv-bandeau--tete.stv-bandeau--tete.stv-bandeau--tete {
  padding-block: var(--stv-espace-48) var(--stv-espace-32);
}

.stv-bandeau--tete .stv-bandeau__titre,
.stv-bandeau--tete .stv-bandeau__titre :where(h1, h2, p, .elementor-heading-title) {
  max-width: var(--stv-largeur-texte);
  margin-inline: auto;
}

/*
   LE BANDEAU À TEXTE LATÉRAL — `stv-bandeau--lateral` (fiche produit,
   section « Image + texte », fiche 177, 23/10 : 315:17636). Rendu en PHP
   (`parties/fiche-presentation.php`), même balisage que le bandeau :
   cadre, photo, voile, contenu, titre, texte. Quatre réglages, pas un
   autre bloc :

   - la photo va BORD À BORD (1 840 × 780) : pas de marge blanche autour
     du cadre, et 80 de marge intérieure sur les quatre côtés ;
   - le texte est À DROITE, centré en hauteur, dans une colonne de 672
     (315:17638), fer à gauche, 24 entre le titre et le paragraphe ; sur un
     écran plus large que la maquette, la colonne s'arrête au bord du
     contenu (1 680), pas au bord de l'écran ;
   - le titre est l'intertitre de la fiche — Outfit Medium 40 à 1,5 —, pas
     le H2 de section ; le paragraphe en Inter Medium 16 sur 528 ;
   - le voile s'appuie là où le texte se pose : `--stv-voile-bandeau-
     lateral` (jetons), sombre à droite. CONTRASTE ≥ 4,5:1 mesuré sur la
     photo réelle, pas sur la maquette (relevé du lot).

   SOUS 1025 (non dessiné, § 5 de l'inventaire) : le texte descend AU BAS
   du cadre, comme le bandeau mobile, sous le voile vertical « centré »
   (qui s'appuie dès le haut : un paragraphe de plusieurs lignes monte
   haut dans le cadre).

   COMPTES : quatre classes (0,4,0) sur le bandeau, le cadre et le contenu —
   devant les règles du bandeau (0,3,0), le plafond de 1 680 du § 4 (qui
   pose `padding-inline` sur le bandeau, plus bas dans le fichier : mesuré
   à 1840, la photo s'arrêtait à 80 des bords) et le § 11 ; cinq sur le
   voile (0,5,1), devant le `:has(.stv-bandeau__texte)` qui le change déjà
   (0,4,1) ; trois sur la photo (0,3,0), devant `.woocommerce img { height:
   auto }` (0,1,1) que la fiche porte. Pas d'atomique V4 à battre ici (PHP),
   mais la variante reste posable dans Elementor.
*/
.stv-bandeau.stv-bandeau--lateral.stv-bandeau--lateral.stv-bandeau--lateral {
  padding: 0;
  background: none;
}

.stv-bandeau--lateral .stv-bandeau__image.stv-bandeau__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}

.stv-bandeau--lateral .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
  --stv-bandeau-hauteur: 780px;

  align-items: flex-end;
  justify-content: center;
  /* Élément flex du bandeau : sans ce zéro, sa largeur minimale est celle
     du contenu (672), et à 393 la page débordait de 311 (mesuré le 23/10). */
  min-width: 0;
  padding-block: var(--stv-section-y);
  padding-inline: max(var(--stv-page-gouttiere), (100% - var(--stv-largeur-contenu)) / 2);
}

.stv-bandeau--lateral.stv-bandeau--lateral .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre::after {
  background: var(--stv-voile-bandeau-lateral);
}

.stv-bandeau--lateral .stv-bandeau__contenu.stv-bandeau__contenu.stv-bandeau__contenu {
  align-items: flex-start;
  gap: var(--stv-espace-24);
  width: 672px;
  max-width: 100%;
  text-align: left;
}

.stv-bandeau--lateral .stv-bandeau__titre.stv-bandeau__titre,
.stv-bandeau--lateral .stv-bandeau__titre.stv-bandeau__titre :where(h2, p, .elementor-heading-title) {
  font-size: 40px;
  line-height: var(--stv-interligne-texte);
  letter-spacing: normal;
}

.stv-bandeau--lateral .stv-bandeau__texte.stv-bandeau__texte,
.stv-bandeau--lateral .stv-bandeau__texte.stv-bandeau__texte :where(p) {
  max-width: 528px;
  font-weight: 500;
}

.stv-bandeau--lateral .stv-bandeau__texte :where(p + p) {
  margin-top: 1em;
}

@media (max-width: 1024px) {
  .stv-bandeau--lateral .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
    --stv-bandeau-hauteur: 480px;

    align-items: flex-start;
    justify-content: flex-end;
    padding: var(--stv-espace-48) var(--stv-espace-32);
  }

  .stv-bandeau--lateral.stv-bandeau--lateral .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre::after {
    background: var(--stv-voile-bandeau-centre);
  }
}

@media (max-width: 767px) {
  .stv-bandeau--lateral .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
    --stv-bandeau-hauteur: 428px;

    padding: var(--stv-espace-32) var(--stv-espace-16) var(--stv-espace-48);
  }

  .stv-bandeau--lateral .stv-bandeau__contenu.stv-bandeau__contenu.stv-bandeau__contenu {
    gap: var(--stv-espace-16);
  }

  .stv-bandeau--lateral .stv-bandeau__titre.stv-bandeau__titre,
  .stv-bandeau--lateral .stv-bandeau__titre.stv-bandeau__titre :where(h2, p, .elementor-heading-title) {
    font-size: 24px;
  }
}


/* =====================================================================
   4. SECTION TEXTE + IMAGE — `stv-split`
   Nœuds 156:10636 (texte à gauche) et 156:10643 (image à gauche) sur La
   marque, 156:9606 (avec tableau) et 156:9569 / 156:9576 sur le guide,
   156:10999 (fond bleu clair) sur le SAV, 156:9264 (avec bouton) sur le
   Contact.

   CINQ PAGES, UNE CLASSE. L'ordre des colonnes, le fond de la section,
   la proportion des colonnes, la hauteur de l'image et l'ordre en
   mobile sont des RÉGLAGES. C'est aussi la mise en page de la
   présentation de catégorie niveau 1 (fiche 98) : à écrire ici une
   fois, pas deux.

   La colonne de texte est bornée à 816 et le texte lui-même respire
   plus court (705 relevé sur 156:10641) : c'est une mesure de lecture,
   exprimée en `ch` plutôt qu'en pixels pour qu'elle survive à un
   changement de taille de police.
   ================================================================== */

/*
   TROIS RÉPÉTITIONS — mesuré le 22/09 sur le SAV, premier écran à poser
   un split sur un élément V4. Symptôme : `display: block` au lieu de
   `flex`, donc les deux colonnes empilées et l'image étalée sur toute
   la largeur. Cause : `.elementor .e-div-block-base` à 0,2,0, chargée
   après nous (voir le relevé du § 2). Les modificateurs montent avec la
   classe, sans quoi la répétition les ferait perdre.
*/
.stv-split.stv-split.stv-split {
  --stv-split-fond: var(--stv-blanc);
  --stv-split-image: 620px;
  --stv-split-texte-ecart: var(--stv-espace-16);
  /*
     RÉGLAGES AJOUTÉS LE 23/09 (Contact, premier écran à varier la
     PROPORTION des colonnes). Jusque-là le partage était écrit en dur
     dans les deux sous-blocs : texte à la mesure de lecture, image qui
     prend le reste. Le Contact en demande deux autres — moitié / moitié
     (156:9211) et un tiers / trois cinquièmes (156:9264) — et un réglage
     se porte par une variable lue par les enfants, pas par un troisième
     jeu de règles à 0,4,0 comme celui de `--boite` plus bas.
     Les valeurs par défaut sont celles d'avant : rien ne bouge ailleurs.
  */
  --stv-split-texte-flex: 0 1 var(--stv-largeur-texte);
  --stv-split-media-flex: 1 1 0;
  /* Hauteur de l'image une fois les colonnes empilées (§ 11). */
  --stv-split-image-empile: 320px;
  /* Le titre de colonne : H2 de section par défaut, H1 sur le Contact. */
  --stv-split-titre: var(--stv-taille-h2);
  --stv-split-titre-interlettre: -0.005em;

  display: flex;
  gap: var(--stv-gouttiere);
  align-items: center;
  padding: var(--stv-section-y) var(--stv-page-gouttiere);
  background: var(--stv-split-fond);
}

/* =====================================================================
   LE PLAFOND DE 1 680 — relevé du 22/09, sur la page Espace pro.

   `jetons.css` dit depuis le 21/08 que la marge latérale d'une section
   pleine largeur vaut « 1840 − 1680 = 160, soit 80 de chaque côté ».
   C'est vrai À 1840, et faux partout au-dessus : une gouttière fixe de
   80 laisse le contenu s'étaler avec l'écran. Mesuré à 2400 avant
   correction — la rangée de cartes de l'Espace pro faisait 2 225 de
   large, et son en-tête, plafonné lui à 816, restait collé au bord
   gauche pendant que les cartes filaient à droite. Deux défauts pour
   une seule cause : le plafond n'était posé que sur DEUX blocs
   intérieurs (`stv-banniere__contenu`, `stv-bandeau__contenu`), jamais
   sur les sections elles-mêmes.

   La parade tient en une ligne et n'a pas besoin de requête de média :
   la gouttière devient le PLUS GRAND des deux — la marge voulue, ou ce
   qu'il faut retirer de chaque côté pour que le contenu tienne dans
   1 680. Sous 1 840 la soustraction est négative et c'est la gouttière
   qui gagne ; au-dessus, c'est le plafond. Le fond, lui, reste à pleine
   largeur : c'est le contenu qu'on borne, pas la section.

   Trois répétitions : voir le relevé du § 2 sur l'atomique V4, qui pose
   `display: block; padding: 10px` à 0,2,0 après nous. Il faut ce compte
   pour que la règle tienne aussi quand la section est un élément V4 —
   et `stv-section`, la classe générique des sections de page montées
   dans Elementor, l'est toujours.
   ================================================================== */
.stv-entete-page.stv-entete-page.stv-entete-page,
.stv-banniere.stv-banniere.stv-banniere,
.stv-bandeau.stv-bandeau.stv-bandeau,
.stv-split.stv-split.stv-split,
.stv-section.stv-section.stv-section {
  padding-inline: max(
    var(--stv-page-gouttiere),
    (100% - var(--stv-largeur-contenu)) / 2
  );
}

/*
   LA SECTION DE PAGE, GÉNÉRIQUE. Une bande pleine largeur qui empile
   ses blocs et tient son contenu dans le plafond ci-dessus : c'est tout
   ce qu'elle fait. Le fond et le rythme intérieur appartiennent à la
   page qui la pose — sur l'Espace pro, le crème et l'écart de 48 sont
   des styles locaux Elementor, pas une variante du socle, parce que
   rien ne dit encore qu'un deuxième écran les reprendra.

   Elle existe parce que `stv-entete-page`, `stv-banniere`, `stv-bandeau`
   et `stv-split` décrivent chacun une FORME ; une section qui n'a pas
   de forme arrêtée — un titre, un chapeau, trois cartes — n'avait aucune
   classe où accrocher sa gouttière, et se la réécrivait à la main.
*/
.stv-section.stv-section.stv-section {
  display: flex;
  flex-direction: column;
  padding-block: var(--stv-section-y);
}

/*
   Le fond crème d'une section de page. Vu deux fois — « Accompagnement
   client » de l'Espace pro (156:10606) et la section du formulaire du
   SAV (156:10921) — donc il quitte les styles locaux des deux pages
   pour venir ici. Le SAV le pose à 80 % d'opacité dans la maquette,
   héritage d'une section qui portait une photo ; sans photo derrière,
   0,8 de crème sur du blanc et du crème plein ne se distinguent pas à
   l'œil, et le jeton est plus sûr qu'une transparence recopiée.
*/
.stv-section--creme.stv-section--creme.stv-section--creme {
  background: var(--stv-beige);
}

/*
   LA SECTION SERRÉE — 32 au-dessus et au-dessous au lieu de 80 (05/10,
   l'encadré « L'essentiel » des pages conseils, 156:9535). En mobile la
   marge de section vaut déjà 32 : rien à redire.
*/
.stv-section--serree.stv-section--serree.stv-section--serree {
  padding-block: var(--stv-espace-32);
}

/* Image à gauche, texte à droite (156:10643) — le même bloc, retourné. */
.stv-split--inverse.stv-split--inverse.stv-split--inverse {
  flex-direction: row-reverse;
}

/* Le fond bleu clair de la section garantie du SAV (156:10999). */
.stv-split--bleu.stv-split--bleu.stv-split--bleu {
  --stv-split-fond: var(--stv-bleu-clair);
}

/*
   LE FOND CRÈME (Contact, 156:9211 : `bg-[var(--beige)]` sur la section
   entière). Un modificateur du split plutôt que `stv-section--creme`
   posé à côté : les deux écrivent `background` à 0,3,0, et le crème ne
   gagnerait que parce qu'il est écrit plus bas dans ce fichier — la
   règle du projet est de ne jamais compter sur l'ordre. Ici le fond
   passe par la même variable que le bleu.
*/
.stv-split--creme.stv-split--creme.stv-split--creme {
  --stv-split-fond: var(--stv-beige);
}

/*
   MOITIÉ / MOITIÉ (Contact, 156:9211 : deux enfants en `flex-[1_0_0]`,
   816 | 48 | 816 à 1840). La colonne de gauche n'est pas une colonne de
   lecture — elle porte le H1 et deux cartes de 648 —, la borner à la
   mesure de 816 laisserait l'image s'effondrer dès que l'écran rétrécit
   (256 de large à 1280, mesuré sur le calcul avant d'écrire cette règle).
*/
.stv-split--moitie.stv-split--moitie.stv-split--moitie {
  --stv-split-texte-flex: 1 1 0;
  --stv-split-media-flex: 1 1 0;
}

/*
   LA GRANDE IMAGE (Contact, section showroom 156:9264 :
   `justify-between`, texte 563, image 1028 × 720). Les deux largeurs
   sont écrites en PROPORTION du contenu de 1 680 et non en pixels : à
   1 840 elles redonnent exactement 563 | 89 | 1028, et en dessous le
   bloc se resserre au lieu de laisser 252 à la colonne de texte (ce que
   donnerait une image fixe de 1 028 à 1 440). L'écart n'est pas le 48
   du site mais ce qui reste — c'est ce que dit `justify-between`.
*/
.stv-split--large.stv-split--large.stv-split--large {
  --stv-split-texte-flex: 0 1 calc(100% * 563 / 1680);
  --stv-split-media-flex: 0 1 calc(100% * 1028 / 1680);
  --stv-split-image: 720px;

  justify-content: space-between;
}

/*
   UNE IMAGE PLUS HAUTE UNE FOIS EMPILÉE (Contact mobile 156:8226 : les
   deux photos à 353 × 420, là où le SAV tient 320). La hauteur empilée
   est un réglage, lu par le § 11.
*/
.stv-split--image-haute.stv-split--image-haute.stv-split--image-haute {
  --stv-split-image-empile: 420px;
}

/*
   LE TITRE DE COLONNE EN H1 (Contact, 156:9214 : Outfit Medium 62 à
   −0,62 px, soit le H1 de page). Le même réglage que
   `stv-banniere--titre-h2`, dans l'autre sens : une variable, pas une
   seconde classe de titre.
*/
.stv-split--titre-h1.stv-split--titre-h1.stv-split--titre-h1 {
  --stv-split-titre: var(--stv-taille-hero);
  --stv-split-titre-interlettre: -0.01em;
}

/* =====================================================================
   LE SPLIT EN BOÎTE — relevé du 22/09 sur le SAV, et correction d'une
   supposition du 21/09.

   Le socle avait rangé la section garantie du SAV sous `--bleu` en
   supposant que le fond coloré allait de bord à bord, comme les splits
   des guides. Le relevé Dev Mode dit autre chose : la boîte bleue de
   `156:11000` est EN RETRAIT — elle vit dans une section à gouttière
   de 80 et porte sa propre marge intérieure de 48 en haut et 64 sur les
   côtés. Un fond qui touche les bords et un fond en retrait ne sont pas
   le même objet : le premier est une bande, le second une carte large.

   Trois conséquences, toutes ici :

   1. La marge intérieure devient la sienne, et le PLAFOND DE 1 680 ne
      s'applique plus — il est déjà tenu par la section qui l'enveloppe.
      Sans cette ligne, la boîte hériterait du `max()` et s'écraserait.
      Écrit après la règle de plafond, à compte égal : c'est l'ordre qui
      tranche.
   2. Les deux colonnes s'échangent leurs rôles. Par défaut le socle
      borne le TEXTE à la mesure de lecture et laisse l'image prendre le
      reste ; ici c'est l'image qui est fixe — 384, soit `--stv-colonne`
      — et le texte qui prend ce qui reste (1 120 à 1840). Une liste
      n'est pas de la prose : elle ne se lit pas en 68 ch, elle se
      balaie.
   3. L'écart de la colonne passe à 24 par la variable ci-dessus.

   Sous 1024 la marge retombe à 24, comme le cadre du bandeau.
   ================================================================== */
.stv-split--boite.stv-split--boite.stv-split--boite {
  --stv-split-texte-ecart: var(--stv-espace-24);

  padding-block: var(--stv-espace-48);
  /* 64 : relevé sur 156:11000, et vu UNE seule fois. Il n'entre donc pas
     dans `jetons.css` — la règle du projet est qu'un jeton se mérite à
     la deuxième occurrence. Le jour où un second écran le reprend, il
     devient `--stv-espace-64` et cette ligne le suit. */
  padding-inline: 64px;
}

/*
   0,4,0 et non 0,3,0 : les deux sous-blocs sont eux-mêmes écrits à
   0,3,0 plus bas dans le fichier pour tenir devant l'atomique V4, et à
   compte égal c'est l'ordre qui gagne. Un modificateur doit passer
   devant la classe qu'il modifie, où qu'elle soit écrite.
*/
.stv-split--boite.stv-split--boite .stv-split__texte.stv-split__texte {
  flex: 1 1 auto;
}

.stv-split--boite.stv-split--boite .stv-split__media.stv-split__media {
  flex: 0 0 var(--stv-colonne);
}

.stv-split__texte.stv-split__texte.stv-split__texte {
  display: flex;
  flex: var(--stv-split-texte-flex);
  flex-direction: column;
  gap: var(--stv-split-texte-ecart);
  align-items: flex-start;
  /* `padding: 0` : les 10 de l'atomique V4, deux fois, c'est 20 de
     moins pour la colonne — et la mesure de lecture en `ch` fausse. */
  padding: 0;
  min-width: 0;
}

/*
   L'ÉCART DE 48 quand la colonne porte un tableau ou une liste de
   blocs (156:9608) plutôt qu'un titre et un paragraphe : un tableau
   collé à son titre se lit mal. Le SAV, lui, demande 24 (156:11002) —
   d'où un RÉGLAGE et non trois nombres écrits à trois endroits.
*/
.stv-split__texte--aere.stv-split__texte--aere.stv-split__texte--aere {
  --stv-split-texte-ecart: var(--stv-gouttiere);
}

/*
   DEUX ÉCARTS DE PLUS — pages conseils, 05/10.

   `--moyen` : 24 entre le titre et son texte (156:9571, et 24 aussi en mobile,
   156:8717), là où La marque en met 16. Un titre suivi de deux paragraphes
   denses se détache un peu plus.

   `--bloc` : un titre puis UN BLOC (un tableau, une liste d'encadrés) — 48 à
   TOUTES les largeurs (156:9579 / 156:9608 en desktop, 156:8724 / 156:8754 en
   mobile). Ce n'est pas `--aere` : la colonne aérée du Contact (156:8229) se
   resserre à 32 en mobile entre trois blocs égaux, le guide garde 48 entre un
   titre et ce qu'il annonce. Deux maquettes, deux réglages.
*/
.stv-split__texte--moyen.stv-split__texte--moyen.stv-split__texte--moyen {
  --stv-split-texte-ecart: var(--stv-espace-24);
}

.stv-split__texte--bloc.stv-split__texte--bloc.stv-split__texte--bloc {
  --stv-split-texte-ecart: var(--stv-espace-48);
}

/*
   DEUX SÉLECTEURS, UN SEUL CORPS — ajouté le 23/09, même cause qu'au § 2
   pour le titre de bannière : sur une page Elementor la classe d'un
   widget Titre V3 se pose sur son ENVELOPPE, et le `<h2>` gardait ce que
   le kit donne à `h2`. Sur le SAV les deux valeurs coïncidaient (50),
   ce qui avait masqué le défaut ; le H1 du Contact (62) l'aurait révélé.
   Le second sélecteur descend au titre en `:where()`, sans rien ajouter
   au compte (0,2,0, devant le 0,1,1 du kit).
*/
.stv-split .stv-split__titre,
.stv-split .stv-split__titre :where(h1, h2, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-split-titre);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: var(--stv-split-titre-interlettre);
  color: var(--stv-texte);
  text-wrap: balance;
}

/*
   UN GROUPE DANS LA COLONNE (Contact, 156:9265 → 156:9266). La colonne
   du showroom a DEUX rythmes : 16 entre le titre et son paragraphe, 48
   avant le bouton — un bouton se détache, un paragraphe se rattache,
   comme dans le bandeau (§ 3). La colonne porte le 48
   (`stv-split__texte--aere`), le groupe porte le 16. Trois répétitions
   et `padding: 0` : c'est un élément V4.
*/
.stv-split__groupe.stv-split__groupe.stv-split__groupe {
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-16);
  align-items: flex-start;
  padding: 0;
}

.stv-split .stv-split__corps.stv-split__corps {
  margin: 0;
  /* La mesure de lecture, quand le corps est un Paragraphe V4 (la classe
     est sur le `<p>` : Contact). Posé par un widget Éditeur de texte, le
     corps est une ENVELOPPE, qu'Elementor tient à 100 % par
     `.elementor.elementor .e-con > .elementor-widget` — 0,4,0 : la mesure
     descend alors aux paragraphes, ci-dessous (La marque, 30/09). */
  max-width: 68ch;
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
}

/*
   PLUSIEURS PARAGRAPHES (La marque, 30/09 : 156:10641 et 156:10649). La
   maquette sépare les deux paragraphes d'une LIGNE VIDE — un paragraphe
   vide de 24 dans le nœud texte —, soit une marge d'un interligne. Le corps
   est alors un widget Éditeur de texte, dont les `<p>` gardaient la marge
   du thème parent (0,9 em, 14,4) : zéro partout, un interligne entre deux.
*/
.stv-split .stv-split__corps.stv-split__corps :where(p) {
  max-width: 68ch;
  margin: 0;
}

.stv-split .stv-split__corps.stv-split__corps :where(p + p) {
  margin-block-start: calc(var(--stv-interligne-texte) * 1em);
}

/* Le gras du corps (156:9574 : « qu'est-ce qui, aujourd'hui, vous empêche…
   ») : Inter Medium NOIR — 600 et 700 ne sont pas livrés. */
.stv-split .stv-split__corps.stv-split__corps :where(strong, b) {
  color: var(--stv-texte);
  font-weight: 500;
}

/*
   L'IMAGE prend le reste et se recadre. `--stv-split-image` vaut la
   hauteur relevée sur La marque ; le tableau du guide (156:9647) la met
   à `100%` pour que l'image suive la hauteur du texte, et le bandeau du
   Contact à 720. Une valeur, trois réglages.
*/
.stv-split__media.stv-split__media.stv-split__media {
  flex: var(--stv-split-media-flex);
  padding: 0;
  min-width: 0;
  align-self: stretch;
}

.stv-split .stv-split__image,
.stv-split .stv-split__image.stv-split__image :where(.elementor-widget-container, figure, img) {
  display: block;
  width: 100%;
  height: var(--stv-split-image);
  object-fit: cover;
}

/*
   L'image d'un split posée depuis Elementor : la classe arrive sur
   l'enveloppe du widget, pas sur le `<img>` — même cause et même parade
   qu'au § 2 pour la photo de bannière. Les niveaux intermédiaires sont
   étirés par la règle ci-dessus ; `margin: 0` retire celle que le
   navigateur donne à `<figure>`.
*/
.stv-split .stv-split__image.stv-split__image :where(figure) {
  margin: 0;
}

/*
   Cadrage haut (03/11, guide pro, photo « profil ») : `object-fit: cover`
   recadre au centre. Pour une photo dont le sujet touche le haut du cadre,
   le cadre large et bas de la tablette (960 × 320 sous 1024) coupait la
   tête. `stv-split__image--haut`, posée avec `stv-split__image` dans les
   « Classes CSS » du widget Image, garde le haut et rogne le bas. Sans
   effet en mobile (le cadre y est presque carré : on rogne les côtés).
*/
.stv-split .stv-split__image--haut.stv-split__image--haut :where(img),
.stv-split img.stv-split__image--haut.stv-split__image--haut {
  object-position: 50% 0;
}

.stv-split--image-pleine.stv-split--image-pleine.stv-split--image-pleine {
  --stv-split-image: 100%;
}

/*
   L'IMAGE QUI SUIT LA COLONNE — premier emploi réel le 23/09 (Contact,
   156:9262 : `self-stretch`, image en `h-full`). `height: 100%` seul ne
   suffit pas : pendant que le navigateur calcule la hauteur de la
   rangée, le pourcentage de l'image ne se résout pas encore, l'image
   prend donc sa hauteur NATURELLE à la largeur de sa colonne — 1 222 de
   haut pour la photo du Contact (1000 × 1498 posée sur 816) — et c'est
   elle qui dicte la rangée au lieu de la suivre.

   La parade : l'image sort du flux de sa colonne. La colonne n'a plus
   de contenu en hauteur, elle s'étire à la hauteur du texte
   (`align-self: stretch`, déjà posé), et l'image la remplit. Quatre
   classes (0,4,0) : devant les sous-blocs écrits à 0,3,0, et devant ce
   que le widget Image d'Elementor pose sur son enveloppe. Le § 11 remet
   l'image dans le flux une fois les colonnes empilées.
*/
.stv-split--image-pleine.stv-split--image-pleine .stv-split__media.stv-split__media {
  position: relative;
}

.stv-split--image-pleine.stv-split--image-pleine .stv-split__image.stv-split__image {
  position: absolute;
  inset: 0;
}

/* Image COURTE (guide pro, section « profil » 378:17295, 03/11) : 480 au lieu de
   620 — la section fait 80 + 480 + 80 = 640 et le texte se centre dans la hauteur
   (align-items: center du split). Un réglage de la variable, pas une seconde
   classe. Une fois les colonnes empilées (§ 11), la règle ×3 de la requête de
   média, écrite plus bas au même compte, rend la main à --stv-split-image-empile. */
.stv-split--image-courte.stv-split--image-courte.stv-split--image-courte {
  --stv-split-image: 480px;
}


/* =====================================================================
   5. ENCADRÉ « L'ESSENTIEL » — `stv-callout`
   Nœud 156:9535 / 156:9536 (guide studio maison).

   CORRECTION DE L'INVENTAIRE DU 21/09 : la fiche de passe 1 décrit
   « fond crème, bordure ». Le relevé Dev Mode donne un fond BLEU CLAIR
   (#ecf7fe, variable Figma `lightblue`) et AUCUNE bordure. Le compte de
   jetons s'en trouve changé — voir le relevé du jour.

   Le sur-titre à flèche est celui du reste du site ; la liste est la
   liste à carrés de la prose (§ 8). L'encadré n'apporte donc que sa
   boîte.
   ================================================================== */

/*
   TROIS RÉPÉTITIONS — monté le 05/10 sur le guide studio maison (126),
   premier écran à poser l'encadré sur un élément V4 : même 0,2,0 à battre
   que les autres enveloppes du socle (§ 2). Le dernier du socle à passer par
   là. Ses règles du § 11 montent avec lui.

   Dans la page : une `stv-section stv-section--serree` (32 au-dessus et
   au-dessous, 156:9535) → l'encadré → le sur-titre (`[stelvoren_surtitre]`,
   la flèche ↳ du thème : 16, écart 6, Outfit 16 bleu pétrole, boîte de 20 —
   156:9538, le dessin du sur-titre de La marque) et la liste à carrés dans un
   Éditeur de texte (`<ul class="stv-liste stv-liste--carres">`, 12 entre les
   lignes, 8 entre la puce et le texte, 156:9544).
*/
.stv-callout.stv-callout.stv-callout {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--stv-espace-16);
  width: 100%;
  max-width: var(--stv-largeur-texte);
  margin-inline: auto;
  padding: var(--stv-espace-32);
  background: var(--stv-bleu-clair);
}

/* Les widgets V3 de l'encadré prennent toute sa largeur (la liste). */
.stv-callout.stv-callout.stv-callout > .elementor-widget {
  width: 100%;
}

/* Le sur-titre est un `inline-flex` (composants.css) : dans l'enveloppe en
   bloc du widget Code court, il s'asseyait sur une ligne de 24 (l'interligne
   du corps) au lieu de sa boîte de 20 — la liste partait à 72 du haut de
   l'encadré au lieu de 68 (156:9538 → 156:9544, mesuré le 05/10). En flex,
   l'enveloppe ne fait plus de ligne : elle prend la hauteur du sur-titre. */
.stv-callout.stv-callout.stv-callout .elementor-shortcode:has(> .stv-surtitre-fleche) {
  display: flex;
}

/* La liste posée dans un Éditeur de texte : ni la marge du navigateur ni
   celle de Hello autour d'elle (0,3,1, devant `.stv-prose ul` à 0,1,1). */
.stv-callout.stv-callout.stv-callout :where(ul, ol, p) {
  margin: 0;
}

/*
   L'ENCADRÉ COMPACT — `stv-callout--compact` (05/10, 156:9583 → 156:9589 :
   « Vous débutez et voulez prendre l'habitude »…). Le même bleu clair et le
   même empilement, à 16 de marge intérieure ; un intitulé Inter Medium 20
   bleu pétrole (`stv-callout__intitule`, un widget Titre H3) et un texte
   Inter 16 anthracite (`stv-callout__texte`, un Éditeur de texte), à 16 l'un
   de l'autre. Il ne se centre pas : il se range dans la colonne de texte
   d'un `stv-split`, à la largeur de lecture (705) plus ses marges — 737 dans
   la maquette, qui ne l'étire pas aux 816 de la colonne.

   N ENCADRÉS (point 5 de l'ouverture) : chacun est un élément V4 à lui ; en
   ajouter un, c'est dupliquer le précédent dans Elementor. La colonne
   `stv-callouts` les empile à 16.
*/
.stv-callout--compact.stv-callout--compact.stv-callout--compact {
  max-width: calc(705px + 2 * var(--stv-espace-16));
  margin-inline: 0;
  padding: var(--stv-espace-16);
}

.stv-callouts.stv-callouts.stv-callouts {
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-16);
  width: 100%;
  padding: 0;
}

/* ENCADRÉ À PICTOGRAMME (guide pro, section « frein », 378:17288 — 03/11).
   Un `stv-callout--compact` dont la première rangée est une TÊTE : le
   pictogramme (64 × 64, `[stelvoren_picto]`, SVG du thème) et l'intitulé,
   écart 12, centrés en hauteur ; le texte suit à 16 (l'écart de l'encadré).
   Balisage : stv-callout stv-callout--compact > stv-callout__tete (V4) >
   Code court [stelvoren_picto nom="…"] + Titre stv-callout__intitule ;
   puis Éditeur de texte stv-callout__texte. Rien d'autre ne change : fond,
   marge 16, intitulé Inter 20 bleu pétrole et texte 16 sont ceux du compact. */
.stv-callout__tete.stv-callout__tete.stv-callout__tete {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 0;
}
.stv-callout__tete.stv-callout__tete > .elementor-widget:has(.stv-picto) {
  flex: 0 0 auto;
  width: auto;
}
.stv-callout__tete.stv-callout__tete > .elementor-widget:not(:has(.stv-picto)) {
  flex: 1 1 0;
  min-width: 0;
}
/* Le pictogramme : un SVG en ligne, en bloc (un inline posé dans l'enveloppe
   en bloc du Code court s'assiérait sur la ligne du corps, piège du 05/10). La
   couleur est celle du texte de l'encadré : le carré de fond est cette couleur
   à 10 % (= --stv-pastille), le tracé cette couleur pleine. */
.stv-picto.stv-picto {
  display: block;
  width: var(--stv-picto-taille, 64px);
  height: var(--stv-picto-taille, 64px);
  color: var(--stv-bleu-petrole);
}
.stv-picto.stv-picto svg {
  display: block;
  width: 100%;
  height: 100%;
}

.stv-callout .stv-callout__intitule,
.stv-callout .stv-callout__intitule :where(h2, h3, h4, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-carte);
  font-weight: 500;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-bleu-petrole);
}

.stv-callout .stv-callout__texte,
.stv-callout .stv-callout__texte :where(p) {
  margin: 0;
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
}

.stv-callout .stv-callout__texte :where(p + p) {
  margin-block-start: calc(var(--stv-interligne-texte) * 1em);
}

.stv-callout__titre {
  display: flex;
  align-items: center;
  gap: var(--stv-espace-6);
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-taille-surtitre);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-bleu-petrole);
}

.stv-callout__titre svg {
  flex: 0 0 auto;
  width: var(--stv-espace-16);
  height: var(--stv-espace-16);
}


/* =====================================================================
   6. CARTE BLANCHE — `stv-carte`
   Nœuds 156:9255 (carte téléphone du Contact) et 156:10524 (carte du
   formulaire de l'Espace pro) : même boîte — fond blanc, marge
   intérieure 32, colonne à écart 48.

   Elle sert d'encart de page, d'enveloppe de formulaire, et de carte à
   en-tête gris dans l'espace client (§ 7). La largeur (648 sur les
   formulaires) appartient à la page, pas à la carte.
   ================================================================== */

/* Trois répétitions : voir le relevé du 22/09 au § 2 (l'atomique V4). */
.stv-carte.stv-carte.stv-carte {
  display: flex;
  flex-direction: column;
  gap: var(--stv-gouttiere);
  align-items: flex-start;
  padding: var(--stv-espace-32);
  background: var(--stv-blanc);
}

/*
   Le titre de carte : Outfit Regular 20 sur la carte téléphone
   (156:9257), Outfit Medium 32 centré sur la carte de formulaire
   (156:10525). La graisse et la taille sont donc des réglages ; la
   valeur par défaut est celle de la carte d'encart, la plus fréquente.
*/
/* Deux sélecteurs, un corps — même raison qu'au § 2 pour le titre de
   bannière : la classe arrive sur l'enveloppe du widget. */
.stv-carte .stv-carte__titre,
.stv-carte .stv-carte__titre :where(h2, h3, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-taille-carte);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-texte);
}

/*
   LA LARGEUR DE LA CARTE DE FORMULAIRE EST UNE VALEUR DU SOCLE, PAS DE
   LA PAGE — amendement du 22/09 au commentaire d'ouverture du § 6.

   Le § 6 disait « la largeur (648 sur les formulaires) appartient à la
   page ». Relevé fait (156:10524), et les deux autres formulaires de
   page — SAV (156:10921) et Contact (156:9215) — portent la même carte :
   la valeur est vue trois fois, elle a donc une source, ici. Une page
   qui aurait besoin d'autre chose redéfinit la variable ; aucune ne
   réécrit 648.

   `max-width` et non `width` : dans la bannière la carte est centrée par
   `align-items: center`, et sous 648 + gouttières elle doit rendre.
*/
.stv-carte--formulaire.stv-carte--formulaire.stv-carte--formulaire {
  /* 648 est un jeton depuis le 23/09 (`--stv-largeur-carte`, vu quatre
     fois) ; la variable locale reste, c'est elle qu'une page redéfinit. */
  --stv-carte-formulaire-largeur: var(--stv-largeur-carte);

  /*
     `margin-inline: auto` — relevé du 22/09 sur le SAV (156:10922 porte
     `justify-center`). Dans la bannière de l'Espace pro la carte était
     centrée par l'`align-items: center` de son parent ; posée dans une
     `stv-section`, qui empile ses blocs en pleine largeur, elle tombait
     à gauche. La marge automatique la centre dans les deux cas, et ne
     dérange pas celui qui la centrait déjà.
  */
  margin-inline: auto;
  width: 100%;
  max-width: var(--stv-carte-formulaire-largeur);
}

.stv-carte--formulaire .stv-carte__titre,
.stv-carte--formulaire .stv-carte__titre :where(h2, h3, p, .elementor-heading-title) {
  width: 100%;
  font-size: var(--stv-taille-h3);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: -0.005em;
  text-align: center;
}

/*
   LE BLOC D'ENVOI (156:10580) : le bouton et la mention se suivent à 16,
   quand la carte respire à 48. Sur une page Elementor le bouton est
   DANS le widget Formulaire et la mention est un widget voisin : sans
   cette enveloppe, la mention tomberait à 48 du bouton. Trois
   répétitions, même raison qu'au § 2.
*/
.stv-carte__envoi.stv-carte__envoi.stv-carte__envoi {
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-16);
  align-items: stretch;
  padding: 0;
  width: 100%;
}

/*
   DANS UNE COLONNE DE SPLIT, LA CARTE SUIT L'AXE DE LA COLONNE (Contact,
   156:9215 posée à x = 0 dans une colonne de 816, `items-start`). La
   marge automatique ci-dessus la centrait, ce que veulent la bannière
   de l'Espace pro et la section du SAV, pas une colonne alignée à
   gauche. 0,4,0 : devant le 0,3,0 de la règle qu'elle corrige.
*/
.stv-split__texte .stv-carte--formulaire.stv-carte--formulaire.stv-carte--formulaire {
  margin-inline: 0;
}

/*
   LA CARTE D'ENCART À LA LARGEUR DES CARTES DE FORMULAIRE (Contact,
   156:9255 : 648 × 198, sous la carte de formulaire et à sa largeur).
   Une carte blanche prend par défaut la largeur de son parent ; celle-ci
   s'aligne sur sa voisine. Même jeton, pas un second 648.
*/
.stv-carte--etroite.stv-carte--etroite.stv-carte--etroite {
  width: 100%;
  max-width: var(--stv-largeur-carte);
}

/*
   L'EN-TÊTE DE CARTE (156:9256 : titre et sous-titre à 8). Remonté à
   trois répétitions et `padding: 0` le 23/09, à son premier emploi sur
   un élément V4 (carte téléphone du Contact) : à 0,1,0 il perdait
   contre le `display: block; padding: 10px` de l'atomique.
*/
.stv-carte__entete.stv-carte__entete.stv-carte__entete {
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-8);
  padding: 0;
}

/* 0,3,0 : l'élément Paragraphe V4 pose sa classe sur le `<p>` lui-même,
   et sa classe de base pèse 0,2,0 — à compte égal elle passerait après
   nous. */
.stv-carte .stv-carte__soustitre.stv-carte__soustitre {
  margin: 0;
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
}

/*
   La ligne à icône (156:9259) : un lien souligné précédé d'un picto de
   20. Deux classes devant `.elementor-kit-44301 a`, qui poserait sinon
   sa propre taille sur le lien — la variante silencieuse n° 1 du piège
   de spécificité (une valeur héritée n'est pas une valeur déclarée).
*/
.stv-carte .stv-carte__lien {
  display: inline-flex;
  align-items: center;
  gap: var(--stv-espace-8);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-texte);
  text-decoration: underline;
  text-underline-position: from-font;
  /* `top` et non la ligne de base : posé seul dans un bloc (le widget
     Shortcode), un `inline-flex` aligné sur la ligne de base laisse
     sous lui la place d'un jambage — la carte téléphone sortait à 202
     au lieu de 198, mesuré le 23/09. */
  vertical-align: top;
}

.stv-carte .stv-carte__lien svg {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
}


/* =====================================================================
   7. BADGE DE STATUT — `stv-badge`
   Nœud 156:5782 (compte, détail de devis) : fond anthracite, marge
   intérieure 6 / 8, Inter Regular 16 blanc, aucun arrondi. La ligne qui
   le porte (156:5777) est sur fond crème, avec des puces carrées de 4.

   UNE SEULE FAMILLE pour les statuts de commande WooCommerce et les
   statuts de devis YITH (fiche 149.5).

   DEUX FAMILLES, DESSINÉES — relevé du 29/09 (lot Compte) sur le
   composant « Compte » `156:5590`, que la passe 1 n'avait pas ouvert :
   « Annulé » en anthracite, texte blanc (`156:5739`), « En cours de
   traitement » en BLEU CLAIR, texte NOIR (`156:5750`). Le socle du 21/09
   avait deviné trois familles (anthracite, bleu pétrole, gris clair) sur un
   seul badge dessiné : la deuxième était fausse, la troisième n'existe pas
   — retirée. Quel statut va dans quelle famille : inc/compte.php,
   `stelvoren_compte_badge_html()` (filtrable).
   ================================================================== */

/*
   24 de haut (`156:5782` : 68 × 24) : le texte est ROGNÉ AUX CAPITALES
   (`text-box`, comme le récapitulatif), 12 de haut, et 6 dessus et dessous.
   En `inline-block` et non en `inline-flex` (29/09) : le rognage s'applique
   à un conteneur de bloc, pas au flux anonyme d'un conteneur flexible.
   Sans la propriété (Firefox), 36 de haut — rien ne se chevauche.
*/
.stv-badge {
  display: inline-block;
  padding: var(--stv-espace-6) var(--stv-espace-8);
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
  border-radius: var(--stv-rayon);
  background: var(--stv-anthracite);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-blanc);
  white-space: nowrap;
}

/* En cours (`156:5750`) : attente de paiement, traitement, devis nouveau, en attente, accepté. */
.stv-badge--encours {
  background: var(--stv-bleu-clair);
  color: var(--stv-noir);
}

/*
   La ligne de titre qui porte le badge (156:5777) : titre, date et
   badge séparés par des carrés de 4. Les séparateurs sont des
   pseudo-éléments, pas des éléments vides : le gabarit surchargé ne doit
   pas fabriquer de balisage décoratif.

   CORRIGÉ LE 29/09, au premier emploi réel (lot Compte) : le carré était
   le `::before` de l'élément qui SUIT — donc peint DANS le badge, sur son
   fond anthracite, où il ne se voyait pas et l'élargissait de 16. Il est
   désormais le `::after` de l'élément qui PRÉCÈDE (le titre, la date) :
   12 de marge dans l'élément, 12 d'écart de la ligne. Titre et date sont
   rognés aux capitales comme la maquette : la ligne fait 48 (12 + 24 + 12).
*/
.stv-badge-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--stv-espace-12);
  box-sizing: border-box;
  width: fit-content;
  max-width: 100%;
  padding: var(--stv-espace-12);
  background: var(--stv-beige);
}

.stv-badge-ligne > :not(:last-child)::after {
  content: "";
  display: inline-block;
  width: var(--stv-espace-4);
  height: var(--stv-espace-4);
  margin-left: var(--stv-espace-12);
  background: var(--stv-noir);
  vertical-align: middle;
}

.stv-badge-ligne .stv-badge-ligne__titre {
  margin: 0;
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-carte);
  font-weight: 500;
  line-height: var(--stv-interligne-texte);
  letter-spacing: 0;
  text-transform: none;
  color: var(--stv-noir);
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

.stv-badge-ligne__date {
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-noir);
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}


/* =====================================================================
   8. LA PROSE — `.stv-prose`
   DÉPLACÉE DEPUIS fiche-produit.css LE 21/09.

   Pourquoi le déplacement : la règle du protocole est « une seule
   prose pour la fiche, l'article, les textes et FAQ de catégorie, les
   éditeurs des pages de contenu, les réponses de la FAQ, le contenu
   des pages légales ». Elle ne pouvait pas tenir : `fiche-produit.css`
   n'est mis en file que sur la fiche produit, et les règles de titre et
   de lien y étaient portées par `.stv-onglets .stv-prose` — donc
   inopérantes hors des onglets. Sept contextes attendaient un habillage
   qui n'arrivait jamais.

   Les valeurs sont celles du relevé `118:5927` / `118:5767` du 15/09,
   inchangées : tout en Inter, corps 16 à 1,5 en anthracite, intertitres
   en Inter Medium 24, rythme vertical de 1,5em sous chaque bloc et
   aucune marge haute. Seule la PORTÉE change.

   Le compte de spécificité monte d'un cran : `.stv-onglets .stv-prose h1`
   pesait 0,2,1, `.stv-prose.stv-prose.stv-prose h1` pèse 0,3,1. Trois
   classes et non deux, parce que le kit est relevé à 0,1,1 sur `h1`…`h6`
   mais à 0,2,1 sur `a` selon le contexte : à poids égal l'ordre décide,
   et le kit passe après nous.

   UNE CLASSE, DES RÉGLAGES (28/09, lot « Article », tâche 121) : les
   valeurs ci-dessous sont portées par des VARIABLES, déclarées sur
   `.stv-prose` à leurs valeurs du 15/09 — mêmes valeurs calculées,
   vérifiées sur la fiche et sur une page légale après la réécriture. La
   variante `stv-prose--article` (§ 8.3) ne fait que les redéfinir : pas
   une seconde prose, la même avec les cotes de la maquette de l'article.
   Le principe est celui des huit classes du socle (`stv-split`,
   `stv-onglets`…) ; les pages légales, elles, avaient tranché « pas de
   variante » parce que l'écart (20 / 24) ne se voyait pas.
   ================================================================== */

.stv-prose {
  --stv-prose-interligne: var(--stv-interligne-texte);
  --stv-prose-bloc-marge: 1.5em;
  --stv-prose-intertitre-police: var(--stv-police-texte);
  --stv-prose-intertitre-taille: var(--stv-taille-intertitre);
  --stv-prose-intertitre-graisse: 500;
  --stv-prose-intertitre-interligne: var(--stv-interligne-texte);
  --stv-prose-intertitre-espacement: normal;
  --stv-prose-intertitre-couleur: var(--stv-anthracite);
  --stv-prose-intertitre-marge-haut: 0;
  --stv-prose-intertitre-marge-bas: 1.5em;
  --stv-prose-soustitre-taille: var(--stv-taille-carte);
  --stv-prose-lien-couleur: var(--stv-bleu-petrole);

  color: var(--stv-anthracite);
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-prose-interligne);
}

/*
   Trois classes ici aussi : la règle de titre ci-dessous pèse 0,3,1 et
   pose une marge haute (nulle par défaut, 48 dans l'article) ; le premier
   enfant doit la perdre quel qu'il soit, donc gagner au compte — 0,4,0.
*/
.stv-prose.stv-prose.stv-prose > :first-child { margin-top: 0; }
.stv-prose.stv-prose.stv-prose > :last-child  { margin-bottom: 0; }

/* Posée sur un widget Éditeur de texte (05/10, pages conseils), la classe est
   sur l'ENVELOPPE du widget : le texte est un niveau plus bas, dans
   `.elementor-widget-container`. Même règle, un niveau plus bas. */
.stv-prose.stv-prose.stv-prose > .elementor-widget-container > :first-child { margin-top: 0; }
.stv-prose.stv-prose.stv-prose > .elementor-widget-container > :last-child  { margin-bottom: 0; }

.stv-prose p,
.stv-prose ul,
.stv-prose ol,
.stv-prose table {
  margin: 0 0 var(--stv-prose-bloc-marge);
}

.stv-prose ul,
.stv-prose ol {
  padding-left: 1.25em;
}

.stv-prose.stv-prose.stv-prose h1,
.stv-prose.stv-prose.stv-prose h2,
.stv-prose.stv-prose.stv-prose h3 {
  margin: var(--stv-prose-intertitre-marge-haut) 0 var(--stv-prose-intertitre-marge-bas);
  color: var(--stv-prose-intertitre-couleur);
  font-family: var(--stv-prose-intertitre-police);
  font-size: var(--stv-prose-intertitre-taille);
  font-weight: var(--stv-prose-intertitre-graisse);
  line-height: var(--stv-prose-intertitre-interligne);
  letter-spacing: var(--stv-prose-intertitre-espacement);
}

.stv-prose.stv-prose.stv-prose h4 {
  margin: var(--stv-prose-intertitre-marge-haut) 0 var(--stv-prose-intertitre-marge-bas);
  color: var(--stv-prose-intertitre-couleur);
  font-family: var(--stv-prose-intertitre-police);
  font-size: var(--stv-prose-soustitre-taille);
  font-weight: var(--stv-prose-intertitre-graisse);
  line-height: var(--stv-prose-intertitre-interligne);
  letter-spacing: var(--stv-prose-intertitre-espacement);
}

.stv-prose.stv-prose.stv-prose a {
  color: var(--stv-prose-lien-couleur);
  font-family: inherit;
  font-size: inherit;
  font-weight: 500;
  line-height: inherit;
  text-decoration: underline;
  text-underline-position: from-font;
}

.stv-prose.stv-prose.stv-prose a:hover,
.stv-prose.stv-prose.stv-prose a:focus-visible {
  color: var(--stv-anthracite);
}

.stv-prose img {
  max-width: 100%;
  height: auto;
}


/* --- 8.1 Le tableau de prose ----------------------------------------
   Nœuds 156:9612 (en-tête) et 156:9617 (corps), guide studio maison.

   Saisi en `<table>` dans l'éditeur, jamais par un widget tiers (règle
   « pas de script tiers » et décision 125.2). Donc : AUCUNE classe
   exigée du client, aucune règle par colonne, aucun compte de lignes.
   Les colonnes se partagent la largeur à parts égales quel qu'en soit
   le nombre.

   MOBILE : défilement horizontal (recommandation 125.2). Le tableau
   n'est pas dessiné en mobile ; empiler les cellules demanderait de
   connaître les en-têtes en CSS, donc de figer le contenu — exactement
   ce que la note de Logan interdit.
   -------------------------------------------------------------------- */

.stv-prose table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.stv-prose thead {
  background: var(--stv-bleu-petrole);
}

.stv-prose.stv-prose.stv-prose th {
  padding: var(--stv-espace-16);
  border: 0;
  background: var(--stv-bleu-petrole);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-intertitre);
  font-weight: 500;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-blanc);
  text-align: left;
  vertical-align: top;
}

.stv-prose.stv-prose.stv-prose td {
  padding: var(--stv-espace-16);
  border: 0;
  background: var(--stv-bleu-clair);
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
  vertical-align: top;
}

/*
   Le filet entre deux lignes (156:9623) : posé sur la ligne, pas sur la
   cellule, pour qu'il traverse le tableau d'un bord à l'autre — et pas
   sur la dernière, qui n'a rien à séparer.

   TROIS CLASSES ET NON UNE. Défaut relevé dans Chrome le 21/09 : écrite
   `.stv-prose tbody tr + tr td` (0,1,3), la règle sortait à
   `border-top-width: 0` — battue non par le kit ni par WooCommerce,
   mais par NOTRE PROPRE `.stv-prose.stv-prose.stv-prose td { border: 0 }`
   (0,3,1), deux blocs plus haut. Un raccourci `border` remet les quatre
   côtés à zéro, et la règle la plus lourde gagne, fût-elle la nôtre.
   0,3,3 passe devant 0,3,1 : à nombre de classes égal, c'est le compte
   d'éléments qui décide.
*/
/*
   UN FILET DESSINÉ, PAS UNE BORDURE — corrigé le 05/10 au montage (126).
   En `border-collapse: collapse`, la bordure de 1 se partage entre les deux
   lignes voisines : 80,5 + 0,5… soit 81 par ligne et 449 pour le tableau
   (444 dans la maquette, où le filet 156:9623 est un trait de largeur nulle
   posé SUR la limite des deux lignes de 80). L'ombre portée intérieure se
   dessine dans la cellule sans prendre de place : 68 + 4 × 80 + 56.
*/
.stv-prose.stv-prose.stv-prose tbody tr + tr td {
  box-shadow: inset 0 1px 0 var(--stv-filet-tableau);
}

/*
   L'écart de 24 entre deux colonnes (156:9612 / 156:9618 : rangée à 16 de
   marge, `gap: 24`, deux cellules de 380 à 16 et 420) se partage entre les
   deux cellules voisines : 12 de chaque côté. CORRIGÉ LE 05/10, au montage
   du tableau sur le guide (126) : la règle du 21/09 posait 24 à GAUCHE de la
   seconde cellule, en plus des 16 à droite de la première — 40 entre les
   deux textes, et la seconde colonne commençait à 432 au lieu de 420.
   `border-spacing` ne marche pas avec `border-collapse: collapse` : c'est la
   marge intérieure latérale qui se règle, et pour N colonnes.
*/
.stv-prose.stv-prose.stv-prose th + th,
.stv-prose.stv-prose.stv-prose td + td {
  padding-left: var(--stv-espace-12);
}

.stv-prose.stv-prose.stv-prose th:not(:last-child),
.stv-prose.stv-prose.stv-prose td:not(:last-child) {
  padding-right: var(--stv-espace-12);
}

/*
   LA ZONE QUI DÉFILE — `stv-tableau-defile` (05/10). Le thème enveloppe
   chaque tableau d'un Éditeur de texte (inc/conseils.php,
   `stelvoren_tableau_defilant()`) : `role="region"`, `tabindex="0"`, un nom.
   C'est elle qui défile sous 1 024 (§ 11), pas le tableau, qui garde ses
   rôles. Ici, en desktop, elle n'est qu'un bloc : la marge sous le tableau
   lui revient.
*/
.stv-prose .stv-tableau-defile {
  margin: 0 0 var(--stv-prose-bloc-marge);
}

.stv-prose .stv-tableau-defile > table {
  margin: 0;
}

.stv-prose .stv-tableau-defile:focus-visible {
  outline: 2px solid var(--stv-noir);
  outline-offset: 2px;
}


/* --- 8.2 Les trois styles de liste ----------------------------------
   Nœuds : carrés 156:9545 (encadré du guide), flèches 156:11005 (SAV,
   section garantie), coches 156:10515 (puces de l'Espace pro).

   UNE CLASSE PAR STYLE, pas une règle par page (règle du protocole).
   La puce est un `::marker` remplacé par un `::before` : `list-style`
   ne sait pas peindre une forme, et un `<img>` par ligne obligerait le
   client à coller du balisage.

   LA FORME DES DEUX PUCES DESSINÉES est portée par une variable de
   masque. Le serveur d'assets du Dev Mode Figma n'était pas joignable
   depuis le conteneur au moment du relevé : les deux tracés ci-dessous
   sont RECONSTRUITS à la géométrie relevée (coche 16 × 11, flèche
   10,667 × 10,667), pas exportés. Le jour où le designer livre ses
   fichiers, une seule ligne change par puce — c'est pour cela qu'elles
   sont des variables et non des règles.
   -------------------------------------------------------------------- */

/* Et la prose de l'article (§ 8.3), dont les listes portent la flèche. */
:where(.stv-liste, .stv-prose--article) {
  --stv-puce-coche: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 11" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M1 5.8 5.9 10 15 1"/></svg>');
  /* Le MÊME tracé que l'icône `fleche-coudee` de inc/icones.php — EXPORTÉ
     du Dev Mode le 25/09 (156:9313, identique à 156:9540), coude arrondi,
     trait 1,333 : il remplace le tracé reconstruit du 21/09. La puce du
     SAV (156:11006, 10,667) est ce dessin de 16 à l'échelle ⅔. */
  --stv-puce-fleche: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="black" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"><path d="M10 6.66667L13.3333 10L10 13.3333M2.66667 2.66667V7.33333C2.66667 8.04058 2.94762 8.71885 3.44772 9.21895C3.94781 9.71905 4.62609 10 5.33333 10H13.3333"/></svg>');
}

.stv-liste {
  display: flex;
  flex-direction: column;
  list-style: none;
  padding-left: 0;
}

.stv-liste li {
  display: flex;
  gap: var(--stv-espace-8);
  align-items: flex-start;
}

/*
   Le carré est centré sur la PREMIÈRE LIGNE de l'item, pas sur le bloc :
   un item de trois lignes garde sa puce en haut. (1,5em − 9px) ÷ 2
   reproduit la cale de 8 relevée sur 156:9546 sans la figer.
*/
.stv-liste li::before {
  content: "";
  flex: 0 0 auto;
  margin-top: calc((1em * var(--stv-interligne-texte) - var(--stv-puce-taille)) / 2);
  width: var(--stv-puce-taille);
  height: var(--stv-puce-taille);
  background: currentColor;
}

/* Carrés — encadré « L'essentiel » (156:9547) : 9 × 9, bleu pétrole. */
.stv-liste--carres {
  --stv-puce-taille: 9px;

  gap: var(--stv-espace-12);
  color: var(--stv-anthracite);
}

.stv-liste--carres li::before {
  color: var(--stv-bleu-petrole);
}

/* Flèches — section garantie du SAV (156:11006) : 10,667, Inter Medium. */
.stv-liste--fleches {
  --stv-puce-taille: 10.667px;

  gap: var(--stv-espace-8);
  color: var(--stv-anthracite);
  font-weight: 500;
}

.stv-liste--fleches li::before {
  mask: var(--stv-puce-fleche) center / contain no-repeat;
  -webkit-mask: var(--stv-puce-fleche) center / contain no-repeat;
}

/*
   Coches — puces de l'Espace pro (156:10516) : 16 × 11, bleu pétrole,
   sur UNE SEULE LIGNE en desktop. C'est la seule des trois qui se pose
   en rangée : `flex-wrap` et non un compte de colonnes, pour qu'une
   quatrième puce descende d'elle-même.
*/
.stv-liste--coches {
  --stv-puce-taille: 16px;

  flex-flow: row wrap;
  gap: var(--stv-espace-24);
  color: var(--stv-bleu-petrole);
}

.stv-liste--coches li {
  align-items: center;
  gap: 10px;
}

.stv-liste--coches li::before {
  margin-top: 0;
  height: 11px;
  mask: var(--stv-puce-coche) center / contain no-repeat;
  -webkit-mask: var(--stv-puce-coche) center / contain no-repeat;
}


/* --- 8.3 La variante de l'article — `stv-prose--article` -------------
   Nœuds 156:9874 → 156:9907 (article de blog), lot du 28/09 (tâche 121,
   tranché avec Logan : variante par variables, pas d'écart assumé — un
   intertitre de 42 contre 24 se voit).

   Ce que la maquette de l'article change à la prose, et rien d'autre :
   intertitres Outfit REGULAR 42 / 1,1 / −0,01em en noir, 48 au-dessus et
   24 dessous (32 en mobile, non dessiné : 32 comme `--stv-taille-h2`) ;
   corps à 1,4 (le 1,5 de la fiche) ; liens Inter Medium en noir (bleu
   pétrole sur la fiche) ; images à 816 de large, ALIGNÉES À GAUCHE dans
   la colonne de 1104, 48 au-dessus et au-dessous — l'éditeur de blocs
   les centre (`aligncenter`), la maquette non ; listes à puce ↳ (le
   tracé exporté de `--stv-puce-fleche`, en bleu pétrole, 16 pour les
   16,75 de la maquette — le trait de 1,333 de l'icône du socle contre
   0,75 : même dessin, un seul tracé), amorce en gras (`<strong>`) en
   noir — Semi Bold 600 non livré, 500 comme partout.

   Les H2 et H3 ont le même dessin (le contenu réel de l'article de la
   maquette alterne les deux, la maquette les dessine pareils) ; le H4
   redescend à 24, non dessiné.

   Tout ce qui n'est pas une variable est écrit à trois classes
   (`.stv-prose.stv-prose--article …`, 0,3,x) : au-dessus des règles de
   base du § 8 et de la feuille des blocs de WordPress
   (`.wp-block-image.aligncenter`, 0,2,0), sans dépendre de l'ordre.
   -------------------------------------------------------------------- */

.stv-prose--article {
  --stv-prose-interligne: 1.4;
  --stv-prose-intertitre-police: var(--stv-police-titres);
  --stv-prose-intertitre-taille: 42px;
  --stv-prose-intertitre-graisse: 400;
  --stv-prose-intertitre-interligne: var(--stv-interligne-titre);
  --stv-prose-intertitre-espacement: -0.01em;
  --stv-prose-intertitre-couleur: var(--stv-texte);
  --stv-prose-intertitre-marge-haut: var(--stv-espace-48);
  --stv-prose-intertitre-marge-bas: var(--stv-espace-24);
  --stv-prose-soustitre-taille: var(--stv-taille-intertitre);
  --stv-prose-lien-couleur: var(--stv-texte);
}

/* Les ancres du sommaire : l'intertitre visé s'arrête sous l'en-tête fixe
   ENTIER (annonce + navigation), à la même marge que la colonne collante
   (`--stv-article-decalage-haut`, posée par article.css sur l'article ; 24
   hors de l'article). `--stv-entete-hauteur` seule (96) faisait atterrir
   l'intertitre sous la barre d'annonce. PAS la barre d'administration ici :
   WordPress la compte déjà par `html { scroll-padding-top: 32px }`
   (admin-bar.css) — l'ajouter la comptait deux fois, mesuré le 28/09
   (227 au lieu de 196). Une marge de défilement ne se corrige que de ce que
   `scroll-padding` ne sait pas ; le `top` d'un élément collant, lui, doit
   l'ajouter (article.css § 2).
   Depuis le 26/10 (R1, tâche 189) la barre d'annonce part dès qu'on a
   défilé : après le saut vers un intertitre, seule la navigation couvre
   le haut — l'annonce n'est plus comptée.
   Depuis le 29/10 (tâche 184) la navigation est comptée PAR LE DOCUMENT :
   `:root { scroll-padding-top: barre d'administration + navigation }`
   (composants.css, « Ancres sous l'en-tête fixe »), pour que toute ancre
   du site — liste d'erreurs de la commande, lien d'évitement — s'arrête
   sous l'en-tête. Il ne reste ici que la marge propre à l'article. */
.stv-prose.stv-prose.stv-prose--article h2,
.stv-prose.stv-prose.stv-prose--article h3,
.stv-prose.stv-prose.stv-prose--article h4 {
  scroll-margin-top: var(--stv-article-decalage-haut, var(--stv-espace-24));
}

/* Les images (156:9877, 816 × 620) : à gauche, 816 au plus, hors du
   centrage de l'éditeur. La hauteur suit la photo — la maquette dessine
   un rapport 816 / 620, le CSS ne recadre pas ce que le client téléverse. */
.stv-prose.stv-prose.stv-prose--article figure,
.stv-prose.stv-prose.stv-prose--article .wp-block-image {
  /* `display: block` : la feuille des blocs pose `display: table` sur une
     figure centrée, qui se resserre alors sur son image (642 pour les
     photos héritées, mesuré le 28/09) au lieu des 816 de la maquette. */
  display: block;
  width: 100%;
  max-width: var(--stv-largeur-texte);
  margin: var(--stv-espace-48) 0;
  text-align: left;
}

.stv-prose.stv-prose.stv-prose--article figure img,
.stv-prose.stv-prose.stv-prose--article p > img {
  display: block;
  width: 100%;
  max-width: var(--stv-largeur-texte);
  height: auto;
  margin: 0;
}

/* Une image seule dans un paragraphe (éditeur classique) : le même rythme. */
.stv-prose.stv-prose.stv-prose--article p:has(> img:only-child) {
  margin: var(--stv-espace-48) 0;
}

/* Légende, non dessinée : le petit corps, à 8 de la photo. */
.stv-prose.stv-prose.stv-prose--article figcaption {
  margin: var(--stv-espace-8) 0 0;
  color: var(--stv-texte-secondaire);
  font-size: var(--stv-taille-petit);
  line-height: var(--stv-interligne-texte);
  text-align: left;
}

/* Les listes (156:9892) : la flèche ↳ en bleu pétrole, 8 entre les
   lignes, l'item à 1,5 (le corps est à 1,4). `flex` sur l'item, comme
   `stv-liste` : la puce est centrée sur la PREMIÈRE ligne.

   LES SEULES LISTES SANS CLASSE — celles que le client tape. Une liste
   qui porte une classe est un bloc qui apporte son propre dessin : la
   grille de produits de WooCommerce (`wc-block-grid__products`, douze
   produits dans « Pourquoi choisir vos coussins de méditation… », relevé
   du 28/09 — en colonne à flèches sans cette garde), une galerie, une
   `stv-liste` du socle. */
.stv-prose.stv-prose.stv-prose--article ul:not([class]) {
  display: flex;
  flex-direction: column;
  gap: var(--stv-espace-8);
  padding-left: 0;
  list-style: none;
}

.stv-prose.stv-prose.stv-prose--article ul:not([class]) > li {
  display: flex;
  gap: var(--stv-espace-8);
  align-items: flex-start;
  line-height: var(--stv-interligne-texte);
}

.stv-prose.stv-prose.stv-prose--article ul:not([class]) > li::before {
  content: "";
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: calc((1em * var(--stv-interligne-texte) - 16px) / 2);
  background: var(--stv-bleu-petrole);
  mask: var(--stv-puce-fleche) center / contain no-repeat;
  -webkit-mask: var(--stv-puce-fleche) center / contain no-repeat;
}

/* Une liste imbriquée reprend la marge de la prose, sans la flèche du parent en double. */
.stv-prose.stv-prose.stv-prose--article ul:not([class]) ul:not([class]) {
  margin: var(--stv-espace-8) 0 0;
}

/* L'amorce en gras (156:9895) : Medium en noir — 600 non livré. Vaut
   pour tout `<strong>` de l'article, pas seulement dans les listes. */
.stv-prose.stv-prose.stv-prose--article strong,
.stv-prose.stv-prose.stv-prose--article b {
  color: var(--stv-texte);
  font-weight: 500;
}

/* --- 8.4 La variante des pages conseils — `stv-prose--conseil` --------
   Nœuds 156:9594 (« Quand un accompagnement en studio reste pertinent »)
   et 156:9653 (« Les accessoires qui font vraiment la différence »), guide
   studio maison ; mobile 156:8740, 156:8796. Lot du 05/10 (126).

   La prose de l'article, à une échelle de moins : corps à 1,4, liens en
   NOIR Inter Medium soulignés (156:9653), gras en Medium noir ; intertitres
   Outfit REGULAR 24 à 1,1, −0,01em, noirs (156:9598) — 24 aussi en mobile
   (156:8744 : 52 pour deux lignes), d'où une valeur et non
   `--stv-taille-intertitre`, qui descend à 20 ; 48 au-dessus d'un intertitre
   (entre deux groupes, 156:9594 : `gap: 48`), 24 dessous (156:9597). Une
   ligne vide entre deux paragraphes : 1,4 em, l'interligne du corps.

   Une seconde prose ne s'écrit jamais : la variante redéfinit les
   variables du § 8 et emprunte deux règles de l'article (le gras).
   -------------------------------------------------------------------- */

.stv-prose--conseil {
  --stv-prose-interligne: 1.4;
  --stv-prose-bloc-marge: 1.4em;
  --stv-prose-intertitre-police: var(--stv-police-titres);
  --stv-prose-intertitre-taille: 24px;
  --stv-prose-intertitre-graisse: 400;
  --stv-prose-intertitre-interligne: var(--stv-interligne-titre);
  --stv-prose-intertitre-espacement: -0.01em;
  --stv-prose-intertitre-couleur: var(--stv-texte);
  --stv-prose-intertitre-marge-haut: var(--stv-espace-48);
  --stv-prose-intertitre-marge-bas: var(--stv-espace-24);
  --stv-prose-soustitre-taille: var(--stv-taille-carte);
  --stv-prose-lien-couleur: var(--stv-texte);
}

.stv-prose.stv-prose.stv-prose--conseil strong,
.stv-prose.stv-prose.stv-prose--conseil b {
  color: var(--stv-texte);
  font-weight: 500;
}

/* Les `<p>` d'un Éditeur de texte gardent sinon la marge de Hello (0,9 em) :
   la prose pose la sienne, et rien en tête. */
.stv-prose.stv-prose.stv-prose--conseil :where(p) {
  margin-top: 0;
}

/* Mobile (non dessiné) : intertitres à 32 (`--stv-taille-h2` sous 768),
   32 au-dessus, images à 32 du texte. */
@media (max-width: 767px) {
  .stv-prose--article {
    --stv-prose-intertitre-taille: var(--stv-taille-h2);
    --stv-prose-intertitre-marge-haut: var(--stv-espace-32);
  }

  .stv-prose.stv-prose.stv-prose--article figure,
  .stv-prose.stv-prose.stv-prose--article .wp-block-image,
  .stv-prose.stv-prose.stv-prose--article p:has(> img:only-child) {
    margin: var(--stv-espace-32) 0;
  }
}


/* =====================================================================
   9. L'HABILLAGE DU FORMULAIRE — UN SEUL, SIX EMPLOIS
   Nœuds 156:10526 → 156:10582 (Espace pro), repris tels quels par le
   SAV (156:10921), le Contact (156:9215), et par les champs
   WooCommerce de la commande et du compte.

   LES DEUX BALISAGES, UNE SEULE DÉCLARATION. Le widget Formulaire
   d'Elementor Pro et les champs de WooCommerce ne partagent aucune
   classe ; ils partagent en revanche exactement le même dessin. Chaque
   règle ci-dessous porte donc DEUX listes de sélecteurs et un seul
   corps. Le jour où une valeur change, elle change une fois.

   DÉCISION 145.4, TRANCHÉE POUR LES CINQ FORMULAIRES DU SITE :
   LIBELLÉS VISIBLES AU-DESSUS DU CHAMP, jamais flottants, jamais
   remplacés par le seul placeholder. C'est ce que dessine la maquette
   (156:10529, « Prénom* » au-dessus du champ) et c'est l'accessibilité
   du formulaire : un libellé flottant disparaît à la saisie, un
   placeholder n'est pas un libellé. Le placeholder reste, en plus, pour
   l'exemple de format.

   LE COMPTE DE SPÉCIFICITÉ. Le widget Formulaire génère sa feuille avec
   `{{WRAPPER}}` = `.elementor-N .elementor-element.elementor-element-id`,
   soit 0,3,0 avant toute cible, et cette feuille peut être chargée après
   la nôtre. Relevé du 04/09 sur post-44689.css, valeurs par défaut :
     - `… .elementor-field-group`                          0,4,0
     - `… .elementor-form-fields-wrapper`                  0,4,0
     - `… .elementor-button[type="submit"]`                0,5,0 (0,6,0 au survol)
     - `… .elementor-field-group:not(…) .elementor-field:not(…)`  0,7,0
   Le kit ajoute `.elementor-kit-44301 input:not([type="button"]):not([type="submit"])`
   à 0,3,1. D'où SIX répétitions de `.elementor-form` (0,6,0) comme
   portée : avec `.elementor-field-group .elementor-field` la règle pèse
   0,8,0 et passe devant le 0,7,0 du widget. Classe répétée et non
   ancêtre de portée : le formulaire doit tenir partout — pied de page,
   page de contenu, tunnel — et un ancêtre l'aurait lié à sa place.
   ================================================================== */

/* --- 9.1 La colonne de champs ---------------------------------------- */

/*
   La rangée du widget est un flex à retour de ligne avec des marges
   négatives de compensation (relevé du 04/09) : on la remet à plat et
   on pose l'écart de 24 relevé sur 156:10526.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-form-fields-wrapper,
.stv-champs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--stv-espace-24) var(--stv-espace-16);
  margin: 0;
}

.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group,
.stv-champs .form-row {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  gap: var(--stv-espace-8);
  align-items: flex-start;
  margin: 0;
  padding: 0;
}

/*
   CORRECTION DU 22/09 — PREMIER CONTRÔLE SOUS LA FEUILLE RÉELLE DU
   WIDGET (Espace pro, fiche 113). Deux défauts que la page styleguide
   ne pouvait PAS voir, parce qu'elle reproduit le balisage du widget
   mais pas la feuille qu'il génère pour son instance.

   1. `flex-wrap: nowrap` ci-dessus. Le widget pose
      `flex-basis: 100%; flex-grow: 1` sur le champ (relevé dans
      `custom-frontend.min.css`) : c'est fait pour un groupe en RANGÉE,
      où le champ prend alors toute la ligne sous le libellé. Notre
      groupe est en COLONNE, et il héritait de `flex-wrap: wrap` du
      widget : les deux enfants tombaient donc dans DEUX lignes flex
      côte à côte — libellé à gauche, champ à sa droite et débordant —
      et la hauteur du champ devenait 100 % de la colonne, soit 74 au
      lieu de 42. Un libellé posé À CÔTÉ du champ n'est pas la décision
      145.4 ; `nowrap` remet les deux enfants dans la même colonne.
      `flex: 0 0 auto` sur le champ, au § 9.3, ferme l'autre moitié.

   2. LES DEUX COLONNES NE TENAIENT PAS SUR LA RANGÉE. Le widget donne
      `width: 50%` à un champ de demi-rangée (`elementor-col-50`), et
      la rangée porte un écart de 16 : 50 % + 50 % + 16 px dépasse, donc
      le second champ passait à la ligne et le formulaire sortait sur
      une seule colonne en desktop. Elementor évite cela par des marges
      négatives et du remplissage, que le § 9.1 a justement remis à
      plat ; la parade compatible avec l'écart est de retirer de chaque
      colonne la moitié de l'écart. Écrit ici pour la demi-rangée, la
      seule que les maquettes emploient ; le tiers et le quart
      s'ajouteront avec l'écran qui les demandera, sur le même modèle.

   0,5,0 de portée + `.elementor-field-group.elementor-col-50` = 0,7,0,
   devant le 0,1,0 du widget.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group.elementor-col-50 {
  width: calc(50% - (var(--stv-espace-16) / 2));
}

/*
   ET LA RANGÉE DE WOOCOMMERCE — ajouté le 28/09, au premier usage réel des
   champs WooCommerce (le calculateur d'expédition du panier, tâche 143) ;
   la commande (145) et le compte (150) en hériteront.

   Le socle posait `.stv-champs .form-row` à 0,2,0 : woocommerce.css écrit
   `.woocommerce form .form-row` à 0,2,1 (marge de 3, 6 dessous) et
   `.woocommerce form .form-row-first / -last` à 0,2,1 (flottant, 47 %) —
   la rangée perdait ses marges, et une rangée pleine (`form-row-wide`, sans
   largeur chez WooCommerce) se resserrait sur son contenu dans le flex.
   Même parade que la demi-rangée du widget ci-dessus : la demi-rangée
   retire de sa moitié la moitié de l'écart de 16. 0,3,0, devant le 0,2,1
   de woocommerce.css ; le § 11 remet tout sur une colonne sous 768, au
   même compte.
*/
.stv-champs .form-row.form-row {
  flex: 1 1 100%;
  float: none;
  width: 100%;
  margin: 0;
  padding: 0;
}

.stv-champs .form-row.form-row-first,
.stv-champs .form-row.form-row-last,
.stv-champs .form-row.stv-demi-rangee {
  flex: 0 0 calc(50% - (var(--stv-espace-16) / 2));
  width: calc(50% - (var(--stv-espace-16) / 2));
}

/*
   ET LE « CLEARFIX » DE LA RANGÉE — 29/09, mesuré à la commande : woocommerce.css
   pose `::before` / `::after` (`display: table`, contenu « ») sur
   `.woocommerce form .form-row` (0,2,2). Dans la rangée en colonne, ce sont
   deux enfants de plus, donc deux écarts de 8 : une rangée « libellé + champ »
   de 90 au lieu de 74, le libellé à 8 sous le haut de sa rangée. Le
   calculateur d'expédition du panier l'avait aussi, sans qu'on le mesure.
*/
.stv-champs .form-row.form-row::before,
.stv-champs .form-row.form-row::after {
  content: none;
  display: none;
}

/*
   ET L'ENVELOPPE DU CHAMP — ajouté le 29/09 avec la commande (146), premier
   usage de `woocommerce_form_field()`. Le calculateur du panier écrivait ses
   champs à la main, directement dans la rangée ; WooCommerce, lui, met chaque
   champ dans un `span.woocommerce-input-wrapper`. Dans la rangée en colonne
   (`align-items: flex-start` ci-dessus), ce `span` se resserrait sur son
   contenu, et le champ à `width: 100 %` avec lui. L'enveloppe prend donc
   toute la largeur de la rangée ; le message d'erreur que checkout.js ajoute
   à la rangée (`p.checkout-inline-error-message`) aussi, au § 9.6.

   `stv-demi-rangee` (29/09) : une demi-rangée que le script d'adresse de
   WooCommerce ne réécrit pas. Il retire et repose `form-row-first / -last /
   -wide` sur les champs d'adresse selon le pays — téléphone compris depuis
   WooCommerce 10 (champ d'adresse par défaut) ; une classe à nous survit.
   Le téléphone | e-mail de la commande (inc/commande.php).
*/
.stv-champs .form-row .woocommerce-input-wrapper {
  display: block;
  align-self: stretch;
  width: 100%;
}

/*
   ET L'ENVELOPPE DU MOT DE PASSE — 29/09, lot Compte (profil, connexion,
   nouveau mot de passe). WooCommerce met chaque champ de mot de passe dans
   un `span.password-input` (woocommerce.css : flex en colonne, relatif) où
   woocommerce.js pose le bouton « afficher » (`.show-password-input`, en
   absolu à droite). Posé DIRECTEMENT dans la rangée — les gabarits du
   compte, contrairement à `woocommerce_form_field()` de la commande —, il
   se resserrait sur le champ : 200 de large au lieu de la rangée, mesuré.
*/
.stv-champs .form-row > .password-input {
  align-self: stretch;
  width: 100%;
}

/* --- 9.2 Le libellé (décision 145.4) --------------------------------- */

.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group > label,
.woocommerce.woocommerce.woocommerce .form-row > label,
.woocommerce-page.woocommerce-page.woocommerce-page .form-row > label {
  display: block;
  margin: 0;
  padding: 0;
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
}

/*
   L'astérisque du champ obligatoire (156:10529, « Prénom* ») : COLLÉ au
   libellé, à l'encre du libellé. WooCommerce le sort en rouge et
   `abbr[title]` le souligne en pointillés dans la feuille du
   navigateur — deux corrections, un sélecteur. Elementor, lui, ne le met
   pas dans le libellé du tout : voir la règle suivante.
*/
.woocommerce.woocommerce.woocommerce .form-row > label .required,
.woocommerce.woocommerce.woocommerce .form-row > label abbr[title] {
  color: inherit;
  text-decoration: none;
  border: 0;
}

/*
   ET LA MÊME CORRECTION POUR LE WIDGET — relevé du 22/09. Elementor ne
   met pas l'astérisque dans le libellé : il le pose en `::after` sur
   `.elementor-mark-required .elementor-field-label`, EN ROUGE VIF
   (`#ff0000`), à 0,2,0. La maquette (156:10529, « Prénom* ») le donne à
   l'encre du libellé, et un rouge pur sur fond blanc n'apporte aucune
   information qu'une astérisque n'apporte déjà — il crie. Cinq
   répétitions plus deux classes, 0,7,0.

   Ce défaut non plus n'était pas visible sur la page styleguide : son
   balisage de contrôle écrit l'astérisque dans le texte du libellé.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group.elementor-mark-required .elementor-field-label::after {
  padding-inline-start: 0;
  color: inherit;
}

/*
   ET L'ASTÉRISQUE N'ÉTAIT TOUJOURS PAS COLLÉE — relevé du 23/09 sur le
   Contact, à la loupe : « Message * ». Le retrait était bien à zéro,
   mais le widget écrit son libellé avec des tabulations autour du texte
   (`<label>\n\t\tMessage\t\t</label>`), et l'espace blanc final, suivi
   d'une boîte en ligne — le `::after` —, se replie en UNE espace au lieu
   de disparaître. Aucune propriété de retrait n'y peut rien.

   En `flex`, le texte devient un élément anonyme dont les blancs de
   début et de fin sont retirés, et l'astérisque vient se coller à lui.
   Le libellé reste un bloc, à la même hauteur. Portée limitée aux
   libellés du widget qui portent l'astérisque : WooCommerce écrit la
   sienne dans le libellé, précédée d'une espace insécable, et n'a pas
   ce défaut. 0,7,0, devant le `display: block` du § 9.2 à 0,6,1.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group.elementor-mark-required .elementor-field-label {
  display: flex;
}

/* --- 9.3 Le champ ----------------------------------------------------
   Relevé 156:10530 : fond `--stv-gris-clair`, filet 1 px
   `rgba(36,38,46,.35)`, marge intérieure 8 / 12, Inter 16 à 1,5,
   hauteur résultante 42, aucun arrondi.

   La marge intérieure du champ téléphone monte à 16 latéral
   (156:10545) : c'est le seul écart, et il appartient au champ
   téléphone, pas au dessin général.
   -------------------------------------------------------------------- */

.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-field,
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-select-wrapper select,
.woocommerce.woocommerce.woocommerce .form-row .input-text,
.woocommerce.woocommerce.woocommerce .form-row select,
.woocommerce.woocommerce.woocommerce .form-row .select2-selection {
  /*
     `flex: 0 0 auto` — voir la correction du 22/09 au § 9.1 : sans
     elle, le `flex-basis: 100%` du widget se lit comme 100 % de la
     HAUTEUR du groupe (qui est une colonne) et le champ passe de 42 à
     74. La hauteur du champ est une valeur relevée, pas une valeur
     calculée par le flux.
  */
  flex: 0 0 auto;
  width: 100%;
  min-height: 42px;
  padding: var(--stv-espace-8) var(--stv-espace-12);
  border: 1px solid var(--stv-filet-champ);
  border-radius: var(--stv-rayon);
  /*
     Le fond est un RÉGLAGE depuis le 29/09 : gris clair sur une carte
     blanche (Espace pro, SAV, Contact — 156:10530), blanc sur la page
     blanche de la commande (156:10790). Même dessin, un fond différent :
     une variable, pas une seconde règle (`commande.css` la pose).
  */
  background: var(--stv-champ-fond, var(--stv-gris-clair));
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-texte);
}

/*
   LA LISTE DÉROULANTE, CORRIGÉE LE 22/09 — troisième défaut trouvé au
   premier contrôle sous la feuille réelle du widget.

   Le widget n'émet pas un `<select>` nu : il l'enveloppe dans un
   `<div class="elementor-field elementor-select-wrapper">` et c'est
   l'ENVELOPPE qui porte `elementor-field`. Le dessin du § 9.3
   l'habillait donc elle, et le `<select>` gardait le sien : une boîte
   dans une boîte, deux filets, 60 de haut au lieu de 42. La capture ne
   le montre pas — c'est un écart de 18 px — les styles calculés si.

   L'enveloppe ne porte plus rien (0,9,0, devant le 0,8,0 du dessin
   général qui la touche aussi) et le `<select>` est ajouté à la liste
   de sélecteurs du dessin, un seul corps comme le veut le § 9.
   La flèche du widget est en absolu dans l'enveloppe : elle survit.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-field.elementor-select-wrapper {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
}

/*
   LA LISTE DÉROULANTE DE WOOCOMMERCE — 29/09, commande (146). La maquette
   dessine la liste des pays comme un champ, avec un chevron de 8 × 4 à 12
   du bord droit (156:10797, tracé 156:10801 exporté du Dev Mode : trait de
   1,33 arrondi, noir). La liste native garde son comportement (clavier,
   lecteur d'écran, liste du système en mobile) ; seul son dessin est
   repris : sans l'apparence du système, chevron en image de fond, 32 à
   droite pour que le texte ne passe pas dessous. Le calculateur du panier
   et les adresses du compte en héritent. Le widget d'Elementor a sa propre
   flèche (règle précédente) : pas concerné.
*/
.woocommerce.woocommerce.woocommerce .form-row select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: var(--stv-espace-32);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.33333' height='5.33333' viewBox='0 0 9.33333 5.33333' fill='none'%3E%3Cpath d='M0.666667 0.666667L4.66667 4.66667L8.66667 0.666667' stroke='%23020A12' stroke-width='1.33333' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--stv-espace-12) center;
  background-size: 9.33333px 5.33333px;
  cursor: pointer;
}

/* La zone de message (156:10578) : 96 de haut, texte en haut. */
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group textarea.elementor-field,
.woocommerce.woocommerce.woocommerce .form-row textarea.input-text {
  min-height: 96px;
  resize: vertical;
}

.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-field::placeholder,
.woocommerce.woocommerce.woocommerce .form-row .input-text::placeholder {
  color: var(--stv-texte-indication);
  opacity: 1;
}

/*
   LE FOCUS. La maquette ne dessine aucun état de champ (demande au
   designer, fiches 112 et 142) ; un champ sans focus visible est une
   faute d'accessibilité, pas une question de style. En attendant : le
   filet passe à l'encre du texte et un contour de 2 double le signal,
   pour ne pas reposer sur la seule couleur.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-field:focus-visible,
.woocommerce.woocommerce.woocommerce .form-row .input-text:focus-visible,
.woocommerce.woocommerce.woocommerce .form-row select:focus-visible {
  border-color: var(--stv-anthracite);
  outline: 2px solid var(--stv-anthracite);
  outline-offset: 2px;
}

/*
   LE CHAMP EN ERREUR. Même remarque : non dessiné. Le filet s'épaissit
   ET le champ reçoit `aria-invalid`, donc le lecteur d'écran l'annonce
   — la couleur seule ne dirait rien à qui ne la voit pas. Côté WooCommerce,
   deux signaux (29/09, commande) : la rangée `woocommerce-invalid` que
   checkout.js pose sur un champ vide ou mal formé, et `aria-invalid` que le
   SERVEUR fait poser après un envoi refusé — un code postal « ABC » n'est
   refusé que par lui, et sa rangée n'avait pas le filet rouge.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-field[aria-invalid="true"],
.woocommerce.woocommerce.woocommerce .form-row.woocommerce-invalid .input-text,
.woocommerce.woocommerce.woocommerce .form-row .input-text[aria-invalid="true"],
.woocommerce.woocommerce.woocommerce .form-row select[aria-invalid="true"] {
  border-width: 2px;
  border-color: var(--stv-message-erreur);
}

/* --- 9.4 Le bouton d'envoi -------------------------------------------
   Relevé 156:10581 : anthracite, 48 de haut, marge 12 / 24, Inter
   Medium 16 blanc, pleine largeur de la carte. C'est
   `.stv-bouton--primaire` de composants.css, aux mêmes valeurs : on ne
   redessine pas, on aligne le bouton du widget et celui de WooCommerce
   dessus.

   0,7,0 pour le widget, devant le texte blanc qu'il pose à 0,5,0 et son
   survol à 0,6,0.
   -------------------------------------------------------------------- */

/*
   PORTÉE DU BOUTON WOOCOMMERCE, corrigée après contrôle dans Chrome le
   21/09. Écrit `button.button[type="submit"]`, le sélecteur ratait tous
   les boutons d'envoi qui ne portent pas l'attribut — et WooCommerce
   sortait alors son propre bouton, mauve pâle à texte gris et graisse
   700, le symptôme décrit dans `piege-specificite-elementor.md`.

   La portée est maintenant la RANGÉE DE FORMULAIRE, pas la boutique :
   on habille le bouton d'envoi d'un formulaire (commande, compte,
   adresses), jamais « Ajouter au panier » ni « Voir le panier », qui
   appartiennent aux fiches 141 à 147 et à leurs propres relevés. 0,5,1
   devant le 0,2,1 de woocommerce.css.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-type-submit .elementor-button,
.woocommerce.woocommerce.woocommerce .form-row button.button,
.woocommerce.woocommerce.woocommerce .form-row input.button,
.woocommerce.woocommerce.woocommerce .form-row button[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--stv-bouton-hauteur);
  padding: var(--stv-bouton-padding);
  border: 0;
  border-radius: var(--stv-rayon);
  background: var(--stv-bouton-primaire-fond);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 500;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-bouton-primaire-texte);
  text-decoration: none;
  cursor: pointer;
  transition: var(--stv-bouton-transition);
}

/* Survol du primaire (331:10551, R4 du 26/10) : jetons du bouton. */
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-type-submit .elementor-button:hover,
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-type-submit .elementor-button:focus,
.woocommerce.woocommerce.woocommerce .form-row button.button:hover,
.woocommerce.woocommerce.woocommerce .form-row input.button:hover {
  background: var(--stv-bouton-primaire-survol-fond);
  box-shadow: var(--stv-bouton-primaire-survol-lueur);
  color: var(--stv-bouton-primaire-texte);
}

/*
   LE BOUTON EST À 48 DU DERNIER CHAMP, PAS À 24 (relevé du 22/09).

   Dans la maquette, la colonne de champs (156:10526) et le bloc d'envoi
   (156:10580) sont deux enfants de la carte, donc séparés par son écart
   de 48 ; dans le widget, le bouton est un GROUPE DE CHAMP de plus et
   hérite de l'écart de 24 de la rangée. Les 24 qui manquent sont
   ajoutés ici, et seulement dans la carte de formulaire : l'infolettre
   du pied met son bouton sur la même ligne que le champ, elle n'en veut
   pas. Portée : la carte en ancêtre puis cinq répétitions, 0,7,0.
*/
.stv-carte--formulaire .elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-type-submit {
  margin-top: calc(var(--stv-gouttiere) - var(--stv-espace-24));
}

/*
   Le pot de miel (décision 5 : pas de reCAPTCHA) sort du widget SANS
   la classe de groupe — relevé du 04/09 sur l'infolettre. Tout enfant
   de la rangée qui n'est pas un groupe de champ est retiré du flux,
   sans quoi il coûte un écart.
*/
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-form-fields-wrapper > :not(.elementor-field-group),
.elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-type-honeypot {
  display: none;
}

/* --- 9.5 La mention sous le bouton ----------------------------------- */
/*
   156:10582 : 14 à 1,5, anthracite à 70 %, le lien vers la politique de
   confidentialité en Inter Medium à l'encre du texte, souligné. Deux
   classes sur le lien : le kit lui donnerait sinon la taille du texte
   courant, et la mention sortirait à 16 dans un bloc à 14 — le défaut
   déjà corrigé sur l'infolettre du pied.

   La mention reCAPTCHA de la maquette est RETIRÉE (décision 5 + 112.1) :
   ce qui reste est la mention RGPD, qui pointe vers une page qui doit
   exister avant le formulaire (139.1).
*/
.stv-mention {
  margin: 0;
  font-size: var(--stv-taille-petit);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-texte-mention);
}

.stv-mention .stv-mention__lien,
.stv-mention.stv-mention a {
  font-family: inherit;
  font-size: inherit;
  font-weight: 500;
  line-height: inherit;
  color: var(--stv-noir);
  text-decoration: underline;
  text-underline-position: from-font;
}

/*
   LA MENTION D'AIDE SOUS UN CHAMP — Contact, 23/09 (décision 136.2 : pas
   de sujet « SAV » ni « Devis », une ligne sous la liste qui renvoie
   vers les deux formulaires dédiés). NON DESSINÉE : elle prend le
   dessin de la mention, 14 à 70 %, liens en Inter Medium soulignés.

   Posée comme champ HTML du widget, elle est un groupe de champ comme
   un autre et hérite de l'écart de rangée, 24 — elle flotterait alors à
   mi-chemin entre la liste et le champ suivant. La marge négative la
   ramène à 8 sous le champ qu'elle commente, l'écart qui sépare un
   libellé de son champ dans le même groupe : l'aide se lit avec la
   liste, pas avec le message. 0,2,0, devant le `margin: 0` de la
   mention à 0,1,0.
*/
.stv-mention--aide.stv-mention--aide {
  margin-top: calc(var(--stv-espace-8) - var(--stv-espace-24));
}

/* --- 9.6 La case à cocher, la mention facultative, l'erreur de rangée --
   Ajouté le 29/09 avec la commande (146).

   LA CASE (156:10830-10831) : 12 × 12, filet noir de 1, sans fond, à 8 de
   son texte (Inter 14 / 1,5 anthracite), centrée sur sa première ligne — « Expédier à une adresse
   différente », et, du même dessin, « J'ai lu et j'accepte les conditions
   générales », « Se souvenir de moi », « Créer un compte ? ». La case
   native garde son rôle et son clavier ; seul le dessin change
   (`appearance: none`). COCHÉE : non dessinée (142) — fond noir et coche
   blanche. Le focus, comme les champs : un contour de 2 à l'encre du texte.
   Portée : la classe de WooCommerce pour les cases de ses formulaires
   (`woocommerce-form__input-checkbox`), jamais une case d'extension ou de
   filtre.

   La cible : la case fait 12, mais le LIBELLÉ entier la coche — la rangée
   fait 21 de haut, un doigt l'atteint.

   POIDS : la case à 0,4,1 — woocommerce.css écrit `.woocommerce form
   .form-row .input-checkbox` à 0,3,2 (en ligne, marge de −2 / 8) ; son
   libellé à 0,5,1 — `.woocommerce form .form-row label.checkbox` (0,3,2, en
   ligne) et surtout le libellé de rangée du § 9.2 (0,4,1 : bloc, 16), que le
   libellé d'une case dans une rangée (CGV) recevrait sinon.
*/
.woocommerce.woocommerce.woocommerce label.woocommerce-form__label-for-checkbox.woocommerce-form__label-for-checkbox,
.woocommerce-page.woocommerce-page.woocommerce-page label.woocommerce-form__label-for-checkbox.woocommerce-form__label-for-checkbox {
  /*
     En BLOC à la largeur de son texte (21 de haut, pas la ligne de 24 d'un
     paragraphe à 16), la case sortie du flux à gauche : le texte du libellé
     coule comme un paragraphe — le libellé des CGV est un texte, un lien, une
     espace insécable et une astérisque (`checkout/terms.php`), qu'un flex
     aurait séparés de 8 chacun (constaté le 29/09 : « générales   * »).
  */
  position: relative;
  display: block;
  box-sizing: border-box;
  width: fit-content;
  max-width: 100%;
  margin: 0;
  padding: 0 0 0 20px;
  color: var(--stv-anthracite);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-petit);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  cursor: pointer;
}

.woocommerce.woocommerce input.woocommerce-form__input-checkbox[type="checkbox"],
.woocommerce-page.woocommerce-page input.woocommerce-form__input-checkbox[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  top: 4.5px;
  left: 0;
  display: inline-grid;
  place-content: center;
  box-sizing: border-box;
  width: 12px;
  height: 12px;
  /* Centrée sur la PREMIÈRE ligne du libellé (21 de haut en 14 / 1,5 :
     4,5 au-dessus, 156:10831) — un libellé de CGV passe sur deux lignes
     dans une colonne de 384. */
  margin: 0;
  padding: 0;
  border: 1px solid var(--stv-noir);
  border-radius: var(--stv-rayon);
  background: transparent;
  vertical-align: middle;
  cursor: pointer;
}

.woocommerce.woocommerce input.woocommerce-form__input-checkbox[type="checkbox"]:checked,
.woocommerce-page.woocommerce-page input.woocommerce-form__input-checkbox[type="checkbox"]:checked {
  border-color: var(--stv-noir);
  background: var(--stv-noir) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='6' viewBox='0 0 8 6' fill='none'%3E%3Cpath d='M.75 3 3 5.25 7.25.75' stroke='%23FFFFFF' stroke-width='1.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 8px 6px no-repeat;
}

.woocommerce.woocommerce input.woocommerce-form__input-checkbox[type="checkbox"]:focus-visible,
.woocommerce-page.woocommerce-page input.woocommerce-form__input-checkbox[type="checkbox"]:focus-visible {
  outline: 2px solid var(--stv-anthracite);
  outline-offset: 2px;
}

/* Case obligatoire non cochée (CGV) : le filet passe au rouge des erreurs, comme un champ. */
.woocommerce.woocommerce .woocommerce-invalid input.woocommerce-form__input-checkbox[type="checkbox"],
.woocommerce-page.woocommerce-page .woocommerce-invalid input.woocommerce-form__input-checkbox[type="checkbox"] {
  border: 2px solid var(--stv-message-erreur);
}

/*
   « (facultatif) » après le libellé : à l'encre de l'indication, pour que le
   libellé se lise d'abord. L'astérisque des champs obligatoires est au § 9.2.
*/
.woocommerce.woocommerce.woocommerce .form-row > label .optional {
  color: var(--stv-texte-indication);
}

/*
   L'ERREUR D'UN CHAMP, sous le champ : `p.checkout-inline-error-message`,
   ajouté à la rangée par checkout.js après un envoi refusé (« Le code postal
   de facturation n'est pas valide. »), relié au champ par
   `aria-describedby`. Non dessinée (112, 142) : Inter 14, rouge des erreurs,
   à 8 du champ (l'écart de la rangée). 0,3,1 : woocommerce.css le passe à
   0,75 em à 0,3,0.
*/
.stv-champs .form-row p.checkout-inline-error-message {
  align-self: stretch;
  margin: 0;
  color: var(--stv-message-erreur);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-petit);
  line-height: var(--stv-interligne-texte);
}


/* =====================================================================
   10. LES MESSAGES WOOCOMMERCE
   `.woocommerce-message`, `.woocommerce-error`, `.woocommerce-info` :
   un seul habillage pour la fiche, le panier, la commande et le compte.

   NON DESSINÉS DANS LA MAQUETTE. La boîte est donc bâtie sur la
   palette relevée — fond gris clair, marge intérieure 16, Inter 16 — et
   seule la BARRE LATÉRALE porte le sens. Deux de ces trois couleurs ne
   sont pas dans la palette Figma : elles sont reprises de WooCommerce,
   déclarées comme jetons pour être remplaçables d'un geste, et la
   question part au designer avec la fiche 142. C'est le même parti que
   l'infolettre du pied, où l'on garde le vert et le rouge d'Elementor
   « parce qu'ils disent quelque chose ».

   `list-style: none` et la marge à zéro : WooCommerce sort ces messages
   en `<ul>`, et la puce du navigateur n'a rien à faire là.
   ================================================================== */

.woocommerce.woocommerce .woocommerce-message,
.woocommerce.woocommerce .woocommerce-error,
.woocommerce.woocommerce .woocommerce-info,
.woocommerce-page.woocommerce-page .woocommerce-message,
.woocommerce-page.woocommerce-page .woocommerce-error,
.woocommerce-page.woocommerce-page .woocommerce-info {
  display: flex;
  flex-wrap: wrap;
  gap: var(--stv-espace-8) var(--stv-espace-16);
  align-items: center;
  margin: 0 0 var(--stv-espace-24);
  padding: var(--stv-espace-16);
  border: 0;
  border-left: 4px solid var(--stv-anthracite);
  border-radius: var(--stv-rayon);
  background: var(--stv-gris-clair);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  line-height: var(--stv-interligne-texte);
  color: var(--stv-anthracite);
  list-style: none;
}

.woocommerce.woocommerce .woocommerce-message::before,
.woocommerce.woocommerce .woocommerce-error::before,
.woocommerce.woocommerce .woocommerce-info::before,
.woocommerce-page.woocommerce-page .woocommerce-message::before,
.woocommerce-page.woocommerce-page .woocommerce-error::before,
.woocommerce-page.woocommerce-page .woocommerce-info::before {
  content: none;
}

.woocommerce.woocommerce .woocommerce-message,
.woocommerce-page.woocommerce-page .woocommerce-message {
  border-left-color: var(--stv-message-succes);
}

.woocommerce.woocommerce .woocommerce-error,
.woocommerce-page.woocommerce-page .woocommerce-error {
  border-left-color: var(--stv-message-erreur);
  background: var(--stv-blanc);
}

.woocommerce.woocommerce .woocommerce-info,
.woocommerce-page.woocommerce-page .woocommerce-info {
  border-left-color: var(--stv-bleu-petrole);
  background: var(--stv-bleu-clair);
}

/*
   UNE LISTE D'ERREURS — 29/09, commande : après un envoi refusé, WooCommerce
   rend TOUTES les erreurs dans un seul `ul.woocommerce-error`, un `li` par
   champ (chacun un lien vers son champ). En rangée à retour de ligne (le flex
   ci-dessus), elles se suivaient sur une même ligne ; une par ligne, à 4.
   0,3,1 contre 0,3,0.
*/
.woocommerce.woocommerce ul.woocommerce-error,
.woocommerce-page.woocommerce-page ul.woocommerce-error {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--stv-espace-4);
}

/*
   Un LIEN dans un message (« Annuler ? » après le retrait d'un article du
   panier, 103.4 ; « Se connecter » à la commande) — ajouté le 28/09 avec la
   page panier, où il sortait en texte nu : l'encre du message, en Medium,
   souligné. Le bouton, lui, garde le dessin ci-dessous. 0,4,1 : le kit
   écrit sur `a` à 0,1,1.
*/
.woocommerce.woocommerce .woocommerce-message a:not(.button),
.woocommerce.woocommerce .woocommerce-error a:not(.button),
.woocommerce.woocommerce .woocommerce-info a:not(.button),
.woocommerce-page.woocommerce-page .woocommerce-message a:not(.button),
.woocommerce-page.woocommerce-page .woocommerce-error a:not(.button),
.woocommerce-page.woocommerce-page .woocommerce-info a:not(.button) {
  color: inherit;
  font-weight: 500;
  text-decoration: underline;
  text-underline-position: from-font;
}

/*
   Le bouton que WooCommerce glisse dans un message (« Voir le
   panier », « Appliquer ») : aligné à droite quand la place le permet,
   sous le texte sinon. Il prend le dessin du bouton secondaire.
*/
.woocommerce.woocommerce .woocommerce-message .button,
.woocommerce.woocommerce .woocommerce-info .button,
.woocommerce-page.woocommerce-page .woocommerce-message .button,
.woocommerce-page.woocommerce-page .woocommerce-info .button {
  order: 1;
  margin-left: auto;
  padding: var(--stv-bouton-padding);
  border: 0;
  border-radius: var(--stv-rayon);
  background: var(--stv-bouton-secondaire-fond);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
  color: var(--stv-bouton-secondaire-texte);
  text-decoration: none;
}


/* =====================================================================
   11. TABLETTE ET MOBILE
   Points de rupture du thème : 1024 / 1025 et 767 / 768 (ceux
   d'Elementor, déjà employés par composants.css).

   Les maquettes mobiles des dix écrans concernés disent toutes la même
   chose : tout s'empile dans l'ordre, l'image passe avant le texte dans
   les sections texte + image des guides, après lui sur le SAV. L'ordre
   est donc un réglage, pas une règle.
   ================================================================== */

@media (max-width: 1024px) {
  /*
     LA BANNIÈRE SE RESSERRE (22/09). En desktop, 80 séparent le bloc de
     texte de ce qui suit — la carte de formulaire sur l'Espace pro.
     Sous 1024 la même respiration vide l'écran d'un demi-défilement :
     48, l'écart de carte, suffit à séparer deux blocs qu'on ne voit
     plus côte à côte. Trois répétitions comme la règle d'origine : à
     compte égal, c'est l'ordre qui tranche, et cette règle est plus bas
     dans le fichier.
  */
  .stv-banniere.stv-banniere.stv-banniere {
    gap: var(--stv-espace-48);
  }

  /*
     NOTRE HISTOIRE SOUS 1024 (15/10, non dessiné — 123.4 : « la bannière
     comme l'Espace pro »). Le bloc de texte garde ses 672 ou prend toute
     la colonne : à 1 024 il finit à 67 % de la largeur, à 393 au bord —
     bien au-delà des 40 % où le voile latéral vaut encore 0,8. Le voile
     devient donc le crème plat de l'Espace pro, dont le contraste tient
     sur n'importe quelle photo (relevé du 22/09 : 8,7:1 au pire pixel),
     et la hauteur redevient celle du contenu. Même compte que les règles
     d'origine, plus bas qu'elles.
  */
  .stv-banniere--lateral.stv-banniere--lateral.stv-banniere--lateral {
    --stv-banniere-voile: var(--stv-voile-creme);
  }

  .stv-banniere--haute.stv-banniere--haute.stv-banniere--haute {
    --stv-banniere-hauteur-min: auto;
  }

  /*
     LES COCHES SE CENTRENT AUSSI. Empilées (règle plus bas), elles
     forment une colonne de lignes de longueurs inégales : centrer
     chaque ligne les aligne sur l'axe du titre plutôt que sur un bord
     que rien ne matérialise. Le centrage est sur l'ITEM, pas sur la
     liste : c'est la ligne « coche + texte » qu'on centre, et la puce
     reste collée à son texte.
  */
  .stv-liste--coches li {
    justify-content: center;
  }

  /*
     TROIS RÉPÉTITIONS ICI AUSSI — une requête de média n'ajoute rien au
     compte de spécificité. Depuis que la classe est écrite à 0,3,0 plus
     haut pour tenir devant l'atomique V4, tout ce qui la redresse sous
     1024 doit être écrit au même compte, sinon il ne s'applique jamais.
     Mesuré le 22/09 sur le SAV : l'image de split restait à 620 de haut
     en mobile au lieu de 320.
  */
  .stv-split.stv-split.stv-split,
  .stv-split--inverse.stv-split--inverse.stv-split--inverse {
    /* 320 par défaut, 420 avec `--image-haute` (23/09) : un réglage lu
       ici plutôt qu'une valeur écrite. */
    --stv-split-image: var(--stv-split-image-empile);

    flex-direction: column;
    align-items: stretch;
  }

  /*
     Empilées, les colonnes reprennent leur hauteur de contenu : une base
     en pourcentage (`--large`) ou à zéro (`--moitie`) se lirait sinon
     sur la HAUTEUR du bloc, qui est indéfinie. Les deux sous-blocs, et
     plus seulement le texte, depuis que la proportion est un réglage.
  */
  .stv-split__texte.stv-split__texte.stv-split__texte,
  .stv-split__media.stv-split__media.stv-split__media {
    flex-basis: auto;
  }

  /* L'écart restant de `--large` n'a plus de sens en colonne. */
  .stv-split--large.stv-split--large.stv-split--large {
    justify-content: flex-start;
  }

  /*
     L'image qui suivait la colonne rentre dans le flux : il n'y a plus
     de colonne voisine à suivre, et hors du flux elle tomberait à zéro
     de haut. Elle reprend la hauteur empilée ci-dessus.
  */
  .stv-split--image-pleine.stv-split--image-pleine .stv-split__image.stv-split__image {
    position: static;
  }

  /* L'image sous le texte par défaut, au-dessus sur demande. */
  .stv-split--media-avant.stv-split--media-avant .stv-split__media.stv-split__media {
    order: -1;
  }

  .stv-split--boite.stv-split--boite.stv-split--boite {
    padding-block: var(--stv-espace-24);
    padding-inline: var(--stv-espace-24);
  }


  .stv-split--boite.stv-split--boite .stv-split__media.stv-split__media {
    flex: 0 0 auto;
  }

  .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
    --stv-bandeau-hauteur: 480px;

    padding: var(--stv-espace-24);
  }

  .stv-liste--coches {
    flex-direction: column;
    gap: var(--stv-espace-12);
  }

  /*
     LE TABLEAU DÉFILE (décision 125.2) plutôt que de s'empiler :
     empiler exigerait de répéter les en-têtes en CSS, donc de figer le
     contenu d'un bloc que le client doit pouvoir réécrire.
     `-webkit-overflow-scrolling` pour l'inertie iOS, et un `tabindex`
     est posé côté PHP pour que la zone soit atteignable au clavier.
  */
  .stv-prose table {
    display: block;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .stv-prose.stv-prose.stv-prose th,
  .stv-prose.stv-prose.stv-prose td {
    min-width: 12rem;
  }

  /*
     ENVELOPPÉ (05/10, `stv-tableau-defile`) : c'est l'enveloppe qui défile,
     le tableau reste un tableau — `display: block` lui retirait ses rôles
     pour certains lecteurs d'écran. Il garde la largeur de la colonne de
     lecture (816) : la maquette mobile du guide (156:8757) pose le tableau
     desktop tel quel dans la colonne de 353, à faire défiler — deux colonnes
     de 380, pas douze lignes de quatre mots.
  */
  .stv-prose .stv-tableau-defile {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .stv-prose .stv-tableau-defile > table {
    display: table;
    width: var(--stv-largeur-texte);
    min-width: 100%;
    overflow: visible;
  }

  .stv-prose.stv-prose.stv-prose .stv-tableau-defile th,
  .stv-prose.stv-prose.stv-prose .stv-tableau-defile td {
    min-width: 0;
  }
}

/*
   SOUS 768, LE TABLEAU ÉTIQUETÉ S'EMPILE (recette d'Estevan R41, 29/10,
   tâche 217 — la 125.2 révisée). Le serveur recopie l'en-tête de chaque
   colonne sur ses cellules (`data-label`, `stelvoren_tableau_etiquettes()`,
   inc/conseils.php) et pose `stv-tableau-defile--empile` sur l'enveloppe :
   plus rien n'est figé en CSS, le client réécrit ses en-têtes, les
   étiquettes suivent. Un tableau sans en-tête garde l'enveloppe simple et
   continue de défiler (règles ci-dessus).

   Une ligne = une carte bleu clair, 16 de marge, 8 entre deux cartes ;
   chaque valeur sous son étiquette (petit, 500, bleu pétrole). L'en-tête
   bleu sort de l'écran mais reste lu. Plus de défilement : la zone garde
   son rôle et son nom. Quatre classes : les cellules du socle en ont
   trois (§ 8.1, dont le filet `tr + tr td`, 0,3,3). Les cellules, CINQ :
   le § mobile plus bas pose 8 à gauche de la première et à droite de la
   dernière (`td:first-child`, 0,4,1, écrit après) — mesuré à 393 le 29/10,
   la première valeur rentrait de 8.
*/
@media (max-width: 767px) {
  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile {
    overflow: visible;
  }

  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile > table,
  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile > table > tbody,
  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile > table > tbody > tr {
    display: block;
    width: 100%;
    min-width: 0;
  }

  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile > table > thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile > table > tbody > tr {
    padding: var(--stv-espace-16);
    background: var(--stv-bleu-clair);
  }

  .stv-prose .stv-tableau-defile.stv-tableau-defile--empile > table > tbody > tr + tr {
    margin-top: var(--stv-espace-8);
  }

  .stv-prose.stv-prose.stv-prose .stv-tableau-defile.stv-tableau-defile--empile td {
    display: block;
    width: 100%;
    min-width: 0;
    padding: 0;
    background: none;
    box-shadow: none;
  }

  .stv-prose.stv-prose.stv-prose .stv-tableau-defile--empile td + td {
    margin-top: var(--stv-espace-12);
  }

  .stv-prose.stv-prose.stv-prose .stv-tableau-defile--empile td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: var(--stv-espace-4);
    color: var(--stv-bleu-petrole);
    font-size: var(--stv-taille-petit);
    font-weight: 500;
    line-height: var(--stv-interligne-texte);
  }
}

@media (max-width: 767px) {
  /* Trois répétitions, comme la règle qu'elle redresse (§ 1, 30/09). La
     citation passe à 20 (156:8365) : le 20 mobile de `--stv-taille-intertitre`. */
  .stv-entete-page.stv-entete-page.stv-entete-page {
    --stv-entete-page-ecart: var(--stv-espace-24);
    --stv-entete-page-citation: var(--stv-taille-intertitre);
    --stv-entete-page-citation-interlettre: -0.005em;
  }

  /*
     L'EN-TÊTE BLEU GARDE SON RYTHME SERRÉ — corrigé le 25/09 (pages
     légales, 156:8198 : marge 32, écart 16, date en 12). La règle
     ci-dessus, au même compte que `.stv-entete-page--bleu` mais plus bas
     dans le fichier, lui imposait l'écart de 24 de la citation de La
     marque ; et la marge de 48 du modificateur, écrite en dur, ne
     descendait jamais à 32. Même compte, plus bas encore : c'est l'ordre
     qui tranche ici, et il est voulu.
  */
  .stv-entete-page--bleu.stv-entete-page--bleu.stv-entete-page--bleu {
    --stv-entete-page-y: var(--stv-espace-32);
    --stv-entete-page-ecart: var(--stv-espace-16);
  }

  /* L'en-tête qui porte la page (Nos marques, 156:7838) garde 48 entre le
     H1 et la grille. Même compte que la règle de la citation, plus bas :
     l'ordre tranche, comme pour le bleu ci-dessus. */
  .stv-entete-page--contenu.stv-entete-page--contenu.stv-entete-page--contenu {
    --stv-entete-page-ecart: var(--stv-espace-48);
  }

  .stv-entete-page .stv-entete-page__meta {
    font-size: var(--stv-taille-copyright);
  }

  /*
     LA COLONNE AÉRÉE SE RESSERRE (Contact mobile 156:8229 : H1, carte
     de formulaire et carte téléphone à 32 l'un de l'autre, contre 48 en
     desktop). Même compte que la règle qu'elle redresse. À revérifier
     sur le guide studio maison (156:9608), l'autre colonne aérée, au
     montage de la 126 : son mobile n'a pas encore été relevé.
  */
  .stv-split__texte--aere.stv-split__texte--aere.stv-split__texte--aere {
    --stv-split-texte-ecart: var(--stv-espace-32);
  }

  /* L'encadré mobile : 16 de marge (156:8682 : 353 × 776, contenu à 16) — le
     24 écrit le 21/09 n'était pas relevé, et à 0,1,0 il ne prenait plus
     effet depuis la répétition (05/10). Même compte que la règle d'origine. */
  .stv-callout.stv-callout.stv-callout {
    padding: var(--stv-espace-16);
  }

  /* Le bandeau d'en-tête de page (156:8676) : 32 / 32, cadre de 420, texte
     centré en hauteur et à 16 des bords. Même compte que les règles qu'il
     redresse, plus bas qu'elles. */
  .stv-bandeau--tete.stv-bandeau--tete.stv-bandeau--tete {
    padding-block: var(--stv-espace-32);
  }

  .stv-bandeau--tete .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
    --stv-bandeau-hauteur: 420px;

    justify-content: center;
    padding: var(--stv-espace-16);
  }

  .stv-bandeau--tete .stv-bandeau__contenu.stv-bandeau__contenu.stv-bandeau__contenu {
    gap: var(--stv-espace-24);
  }

  /* Le texte centré en hauteur monte dans la partie légère du voile : celui
     du bandeau laissait le H1 du guide Pilates à 2,7:1 au pire pixel (393,
     mesuré le 05/10). Le voile « centré » des jetons le remonte à 5,6. */
  .stv-bandeau--tete .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre::after {
    background: var(--stv-voile-bandeau-centre);
  }

  /* Le tableau mobile (156:8763) : rangées à 8 de marge, l'en-tête garde 16
     (156:8758). */
  .stv-prose.stv-prose.stv-prose td {
    padding-block: var(--stv-espace-8);
  }

  .stv-prose.stv-prose.stv-prose td:first-child {
    padding-left: var(--stv-espace-8);
  }

  .stv-prose.stv-prose.stv-prose td:last-child {
    padding-right: var(--stv-espace-8);
  }

  /*
     LA CARTE SE RESSERRE À 16 — corrigé le 23/09. Cette règle était
     écrite `.stv-carte { gap: 24; padding: 24 }` à 0,1,0 depuis le 21/09,
     et n'a JAMAIS pris effet : la carte est à 0,3,0 depuis le 22/09 (la
     répétition contre l'atomique V4), et une requête de média n'ajoute
     rien au compte. Mesuré sur le Contact à 393 : marge 32, écart 48,
     les valeurs desktop. Les deux maquettes mobiles relevées donnent
     une marge de 16 (SAV 156:8418, Contact 156:8232 et 156:8272) ; elles
     ne s'accordent pas sur l'écart (48 sur le SAV, 32 sur le Contact),
     qui reste donc celui du desktop, 48, plutôt qu'un 24 qu'aucune des
     deux ne dessine. Touche aussi l'Espace pro et le SAV en mobile.
  */
  .stv-carte.stv-carte.stv-carte {
    padding: var(--stv-espace-16);
  }

  /*
     LES CHAMPS PASSENT SUR UNE COLONNE. En desktop, deux champs se
     partagent la rangée par la largeur que le widget leur donne (50 %) ;
     en mobile chacun prend toute la largeur. On ne compte pas les
     champs : on force la base.
  */
  .elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group,
  .stv-champs .form-row,
  .stv-champs .form-row.form-row-first,
  .stv-champs .form-row.form-row-last,
  .stv-champs .form-row.stv-demi-rangee {
    flex: 1 1 100%;
    width: 100%;
    max-width: 100%;
  }

  /*
     LE BANDEAU MOBILE (156:8381, relevé du 30/09) : cadre de 428 et non de
     360 — la valeur écrite le 21/09 n'était pas relevée —, contenu à 48 du
     bas et 16 des bords, 32 entre le titre et le bouton (48 en desktop). Le
     guide studio maison (156:8676) dessine 420, texte centré : à vérifier
     au montage de la 126. Trois répétitions, comme les règles d'origine.
  */
  .stv-bandeau__cadre.stv-bandeau__cadre.stv-bandeau__cadre {
    --stv-bandeau-hauteur: 428px;

    padding: var(--stv-espace-16) var(--stv-espace-16) var(--stv-espace-48);
  }

  .stv-bandeau__contenu.stv-bandeau__contenu.stv-bandeau__contenu {
    gap: var(--stv-espace-32);
  }
}


/* =====================================================================
   12. PAGE LÉGALE — le cadre du modèle `page-legale.php` (tâche 140)
   Nœuds 156:9317 (desktop : section 1840, marge 48 / 80, colonne de
   816 centrée) et 156:8206 (mobile : marge 32 / 20, colonne pleine).

   CE QUI N'EST PAS ICI. L'en-tête est `stv-entete-page--bleu` (§ 1),
   le texte `stv-prose` (§ 8), sans variante : la maquette dessine des
   intertitres Inter Semi Bold 20 à 1,4 (graisse 600 non livrée), la
   prose du site les rend en Medium 24 à 1,5 — écart assumé, décision de
   Logan du 25/09 (« une seule prose »). Ce paragraphe ne porte que la
   colonne.

   La page est rendue en PHP, pas par Elementor : pas d'atomique V4 à
   battre, une classe suffit, et le compte est celui d'une règle de
   composant (0,2,0, sous `.stv-page-legale` pour ne rien atteindre
   ailleurs).

   LA MARGE MOBILE EST ÉCRITE DANS CE PARAGRAPHE, pas au § 11 : le § 11
   est plus haut dans le fichier, et une règle mobile au même compte que
   la règle desktop qu'elle corrige perdrait à l'ordre — la leçon de la
   carte mobile du 23/09, dans l'autre sens.
   ================================================================== */

/*
   HELLO BORNE `.site-main` hors des pages Elementor : theme.css écrit
   `body:not([class*=elementor-page-]) .site-main` — 0,2,1 — avec une
   largeur maximale par palier (1 140 au-dessus de 1 200) et une marge
   latérale de 10 sous 576. Mesuré le 25/09 au premier affichage : en-tête
   bleu de 1 140 au lieu de pleine largeur. Le modèle garde la classe
   `site-main` (lien d'évitement, repère `#content` du thème parent) et en
   retire la borne, comme le gabarit d'archive — mais à 0,3,1, au-dessus
   du compte de Hello, et non à égalité en comptant sur l'ordre des
   fichiers comme `main.stv-catalogue-page.stv-catalogue-page`.
*/
main.stv-page-legale.stv-page-legale.stv-page-legale {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 0;
}

.stv-page-legale .stv-page-legale__corps {
  padding-block: var(--stv-espace-48);
  padding-inline: max(
    var(--stv-page-gouttiere),
    (100% - var(--stv-largeur-contenu)) / 2
  );
}

.stv-page-legale .stv-page-legale__texte {
  max-width: var(--stv-largeur-texte);
  margin-inline: auto;
}

@media (max-width: 767px) {
  .stv-page-legale .stv-page-legale__corps {
    padding-block: var(--stv-espace-32);
  }
}


/* =====================================================================
   13. FRISE CHRONOLOGIQUE — `stv-frise` (Notre histoire, fiche 124, 15/10)
   Nœuds 156:9489 (section 1840 × 912), en-tête 156:9490 (titre 156:9491,
   flèches 156:9492), ligne des années 156:9499, cartes 156:9510 →
   156:9519. Pas de maquette mobile (123.4) : construction par défaut.

   UNE PISTE DU THÈME, PAS UN CARROUSEL (choix du 15/10 : un seul moteur
   de défilement sur le site). Le défilement est celui du navigateur
   (`scroll-snap`) ; les flèches sont câblées par carrousels.js, bloc
   « pistes à commandes » — celui des tuiles et de la recherche. La classe
   `stv-piste` sur la section et `stv-piste__cadre` sur la piste y valent
   `[data-stv-piste]` / `[data-stv-piste-cadre]` : un élément V4
   d'Elementor ne porte que des classes. Les deux flèches sont écrites par
   le code court `[stelvoren_piste_fleches]` (inc/piste.php).

   UNE ÉTAPE = UN DIV BLOCK V4 `stv-frise__etape` : l'année, une photo
   facultative, un titre, un texte. Le client en ajoute, en retire, en
   réordonne dans l'éditeur ; RIEN N'EST COMPTÉ ICI (fiche 123) :
     - la graduation est dessinée par l'année de chaque carte — une étape
       de plus, une graduation de plus ;
     - la ligne est le FOND DE LA PISTE, en `background-attachment: local` :
       il couvre toute la zone qui défile, de la première carte à la
       dernière (156:9505 : 0 → 1 680, bord à bord des cartes), et défile
       avec elles, quel que soit leur nombre ;
     - les cartes prennent la hauteur de la plus haute (étirement du flex) ;
     - sans photo, le titre et le texte remontent sous l'année.
   La ligne est un repère de lecture, pas une échelle de temps : une
   graduation par carte, espacement régulier — 2021 → 2025 n'y prend pas
   plus de place que 2019 → 2020. Pas d'étape active (non dessinée).

   LA PAGE DE TROIS. La maquette pose trois cartes de 323 dans les 1 680
   (156:9509 : x = 0, 678, 1 357) : l'écart est ce qui reste, 355,5. Une
   flèche avance d'une page — carrousels.js compte les cartes ENTIÈRES
   visibles, et l'écart est calculé pour que trois tiennent exactement.
   La carte garde 323 tant que trois tiennent avec 32 d'écart au moins,
   puis se resserre ; deux par vue sous 1024, une sous 768, en pleine
   largeur. Le nombre par vue est le seul réglage par palier.

   Trois répétitions sur les enveloppes (éléments V4) : l'atomique pose
   `display: block; padding: 10px` à 0,2,0, après nous (§ 2). Les règles
   mobiles sont écrites DANS ce paragraphe, après celles qu'elles
   corrigent (même leçon qu'au § 12).
   ================================================================== */

.stv-frise.stv-frise.stv-frise {
  --stv-frise-par-vue: 3;
  --stv-frise-carte-max: 323px;               /* 156:9510 */
  --stv-frise-ecart-min: var(--stv-espace-32);
  /* La carte : 323, ou ce que laissent les cartes d'une vue et leurs écarts
     minimaux. `100%` se lit là où la variable sert — la piste et ses
     cartes —, donc sur la largeur de la piste. */
  --stv-frise-carte: min(
    var(--stv-frise-carte-max),
    (100% - (var(--stv-frise-par-vue) - 1) * var(--stv-frise-ecart-min)) / var(--stv-frise-par-vue)
  );
  /* La ligne et ses graduations (156:9504) : bleu pétrole, trait de 2
     (`inset -2px` sur un trait de hauteur nulle), graduation de 12. */
  --stv-frise-trait: 2px;
  --stv-frise-graduation: 12px;
  --stv-frise-encre: var(--stv-bleu-petrole);
  /* L'année (156:9501) : Inter Regular 20 à 1,1, 12 au-dessus de la
     graduation. */
  --stv-frise-annee: var(--stv-taille-carte);

  /* 64 entre l'en-tête et la ligne (156:9490 finit à 223, 156:9498
     commence à 287) : aucun jeton ne le dit, il n'a qu'un emploi. */
  gap: 64px;
  align-items: stretch;
}

.stv-frise__entete.stv-frise__entete.stv-frise__entete {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--stv-espace-48);                  /* 156:9490 */
  padding: 0;
  text-align: center;
}

/* Le titre (156:9491) : Outfit Medium 50 à 1,1 et −1 % (−0,5 px). Widget
   Titre : deux sélecteurs, un corps (§ 2). */
.stv-frise .stv-frise__titre,
.stv-frise .stv-frise__titre :where(h2, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-titres);
  font-size: var(--stv-taille-h2);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: -0.01em;
  color: var(--stv-texte);
  text-wrap: balance;
}

/*
   LES FLÈCHES (156:9492) : deux boutons de 40 × 40 à 16 l'un de l'autre,
   fond gris clair, la flèche des tuiles du catalogue — même dessin
   (20 × 8, trait de 1,5), même tracé exporté (`fleche-tuile-*`,
   inc/icones.php), mêmes états : la précédente à 50 % en début de course
   (`aria-disabled` : un bouton `disabled` perdrait le focus du clavier).

   Elles naissent `hidden` (inc/piste.php) et carrousels.js ne les montre
   que si la piste déborde. CACHÉES, ELLES GARDENT LEUR PLACE : elles sont
   dans le flux, sous le titre, et l'en-tête grandirait de 88 sous les
   yeux à l'arrivée du script — la ligne et les cartes descendraient
   (CLS, critère de fin de la 124). Quand la piste est mesurée et que
   tout tient (deux ou trois étapes sur grand écran), la barre s'efface.

   Compte : 0,3,0 sur le bouton, contre le `reset.css` de Hello
   (`[type=button]` 0,1,0, survol et focus roses à 0,2,0) et le kit
   (`button` 0,1,1) — comme les tuiles.
*/
.stv-piste-fleches {
  display: flex;
  justify-content: center;
  gap: var(--stv-espace-16);
}

.stv-piste-fleches .stv-piste-fleches__bouton.stv-piste-fleches__bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--stv-rayon);
  background: var(--stv-gris-clair);
  color: var(--stv-noir);
  cursor: pointer;
  transition: opacity 0.2s, background-color 0.2s;
}

.stv-piste-fleches .stv-piste-fleches__bouton.stv-piste-fleches__bouton[hidden] {
  visibility: hidden;
}

.stv-piste-fleches .stv-piste-fleches__bouton.stv-piste-fleches__bouton[aria-disabled="true"] {
  opacity: 0.5;
  cursor: default;
}

/* Survol : NON DESSINÉ — celui des tuiles (le bleu clair du bouton secondaire). */
.stv-piste-fleches .stv-piste-fleches__bouton.stv-piste-fleches__bouton:not([aria-disabled="true"]):hover {
  background: var(--stv-bleu-clair);
  color: var(--stv-noir);
}

.stv-piste-fleches .stv-piste-fleches__bouton.stv-piste-fleches__bouton:focus-visible {
  outline: 2px solid var(--stv-noir);
  outline-offset: 2px;
}

.stv-piste-fleches .stv-piste-fleches__glyphe {
  display: block;
  flex-shrink: 0;
  width: 21.5px;
  height: 9.5px;
}

.stv-frise[data-stv-piste-mesuree]:not([data-stv-piste-deborde]) .stv-frise__commandes.stv-frise__commandes {
  display: none;
}

/*
   LA PISTE. L'écart est ce que laissent les cartes d'une vue (355,5 à
   1 840), jamais moins que l'écart minimal ; avec une carte par vue, le
   minimal seul. La ligne est son fond (voir l'en-tête du paragraphe) :
   à 22 + 12 + 5 du haut — la hauteur de l'année, son écart, puis le
   milieu de la graduation moins la moitié du trait (156:9505, y = 39).
*/
.stv-frise__piste.stv-frise__piste.stv-frise__piste {
  display: flex;
  align-items: stretch;
  column-gap: max(
    var(--stv-frise-ecart-min),
    (100% - var(--stv-frise-par-vue) * var(--stv-frise-carte)) / max(1, var(--stv-frise-par-vue) - 1)
  );
  padding: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  background-image: linear-gradient(var(--stv-frise-encre), var(--stv-frise-encre));
  background-repeat: no-repeat;
  background-attachment: local;
  background-size: 100% var(--stv-frise-trait);
  background-position: 0 calc(var(--stv-frise-annee) * 1.1 + var(--stv-espace-12) + (var(--stv-frise-graduation) - var(--stv-frise-trait)) / 2);
}

.stv-frise__piste::-webkit-scrollbar {
  display: none;
}

/* La carte (156:9510) : 16 entre la photo et le titre, 16 entre le titre et
   le texte (156:9512). */
.stv-frise__etape.stv-frise__etape.stv-frise__etape {
  display: flex;
  flex-direction: column;
  flex: 0 0 var(--stv-frise-carte);
  gap: var(--stv-espace-16);
  min-width: 0;
  padding: 0;
  scroll-snap-align: start;
}

/* L'année et sa graduation. 32 jusqu'à la photo (156:9499 finit à 46,
   156:9509 commence à 78) : 16 de marge plus l'écart de la carte.
   Paragraphe V4 : la classe est sur le `<p>` lui-même. */
.stv-frise .stv-frise__annee.stv-frise__annee {
  position: relative;
  margin: 0 0 var(--stv-espace-16);
  padding: 0 0 calc(var(--stv-espace-12) + var(--stv-frise-graduation));
  font-family: var(--stv-police-texte);
  font-size: var(--stv-frise-annee);
  font-weight: 400;
  line-height: var(--stv-interligne-titre);
  letter-spacing: -0.01em;
  color: var(--stv-texte);
  text-align: center;
  white-space: nowrap;
}

.stv-frise .stv-frise__annee.stv-frise__annee::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: var(--stv-frise-trait);
  height: var(--stv-frise-graduation);
  background: var(--stv-frise-encre);
  transform: translateX(-50%);
}

/* La photo (156:9511) : 323 × 215, recadrée. Widget Image V3 : la classe
   arrive sur l'enveloppe (même parade qu'au § 2) ; trois répétitions
   devant les règles d'image d'Elementor (0,2,1 au plus). */
.stv-frise__image.stv-frise__image.stv-frise__image :where(.elementor-widget-container, figure) {
  margin: 0;
}

.stv-frise__image.stv-frise__image.stv-frise__image :where(img) {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 323 / 215;
  object-fit: cover;
}

/* Le titre de l'étape (156:9513) : Inter Medium 20 à 1,1 et −1 %. */
.stv-frise .stv-frise__intitule,
.stv-frise .stv-frise__intitule :where(h3, p, .elementor-heading-title) {
  margin: 0;
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-carte);
  font-weight: 500;
  line-height: var(--stv-interligne-titre);
  letter-spacing: -0.01em;
  color: var(--stv-texte);
}

/* Le texte (156:9514) : Inter Regular 16 à 1,4, anthracite. Deux
   paragraphes se séparent comme ceux d'un split (§ 4), à l'échelle d'une
   carte. */
.stv-frise .stv-frise__texte,
.stv-frise .stv-frise__texte :where(p) {
  margin: 0;
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-texte);
  font-weight: 400;
  line-height: 1.4;
  color: var(--stv-anthracite);
}

.stv-frise .stv-frise__texte :where(p + p) {
  margin-top: 0.75em;
}

@media (max-width: 1024px) {
  .stv-frise.stv-frise.stv-frise {
    --stv-frise-par-vue: 2;
  }
}

/* Une carte par vue, pleine largeur, avec sa graduation (123.4) ; 32 sous
   l'en-tête, au rythme mobile des sections. */
@media (max-width: 767px) {
  .stv-frise.stv-frise.stv-frise {
    --stv-frise-par-vue: 1;
    --stv-frise-carte-max: 100%;
    --stv-frise-ecart-min: var(--stv-espace-16);

    gap: var(--stv-espace-32);
  }

  .stv-frise__entete.stv-frise__entete.stv-frise__entete {
    gap: var(--stv-espace-24);
  }
}


/* =====================================================================
   14. CARTES SERVICES — LA TABLETTE (768 → 1024)
   « Aménagez votre studio », « Nous contacter », « Showroom Stelvoren ».
   Sections Elementor `fiche-services` (44741) et
   `categorie-services-{pilates,yoga,fitness}` (44796 → 44798) : fiche
   produit, catégories racines, pages conseils. Classes globales
   `stv-service-*`, écrites dans le kit.

   LE DÉFAUT (signalé par Logan le 26/10). Desktop et mobile sont dessinés
   (156:11168, 156:7680), la tablette non. Les sections passent en colonne
   à 1024 (réglage `flex_direction_tablet`), mais la carte garde ses 620 de
   haut — le mobile seul les lève. La photo, en 3:2 sur toute la largeur,
   monte à 427 (768) puis 597 (1024) : texte et lien débordent de 30 à
   180 et passent sous la carte suivante, qui les recouvre.

   LA DISPOSITION. Une carte par rangée, photo à gauche (deux cinquièmes),
   titre, texte et lien à droite — le lien calé en bas, comme sur le
   desktop. Les trois rangées font la hauteur de la plus haute (`1fr`), et
   chaque photo remplit la hauteur de sa carte : les trois photos ont donc
   toujours la même hauteur, quel que soit le texte. Le 3:2 reste un
   plancher — la photo ne descend jamais sous le format des autres
   largeurs ; si le texte est plus haut, elle se recadre (`cover`).
   Aucune hauteur en dur : un texte plus long agrandit les trois cartes au
   lieu de déborder.

   POURQUOI ICI ET PAS DANS LE KIT. Une règle de thème part par git ; une
   retouche des classes globales partirait par le kit et demanderait un
   réimport le soir de la bascule. Rien n'est à rejouer en base.

   LES POIDS. Classes globales `.elementor .stv-service-*` à 0,2,0 (feuilles
   `global-<n>-frontend-*`, chargées après nous) : trois répétitions sur la
   carte, 0,3,0 sur la photo. Le conteneur d'Elementor écrit `display` sur
   `.e-con > .e-con-inner` (0,2,0) : 0,4,0 ici.
   ================================================================== */
@media (min-width: 768px) and (max-width: 1024px) {
  .e-con.e-con > .e-con-inner:has(> .stv-service-carte) {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-auto-rows: 1fr;
  }

  .stv-service-carte.stv-service-carte.stv-service-carte {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    grid-template-rows: auto 1fr auto;
    column-gap: var(--stv-espace-32);
    row-gap: var(--stv-espace-16);
    align-items: start;
    height: auto;
  }

  /* La photo couvre les trois rangées de la colonne de gauche. Sa hauteur
     en % est traitée comme `auto` pendant le calcul des rangées — c'est le
     3:2 qui compte alors, d'où le plancher —, puis elle remplit la carte. */
  .stv-service-carte .stv-service-image.stv-service-image {
    grid-column: 1;
    grid-row: 1 / -1;
    align-self: stretch;
    width: 100%;
    height: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
  }

  .stv-service-carte .stv-service-titre { grid-column: 2; grid-row: 1; }
  .stv-service-carte .stv-service-texte { grid-column: 2; grid-row: 2; }
  .stv-service-carte .stv-service-div-lien { grid-column: 2; grid-row: 3; }
}

/* =====================================================================
   15. LA POP-UP « PLANIFIER UNE VISITE » — `stv-visite`
   Recette d'Estevan R18 / R20, tâche 196 (26/10). Maquette 331:17398
   (la carte) sur 331:17397 (le voile : rgba(0, 29, 61, .4), flou de
   2 px, carte centrée). Balisage : inc/visite.php ; comportements :
   assets/js/visite.js ; formulaire : section `planifier-une-visite`.

   LA CARTE est celle des formulaires de page (§ 6, `stv-carte
   stv-carte--formulaire`, 648 au plus) et ses champs ont l'habillage
   commun (§ 9) : rien n'est redit ici. Ce bloc ne pose que ce qui est
   propre à la pop-up : le voile, la place de la carte, la croix, le
   titre à gauche (centré sur les cartes de page), le champ Date et son
   calendrier, l'état « envoyée ».

   LE VOILE EST LE <dialog> LUI-MÊME, plein écran : un clic sur lui est
   un clic hors de la carte. Son `::backdrop` reste transparent. La carte
   est centrée par des marges automatiques et non par `align-items` :
   plus haute que l'écran, elle se cale en haut et le voile défile, au
   lieu d'être rognée par le haut.
   ================================================================== */

.stv-visite {
  position: fixed;
  inset: 0;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: var(--stv-espace-32) var(--stv-page-gouttiere);
  border: 0;
  background: rgba(0, 29, 61, 0.4);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  color: var(--stv-texte);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.stv-visite[open] {
  display: flex;
}

.stv-visite::backdrop {
  background: transparent;
}

/* La page ne défile plus sous la pop-up. */
html:has(.stv-visite[open]) {
  overflow: hidden;
}

.stv-visite__boite {
  position: relative;
  width: 100%;
  max-width: var(--stv-largeur-carte);
  margin: auto;
}

/* Le titre à gauche, comme la maquette ; la place de la croix réservée. */
.stv-visite .stv-carte--formulaire .stv-carte__titre,
.stv-visite .stv-carte--formulaire .stv-carte__titre :where(h2, h3, p, .elementor-heading-title) {
  text-align: start;
}

.stv-visite .stv-carte--formulaire .stv-carte__titre {
  padding-inline-end: var(--stv-espace-32);
}

/*
   LA CROIX — non dessinée : 40 × 40 dans le coin, à 16 des bords, la
   croix de 17 du thème. 0,3,0 et 0,4,0 : devant `.elementor-kit-NNN
   button` (0,1,1) et son survol (0,2,1), qui la peindraient en bouton.
*/
.stv-visite.stv-visite .stv-visite__fermer {
  position: absolute;
  top: var(--stv-espace-16);
  right: var(--stv-espace-16);
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--stv-rayon);
  background: transparent;
  color: var(--stv-texte);
  cursor: pointer;
}

.stv-visite.stv-visite .stv-visite__fermer:is(:hover, :focus-visible) {
  background: var(--stv-gris-clair);
  color: var(--stv-texte);
}

.stv-visite.stv-visite .stv-visite__fermer:focus-visible {
  outline: 2px solid var(--stv-texte);
  outline-offset: 2px;
}

/*
   LE CHAMP DATE (331:17429) : icône calendrier à 16 du bord, texte à 46,
   chevrons haut / bas à 16 du bord droit — les deux SVG exportés de la
   maquette (assets/images/visite-*.svg). C'est le champ VISIBLE du
   calendrier (`stv-date`, créé par visite.js) ; il garde les classes et
   donc l'habillage du champ d'origine. `background-image` seul : le fond
   gris du champ reste celui du § 9.
*/
.stv-visite .elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-field-group .elementor-field.stv-date {
  padding-inline: 46px 44px;
  background-image: url("../images/visite-calendrier.svg"), url("../images/visite-chevrons.svg");
  background-repeat: no-repeat, no-repeat;
  background-position: left 16px center, right 16px center;
  background-size: 19.33px 20.33px, 12px 15.33px;
  cursor: pointer;
}

/*
   LE CALENDRIER (flatpickr, celui d'Elementor) — non dessiné : aux
   couleurs du thème plutôt qu'au bleu de la bibliothèque. Il est logé
   dans la boîte de la pop-up et placé par le script : sa flèche, qui
   suppose le placement d'origine, est retirée.
*/
.stv-visite .flatpickr-calendar {
  border-radius: var(--stv-rayon);
  box-shadow: 0 8px 24px rgba(2, 10, 18, 0.16);
  font-family: var(--stv-police-texte);
}

.stv-visite .flatpickr-calendar::before,
.stv-visite .flatpickr-calendar::after {
  display: none;
}

.stv-visite .flatpickr-current-month {
  font-family: var(--stv-police-titres);
  font-size: 16px;
  font-weight: 500;
}

/* L'année est un <input> : sans ceci, il prend l'habillage des champs du
   site (fond gris, filet, 8 / 12 de marge) et l'année sort coupée. */
.stv-visite.stv-visite .flatpickr-calendar .flatpickr-current-month .numInputWrapper input.cur-year {
  height: auto;
  margin: 0;
  padding: 0 0 0 0.5ch;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: inherit;
  font: inherit;
  line-height: inherit;
}

.stv-visite .flatpickr-day {
  color: var(--stv-texte);
}

.stv-visite .flatpickr-day.today {
  border-color: var(--stv-texte);
}

.stv-visite .flatpickr-day:is(:hover, :focus):not(.flatpickr-disabled):not(.selected) {
  border-color: var(--stv-gris-clair);
  background: var(--stv-gris-clair);
}

.stv-visite .flatpickr-day.selected,
.stv-visite .flatpickr-day.selected:is(:hover, :focus) {
  border-color: var(--stv-anthracite);
  background: var(--stv-anthracite);
  color: var(--stv-blanc);
}

.stv-visite .flatpickr-day.flatpickr-disabled,
.stv-visite .flatpickr-day.flatpickr-disabled:hover {
  color: rgba(36, 38, 46, 0.25);
}

/*
   ENVOYÉE : la carte ne garde que son titre et le message de
   remerciement d'Elementor (« Merci, votre demande de visite est bien
   envoyée… »), qui reçoit le focus. Rouverte, la pop-up repart vierge
   (visite.js). Le masque passe devant le `display: flex` de l'habillage
   commun (§ 9, `.elementor-form` × 5 : 0,6,0).
*/
.stv-visite.stv-visite--envoyee .elementor-form.elementor-form.elementor-form.elementor-form.elementor-form .elementor-form-fields-wrapper,
.stv-visite.stv-visite--envoyee .stv-carte__envoi .elementor-widget-shortcode {
  display: none;
}

/*
   Les messages d'Elementor sous le bouton (erreur, remerciement) : 24 de
   marge au lieu des 10 d'Elementor, et l'interligne du texte (Elementor
   pose 1 : deux lignes collées). Demandé par Logan le 26/10. Dans l'état
   « envoyée », le message suit directement le titre : l'écart de la carte
   (48) suffit.
*/
.stv-visite.stv-visite .elementor-form.elementor-form.elementor-form.elementor-form.elementor-form > .elementor-message {
  margin: var(--stv-espace-24) 0 0;
  line-height: var(--stv-interligne-texte);
}

.stv-visite.stv-visite--envoyee .elementor-form.elementor-form.elementor-form.elementor-form.elementor-form > .elementor-message-success {
  margin: 0;
}

.stv-visite--envoyee .elementor-message-success:focus {
  outline: none;
}

@media (max-width: 767px) {
  .stv-visite {
    padding: var(--stv-espace-16);
  }
}

/* =====================================================================
   16. PAGE SHOWROOM — `stv-entete-page--blanc`, `--showroom`
   Recette d'Estevan R22, tâche 199 (26/10). Maquette 331:20476 : la
   section 331:20478 est un en-tête de page (§ 1) sur fond BLANC — 80 de
   marge, 48 d'écart — qui porte, centrés, un groupe de textes, le bouton
   « Planifier une visite » et une grande photo (1104 × 720). Mobile non
   dessiné : les jetons du § 1 (H1 42, chapeau 16, marges 32 / 20).

   Les deux enveloppes sont des éléments V4 : leur `display: block` et leur
   marge intérieure de 10 d'origine (styles atomiques) sont repris à 0,3,0,
   comme la carte du § 6. La photo, elle, est un widget : Elementor borne
   son enveloppe à 100 % à 0,4,0 (`.elementor.elementor .e-con >
   .elementor-widget`) — la borne de 1104 est donc posée à 0,5,0.
   ================================================================== */

.stv-entete-page--blanc.stv-entete-page--blanc.stv-entete-page--blanc {
  --stv-entete-page-fond: var(--stv-blanc);
}

/* Titre + chapeau (16 d'écart, 331:20481), puis les coches à 24 (331:20480). */
.stv-entete-page__groupe.stv-entete-page__groupe.stv-entete-page__groupe,
.stv-entete-page__textes.stv-entete-page__textes.stv-entete-page__textes {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--stv-espace-24);
  width: 100%;
  padding: 0;
}

.stv-entete-page__textes.stv-entete-page__textes.stv-entete-page__textes {
  gap: var(--stv-espace-16);
}

/* Le chapeau : Inter 20 / 1,5 anthracite, 792 au plus (331:20483). */
.stv-entete-page .stv-entete-page__intro {
  margin: 0;
  max-width: 792px;
  color: var(--stv-anthracite);
  font-family: var(--stv-police-texte);
  font-size: var(--stv-taille-accroche);
  font-weight: 400;
  line-height: var(--stv-interligne-texte);
}

/* Les coches du § 8, centrées sur leur rangée (331:20484). */
.stv-entete-page .stv-liste--coches {
  justify-content: center;
  margin: 0;
}

/* La photo (331:20496) : 1104 × 720 recadrée, toute la largeur en dessous. */
.stv-entete-page.stv-entete-page .stv-entete-page__image.stv-entete-page__image.stv-entete-page__image {
  width: 100%;
  max-width: 1104px;
}

.stv-entete-page .stv-entete-page__image img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1104 / 720;
  object-fit: cover;
}

/* =====================================================================
   17. PLANCHE DE PHOTOS — `stv-planche` (page Showroom, fiche 227, 05/11)
   Demande de Jonathan (J16 : « galerie en grille avec les photos du
   mail »). RIEN N'EST DESSINÉ : la maquette Showroom (398:20727, ex-
   331:20476) s'arrête à l'en-tête. Premier jet, sur les règles du socle :

   - la SECTION est une `stv-section` (gouttière, plafond de 1 680, 80 /
     32 de haut et de bas) qui porte l'en-tête `stv-titre-section`
     (composants.css, celui de La marque) puis la grille, à
     `--stv-entete-grille` l'un de l'autre — comme `stv-section-produits` ;
   - la GRILLE : trois colonnes au bureau (544 × 408 dans 1 680, écart
     24), deux sous 1 024, une sous 768 ; `--deux` : deux colonnes dès le
     bureau (le Showroom, Logan, 05/11 à 16 h : quatre photos en deux
     rangées de deux, 828 × 621 dans 1 680) ;
   - une PHOTO = un widget Image V3 « stv-planche__photo » : le client en
     ajoute, en retire ou les réordonne dans Elementor, rien d'autre à
     toucher. Le 4:3 est tenu ICI (`aspect-ratio` + `cover`), pas par le
     fichier : une photo d'un autre format se recadre au lieu de casser
     la rangée.

   NOM. Le composant s'appelait `stv-galerie` jusqu'au 05/11 à 16 h : la
   galerie de la FICHE PRODUIT porte déjà `stv-galerie` et
   `stv-galerie__image` (fiche-produit.css, tâche 71), et la règle des
   photos (0,2,0) y forçait `width: 100 %` et `max-width: none` sur ses
   images. Un bloc ne partage jamais le nom d'un autre.

   Puis `stv-mosaique` jusqu'au 06/11 : le nom de la mosaïque de la page
   FAQ (composants.css, 25/09, tâche 135), chargée AVANT ce fichier — la
   règle de la section (0,3,0, plus loin) y portait l'écart de sa grille
   de 16 à `--stv-entete-grille` (80, 32 en mobile). Renommé
   `stv-planche` (la planche-contact du photographe) le 06/11.

   RIEN N'EST COMPTÉ. Le nombre de colonnes est la mise en page de la
   grille, pas un nombre de photos. La seule règle de position —
   `:first-child:nth-last-child(odd)` — vaut pour N photos : à deux
   colonnes, quand le nombre est IMPAIR, la première prend la rangée en
   2:1 au lieu de laisser la dernière seule (Logan, 05/11). Pair : rien.

   Pas d'agrandissement au clic en premier jet (rien à charger). Les
   photos partent en différé (`stv-chargement-differe`, inc/images.php).

   Trois répétitions sur les enveloppes (éléments V4 : `display: block;
   padding: 10px` de l'atomique, à 0,2,0, après nous). La photo est un
   widget : la classe arrive sur son ENVELOPPE, le second sélecteur
   descend à l'image en `:where()` — même parade que `stv-split__image`.
   ================================================================== */

.stv-planche.stv-planche.stv-planche {
  gap: var(--stv-entete-grille);
  align-items: stretch;
}

.stv-planche__grille.stv-planche__grille.stv-planche__grille {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--stv-espace-24);
  margin: 0;
  padding: 0;
}

/* Deux colonnes dès le bureau. Même poids que la règle de base, placée
   après elle et AVANT les media queries : sous 768, la colonne unique
   (même poids, plus loin) l'emporte. */
.stv-planche__grille--deux.stv-planche__grille--deux.stv-planche__grille--deux {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.stv-planche .stv-planche__photo,
.stv-planche .stv-planche__photo.stv-planche__photo :where(.elementor-widget-container, figure, a, img) {
  display: block;
  width: 100%;
  max-width: none;
  margin: 0;
}

/* 0,3,0 : devant `.elementor img` et `.elementor-widget-image img` (0,1,1). */
.stv-planche .stv-planche__photo.stv-planche__photo :where(img) {
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

@media (max-width: 1024px) {
  .stv-planche__grille.stv-planche__grille.stv-planche__grille {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Nombre impair : la première photo prend la rangée, en 2:1. Les deux
     règles pèsent 0,4,0 : le format passe devant le 4:3 ci-dessus (0,3,0). */
  .stv-planche__grille.stv-planche__grille > :first-child:nth-last-child(odd) {
    grid-column: 1 / -1;
  }

  .stv-planche .stv-planche__grille > :first-child:nth-last-child(odd) :where(img) {
    aspect-ratio: 2 / 1;
  }
}

@media (max-width: 767px) {
  .stv-planche__grille.stv-planche__grille.stv-planche__grille {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--stv-espace-16);
  }

  /* Une colonne : la première redevient une photo comme les autres. */
  .stv-planche .stv-planche__grille > :first-child:nth-last-child(odd) :where(img) {
    aspect-ratio: 4 / 3;
  }
}
