/* =====================================================================
   THEME V19 — feuille de style autonome, portée depuis la page de
   référence `_missions/debouchage-reseau-francilien-v19.html`.

   PÉRIMÈTRE — LIRE AVANT DE MODIFIER
   -----------------------------------------------------------------
   Ce fichier est neuf : il n'est chargé par aucun template pour le
   moment (le câblage dans `templates/base.html.twig` — bloc
   `stylesheets` — est hors périmètre de cette tâche, à faire
   séparément une fois le contenu CMS validé).

   TOUT le contenu ci-dessous est scopé sous le sélecteur composé
   `body.theme-v19` (jamais sous `:root` ni sous un sélecteur de type
   nu comme `html`/`body`/`.container`/`.btn`). Le site sert 26 gabarits
   Twig différents (voir docs/theme-v19/01-etat-des-lieux.md §3) qui
   n'auront jamais la classe `theme-v19` sur leur <body> : ce fichier ne
   doit donc avoir strictement AUCUN effet visuel sur ces pages tant que
   le contrôleur d'accueil n'ajoute pas explicitement cette classe.

   Beaucoup de noms de classes de la référence V19 (`.container`, `.btn`,
   `.btn-primary`, `.btn-outline-primary`, `.card`, `.row`, `.col`,
   `.navbar`, `.nav-link`, `.form-control`, `.form-group`…) sont DÉJÀ
   utilisés par le CSS legacy du site (`public/assets/css/style.min.css`
   et consorts, chargés sur toutes les pages y compris l'accueil — voir
   01-etat-des-lieux.md §5). Le scoping `body.theme-v19 .xxx` n'est donc
   pas qu'une précaution de confinement : c'est aussi ce qui donne à ces
   règles une spécificité (0,0,2,x) supérieure à celle des règles
   génériques `.xxx` (0,0,1,x) du CSS existant, sans avoir à renommer la
   moindre classe ni à toucher au moindre fichier existant.

   NETTOYAGE APPLIQUÉ PAR RAPPORT À LA RÉFÉRENCE (voir
   docs/theme-v19/02-inventaire-v19-verifie.md §5 et §9) :
   - Les deux blocs `:root` de la référence (« SYSTEM UI KIT » L12-38 et
     « DESIGN SYSTEM » L309-362) sont fusionnés en UN seul bloc de
     custom properties, scopé `body.theme-v19` au lieu de `:root` global.
   - `--ev-grid-max-width: 62rem` (1er bloc, valeur morte écrasée par la
     cascade) n'est PAS repris : seule `74rem` (valeur réellement
     utilisée) apparaît ci-dessous.
   - `.ratio-24x7` et `.ratio-full` (définies mais jamais utilisées dans
     le corps de la référence) ne sont pas reprises.
   - `.section-inspector` (classe présente sur 31 éléments HTML de la
     référence, sans la moindre règle CSS/JS associée — artefact
     d'outillage de maquette) n'a aucune règle dans la référence : rien
     à porter ici, mais ne pas la réintroduire si du HTML est copié
     depuis la référence.
   - L'`@import url(...fonts.googleapis...)` CSS (bloquant) de la référence
     n'est PAS repris tel quel : Space Grotesk/DM Sans sont chargées via
     un `<link rel="stylesheet">` + `preconnect` dans
     `templates/home/index.html.twig` (non bloquant), demande explicite du
     client tranchant le point B8 (docs/theme-v19/06-points-a-arbitrer.md).
   - `scroll-behavior: smooth` est repris via `html:has(body.theme-v19)`
     (et non plus `html { … }` global) : ce sélecteur ne s'applique que
     si le document a effectivement `<body class="theme-v19">`, ce qui
     préserve le comportement de scroll des 26 autres gabarits. `:has()`
     est supporté par tous les navigateurs évergreens depuis 2023-2024 ;
     en cas de navigateur trop ancien, le pire résultat possible est un
     simple scroll instantané au lieu d'un scroll fluide (dégradation
     sans casse).
   - Les !important conservés (repris de la référence, jamais ajoutés ici)
     sont documentés individuellement par un commentaire inline au fil du
     fichier (forme : "!important : raison"). ATTENTION en modifiant ce
     commentaire d'en-tête : ne jamais écrire une paire littérale slash-étoile
     ... étoile-slash à l'intérieur de ce bloc, même entre apostrophes — les
     commentaires CSS ne s'imbriquent pas, la première occurrence de
     étoile-slash le refermerait prématurément et casserait le bloc TOKENS
     juste en dessous (cause réelle du bug de couleurs/police constaté le
     2026-09-04 : ce commentaire d'en-tête se refermait à cet endroit précis,
     rendant tout le bloc body.theme-v19 { --ev-primary: ...; ... } invisible
     du navigateur alors que le fichier se chargeait avec un statut 200,
     sans la moindre erreur réseau).

   COMPOSANTS VOLONTAIREMENT NON PRIORITAIRES (conservés quand même,
   car sans coût puisqu'ils ne sont scopés que sous body.theme-v19 et
   ne s'affichent pas tant qu'ils ne sont pas insérés en HTML) :
   static-metrics, animated-counter, countdown-timer, pricing-structure,
   single-case-study, team-members, awards-distinctions,
   testimonials-certifications, video-presentation,
   #floating_google_review, #cookieConsent.
   ===================================================================== */

/* ============ TOKENS (fusion des 2 blocs :root de la référence) ============ */
body.theme-v19 {
  /* --- Système de grille & en-têtes de section (ex 1er bloc :root) --- */
  --ev-grid-min-width: 20rem;
  --ev-grid-preferred-width: 80%;
  --ev-grid-max-width: 88.75rem; /* 1420px : aligné sur groupecuratech.fr (même famille de template), 74rem (1184px) laissait trop de marge à partir de ~1280px d'écran */
  /* Fluide (clamp) plutôt que fixe : la valeur figée à 2.5rem/40px reprenait
     le gutter DESKTOP de groupecuratech.fr, mais leur .container n'a jamais
     40px fixe — vérifié en direct sur leur site (.intro__container) : ~20px
     en mobile (390px), qui grandit progressivement jusqu'à ~40px seulement
     à partir de --ev-grid-max-width. Chez nous le gutter fixe ne réduisait
     jamais en mobile, où il mangeait ~40px de chaque côté sur un écran de
     ~390px (~20% de la largeur à lui seul) — répété sur TOUTE section
     utilisant .container/.container-fluid/*__content (liste ci-dessous),
     cause structurelle du titre "Une finition pensée pour votre intérieur"
     cassé en 4 lignes vu précédemment, et plus largement de tout texte
     inutilement à l'étroit en mobile sur le site — repéré par l'utilisateur
     ("pas de container en mobile" chez curatech, capture à l'appui).
     Plafonne à 2.5rem/40px à partir de --ev-grid-max-width (88.75rem) :
     comportement desktop identique à l'ancienne valeur fixe au-delà de ce
     point, donc AUCUNE régression sur les captures desktop déjà vérifiées
     dans les sections précédentes (toutes prises à des largeurs ≥1420px). */
  --ev-grid-gutter: clamp(1.25rem, 0.75rem + 2vw, 2.5rem); /* ~20px (mobile) -> 40px (>=1420px) */
  --ev-grid-gap: var(--ev-grid-gutter);
  --ev-header-max-width: 75ch;
  --ev-eyebrow-color: var(--ev-primary, #2563eb);
  --ev-eyebrow-font-size: var(--ev-step--1, .8rem);
  --ev-eyebrow-font-weight: 700;
  --ev-eyebrow-letter-spacing: .08em;
  --ev-eyebrow-case: uppercase;
  --ev-eyebrow-margin-bottom: var(--ev-space-3xs, .25rem);
  --ev-btn-bg: var(--ev-primary, #2563eb);
  --ev-btn-color: #fff;
  --ev-btn-outline-color: var(--ev-primary, #2563eb);
  --ev-btn-border-radius: var(--ev-border-radius, 6px);
  --ev-btn-border-width: 1px;
  --ev-btn-padding-x: var(--ev-space-s, 1rem);
  --ev-btn-padding-y: var(--ev-space-2xs, .5rem);
  --ev-btn-font-family: inherit;
  --ev-btn-font-size: var(--ev-step-0, 1rem);
  --ev-btn-font-weight: 600;
  --ev-btn-line-height: normal;
  --ev-btn-letter-spacing: normal;
  --ev-btn-case: none;

  /* --- Palette, typo, ombres, échelles fluides (ex 2e bloc :root) ---
     !important sur les couleurs de marque : renfort demandé après
     plusieurs retours persistants de couleurs non conformes (orange/jaune
     au lieu du rouge/bleu marine V19) malgré une vérification exhaustive
     de la cascade (aucune règle globale --ev-primary trouvée avec !important
     ailleurs sur le site, aucune règle de spécificité supérieure identifiée).
     Élimine toute ambiguïté résiduelle de cascade sur ces variables précises. */
  --ev-primary: #c01010 !important;
  --ev-primary-rgb: 192, 16, 16 !important;
  /* Composantes HSL de --ev-primary (équivalent de #c01010), pour les thèmes
     qui reconstruisent une couleur via hsl(var(--ev-primary-hue), ...) au
     lieu de réutiliser --ev-primary directement (ex. objet.css, composant
     eva-section importé le 2026-09-14 : ses dégradés de bande/carte partent
     de ces 3 variables). root.css les définit (21.2 / 88.9% / 53.9% — soit
     #f26b21, le même orange générique que l'ancien --ev-primary, cf.
     commentaire ci-dessus) sans jamais être écrasées comme --ev-primary
     lui-même : d'où un dégradé orange -> rouge au lieu de rouge -> rouge. */
  --ev-primary-hue: 0 !important;
  --ev-primary-saturation: 85% !important;
  --ev-primary-lightness: 41% !important;
  --ev-accent: #7fb0e8 !important;
  --ev-accent-rgb: 127, 176, 232 !important;
  --ev-navy: #002050 !important;
  --ev-navy-rgb: 0, 32, 80 !important;
  --ev-navy-light: #103070;
  --ev-navy-deep: #001838;
  --ev-body-bg: #f4f6f8 !important;
  --ev-body-color: #22303f;
  --ev-text-color: #42526b;
  --ev-heading-color: #002050 !important;
  --ev-border-color: #e2e6ec;
  --ev-dark: #002050; /* dupliqué avec --ev-heading-color, repris tel quel (cf. audit §5) : les 2 noms sont utilisés par des règles différentes de la référence */
  --ev-dark-rgb: 0, 32, 80;
  --ev-light: #ffffff;

  /* Police : demande explicite du client (2026-09-04) d'utiliser les
     mêmes polices que la référence V19 — arbitrage du point B8
     (docs/theme-v19/06-points-a-arbitrer.md) tranché en faveur du
     changement. Space Grotesk (titres) / DM Sans (texte), chargées via
     Google Fonts (templates/home/index.html.twig, accueil uniquement,
     `<link rel="preconnect">` + feuille de style — pas d'`@import` CSS
     bloquant, cf. 01-etat-des-lieux.md §5 sur les CSS bloquants). Montserrat
     reste la police du reste du site (25 autres gabarits), inchangée. */
  --ev-heading-font-family: 'Space Grotesk', sans-serif;
  --ev-heading-font-weight: 700;
  --ev-heading-case: none;
  --ev-heading-line-height: 1.12;
  --ev-heading-letter-spacing: -0.02em;
  --ev-heading-margin-bottom: 0;
  --ev-text-font-family: 'DM Sans', sans-serif;
  --ev-text-line-height: 1.65;
  --ev-text-margin-bottom: 1rem;
  --ev-border-radius: 16px;
  --ev-shadow-sm: 0 2px 8px rgba(0, 32, 80, 0.08);
  --ev-shadow-lg: 0 24px 60px rgba(0, 32, 80, 0.18);
  --ev-step--2: clamp(0.7rem, 0.68rem + 0.1vw, 0.78rem);
  --ev-step--1: clamp(0.8rem, 0.77rem + 0.15vw, 0.89rem);
  --ev-step-0: clamp(1rem, 0.96rem + 0.2vw, 1.13rem);
  --ev-step-1: clamp(1.125rem, 1.08rem + 0.25vw, 1.35rem);
  --ev-step-2: clamp(1.27rem, 1.2rem + 0.35vw, 1.55rem);
  --ev-step-3: clamp(1.42rem, 1.32rem + 0.5vw, 1.75rem);
  --ev-step-4: clamp(1.6rem, 1.45rem + 0.75vw, 2.1rem);
  --ev-step-5: clamp(1.8rem, 1.6rem + 1vw, 2.25rem);
  --ev-step-6: clamp(2.1rem, 1.85rem + 1.25vw, 2.75rem);
  --ev-step-7: clamp(2.4rem, 2.05rem + 1.75vw, 3.5rem);
  --ev-step-8: clamp(2.75rem, 2.3rem + 2.25vw, 4.25rem);
  --ev-step-9: clamp(3.1rem, 2.5rem + 3vw, 5rem);
  --ev-step-10: clamp(3.5rem, 2.75rem + 3.75vw, 6rem);
  --ev-space-3xs: clamp(0.25rem, 0.23rem + 0.1vw, 0.31rem);
  --ev-space-2xs: clamp(0.5rem, 0.46rem + 0.2vw, 0.63rem);
  --ev-space-xs: clamp(0.75rem, 0.69rem + 0.3vw, 0.94rem);
  --ev-space-s: clamp(1rem, 0.93rem + 0.35vw, 1.25rem);
  --ev-space-s-m: clamp(1.25rem, 1.1rem + 0.6vw, 1.63rem);
  --ev-space-m: clamp(1.5rem, 1.3rem + 1vw, 2rem);
  --ev-space-l: clamp(2rem, 1.7rem + 1.5vw, 3rem);
  --ev-space-xl: clamp(3rem, 2.5rem + 2.5vw, 4.5rem);
  --ev-space-2xl: clamp(4rem, 3.3rem + 3.5vw, 6rem);
  --ev-space-3xl: clamp(5rem, 4rem + 5vw, 8rem);
}

/* ============ SYSTEM UI KIT (recopié verbatim) ============ */

body.theme-v19 .container{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
@media (min-width: 768px) {
  body.theme-v19 .container{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
}
body.theme-v19 .container-fluid{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .d-grid{ display: grid; gap: var(--ev-grid-gutter); }
body.theme-v19 .grid-column, body.theme-v19 .grid-header{
  grid-template-columns: repeat(var(--grid-columns-sm, 1), minmax(0, 1fr));
}
@media (min-width: 641px) {
  body.theme-v19 .grid-column, body.theme-v19 .grid-header{ grid-template-columns: repeat(var(--grid-columns-md, var(--grid-columns-sm, 1)), minmax(0, 1fr)); }
}
@media (min-width: 1025px) {
  body.theme-v19 .grid-column, body.theme-v19 .grid-header{ grid-template-columns: repeat(var(--grid-columns-lg, var(--grid-columns-md, var(--grid-columns-sm, 1))), minmax(0, 1fr)); }
}
body.theme-v19 .grid-column{ gap: var(--pb-gap, var(--ev-grid-gutter)) !important /* !important : gap toujours calé sur --pb-gap (variable de densité par section) plutôt que sur la valeur courte de .d-grid */; }
body.theme-v19 .grid-header{ gap: 0 var(--ev-grid-gap) !important /* !important : gap du header de grille toujours calé sur --ev-grid-gap, quel que soit un gap hérité */; }
body.theme-v19 .grid-title{ font-size: var(--ev-step-5, 2rem); font-weight: 700; color: var(--ev-heading-color, #222); margin: 0 0 var(--ev-space-2xs, .5rem); }
body.theme-v19 .grid-subtitle, body.theme-v19 .subtitle{ font-size: var(--ev-step-1, 1.125rem); font-weight: 500; color: var(--ev-text-color, #555); margin: 0 0 var(--ev-space-xs, .75rem); }
body.theme-v19 .grid-paragraph{ color: var(--ev-text-color, #555); }
body.theme-v19 .grid-description{ font-size: var(--ev-step-0, 1rem); font-weight: 400; color: var(--ev-text-color, #555); margin: 0; }
body.theme-v19 .grid-header-lead, body.theme-v19 .grid-header-aside{ display: flex; flex-direction: column; justify-content: flex-end; gap: var(--ev-space-2xs, .5rem); min-width: 0; }

body.theme-v19 figure{ margin: 0; }
body.theme-v19 .grid-image{ width: 100%; background: var(--ev-border-color, #e8e8e8); }
body.theme-v19 .grid-image img{ display: block; width: 100%; height: auto; }
body.theme-v19 .ratio-1x1, body.theme-v19 .ratio-3x2, body.theme-v19 .ratio-2x3{ overflow: hidden; }
body.theme-v19 .ratio-1x1 img, body.theme-v19 .ratio-3x2 img, body.theme-v19 .ratio-2x3 img, body.theme-v19 .ratio-1x1 .grid-image img, body.theme-v19 .ratio-3x2 .grid-image img, body.theme-v19 .ratio-2x3 .grid-image img{
  width: 100%; height: 100%; object-fit: cover; display: block;
}
body.theme-v19 .ratio-1x1{ aspect-ratio: 1 / 1; }
body.theme-v19 .ratio-3x2{ aspect-ratio: 3 / 2; }
body.theme-v19 .ratio-2x3{ aspect-ratio: 2 / 3; }
body.theme-v19 .grid-cta{ display: flex; align-items: center; gap: var(--ev-space-xs, .75rem); flex-wrap: wrap; }
body.theme-v19 .item-title{ font-weight: 600; color: var(--ev-heading-color, #222); margin: 0 0 .3em; }
body.theme-v19 .list-style-none{ list-style: none; margin: 0; padding: 0; }
body.theme-v19 a[class]:not(.btn){ text-decoration: none; color: currentColor; }
/* Le site (26 gabarits, hors sections V19) utilise DÉJÀ une classe `.icon`
   générique avec le même principe de masque, mais des noms de variable
   différents : --icon-svg (pas --icon-url) et --icon-width/--icon-height
   séparés (public/assets/css/style.css:5984). Comme body.theme-v19
   s'applique maintenant à tout le site, notre `.icon` (plus spécifique)
   prenait le dessus SANS reprendre --icon-svg : toute icône du CMS existant
   (chevron de sous-menu, loupe de recherche, téléphone, etc., aucune ne
   définissant --icon-url) perdait son masque et s'affichait comme un carré
   plein — constaté le 2026-09-07 sur le menu (chevrons, loupe). Corrigé en
   repliant sur --icon-svg/--icon-width quand nos propres variables ne sont
   pas définies : les icônes déjà utilisées ailleurs sur le site continuent
   de fonctionner à l'identique, sans rien changer pour les icônes propres
   aux sections V19 (qui définissent --icon-url via leur style inline). */
body.theme-v19 .icon{
  display: inline-block; flex: 0 0 auto;
  width: var(--icon-width, var(--icon-height, 20px)); height: var(--icon-height, 20px);
  background-color: var(--icon-color, currentColor);
  -webkit-mask-image: var(--icon-url, var(--icon-svg)); mask-image: var(--icon-url, var(--icon-svg));
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}
body.theme-v19 .icon--check-circle{ --icon-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M256 512a256 256 0 1 0 0-512 256 256 0 1 0 0 512zm113-303L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z'/%3E%3C/svg%3E"); }
/* style.css:6045 .icon--chevron-down pose un SVG SANS viewBox : sans lui,
   la taille intrinsèque de l'image (utilisée comme référence par
   mask-size:contain) tombe sur le comportement de repli du navigateur
   (300x150 par défaut) au lieu du path réel (dessiné dans un espace
   ~24x24) — le chevron s'affichait tronqué/à moitié coupé (repéré via
   capture par l'utilisateur devant "Gammes de produits"). Même path,
   viewBox='0 0 24 24' ajouté : override ciblé plutôt que modifier le
   fichier tiers partagé par les 26 gabarits. */
body.theme-v19 .icon--chevron-down{ --icon-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 16.75a.744.744 0 0 1-.53-.22l-7-7a.75.75 0 0 1 1.06-1.06L12 14.939l6.47-6.469a.75.75 0 0 1 1.06 1.06l-7 7a.744.744 0 0 1-.53.22z'/%3E%3C/svg%3E"); }
/* .icon--home n'a AUCUNE règle dans style.css (contrairement à
   icon--chevron-down, qui existait mais était mal formé) : l'icône se
   rendait en carré plein, d'où le repli sur le texte "Accueil" par le
   passé (cf. commentaire historique dans nav.html.twig). Ajouté ici,
   même principe que les autres icônes (masque SVG + currentColor via
   --icon-color/background-color hérité de .icon). */
body.theme-v19 .icon--home{ --icon-width: 18px; --icon-height: 18px; --icon-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11.47 3.84a.75.75 0 0 1 1.06 0l8.69 8.69a.75.75 0 1 0 1.5-1.5l-8.69-8.69a2.25 2.25 0 0 0-3.36 0L2.34 10.5a.75.75 0 0 0 1.06 1.06l8.07-8.07z'/%3E%3Cpath d='M12 5.432l8.159 8.159c.03.03.06.058.091.086v6.198a1.875 1.875 0 0 1-1.875 1.875H15a.75.75 0 0 1-.75-.75v-4.5a.75.75 0 0 0-.75-.75h-3a.75.75 0 0 0-.75.75V21a.75.75 0 0 1-.75.75H5.625a1.875 1.875 0 0 1-1.875-1.875v-6.198c.031-.028.06-.056.091-.086L12 5.432z'/%3E%3C/svg%3E"); }
/* Pas de background-color codée en dur sur l'icône (ex-version : marine
   fixe, rouge au survol) : style.min.css bascule déjà TOUT nav-link en
   blanc au survol/à l'état actif (`.nav-item:hover .nav-link,
   .nav-item.active .nav-link{ color:#fff !important }`, pastille sombre
   derrière). L'icône .icon retombe sur currentColor par défaut (règle de
   base plus haut dans ce fichier) : elle suit donc automatiquement cette
   même couleur (marine au repos, blanc au survol/actif, cohérent avec
   tous les autres liens texte du menu) sans règle dédiée. Repéré :
   l'ancienne version forçait du rouge au survol, peu lisible sur la
   pastille sombre de l'état actif — l'utilisateur voulait du blanc. */
body.theme-v19 .nav-link--home{ display: inline-flex; align-items: center; justify-content: center; }
body.theme-v19 .icon--scrollup{ --icon-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12.7 12.5c-.4-.4-1-.4-1.4 0l-3 3c-.4.4-.4 1 0 1.4s1 .4 1.4 0l2.3-2.3 2.3 2.3c.2.2.4.3.7.3s.5-.1.7-.3c.4-.4.4-1 0-1.4zm-3-1L12 9.2l2.3 2.3c.2.2.4.3.7.3s.5-.1.7-.3c.4-.4.4-1 0-1.4l-3-3c-.4-.4-1-.4-1.4 0l-3 3c-.4-.4.4-1 0 1.4.4.3 1 .3 1.4 0z'/%3E%3C/svg%3E"); }
body.theme-v19 .btn{
  display: inline-flex; align-items: center; justify-content: center; gap: .5em; text-decoration: none; cursor: pointer;
  font-family: var(--ev-btn-font-family); font-size: var(--ev-btn-font-size); font-weight: var(--ev-btn-font-weight);
  line-height: var(--ev-btn-line-height); letter-spacing: var(--ev-btn-letter-spacing); text-transform: var(--ev-btn-case);
  padding: var(--ev-btn-padding-y) var(--ev-btn-padding-x); border-radius: var(--ev-btn-border-radius);
  border: var(--ev-btn-border-width) solid transparent;
  transition: transform .18s ease, box-shadow .18s ease, filter .18s ease, background .18s ease, border-color .18s ease;
}
body.theme-v19 .btn:focus-visible{ outline: 2px solid var(--ev-btn-bg); outline-offset: 2px; }
body.theme-v19 .btn:disabled, body.theme-v19 .btn[aria-disabled="true"]{ opacity: .55; cursor: not-allowed; transform: none !important /* !important : empêche toute translation resurgissant d'un :hover en cours une fois le bouton désactivé */; }
body.theme-v19 .btn-primary{
  background: linear-gradient(135deg, var(--ev-btn-bg), color-mix(in srgb, var(--ev-btn-bg) 100%, black 16%)) !important; /* !important : renfort couleur, voir bloc TOKENS plus haut */
  /* border-color posée en UNE seule teinte plate (--ev-btn-bg, le ton le
     plus clair du dégradé) sur un fond en dégradé diagonal 135deg (clair
     en haut-gauche, ~16% plus sombre en bas-droite) : le contour reste à
     la teinte claire tout le tour du bouton, alors que le fond juste en
     dessous s'assombrit progressivement — liseré clair bien visible en
     zoomant sur les coins arrondis droit/gauche (repéré par l'utilisateur,
     capture à l'appui, "bug d'affichage"). transparent : le dégradé seul
     dessine le contour du bouton, sans liseré qui ne peut de toute façon
     pas suivre un dégradé diagonal avec une seule couleur plate. Même
     cause sur .navbar-cta .btn-secondary plus bas dans ce fichier (même
     dégradé + bordure plate) — demande explicite "partout". */
  border-color: transparent !important; color: var(--ev-btn-color) !important;
  /* Portage initial identique à la référence : box-shadow: 0 10px 24px -6px
     color-mix(in srgb, var(--ev-btn-bg) 55%, transparent). Remplacé le
     2026-09-07 : ce color-mix() dans un box-shadow à spread négatif produit
     une entaille blanche visible sur le coin du bouton (constatée et
     reproduite avec un vrai navigateur, y compris hors de cet environnement
     de test), un défaut déjà présent dans la référence elle-même. rgba()
     classique = même effet de halo, sans ce problème de rendu. */
  box-shadow: 0 10px 24px -6px rgba(var(--ev-primary-rgb), 0.55);
}
/* Effet au survol, absent jusqu'ici sur TOUT bouton .btn-primary du site
   (vérifié : aucun ne changeait à part le curseur — seuls 2 boutons très
   spécifiques, .countdown-timer/.video-presentation__action, avaient leur
   propre survol dédié). Repéré par l'utilisateur en comparant "Une autre
   question ?" (FAQ accueil) à "Contactez-nous" (section suivante) : les
   deux sont en réalité un seul et même composant, à l'octet près (aucune
   différence de CSS trouvée) — ce qui manquait, c'était un survol sur le
   bouton lui-même, nulle part sur le site. `transform`/`box-shadow` sont
   déjà dans la liste `transition` de .btn (ligne ~291) : ce survol se
   greffe simplement dessus. Légère élévation + ombre renforcée, cohérent
   avec `.btn:disabled{ transform:none!important }` déjà en place pour ne
   jamais lever un bouton désactivé. */
body.theme-v19 .btn-primary:hover, body.theme-v19 .btn-primary:focus-visible{
  transform: translateY(-2px);
  box-shadow: 0 16px 30px -6px rgba(var(--ev-primary-rgb), 0.65);
}
body.theme-v19 .btn-outline-primary{
  background: transparent !important; border-color: var(--ev-btn-outline-color) !important; color: var(--ev-btn-outline-color) !important;
}
/* Échelle de tailles cohérente pour TOUT le site (h1..h6, p) : reprend les
   valeurs déjà utilisées par style.css (h1:--ev-step-5 ... h6:--ev-step--1,
   même jetons --ev-step-*), mais posée ici explicitement plutôt que
   déléguée à ce fichier tiers — audit du 2026-09-07 (tailles réellement
   rendues, mesurées en navigateur). RÉGRESSION CORRIGÉE LE 2026-09-07 :
   la première version de ce bloc posait `body.theme-v19 h2{font-size:...}`
   (spécificité 0,1,1) — plus fort qu'une classe seule (0,1,0). Beaucoup de
   contenu réel (CMS + templates) utilise le pattern "balise sémantique +
   classe de taille visuelle" (ex. `<h2 class="title h4">` pour un titre de
   carte d'article, `<h3 class="label label-secondary">` pour un badge de
   catégorie) : style.css liste ces règles dans un ordre précis (h1 puis .h1
   puis h2 puis .h2...) pour qu'à spécificité égale, la classe l'emporte sur
   la balise. Notre règle plus spécifique cassait ce mécanisme et forçait
   CES ÉLÉMENTS à la taille de leur balise réelle plutôt que celle voulue —
   d'où des titres de carte et des badges anormalement gros, repéré par
   l'utilisateur sur /articles/{type}. `:where(...)` ramène la spécificité
   de tout le sélecteur à 0 : la règle ne sert plus que de filet de sécurité
   quand AUCUNE classe de taille ne s'applique (elle perd alors face à
   .h4/.label-secondary/etc., comme le fait déjà la règle historique de
   style.css). Les classes de composant (.grid-title, .page-hero__title...)
   restent prioritaires comme avant. */
body.theme-v19 h1, body.theme-v19 h2, body.theme-v19 h3, body.theme-v19 h4, body.theme-v19 h5, body.theme-v19 h6{
  font-family: var(--ev-heading-font-family); font-weight: var(--ev-heading-font-weight);
  line-height: var(--ev-heading-line-height); letter-spacing: var(--ev-heading-letter-spacing); text-transform: var(--ev-heading-case);
  margin: 0 0 var(--ev-heading-margin-bottom);
}
/* `color` isolé du bloc ci-dessus, même raison que le passage de font-size
   en :where() juste au-dessus (même régression du 2026-09-07, seul
   font-size avait été corrigé sur le coup) : `body.theme-v19 h2{color:...}`
   (spécificité 0,1,1) l'emportait sur des composants CMS qui posent leur
   propre couleur de titre via une simple classe (0,1,0) — ex.
   `.color-palette__title{ color:#fff }` (objet.css, section "Une finition
   pensée pour votre intérieur"), sur fond sombre : le titre héritait de la
   couleur marine par défaut des titres, quasi invisible sur ce fond
   (repéré par l'utilisateur, capture à l'appui). */
:where(body.theme-v19 h1, body.theme-v19 h2, body.theme-v19 h3, body.theme-v19 h4, body.theme-v19 h5, body.theme-v19 h6){ color: var(--ev-heading-color); }
:where(body.theme-v19 h1){ font-size: var(--ev-step-5); }
:where(body.theme-v19 h2){ font-size: var(--ev-step-4); }
:where(body.theme-v19 h3){ font-size: var(--ev-step-3); }
:where(body.theme-v19 h4){ font-size: var(--ev-step-2); }
:where(body.theme-v19 h5){ font-size: var(--ev-step-1); }
:where(body.theme-v19 h6){ font-size: var(--ev-step--1); }
body.theme-v19 p{
  font-family: var(--ev-text-font-family); line-height: var(--ev-text-line-height);
  margin: 0 0 var(--ev-text-margin-bottom, 1rem);
}
/* Isolé en :where() pour la même raison que h1..h6 juste au-dessus (utile
   contre une classe de composant qui viserait directement le <p> avec une
   spécificité plus faible) — mais ne suffit PAS seul contre .color-palette__
   description{ color:#bdbdbd } (objet.css) juste en dessous : une valeur
   DIRECTEMENT posée sur l'élément (même à spécificité nulle via :where())
   l'emporte toujours sur une valeur seulement HÉRITÉE du parent, quelle que
   soit la spécificité de cette dernière — le <p> matche "body.theme-v19 p"
   directement, donc gagne face à la couleur seulement héritée de
   .color-palette__description. Texte quasi illisible (bleu-gris sombre sur
   fond presque noir), repéré par l'utilisateur, capture à l'appui. */
:where(body.theme-v19 p){ color: var(--ev-text-color); }
/* --ev-step-0 (16-18px) donnait un corps de texte plus gros que
   groupecuratech.fr (même famille de template, référence explicite de
   l'utilisateur) : vérifié en direct sur leur site, un <p> de contenu y
   fait 16px en desktop et descend à ~14px en mobile (fluide), contre 18px
   / 16px fixe chez nous (--ev-step-0 ne descend jamais sous 1rem, quelle
   que soit l'étroitesse de l'écran) — repéré par l'utilisateur ("un peu
   grande"). Clamp dédié aux paragraphes plutôt que de modifier
   --ev-step-0 : ce token sert aussi ailleurs (boutons, labels, nav —
   20 usages dans ce fichier), le changer aurait un effet de bord bien
   plus large que "les textes dans les paragraphes". */
:where(body.theme-v19 p){ font-size: clamp(0.875rem, 0.84rem + 0.2vw, 1rem); }
body.theme-v19 .color-palette__description p{ color: inherit; }
/* Cartes de teinte ("Blanc", "Bordeaux", "Gris tourterelle", "Noir") :
   le `min-height:2lh` posé ici forçait TOUJOURS 2 lignes de hauteur sous le
   libellé, même quand la carte est large (layout horizontal ci-dessous) et
   que le nom tient sur 1 seule ligne — grand vide entre le libellé et la
   description ("Bordeaux" / "Finition profonde"), repéré par l'utilisateur
   (capture, écart marqué d'une flèche). Cette réserve datait d'un layout
   bien plus étroit (carte 174px de large d'origine, puis carte verticale
   ensuite) où un nom sur 2 lignes était courant ; en carte horizontale
   large, le texte a la place de tenir sur 1 ligne dans la quasi-totalité
   des cas. Le `min-height` est retiré ; le `line-clamp` reste en garde-fou
   pur (coupe un nom exceptionnellement long à 2 lignes sans jamais
   dépasser), et la grille (`display:grid`) égalise déjà la hauteur des
   cartes d'une même rangée si l'une d'elles venait à réellement wrapper. */
body.theme-v19 .color-palette__label{
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Cartes de teinte : la 1re version (carte verticale, pastille en haut /
   texte en dessous, ex-commentaire ci-dessus) réglait le manque de place
   d'origine (174px de large, texte contraint à 2 lignes), mais une fois
   passé à 2 colonnes desktop (voir plus bas) la carte s'est retrouvée
   ~345px de large pour un contenu qui n'en occupe qu'une petite partie —
   grand vide à droite du texte, repéré par l'utilisateur (capture, croix
   rouges). Repassé en carte HORIZONTALE (pastille à gauche, texte à
   droite en `flex:1`) : le texte occupe toute la largeur restante de la
   carte, plus de vide, et la carte redevient compacte en hauteur (elle ne
   dépend plus que de la hauteur du texte, ~120px au lieu de ~280px). */
body.theme-v19 .color-palette__item{
  flex-direction: row;
  align-items: center;
  gap: var(--ev-space-m);
  padding: var(--ev-space-s-m);
}
body.theme-v19 .color-palette__swatch{
  width: 56px;
  height: 56px;
  flex-shrink: 0;
}
body.theme-v19 .color-palette__text{ flex: 1 1 auto; min-width: 0; width: auto; }
body.theme-v19 .color-palette__grid{ gap: var(--ev-space-s); }
/* Petite touche de couleur template sur les cartes blanches (accord avec
   l'utilisateur) : pas d'effet hover/sélection, ces cartes n'ont aucun
   comportement cliquable (aucun handler JS, pas de <button>/<a>, aucune
   liaison au formulaire de devis, vérifié dans public/assets/js) — un
   style "sélectionnable" serait trompeur. À la place : liseré supérieur
   fin en --ev-primary (même logique que le trait rouge du kicker
   juste au-dessus) pour rattacher la carte à l'identité de la marque sans
   jamais concurrencer les pastilles de couleur produit elles-mêmes, + une
   ombre douce pour les détacher du fond navy plutôt que de rester des
   blocs plats posés directement dessus. */
body.theme-v19 .color-palette__item{
  border-top: 3px solid var(--ev-primary);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
}
/* Sous 600px, la grille repasse à 1 colonne mais reste étroite (~155px de
   large une fois les paddings du bloc + du container retranchés du
   viewport mobile) : la carte horizontale ci-dessus n'a plus la place
   pour la pastille (56px figée) + le texte, qui déborde ("Finition
   lumineuse" ne peut pas descendre sous ~155px de large) — vérifié en
   375px, `grid.scrollWidth` (207px) dépassait `grid.clientWidth` (155px).
   Carte reposée en colonne (pastille au-dessus, texte en dessous en
   pleine largeur) uniquement sur ce palier, où la largeur disponible en
   hauteur ne manque pas. */
@media (width < 600px) {
  body.theme-v19 .color-palette__item{ flex-direction: column; align-items: flex-start; }
  body.theme-v19 .color-palette__text{ width: 100%; flex: none; }
}
/* Libellé du kicker "PERSONNALISATION" : objet.css le pose en
   var(--ev-primary) (rouge), lisible sur l'ancien fond de section blanc
   mais illisible sur le fond --ev-navy posé ci-dessous — repéré par
   l'utilisateur (capture). Le petit trait ::before reste rouge (accent),
   seul le texte passe en blanc. */
body.theme-v19 .color-palette__kicker{ color: #fff; }
/* Fond de la section : #18171c (objet.css) est un gris anthracite posé au
   hasard, sans lien avec les couleurs de la template (uniquement --ev-navy
   #002050, --ev-primary #c01010, --ev-light blanc) — repéré par
   l'utilisateur ("pourquoi t'as mis le design en noir ?"). Remplacé par
   --ev-navy, déjà utilisé comme fond sombre ailleurs dans le thème
   (.animated-counter, .final-cta) : le texte/bouton en blanc posé plus haut
   reste lisible (contraste équivalent à l'ancien fond quasi noir). */
body.theme-v19 .color-palette{ background: var(--ev-navy); }
/* Double padding horizontal, catastrophique en mobile : objet.css pose
   `padding: var(--ev-space-l) var(--ev-space-m)` sur .color-palette (donc
   aussi de l'horizontal) PUIS `.color-palette__container` rajoute encore
   `padding-inline: var(--ev-grid-gutter)` (2.5rem = 40px fixe, non fluide)
   par-dessus — les deux s'additionnent. Sur mobile (~375px), ça ne
   laissait que ~170px de large pour le titre H2, qui retombait sur 4
   lignes d'1-2 mots ("Une finition / pensée pour / votre / intérieur"),
   rendu illisible et disproportionné — repéré par l'utilisateur (capture,
   "catastrophique"). Comparé à .callout-color-bg (même thème, même
   schéma carte+container) qui ne pose QUE du padding-block sur l'élément
   extérieur et laisse `__container` gérer seul le padding horizontal :
   .color-palette suit maintenant la même convention, avec
   --ev-grid-gutter (déjà utilisé par .container partout ailleurs dans le
   site, y compris la homepage) comme unique source d'inset horizontal. */
body.theme-v19 .color-palette{ padding-inline: 0; }
/* Grille desktop : objet.css passe à 4 colonnes dès 993px, ce qui écrase
   les cartes (désormais plus grandes, cf. ci-dessus) à ~163px de large dans
   la colonne de contenu article (~830-900px) — demande explicite de
   l'utilisateur (2 par ligne en desktop). Cartes ~2x plus larges, mieux
   proportionnées avec la pastille 56px + texte empilé. */
@media (min-width: 993px) {
  body.theme-v19 .color-palette__grid{ grid-template-columns: repeat(2, 1fr); }
}
body.theme-v19 .eyebrow{
  display: block; color: var(--ev-eyebrow-color); font-size: var(--ev-eyebrow-font-size);
  font-weight: var(--ev-eyebrow-font-weight); letter-spacing: var(--ev-eyebrow-letter-spacing);
  text-transform: var(--ev-eyebrow-case); margin-bottom: var(--ev-eyebrow-margin-bottom);
}
/* La mise en ligne horizontale de .navbar-nav (flex-direction:row) ne
   s'applique qu'à partir de 1800px, cf. plus bas dans le fichier (section
   HEADER / NAV) — en dessous, le panneau .navbar-collapse s'ouvre en menu
   déroulant vertical (comportement mobile standard), pas de forçage ici. */

/* templates/vitrine/includes/_sidebar_cta.html.twig rend cette structure
   (`.sidebar-cta__button` > `.btn` + `.sidebar-cta__button-text`), 3
   boutons réels (Devis, Contact, Téléphone — cf. commentaire du twig pour
   l'origine de ce contenu). Contrairement à la version précédente (V19
   verbatim, 4 boutons dont un placeholder masqué en 1er enfant), les 3
   boutons ici sont tous réels : plus de règle `:first-child{display:none}`.
   Point relevé par l'audit (docs/theme-v19/02-inventaire-v19-verifie.md §2.1
   G3) : `.custom-tooltip` (ci-dessous) n'est jamais instancié par aucun des
   12 scripts de la référence — la maquette source n'a donc pas de tooltip
   fonctionnel au survol. Un petit ajout `::before` (hors périmètre de la
   référence, cf. règle `[data-tooltip]::before` un peu plus bas) fournit un
   tooltip 100% CSS pour ne pas reproduire cette lacune. */
body.theme-v19 .sidebar-cta{ position: fixed; right: 0px; top: 30%; margin-top: -90px; display: grid; gap: var(--ev-space-s); z-index: 999; }
/* public/assets/css/objet.css (généré depuis ftp/csv/objet.csv, widget
   NOBIS d'origine #sidebar-cta-16086) pose `.sidebar-cta .icon{
   --icon-color: var(--ev-heading-color) }` à partir de 768px — notre
   #sidebar_cta réutilise le même nom de classe `.sidebar-cta` que ce
   widget désactivé, donc en hérite : icônes marine (perçues "bleu" par
   l'utilisateur) sur un bouton plein rouge, au lieu du blanc attendu.
   Sélecteur #id, plus spécifique qu'une classe seule, pour reprendre la
   main sans toucher au fichier généré. */
body.theme-v19 #sidebar_cta .icon{ --icon-color: #fff; }
body.theme-v19 .sidebar-cta .btn{ padding: var(--ev-space-s); border-top-right-radius: 0; border-bottom-right-radius: 0; }
body.theme-v19 .sidebar-cta__button-text{ display: none; }
body.theme-v19 .custom-tooltip{ display: block; position: absolute; background-color: rgba(var(--ev-dark-rgb), .75); color: #fff; padding: var(--ev-space-2xs) var(--ev-space-xs); border-radius: 4px; font-size: var(--ev-step--1); pointer-events: none; white-space: nowrap; z-index: 1000; }
body.theme-v19 .custom-tooltip::after{ content: ""; position: absolute; border-style: solid; }
body.theme-v19 .custom-tooltip[data-placement="top"]::after{ border-width: 5px 5px 0 5px; border-color: rgba(var(--ev-dark-rgb), .75) transparent transparent transparent; top: 100%; left: 50%; transform: translateX(-50%); }
body.theme-v19 .custom-tooltip[data-placement="bottom"]::after{ border-width: 0 5px 5px 5px; border-color: transparent transparent rgba(var(--ev-dark-rgb), .75) transparent; bottom: 100%; left: 50%; transform: translateX(-50%); }
body.theme-v19 .custom-tooltip[data-placement="left"]::after{ border-width: 5px 5px 5px 0; border-color: transparent rgba(var(--ev-dark-rgb), .75) transparent transparent; left: 100%; top: 50%; transform: scaleX(-1) translateY(-50%); }
body.theme-v19 .custom-tooltip[data-placement="right"]::after{ border-width: 5px 0 5px 5px; border-color: transparent transparent transparent rgba(var(--ev-dark-rgb), .75); right: 100%; top: 50%; transform: translateY(-50%); }
@media (width < 768px) {
  body.theme-v19 .sidebar-cta .btn{ border-radius: 0; }
  body.theme-v19 .sidebar-cta .btn::before, body.theme-v19 .sidebar-cta .btn::after{ content: unset; }
  body.theme-v19 .sidebar-cta__button-text{ display: block; font-weight: 600; }
  body.theme-v19 .sidebar-cta__button[data-mobile-display="hide"], body.theme-v19 .custom-tooltip{ display: none; }
  body.theme-v19 .sidebar-cta{
    display: flex; top: unset; left: 0; width: 100%; place-content: stretch; background: var(--ev-primary);
    bottom: 0; height: fit-content; box-shadow: 0 -8px 24px rgba(0, 0, 0, .18);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  /* 2 boutons restants (Devis / Contact) : chacun occupe la moitié de la
     largeur, comme les 2 CTA pleine largeur de la référence groupecuratech.fr,
     séparés par un léger liseré plutôt qu'un espace vide. `.sidebar-cta > *`
     (form-theme.css, pensé pour l'ancien widget NOBIS #sidebar-cta-16086)
     pose déjà un `border-left: var(--ev-border-color)` (gris) sur TOUS les
     enfants, 1er compris — repris ici en blanc translucide, et neutralisé
     sur le 1er bouton (bord gauche collé à l'écran, aucun repère à séparer). */
  body.theme-v19 .sidebar-cta__button{ flex: 1 1 0; border-left: 0; }
  body.theme-v19 .sidebar-cta__button:not(:first-child){ border-left: 1px solid rgba(255, 255, 255, .25); }
  body.theme-v19 .sidebar-cta .btn{ display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; min-height: 52px; }
  body.theme-v19 .sidebar-cta .icon{ display: none; }
}

body.theme-v19 .floating-google-review{
  position: fixed;
  z-index: 999;
  left: 1rem;
  bottom: 1rem;
  background: #fff;
  padding: .8rem .85rem .75rem;
  border: 1px solid var(--ev-border-color, #e2e6ec);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 32, 80, 0.12);
  transition: opacity .2s ease, transform .2s ease, visibility .2s ease;
}
/* .is-hidden posée par hide-review-badge-near-footer.js dès que le pied de
   page entre dans le viewport : évite le chevauchement avec son contenu
   en bas de page (raison initiale de la désactivation de ce badge, cf.
   commentaire dans base.html.twig). */
body.theme-v19 .floating-google-review.is-hidden{
  opacity: 0; transform: translateY(8px); visibility: hidden; pointer-events: none;
}
body.theme-v19 .floating-google-review__content{ display: grid; place-items: center; gap: .45rem; }
body.theme-v19 .floating-google-review__logo{
  margin: 0;
  display: flex;
  align-items: center;
  gap: .35rem;
  border: 1px solid var(--ev-border-color, #e2e6ec);
  border-radius: 100vmax;
  padding: .3rem .55rem .3rem .38rem;
  white-space: nowrap;
  width: fit-content;
  background: #fff;
}
body.theme-v19 .floating-google-review__logo img{ height: 24px; width: 24px; }
body.theme-v19 .floating-google-review figcaption{
  line-height: 1;
  margin: 0;
  font-family: var(--ev-heading-font-family);
  font-size: 1rem;
  font-weight: 700;
  color: var(--ev-heading-color);
}
body.theme-v19 .floating-google-review__stars-wrapper{ display: flex; align-items: center; justify-content: center; min-height: 20px; }
body.theme-v19 .floating-google-review__stars{ display: flex; align-items: center; gap: 2px; }
body.theme-v19 .floating-google-review__star{
  position: relative;
  display: inline-block;
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  color: #d9dee7;
}
body.theme-v19 .floating-google-review__star > svg, body.theme-v19 .floating-google-review__star-fill > svg{ width: 18px; height: 18px; display: block; }
body.theme-v19 .floating-google-review__star-fill{
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--fill, 0%);
  overflow: hidden;
  color: #f5b942;
  transition: width .25s ease;
}
body.theme-v19 .floating-google-review__number{ font-size: var(--ev-step--1); }
body.theme-v19 .floating-google-review a{ text-decoration: none; font-weight: 600; color: var(--ev-text-color, #42526b); }
body.theme-v19 .floating-google-review a:hover{ text-decoration: underline; color: var(--ev-primary); }
body.theme-v19 .floating-google-review img{ object-fit: contain; }
/* Seuil aligné sur celui de #sidebar_cta (`width < 768px`, plus haut dans ce
   fichier), qui devient à cette largeur une barre fixe pleine largeur
   ~52px+ : un seuil différent ici (599px à l'origine) laissait un
   entre-deux 599-768px où le badge (bottom:1rem de base) se retrouvait
   partiellement masqué derrière cette barre. */
@media (width < 768px) {
  body.theme-v19 .floating-google-review{ left: .5rem; bottom: calc(52px + env(safe-area-inset-bottom, 0px) + .75rem); padding: .7rem .75rem; transform: none; }
  body.theme-v19 .floating-google-review__content{ gap: .35rem; }
  body.theme-v19 .floating-google-review__logo{ padding: .25rem .5rem .25rem .35rem; }
  body.theme-v19 .floating-google-review__star{ width: 16px; height: 16px; flex-basis: 16px; }
  body.theme-v19 .floating-google-review__star > svg, body.theme-v19 .floating-google-review__star-fill > svg{ width: 16px; height: 16px; }
  body.theme-v19 .floating-google-review__number{ font-size: .75rem; }
}

body.theme-v19 .carousel-google-review{ overflow: hidden; }
body.theme-v19 .carousel-google-review__body{ position: relative; margin-top: var(--ev-grid-gutter); }
body.theme-v19 .carousel-google-review__item-text{ padding: var(--ev-space-s-m); }
body.theme-v19 .carousel-google-review__item-description-content{ font-size: var(--ev-step--1); margin-block: 0; -webkit-box-orient: vertical; -webkit-line-clamp: var(--max-line, 4); display: -webkit-box; overflow: hidden; }
body.theme-v19 .carousel-google-review__item-title:hover{ cursor: pointer; text-decoration: underline; }
body.theme-v19 .carousel-google-review__item-title{ grid-area: title; }
body.theme-v19 .carousel-google-review__item .google-logo{ grid-area: google-logo; }
body.theme-v19 .carousel-google-review__item-description{ grid-area: description; }
body.theme-v19 .carousel-google-review__item-rating{ grid-area: rating; }
body.theme-v19 .carousel-google-review__item{ position: relative; display: grid; gap: var(--ev-space-xs); grid-template-areas: "rating google-logo" "description description"; grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; perspective: 1000px; width: 100%; height: 100%; }
body.theme-v19 .carousel-google-review .link-primary{ display: inline-block; font-size: var(--ev-step--1); margin-top: var(--ev-space-xs); color: var(--ev-heading-color) !important /* !important : force la couleur du lien même si un style de lien générique (CMS) redéfinit `color` */; }
body.theme-v19 .carousel-google-review__title{ grid-column: 1; }
body.theme-v19 .carousel-google-review__header .btn-primary{ grid-column: 1; width: fit-content; margin-block: var(--ev-space-s); }
@media (width > 768px) { body.theme-v19 .carousel-google-review__description{ grid-row: 2/4; grid-column: 2; } }
body.theme-v19 .carousel-google-review__details, body.theme-v19 .carousel-google-review__item{ padding: var(--ev-space-m); background: var(--ev-light, #f5f5f5); border-color: transparent; border-radius: var(--ev-border-radius); border-inline: hidden; }
body.theme-v19 .carousel-google-review__rating.d-grid{ grid-template-areas: "img count count" "img score stars"; column-gap: 6px; }
body.theme-v19 .carousel-google-review__image{ display: grid; place-content: center; border: 1px solid var(--ev-border-color); border-radius: 100vmax; background: white !important /* !important : fond blanc du badge Google garanti même sur un fond de section coloré */; margin-bottom: 0; padding: var(--ev-space-2xs); aspect-ratio: 1/1; }
body.theme-v19 .carousel-google-review__rating img{ height: 32px; }
body.theme-v19 .carousel-google-review__item img{ height: 20px; }
body.theme-v19 .carousel-google-review__details{ display: flex; place-content: space-between; gap: var(--ev-grid-gutter, 1rem); flex-wrap: wrap; align-items: center; }
body.theme-v19 .carousel-google-review__score.grid-score{ grid-area: score; font-weight: var(--ev-heading-font-weight); font-size: var(--ev-step-3); line-height: 1; }
body.theme-v19 .carousel-google-review__stars.grid-stars{ grid-area: stars; align-self: center; }
body.theme-v19 .carousel-google-review__stars{ display: flex; }
body.theme-v19 .carousel-google-review__count.grid-count{ grid-area: count; }
body.theme-v19 .carousel-google-review__rating .icon{ --icon-height: 24px; }
body.theme-v19 .carousel-google-review__item .item-title{ font-size: var(--ev-step-1); margin-bottom: var(--ev-space-3xs); }
body.theme-v19 .carousel-google-review__item .icon{ --icon-height: 20px; }
body.theme-v19 .carousel-google-review .swiper-button-next, body.theme-v19 .carousel-google-review .swiper-button-prev{ background-color: rgba(var(--ev-dark-rgb), 70%); padding: var(--ev-space-xs); color: white !important /* !important : neutralise les classes .swiper-button-* par défaut si Swiper est un jour chargé sur cette page */; display: none; position: absolute !important /* !important : neutralise les classes .swiper-button-* par défaut si Swiper est un jour chargé sur cette page */; width: fit-content !important /* !important : neutralise les classes .swiper-button-* par défaut si Swiper est un jour chargé sur cette page */; height: fit-content !important /* !important : neutralise les classes .swiper-button-* par défaut si Swiper est un jour chargé sur cette page */; top: 50% !important /* !important : neutralise les classes .swiper-button-* par défaut si Swiper est un jour chargé sur cette page */; }
body.theme-v19 .carousel-google-review__body:hover .swiper-button-next, body.theme-v19 .carousel-google-review__body:hover .swiper-button-prev{ display: block; }
body.theme-v19 .carousel-google-review .swiper-button-prev{ left: 0 !important /* !important : idem : override de position Swiper par défaut */; right: unset !important /* !important : idem : override de position Swiper par défaut */; }
body.theme-v19 .carousel-google-review .swiper-button-next{ left: unset !important /* !important : idem : override de position Swiper par défaut */; right: 0 !important /* !important : idem : override de position Swiper par défaut */; }

body.theme-v19 .cookie-consent{
  display: none;
  position: fixed;
  z-index: 1000;
  left: var(--ev-space-s, 1rem);
  right: var(--ev-space-s, 1rem);
  bottom: var(--ev-space-s, 1rem);
  max-width: var(--ev-grid-max-width, 62rem);
  margin-inline: auto;
  background: var(--ev-body-bg, #fff);
  color: var(--ev-body-color, #222);
  border: 1px solid var(--ev-border-color, #e8e8e8);
  border-radius: var(--ev-border-radius, 10px);
  box-shadow: var(--ev-shadow-lg, 0 20px 44px rgba(0,0,0,.16));
  font-size: var(--ev-step--1);
}
body.theme-v19 .cookie-content{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-rows: auto auto;
  grid-template-areas: "img title actions close" "img text actions close";
  align-items: center;
  column-gap: var(--ev-space-s, 1rem);
  padding: var(--ev-space-s, 1rem) var(--ev-space-m, 1.5rem);
}
body.theme-v19 .cookie-image{ grid-area: img; width: 40px; height: 40px; border-radius: var(--ev-border-radius, 8px); overflow: hidden; margin: 0; }
body.theme-v19 .cookie-image img{ width: 100%; height: 100%; object-fit: cover; display: block; }
@media (width < 640px) { body.theme-v19 .cookie-image{ display: none; } }
body.theme-v19 .cookie-header{ grid-area: title; }
body.theme-v19 .cookie-title{ margin: 0; font-family: var(--ev-heading-font-family); font-size: var(--ev-step-0); font-weight: 700; color: var(--ev-primary, #2563eb); }
body.theme-v19 .cookie-text{ grid-area: text; }
body.theme-v19 .cookie-consent p, body.theme-v19 .cookie-description{ margin-block: 0; font-size: var(--ev-step--1); }
body.theme-v19 .cookie-link{ margin-inline-start: var(--ev-space-3xs, .25rem); display: inline-block; white-space: nowrap; }
body.theme-v19 .cookie-link:hover{ text-decoration-line: underline !important /* !important : soulignement du lien cookie forcé même si un style de lien générique le supprime */; text-decoration-style: dashed !important /* !important : soulignement du lien cookie forcé même si un style de lien générique le supprime */; text-underline-offset: 3px; }
body.theme-v19 .cookie-actions{ grid-area: actions; display: flex; align-items: center; gap: var(--ev-space-2xs, .5rem); flex-wrap: wrap; }
body.theme-v19 .cookie-consent .btn-sm{ padding: var(--ev-space-3xs) var(--ev-space-s); font-size: var(--ev-step--1); white-space: nowrap; }
body.theme-v19 .cookie-close, body.theme-v19 #closeCookieConsent{ grid-area: close; justify-self: end; align-self: start; background: none; border: none; font-size: 18px; line-height: 1; color: var(--ev-text-color, #666); cursor: pointer; padding: var(--ev-space-3xs, .25rem); border-radius: 100vmax; }
body.theme-v19 .cookie-close:hover, body.theme-v19 #closeCookieConsent:hover{ background: var(--ev-border-color, #e8e8e8); }
@media (width < 640px) {
  body.theme-v19 .cookie-consent{ left: var(--ev-space-2xs, .5rem); right: var(--ev-space-2xs, .5rem); bottom: var(--ev-space-2xs, .5rem); }
  body.theme-v19 .cookie-content{ grid-template-columns: 1fr auto; grid-template-areas: "title close" "text text" "actions actions"; row-gap: var(--ev-space-3xs, .25rem); padding: var(--ev-space-xs, .75rem); }
  body.theme-v19 .cookie-consent p, body.theme-v19 .cookie-description{ display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  body.theme-v19 .cookie-link{ display: none; }
  body.theme-v19 .cookie-actions > *{ flex: 1; }
}

body.theme-v19 [data-header-align="center"]{text-align:left;align-items:flex-start;justify-items:start;}
body.theme-v19 [data-header-align="center"]{text-align:center;align-items:center;justify-items:center;justify-content:center;}
body.theme-v19 .grid-header[data-header-align="center"]{grid-template-columns:1fr !important /* !important : aligne la grille d'en-tête en une seule colonne quel que soit --grid-columns-* défini par la section */;}
body.theme-v19 .grid-header[data-header-align="start"]{grid-template-columns:1fr !important /* !important : idem, variante start */;}
body.theme-v19 .grid-header[data-header-align="start"], body.theme-v19 .grid-header[data-header-align="center"]{max-width:var(--ev-header-max-width,75ch) !important /* !important : plafonne la largeur de l'en-tête même si une section définit une largeur plus grande */;}
body.theme-v19 .grid-header[data-header-align="center"]{margin-inline:auto !important /* !important : centre l'en-tête même si un margin hérité s'applique */;}
body.theme-v19 .grid-header[data-header-align="columns"]{grid-template-columns:repeat(2,minmax(0,1fr));align-items:end;row-gap:0;}
body.theme-v19 .grid-header[data-header-align="columns"]>.eyebrow, body.theme-v19 .grid-header[data-header-align="columns"]>.grid-title, body.theme-v19 .grid-header[data-header-align="columns"]>.grid-subtitle{grid-column:1;}
body.theme-v19 .grid-header[data-header-align="columns"]>.grid-description{grid-column:2;grid-row:1 / span 99;align-self:end;}
@media (max-width:640px){
  body.theme-v19 .grid-header[data-header-align="columns"]{grid-template-columns:1fr;}
  body.theme-v19 .grid-header[data-header-align="columns"]>.eyebrow, body.theme-v19 .grid-header[data-header-align="columns"]>.grid-title, body.theme-v19 .grid-header[data-header-align="columns"]>.grid-subtitle, body.theme-v19 .grid-header[data-header-align="columns"]>.grid-description{grid-column:auto;grid-row:auto;align-self:auto;}
}

/* Le 2e bloc :root « DESIGN SYSTEM (tokens) » de la référence a été fusionné
   dans le bloc TOKENS en tête de fichier (voir plus haut) — rien à ce niveau. */

/* ============ FONDATIONS ============ */
body.theme-v19 *, body.theme-v19 *::before, body.theme-v19 *::after{ box-sizing: border-box; }
body.theme-v19 img{ max-width: 100%; height: auto; display: block; }
html:has(body.theme-v19){ scroll-behavior: smooth; }
body.theme-v19{ margin: 0; background: var(--ev-body-bg); color: var(--ev-body-color); font-family: var(--ev-text-font-family); line-height: var(--ev-text-line-height); -webkit-font-smoothing: antialiased; }

/* Galerie réalisations : 3 cartes desktop, 2 tablette, 1 mobile. */
@media (min-width: 1025px) {
  body.theme-v19 .gallery-portfolio__grid{
    grid-template-columns: repeat(6, minmax(0, 1fr)) !important /* !important : 3 colonnes desktop : doit gagner sur la valeur --grid-columns-lg générique */;
  }
  body.theme-v19 .gallery-portfolio__item{ grid-column: span 2; }
  body.theme-v19 .gallery-portfolio__item:nth-last-child(2):nth-child(3n + 1){
    grid-column: 2 / span 2;
  }
}
@media (min-width: 641px) and (max-width: 1024px) {
  body.theme-v19 .gallery-portfolio__grid{
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important /* !important : 2 colonnes tablette : doit gagner sur la valeur --grid-columns-md générique */;
  }
  body.theme-v19 .gallery-portfolio__item{ grid-column: auto; }
}
@media (max-width: 640px) {
  body.theme-v19 .gallery-portfolio__grid{
    grid-template-columns: 1fr !important /* !important : 1 colonne mobile : doit gagner sur la valeur --grid-columns-sm générique */;
  }
  body.theme-v19 .gallery-portfolio__item{ grid-column: auto; }
  body.theme-v19 .gallery-portfolio__open{ aspect-ratio: 1 / 1; }
}

@media (prefers-reduced-motion: reduce) {
  body.theme-v19 *, body.theme-v19 *::before, body.theme-v19 *::after{ animation: none !important /* !important : kill-switch WCAG prefers-reduced-motion : doit gagner sur toute transition/animation de composant */; transition: none !important /* !important : kill-switch WCAG prefers-reduced-motion : doit gagner sur toute transition/animation de composant */; }
  html:has(body.theme-v19){ scroll-behavior: auto; }
}

/* ============ TOPBAR ============ */
body.theme-v19 .site-topbar{ background: var(--ev-dark); color: #fff; overflow: hidden; font-size: var(--ev-step--1); }
body.theme-v19 .site-topbar__track{ display: flex; align-items: center; gap: var(--ev-space-l); width: max-content; padding: var(--ev-space-2xs) 0; animation: topbar-scroll 32s linear infinite; }
body.theme-v19 .site-topbar__item{ display: flex; align-items: center; gap: var(--ev-space-l); white-space: nowrap; }
body.theme-v19 .site-topbar__item::after{ content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--ev-accent); flex: 0 0 auto; }
@keyframes topbar-scroll { to { transform: translateX(-50%); } }

/* ============ HEADER ============ */
body.theme-v19 .site-header{ position: sticky; top: 0; z-index: 500; background: #fff; border-bottom: 1px solid var(--ev-border-color); transition: box-shadow .25s ease; }
body.theme-v19 .site-header.scrolled{ box-shadow: var(--ev-shadow-sm); }
body.theme-v19 .site-header__wrap{ padding-inline: clamp(1.5rem, 3.5vw, 4rem); }
body.theme-v19 .site-header__bar{ display: flex; align-items: center; justify-content: space-between; gap: var(--ev-space-m); min-height: 78px; width: 100%; }
body.theme-v19 .site-header__head{ display: flex; align-items: center; gap: var(--ev-space-s); flex: 0 0 auto; }
body.theme-v19 .site-header__toggle{ border: 0; background: transparent; cursor: pointer; padding: var(--ev-space-2xs); color: var(--ev-heading-color); display: none; align-items: center; }
body.theme-v19 .site-header__toggle .icon{ --icon-height: 26px; }
body.theme-v19 .site-header__brand-link{ display: inline-flex; align-items: center; gap: var(--ev-space-xs); }
/* Logo en hauteur fixe (largeur auto) plutôt qu'en largeur fixe de 230px :
   ce dernier réservait à lui seul ~230px de la barre de navigation, ce qui
   forçait le vrai menu (9 entrées, plus long que la démo V19) à passer à
   la ligne en plusieurs rangées empilées (repéré via capture d'écran par
   l'utilisateur, comparé à https://groupecuratech.fr/, même famille de
   template, dont le logo tient dans ~90px de large). */
body.theme-v19 .site-header__logo{ width: auto; height: 52px; max-width: 200px; }
body.theme-v19 .site-header__brand{ font-family: var(--ev-heading-font-family); font-weight: 700; color: var(--ev-heading-color); font-size: var(--ev-step-0); line-height: 1.15; max-width: 16ch; }
body.theme-v19 .site-header__navwrap{ display: flex; align-items: center; }
body.theme-v19 .site-header__nav{ display: flex; align-items: center; flex-wrap: wrap; gap: var(--ev-space-s); }
body.theme-v19 .site-header .nav-item{ position: relative; }
body.theme-v19 .site-header .nav-link{ display: inline-flex; align-items: center; gap: var(--ev-space-3xs); padding: var(--ev-space-2xs) var(--ev-space-xs); color: var(--ev-heading-color); font-weight: 500; font-size: var(--ev-step-0); }
body.theme-v19 .site-header .nav-link:hover{ color: var(--ev-primary); }
body.theme-v19 .site-header .dropdown-menu{ position: absolute; top: 100%; left: 0; min-width: 220px; background: #fff; border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); box-shadow: var(--ev-shadow-lg); padding: var(--ev-space-2xs); margin: 0; }
body.theme-v19 .site-header .dropdown-item{ display: block; padding: var(--ev-space-2xs) var(--ev-space-xs); color: var(--ev-text-color); font-size: var(--ev-step-0); border-radius: 10px; }
body.theme-v19 .site-header .dropdown-item:hover, body.theme-v19 .site-header .dropdown-item:focus-visible{ background: var(--ev-body-bg); color: var(--ev-primary); }
/* style.css pose `.dropdown-item.active, .dropdown-item:active{ color:
   ... white !important }` — un !important qui survit à mon survol
   ci-dessus (qui ne touche que background, pas color en !important) :
   au survol d'un item actif (ex. menu Contact sur la page "Demander un
   devis"), le fond redevenait clair mais le texte restait blanc, donc
   illisible (repéré par l'utilisateur, confirmé par inspection CSSOM
   réelle des règles appliquées en état :hover forcé). Corrigé en gardant
   le fond rouge (au lieu de le laisser s'éclaircir) pour du blanc sur
   rouge, toujours lisible, plutôt que de complexifier avec un second
   !important sur la couleur. */
body.theme-v19 .site-header .dropdown-item.active:hover,
body.theme-v19 .site-header .dropdown-item.active:focus-visible{ background: var(--ev-primary); color: #fff !important; }
body.theme-v19 .site-header .btn-arrow{ display: inline-flex; align-items: center; }
body.theme-v19 .site-header .btn-arrow .icon{ --icon-height: 14px; }
body.theme-v19 .site-header__cta{ display: flex; align-items: center; gap: var(--ev-space-2xs); flex: 0 0 auto; }
@media (max-width: 1280px) and (min-width: 992px) {
  body.theme-v19 .site-header__wrap{ padding-inline: clamp(1.25rem, 2vw, 2rem); }
  body.theme-v19 .site-header__nav{ gap: var(--ev-space-xs); }
  body.theme-v19 .site-header .nav-link{ padding-inline: var(--ev-space-2xs); }
}
@media (max-width: 991px) {
  body.theme-v19 .site-header__wrap{ padding-inline: clamp(1rem, 4vw, 1.5rem); }
  body.theme-v19 .site-header__toggle{ display: inline-flex; }
  body.theme-v19 .site-header__brand{ display: none; }
  body.theme-v19 .site-header__logo{ height: 44px; max-width: 160px; }
  body.theme-v19 .site-header__navwrap{ display: none; }
  body.theme-v19 .site-header__cta .btn{ padding-inline: var(--ev-space-2xs); }
  /* style.css pose `.navbar-wrapper{ flex-direction:column }` à cette même
     largeur (pensé pour l'empilement vertical de l'ancien header NOBIS,
     menu ouvert compris) : `.site-header__bar` porte aussi la classe
     `.navbar-wrapper` (même élément) et en hérite, sans qu'aucune règle V19
     ne repose `flex-direction:row` pour la contrer. Résultat : bouton
     burger + logo (seul enfant visible du conteneur flex, le menu et les
     CTA étant `display:none` en mobile) centrés horizontalement au lieu
     d'être collés à gauche (`align-items:center` s'applique alors à l'axe
     transversal, qui devient l'axe horizontal en colonne) — repéré par
     l'utilisateur, capture à l'appui. */
  /* flex-wrap:wrap + flex-basis:100% sur le panneau : une fois rangé de
     nouveau sur l'axe horizontal (flex-direction:row ci-dessus), le panneau
     de menu déroulant (#navbarSupportedContent, `display:block` posé par le
     plugin collapse de Bootstrap dès `.show`) devenait un 2e élément flex
     sur la MÊME ligne que burger+logo au lieu de s'afficher dessous (repéré
     en ouvrant le menu après le correctif ci-dessus). */
  body.theme-v19 .site-header__bar{ flex-direction: row; flex-wrap: wrap; }
  /* `.site-header__navwrap` (utilisée juste au-dessus) ne correspond à
     aucun élément réel : le panneau de menu (templates/vitrine/includes/
     nav.html.twig) est `<div class="collapse navbar-collapse" id=
     "navbarSupportedContent">`, sans cette classe. Bon sélecteur ici. */
  body.theme-v19 .navbar-collapse.show{ flex-basis: 100%; width: 100%; }
}

/* ============ HERO ============ */
/* style.min.css pose `#home .main-content > *{ margin-top: var(--ev-spacer-lg/
   --ev-space-5xl) }` (>=992px, ~104px) : un espacement vertical hérité,
   pensé pour séparer les sections empilées de l'ancien site NOBIS. Nos
   sections V19 ont chacune leur propre padding-block (voir plus bas) : cette
   marge globale ne sert donc plus qu'à créer un vide indésirable AVANT la
   toute première section (repéré par l'utilisateur : espace entre le header
   et le hero). Neutralisée uniquement pour le 1er enfant de .main-content
   sur l'accueil — les autres sections ne sont pas concernées (aucun bug
   signalé entre elles). */
body.theme-v19 #home .main-content > *:first-child{ margin-top: 0 !important; }

/* La référence V19 pose un fond photo (Unsplash) en style inline sur la
   section ; interdit en production (hotlink, cf. docs/theme-v19/06-points-a-arbitrer.md).
   Remplacé par une image locale déjà déboîchage-thématique (décodée du
   base64 de la référence pour une autre section, réutilisée ici en fond),
   sous le même dégradé --before-- que la référence (opacité 72-96%, donc
   la photo ne fait qu'apporter une légère texture, comme dans l'original). */
/* min-height (plutôt qu'un simple padding-block généreux) : étire la bannière
   pour qu'elle occupe la quasi-totalité de la hauteur d'écran quel que soit
   l'appareil — demande explicite de l'utilisateur (photo qui descendait
   davantage avant le retrait de l'ancien encart image, cf. commentaire plus
   bas). display:flex + align-items:center recentre le contenu verticalement
   dans cette hauteur, au lieu de le laisser collé en haut. */
body.theme-v19 .hero-showcase{ position: relative; color: #fff; overflow: hidden; display: flex; align-items: center; min-height: 85vh; padding-block: var(--ev-space-2xl); background-image: url("/assets/img/theme-v19/hero-vehicule-tour-eiffel.png"); background-size: cover; background-position: center; }
/* Dégradé neutre (noir, sans teinte marine/rouge) au lieu de l'ancien filtre
   coloré : juste assez opaque derrière le texte (colonne de gauche, ~55% de
   la largeur, cf. .hero-showcase__content) pour la lisibilité, totalement
   transparent au-delà pour laisser voir la photo (véhicule + Tour Eiffel)
   sans altération de ses couleurs — demande explicite de l'utilisateur. */
body.theme-v19 .hero-showcase::before{ content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, rgba(0, 0, 0, 0.78) 0%, rgba(0, 0, 0, 0.55) 32%, rgba(0, 0, 0, 0.15) 55%, rgba(0, 0, 0, 0) 70%); }
body.theme-v19 .hero-showcase::after{ content: ""; position: absolute; right: -120px; bottom: -120px; width: 420px; height: 420px; border-radius: 50%; background: radial-gradient(circle, rgba(127, 176, 232, 0.28), transparent 70%); }
body.theme-v19 .hero-showcase__content{ position: relative; z-index: 1; display: grid; grid-template-columns: 1.1fr 0.9fr; gap: var(--ev-space-xl); align-items: center; }
/* text-shadow sur tout le texte de la bannière : le dégradé de .hero-showcase::before
   (cf. plus haut) est volontairement transparent au-delà de 70% de large pour
   laisser voir la photo — mais le texte peut déborder sur cette zone claire
   (ciel) à cause du retour à la ligne, où le blanc devient peu lisible sans
   filtre derrière. Un halo sombre porté résout ça sans réintroduire de teinte
   sur la photo (repéré par l'utilisateur, capture à l'appui). */
body.theme-v19 .hero-showcase__eyebrow{ display: inline-flex; align-items: center; gap: var(--ev-space-2xs); color: var(--ev-accent); font-size: var(--ev-step--1); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; margin-bottom: var(--ev-space-s); text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6); }
body.theme-v19 .hero-showcase__eyebrow::before{ content: ""; width: 26px; height: 2px; background: var(--ev-accent); }
body.theme-v19 .hero-showcase__title{ color: #fff; font-size: var(--ev-step-7); line-height: 1.05; margin: 0 0 var(--ev-space-m); overflow-wrap: break-word; text-shadow: 0 2px 16px rgba(0, 0, 0, 0.65); }
body.theme-v19 .hero-showcase__intro{ color: rgba(255, 255, 255, 0.85); font-size: var(--ev-step-1); max-width: 52ch; margin-bottom: var(--ev-space-l); text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6); }
body.theme-v19 .hero-showcase__cta{ display: flex; flex-wrap: wrap; gap: var(--ev-space-xs); margin-bottom: var(--ev-space-m); }
body.theme-v19 .hero-showcase__cta .btn-outline-primary{ --ev-btn-outline-color: #ffffff; border-color: rgba(255, 255, 255, 0.55); }
body.theme-v19 .hero-showcase__points{ list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--ev-space-m); }
body.theme-v19 .hero-showcase__points li{ display: flex; align-items: center; gap: var(--ev-space-2xs); color: rgba(255, 255, 255, 0.9); font-size: var(--ev-step--1); font-weight: 500; text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6); }
body.theme-v19 .hero-showcase__points li::before{ content: ""; flex: 0 0 auto; width: 18px; height: 18px; background: var(--ev-accent); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; }
/* .hero-showcase__media / __media-frame (cadre image flottant à droite) et le
   keyframe hero-media-float ont été retirés avec la bannière : la nouvelle
   photo de fond (van + Tour Eiffel) couvre toute la section en pleine largeur,
   il n'y a plus d'image encadrée séparée à faire flotter (cf. objet.csv,
   objet #90001 hero-showcase). */
@media (max-width: 900px) {
  body.theme-v19 .hero-showcase{ min-height: 70vh; }
  body.theme-v19 .hero-showcase__content{ grid-template-columns: 1fr; }
}

/* ============ PAGE / ARTICLE HERO — bannière des pages internes ============
   Remplace l'ancien duo "bandeau sombre (titre+fil d'Ariane) + section
   claire séparée (sous-titre+texte+image+CTA)" : les deux sont fusionnés en
   UNE section, même famille visuelle que .hero-showcase (dégradé marine ->
   rouge de la marque, cf. tokens --ev-navy-rgb/--ev-primary-rgb) mais sans
   photo de fond (générique, utilisée par 26 gabarits, pas de photo qui ait
   un sens partout) : fil d'Ariane -> eyebrow (petit "H2") -> H1 -> texte ->
   CTA à gauche, image réelle de la page à droite (repris de la référence
   groupecuratech.fr/page/2604294810-maconnerie-et-gros-oeuvre, adapté à nos
   couleurs plutôt que copié tel quel). Rendu par vitrine/includes/_intro.html.twig
   (pages + gabarits combi) et vitrine/article/details.html.twig (articles). */
body.theme-v19 .page-hero{
  position: relative; color: #fff; overflow: hidden;
  padding-block: var(--ev-space-2xl);
  background: linear-gradient(120deg, rgba(var(--ev-navy-rgb), 1) 0%, rgba(var(--ev-navy-rgb), 0.94) 55%, rgba(var(--ev-primary-rgb), 0.82) 100%);
}
/* Image en plein bord (bord droit du viewport, pleine hauteur de la
   section), PAS une carte arrondie flottant dans la grille : vérifié sur
   la référence (image .intro__image de groupecuratech.fr touche
   littéralement x=100% du viewport et le haut/bas de la section, aucun
   border-radius/ombre). .page-hero__media est donc un enfant direct de
   .page-hero (pas de .page-hero__content/.container, dont le padding et le
   plafond de largeur l'auraient empêchée d'atteindre le bord), positionné
   en absolu ; .page-hero__body garde une largeur max pour ne jamais passer
   dessous. */
body.theme-v19 .page-hero__content{ position: relative; z-index: 1; }
body.theme-v19 .page-hero__body{ max-width: 46%; }
body.theme-v19 .page-hero__content.no-img .page-hero__body{ max-width: 62rem; }
body.theme-v19 .page-hero__breadcrumb{ margin-bottom: var(--ev-space-m); }
body.theme-v19 .page-hero__breadcrumb .breadcrumb{ margin: 0; }
body.theme-v19 .page-hero__breadcrumb .breadcrumb-text,
body.theme-v19 .page-hero__breadcrumb .breadcrumb-item{ color: rgba(255, 255, 255, 0.7); }
body.theme-v19 .page-hero__breadcrumb .breadcrumb-item.active{ color: rgba(255, 255, 255, 0.95); }
body.theme-v19 .page-hero__breadcrumb .breadcrumb-item + .breadcrumb-item::before{ color: rgba(255, 255, 255, 0.4); }
body.theme-v19 .page-hero__eyebrow{ display: inline-flex; align-items: center; gap: var(--ev-space-2xs); color: var(--ev-accent); font-size: var(--ev-step--1); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; margin: 0 0 var(--ev-space-s); }
body.theme-v19 .page-hero__eyebrow::before{ content: ""; width: 26px; height: 2px; background: var(--ev-accent); flex: 0 0 auto; }
/* Même taille que .hero-showcase__title (accueil) : les deux sont LE titre
   principal (H1) de leur page, ils ne doivent pas changer de taille en
   naviguant de l'accueil vers une page interne (incohérence mesurée le
   2026-09-07 : 56px vs 44px à 1440px de large). */
body.theme-v19 .page-hero__title{ color: #fff; font-size: var(--ev-step-7); line-height: 1.1; margin: 0 0 var(--ev-space-m); overflow-wrap: break-word; }
/* Sur les pages de listing (vitrine/article/index.html.twig), le préfixe de
   type ("Gammes de produits :") est mis en <b>, sans règle de couleur du
   thème V19 : hérite alors de style.css (probablement pensé pour un fond
   clair ailleurs), qui le pose en rouge — illisible/disgracieux sur ce
   bandeau marine->rouge où le reste du titre est blanc (repéré par
   l'utilisateur, capture à l'appui). Aligné sur la couleur du reste du H1
   plutôt que d'introduire une 3e couleur. */
body.theme-v19 .page-hero__title b{ color: inherit; }
body.theme-v19 .page-hero__description{ color: rgba(255, 255, 255, 0.85); font-size: var(--ev-step-1); max-width: 58ch; margin-bottom: var(--ev-space-l); }
body.theme-v19 .page-hero__description p{ color: inherit; margin: 0 0 var(--ev-space-xs); }
/* Même bug que .page-hero__title b ci-dessus : un H3 CMS injecté dans la
   description du hero (ex. page mentions légales, "Informations sur
   l'entreprise :") passe par <strong>, visé par la règle `h3 strong` de
   style.css qui le pose en rouge (--ev-primary) — illisible sur ce bandeau
   sombre où le reste du texte est blanc. */
body.theme-v19 .page-hero__description h2,
body.theme-v19 .page-hero__description h3,
body.theme-v19 .page-hero__description h2 strong,
body.theme-v19 .page-hero__description h3 strong{ color: inherit; }
/* Même cause que le bloc .paragraph__description h3 plus bas : un titre CMS
   (H2/H3) écrit directement dans la description du hero (ex. page mentions
   légales, "Informations sur l'entreprise :") referme le <p> qui l'entoure
   (un heading n'est pas autorisé dans un <p>) — le texte qui suit devient un
   simple nœud de texte, sans la marge de .page-hero__description p ci-dessus.
   Seule la marge propre du heading sépare alors titre et texte, quasi nulle
   faute de règle dédiée. */
body.theme-v19 .page-hero__description h2,
body.theme-v19 .page-hero__description h3{ margin: var(--ev-space-m) 0 var(--ev-space-3xs); }
body.theme-v19 .page-hero__description h2:first-child,
body.theme-v19 .page-hero__description h3:first-child{ margin-top: 0; }
/* Sur les articles (.article--details), la description du hero est souvent
   un bloc de contenu long (ex. mentions légales) et non un simple chapeau de
   2-3 lignes comme sur les pages (.page) : --ev-step-1 (jusqu'à 1.35rem, taille
   "lead") y reste correct, mais alourdit la lecture d'un texte long. On
   ramène les articles à --ev-step-0, la taille de paragraphe standard déjà
   utilisée pour le reste du contenu (cf. .faq-section__answer etc.). */
body.theme-v19 .article--details .page-hero__description{ font-size: var(--ev-step-0); }
body.theme-v19 .page-hero__cta{ display: flex; flex-wrap: wrap; gap: var(--ev-space-xs); margin: 0; }
body.theme-v19 .page-hero__cta .btn-outline-primary{ --ev-btn-outline-color: #ffffff; border-color: rgba(255, 255, 255, 0.55); }
body.theme-v19 .page-hero__media{ position: absolute; top: 0; right: 0; bottom: 0; width: 44%; }
body.theme-v19 .page-hero__media img{ display: block; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 900px) {
  body.theme-v19 .page-hero__media{ display: none; }
  body.theme-v19 .page-hero__body{ max-width: none; }
}

/* ============ SERVICES ============ */
body.theme-v19 .services-offer{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .services-offer__grid{
  margin-top: var(--ev-space-l);
  align-items: stretch;
}
body.theme-v19 .services-offer__item{
  background: var(--ev-light, #fff);
  border: 1px solid var(--ev-border-color);
  border-radius: var(--ev-border-radius);
  padding: var(--ev-space-m);
  display: flex;
  flex-direction: column;
  gap: var(--ev-space-s);
  height: 100%;
  transition: transform .2s ease, box-shadow .2s ease;
}
body.theme-v19 .services-offer__item:hover{ transform: translateY(-6px); box-shadow: var(--ev-shadow-lg); }
/* Toutes les icônes utilisent désormais le même traitement bleu de la template. */
body.theme-v19 .services-offer__icon{
  width: 52px;
  height: 52px;
  flex: 0 0 52px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--ev-navy) 10%, white);
}
body.theme-v19 .services-offer__icon .icon{
  --icon-height: 26px;
  --icon-color: var(--ev-navy);
}
body.theme-v19 .services-offer__item-title{
  margin: 0;
  min-height: 2.35em;
  display: flex;
  align-items: flex-start;
  font-size: var(--ev-step-2);
  line-height: 1.16;
}
body.theme-v19 .services-offer__item-text{
  margin: 0;
  font-size: var(--ev-step-0);
  line-height: 1.55;
}
@media (max-width: 620px) {
  body.theme-v19 .services-offer__item-title{ min-height: 0; }
}

/* ============ AVANTAGES ============ */
body.theme-v19 .advantages-reasons{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .advantages-reasons__content{ display: grid; grid-template-columns: 1.05fr 0.95fr; gap: var(--ev-space-xl); align-items: stretch; }
body.theme-v19 .advantages-reasons__body{ display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
body.theme-v19 .advantages-reasons__header{ width: 100%; }
body.theme-v19 .advantages-reasons__list{ width: 100%; list-style: none; margin: var(--ev-space-s) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--ev-space-s); }
body.theme-v19 .advantages-reasons__list li{ display: flex; align-items: flex-start; gap: var(--ev-space-xs); font-size: var(--ev-step-0); }
body.theme-v19 .advantages-reasons__list li::before{ content: ""; flex: 0 0 auto; width: 22px; height: 22px; margin-top: 2px; background: var(--ev-primary); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M256 512a256 256 0 1 0 0-512 256 256 0 1 0 0 512zm113-303L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M256 512a256 256 0 1 0 0-512 256 256 0 1 0 0 512zm113-303L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z'/%3E%3C/svg%3E") center / contain no-repeat; }
body.theme-v19 .advantages-reasons__cta{ margin-top: var(--ev-space-m); }
body.theme-v19 .advantages-reasons__media{ position: relative; min-width: 0; min-height: 0; }
body.theme-v19 .advantages-reasons__media-frame{ position: absolute; inset: 0; width: 100%; height: 100%; border-radius: var(--ev-border-radius); overflow: hidden; aspect-ratio: auto !important /* !important : l'image suit la hauteur réelle du texte voisin plutôt que le ratio par défaut hérité de .grid-image */; }
body.theme-v19 .advantages-reasons__media-frame img{ width: 100%; height: 100%; object-fit: cover; object-position: center; }
body.theme-v19 .advantages-reasons__chip{ position: absolute; top: 20px; right: -14px; background: var(--ev-primary); color: #fff; font-weight: 700; border-radius: 100vmax; padding: var(--ev-space-2xs) var(--ev-space-s); font-size: var(--ev-step--1); box-shadow: var(--ev-shadow-sm); z-index: 1; }
@media (max-width: 900px) {
  body.theme-v19 .advantages-reasons__content{ grid-template-columns: 1fr; }
  body.theme-v19 .advantages-reasons__media{ order: -1; min-height: 0; }
  body.theme-v19 .advantages-reasons__media-frame{ position: relative; inset: auto; height: auto; aspect-ratio: 3 / 2 !important /* !important : réintroduit un ratio fixe 3/2 en mobile, en écrasant le aspect-ratio:auto du desktop */; }
  body.theme-v19 .advantages-reasons__media-frame img{ height: 100%; }
  body.theme-v19 .advantages-reasons__chip{ right: var(--ev-space-s); }
}

/* ============ À PROPOS ============ */
body.theme-v19 .about-company{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .about-company__content{
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: var(--ev-space-xl);
  align-items: stretch;
}
body.theme-v19 .about-company__media-frame{
  position: relative;
  width: 100%;
  max-width: 600px;
  min-height: 0;
  height: 100%;
  aspect-ratio: auto;
  margin: 0;
  border-radius: var(--ev-border-radius);
  overflow: hidden;
  justify-self: start;
  align-self: stretch;
}
body.theme-v19 .about-company__media-frame img{
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
body.theme-v19 .about-company__body{
  display: flex;
  flex-direction: column;
  gap: var(--ev-space-s);
  min-width: 0;
}
body.theme-v19 .about-company__text{ margin: 0; }
body.theme-v19 .about-company__cta{ margin-top: auto; }
@media (max-width: 900px) {
  body.theme-v19 .about-company__content{ grid-template-columns: 1fr; align-items: start; }
  body.theme-v19 .about-company__media-frame{
    position: relative;
    max-width: 600px;
    height: auto;
    aspect-ratio: 3 / 2;
    justify-self: center;
    align-self: auto;
  }
  body.theme-v19 .about-company__media-frame img{ position: static; height: 100%; }
  body.theme-v19 .about-company__cta{ margin-top: 0; }
}

/* ============ FONCTIONNALITÉS ============ */
body.theme-v19 .features-product{ background: var(--ev-dark); padding-block: var(--ev-space-2xl); color: #fff; }
body.theme-v19 .features-product__header .features-product__eyebrow{ color: var(--ev-accent); }
body.theme-v19 .features-product__title, body.theme-v19 .features-product__intro{ color: #fff; }
body.theme-v19 .features-product__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .features-product__item{ background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.12); border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-s); }
body.theme-v19 .features-product__icon{ width: 48px; height: 48px; border-radius: 12px; display: grid; place-items: center; background: rgba(127, 176, 232, 0.18); }
body.theme-v19 .features-product__icon .icon{ --icon-height: 24px; --icon-color: var(--ev-accent); }
body.theme-v19 .features-product__item-title{ color: #fff; font-size: var(--ev-step-1); }
body.theme-v19 .features-product__item-text{ color: rgba(255, 255, 255, 0.78); margin: 0; font-size: var(--ev-step--1); }

/* ============ PROCESSUS ============ */
body.theme-v19 .process-steps{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .process-steps__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .process-steps__item{ position: relative; padding: var(--ev-space-m); border-radius: var(--ev-border-radius); background: var(--ev-body-bg); display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .process-steps__num{ font-family: var(--ev-heading-font-family); font-weight: 700; font-size: var(--ev-step-6); color: var(--ev-primary); line-height: 1; }
body.theme-v19 .process-steps__item-title{ font-size: var(--ev-step-1); }
body.theme-v19 .process-steps__item-text{ margin: 0; font-size: var(--ev-step--1); }

/* ============ STATISTIQUES ============ */
body.theme-v19 .static-metrics{ background: var(--ev-primary); padding-block: var(--ev-space-xl); color: #fff; }
body.theme-v19 .static-metrics__grid{ gap: var(--ev-space-l); }
body.theme-v19 .static-metrics__item{ text-align: center; display: flex; flex-direction: column; gap: var(--ev-space-3xs); }
body.theme-v19 .static-metrics__number{ font-family: var(--ev-heading-font-family); font-weight: 700; font-size: var(--ev-step-6); color: #fff; line-height: 1; }
body.theme-v19 .static-metrics__label{ color: rgba(255, 255, 255, 0.85); margin: 0; font-size: var(--ev-step-0); }

/* ============ COMPARATIF ============ */
body.theme-v19 .compare-methods{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .compare-methods__panels{ margin-top: var(--ev-space-l); display: grid; grid-template-columns: 1fr 1fr; gap: var(--ev-space-m); }
body.theme-v19 .compare-methods__panel{ border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-s); }
body.theme-v19 .compare-methods__panel--bad{ background: #fff; border: 1px solid var(--ev-border-color); }
body.theme-v19 .compare-methods__panel--good{ background: var(--ev-dark); color: #fff; }
body.theme-v19 .compare-methods__panel-title{ font-size: var(--ev-step-2); }
body.theme-v19 .compare-methods__panel--good .compare-methods__panel-title{ color: #fff; }
body.theme-v19 .compare-methods__list{ list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .compare-methods__list li{ display: flex; align-items: flex-start; gap: var(--ev-space-2xs); font-size: var(--ev-step-0); }
body.theme-v19 .compare-methods__panel--bad .compare-methods__list li::before{ content: ""; flex: 0 0 auto; width: 16px; height: 16px; margin-top: 3px; background: var(--ev-primary); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center / contain no-repeat; }
body.theme-v19 .compare-methods__panel--good .compare-methods__list li::before{ content: ""; flex: 0 0 auto; width: 16px; height: 16px; margin-top: 3px; background: var(--ev-accent); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; }
body.theme-v19 .compare-methods__panel--good .compare-methods__list li{ color: rgba(255, 255, 255, 0.88); }
body.theme-v19 .compare-methods__cta{ align-self: flex-start; margin-top: auto; }
body.theme-v19 .compare-methods__panel--good .compare-methods__cta{ background: #fff; border-color: #fff; color: var(--ev-primary); box-shadow: none; }
body.theme-v19 .compare-methods__panel--good .compare-methods__cta:hover{ background: rgba(255,255,255,.92); border-color: rgba(255,255,255,.92); }
body.theme-v19 .compare-methods__cta[hidden]{ display: none !important /* !important : renforce l'attribut HTML natif hidden face à display:inline-flex de .btn */; }
@media (max-width: 860px) { body.theme-v19 .compare-methods__panels{ grid-template-columns: 1fr; } }
@media (max-width: 560px) { body.theme-v19 .compare-methods__cta{ width: 100%; } }

/* ============ GARANTIES ============ */
body.theme-v19 .guarantees-reassurance{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .guarantees-reassurance__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .guarantees-reassurance__item{ display: flex; flex-direction: column; gap: var(--ev-space-2xs); align-items: flex-start; }
body.theme-v19 .guarantees-reassurance__icon{ width: 52px; height: 52px; border-radius: 100vmax; display: grid; place-items: center; background: color-mix(in srgb, var(--ev-primary, #c01010) 12%, white); }
body.theme-v19 .guarantees-reassurance__icon .icon{ --icon-height: 26px; --icon-color: var(--ev-primary); }
body.theme-v19 .guarantees-reassurance__item-title{ font-size: var(--ev-step-1); }
body.theme-v19 .guarantees-reassurance__item-text{ margin: 0; font-size: var(--ev-step--1); }

/* ============ TARIFS ============ */
body.theme-v19 .pricing-structure{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .pricing-structure__grid{ margin-top: var(--ev-space-l); align-items: stretch; }
body.theme-v19 .pricing-structure__item{ background: #fff; border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-s); }
body.theme-v19 .pricing-structure__item--featured{ background: var(--ev-dark); border-color: var(--ev-dark); color: #fff; position: relative; }
body.theme-v19 .pricing-structure__tag{ display: inline-block; align-self: flex-start; background: var(--ev-primary); color: #fff; font-weight: 700; font-size: var(--ev-step--2); border-radius: 100vmax; padding: var(--ev-space-3xs) var(--ev-space-2xs); text-transform: uppercase; letter-spacing: .05em; }
body.theme-v19 .pricing-structure__item-title{ font-size: var(--ev-step-2); }
body.theme-v19 .pricing-structure__item--featured .pricing-structure__item-title{ color: #fff; }
body.theme-v19 .pricing-structure__desc{ margin: 0; font-size: var(--ev-step-0); }
body.theme-v19 .pricing-structure__item--featured .pricing-structure__desc{ color: rgba(255, 255, 255, 0.82); }
body.theme-v19 .pricing-structure__list{ list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .pricing-structure__list li{ display: flex; align-items: flex-start; gap: var(--ev-space-2xs); font-size: var(--ev-step--1); }
body.theme-v19 .pricing-structure__list li::before{ content: ""; flex: 0 0 auto; width: 16px; height: 16px; margin-top: 3px; background: var(--ev-primary); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; }
body.theme-v19 .pricing-structure__item--featured .pricing-structure__list li{ color: rgba(255, 255, 255, 0.88); }
body.theme-v19 .pricing-structure__item--featured .pricing-structure__list li::before{ background: var(--ev-accent); }
body.theme-v19 .pricing-structure__note{ margin: 0; font-size: var(--ev-step--1); text-align: center; margin-top: var(--ev-space-m); }
body.theme-v19 .pricing-structure__item .btn{ margin-top: auto; }

/* ============ SIMULATEUR ============ */
/* ============ COMPTEUR ANIMÉ ============ */
body.theme-v19 .animated-counter{ background: var(--ev-navy); padding-block: var(--ev-space-xl); color: #fff; }
body.theme-v19 .animated-counter__header .animated-counter__eyebrow{ color: var(--ev-accent); }
body.theme-v19 .animated-counter__title, body.theme-v19 .animated-counter__intro{ color: #fff; }
body.theme-v19 .animated-counter__grid{ gap: var(--ev-space-l); }
body.theme-v19 .animated-counter__item{ text-align: center; display: flex; flex-direction: column; gap: var(--ev-space-3xs); align-items: center; }
body.theme-v19 .animated-counter__number{ font-family: var(--ev-heading-font-family); font-weight: 700; font-size: var(--ev-step-6); color: var(--ev-accent); line-height: 1; }
body.theme-v19 .animated-counter__suffix{ color: var(--ev-accent); font-weight: 600; }
body.theme-v19 .animated-counter__label{ color: rgba(255, 255, 255, 0.85); margin: 0; font-size: var(--ev-step-0); }

/* ============ COMPTE À REBOURS ============ */
body.theme-v19 .countdown-timer{ background: linear-gradient(120deg, var(--ev-primary), #8c0c0c); padding-block: var(--ev-space-xl); color: #fff; }
body.theme-v19 .countdown-timer__inner{ display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--ev-space-m); }
body.theme-v19 .countdown-timer__title{ color: #fff; font-size: var(--ev-step-5); }
body.theme-v19 .countdown-timer__text{ color: rgba(255, 255, 255, 0.85); margin: 0; }
body.theme-v19 .countdown-timer__clock{ display: flex; gap: var(--ev-space-s); align-items: center; }
body.theme-v19 .countdown-timer__unit{ background: rgba(255, 255, 255, 0.12); border: 1px solid rgba(255, 255, 255, 0.22); border-radius: 14px; padding: var(--ev-space-s); min-width: 92px; text-align: center; }
body.theme-v19 .countdown-timer__value{ font-family: var(--ev-heading-font-family); font-weight: 700; font-size: var(--ev-step-5); color: #fff; line-height: 1; }
body.theme-v19 .countdown-timer__unit-label{ display: block; font-size: var(--ev-step--2); color: rgba(255, 255, 255, 0.8); text-transform: uppercase; letter-spacing: .08em; margin-top: var(--ev-space-3xs); }
body.theme-v19 .countdown-timer__sep{ font-family: var(--ev-heading-font-family); font-weight: 700; font-size: var(--ev-step-4); color: rgba(255, 255, 255, 0.7); }
body.theme-v19 .countdown-timer .btn-primary{ background: #fff; border-color: #fff; color: var(--ev-primary); box-shadow: 0 12px 30px -8px rgba(0, 0, 0, 0.22); }
body.theme-v19 .countdown-timer .btn-primary:hover{ background: #f7f7f7; border-color: #f7f7f7; color: var(--ev-primary); }
/* 3 blocs `min-width:92px` + séparateurs + gaps dépassaient la largeur
   dispo sur les téléphones étroits (débordement horizontal de 21px mesuré
   à 320px, ex. iPhone SE) : resserré ici plutôt que de laisser passer en
   `flex-wrap` (casserait l'alignement horizontal du décompte). */
@media (max-width: 380px) {
  body.theme-v19 .countdown-timer__clock{ gap: var(--ev-space-2xs); }
  body.theme-v19 .countdown-timer__unit{ min-width: 72px; padding: var(--ev-space-2xs); }
  body.theme-v19 .countdown-timer__value{ font-size: var(--ev-step-3); }
}

/* ============ RÉSERVATION ============ */
body.theme-v19 .booking-cta{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .booking-cta__inner{ display: grid; grid-template-columns: 1fr auto; gap: var(--ev-space-m); align-items: center; background: var(--ev-body-bg); border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); padding: var(--ev-space-m); }
body.theme-v19 .booking-cta__body{ display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .booking-cta__title{ font-size: var(--ev-step-4); }
body.theme-v19 .booking-cta__text{ margin: 0; }
body.theme-v19 .booking-cta__actions{ display: flex; flex-wrap: wrap; gap: var(--ev-space-2xs); }
@media (max-width: 760px) { body.theme-v19 .booking-cta__inner{ grid-template-columns: 1fr; } }

/* ============ HORAIRES ============ */
body.theme-v19 .opening-hours{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .opening-hours__grid{ margin-top: var(--ev-space-l); display: grid; grid-template-columns: 1fr 1fr; gap: var(--ev-space-m); align-items: center; }
body.theme-v19 .opening-hours__list{ margin: 0; padding: 0; display: flex; flex-direction: column; }
body.theme-v19 .opening-hours__row{ display: flex; justify-content: space-between; align-items: center; gap: var(--ev-space-s); padding: var(--ev-space-s) 0; border-bottom: 1px solid var(--ev-border-color); font-size: var(--ev-step-0); }
body.theme-v19 .opening-hours__row:last-child{ border-bottom: 0; }
body.theme-v19 .opening-hours__day{ font-weight: 600; color: var(--ev-heading-color); }
body.theme-v19 .opening-hours__value{ color: var(--ev-primary); font-weight: 600; }
body.theme-v19 .opening-hours__note{ background: #fff; border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .opening-hours__note-icon{ width: 48px; height: 48px; border-radius: 100vmax; display: grid; place-items: center; background: color-mix(in srgb, var(--ev-primary, #c01010) 12%, white); }
body.theme-v19 .opening-hours__note-icon .icon{ --icon-height: 24px; --icon-color: var(--ev-primary); }
body.theme-v19 .opening-hours__note-title{ font-size: var(--ev-step-2); }
body.theme-v19 .opening-hours__note-text{ margin: 0; font-size: var(--ev-step--1); }
@media (max-width: 820px) { body.theme-v19 .opening-hours__grid{ grid-template-columns: 1fr; } }

/* ============ GALERIE ============ */
body.theme-v19 .gallery-portfolio{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .gallery-portfolio__content{ max-width: 82rem; }
body.theme-v19 .gallery-portfolio__grid{
  margin-top: var(--ev-space-l);
  gap: clamp(1.25rem, 2vw, 2rem) !important /* !important : gap fluide de la galerie toujours strictement calé, indépendamment d'un gap hérité */;
  align-items: stretch;
}
body.theme-v19 .gallery-portfolio__item{
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  height: 100%;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--ev-border-color);
  border-radius: 20px;
  box-shadow: 0 10px 28px rgba(0, 32, 80, 0.07);
  transition: transform .3s ease, box-shadow .3s ease, border-color .3s ease;
}
body.theme-v19 .gallery-portfolio__item:hover{
  transform: translateY(-7px);
  border-color: color-mix(in srgb, var(--ev-primary) 22%, var(--ev-border-color));
  box-shadow: 0 22px 46px rgba(0, 32, 80, 0.14);
}
body.theme-v19 .gallery-portfolio__open{
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: #eef2f6;
  cursor: zoom-in;
  overflow: hidden;
  aspect-ratio: 1 / 1;
  min-height: 0;
}
body.theme-v19 .gallery-portfolio__open::before{
  content: "Voir en grand";
  position: absolute;
  z-index: 2;
  top: 14px;
  right: 14px;
  padding: .42rem .72rem;
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 100vmax;
  background: rgba(255, 255, 255, .94);
  color: var(--ev-heading-color);
  box-shadow: 0 6px 18px rgba(0, 32, 80, .12);
  font-family: var(--ev-text-font-family);
  font-size: var(--ev-step--2);
  font-weight: 700;
  line-height: 1;
  opacity: 0;
  transform: translateY(-5px);
  transition: opacity .25s ease, transform .25s ease;
  pointer-events: none;
}
body.theme-v19 .gallery-portfolio__open::after{
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 58%, rgba(0, 32, 80, .12) 100%);
  opacity: .7;
  transition: opacity .3s ease;
  pointer-events: none;
}
body.theme-v19 .gallery-portfolio__item:hover .gallery-portfolio__open::before, body.theme-v19 .gallery-portfolio__open:focus-visible::before{
  opacity: 1;
  transform: translateY(0);
}
body.theme-v19 .gallery-portfolio__open:focus-visible{
  outline: 3px solid var(--ev-primary);
  outline-offset: -3px;
}
body.theme-v19 .gallery-portfolio__item img{
  width: 100%;
  height: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 0;
  transition: transform .45s cubic-bezier(.2, .65, .3, 1), filter .35s ease;
}
body.theme-v19 .gallery-portfolio__item:hover img, body.theme-v19 .gallery-portfolio__open:focus-visible img{
  transform: scale(1.055);
  filter: saturate(1.04) contrast(1.02);
}
body.theme-v19 .gallery-portfolio__caption{
  position: static;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .48rem;
  flex: 1;
  margin: 0;
  padding: 1rem 1.15rem 1.15rem;
  background: #fff;
  color: var(--ev-heading-color);
  font-family: var(--ev-heading-font-family);
  font-size: clamp(1rem, .96rem + .18vw, 1.14rem);
  font-weight: 700;
  line-height: 1.3;
}
body.theme-v19 .gallery-portfolio__caption::before{
  content: "";
  display: block;
  width: 34px;
  height: 3px;
  border-radius: 100vmax;
  background: var(--ev-primary);
}
@media (max-width: 640px) {
  body.theme-v19 .gallery-portfolio__grid{ gap: 1.15rem !important /* !important : gap resserré en mobile, doit gagner sur la valeur fluide desktop définie plus haut */; }
  body.theme-v19 .gallery-portfolio__item{ border-radius: 16px; }
  body.theme-v19 .gallery-portfolio__caption{ padding: .9rem 1rem 1rem; }
  body.theme-v19 .gallery-portfolio__open::before{
    top: 10px;
    right: 10px;
    opacity: 1;
    transform: none;
    font-size: .7rem;
  }
}
@media (prefers-reduced-motion: reduce) {
  body.theme-v19 .gallery-portfolio__item, body.theme-v19 .gallery-portfolio__item img, body.theme-v19 .gallery-portfolio__open::before{ transition: none !important /* !important : reduced-motion : coupe les transitions propres à la galerie en plus du kill-switch global */; }
  body.theme-v19 .gallery-portfolio__item:hover{ transform: none; }
  body.theme-v19 .gallery-portfolio__item:hover img{ transform: none; }
}
body.theme-v19 .gallery-lightbox{
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 3vw, 2.5rem);
  background: rgba(0, 19, 48, 0.92);
  backdrop-filter: blur(5px);
}
body.theme-v19 .gallery-lightbox.is-open{ display: flex; }
body.theme-v19 .gallery-lightbox__dialog{
  position: relative;
  width: min(1180px, 94vw);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ev-space-xs);
}
body.theme-v19 .gallery-lightbox__image{
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 82vh;
  object-fit: contain;
  border-radius: var(--ev-border-radius);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
}
body.theme-v19 .gallery-lightbox__caption{
  margin: 0;
  color: #fff;
  font-family: var(--ev-heading-font-family);
  font-size: var(--ev-step-0);
  font-weight: 600;
  text-align: center;
}
body.theme-v19 .gallery-lightbox__close{
  position: absolute;
  top: -14px;
  right: -14px;
  z-index: 2;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  background: #fff;
  color: var(--ev-primary);
  font: inherit;
  font-size: 30px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--ev-shadow-lg);
}
body.theme-v19 .gallery-lightbox__close:hover{ background: #f7f7f7; }
body.theme-v19 .gallery-lightbox__close:focus-visible{ outline: 3px solid #fff; outline-offset: 3px; }
body.theme-v19.gallery-lightbox-open{ overflow: hidden; }
@media (max-width: 640px) {
  body.theme-v19 .gallery-portfolio__grid{ gap: var(--ev-space-l) !important /* !important : gap agrandi en mobile (variante focus clavier), doit gagner sur la valeur desktop */; }
  body.theme-v19 .gallery-portfolio__caption{ font-size: var(--ev-step-1); }
  body.theme-v19 .gallery-lightbox{ padding: var(--ev-space-s); }
  body.theme-v19 .gallery-lightbox__dialog{ width: 100%; }
  body.theme-v19 .gallery-lightbox__image{ max-height: 78vh; }
  body.theme-v19 .gallery-lightbox__close{ top: -12px; right: -4px; width: 42px; height: 42px; }
}

/* ============ RÉALISATIONS ============ */
body.theme-v19 .case-achievements{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .case-achievements__grid{
  margin-top: var(--ev-space-l);
  align-items: stretch;
}
body.theme-v19 .case-achievements__item{
  background: #fff;
  border: 1px solid var(--ev-border-color);
  border-radius: var(--ev-border-radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 100%;
}
body.theme-v19 .case-achievements__media{
  flex: 0 0 auto;
}
body.theme-v19 .case-achievements__body{
  padding: var(--ev-space-m);
  display: flex;
  flex-direction: column;
  gap: var(--ev-space-xs);
  flex: 1;
}
body.theme-v19 .case-achievements__item-title{
  margin: 0;
  font-size: var(--ev-step-1);
  line-height: 1.3;
  min-height: 2.6em;
  display: flex;
  align-items: flex-start;
}
body.theme-v19 .case-achievements__item-text{
  margin: 0;
  font-size: var(--ev-step--1);
  line-height: 1.6;
  flex: 1;
}
body.theme-v19 .case-achievements__result{ display: inline-flex; align-items: center; gap: var(--ev-space-2xs); font-size: var(--ev-step--1); font-weight: 600; color: var(--ev-primary); }
body.theme-v19 .case-achievements__cta{
  margin-top: auto;
  width: fit-content;
  align-self: flex-start;
}
body.theme-v19 .case-achievements__cta.btn{ padding-inline: var(--ev-space-m); }
@media (max-width: 767px) {
  body.theme-v19 .case-achievements__item-title{ min-height: 0; }
  body.theme-v19 .case-achievements__cta{ margin-top: var(--ev-space-xs); }
}

/* ============ ÉTUDE DE CAS ============ */
body.theme-v19 .single-case-study{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .single-case-study__content{
  display: grid;
  grid-template-columns: .95fr 1.05fr;
  gap: var(--ev-space-xl);
  align-items: stretch;
}
/* Même logique de dimensionnement que l'image de la section “Un intervenant de confiance” :
   l'image suit la hauteur réelle du contenu texte sans l'allonger artificiellement. */
body.theme-v19 .single-case-study__media-frame{
  position: relative;
  min-width: 0;
  min-height: 0;
  width: 100%;
  height: 100%;
  border-radius: var(--ev-border-radius);
  overflow: hidden;
  aspect-ratio: auto !important /* !important : même logique que la carte 'à propos' : l'image suit la hauteur du texte plutôt qu'un ratio fixe */;
}
body.theme-v19 .single-case-study__media-frame img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
body.theme-v19 .single-case-study__body{ display: flex; flex-direction: column; gap: var(--ev-space-s); min-width: 0; }
body.theme-v19 .single-case-study__text{ margin: 0; font-size: var(--ev-step--1); }
body.theme-v19 .single-case-study__facts{
  margin: var(--ev-space-2xs) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ev-space-xs);
}
body.theme-v19 .single-case-study__fact{
  background: var(--ev-body-bg);
  border-radius: 10px;
  padding: var(--ev-space-xs) var(--ev-space-s);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--ev-space-3xs);
  min-height: 82px;
}
body.theme-v19 .single-case-study__fact-label{
  font-size: var(--ev-step--2);
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ev-text-color);
}
body.theme-v19 .single-case-study__fact-value{
  font-family: var(--ev-heading-font-family);
  font-weight: 700;
  color: var(--ev-heading-color);
  font-size: var(--ev-step-0);
  line-height: 1.25;
  overflow-wrap: anywhere;
}
body.theme-v19 .single-case-study__body > .btn{ align-self: flex-start; }
@media (max-width: 860px) {
  body.theme-v19 .single-case-study__content{ grid-template-columns: 1fr; gap: var(--ev-space-l); }
  body.theme-v19 .single-case-study__media-frame{
    height: auto;
    aspect-ratio: 3 / 2 !important /* !important : réintroduit un ratio fixe 3/2 en mobile, en écrasant le aspect-ratio:auto du desktop */;
  }
  body.theme-v19 .single-case-study__media-frame img{ position: static; height: 100%; }
  body.theme-v19 .single-case-study__facts{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  body.theme-v19 .single-case-study__facts{ grid-template-columns: 1fr; gap: var(--ev-space-2xs); }
  body.theme-v19 .single-case-study__fact{ min-height: 0; padding: var(--ev-space-xs); }
  body.theme-v19 .single-case-study__body > .btn{ width: 100%; }
}

/* ============ CHRONOLOGIE ============ */
body.theme-v19 .company-timeline{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .company-timeline__list{ margin-top: var(--ev-space-l); display: flex; flex-direction: column; gap: 0; position: relative; padding-left: var(--ev-space-m); }
body.theme-v19 .company-timeline__list::before{ content: ""; position: absolute; left: 9px; top: 8px; bottom: 8px; width: 2px; background: var(--ev-border-color); }
body.theme-v19 .company-timeline__item{ position: relative; padding: 0 0 var(--ev-space-l) 0; display: flex; flex-direction: column; gap: var(--ev-space-3xs); }
body.theme-v19 .company-timeline__item:last-child{ padding-bottom: 0; }
body.theme-v19 .company-timeline__item::before{ content: ""; position: absolute; left: calc(-1 * var(--ev-space-m) + 4px); top: 6px; width: 12px; height: 12px; border-radius: 50%; background: var(--ev-primary); box-shadow: 0 0 0 4px var(--ev-body-bg); }
body.theme-v19 .company-timeline__period{ font-size: var(--ev-step--1); font-weight: 700; color: var(--ev-primary); text-transform: uppercase; letter-spacing: .06em; }
body.theme-v19 .company-timeline__item-title{ font-size: var(--ev-step-1); }
body.theme-v19 .company-timeline__item-text{ margin: 0; font-size: var(--ev-step--1); }

/* ============ ÉQUIPE ============ */
body.theme-v19 .team-members{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .team-members__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .team-members__item{ text-align: center; display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .team-members__photo{ border-radius: var(--ev-border-radius); overflow: hidden; }
body.theme-v19 .team-members__item-name{ font-size: var(--ev-step-1); margin: 0; }
body.theme-v19 .team-members__item-role{ margin: 0; font-size: var(--ev-step--1); color: var(--ev-text-color); }

/* ============ RÉCOMPENSES ============ */
body.theme-v19 .awards-distinctions{ background: var(--ev-dark); padding-block: var(--ev-space-xl); color: #fff; }
body.theme-v19 .awards-distinctions__header .awards-distinctions__eyebrow{ color: var(--ev-accent); }
body.theme-v19 .awards-distinctions__title{ color: #fff; }
body.theme-v19 .awards-distinctions__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .awards-distinctions__item{ background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.12); border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-2xs); align-items: center; text-align: center; }
body.theme-v19 .awards-distinctions__icon{ width: 48px; height: 48px; border-radius: 100vmax; display: grid; place-items: center; background: rgba(127, 176, 232, 0.18); }
body.theme-v19 .awards-distinctions__icon .icon{ --icon-height: 24px; --icon-color: var(--ev-accent); }
body.theme-v19 .awards-distinctions__item-title{ color: #fff; font-size: var(--ev-step-1); }
body.theme-v19 .awards-distinctions__item-text{ color: rgba(255, 255, 255, 0.78); margin: 0; font-size: var(--ev-step--1); }

/* ============ TÉMOIGNAGES ============ */
body.theme-v19 .testimonials-certifications{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); overflow: hidden; }
body.theme-v19 .testimonials-certifications__summary{ margin-top: var(--ev-space-m); display: flex; align-items: center; justify-content: center; gap: var(--ev-space-s); flex-wrap: wrap; }
body.theme-v19 .testimonials-certifications__score-card{ display: inline-flex; align-items: center; gap: var(--ev-space-s); background: #fff; border: 1px solid var(--ev-border-color); border-radius: 14px; padding: var(--ev-space-xs) var(--ev-space-s); box-shadow: var(--ev-shadow-sm); }
body.theme-v19 .testimonials-certifications__score-main{ display: flex; align-items: baseline; gap: .35rem; white-space: nowrap; }
body.theme-v19 .testimonials-certifications__score-value{ font-family: var(--ev-heading-font-family); font-size: var(--ev-step-2); line-height: 1; font-weight: 700; color: var(--ev-heading-color); }
body.theme-v19 .testimonials-certifications__score-label{ font-size: var(--ev-step--2); font-weight: 600; color: var(--ev-text-color); }
body.theme-v19 .testimonials-certifications__score-stars{
  display: flex;
  align-items: center;
  gap: 2px;
}
body.theme-v19 .testimonials-certifications__score-star{
  position: relative;
  display: inline-block;
  width: 17px;
  height: 17px;
  flex: 0 0 17px;
  color: #d9dee7;
}
body.theme-v19 .testimonials-certifications__score-star > svg, body.theme-v19 .testimonials-certifications__score-star-fill > svg{
  display: block;
  width: 17px;
  height: 17px;
}
body.theme-v19 .testimonials-certifications__score-star-fill{
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--fill, 0%);
  overflow: hidden;
  color: #f5b942;
  transition: width .25s ease;
}

body.theme-v19 .testimonials-certifications__review-count{ margin: 0; font-size: var(--ev-step--1); font-weight: 600; color: var(--ev-text-color); white-space: nowrap; }
body.theme-v19 .testimonials-certifications__review-btn{ min-width: 150px; }
body.theme-v19 .testimonials-certifications__swiper{ position: relative; margin-top: var(--ev-space-l); }
body.theme-v19 .testimonials-certifications__viewport{ overflow: hidden; padding: 4px; margin: -4px; }
body.theme-v19 .testimonials-certifications__track{ display: flex; gap: 1.25rem; transition: transform .45s cubic-bezier(.22,.61,.36,1); will-change: transform; touch-action: pan-y; }
body.theme-v19 .testimonials-certifications__item{ flex: 0 0 calc((100% - 2.5rem) / 3); min-width: 0; background: #fff; border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-s); box-shadow: 0 8px 24px rgba(0, 32, 80, 0.06); }
body.theme-v19 .testimonials-certifications__rating{ color: var(--ev-navy); display: flex; gap: 2px; }
body.theme-v19 .testimonials-certifications__quote{ margin: 0; font-size: var(--ev-step-0); flex: 1; }
body.theme-v19 .testimonials-certifications__person{ display: flex; align-items: center; gap: var(--ev-space-xs); }
body.theme-v19 .testimonials-certifications__avatar{ width: 46px; height: 46px; border-radius: 100vmax; overflow: hidden; flex: 0 0 auto; }
body.theme-v19 .testimonials-certifications__avatar img{ width: 100%; height: 100%; object-fit: cover; }
body.theme-v19 .testimonials-certifications__name{ font-weight: 600; color: var(--ev-heading-color); margin: 0; }
body.theme-v19 .testimonials-certifications__zone{ font-size: var(--ev-step--2); color: var(--ev-text-color); margin: 0; }
body.theme-v19 .testimonials-certifications__controls{ display: flex; justify-content: center; gap: var(--ev-space-2xs); margin-top: var(--ev-space-s); }
body.theme-v19 .testimonials-certifications__nav{ width: 42px; height: 42px; border-radius: 100vmax; border: 1px solid var(--ev-border-color); background: #fff; color: var(--ev-heading-color); display: grid; place-items: center; cursor: pointer; box-shadow: var(--ev-shadow-sm); transition: transform .18s ease, border-color .18s ease, color .18s ease; }
body.theme-v19 .testimonials-certifications__nav:hover{ transform: translateY(-2px); border-color: var(--ev-primary); color: var(--ev-primary); }
body.theme-v19 .testimonials-certifications__nav:focus-visible{ outline: 2px solid var(--ev-primary); outline-offset: 2px; }
body.theme-v19 .testimonials-certifications__nav svg{ width: 18px; height: 18px; }
@media (max-width: 1024px) {
  body.theme-v19 .testimonials-certifications__item{ flex-basis: calc((100% - 1.25rem) / 2); }
}
@media (max-width: 640px) {
  body.theme-v19 .testimonials-certifications__summary{ align-items: stretch; flex-direction: column; }
  body.theme-v19 .testimonials-certifications__score-card{ justify-content: center; flex-wrap: wrap; text-align: center; gap: var(--ev-space-2xs) var(--ev-space-s); }
  body.theme-v19 .testimonials-certifications__review-btn{ width: 100%; }
  body.theme-v19 .testimonials-certifications__item{ flex-basis: 100%; padding: var(--ev-space-s); }
}

/* ============ PARTENAIRES ============ */
body.theme-v19 .partners-logos{ background: #fff; padding-block: var(--ev-space-xl); }
body.theme-v19 .partners-logos__list{ list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--ev-space-s); justify-content: center; margin-top: var(--ev-space-l); }
body.theme-v19 .partners-logos__list li{ display: inline-flex; align-items: center; gap: var(--ev-space-2xs); background: var(--ev-body-bg); border: 1px solid var(--ev-border-color); border-radius: 100vmax; padding: var(--ev-space-2xs) var(--ev-space-s); font-weight: 600; color: var(--ev-heading-color); font-size: var(--ev-step--1); }
body.theme-v19 .partners-logos__list li::before{ content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--ev-primary); flex: 0 0 auto; }

/* ============ BLOG ============ */
body.theme-v19 .blog-news{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .blog-news__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .blog-news__item{ background: #fff; border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); overflow: hidden; display: flex; flex-direction: column; }
body.theme-v19 .blog-news__body{ padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-2xs); flex: 1; }
body.theme-v19 .blog-news__tag{ align-self: flex-start; display: inline-block; background: color-mix(in srgb, var(--ev-primary, #c01010) 12%, white); color: var(--ev-primary); font-weight: 700; font-size: var(--ev-step--2); border-radius: 100vmax; padding: var(--ev-space-3xs) var(--ev-space-2xs); text-transform: uppercase; letter-spacing: .05em; }
body.theme-v19 .blog-news__item-title{ font-size: var(--ev-step-1); }
body.theme-v19 .blog-news__item-text{ margin: 0; font-size: var(--ev-step--1); }
body.theme-v19 .blog-news__link{
  margin-top: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  min-height: 44px;
  padding: .72rem 1.1rem;
  border: 1px solid var(--ev-primary);
  border-radius: 100vmax;
  background: var(--ev-primary);
  color: #fff !important /* !important : blanc forcé même sur :visited (un lien de blog visité ne doit pas virer violet) */;
  font-family: var(--ev-btn-font-family);
  font-size: var(--ev-step--1);
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 9px 20px -10px rgba(192, 16, 16, .8);
  transition: transform .2s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease;
}
body.theme-v19 a.blog-news__link, body.theme-v19 a.blog-news__link:visited{
  color: #fff !important /* !important : idem, variante a.blog-news__link:visited */;
}
body.theme-v19 .blog-news__link::after{
  content: "→";
  color: #fff;
  display: inline-block;
  font-size: 1.05em;
  line-height: 1;
  transition: transform .2s ease;
}
body.theme-v19 .blog-news__link:hover{
  background: color-mix(in srgb, var(--ev-primary) 88%, black);
  border-color: color-mix(in srgb, var(--ev-primary) 88%, black);
  color: #fff !important /* !important : blanc forcé même au survol, au-dessus d'un éventuel style de lien hérité */;
  transform: translateY(-2px);
  box-shadow: 0 13px 26px -12px rgba(192, 16, 16, .9);
}
body.theme-v19 .blog-news__link:hover::after{ transform: translateX(3px); }
body.theme-v19 .blog-news__link:focus-visible{
  outline: 3px solid color-mix(in srgb, var(--ev-primary) 28%, transparent);
  outline-offset: 3px;
}
@media (max-width: 520px) {
  body.theme-v19 .blog-news__link{ width: 100%; }
}

/* ============ ÉVÉNEMENTS ============ */
body.theme-v19 .events-prevention{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .events-prevention__grid{ margin-top: var(--ev-space-l); }
body.theme-v19 .events-prevention__item{ border-radius: var(--ev-border-radius); padding: var(--ev-space-m); display: flex; flex-direction: column; gap: var(--ev-space-2xs); border: 1px solid var(--ev-border-color); }
body.theme-v19 .events-prevention__item:nth-child(1){ background: color-mix(in srgb, var(--ev-navy) 6%, white); }
body.theme-v19 .events-prevention__item:nth-child(2){ background: color-mix(in srgb, var(--ev-primary) 6%, white); }
body.theme-v19 .events-prevention__item:nth-child(3){ background: color-mix(in srgb, var(--ev-accent) 12%, white); }
body.theme-v19 .events-prevention__period{ font-size: var(--ev-step--2); font-weight: 700; color: var(--ev-primary); text-transform: uppercase; letter-spacing: .06em; }
body.theme-v19 .events-prevention__item-title{ font-size: var(--ev-step-1); }
body.theme-v19 .events-prevention__item-text{ margin: 0; font-size: var(--ev-step--1); }

/* ============ VIDÉO ============ */
body.theme-v19 .video-presentation{
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(circle at 85% 20%, rgba(192,16,16,.12), transparent 28%),
    radial-gradient(circle at 8% 85%, rgba(127,176,232,.12), transparent 32%),
    linear-gradient(135deg, var(--ev-dark), var(--ev-navy));
  padding-block: clamp(4rem, 7vw, 6.5rem);
  color: #fff;
}
body.theme-v19 .video-presentation::before{
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.025) 1px, transparent 1px);
  background-size: 42px 42px;
  mask-image: linear-gradient(to bottom, rgba(0,0,0,.7), transparent 82%);
}
body.theme-v19 .video-presentation__content{
  position: relative;
  z-index: 1;
  max-width: 1220px;
}
body.theme-v19 .video-presentation__header{
  max-width: 900px;
  margin-inline: auto;
  text-align: center;
  justify-items: center;
}
body.theme-v19 .video-presentation__eyebrow{
  color: var(--ev-accent);
}
body.theme-v19 .video-presentation__title{
  color: #fff;
  max-width: none;
  margin-inline: auto;
}
body.theme-v19 .video-presentation__intro{
  color: rgba(255,255,255,.78);
  max-width: 72ch;
  margin-inline: auto;
}
body.theme-v19 .video-presentation__action{
  margin-top: var(--ev-space-m);
  display: flex;
  justify-content: center;
}
body.theme-v19 .video-presentation__action .btn{
  width: auto;
  min-width: min(280px, 100%);
  max-width: 100%;
  justify-content: center;
  padding-inline: clamp(1.4rem, 3vw, 2.4rem);
  background: rgba(255,255,255,.035);
  box-shadow: none;
}
/* .btn-outline-primary pose background/border-color/color en !important
   (voir plus haut dans ce fichier) : les déclarations `color`/`border-color`
   directes ci-dessus ne peuvent pas les battre, quelle que soit leur
   spécificité — d'où le bouton resté rouge sur fond sombre malgré cette
   règle (repéré par l'utilisateur, capture à l'appui). Même méthode que
   .hero-showcase__cta/.page-hero__cta/.final-cta__actions : repasser par la
   variable que la règle !important lit elle-même. */
body.theme-v19 .video-presentation__action .btn-outline-primary{
  /* border-color hérite aussi de cette variable (règle !important plus
     haut) : blanc plein, pas la peine de redéclarer border-color ici, ça
     resterait sans effet face au !important. */
  --ev-btn-outline-color: #fff;
}
/* !important nécessaire ici : .btn-outline-primary (non scopé à :hover)
   pose background/border-color/color en !important en permanence, y
   compris pendant le survol — sans ça cette règle reste sans effet, comme
   color/border-color l'étaient plus haut avant le passage par la variable
   (même cause). Constaté ici en vérifiant le survol après coup : aucun
   changement visuel sans le !important. */
body.theme-v19 .video-presentation__action .btn:hover{
  background: #fff !important;
  color: var(--ev-primary) !important;
  border-color: #fff !important;
}
body.theme-v19 .video-presentation__media{
  position: relative;
  margin-top: clamp(2rem, 4vw, 3.4rem);
  border-radius: clamp(18px, 2vw, 26px);
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.13);
  background: #00142f;
  box-shadow: 0 28px 70px rgba(0,0,0,.28);
}
body.theme-v19 .video-presentation__video{
  display: block;
  width: 100%;
  aspect-ratio: 16 / 8.7;
  object-fit: cover;
  background: #00142f;
}
body.theme-v19 .video-presentation__media::after{
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(0,17,45,.12), rgba(0,17,45,.48));
  transition: opacity .25s ease;
}
body.theme-v19 .video-presentation__media.is-playing::after{
  opacity: 0;
}
body.theme-v19 .video-presentation__play{
  position: absolute;
  z-index: 2;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: clamp(64px, 6vw, 84px);
  height: clamp(64px, 6vw, 84px);
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.9);
  background: #fff;
  color: var(--ev-primary);
  display: grid;
  place-items: center;
  cursor: pointer;
  box-shadow: 0 18px 45px rgba(0,0,0,.28);
  transition: transform .2s ease, box-shadow .2s ease;
}
body.theme-v19 .video-presentation__play:hover{
  transform: translate(-50%, -50%) scale(1.06);
  box-shadow: 0 22px 55px rgba(0,0,0,.36);
}
body.theme-v19 .video-presentation__play:focus-visible{
  outline: 3px solid var(--ev-accent);
  outline-offset: 4px;
}
body.theme-v19 .video-presentation__play::before{
  content: "";
  width: 0;
  height: 0;
  margin-left: 5px;
  border-left: 20px solid currentColor;
  border-top: 12px solid transparent;
  border-bottom: 12px solid transparent;
}
body.theme-v19 .video-presentation__media.is-playing .video-presentation__play{
  opacity: 0;
  pointer-events: none;
}
@media (max-width: 760px) {
  body.theme-v19 .video-presentation{ padding-block: 3.5rem; }
  body.theme-v19 .video-presentation__title{ max-width: none; }
  body.theme-v19 .video-presentation__media{ margin-top: 1.5rem; border-radius: 16px; }
  body.theme-v19 .video-presentation__video{ aspect-ratio: 4 / 3; }
}
@media (prefers-reduced-motion: reduce) {
  body.theme-v19 .video-presentation__play{ transition: none; }
}

/* ============ FAQ ============ */
body.theme-v19 .faq-section{ background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .faq-section__list{ margin-top: var(--ev-space-l); display: flex; flex-direction: column; gap: var(--ev-space-2xs); }
body.theme-v19 .faq-section__item{ background: #fff; border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius); overflow: hidden; }
body.theme-v19 .faq-section__item summary{ list-style: none; cursor: pointer; padding: var(--ev-space-s) var(--ev-space-m); display: flex; align-items: center; justify-content: space-between; gap: var(--ev-space-s); font-family: var(--ev-heading-font-family); font-weight: 600; font-size: var(--ev-step-1); color: var(--ev-heading-color); }
body.theme-v19 .faq-section__item summary::-webkit-details-marker{ display: none; }
body.theme-v19 .faq-section__item summary::marker{ content: ""; }
body.theme-v19 .faq-section__item summary::after{ content: ""; flex: 0 0 auto; width: 11px; height: 11px; border-right: 2px solid var(--ev-primary); border-bottom: 2px solid var(--ev-primary); transform: rotate(45deg); transition: transform .2s ease; margin-right: 4px; }
body.theme-v19 .faq-section__item[open] summary::after{ transform: rotate(225deg); }
body.theme-v19 .faq-section__item summary:focus-visible{ outline: 2px solid var(--ev-primary); outline-offset: -2px; }
body.theme-v19 .faq-section__answer{ padding: 0 var(--ev-space-m) var(--ev-space-m); margin: 0; font-size: var(--ev-step-0); }
body.theme-v19 .faq-section__item.is-single summary{ cursor: default; }
body.theme-v19 .faq-section__item.is-single summary::after{ display: none; }
body.theme-v19 .faq-section__cta-wrap{ display: flex; justify-content: center; margin-top: var(--ev-space-m); }
body.theme-v19 .faq-section__cta{ min-width: 190px; justify-content: center; }
@media (max-width: 560px) {
  body.theme-v19 .faq-section__cta-wrap{ margin-top: var(--ev-space-s); }
  body.theme-v19 .faq-section__cta{ width: 100%; }
}

/* ============ LOCALISATION ============ */
body.theme-v19 .location-map{ background: #fff; padding-block: var(--ev-space-2xl); }
body.theme-v19 .location-map__grid{ margin-top: var(--ev-space-l); display: grid; grid-template-columns: 1fr 0.9fr; gap: var(--ev-space-m); align-items: center; }
body.theme-v19 .location-map__media{ position: relative; }
body.theme-v19 .location-map__media-frame{ border-radius: var(--ev-border-radius); overflow: hidden; }
body.theme-v19 .location-map__body{ display: flex; flex-direction: column; gap: var(--ev-space-s); }
body.theme-v19 .location-map__zones{ list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--ev-space-2xs); }
body.theme-v19 .location-map__zones li{ display: flex; align-items: center; gap: var(--ev-space-2xs); font-size: var(--ev-step-0); }
body.theme-v19 .location-map__zones li::before{ content: ""; flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--ev-primary); }
body.theme-v19 .location-map__cta{ align-self: flex-start; margin-top: var(--ev-space-2xs); }
@media (max-width: 860px) { body.theme-v19 .location-map__grid{ grid-template-columns: 1fr; } }
@media (max-width: 560px) { body.theme-v19 .location-map__cta{ width: 100%; } }

/* ============ CTA FINAL ============ */
body.theme-v19 .final-cta{ background: linear-gradient(120deg, var(--ev-navy-light), var(--ev-dark)); padding-block: var(--ev-space-2xl); color: #fff; }
body.theme-v19 .final-cta__content{ text-align: center; display: flex; flex-direction: column; align-items: center; gap: var(--ev-space-s); max-width: 70ch; margin-inline: auto; }
body.theme-v19 .final-cta__eyebrow{ color: var(--ev-accent); }
body.theme-v19 .final-cta__title{ color: #fff; font-size: var(--ev-step-6); }
body.theme-v19 .final-cta__text{ color: rgba(255, 255, 255, 0.85); margin: 0; font-size: var(--ev-step-1); }
body.theme-v19 .final-cta__actions{ display: flex; flex-wrap: wrap; gap: var(--ev-space-xs); justify-content: center; }
body.theme-v19 .final-cta__actions .btn-primary{ box-shadow: 0 12px 30px -8px rgba(192, 16, 16, 0.55); }
body.theme-v19 .final-cta__actions .btn-outline-primary{ --ev-btn-outline-color: #fff; color: #fff; border-color: rgba(255, 255, 255, 0.5); }

/* ============ FOOTER ============ */
/* Mise en page reprise de _sources/debouchage-reseau-francilien-footer-photo-pro.html
   (maquette fournie par l'utilisateur) : double dégradé (fondu dans
   background-image + ::before en voile léger) + panneau "verre dépoli" sur
   .site-footer__content (pas .site-footer__grid : il englobe aussi
   .site-footer__bar, la barre de copyright, contrairement à la version
   précédente). Photo de fond : remplacée sur demande explicite par le
   visuel technicien + véhicule + Tour Eiffel (footer-technicien-tour-eiffel.png,
   celui de la maquette d'origine utilisait la même photo que .hero-showcase). */
body.theme-v19 .site-footer{
  position: relative;
  overflow: hidden;
  background-color: #001838;
  background-image:
    linear-gradient(125deg, rgba(0, 24, 56, 0.78) 0%, rgba(0, 24, 56, 0.66) 42%, rgba(0, 24, 56, 0.74) 100%),
    url("/assets/img/theme-v19/footer-technicien-tour-eiffel.png");
  background-size: cover;
  background-position: center 38%;
  background-repeat: no-repeat;
  color: rgba(255, 255, 255, 0.86);
  padding-block: clamp(2.75rem, 5vw, 4.5rem) var(--ev-space-m);
}
body.theme-v19 .site-footer::before{
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 9, 25, 0.08) 0%, rgba(0, 9, 25, 0.24) 100%);
  pointer-events: none;
}
body.theme-v19 .site-footer__content{
  position: relative;
  z-index: 1;
  padding: clamp(1.25rem, 2.5vw, 2rem);
  border-radius: 1.75rem;
  background: linear-gradient(180deg, rgba(0, 18, 43, 0.30) 0%, rgba(0, 18, 43, 0.22) 100%);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: 0 18px 44px rgba(0, 9, 25, 0.18);
}
body.theme-v19 .site-footer__grid{
  display: grid;
  grid-template-columns: minmax(0, 2.1fr) minmax(180px, .62fr) minmax(220px, .78fr);
  gap: clamp(2rem, 5vw, 6rem);
  align-items: start;
}
body.theme-v19 .site-footer__about{ min-width: 0; }
body.theme-v19 .site-footer__about-title, body.theme-v19 .site-footer__col-title{
  color: #fff;
  font-size: var(--ev-step-1);
  font-weight: 700;
  line-height: 1.25;
  margin: 0 0 var(--ev-space-s);
}
body.theme-v19 .site-footer__about-text{
  margin: 0;
  max-width: 72ch;
  color: rgba(255, 255, 255, 0.84);
  font-size: var(--ev-step--1);
  line-height: 1.65;
}
body.theme-v19 .site-footer__about-text + .site-footer__about-text{ margin-top: var(--ev-space-s); }
body.theme-v19 .site-footer__links, body.theme-v19 .site-footer__contact-list{
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .85rem;
}
body.theme-v19 .site-footer__links a, body.theme-v19 .site-footer__contact-list li{
  color: rgba(255, 255, 255, 0.82);
  font-size: var(--ev-step--1);
  line-height: 1.45;
}
body.theme-v19 .site-footer__links a{
  text-decoration: none;
  transition: color .2s ease, text-decoration-color .2s ease;
}
body.theme-v19 .site-footer__links a:hover, body.theme-v19 .site-footer__links a:focus-visible{
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* Le numéro de téléphone dans "Nos coordonnées" est désormais un lien
   tel: (au lieu d'un texte brut) : sans ceci, la couleur bleue/soulignée
   par défaut du navigateur pour <a> l'emporte sur la couleur héritée du
   <li> (une valeur héritée perd face à n'importe quelle valeur posée
   directement sur l'élément, même d'origine navigateur). */
body.theme-v19 .site-footer__contact-list li a{
  color: inherit;
  text-decoration: none;
  transition: color .2s ease, text-decoration-color .2s ease;
}
body.theme-v19 .site-footer__contact-list li a:hover, body.theme-v19 .site-footer__contact-list li a:focus-visible{
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 3px;
}
body.theme-v19 .site-footer__contact-block{ margin-top: var(--ev-space-l); }
body.theme-v19 .site-footer__bar{
  margin-top: clamp(2.75rem, 5vw, 4.75rem);
  padding-top: var(--ev-space-s);
  border-top: 1px solid rgba(255, 255, 255, 0.24);
  display: flex;
  flex-wrap: wrap;
  gap: var(--ev-space-s);
  justify-content: space-between;
  align-items: center;
  color: rgba(255, 255, 255, 0.74);
  font-size: var(--ev-step--2);
}
body.theme-v19 .site-footer__bar a{
  color: rgba(255, 255, 255, 0.82);
  text-decoration: underline;
  text-underline-offset: 2px;
}
body.theme-v19 .site-footer__scroll-top{
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  text-decoration: none !important /* !important : empêche le lien 'retour en haut' d'hériter du soulignement de .site-footer__bar a */;
  white-space: nowrap;
}
body.theme-v19 .site-footer__scroll-top:hover, body.theme-v19 .site-footer__scroll-top:focus-visible{ color: #fff; }
body.theme-v19 .site-footer__scroll-icon{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 1rem;
  line-height: 1;
  transform: translateY(-1px);
}
@media (max-width: 980px) {
  body.theme-v19 .site-footer__grid{
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--ev-space-xl) var(--ev-space-l);
  }
  body.theme-v19 .site-footer__about{ grid-column: 1 / -1; }
}
/* La compensation de padding ci-dessous doit couvrir exactement la plage où
   #sidebar_cta devient une barre fixe pleine largeur en bas d'écran
   (`width < 768px`, cf. règle plus haut dans ce fichier) : un seuil
   différent ici (620px à l'origine) laissait un entre-deux 620-768px où le
   footer restait masqué par la barre sans compensation. */
@media (width < 768px) {
  body.theme-v19 .site-footer{ padding-block: var(--ev-space-xl) calc(var(--ev-space-l) + 2.5rem); }
}
@media (max-width: 620px) {
  body.theme-v19 .site-footer__content{ padding: 1rem; border-radius: 1.25rem; }
  body.theme-v19 .site-footer__grid{ grid-template-columns: 1fr; gap: var(--ev-space-l); }
  body.theme-v19 .site-footer__about{ grid-column: auto; }
  body.theme-v19 .site-footer__contact-block{ margin-top: var(--ev-space-l); }
  body.theme-v19 .site-footer__bar{
    margin-top: var(--ev-space-xl);
    align-items: flex-start;
    flex-direction: column;
  }
}


/* ============ FORMULAIRE FIN DE PAGE ============ */
body.theme-v19 .lead-request-form{
  background: #fff;
  padding-block: var(--ev-space-2xl);
}
body.theme-v19 .lead-request-form__shell{
  display: grid;
  grid-template-columns: minmax(350px, .88fr) minmax(0, 1.12fr);
  max-width: 82rem;
  margin-inline: auto;
  background: #fff;
  border: 1px solid var(--ev-border-color);
  border-radius: 24px;
  overflow: hidden;
  box-shadow: 0 20px 52px rgba(0, 32, 80, .10);
}
body.theme-v19 .lead-request-form__aside{
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 610px;
  padding: clamp(2rem, 4vw, 3.5rem) clamp(1.75rem, 3vw, 3rem);
  background: linear-gradient(155deg, #001838 0%, var(--ev-navy) 58%, #0a2d63 100%);
  color: #fff;
}
body.theme-v19 .lead-request-form__aside > *{
  position: relative;
  z-index: 1;
}
body.theme-v19 .lead-request-form__aside::before{
  content: "";
  position: absolute;
  z-index: 0;
  left: clamp(1.75rem, 3vw, 3rem);
  bottom: 46px;
  width: 76px;
  height: 4px;
  border-radius: 100vmax;
  background: var(--ev-primary);
  box-shadow: 90px 0 0 rgba(127, 176, 232, .65);
}
body.theme-v19 .lead-request-form__decor{
  position: absolute;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}
body.theme-v19 .lead-request-form__decor svg{
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 100 / 130;
}
body.theme-v19 .lead-request-form__decor--bottom{
  right: 34px;
  bottom: 30px;
  width: clamp(126px, 11vw, 158px);
  opacity: .58;
}
@media (max-width: 980px) {
  body.theme-v19 .lead-request-form__decor--bottom{ right: 34px; bottom: 18px; width: 142px; }
}
@media (max-width: 640px) {
  body.theme-v19 .lead-request-form__decor--bottom{ right: 14px; bottom: 12px; width: 108px; opacity: .55; }
}
body.theme-v19 .lead-request-form__eyebrow{
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  margin: 0 0 var(--ev-space-s);
  color: var(--ev-accent);
  font-size: var(--ev-step--1);
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}
body.theme-v19 .lead-request-form__eyebrow::before{
  content: "";
  width: 28px;
  height: 2px;
  border-radius: 100vmax;
  background: var(--ev-primary);
}
body.theme-v19 .lead-request-form__title{
  width: 100%;
  max-width: 11ch;
  margin: 0 0 var(--ev-space-m);
  color: #fff;
  font-family: var(--ev-heading-font-family);
  font-size: clamp(2.25rem, 3.35vw, 3.75rem);
  line-height: 1.06;
  letter-spacing: -.03em;
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
}
body.theme-v19 .lead-request-form__intro{
  max-width: 36ch;
  margin: 0;
  color: rgba(255,255,255,.86);
  font-size: var(--ev-step-1);
  line-height: 1.55;
}
body.theme-v19 .lead-request-form__benefits{
  list-style: none;
  margin: var(--ev-space-l) 0 0;
  padding: 0;
  display: grid;
  gap: var(--ev-space-xs);
}
body.theme-v19 .lead-request-form__benefits li{
  display: flex;
  align-items: center;
  gap: .65rem;
  color: rgba(255,255,255,.9);
  font-size: var(--ev-step--1);
}
body.theme-v19 .lead-request-form__benefits li::before{
  content: "";
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ev-accent);
  box-shadow: 0 0 0 4px rgba(127, 176, 232, .10);
}
body.theme-v19 .lead-request-form__panel{
  min-width: 0;
  padding: clamp(2rem, 4vw, 4rem);
  background: #fff;
}
body.theme-v19 .lead-request-form__progress{
  display: flex;
  align-items: center;
  gap: .55rem;
  margin-bottom: var(--ev-space-m);
}
body.theme-v19 .lead-request-form__progress-dot{
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--ev-border-color);
  transition: background .2s ease, transform .2s ease;
}
body.theme-v19 .lead-request-form__progress-dot.is-active{
  background: var(--ev-primary);
  transform: scale(1.12);
}
body.theme-v19 .lead-request-form__step-title{
  display: block;
  float: none;
  width: 100%;
  margin: 0;
  padding: 0;
  color: var(--ev-heading-color);
  font-family: var(--ev-heading-font-family);
  font-size: var(--ev-step-2);
  font-weight: var(--ev-heading-font-weight);
  line-height: 1.2;
  letter-spacing: var(--ev-heading-letter-spacing);
}
body.theme-v19 .lead-request-form__step-title::after{
  content: "";
  display: block;
  width: 36px;
  height: 3px;
  margin-top: var(--ev-space-xs);
  border-radius: 100vmax;
  background: var(--ev-primary);
}
body.theme-v19 .lead-request-form__step-title + .lead-request-form__grid{
  margin-top: var(--ev-space-m);
}
body.theme-v19 .lead-request-form__fieldset{
  margin: var(--ev-space-l) 0 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
body.theme-v19 .lead-request-form__fieldset[hidden]{ display: none !important /* !important : renforce l'attribut HTML natif hidden face au layout grid/flex du formulaire */; }
body.theme-v19 .lead-request-form__grid{
  display: grid;
  grid-template-columns: repeat(2, minmax(0,1fr));
  gap: var(--ev-space-s);
}
body.theme-v19 .lead-request-form__field{
  display: flex;
  flex-direction: column;
  gap: .42rem;
  min-width: 0;
}
body.theme-v19 .lead-request-form__field--full{ grid-column: 1 / -1; }
body.theme-v19 .lead-request-form__label{
  color: var(--ev-heading-color);
  font-size: var(--ev-step--1);
  font-weight: 600;
}
body.theme-v19 .lead-request-form__required{ color: var(--ev-primary); }
body.theme-v19 .lead-request-form__input, body.theme-v19 .lead-request-form__select, body.theme-v19 .lead-request-form__textarea{
  width: 100%;
  min-height: 48px;
  border: 1px solid #d9e0e9;
  border-radius: 9px;
  background: #f8fafc;
  color: var(--ev-body-color);
  padding: .78rem .9rem;
  font: inherit;
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
body.theme-v19 .lead-request-form__textarea{
  min-height: 132px;
  resize: vertical;
}
body.theme-v19 .lead-request-form__input:focus, body.theme-v19 .lead-request-form__select:focus, body.theme-v19 .lead-request-form__textarea:focus{
  outline: none;
  background: #fff;
  border-color: color-mix(in srgb, var(--ev-primary) 65%, #fff);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ev-primary) 12%, transparent);
}
body.theme-v19 .lead-request-form__choice-grid{
  display: grid;
  grid-template-columns: repeat(2, minmax(0,1fr));
  gap: .65rem;
}
body.theme-v19 .lead-request-form__choice{
  position: relative;
  display: flex;
  align-items: center;
  gap: .7rem;
  min-height: 50px;
  padding: .72rem .8rem;
  border: 1px solid #d9e0e9;
  border-radius: 10px;
  background: #f8fafc;
  cursor: pointer;
  font-size: var(--ev-step--1);
  font-weight: 600;
  color: var(--ev-heading-color);
}
body.theme-v19 .lead-request-form__choice input{
  width: 17px;
  height: 17px;
  accent-color: var(--ev-primary);
}
body.theme-v19 .lead-request-form__choice:has(input:checked){
  border-color: color-mix(in srgb, var(--ev-primary) 55%, #fff);
  background: color-mix(in srgb, var(--ev-primary) 5%, #fff);
}
body.theme-v19 .lead-request-form__actions{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ev-space-s);
  margin-top: var(--ev-space-l);
}
body.theme-v19 .lead-request-form__actions--end{ justify-content: flex-end; }
body.theme-v19 .lead-request-form__back{
  border: 0;
  background: transparent;
  color: var(--ev-heading-color);
  padding: .75rem 0;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
body.theme-v19 .lead-request-form__back:hover{ color: var(--ev-primary); }
body.theme-v19 .lead-request-form__submit, body.theme-v19 .lead-request-form__next{
  min-width: 150px;
}
body.theme-v19 .lead-request-form__privacy{
  margin: var(--ev-space-m) 0 0;
  padding-top: var(--ev-space-s);
  border-top: 1px solid var(--ev-border-color);
  color: var(--ev-text-color);
  font-size: var(--ev-step--2);
  line-height: 1.55;
}
body.theme-v19 .lead-request-form__status{
  min-height: 1.2em;
  margin: var(--ev-space-xs) 0 0;
  color: var(--ev-primary);
  font-size: var(--ev-step--2);
  font-weight: 600;
}
@media (max-width: 900px) {
  body.theme-v19 .lead-request-form__shell{ grid-template-columns: 1fr; }
  body.theme-v19 .lead-request-form__aside{ min-height: auto; }
  body.theme-v19 .lead-request-form__title{ max-width: 18ch; font-size: clamp(2.15rem, 6vw, 3.25rem); }
  body.theme-v19 .lead-request-form__benefits{ grid-template-columns: repeat(3, minmax(0,1fr)); }
}
@media (max-width: 640px) {
  body.theme-v19 .lead-request-form{ padding-block: var(--ev-space-xl); }
  body.theme-v19 .lead-request-form__shell{ border-radius: 18px; }
  body.theme-v19 .lead-request-form__aside, body.theme-v19 .lead-request-form__panel{ padding: 1.35rem; }
  body.theme-v19 .lead-request-form__benefits{ grid-template-columns: 1fr; }
  body.theme-v19 .lead-request-form__grid, body.theme-v19 .lead-request-form__choice-grid{ grid-template-columns: 1fr; }
  body.theme-v19 .lead-request-form__field--full{ grid-column: auto; }
  body.theme-v19 .lead-request-form__actions{ align-items: stretch; flex-direction: column-reverse; }
  body.theme-v19 .lead-request-form__actions .btn{ width: 100%; }
  body.theme-v19 .lead-request-form__back{ width: 100%; text-align: center; }
}


/* =====================================================================
   ADAPTATIONS AUX GABARITS TWIG RÉELS DU PROJET
   -----------------------------------------------------------------
   Les deux sections ci-dessous NE viennent PAS de la référence V19
   telle quelle : la référence utilise des classes BEM propres
   (`.site-header`, `.lead-request-form__*`) qui n'existent dans AUCUN
   template du CMS NOBIS. Le header/nav et le formulaire de devis du
   projet sont déjà rendus par des partials Twig existants avec leurs
   propres classes (Bootstrap-like pour la nav, BEM `.flexible-form__*`
   pour le formulaire) — voir templates/vitrine/includes/header.html.twig,
   templates/vitrine/includes/nav.html.twig,
   templates/vitrine/formulaire/includes/{_form,_inputs}.html.twig.
   Renommer ces classes est hors périmètre (fichier Twig = interdit de
   toucher ici, cf. consigne de la tâche) et casserait le JS existant
   (Bootstrap Collapse pour le menu mobile, nextPrev()/captcha/upload
   pour le formulaire). On reprend donc uniquement le LANGAGE VISUEL
   V19 (couleurs, rayons, ombres, typo, espacements) et on l'applique
   directement sur les classes réelles, sans toucher au display/position
   qui pilote le comportement JS (collapse, étapes du formulaire).
   ===================================================================== */

/* ============ HEADER / NAV — classes réelles (.navbar, .nav-link, .navbar-cta…) ============ */
/* style.min.css pose `.navbar{ position:absolute !important; ... }` sans
   condition (pensé à l'origine pour un header transparent flottant sur une
   image de hero) : sorti du flux normal, il ne réserve plus sa hauteur, et
   le contenu qui suit (dont .page-hero) démarre SOUS le header au lieu
   d'après lui. Repéré via inspection CSSOM réelle : invisible sur l'accueil
   (le hero-showcase a assez de padding en haut pour absorber le
   chevauchement sans que ça se voie), flagrant sur .page-hero (fil
   d'Ariane collé tout en haut, rendu invisible sous le header). Un
   !important suffit à retrouver la position normale, aucune autre override
   nécessaire (background/box-shadow ci-dessous n'ont pas ce problème : la
   règle historique ne les pose pas en !important). */
body.theme-v19 .navbar {
  position: sticky !important;
  top: 0;
  z-index: 500;
  background: #fff;
  border-bottom: 1px solid var(--ev-border-color);
  transition: box-shadow .25s ease;
  /* Même règle historique que ci-dessus : width/padding posés en
     !important (ou sans contre-valeur explicite) laissaient un bandeau
     gris visible sur le bord droit du header (fond de la page qui
     transparaissait). Repris à zéro pour un bandeau plein largeur. */
  width: 100% !important;
  padding: 0 !important;
}
body.theme-v19 .navbar.scrolled { box-shadow: var(--ev-shadow-sm); }
/* Pas de max-width/padding-inline ici (contrairement à .container plus bas
   dans ce fichier) : sur groupecuratech.fr (même famille de template,
   inspecté en conditions réelles), la barre de nav est portée par un
   .container-fluid (padding seul, plein largeur, voir .site-header__wrap
   juste au-dessus) — .navbar-wrapper lui-même n'ajoute ni plafond ni
   second padding. Avec les deux (comme précédemment ici), le menu perdait
   ~250px de large disponible pour rien, ce qui l'empêchait de tenir sur
   une seule ligne même sur grand écran. */
body.theme-v19 .navbar-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ev-space-m);
  min-height: 78px;
  width: 100%;
}
body.theme-v19 .navbar-header { display: flex; align-items: center; gap: var(--ev-space-s); }
body.theme-v19 .navbar-header figure { margin: 0; }
/* Le logo (<img class="site-header__logo">, dans templates/vitrine/includes/
   _header_v19.html.twig) porte AUSSI la classe .navbar-header comme
   ancêtre : cette règle (class+class+tag, plus spécifique que .site-header__logo
   seule, class+class) écrasait silencieusement sa taille voulue (52px/44px
   plus bas dans ce fichier, jamais rendue) en 40px fixe, sans distinction
   desktop/mobile — repéré en demandant "agrandi un peu le logo" : la valeur
   affichée ne bougeait pas tant que celle-ci restait ici. Retirée plutôt que
   dupliquée : .site-header__logo est la règle voulue pour cet élément. */
body.theme-v19 .navbar-toggler {
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: var(--ev-space-2xs);
  color: var(--ev-heading-color);
}
body.theme-v19 .navbar-toggler .icon { --icon-height: 26px; --icon-color: var(--ev-heading-color); }
/* public/assets/css/style.min.css cible #navbarSupportedContent (l'id du
   menu, inchangé dans nav.html.twig) avec un fond arrondi en pilule
   (background: var(--ev-body-bg); border-radius: 100vmax) — un habillage
   NOBIS pensé pour un menu plus court. Avec le vrai menu du site (9 entrées,
   plus long que la maquette V19) et nos nouveaux espacements, les liens
   passent à la ligne À L'INTÉRIEUR de cette pilule, d'où l'effet "empilé"
   constaté le 2026-09-07. Un sélecteur #id a une spécificité plus forte que
   nos classes : on neutralise explicitement au même niveau (id + classe)
   pour retrouver un menu qui s'affiche directement dans la barre du header,
   sans fond ni découpe, comme dans la référence V19. */
/* min-width:0 + flex:1 1 auto : sans ça, un flex-item ne rétrécit jamais
   sous sa largeur de contenu naturelle (comportement par défaut de
   min-width:auto sur les items flex) — le menu poussait alors les boutons
   .navbar-cta hors de l'écran. */
body.theme-v19 #navbarSupportedContent{ background: none; border-radius: 0; padding: 0; min-width: 0; flex: 1 1 auto; }
/* flex-wrap: nowrap (et non wrap) : la référence groupecuratech.fr (même
   famille de template) tient tout le menu sur une seule ligne en
   réduisant gap/padding/police plutôt qu'en laissant les liens passer à
   la ligne. Avec wrap, un menu plus long que prévu se scindait en 2-3
   rangées centrées verticalement entre logo et CTA — effet "empilé"
   repéré par l'utilisateur, réglé par le seuil 1800px (media query plus
   bas) qui garantit que le menu ne s'affiche en ligne que quand il tient
   vraiment. Pas d'overflow-x:auto en secours (une version précédente en
   avait un) : ça clippait aussi les menus déroulants verticalement (règle
   CSS : overflow-x non-visible force overflow-y en auto), les rendant
   invisibles au clic. */
/* Par défaut (panneau burger, <1800px) : liste verticale classique. À partir
   de 1800px (voir media query plus bas), bascule en ligne horizontale. */
body.theme-v19 .navbar-nav { display: flex; flex-direction: column; align-items: stretch; gap: .15rem; margin: 0; padding: var(--ev-space-xs) 0; }
body.theme-v19 .navbar-nav .nav-item { position: relative; }
body.theme-v19 .navbar-nav .nav-link {
  display: inline-flex;
  align-items: center;
  gap: var(--ev-space-3xs);
  padding: .4rem .45rem;
  color: var(--ev-heading-color);
  font-weight: 600;
  font-size: .9rem;
  white-space: nowrap;
  text-decoration: none;
}
body.theme-v19 .navbar-nav .nav-link:hover,
body.theme-v19 .navbar-nav .nav-link:focus-visible { color: var(--ev-primary); }
body.theme-v19 .nav-link--sm-search,
body.theme-v19 .nav-link--lg-search { color: var(--ev-heading-color); }
/* Recherche : icône seule dans la barre (comme la référence), texte
   "Rechercher" conservé pour l'accessibilité mais masqué visuellement
   (pattern standard, pas de display:none pour rester lisible aux lecteurs
   d'écran). */
/* Classe utilitaire réutilisable (pas de .visually-hidden dans ce sous-set
   Bootstrap) : texte conservé pour les lecteurs d'écran, masqué à l'écran.
   Utilisée ici pour "Rechercher" et pour "Accueil" (nav-item--home,
   nav.html.twig). */
body.theme-v19 .visually-hidden-text{ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
body.theme-v19 .nav-link--lg-search span{ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
body.theme-v19 .navbar-cta { display: flex; align-items: center; gap: .5rem; flex: 0 0 auto; }
/* style.min.css pose .navbar-cta::before/::after : une encoche circulaire
   blanche décorative (radial-gradient, pensée à l'origine pour se fondre
   dans un fond de header blanc, donc invisible dans la maquette NOBIS
   d'origine). Le bouton .btn-primary rouge occupe maintenant exactement
   ce coin (right:0 = coin du dernier bouton) : l'encoche, restée blanche,
   devient visible dessus ("tache blanche" repérée par l'utilisateur).
   Repéré via inspection CSSOM réelle (getComputedStyle(::before/::after)),
   invisible en lecture statique du CSS. Neutralisée ici plutôt que
   supprimée dans style.min.css (fichier tiers partagé, non modifié). */
body.theme-v19 .navbar-cta::before,
body.theme-v19 .navbar-cta::after{ content: none; }
/* Boutons du header un peu plus compacts que les .btn génériques (utilisés
   ailleurs en pleine taille) : ça libère de la place pour le menu sans
   changer leur lisibilité. */
body.theme-v19 .navbar-cta .btn { padding: .55rem .9rem; font-size: .9rem; white-space: nowrap; }
body.theme-v19 .navbar-cta .btn.btn-secondary {
  background: linear-gradient(135deg, var(--ev-primary), color-mix(in srgb, var(--ev-primary) 100%, black 16%));
  /* border-color transparent : même liseré clair que .btn-primary plus
     haut dans ce fichier, même cause (bordure plate sur fond en dégradé
     diagonal) — corrigé partout, ce bouton du header inclus. */
  border: var(--ev-btn-border-width) solid transparent;
  color: #fff;
  border-radius: var(--ev-btn-border-radius);
  padding: var(--ev-btn-padding-y) var(--ev-btn-padding-x);
  font-weight: var(--ev-btn-font-weight);
}
/* Sous-menu Bootstrap standard, au cas où le HTML de navigation du CMS en
   ajoute un (structure absente aujourd'hui, cf. nav.html.twig, mais sans
   coût si jamais introduite plus tard). */
body.theme-v19 .navbar .dropdown-menu {
  position: absolute; top: 100%; left: 0; min-width: 220px; background: #fff;
  border: 1px solid var(--ev-border-color); border-radius: var(--ev-border-radius);
  box-shadow: var(--ev-shadow-lg); padding: var(--ev-space-2xs); margin: 0;
}
body.theme-v19 .navbar .dropdown-item { display: block; padding: var(--ev-space-2xs) var(--ev-space-xs); color: var(--ev-text-color); font-size: var(--ev-step-0); border-radius: 10px; }
body.theme-v19 .navbar .dropdown-item:hover,
body.theme-v19 .navbar .dropdown-item:focus-visible { background: var(--ev-body-bg); color: var(--ev-primary); }
/* Même correctif que .site-header .dropdown-item.active:hover ci-dessus
   (texte blanc illisible sur fond éclairci au survol d'un item actif). */
body.theme-v19 .navbar .dropdown-item.active:hover,
body.theme-v19 .navbar .dropdown-item.active:focus-visible { background: var(--ev-primary); color: #fff !important; }
@media (max-width: 991px) {
  body.theme-v19 .navbar-cta .btn { padding-inline: var(--ev-space-2xs); }
}
/* Boutons "Devis en ligne"/"Urgence 24/7" masqués en mobile : à 375px leur
   texte dépassait déjà du viewport ("Urgence 24/7" tronqué, capture
   utilisateur) et ils font doublon avec les actions équivalentes de
   #sidebar_cta, qui prennent le relais en bas d'écran sous la même largeur
   (`width < 768px` — inspiration https://groupecuratech.fr/, adapté à notre
   charte). L'élément porte 2 classes (`navbar-cta site-header__cta`,
   templates/vitrine/includes/_header_v19.html.twig) stylées séparément à 2
   endroits distincts de ce fichier (`.navbar-cta` ci-dessus, `.site-header__cta`
   plus haut ~L629) : masquer les 2 sélecteurs ici, APRÈS les deux définitions
   `display:flex`, pour que ce soit bien la dernière règle du fichier à
   s'appliquer aux deux (à spécificité égale, l'ordre source tranche). */
@media (width < 768px) {
  body.theme-v19 .site-header__cta,
  body.theme-v19 .navbar-cta{ display: none; }
}
/* Le vrai menu (9 entrées + 2 CTA) est plus long que celui de la démo V19 ou
   de groupecuratech.fr : même resserré au maximum (ci-dessus), il ne tient
   sur une seule ligne qu'à partir d'environ 1800px de large. `navbar-expand-lg`
   (Bootstrap, 992px) l'aurait affiché "en ligne" bien avant que ça ne rentre,
   ce qui recréait l'effet "empilé" repéré par l'utilisateur (menu qui
   passe à la ligne À L'INTÉRIEUR de la barre plutôt que de rester compact
   dans le menu burger). On repousse donc le seuil menu burger / menu en
   ligne à 1800px, en neutralisant ici la bascule à 992px de style.css. */
@media (max-width: 1799.98px) {
  body.theme-v19 .navbar-expand-lg .navbar-toggler { display: inline-flex !important; }
  body.theme-v19 .navbar-expand-lg .navbar-collapse:not(.show) { display: none !important; }
}
/* La pastille "actif/survol" (.nav-item:hover/.active, style.min.css:7855 —
   background + border-radius:100vmax) est pensée pour la barre horizontale
   desktop (item à largeur automatique, >=1800px ci-dessous) : sur un item
   pleine largeur du menu burger (<1800px, .navbar-collapse empilé), la même
   pastille s'étire sur toute la ligne et donne un gros bouton noir plein
   derrière l'icône "Accueil" (repéré par l'utilisateur, capture vs. menu
   burger épuré de https://groupecuratech.fr/ : aucune mise en avant de
   l'item courant, toutes les lignes ont le même style). On neutralise la
   pastille + le blanc forcé uniquement dans le menu burger ; la version
   desktop (>=1800px, largeur auto) garde son comportement d'origine. */
@media (max-width: 1799.98px) {
  body.theme-v19 .navbar-collapse .nav-item:hover,
  body.theme-v19 .navbar-collapse .nav-item.active {
    background: transparent;
    border-radius: 0;
  }
  body.theme-v19 .navbar-collapse .nav-item:hover .nav-link,
  body.theme-v19 .navbar-collapse .nav-item.active .nav-link {
    color: var(--ev-heading-color) !important;
  }
}
@media (min-width: 1800px) {
  body.theme-v19 .navbar-toggler { display: none !important; }
  /* Pas d'overflow-x:auto ici (versions précédentes en avaient un, en
     garde-fou anti-retour-à-la-ligne) : `overflow-x` non-`visible` force
     `overflow-y` à se comporter comme `auto` aussi (règle CSS, pas
     contournable avec overflow-y:visible séparément) — ça clippait
     verticalement TOUS les menus déroulants (.dropdown-menu, position
     absolute, dépasse sous la barre), les rendant invisibles au clic sur
     "Gammes de produits"/"Contact" (repéré par l'utilisateur). Le seuil
     1800px (ci-dessus) garantit déjà que le menu tient sans repasser à la
     ligne (vérifié empiriquement à l'ajout de ce seuil) ; si un jour le
     menu s'allonge encore, mieux vaut un débordement horizontal visible
     (repérable, non bloquant pour la navigation) que des menus déroulants
     muets. */
  body.theme-v19 .navbar-nav { flex-direction: row; align-items: center; flex-wrap: nowrap; gap: .6rem; padding: 0; }
  body.theme-v19 .navbar-nav .nav-item { flex: 0 0 auto; }
}

/* ============ FORMULAIRE DE DEMANDE — classes réelles (.flexible-form…) ============
   Bannière à 2 colonnes (volet marine + panneau blanc) reprise de la
   référence V19 (.lead-request-form du fichier source, tokens identiques
   aux nôtres : var(--ev-navy), var(--ev-primary), var(--ev-accent)...),
   appliquée aux classes RÉELLEMENT utilisées par ce projet plutôt que
   renommées (voir commentaire en tête de vitrine/formulaire/includes/_form.html.twig) :
   .flexible-form__aside (volet gauche, nouveau) + .flexible-form__panel
   (panneau droit, nouveau, contient l'ancien .flexible-form__container
   inchangé). Partagé par TOUTES les pages qui incluent _form.html.twig
   (accueil, page, article, combi, /contact/{id}). */
body.theme-v19 .flexible-form { background: var(--ev-body-bg); padding-block: var(--ev-space-2xl); }
body.theme-v19 .flexible-form__shell {
  display: grid;
  grid-template-columns: minmax(320px, .88fr) minmax(0, 1.12fr);
  max-width: var(--ev-grid-max-width);
  margin-inline: auto;
  background: #fff;
  border: 1px solid var(--ev-border-color);
  border-radius: 24px;
  overflow: hidden;
  box-shadow: var(--ev-shadow-lg);
}
body.theme-v19 .flexible-form__aside {
  position: relative;
  overflow: hidden;
  min-height: 560px;
  padding: clamp(2rem, 4vw, 3.5rem) clamp(1.75rem, 3vw, 3rem);
  background: linear-gradient(155deg, var(--ev-navy-deep) 0%, var(--ev-navy) 58%, var(--ev-navy-light) 100%);
  color: #fff;
}
/* Même halo décoratif que .hero-showcase::after (cohérence visuelle) :
   comble le vide du bas du volet marine, plus haut que large ici (contenu
   court, volet grand) sans gêner la lisibilité (derrière le texte, z-index
   implicite via position:relative sur les enfants directs uniquement). */
body.theme-v19 .flexible-form__aside::after{
  content: ""; position: absolute; left: -100px; bottom: -140px; width: 380px; height: 380px;
  border-radius: 50%; background: radial-gradient(circle, rgba(127, 176, 232, 0.22), transparent 70%);
  pointer-events: none;
}
body.theme-v19 .flexible-form__aside > * { position: relative; z-index: 1; }
body.theme-v19 .flexible-form__eyebrow {
  display: inline-flex; align-items: center; gap: .65rem; margin: 0 0 var(--ev-space-s);
  color: var(--ev-accent); font-size: var(--ev-step--1); font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
}
body.theme-v19 .flexible-form__eyebrow::before { content: ""; width: 28px; height: 2px; border-radius: 100vmax; background: var(--ev-primary); }
body.theme-v19 .flexible-form__aside .flexible-form__title {
  max-width: 12ch; margin: 0 0 var(--ev-space-m); color: #fff;
  font-size: clamp(2rem, 3vw, 2.75rem); line-height: 1.08; letter-spacing: -.02em;
}
/* public/assets/css/form-theme.css pose `.flexible-form .flexible-form__title::after`
   (tiret décoratif, pensé pour l'ancien titre centré) en `background:
   var(--ev-secondary)` — jaune hérité de NOBIS, jamais redéfini par notre
   thème (même variable déjà rencontrée pour #sidebar-cta-16086 et le
   survol des cartes d'article). Bien visible maintenant que le titre est
   dans le volet marine (repéré par l'utilisateur). Neutralisé : la
   référence V19 ne porte pas de tiret sous ce titre (l'eyebrow au-dessus
   en tient déjà lieu). */
body.theme-v19 .flexible-form__aside .flexible-form__title::after{ content: none; }
body.theme-v19 .flexible-form__aside .flexible-form__description {
  max-width: 38ch; margin: 0; color: rgba(255, 255, 255, .86); font-size: var(--ev-step-1); line-height: 1.55;
}
body.theme-v19 .flexible-form__benefits {
  list-style: none; margin: var(--ev-space-l) 0 0; padding: 0; display: grid; gap: var(--ev-space-xs);
}
body.theme-v19 .flexible-form__benefits li { display: flex; align-items: center; gap: .65rem; color: rgba(255, 255, 255, .9); font-size: var(--ev-step--1); }
body.theme-v19 .flexible-form__benefits li::before {
  content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
  background: var(--ev-accent); box-shadow: 0 0 0 4px rgba(127, 176, 232, .12);
}
body.theme-v19 .flexible-form__panel { min-width: 0; padding: clamp(1.75rem, 3.5vw, 3rem); background: #fff; }
body.theme-v19 .flexible-form__panel .flexible-form__container { max-width: none; margin: 0; padding-inline: 0; }
body.theme-v19 .flexible-form__steps { margin-bottom: var(--ev-space-m); }
body.theme-v19 .step-group { display: flex; align-items: center; gap: .5rem; justify-content: flex-start; }
body.theme-v19 .step-group .step { width: 11px; height: 11px; border-radius: 50%; background: var(--ev-border-color); transition: background .2s ease, transform .2s ease; }
body.theme-v19 .step-group .step.completed { background: var(--ev-primary); transform: scale(1.12); }
body.theme-v19 .flexible-form__panel .flexible-form__wrapper {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
}
@media (max-width: 900px) {
  body.theme-v19 .flexible-form__shell { grid-template-columns: 1fr; }
  body.theme-v19 .flexible-form__aside { min-height: auto; }
}
body.theme-v19 .alert-message--form { text-align: center; display: flex; flex-direction: column; align-items: center; gap: var(--ev-space-s); }
body.theme-v19 .alert-message__graphic svg #circle,
body.theme-v19 .alert-message__graphic svg #check { fill: var(--ev-primary); }
body.theme-v19 .alert-message__cta { display: flex; flex-wrap: wrap; gap: var(--ev-space-xs); justify-content: center; }
body.theme-v19 .flexible-form__body .row { display: flex; flex-wrap: wrap; gap: var(--ev-space-l); margin: 0; }
body.theme-v19 .flexible-form__body .row > .col { flex: 1 1 320px; min-width: 0; padding: 0; }
body.theme-v19 .flexible-form__step-title { font-size: var(--ev-step-2); color: var(--ev-heading-color); }
body.theme-v19 .flexible-form__step-title::after {
  content: ""; display: block; width: 36px; height: 3px; margin-top: var(--ev-space-xs);
  border-radius: 100vmax; background: var(--ev-primary);
}
/* style.css pose AUSSI `.flexible-form__step::after` (barre rouge en
   position absolute, bottom:0, sur le conteneur .flexible-form__step qui
   enveloppe subtitle+title+descr) : un second tiret, redondant avec celui
   ci-dessus mais positionné différemment (ancré au bas du conteneur plutôt
   qu'au fil du texte). Les deux étaient invisibles l'un sous l'autre avant
   la bannière à 2 colonnes ; désormais nettement séparés (repéré par
   l'utilisateur : "deux tiraits en rouge"). Un seul suffit, celui-ci
   (ancré au texte, cohérent quelle que soit la hauteur du conteneur) :
   l'autre est neutralisé ci-dessous plutôt que ce fichier-ci auquel il
   n'appartient pas. */
body.theme-v19 .flexible-form__step::after { content: none; }
body.theme-v19 .flexible-form__step-subtitle { font-size: var(--ev-step--2); text-transform: uppercase; letter-spacing: .06em; color: var(--ev-primary); font-weight: 700; }
body.theme-v19 .flexible-form__step-descr { color: var(--ev-text-color); margin-top: var(--ev-space-3xs); }
body.theme-v19 .form-group { margin-top: var(--ev-space-m); }
/* Libellés/champs alignés sur https://groupecuratech.fr/contact/demander-devis
   (même famille de gabarit, demandé explicitement par l'utilisateur pour
   /contact/demandez-un-devis — appliqué au composant partagé .flexible-form,
   donc valable partout où il est inclus) : libellé en graisse normale
   (curatech: font-weight 400, ici 600 à l'origine) et champs beaucoup moins
   arrondis (curatech: border-radius 0 — ramené ici à 6px plutôt que 0 pour
   rester cohérent avec le reste de notre charte, qui arrondit partout
   ailleurs boutons/cartes/pastilles). Couleur du libellé et fond/bordure du
   champ laissés inchangés : déjà très proches de la référence mesurée en
   CSSOM (fond #f8fafc vs référence rgb(248,248,251), bordure #d9e0e9 vs
   rgb(228,228,228)). */
body.theme-v19 .form-label { display: block; font-weight: 400; color: var(--ev-heading-color); font-size: var(--ev-step--1); margin-bottom: var(--ev-space-2xs); }
body.theme-v19 .form-help { display: block; color: var(--ev-text-color); font-size: var(--ev-step--2); font-weight: 400; }
body.theme-v19 .form-control,
body.theme-v19 select.form-control,
body.theme-v19 textarea.form-control {
  width: 100%; min-height: 48px; border: 1px solid #d9e0e9; border-radius: 6px;
  background: #f8fafc; color: var(--ev-body-color); padding: .78rem .9rem; font: inherit;
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
body.theme-v19 textarea.form-control { min-height: 132px; resize: vertical; }
body.theme-v19 .form-control:focus {
  outline: none; background: #fff;
  border-color: color-mix(in srgb, var(--ev-primary) 65%, #fff);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ev-primary) 12%, transparent);
}
/* form-theme.css pose 2 règles à spécificité égale ou supérieure qui
   forçaient une seule colonne quelle que soit la largeur d'écran :
   `.flexible-form .form-check-group{ grid-template-columns:1fr }` (2
   classes, source SCSS absente du style.min.css réellement servi, cf. son
   propre commentaire) et surtout `.form-page .flexible-form .form-check-group
   { max-width:480px; grid-template-columns:1fr }` (3 classes, spécifique à
   /contact) qui l'emportait sur la règle ci-dessous (2 classes) — d'où les
   réponses "Quel produit vous intéresse ?" empilées une par ligne au lieu
   des 2 colonnes voulues (repéré par l'utilisateur, capture à l'appui).
   Étendue à 3 classes (`.flexible-form` en plus) pour égaler l'ancre la
   plus spécifique ; theme-v19.css étant chargé après form-theme.css dans
   base.html.twig, elle l'emporte à spécificité égale. max-width neutralisé
   (form-theme.css le limitait à 480px, ce qui aurait cassé la disposition à
   2 colonnes une fois réellement appliquée). */
body.theme-v19 .flexible-form .form-check-group {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--ev-space-2xs); max-width: none;
}
/* Même cause que le fix .form-check-group juste au-dessus, sur les autres
   champs de l'étape 2 (textarea "Merci de décrire vos besoins", zone de
   dépôt de fichiers FilePond, bouton "Enregistrer") : form-theme.css pose
   `.form-page .flexible-form .form-control{ max-width:480px }` et
   `.form-page .flexible-form .flexible-form__footer .button-group{
   max-width:480px }`, hérité de l'époque où la grille de produits
   ("Quel produit vous intéresse ?") était ELLE AUSSI resserrée à 480px.
   Une fois cette grille repassée en pleine largeur (fix ci-dessus), ces
   champs sont restés bloqués à 480px, créant un décalage visible entre les
   pastilles produit (pleine largeur) et le reste du formulaire (resserré) —
   repéré par l'utilisateur, capture à l'appui. FilePond copie la classe
   `form-control` de l'<input type="file"> d'origine sur son propre
   `.filepond--root` (comportement standard de la librairie), donc la zone
   de dépôt est concernée par le même sélecteur que le textarea. */
body.theme-v19 .flexible-form .form-control { max-width: none; }
body.theme-v19 .flexible-form .flexible-form__footer .button-group { max-width: none; }
body.theme-v19 .form-check {
  position: relative; display: flex; align-items: center; gap: .7rem; min-height: 50px;
  padding: .72rem .8rem; border: 1px solid #d9e0e9; border-radius: 10px; background: #f8fafc;
}
body.theme-v19 .form-check:has(.form-check-input:checked) {
  /* :has() est utilisé ailleurs dans ce fichier (scroll-behavior scopé) ;
     ici, simple confort visuel — dégradation neutre (pas de highlight) si
     un navigateur ne le supporte pas. */
  border-color: color-mix(in srgb, var(--ev-primary) 55%, #fff);
  background: color-mix(in srgb, var(--ev-primary) 5%, #fff);
}
body.theme-v19 .form-check-input { width: 17px; height: 17px; accent-color: var(--ev-primary); }
body.theme-v19 .form-check-label { display: flex; align-items: center; gap: var(--ev-space-2xs); font-size: var(--ev-step--1); font-weight: 600; color: var(--ev-heading-color); cursor: pointer; }
body.theme-v19 .form-check-price { color: var(--ev-primary); }
body.theme-v19 .quantity-wrapper { display: flex; align-items: center; gap: var(--ev-space-2xs); margin-top: var(--ev-space-2xs); }
body.theme-v19 .quantity-btn { width: 32px; height: 32px; border-radius: 100vmax; border: 1px solid var(--ev-border-color); background: #fff; color: var(--ev-heading-color); cursor: pointer; }
body.theme-v19 .quantity-btn:hover { border-color: var(--ev-primary); color: var(--ev-primary); }
body.theme-v19 .captcha-container { display: flex; align-items: center; gap: var(--ev-space-xs); margin-bottom: var(--ev-space-2xs); }
body.theme-v19 .captcha-image { border-radius: 9px; border: 1px solid var(--ev-border-color); }
/* #recapCard (2e .col du .row dans .flexible-form__body, cf. _form.html.twig)
   n'affiche un vrai récapitulatif que pour les champs dont label_recap est
   renseigné (ftp/csv/rq_form.csv) — vide pour "demandez-un-devis" et
   "contactez-nous" (aucun champ concerné), mais reste dans le flux flex
   même vide. Avec .row en flex-wrap:wrap et le 1er .col déjà large, ce 2e
   .col vide (flex-basis:320px, style.css) ne tenait plus sur la même ligne
   et repassait à la ligne suivante : son row-gap (~46px) s'ajoutait quand
   même, créant un grand vide sous les champs avant le bouton "Suivant"
   (repéré par l'utilisateur, comparé à groupecuratech.fr — même famille de
   template, dont le formulaire n'a pas ce vide car son récapitulatif est
   soit absent soit non vide selon la page). Masqué seulement quand
   #recapCard ne contient aucune vraie carte de récap (:has() déjà utilisé
   ailleurs dans ce fichier) : sur un formulaire qui EN a (ex. un
   configurateur avec prix), le comportement à 2 colonnes reste inchangé. */
body.theme-v19 #recapCard:not(:has(.card--recap)) { display: none; }
body.theme-v19 .flexible-form__footer { margin-top: var(--ev-space-l); }
body.theme-v19 .button-group { display: flex; justify-content: flex-end; gap: var(--ev-space-xs); }
body.theme-v19 .flexible-form__recaptcha-info {
  margin-top: var(--ev-space-m); padding-top: var(--ev-space-s); border-top: 1px solid var(--ev-border-color);
  color: var(--ev-text-color); font-size: var(--ev-step--2); line-height: 1.55;
}
body.theme-v19 .link-primary { color: var(--ev-primary); text-decoration: underline; text-underline-offset: 2px; }
body.theme-v19 .btn-light { background: #fff; border: 1px solid var(--ev-border-color); color: var(--ev-heading-color); }
@media (max-width: 460px) {
  /* Sous 460px, 2 colonnes de cartes deviennent trop étroites pour les
     libellés les plus longs ("Insert à granulés", "Cuisinière à bois") :
     repasse à 1 colonne uniquement à partir de ce seuil, pas avant (à la
     différence de la règle précédente qui repassait à 1 colonne dès
     640px — hérité d'une époque où form-theme.css forçait de toute façon
     1 colonne partout, donc jamais visible en pratique). */
  body.theme-v19 .flexible-form .form-check-group { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  body.theme-v19 .flexible-form__body .row { flex-direction: column; }
  body.theme-v19 .button-group { flex-direction: column-reverse; }
  body.theme-v19 .button-group .btn { width: 100%; }
}

/* ============ CTA LATÉRAUX — tooltip CSS (complète le portage verbatim) ============
   Ajout minimal, hors périmètre strict de la référence (voir commentaire
   au-dessus du bloc verbatim `.sidebar-cta`, plus haut dans ce fichier) :
   un tooltip 100% CSS via `content: attr(data-tooltip)` sur les vrais boutons
   `.sidebar-cta__button .btn[data-tooltip]`, puisque `.custom-tooltip` n'est
   instancié par aucun script de la référence. */
body.theme-v19 .sidebar-cta__button .btn[data-tooltip] { position: relative; }
body.theme-v19 .sidebar-cta__button .btn[data-tooltip]::before {
  content: attr(data-tooltip);
  position: absolute;
  right: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  background: rgba(var(--ev-dark-rgb), .9);
  color: #fff;
  padding: var(--ev-space-2xs) var(--ev-space-xs);
  border-radius: 4px;
  font-size: var(--ev-step--2);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s ease;
  z-index: 1000;
}
body.theme-v19 .sidebar-cta__button .btn[data-tooltip]:hover::before,
body.theme-v19 .sidebar-cta__button .btn[data-tooltip]:focus-visible::before { opacity: 1; }
@media (max-width: 767px) {
  body.theme-v19 .sidebar-cta__button .btn[data-tooltip]::before { display: none; } /* évite tout scintillement de la bulle au tap sur mobile */
}

/* ============ ANCRE #request-form ============
   templates/home/index.html.twig ajoute un <span id="request-form"> juste
   avant l'include du formulaire réel (_form.html.twig, dont l'id rendu est
   dynamique : flexibleForm{tb_form_c_nom}). Tous les CTA V19 de la page
   ("Devis", CTA latéral, booking-cta, final-cta, faq-section, location-map…)
   pointent vers #request-form : display: block est nécessaire pour qu'un
   <span> (inline par défaut) accepte scroll-margin-top ; le décalage
   compense le header sticky (.site-header) pour que le clic sur un CTA ne
   fasse pas défiler le titre du formulaire sous le header. */
body.theme-v19 .theme-v19-anchor {
  display: block;
  scroll-margin-top: calc(var(--ev-space-l, 2rem) + 72px);
}

/* ============ LARGEUR EXPLICITE PAR SECTION (renfort) ============
   Renfort demandé par le client : une règle dédiée par section (comme
   gallery-portfolio, qui en avait déjà une héritée de la référence),
   plutôt que de compter uniquement sur la règle générique .container
   ci-dessus. Même formule que .container (clamp(20rem,80%,74rem) à
   partir de 768px), donc aucun changement de largeur réelle attendu —
   seulement une garantie supplémentaire, section par section, contre
   toute règle qui pourrait un jour neutraliser .container pour un
   conteneur en particulier. gallery-portfolio__content (82rem, plus
   large, voir plus haut) et final-cta__content (70ch, texte centré)
   gardent leur traitement spécifique déjà correct. */
body.theme-v19 .hero-showcase__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .services-offer__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .advantages-reasons__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .about-company__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .features-product__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .process-steps__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .static-metrics__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .compare-methods__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .guarantees-reassurance__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .pricing-structure__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .animated-counter__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .countdown-timer__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .booking-cta__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .opening-hours__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .case-achievements__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .single-case-study__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .company-timeline__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .team-members__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .awards-distinctions__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .testimonials-certifications__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .partners-logos__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .blog-news__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .events-prevention__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .video-presentation__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .faq-section__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
body.theme-v19 .location-map__content{ width: 100%; margin-inline: auto; padding-inline: var(--ev-grid-gutter); }
@media (min-width: 768px) {
  body.theme-v19 .hero-showcase__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .services-offer__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .advantages-reasons__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .about-company__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .features-product__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .process-steps__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .static-metrics__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .compare-methods__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .guarantees-reassurance__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .pricing-structure__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .animated-counter__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .countdown-timer__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .booking-cta__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .opening-hours__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .case-achievements__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .single-case-study__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .company-timeline__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .team-members__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .awards-distinctions__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .testimonials-certifications__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .partners-logos__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .blog-news__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .events-prevention__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .video-presentation__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .faq-section__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
  body.theme-v19 .location-map__content{ max-width: clamp(var(--ev-grid-min-width), var(--ev-grid-preferred-width), var(--ev-grid-max-width)); }
}

/* ============ MASQUAGE DU CTA LATÉRAL NOBIS D'ORIGINE (accueil) ============
   CAUSE RÉELLE DE L'ORANGE/JAUNE ET DU CHEVAUCHEMENT SIGNALÉS À PLUSIEURS
   REPRISES : `ftp/csv/objet.csv` contient une ligne (ID 16086, position
   `after_menu`, VISIBLE_ALL=1 — donc affichée sur les 26 gabarits du site,
   pas seulement l'accueil) qui injecte un CTA latéral NOBIS D'ORIGINE,
   totalement distinct de #sidebar_cta (le nôtre, aux couleurs V19) :
     <section id="sidebar-cta-16086" class="sidebar-cta__fixed">
   Stylé par public/assets/css/objet.css avec `.sidebar-cta__fixed{
   position:fixed; right:0; top:33vh; z-index:999 }` (quasi la même position
   que notre #sidebar_cta) et `.sidebar-cta__icon{ background:
   var(--ev-secondary, ...) }`, où --ev-secondary vaut #ffbb00 (JAUNE) dans
   public/assets/css/root.css — variable que notre thème ne redéfinit pas
   (nous ne redéfinissons que --ev-primary/--ev-navy/--ev-accent). Aucun bug
   de cascade ou de cache : c'est un second composant, entièrement différent,
   qui se superposait au nôtre.
   On ne désactive PAS la ligne 16086 dans objet.csv (elle reste nécessaire
   sur les 25 autres pages, qui n'ont pas de #sidebar_cta V19) : on masque
   uniquement son rendu sur l'accueil, par CSS scopé. */
body.theme-v19 #sidebar-cta-16086{ display: none !important; }

/* ============ SURVOL DES CARTES D'ARTICLE (listing blog/catégorie) ============
   style.min.css pose `.article--list .article__item:hover{ background-color:
   var(--ev-secondary) }` — --ev-secondary vaut #ffbb00 (jaune), la même
   variable "secondaire" héritée de NOBIS déjà identifiée au-dessus pour
   #sidebar-cta-16086. Pas touché à --ev-secondary lui-même (44 usages dans
   style.css, dont .btn-secondary — trop large pour être sûr de ne rien
   casser ailleurs) : override ciblé sur ce survol précis, avec nos propres
   couleurs (rouge/marine) plutôt que le jaune resté de la maquette NOBIS. */
body.theme-v19 .article--list .article__item{ transition: box-shadow .2s ease, border-color .2s ease, background-color .2s ease; }
body.theme-v19 .article--list .article__item:hover{
  background-color: var(--ev-body-bg);
  border-color: rgba(var(--ev-primary-rgb), .35);
  box-shadow: var(--ev-shadow-lg);
}
/* Même famille de résidu NOBIS que .article--list .article__item:hover
   ci-dessus : `.label-secondary` (badge catégorie des cartes, ex. "POÊLES
   À GRANULÉS", templates/vitrine/article/index.html.twig) pose en dur
   `background-color:rgba(255,187,0,.16)!important; color:#8a6100!important`
   (jaune/brun --ev-secondary), détonnant sur les cartes blanches du thème
   V19 (repéré par l'utilisateur, capture à l'appui). `.label-secondary`
   n'est utilisée nulle part ailleurs sur le site (vérifié) : sûr de
   redéfinir la classe elle-même plutôt que de la neutraliser au cas par
   cas. !important nécessaire pour battre la règle ci-dessus, elle-même
   !important. Teinte marine douce plutôt que rouge plein, pour rester
   visuellement distincte du badge `.label-danger` (rouge) déjà utilisé sur
   les mêmes cartes pour d'autres informations. */
body.theme-v19 .label-secondary{
  background-color: color-mix(in srgb, var(--ev-navy) 12%, white) !important;
  color: var(--ev-navy) !important;
  border: none !important;
}
/* Le contenu de descriptionCategorie (ftp/csv/article.csv, colonne
   DESCRIPTION_CATEGORIE) embarque son propre "<h2>Titre</h2>texte" ; le
   gabarit l'enveloppe dans <p>...</p> (vitrine/article/index.html.twig
   L90), qui ne peut pas contenir de <h2> (bloc dans bloc) : le navigateur
   ferme le <p> avant, laissant le <h2> et son texte sans <p> autour —
   aucun style de marge ne s'applique donc plus (`.article__description--
   start__text p{ margin:0 }`, style.css, ne concerne que les vrais <p>),
   d'où le titre collé au texte qui suit (repéré par l'utilisateur, capture
   à l'appui, "partout" = ce même schéma sur toutes les catégories). */
body.theme-v19 .article__description--start__text h2{ margin: 0 0 var(--ev-space-2xs); }

/* Titre de carte produit (grille "Gammes de produits") sur 1 ligne pour un
   nom court ("Poêle à granulés A10 Light") mais 2 lignes pour un nom plus
   long ("... A10 Classic Plus") : chaque carte a sa propre grille interne
   (style.css `.article__item-content{ grid-template-areas: "title"
   "description" ... }`), indépendante des cartes voisines — la zone
   description démarre donc juste après SON titre à elle, à une hauteur qui
   varie d'une carte à l'autre selon que le titre tienne sur 1 ou 2 lignes,
   ce qui décale tout le bas de carte (description, CTA) d'une carte à
   l'autre sur une même rangée (repéré par l'utilisateur, capture à
   l'appui). Hauteur de titre réservée pour 2 lignes systématiquement (les
   titres plus courts gardent l'espace vide plutôt que de laisser la
   description remonter), + line-clamp à 2 lignes en garde-fou si jamais un
   titre futur était encore plus long. */
body.theme-v19 .article--list .article__item-content .title{
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.3em;
}

/* Fiche article (main.article--details) : après le bandeau .page-hero
   (fond pleine largeur, mais avec son propre .container interne pour le
   texte — inchangé ici), tout le reste de la page (tableau de
   caractéristiques + blocs paragraphe : personnalisation, accordéons...)
   est enveloppé dans un vrai <div class="container-fluid"> Bootstrap
   (style.css : `.container-fluid{ max-width: var(--ev-container-fluid-
   max-width, initial) }`, donc réellement illimité), contrairement au
   reste du site qui passe systématiquement par .container (~1140px) ou
   --ev-grid-max-width (1420px). Résultat : le corps de la fiche s'étire en
   continu avec la largeur d'écran, jusqu'à ~2530px de large mesuré sur un
   viewport de 2560px — repéré par l'utilisateur ("container fluide"), qui
   ne correspond à aucune autre page du site. Recentré avec les mêmes
   valeurs que .container (mêmes variables). Certains blocs à l'intérieur
   (ex. .color-palette__container) ont déjà leur propre max-width/padding
   interne : sans effet indésirable ici, la colonne qui les contient
   (.article__container--criteria, grille 70/30) est de toute façon déjà
   plus étroite que --ev-grid-max-width à tous les gabarits d'écran
   courants — leur propre contrainte ne s'active donc jamais en pratique. */
body.theme-v19 main.article--details > .container-fluid{
  max-width: var(--ev-grid-max-width);
  margin-inline: auto;
  padding-inline: var(--ev-grid-gutter);
}
/* Le tableau de caractéristiques (.article__criteria, 2e colonne de la
   grille 70/30 .article__container--criteria) doit rester aéré/continuer
   jusqu'au bord droit de l'écran, contrairement à la colonne de texte à sa
   gauche qui reste dans le conteneur recentré ci-dessus (demande explicite
   de l'utilisateur, capture à l'appui — pas un retour en arrière sur le
   recentrage : seule cette colonne "casse" volontairement le conteneur).
   Marge négative = exactement l'espace retiré par le recentrage ci-dessus
   (padding-right du conteneur + la moitié de l'espace au-delà de
   --ev-grid-max-width, quand l'écran est plus large) ; padding-right
   repose ensuite un peu d'air propre entre le tableau et le vrai bord de
   l'écran plutôt qu'un collage complet — porté à 62px (largeur mesurée
   d'un bouton rond de #sidebar_cta, fixed right:0, présent sur toutes les
   pages) + le gutter habituel : sans cette marge, les valeurs alignées à
   droite du tableau (ex. "3,4 – 9,3") passaient sous les boutons flottants
   au lieu de s'arrêter avant (#sidebar_cta est vertical, ~30% de la
   hauteur d'écran, mais .article__criteria est sticky sur ~88vh : les deux
   se croisent forcément pendant le défilement). */
body.theme-v19 .article--details .article__criteria{
  /* --ev-grid-gutter fixé en dur ici (2.5rem, PAS la variable) : ce calc
     n'agit qu'à partir de 992px (colonne masquée en dessous), où le gutter
     fluide vaut maintenant moins que 2.5rem jusqu'à 1420px — réduire ce
     padding-right réduirait d'autant le dégagement déjà ajusté au pixel
     près contre #sidebar_cta (62px, largeur mesurée du bouton rond fixed),
     recréant le chevauchement que ce correctif visait justement à éviter.
     Comportement figé à l'identique d'avant le passage du gutter en
     fluide. */
  margin-right: calc(-1 * (2.5rem + max(0px, (100vw - var(--ev-grid-max-width)) / 2)));
  padding-right: calc(62px + 2.5rem);
}

/* ============ FICHE ARTICLE — TABLEAU DE CARACTÉRISTIQUES ============
   style.css ne fixe aucune taille de police pour .article__criteria-item :
   il hérite donc du corps de texte courant (--ev-step-0, 16-18px selon la
   largeur d'écran) — correct pour un paragraphe, mais visuellement gros
   pour un tableau dense de caractéristiques techniques (repéré par
   l'utilisateur, capture à l'appui : 18px à 1440px). Ramené à
   --ev-step--1 (12.8-14.2px), déjà utilisé ailleurs sur le site pour ce
   type de texte secondaire dense (badges, aide de formulaire...). */
body.theme-v19 .article--details .article__criteria-item{ font-size: var(--ev-step--1); }
/* Trait sous "Informations générales"/"Technologies" (.article__criteria-title
   ::after, style.css) : `background-color: var(--ev-primary-300, var(--ev-neutral))`
   — --ev-primary-300 n'est jamais défini à la racine (seulement à
   l'intérieur de classes utilitaires .text-danger/.bg-success/etc., sans
   rapport ici), retombe donc sur --ev-neutral (#25303b, un bleu-ardoise
   sombre) — perçu comme bleu par l'utilisateur, capture à l'appui. Recoloré
   en rouge (--ev-primary), cohérent avec les autres accents/soulignés du
   thème. Règle déjà commune à toutes les fiches produit avec tableau de
   caractéristiques (aucun scope supplémentaire nécessaire pour "partout"). */
body.theme-v19 .article--details .article__criteria-title::after{ background-color: var(--ev-primary); }

/* Puces "Couleurs disponibles" (critère à plusieurs valeurs, ex. "# blanc",
   "# noir"...) : style.css transforme ces liens en chips grises génériques
   (background #e9ecef, texte #495057, contour gris #d0d0d0, préfixe "#" en
   ::before) — un style de secours neutre, sans rapport avec la charte du
   site, avec ce "#" que l'utilisateur n'aime pas (capture à l'appui).
   Repassé en marine doux plutôt que rouge (1er essai) : ces puces
   affichent de VRAIES couleurs produit (blanc, noir, bordeaux...) — les
   teinter toutes en rouge égalait leur sens informatif à celui d'un CTA,
   incohérent avec .label-secondary (badge catégorie des cartes produit,
   plus haut dans ce fichier) déjà repassé en marine pour la même raison de
   badge informatif plutôt qu'accent. Rouge réservé aux boutons/CTA/accents
   (bouton "Découvrir nos produits", traits sous les titres...), marine aux
   badges d'info — cohérence gardée entre les deux badges similaires du
   site plutôt qu'un choix isolé au cas par cas. */
/* !important nécessaire sur color : style.css groupe ce même sélecteur
   avec .btn (`.btn, .article--details .article__criteria-item:not(
   [data-tag-number="1"]) a { color: var(--btn-color) !important }`) —
   --btn-color n'est jamais définie ici (aucune classe .btn-primary/
   .btn-outline-primary posée sur ce lien), var() invalide retombe alors sur
   la couleur héritée (gris ~#666, ni le gris d'origine ni la nôtre).
   !important nécessaire sur padding pour la même raison : une autre règle
   de style.css pose `padding: var(--ev-space-2xs) var(--ev-space-m)
   var(--ev-space-xs) !important` (haut ≠ bas, ~10px/~15px) — texte décalé
   verticalement dans la puce plutôt que centré (repéré par l'utilisateur,
   capture à l'appui). Repassé symétrique. */
body.theme-v19 .article--details .article__criteria-item:not([data-tag-number="1"]) a{
  background-color: color-mix(in srgb, var(--ev-navy) 8%, white);
  color: var(--ev-navy) !important;
  border: 1px solid color-mix(in srgb, var(--ev-navy) 25%, white);
  padding: var(--ev-space-2xs) var(--ev-space-m) !important;
}
body.theme-v19 .article--details .article__criteria-item:not([data-tag-number="1"]) a::before{ content: none; }
body.theme-v19 .article--details .article__criteria-item:not([data-tag-number="1"]) a:hover,
body.theme-v19 .article--details .article__criteria-item:not([data-tag-number="1"]) a:focus{
  background-color: var(--ev-navy);
  color: #fff !important;
  border-color: var(--ev-navy);
}

/* ============ FICHE ARTICLE — BLOCS OBJET DANS LA COLONNE ÉTROITE ============
   `.article__container--criteria` (posée par details.html.twig uniquement
   si criteriaGroup est défini — donc seulement quand un tableau de
   caractéristiques existe) réduit la colonne de contenu (paragraphes,
   FAQ...) à ~70% de la largeur de page, au lieu de la pleine largeur.
   Les blocs "objet" du CMS insérés dans cette colonne (accordéon FAQ,
   palette de couleurs...) sont conçus par objet.css pour occuper jusqu'à
   --ev-grid-max-width (1420px) en 2 colonnes côte à côte (question/kicker à
   gauche, contenu à droite) — cette disposition ne passe déjà en 1 colonne
   empilée qu'en dessous de 992px de LARGEUR D'ÉCRAN (media query), qui ne
   sait rien de la largeur réelle, bien plus étroite, de cette colonne à
   70%. Résultat sur desktop large : les 2 sous-colonnes de l'accordéon FAQ
   ("Questions fréquentes sur...") se retrouvaient écrasées sur ~400px
   chacune, texte des questions cassé n'importe où, gros vide sous le
   bandeau de titre à gauche pendant que les questions s'empilent à droite
   — repéré par l'utilisateur ("tout est décalé"), capture à l'appui.
   Rebasculé en disposition empilée (comme sous 992px) dès que ce bloc est
   dans la colonne étroite, quelle que soit la largeur d'écran réelle. */
body.theme-v19 .article__container--criteria .accordion__row{ flex-direction: column; }
body.theme-v19 .article__container--criteria .accordion__header:has(.accordion__figure){ flex: 1; }
/* .accordion__body-wrap (liste des questions) a `margin-top:3.25rem` (52px,
   objet.css) : pensé pour la disposition 2 colonnes d'origine, où ce
   décalage aligne à peu près le haut des questions sur le texte du titre à
   côté. Une fois rebasculé en pile (règle ci-dessus), ce même décalage
   devient un grand vide entre le titre et la 1ère question — déjà neutralisé
   par objet.css en dessous de 992px de largeur d'écran (même schéma que la
   correction précédente), mais pas dans ce cas (colonne étroite due au
   tableau de caractéristiques, largeur d'écran normale) — repéré par
   l'utilisateur, capture à l'appui. */
body.theme-v19 .article__container--criteria .accordion__body-wrap{ margin-top: 0; }
/* Même cause, sur le FAQ accordéon de l'accueil (#accordion-90029, avec
   image ajoutée à la demande de l'utilisateur) : objet.css pousse
   `.accordion__body-wrap` de 3.25rem (52px) vers le bas, pensé pour
   compenser la hauteur du seul titre+kicker à côté (disposition d'origine,
   sans image) — une fois une image ajoutée sous le titre, ce décalage fixe
   n'a plus de rapport avec le contenu réel de la colonne de gauche et
   pousse la 1ère question plus bas que le haut de l'image, sans raison —
   repéré par l'utilisateur ("l'image ne doit pas être décalée par rapport
   aux questions"). Scopé à cet objet précis (pas une règle générale sur
   .accordion__header:has(.accordion__figure), qui existe aussi ailleurs
   sur des fiches produit non concernées par cette demande). */
body.theme-v19 #accordion-90029 .accordion__body-wrap{ margin-top: 0; }
/* Titre collé à l'image (#accordion-90029) : objet.css prévoit un espace
   au-dessus de la figure (`.accordion__figure{ margin-top: var(--ev-space-m) }`)
   mais TROIS règles l'écrasent en cascade : `body.theme-v19 figure{ margin:0 }`
   (reset générique, plus haut dans ce fichier) est déjà battue par
   `figure{ margin:0 !important }` posée par style.css (sélecteur nu, sans
   scoping — probablement un reset générique visant blockquote/figure/etc.),
   qui gagne quelle que soit la spécificité en face tant qu'elle n'est pas
   elle-même battue par un autre !important — vérifié via CSS.getMatchedStylesForNode
   (CDP), qui montre la valeur finale calculée à 0px malgré la règle
   `.accordion__figure` d'objet.css. D'où le titre collé directement au
   sommet de l'image, sans le moindre espace — repéré par l'utilisateur,
   capture à l'appui. !important nécessaire ici pour la même raison que
   `.grid-column{ gap:...!important }` un peu plus haut dans ce fichier.
   Pas scopé à #accordion-90029 : la même figure `.accordion__figure`
   existe aussi sur plusieurs fiches produit (ex. "Tout savoir sur l'insert
   à granulés") avec exactement le même bug latent, jamais signalé jusqu'ici
   mais pas propre à l'accueil — restaure l'espacement prévu par objet.css
   partout où ce composant a une image. */
body.theme-v19 .accordion__figure{ margin-top: var(--ev-space-m) !important; }
/* "Espace sous la dernière question" / section qui semble décalée
   (#accordion-90029) : `.accordion__row{ display:flex }` (objet.css, sans
   align-items déclaré donc stretch par défaut) étire la colonne de gauche
   (.accordion__header, titre+kicker+image) à la même hauteur que la
   colonne de droite (.accordion__body-wrap, 4 questions + bouton, plus
   haute) — mais l'image elle-même garde sa taille fixe (400px), elle ne
   grandit pas avec cet étirement invisible : il reste donc un bloc de vide
   blanc sous l'image, à peu près à la hauteur du bouton "Une autre
   question ?" en face — repéré par l'utilisateur (capture, flèche sous le
   bouton). Fait grandir l'image elle-même pour occuper tout l'espace
   disponible dans la colonne étirée (recadrée en hauteur via
   object-fit:cover, sans déformation ni recadrage horizontal) au lieu de
   laisser un vide à côté d'elle. Scopé à cet objet précis : les autres
   accordéons avec image (fiches produit) ont une seule question courte en
   face, pas de déséquilibre de hauteur comparable à corriger là-bas. */
body.theme-v19 #accordion-90029 .accordion__header{ display: flex; flex-direction: column; }
body.theme-v19 #accordion-90029 .accordion__figure{ flex: 1 1 auto; min-height: 0; }
body.theme-v19 #accordion-90029 .accordion__img{ width: 100%; height: 100%; object-fit: cover; }
/* Kicker "Les réponses qui peuvent faire la différence" en pastille grise
   (#accordion-90029) : objet.css le stylise via `.accordion__header
   .accordion__description` (fond gris clair, contour arrondi en pilule,
   texte marine) — un style repris de l'exemple produit dont ce markup est
   issu (nécessaire pour placer correctement l'image, cf. plus haut), mais
   visuellement à part du reste de l'accueil, où chaque section utilise le
   même kicker "eyebrow" : texte rouge, majuscules, sans fond ni contour
   (ex. "CONSEILS" sur .blog-news, "Où nous trouver" sur .location-map) —
   repéré par l'utilisateur en comparant les deux captures. Réaligné sur ce
   même style .eyebrow (mêmes jetons --ev-eyebrow-*) plutôt que d'inventer
   une couleur : cohérent avec tout le reste de la page. Scopé à cet objet
   précis : la pastille grise reste inchangée sur les fiches produit qui
   utilisent la même figure (pas concernées par cette demande, propre à
   l'accueil). */
body.theme-v19 #accordion-90029 .accordion__description{
  background: none; border: none; border-radius: 0; padding: 0;
  display: block; width: auto;
  color: var(--ev-eyebrow-color); font-family: var(--ev-heading-font-family);
  font-size: var(--ev-eyebrow-font-size); font-weight: var(--ev-eyebrow-font-weight);
  letter-spacing: var(--ev-eyebrow-letter-spacing); text-transform: var(--ev-eyebrow-case);
  margin: 0 0 var(--ev-eyebrow-margin-bottom);
}
/* Le texte du kicker vit dans un <p> imbriqué (`<div class="accordion__
   description"><p>...</p></div>`) : `body.theme-v19 p{ color:... }` plus
   haut dans ce fichier matche ce <p> DIRECTEMENT et l'emporte sur la
   couleur seulement héritée du div ci-dessus, quelle que soit sa
   spécificité (même leçon que .color-palette__description /
   .callout-color-bg__description déjà rencontrée dans ce fichier). */
body.theme-v19 #accordion-90029 .accordion__description p{ color: inherit; margin: 0; }
/* .accordion (bloc FAQ, ex. "Questions fréquentes sur ...") n'a lui-même
   aucune marge propre (contrairement à .color-palette, plus haut, qui en a
   une) : collé directement au bloc paragraphe précédent, dont le bouton CTA
   se retrouvait à ~8px du kicker "Les réponses qui peuvent faire la
   différence" du FAQ suivant — repéré par l'utilisateur sur une fiche
   produit, capture à l'appui, demande explicite "partout dans le site" (le
   bloc FAQ est un objet CMS générique, réutilisé sur toute fiche produit
   qui en a un, pas propre à cette seule page). Même espace que
   .color-palette pour une respiration cohérente entre blocs consécutifs. */
body.theme-v19 .accordion{ margin-top: var(--ev-space-l); }
/* .accordion__item-header (question + bouton +/-) : objet.css ne pose pas
   d'align-items (défaut "stretch") — sur desktop la question tient sur 1
   ligne, ça ne se voit pas, mais sur mobile une question longue passe sur
   4-5 lignes ("Quelle est la puissance de chauffe du poêle à granulés 10
   Lisa ?") : le bouton s'étire alors sur toute cette hauteur et l'icône
   +/- à l'intérieur (simple <i>, pas elle-même centrée) atterrit collée en
   haut du bouton au lieu d'être alignée avec le texte — flottement visuel
   au milieu du bloc, repéré par l'utilisateur ("pas tout à fait
   responsive"), demande explicite "partout" (composant CMS générique,
   réutilisé sur toutes les fiches produit avec FAQ). Bouton aligné en haut
   de la question (aligné à la 1ère ligne, lecture naturelle) plutôt
   qu'étiré, et centré sur lui-même quelle que soit sa hauteur propre. */
body.theme-v19 .accordion__item-header{ align-items: flex-start; }
body.theme-v19 .accordion__item-toggler{
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; margin-top: 0.2em;
}

/* public/assets/css/style.css:7061 pose `.article__criteria-label{
   white-space: nowrap }` sans exception mobile : le libellé le plus long
   d'une fiche produit (ex. "Puissance électrique en fonctionnement (W)")
   forçait alors `.article__criteria-item` (flex row, sans wrap) à dépasser
   du viewport (débordement horizontal mesuré : 39px à 375px). Fichier tiers
   non modifié : autorisé à repasser à la ligne uniquement sous 768px, où la
   place manque (au-dessus, la sidebar sticky a la place voulue). */
@media (max-width: 767px) {
  body.theme-v19 .article--details .article__criteria-label{ white-space: normal; }
}

/* ============ BLOC OBJET "CALLOUT-COLOR-BG" — IMAGE OPTIONNELLE ============
   .callout-color-bg (ex. objet 16072 "<<<#entreprise.nom#>>>, le confort
   d'un chauffage performant et élégant", page "À propos") a par défaut une
   flamme SVG décorative posée en ::after par objet.css, hotlink vers
   l'ancien CDN Nobis (/nobis/svg/abstract-1.svg) — demande de l'utilisateur :
   remplacer cette flamme par un VRAI champ image (400x400), configurable
   à gauche ou à droite, capture à l'appui.

   CONTRAT (à copier tel quel pour un nouvel objet basé sur ce même bloc,
   ou pour un objet EXISTANT qui utilise déjà .callout-color-bg et qu'on
   veut faire passer à une image réelle) :
     - ajouter, en enfant direct de .callout-color-bg__container, À CÔTÉ de
       .callout-color-bg__content (pas dedans) :
       <figure class="callout-color-bg__media" data-position="right"> <!-- ou "left" -->
         <img src="..." width="400" height="400" alt="..." loading="lazy">
       </figure>
     - data-position="right" ou "left" choisit le côté.
     - ACTIVER/DÉSACTIVER l'image (config demandée par l'utilisateur) :
       ajouter l'attribut HTML `hidden` sur la balise <figure> pour la
       désactiver (texte seul, sans flamme, qui reprend automatiquement
       toute la largeur disponible — voir juste en dessous) ; retirer
       `hidden` pour la réactiver. Rien d'autre à changer : l'attribut
       `src`/position restent en place, prêts à réafficher l'image telle
       quelle dès que `hidden` est retiré.

   RÉTROCOMPATIBILITÉ (sujet explicite de l'utilisateur — 3 autres objets
   utilisent déjà .callout-color-bg SANS ce champ image du tout : 16070
   (pages 2606244871/2606244872), 16071 (page 2606244873)) : tout est scopé
   via :has(.callout-color-bg__media), donc SANS EFFET sur un objet qui n'a
   pas ajouté cette figure — il continue de s'afficher exactement comme
   avant (texte seul + flamme SVG en ::after, inchangée). La flamme n'est
   neutralisée QUE sur les instances qui ont VRAIMENT une figure .callout-
   color-bg__media dans leur HTML — qu'elle soit actuellement affichée ou
   désactivée via `hidden` (un objet qui a adopté ce nouveau système
   d'image ne doit plus jamais revoir l'ancienne flamme, même image
   désactivée) ; seule la mise en page à 2 colonnes (texte + image) dépend
   elle de :not([hidden]) — désactivée, le texte repasse en 1 colonne
   centrée pleine largeur automatiquement, pas besoin d'ajuster autre
   chose. */
body.theme-v19 .callout-color-bg:has(.callout-color-bg__media)::after{ content: none; }
body.theme-v19 .callout-color-bg__container:has(.callout-color-bg__media:not([hidden])){
  display: flex;
  align-items: center;
  gap: var(--ev-space-xl);
  flex-wrap: wrap;
}
body.theme-v19 .callout-color-bg__container:has(.callout-color-bg__media:not([hidden])) .callout-color-bg__content{
  flex: 1 1 380px;
  min-width: 0;
  max-width: none;
}
/* Image désactivée (hidden) ou tout simplement absente : le texte reprend
   toute la largeur du conteneur, centré, plutôt que de rester calé à
   gauche avec un grand vide à droite (l'ancien espace de la flamme). */
body.theme-v19 .callout-color-bg__container:has(.callout-color-bg__media[hidden]) .callout-color-bg__content{
  max-width: 640px;
  margin-inline: auto;
  text-align: center;
}
body.theme-v19 .callout-color-bg__media{
  flex: 0 0 auto;
  width: min(400px, 100%);
  aspect-ratio: 1 / 1;
  border-radius: var(--ev-border-radius);
  overflow: hidden;
  margin: 0;
}
body.theme-v19 .callout-color-bg__media img{ width: 100%; height: 100%; object-fit: cover; display: block; }
body.theme-v19 .callout-color-bg__media[data-position="left"]{ order: -1; }
@media (width < 640px) {
  /* Empilé verticalement plutôt que côte à côte trop resserré : image
     après le texte quel que soit data-position (le texte doit rester lu
     en premier sur mobile). */
  body.theme-v19 .callout-color-bg__media{ order: 1; width: 100%; max-width: 400px; margin-inline: auto; }
}
/* Espace avant/après la carte : objet.css pose padding-block:var(--ev-space-2xl)
   (jusqu'à 96px en haut ET en bas) sur .callout-color-bg — pensé pour une
   section pleine largeur entre 2 blocs de page, ça fait beaucoup de vide
   une fois que .callout-color-bg est une carte blanche compacte avec ses
   propres coins arrondis (repéré par l'utilisateur, capture à l'appui,
   traits au-dessus du titre et en dessous du bouton/image). Réduit à
   --ev-space-l : s'applique aux 4 objets existants (composant partagé),
   aucun n'a signalé ce padding réduit comme un problème. */
body.theme-v19 .callout-color-bg{ padding-block: var(--ev-space-l); }
/* Espace titre -> description : objet.css pose .callout-color-bg__description
   { margin-block: var(--ev-space-l) ... } (48px au-dessus), redéfini une 2e
   fois plus loin dans le fichier avec la même valeur — la règle de reset
   .callout-color-bg__content > *{ margin:0 } (même spécificité, plus tôt
   dans le fichier) ne l'emporte donc pas. Repéré par l'utilisateur sur la
   variante centrée sans image, capture à l'appui, mais la règle est
   commune aux 4 objets qui partagent ce composant. Resserré à --ev-space-xs. */
body.theme-v19 .callout-color-bg__description{ margin-top: var(--ev-space-xs); }

/* ============ BLOC OBJET "CALLOUT-COLOR-BG" — COULEUR DE FOND ============
   Demande de l'utilisateur : pouvoir choisir le fond de la carte entre
   blanc/clair, rouge et bleu marine (les 3 couleurs de la charte), avec une
   config pour ça — en vérifiant d'abord si ça existe déjà.

   ÇA EXISTAIT DÉJÀ EN PARTIE, MAIS CASSÉ : le <section id="callout-color-bg-
   ..."> porte un style inline `--bg-color: var(--ev-light)` (visible sur
   les 4 objets existants), qui ressemble à une config de couleur... mais
   objet.css n'utilise JAMAIS cette variable : `.callout-color-bg{
   background-color: var(--ev-light) }` est câblé en dur. Ce style inline
   n'a donc jamais eu d'effet, sur aucun des 4 objets. Remplacé par un
   mécanisme qui fonctionne réellement.

   CONFIG (attribut `data-theme` posé directement sur l'élément qui porte la
   classe .callout-color-bg — <div class="callout-color-bg container">,
   PAS sur le <section> parent, qui ne porte pas cette classe) — 3 valeurs :
     data-theme="light"   fond clair (défaut actuel), titre/texte marine, bouton rouge plein
     data-theme="primary" fond rouge, titre/texte blancs, bouton inversé (fond blanc, texte rouge)
     data-theme="navy"    fond marine, titre/texte blancs, bouton rouge plein (déjà lisible sur
                           marine, même traitement que .final-cta ailleurs sur le site)
   Sans attribut data-theme du tout (objet qui n'a pas encore adopté cette
   config) : comportement inchangé, fond clair par défaut — rétrocompatible
   avec les 4 objets existants. */
body.theme-v19 .callout-color-bg[data-theme="primary"]{ background-color: var(--ev-primary); }
body.theme-v19 .callout-color-bg[data-theme="navy"]{ background-color: var(--ev-navy); }
/* .callout-color-bg__description contient un <p> (contenu CSV) : lui poser
   color:#fff ne suffit pas, un <p> matche directement `body.theme-v19 p`
   (même passé en :where() plus haut dans ce fichier, pour battre .color-
   palette__description au même titre) — un <p> a beau être moins
   spécifique, une couleur posée DIRECTEMENT sur un élément l'emporte
   toujours sur une couleur seulement HÉRITÉE d'un ancêtre (même leçon que
   .color-palette__description un peu plus haut) : il faut viser le <p> lui
   -même, pas seulement son parent .callout-color-bg__description. */
body.theme-v19 .callout-color-bg[data-theme="primary"] .callout-color-bg__title,
body.theme-v19 .callout-color-bg[data-theme="primary"] .callout-color-bg__description,
body.theme-v19 .callout-color-bg[data-theme="primary"] .callout-color-bg__description p,
body.theme-v19 .callout-color-bg[data-theme="navy"] .callout-color-bg__title,
body.theme-v19 .callout-color-bg[data-theme="navy"] .callout-color-bg__description,
body.theme-v19 .callout-color-bg[data-theme="navy"] .callout-color-bg__description p{
  color: #fff;
}
body.theme-v19 .callout-color-bg[data-theme="primary"] .btn-primary{
  background: #fff !important;
  border-color: #fff !important;
  color: var(--ev-primary) !important;
}

/* ============ BARRE DE DÉBOGAGE SYMFONY (web debug toolbar) ============
   Repéré par l'utilisateur en bas de page (capture) : "Loading the web
   debug toolbar… Attempt #1" restait bloqué au lieu de disparaître,
   au lieu du contenu normal de la barre (temps de réponse, requêtes SQL…).
   Ce texte de secours vient de WebProfilerBundle lui-même (vendor/symfony/
   web-profiler-bundle/Resources/views/Profiler/cancel.html.twig) : la
   barre se charge normalement via une requête JS de fond vers /_wdt/{token}
   une fois la page affichée, et affiche ce placeholder tant que cette
   requête n'a pas abouti.
   Cause probable, hors périmètre de ce dépôt : nobis.arbi.entmail.fr est
   derrière une passerelle SSO (auth.arbi.entmail.fr, vérifié — toute
   requête vers le domaine, y compris de simples pages, y est redirigée) ;
   si cette passerelle intercepte aussi la requête de fond vers /_wdt/*,
   celle-ci échoue en boucle et la barre reste bloquée sur ce message. Cette
   passerelle est configurée au niveau de l'infrastructure (VPS/Cloudflare),
   pas dans ce dépôt (nobis/_save) : aucun fichier ici ne peut agir dessus.
   En local (sans cette passerelle), la même requête répond 200 sans
   problème — le mécanisme applicatif lui-même n'est pas en cause.
   Cette barre est un outil de DEBUG DEV uniquement (jamais censée être
   vue par un vrai visiteur, cf. APP_ENV=dev documenté dans CLAUDE.md) :
   on la masque entièrement plutôt que de laisser cet état cassé visible,
   y compris son "clearer" (réservait l'espace en bas de page pour elle,
   sinon un vide inutile subsisterait à sa place une fois masquée). */
body.theme-v19 .sf-toolbar,
body.theme-v19 .sf-toolbar-clearer{ display: none !important; }

/* ============ H3 CMS dans un bloc "paragraph" (ex. page mentions légales :
   "Éditeur du site :", "Hébergeur du site :"...) ============
   Le contenu vient du back-office sous forme de <h3>Titre :</h3>Texte...<br>
   directement dans .paragraph__description, sans <p> autour du texte (un H3
   n'est pas autorisé dans un <p>, donc le navigateur referme le <p> dès qu'il
   le rencontre) : le texte qui suit est un simple nœud de texte, pas un bloc.
   style.css ne fixe aucune marge sur h1..h6 (laissée aux composants), donc
   seule la marge propre du H3 sépare le titre du texte — ici quasi nulle,
   d'où le collage titre/texte repéré par l'utilisateur. */
body.theme-v19 .paragraph__description h2,
body.theme-v19 .paragraph__description h3{ margin: var(--ev-space-m) 0 var(--ev-space-3xs); }
body.theme-v19 .paragraph__description h2:first-child,
body.theme-v19 .paragraph__description h3:first-child{ margin-top: 0; }

/* ============ OBJET CMS #16552 "Nos services de débouchage WC et sanitaires" ============
   Import eva-section du 2026-09-14 (objet.csv/objet.css/objet.js, cf.
   _sources/Nos services de débouchage WC et sanitaires.zip). Son thème
   `data-theme="section-transparent"` force `padding: 0 ... !important` en
   haut (objet.css) — pensé pour s'empiler SANS coupure sous une section
   colorée, mais ici collé directement à .final-cta juste au-dessus (repéré
   par l'utilisateur). Ciblé par ID plutôt que sur `[data-theme="section-
   transparent"]` en général : ce thème est réutilisable par d'autres objets
   (actuels ou futurs) où ce padding nul en haut peut être voulu. */
#eva_section-16552{ padding-top: var(--ev-space-2xl) !important; }
/* Titre illisible dans les pastilles "visible-cadre" (fond rouge, cf. capture
   utilisateur) : objet.css met le texte en blanc via `color:
   var(--eva-theme-card-title-color)` sur .eva-card__title-link (le lien qui
   porte le fond dégradé), mais .eva-card__title-text hérite aussi de la
   classe .item-title — un utilitaire du thème V19 (générique, utilisé par
   plein d'autres cartes du site) qui pose sa propre couleur (bleu marine)
   *directement* sur ce même span. Une valeur posée directement bat toujours
   une valeur héritée, quelle que soit la spécificité : d'où le texte marine
   au lieu du blanc voulu. Pas propre à l'objet #16552 : tout futur import
   eva-section avec ce style de titre buterait sur le même conflit. */
body.theme-v19 .eva-section[data-show-title="visible-cadre"] .eva-card__title-text.item-title{ color: #fff; }
