.elementor-kit-9{--e-global-color-primary:#0E2243;--e-global-color-secondary:#EDEEF0;--e-global-color-text:#0E2243;--e-global-color-accent:#23405F;--e-global-color-bg:#EDEEF0;--e-global-color-surface:#F7F8F9;--e-global-color-surfacelow:#E4E6EA;--e-global-color-warmbeige:#F1F0EB;--e-global-color-border:#8B93A4;--e-global-color-error:#B3261E;--e-global-color-reliure:#1E2E3D;--e-global-color-tampon:#9E3B33;--e-global-color-bristol:#CBD6D9;--e-global-color-bristol2:#D8CBCE;--e-global-color-bristol3:#C0CDDC;--e-global-color-bristol4:#D9D2C1;--e-global-typography-primary-font-family:"Instrument Serif";--e-global-typography-primary-font-weight:400;--e-global-typography-secondary-font-family:"Instrument Sans";--e-global-typography-secondary-font-weight:400;--e-global-typography-text-font-family:"Instrument Sans";--e-global-typography-text-font-weight:500;--e-global-typography-accent-font-family:"Instrument Serif";--e-global-typography-accent-font-weight:400;--e-global-typography-wordmark-font-family:"Instrument Serif";--e-global-typography-wordmark-font-size:22px;--e-global-typography-wordmark-font-weight:500;--e-global-typography-wordmark-line-height:1.2em;--e-global-typography-wordmark-letter-spacing:0.5px;--e-global-typography-navlink-font-family:"Instrument Sans";--e-global-typography-navlink-font-size:16px;--e-global-typography-navlink-font-weight:500;--e-global-typography-navlink-line-height:1.4em;--e-global-typography-navlink-letter-spacing:0.2px;--e-global-typography-small-font-family:"Instrument Sans";--e-global-typography-small-font-size:14px;--e-global-typography-small-font-weight:400;--e-global-typography-small-line-height:1.6em;--e-global-typography-label-font-family:"Instrument Sans";--e-global-typography-label-font-size:16px;--e-global-typography-label-font-weight:600;--e-global-typography-label-line-height:1.4em;--e-global-typography-label-letter-spacing:0.2px;--e-global-typography-cmarque-font-family:"Instrument Serif";--e-global-typography-cmarque-font-size:21px;--e-global-typography-cmarque-font-weight:400;--e-global-typography-cmarque-line-height:1.2em;--e-global-typography-cmarque-letter-spacing:-0.2px;--e-global-typography-cnavlink-font-family:"Instrument Sans";--e-global-typography-cnavlink-font-size:12px;--e-global-typography-cnavlink-font-weight:500;--e-global-typography-cnavlink-text-transform:uppercase;--e-global-typography-cnavlink-line-height:1.4em;--e-global-typography-cnavlink-letter-spacing:1.5px;--e-global-typography-clabel-font-family:"Instrument Sans";--e-global-typography-clabel-font-size:12px;--e-global-typography-clabel-font-weight:600;--e-global-typography-clabel-text-transform:uppercase;--e-global-typography-clabel-line-height:1.4em;--e-global-typography-clabel-letter-spacing:2.2px;color:var( --e-global-color-primary );font-family:"Instrument Sans", Sans-serif;font-size:16px;font-weight:400;line-height:1.6em;}.elementor-kit-9 button,.elementor-kit-9 input[type="button"],.elementor-kit-9 input[type="submit"],.elementor-kit-9 .elementor-button{background-color:var( --e-global-color-accent );font-family:"Instrument Sans", Sans-serif;font-size:16px;font-weight:600;line-height:1.4em;color:var( --e-global-color-secondary );border-radius:4px 4px 4px 4px;padding:14px 28px 14px 28px;}.elementor-kit-9 button:hover,.elementor-kit-9 button:focus,.elementor-kit-9 input[type="button"]:hover,.elementor-kit-9 input[type="button"]:focus,.elementor-kit-9 input[type="submit"]:hover,.elementor-kit-9 input[type="submit"]:focus,.elementor-kit-9 .elementor-button:hover,.elementor-kit-9 .elementor-button:focus{background-color:var( --e-global-color-primary );color:var( --e-global-color-secondary );border-radius:4px 4px 4px 4px;}.elementor-kit-9 e-page-transition{background-color:#FFBC7D;}.elementor-kit-9 a{color:var( --e-global-color-accent );}.elementor-kit-9 a:hover{color:var( --e-global-color-primary );}.elementor-kit-9 h1{color:var( --e-global-color-primary );font-family:"Instrument Serif", Sans-serif;font-size:48px;font-weight:500;line-height:1.1em;}.elementor-kit-9 h2{color:var( --e-global-color-primary );font-family:"Instrument Serif", Sans-serif;font-size:32px;font-weight:500;}.elementor-kit-9 h3{color:var( --e-global-color-primary );font-family:"Instrument Serif", Sans-serif;font-size:24px;font-weight:500;}.elementor-kit-9 h4{color:var( --e-global-color-primary );font-family:"Instrument Serif", Sans-serif;font-size:20px;font-weight:600;}.elementor-kit-9 label{color:var( --e-global-color-primary );font-family:"Instrument Sans", Sans-serif;font-size:14px;font-weight:600;}.elementor-kit-9 input:not([type="button"]):not([type="submit"]),.elementor-kit-9 textarea,.elementor-kit-9 .elementor-field-textual{font-family:"Instrument Sans", Sans-serif;font-size:16px;color:var( --e-global-color-primary );background-color:var( --e-global-color-surface );border-style:solid;border-width:1px 1px 1px 1px;border-color:var(--rl-filet-fort);border-radius:4px 4px 4px 4px;}.elementor-kit-9 input:focus:not([type="button"]):not([type="submit"]),.elementor-kit-9 textarea:focus,.elementor-kit-9 .elementor-field-textual:focus{color:var( --e-global-color-primary );background-color:var( --e-global-color-surface );border-style:solid;border-width:2px 2px 2px 2px;border-color:var( --e-global-color-accent );border-radius:4px 4px 4px 4px;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:1200px;}.e-con{--container-max-width:1200px;}.elementor-widget:not(:last-child){margin-block-end:24px;}.elementor-element{--widgets-spacing:24px 24px;--widgets-spacing-row:24px;--widgets-spacing-column:24px;}{}h1.entry-title{display:var(--page-title-display);}.site-header .site-branding{flex-direction:column;align-items:stretch;}.site-header{padding-inline-end:0px;padding-inline-start:0px;}.site-footer .site-branding{flex-direction:column;align-items:stretch;}@media(max-width:1024px){.elementor-kit-9{--e-global-typography-wordmark-font-size:20px;--e-global-typography-cmarque-font-size:19px;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:1024px;}.e-con{--container-max-width:1024px;}}@media(max-width:767px){.elementor-kit-9{--e-global-typography-wordmark-font-size:18px;--e-global-typography-cmarque-font-size:17px;}.elementor-kit-9 h1{font-size:28px;line-height:1.2em;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:767px;}.e-con{--container-max-width:767px;--container-default-padding-top:0px;--container-default-padding-right:16px;--container-default-padding-bottom:0px;--container-default-padding-left:16px;}}
/* Start custom CSS *//* ═══ REFONTE 2026-09 — COUCHE DERIVEE ═══
   Trois graines pilotent tout le site. Elles vivent dans les couleurs
   globales systeme (Reglages du site > Couleurs globales) :
     Encre  = --e-global-color-primary
     Fond   = --e-global-color-secondary
     Marque = --e-global-color-accent
   Tout le reste est CALCULE ici. Ne jamais ecrire un hex dans un widget :
   changer une graine doit suffire a changer le site entier.
   Taux verifies : au moins 4,5:1 en texte et 3:1 en bordure d'interface. */
body{ /* PAS :root — voir LESSON-072 : --e-global-color-* vit sur body.elementor-kit-9 */
  --rl-encre:  var(--e-global-color-primary);
  --rl-fond:   var(--e-global-color-secondary);
  --rl-marque: var(--e-global-color-accent);

  --rl-fond-alt:    color-mix(in oklab, var(--rl-fond),  var(--rl-encre)  5%);
  --rl-fond-creux:  color-mix(in oklab, var(--rl-fond),  var(--rl-encre)  9%);
  --rl-carte:       color-mix(in oklab, var(--rl-fond),  #fff            72%);

  --rl-encre-douce: color-mix(in oklab, var(--rl-encre), var(--rl-fond)  16%);
  --rl-encre-tenue: color-mix(in oklab, var(--rl-encre), var(--rl-fond)  32%);

  --rl-filet:       color-mix(in oklab, var(--rl-fond),  var(--rl-encre) 16%);
  --rl-filet-fort:  color-mix(in oklab, var(--rl-fond),  var(--rl-encre) 56%);

  --rl-marque-surv: color-mix(in oklab, var(--rl-marque), #000 20%);
  --rl-sur-marque:  color-mix(in oklab, #fff 94%, var(--rl-marque));

  /* Voile de lisibilite sur photo (S3b). Une carte a texte blanc pose sur une
     photo ne peut pas garantir son contraste : la photo change, le client en
     televerse une autre, et le taux suit. Mesure du 2026-09-04 sur la grande
     carte prestation de l'Accueil (gabarit 166) : voile a 45 %, titre blanc,
     contraste REEL lu sur capture = 1,65:1 — trois fois sous le seuil.
     28 % de transparence, soit 72 % de reliure, tient AA meme sur une photo
     entierement blanche : composite (75, 89, 100), L=0,106, donc 6,4:1 contre
     l'encre claire. C'est le pire cas, pas le cas moyen — d'ou la valeur. */
  --rl-scrim: color-mix(in oklab, var(--rl-reliure), transparent 28%);

  --rl-t-micro: 11px;
  --rl-t-petit: 13px;
  --rl-t-corps: 15px;
  --rl-t-mid:   clamp(18px, 1.1vw + 14px, 21px);
  --rl-t-h2:    clamp(28px, 3.2vw + 12px, 46px);
  --rl-t-h1:    clamp(42px, 6.4vw + 8px, 92px);

  --rl-e1: 8px;  --rl-e2: 16px; --rl-e3: 24px;
  --rl-e4: 40px; --rl-e5: 64px; --rl-e6: 104px;

  --rl-sortie: cubic-bezier(.16,1,.3,1);
}

body{ background: var(--rl-fond); color: var(--rl-encre); }
body p, body li{ color: var(--rl-encre-douce); }

/* Label capitales tres espacees — le detail le moins cher du systeme. */
.rl-label{
  font-size: var(--rl-t-micro); text-transform: uppercase;
  letter-spacing: .19em; color: var(--rl-encre-tenue); font-weight: 500;
}

/* Cibles tactiles : 48 px, y compris sur les boutons WooCommerce natifs. */
.elementor-button, body.woocommerce a.button, body.woocommerce button.button,
.single_add_to_cart_button{ min-height: 48px; }

/* 16 px sur les champs : empeche le zoom automatique iOS a la mise au point. */
input[type=text], input[type=email], input[type=tel], input[type=number],
input[type=password], textarea, select{
  font-size: 16px; border-color: var(--rl-filet-fort);
}

/* Anneau de focus visible partout, contraste garanti par la graine. */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible{
  outline: 2px solid var(--rl-marque); outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{ animation-duration: .01ms !important; transition-duration: .01ms !important; }
}


/* --- Role « titre » (S3b, 2026-09-04) -------------------------------------
   144 elements portaient une globale sur la SEULE sous-cle
   typography_font_family. Elementor n'a pas de cle globale pour une sous-cle
   de groupe (core/files/css/base.php : la cle est toujours
   « typography_typography ») : la valeur repartait par le chemin local, ou le
   gabarit du controle de police entoure la valeur de guillemets. Le site
   servait donc 140 fois
     font-family:"var( --e-global-typography-primary-font-family ), Sans-serif", Sans-serif;
   soit une famille CITEE, donc inexistante, et un repli sur le Sans-serif
   generique. C'est ce qui faisait que les titres ne rendaient pas en serif.
   La cle a ete retiree des 144 elements. Ceux dont la balise est h1 a h4
   reprennent la police par la regle de titre du Kit ; les autres — intitules
   en div, titres d'accordeon, prix — portent desormais ce role, qui lit la
   MEME variable de Kit : une seule police a changer pour tout le site.
   Poids (0,2,0) : superieur a « body.elementor-kit-9 h2 » (0,1,2) comme a
   l'heritage, donc l'ordre de chargement n'a pas voix au chapitre. */
.rl-titre,
.rl-titre .elementor-heading-title,
.rl-titre .elementor-accordion-title,
.rl-titre .elementor-tab-title,
.rl-titre .price,
.rl-titre .price bdi,
.rl-titre .product_title{
  font-family: var(--e-global-typography-primary-font-family), Georgia, serif;
}

/* ═══ SOCLE WOOCOMMERCE — REMIS EN SERVICE (S3b, 2026-09-04) ═══
   Ce bloc etait enferme dans un commentaire CSS depuis la refonte : ses
   commentaires internes avaient ete reecrits en (§ §) pour ne pas fermer le
   commentaire englobant, et PLUS UNE de ses regles n'etait emise. Il est repris
   ici regle par regle, pas en bloc :
     - remis    : ce dont il est encore le seul recours ;
     - supprime : ce qu'une phase ulterieure couvre desormais mieux
                  (l'en-tete S2, le Loop Item S4b, les ratios S3a) ;
     - REPOINTE : les couleurs. L'ancienne direction nommait « secondary » un
                  gris de texte ; depuis S1, « secondary » est la graine FOND,
                  quasi blanche. Reprendre ces regles telles quelles ecrivait
                  du quasi-blanc sur du quasi-blanc — invisible. Toutes passent
                  donc par la couche derivee --rl-*. */

/* --- Tunnel de commande : separer le paiement de l'apres-vente -------------
   REMIS. La page 17 sert deux ecrans : /commande/ (le tunnel) et
   /commande/order-received/ (le remerciement). WooCommerce ajoute la classe
   body woocommerce-order-received sur le second. Aucun reglage Elementor natif
   ne permet cette condition, et le document 17 porte bien les deux blocs. */
.vbe-apres-achat{display:none}
.woocommerce-order-received .vbe-apres-achat{display:flex}
.woocommerce-order-received .vbe-avant-achat{display:none}

/* --- Boutons WooCommerce : neutraliser le violet natif ---------------------
   REMIS ET REPOINTE. woocommerce.css impose #7f54b3 sur .button.alt en (0,3,1) ;
   a specificite egale c'est l'ordre de chargement qui tranche, d'ou un violet
   qui apparait sur certaines fiches seulement. Socle en (0,3,2) : il bat
   woocommerce.css et reste sous les reglages par widget d'Elementor (0,4,1).
   Repointage : le survol visait --e-global-color-secondary, qui vaut
   aujourd'hui le FOND quasi blanc — le bouton devenait blanc sur blanc. */
body.woocommerce a.button, body.woocommerce button.button,
body.woocommerce input.button, body.woocommerce #respond input#submit,
body.woocommerce a.button.alt, body.woocommerce button.button.alt,
body.woocommerce input.button.alt, body.woocommerce #respond input#submit.alt{
  background-color:var(--rl-marque);
  color:var(--rl-sur-marque);
  border-radius:3px;
}
body.woocommerce a.button:hover, body.woocommerce button.button:hover,
body.woocommerce input.button:hover, body.woocommerce #respond input#submit:hover,
body.woocommerce a.button.alt:hover, body.woocommerce button.button.alt:hover,
body.woocommerce input.button.alt:hover{
  background-color:var(--rl-encre);
  color:var(--rl-sur-marque);
}

/* --- Formulaire d'ajout au panier -----------------------------------------
   REMIS — c'est la regle dont l'absence coutait le plus cher. Le widget
   Elementor impose display:flex + flex-wrap:nowrap sur form.cart en (0,4,1)
   via :is(). Tout enfant devenait un element flex etire sur la hauteur du plus
   grand : mesure du 2026-09-04 sur /produit/carte-cadeau-100-euros/,
   bouton d'achat a 789 px de haut et page en debordement de 132 px a 390 px.
   ATTENTION — le poids annonce par l'ancien commentaire etait FAUX, et la
   mesure du 2026-09-04 l'a montre : la regle d'Elementor n'est pas en (0,4,1)
   mais en (0,6,2), parce que son :is() vaut son argument le plus lourd
   (.woocommerce div.product .elementor-widget-woocommerce-product-add-to-cart)
   et qu'elle ajoute :not(.grouped_form):not(.variations_form). Le selecteur
   d'origine, en (0,4,3), perdait donc SUR flex-wrap tout en gagnant sur
   align-items et gap — d'ou un bouton correctement centre mais une rangee qui
   refusait de passer a la ligne, et 23 px de debordement a 320 px.
   On reprend donc exactement la meme paire de :not() : (0,6,3) contre (0,6,2),
   departage au nombre d'elements. Une colonne de blocs, mais la ligne d'achat
   reste horizontale. */
body.woocommerce div.product[class*="product-type"] form.cart:not(.grouped_form):not(.variations_form){
  display:flex;flex-wrap:wrap;align-items:center;
  gap:16px 12px;margin:0 0 24px;
}
/* Chaque bloc prend toute la largeur et sa hauteur naturelle. */
body.woocommerce div.product[class*="product-type"] form.cart > *{flex:1 1 100%;margin:0}
/* Sauf la quantite et le bouton, qui partagent la derniere ligne. */
body.woocommerce div.product[class*="product-type"] form.cart > .quantity{flex:0 0 auto;width:auto}
body.woocommerce div.product[class*="product-type"] form.cart > .single_add_to_cart_button{flex:0 1 auto;width:auto;min-height:48px}
@media(max-width:767px){
  body.woocommerce div.product[class*="product-type"] form.cart > .single_add_to_cart_button{flex:1 1 auto}
}
/* Sous 480 px, la quantite et le bouton ne tiennent plus cote a cote : mesure
   du 2026-09-04, a 320 px le bouton debordait encore de 23 px — le seul
   debordement restant du site. Chacun prend alors sa propre ligne, pleine
   largeur ; la cible tactile y gagne. 390 et 414 px gardent la ligne unique. */
@media(max-width:479px){
  body.woocommerce div.product[class*="product-type"] form.cart > .quantity,
  body.woocommerce div.product[class*="product-type"] form.cart > .single_add_to_cart_button{
    flex:1 1 100%;width:100%;
  }
}
/* Le champ quantite doit s'aligner sur la hauteur du bouton.
   REMIS SEUL de l'ancien pave « taille des boutons natifs » : le min-height de
   48 px est deja pose par le socle S2 plus haut, et reprendre en plus son
   padding:12px 26px repeignait les boutons de /boutique/, page verifiee en
   production — on ne remet donc que ce qui n'est couvert nulle part. */
body.woocommerce form.cart .quantity input.qty{
  min-height:48px;padding:0 10px;font-size:15px;text-align:center;
  border:1px solid var(--rl-filet-fort);border-radius:3px;
}

/* --- Galerie produit ------------------------------------------------------
   MISE EN PAGE NON REMISE — et c'est la mesure qui l'a tranche contre
   l'intention de depart. L'ancien bloc posait sur .woocommerce-product-gallery__wrapper
   une grille de deux colonnes, au motif ecrit dans son propre commentaire que
   « le carrousel n'est pas actif, il n'y a pas de .flex-viewport ».
   Cette premisse est FAUSSE aujourd'hui : mesure du 2026-09-04 sur
   /produit/carte-cadeau-100-euros/, .flex-viewport existe, fait 294 px
   et porte overflow:hidden. FlexSlider est donc bien en service et dimensionne
   lui-meme le rail de diapositives — 1752 px pour quatre vues. Une grille
   « repeat(2,1fr) » posee sur ce rail resout ses 1fr contre 1752 px et produit
   deux colonnes de 872 px dans un ecran de 390. Remettre ce bloc tel quel
   aurait donc REINTRODUIT un defaut, pas repare un manque.
   La mise en page appartient a FlexSlider ; il ne reste ici que le confinement.
   Les aspect-ratio de l'ancien bloc (1/1 et 4/3) sont abandonnes pour une autre
   raison : en (0,5,2) ils battaient la regle de role de S3a (0,1,1) et auraient
   defait l'harmonisation des medias. Le ratio vient de --rl-ratio-produit. */
/* overflow:hidden sur la diapositive : c'est le confinement prevu par
   WooCommerce pour l'image de zoom (position:absolute, 1024 px de large,
   mesuree a +683 px hors de l'ecran a 390 px). On ne lui impose ni largeur ni
   ratio — le grossissement a besoin d'une image PLUS GRANDE que son cadre. */
.woocommerce div.product .woocommerce-product-gallery__image{margin:0;overflow:hidden;border-radius:3px}
.woocommerce div.product .woocommerce-product-gallery__image a{display:block}

/* --- Rendez-vous : calendrier de reservation ------------------------------
   REMIS ET REPOINTE. WPS Bookings s'appuie sur flatpickr, injecte en
   JavaScript hors de l'arbre du widget : aucun reglage Elementor ne l'atteint.
   Le document 469 « Premier rendez-vous » porte bien la classe .vbe-rdv.
   Le blanc en dur de l'ancien bloc devient --rl-sur-marque. */
.flatpickr-calendar{border:1px solid var(--rl-filet-fort);border-radius:3px;box-shadow:none;font-family:inherit}
.flatpickr-months .flatpickr-month,.flatpickr-weekdays,span.flatpickr-weekday{background:transparent;color:var(--rl-encre);fill:var(--rl-encre)}
span.flatpickr-weekday{font-size:11px;letter-spacing:.08em;text-transform:uppercase;font-weight:600;color:var(--rl-encre-tenue)}
.flatpickr-current-month{font-size:16px}
.flatpickr-day{border-radius:3px;color:var(--rl-encre)}
.flatpickr-day:hover{background:var(--rl-fond-creux);border-color:var(--rl-filet-fort)}
.flatpickr-day.selected,.flatpickr-day.selected:hover,.flatpickr-day.startRange,.flatpickr-day.endRange{
  background:var(--rl-marque);border-color:var(--rl-marque);color:var(--rl-sur-marque)}
.flatpickr-day.today{border-color:var(--rl-marque)}
.flatpickr-day.flatpickr-disabled,.flatpickr-day.prevMonthDay,.flatpickr-day.nextMonthDay{color:var(--rl-encre-tenue);opacity:.35}
.flatpickr-months .flatpickr-prev-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg{fill:var(--rl-marque)}

/* champs et creneaux generes par le plugin */
.vbe-rdv input[type=text],.vbe-rdv input[type=number],.vbe-rdv select,
.vbe-rdv .mwb-mbfw-cart-page-data input,.vbe-rdv .mwb-mbfw-cart-page-data select{
  min-height:50px;padding:0 13px;border:1px solid var(--rl-filet-fort);
  border-radius:3px;background:var(--rl-carte);color:var(--rl-encre);
  font-family:inherit;font-size:16px;width:100%}
.vbe-rdv label{font-size:12px;letter-spacing:.11em;text-transform:uppercase;font-weight:600;
  color:var(--rl-encre-tenue);display:block;margin-bottom:7px}
.vbe-rdv .mwb-mbfw-total-area{margin:18px 0 0;padding-top:16px;border-top:1px solid var(--rl-filet)}
.vbe-rdv form.cart{display:grid;gap:18px;margin:0}
/* produit vendu a l'unite : la quantite n'a pas de sens ici */
.vbe-rdv .quantity{display:none}
.vbe-rdv .single_add_to_cart_button{width:100%;min-height:56px}

/* --- Tableau de tarifs — shortcode [tarifs] -------------------------------
   REMIS ET REPOINTE. Le shortcode est servi par
   wp-content/novamira-sandbox/vbe-tarifs-shortcode.php et [tarifs] figure dans
   le contenu des pages 682, 709, 710 et 711 : la table etait donc bien rendue,
   simplement sans style. Un balayage des seuls documents Elementor l'aurait
   crue morte — elle ne vit pas dans _elementor_data.
   Repointage : les intitules de colonne et la legende visaient
   --e-global-color-secondary, aujourd'hui le fond quasi blanc. */
.vbe-tarifs{overflow-x:auto;margin-block:8px}
.vbe-tarifs table{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums}
.vbe-tarifs caption{text-align:left;padding-bottom:12px;font-size:14px;color:var(--rl-encre-tenue)}
.vbe-tarifs thead th{font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:600;color:var(--rl-encre-tenue);padding:0 8px 10px;border-bottom:1px solid var(--rl-filet-fort);text-align:right;white-space:nowrap}
.vbe-tarifs thead th:first-child{text-align:left;padding-left:0}
.vbe-tarifs tbody th{font-weight:400;text-align:left;padding:13px 8px 13px 0;font-size:15px;border-bottom:1px solid var(--rl-filet)}
.vbe-tarifs tbody td{text-align:right;padding:13px 8px;white-space:nowrap;font-size:15px;border-bottom:1px solid var(--rl-filet)}
.vbe-tarifs tbody td:last-child{padding-right:0;color:var(--rl-marque)}
.vbe-tarifs tbody tr:hover th,.vbe-tarifs tbody tr:hover td{background:var(--rl-fond-alt)}
@media(max-width:560px){
.vbe-tarifs thead th,.vbe-tarifs tbody th,.vbe-tarifs tbody td{font-size:14px;padding-inline:5px}
.vbe-tarifs tbody th{padding-right:4px}
}

/* --- Carte cadeau : champs de personnalisation ----------------------------
   REMIS ET REPOINTE. Emis par wp-content/novamira-sandbox/carte-cadeau-champs.php
   (14 occurrences) : la aussi, invisible pour un balayage des documents.
   Les trois rgba(53,99,98,…) en dur — l'ancien vert — deviennent des melanges
   de la graine Marque. */
.vbe-cc{display:grid;gap:20px;margin:24px 0}
.vbe-cc-group{border:0;margin:0;padding:0;min-width:0}
.vbe-cc-legend{padding:0;margin:0 0 12px;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--rl-marque);font-weight:600}
.vbe-cc-group:first-child{display:grid;gap:10px}
.vbe-cc-opt{display:flex;gap:12px;align-items:flex-start;padding:16px;cursor:pointer;
 border:1px solid var(--rl-filet-fort);border-radius:4px;background:var(--rl-carte);transition:border-color .15s}
.vbe-cc-opt:hover{border-color:var(--rl-marque)}
.vbe-cc-opt input[type=radio]{margin:3px 0 0;flex:0 0 auto;width:18px;height:18px;accent-color:var(--rl-marque)}
.vbe-cc-opt > span{display:grid;gap:3px;min-width:0}
.vbe-cc-opt b{font-weight:600;font-size:15px;line-height:1.35}
.vbe-cc-desc{font-size:13.5px;line-height:1.5;color:var(--rl-encre-douce)}
.vbe-cc-opt:has(input:checked){border-color:var(--rl-marque);background:color-mix(in oklab, var(--rl-carte), var(--rl-marque) 6%)}
.vbe-cc-opt:has(input:focus-visible){outline:2px solid var(--rl-marque);outline-offset:2px}
.vbe-cc-field{display:grid;gap:6px;margin:0 0 16px}
.vbe-cc-field:last-child{margin-bottom:0}
.vbe-cc-field label{font-size:13.5px;font-weight:600}
.vbe-cc-field input,.vbe-cc-field textarea{width:100%;min-height:48px;padding:12px 14px;font:inherit;font-size:15px;
 color:var(--rl-encre);background:var(--rl-carte);
 border:1px solid var(--rl-filet-fort);border-radius:4px;box-sizing:border-box}
.vbe-cc-field textarea{min-height:104px;resize:vertical;line-height:1.55}
.vbe-cc-field input:focus,.vbe-cc-field textarea:focus{outline:0;border-color:var(--rl-marque);box-shadow:0 0 0 3px color-mix(in oklab, var(--rl-marque), transparent 84%)}
.vbe-cc-hint{font-size:12.5px;line-height:1.45;color:var(--rl-encre-tenue)}

/* SUPPRIMES de l'ancien bloc, et pourquoi :
   - .elementor-97 …{white-space:nowrap} (en-tete) : S2 a reconstruit l'en-tete ;
     .carnet-nav .elementor-nav-menu a porte deja nowrap, et la nav defile en
     place au lieu de pousser la page. Deux de ses selecteurs etaient de toute
     facon morts (entite HTML au lieu du combinateur).
   - .elementor-loop-container .button{display:flex;width:100%} : le Loop Item
     194 a ete reconstruit en S4b avec les reglages natifs, et /boutique/ est
     mesuree conforme. En (0,3,2) cette regle aurait battu le socle S2 en
     (0,1,0) et repeint une page verifiee.
   - le pave « taille des boutons natifs » : min-height:48px double le socle S2 ;
     .elementor-button.elementor-size-md double « .elementor-button » du socle ;
     .widget_price_filter ne correspond a aucun widget du site (recense).
   - les aspect-ratio de la galerie : remplaces par les roles de S3a.
   - un @media(max-width:767px){} vide. */
/* ═══ fin SOCLE WOOCOMMERCE ═══ */

/* ═══ CARNET DE CURE — gabarit Boutique (2026-09-02) ═══
   Quatre intercalaires de bristol. L'onglet actif repeint le rayon : :has()
   lit l'attribut aria-pressed que le filtre Elementor met a jour lui-meme,
   donc AUCUN script maison. Sans support de :has(), la teinte par defaut
   reste en place — degradation silencieuse, jamais de page cassee.
   Les teintes sont attribuees par nth-child et non par slug : une nouvelle
   categorie boutique recoit la sienne sans qu'on retouche ce fichier. */
body{ /* idem bloc 1 : les derivees du Carnet doivent naitre sur body */
  --rl-reliure:       var(--e-global-color-reliure);
  --rl-reliure-fonce: color-mix(in oklab, var(--rl-reliure), #000 32%);
  --rl-reliure-clair: color-mix(in oklab, var(--rl-reliure), #fff 14%);
  /* Filet visible : 4,19:1 sur la reliure foncee et 3,21:1 sur la reliure.
     reliure-clair (1,9:1) reste reserve aux fonds et aux survols, jamais
     a un trait qui doit se voir (WCAG 1.4.11). */
  --rl-filet-reliure: color-mix(in oklab, var(--rl-reliure), #fff 40%);
  --rl-tampon:        var(--e-global-color-tampon);
  --rl-sur-reliure:   color-mix(in oklab, #fff 94%, var(--rl-reliure));
  --rl-sur-reliure-b: color-mix(in oklab, #fff 74%, var(--rl-reliure));
}

/* La teinte du rayon selectionne est une variable de PAGE, pas de bloc : elle
   habille l'onglet actif ET le rayon en dessous, qui se lisent alors comme une
   seule surface. Les deux teintes d'intercalaire au repos en derivent aussi.
   Taux mesures au pixel (canvas 1x1, jamais par lecture de chaine color-mix) :
   encre 6,41:1 sur le repos, 8,14:1 sur le survol, 10,66:1 sur l'actif ;
   limite onglet/reliure 5,62:1 pour un seuil de 3:1. */
body{
  --rl-bristol-actif: var(--e-global-color-bristol);
  --rl-onglet-repos:  color-mix(in oklab, var(--e-global-color-bristol), var(--rl-reliure) 26%);
  --rl-onglet-survol: color-mix(in oklab, var(--e-global-color-bristol), var(--rl-reliure) 14%);
}
/* Elementor rend l'onglet « tout » EN DERNIER dans le DOM, quel que soit son
   rang visuel. nth-child seul lui attribuait donc la 4e teinte : le rayon
   s'ouvrait en beige (bristol4) au lieu du mineral pale. On l'ecarte par son
   attribut — le seul stable — et les rayons prennent les trois autres teintes
   en cycle, dans l'ordre du DOM. Aucun slug n'est ecrit ici : une nouvelle
   categorie boutique recoit sa teinte sans qu'on retouche ce fichier.
   :has() lit l'attribut aria-pressed que le filtre Elementor met a jour
   lui-meme : aucun script maison, et sans support de :has() la teinte par
   defaut reste en place — degradation silencieuse, jamais de page cassee. */
body:has(.carnet-onglets .e-filter-item:not([data-filter="__all"]):nth-child(3n+1)[aria-pressed="true"]){ --rl-bristol-actif: var(--e-global-color-bristol2); }
body:has(.carnet-onglets .e-filter-item:not([data-filter="__all"]):nth-child(3n+2)[aria-pressed="true"]){ --rl-bristol-actif: var(--e-global-color-bristol3); }
body:has(.carnet-onglets .e-filter-item:not([data-filter="__all"]):nth-child(3n)[aria-pressed="true"]){   --rl-bristol-actif: var(--e-global-color-bristol4); }

.carnet-rayon{
  --rl-carte-bristol: color-mix(in oklab, var(--rl-bristol-actif), #fff 60%);
  --rl-filet-bristol: color-mix(in oklab, var(--rl-encre), transparent 55%);
}

/* Les trois FONDS d'onglet sont desormais des reglages natifs du widget de
   filtre (Style > Normal / Survol / Actif). Ecrits ici, ils perdaient : la
   feuille du widget pose « background-color: initial » a specificite egale et
   se charge apres le CSS du Kit — la regle etait bien presente et sans effet
   (LESSON-062). Ne restent ici que les trois choses qu'aucun controle natif
   n'expose : la hauteur de cible, l'ancrage de l'actif, le degrade de bord. */
/* La feuille du widget laisse box-sizing a « initial », donc content-box : un
   min-height s'y AJOUTE au remplissage et l'onglet montait a 78 px au lieu de
   48. On ne peut pas le corriger sur « .carnet-onglets .e-filter-item » : la
   regle du widget a la MEME specificite (0,2,0) et se charge apres, elle
   gagne. On passe donc par la variable que cette regle lit, posee sur le
   widget lui-meme avec une specificite superieure (0,2,0 contre 0,1,0) :
   l'ordre de chargement n'a alors plus voix au chapitre. */
.elementor-widget.carnet-onglets{ --e-filter-item-box-sizing: border-box; }
.carnet-onglets .e-filter-item{
  min-height: 48px;                /* cible tactile, CLAUDE.md §3.2 */
  position: relative; top: 0;
  transition: top .22s var(--rl-sortie), background-color .22s var(--rl-sortie);
}
/* L'onglet actif descend de 3 px et vient s'ancrer dans le rayon : les deux
   surfaces se touchent, sans filet de reliure entre elles. Les 3 px de
   remplissage bas de la bande empechent que ce decalage soit rogne par le
   conteneur de defilement du mobile (overflow-x rend overflow-y non visible). */
.carnet-onglets .e-filter{ padding-bottom: 3px; }
.carnet-onglets .e-filter-item[aria-pressed="true"]{ top: 3px; font-weight: 600; }

/* Sous 768 px la bande defile horizontalement : un degrade de bord rend le
   hors-champ perceptible, sans quoi rien n'indique qu'il reste des rayons a
   droite. Il ne capte pas le pointeur et ne masque aucun onglet entier. */
@media (max-width: 767px){
  .carnet-onglets .elementor-widget-container{ position: relative; }
  .carnet-onglets .elementor-widget-container::after{
    content: ""; position: absolute; inset-block: 0; inset-inline-end: 0;
    width: 32px; pointer-events: none;
    background: linear-gradient(to left, var(--rl-reliure), transparent);
  }
}

/* SUPPRIME en S5 (2026-09-04) : `.carnet-vue img{aspect-ratio:1/1;...}` en
   (0,1,1) faisait doublon avec la regle de role posee en S3a plus bas dans ce
   fichier -- `.rl-media-produit img:not(.zoomImg), .carnet-vue img:not(.zoomImg)`
   en (0,2,1) -- qui la battait au comptage. Le bloc etait donc INERTE : verifie
   sur la valeur calculee avant retrait, aucun pixel ne bouge. Il ne restait
   deroutant, laissant croire que le carre des packshots venait d'ici. */

/* Resume borne : la grille reste reguliere quelle que soit la longueur du texte. */
.carnet-resume p{
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; margin-bottom: 0;
}
@media (max-width:767px){ .carnet-resume p{ -webkit-line-clamp: 3; } }

/* Anneau de focus sur le bristol : la graine marque y perd son contraste. */
.carnet-rayon a:focus-visible, .carnet-rayon button:focus-visible,
.carnet-onglets .e-filter-item:focus-visible{
  outline: 2px solid var(--rl-encre); outline-offset: 3px;
  box-shadow: 0 0 0 5px var(--e-global-color-bristol4);
}
/* ═══ fin CARNET DE CURE ═══ */

/* CARNET — EN-TETE ET PIED (S2, 2026-09-02)
   Tout ce qui est reglable dans le panneau Elementor l'est. Ne restent ici
   que les trois choses qu'aucun controle natif n'expose. */

/* 1. La nav ne doit JAMAIS pousser la page : elle defile en place.
   Le menu principal du client peut compter 5 entrees comme 12 ; sans cette
   soupape, la 10e sortait de l'ecran et creait le seul debordement
   horizontal du site. Rien n'est masque : tout reste atteignable. */
/* flex:1 1 0% est indispensable : Elementor pose flex-shrink:0 sur ses
   enfants, donc un conteneur « grow » ne se RETRECIT pas et deborde. */
.carnet-nav{ flex: 1 1 0% !important; min-width: 0; }
.carnet-marque a{ min-height: 48px; display: inline-flex; align-items: center; }
.carnet-nav .elementor-nav-menu{ flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
.carnet-nav .elementor-nav-menu::-webkit-scrollbar{ display: none; }
.carnet-nav .elementor-nav-menu a{ white-space: nowrap; }

/* 2. Le registre : pastille carree, comme un tampon, pas une bulle. */
.carnet-registre .elementor-button-icon-qty{
  border-radius: 2px; font-variant-numeric: tabular-nums;
}

/* 3. Cibles tactiles : 48 px sur tout ce qui se clique, et pas seulement dans
   l'en-tete. Les liens au fil d'un paragraphe restent hors perimetre (WCAG
   2.5.8, exception « cible en ligne »). Mesure avant : 13 entrees de menu a
   47 px dans le pied et le sommaire mobile, 3 boutons d'achat a 43 px. */
.carnet-nav .elementor-nav-menu a.elementor-item{ min-height: 48px; display: flex; align-items: center; }
.elementor-nav-menu a.elementor-item{ min-height: 48px; display: inline-flex; align-items: center; }
.carnet-registre a{ min-height: 48px; display: inline-flex; align-items: center; }
/* Les boutons d'achat des cartes produit ne vivent pas toujours sous
   « body.woocommerce » — l'Accueil n'est pas une page boutique — donc la regle
   du socle les manquait et ils rendaient a 43 px. */
a.button, button.button, .add_to_cart_button, .single_add_to_cart_button{
  min-height: 48px; display: inline-flex; align-items: center; justify-content: center;
}

/* 4. Le pied et le sommaire mobile vivent sur la reliure. La regle
   « body p, body li » du socle y poserait de l'encre sur du bleu nuit :
   on la reprend, une seule fois, avec un poids de classe. */
/* La regle « body p, body li » du socle vise le <p> LUI-MEME, alors que la
   couleur d'un widget Elementor est posee sur son conteneur : ce n'est pas
   une affaire de specificite, c'est une affaire de cible, et l'heritage
   perd toujours. Tout bloc a fond sombre porte donc « carnet-sombre ». */
.carnet-sombre p, .carnet-sombre li{ color: var(--rl-sur-reliure-b); }
.carnet-pied p, .carnet-pied li{ color: var(--rl-sur-reliure-b); }
.carnet-pied a{ color: var(--rl-sur-reliure); }
.carnet-popup, .carnet-popup p, .carnet-popup li{ color: var(--rl-sur-reliure-b); }
.carnet-popup a{ color: var(--rl-sur-reliure); }
/* MEDIAS - UN RATIO PAR ROLE (S3a, 2026-09-04)
   Le GABARIT impose le ratio, jamais le fichier. Une photo 2:3 et une photo 3:2
   televersees par le client rendent exactement pareil : c est cette regle qui
   rend la grille scalable, pas la discipline de celui qui televerse.
   DEUX ratios pour tout le site, deliberement opposes (regle 4 de
   docs/20_REFONTE_DESIGN_SYSTEM.md, qui associe 3:2 a Mineral Clinique) :
     produit   1:1  packshot - boutique, panier, fiche produit, cartes cadeaux
     soin      3:2  photo de prestation - grilles, cartes, archive Prestations
     ouverture 3:2  visuel de haut de page - meme valeur, role distinct pour
                    rester dissociable en changeant UNE ligne.
   Ici le RENDU. Le POIDS et le srcset sont dans wp-content/mu-plugins/rl-medias.php. */
body{
  --rl-ratio-produit:   1 / 1;
  --rl-ratio-soin:      3 / 2;
  --rl-ratio-ouverture: 3 / 2;
}
/* :not(.zoomImg) : WooCommerce superpose une image de zoom en position absolue
   sur la fiche produit. Lui imposer un ratio casserait le grossissement. */
.rl-media-produit img:not(.zoomImg),
.carnet-vue img:not(.zoomImg){
  aspect-ratio: var(--rl-ratio-produit);
  object-fit: cover; object-position: center center;
  width: 100%; height: auto; display: block;
}
.rl-media-soin img:not(.zoomImg){
  aspect-ratio: var(--rl-ratio-soin);
  object-fit: cover; object-position: center center;
  width: 100%; height: auto; display: block;
}
.rl-media-ouverture img:not(.zoomImg){
  aspect-ratio: var(--rl-ratio-ouverture);
  object-fit: cover; object-position: center center;
  width: 100%; height: auto; display: block;
}
/* Les vignettes de navigation d une galerie sont des reperes, pas des photos :
   elles gardent le carre. Poids de classe superieur (0,2,1) a la regle de role
   (0,1,1), donc l ordre de chargement n a pas voix au chapitre (LESSON-077). */
.rl-media-produit .flex-control-thumbs img,
.rl-media-soin .flex-control-thumbs img,
.rl-media-ouverture .flex-control-thumbs img{
  aspect-ratio: var(--rl-ratio-produit);
}

/* --- S4b : l'EMPLACEMENT doit epouser l'image (2026-09-04) ----------------
   Le role donne le ratio ; encore faut-il que la boite qui porte l'image ait
   exactement la taille de l'image. Deux vides mesures sur le rendu servi :

   1. LE VIDE DE 7,6 px, A TOUTES LES LARGEURS. Le lien qui enveloppe un media
      de role est un inline-block (`.elementor-widget-image a`, poids 0-1-1) :
      il s'assoit sur la ligne de base, et la ligne reserve sous lui la place
      des jambages. Mesure a 1440 px : image 300, emplacement 307,6. La preuve
      de la cause est dans les medias SANS lien (Accueil, visuel d'ouverture) :
      ils mesurent deja 0. Le lien passe donc en bloc, et la ligne disparait.
      Poids (0,2,1) contre (0,1,1) : la regle d'Elementor est battue au
      comptage, l'ordre de chargement n'a donc pas voix au chapitre
      (LESSON-091) -- et il aurait compte, `widget-image.min.css` se chargeant
      APRES `post-9.css`.

   2. LA BANDE MOBILE. Sous 768 px la fiche du Carnet passe en rangee : la
      colonne d'image n'est plus un packshot pose en haut d'une carte, c'est
      une bande qui doit courir sur toute la hauteur de la fiche. Le carre 1:1
      y laissait 179 px de fond gris a 390 px (image 132x132 dans un
      emplacement de 132x311).
      EXCEPTION ASSUMEE au « un ratio par role », et elle ne l'affaiblit pas :
      ce que le role promet, c'est que toutes les vues d'un meme role soient
      harmonisees. En grille cela se dit « carre » ; en fiche horizontale cela
      se dit « toutes les bandes identiques ». Les sept fiches de /boutique/
      ont la meme hauteur a chaque largeur (mesure du 2026-09-04 : 346, 313,
      281, 256 px), donc les sept bandes sont identiques entre elles. Le 1:1
      reste la regle en contexte grille -- ce n'est pas une regression.
      La classe `rl-media-bande` porte le CONTEXTE, pas le role : elle n'est
      posee que sur un media dont la carte devient horizontale, et elle est
      inerte au-dessus de 768 px. Le point de bascule est celui d'Elementor :
      si le gabarit change de point d'arret, cette media query doit suivre.
      `height:100%` sur l'image ne suffisait pas seul -- la chaine
      `.elementor-widget-container` puis `a` avait une hauteur `auto`, et un
      pourcentage ne resout rien contre `auto`. */
.rl-media-produit > .elementor-widget-container > a,
.rl-media-soin > .elementor-widget-container > a,
.rl-media-ouverture > .elementor-widget-container > a{ display: block; }

@media (max-width: 767px){
  .rl-media-bande > .elementor-widget-container,
  .rl-media-bande > .elementor-widget-container > a{ height: 100%; }
  .rl-media-produit.rl-media-bande img:not(.zoomImg),
  .rl-media-soin.rl-media-bande img:not(.zoomImg),
  .rl-media-ouverture.rl-media-bande img:not(.zoomImg){
    aspect-ratio: auto; height: 100%; width: 100%;
    object-fit: cover; object-position: center center;
  }
}

/* fin MEDIAS */

/* ═══ CORRECTIFS DE CONTRASTE — S4, 2026-09-04 ═══
   Quatre taux sous le seuil, tous lus au pixel sur canvas 1x1 (jamais par
   analyse de la chaine color-mix, qui se calcule en oklab). Chacun est corrige
   a sa cause : une variable manquante, pas l'element ou le defaut se voit. */

/* 1. --rl-carte-bristol et --rl-filet-bristol n'existaient QUE sous
   .carnet-rayon. Le Loop Item de la Boutique (194) les lit pour son bouton
   d'ajout ; partout ailleurs — Accueil, /panier/, fiche produit, ou la meme
   boucle est reutilisee hors d'un rayon — la variable etait vide et la couleur
   retombait sur l'heritage : de l'ENCRE SUR DE L'ENCRE. Mesure du 2026-09-04 :
   « Ajouter au panier » et « Choix des options » a 1,00:1, sur trois pages.
   Ce n'est pas un plancher decoratif, c'est ce qui rend la boucle reutilisable :
   le rayon garde son propre calcul (specificite 0,1,0 contre 0,0,1). */
body{
  --rl-carte-bristol: var(--rl-carte);
  --rl-filet-bristol: var(--rl-filet-fort);
}

/* 2. Lien d'evitement : graine marque sur encre, 1,48:1. C'est le PREMIER
   element atteint au clavier ; s'il est illisible, le raccourci n'existe pas. */
.vbe-evitement, a.vbe-evitement{
  background: var(--rl-encre);
  color: var(--rl-carte);
}
.vbe-evitement:focus-visible{ outline: 2px solid var(--rl-carte); outline-offset: 2px; }

/* 3. Etat de stock WooCommerce : sa feuille impose sa propre teinte, mesuree
   a 2,30:1 sur le bristol pour un texte de 14,7 px. */
body.woocommerce div.product p.stock, body.woocommerce div.product .stock{ color: var(--rl-encre-douce); }
body.woocommerce div.product p.stock.out-of-stock, body.woocommerce div.product .out-of-stock{
  color: var(--e-global-color-error);
}

/* 4. Bouton de panier de l'en-tete : son intitule heritait du filet de reliure,
   3,71:1. Le filet reste au BORD, ou 3:1 suffit (WCAG 1.4.11) ; le texte prend
   la couleur de la nav, mesuree a 10,28:1 sur la meme barre.
   Aucun controle Elementor n'expose la couleur de texte de ce bouton — le
   widget n'en declare pas ; c'est la seule raison pour laquelle la regle est
   ici et non dans le document 97. */
.elementor-widget.elementor-widget-woocommerce-menu-cart{
  --toggle-button-text-color: var(--rl-sur-reliure-b);
  --toggle-button-hover-text-color: var(--rl-sur-reliure);
}

/* ═══ S5 — CIBLES DE FICHE ET TUNNEL (2026-09-04) ═══
   Trois choses qu'aucun controle Elementor n'expose, et rien d'autre : tout ce
   qui etait reglable dans le panneau l'a ete dans les documents 16, 17 et 194. */

/* --- 1. LA CARTE ENTIERE EST LA CIBLE -------------------------------------
   Mesure du 2026-09-04 sur le rendu servi : le lien de titre d'une fiche de
   boucle fait 20 a 34 px de haut -- 14 cibles sous 48 px sur /boutique/, 11 sur
   l'Accueil, 11 sur /panier/. Grossir le titre changerait la maquette ;
   l'etendre a la carte ne change rien a l'oeil et donne une cible de 250 a
   550 px de haut selon la largeur.
   UN SEUL lien est etendu -- celui du titre -- donc la carte n'a qu'une
   destination possible. Le formulaire d'ajout au panier repasse AU-DESSUS :
   c'est le seul endroit de la carte ou le clic ne doit pas ouvrir la fiche.
   Sans ce z-index le bouton d'achat serait avale en silence ; le piege est
   connu, et il est verifie au clic, pas suppose.
   Le lien du visuel reste en place : il pointe vers la meme fiche, il passe
   sous le calque, et le retirer aurait coute une affordance pour rien. */
.carnet-fiche{ position: relative; }
/* Elementor pose `position: relative` sur CHAQUE widget. Sans cette ligne, le
   calque se resolvait contre le widget de titre et mesurait 270 x 24 px -- le
   titre, et rien d'autre : la carte n'etait pas cliquable, et le test de clic
   le disait (le pointeur au centre du resume retombait sur un <p>). Neutraliser
   la position du seul widget de titre suffit : le calque se resout alors contre
   le corps de la fiche, qui est le conteneur `.e-con` juste au-dessus. Le
   widget de titre n'a aucun enfant positionne, la ligne ne coute rien. */
.carnet-fiche .elementor-widget-theme-post-title{ position: static; }
.carnet-fiche .elementor-widget-theme-post-title .elementor-heading-title a::after{
  content: ""; position: absolute; inset: 0; z-index: 1;
}
.carnet-fiche .elementor-widget-woocommerce-product-add-to-cart{
  position: relative; z-index: 2;
}
/* L'anneau de focus doit dire ce que le clic fera : il entoure la carte, pas
   les trois mots du titre. Sans support de :has(), l'anneau reste sur le lien
   -- degradation silencieuse, jamais de focus invisible. */
.carnet-fiche:has(.elementor-widget-theme-post-title a:focus-visible){
  outline: 2px solid var(--rl-marque); outline-offset: 3px;
}

/* --- 2. TUNNEL : LES ETATS FONCTIONNELS ----------------------------------- */

/* 2a. UN CHAMP EN ERREUR NE SE DISTINGUAIT PAS D'UN CHAMP VALIDE.
   Cause mesuree, et le comptage a ete refait apres un premier echec -- c'est
   la partie qui compte. Le reglage de bordure du widget Commande sort en
   `.elementor-17 .elementor-element.elementor-element-087193a .woocommerce
    #customer_details .form-row .input-text`, soit UN identifiant et SIX
   classes, (1,6,0). Il bat la regle de WooCommerce
   `.woocommerce form .form-row.woocommerce-invalid input.input-text` en
   (0,4,2) : le champ en erreur avait donc exactement la bordure d'un champ
   valide. Le reglage du widget est legitime ; c'est l'etat d'erreur qu'il
   ecrasait sans le dire.
   Premiere tentative : `.woocommerce #customer_details .form-row
   .woocommerce-invalid .input-text`, (1,4,0) -- ecrite, servie, SANS EFFET,
   parce que j'avais compte (0,5,1) au lieu de (1,6,0) chez l'adversaire. La
   mesure l'a dit tout de suite : bordure identique des deux cotes. On ajoute
   donc la classe de body du tunnel, qui porte le selecteur a (1,6,1) -- un
   element de plus a identifiants et classes egaux, ce qui suffit, et l'ordre
   de chargement n'a pas voix au chapitre.
   La couleur ne porte pas seule l'information (WCAG 1.4.1) : le trait double
   d'epaisseur, et la liste d'erreurs en tete de formulaire -- role="alert",
   rendue par le widget Notices -- reste le message. */
body.woocommerce-checkout .elementor-widget-woocommerce-checkout-page .woocommerce #customer_details .form-row.woocommerce-invalid .input-text,
body.woocommerce-checkout .elementor-widget-woocommerce-checkout-page .woocommerce #customer_details .form-row.woocommerce-invalid select,
body.woocommerce-checkout .elementor-widget-woocommerce-checkout-page .woocommerce #customer_details .form-row.woocommerce-invalid textarea{
  border-color: var(--e-global-color-error);
  border-width: 2px;
}

/* 2b. LE TON DISCRET SUR UN INTERCALAIRE.
   `--rl-encre-tenue` est calibre contre le FOND quasi blanc. Pose sur un
   bristol, il tombe a 4,43:1 pour un texte de 12,5 px -- mesure du
   2026-09-04 sur les indications du formulaire de carte cadeau, dont la
   section est passee en intercalaire. Ce n'est pas au composant de se
   corriger : c'est le TON qui depend du fond, comme `--rl-carte-bristol` et
   `--rl-filet-bristol` juste au-dessus. Il est donc redefini pour le
   contexte, en melangeant vers le bristol reellement affiche. Mesure
   apres : 6,4:1. Le ton reste plus clair que l'encre : la hierarchie tient. */
.carnet-rayon{
  --rl-encre-tenue: color-mix(in oklab, var(--rl-encre), var(--rl-bristol-actif) 22%);
}

/* NOTE — 2b PRECEDENT, RETIRE ET REMPLACE PAR UN REGLAGE NATIF.
   Le lien de la politique de confidentialite, dernier texte lu avant de
   valider une commande, mesurait 2,01:1 : bleu #5bc0de. Une regle de Kit
   `.woocommerce-privacy-policy-text a` a d'abord ete ecrite, et elle a perdu
   -- LESSON-091, le cas d'ecole. La regle de Pro est
   `.elementor-widget-woocommerce-checkout-page a{color:var(--links-normal-color,#5bc0de)}`,
   soit (0,1,1), exactement le poids de la regle du Kit ; a egalite, la
   feuille du widget se charge APRES et gagne. La reponse n'est pas de
   grossir le selecteur mais de passer par la VARIABLE que cette regle lit :
   le widget Commande expose « Liens » dans son panneau, qui ecrit
   `--links-normal-color` sur le widget lui-meme. C'est donc pose dans le
   document 17, pas ici -- et cela corrige du meme coup « Cliquer pour saisir
   un code promo », qui echouait pour la meme raison. */

/* 2c. CIBLES TACTILES DU TUNNEL. Le socle S2 couvre les boutons ; restaient
   les champs et le lien de suppression d'une ligne de panier, mesures le
   2026-09-04 a 38 px (code promo), 28 px (quantite) et 21,6 px (la croix).
   La croix garde sa taille APPARENTE : c'est sa zone de clic qui grandit. */
.checkout_coupon input.input-text,
form.fid-carte-form input[type="text"],
#coupon_code{ min-height: 48px; }
/* La quantite d'une ligne de panier : le widget Panier lui pose `height` ET
   `min-height` a 28 px. Un `min-height` seul ne suffisait pas -- mesure a 28 px
   apres ecriture -- parce que `height` restait fige au meme chiffre. Il faut
   donc rendre la hauteur au contenu ET poser le plancher. La classe de body du
   panier porte le selecteur au-dessus de celui du widget. */
body.woocommerce-cart .elementor-widget-woocommerce-cart .woocommerce-cart-form .quantity input.qty{
  height: auto; min-height: 48px;
  /* Son filet mesurait 1,37:1 : le champ ne se voyait pas comme un champ
     (WCAG 1.4.11 demande 3:1 pour la limite d'un composant). Meme filet que
     les autres champs du site, mesure a 4,4:1 sur la carte. */
  border: 1px solid var(--rl-filet-fort);
}
.woocommerce-cart-form__cart-item .product-remove a.remove,
td.product-remove a.remove{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 48px; min-height: 48px;
}
/* Le nom du produit dans le tableau du panier (16 px) et la loupe de la
   galerie produit (36 px) : deux liens que rien d'autre ne couvre. */
.woocommerce-cart-form__cart-item .product-name a{
  display: inline-flex; align-items: center; min-height: 48px;
}
.woocommerce-product-gallery__trigger{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 48px; min-height: 48px;
}
/* Le formulaire de carte cadeau vient de l'extension Fidelite : il n'a ni
   classe ni reglage Elementor. On lui donne la meme mise que le code promo,
   sans lui inventer de couleur. */
form.fid-carte-form{ display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; margin: 0 0 20px; }
form.fid-carte-form label{ flex: 1 1 100%; font-size: var(--rl-t-petit); color: var(--rl-encre-douce); }
form.fid-carte-form input[type="text"]{ flex: 1 1 12ch; min-width: 0; padding: 0 13px;
  border: 1px solid var(--rl-filet-bristol); border-radius: 3px;
  background: var(--rl-carte); color: var(--rl-encre); }
form.fid-carte-form button{ flex: 0 0 auto; min-height: 48px; padding: 0 22px;
  border: 1px solid var(--rl-encre); border-radius: 3px;
  background: var(--rl-encre); color: var(--rl-carte); font: inherit; cursor: pointer; }
form.fid-carte-form button:hover{ background: var(--rl-marque); border-color: var(--rl-marque); }

/* 2d. LES NOTICES, ET POURQUOI ELLES NE PASSENT PAS PAR LE REGLAGE NATIF.
   Le widget Notices masque les notices de WooCommerce (display:none) et les
   re-rend dans son propre bloc `.e-woocommerce-notices-wrapper`. Elementor
   Pro expose bien un reglage de Kit pour leur design -- Reglages du site >
   WooCommerce > Notices -- et il a ete essaye : les 20 cles s'ecrivent et se
   relisent, mais AUCUN octet de CSS n'en sort. La cause est dans le
   selecteur : `body.e-wc-error-notice .woocommerce-error`. Cette classe de
   body n'est posee par aucun PHP -- elle est ajoutee par le JavaScript de
   Pro, a partir du reglage « Notice Type ». Faire dependre d'un script
   l'apparence d'un MESSAGE D'ERREUR de tunnel serait accepter qu'il soit
   illisible tant que le script n'a pas tourne. Les 20 cles ont donc ete
   remises a vide, et la boite est decrite ici, ou elle est servie avec la
   page. Les trois etats restent distinguables autrement que par la couleur :
   filet lateral epais, et l'erreur est la seule a porter role="alert". */
.e-woocommerce-notices-wrapper .woocommerce-error,
.e-woocommerce-notices-wrapper .woocommerce-info,
.e-woocommerce-notices-wrapper .woocommerce-message{
  color: var(--rl-encre);
  background: var(--rl-carte);
  border: 1px solid var(--rl-filet-bristol);
  border-inline-start: 4px solid var(--rl-filet-fort);
  border-radius: 3px;
  padding: 14px 16px; margin: 0 0 18px; list-style: none;
}
.e-woocommerce-notices-wrapper .woocommerce-error{ border-inline-start-color: var(--e-global-color-error); }
.e-woocommerce-notices-wrapper .woocommerce-message{ border-inline-start-color: var(--rl-marque); }
.e-woocommerce-notices-wrapper .woocommerce-error li,
.e-woocommerce-notices-wrapper .woocommerce-info,
.e-woocommerce-notices-wrapper .woocommerce-message{ color: var(--rl-encre); }
.e-woocommerce-notices-wrapper a{ color: var(--rl-marque); }

/* ═══ fin S5 ═══ *//* End custom CSS */