@charset "UTF-8";
/* ==========================================================================
   Spin’Info — feuille de style du site

   Écrite à la main. Les valeurs numériques ne sont pas approchées à l'œil :
   elles viennent du relevé de l'original (Divi 4.27.7 + thème enfant
   « spininfobyinova ») — spinwork/design/charte.md et charte.json pour les
   réglages du thème, spinwork/live/pages/*.json pour les styles calculés à
   1440 et 390 px. Aucun reliquat de classe et_pb_*.

   Référence de mesure : fenêtre de 1440 px de large.

   L'architecture (sommaire, jetons, base, grille, en-tête, pied, blocs,
   formulaire, utilitaires, mobile) est celle du site Raon Informatique, déjà
   livré : ce qui y est générique et éprouvé est repris — contours de focus
   doubles, [hidden] !important, color-scheme, lien d'évitement, boutons de
   révélation, pied de page en grille. Les COTES, elles, sont celles de Spin :
   celles de Raon ne valaient que pour Raon.

   ---------------------------------------------------------------------------
   FUSION DU 12 SEPTEMBRE 2026 — d'où vient ce fichier
   ---------------------------------------------------------------------------
   Pendant le chantier, dix feuilles de composants vivaient dans
   public/assets/css/parts/ et étaient chargées APRÈS celle-ci, pour que
   plusieurs agents puissent écrire chacun sa section sans se disputer un même
   fichier. Elles sont maintenant fusionnées ici, à leur place dans le
   sommaire, et le dossier parts/ a été supprimé avec le bloc de chargement
   temporaire de templates/layout.php : le site ne charge plus que fonts.css
   puis site.css.

   Les feuilles fusionnées : 10-partages, 20-formulaire, 30-entete, 31-mobile,
   32-pied, 40-accueil, 41-services, 42-annexes, 43-coordonnees, 44-legales.

   Une feuille chargée après une autre peut la contredire à spécificité égale.
   C'est de cela que les composants vivaient, et c'est ce qui devait être
   TRANCHÉ ici : chaque contradiction est résolue en faveur de la MESURE, et la
   raison est écrite à l'endroit de la règle. Les arbitrages qui changent la
   géométrie, et non seulement la forme du code :
     - § 2   cotes de LISTE de l'original : interligne de 26 px, aucune marge
             entre les éléments, retrait de 1 em (la base portait 0,25 em de
             marge et 1,4 em de retrait, qui ne venaient d'aucun relevé) ;
     - § 2   remise à zéro du remplissage par défaut des <button> ;
     - § 4   une seule construction de menu (la mesurée, en blocs sur un
             interligne de 30 px) là où la base en posait une en flex ;
     - § 5   pied de page REMPLACÉ par l'ancien 32-pied : mêmes noms de
             classes, autre construction — c'est le relevé qui l'a imposée ;
     - § 6   galerie en flottants et non en grille (gouttières en POURCENTAGE),
             plan du site sans la carte blanche de Raon, titres intérieurs des
             pages légales en NOIR, encadré de fin à 40 px à toutes les
             largeurs (mesuré sur l'original à 390 px) — le bandeau de la page
             Avis clients y déroge depuis, et lui seul : son remplissage
             redescend sur téléphone, par décision du client du 12 septembre
             2026, parce que son bouton ne tenait pas sur une ligne (§ 6.12) ;
     - § 9   règles mortes du tiroir mobile retirées, bascule unique à 981 px.
   Les hauteurs obtenues après fusion sont comparées au relevé, page par page
   et largeur par largeur, dans le rapport de l'agent de fusion.

   Sommaire
     1. Jetons
     2. Base
     3. Enveloppe et grille
     4. En-tête
     5. Pied de page
     6. Blocs de contenu, un sous-point par gabarit de templates/blocks/.
        Ces numéros sont l'ADRESSE que citent les commentaires du site depuis
        le 12 septembre 2026, où les renvois vers les anciennes feuilles de
        composants ont été remplacés : ils sont donc tenus à jour ici.
          6.1  Texte courant             6.7   « Nos services »
          6.2  Image et deux colonnes    6.8   Carte et photo
          6.3  Titre de page             6.9   Galerie et visionneuse
          6.4  Diaporama figé            6.10  Plan du site
          6.5  Trois blocs de services   6.11  Pages légales
          6.6  Section d'ouverture       6.12  Appel à l'action, bandeau d'avis
     7. Formulaire
     8. Utilitaires
     9. Mobile

   Où sont les points de rupture : chaque composant porte les SIENS, à côté des
   cotes dont ils sont la variante — l'en-tête au § 4, le pied au § 5, chaque
   bloc au § 6. Le § 9 tient ce qui n'existe QUE sur téléphone (barre, tiroir,
   bouton d'appel), la bascule entre les deux en-têtes, et le repli général de
   la page (sections, colonnes, formulaire).
   ========================================================================== */

/* ==========================================================================
   1. Jetons
   ========================================================================== */

:root {
    /* Ce site s'affiche sur fond clair, et il le DÉCLARE.
       Sans cette ligne, Chrome sur Android se donne le droit de recalculer les
       couleurs quand le visiteur a coché l'assombrissement automatique des
       pages — une case des réglages du navigateur, indépendante du thème du
       système. Mesuré sur le site Raon : 72,4 % des pixels du premier écran
       changeaient, le bleu nuit #283851 — l'identité du magasin — devenait un
       gris-lavande pâle sur les titres tandis que le pied gardait son bleu
       nuit : deux bleus différents sur la même page. Rien n'est illisible, et
       c'est le piège : le défaut est invisible depuis un ordinateur.
       `only light` demande au navigateur de ne pas y toucher. */
    color-scheme: only light;

    /* --- Couleurs relevées (charte.md § 1) ---------------------------------
       Le bleu nuit est l'accent Divi du site (opt:et_divi.accent_color), la
       même valeur que sur le site Raon. Le noir est la couleur de texte, de
       titre et de lien réglée dans le customizer — et non un gris, contrairement
       au défaut #666 de Divi qu'il écrase. */
    --navy: #283851;
    --ink: #000000;
    --white: #ffffff;
    --grey-bg: #f7f7f7;
    --mobile-bar: #111111;
    --mobile-link: #666666;

    /* Bleu de l'élément de menu « DPH Net (Espace Professionnel) », imposé par
       le thème enfant avec !important sur tous les menus. */
    --dph: #3e8cb6;
    /* Carré de l'icône Facebook du pied. */
    --facebook: #3b5998;

    /* Voile relevé sur les diapositives de l'accueil : .5 en mélange multiply.
       Celui de la galerie — bleu nuit à 60 % au survol — n'a PAS de jeton :
       il n'est pas peint par une couche mais obtenu en laissant paraître le
       fond de la tuile à travers l'image (§ 6, `.gallery__item:hover img`).
       Un jeton que personne n'emploie finit par mentir. */
    --veil-slide: rgba(40, 56, 81, 0.5);
    /* Voile posé sur la page quand le tiroir mobile est ouvert (défaut de
       l'extension WP Mobile Menu, jamais configurée). */
    --veil-menu: rgba(0, 0, 0, 0.83);

    /* Ombres Divi relevées : préréglage 1 pour les boîtes, et le préréglage de
       texte des titres sur photo. */
    --box-shadow: 0 2px 18px 0 rgba(0, 0, 0, 0.3);
    --text-shadow: 0 0 0.3em #000;

    /* Couleurs de service, absentes de l'original : il n'avait ni formulaire
       ni message d'erreur. Choisies pour tenir 4,5:1 sur blanc. */
    --error: #a32b22;
    --ok: #1f6349;
    /* Bordure de champ : noir 2 px, comme les champs du livre d'or de
       l'original (charte.md § 5) — le seul formulaire qu'il ait porté. */
    --field-border: #000000;

    /* --- Typographie -------------------------------------------------------
       Pile rendue sur l'original : Open Sans, puis Arial. Dosis ne sert qu'au
       menu mobile, en graisse 400, seule face que chargeait l'extension. */
    --sans: "Open Sans", Arial, Helvetica, sans-serif;
    --dosis: "Dosis", "Trebuchet MS", Arial, sans-serif;

    /* --- Gabarit -----------------------------------------------------------
       Défaut de Divi, que l'original ne redéfinit pas : chaque rangée prend
       80 % de la page, au plus 1080 px. Gouttière « 3 » (5,5 %) par défaut,
       gouttière « 2 » (3 %) sur les cartes de services et les colonnes du pied. */
    --row: 1080px;
    --gutter: 5.5%;
    --gutter-narrow: 3%;

    --transition: 0.3s ease;
    /* Transition des boutons Divi : all .2s. */
    --btn-transition: 0.2s;
}

/* ==========================================================================
   2. Base
   ========================================================================== */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    /* Défilement doux : activé sur l'original (divi_smooth_scroll = on). */
    scroll-behavior: smooth;
}

body {
    margin: 0;
    background: var(--white);
    color: var(--ink);
    font-family: var(--sans);
    /* Relevé : 14 px, interligne 1,7 em = 23,8 px. */
    font-size: 14px;
    line-height: 1.7em;
    /* ÉCART ASSUMÉ, et c'est une fidélité et non une trahison : Divi DÉCLARE
       une graisse 500 sur le corps, mais l'original ne chargeait aucune face
       500 — le navigateur affichait donc le texte en 400 (charte.md § 12.4,
       et les faces réellement rendues dans live/pages/index.json). Notre
       Open Sans est VARIABLE de 300 à 800 : écrire 500 ici donnerait une vraie
       graisse 500, plus grasse que l'original sur toutes les pages. On écrit
       donc la graisse RENDUE. Le site Raon écrit 500, et c'est correct pour
       lui : son original chargeait bien cette face. */
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* Relevé : titres en bleu nuit, interligne égal à la taille, 10 px de
   retombée (margin-bottom des titres Divi). Les graisses sont celles des
   titres RÉELLEMENT affichés (charte.md § 3) et non le 500 déclaré par
   défaut : 700 pour le titre de page, 600 pour les titres du texte. */
h1,
h2,
h3,
h4,
h5,
h6 {
    margin: 0;
    padding-bottom: 10px;
    color: var(--navy);
    font-family: var(--sans);
    font-weight: 600;
    line-height: 1em;
    text-wrap: pretty;
}

/* Relevé : le H1 de chaque page vient du module « titre » de Divi, réglé à
   32 px / 700 sur les onze pages (title_font_size=32px). */
h1 {
    font-size: 32px;
    line-height: 32px;
    font-weight: 700;
}

h2 {
    font-size: 26px;
    line-height: 26px;
}

h3 {
    font-size: 22px;
    line-height: 22px;
}

h4 {
    font-size: 18px;
    line-height: 1.4em;
}

h5 {
    font-size: 16px;
}

h6 {
    font-size: 14px;
}

/* Relevé : chaque paragraphe porte 1 em de retombée, sauf le dernier d'un
   module. */
p {
    margin: 0;
    padding-bottom: 1em;
}

p:last-child {
    padding-bottom: 0;
}

/* Relevé : liens en noir (customizer), jamais soulignés (Divi). */
a {
    color: var(--ink);
    text-decoration: none;
    transition: color var(--transition), opacity var(--transition);
}

a:hover {
    color: var(--navy);
}

img {
    max-width: 100%;
    height: auto;
    border: 0;
    vertical-align: middle;
}

picture {
    display: contents;
}

/* COTES DE LISTE DE L'ORIGINAL, et elles ne sont pas déduites : la feuille du
   thème de la sauvegarde WordPress (Divi/style-static.min.css) porte

       .et-l--body ul, .et-l--footer ul, .et-l--header ul
           { list-style-type: disc; padding: 0 0 23px 1em; line-height: 26px }

   soit un interligne de 26 px, un retrait de 1 em, et AUCUNE marge sur les
   <li> — le sélecteur couvre le corps de page, l'en-tête et le pied, donc
   toutes les listes du site, y compris celles des pages légales.

   Cette base portait auparavant `li { margin-bottom: .25em }` et
   `ul { padding-left: 1.4em }`, deux valeurs venues du site Raon. Trois
   vérifications l'avaient déjà prise en défaut, chacune sur une page
   différente, et chacune avait dû écrire la correction chez elle :
     - prestations de l'accueil : cinq lignes à 26 px plus 1 em de retombée
       font exactement les 144 px mesurés entre les deux paragraphes qui les
       encadrent ; avec 0,25 em de marge la liste en faisait 136,5 et la
       section était trop courte de 7,5 px ;
     - intervention technique de Maintenance : six éléments, six fois 3,5 px
       de trop, et la section dépassait sa cote relevée ;
     - plan du site : pas de 30,9 px au lieu des 26 px relevés.
   Le retrait, lui, a été LU sur la capture de l'accueil : la puce tombe sur le
   bord de la rangée, à x = 180, ce que donne 1 em (14 px) et non 1,4 em.

   La retombée est écrite `margin: 0 0 1em`, soit 14 px, et non les 23 px du
   thème : c'est la valeur MESURÉE sous la liste de l'accueil. Le plan du site,
   où les 23 px se mesurent bien, les redemande chez lui (§ 6). Divi écrit
   l'une en remplissage et l'autre par la marge de son module ; ici une seule
   propriété suffit, et c'est la mesure qui dit laquelle. */
ul,
ol {
    margin: 0 0 1em;
    padding-left: 1em;
    line-height: 26px;
}

strong,
b {
    font-weight: 700;
}

/* Le remplissage PAR DÉFAUT d'un <button> — 1px 6px dans les navigateurs — a
   coûté deux mesures avant d'être vu : la croix du tiroir mobile s'arrêtait
   6 px avant le bord du panneau et sa boîte de contenu tombait à 32 px, ce qui
   rétrécissait son icône de 36 px. Il ne se voyait pas ailleurs par chance (la
   barre mobile centre son icône, donc l'écart se compense de part et d'autre ;
   les boutons habillés réécrivent leur remplissage), et c'est exactement ce
   qui en fait un piège. Remis à zéro ici une fois pour toutes : tous les
   boutons du site qui ont un remplissage l'écrivent. */
button {
    font: inherit;
    color: inherit;
    padding: 0;
}

/* Indicateur de focus : un contour bleu nuit était invisible sur les
   nombreuses sections bleu nuit du site (en-tête, pied, panneau de contact).
   Un double contour — clair puis sombre — reste perceptible sur tous les
   fonds. Repris du site Raon, où le défaut avait été mesuré. */
:focus-visible {
    outline: 2px solid var(--white);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px var(--navy);
    border-radius: 1px;
}

/* Sur fond clair, on inverse les deux couleurs. */
.section :focus-visible,
.prose :focus-visible,
.masthead :focus-visible,
.sitemap :focus-visible,
.legal :focus-visible,
.contact-grid__form :focus-visible,
.gallery :focus-visible,
.mobile-panel :focus-visible {
    outline-color: var(--navy);
    box-shadow: 0 0 0 4px var(--white);
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 200;
    padding: 12px 20px;
    background: var(--white);
    color: var(--navy);
    font-weight: 700;
}

.skip-link:focus {
    left: 0;
}

/* L'attribut hidden doit gagner sur les display des composants : plusieurs
   éléments sont livrés masqués et révélés par le script (bouton du menu
   mobile, bouton d'appel, voile). Sans !important, le display d'un composant
   l'emporte et un élément « masqué » reste visible. */
[hidden] {
    display: none !important;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   3. Enveloppe et grille
   ========================================================================== */

/* Rythme vertical de Divi, relevé (charte.md § 6) : les sections portent 4 %
   de respiration haute et basse, les rangées 2 %, et le customizer fixe ces
   valeurs en pixels au-delà de 1350 px — 54 px et 27 px. Sous 981 px, Divi
   passe à 50 px pour les sections et 30 px pour les rangées (voir § 9). */
.section {
    position: relative;
    padding: 4% 0;
    background: var(--white);
}

.section > .row {
    padding: 2% 0;
}

@media (min-width: 1350px) {
    .section {
        padding: 54px 0;
    }

    .section > .row {
        padding: 27px 0;
    }
}

.row {
    width: 80%;
    max-width: var(--row);
    margin: 0 auto;
    position: relative;
}

/* Rangées « pleine largeur » de Divi : elles gardent les 80 % mais perdent le
   plafond de 1080 px — relevé à 1152 px dans une fenêtre de 1440. Ce sont
   celles de l'en-tête, de la section « Nos services » et du pied. */
.row--wide {
    width: 80%;
    max-width: none;
}

/* Colonnes : mêmes proportions et mêmes gouttières que l'original. Les
   largeurs sont celles de Divi et non un calc() : 47,25 % + 5,5 % + 47,25 %
   font exactement 100.

   Trois largeurs de colonne servent, et trois seulement : deux moitiés
   (card_split, deux colonnes de texte), trois tiers (les trois blocs de
   l'accueil) et cinq colonnes en gouttière 2 (les cartes de « Nos services »).
   Les quarts et la classe `.cols--narrow` de la base ont été RETIRÉS à la
   fusion : rien ne les émettait — le pied, seul endroit du site en quatre
   colonnes, est en grille et non en `.cols` (§ 5). */
.cols {
    display: flex;
    flex-wrap: wrap;
}

.cols > * {
    margin-right: var(--gutter);
}

.cols > *:last-child {
    margin-right: 0;
}

.cols--2 > * {
    width: 47.25%;
}

.cols--3 > * {
    width: 29.6667%;
}

/* Gouttière « 2 » (3 %) : les cinq cartes de « Nos services ».
   5 × 17,6 + 4 × 3 = 100. */
.cols--5 > * {
    width: 17.6%;
    margin-right: var(--gutter-narrow);
}

.cols--equal {
    align-items: stretch;
}

/* Photo posée en fond, en <img> et non en background CSS : la politique de
   sécurité du site interdit le style en ligne, et une balise se précharge et
   se décrit mieux. */
.bg-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
}

/* Voile des diapositives : relevé rgba(40,56,81,.5) en mélange multiply. */
.veil {
    position: absolute;
    inset: 0;
    z-index: 1;
    background: var(--veil-slide);
    mix-blend-mode: multiply;
    pointer-events: none;
}

/* --- Sous 981 px : le repli général de la page -------------------------
   Relevé : sections 50 px, rangées 30 px, et les colonnes s'empilent avec
   30 px de retombée.

   CES TROIS RÈGLES SONT ICI, à la fin du § 3, et non au § 9 avec la barre
   mobile. Elles portent sur les mêmes sélecteurs que la grille ci-dessus, à la
   même spécificité, et les blocs du § 6 doivent pouvoir les REPRENDRE : le
   titre de page ne garde que sa respiration haute, les sections card_split et
   la section d'ouverture passent à zéro, la rangée de l'encadré de fin aussi.
   Écrites plus bas dans le fichier, elles gagnaient sur les blocs par simple
   ordre d'écriture — mesuré au moment de la fusion, à 390 comme à 768 px :
   +80 px sur chaque bloc de titre (sa respiration basse revenait), +100 px sur
   chaque section card_split et sur la section d'ouverture, +60 px sur
   l'encadré de fin. Du temps où les composants vivaient dans dix feuilles
   séparées — la note de fusion en tête de ce fichier le raconte —, l'ordre de
   CHARGEMENT suffisait à les faire gagner ; dans un seul fichier, c'est la
   PLACE qui décide. */

@media (max-width: 980px) {
    .section {
        padding: 50px 0;
    }

    .section > .row {
        padding: 30px 0;
    }

    .cols > *,
    .cols--2 > *,
    .cols--3 > *,
    .cols--5 > * {
        width: 100%;
        margin-right: 0;
        margin-bottom: 30px;
    }

    .cols > *:last-child {
        margin-bottom: 0;
    }
}

/* ==========================================================================
   4. En-tête
   ========================================================================== */
/* PROPOSITION A — « barre de contact et en-tête épuré ».

   DÉCISION DU CLIENT, 17-18 septembre 2026 (racontée en tête de
   templates/partials/masthead.php et topbar.php) : « rends cet espace plus
   jolie et pro », a demandé le client, qui accepte que l'en-tête s'écarte de
   l'original et a choisi cette proposition parmi trois. Au-dessus de 981 px,
   l'en-tête n'est donc plus la reproduction mesurée de la mise en page Divi
   2736 (175,4 px, trois colonnes 1/4 – 1/2 – 1/4, logos en rectangles noirs,
   horaires en 12 px) : c'est la structure des sites de commerce, en 128 px.
   Sous 981 px, RIEN ne change — la barre noire du menu mobile (§ 9) et la
   rangée bleue de contact gardent leurs cotes relevées, et leurs règles
   ci-dessous sont celles d'avant la proposition, à la ligne près (vérifié à
   l'intégration : les trente captures pleine page à 900, 768 et 390 px sont
   identiques au pixel à celles d'avant).

   CE QUI SE VOIT AU-DESSUS DE 981 px
     .masthead__top    barre fine de 40 px, bleu nuit profond : la boutique
                       d'Épinal sur une ligne, et le bouton « Aussi à
                       Raon-l’Étape » qui ouvre la carte de la boutique sœur ;
     .masthead__main   barre principale de 88 px, bleu nuit : logo, menu,
                       DPH Net en contour, bouton d'appel ;
                       = 128 px, premier contenu à 128 px à toutes les
                       largeurs d'ordinateur (175,4 px auparavant) ;
     .sticky-header    après 250 px de défilement : la barre principale
                       seule, en 64 px.

   COULEURS — toutes DÉRIVÉES du bleu nuit #283851 et du bleu de DPH Net
   #3e8cb6, contrastes CALCULÉS selon la formule WCAG 2 (luminance relative) :
     texte clair du menu    #dfe5ee sur #283851   9,34:1
     texte de la barre haute #c7d0dc sur #1d2939  9,44:1
     blanc                  sur #283851 11,83:1 ; sur #1d2939 14,70:1
     bleu nuit du bouton    #283851 sur blanc 11,83:1 ; sur #e6edf5 10,03:1
     contour de DPH Net     #3e8cb6, la couleur DÉCIDÉE par le client, sur
                            #283851 : 3,17:1 — il tient le seuil de 3:1 d'un
                            contour d'élément d'interface, il est gardé tel
                            quel ;
     texte de DPH Net       #3e8cb6 n'y tient PAS 4,5:1 (3,17:1). Le texte
                            prend #a8d1e8, 7,30:1 : le bleu pâle de la
                            proposition A TELLE QUE LE CLIENT L'A CHOISIE sur
                            capture le 18 septembre 2026. ABANDONNÉ le même
                            jour : #5aa8d4, posé à l'intégration comme la
                            nuance la plus proche de #3e8cb6 tenant 4,5:1 — il
                            n'en tenait que 4,50016:1, au seuil exact, et
                            s'écartait de ce que le client avait vu et validé.
                            Le bleu décidé du client reste présent : c'est le
                            contour, ci-dessus. Au survol, le texte passe en
                            blanc (9,13:1 sur le mélange #2d4a67).
     trait de page courante #6fb3dc sur #283851 5,16:1 (seuil 3:1)
     contour des boutons    #8795ab sur #1d2939 4,84:1 ; sur #283851 3,90:1
     icônes                 #8fbbd9 sur #1d2939 7,19:1 ; sur #283851 5,79:1
     survols                bouton de la barre, blanc sur #2f3a49 11,52:1 ;
                            bouton de la carte, blanc sur #39485f 9,27:1 ;
                            trait blanc à 45 % (#89929f) sur #283851 3,76:1
     focus                  contour blanc : 11,83:1 sur le bleu nuit, 14,70:1
                            sur le bleu profond ; son anneau #1d2939 sépare le
                            contour du bouton d'appel blanc (14,70:1)

   LES LOGOS SUR FOND NOIR — relevé au pixel des deux JPEG : le « noir » est
   #242422, et le bruit de compression ne dépasse jamais 38 sur un canal. Le
   bleu nuit (40, 56, 81) est plus clair que ce fond sur les TROIS canaux.
   `mix-blend-mode: lighten` garde, canal par canal, la valeur la plus claire :
   le fond du logo rend exactement le bleu nuit de la barre, le texte blanc
   reste blanc, et le fichier n'est ni filtré ni recadré. `screen`, l'autre
   piste, ÉCLAIRCIT le bleu là où le fond n'est pas d'un noir pur : il aurait
   laissé un rectangle (70, 84, 104) sur (40, 56, 81). Condition de tenue : la
   barre ne doit jamais descendre sous (38, 38, 38) sur un canal, et aucun
   ancêtre du logo ne doit créer de groupe isolé transparent (opacité < 1,
   transform, filter) — il n'y aurait plus de bleu à mélanger.              */

/* --- Rangée bleue de contact (#secondary_line), SOUS 981 px -------------
   Relevé : fond bleu nuit, coordonnées à gauche en blanc 14 px, 8 px de
   respiration haute et 4 px de basse avec 50 px sur les côtés.

   Cette rangée n'existe que DANS l'en-tête collant (templates/partials/
   topbar.php la rend, et rien d'autre), et elle ne s'affiche plus que sous
   981 px : au-dessus, la barre du haut du grand en-tête la remplace (plus bas,
   « Au-dessus de 981 px »). Ses règles sont celles d'avant la proposition.
   Seules ont disparu celles du menu secondaire (.topbar__menu, .topbar__nav) :
   masqué sous 981 px dans l'original, et retiré au-dessus avec la rangée, il
   ne s'affichait plus à aucune largeur — Galerie et Avis clients sont passés
   dans le menu principal.                                                   */

.topbar {
    background: var(--navy);
    color: var(--white);
}

/* La rangée prend toute la largeur de la page avec 50 px de côtés
   (width="100%" max_width="100%"), et non les 80 % d'une rangée ordinaire.
   Les 42 px sont une hauteur MINIMALE et non une hauteur fixe : sous 981 px le
   texte se replie et la rangée grandit, comme dans l'original. */
.topbar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 8px 50px 4px;
    min-height: 42px;
}

.topbar__info {
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* Aucun écart VERTICAL : le #et-info de l'original est un paragraphe de
       contenu en ligne, où les deux lignes du repli se suivent sans espace. La
       base en posait 6 px, qui grandissaient la rangée mobile d'autant. Seul
       l'écart horizontal de 26 px est conservé — les six espaces insécables
       qui séparaient l'e-mail de l'icône. */
    gap: 0 26px;
    color: var(--white);
    line-height: 1.7em;
}

.topbar a,
.topbar .reveal {
    color: var(--white);
}

.topbar a:hover,
.topbar .reveal:hover {
    color: rgba(255, 255, 255, 0.7);
}

.topbar__social {
    display: inline-flex;
    align-items: center;
}

/* Relevé : l'icône Facebook de l'en-tête fait 1,5 em, soit 21 px. */
.topbar__social svg {
    width: 21px;
    height: 21px;
    fill: currentColor;
}

/* --- Sous 981 px : la rangée bleue seule -------------------------------- */

@media (max-width: 980px) {
    /* LA RANGÉE BLEUE MOBILE SE DÉMONTE AUSSI. Relevée 90,6 px à 390 px —
       bloc `et-l--header` à top 50, hauteur 90,6, sur les DIX pages de
       live/pages/*_390.json — et 67 px à 768 px (charte.md § 13).

         8 px      respiration haute de la rangée (custom_padding=
                   "8px|50px|4px|50px" : aucun réglage de téléphone, donc les
                   50 px de côtés valent aussi à 390 px — 290 px de contenu,
                   ce que la mesure confirme)
       + 23,8 px   ligne 1 : le téléphone et l'e-mail (14 px / 1,7 em)
       + 24,8 px   ligne 2 : l'icône Facebook, seule
       + 30 px     marge basse de la COLONNE EMPILÉE (voir ci-dessous)
       +  4 px     respiration basse
       = 90,6 px
       À 768 px les deux lignes n'en font qu'une (668 px de contenu pour
       248,8 px de coordonnées et 21 px d'icône) : 8 + 24,8 + 30 + 4 = 66,8 px,
       les 67 px relevés à l'unité près.

       LES 30 px NE SONT PAS UN CHOIX DE MISE EN PAGE ni du vide inventé :
       c'est une règle de Divi, la même qui se retrouve à la mesure sous les
       cartes de card_split (§ 6). Sous 981 px Divi empile les colonnes et leur
       donne 30 px de marge basse, SAUF à la dernière. Or la seconde colonne de
       cette rangée, celle du menu secondaire, est `disabled_on="on|on|off"` :
       elle ne s'affiche ni sur téléphone ni sur tablette mais reste la
       dernière du document, si bien que c'est ELLE qui reçoit l'exemption —
       sans prendre de place — et que la colonne des coordonnées garde ses
       30 px. */
    .topbar__info {
        margin-bottom: 30px;
    }

    /* La ligne de l'icône doit faire 24,8 px ; notre construction en donnait
       27,8. Le SVG est une boîte EN LIGNE dont la ligne de base est le bas :
       elle emporte donc sous elle les 6,8 px de retombée de l'interligne de
       23,8 px (21 + 6,8 = 27,8). `display: block` retire cette ligne de base —
       la boîte ne fait plus que ses 21 px — et les 3,8 px qui restent à
       retrouver sont écrits : 21 + 3,8 = 24,8 px.
       C'est la seule cote de cette rangée qui vienne du RENDU de l'original et
       non d'un de ses réglages : le glyphe d'ETmodules qu'il employait n'existe
       pas ici (icônes en SVG, décisions du 11 septembre 2026), et c'est sa
       ligne de 24,8 px qu'il faut retrouver, pas son fichier de police. */
    .topbar__social svg {
        display: block;
    }

    .topbar__social {
        margin-bottom: 3.8px;
    }
}

/* --- Jetons de l'en-tête ----------------------------------------------
   Posés sur les deux en-têtes et non dans :root (§ 1) : ils ne servent qu'ici,
   et la carte de Raon — un popover, rendu dans la couche supérieure du
   navigateur mais toujours DANS .masthead au sens du DOM — en hérite comme le
   reste. Contrastes calculés : voir l'en-tête de ce paragraphe.             */

.masthead,
.sticky-header {
    /* Bleu nuit profond de la barre du haut : le bleu nuit #283851 assombri
       d'un quart, même teinte. Il sépare les deux barres sans filet. */
    --head-deep: #1d2939;
    --head-text: #dfe5ee;
    --head-muted: #c7d0dc;
    --head-icon: #8fbbd9;
    --head-accent: #6fb3dc;
    /* Texte de DPH Net : le bleu pâle de la capture choisie par le client,
       7,30:1 sur le bleu nuit (calcul en tête de ce paragraphe). */
    --head-pro-text: #a8d1e8;
    --head-line: #8795ab;
    --head-cta-hover: #e6edf5;
    /* Largeur utile : 1 680 px au plus, marges de 40 px. Les rangées du corps
       de page (80 %, 1 080 px) seraient trop étroites pour un menu de huit
       entrées sur une ligne dès 1 280 px ; l'en-tête prend donc la largeur des
       barres de navigation, pas celle du texte. */
    --head-max: 1680px;
    --head-pad: 40px;
}

.masthead {
    position: relative;
    z-index: 50;
    background: var(--navy);
}

.masthead__wrap {
    width: 100%;
    max-width: var(--head-max);
    margin: 0 auto;
    padding: 0 var(--head-pad);
}

/* --- Barre du haut (.masthead__top) -----------------------------------
   40 px, texte de 13 px sur un interligne de 20 px — et non les 12 px sur
   15 px des anciens horaires, que le client trouvait « minuscules et
   tassés ». Une seule ligne à toutes les largeurs d'ordinateur : les éléments
   ne passent jamais à la ligne (white-space: nowrap), ce sont les réglages
   sous 1 280 et 1 100 px, plus bas, qui les font tenir.                      */

.masthead__top {
    background: var(--head-deep);
    color: var(--head-muted);
    font-size: 13px;
    line-height: 20px;
}

.masthead__top-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    height: 40px;
}

/* La liste des coordonnées d'Épinal. Les marges, le retrait et l'interligne
   de 26 px des listes du site (§ 2) n'ont rien à faire dans une barre. */
.masthead__address {
    display: flex;
    align-items: center;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    line-height: 20px;
    white-space: nowrap;
}

.masthead__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 7px;
}

/* Séparateur : un filet de 16 px centré entre deux éléments, dessiné en
   position absolue pour ne pas compter dans l'écart de 7 px entre l'icône et
   son texte. 37 px entre deux éléments, le filet au milieu. */
.masthead__item + .masthead__item {
    margin-left: 37px;
}

.masthead__item + .masthead__item::before {
    content: "";
    position: absolute;
    left: -19px;
    top: 50%;
    width: 1px;
    height: 16px;
    margin-top: -8px;
    background: rgba(255, 255, 255, 0.18);
}

.masthead__icon {
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    fill: var(--head-icon);
}

/* « sur rendez-vous » : un lien, et il se voit comme tel — souligné. Bloc en
   ligne de 24 px (20 px d'interligne et 2 px de part et d'autre) : la cible
   atteint le minimum de 24 × 24 px sans changer la ligne. */
.masthead__link {
    display: inline-block;
    padding: 2px 0;
    color: var(--white);
    text-decoration: underline;
    text-decoration-color: rgba(255, 255, 255, 0.55);
    text-underline-offset: 3px;
}

.masthead__link:hover {
    color: var(--white);
    text-decoration-color: currentColor;
}

/* --- Boutons de révélation de l'en-tête ---------------------------------
   Le défaut relevé par le client : « Voir le numéro » et « Voir l'adresse
   e-mail » se lisaient comme du texte perdu. Ils deviennent de petits
   boutons à contour (26 px de haut, cible au-dessus des 24 × 24 px requis),
   blancs sur le bleu profond.

   LES DEUX ÉTATS ONT LA MÊME BOÎTE. Le script remplace le <button> par un
   <a class="reveal" data-state="done"> (assets/js/site.js, applyReveal) : les
   règles visent `.reveal` dans sa case, donc s'appliquent aux deux. La largeur
   minimale de chaque case est celle du PLUS LONG de ses deux textes, mesuré en
   Open Sans 13 px dans Chrome, plus 22 px de remplissage et de contour :
     tel         « Voir le numéro » 89,9 px / « 03 29 32 73 51 » 87,8 px → 114
     email       « Voir l’adresse e-mail » 121,2 / « contact@spin-info.fr »
                 122,5 px → 146
     email_raon  121,2 / « contact@raon-informatique.fr » 181,2 px → 206
   Le texte est centré : le libellé et la valeur occupent la même case, rien
   ne bouge autour au clic. Mesuré au rapport, avant et après le clic.       */

.masthead__slot .reveal {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 26px;
    padding: 0 10px;
    border: 1px solid var(--head-line);
    border-radius: 13px;
    background: transparent;
    color: var(--white);
    font-size: 13px;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.masthead__slot .reveal:hover {
    color: var(--white);
    opacity: 1;
    text-decoration: none;
    border-color: var(--white);
    background: rgba(255, 255, 255, 0.08);
}

/* Une fois révélé, c'est un lien tel: ou mailto: : il reste une action. */
.masthead__slot .reveal[data-state="done"] {
    cursor: pointer;
}

.masthead__slot--tel .reveal {
    min-width: 114px;
}

.masthead__slot--email .reveal {
    min-width: 146px;
}

/* Dans la carte, les deux boutons de Raon prennent la même largeur, celle de
   la plus longue valeur : une colonne nette plutôt que deux boutons
   dépareillés. */
.masthead__slot--email-raon .reveal,
.masthead__card .masthead__slot--tel .reveal {
    min-width: 206px;
}

/* --- Bouton « Aussi à Raon-l’Étape » et sa carte -----------------------
   Même dessin que les boutons de révélation, en graisse 600 : c'est une
   commande, pas une coordonnée. Le chevron se retourne quand la carte est
   ouverte (:has et :popover-open), sans animation.

   PAR DÉFAUT, LE REPLI ; LA CARTE SEULEMENT SI LE NAVIGATEUR LA CONNAÎT.
   Un navigateur sans l'API popover (Chrome < 114, Firefox < 125, Safari < 17)
   ignore l'attribut `popover` : avec les seules règles de la proposition, la
   carte s'y affichait en permanence — `position: absolute` sous la barre du
   haut, 384 × 309 px par-dessus DPH Net et le bouton d'appel, mesuré en
   simulation — et la pastille était un bouton sans effet. Désormais :
     - hors de tout @supports, donc partout, le LIEN de repli
       (.masthead__sister-link, vers le site de Raon Informatique) est
       affiché, le bouton et la carte ne le sont pas ;
     - sous @supports selector(:popover-open), c'est l'inverse, et la carte
       ouverte reçoit son display.
   Le repli est écrit par défaut, et non sous « @supports not », parce qu'un
   navigateur trop ancien pour connaître selector() dans @supports ignorerait
   le bloc entier : le repli ne s'y appliquerait pas. Écrit ainsi, il tient
   même là. Toutes les règles qui nomment :popover-open sont dans ce bloc,
   séparées de toute autre : un navigateur qui ne connaît pas ce sélecteur
   jette la règle ENTIÈRE, et la proposition le groupait avec
   `.masthead__sister-toggle:hover`, dont le survol aurait disparu avec lui. */

.masthead__sister {
    flex: 0 0 auto;
}

.masthead__sister-toggle {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 26px;
    padding: 0 11px 0 10px;
    border: 1px solid var(--head-line);
    border-radius: 13px;
    background: transparent;
    color: var(--white);
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

/* `color` écrit ici pour le lien de repli : sans lui, le `a:hover` du § 2 le
   passait en bleu nuit, sur le bleu profond. */
.masthead__sister-toggle:hover {
    color: var(--white);
    border-color: var(--white);
    background: rgba(255, 255, 255, 0.08);
}

.masthead__caret {
    width: 9px;
    height: 9px;
    flex: 0 0 9px;
    fill: currentColor;
}

/* Le repli, par défaut (voir plus haut) : le bouton et la carte sortent de
   la page, le lien reste. */
.masthead__sister-toggle[popovertarget],
.masthead__card {
    display: none;
}

@supports selector(:popover-open) {
    .masthead__sister-link {
        display: none;
    }

    .masthead__sister-toggle[popovertarget] {
        display: inline-flex;
    }

    .masthead__card:popover-open {
        display: block;
    }

    .masthead__sister:has(.masthead__card:popover-open) .masthead__sister-toggle {
        border-color: var(--white);
        background: rgba(255, 255, 255, 0.08);
    }

    .masthead__sister:has(.masthead__card:popover-open) .masthead__caret {
        transform: rotate(180deg);
    }
}

/* La carte. Un popover est rendu dans la couche supérieure : il passe devant
   tout sans z-index. `position: absolute` l'y place par rapport au HAUT DU
   DOCUMENT (le bloc conteneur initial), donc sous la barre du haut, et il
   défile avec elle. Son bord droit s'aligne sur celui de la barre : la même
   largeur utile et la même marge que .masthead__wrap.

   Son `display` n'est écrit que deux fois, juste au-dessus : `none` par
   défaut, `block` une fois ouverte. Aucune autre règle ne doit en poser : un
   `display: flex` écrit ici l'afficherait en permanence.                    */

.masthead__card {
    position: absolute;
    inset: auto;
    top: 46px;
    right: calc(max(0px, (100% - var(--head-max)) / 2) + var(--head-pad));
    /* 384 px : « Boutique : Mercredi et vendredi de 14 h à 18 h » tient sur
       une ligne à côté de sa colonne d'icônes ; le régime « À distance » en
       prend deux. */
    width: 384px;
    margin: 0;
    padding: 18px 20px 16px;
    overflow: visible;
    border: 0;
    border-top: 3px solid var(--dph);
    border-radius: 0 0 4px 4px;
    background: var(--navy);
    color: var(--head-text);
    font-size: 13px;
    line-height: 20px;
    /* Une ombre courte, pour détacher la carte de la photo qu'elle recouvre. */
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.22);
}

/* Logo de Raon : 240 × 75 rendu à 56 px de haut (179 px de large). Son encre,
   relevée au pixel, commence à la colonne 15 et à la ligne 25 du fichier —
   11,2 et 18,7 px à cette taille : les marges négatives alignent le texte du
   logo sur la colonne des icônes et le remontent en haut de la carte. Même
   mélange `lighten` que le logo Spin’Info : la carte est du même bleu nuit. */
.masthead__card-logo {
    display: inline-block;
    margin: -17px 0 2px -11px;
    line-height: 0;
}

.masthead__card-logo img {
    display: block;
    width: auto;
    height: 56px;
    mix-blend-mode: lighten;
}

.masthead__card-list {
    margin: 0 0 10px;
    padding: 0;
    list-style: none;
    line-height: 20px;
}

.masthead__card-list li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 5px 0;
}

.masthead__card-list .masthead__icon {
    margin-top: 3px;
}

.masthead__card-list .masthead__slot {
    align-items: center;
}

.masthead__card-list .masthead__slot .masthead__icon {
    margin-top: 0;
}

.masthead__card strong {
    color: var(--white);
    font-weight: 600;
}

.masthead__card-site {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 24px;
    color: var(--white);
    font-weight: 600;
    text-decoration: underline;
    text-decoration-color: rgba(255, 255, 255, 0.55);
    text-underline-offset: 3px;
}

.masthead__card-site:hover {
    color: var(--white);
    text-decoration-color: currentColor;
}

.masthead__card-site .masthead__icon {
    width: 12px;
    height: 12px;
    flex-basis: 12px;
    fill: currentColor;
}

.masthead__card-close {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 3px;
    background: none;
    color: var(--head-text);
    cursor: pointer;
}

.masthead__card-close svg {
    width: 20px;
    height: 20px;
    fill: currentColor;
}

.masthead__card-close:hover {
    color: var(--white);
    background: rgba(255, 255, 255, 0.08);
}

/* --- Barre principale (.masthead__main) -------------------------------
   88 px. Le logo à gauche, la navigation poussée à droite.                  */

.masthead__main {
    background: var(--navy);
}

.masthead__main-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
    height: 88px;
}

/* --logo-h : la hauteur du logo, seule cote que changent l'en-tête collant et
   les largeurs étroites ; les deux décalages ci-dessous en sont des
   proportions. */
.masthead__logo {
    --logo-h: 72px;
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    line-height: 0;
}

/* Le logo Spin’Info, 72 px de haut (185,8 px de large) : le fichier fait
   93 px, il est donc réduit et non agrandi. Son rectangle ne se voit plus
   (mélange `lighten`, en-tête de ce paragraphe) : ce qui compte est son
   ENCRE, le texte et le filet, relevée au pixel sur les colonnes 20 à 221 et
   les lignes 32 à 80 du fichier. D'où deux décalages, proportionnels à la
   hauteur affichée :
     - vers le haut, 9,5 / 93 = 0,102 × hauteur (7,4 px à 72 px) : le centre
       de l'encre (ligne 56) est sous le centre du fichier (46,5) ; on centre
       l'encre, et non le rectangle invisible, dans la barre ;
     - vers la gauche, 20 / 240 × 186 / 72 = 0,215 × hauteur (15,5 px) :
       l'encre commence alors au bord de la largeur utile, à l'aplomb de
       l'icône d'adresse de la barre du haut.
   `position: relative` ne crée pas de contexte d'empilement : le mélange voit
   toujours le bleu de la barre.

   `max-width: none`, AJOUTÉ à l'intégration : le `max-width: 100%` de toutes
   les images (§ 2) se calculait sur la largeur du lien, qui est celle de
   l'image MOINS son décalage de 15,5 px — le logo était donc comprimé en
   largeur. Mesuré : 170,3 × 72 px au lieu de 185,8 × 72 (rapport 2,37 au
   lieu des 2,58 du fichier, 8,3 % d'écrasement), et 127,7 × 54 au lieu de
   139,4 × 54 dans l'en-tête collant. */
.masthead__logo img {
    position: relative;
    top: calc(var(--logo-h) * -0.102);
    display: block;
    width: auto;
    max-width: none;
    height: var(--logo-h);
    margin-left: calc(var(--logo-h) * -0.215);
    mix-blend-mode: lighten;
}

/* COULEURS FORCÉES (thèmes de contraste de Windows) : le navigateur remplace
   le fond des barres et de la carte par la couleur système du fond, et le
   mélange `lighten` n'a plus de bleu à garder. Sur un thème CLAIR, il gardait
   le blanc partout : les trois logos — grand en-tête, collant, carte de Raon —
   disparaissaient en entier, relevé le 18 septembre 2026 à la vérification
   (émulation `forced-colors: active` de Chrome, schéma clair). Le mélange est
   donc retiré dans ce mode : le JPEG s'affiche tel quel, rectangle noir
   compris, comme dans l'en-tête d'avant la proposition. Hors de ce mode, rien
   ne change. */
@media (forced-colors: active) {
    .masthead__logo img,
    .masthead__card-logo img {
        mix-blend-mode: normal;
    }
}

/* --- Navigation --------------------------------------------------------
   Une seule ligne, poussée à droite : six entrées en capitales espacées
   (Open Sans 13 px, graisse 600, interlettrage 0,06 em), puis DPH Net et le
   bouton d'appel. Page courante : texte blanc et trait de 2 px #6fb3dc sous
   le mot. Survol : texte blanc et trait blanc à 45 %. Aucun mouvement.

   Chaque lien fait 40 px de haut (12 + 16 + 12) : cible largement au-dessus
   de 24 px, sans agrandir la barre.                                         */

.nav {
    flex: 1 1 auto;
    min-width: 0;
}

.nav__list {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin: 0;
    padding: 0;
    list-style: none;
    line-height: normal;
}

.nav__item {
    position: relative;
    margin: 0;
}

.nav__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 12px 13px;
    color: var(--head-text);
    font-size: 13px;
    font-weight: 600;
    line-height: 16px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    transition: color 0.2s ease;
}

.nav__link::after {
    content: "";
    position: absolute;
    left: 13px;
    right: 13px;
    bottom: 5px;
    height: 2px;
    background: transparent;
    transition: background-color 0.2s ease;
}

.nav__link:hover {
    color: var(--white);
}

.nav__link:hover::after {
    background: rgba(255, 255, 255, 0.45);
}

.nav__link[aria-current="page"] {
    color: var(--white);
}

.nav__link[aria-current="page"]::after {
    background: var(--head-accent);
}

button.nav__link {
    background: none;
    border: 0;
    cursor: pointer;
    font-family: var(--sans);
}

/* DPH Net (Espace Professionnel) — un lien vers un AUTRE site, pour les
   professionnels : il se distingue des pages du site par un contour de sa
   couleur, #3e8cb6, décidée par le client, et se lit sur deux lignes. */
.nav__item--pro {
    margin-left: 14px;
}

.nav__link--pro {
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: 5px 12px 6px;
    border: 1px solid var(--dph);
    border-radius: 3px;
    color: var(--head-pro-text);
    letter-spacing: 0.05em;
    transition: color 0.2s ease, background-color 0.2s ease;
}

.nav__link--pro::after {
    content: none;
}

.nav__link--pro:hover {
    /* Blanc, 9,13:1 sur ce fond de survol : le changement de couleur dit le
       survol sans dépendre du seul fond. */
    color: var(--white);
    background: rgba(62, 140, 182, 0.22);
}

.nav__pro-name {
    font-size: 12.5px;
    font-weight: 700;
    line-height: 15px;
}

.nav__pro-detail {
    font-size: 10px;
    font-weight: 600;
    line-height: 13px;
    letter-spacing: 0.06em;
}

/* Le tiroir mobile garde le lien DPH Net d'avant la proposition : le bleu du
   client sur son fond gris clair, SANS cadre. La règle `.nav__link--pro`
   ci-dessus n'est pas limitée aux deux en-têtes d'ordinateur : le lien du
   tiroir porte la même classe (partials/mobile_bar.php), et elle l'atteignait
   SOUS 981 px — relevé le 18 septembre 2026 à la vérification, tiroir ouvert à
   390, 768 et 900 px : contour de 1 px #3e8cb6 à coins de 3 px, interlettrage
   de 0,7 px, lien de 43 px au lieu de 41 (Galerie, Avis clients et
   Coordonnées descendus de 2 px), transition de 0,2 s au lieu de 0,3 s. Les
   captures pleine page de l'intégration ne pouvaient pas le voir : le tiroir y
   est fermé. Ces quatre propriétés reprennent donc ici leur valeur d'avant (la
   transition est celle de tous les liens, § 2) ; le remplissage restait déjà
   celui de `.mobile-panel a`, plus spécifique. Ce sélecteur (0,2,1) l'emporte
   sur `.nav__link--pro` (0,1,0).
   ABANDONNÉ : « règle d'avant la proposition, que rien ici ne touche » — la
   règle ci-dessus la touchait. */
.mobile-panel a.nav__link--pro {
    color: var(--dph);
    border: 0;
    border-radius: 0;
    letter-spacing: normal;
    transition: color var(--transition), opacity var(--transition);
}

/* Bouton d'appel : l'entrée Coordonnées, en blanc plein — le seul aplat clair
   de l'en-tête, donc le premier repère de l'œil. Deux lignes : l'action, puis
   l'argument « Devis et diagnostic gratuits ». Sur la page Coordonnées, il
   porte aria-current et passe en contour blanc : la page courante reste
   marquée, et le bouton ne propose pas d'aller où l'on est déjà. */
.nav__item--cta {
    margin-left: 12px;
}

.nav__cta {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 46px;
    padding: 5px 18px;
    border-radius: 3px;
    background: var(--white);
    color: var(--navy);
    text-align: center;
    white-space: nowrap;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.nav__cta:hover {
    color: var(--navy);
    background: var(--head-cta-hover);
}

.nav__cta-main {
    font-size: 13px;
    font-weight: 700;
    line-height: 17px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.nav__cta-detail {
    font-size: 11.5px;
    font-weight: 400;
    line-height: 16px;
}

.nav__cta[aria-current="page"],
.nav__cta[aria-current="page"]:hover {
    color: var(--white);
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--white);
}

.nav__caret {
    width: 8px;
    height: 8px;
    flex: 0 0 8px;
    fill: currentColor;
    transition: transform var(--transition);
}

/* Aucun menu de l'original n'a de sous-menu : ces règles servent au cas où
   un niveau serait ajouté, et au clavier que pilote assets/js/site.js. */
.nav__sub {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 60;
    min-width: 240px;
    margin: 0;
    padding: 14px 0;
    list-style: none;
    background: var(--white);
    border-top: 3px solid var(--navy);
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
    transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}

.nav__item--has-sub:hover > .nav__sub,
.nav__item--has-sub:focus-within > .nav__sub,
.nav__item--open > .nav__sub {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.nav__item--has-sub:hover > .nav__link .nav__caret,
.nav__item--has-sub:focus-within > .nav__link .nav__caret,
.nav__item--open > .nav__link .nav__caret {
    transform: rotate(180deg);
}

/* Échap referme le sous-menu mais rend le focus à son bouton — donc
   :focus-within continuait de le tenir ouvert alors qu'aria-expanded annonçait
   « replié ». Cette classe, de même spécificité et posée plus bas, tranche.
   (Piège relevé sur le site Raon.) */
.nav__item--has-sub.nav__item--escaped > .nav__sub {
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
}

.nav__item--has-sub.nav__item--escaped > .nav__link .nav__caret {
    transform: none;
}

.nav__sub a {
    display: block;
    padding: 6px 20px;
    font-size: 14px;
    line-height: 24px;
    font-weight: 600;
    color: var(--navy);
}

.nav__sub a:hover {
    background: rgba(40, 56, 81, 0.06);
}

/* --- En-tête collant (.sticky-header) -----------------------------------
   Régime de base = celui de l'original sous 981 px : la section reste dans le
   flux, visible, réduite à sa rangée bleue. Au-dessus de 981 px elle quitte le
   flux, se fixe en haut et attend le défilement (plus bas).                 */

.sticky-header {
    background: var(--white);
}

/* Barre principale compacte : n'existe qu'au-dessus de 981 px. */
.sticky-header__main {
    display: none;
}

/* --- Au-dessus de 981 px : l'en-tête d'ordinateur et son collant --------
   La bascule elle-même — quel en-tête s'affiche — est au § 9, avec la barre
   mobile qui en est l'autre moitié. Ici, ce que l'en-tête collant fait quand
   il est en régime d'ordinateur.                                           */

@media (min-width: 981px) {
    /* Il quitte le flux, se fixe en haut et attend. z-index 99999, celui que
       le thème enfant lui donnait : il doit passer devant tout, y compris le
       bouton « retour en haut » de Divi. */
    .sticky-header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 99999;
        background: var(--navy);
        /* Ombre courte et légère : la barre flotte au-dessus du contenu qui
           défile dessous, elle doit s'en détacher sans peser. */
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
        /* Masqué en haut de page, comme la classe hidden_lg de l'original.
           visibility et non display : une transition est alors possible, et
           un élément en visibility:hidden sort aussi de l'ordre de
           tabulation et de l'arbre d'accessibilité — un lien invisible mais
           atteignable au clavier serait un piège.
           0,4 s : la durée par défaut du fadeIn de jQuery, qu'employait le
           script du thème enfant (charte.md § 7). La règle
           prefers-reduced-motion du § 9 ramène déjà toute transition à
           0,01 ms : rien à ajouter ici pour la respecter. */
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.4s ease, visibility 0.4s ease;
        /* Pendant les 0,4 s du fondu de SORTIE, visibility ne bascule qu'à la
           fin : le collant, déjà presque transparent, recevait encore les
           clics. Mesuré le 18 septembre 2026 au retour en haut de page : à
           50, 150 et 300 ms, un clic au centre de « Voir le numéro » tombait
           sur le lien « Accueil » du collant. pointer-events bascule, lui,
           tout de suite. */
        pointer-events: none;
    }

    /* assets/js/site.js pose cet attribut après 250 px de défilement. */
    .sticky-header[data-shown="true"] {
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
    }

    /* La rangée bleue de contact n'a plus cours ici : la barre du haut du
       grand en-tête porte les coordonnées, et le collant ne reprend que la
       barre principale. */
    .sticky-header .topbar {
        display: none;
    }

    /* Filet clair de 1 px en bas, dessiné en ombre intérieure pour ne pas
       ajouter de hauteur : l'accueil et les pages de service ont des sections
       du même bleu nuit, sur lesquelles la barre se confondait (capture d,
       première version). */
    .sticky-header__main {
        display: block;
        box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.12);
    }

    /* 64 px au lieu de 88 : logo de 54 px, liens de 36 px, bouton d'appel sur
       une ligne. Mêmes couleurs, même menu, même ordre. */
    .sticky-header__inner {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 32px;
        height: 64px;
    }

    /* Logo de 54 px : les décalages de l'encre suivent (§ 4, « Barre
       principale »). */
    .sticky-header .masthead__logo {
        --logo-h: 54px;
    }

    .sticky-header .nav__link {
        padding-top: 10px;
        padding-bottom: 10px;
    }

    .sticky-header .nav__link::after {
        bottom: 4px;
    }

    .sticky-header .nav__link--pro {
        padding-top: 3px;
        padding-bottom: 4px;
    }

    .sticky-header .nav__cta {
        min-height: 36px;
        padding-top: 0;
        padding-bottom: 0;
    }

    .sticky-header .nav__cta-detail {
        display: none;
    }

    /* Focus clavier sur fond sombre : contour BLANC, puis un anneau du bleu
       profond entre le contour et l'élément. La règle des fonds clairs du § 2
       (`.masthead :focus-visible`, contour bleu nuit) date de l'en-tête blanc :
       sur le bleu nuit, son contour ne se voyait plus, et sur le bouton
       d'appel blanc son anneau blanc se confondait avec le bouton. Même
       spécificité, écrite plus bas : elle l'emporte. */
    .masthead :focus-visible,
    .sticky-header :focus-visible {
        outline: 2px solid var(--white);
        outline-offset: 2px;
        box-shadow: 0 0 0 4px var(--head-deep);
    }

    /* La carte de Raon reçoit le focus à son ouverture (autofocus, voir
       partials/masthead.php). Son contour blanc est posé À L'INTÉRIEUR :
       dehors, il se perdrait sur la photo claire que la carte recouvre, et
       l'anneau de la règle ci-dessus remplacerait son ombre. Blanc sur le
       bleu nuit de la carte : 11,83:1. Ouverte à la souris, la carte a le
       focus sans ce contour (:focus-visible ne s'allume qu'au clavier). */
    .masthead__card:focus-visible {
        outline-offset: -6px;
        box-shadow: 0 8px 22px rgba(0, 0, 0, 0.22);
    }

    /* La carte de Raon, rendue dans la couche supérieure, passe DEVANT le
       collant : c'est pourquoi assets/js/site.js la referme quand le collant
       apparaît (bloc « en-tête collant », où la mesure est écrite). */
}

/* --- De 981 à 1 279 px : on resserre -----------------------------------
   Sans ces réglages, mesuré à 1 100 px : la liste d'Épinal chevauchait le
   bouton de Raon de 93 px, et le menu passait sous le logo de 32 px. Ce qui se
   retire est ce qui se DÉDUIT du reste — rien d'autre :
     - le code postal : « 47 rue de Nancy, Épinal » ;
     - les icônes du numéro et de l'e-mail : le bouton dit « Voir le numéro »,
       puis montre le numéro lui-même ;
     - « Aussi à » : le bouton garde l'icône de lieu, le nom de la ville et son
       chevron, et la carte dit le reste ;
     - la seconde ligne du bouton d'appel, « Devis et diagnostic gratuits » ;
   et les marges se resserrent : 28 px de côtés, 25 px entre deux éléments de
   la barre du haut, 10 px autour des entrées du menu, logo de 64 px.
   Le balayage de 981 à 1 440 px, pixel par pixel, est au rapport.           */

@media (min-width: 981px) and (max-width: 1279px) {
    .masthead,
    .sticky-header {
        --head-pad: 28px;
    }

    .masthead__postcode,
    .masthead__slot > .masthead__icon {
        display: none;
    }

    /* « Aussi à » est retiré de l'ÉCRAN faute de place, mais PAS du nom
       accessible de la pastille : en display:none, un lecteur d'écran
       n'annonçait plus que « Raon L’Étape », sans dire qu'il s'agit d'une
       seconde boutique (relevé le 18 septembre 2026). Masquage visuel
       seulement, comme .sr-only. */
    .masthead__sister-prefix {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
    }

    /* Les icônes de la carte de Raon, elles, restent : la carte a la place. */
    .masthead__card .masthead__slot > .masthead__icon {
        display: block;
    }

    .masthead__item + .masthead__item {
        margin-left: 25px;
    }

    .masthead__item + .masthead__item::before {
        left: -13px;
    }

    .masthead__main-inner,
    .sticky-header__inner {
        gap: 24px;
    }

    .masthead .masthead__logo {
        --logo-h: 64px;
    }

    .nav__link {
        padding-left: 10px;
        padding-right: 10px;
        letter-spacing: 0.04em;
    }

    .nav__link::after {
        left: 10px;
        right: 10px;
    }

    .nav__item--pro,
    .nav__item--cta {
        margin-left: 10px;
    }

    .masthead .nav__cta {
        min-height: 40px;
        padding-top: 0;
        padding-bottom: 0;
    }

    .masthead .nav__cta-detail {
        display: none;
    }
}

/* --- De 981 à 1 199 px : texte de 12 px ---------------------------------
   La barre du haut et le menu passent en 12 px. Les cases des boutons de
   révélation suivent, mesurées en 12 px dans Chrome, plus les 22 px de
   remplissage et de contour : « Voir le numéro » 83,0 px et « 03 29 32 73 51 »
   81,1 px → 106 ; « Voir l’adresse e-mail » 111,9 px et
   « contact@spin-info.fr » 113,1 px → 136.                                  */

@media (min-width: 981px) and (max-width: 1199px) {
    .masthead,
    .sticky-header {
        --head-pad: 20px;
    }

    .masthead__top,
    .masthead__address .reveal,
    .masthead__sister-toggle {
        font-size: 12px;
    }

    .masthead__address .masthead__slot--tel .reveal {
        min-width: 106px;
    }

    .masthead__address .masthead__slot--email .reveal {
        min-width: 136px;
    }

    .masthead__item + .masthead__item {
        margin-left: 21px;
    }

    .masthead__item + .masthead__item::before {
        left: -11px;
    }

    .masthead__main-inner,
    .sticky-header__inner {
        gap: 16px;
    }

    .masthead .masthead__logo {
        --logo-h: 56px;
    }

    .nav__link {
        padding-left: 8px;
        padding-right: 8px;
        font-size: 12px;
        letter-spacing: 0.03em;
    }

    .nav__link::after {
        left: 8px;
        right: 8px;
    }

    .nav__link--pro {
        padding-left: 9px;
        padding-right: 9px;
    }

    .nav__item--pro,
    .nav__item--cta {
        margin-left: 8px;
    }

    .nav__cta {
        padding-left: 12px;
        padding-right: 12px;
    }

    .nav__cta-main {
        font-size: 12px;
        letter-spacing: 0.04em;
    }
}

/* --- De 981 à 1 049 px : la barre du haut au plus juste -----------------
   Mesuré à 981 px avec les réglages précédents : 7 px seulement entre la
   liste d'Épinal et le bouton de Raon. Les séparateurs se rapprochent de 4 px
   de chaque côté ; rien ne se retire. */

@media (min-width: 981px) and (max-width: 1049px) {
    /* 13 px et non 17 : avec une barre de défilement classique de Windows
       (17 px, comptés dans la largeur des media queries), une fenêtre de
       981 px ne laisse que 964 px de page, et « sur rendez-vous » TOUCHAIT la
       pastille de Raon — −0,92 px mesuré le 18 septembre 2026 en émulant
       cette barre. Trois intervalles de 4 px rendent 12 px. ABANDONNÉ : 17 px
       et un séparateur à −9 px. */
    .masthead__item + .masthead__item {
        margin-left: 13px;
    }

    .masthead__item + .masthead__item::before {
        left: -7px;
    }
}


/* --- Boutons -----------------------------------------------------------
   Base Divi relevée (charte.md § 5) : texte 20 px, interligne 1,7 em (34 px),
   remplissage .3em 1em (6 px 20 px), bordure PLEINE de 2 px de la couleur du
   texte, coins de 3 px, fond transparent, transition all .2s.

   Au survol, l'original décale le texte vers la gauche (.3em 2em .3em .7em) et
   rend la bordure transparente, puis fait apparaître une flèche ETmodules de
   32 px à droite. Le décalage et le fond sont reproduits ; la FLÈCHE ne l'est
   pas — elle venait d'une police d'icônes de 600 Ko que ce site ne charge pas
   (les icônes sont en SVG, src/icons.php). À reprendre en SVG si le client la
   réclame.

   Note de graisse : Divi déclare 500 sur les boutons, et l'original le rendait
   en 400 faute de face 500 chargée. On garde ici le 500 DÉCLARÉ, qui est ce
   que le thème demandait — contrairement au corps de page (§ 2), où le 400
   rendu concerne tout le texte du site et se remarque.                      */

.btn {
    display: inline-block;
    padding: 6px 20px;
    border: 2px solid currentColor;
    border-radius: 3px;
    background: transparent;
    color: var(--ink);
    font-family: var(--sans);
    font-size: 20px;
    font-weight: 500;
    line-height: 1.7em;
    text-align: center;
    cursor: pointer;
    transition: all var(--btn-transition);
}

.btn:hover {
    padding: 6px 40px 6px 14px;
    border-color: transparent;
    background: rgba(0, 0, 0, 0.05);
    color: var(--ink);
}

/* Sur fond sombre : texte et bordure blancs, fond de survol clair. */
.btn--light {
    color: var(--white);
}

.btn--light:hover {
    background: rgba(255, 255, 255, 0.2);
    color: var(--white);
}

/* Bouton plein bleu nuit — celui du livre d'or de l'original, repris pour les
   appels à l'action et les pages d'erreur. */
.btn--navy {
    background: var(--navy);
    border-color: var(--navy);
    color: var(--white);
}

.btn--navy:hover {
    background: var(--navy);
    border-color: transparent;
    color: var(--white);
}

/* --- Marge de défilement des cibles d'ancre -----------------------------
   Quatre liens du site visent une section : les cartes de « Nos services »
   mènent à /reparation/#part1, #part2, /maintenance/#part1 et #part2. La cible
   arrivait SOUS ce qui est tenu en haut de l'écran, et c'était mesurable : à
   1440 px, après clic sur la carte, #part2 se posait à 0,1 px du haut de la
   fenêtre, sous un en-tête collant de 132 px — le haut de la carte et son
   titre étaient recouverts ; à 390 px, la cible arrivait à −0,4 px sous la
   barre noire de 50 px. Défaut de l'original, corrigé (décisions du
   11 septembre 2026, § 6 : les défauts d'affichage se corrigent, et se
   signalent).

   Deux régimes, parce que ce qui recouvre n'est pas le même élément :
     - au-dessus de 981 px, l'en-tête collant, 64 px — la hauteur de
       .sticky-header__inner, plus haut dans ce paragraphe, MESURÉE à 64 px
       à 1100 comme à 1440 px ;
     - en dessous, la barre noire du menu mobile, 50 px, elle aussi tenue en
       haut de l'écran.
   Les deux cotes sont écrites ICI, dans la section de l'en-tête, avec les
   hauteurs dont elles sont la copie : elles doivent changer avec elles. C'est
   la raison pour laquelle ces deux règles ne sont pas au § 6 avec le bloc
   qu'elles visent.

   ABANDONNÉ le 18 septembre 2026, avec l'en-tête de la proposition A :
   132 px, la hauteur de l'ANCIEN collant (8 + 30 + 4 de rangée bleue,
   15 + 60 + 15 de rangée blanche). Gardée sous le nouveau collant de 64 px,
   elle arrêtait la cible 67,8 px trop bas — mesuré après clic sur la carte
   de #part2, à 1440 comme à 1100 px : haut de la section à 131,8 px, bas du
   collant à 64.

   La première ancre de chaque page tombe juste elle aussi, et pour une autre
   raison : #part1 est à 128 px, on s'arrête donc à 64 px de défilement, où
   l'en-tête collant n'est pas encore apparu (il attend 250 px) — mais où le bas
   du grand en-tête, lui, est exactement à 64 px du haut de la fenêtre. La
   cible arrive donc sous l'en-tête visible dans un cas comme dans l'autre.

   Portée : les sections qui portent un identifiant, et elles seules. Ce sont
   aujourd'hui les quatre sections de card_split de Réparation et de
   Maintenance ; une section ancrée ajoutée demain sera couverte sans qu'on y
   pense. #contenu, la cible du lien d'évitement, n'est pas une section : il est
   en haut de page, il n'a besoin de rien. */

.section[id] {
    scroll-margin-top: 50px;
}

@media (min-width: 981px) {
    .section[id] {
        scroll-margin-top: 64px;
    }
}

/* ==========================================================================
   5. Pied de page
   ========================================================================== */

/* Mise en page Divi « et_footer_layout » 2724 : une bande de coordonnées sur
   fond bleu nuit à quatre colonnes, une barre noire, et 30 px de blanc SOUS
   elle — la page de l'original se termine par cette bande blanche.

   CETTE SECTION A REMPLACÉ celle que la base portait, et non pas complétée :
   les noms de classes sont les mêmes, la CONSTRUCTION est autre. La base
   décrivait des listes en flex avec 14 px de gouttière, un filet à 10 px sous
   le titre, 27 px de respiration sur les colonnes et une barre basse en flex —
   c'étaient les cotes du site Raon. Le relevé de Spin en donne d'autres, et
   c'est lui qui a tranché. Trois classes de la base ne visaient d'ailleurs plus
   rien et ont disparu avec elle : `.footer__contact`, `.footer__menu` et
   `.footer__credit` (templates/partials/footer.php émet `.footer__coord`,
   `.footer__hours`, `.footer__legal` et `.footer__social`).

   D'où viennent les nombres — rien n'est approché à l'œil :
     - hauteurs de bande : spinwork/live/pages/*_1440.json et *_390.json,
       sections kind=footer (les onze pages donnent les mêmes valeurs) ;
     - réglages Divi : spinwork/db/arbres/et_footer_layout-2724-*.json et le
       CSS que Divi émet dans la page (spinwork/live/pages/accueil_1440.html) ;
     - géométrie fine : balayage des pixels blancs des captures
       accueil_1440.png et accueil_390.png, colonne par colonne — c'est lui qui
       donne la position des filets et de chaque ligne de texte.

   ---------------------------------------------------------------------------
   LES QUATRE PIÈGES DE CE PIED, mesurés et non devinés
   ---------------------------------------------------------------------------

   1. INTERLIGNE DE 23,8 px PARTOUT, quelle que soit la taille du texte.
      Divi déclare `line-height: 1.7em` sur un corps de 14 px. La valeur
      CALCULÉE, 23,8 px, est ce que tous les descendants héritent : un
      interligne en `em` se calcule une fois, chez l'ancêtre qui le déclare.
      Le titre de 22 px, l'adresse de 18 px et les horaires de 14 px sont donc
      tous sur le même rythme de 23,8 px. Écrire `1.7em` sur le titre donnerait
      37,4 px, soit 13,6 px de trop par colonne. D'où les `line-height:
      inherit` ci-dessous, et aucune autre déclaration d'interligne.

   2. LE FILET N'EST PAS COLLÉ AU TITRE, et les dix pixels du relevé sont un
      leurre. Mesuré dans les quatre colonnes, à 1440 comme à 390 px : le
      filet est à 53,5 px du haut du pied, soit 10 px de respiration de
      section + 23,8 px de ligne de titre + 20 px de marge. Or les séparateurs
      des colonnes 3 et 4 portent `margin-top: 10px !important` : cette marge
      est INERTE, elle fusionne avec la marge basse de 20 px du titre, son
      frère immédiat, et max(20, 10) fait 20. La reproduire comme un vrai
      décalage descendrait deux colonnes sur quatre de 10 px.
      Sous le filet il reste 19 px d'air avant le texte : dans l'original,
      4 + 19 = 23 px sont la hauteur du module « séparateur » de Divi, dont le
      trait est un ::before en position absolue calé sur son bord haut.

   3. GRILLE ET NON FLEX pour les colonnes (les deux bandes). Piège mesuré sur
      le site Raon, écrit dans son site.css : en flex, les
      `grid-template-columns` des media queries n'ont aucun effet et le pied
      garde quatre colonnes de 73 px à 390 px, la quatrième seule sur une
      deuxième rangée.

   4. LES ~30 px DE BLANC SOUS LE PIED ne sont pas une erreur de mesure : ils
      sont la marge basse de la section noire. Ils sont reproduits.

   ---------------------------------------------------------------------------
   LES SOMMES — chaque bande de l'original se reconstitue au dixième de pixel
   ---------------------------------------------------------------------------

   Bande 1 à 1440 px — mesurée 305,2 px :
       10 (section) + 0 (rangée) + 280,2 (la plus haute colonne) + 5 + 10
     où la plus haute est « Nos horaires » :
       23,8 (titre) + 20 (marge) + 23 (filet + air) + 204,4 (texte) + 9
     et 204,4 = 8 lignes de 23,8 + 14 px entre les deux paragraphes.
   Barre noire à 1440 px — mesurée 101,6 px :
       27 (rangée) + 47,6 (deux lignes de 23,8) + 27.
   Bande 1 à 390 px — mesurée 1007,5 px :
       10 + (232 + 30) + (232 + 30) + (148,4 + 30) + 280,2 + 5 + 10 = 1007,6
     où chaque bloc sauf le dernier ajoute 25 px de respiration basse et 30 px
     de marge (l'empilement des colonnes de Divi sous 981 px).
   Barre noire à 390 px — mesurée 225,2 px :
       30 (rangée) + 95,2 (quatre lignes) + 30 (marge de colonne)
     + 32 (carré Facebook) + 8 (marge du <li> de Divi) + 30.

   ---------------------------------------------------------------------------
   CE QUE MESURE LE PIED NEUF, et pourquoi il est plus haut que l'original
   ---------------------------------------------------------------------------

   Ce commentaire renvoyait ces valeurs à un « rapport de fusion » qui n'est
   pas dans le site. Les voici, mesurées le 16 septembre 2026, identiques sur
   les dix pages :
     1440 px — 454,4 px contre 406,8 relevés, soit +47,6 : bande 1 352,8
               contre 305,2 ; barre noire 101,6, la cote de l'original ;
      390 px — 1 256,5 px contre 1 232,7 relevés, soit +23,8 : bande 1
               1 031,3 contre 1 007,5 ; barre noire 225,2, la cote de
               l'original.
   La construction est celle des sommes ci-dessus — la barre noire, dont le
   crédit a changé mais garde ses deux lignes à 1440 px et ses quatre à
   390 px, retombe au dixième. Tout l'écart vient du TEXTE de deux colonnes :
     - « Nos horaires » : 327,8 px à 1440 px contre 280,2, DIX lignes au lieu
       de huit, cinq par ville. Les horaires validés le 11 septembre 2026 —
       la phrase d'Épinal et ses deux boutons de numéro, les deux régimes de
       Raon-l'Étape, « Boutique » et « À distance » (écart nº 2 de
       partials/footer.php) — sont plus longs que ceux de l'original. C'est
       la plus haute colonne : 10 + 327,8 + 5 + 10 = 352,8, les +47,6 px.
       À 390 px, dans une colonne de 312 px, ils tiennent en huit lignes :
       280,2 px, la cote de l'original.
     - « Siège social » : trois lignes au lieu de deux, la raison sociale
       DPHNET étant ajoutée au-dessus de l'adresse (écart nº 1 de
       partials/footer.php). À 390 px : 172,2 px contre 148,4, ce sont les
       +23,8 px (10 + 262 + 262 + 202,2 + 280,2 + 5 + 10 = 1 031,4). À
       1440 px, 147,2 px, sous « Nos horaires » : sans effet.
   Les deux colonnes de boutique NE BOUGENT PAS : 207 px à 1440 px, 232 px à
   390 px. La troisième raison qu'écrivait ce commentaire, « une coordonnée
   révélée au clic tient sur une ligne là où l'adresse en clair en prenait
   deux », ne compte donc pas dans l'écart : posées en clair à la place des
   boutons, les coordonnées ne font passer sur deux lignes que
   « contact@raon-informatique.fr », à 1440 px seulement, et sa colonne monte
   à 230,8 px — encore sous « Nos horaires ». À 390 px, rien ne change.     */

.footer {
    background: var(--white);
}

/* --- Bande 1 : les coordonnées ----------------------------------------- */

/* Les deux bandes n'ont pas la même laize dans l'original, et c'est visible :
   la rangée des coordonnées est en « largeur maximale 100 % » (1152 px à
   1440 px, classe .row--wide), la barre basse est une rangée de contenu
   ordinaire (80 %, plafonnée à 1080 px). Les liens de la barre commencent donc
   36 px plus à droite que « Boutique Épinal ». Relevé : x = 144 pour la
   bande 1, x = 180 pour la barre. */

.footer__main {
    background: var(--navy);
    color: var(--white);
    /* custom_padding="10px||10px||false|false" — aucune variante responsive :
       10 px à toutes les largeurs, y compris sur téléphone. */
    padding: 10px 0;
}

/* custom_padding="0px||5px|||" sur la rangée : rien en haut, 5 px en bas.
   Pas de variante responsive non plus. */
.footer__main > .row {
    padding: 0 0 5px;
}

/* Les liens et les boutons de révélation du pied sont blancs. Le survol est un
   ÉCART ASSUMÉ : le relevé dit « liens du pied : aucun changement »
   (charte.md § 13), mais un lien qui ne répond pas au pointeur laisse croire
   qu'il n'est pas cliquable. À ne pas « corriger » par mégarde dans l'autre
   sens : c'est un choix, pas un oubli. */
.footer a,
.footer .reveal {
    color: var(--white);
}

.footer a:hover,
.footer .reveal:hover {
    color: rgba(255, 255, 255, 0.7);
}

/* Quatre colonnes 1/4 en gouttière « 2 » (3 %), à hauteurs égales
   (make_equal="on", invisible ici : le fond est uniforme).
   `repeat(4, 1fr)` avec 3 % de gouttière donne (100 − 9) / 4 = 22,75 % par
   colonne, la largeur exacte de Divi — 262,08 px à 1440 px, relevé 262.
   Voir le piège nº 3 : GRILLE, pas flex.
   `gap` en DEUX valeurs, et non `column-gap` seul : l'original n'a aucune
   gouttière de rangée, et un row-gap oublié s'ajouterait aux 55 px
   d'empilement — 84 px de trop sur la bande à 390 px, mesurés. */
.footer__cols {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0 var(--gutter-narrow);
    align-items: start;
    padding: 0;
}

/* Intitulé de colonne : 22 px, graisse 600, ITALIQUE, blanc.
   La marge basse est de 19 et non 20 px : les 20 px de l'original sont entre
   le titre et le filet, et le filet est ici DANS le titre (::after). Le compte
   est le même — 23,8 + 20 + 4 + 19 = 66,8 px avant la première ligne de
   texte —, mais il ne demande aucune balise en plus.
   ÉCART ASSUMÉ, sans effet sur le rendu : ce sont des h2, alors que l'original
   employait de simples modules de texte. Le pied a besoin de titres réels pour
   qu'un lecteur d'écran puisse sauter de colonne en colonne ; le site Raon
   fait le même choix. */
.footer h2 {
    margin: 0 0 19px;
    padding-bottom: 0;
    color: var(--white);
    font-size: 22px;
    font-weight: 600;
    font-style: italic;
    line-height: inherit;
}

/* Le filet : 4 px de haut sur 9 % de la largeur de la colonne — 23,6 px à
   1440 px, relevé 24 px de pixels blancs —, aligné à gauche, à 20 px sous la
   ligne du titre (piège nº 2). Un ::after et non une image : rien à
   télécharger, et il suit la couleur du texte. */
.footer h2::after {
    content: "";
    display: block;
    width: 9%;
    height: 4px;
    margin-top: 20px;
    background: var(--white);
}

/* Adresse, téléphone, e-mail : 18 px, graisse 600, italique, et 9 px de marge
   basse (custom_margin="||9px|||" du module). L'écart entre les paragraphes
   est la retombée de 1 em du § 2, soit 18 px ici : c'est exactement l'écart
   mesuré sur l'original (23,8 + 18 px d'une ligne à l'autre).
   Hauteur reconstituée d'une colonne de boutique : 2 lignes + 18 + 1 ligne
   + 18 + 1 ligne = 131,2 px, la valeur mesurée. */
.footer__coord {
    margin-bottom: 9px;
    font-size: 18px;
    font-weight: 600;
    font-style: italic;
}

/* Les icônes sont DANS le fil du texte, comme les <i> de Font Awesome de
   l'original, et non dans une colonne à part : c'est ce qui fait que la
   deuxième ligne d'une adresse (« 88000 Épinal ») commence au même x que
   l'icône de la première, sans retrait. Relevé : icône de 144 à 155,
   texte à partir de 162 ; « 88000 Épinal » à 144. La base posait ici des <li>
   en flex avec 14 px de gouttière, ce qui mettait justement le texte en
   retrait. */
.footer__coord svg {
    width: 18px;
    height: 18px;
    /* L'icône est calée sur la ligne de base du texte, pas centrée : les
       glyphes de Font Awesome descendent légèrement sous elle. */
    vertical-align: -3px;
    fill: var(--white);
}

/* L'arobase de la ligne e-mail (voir l'en-tête de partials/footer.php) :
   redressée et en graisse 700, elle rend le glyphe « fa-at » de l'original,
   qui n'est ni penché ni maigre. */
.footer__at {
    font-style: normal;
    font-weight: 700;
}

/* Horaires : 14 px — la taille du corps, le module n'en déclare pas —,
   graisse 600, italique, 9 px de marge basse. L'intitulé de ville n'est pas
   en gras dans l'original : tout ce bloc a la même graisse.
   L'interligne est l'hérité, 23,8 px : la base mettait ici 1,5 em, soit
   21 px — le piège nº 1 pris sur le fait, 2,8 px par ligne et 28 px de moins
   sur une colonne de dix lignes. */
.footer__hours {
    margin-bottom: 9px;
    font-size: 14px;
    font-weight: 600;
    font-style: italic;
    line-height: inherit;
}

/* Les deux paragraphes d'horaires sont séparés par 1 em, soit 14 px : c'est
   l'écart mesuré sur l'original (23,8 px de ligne + 14 px = 37 px d'une ligne
   à l'autre). La base mettait 0,6 em — 8,4 px. */
.footer__hours p {
    padding-bottom: 1em;
}

.footer__hours p:last-child {
    padding-bottom: 0;
}

/* Le repli sans JavaScript, lui, n'est pas un relevé : l'original n'en avait
   pas besoin, il affichait tout en clair. Texte courant, pour qu'il se lise
   comme une phrase et non comme une coordonnée. */
.footer__noscript {
    font-size: 14px;
    font-weight: 400;
    font-style: normal;
}

.footer__fallback {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 18px;
    font-weight: 600;
    font-style: italic;
}

/* --- Barre basse, crédit, Facebook, les 30 px de blanc ----------------- */

/* LES 30 px DE BLANC SOUS LE PIED — une cote de l'ORIGINAL, reproduite. Ils
   viennent de la marge basse de la section noire de l'original
   (`margin-bottom: 30px`, relevée dans spinwork/live/pages/accueil_1440.json
   et _390.json : sections kind=footer, inner[1].margin). Le relevé les montre
   sur les onze pages de l'original et aux deux largeurs : 29,5 à 30,5 px
   entre le bas du pied et la fin du document, selon l'arrondi de la hauteur
   de page (accueil : pied jusqu'à 5 157,3 px pour une page de 5 187 à
   1440 px, jusqu'à 8 341,5 pour 8 372 à 390 px). Les captures le confirment :
   30 rangées de pixels entièrement blancs sous une rangée entièrement noire,
   à 1440 comme à 390 px (accueil, reparation et coordonnees, relu le
   16 septembre 2026). Ils sont REPRODUITS, et par le même moyen — une marge
   basse, qui sort du pied par fusion des marges. Deux conséquences voulues :
     - la hauteur du <footer> reste celle de ses deux bandes (406,8 px à
       1440 px dans l'original, 454,4 ici), les 30 px sont sous lui et non
       dedans ;
     - la page se termine par une bande blanche, comme l'original.
   Ce n'est PAS une décision du client. Ce commentaire le laissait lire
   (« c'est une décision de client, pas une décision de gabarit ») ; aucune
   décision n'existe sur cette bande, ni pour la garder ni pour la retirer.
   C'est un héritage de l'original, gardé comme toute cote relevée. Coller la
   barre noire au bas de la page serait un écart de fidélité : à faire
   trancher par le client, et à écrire ici s'il était retenu.
   Sous 768 px, ce blanc mesure 80 px et non 30 (79,6 à 80,5 px sur les dix
   pages à 390 px, selon le même arrondi ; le « 80,3 px » écrit ici
   auparavant n'était que l'une de ces valeurs). Les 50 px de plus sont la
   réserve que le § 9 pose sur le <body> pour la barre d'appel, sans laquelle le
   crédit passerait dessous. L'original n'en avait pas besoin, son bouton
   collant recouvrait la fin de la page. */
.footer__bar {
    background: var(--ink);
    color: var(--white);
    margin-bottom: 30px;
}

/* Rangée de contenu ordinaire : la respiration de Divi, 2 %, que le customizer
   fixe à 27 px au-delà de 1350 px et à 30 px sous 981 px (le § 3 fait de même
   pour .section > .row). C'est elle qui donne les 101,6 px de la barre :
   27 + 47,6 + 27. La base posait cette respiration sur le contenu de la barre,
   qui n'en porte aucune. */
.footer__bar > .row {
    padding: 2% 0;
}

@media (min-width: 1350px) {
    .footer__bar > .row {
        padding: 27px 0;
    }
}

/* Deux colonnes de moitié en gouttière « 3 » (5,5 %), soit 47,25 % chacune —
   510,3 px à 1080 px, relevé 510. En GRILLE, comme la bande du haut et pour la
   même raison. Deux valeurs de `gap` pour la même raison aussi : un row-gap de
   24 px, invisible à 1440 px où il n'y a qu'une rangée, portait la barre de
   225,2 à 249,2 px à 390 px. */
.footer__bar-inner {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0 var(--gutter);
    align-items: start;
    padding: 0;
}

/* Liens et crédit : 14 px blanc, DROIT (la barre basse n'est pas en italique,
   contrairement à la bande du haut), liens en graisse 700. Deux lignes à
   1440 px, quatre à 390 px. */
.footer__legal {
    font-size: 14px;
    font-weight: 400;
    font-style: normal;
}

.footer__legal a {
    font-weight: 700;
}

/* Facebook : carré de 32 × 32 px, fond #3b5998, coins de 3 px, aligné à droite
   de sa colonne — et calé en HAUT, pas centré (mesuré : le carré commence au
   bord haut du contenu de la rangée, son centre est à 348 px du haut du pied
   et non à 356). Les 8 px de marge basse sont ceux du <li> de Divi : ils ne se
   voient pas à 1440 px, où la colonne de gauche est plus haute, mais ils
   entrent dans les 225,2 px de la barre à 390 px. */
.footer__social {
    display: flex;
    justify-content: flex-end;
    gap: 14px;
    margin-bottom: 8px;
}

.footer__social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: var(--facebook);
    border-radius: 3px;
}

.footer__social svg {
    width: 18px;
    height: 18px;
    fill: var(--white);
}

/* --- Sous 981 px ------------------------------------------------------- */

/* Divi empile les colonnes et leur donne 30 px de marge basse ; les trois
   premières colonnes du pied reçoivent en plus 25 px de respiration basse
   (`custom_padding_tablet="||25px||false|false"`, émis par Divi dans
   @media (max-width: 980px) — vérifié, ce n'est PAS une règle de bureau).
   Soit 55 px entre deux blocs, et rien après le dernier. C'est ce qui fait
   tomber la bande à 1007,6 px contre 1007,5 mesuré. La rangée, elle, garde ses
   0 et 5 px : son custom_padding n'a pas de variante responsive.
   UN SEUL PALIER, à 981 px : la base en avait deux, 981 et 480, avec deux
   colonnes entre les deux — c'étaient les cotes de Raon. */
@media (max-width: 980px) {
    .footer__cols {
        grid-template-columns: 1fr;
    }

    .footer__col:not(:last-child) {
        padding-bottom: 25px;
        margin-bottom: 30px;
    }

    .footer__bar > .row {
        padding: 30px 0;
    }

    .footer__bar-inner {
        grid-template-columns: 1fr;
    }

    /* La marge d'empilement des colonnes de Divi, ici entre les liens et
       Facebook. */
    .footer__legal {
        margin-bottom: 30px;
    }

    /* L'icône reste à DROITE quand elle passe sous les liens : le module de
       l'original est aligné à droite à toutes les largeurs (relevé à 390 px :
       le carré est collé au bord droit de la rangée, x = 351). Le pied du site
       Raon, lui, repasse son crédit à gauche : ne pas reprendre ce réflexe —
       d'où l'absence de règle ici, et cette ligne pour le dire. */
}

/* ==========================================================================
   6. Blocs de contenu
   ========================================================================== */

/* Un bloc = un gabarit de templates/blocks/ = un paragraphe ici, dans l'ordre
   du plus générique au plus particulier. Chaque bloc porte SES points de
   rupture, à côté des cotes dont ils sont la variante.

   Aucune valeur n'est approchée à l'œil. Toutes viennent du relevé de
   l'original — spinwork/live/pages/*_1440.json et *_390.json pour les
   rectangles et les styles calculés, spinwork/db/arbres/*.json pour les
   réglages Divi, spinwork/design/charte.md pour la charte, et les captures PNG
   sondées pixel par pixel pour ce qu'aucun nombre ne dit (un bouton évidé, un
   filet visible, la bascule d'un dégradé).

   Les sommes sont vérifiables : chaque section reconstituée ci-dessous tombe
   au dixième de pixel sur la hauteur mesurée de l'original.
     titre de page    — h1 à 256,4 px à 1440, à 220,6 px à 390
     diaporama        — 577,5 px à 1440 ; masqué sous 981 px
     trois blocs      — 378 px à 1440, 868 px à 390 ; carte de 216 px aux deux
     ouverture        — 1366,6 px à 1440, 1315,9 px à 390
     « Nos services » — 505,2 px à 1440, 1651,8 px à 390
     carte + photo    — carte à 3397,5 px, texte à 3463,5 px (accueil, 1440)
     galerie          — 803,0 px à 1440
     appel à l'action — 313,8 px à 1440

   Rien du site Raon ici : ses sections à lui (hero, infobar, photo-tiles,
   feature-split, dark-split) n'ont pas d'équivalent mesuré sur Spin.        */

/* --- 6.1 Texte courant -------------------------------------------------
   Relevé : les modules de texte de l'original n'ont pas de taille propre, ils
   héritent du corps — 14 px / 23,8 px. C'est une différence avec le site
   Raon, dont les modules composaient en 15 px / 27 px.                      */

.prose {
    color: var(--ink);
}

.prose h2,
.prose h3,
.prose h4 {
    color: var(--navy);
}

/* ÉCART ASSUMÉ pour tout le site : l'original ne soulignait pas les liens de
   son texte courant. Un lien qui ne se distingue que par sa couleur n'est pas
   repérable par un daltonien. */
.prose a {
    color: var(--ink);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.prose a:hover {
    color: var(--navy);
}

.prose .u {
    text-decoration: underline;
}

/* --- 6.2 Image et deux colonnes ----------------------------------------
   Ces deux gabarits (blocks/image.php, blocks/two_col.php) font partie du jeu
   repris du site Raon et aucune des dix pages de Spin ne les demande
   aujourd'hui. Leurs règles restent : un bloc dont le gabarit existe mais dont
   la feuille a été nettoyée est une mine posée pour le prochain qui l'emploie.
   L'image prolonge la rangée du texte — elle ne porte pas de respiration de
   section, seulement le bas de rangée.                                      */

.block-image {
    padding: 0;
}

.block-image .row {
    padding-bottom: 27px;
}

.block-image img {
    display: block;
    width: 100%;
    height: auto;
}

.two-col__media {
    display: block;
    margin-bottom: 30px;
}

.two-col__media img {
    display: block;
    width: 100%;
    height: auto;
}

.two-col__media--after {
    margin: 30px 0 0;
}

/* --- 6.3 Titre de page (blocks/page_title.php) -------------------------
   Le module « titre » de l'original vit dans la MÊME rangée que le contenu de
   la page : entre le bas du titre et le début du contenu il n'y a que la
   retombée de 10 px du h1 (mesuré sur la galerie : h1 à 256,4 + 32 + 10 =
   298,4, exactement le haut de la grille de photos).

   Ici, chaque bloc est une section. Si le bloc de titre gardait sa respiration
   basse (54 + 27) et le bloc suivant sa respiration haute (54 + 27), il y
   aurait 162 px là où l'original en met 10. D'où ces deux séries de règles :
   le titre ne porte QUE sa respiration haute, et le bloc qui le suit perd la
   sienne. Le résultat est celui de la rangée d'origine, sans style en ligne ni
   classe à poser à la main dans les fichiers de contenu. La page Coordonnées
   est l'exception, et elle est traitée au § 7 : là, le contenu est dans la
   rangée SUIVANTE et les 54 px existent pour de bon.                        */

.page-title {
    padding: 4% 0 0;
}

.page-title > .row {
    padding: 2% 0 0;
}

@media (min-width: 1350px) {
    .page-title {
        padding: 54px 0 0;
    }

    .page-title > .row {
        padding: 27px 0 0;
    }
}

/* Sous 981 px, Divi passe à 50 px pour les sections et 30 px pour les rangées.
   Vérifié sur Coordonnées à 390 px : h1 à 220,6 = 140,6 (barre mobile de 50 px
   + rangée bleue de 90,6 px) + 50 + 30. */
@media (max-width: 980px) {
    .page-title {
        padding: 50px 0 0;
    }

    .page-title > .row {
        padding: 30px 0 0;
    }
}

/* Deux classes : l'emporte sur `.section` et sur `.section > .row` du § 3, y
   compris dans leurs media queries. */
.page-title + .section {
    padding-top: 0;
}

.page-title + .section > .row {
    padding-top: 0;
}

/* Écrit ici bien que ce soit déjà le défaut des titres au § 2 : c'est cette
   retombée, et elle seule, qui sépare le titre du contenu. */
.page-title__heading {
    padding-bottom: 10px;
}

/* Filet sous le titre — relevé sur la seule page Coordonnées (et_pb_divider,
   3 px, 6 % de large, 10 px de marge haute). Sa couleur n'est pas dans le
   code court : elle a été LUE dans la capture, pixel par pixel — #283851 aux
   lignes y = 308, 309 et 310, soit 3 px pleins à 10 px sous la retombée du
   titre (256,4 + 32 + 10 + 10 = 308,4). */
.page-title__rule {
    display: block;
    width: 6%;
    height: 3px;
    margin-top: 10px;
    background: var(--navy);
}

/* --- 6.4 Diaporama figé (blocks/hero_slide.php) ------------------------
   Décomposition des 577,5 px relevés à 1440 px de large — et la surprise de
   cette section, trouvée en mesurant le rendu neuf, pas en lisant le code :

     202,5  remplissage haut de la colonne de texte (25 % de ses 810 px)
      46    le titre, sur UNE ligne
      30    l'écart avant le bouton
      50    le bouton (34 d'interligne + 2 × 6 de remplissage + 2 × 2 de filet)
     202,5  remplissage bas
     -----
     531    la hauteur PROPRE de la première diapositive

   Il manque 46,5 px pour tomber sur les 577,5 px mesurés, et ils ne sont pas
   égarés : ils appartiennent à la SECONDE diapositive. Son titre —
   « Réparation informatique à Raon L'Étape » — est plus long de six caractères
   et passe à la ligne dans la même colonne de 680,4 px utiles. Or le conteneur
   du diaporama de Divi prend la hauteur de la diapositive la PLUS HAUTE, et
   les deux se le partagent : la première y flottait avec 202,5 px de photo
   au-dessus de son titre et 249 px sous son bouton. Elle n'était donc pas
   centrée dans la bande, et c'est bien ce que montre la capture.

   On garde la bande à 577,5 px. C'est la hauteur du premier écran de
   l'original, celle qui pose l'encadré bleu suivant à 752,9 px et, derrière
   lui, toute la page. Sans ce min-height, la bande tomberait à 531 px et tout
   remonterait de 46,5 px. Le titre, le badge et le bouton, eux, gardent leurs
   positions relevées : section 577,5 pour 577,5 relevés, titre à 377,9 pour
   378,1, badge à 306,1 pour 306,1.                                          */

.hero {
    position: relative;
    /* Le voile doit se mêler à CETTE photo et à rien d'autre : sans contexte
       d'isolement, mix-blend-mode remonte jusqu'au fond de la page. Même
       précaution que la section « Nos services ». */
    isolation: isolate;
    overflow: hidden;
    /* Fond sous la photo : la section n'est jamais transparente, même le temps
       du chargement de l'image. */
    background: var(--navy);
}

/* Masqué sous 981 px : `disabled_on="on|on|off"` sur la section de l'original
   — ni téléphone ni tablette. Relevé à 390 px : hauteur 0, display none. La
   photo part en loading="lazy" avec un sizes de 1 px et un préchargement fermé
   par `media="(min-width: 981px)"` (src/helpers.php) : rien n'est alors
   téléchargé — vérifié, zéro octet pour le bandeau à 390 px. */
@media (max-width: 980px) {
    .hero {
        display: none;
    }
}

/* Rangée de Divi : 80 % de la page, plafond 1080 px. Les deux colonnes sont
   des cellules de tableau dans l'original (`display: table-cell;
   vertical-align: middle`) ; un flex donne la même géométrie. */
.hero__container {
    position: relative;
    z-index: 2;
    display: flex;
    /* Les deux colonnes ne se placent PAS de la même façon dans la bande, et
       c'est encore la seconde diapositive qui l'explique : le texte commence
       au remplissage de 25 % (titre relevé à 378,1 px, soit 202,5 dans la
       section) et laisse le reste de la bande sous lui, tandis que le badge
       est centré. Avec `align-items: center`, la colonne de texte se centrait
       dans les 577,5 px et le titre descendait à 401,1 — 23 px de trop,
       mesurés. D'où l'alignement en haut ici, et le centrage posé sur le seul
       badge. */
    align-items: flex-start;
    width: 80%;
    max-width: var(--row);
    margin: 0 auto;
    /* La hauteur de la bande, imposée à l'origine par la seconde diapositive.
       Elle cède si le contenu devient plus haut — c'est ce qui arrive entre
       981 et 1350 px, où le titre passe à la ligne : la bande grandit alors
       d'elle-même, comme le faisait celle de Divi, qui se recalculait à chaque
       largeur. */
    min-height: 577.5px;
}

/* Le badge : 25 % du conteneur (`custom_css_slide_image="width:25%;"`), soit
   270 px, pour un fichier de 352 × 352.

   Les -46 px ne sont pas un réglage à l'œil. Le script de Divi pose un
   `margin-top: -158px` sur l'image alors que le centrage n'en demandait que
   135 (la moitié de 270) : le badge se retrouve 23 px plus haut que le milieu
   de la bande — haut relevé 306,1 px, soit 130,75 dans la section, et
   288,75 − 158 = 130,75 exactement.

   Ici le centrage est celui de flexbox, qui centre la boîte MARGE : une marge
   négative n'y déplace l'élément que de la moitié de sa valeur. Il faut donc
   écrire -46 px pour obtenir les -23 px voulus :
   (577,5 − (270 − 46)) / 2 − 46 = 130,75. Mesuré après correction : 130,7.
   La valeur tient pour la fenêtre de référence de 1440 px, où le badge fait
   270 px de haut. */
.hero__media {
    flex: 0 0 25%;
    width: 25%;
    align-self: center;
    margin-top: -46px;
}

.hero__media img {
    display: block;
    width: 100%;
    height: auto;
}

.hero__body {
    flex: 0 0 75%;
    width: 75%;
}

/* Les pourcentages se calculent sur la largeur de .hero__body (810 px), pas
   sur celle du conteneur : 25 % = 202,5 px de respiration verticale, 8 % =
   64,8 px de chaque côté. C'est pour cette raison que le remplissage est posé
   sur un élément intérieur et non sur la colonne elle-même — sur un enfant de
   flex, un pourcentage se calcule sur la largeur du CONTENEUR (1080), et
   aurait donné 270 px. */
.hero__inner {
    padding: 25% 8%;
}

/* Relevé : 46 px, graisse 300, blanc, ombre 0 0 .3em #000 (13,8 px à cette
   taille), aligné à gauche. Le remplissage bas des paragraphes du § 2 est
   retiré : ici, c'est l'écart du bouton qui fait la séparation. */
.hero__title {
    margin: 0;
    padding: 0;
    color: var(--white);
    font-size: 46px;
    font-weight: 300;
    line-height: 46px;
    text-shadow: var(--text-shadow);
}

.hero__actions {
    margin-top: 30px;
}

/* `button_text_shadow_style="preset3"` sur les deux diapositives : le bouton
   porte la même ombre que le titre. */
.hero__actions .btn {
    text-shadow: var(--text-shadow);
}

/* --- 6.5 Trois blocs de services (blocks/service_blocks.php) -----------
   Décomposition des 378 px relevés à 1440 px : 54 de section + 27 de rangée
   + 216 de carte + 27 + 54. Et des 868 px relevés à 390 px : 50 + 30
   + 3 × 216 + 2 × 30 (les colonnes empilées) + 30 + 50.

   La carte fait 216 px aux deux largeurs :
     30  remplissage (custom_padding="30px|30px|30px|30px")
     96  l'icône (glyphe de police en 96 px dans l'original)
     30  l'écart sous l'icône
     20  le titre (20 px d'interligne, graisse 700)
     10  sa retombée
     30  remplissage bas
   Les 20 + 10 ne sont pas déduits mais VÉRIFIÉS par la position des titres :
   1147,7 + 30 + 96 + 30 = 1303,7 mesuré à 1440, et 597,8 + 30 + 96 + 30 =
   753,8 mesuré à 390.

   Les respirations viennent de `.section` et `.section > .row` (§ 3), qui
   portent déjà les 54/27 au-delà de 1350 px, les 4 %/2 % entre 981 et 1350, et
   les 50/30 en dessous. Seul le FOND change ici.                            */

.service-blocks {
    position: relative;
    isolation: isolate;
    /* Le dégradé de l'original (`#000000 55%|#ffffff 55%`), sur lequel la
       photo est mêlée en `screen`. Deux arrêts au même pourcentage : la
       bascule est franche. Sondée sur la capture à y = 1275, soit 55 % des
       378 px de la section à partir de 1066,7. */
    background-image: linear-gradient(180deg, #000000 55%, #ffffff 55%);
}

/* `background_blend="screen"` : sur le noir, screen laisse la photo intacte ;
   sur le blanc, screen rend du blanc. Et `background_position="left bottom"`,
   rendu ici par object-position, la photo étant une balise <img>. */
.service-blocks__photo {
    mix-blend-mode: screen;
    object-position: left bottom;
}

/* Sous 981 px, `use_background_color_gradient_tablet="off"` : plus de dégradé,
   la photo seule. Le mélange DOIT partir avec lui — un screen sur le blanc de
   la page aurait effacé la photo entière, alors que la capture à 390 px la
   montre à sa clarté normale derrière les trois cartes. */
@media (max-width: 980px) {
    .service-blocks {
        background-image: none;
    }

    .service-blocks__photo {
        mix-blend-mode: normal;
    }
}

/* La rangée passe devant la photo (.bg-photo est en z-index 0). */
.service-blocks > .row {
    position: relative;
    z-index: 2;
}

/* La cellule porte la largeur de colonne (29,6667 % en gouttière 3, soit
   320,4 px dans une rangée de 1080) ; la carte, elle, remplit la hauteur de la
   rangée — les trois colonnes de l'original sont à hauteurs égales. */
.service-blocks__cell {
    display: flex;
}

.service-block {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 30px;
    text-align: center;
    /* Ombre Divi, préréglage 1, en NOIR PLEIN (`box_shadow_color="#000000"`)
       et non dans le rgba(0,0,0,.3) du jeton --box-shadow, qui est celui des
       blocs de texte blancs. */
    box-shadow: 0 2px 18px 0 #000000;
    transition: transform var(--transition);
}

/* Survol relevé : la colonne rétrécit de 10 % en 300 ms (charte § 10). Le
   focus reçoit le même traitement — au clavier, on doit voir ce qu'on vise. */
.service-block:hover,
.service-block:focus-visible {
    transform: scale(0.9);
}

/* Les trois fonds, et les couleurs qui vont avec. La couleur de TEXTE de la
   carte est celle de l'icône (le SVG est en currentColor) ; le titre, lui,
   porte la sienne, parce que l'original les règle séparément : la carte
   blanche a une icône bleu nuit — la couleur d'accent, défaut de Divi quand
   `icon_color` n'est pas renseigné — et un titre noir. */
.service-block--navy {
    background: var(--navy);
    color: var(--white);
}

.service-block--light {
    background: var(--white);
    color: var(--navy);
}

.service-block--dark {
    background: var(--ink);
    color: var(--white);
}

.service-block--navy .service-block__title,
.service-block--dark .service-block__title {
    color: var(--white);
}

.service-block--light .service-block__title {
    color: var(--ink);
}

/* L'icône : 96 px, centrée, 30 px avant le titre. Les tracés redessinés
   remplissent leur boîte de 96 × 96, quand les glyphes d'origine occupaient
   environ 106 × 86 (encre relevée sur la capture) : la largeur de l'encre
   diffère d'une dizaine de pixels, ce qui ne déplace rien — l'icône est
   centrée et c'est sa HAUTEUR de 96 px qui tient la carte. */
.service-block__icon {
    display: block;
    width: 96px;
    height: 96px;
    margin: 0 auto 30px;
    fill: currentColor;
}

/* Relevé : 20 px sur 20 px d'interligne, graisse 700, centré, et 10 px de
   retombée — celle des titres du § 2, qu'un <p> n'a pas.

   PIÈGE MESURÉ. Écrite `.service-block__title`, cette retombée était perdue :
   `p:last-child { padding-bottom: 0 }` (§ 2) compte deux éléments de sélecteur
   contre un seul, donc plus spécifique — et le titre est bien le dernier
   enfant de la carte. Le rendu donnait des cartes de 206 px au lieu de 216,
   une section de 368 au lieu de 378 à 1440 px, et de 838 au lieu de 868 à
   390 px (trois cartes empilées, trois fois 10 px). Deux classes suffisent à
   trancher. */
.service-block .service-block__title {
    margin: 0;
    padding-bottom: 10px;
    font-size: 20px;
    font-weight: 700;
    line-height: 20px;
}

/* --- 6.6 Section d'ouverture (blocks/page_intro.php) -------------------
   Respiration de section de 50 px (`custom_padding="50px||50px"`) et non 54, à
   toutes les largeurs de bureau ; zéro sous 981 px (`custom_padding_tablet` et
   `_phone` à « 0px||0px »). Les deux règles sont posées après celles du § 3,
   qu'elles doivent battre à spécificité égale.                              */

.page-intro {
    padding: 50px 0;
}

@media (max-width: 980px) {
    .page-intro {
        padding: 0;
    }
}

/* Le rythme de la rangée : 30 px entre deux modules voisins, la marge d'un
   module Divi. C'est le seul écart entre le titre, le texte, la photo et la
   liste — et il tombe juste aux deux largeurs relevées (le détail des sommes
   est en tête de blocks/page_intro.php). */
.page-intro > .row > * + * {
    margin-top: 30px;
}

/* Écrit bien que ce soit déjà le défaut des titres au § 2 : c'est cette
   retombée de 10 px, et elle seule, qui sépare le titre du texte — les 30 px
   du rythme s'ajoutent après elle. */
.page-intro__heading {
    padding-bottom: 10px;
}

.page-intro__media img {
    display: block;
    width: 100%;
    height: auto;
}

/* La liste des prestations ne demande RIEN ici : ses cotes — interligne de
   26 px, aucune marge entre les éléments, retrait de 1 em — sont celles de
   toutes les listes du site, et elles sont au § 2. C'est cette section qui les
   a fait mesurer (cinq lignes à 26 px plus 1 em font les 144 px relevés entre
   les deux paragraphes qui encadrent la liste). */

/* --- 6.7 « Nos services » (blocks/nos_services.php) --------------------
   Section de la bibliothèque 2974, posée telle quelle sur l'accueil et sur les
   trois pages de services : elle mesure 505,2 px à 1440 px et 1651,8 px à
   390 px sur les QUATRE pages. Décomposition des 505,2 px :
     54    respiration de section
     27    respiration haute de la rangée 1 (sa respiration basse est à 0 :
           custom_padding="||0px|")
     23,8  le titre « Nos services » — 26 px sur l'interligne du corps, hérité
     20    sa marge basse (custom_margin="||20px")
      5    le filet
     27    respiration haute de la rangée 2
    267,4  la carte (18 + 135,4 + 30 + 54 + 10 + 20)
     27    respiration basse de la rangée 2
     54    respiration de section
   Total : 505,2. Mesuré : 505,2.                                            */

.services {
    position: relative;
    /* Le mélange de la photo doit se faire avec le bleu nuit de CETTE section
       et de rien d'autre : sans contexte d'isolement, mix-blend-mode remonte
       jusqu'au fond de la page et le bleu disparaît. */
    isolation: isolate;
    background: var(--navy);
    padding: 4% 0;
}

@media (min-width: 1350px) {
    .services {
        padding: 54px 0;
    }
}

@media (max-width: 980px) {
    .services {
        padding: 50px 0;
    }
}

/* L'original supprime la respiration de cette section sur téléphone
   (custom_padding_phone="0px||0px") : mesuré 0 à 390 px, la photo de fond
   touche la section précédente et la suivante. */
@media (max-width: 767px) {
    .services {
        padding: 0;
    }
}

/* `background_blend="overlay"` de l'original : la photo du clavier n'est pas
   posée SUR le bleu nuit, elle y est mêlée. C'est ce mélange qui donne les
   bleus clairs relevés dans la capture — #354a6a dans un coin, #304362 sur le
   clavier — et non le #283851 du fond seul. */
.services__photo {
    mix-blend-mode: overlay;
}

/* Deux classes pour passer devant `.section > .row` du § 3. La rangée du titre
   est une rangée ORDINAIRE (plafonnée à 1080 px) : c'est la rangée des cartes,
   et elle seule, qui est en pleine largeur. Le filet fait 5 % de la rangée,
   donc 54 px et non 57,6. */
.services .services__head {
    padding: 2% 0 0;
}

@media (min-width: 1350px) {
    .services .services__head {
        padding: 27px 0 0;
    }
}

@media (max-width: 980px) {
    .services .services__head {
        padding: 30px 0 0;
    }
}

/* ÉCART ASSUMÉ, sans effet sur le rendu : c'est un <h2>. Dans l'original, ce
   titre est un module de texte sans balise de titre — à l'œil un titre de
   section, pour un lecteur d'écran rien du tout. Les cotes, elles, sont celles
   du module : 26 px, graisse 700, blanc, ombre de texte, centré, et surtout un
   interligne de 23,8 px HÉRITÉ du corps (les h2 du site sont en 26/26). */
.services__title {
    margin: 0 0 20px;
    padding: 0;
    color: var(--white);
    font-size: 26px;
    font-weight: 700;
    line-height: 23.8px;
    text-align: center;
    text-shadow: var(--text-shadow);
}

.services__rule {
    display: block;
    width: 5%;
    height: 5px;
    margin: 0 auto;
    background: var(--white);
}

.services .services__cards {
    padding: 2% 0;
}

@media (min-width: 1350px) {
    .services .services__cards {
        padding: 27px 0;
    }
}

@media (max-width: 980px) {
    .services .services__cards {
        padding: 30px 0;
    }
}

/* La cellule porte la largeur de colonne (17,6 % en gouttière 2, soit
   202,75 px dans une rangée de 1152) ; la carte, elle, doit remplir toute la
   hauteur de la rangée — `make_equal` de l'original. */
.services__cell {
    display: flex;
}

/* La carte : 18 px de blanc au-dessus de l'image, puis l'image, 30 px, le
   titre, sa retombée de 10 px, et 20 px de remplissage bas
   (custom_padding="||20px"). Les 18 px ne sont pas une invention : à 1440 px
   la carte commence à 2968,1 et l'image à 2986,1 ; à 390 px, 2810,5 et
   2828,5. Deux largeurs, le même écart. */
.service-item {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 18px 0 20px;
    background: var(--white);
    color: var(--navy);
    text-align: center;
    transition: transform var(--transition);
}

/* Survol relevé : la carte grossit de 10 % en 300 ms (charte § 10). Le
   z-index la fait passer devant ses voisines, qui seraient sinon peintes
   par-dessus elle. Le focus reçoit le même agrandissement : au clavier, on
   doit voir ce qu'on vise. */
.service-item:hover,
.service-item:focus-visible {
    transform: scale(1.1);
    z-index: 3;
}

.service-item__media {
    display: block;
}

/* `max-width` et non `width` : à 1440 px l'image est bornée par la carte
   (202,75 px, rendu mesuré 203 × 135) ; à 390 px la carte fait 312 px et
   l'image reprend sa taille naturelle de 268 × 179, CENTRÉE — ce que la
   capture montre et qu'un width: 100% aurait étiré, faussant du même coup la
   hauteur de la section. */
.service-item__media img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0 auto;
}

/* Balise h3 (l'original : h4 après un h1, donc un niveau sauté). Cotes du
   module : 18 px sur 18 px, graisse 600, bleu nuit, centré ; 30 px le séparent
   de l'image, 10 px de retombée le suivent. */
.service-item__title {
    margin: 30px 0 0;
    padding-bottom: 10px;
    color: var(--navy);
    font-size: 18px;
    font-weight: 600;
    line-height: 18px;
}

@media (max-width: 980px) {
    /* Relevé à 390 px : 12 px entre deux cartes empilées, et non les 30 px que
       le § 9 donne aux colonnes ordinaires — c'est la gouttière 2 (3 %) de
       cette rangée-là. Cartes de 275 px, pas de 293 : les 5 cartes et leurs
       4 écarts donnent bien les 1651,8 px mesurés. */
    .services .cols--5 > * {
        margin-bottom: 12px;
    }

    .services .cols--5 > *:last-child {
        margin-bottom: 0;
    }
}

/* --- 6.8 Carte et photo (blocks/card_split.php) ------------------------
   Une seule construction pour trois sections de l'original — accueil s6 (les
   deux boutiques), section 3 des pages de services (#part2), et section 1 des
   pages de services (le titre de la page dans la carte). Elles partagent la
   rangée 1/2 - 1/2 en gouttière 3 (5,5 %), le centrage vertical
   (`ds-vertical-align` + `make_equal`), la carte blanche à 30 px de
   remplissage et le décalage de 135 px de la carte VERS la photo. Ce qui les
   sépare tient en trois variantes, mesurées page par page (voir le tableau en
   tête de blocks/card_split.php).

   Vérification (accueil, 1440 px) : section à 3316,5, carte à
   3316,5 + 54 + 27 = 3397,5 ; titre à 3427,5 (+30 de remplissage) ; premier
   paragraphe à 3463,5 (+26 de titre +10 de retombée). Mesuré : 3427,5 et
   3463,5.                                                                   */

.card-split {
    padding: 4% 0;
}

@media (min-width: 1350px) {
    .card-split {
        padding: 54px 0;
    }
}

/* Sous 981 px, l'original met la respiration de ces sections à zéro
   (custom_padding_tablet="0px||0px") : mesuré 0 à 390 px. */
@media (max-width: 980px) {
    .card-split {
        padding: 0;
    }
}

.card-split__row {
    display: flex;
    flex-wrap: wrap;
    /* `ds-vertical-align` du thème enfant : le contenu de chaque colonne est
       centré verticalement. C'est ce qui place la photo de l'accueil à 3551,9
       (colonne de 564,5 px, photo de 256) et qui fait descendre le titre de la
       page Maintenance à 333,3 px, sa photo étant en hauteur. */
    align-items: center;
}

.card-split__body {
    position: relative;
    z-index: 2;
    width: 47.25%;
    padding: 30px;
    background: var(--white);
    box-shadow: var(--box-shadow);
    /* Décalage relevé (transform_translate="135px|0px", z_index 24) : la carte
       chevauche la photo. Une transformation et non une marge — la boîte ne
       bouge pas dans le flux, exactement comme dans l'original. */
    transform: translateX(135px);
}

.card-split__media {
    width: 47.25%;
    margin-left: 5.5%;
}

/* Photo à 75 % de sa colonne : rendu mesuré 383 × 256 pour une colonne de
   510,3 px, sur l'accueil comme sur la section 3 des pages de services. */
.card-split__media img {
    display: block;
    width: 75%;
    height: auto;
}

/* Variante « reverse » : photo à gauche. */
.card-split--reverse .card-split__row {
    flex-direction: row-reverse;
}

.card-split--reverse .card-split__body {
    transform: translateX(-135px);
}

.card-split--reverse .card-split__media {
    margin-left: 0;
    margin-right: 5.5%;
}

/* Variante « flat » : les deux modules de la première section des pages de
   services ne portent aucun box_shadow, contrairement à ceux des sections 3
   et 6. */
.card-split--flat .card-split__body {
    box-shadow: none;
}

/* Variante « title » : le titre de la page est dans la carte. Respiration de
   section de 50 px (custom_padding="50px||50px") et non 54 ; placée après la
   règle des 54 px pour l'emporter à spécificité égale. */
.card-split--title {
    padding: 50px 0;
}

@media (max-width: 980px) {
    .card-split--title {
        padding: 0;
    }
}

/* L'original empile ici DEUX modules blancs jointifs de 30 px chacun : le
   titre, puis le texte. Entre le bas du titre et le texte il y a donc
   30 + 30 = 60 px de plus que dans une carte ordinaire. Vérifié sur
   Réparation : h1 à 282,4, texte à 384,4 = 282,4 + 32 + 10 + 60. Une seule
   carte et cette marge donnent le même rendu — et une seule ombre, quand la
   variante en porte une. */
.card-split--title .card-split__heading {
    margin-bottom: 60px;
}

/* Photo pleine colonne : rendu mesuré 510 × 341 sur Vente, 510 × 764 sur
   Maintenance (l'et_pb_image de ces sections ne fixe aucune largeur). */
.card-split--title .card-split__media img {
    width: 100%;
}

@media (max-width: 980px) {
    .card-split__body {
        width: 100%;
        transform: none;
    }

    /* Répété malgré la règle ci-dessus : `.card-split--reverse
       .card-split__body` compte deux classes et l'emporterait sinon sur une
       seule, media query ou pas. */
    .card-split--reverse .card-split__body {
        transform: none;
    }

    /* La colonne de la photo est `disabled_on="on|on|off"` dans l'original :
       la photo ne s'affiche NI sur téléphone NI sur tablette. Reproduit ;
       avec loading="lazy", le fichier n'est alors pas téléchargé. */
    .card-split__media {
        display: none;
    }

    /* LES 30 px SOUS LA CARTE, trouvés en mesurant et non en lisant : les
       TROIS sections 3 des pages de services mesuraient exactement 30 px de
       moins que l'original — Réparation 852,5 pour 882,5 relevés, Maintenance
       1188,1 pour 1218,1, Vente 926,1 pour 956,1. Trois pages, le même écart
       au dixième : ce n'est pas du texte, c'est une règle.

       L'explication est dans l'ordre des colonnes. Sous 981 px, Divi empile
       les colonnes et leur donne 30 px de marge basse, sauf à la DERNIÈRE. Or
       la colonne de la photo est `disabled_on="on|on|off"` : elle ne s'affiche
       pas, mais elle reste la dernière du document. C'est donc elle qui reçoit
       l'exemption — en ne prenant aucune place — et la colonne de TEXTE, qui
       la précède, garde ses 30 px. La même règle de Divi explique les 30 px de
       la rangée bleue mobile (§ 4).

       D'où la condition, qui est celle du relevé et pas une astuce : seules
       les sections où la photo SUIT la carte sont concernées. Dans la
       section 1 des trois pages (variante « reverse »), la photo est la
       première colonne et la carte la dernière : aucune marge, et c'est bien
       pourquoi les trois sections 1 tombent juste à 390 px (888,9 / 801,1 /
       662,1, exactement les cotes relevées) sans rien écrire. La sixième
       section de l'accueil, même construction, mesure 1039,7 px comme
       l'original grâce à cette règle. */
    .card-split:not(.card-split--reverse) .card-split__body {
        margin-bottom: 30px;
    }
}

@media (max-width: 767px) {
    /* Variante « title » seulement : l'original y met le remplissage de la
       carte à zéro sur téléphone (custom_padding_phone="0px|0px|0px|0px"), et
       le titre touche le bord de la rangée — ce que montre la capture à
       390 px. Les cartes des sections 3 et 6, elles, gardent leurs 30 px. */
    .card-split--title .card-split__body {
        padding: 0;
    }

    .card-split--title .card-split__heading {
        margin-bottom: 0;
    }
}

/* Les listes des cartes — les six prestations de l'intervention technique de
   Maintenance — ne demandent rien ici : leurs cotes sont celles de toutes les
   listes du site (§ 2). */

/* --- 6.9 Galerie et visionneuse (blocks/gallery.php) -------------------
   Décomposition des 802,9 px mesurés sur la section de contenu à 1440 px :
     54 (section) + 27 (rangée) + 32 (h1) + 10 (sa retombée, la SEULE
     respiration entre le titre et la grille) + 599,0 (la grille : 3 rangées de
     160,07 + 2 gouttières de 59,4) + 27 + 54 = 803,0 pour 802,9 mesurés (le
     dixième vient de l'arrondi du rendu : 225,45 × 284/400 = 160,07 px, que
     Chrome rapporte à 160).

   La grille de l'original est celle de Divi en gouttière 3 : quatre colonnes
   de 20,875 % et des gouttières de 5,5 %, qui tombent juste — 4 × 20,875 +
   3 × 5,5 = 100. Sur une rangée de 1080 px : colonnes de 225,45 (rendu 225),
   gouttières de 59,4. Le relevé le confirme aux deux axes : les douze photos
   se rangent 4 × 3, les trois rangées commencent à 298,4, 517,8 et 737,3 px,
   soit un pas de 219,4 = 160,07 + 59,4.

   POURQUOI DES FLOTTANTS ET NON UNE GRILLE CSS. La base disposait la galerie
   en `display: grid`, ce qui convient à Raon et à ses gouttières de 2 px, mais
   interdit de placer celles de Spin, qui sont en POURCENTAGE :
     - une marge en pourcentage posée sur un élément de grille se calcule sur
       son AIRE de grille (225,45 px), pas sur la rangée : 5,5 % y donneraient
       12,4 px au lieu de 59,4 ;
     - `row-gap: 5.5%` ne vaut rien non plus, un pourcentage de gouttière
       verticale se résolvant sur une hauteur indéfinie, donc sur zéro.
   Les flottants de Divi, eux, calculent TOUS leurs pourcentages sur la largeur
   de la rangée, à n'importe quelle largeur de fenêtre. C'est la construction
   de l'original, reprise telle quelle : elle est exacte entre 981 et 1350 px,
   là où la rangée suit la fenêtre, alors qu'une gouttière écrite en pixels ne
   le serait qu'au-delà de 1350.                                             */

/* Les tuiles flottent : sans cela la section se refermerait sur une hauteur
   nulle et le pied remonterait sous le titre. */
.gallery::after {
    content: "";
    display: table;
    clear: both;
}

.gallery__item {
    float: left;
    width: 20.875%;
    margin: 0 5.5% 5.5% 0;
    position: relative;
    line-height: 0;
    overflow: hidden;
    background: var(--navy);
}

/* Quatre par rangée : la quatrième ne porte pas de gouttière à droite, sinon
   la rangée déborderait et la cinquième photo passerait à la ligne seule. */
.gallery__item:nth-child(4n) {
    margin-right: 0;
}

/* Dernière rangée sans retombée : la somme de l'original le prouve (54 + 27 +
   32 + 10 + 599 + 27 + 54 = 802,9 sans rien de plus sous les photos). Les
   douze photos font exactement trois rangées de quatre, donc les quatre
   derniers enfants SONT la dernière rangée. */
.gallery__item:nth-last-child(-n + 4) {
    margin-bottom: 0;
}

/* La vignette à son propre format. La base lui imposait `aspect-ratio:
   268 / 179` — les vignettes de Raon. Celles de Spin sont les recadrages
   WordPress 400 × 284 de l'original, affichés sans rognage : mesuré 225 × 160
   à 1440, et 225,45 × 284/400 = 160,07.
   Le format est ÉCRIT (400 / 284) et non laissé à `auto`, et c'est le rendu
   qui l'a imposé : en `auto`, la hauteur suit le format de la variante
   réellement servie, dont les pixels sont arrondis — la variante de 320 px
   fait 320 × 227 au lieu de 320 × 227,2, soit un format de 1,4097 au lieu de
   1,40845. Chaque rangée perdait 0,15 px et la grille tombait à 598,5 px au
   lieu de 599,0. Le format du recadrage, lui, ne dépend pas de la variante :
   la page fait la même hauteur quelle que soit celle que le navigateur
   choisit, et le rognage résiduel d'un millième reste invisible. */
.gallery__item img {
    width: 100%;
    height: auto;
    aspect-ratio: 400 / 284;
    object-fit: cover;
    transition: transform var(--transition), opacity var(--transition);
}

/* Le voile du survol, relevé à rgba(40,56,81,.6) : il n'est pas peint par une
   couche posée sur la photo mais obtenu en laissant paraître le fond bleu nuit
   de la tuile à travers elle — 40 % d'opacité sur l'image donnent 60 % de
   bleu. Une couche en plus aurait demandé un pseudo-élément et un empilement ;
   une propriété suffit. */
.gallery__item:hover img {
    opacity: 0.4;
}

@media (max-width: 980px) {
    /* Relevé à 390 px : une photo par rangée, large de 312 px (les 80 % de la
       rangée), et 35,9 px entre deux photos. La base en mettait trois par
       rangée sous 981 px et deux sous 768 px : ce sont les cotes de Raon.
       Le seuil est unique, à 981 px (décision du 11 septembre 2026), et c'est
       aussi ce que les deux relevés permettent d'affirmer : quatre colonnes à
       1440 et une à 390, sans aucune capture entre 768 et 980 px qui
       justifierait un nombre intermédiaire.
       La gouttière est écrite en pixels et non en pourcentage : 35,9 px est la
       valeur mesurée, et une seule largeur de téléphone a été relevée — rien
       ne permet de dire si l'original la calculait sur la rangée (ce serait
       11,5 %). Le pixel est donc exact là où l'on a mesuré, et stable
       ailleurs. */
    .gallery__item {
        width: 100%;
        margin: 0 0 35.9px;
    }

    /* Répété pour reprendre la main sur la règle `:nth-last-child(-n + 4)`
       ci-dessus, qui compte la même spécificité et viserait, à une colonne,
       les QUATRE dernières photos. */
    .gallery__item:nth-last-child(-n + 4) {
        margin-bottom: 35.9px;
    }

    /* ÉCART ASSUMÉ, et il rapproche du relevé. À 390 px l'original laisse
       35,9 px de blanc SOUS la dernière photo (3232,8 px de section mesurés
       contre 3196,9 sans cette retombée) : Divi n'annule la marge de la
       dernière rangée qu'au-dessus de 981 px. C'est un reliquat, pas une
       intention — et le reproduire éloignerait du modèle plutôt que l'inverse.
       Reste, à 390 px, le seul écart de cette page : nos douze vignettes sont
       le recadrage 400 × 284 affiché en 312 × 221,5, soit 3053,1 px de grille,
       là où l'original CHANGE de fichier sous 480 px (son `sizes` vaut
       « (max-width:479px) 479px, 100vw », qui sert la photo entière de 960 px)
       et affiche onze photos en 312 × 208 plus une carrée en 312 × 312, soit
       2994,9 px. Servir la même vignette à toutes les largeurs garde des
       rangées égales, évite de télécharger douze photos de 960 px sur un
       téléphone, et coûte 22,3 px de haut sur la page. */
    .gallery__item:last-child {
        margin-bottom: 0;
    }
}

/* La visionneuse est un <dialog> natif piloté par assets/js/site.js. Elle
   n'existe pas dans l'original, qui ouvrait la lightbox de Divi (magnific
   popup, 40 Ko de script) : même service, sans dépendance. */
.lightbox {
    border: 0;
    padding: 0;
    max-width: 100vw;
    max-height: 100vh;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.92);
}

.lightbox::backdrop {
    background: rgba(0, 0, 0, 0.92);
}

.lightbox__figure {
    margin: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    padding: 40px 60px;
}

.lightbox__figure img {
    max-width: 100%;
    max-height: calc(100vh - 140px);
    width: auto;
    object-fit: contain;
}

.lightbox__figure figcaption {
    color: var(--white);
    font-size: 14px;
    text-align: center;
}

.lightbox__close,
.lightbox__prev,
.lightbox__next {
    position: absolute;
    background: none;
    border: 0;
    color: var(--white);
    cursor: pointer;
    padding: 12px;
    line-height: 0;
}

.lightbox__close {
    top: 12px;
    right: 16px;
}

.lightbox__prev {
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
}

.lightbox__next {
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
}

.lightbox svg {
    width: 26px;
    height: 26px;
    fill: currentColor;
}

@media (max-width: 767px) {
    /* Les boutons de navigation sont au bord de l'écran : la photo leur laisse
       la place plutôt que de passer dessous. */
    .lightbox__figure {
        padding: 60px 16px 30px;
    }
}

/* --- 6.10 Plan du site (blocks/sitemap.php) ----------------------------
   Décomposition des 1069,8 px mesurés sur l'original à 1440 px :
     54 + 27 + 32 (h1) + 10 + 26 (le h2 « Pages ») + 10 + 312 (douze pages à
     26 px de pas) + 37,8 (la fin du premier bloc et le <br> qui le suit)
     + 26 + 10 + … (le h2 « Articles par catégorie » et les quinze articles)
     + 27 + 54.
   Les repères mesurés : h1 à 256,4 px, « Pages » à 298,4 (= 256,4 + 32 + 10),
   la liste à 334,4 (= 298,4 + 26 + 10) et « Articles par catégorie » à 684,2
   (= 334,4 + 12 × 26 + 37,8). À 390 px, les mêmes écarts à partir d'un h1 à
   220,6.

   Notre page ne liste que les DIX pages servies (ni « Login Designer », ni
   « Actualités », ni les quinze articles, ni la catégorie) : sa section de
   contenu tombe donc à
     54 + 27 + 32 + 10 + 26 + 10 + (10 × 26 = 260) + 23 + 27 + 54 = 523 px
   à 1440, et à 521 px à 390 (50/30 de respirations, mêmes blocs, aucun titre
   ne passant à la ligne dans une colonne de 298 px utiles).

   La carte blanche de Raon — 40 px de remplissage, ombre portée, fond gris de
   service, grille à deux colonnes — n'existe pas chez Spin : le plan est une
   liste nue sur blanc (la section mesurée est en rgb(255,255,255) et le blanc
   domine la capture). La classe `.sitemap` ne demande donc plus AUCUNE règle,
   et celles qui l'habillaient ont disparu avec la carte ; la seconde colonne
   n'a de toute façon plus d'objet, sitemap.xml et robots.txt n'étant plus
   présentés au visiteur.                                                    */

/* `.sitemap-section` n'est pas un `.section` : elle ne reçoit aucune
   respiration du § 3, et sans ces règles le titre toucherait l'en-tête. Ce
   sont les respirations de toutes les pages du site. */
.sitemap-section {
    background: var(--white);
    padding: 4% 0;
}

.sitemap-section > .row {
    padding: 2% 0;
}

@media (min-width: 1350px) {
    .sitemap-section {
        padding: 54px 0;
    }

    .sitemap-section > .row {
        padding: 27px 0;
    }
}

@media (max-width: 980px) {
    .sitemap-section {
        padding: 50px 0;
    }

    .sitemap-section > .row {
        padding: 30px 0;
    }
}

/* Le h1 de cette page est rendu par le bloc, pas par blocks/page_title : il
   reçoit donc ici les cotes du titre de page — 32 px sur 32, graisse 700,
   bleu nuit, et surtout la retombée de 10 px, et non les 26 px de la carte de
   Raon. */
.sitemap__title {
    padding-bottom: 10px;
    color: var(--navy);
    font-size: 32px;
    font-weight: 700;
    line-height: 32px;
}

/* Le h2 « Pages » est NOIR dans l'original (relevé rgb(0, 0, 0)) : le
   customizer du site met tous les titres en noir, et ce module de texte ne
   redéfinit que la couleur du texte et des liens. */
.sitemap h2 {
    padding-bottom: 10px;
    color: var(--ink);
    font-size: 26px;
    line-height: 26px;
}

/* La règle de liste du thème d'origine, dont le § 2 tient déjà l'interligne de
   26 px et le retrait de 1 em. Ne restent ici que les 23 px SOUS la liste —
   `padding: 0 0 23px 1em` de Divi — au lieu du 1 em (14 px) mesuré ailleurs :
   sans eux, la section tombait à 514 px au lieu des 523 attendus. Et la marge
   à zéro, parce que le 1 em du § 2 n'a rien à justifier ici, la liste étant le
   dernier élément de la page. */
.sitemap ul {
    margin: 0;
    padding: 0 0 23px 1em;
}

.sitemap a {
    color: var(--navy);
    font-size: 14px;
    line-height: 26px;
}

/* --- 6.11 Pages légales (blocks/legal.php) -----------------------------
   Relevé (spinwork/live/pages/mentions-legales_{1440,390}.json et
   politique-de-confidentialite_{1440,390}.json, styles calculés) :
     section de contenu  54 px de respiration à 1440, 50 px sous 981 — le § 3
     colonne de texte    aucune respiration intérieure : le h1 tombe à
                         54 + 27 = 81 px du haut de la section à 1440 (h1
                         relevé à 256,4 px pour une section à 175,4). NE PAS
                         reprendre les 60 px de retrait du site Raon.
     h1                  32 px / 32 px, graisse 700, bleu nuit — le § 2
     h2 26/26, h3 22/22, h4 18/18, h5 16/16 — NOIRS, et non bleu nuit
     paragraphes         14 px / 23,8 px, noir — le § 2

   DEUX CORRECTIONS de la base ici, et une TROISIÈME trouvée à la fusion :
   la base posait `.legal h1 { padding-bottom: 24px }`, une cote du site Raon
   qui contredisait la retombée de 10 px que TOUS les titres de l'original
   portent, la page légale comme les autres. Elle a été retirée ; l'effet
   mesuré est de −14 px sur chacune des deux pages.
   Les listes, elles, suivent maintenant la règle du site (26 px d'interligne,
   § 2) : la base leur écrivait ici un interligne de 23,8 px, alors que la
   règle de liste du thème d'origine — `.et-l--body ul` — couvre le corps de
   page entier, pages légales incluses.                                      */

/* Les titres INTÉRIEURS sont noirs sur l'original, comme le texte qui les
   suit : ce sont les titres par défaut du contenu, que le thème d'origine ne
   colorait pas.
   Graisse : l'original DÉCLARE 500 sur ces titres, mais ne chargeait aucune
   face 500 — le navigateur les rendait donc avec la face régulière (relevé :
   « Open Sans (webfont) », et non « Open Sans SemiBold », sur les 21 titres de
   la politique). Notre Open Sans est VARIABLE de 300 à 800 : écrire 500
   donnerait une vraie graisse 500, plus grasse que l'original. On écrit la
   graisse RENDUE, 400 — même raisonnement que le corps de page au § 2. Sans
   cette ligne, les titres héritent du 600 des titres du site. */
.legal h2,
.legal h3,
.legal h4,
.legal h5 {
    padding: 0 0 10px;
    color: var(--ink);
    font-weight: 400;
}

/* Le § 2 compose les h4 sur 1,4 em (25,2 px) parce que les h4 du contenu
   éditorial sont des sous-titres de paragraphe. Sur les pages légales, le h4
   suit la règle des autres titres — interligne égal à la taille. Quatre h4 sur
   la politique d'origine : 4 × 7,2 px d'écart, soit 29 px de page. */
.legal h4 {
    line-height: 18px;
}

/* L'original marquait certains intitulés par un style en ligne
   (<p style="font-weight:bold">), interdit par la politique de sécurité du
   nouveau site : ils portent donc une classe. */
.legal__strong {
    font-weight: 700;
}

.legal a {
    word-break: break-word;
}

/* Les tableaux défilent dans leur conteneur : sur l'original ils faisaient
   déborder toute la page en mobile. Aucune des deux pages légales de Spin n'en
   porte aujourd'hui ; les règles restent pour un contenu futur. */
.legal .table-scroll {
    overflow-x: auto;
    margin: 0 0 1.4em;
    -webkit-overflow-scrolling: touch;
}

.legal table {
    width: 100%;
    border-collapse: collapse;
    min-width: 560px;
    font-size: 13px;
    margin-bottom: 15px;
}

.legal table td,
.legal table th {
    padding: 6px;
    border: 1px solid var(--ink);
    text-align: left;
    vertical-align: top;
}

/* --- 6.12 Appel à l'action, et bandeau d'avis (blocks/cta.php) ---------
   Relevé sur l'accueil de l'original : une rangée bordée d'un filet BLANC de
   2 px sur le fond bleu nuit, avec 40 px de respiration intérieure, un titre
   en 18 px italique capitales avec ombre, un texte en 16 px et un bouton
   blanc. Repris tel quel pour les trois pages de services, qui n'avaient aucun
   lien vers le contact ni l'une vers l'autre.

   La section retombe sur ses 313,8 px mesurés :
     54 + 2 (filet) + 40 + 18 (titre) + 10 + 27,2 (texte 16 px sur 1,7 em)
     + 16,6 + 50 (bouton) + 40 + 2 + 54 = 313,8.

   La MISE EN PAGE est celle de Spin et non celle de Raon, dont la structure
   mettait le titre à gauche et le bouton à droite (`justify-content:
   space-between`) : l'original de Spin empile et CENTRE — titre, phrase,
   bouton. Sans cela, titre et bouton partagent une ligne et la section perd
   80 px.

   DEUX INTERLIGNES, et c'est la démonstration la plus nette de l'utilité de
   rendre un bloc avant de le croire juste. Le premier jet mesurait 318,4 px au
   lieu de 313,8, et les 4,6 px se décomposaient en deux erreurs de sens
   contraire :
     +8    la taille du titre passait à 18 px mais pas son interligne, resté
           aux 26 px en dur du h2 : le titre occupait 26 + 10 = 36 px là où
           l'original en occupe 18 + 10 = 28 ;
     -3,4  le texte de l'encadré héritait de l'interligne du corps, calculé
           une fois pour toutes à 23,8 px (1,7 em de 14 px). Divi, lui,
           applique 1,7 à la taille PROPRE de ce texte, 16 px, soit 27,2.
   Un interligne écrit en `em` se calcule chez le parent et s'hérite en
   PIXELS : le redéclarer est le seul moyen qu'il suive la taille de l'enfant.

   Le bouton est `btn--light` dans le gabarit, et non `btn--navy` : la capture
   montre un bouton ÉVIDÉ à filet blanc, et le sondage de pixels le confirme —
   #283851 à l'intérieur (le fond de la section, donc transparent), #ffffff sur
   le bord supérieur, à y = 921 exactement là où le calcul le place.          */

.cta {
    background: var(--navy);
    color: var(--white);
}

/* Rangée à zéro : custom_padding="0px||0px" sur la rangée de l'original. Le
   filet de 2 px est donc collé à la respiration de la section. */
.cta > .row {
    padding: 0;
}

/* 40 px EN HAUT ET EN BAS À TOUTES LES LARGEURS, et c'est mesuré : à 390 px le
   titre de l'encadré est relevé à 232,6 px, soit 140,6 (en-tête mobile) + 50
   (section) + 2 (filet) + 40. La base réduisait ce remplissage à 24 px sous
   981 px et à 20 px sous 480 px — les cotes de Raon —, et la feuille de
   composants les annulait par accident, en écrivant `padding: 40px` sans media
   query. Ce qui était juste par hasard est maintenant écrit exprès, mais pour
   le seul axe VERTICAL : c'est celui que le relevé tient.

   Le remplissage de CÔTÉ, lui, descend à 12 px sous 480 px — la règle qui suit
   celle-ci, écrite le 12 septembre 2026. Aucune cote verticale ne le contraint,
   et c'est lui seul qui manquait au bouton.

   Le bandeau d'avis, plus bas dans ce même §, a reçu la même correction le même
   jour, sur ses deux axes : son libellé est plus long que « Nos coordonnées »
   et il passait à deux lignes sur téléphone. Les deux blocs ne partagent donc
   pas leur remplissage sous 981 px (24 px pour le bandeau, 40 px ici) ; sous
   480 px ils partagent les 12 px de côté, et au-dessus de 980 px ils sont
   identiques. */
.cta__panel {
    display: block;
    padding: 40px;
    border: 2px solid var(--white);
    text-align: center;
}

/* --- Le remplissage de CÔTÉ sur téléphone : 12 px sous 480 px ------------
   LE DÉFAUT, mesuré sur les QUATRE pages qui portent cet encadré. À 390 px la
   place intérieure valait 0,8 × 390 − 80 (remplissage) − 4 (filet) = 228 px, et
   le libellé « Demander un devis » de /reparation/ en demande 229,1 : 185,1 px
   de texte en 20 px, plus les 40 px de remplissage du bouton et ses 4 px de
   filet. Pour 1,1 px, le bouton passait à DEUX lignes — 84 px de haut au lieu
   de 50. Relevé page par page (place intérieure → hauteur du bouton) :
     /reparation/   besoin 229,1 : cassé à 390 (228), 375 (216), 360 (204) et
                    320 (172) — les quatre largeurs de téléphone ;
     /              « Nos coordonnées », besoin 210,5 : tenait à 390 (17,5 px de
                    marge) et à 375 avec 5,5 px seulement, cassé dès 360 ;
     /maintenance/  « Nous contacter », besoin 189,1 : cassé à 320 (172) ;
     /vente/        même libellé, même cas.
   Les QUATRE pages sont donc touchées, et non deux : la revue adverse n'avait
   pas mesuré Maintenance ni Vente.

   POURQUOI LE SEUL AXE HORIZONTAL : les 40 px verticaux sont une cote de
   l'original, tenue par le titre de l'encadré de l'accueil relevé à 232,6 px à
   390 px = 140,6 + 50 + 2 + 40 (spinwork/live/pages/accueil_390.json,
   typography.headings[2]). Cette règle ne la déplace pas d'un dixième : titre
   vérifié à 232,6 px à 390, 375, 360, 348 et 320 px, avant comme après.

   POURQUOI 12 px : c'est la valeur que porte déjà le bandeau `.avis-google`
   sous 480 px, si bien que les deux encadrés bleu nuit jumeaux ont enfin UN
   seul comportement sur téléphone ; et c'est celle qui laisse la plus grande
   marge au pire libellé — 54,9 px à 390, 42,9 à 375, 30,9 à 360, très au-delà
   des 8 px de garde qu'exige une variation de rendu de police. Valeurs
   ESSAYÉES ET ABANDONNÉES, toutes mesurées sur « Demander un devis » : 24 px ne
   laissent que 6,9 px à 360 px (sous la garde) et rouvrent le défaut à 348 ;
   20 px tombent à 5,3 px à 348 px ; 16 px tiennent à 360 mais n'apportent rien
   de plus à 320, où le défaut subsiste de toute façon.

   LA BASCULE EST À 479 px ET PAS À 480, et c'est mesuré : la même réduction
   posée à 480 px y raccourcirait /reparation/ de 27,2 px (encadré 321,8 →
   294,6, page 4915 → 4888) en réenroulant sa phrase. Au-dessus, RIEN ne bouge —
   vérifié en posant la règle sans media query du tout à 1440, 1024, 981, 980 et
   768 px : aucune hauteur ne change sur les quatre pages.

   CE QUE ÇA DÉPLACE, valeur abandonnée citée comme le veut la règle du site.
   Mesuré le 16 septembre 2026 à 390 px : la page servie, puis la même page
   après retrait de CETTE seule règle du CSSOM, sans toucher au fichier :
     /reparation/   perd 52,0 px (page 5364 → 5312, encadré 373,8 → 321,8) :
                    le titre « Un ordinateur à réparer ? » repasse de deux
                    lignes à une (46 → 28 px) et le bouton aussi (84 → 50) ;
     /vente/        perd 45,2 px (page 5219 → 5174, encadré 339,8 → 294,6) :
                    le titre « Un conseil avant d’acheter ? » repasse de deux
                    lignes à une (46 → 28 px) et la phrase de trois à deux
                    (81,6 → 54,4) ;
     /maintenance/  ne bouge PAS : page 5543 px et encadré 294,6 avant comme
                    après, son titre et sa phrase tenant déjà dans 228 px.
   Deux encadrés rétrécissent donc, et non trois comme l'écrivait ce
   commentaire. Ces encadrés, nous les avons ajoutés (décisions du 11 septembre
   2026, § 2) : aucun relevé ne les contraint. Une hauteur de page à 390 px
   relevée AVANT cette règle est périmée sur ces deux pages et sur l'accueil :
   content/pages/vente.php en portait trois, corrigées le même jour.
   Et l'accueil perd 27,2 px à 390 px (page 6716 → 6689), parce que sa phrase
   dispose de 284 px au lieu de 228 et retombe de quatre lignes à trois. C'est
   une conséquence HORIZONTALE et non verticale : sa section passe de 387,4 px à
   360,2 px quand l'original en mesure 377,2 (accueil_390.json, sections[2]) —
   elle était déjà à +10,2 px de l'original avant cette règle, elle est à
   −17,0 px après, et le seul point que le relevé fixe au dixième, le titre à
   232,6 px, ne bouge pas.

   Le relevé donne une SECONDE cote sur cet encadré à 390 px : le haut de son
   bouton, à 375,8 px (accueil_390.json, typography.buttons[2]). Notre bouton s'y
   posait à 386,0 px avant cette règle, il s'y pose à 358,8 px après : l'original
   est ENTRE les deux états, +10,2 puis −17,0 px, le même écart que la section.
   Aucun remplissage de côté ne tient les deux, et c'est arithmétique : à 40 px
   la phrase occupe quatre lignes (108,8 px), à 12 px elle en occupe trois
   (81,6), et l'original en occupe 98,6 — une valeur qu'on ne peut pas
   reconstituer ligne à ligne, la description de Divi n'étant pas un `<p>` et
   n'ayant donc aucune cote propre dans le relevé (typography.paragraphs ne la
   contient pas). Le bouton sur UNE ligne prime, comme pour le bandeau d'avis :
   décision du client du 12 septembre 2026.

   CE QUI RESTE, et qui ne se répare pas ici : à 320 px de fenêtre la place
   intérieure retombe à 228 px et « Demander un devis » en demande toujours
   229,1 — le même manque de 1,1 px, revenu à l'autre bout de l'échelle. Un
   bouton en PLEINE LARGEUR n'y changerait rien, c'est mesuré (bouton élargi à
   228 px, hauteur toujours 84) : les 229,1 px incluent les 40 px de
   remplissage du bouton lui-même. Il faudrait rogner `.btn`, partagé par tout
   le site, pour 1,1 px sur une seule largeur : hors de proportion, non écrit.
   Le bandeau d'avis a la même limite au même endroit (besoin 250,3, place
   228). */
@media (max-width: 479px) {
    .cta__panel {
        padding: 40px 12px;
    }
}

.cta h2 {
    color: var(--white);
    font-size: 18px;
    line-height: 18px;
    font-weight: 600;
    font-style: italic;
    text-transform: uppercase;
    text-shadow: var(--text-shadow);
}

.cta__text {
    font-size: 16px;
    line-height: 1.7em;
}

.cta__text p {
    margin: 0;
}

/* Colonne centrée, avec l'écart de 14 px entre le bouton et le lien, et les
   16,6 px relevés entre la phrase et le bouton. */
.cta__actions {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    margin-top: 16.6px;
}

.cta__link {
    margin: 0;
    padding: 0;
}

.cta__link a {
    color: var(--white);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Bandeau de la page Avis clients. Ses cotes ne sont pas inventées : ce sont
   celles de l'encadré ci-dessus — filet blanc de 2 px, 40 px de remplissage,
   contenu centré, bouton évidé de 50 px. Le site a donc UN seul bandeau bleu
   nuit, pas deux qui se ressemblent. Sur téléphone, en revanche, son
   remplissage n'est plus celui de l'encadré : voir la règle sous la base. Il
   vit dans le HTML éditorial de la page, d'où les deux règles de bouton qui
   reprennent la main sur `.prose a`.

   Pourquoi il n'est PAS rendu par le bloc cta, qui ferait le même effet : ce
   n'est plus la clé `target` qui manque au bloc — blocks/cta.php a reçu sa clé
   `external` le 12 septembre 2026 —, c'est le REMPLISSAGE qui a divergé le même
   jour. Sous 981 px ce bandeau descend à 24 px, puis à 20 px de haut et 12 px
   de côté sous 480 px, quand `.cta__panel` garde ses 40 px verticaux et ne cède
   que ses côtés. Le rendre par le bloc lui rendrait ces 40 px et rallongerait
   la page sur téléphone : la bascule demande une clé de variante et une
   mesure. */
.avis-google {
    padding: 40px;
    border: 2px solid var(--white);
    background: var(--navy);
    text-align: center;
}

/* --- Le remplissage sur téléphone : la cote relevée n'est PAS tenue ------
   C'est le seul endroit du site où une cote mesurée sur l'original cède, et
   ce n'est pas un arbitrage de style : c'est la DÉCISION DU CLIENT du
   12 septembre 2026, « Réduire », prise après lui avoir montré le bouton sur
   deux lignes. Le bouton sur UNE ligne prime désormais sur la cote.

   LA COTE RELEVÉE, pour qui reviendrait dessus : 40 px À TOUTES LES LARGEURS.
   Elle vient de l'encadré d'appel à l'action de l'ACCUEIL de l'original, dont
   le titre est relevé à 232,6 px à 390 px = 140,6 (en-tête mobile) + 50
   (section) + 2 (filet) + 40 (remplissage) — spinwork/live/pages/
   accueil_390.json, typography.headings[2]. Elle est donc TRANSPOSÉE ici :
   la page Avis clients de l'original ne portait aucun bandeau (sa seule
   section de corps : 50 px de respiration, aucun encadré, un bouton de livre
   d'or et la ligne « (Pas de message) »), si bien qu'aucune cote mesurée ne
   contraint ce bloc-ci directement.

   CE QUI EST MESURÉ ICI, et qui décide : le libellé « Lire et donner un avis »
   demande 250,3 px pour tenir sur une ligne — 206,3 px de texte en 20 px,
   plus 40 px de remplissage de bouton et 4 px de filet. Le bandeau fait 80 %
   de la fenêtre (la rangée) : 312 px à 390 px, 288 px à 360 px. Avec les
   40 px relevés, il ne restait que 228 px à 390 px et 204 px à 360 px, et le
   bouton faisait 84 px de haut au lieu de 50 — la page gagnait 66 px.

   Pourquoi 24 px, puis 20 px de haut et 12 px de côté :
     - 24 px sous 981 px et 20 px sous 480 px sont les cotes que portait la
       feuille de composants avant la fusion (spinwork/port/fusion/isole.cjs,
       reprises de Raon, dont `.cta__panel` mesure 28 px 24 px sous 981 px).
       Rétablies telles quelles : 24 px suffisent à 768, 480 et 390 px ;
     - à 360 px elles ne suffisent PAS, et c'est mesuré : 20 px ne laissent que
       244 px pour 250,3 nécessaires, le bouton repasse à deux lignes. Seul le
       remplissage HORIZONTAL est donc descendu sous 480 px, le vertical
       gardant les 20 px d'avant la fusion ;
     - 16 px laisseraient 252 px, soit 1,7 px de marge : trop peu pour une
       variation de rendu de police. 12 px en laissent 260, soit 9,7 px de
       marge, et le bouton tient sur une ligne jusqu'à 348 px de fenêtre — le
       site vise 360 px.
   AU-DESSUS DE 981 px, RIEN NE CHANGE : ce bandeau garde ses 40 px sur
   ordinateur, l'encadré de l'accueil ses 313,8 px et celui des pages de
   services ses 351,6 px.                                                   */
@media (max-width: 980px) {
    .avis-google {
        padding: 24px;
    }
}

@media (max-width: 479px) {
    .avis-google {
        padding: 20px 12px;
    }
}

/* `.prose a` souligne les liens du texte courant et les met en noir : juste
   pour un lien dans une phrase, faux pour un bouton. */
.avis-google .btn {
    color: var(--white);
    text-decoration: none;
}

/* Et `.prose a:hover` les passe en bleu nuit — sur un bandeau bleu nuit, le
   libellé disparaîtrait au survol. Trois classes pour l'emporter à coup sûr,
   `.btn--light:hover` (deux) perdant ici sur l'ordre d'écriture. Le reste du
   survol (le décalage du remplissage, propre aux boutons Divi) reste celui du
   § 4. */
.avis-google .btn:hover,
.avis-google .btn:focus-visible {
    background: rgba(255, 255, 255, 0.2);
    color: var(--white);
}

/* ==========================================================================
   7. Formulaire
   ========================================================================== */

/* Le site d'origine n'avait AUCUN formulaire : sa page Coordonnées ne portait
   que du texte (vérifié sur sp_posts 3017 : aucun module et_pb_contact_form).
   Il n'y a donc rien à mesurer pour ce bloc. Le moteur vient du site Raon
   (jeton signé, quotas, leurre, archivage) et son habillage suit les
   conventions de Spin plutôt que celles de Raon — champs à bordure noire de
   2 px et coins de 3 px, bouton bleu nuit de 20 px : ce sont les cotes du seul
   formulaire que l'original ait porté, celui du livre d'or (charte.md § 5).

   Cette section tient TOUT ce qui concerne la page de contact, y compris ses
   points de rupture : la colonne unique sous 981 px, le champ pleine largeur
   sous 768 px et les champs à 16 px sous 480 px. Ils étaient dispersés dans
   trois feuilles de composants ; ils sont ici, avec les cotes dont ils sont la
   variante.                                                                 */

/* --- L'écart entre le filet du titre et l'encart ------------------------
   Dans l'original, le titre, le filet et le contenu de la page vivent dans la
   MÊME section, en deux rangées : entre le bas du filet et le haut du texte il
   y a la respiration basse de la rangée 1 et la respiration haute de la
   rangée 2, soit 27 + 27 = 54 px à 1440 px et 30 + 30 = 60 px à 390 px.
   Vérifié sur le relevé : filet à 308,4 + 3 = 311,4, texte à 365,4 — 54 px
   exactement.

   Or le § 6 colle le bloc suivant au titre (`.page-title + .section`). C'est
   juste, et mesuré, pour la Galerie : là, 10 px seulement séparent le titre de
   la grille de photos, parce que la grille suit le titre DANS la même rangée.
   Ici le contenu est dans la rangée SUIVANTE, et les 54 px existent. Sans ces
   règles, l'encart blanc touche le filet.

   On rend donc à la seule rangée de la section de contact la respiration haute
   des DEUX rangées d'origine — c'est-à-dire 2 % + 2 %, qui se calculent sur la
   même largeur de référence, donc 4 %. La respiration basse n'est pas touchée :
   le § 3 la tient déjà à 2 % / 27 px / 30 px, ce que l'original porte aussi.
   Trois classes dans le sélecteur, autant que dans celui du § 6 : il est écrit
   APRÈS lui, et c'est l'ordre qui tranche à spécificité égale. */

.page-title + .contact-section > .row {
    padding-top: 4%;
}

@media (min-width: 1350px) {
    .page-title + .contact-section > .row {
        padding-top: 54px;
    }
}

@media (max-width: 980px) {
    .page-title + .contact-section > .row {
        padding-top: 60px;
    }
}

/* --- L'encart : formulaire à gauche, coordonnées à droite --------------- */

.contact-grid {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    background: var(--white);
    box-shadow: var(--box-shadow);
}

.contact-grid__form {
    width: 66.667%;
    padding: 40px;
    background: var(--white);
}

.contact-grid__panel {
    width: 33.333%;
    padding: 40px;
    background: var(--navy);
    color: var(--white);
}

.contact-heading {
    color: var(--navy);
    font-size: 26px;
    line-height: 26px;
    padding-bottom: 10px;
}

.panel-heading {
    color: var(--white);
    font-size: 22px;
    line-height: 22px;
    padding-bottom: 10px;
}

.panel-item {
    display: flex;
    gap: 16px;
    margin-bottom: 22px;
}

.panel-item svg {
    width: 24px;
    height: 24px;
    flex: 0 0 24px;
    fill: var(--white);
    margin-top: 3px;
}

.panel-item h4 {
    color: var(--white);
    font-size: 16px;
    font-weight: 600;
    padding-bottom: 4px;
}

.panel-item p {
    padding-bottom: 0;
}

.panel-item .reveal {
    color: var(--white);
}

/* --- Champs ------------------------------------------------------------
   Les étiquettes sont réelles, pour les lecteurs d'écran, mais masquées à
   l'écran : le formulaire d'origine de Raon n'affichait que des textes
   indicatifs, et on garde ce rendu sans perdre l'accessibilité.            */

.form {
    padding-top: 20px;
}

.form__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
}

.form__field {
    display: flex;
    flex-direction: column;
}

.form__field--full {
    grid-column: 1 / -1;
}

.form__label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.form__input,
.form__textarea {
    width: 100%;
    padding: 14px;
    background: transparent;
    border: 2px solid var(--field-border);
    border-radius: 3px;
    color: var(--ink);
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 400;
    line-height: 1.6em;
}

/* Les étiquettes étant masquées, le texte indicatif est le seul intitulé
   VISIBLE de chaque champ. Laissé au défaut du navigateur, il varie de l'un à
   l'autre — Chrome le pose à #757575 (4,6:1 sur blanc), Firefox applique une
   opacité qui descend plus bas — et le nom du champ deviendrait le texte le
   moins lisible du formulaire. Fixé à #616161, soit 5,9:1 sur blanc, au-dessus
   du seuil de 4,5:1 et encore nettement plus clair que le noir d'une valeur
   saisie : un champ vide ne se lit pas comme un champ rempli. */
.form__input::placeholder,
.form__textarea::placeholder {
    color: #616161;
    /* Firefox descend l'opacité à 0,54 par défaut, ce qui annulerait le
       contraste choisi ci-dessus. */
    opacity: 1;
}

.form__textarea {
    min-height: 130px;
    resize: vertical;
}

.form__input:focus,
.form__textarea:focus {
    outline: 2px solid var(--navy);
    outline-offset: -1px;
    border-color: var(--navy);
}

.form__input[aria-invalid="true"],
.form__textarea[aria-invalid="true"] {
    border-color: var(--error);
}

/* Chrome peint les champs qu'il autoremplit en jaune pâle (ou en bleu sombre
   selon le thème du système) et remplace la couleur du texte, ce qui passe
   au-dessus de tout ce que déclare la feuille : un formulaire à moitié jaune,
   dont on ne maîtrise plus le contraste. L'ombre intérieure de 100 px est la
   seule façon connue de recouvrir ce fond, `-webkit-text-fill-color` la seule
   de tenir la couleur du texte. Les champs concernés sont ceux qu'un
   navigateur sait remplir : nom, prénom, téléphone, e-mail. */
.form__input:-webkit-autofill,
.form__input:-webkit-autofill:hover,
.form__input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--ink);
    box-shadow: 0 0 0 100px var(--white) inset;
}

.form__error {
    color: var(--error);
    font-size: 13px;
    padding: 4px 0 0;
}

/* Règle du « téléphone OU e-mail », écrite au-dessus des champs plutôt que
   découverte par un message d'erreur. Le texte est rattaché aux deux champs
   par aria-describedby (partials/contact_form.php) : il est donc lu à la prise
   de focus sur le téléphone comme sur l'e-mail, et pas seulement rencontré à
   l'œil en descendant. Il occupe toute la largeur de la grille, et sa
   respiration basse est de 18 px pour qu'il ne colle pas au champ « Message »
   qui le suit. */
.form__hint {
    margin: 0;
    padding: 0 0 18px;
    font-size: 14px;
    line-height: 1.7em;
    color: var(--ink);
}

.form__consent {
    grid-column: 1 / -1;
}

.form__consent-label {
    display: block;
    font-size: 14px;
    font-weight: 600;
    line-height: 23.8px;
    margin-bottom: 7px;
}

/* La case flotte, comme dans l'original où elle est posée dans le fil du
   texte : les lignes suivantes reprennent donc toute la largeur au lieu
   d'être décalées. */
.form__check {
    line-height: 1.5em;
}

.form__check input {
    float: left;
    width: 16px;
    height: 16px;
    margin: 4px 10px 0 0;
    accent-color: var(--navy);
}

.form__check label {
    display: block;
    font-weight: 600;
    cursor: pointer;
}

.form__check-detail {
    display: block;
    padding-top: 2px;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.7em;
}

.form__check a {
    text-decoration: underline;
}

.form__actions {
    grid-column: 1 / -1;
    display: flex;
    justify-content: flex-end;
}

/* Bouton d'envoi : celui du livre d'or de l'original — fond et bordure bleu
   nuit, texte blanc 20 px, graisse 500, coins de 3 px. */
.form__submit {
    padding: 6px 20px;
    background: var(--navy);
    border: 2px solid var(--navy);
    border-radius: 3px;
    color: var(--white);
    font-family: var(--sans);
    font-size: 20px;
    font-weight: 500;
    line-height: 1.7em;
    cursor: pointer;
    transition: all var(--btn-transition);
}

.form__submit:hover {
    padding: 6px 40px 6px 14px;
    border-color: transparent;
}

/* Champ leurre : invisible pour un humain, atteignable pour un robot. */
.form__decoy {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* --- Encadrés de message ----------------------------------------------- */

/* Relevé : la notice du livre d'or était un encadré bleu nuit à texte blanc
   et gras. On garde le filet bleu nuit et un fond teinté, plus lisible pour
   un message long. */
.notice {
    padding: 16px 20px;
    margin-bottom: 24px;
    border-left: 3px solid var(--navy);
    background: rgba(40, 56, 81, 0.06);
    line-height: 1.6em;
}

.notice--ok {
    border-left-color: var(--ok);
    background: rgba(31, 99, 73, 0.08);
}

.notice--error {
    border-left-color: var(--error);
    background: rgba(163, 43, 34, 0.07);
}

.notice p:last-child {
    padding-bottom: 0;
}

/* Quand la saisie est à corriger, l'encadré liste les points en cause, et
   chaque point est un LIEN vers le champ concerné (partials/contact_form.php).
   Or `.prose a` ne s'applique pas dans un encadré : ces liens sortaient en
   noir, sans soulignement, donc indiscernables du texte — la liste devenait
   décorative alors qu'elle est le chemin le plus court vers le champ fautif.
   Le retrait et l'interligne de la liste sont ceux du site (§ 2). */
.notice ul {
    margin: 8px 0 0;
}

.notice li {
    margin-bottom: 0.25em;
}

.notice a {
    color: var(--navy);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.notice--error a {
    color: var(--error);
}

/* --- Points de rupture du formulaire ----------------------------------- */

/* Sous 981 px, l'encart passe en colonne unique et le panneau « Nous joindre »
   passe DEVANT le formulaire. Mesuré sur le site Raon : à 390 px, le bouton
   « Voir le numéro » tombait à 1 513 px du haut — 1,8 écran, derrière cinq
   champs et une case de consentement — alors que sur bureau il est dans le
   premier écran. Celui qui préférait téléphoner devait franchir exactement ce
   qu'il voulait éviter. Une propriété, et il remonte. La colonne de droite du
   bureau n'est pas touchée : la comparaison au pixel avec l'original y reste
   valable. */
@media (max-width: 980px) {
    .contact-grid {
        flex-direction: column;
    }

    .contact-grid__form,
    .contact-grid__panel {
        width: 100%;
        padding: 28px 20px;
    }

    .contact-grid__panel {
        order: -1;
    }

    .form__actions {
        justify-content: stretch;
    }

    .form__submit {
        width: 100%;
    }
}

/* Sous 768 px, les deux colonnes de champs n'en font plus qu'une. */
@media (max-width: 767px) {
    .form__grid {
        grid-template-columns: 1fr;
    }
}

/* Décision du client : champs de formulaire à 16 px sous 480 px. La raison est
   mécanique et non esthétique — un champ dont le texte est écrit sous 16 px
   fait ZOOMER la page à la prise de focus sur iOS (Safari comme Chrome). Le
   visiteur perd alors la largeur de l'écran, le formulaire sort du cadre, et
   il faut pincer pour revenir : sur la seule page du site qui porte un
   formulaire, c'est le geste le plus coûteux de toute la visite.

   Les 14 px des champs sont ceux du livre d'or de l'original, le seul
   formulaire qu'il ait porté (charte.md § 5) : ils restent jusqu'à 480 px, et
   ce sont eux que l'on compare à l'original. En dessous, le confort tranche —
   et l'original n'avait, à cette largeur, aucun champ à comparer.
   Le texte indicatif suit la taille du champ sans être redéclaré : il hérite
   de `font-size`. */
@media (max-width: 479px) {
    .form__input,
    .form__textarea {
        font-size: 16px;
    }
}

/* ==========================================================================
   8. Utilitaires
   ========================================================================== */

/* Bouton de révélation des coordonnées. Il y en a six types sur ce site — les
   deux boutiques, les deux personnes — et tous partagent ce style : un bouton
   qui ne se distingue pas du texte qui l'entoure, puisqu'il prendra la place
   d'un numéro ou d'une adresse. Le script le remplace par un <a> qui ne garde
   que la classe `reveal` : le style doit donc valoir pour les deux. */
.reveal {
    display: inline;
    padding: 0;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: opacity var(--transition);
}

.reveal:hover {
    opacity: 0.75;
    text-decoration: underline;
}

.reveal[data-state="loading"] {
    opacity: 0.6;
    cursor: progress;
}

.reveal[data-state="done"] {
    cursor: default;
    text-decoration: none;
}

.reveal[data-state="done"]:hover {
    opacity: 1;
}

.u {
    text-decoration: underline;
}

/* --- Pages d'erreur (404, 410, 500) ------------------------------------ */

.error-page {
    text-align: center;
}

.error-page h1 {
    padding-bottom: 18px;
}

.error-page p {
    max-width: 52ch;
    margin: 0 auto;
    padding-bottom: 1.4em;
}

/* flex-wrap : sans lui, les deux boutons dépassaient la gouttière de 13 px de
   chaque côté à 320 px et leur texte se repliait sur trois lignes (relevé sur
   le site Raon). */
.error-page__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    justify-content: center;
    padding-top: 10px;
}

/* ==========================================================================
   9. Mobile
   ========================================================================== */

/* Quatre ruptures, relevées sur l'original (charte.md § 6) :
     1024 px — l'extension WP Mobile Menu affiche sa barre jusqu'ici ;
      980 px — Divi passe de l'ordinateur à la tablette ;
      767 px — Divi passe de la tablette au téléphone, et le bouton
               « Nous appeler » apparaît ;
      479 px — petits téléphones.

   DÉFAUT DE L'ORIGINAL CORRIGÉ ICI : entre 981 et 1024 px, la barre mobile
   noire ET l'en-tête de bureau s'affichaient ENSEMBLE, alors que l'extension
   masquait les trois menus Divi (.nav{display:none!important}) — le visiteur
   voyait deux en-têtes empilés et ne pouvait naviguer que par le hamburger
   (charte.md § 13, capture accueil_1000_haut.png).

   On bascule donc d'un seul coup, et à 981 px. Pourquoi 981 et non 1024 :
   981 px est la rupture de Divi elle-même, celle que suit TOUT le reste du
   site — sections de 50 px, rangées de 30 px, colonnes empilées. L'en-tête
   bascule ainsi exactement quand la mise en page bascule. Choisir 1024 px
   laisserait au contraire une bande de 44 px de large où le corps de la page
   est déjà en colonnes d'ordinateur sous une barre de téléphone.

   La rangée bleu nuit, elle, n'est PAS masquée : elle appartient à l'en-tête
   collant, qui décide seul de sa visibilité (§ 4) — masqué jusqu'au
   défilement au-dessus de 981 px, statique et visible en dessous, comme dans
   l'original.

   Ce que tient ce paragraphe : les trois composants qui n'existent QUE sur
   téléphone — barre du haut, tiroir, bouton d'appel — et la bascule entre les
   deux en-têtes, écrite après eux pour la raison expliquée sur place. Le repli
   général de la page (sections, rangées, colonnes) est au § 3, avec la grille
   dont il est la variante ; les autres points de rupture sont chez leurs
   composants — l'en-tête au § 4, le pied au § 5, chaque bloc au § 6, le
   formulaire au § 7.

   Sources, toutes mesurées, aucune valeur approchée à l'œil :
     — spinwork/live/pages/accueil_390.json (fixedElements, otherBlocks,
       stickyFooter, typography.menuItems, typography.buttons) ;
     — captures spinwork/design/captures/accueil_375_haut.png et
       accueil_375_menu_ouvert.png, lues au pixel (encre des glyphes) ;
     — les feuilles de l'extension dans la sauvegarde WordPress :
       wp-content/uploads/dynamic-mobmenu.css (réglages du site) et
       wp-content/plugins/mobile-menu/includes/css/mobmenu.css (défauts) ;
     — spinwork/design/charte.md § 8, § 9 et § 13.                          */

/* --- Barre du haut -----------------------------------------------------
   Relevé : barre fixe en haut, 50 px de haut, fond #111 (pixel : 17,17,17),
   z-index 10000 ; hamburger dont l'encre fait 20 × 15 px à x 16..35 et
   y 18..32, donc centrée sur (25,5 ; 25) ; au centre le titre « Spin Info » en
   Dosis 20 px blanc, encre x 155..219 et y 17..37 sur une barre de 375 px.
   C'est du TEXTE et non le logo, parce que l'extension n'a jamais été
   configurée.

   Le body d'origine recevait 50 px de marge haute (barre fixe) ; ici la barre
   est `sticky` et occupe ses 50 px dans le flux : même résultat, sans marge à
   compenser.                                                               */

.mobile-bar {
    display: none;
    position: sticky;
    top: 0;
    z-index: 10000;
    height: 50px;
    background: var(--mobile-bar);
}

.mobile-bar__inner {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
}

/* Relevé : `.headertext span { line-height: 50px }` dans la feuille de
   l'extension — le texte occupe toute la hauteur de la barre, ce qui place sa
   ligne de base comme sur l'original (encre y 17..37). */
.mobile-bar__title {
    color: var(--white);
    font-family: var(--dosis);
    font-size: 20px;
    font-weight: 700;
    line-height: 50px;
}

.mobile-bar__title:hover {
    color: var(--white);
}

/* La cible couvre toute la hauteur de la barre et les 51 premiers pixels, ce
   qui met son centre exactement sur celui de l'encre d'origine (25,5 ; 25)
   tout en dépassant les 44 px du doigt. Une cible de 44 × 44 px posée à 5 px
   du bord et centrée par translateY, comme le faisait la première écriture de
   cette feuille, mettait l'encre à 27 px du bord au lieu de 25,5. */
.mobile-bar__toggle {
    position: absolute;
    left: 0;
    top: 0;
    width: 51px;
    height: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 0;
    cursor: pointer;
    color: var(--white);
}

/* L'encre du glyphe d'origine fait 20 × 15 px, à x 16..35 ; la nôtre, dans une
   boîte de 28 px, fait 20 × 14 px — au même x 16..35, mesuré sur le rendu. Nos
   trois barres sont un peu plus fines que celles de la police mobmenu : il
   manque 1 px de hauteur d'encre, et c'est le seul écart. Redessiner le glyphe
   pour ce pixel n'aurait pas de sens : l'icône est partagée avec tout le site
   (src/icons.php). */
.mobile-bar__toggle svg {
    width: 28px;
    height: 28px;
    fill: currentColor;
}

/* --- Tiroir ------------------------------------------------------------
   Relevé : le panneau glisse depuis la GAUCHE par-dessus la page, sur 270 px
   (bord droit mesuré à x = 270), fond #f7f7f7 (247,247,247), avec un voile
   rgba(0,0,0,.83) sur le reste — qui couvre AUSSI la barre (pixel (320,25) =
   3,3,3). Liens en Dosis 14 px, interligne 21 px, graisse 500, #666,
   remplissage 10 px 20 px → pas de 41 px entre deux liens (mesuré : 41, 41,
   41, 40, 41, 41, 41, 41 — la moyenne exacte est 41, l'écart de 1 px vient de
   l'arrondi des hauteurs d'encre relevées).                                */

.mobile-panel {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 10010;
    width: 270px;
    max-width: 85vw;
    height: 100%;
    /* Relevé : `.mobmenu-content { margin-top: 45px; padding-top: 10px;
       padding-bottom: 120px }`, d'où la boîte du premier lien à 55 px du haut
       du panneau (confirmé par le relevé : premier lien à top = 55). Les
       120 px du bas ne sont pas du décor : c'est ce qui permet d'atteindre le
       dernier lien au pouce quand le tiroir défile. */
    padding: 55px 0 120px;
    background: var(--grey-bg);
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform var(--transition);
    visibility: hidden;
}

.mobile-panel[data-open="true"] {
    transform: translateX(0);
    visibility: visible;
}

/* La croix d'origine est un glyphe de police de 30 px posé au coin haut droit
   du panneau : son encre tombe à x 238..259 et y 4..24, en #666
   (102,102,102). Deux écarts assumés :
     — la cible fait 44 × 44 px, contre 30 × 30 px sur l'original (seuil du
       doigt) : elle s'étend donc vers le bas et vers la gauche, jamais vers
       le haut, où elle sortirait du panneau ;
     — le SVG est aligné à DROITE dans cette cible (justify-content) et non
       centré, sans quoi son encre partait 4,5 px trop à gauche.
   Mesuré après correction : encre à x 238..259 et y 3..24 — la largeur et le
   bord droit de l'original au pixel, avec 1 px d'encre en plus vers le haut
   (notre croix est un carré plein, le glyphe de l'extension a ses propres
   approches). Le remplissage par défaut des <button> est remis à zéro au § 2 :
   il faisait tomber la boîte de contenu à 32 px et arrêtait le bord droit
   6 px avant celui du panneau. */
.mobile-panel__close {
    position: absolute;
    top: 0;
    right: 3.5px;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    background: none;
    border: 0;
    color: var(--mobile-link);
    cursor: pointer;
}

/* Boîte de 36 px : notre croix occupe 58 % de sa boîte, ce qui donne 22 px
   d'encre — exactement ceux de l'original (une boîte de 30 px n'en donnait que
   17,5). La marge négative la remonte là où l'original la posait : sans elle,
   notre carré plein commençait à 8,5 px du haut du panneau, contre 4 px pour
   le glyphe de l'extension. */
.mobile-panel__close svg {
    width: 36px;
    height: 36px;
    margin-top: -4px;
    fill: currentColor;
}

.mobile-panel ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Graisse relevée sur les liens du tiroir : 500. Seule la face Dosis 400 est
   chargée — comme sur l'original, qui ne chargeait qu'elle : le navigateur
   affiche donc la 400 sans graisser, et c'est bien ce qu'on voit sur la
   capture. La déclarer tout de même garde la mesure vraie si une face 500
   était ajoutée un jour. */
.mobile-panel a {
    display: block;
    padding: 10px 20px;
    color: var(--mobile-link);
    font-family: var(--dosis);
    font-size: 14px;
    font-weight: 500;
    line-height: 1.5em;
}

.mobile-panel a:hover {
    background: var(--mobile-link);
    color: var(--white);
}

/* Le voile est retiré du document quand le menu est fermé (attribut hidden),
   et non simplement rendu invisible : un bouton invisible mais focusable est
   un piège pour la navigation au clavier. */
.mobile-overlay {
    position: fixed;
    inset: 0;
    z-index: 10005;
    background: var(--veil-menu);
    opacity: 0;
    transition: opacity var(--transition);
    border: 0;
    padding: 0;
    cursor: pointer;
}

.mobile-overlay[data-open="true"] {
    opacity: 1;
}

body[data-menu-open="true"] {
    overflow: hidden;
}

/* Au-dessus de la rupture, le tiroir et son voile sortent du document pour de
   bon, comme dans l'original, qui écrivait
   `@media only screen and (min-width:1025px){ .mobmenu-panel, .mobmenu,
   .mobmenu-left-panel { display:none!important } }`. Sans cela, le tiroir
   reste dans la page, invisible (visibility: hidden, hors écran) mais présent.
   La barre et le bouton d'appel n'ont pas besoin d'y figurer : ils sont en
   `display: none` par défaut et ne s'affichent que dans leurs propres media
   queries, plus bas. */
@media (min-width: 981px) {
    .mobile-panel,
    .mobile-overlay {
        display: none;
    }
}

/* --- Bouton « Nous appeler » -------------------------------------------
   Relevé : l'original porte un pied collant (module global 2259) affiché
   SOUS 768 px, fixé en bas de l'écran, pleine largeur, 375 × 50 px à 375 px
   de large : fond #000000, bordure blanche de 2 px sur les QUATRE côtés
   (pixels : x 0..1 et 373..374, y 762..763 et 810..811), coins de 3 px, texte
   Open Sans 20 px / 34 px d'interligne, graisse 500, capitales, blanc
   (2 + 6 + 34 + 6 + 2 = 50 px), et une icône téléphone toujours visible à
   gauche, sans aucune animation au survol.

   Le bouton est un `.reveal` comme les autres : le numéro affiché vient
   toujours de /api/coordonnees après un clic, jamais du HTML. Il porte
   `data-call`, qui demande au script de COMPOSER le numéro dès qu'il l'a reçu
   — le visiteur a touché « Nous appeler », il s'attend à appeler, pas à lire.
   Livré masqué et révélé par le script : sans JavaScript il ne pourrait rien
   obtenir, et un bouton mort est pire qu'un bouton absent.

   La classe .mobile-bar__call est conservée telle quelle : c'est par elle que
   assets/js/site.js retrouve le bouton pour le démasquer.                   */

.mobile-call {
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9990;
}

/* Mesuré sur l'original : 9 px entre l'ENCRE de l'icône et celle du texte, et
   une encre d'icône de 18 × 18 px. Notre combiné occupe 72 % de sa boîte :
   25 px de boîte donnent 17 à 18 px d'encre.

   D'où un écart CSS de 3 px et non de 9 : les 4 px de boîte vide que notre SVG
   porte à droite de son encre s'ajoutent à l'écart, là où le glyphe ETmodules
   de l'original n'en portait presque pas. Mesuré à 390 px avec un écart CSS de
   9 px : encre de l'icône 110..126, texte 142..282, soit 15 px entre les deux
   — 6 px de trop. Avec 3 px, les deux encres retrouvent leurs 9 px. C'est la
   seule façon d'obtenir le rendu de l'original sans redessiner le glyphe, qui
   est partagé avec le reste du site (src/icons.php). */
.mobile-call .reveal {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: 100%;
    min-height: 50px;
    padding: 6px 20px;
    background: var(--ink);
    border: 2px solid var(--white);
    border-radius: 3px;
    color: var(--white);
    font-family: var(--sans);
    font-size: 20px;
    font-weight: 500;
    line-height: 1.7em;
    text-transform: uppercase;
    text-decoration: none;
}

.mobile-call .reveal:hover {
    opacity: 1;
    text-decoration: none;
}

.mobile-call .reveal svg {
    width: 25px;
    height: 25px;
    flex: 0 0 25px;
    fill: currentColor;
}

/* --- La bascule entre les deux en-têtes --------------------------------
   Écrite APRÈS les composants ci-dessus, et il le faut : `.mobile-bar` est
   livrée en `display: none` — elle n'existe pas sur ordinateur — et cette
   règle-ci la rallume à la MÊME spécificité. Placée avant, elle perdait par
   simple ordre d'écriture et la barre noire ne s'affichait plus du tout :
   mesuré au moment de la fusion, le premier contenu remontait à 90,6 px au
   lieu de 140,6 à 390 px, et à 66,8 au lieu de 116,8 à 768 px, sur les dix
   pages. La rangée bleue, elle, n'est pas concernée : c'est l'en-tête collant
   qui décide de sa visibilité (§ 4). */

@media (max-width: 980px) {
    .masthead {
        display: none;
    }

    .mobile-bar {
        display: block;
    }
}

/* --- 767 px : Divi passe en téléphone, le bouton d'appel apparaît ------- */

@media (max-width: 767px) {
    .mobile-call {
        display: block;
    }

    /* La barre d'appel couvre le bas de l'écran : sans cette réserve, le
       dernier élément de la page — le crédit du pied — passe dessous et
       devient inatteignable. */
    body {
        padding-bottom: 50px;
    }
}

/* --- Mouvement et impression ------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* L'en-tête collant ne s'imprime pas : c'est un doublon de l'en-tête visible,
   et il porte la rangée bleue — inutile de nommer `.topbar` séparément. */
@media print {
    .sticky-header,
    .masthead,
    .mobile-bar,
    .mobile-panel,
    .mobile-overlay,
    .mobile-call,
    .footer__social,
    .lightbox {
        display: none !important;
    }

    body {
        color: #000;
        background: #fff;
        padding-bottom: 0;
    }

    a {
        text-decoration: underline;
    }
}
