/*
Theme Name: Bisem Vitrine
Theme URI:
Author: Michel
Description: Thème généré à partir de la maquette Adobe XD BISEM_V4_responsive_dev_ok — site vitrine du fabricant français d'ascenseurs Bisem.
Version: 1.0
Requires at least: 6.0
Requires PHP: 7.4
Text Domain: bisem-vitrine
*/

/* Masqué temporairement à la demande du client (2026-09-22) : MyBisem et le
   sélecteur de langue seront affichés plus tard — ne pas supprimer le HTML
   qui porte cette classe, juste ce display:none, pour pouvoir tout
   réactiver d'un coup en retirant la classe. */
.is-hidden-tmp { display: none !important; }

/* ==========================================================================
   Design tokens — voir notes-design.md pour la source
   ========================================================================== */
:root {
  /* Couleurs */
  /* Couleurs exactes extraites du fichier .xd (style.fill.color de chaque
     calque texte, voir scripts/extract_typography.py) — remplacent les
     valeurs approchées par échantillonnage pixel utilisées précédemment. */
  --color-primary: #E62E40;
  --color-primary-dark: #BC2534;
  --color-primary-light: #E62E40; /* MyBisem : même rouge que le CTA principal (voir header.php) */
  --color-navy: #081020;
  --color-navy-accent: #23397D;
  --color-star: #FFDA44; /* notes des témoignages */
  --color-bg-light: #FFF4F5;
  --color-bg-white: #FFFFFF;
  --color-text: #000000;
  --color-text-inverse: #FFFFFF;
  --color-border: #DCDCDC;

  /* Typographie — polices de marque confirmées, voir functions.php
     (titres/sous-titres en Stack Sans Notch, texte/boutons en Google Sans Flex) */
  --font-heading: 'Stack Sans Notch', 'Arial Narrow', Impact, sans-serif;
  --font-body: 'Google Sans Flex', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  /* Rayons / ombres */
  --radius-hero: 48px;
  --radius-pill: 999px;
  --radius-card: 16px;

  /* Largeurs */
  --container-max: 1200px;

  /* Breakpoints (référence — voir notes-design.md) */
  --breakpoint-tablet: 768px;
  --breakpoint-desktop: 1200px;
}

/* ==========================================================================
   Reset minimal
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; overflow-x: hidden; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px; /* taille de corps de texte dominante dans le .xd (Google Sans Flex Regular 17px / lh 25px) */
  color: var(--color-text);
  background: var(--color-bg-white);
  line-height: 1.47;
  /* Garde-fou : plusieurs éléments décoratifs (ex. .stats-timeline__item::after)
     utilisent width:100vw + translateX(-50%) pour déborder jusqu'aux bords
     réels de l'écran sur mobile — un écart de calcul de quelques pixels
     suffit à provoquer un vrai scroll horizontal du document. */
  overflow-x: hidden;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
button { font-family: inherit; cursor: pointer; }
h1, h2, h3, h4 {
  font-family: var(--font-heading);
  font-weight: 700;
  font-style: normal;
  text-transform: uppercase;
  line-height: 1.05;
  margin: 0 0 0.5em;
  color: var(--color-navy-accent);
}
.hero__title { color: var(--color-text-inverse) !important; }

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: 16px;
}

/* ==========================================================================
   Header / nav
   ========================================================================== */
.site-header {
  position: absolute;
  /* Alignée sur la marge du hero (.hero { margin: 28px }) + son padding
     interne (32px) pour donner l'impression que le header vit dans le
     cadre du hero, avec le même retrait que .hero__content, .hero__social... */
  top: 28px; left: 28px; right: 28px;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 24px 32px;
}
/* Pastille blanche derrière le logo (visible dans le .xd — "BISEM®" vit
   dans une capsule blanche, pas flottant directement sur le dégradé). */
.site-header__logo {
  display: inline-flex; align-items: center;
  background: var(--color-bg-white);
  border-radius: var(--radius-pill);
  padding: 2px 0;
}
.site-header__logo img { height: 52px; }
.site-header__actions { display: flex; align-items: center; gap: 8px; }
/* Mobile : logo + MyBisem + Contact + burger déborde à 375px avec les
   paddings desktop — on réduit les pilules et on masque "Contact" (déjà
   accessible depuis le menu burger) plutôt que de les faire wrapper. */
@media (max-width: 480px) {
  .site-header__logo img { height: 40px; }
  .site-header__actions { gap: 6px; }
  .site-header__actions .btn--contact { display: none; }
  .site-header__actions .btn--accent { padding: 8px 16px; font-size: 0.75rem; }
}
/* MyBisem passe sous le logo (au lieu d'à côté, dans .site-header__actions),
   même taille que la pastille du logo (112x44px, mesuré) — position:absolute
   par rapport à .site-header (premier ancêtre positionné, ignore le flex
   .site-header__actions qui n'est pas lui-même positionné). Le burger reste
   seul dans .site-header__actions, toujours callé à droite via le
   justify-content:space-between du header. */
@media (max-width: 767px) {
  .site-header .js-mybisem-soon {
    position: absolute;
    /* left:16px (pas 0) : position:absolute se cale sur le bord du
       padding-box de .site-header, qui ignore son propre padding interne
       (16px en mobile) — sans ce décalage explicite, le bouton partait 16px
       plus à gauche que le logo (positionné, lui, dans le flux normal donc
       affecté par ce padding). */
    top: 81px; left: 16px;
    width: 112px; height: 44px;
    padding: 0;
    display: flex; align-items: center; justify-content: center;
  }
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 17px 35px;
  border-radius: var(--radius-pill);
  /* Google Sans Flex Medium 15px, letter-spacing 1.5px, uppercase — valeurs
     exactes du .xd (ex: calques "Demander un devis", "En savoir plus"). */
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  border: none;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.btn--primary { background: var(--color-primary); color: var(--color-text-inverse); }
@media (max-width: 767px) {
  .btn--primary { padding: 12px 25px; }
  .btn--icon { padding: 10px 10px; }
}
/* MyBisem (portail SAV) utilise une teinte rouge plus claire et distincte
   du CTA principal dans le .xd (calque "MYBISEM", #F56573). */
/* Même base que "Contact" (.btn : Medium 15px, interlettrage 1.5px) —
   fond rouge de marque, texte blanc. */
.btn--accent { background: var(--color-primary-light); color: var(--color-text-inverse); gap: 0; padding: 12px 30px; }
.btn--accent sup { font-size: 22px; font-weight: 300; }
.btn--ghost { background: var(--color-bg-white); color: #E62E40; }
.btn--ghost:not(.btn--contact) { padding: 17px 18px; }
/* Sélecteur de langue (header.php, shortcode TranslatePress) uniquement. */
.site-header__lang-switcher.btn--ghost {
  width: 56px; height: 56px; padding: 0;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
@media (max-width: 767px) {
  .site-header__lang-switcher.btn--ghost { width: 50px; height: 50px; }
}
.site-header__lang-switcher .trp-shortcode-switcher { padding: 0; }
/* Seul le drapeau de la langue courante s'affiche par défaut (bouton
   fermé) ; le nom reste visible dans la liste déroulante une fois ouverte
   (.trp-switcher-dropdown-list, pas ciblée ici). */
.site-header__lang-switcher .trp-current-language-item__wrapper .trp-language-item-name { display: none; }
.site-header__lang-switcher .trp-shortcode-arrow { display: none; }
/* Bug du plugin : .trp-switcher-dropdown-list garde display:flex (CSS du
   plugin) malgré son attribut [hidden] tant que fermé — une boîte de
   ~148px de large, invisible (height:0) mais débordant bien réellement du
   bouton rond (le "champ qui dépasse" signalé). !important + [hidden] :
   ne s'applique que fermé, le plugin retire cet attribut à l'ouverture. */
.site-header__lang-switcher .trp-switcher-dropdown-list[hidden] { display: none !important; }
.site-header__lang-switcher .trp-current-language-item__wrapper { padding: 0; }
/* Le plugin réintroduit padding-right:10px via une règle plus spécifique
   (espace réservé pour la flèche, qu'on a retirée) — !important nécessaire. */
.site-header__lang-switcher .trp-current-language-item__wrapper { padding-right: 0 !important; }
.site-header__lang-switcher .trp-language-item { padding: 7px; }
.site-header__lang-switcher .trp-shortcode-switcher__wrapper { height: 35px; }
/* Sur mobile, le plugin réduit la hauteur du conteneur de langue, et le
   ratio interne (--aspect-ratio:4/3) écrasait la largeur du drapeau à 6px
   (quasi invisible). Taille fixée explicitement, peu importe ce calcul. */
.site-header__lang-switcher .trp-flag-image { width: 24px !important; height: 18px !important; flex-shrink: 0 !important; }
/* "Contact" en rouge de marque (police déjà Medium 15px / interlettrage
   1.5px via .btn) — distinct du gris de "FR" qui garde .btn--ghost seul. */
.btn--contact { color: #E62E40; }
.btn--icon {
  width: 40px; height: 40px; padding: 0;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-bg-white);
  color: var(--color-primary);
}
/* Bouton téléphone du hero : même style que "FR" (.btn.btn--ghost, header.php)
   — pill blanche à padding auto plutôt que le cercle fixe 40px de .btn--icon.
   Scopé à .hero__actions pour ne pas toucher au bouton fermeture menu
   (nav-menu.php) qui partage la classe .btn--icon. */
.hero__actions .btn--icon {
  width: auto; height: auto;
  padding: 15px 15px;
  border-radius: var(--radius-pill);
  gap: 8px;
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  border: none;
  transition: background-color 0.15s ease, color 0.15s ease;
  background: var(--color-bg-white);
  color: #E62E40;
}
.btn--burger {
  width: 56px; height: 56px; padding: 0;
  border-radius: 50%;
  background: var(--color-bg-white);
  display: inline-flex; align-items: center; justify-content: center;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  border: none;
}
@media (max-width: 767px) {
  .btn--burger { width: 50px; height: 50px; }
}
/* Même style que #nav-menu-toggle (.btn--burger) */
#nav-menu-close {
  width: 56px; height: 56px; padding: 0;
  border-radius: 50%;
  background: var(--color-bg-white);
  display: inline-flex; align-items: center; justify-content: center;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  border: none;
}

/* Panneau de navigation off-canvas — reconstruit d'après MENU.svg
   (2026-09-16). Fond #FFF4F5 (même rose que .faq-section), filets
   #FFEAEC entre chaque item de nav. */
/* Ouverture/fermeture animées (fondu + léger glissement) plutôt qu'un
   display:none/block qui bascule sans transition. visibility reste en
   display:none-like (non interactif, hors du parcours clavier) mais avec un
   délai de transition pour ne changer qu'une fois le fondu de sortie fini —
   sinon le panneau disparaîtrait instantanément avant la fin de
   l'animation. */
.nav-menu-panel {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: #FFF4F5;
  overflow-y: auto;
  overflow-x: hidden;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-24px);
  transition: opacity 0.35s ease, transform 0.35s ease, visibility 0s linear 0.35s;
}
.nav-menu-panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.35s ease, transform 0.35s ease, visibility 0s linear 0s;
}
/* close-menu.svg embarque déjà son propre disque blanc 52px : pas besoin du
   disque de .btn--icon par-dessus, juste le positionnement. */
.nav-menu-panel__close {
  position: absolute;
  top: 32px; right: 32px;
  width: 52px; height: 52px;
  padding: 0;
  border: none;
  background: none;
}
.nav-menu-panel__close svg { width: 52px; height: 52px; display: block; }
@media (max-width: 767px) {
  .nav-menu-panel__close { width: 50px; height: 50px; }
  .nav-menu-panel__close svg { width: 50px; height: 50px; }
}

.nav-menu-panel__grid {
  max-width: none;
  margin-inline: 0;
  padding-inline: 0;
  min-height: 100vh;
  display: grid;
  /* minmax(0, 1fr) et pas juste 1fr : sinon la piste grid se dimensionne sur
     le min-content de son contenu (mot le plus long non coupable, ex.
     "Monte-voitures" dans .nav-menu-panel__sublinks), qui déborde largement
     du viewport mobile — "grid blowout" classique. */
  grid-template-columns: minmax(0, 1fr);
  gap: 48px;
  padding-top: 0;
  padding-bottom: 0;
}
@media (min-width: 992px) {
  .nav-menu-panel__grid { grid-template-columns: 60% 40%; gap: 64px; height: 100vh; min-height: 0; }
}

/* border-top/border-right ici (pas de padding-inline sur .links elle-même)
   pour que les deux lignes se collent au bord gauche de l'écran et à la
   largeur réelle de la colonne. .nav-menu-panel__item en flex:1 1 0 : chaque
   item prend une part égale de la hauteur, pour que la colonne remplisse
   toute la hauteur de l'écran (min-height:100vh sur .nav-menu-panel__grid)
   au lieu de s'arrêter à la hauteur de son contenu. */
.nav-menu-panel__links {
  display: flex;
  flex-direction: column;
  border-top: 2px solid #FFEAEC;
  border-right: 2px solid #FFEAEC;
}
.nav-menu-panel__item {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-bottom: 2px solid #FFEAEC;
  padding: 12px 40px;
}
/* Indépendant de .is-open (pas scopé dessus) : sinon le retrait immédiat de
   la classe par le JS à la fermeture repasse le texte en casse normale
   pendant le fondu de sortie (0.35s), visible depuis que le panneau n'est
   plus caché instantanément via display:none. */
.nav-menu-panel__item { text-transform: uppercase; }
.nav-menu-panel__item > a,
.nav-menu-panel__item > .nav-menu-panel__item-label {
  display: flex; align-items: center; justify-content: flex-start; gap: 16px;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 45px;
  color: var(--color-primary);
}
.nav-menu-panel__arrow { display: inline-flex; flex: 0 0 auto; transform: rotate(90deg); }
.nav-menu-panel__arrow svg { width: 20px; height: 20px; }
.nav-menu-panel__sublinks {
  display: grid;
  grid-template-columns: repeat(4, auto);
  column-gap: 48px;
  row-gap: 12px;
  margin-top: 16px;
}
.nav-menu-panel__sublinks--2col { grid-template-columns: repeat(2, auto); }
.nav-menu-panel__sublinks a {
  font-family: var(--font-body);
  font-weight: 200;
  font-size: 25px;
  color: var(--color-primary);
  text-transform: none;
}
/* grid-template-columns: repeat(N, auto) dimensionne les colonnes sur le
   contenu ("Monte-voitures"…) sans jamais rétrécir sous ~1000px de large :
   ça forçait tout .nav-menu-panel__item (et le titre au-dessus) à s'élargir
   au-delà de l'écran, avec juste une coupe silencieuse par l'overflow:hidden
   du panneau. minmax(0,1fr) force les colonnes à respecter la largeur
   réellement disponible. */
/* Colonne coordonnées : icône au-dessus du texte (même principe que
   .footer-grid__heading:has(.footer-mini-icon)), icônes gardées rouges
   (pas de disque, pas de filtre blanc — fond clair ici). */
.nav-menu-panel__contact-heading {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 30px;
  text-transform: uppercase;
  color: var(--color-primary);
  margin: 0 0 8px;
}
.nav-menu-panel__contact-heading:not(:first-child) { margin-top: 50px; }
/* pin.svg / mail.svg sont blancs dans le fichier source (prévus pour un fond
   coloré) — invisibles sur le fond rose clair du panneau, on force le rouge
   de marque comme phone.svg (déjà rouge nativement). */
.nav-menu-panel__contact-icon svg { width: 24px; height: auto; display: block; }
.nav-menu-panel__contact-icon svg path { fill: #E62E40; }
.nav-menu-panel__contact-value {
  font-family: var(--font-body);
  font-weight: 200;
  font-size: 30px;
  color: var(--color-primary);
  margin: 0;
  text-transform: none;
}
/* text-decoration:underline ne s'étend pas sous un enfant flex (la flèche) —
   même technique que .footer-mybisem : ::after sur toute la largeur de la
   boîte (icône + texte + flèche). white-space:nowrap pour rester sur une
   seule ligne. */
/* Le trait vit sur .nav-menu-panel__sav-row (bloc pleine largeur de
   .nav-menu-panel__contact) plutôt que sur .nav-menu-panel__sav lui-même
   (inline-flex, donc rétréci à la largeur de son contenu). */
/* Étire le trait vers la gauche à travers le gap (64px) entre les deux
   colonnes de .nav-menu-panel__grid, pour qu'il touche .nav-menu-panel__links
   — margin-left négatif + width compensée pour ne pas bouger le bord droit,
   padding-left équivalent pour que le lien reste à sa place visuelle. */
.nav-menu-panel__sav-row {
  margin-top: 32px;
  margin-left: -64px;
  width: calc(100% + 64px);
  padding-top: 32px;
  padding-left: 64px;
  border-top: 2px solid #FFEAEC;
}
.nav-menu-panel__sav {
  display: inline-flex; align-items: center; gap: 12px;
  white-space: nowrap;
  font-family: var(--font-heading);
  font-size: 25px;
  color: var(--color-primary);
}
/* Le trait ne couvre que .nav-menu-panel__sav-label (texte + flèche), pas
   l'icône mail qui précède — position:relative/::after déplacés ici au lieu
   d'être sur .nav-menu-panel__sav en entier. */
.nav-menu-panel__sav-label {
  position: relative;
  display: inline-flex; align-items: center; gap: 12px;
  text-transform: uppercase;
}
.nav-menu-panel__sav-label::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
}
.nav-menu-panel__sav .nav-menu-panel__contact-icon svg { width: 20px; }
.nav-menu-panel__contact {
  display: flex;
  flex-direction: column;
  padding-top: 50px;
}
/* Deux sections : les <p> (adresse/téléphone/e-mail) dans les 80% du haut,
   le reste (Assistance après-vente + réseaux sociaux) dans les 20% du bas. */
.nav-menu-panel__contact-info { height: 65%; }
.nav-menu-panel__contact-extra {
  height: 35%;
  display: flex;
  flex-direction: column;
}
/* margin-top:auto pousse le bloc social tout en bas de la colonne (au lieu
   d'un position:absolute) ; align-self:flex-end le colle à droite. */
.nav-menu-panel__social { display: flex; gap: 8px; margin-top: auto; margin-right: 60px; margin-bottom: 30px; align-self: flex-end; }
.nav-menu-panel__social .social-icon { background: var(--color-primary); }
.nav-menu-panel__social .social-icon svg rect { fill: var(--color-primary); }
.nav-menu-panel__social .social-icon svg path { fill: #fff; }

/* Media queries après toutes les règles de base ci-dessus (même sélecteurs,
   même spécificité) : sinon une déclaration de base placée après dans le
   fichier écrase silencieusement l'override en media query au tie-break de
   la cascade, même quand le viewport correspond bien à la condition. */
@media (max-width: 767px) {
  .nav-menu-panel__grid { gap: 0; }
  .nav-menu-panel__item > a, .nav-menu-panel__item > .nav-menu-panel__item-label { font-size: 18px; }
  .nav-menu-panel__sublinks,
  .nav-menu-panel__sublinks--2col {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 20px;
  }
  .nav-menu-panel__sublinks a { font-size: 16px; }
  .nav-menu-panel__contact-heading { font-size: 18px; }
  .nav-menu-panel__contact-value { font-size: 16px; }
  .nav-menu-panel__sav-row { border-top: none; padding-top: 0; }
  .nav-menu-panel__sav-label { font-size: 18px; }
}
@media (min-width: 768px) and (max-width: 1199px) {
  .nav-menu-panel__item > a, .nav-menu-panel__item > .nav-menu-panel__item-label { font-size: 35px; line-height: 46px; letter-spacing: 0; }
  .nav-menu-panel__sublinks a { font-size: 22px; line-height: 26px; letter-spacing: 0; }
  .nav-menu-panel__contact { padding: 12px 40px; }
  .nav-menu-panel__contact-heading { font-size: 20px; line-height: 26px; letter-spacing: 0; }
  .nav-menu-panel__contact-value { font-size: 20px; line-height: 30px; letter-spacing: 0; }
  .nav-menu-panel__sav-row { border-top: none; padding-top: 0; }
  .nav-menu-panel__sav-label { font-size: 20px; }
}
/* 2 colonnes sur tablette/mobile : Adresse postale + Adresse e-mail à
   gauche, Téléphone + réseaux sociaux + Assistance après-vente à droite —
   display:contents sur les 2 wrappers pour que tous leurs enfants
   deviennent des items directs de la grille. grid-row explicite sur chaque
   paire heading/value (pas d'auto-placement) : sinon l'algorithme sparse de
   la grille ne garantit pas l'alignement ligne à ligne entre les 2 colonnes
   dès que le nombre d'items par colonne diffère. */
@media (max-width: 1199px) {
  .nav-menu-panel__contact { display: grid; grid-template-columns: 1fr 1fr; column-gap: 24px; padding-bottom: 32px; }
  .nav-menu-panel__contact-info,
  .nav-menu-panel__contact-extra { display: contents; }
  .nav-menu-panel__contact--address,
  .nav-menu-panel__contact--email { grid-column: 1; }
  .nav-menu-panel__contact--phone { grid-column: 2; }
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--address { grid-row: 1; }
  .nav-menu-panel__contact-value.nav-menu-panel__contact--address { grid-row: 2; }
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--phone { grid-row: 1; }
  .nav-menu-panel__contact-value.nav-menu-panel__contact--phone { grid-row: 2; }
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--email { grid-row: 3; }
  .nav-menu-panel__contact-value.nav-menu-panel__contact--email { grid-row: 4; }
  .nav-menu-panel__social { grid-column: 2; grid-row: 3; margin: 0; align-self: start; }
  .nav-menu-panel__sav-row { grid-column: 2; grid-row: 4; margin-top: 0; align-self: start; }
  /* :not(:first-child) (règle de base, plus haut dans le fichier) vaut pour
     la position DOM d'origine, pas la position visuelle dans cette grille :
     ça ajoutait 50px en haut du bloc téléphone (3e enfant de
     .nav-menu-panel__contact-info) alors qu'il doit s'aligner avec l'adresse
     postale en ligne 1. On neutralise cette règle ici et on réintroduit
     l'espacement uniquement là où il doit visuellement apparaître : avant le
     2e groupe (e-mail / réseaux sociaux, ligne 3). */
  .nav-menu-panel__contact-heading:not(:first-child) { margin-top: 0; }
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--email,
  .nav-menu-panel__social { margin-top: 40px; }
  /* pin/phone/mail.svg n'ont pas le même ratio (18x26, 25x25, 22x16) : à
     largeur fixe (24px, règle desktop) leur hauteur rendue variait de 18 à
     34px, ce qui décalait le texte de chaque heading d'une colonne à
     l'autre. Hauteur fixe (largeur libre) pour un point de départ de texte
     identique quelle que soit l'icône. */
  .nav-menu-panel__contact-heading .nav-menu-panel__contact-icon svg { width: auto; height: 24px; }
  .nav-menu-panel__social .social-icon { width: 30px; height: 30px; }
}
/* Mobile : une seule colonne (contre 2 ci-dessus pour tablette/desktop) —
   placé après ce bloc (même sélecteurs, même spécificité) pour gagner le
   tie-break de la cascade. grid-column figé à 1 et grid-row remis à auto
   pour laisser l'auto-placement retomber sur l'ordre naturel du DOM
   (adresse, téléphone, e-mail, puis SAV + réseaux sociaux). Marge gauche
   alignée sur .nav-menu-panel__item juste au-dessus (padding-inline: 40px). */
@media (max-width: 767px) {
  .nav-menu-panel__contact { grid-template-columns: 1fr; padding-inline: 40px; }
  .nav-menu-panel__contact--address,
  .nav-menu-panel__contact--phone,
  .nav-menu-panel__contact--email,
  .nav-menu-panel__social,
  .nav-menu-panel__sav-row { grid-column: 1; }
  /* Mêmes sélecteurs composés que les règles ci-dessus (spécificité égale,
     2 classes) : un simple .nav-menu-panel__contact--phone { grid-row:auto }
     (1 classe) perdait face à .nav-menu-panel__contact-heading.nav-menu-panel__contact--phone
     et les 2 lignes se superposaient à celles de l'adresse. */
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--address,
  .nav-menu-panel__contact-value.nav-menu-panel__contact--address,
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--phone,
  .nav-menu-panel__contact-value.nav-menu-panel__contact--phone,
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--email,
  .nav-menu-panel__contact-value.nav-menu-panel__contact--email { grid-row: auto; }
  .nav-menu-panel__social { grid-row: auto; }
  .nav-menu-panel__sav-row { grid-row: auto; margin-top: 40px; }
  .nav-menu-panel__contact-heading { flex-direction: row; align-items: center; }
  .nav-menu-panel__contact-heading .nav-menu-panel__contact-icon svg { width: auto; height: 16px; }
  .nav-menu-panel__contact-heading.nav-menu-panel__contact--phone { margin-top: 40px; }
}

/* ==========================================================================
   Hero (template-parts/hero.php)
   ========================================================================== */
/* Contexte de positionnement pour .hero__scroll-cue : sorti de <section
   class="hero"> (overflow:hidden) pour pouvoir déborder sur la section
   suivante sans être rogné. Pas de flow-root ici : on veut au contraire que
   la margin de .hero (28px) continue de "traverser" ce wrapper comme avant,
   pour que bottom:-1px reste calé sur le bord bas réel de .hero. */
.hero-wrapper {
  position: relative;
}
.hero {
  position: relative;
  min-height: calc(100vh - 56px); /* 100vh moins les 28px de marge haut+bas */
  margin: 28px;
  display: flex;
  align-items: flex-end;
  padding: 32px;
  border-radius: var(--radius-hero);
  overflow: hidden;
  background-color: var(--color-navy);
  /* Dégradé de secours tant qu'aucune photo n'est fournie pour cette page
     (voir notes-design.md, section "Assets manquants") — l'image, quand
     elle existe, s'affiche par-dessus via background-image inline. */
  background-image: linear-gradient(135deg, #1a2740 0%, var(--color-navy) 100%);
  background-size: cover;
  background-position: center;
  color: var(--color-text-inverse);
}
.hero::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(0deg, rgba(8,16,32,0.55) 0%, rgba(8,16,32,0.05) 60%);
  pointer-events: none;
}
.hero--no-overlay::after { display: none; }
.hero--compact { height: 555px; min-height: 0; }
/* Variante "claire" (Accueil) : la vidéo est cantonnée à droite (voir
   .hero__video) et le texte vit sur un panneau à part, donc pas besoin
   d'assombrir une photo derrière le texte comme sur les autres pages —
   fond blanc, et le dégradé devient horizontal (fondu blanc -> vidéo) au
   lieu du dégradé vertical sombre utilisé quand le texte est sur la photo. */
.hero--light {
  background-color: #F7F5F5;
  background-image: none;
}
.hero--light::after {
  background: linear-gradient(90deg, #F7F5F5 0%, #F7F5F5 40%, rgba(247,245,245,0) 60%);
}
/* Voile diagonal sur l'ensemble du hero (pas seulement la vidéo) — c'est ce
   qui assombrit suffisamment le panneau de texte pour que le texte reste
   blanc (comme sur les autres pages) malgré le fond clair #F7F5F5. */
.hero--light::before {
  content: '';
  position: absolute; inset: 0;
  z-index: 1;
  background: transparent linear-gradient(73deg, #232C4A 0%, #FFFFFF00 100%) 0% 0% no-repeat padding-box;
  mix-blend-mode: darken;
  opacity: 0.63;
  pointer-events: none;
}
/* Cantonnée à la droite, avec une marge de sécurité fixe par rapport au bord
   du bloc de texte (.hero__content : padding 32px + max-width 640px), pour
   ne jamais passer derrière le texte quelle que soit la largeur d'écran —
   un simple pourcentage de largeur se remettrait à chevaucher le texte dès
   que le hero devient plus étroit que ~1450px. */
.hero__video {
  position: absolute; top: 0; bottom: 0; right: 0;
  left: max(45%, 712px);
  z-index: 0;
  width: auto; height: 100%;
  object-fit: cover;
}
/* Le calage à droite avec left:712px minimum n'a plus de sens dès que le
   hero est plus étroit que ça (mobile/tablette) : la vidéo débordait très
   loin à droite. On la fait plutôt couvrir tout le hero, comme sur les
   autres pages — le fondu blanc (.hero--light::after) n'a alors plus lieu
   d'être puisqu'il n'y a plus de panneau texte séparé à sa gauche. */
@media (max-width: 991px) {
  .hero__video { left: 0; width: 100%; object-fit: cover; }
  .hero--light::after { display: none; }
}
/* Recadrage du sujet (ascenseur décomposé) : il n'est pas au centre
   géométrique de la vidéo source, mais plutôt sur sa partie droite —
   object-position:center (défaut) le décalait donc hors du centre visuel du
   cadre mobile. Placé après le bloc 991px ci-dessus (même sélecteur, même
   spécificité) pour gagner le tie-break de la cascade sur la plage ≤767px. */
@media (max-width: 767px) {
  .hero__video { object-position: 70% center; }
}
.hero__content {
  position: relative;
  z-index: 2;
  max-width: 640px;
  padding-bottom: 64px;
}
/* Page À propos (ID 8) uniquement. */
body.page-id-8 .hero__content { max-width: 570px; }
/* Titre héro (ex: "BISEM ascenseurs") : Stack Sans Notch Bold, 90px sur
   desktop/tablette, 41px sur mobile dans le .xd (lh ~0.89, très condensé). */
.hero__title {
  width: 100%;
  font-weight: 700;
  font-size: 90px;
  line-height: 80px;
  letter-spacing: 0;
  text-align: left;
  text-transform: uppercase;
  color: var(--color-text-inverse);
  margin: 0;
}
.hero__title sup { font-size: 0.5em; font-weight: 300; }
/* Le 41px prévu par le .xd sur mobile n'était jamais appliqué : à 90px le
   titre passait sur de nombreuses lignes très serrées (line-height 80px). */
@media (max-width: 767px) {
  .hero__title { font-size: 41px; line-height: 36px; }
  .hero__title[style*="white-space:nowrap"] { white-space: normal !important; width: 100% !important; }
}
@media (min-width: 768px) and (max-width: 1199px) {
  .hero__title { font-size: 80px; line-height: 70px; }
  /* Même correctif que le mobile juste au-dessus : à 80px, les titres longs
     en nowrap (ex. "Nos parties électriques", title_nowrap => true) débordent
     hors du cadre au lieu de revenir à la ligne. */
  .hero__title[style*="white-space:nowrap"] { white-space: normal !important; width: 100% !important; }
  .hero { min-height: calc(75vh - 56px); }
}
/* "La sérénité aux sommets…" (accueil) */
.hero__subtitle { font-family: var(--font-body); font-size: 27px; font-weight: 400; font-style: italic; margin-top: 10px; margin-bottom: 0; color: var(--color-text-inverse); text-transform: none; }
@media (max-width: 767px) {
  .hero__subtitle { font-size: 19px; }
}
/* Séparateur court entre le sous-titre et la description (accueil) */
.hero__divider { width: 86px; height: 1px; background: var(--color-text-inverse); margin-top: 50px; margin-bottom: 30px; }
@media (max-width: 767px) {
  .hero__divider { margin-top: 25px; margin-bottom: 20px; }
}
.hero__description { width: 100%; font-size: 1.0625rem; font-weight: 400; opacity: 0.9; margin-top: 12px; margin-bottom: 34px; }
.hero__description-break { display: none; }
@media (max-width: 767px) {
  /* .hero__desc-strong a sa propre règle de taille (18px), plus spécifique
     (2 classes) : elle continue de l'emporter sur ce 15px hérité du parent. */
  .hero__description { font-size: 15px; }
  .hero__description-break { display: block; }
}
/* Première ligne de description (ex: "Fabricant français d'ascenseurs.") */
.hero__desc-strong { display: block; font-family: var(--font-heading); font-size: 1.4375rem; font-weight: 700; margin-bottom: 0.25em; }
@media (max-width: 767px) {
  .hero__desc-strong { font-size: 18px; }
}
.hero__actions { display: flex; align-items: center; gap: 20px; }
@media (max-width: 480px) {
  .hero__actions { flex-wrap: wrap; gap: 12px; }
}
.hero__scroll-cue {
  position: absolute;
  bottom: -2px; left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  width: 284px; height: 84px;
  padding-top: 40px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
}
/* Fond en pseudo-élément séparé, taille fixe (284x82, dimensions naturelles
   du SVG) indépendante de .hero__scroll-cue elle-même : un simple
   `background` directement sur l'élément est toujours rogné aux dimensions
   de sa boîte (impossible à faire déborder en CSS), ce qui coupait le
   dessin dès que la boîte est réduite en mobile (voir plus bas). */
.hero__scroll-cue::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 284px; height: 84px;
  z-index: -1;
  background: url('assets/img/icons/scroll-cue-bg.svg') no-repeat center;
}
/* Variante Devis/Contact (fond de section rose derrière le hero) : décalée à
   15% au lieu de centrée, et fond rose à la place du blanc — voir
   template-parts/hero.php $args['scroll_cue_pink']. */
.hero__scroll-cue--pink {
  left: 15%;
}
.hero__scroll-cue--pink::before {
  background-image: url('assets/img/icons/scroll-cue-bg-pink.svg');
}
/* Le décalage à 15% associé à la largeur fixe de 284px pousse le repère
   hors de l'écran à gauche sous les formats tablette/mobile — on recentre. */
@media (max-width: 1199px) {
  .hero__scroll-cue--pink { left: 50%; }
}
.hero__scroll-cue__dot { width: 84px; height: 84px; display: flex; align-items: center; justify-content: center; }
.hero__scroll-cue__dot svg { width: 100%; height: 100%; }
.hero__scroll-cue__line { width: 1px; height: 24px; background: var(--color-primary); opacity: 0.4; }
@media (max-width: 767px) {
  .hero__scroll-cue { width: 200px; height: 62px; }
  .hero__scroll-cue__dot { width: 60px; height: 60px; }
}
.hero__social {
  position: absolute;
  right: 32px; bottom: 32px;
  z-index: 2;
  display: flex; gap: 8px;
}
@media (max-width: 767px) {
  .hero__social { display: none; }
}
/* Même style que le bouton téléphone du hero (.hero__actions .btn--icon). */
.social-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px; height: 58px;
  border-radius: var(--radius-pill);
  gap: 8px;
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  border: none;
  transition: background-color 0.15s ease, color 0.15s ease;
  background: var(--color-bg-white);
  color: #E62E40;
}
.social-icon svg { width: 100%; height: 100%; }

/* ==========================================================================
   Sections communes (template-parts/*)
   ========================================================================== */
.section { padding: 80px 0; }
.section--tight { padding: 48px 0; }
@media (max-width: 767px) {
  /* Générique : ne s'applique en pratique qu'aux images sans règle plus
     spécifique déjà en place (ex. coverage-map) — .product-gallery__item img
     et .partners-section__note-media img ont chacune leur propre règle à
     spécificité plus élevée, qui continue de gagner. */
  .section--tight { margin-top: 0; }
  .section--tight img { height: 200px; object-fit: cover; }
}
.section--bg-light { background: var(--color-bg-light); }
/* Réglages spécifiques au bloc à fond rose qui suit directement le hero sur
   les pages Devis/Contact (template-parts/form.php) : marges gauche/droite
   alignées sur celles du hero, remontée dans la marge basse du hero pour
   supprimer le décalage blanc, paddings internes élargis. Scopé au 1er
   enfant de <main> pour NE PAS s'appliquer aux autres pages, où
   .section--bg-light est une classe partagée (accueil, à-propos, pages
   service, etc.) et ne doit pas changer de marge/padding. */
main#content > .section--bg-light:first-child {
  margin-left: 28px;
  margin-right: 28px;
  max-width: 100%;
  margin-top: -100px !important;
  margin-bottom: -50px;
  padding-top: 200px;
  padding-bottom: 150px;
}

/* "Notre gamme d'X" — carrousel photo (template-parts/product-gallery.php) */
.product-gallery .container { width: calc(100% - 70px); max-width: none; margin-inline: 0; margin-left: 70px; padding-inline: 0; }
.product-gallery__head { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.product-gallery__title { margin: 0; text-transform: none; }
.product-gallery__title-break { display: none; }
@media (min-width: 768px) and (max-width: 1199px) {
  .product-gallery__title-break { display: block; }
}
@media (max-width: 767px) {
  /* Sans min-width:0, un flex item texte ne se laisse jamais rétrécir sous
     sa largeur intrinsèque : le titre poussait les flèches hors écran. */
  .product-gallery__title { min-width: 0; }
}
.product-gallery__nav { display: flex; align-items: center; gap: 16px; flex: 0 0 auto; margin-right: 28px; }
@media (max-width: 767px) {
  .product-gallery .container { margin-left: 20px; width: calc(100% - 20px); }
  .product-gallery__nav { margin-right: 20px; gap: 10px; }
}
.product-gallery__arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  padding: 0;
  border: none;
  background: none;
  color: var(--color-navy-accent);
}
/* carousel-arrow-left/right.svg sont déjà orientées (rotate interne opposé
   l'une de l'autre) et rouges en dur — pas de rotation/filtre CSS ici. */
.product-gallery__arrow svg { width: 27px; height: 27px; }
.product-gallery__viewport { position: relative; overflow: hidden; margin-top: 24px; }
/* Trait horizontal décoratif à mi-hauteur des cartes, derrière (même
   principe que .stats-timeline__line). */
.product-gallery__viewport::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -70px;
  right: 0;
  height: 1px;
  background: var(--color-border);
  z-index: 0;
}
.product-gallery__track {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 16px;
  transition: transform 0.4s ease;
}
.product-gallery__item {
  flex: 0 0 auto;
  width: 320px;
  aspect-ratio: 1 / 1;
  border-radius: 30px;
  border: 2px solid var(--color-border);
  overflow: hidden;
}
.product-gallery__item img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Page Cabine (ID 18) uniquement : visuels "KIT GCxxx" en bannière large
   (ratio ~1.8:1, texte + schémas), pas des photos carrées comme ailleurs —
   aspect-ratio calé sur le ratio exact des fichiers sources (902x500) et
   object-fit:contain pour ne rien recadrer/couper. */
body.page-id-18 .product-gallery__item { width: 500px; aspect-ratio: 902 / 500; }
body.page-id-18 .product-gallery__item img { object-fit: contain; }
/* Page Partie électrique (ID 17) : même traitement, visuels "KIT GExxx" au
   même ratio source (902x500). */
body.page-id-17 .product-gallery__item { width: 500px; aspect-ratio: 902 / 500; }
body.page-id-17 .product-gallery__item img { object-fit: contain; }
/* Page Moteur (ID 16) : même traitement, visuels "KIT GMxxx" au même ratio
   source (902x500). */
body.page-id-16 .product-gallery__item { width: 500px; aspect-ratio: 902 / 500; }
body.page-id-16 .product-gallery__item img { object-fit: contain; }
/* Page Portes (ID 19) : même traitement, visuels "KIT GPxxx" au même ratio
   source (902x500). */
body.page-id-19 .product-gallery__item { width: 500px; aspect-ratio: 902 / 500; }
body.page-id-19 .product-gallery__item img { object-fit: contain; }
/* Mobile : les 500px ci-dessus (4 pages kit) débordaient largement un écran
   375px — largeur réduite, l'aspect-ratio (toujours 902/500) ajuste la
   hauteur en conséquence, sans déformer/recadrer les visuels. */
@media (max-width: 767px) {
  body.page-id-16 .product-gallery__item,
  body.page-id-17 .product-gallery__item,
  body.page-id-18 .product-gallery__item,
  body.page-id-19 .product-gallery__item { width: 300px; }
}
.product-gallery__dots { display: flex; justify-content: center; align-items: center; gap: 8px; margin-top: 24px; }
.product-gallery__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--color-border); }
.product-gallery__dot.is-active { width: 10px; height: 10px; background: var(--color-navy-accent); }
@media (max-width: 767px) {
  .product-gallery__item { width: 260px; }
}
/* Titre de section rouge centré (ex: "Nos cabines", "Foire Aux Questions",
   "Nos partenaires") : c'est la variante dominante dans le .xd — Stack Sans
   Notch Bold/SemiBold, 40-60px desktop selon le contexte, ~35px mobile. On
   prend 54px comme taille de référence (la plus fréquente). */
.section__title {
  font-size: clamp(2.1875rem, 6vw, 3.375rem);
  color: var(--color-primary);
}
.section__title strong,
.section__title .accent { color: var(--color-primary); }
.section__title .navy { color: var(--color-navy-accent); }
.section__title .extralight { font-weight: 200; }
/* Variante navy à taille fixe pour les blocs 2 colonnes texte/photo
   (template-parts/content-block.php) : Stack Sans Notch Bold 35px navy,
   constante sur tous les breakpoints dans le .xd (ex: "Ascenseurs complets
   sur-mesure", "EPMR sur-mesure"). */
.section__title--split {
  font-size: 2.1875rem;
  color: var(--color-navy-accent);
}
.nos-pieces__title-break { display: none; }
@media (min-width: 1200px) {
  .nos-pieces__title-break { display: block; }
}
/* Casse respectée telle quelle (ex: "Une gamme complète & sur-mesure",
   export_groupe.html) — modificateur scopé, h1-h4 restent en MAJUSCULES
   partout ailleurs (règle globale). */
.section__title--case-normal { text-transform: none; }
.section__lead { max-width: 434px; margin: 0 auto 2em; text-align: center; }
.section__lead .semibold { font-weight: 600; }
/* Retour à la ligne après cette phrase sans <br> (donc sans forcer de coupure
   sur les petits écrans où le texte est déjà plus étroit) : display:block
   fait juste suivre naturellement le texte suivant sur la ligne d'après. */
.section__lead .semibold--line { display: block; }

/* Neutralise .container (max-width + margin-inline:auto) : ce bandeau doit
   occuper toute la largeur de la fenêtre, pas la largeur de contenu. */
.specs-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 32px;
  width: 100%;
  max-width: none;
  margin: 0;
  margin-top: -10px;
  height: 333px;
  padding: 24px 0;
  border-bottom: 2px solid var(--color-border);
  font-weight: 700;
  color: var(--color-navy-accent);
}
.specs-bar__col { display: flex; flex-direction: column; align-items: center; gap: 20px; width: 47%; text-transform: uppercase; font-size: 0.8125rem; text-align: center; }
.specs-bar__col svg { width: 64px; height: 56px; }
.specs-bar__col span { font-size: 25px; font-family: var(--font-heading); }
.specs-bar__divider { width: 2px; align-self: stretch; margin-block: -24px; background: var(--color-border); flex: 0 0 auto; }
.specs-bar__codes-break { display: none; }
/* Media queries après les règles de base ci-dessus (même règle que pour
   .nav-menu-panel__* plus haut dans ce fichier) : sinon la base, placée
   après en source, écrase l'override en media query au tie-break. */
@media (max-width: 767px) {
  .specs-bar__col span { font-size: 20px; }
  .specs-bar__col:last-of-type span { width: 100%; }
  /* 1 seule colonne empilée (contre 2 côte à côte) : hauteur fixe (333px,
     pensée pour la ligne horizontale) retirée, sinon le 2e groupe empilé se
     retrouvait tronqué. Le diviseur passe de vertical (align-self:stretch en
     flex-row) à horizontal (même propriété, mais stretch s'applique
     maintenant à l'axe croisé de la colonne = la largeur). */
  .specs-bar { flex-direction: column; height: auto; }
  .specs-bar__col { width: 100%; }
  .specs-bar__divider { width: auto; height: 2px; margin-block: 0; margin-inline: -24px; }
  .specs-bar__codes-break { display: block; }
  .specs-bar__col:first-child { margin-top: 50px; }
}
@media (min-width: 768px) and (max-width: 1199px) {
  .specs-bar { width: 100%; }
  .specs-bar__col { width: 40%; }
  .specs-bar__col span { font-size: 20px; }
  .specs-bar__col:last-of-type span { width: 200px; }
}

/* Stack Sans Notch Bold 15px uppercase (ex: calque "Caractéristiques" dans
   le .xd) — remplace l'estimation précédente à 13px. */
.kicker {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 700; font-size: 0.9375rem; letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 12px;
}
.kicker--primary { color: var(--color-primary); }
.kicker--navy { color: var(--color-navy-accent); }
/* Casse respectée telle quelle (ex: "Nos programmes neufs", export_groupe.html)
   — modificateur scopé, .kicker reste en MAJUSCULES partout ailleurs. */
.kicker--case-normal { text-transform: none; }
.kicker__dash {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.kicker__dash::before {
  content: '';
  width: 35px; height: 10px;
  border-radius: 11px;
  background: var(--color-navy-accent);
}
/* Point du milieu (blanc, liseré gris) entre la pastille navy et la pastille
   rouge (::after) — élément réel plutôt qu'un 3e pseudo-élément, impossible
   en CSS. Voir export_groupe.html, dash à 3 segments. */
.kicker__dash__dot {
  width: 15px; height: 10px;
  border-radius: 11px;
  background: var(--color-bg-white);
  border: 1px solid var(--color-border);
}
.kicker__dash::after {
  content: '';
  width: 15px; height: 10px;
  border-radius: 11px;
  background: var(--color-primary);
}

/* Bouton "En savoir plus" en casse normale (export_groupe.html) — modificateur
   scopé, .btn reste en MAJUSCULES partout ailleurs. */
.btn--case-normal { text-transform: none; }

/* Lien flèche rouge (ex: "Contactez nous", export_groupe.html) — alternative
   au lien souligné par défaut de content-block.php (secondary_arrow: true). */
.link-arrow {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--color-primary);
  font-weight: 500; font-size: 0.9375rem;
  text-transform: uppercase;
}
.link-arrow svg { width: 16px; height: 16px; flex: 0 0 auto; transition: transform 0.2s ease; }
.link-arrow__label { display: inline-block; transition: transform 0.2s ease; }
.link-arrow:hover svg { transform: rotate(45deg); }
.link-arrow:hover .link-arrow__label { transform: translateX(4px); }

/* Bord perdu (content-block.php, media_bleed: true) : section pleine largeur
   d'écran, 2 colonnes 50/50 — .container (texte) et la photo, chacune sur
   toute la hauteur — voir export_groupe.html. En dessous de 768px, pas de
   place pour 2 colonnes : tout repasse en flux normal empilé. */
/* Neutralise .section--bg-light : ce bloc a son propre fond via la photo,
   pas de teinte de section derrière. */
.content-block--bleed { width: 100%; padding-block: 0; background: none; }
.content-block--bleed .container { max-width: none; margin: 0; padding-block: 48px; }
/* Conteneur de la photo : porte le sizing/l'arrondi (repris de l'ex-
   .content-block__bleed-media) + position:relative pour ancrer l'accent
   décoratif en absolu par-dessus la photo. */
.content-block__bleed-media-wrap {
  position: relative;
  overflow: hidden;
  width: 100%;
  aspect-ratio: 4/3;
  border-radius: var(--radius-card);
}
.content-block__bleed-media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Accent "Soustraction 1" (voir export_groupe.html) : même forme que
   scroll-cue-bg.svg, pivotée à la verticale, calée sur le bord de la photo
   qui touche le texte — en bas à gauche (bloc "Une gamme complète", image à
   droite) ou en haut à droite, retournée 180° (bloc "Solutions modulaires",
   image à gauche — 2e export_groupe.html). */
.content-block__bleed-accent {
  position: absolute;
  width: 82px;
  height: auto;
  pointer-events: none;
}
.content-block__bleed-accent--bottom-left { bottom: 12%; left: 0; }
.content-block__bleed-accent--top-right { top: 10%; right: 0; transform: rotate(180deg); }
/* 1 seule colonne (texte au-dessus, photo en dessous) sous 1200px : la mise
   en page 2 colonnes 50/50 pleine hauteur ne passe qu'à partir du desktop. */
@media (max-width: 1199px) {
  .content-block--bleed { display: flex; flex-direction: column; height: auto; }
  .content-block--bleed .container { width: 100%; order: 1 !important; padding-block: 48px; }
  .content-block__bleed-media-wrap { width: 100%; height: 450px; aspect-ratio: auto; order: 2 !important; }
  .content-block__bleed-media-wrap--right { border-radius: 100px 0 0 0; }
  /* rotate(90deg) tourne autour du centre de la boîte d'origine (82×282,
     ratio du SVG) : sans repositionnement, le résultat pivoté (282×82)
     partagerait ce même centre mais ne collerait plus au coin. Décalage =
     (hauteur-largeur)/2 = (282-82)/2 = 100px, dans les deux axes, pour que
     le coin haut-gauche de la forme pivotée retombe exactement sur (0,0). */
  .content-block__bleed-accent--bottom-left { top: -100px; bottom: auto; left: 25%; transform: rotate(90deg); }
  .content-block__bleed-media-wrap--left { border-radius: 0 100px 0 0; }
  .content-block__bleed-accent--top-right { top: -100px; right: 25%; transform: rotate(90deg); }
}
@media (max-width: 767px) {
  /* .section { padding: 48px 0; } (règle générique tout en bas du fichier)
     réintroduisait un padding-top malgré padding-block:0 posé plus haut sur
     .content-block--bleed — même spécificité (1 classe), mais plus tard en
     source, donc gagnant le tie-break de la cascade pour cet élément qui
     porte les deux classes. */
  .content-block__bleed-media-wrap { height: 250px; }
  .content-block__bleed-media-wrap--right { border-radius: 50px 0 0 0; }
  .content-block__bleed-accent { width: 60px; }
  .content-block__bleed-accent--bottom-left { left: 32%; top: -61px; width: 50px; }
  /* Section 2 (image à gauche, accent top-right) : même traitement en
     miroir que la section 1 ci-dessus. */
  .content-block__bleed-media-wrap--left { border-radius: 0 50px 0 0; }
  .content-block__bleed-accent--top-right { right: 32%; top: -61px; width: 50px; }
}
@media (min-width: 1200px) {
  .content-block--bleed {
    display: flex;
    align-items: stretch;
    height: 925px;
  }
  .content-block--bleed .container {
    width: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-block: 0;
    padding-inline: 64px;
  }
  .content-block__bleed-media-wrap {
    width: 50%;
    height: 100%;
    aspect-ratio: auto;
    border-radius: 0;
  }
  .content-block__bleed-media-wrap--right { border-radius: 0 0 0 100px; }
  .content-block__bleed-media-wrap--left { border-radius: 0 100px 0 0; }
}

.checklist { display: flex; flex-direction: column; gap: 10px; margin: 0; }
.checklist__mark { color: var(--color-primary); font-weight: 700; margin-right: 8px; }

.content-split {
  display: flex;
  flex-direction: column;
  gap: 32px;
  align-items: center;
}
.content-split--left { flex-direction: column-reverse; }
.content-split__media { flex: 1 1 0; width: 100%; }
.content-split__media img { width: 100%; border-radius: var(--radius-card); aspect-ratio: 4/3; object-fit: cover; }
.content-split__text { flex: 1 1 0; width: 100%; max-width: 425px; }
.content-block__top-image { display: block; width: 100%; height: auto; border-radius: var(--radius-card); margin-bottom: 24px; }
/* Titre en casse normale (pas la règle globale h1-h4 en MAJUSCULES) pour tous
   les blocs content-block.php avec image/texte. */
.content-split__text h2 { text-transform: none; }
@media (max-width: 1199px) {
  /* !important : certains appels (ex: 2e section accueil) passent
     $text_max_width, qui pose un style inline max-width sur cet élément —
     sinon plus prioritaire qu'une règle externe à spécificité égale. */
  .content-split__text { max-width: 80% !important; margin-left: 75px; }
}
@media (max-width: 767px) {
  .content-block--bleed .content-split__text { margin-left: 0; }
  .content-split__text { max-width: 95% !important; }
}
@media (min-width: 768px) {
  .content-split { flex-direction: row; align-items: center; }
  .content-split--left { flex-direction: row-reverse; }
}

/* "Pourquoi choisir Bisem Ascenseurs ?" (export_groupe.html) : frise
   horizontale — une ligne grise reliant 4 pastilles, un texte sur 3 lignes
   sous chacune. La ligne est un ::before par item (sauf le 1er), tirée du
   centre de l'item vers le centre de l'item précédent — pattern "stepper"
   classique, fonctionne quel que soit le nombre d'items. */
#stats { padding-bottom: 200px; width: 90vw; margin-inline: auto; display: flex; justify-content: center; }
#stats .container { margin: 0; padding: 0; }
.stats-timeline {
  display: flex;
  width: 100%;
  margin-top: 105px;
}
.stats-timeline__item {
  position: relative;
  flex: 1;
  display: flex; flex-direction: column; align-items: center;
  padding-top: 30px;
  text-align: center;
}
.stats-timeline__item:not(:first-child)::before {
  content: '';
  position: absolute;
  top: 10px; right: 50%;
  width: 100%; height: 2px;
  background: var(--color-border);
}
.stats-timeline__dot {
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--color-bg-white);
  border: 2px solid rgb(150, 150, 150);
  z-index: 1;
}
.stats-timeline__text { margin-top: 20px; }
.stats-timeline__text span { display: block; }
.stats-timeline__text span:nth-child(1) {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 26px;
  line-height: 31px;
  letter-spacing: 0;
  text-align: center;
  color: var(--color-primary);
}
.stats-timeline__text span:nth-child(2) {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 26px;
  line-height: 31px;
  letter-spacing: 0;
  text-align: center;
  color: var(--color-text);
}
/* La frise horizontale (4 items flex:1) écrase le texte en dessous de
   ~600px : on passe en grille 2x2 et on abandonne la ligne de liaison
   (elle ne peut plus être tracée correctement une fois les items empilés). */
@media (max-width: 600px) {
  #stats { width: 90%; padding-bottom: 50px; }
  .stats-timeline { flex-direction: column; row-gap: 48px; }
  .stats-timeline__item { flex: 0 0 auto; width: 100%; padding-top: 24px; }
  .stats-timeline__item::before { display: none; }
  /* En colonne, chaque item a son propre trait horizontal plein-largeur à la
     hauteur de son dot (contre un seul trait continu reliant les dots entre
     eux en desktop/ligne). top:10px = centre du dot (20px de haut, top:0). */
  .stats-timeline__item::after {
    content: '';
    position: absolute;
    top: 10px; left: 50%; width: 100vw;
    transform: translateX(-50%);
    height: 2px;
    background: var(--color-border);
  }
  /* left:50%+translateX(-50%)+100vw : le trait déborde du conteneur (#stats
     fait 90% de large, centré) pour toucher les vrais bords de l'écran — le
     centre de chaque item coïncide avec le centre du viewport puisque #stats
     est lui-même centré. 1er item : uniquement la moitié droite (à partir du
     dot) ; dernier : uniquement la moitié gauche. */
  .stats-timeline__item:first-child::after { left: 50%; width: 50vw; transform: none; }
  .stats-timeline__item:last-child::after { left: auto; right: 50%; width: 50vw; transform: none; }
  /* nth-child(1)/(2)/(3), pas juste "span" : la règle de base ci-dessus
     cible déjà chaque ligne via :nth-child (spécificité plus élevée qu'un
     simple .stats-timeline__text span), donc un sélecteur générique perdrait
     le tie-break. */
  .stats-timeline__text span:nth-child(1),
  .stats-timeline__text span:nth-child(2),
  .stats-timeline__text span:nth-child(3) { font-size: 20px; }
}

.product-grid {
  display: flex;
  flex-direction: column;
  gap: 45px;
}
.product-grid__col {
  display: flex;
  flex-direction: column;
  gap: 45px;
  flex: 1;
}
@media (min-width: 1200px) {
  .product-grid { flex-direction: row; }
  .product-grid__col:nth-child(1),
  .product-grid__col:nth-child(3) {
    margin-top: 50px;
  }
}
/* Tablette : 2 colonnes au lieu de 3. Les 6 cartes sont réparties en dur
   dans 3 <div class="product-grid__col"> côté PHP (voir product-grid.php)
   — display:contents les efface pour laisser une simple grille 2 colonnes
   replacer les 6 cartes dans l'ordre du DOM (pas le même regroupement que
   sur desktop, mais pas de restructuration du template nécessaire). */
@media (min-width: 768px) and (max-width: 1199px) {
  .product-grid { display: grid; grid-template-columns: 1fr 1fr; }
  .product-grid__col { display: contents; }
  /* Réassigne explicitement chaque carte (le tourniquet PHP par i%3 ne donne
     pas l'ordre voulu en 2 colonnes) : col.1 Ascenseurs/Monte-voiture/Homelift,
     col.2 Monte-charge/Monte-plat/EPMR — voir product-grid.php pour le detail
     du regroupement d'origine (Ascenseurs+Monte-plat / Monte-charge+Homelift
     / Monte-voiture+EPMR dans les 3 colonnes desktop). */
  .product-grid__col:nth-child(1) .product-card:nth-child(1) { grid-column: 1; grid-row: 1; } /* Ascenseurs */
  .product-grid__col:nth-child(2) .product-card:nth-child(1) { grid-column: 2; grid-row: 1; margin-top: -50px; } /* Monte-charge */
  .product-grid__col:nth-child(3) .product-card:nth-child(1) { grid-column: 1; grid-row: 2; } /* Monte-voiture */
  .product-grid__col:nth-child(1) .product-card:nth-child(2) { grid-column: 2; grid-row: 2; margin-top: -50px; } /* Monte-plat */
  .product-grid__col:nth-child(2) .product-card:nth-child(2) { grid-column: 1; grid-row: 3; } /* Homelift */
  .product-grid__col:nth-child(3) .product-card:nth-child(2) { grid-column: 2; grid-row: 3; margin-top: -50px; } /* EPMR */
  .product-card__label { font-size: 19px; padding: 18px 25px; }
}
.product-card {
  position: relative;
  border-radius: var(--radius-card);
  overflow: hidden;
  aspect-ratio: 405 / 553;
  display: block;
  transition: transform 0.25s ease;
}
.product-card:hover { transform: translateY(-10px); }
.product-card img { width: 100%; height: 100%; object-fit: cover; }
/* Étiquette "wagon" (export_groupe.html) : coin bas-droit non arrondi, comme
   si elle était accrochée au coin haut-gauche de la photo. */
.product-card__label {
  position: absolute;
  top: 0; right: 0;
  background: var(--color-primary);
  color: var(--color-text-inverse);
  padding: 24px 32px;
  border-radius: 30px 30px 0 30px;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.4375rem;
}
@media (max-width: 767px) {
  .product-card { height: 275px; border-radius: 30px; }
  .product-card__label { font-size: 19px; padding: 19px 32px; }
}

/* "Ils parlent de nous" (export_groupe.html) : 3 colonnes flexbox, 2 avis
   empilés par colonne — voir template-parts/testimonials.php pour pourquoi
   la colonne du milieu (avec le titre) paraît plus basse sans margin-top. */
/* Tablette/mobile : slider horizontal (1 colonne = 1 slide, scroll-snap,
   piloté aussi par les points .testimonials-columns__dots — voir main.js).
   Desktop (≥768px, media query plus bas) repasse en 3 colonnes visibles
   sans scroll. */
.testimonials-columns {
  display: flex;
  flex-direction: row;
  gap: 50px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.testimonials-columns::-webkit-scrollbar { display: none; }
.testimonials-columns__col {
  display: flex;
  flex-direction: column;
  gap: 40px;
  flex: 0 0 100%;
  scroll-snap-align: start;
}
.testimonials-columns__title {
  margin: 0;
  /* S'ajoute au gap de 40px de .testimonials-columns__col (le gap et les
     margins se cumulent, ne se remplacent pas) : 72px au total avant la
     1re carte. */
  margin-bottom: 32px;
  color: var(--color-primary);
  text-align: center;
  font-weight: 600;
}
.testimonials-columns__dots { display: flex; justify-content: center; gap: 6px; margin-top: 32px; }
.testimonials-columns__dots span { width: 8px; height: 8px; border-radius: 50%; background: var(--color-bg-white); border: 1px solid var(--color-border); }
.testimonials-columns__dots span.is-active { background: var(--color-border); }
@media (min-width: 1200px) {
  /* Desktop : 3 colonnes visibles côte à côte, plus de slider/scroll-snap. */
  .testimonials-columns { overflow-x: visible; scroll-snap-type: none; }
  .testimonials-columns__col { flex: 1; scroll-snap-align: none; }
  /* Pagination masquée en desktop (3 colonnes visibles en même temps) —
     réservée au responsive, où les avis deviennent un slider. */
  .testimonials-columns__dots { display: none; }
}
/* Tablette + mobile : présentation revue en liste simple à une colonne
   (display:contents sur les 3 .testimonials-columns__col pour aplatir le
   regroupement en 3 lots fait côté PHP), sans le slider/scroll-snap horizontal
   ni les traits décoratifs entre étoiles (::before) qui n'ont plus de sens
   une fois tout empilé — ils étaient calculés pour la disposition 3 colonnes
   uniquement. Le titre (normalement 1er enfant de la colonne du milieu) est
   remonté en tête de liste via order. */
@media (max-width: 1199px) {
  .testimonials-columns {
    flex-direction: column;
    overflow-x: visible;
    scroll-snap-type: none;
    gap: 50px;
  }
  .testimonials-columns__col { display: contents; }
  .testimonials-columns__title { order: -1; margin-bottom: 75px; }
  .testimonial-card { width: 90%; margin-inline: auto; background: var(--color-bg-white); }
  /* Trait de liaison entre étoiles restauré pour la liste empilée (celui
     d'origine, ::before de la 2e carte de chaque colonne, ne fonctionnait
     que pour 2 cartes groupées ; ici tout est aplati en une seule liste).
     Hauteur exacte (gap + hauteur réelle de la carte précédente) calculée
     en JS (voir main.js, updateTestimonialConnectors) et posée en variable
     CSS sur chaque carte : les avis ont des longueurs très variables, donc
     aucune valeur fixe ne peut à la fois toucher l'étoile du dessus sans
     jamais déborder. Fallback figé seulement pour l'instant qui précède
     l'exécution du JS. z-index:-1 + fond blanc opaque ci-dessus sur la
     carte : le trait passe bien derrière cartes ET étoiles, seul le
     segment dans le gap reste visible — fiable maintenant que la hauteur
     calculée correspond exactement à la distance réelle entre cartes. */
  .testimonial-card::before {
    content: '';
    position: absolute;
    top: calc(-1 * var(--connector-h, 90px)); left: calc(50% - 1px);
    width: 2px; height: var(--connector-h, 90px);
    background: var(--color-border);
    z-index: -1;
  }
  /* :first-of-type/:nth-of-type comptent parmi les vrais frères DOM (dans
     leur .testimonials-columns__col d'origine, display:contents n'y change
     rien) — pas utilisables pour cibler "la toute 1re carte de la liste
     aplatie". On active le trait sur toutes les cartes puis on le masque
     uniquement sur cette 1re carte réelle. */
  .testimonials-columns__col:first-child .testimonial-card:first-child::before {
    display: none;
  }
  .testimonials-columns__dots { display: none; }
}
.testimonial-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 11px 17px;
  border: 2px solid var(--color-border);
  border-radius: 15px;
  text-align: center;
}
/* Traits de liaison desktop uniquement (≥1200px, 3 colonnes visibles côte à
   côte) — scopés ici depuis leur passage en conflit avec le trait unique
   calculé en JS pour la liste empilée tablette/mobile (voir plus haut et
   .testimonial-card::before, main.js updateTestimonialConnectors). */
@media (min-width: 1200px) {
  /* Trait qui relie la 1re carte des colonnes de gauche/droite à la
     .product-card de la section au-dessus (colonnes 1 et 3 du product-grid,
     plus hautes que la colonne du milieu) — remonte dans l'espace entre les
     deux sections (2 × padding de .section = 160px) et dépasse de 15px dans
     la carte. Pas la colonne du milieu : elle commence par le titre, pas une
     carte, donc rien à relier au même endroit. */
  .testimonials-columns__col:nth-child(1) .testimonial-card:first-child::before,
  .testimonials-columns__col:nth-child(3) .testimonial-card:first-child::before {
    content: '';
    position: absolute;
    top: -180px; left: calc(50% - 1px);
    width: 2px; height: 195px;
    background: var(--color-border);
    z-index: -1;
  }
  /* Même trait, entre la 1re et la 2e carte de chaque colonne (gap de 40px
     entre elles) — nth-of-type plutôt que nth-child car la colonne du milieu
     a le <h2> comme 1er enfant, pas une carte. */
  .testimonial-card:nth-of-type(2)::before {
    content: '';
    position: absolute;
    top: -43px; left: calc(50% - 1px);
    width: 2px; height: 55px;
    background: var(--color-border);
  }
}
/* Étoiles à cheval sur la bordure haute de la carte (moitié dehors, moitié
   dedans) — comme les pastilles de .stats-timeline. */
.testimonial-card__stars {
  position: absolute;
  top: -1px; left: 50%;
  transform: translate(-50%, -50%);
  display: flex; justify-content: center; gap: 6px;
}
.testimonial-card__stars svg { width: 40px; height: 40px; }
.testimonial-card__author { display: block; font-family: var(--font-heading); color: var(--color-primary); text-transform: uppercase; margin-top: 20px; margin-bottom: 12px; }
.testimonial-card__author-first { font-weight: 200; }
.testimonial-card__author-last { font-weight: 700; }

/* "Nos partenaires" (export_groupe.html) : bandeau bordé haut/bas, titre en
   légende sur la bordure haute (comme un <legend> de <fieldset>). */
.partners-section {
  margin-top: 150px;
  padding-bottom: 0;
  border-top: 2px solid var(--color-border);
}
.partners-section__container { position: relative; }
.partners-section__title {
  position: absolute;
  /* -82px = écart réel mesuré entre .partners-section__container et le haut
     de .partners-section (border+padding combinés dépassent ce qu'implique
     .section--tight seul) : cale le titre pile sur la bordure haute. */
  top: -82px; left: 0;
  transform: translateY(-50%);
  margin: 0;
  background: var(--color-bg-white);
  text-align: left;
  font-size: 40px;
}
/* Chevauchement avec la bordure rétabli sur mobile (demandé explicitement) :
   on garde position:absolute/top/transform hérités de la règle de base
   ci-dessus, juste une taille de police plus petite. */
@media (max-width: 767px) {
  .partners-section__title { font-size: 28px; left: 25px; }
}
@media (min-width: 768px) and (max-width: 1199px) {
  .partners-section__title { left: 5%; }
}
/* Carrousel infini : .partners-row est la fenêtre visible (overflow:hidden),
   .partners-row__track contient 2 copies de la liste et défile en boucle via
   translateX(-50%) — cette valeur correspond toujours exactement à une copie
   complète, quel que soit le nombre de logos. Taille de logo fixe
   150×110px (gabarit natif de l'export) — moins de 8 visibles à la fois en
   desktop avec cette taille, mais le défilement reste continu. */
.partners-row {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  margin-bottom: 64px;
  overflow: hidden;
  opacity: 1;
}
.partners-row__track {
  display: flex;
  align-items: center;
  gap: 48px;
  width: max-content;
  animation: partners-scroll 30s linear infinite;
}
.partners-row__track img,
.partners-row__track span {
  flex: 0 0 150px;
}
.partners-row__track img {
  height: 110px;
  width: 150px;
  object-fit: contain;
}
.partners-row:hover .partners-row__track { animation-play-state: paused; }
@keyframes partners-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .partners-row__track { animation: none; }
}
/* Trait pleine largeur d'écran entre le carrousel et la note Fédération —
   même technique que .coverage-map__flags mais via margin-inline (fiable
   quel que soit le display du parent, pas besoin qu'il soit flex centré). */
.partners-section__divider {
  height: 2px;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  margin-top: 32px;
  background: var(--color-border);
}
.partners-section__note {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 58px;
  margin-bottom: 124px;
}
.partners-section__note-media {
  width: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.partners-section__note-media img { max-width: 100%; height: 212px; display: block; }
.partners-section__note-text-col { width: 50%; }
.partners-section__note-text {
  width: 100%;
  max-width: 475px;
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 300;
  font-size: 25px;
  line-height: 35px;
  letter-spacing: 0;
  text-align: left;
}
.partners-section__note-text strong { font-weight: 600; }
@media (max-width: 767px) {
  .partners-section__note { flex-direction: column; gap: 24px; margin-bottom: 64px; }
  .partners-section__note-media, .partners-section__note-text-col { width: 100%; }
  .partners-section__note-text { width: 100%; font-size: 19px; line-height: 27px; text-align: center; }
}
@media (min-width: 768px) and (max-width: 1199px) {
  .partners-section__note-media { width: 40%; }
  .partners-section__note-text-col { width: 60%; }
  .partners-section__note-text { font-size: 20px; width: 80%; }
  .testimonial-card__author { margin-bottom: 0; }
}

.faq-list { max-width: 1089px; margin: 0; }
.icon-grid-section { padding-top: 0; }
/* "Nos Solutions Techniques" (export_groupe.html) : grille bento sur filets
   gris clairs — obtenue en mettant le fond de .icon-grid dans la couleur du
   filet et un gap de 1px, chaque cellule ayant son propre fond blanc (pas
   besoin de gérer les bordures une à une malgré la 1re ligne irrégulière). */
.icon-grid {
  display: grid;
  grid-template-columns: 1fr;
  background: var(--color-border);
  gap: 2px;
  border: 1px solid var(--color-border);
}
.section.icon-grid-section .icon-grid { border-width: 2px; border-left: 0; border-right: 0; }
@media (max-width: 767px) {
  .icon-grid-section .icon-grid { border-top: 0; }
}
.icon-grid__intro {
  background: var(--color-bg-white);
  display: flex; align-items: center; justify-content: center; gap: 90px;
  padding: 32px;
  min-height: 220px;
}
.icon-grid__intro svg { width: 67px; height: 72px; flex: 0 0 auto; }
@media (max-width: 767px) {
  .icon-grid__intro { flex-wrap: wrap; gap: 24px; text-align: center; justify-content: center; }
}
.icon-grid__title { margin: 0 0 0.3em; text-align: left; text-transform: none; font-size: 2.1875rem; }
.icon-grid__lead {
  margin: 0; margin-top: 17px; text-align: left; max-width: 434px;
  color: var(--color-navy-accent);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 23px;
  line-height: 30px;
  letter-spacing: 0;
}
.icon-grid__lead .regular { font-weight: 400; }
@media (max-width: 767px) {
  /* Placé après les règles de base ci-dessus (même sélecteurs, même
     spécificité) : sinon text-align:left écrase silencieusement ce
     text-align:center au tie-break de la cascade. */
  .icon-grid__title, .icon-grid__lead { text-align: center; max-width: 100%; }
}
.icon-card {
  background: var(--color-bg-white);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  padding: 32px 24px;
  text-align: center;
  min-height: 220px;
}
/* Icône + libellé (vers la page produit) : lien séparé de .icon-card__file
   (vers le PDF) pour ne pas imbriquer deux <a>. */
.icon-card__link {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  text-decoration: none;
  color: inherit;
}
.icon-card__label {
  order: 1;
  max-width: 285px;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 24px;
  line-height: 27px;
  letter-spacing: 0;
  text-align: center;
}
.icon-card__icon { order: 2; }
.icon-card__icon svg { width: 20px; height: 25px; }
/* Le fond/la bordure de la pastille et le texte du nom de fichier ont des
   opacités distinctes dans l'export (40% / 61%) — d'où le fond en ::before
   plutôt que sur .icon-card__file directement (sinon l'icône aussi serait
   affectée). */
.icon-card__file {
  order: 3;
  position: relative;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 16px;
  text-decoration: none;
}
.icon-card__file::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: var(--radius-pill);
  background: rgba(230, 46, 64, 0.1922);
  border: 1px solid rgba(230, 46, 64, 0.6275);
  opacity: 0.4044;
}
.icon-card__file-name {
  position: relative;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 13px;
  line-height: 13px;
  letter-spacing: 0;
  text-align: center;
  color: var(--color-primary);
  opacity: 0.61;
}
.icon-card__file svg { width: 10px; height: 10px; flex: 0 0 auto; }
@media (max-width: 767px) {
  .icon-card__file-name { font-size: 10px; }
}
@media (min-width: 992px) {
  .icon-grid { grid-template-columns: 511.57fr 426.86fr 511.57fr; }
  .icon-grid__intro { grid-column: 1 / 3; }
}
/* Tablette : intro sur 50px de gap au lieu de 90px, cartes en grille 2x2
   (l'intro reste en pleine largeur au-dessus). Placé après les 2 règles
   ci-dessus (même sélecteurs) pour gagner sur toute la plage 768-1199px,
   qui chevauche le point de bascule desktop à 992px. */
@media (min-width: 768px) and (max-width: 1199px) {
  .icon-grid__intro { gap: 50px; }
  .icon-grid { grid-template-columns: 1fr 1fr; }
  .icon-grid__intro { grid-column: 1 / 3; }
  .icon-card__file-name { font-size: 10px; }
  /* Pages à une seule carte (cabine/moteur/partie-electrique/portes, contre
     4 sur l'accueil) : sans ça la carte unique reste dans la 1re colonne de
     la grille 2x2, laissant la 2e vide à côté. 2e enfant + dernier enfant =
     seul .icon-card présent (l'intro est toujours le 1er enfant). */
  .icon-card:nth-child(2):last-child { grid-column: 1 / 3; }
  /* Pages kit (1 seule carte) : contenu de l'intro centré, comme le mobile
     (voir @media max-width:767px plus haut) — ciblé via :has() sur la même
     carte unique que la règle juste au-dessus, pour ne pas toucher
     l'accueil (4 cartes, intro alignée à gauche). */
  .icon-grid:has(.icon-card:nth-child(2):last-child) .icon-grid__intro { flex-wrap: wrap; text-align: center; justify-content: center; }
  .icon-grid:has(.icon-card:nth-child(2):last-child) .icon-grid__title { text-align: center; max-width: 100%; }
  .icon-grid:has(.icon-card:nth-child(2):last-child) .icon-grid__lead { text-align: center; max-width: 80%; margin-inline: auto; }
  #stats .section__title .navy { display: block; }
  /* 2 lignes de 2 items. Ligne 1 : trait qui part du 1er item et va jusqu'au
     bord droit de l'écran (par-dessus le connecteur existant item1<->item2,
     inchangé). Ligne 2 : miroir, le connecteur hérité vers l'item précédent
     (item2, sur l'autre ligne) est retiré et remplacé par un trait qui part
     du 1er item de la 2e ligne (item3) et va jusqu'au bord gauche. Largeurs
     en vw approximées depuis la position réelle du point (#stats fait 90vw
     centré, item = 50% du conteneur) — à ajuster visuellement si besoin. */
  .stats-timeline { flex-wrap: wrap; row-gap: 48px; }
  .stats-timeline__item { flex: 0 0 50%; padding-top: 24px; }
  .stats-timeline__item:nth-child(3)::before { display: none; }
  .stats-timeline__item:nth-child(1)::after {
    content: '';
    position: absolute;
    top: 10px; left: 50%;
    width: 72vw; height: 2px;
    background: var(--color-border);
  }
  .stats-timeline__item:nth-child(3)::after {
    content: '';
    position: absolute;
    top: 10px; right: 50%;
    width: 27vw; height: 2px;
    background: var(--color-border);
  }
  .coverage-map__title { font-size: 70px; }
  .coverage-map__title-break { display: block; }
  .section__lead { max-width: 80%; }
}

/* "Foire Aux Questions" (export_groupe11.html) : carte rose arrondie, ombre
   légère en bas. */
/* Même gabarit de largeur que .hero : margin:28px, pleine largeur d'écran
   sinon (indépendant du max-width de .container à l'intérieur). */
.faq-section {
  margin: 0 28px;
  padding-bottom: 115px;
  background: #FFF4F5;
  border-radius: 40px 40px 0 0;
  box-shadow: 0 24px 24px -12px rgba(255, 244, 245, 0.82);
}
.faq-section h2 { font-size: 60px; }
@media (max-width: 767px) {
  /* "Questions" ne peut pas se couper : à 60px il déborde de sa boîte sur
     les plus petits écrans (320px) sans que scrollWidth le rattrape via le
     rect du h2 lui-même (débord d'encre, pas de la boîte). */
  .faq-section h2 { font-size: 35px; }
  .faq-section { margin: 0; }
}
/* La bordure n'est plus un border-bottom natif sur .faq-item (sa position
   coïncidait exactement avec le bord bas qui bouge pendant l'animation de
   .faq-item__answer, ce qui provoquait les filets fantômes en toggle rapide
   — le navigateur repeint un trait "interpolé" à chaque frame de la
   transition). Elle est maintenant un ::after à plat, positionné en
   absolute sur .faq-item (position:relative), peint sur son propre calque
   indépendant de la boîte qui grandit/rétrécit. isolation:isolate crée un
   contexte d'empilement par item pour éviter tout bleed de repaint entre
   items voisins qui s'animent en même temps (fermeture + ouverture
   simultanées lors d'un clic rapide sur un autre item). */
.faq-item {
  position: relative;
  isolation: isolate;
  padding: 25px 0;
}
.faq-item::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: rgba(230, 46, 64, 0.4432);
}
.faq-item__question {
  font-weight: 600;
  font-size: 35px;
  color: var(--color-primary);
  cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
/* La question ouverte passe en plus grand (44px vs 35px fermée). */
.faq-item.is-open .faq-item__question { font-size: 35px; }
.faq-item__toggle { flex: 0 0 auto; color: var(--color-primary); font-size: 45px; line-height: 40px; font-weight: 100; }
@media (max-width: 767px) {
  /* 35px (taille desktop/tablette) fait passer les questions les plus
     longues sur 3-4 lignes sur un écran mobile ; le "+"/"-" (align-items:
     center sur la ligne flex) se retrouvait alors centré au milieu du bloc
     replié au lieu d'être aligné avec la 1re ligne de texte. */
  .faq-item__question { font-size: 20px; align-items: flex-start; }
  .faq-item.is-open .faq-item__question { font-size: 20px; }
  .faq-item__toggle { font-size: 28px; line-height: 26px; }
}
/* grid-template-rows 0fr->1fr plutôt que max-height : anime jusqu'à la
   vraie hauteur du contenu (pas une valeur arbitraire), donc pas de saut ni
   de temps mort selon la longueur de la réponse — plus fluide.
   overflow:hidden + contain:paint directement sur le conteneur grid (pas
   seulement sur .faq-item__answer-inner) : pendant l'interpolation de la
   row, sa hauteur passe par des valeurs sub-pixel et le texte contenu peut
   fuir/clignoter au bord si le clip n'est pas posé au même niveau que la
   boîte qui anime. contain:paint isole aussi le repaint de ce sous-arbre
   du reste de la page. */
.faq-item__answer {
  display: grid;
  grid-template-rows: 0fr;
  max-width: 600px;
  opacity: 0;
  margin-top: 0;
  color: var(--color-primary);
  overflow: hidden;
  contain: paint;
  transition: grid-template-rows 0.35s ease, opacity 0.3s ease, margin-top 0.35s ease;
}
/* Le calque GPU (will-change/translateZ) est posé sur le contenu texte
   lui-même plutôt que sur la boîte qui interpole sa taille : ça isole le
   rendu du texte de l'interpolation de la grid-row sans faire porter à
   .faq-item__answer les artefacts de bord de calque. */
.faq-item__answer-inner {
  overflow: hidden;
  min-height: 0;
  will-change: transform;
  transform: translateZ(0);
}
.faq-item.is-open .faq-item__answer { grid-template-rows: 1fr; opacity: 1; margin-top: 19px; }
.faq-item.is-open { padding-bottom: 47px; }

/* Traits verticaux gauche/droite qui relient l'image du haut à la ligne
   horizontale des drapeaux, en bas (export_groupe.html). */
.coverage-map {
  display: flex; flex-direction: column; align-items: center; gap: 16px; text-align: center;
  padding-top: 32px;
  border-left: 2px solid var(--color-border);
  border-right: 2px solid var(--color-border);
}
.coverage-map__title { color: var(--color-primary); margin-top: 32px; font-size: 80px; }
.coverage-map__title-break { display: none; }
@media (max-width: 767px) {
  /* À 80px, un mot un peu long ("chalandise", "PARTENAIRES"...) ne peut pas
     se couper et déborde symétriquement des deux côtés (texte centré). */
  .coverage-map__title { font-size: 36px; }
  .coverage-map__title-break { display: block; }
}
/* Même gabarit de largeur que .hero (margin: 28px de chaque côté) — l'image
   est sortie de .container pour ne pas être plafonnée à 1200px. Pas de
   margin-bottom : le trait de .coverage-map doit se coller directement au
   bas de l'image (l'espacement de 32px est le padding-top de .coverage-map). */
.coverage-map__image {
  display: block;
  width: calc(100% - 56px);
  margin: 0 28px;
  border-radius: var(--radius-hero);
}
/* France > UE > Monde reliés par une ligne continue (export_groupe.html) —
   même pattern de ligne "derrière, badges par-dessus" que .stats-timeline. */
.coverage-map__flags {
  position: relative;
  width: 100vw;
  display: flex; align-items: center; justify-content: center; gap: 8%;
  margin-top: 24px;
  /* Le trait de .coverage-map doit s'arrêter pile sur la ligne horizontale
     (le ::before, calé au centre vertical des pastilles) plutôt qu'en bas
     des pastilles : on remonte le bas de la boîte flex de la moitié de leur
     hauteur — les pastilles débordent sous la bordure, comme sur l'export. */
  margin-bottom: -30px;
}
.coverage-map__flags::before {
  content: '';
  position: absolute; top: 50%; left: 0; right: 0;
  height: 2px;
  width: 100%;
  background: var(--color-border);
}
/* Les SVG (flag-france/flag-eu/flag-world) intègrent déjà leur propre
   cercle blanc + liseré gris — pas de fond/bordure en plus ici. */
.coverage-map__flag {
  position: relative;
  width: 60px; height: 60px;
  display: inline-flex; align-items: center; justify-content: center;
}
@media (max-width: 767px) {
  .coverage-map__flag { width: 50px; height: 50px; }
}
.coverage-map__flag svg { width: 100%; height: 100%; }
.coverage-map__chevron {
  position: relative;
  display: inline-flex; align-items: center;
  padding: 0 4px;
}
.coverage-map__chevron svg { width: 25px; height: 25px; }

/* ==========================================================================
   Formulaires (page Demande de devis / Contact)
   ========================================================================== */
.form-field {
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-pill);
  padding: 14px 20px;
  width: 100%;
  background: transparent;
  color: var(--color-text);
  font-size: 0.9375rem;
}
.form-field::placeholder { color: var(--color-primary); opacity: 0.6; }
textarea.form-field { resize: vertical; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.bisem-form { width: 75%; margin-inline: auto; }
.bisem-form__title { color: var(--color-primary); font-size: 90px; margin-bottom: 0; }
.bisem-form__title-break { display: none; }
@media (max-width: 767px) {
  .bisem-form { width: 100%; }
  /* "DEMANDE DE DEVIS", "CONTACTEZ-NOUS !" à 90px ne rentrent pas sur un
     écran mobile (mots non coupables, notamment avec le tiret). */
  .bisem-form__title { font-size: 40px; }
}
/* Pages Devis/Contact (template-parts/form.php) : h1 + lead/sublead centrés.
   :has() cible le conteneur du formulaire (le seul avec .bisem-form__title)
   sans dépendre de .section--bg-light, partagée avec d'autres blocs. */
@media (max-width: 1199px) {
  .container:has(> .bisem-form__title) > h1,
  .container:has(> .bisem-form__title) > p { text-align: center; }
  .bisem-form__title-break { display: block; }
}
.form-field-label-wrap { display: block; position: relative; }
/* Le label se superpose au contour haut du champ (style "outlined" à la
   Material) : span en absolu, centré verticalement sur le bord haut de
   l'input, avec un fond qui masque le trait du contour derrière le texte. */
.form-field-label {
  position: absolute;
  top: 0; left: 20px;
  transform: translateY(-50%);
  z-index: 1;
  background: var(--color-bg-light);
  padding: 0 6px;
  font-size: .8125rem;
  line-height: 1;
  color: var(--color-primary);
}
.form-field-select {
  appearance: none;
  cursor: pointer;
  color: var(--color-primary);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%23E62E40' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 22px center;
}
.form-field-select option { color: var(--color-text); }

/* Checkbox de consentement (page Demande de devis) — case dessinée en CSS
   pour reprendre le rouge de marque au lieu du rendu natif du navigateur. */
.form-consent { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; }
.form-consent input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 14px; height: 14px;
  margin: 0;
  cursor: pointer;
}
.form-consent__box {
  flex: 0 0 14px;
  width: 14px; height: 14px;
  margin-top: 1px;
  border: 1.5px solid var(--color-primary);
  border-radius: 4px;
  position: relative;
  transition: background-color .15s ease;
}
.form-consent input[type="checkbox"]:checked + .form-consent__box { background: var(--color-primary); }
.form-consent input[type="checkbox"]:checked + .form-consent__box::after {
  content: '';
  position: absolute;
  left: 4px; top: 1px;
  width: 4px; height: 7px;
  border: solid var(--color-text-inverse);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
.form-consent input[type="checkbox"]:focus-visible + .form-consent__box { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.form-consent__text { font-size: 13px; line-height: 16px; letter-spacing: 0; font-weight: 400; text-align: left; color: var(--color-primary); opacity: 1; }
.form-notice { padding: 14px 20px; border-radius: var(--radius-pill); font-weight: 500; margin-bottom: 24px; }
.form-notice--success { background: #E6F4EA; color: #1E7E34; }
.form-notice--error { background: #FDECEA; color: var(--color-primary); }
/* Badge reCAPTCHA v3 masqué par Google par défaut en bas à droite : laissé
   visible (obligation des conditions d'utilisation de reCAPTCHA sans mention
   "protected by reCAPTCHA" affichée ailleurs sur la page). */
.form-field-file__row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 6px 6px 6px 20px;
  position: relative;
}
.form-field-file__placeholder { flex: 1; font-size: 0.9375rem; color: var(--color-primary); opacity: 0.6; }
.form-field-file__browse { flex: 0 0 auto; pointer-events: none; padding: 12px 24px; }
@media (max-width: 480px) {
  /* Le placeholder passe sur plusieurs lignes à côté du bouton "Parcourir"
     à cette largeur : on empile plutôt que de les garder côte à côte. */
  .form-field-file__row { flex-wrap: wrap; padding: 14px 14px 14px 20px; }
  .form-field-file__placeholder { flex: 1 1 100%; }
  .form-field-file__browse { flex: 0 0 auto; }
}
.form-field-file input[type="file"] {
  position: absolute; inset: 0;
  opacity: 0;
  cursor: pointer;
}

/* ==========================================================================
   Footer (export_groupe12.html, 2026-09-10) — bleu marine, coin haut-gauche
   arrondi avec le logo en pastille superposée (même gabarit margin:28px que
   .hero), 4 colonnes séparées par des filets blancs translucides.
   ========================================================================== */
/* Le cadre porte la marge (0 28px, même rythme que .faq-section/.hero) et
   le fond #FFF4F5 : .site-footer le remplit entièrement, donc l'encoche que
   son border-radius découpe dans le coin haut-droit révèle ce rose au lieu
   du blanc/transparent de la page derrière. */
.site-footer__frame {
  margin: 0 28px 0;
  background: #FFF4F5;
}
.site-footer {
  position: relative;
  background: var(--color-navy-accent);
  color: var(--color-text-inverse);
  padding: 64px 0 0;
  border-radius: 0 40px 0 0;
}
.site-footer__badge {
  position: absolute;
  top: 0; left: -2px;
  line-height: 0;
}
.site-footer__badge img { width: 250px; height: auto; display: block; }
/* .site-footer .site-footer__badge-img--X (2 classes) : la règle de base
   ci-dessus (.site-footer__badge img, 1 classe + 1 élément) a une
   spécificité plus élevée qu'un simple .site-footer__badge-img--X (1
   classe) et gagnait le display:block quoi qu'il arrive. */
.site-footer .site-footer__badge-img--mobile { display: none; }
@media (max-width: 767px) {
  .site-footer .site-footer__badge-img--desktop { display: none; }
  .site-footer .site-footer__badge-img--mobile { display: block; }
}
/* .container est plafonné à --container-max et centré : dans le footer (déjà
   borné par .site-footer__frame), ça laissait de grandes marges vides de
   part et d'autre. On neutralise le plafond/centrage, ne garde qu'un
   padding pour respirer. */
.site-footer .container { max-width: none; margin-inline: 0; padding-inline: 40px; }
.footer-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  width: 90%;
  margin-inline: auto;
}
.footer-grid > * { min-width: 0; }
.footer-grid__heading {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 18px;
  line-height: 27px;
  letter-spacing: 0;
  text-align: left;
  text-transform: uppercase;
  color: var(--color-text-inverse);
  opacity: 1;
  margin-bottom: 5px;
}
/* Titres à flèche : retour à la ligne forcé (<br> dans le markup) avant le
   dernier mot, et la flèche reste collée en inline juste après ce mot au
   lieu d'être un item flex séparé (qui la centrait à côté du bloc de texte
   entier une fois passé sur 2 lignes). */
.footer-grid__heading--arrow { display: block; margin-bottom: 12px; }
.footer-grid__heading--arrow .footer-arrow { display: inline-flex; margin-left: 8px; vertical-align: middle; }
/* Titres de la colonne adresse (pin/téléphone/mail) : icône empilée
   au-dessus du texte plutôt qu'à côté, contrairement aux titres à flèche
   (Nos programmes neufs…) qui restent sur une ligne. */
.footer-grid__heading:has(.footer-mini-icon) {
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}
.footer-grid__list { display: flex; flex-direction: column; gap: 8px; }
.footer-grid__list a {
  font-family: var(--font-heading);
  font-weight: 200;
  font-size: 17px;
  line-height: 22px;
  letter-spacing: 0;
  text-align: left;
  text-transform: uppercase;
  color: var(--color-text-inverse);
  opacity: 1;
}
/* Colonnes 2 et 3 (Nos programmes neufs / Nos kits de modernisation) : casse
   normale, contrairement à la colonne nav qui reste en majuscules.
   :nth-of-type (pas :nth-child) : les 5 <div class="footer-grid__divider">
   sont des enfants directs de .footer-grid AVANT les colonnes, ce qui
   décale complètement le comptage nth-child. nth-of-type ne compte que les
   <nav> entre eux (les 3 premières colonnes), en ignorant les <div> — la
   seule façon fiable de cibler encore la 2e et la 3e ici. */
.footer-grid__col:nth-of-type(2) .footer-grid__list a,
.footer-grid__col:nth-of-type(3) .footer-grid__list a {
  text-transform: none;
}
/* Soulignement animé (scaleX) plutôt que le text-decoration:underline natif
   qui apparaît d'un coup : trait qui se déploie depuis la gauche au survol.
   Exclut .footer-mybisem, déjà souligné en permanence (pas de survol à
   animer, ça ferait un double trait). */
.footer-grid a:not(.footer-mybisem):not(.social-icon) {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
.footer-grid a:not(.footer-mybisem):not(.social-icon)::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}
.footer-grid a:hover { opacity: 1; }
.footer-grid a:not(.footer-mybisem):not(.social-icon):hover::after { transform: scaleX(1); }
/* Colonne nav (Accueil, À propos…) : libellés en MAJUSCULES, décalés vers le
   bas pour s'aligner sur le 1er lien des autres colonnes (qui, elles, ont un
   titre au-dessus) plutôt que sur ces titres eux-mêmes — voir capture
   export_groupe12.html du 2026-09-15. */
.footer-grid__list--nav a { text-transform: uppercase; }
/* Doublon invisible du titre des colonnes voisines (même largeur de colonne
   en desktop, donc même retour à la ligne) : pousse le 1er lien nav au bon
   niveau sans valeur en dur qui casserait si le titre change de nombre de
   lignes. Masqué par défaut (pas de titre visible sur les autres colonnes
   en mobile où les colonnes s'empilent). */
.footer-grid__spacer { display: none; }
/* Icônes réutilisées telles quelles (couleur d'origine rouge) puis passées
   en blanc via filtre — évite de dupliquer des assets recolorés. */
.footer-arrow, .footer-mini-icon { display: inline-flex; filter: brightness(0) invert(1); }
.footer-arrow { transform: rotate(90deg); }
.footer-arrow svg { width: 16px; height: 16px; }
.footer-mini-icon svg { width: 20px; height: auto; }
.footer-mini-icon--mail { margin-bottom: 4px; }
.footer-mybisem {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 16px;
  color: var(--color-primary);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 17px;
  line-height: 22px;
  letter-spacing: 0;
  text-align: left;
  text-transform: uppercase;
  opacity: 1;
}
/* text-decoration:underline ne se propage pas sous les enfants flex (la
   flèche svg) : trait dessiné en ::after sur toute la largeur de la boîte
   (texte + flèche) à la place. */
.footer-mybisem::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
}
.footer-mybisem svg { width: 14px; height: 14px; }
.footer-grid__address, .footer-contact-row a {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 17px;
  line-height: 23px;
  letter-spacing: 0;
  text-align: left;
  color: var(--color-text-inverse);
  opacity: 1;
}
.footer-grid__address { margin: 0; }
.footer-contact-row { display: flex; flex-wrap: nowrap; gap: 32px; margin: 16px 0; }
@media (max-width: 767px) {
  /* Téléphone + e-mail côte à côte sans wrap déborde dès que la colonne du
     footer devient étroite (grille à 2 colonnes entre 480 et 767px). */
  .footer-contact-row { flex-wrap: wrap; gap: 16px; }
}
@media (max-width: 479px) {
  /* Le 38px réglé plus bas ne couvre que 480-1199px (bento tablette) : en
     dessous de 480px (téléphone), .social-icon retombait sur son 58px de
     base (pensé pour le hero), disproportionné dans la colonne du footer. */
  .footer-social .social-icon { width: 38px; height: 38px; }
}
.footer-social { display: flex; gap: 8px; margin-top: 32px; }
/* Pastilles inversées dans le footer : les icônes social-*.svg intègrent
   leur propre cercle blanc + glyphe rouge (voir fichiers sources) ; ici on
   veut l'inverse (cercle rouge, glyphe blanc) — on cible directement le
   rect/path du SVG inliné plutôt que de dupliquer 3 assets recolorés. */
.footer-social .social-icon { background: none; }
.footer-social .social-icon svg rect { fill: var(--color-primary); }
.footer-social .social-icon svg path { fill: #fff; }
.footer-bottom__credit-break { display: none; }
.footer-bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 16px;
  margin-top: 48px;
  /* Annule le padding-inline:40px de .container (site-footer) pour que le
     border-top fasse toute la largeur du bloc bleu, tout en gardant le
     contenu aligné au même endroit via un padding-inline équivalent ici. */
  margin-inline: -40px;
  padding-inline: 40px;
  padding-top: 24px;
  padding-bottom: 24px;
  border-top: 1px solid rgba(255, 255, 255, 0.102);
  font-size: 0.875rem;
  font-weight: 200;
  opacity: 0.65;
}
.footer-bottom p { margin: 0; }
.footer-bottom a { opacity: 1; }
.footer-bottom__credit { font-weight: 700; opacity: 1; cursor: pointer; }
.footer-bottom__links { display: flex; align-items: center; gap: 10px; }
.footer-bottom__links a {
  font-family: var(--font-heading);
  font-weight: 200;
  text-transform: uppercase;
}
/* Même soulignement animé (scaleX) que .footer-grid__list a plutôt que le
   text-decoration:underline au survol utilisé jusque-là ici. */
.footer-bottom__credit, .footer-bottom__links a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
.footer-bottom__credit::after, .footer-bottom__links a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}
.footer-bottom__credit:hover::after, .footer-bottom__links a:hover::after { transform: scaleX(1); }
@media (min-width: 480px) {
  .footer-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Grille de fond qui segmente chaque colonne (2x2 ici, contre 1x4 en
   desktop où .footer-grid__divider s'en charge déjà) : même technique bento
   que .icon-grid — fond = couleur du trait, gap = épaisseur du trait,
   chaque cellule récupère sa propre couleur de fond (celle du footer) +
   son padding pour ne pas coller aux traits. */
@media (min-width: 480px) and (max-width: 1199px) {
  /* Même technique que .footer-bottom un peu plus bas : margin-inline:-40px
     annule le padding-inline:40px de .site-footer .container pour que les
     traits (fond de grille + gap) aillent jusqu'aux bords réels de la carte
     (pas de padding-inline compensatoire ici : ça remettrait la couleur du
     trait en bandeau plein sur toute sa largeur au lieu d'un fin trait — le
     texte garde son retrait via le padding de chaque cellule uniquement).
     gap:1px, même couleur que .footer-bottom { border-top } : trait de
     taille identique. column-gap:0 (pas 1px) : la ligne verticale centrale
     est déjà fournie par .footer-grid__divider--2 juste plus bas (qui déborde
     en haut/bas, contrairement à un simple gap borné à la grille) — un
     column-gap ici dupliquerait cette ligne pile au même endroit, d'où le
     dédoublement visuel observé. */
  .footer-grid {
    width: auto;
    margin-inline: -40px;
    background: rgba(255, 255, 255, 0.102);
    row-gap: 1px;
    column-gap: 0;
  }
  .footer-grid__col {
    background: var(--color-navy-accent);
    padding: 24px;
  }
  /* La colonne nav (accueil/à propos/…) n'a pas de titre au-dessus de sa
     liste, contrairement à la colonne "Nos programmes neufs" à sa droite —
     du coup les 2 listes ne démarraient pas à la même hauteur. Le markup a
     déjà un titre invisible dédié à ça (.footer-grid__spacer, aria-hidden,
     copie du titre voisin) : utilisé en desktop pour la même raison,
     on l'active aussi ici plutôt que d'inventer un autre calage. */
  .footer-grid__spacer { display: flex; visibility: hidden; }
  .footer-social .social-icon { width: 38px; height: 38px; }
}
/* Séparateurs verticaux : plus des border-left sur .footer-grid__col (donc
   bornés à la hauteur de son propre contenu) mais des lignes indépendantes,
   position:absolute sur .footer-grid lui-même (position:relative) : top:-64px
   remonte jusqu'au sommet du cadre (compense le padding-top:64px de
   .site-footer, que .footer-grid n'a pas) et bottom:0 s'arrête pile au bas
   de .footer-grid, donc avant le margin-top de .footer-bottom — sans entrer
   dedans. Position horizontale en calc() (gap:32px, colonnes
   1fr/1fr/1fr/1.2fr, plus de terme padding-inline vu que .footer-grid est
   déjà dans le padding du container). */
.footer-grid__divider {
  display: none;
  position: absolute;
  top: -64px;
  /* -48px : comble le margin-top de .footer-bottom (le gap entre le bas de
     .footer-grid et le haut de .footer-bottom), pour que la ligne aille
     jusqu'à toucher .footer-bottom au lieu de s'arrêter avant. */
  bottom: -48px;
  width: 1px;
  background: rgba(255, 255, 255, 0.102);
}
/* Override placé après la règle de base ci-dessus (même sélecteur de classe,
   même spécificité) : sinon .footer-grid__divider { display:none } plus bas
   dans le fichier écraserait silencieusement ce display:block au tie-break
   de la cascade. Réutilise le trait --2 (déjà en top:-64px/bottom:-48px, prévu
   pour déborder dans la FAQ et .footer-bottom) avec juste un left:50%. */
@media (min-width: 480px) and (max-width: 1199px) {
  .footer-grid__divider--2 { display: block; left: 50%; }
}
@media (min-width: 1200px) {
  .footer-grid { grid-template-columns: 1fr 1fr 1fr 1.2fr; }
  .footer-grid__col { padding-inline: 32px; }
  .footer-grid__col:first-child { padding-left: 0; }
  .footer-grid__spacer { display: flex; visibility: hidden; }
  .footer-grid { --footer-col-unit: calc((100% - 96px) / 4.2); }
  .footer-grid__divider { display: block; }
  .footer-grid__divider--0 { left: 0; }
  .footer-grid__divider--1 { left: calc(var(--footer-col-unit) + 32px); }
  .footer-grid__divider--2 { left: calc(var(--footer-col-unit) * 2 + 64px); }
  .footer-grid__divider--3 { left: calc(var(--footer-col-unit) * 3 + 96px); }
  .footer-grid__divider--4 { left: 100%; }
}

/* ==========================================================================
   Gallery tabs (template-parts/gallery-tabs.php) — grille de photos filtrée
   par service, réutilise les photos des .product-gallery des pages service.
   ========================================================================== */
.gallery-tabs__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  gap: 28px;
  margin: 40px 0 48px;
}
.gallery-tabs__tab {
  font-family: inherit;
  font-size: 1.0625rem;
  font-weight: 200;
  letter-spacing: 0;
  text-transform: none;
  color: rgba(230, 46, 64, 0.55);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  transition: color .2s ease;
}
.gallery-tabs__tab:hover { color: var(--color-primary); }
.gallery-tabs__tab.is-active {
  font-weight: 700;
  color: var(--color-primary);
  text-decoration: underline;
}
/* Les panneaux se superposent dans la même cellule de grille (au lieu de
   s'empiler en flux normal) pour que le fondu croisé sortant/entrant ne
   provoque pas de saut de mise en page pendant les 250ms où les deux sont
   affichés en même temps. */
.gallery-tabs__panels { display: grid; }
.gallery-tabs__panel { display: none; grid-column: 1; grid-row: 1; }
.gallery-tabs__panel.is-active { display: block; animation: gallery-tabs-fade-in .3s ease; }
.gallery-tabs__panel.is-leaving { display: block; animation: gallery-tabs-fade-out .25s ease; }
@keyframes gallery-tabs-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes gallery-tabs-fade-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(8px); }
}
.gallery-tabs__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
@media (max-width: 767px) {
  .gallery-tabs__grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .gallery-tabs__nav { gap: 16px 20px; }
}
.gallery-tabs__cell {
  aspect-ratio: 1/1;
  border-radius: 20px;
  overflow: hidden;
  border: 2px solid var(--color-border);
}
.gallery-tabs__cell img { width: 100%; height: 100%; object-fit: cover; }

/* ==========================================================================
   Contenu juridique (Mentions légales / RGPD) — présentation simple :
   titre + articles numérotés, sans photo ni composant spécifique.
   ========================================================================== */
.legal-content { max-width: 760px; margin: 0 auto; }
.legal-content__updated { color: var(--color-border); font-size: .875rem; margin: 0 0 2.5em; }
.legal-content h2 {
  color: var(--color-primary);
  font-size: clamp(2.1875rem, 6vw, 3.375rem);
  margin-bottom: 0.6em;
}
.legal-content h3 {
  color: var(--color-navy-accent);
  font-size: 1.125rem;
  margin-top: 2.2em;
  margin-bottom: 0.7em;
}
.legal-content h3:first-of-type { margin-top: 0; }
.legal-content p { margin: 0 0 1.2em; }
.legal-content ul { list-style: disc; padding-left: 1.3em; margin: 0 0 1.2em; }
.legal-content ul li { margin-bottom: 0.5em; }
.legal-content a { color: var(--color-primary); text-decoration: underline; }

/* ==========================================================================
   Popup "MyBisem bientôt disponible" (header.php) — même transition
   opacity/visibility que .nav-menu-panel pour rester cohérent.
   ========================================================================== */
.mybisem-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity .25s ease, visibility 0s linear .25s;
}
.mybisem-modal.is-open { opacity: 1; visibility: visible; transition: opacity .25s ease, visibility 0s linear 0s; }
.mybisem-modal__backdrop { position: absolute; inset: 0; background: rgba(8, 16, 32, 0.55); }
.mybisem-modal__box {
  position: relative;
  z-index: 1;
  background: var(--color-bg-white);
  border-radius: 24px;
  padding: 40px;
  max-width: 420px;
  width: calc(100% - 48px);
  text-align: center;
}
.mybisem-modal__box h3 { color: var(--color-primary); margin-bottom: 0.6em; }
.mybisem-modal__box p { margin: 0; color: var(--color-text); }
.mybisem-modal__close {
  position: absolute;
  top: 12px; right: 12px;
  width: 32px; height: 32px;
  border: none;
  background: none;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--color-primary);
  cursor: pointer;
}

/* ==========================================================================
   Mobile-first breakpoints
   ========================================================================== */
@media (min-width: 768px) {
  .form-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1200px) {
  .container { padding-inline: 32px; }
  .form-grid { grid-template-columns: repeat(2, 1fr); }
  .specs-bar__col:last-of-type span { width: 350px; }
}

@media (max-width: 767px) {
  .site-header { padding: 16px; }
  /* min-height repassé à 100vh (comme desktop) : à 75vh (repris du réglage
     tablette), le contenu du hero (surtout accueil avec sous-titre+séparateur
     +description) remplissait toute la hauteur de la boîte sans marge au-dessus,
     et le titre passait derrière .site-header (position:absolute, z-index:100). */
  .hero { padding: 16px; min-height: calc(100vh - 56px); }
  /* Devis/Contact (.hero--compact, seules pages à passer compact => true) :
     hauteur fixe courte plutôt que dépendante du viewport — !important pour
     battre à coup sûr min-height:calc(100vh - 56px) ci-dessus (même
     spécificité, .hero--compact vient après en source mais min-height et
     height sont deux propriétés différentes, pas un vrai conflit de
     cascade ; !important lève toute ambiguïté). */
  .hero.hero--compact { height: 350px !important; min-height: 0; }
  /* Page Portes (ID 19) : même recadrage que .hero__video sur l'accueil,
     appliqué ici à l'image de fond statique (pas de vidéo sur cette page). */
  body.page-id-19 .hero { background-position: 70% center; }
  .container:has(> .bisem-form__title) > p { width: 90%; margin-inline: auto; }
  /* Même largeur que .hero (margin:15px en mobile, contre 28px hérité ici). */
  main#content > .section--bg-light:first-child { margin-left: 15px; margin-right: 15px; }
  textarea.form-field, .form-field-file__row { border-radius: 30px; }
  .form-grid { grid-template-columns: 1fr; }
  .section { padding: 48px 0; }
  /* Tout ce qui suit est placé après .section{padding:48px 0;} ci-dessus
     (même spécificité, 1 classe) pour gagner le tie-break de la cascade —
     un override plus haut dans le fichier perdait silencieusement face à
     cette règle générique, plus tardive en source. */
  .content-block--bleed { padding-top: 0; }
  .icon-grid-section { padding-top: 0; }
  /* Marge du cadre hero (et du header qui vit dedans, voir .site-header
     plus haut dans ce même bloc) réduite de 28px à 15px sur mobile. */
  .hero { margin: 15px; }
  .site-header { top: 15px; left: 15px; right: 15px; }
  .testimonials-columns__title { margin-bottom: 25px; }
  .partners-section { margin-top: 50px; }
  .partners-section__note-media img { height: 150px; }
  .site-footer__badge img { width: 200px; margin-left: -2px; }
  /* Trait au-dessus de chaque colonne, collé aux bords réels de l'écran —
     même technique que .stats-timeline__item::after (100vw + translateX
     centré sur l'axe vertical du footer, qui est lui-même pleine largeur). */
  .footer-grid__col { position: relative; }
  .footer-grid__col::before {
    content: '';
    position: absolute;
    top: 0; left: 50%; width: 100vw;
    transform: translateX(-50%);
    height: 1px;
    background: rgba(255, 255, 255, 0.102);
  }
  .footer-grid__list--nav { margin-top: 18px; }
  .footer-bottom__credit-break { display: block; }
  /* .site-footer__frame porte une marge de 28px de chaque côté (même
     gabarit que .hero) qui laisse voir sa couleur de fond (#FFF4F5, le rose
     de la FAQ juste au-dessus) tout autour du bloc bleu — supprimée ici pour
     que le bleu touche les bords de l'écran. */
  /* Le fond rose reste nécessaire (contrairement à ce qu'on a fait plus tôt) :
     .site-footer se découpe maintenant aussi en haut-gauche (border-radius
     ci-dessous) et cette découpe doit révéler le rose du frame, pas du blanc. */
  .site-footer__frame { margin: 0; background: #FFF4F5; }
  /* Le badge est en absolute par rapport à .site-footer (left:-2px de base,
     pensé pour un site-footer qui démarrait à 28px, aligné sur la marge de
     .faq-section juste au-dessus). Le site-footer commençant maintenant à
     0 (marge retirée ci-dessus), on réintroduit ce même décalage (28-2=26px)
     pour rester calé sur le début visuel de la FAQ. */
  .site-footer__badge { left: 0; }
  /* Le bleu ne démarre pas en haut à gauche : grand rayon en haut-gauche
     pour que le bleu remonte en pente depuis le bas du badge (posé sur le
     rose de la FAQ) jusqu'au sommet de l'écran, plus à droite. */
  .site-footer { padding: 100px 0 0; }
  .footer-grid { width: 100%; }
}
