/* Page d'accueil — styles propres a la page.
 * Les composants partages (tuiles.css, gaf.css) en ont ete RETIRES :
 * ils sont deja deployes et enqueues a part par functions.php.
 *
 * Extrait de tests/home/home-a.html (maquette generee par build-home.py).
 * Ne pas editer a la main : corriger la maquette puis rejouer
 * scripts/portage-home/, sinon la prochaine extraction ecrase en silence.
 */

/* ══ TOKENS, SCOPÉS À CETTE PAGE ════════════════════════════════════════════
   Méthode reprise du chantier garde-meuble : une page qui a besoin d'un token
   le déclare dans SON `:root`, jamais dans assets/lab.css, qui est le socle
   partagé par les huit fragments d'options. Ici les trois valeurs de motion
   existent déjà à l'identique dans le socle — elles sont réécrites pour que
   la maquette reste juste si on la détache de lab.css, pas pour le contredire.
   Une seule courbe, deux durées, rien d'autre ; on n'anime que `transform` et
   `opacity`. `--color-link` est l'ALIAS du nom porté par le socle du chantier
   garde-meuble, même valeur que `--color-primary-text` : on ajoute, on ne
   renomme pas, sinon les 40 usages de `--color-primary-text` tombent. */
:root{
  --ease-out:cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast:150ms;
  --duration-normal:300ms;
  --color-link:#7A6200;
}


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

html{-webkit-text-size-adjust:100%}

body{margin:0;background:var(--color-bg);color:var(--color-dark);
     font-family:var(--font-body);font-size:16px;line-height:1.55}

h1,h2,h3{font-family:var(--font-display);line-height:1.2;margin:0 0 .5rem}

h1{font-size:1.75rem;letter-spacing:-.02em}

h2{font-size:1.375rem;letter-spacing:-.01em}

h3{font-size:1rem}

p{margin:0 0 .75rem}

a{color:var(--color-primary-text)}

/* ══ CENTRAGE DU CONTENU — PAR LE PADDING DE LA SECTION ══════════════════════
   Le fond reste bord à bord, le CONTENU se contraint. Il l'a d'abord été par
   `.hm-b > *{max-width:1200px;margin-left:auto;margin-right:auto}
` : un seul
   sélecteur, aucun <div> enveloppant à ajouter. Ce montage avait un défaut de
   conception, pas un bug ponctuel — la contrainte était portée par des marges
   `auto` de spécificité (0,1,0), que TOUT raccourci `margin` écrit ensuite sur
   un enfant remettait silencieusement à zéro. L'enfant restait plafonné à
   1200 px mais collé à gauche, et le bord gauche de la page zigzaguait.

   Mesuré à 1440 px, sur les positions gauches des enfants directs des neuf
   sections : HUIT enfants à 16 px au lieu de 120 — `.hm-cta2` et `.hm-note`
   dans le héros, `.hm-trust ul`, `.hm-kicker`, `.tc4-route`,
   `.tc4-legend-fits`, `.hm-steps ol`, `.hm-guides ul`. Le titre « Nos guides »
   commençait 104 px à droite de ses propres cartes.

   Le piège était déjà connu, déjà commenté, et déjà réparé une fois au cas par
   cas — sur l'ancienne `.hm-hero__img`, une règle qui n'existe plus depuis que
   le héros a été remplacé par la composition à deux photos. C'est ce qui
   tranche : le réparer une neuvième fois, c'est le laisser ouvert pour le
   dixième. Le padding de la section produit le même centrage SANS marge `auto`
   à préserver, donc aucun raccourci `margin`, présent ou futur, ne peut le
   défaire.

   NOTE, depuis le 2026-08-11 : le héros est désormais la SEULE section sans
   `.hm-b`, parce que ses photos saignent bord à bord. Il reprend la même
   expression de centrage sur `.hm-hero__txt`, mais en `vw` et non en `%` — le
   bloc de texte ne s'étend pas sur toute la section au-delà de 768 px, donc un
   pourcentage s'y calculerait sur la mauvaise référence.

     max(--space-sm, (100% - --max-width)/2)
     · en dessous de 1232 px la parenthèse est négative → le `max` rend
       --space-sm, exactement le padding d'avant. À 375 px la boîte de contenu
       reste à 343 px : les hauteurs arbitrées ne bougent pas ;
     · au-delà, elle vaut la moitié du débord et la boîte plafonne à 1200 px.
   `100%` se résout sur le bloc conteneur, ici <body> — marge nulle, padding
   nul, donc la largeur du viewport.

   ATTENTION AUX SECTIONS QUI REDÉCLARENT `padding` : elles écrasent celui-ci
   et doivent recevoir le même traitement. `.hm-trust` est la seule aujourd'hui
   (voir plus bas) ; toute nouvelle est à vérifier au même endroit. */
.hm-b{padding:var(--space-md) max(var(--space-sm), (100% - var(--max-width)) / 2);
      background:var(--color-white)}


/* L'ALTERNANCE, ET SON PIÈGE — trouvé le 2026-08-11 en production de maquette.
   `.hm-b:nth-child(even)` pèse (0,2,0) : une classe PLUS une pseudo-classe. Les
   sections qui déclarent leur propre fond le font en (0,1,0) — `.hm-final` en
   noir, `.hm-trust` en jaune pâle. Elles PERDENT donc l'arbitrage, et pas à
   cause de leur position dans la feuille : aucun déplacement de règle n'y
   changerait rien, c'est la spécificité qui tranche.

   Tant que ces sections tombaient en rang impair, la règle ne les atteignait
   pas et le bug dormait. L'insertion du bloc « avantages » après les tuiles a
   décalé la parité de tout ce qui suit, le CTA final est passé en pair, et son
   noir a disparu — silencieusement, sans erreur, en changeant un bloc qui n'a
   rien à voir. C'est le mode de défaillance le plus coûteux : le symptôme
   apparaît loin de sa cause.

   La parade est ici et pas ailleurs : l'alternance s'efface devant toute
   section qui possède sa couleur. Ajouter une section colorée = l'ajouter à
   cette liste, au même endroit que le commentaire qui l'explique. */
/* PASSÉ DE `even` À `odd` LE 2026-08-12, et c'est bien le même piège qui a
   frappé une seconde fois — sous un autre visage. Le retrait du bandeau de
   réassurance a fait remonter tous les blocs d'un rang. Aucune couleur n'a
   disparu cette fois : c'est le RYTHME qui s'est cassé. Le bloc avantages, qui
   porte son propre beige, est passé en rang impair, et l'étape suivante a reçu
   le beige de l'alternance — deux sections beiges collées, puis deux blanches
   plus bas. Le symptôme est plus discret que la perte du noir, donc plus facile
   à laisser passer : il faut regarder les neuf fonds ensemble pour le voir.
   `odd` remet les sections à couleur propre en phase avec l'alternance.
   La leçon ne change pas : AJOUTER ou RETIRER une section oblige à relire les
   neuf fonds dans le navigateur, pas seulement à vérifier que la page se
   construit. */
.hm-b:nth-child(even):not(.hm-final):not(.tvof-section):not(.avp):not(.gaf):not(.chp){background:var(--color-bg)}

.btn-primary,.btn-tertiary{display:inline-flex;align-items:center;justify-content:center;
  min-height:48px;padding:.75rem 1.15rem;border-radius:var(--radius-md);font-weight:600;
  font-size:.95rem;text-decoration:none;line-height:1.2}

.btn-primary{background:var(--color-primary);color:var(--color-dark)}

.btn-tertiary{background:transparent;color:var(--color-dark);border:2px solid var(--color-dark)}

/* Retour d'appui : le seul défaut de motion qu'on ressent consciemment, parce
   qu'il n'y a pas de :hover sur mobile — rien ne confirmait que le bouton a
   entendu. La transition ne porte que `transform`. */
.btn-primary,.btn-tertiary{transition:transform var(--duration-fast) var(--ease-out)}

.btn-primary:active,.btn-tertiary:active{transform:scale(.97)}


/* Focus clavier. Le socle porte un `:focus-visible` nu ; on nomme ici les
   quatre sélecteurs du système — un `summary` ou un `[tabindex]` ne doit pas
   dépendre du fait qu'aucune règle de page n'ait posé `outline:none`. */
a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visible{
  outline:3px solid var(--color-dark);outline-offset:2px;border-radius:var(--radius-sm)}


/* ---------------------------------------------------------------- LE DUOTONE
   Le moteur de teinte. UNE SEULE VALEUR A REGLER : `--duo-force`, de 0 a 1.
   0 = photo d'origine, 1 = duotone plein entre le noir et le jaune de la
   charte. 0.55 a 0.7 donne un jaune discret.

   `--duo-lum` est un second cadran, separe EXPRES : il gere la luminosite,
   donc le contraste du texte pose dessus. Baisser `--duo-force` est sans
   risque ; toucher `--duo-lum` oblige a remesurer les contrastes.

   LE PIEGE, ET IL EST SILENCIEUX : `::before` est genere comme PREMIER enfant
   dans l'arbre de boites. Sans z-index, la couche `multiply` se peint donc
   SOUS l'image, qui est opaque et la recouvre entierement — on obtient une
   image grise parfaitement plausible, sans la moindre erreur console. La
   premiere passe de mesure a rendu exactement ca : trois heros en noir et
   blanc, sans un pixel de jaune. D'ou le z-index explicite ci-dessous. */
.duo{--duo-force:1;--duo-lum:.52;--duo-clair:#F5C518;--duo-sombre:#1A1A1A;
  position:relative;isolation:isolate;overflow:hidden;background:var(--color-dark)}

.duo > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:grayscale(var(--duo-force)) contrast(1.04) brightness(var(--duo-lum));z-index:0}

.duo::before,.duo::after{content:'';position:absolute;inset:0;z-index:1;
  opacity:var(--duo-force);pointer-events:none}

.duo::before{background:var(--duo-clair);mix-blend-mode:multiply}

.duo::after{background:var(--duo-sombre);mix-blend-mode:lighten}

/* Repli : sans mix-blend-mode, les deux couches deviendraient deux aplats
   opaques et masqueraient la photo. On les retire, le filtre suffit. */
@supports not (mix-blend-mode: multiply){.duo::before,.duo::after{display:none}}


/* ------------------------------------------------------------------- LE HERO
   Seul bloc sans `.hm-b` : les photos saignent bord a bord. Le centrage sur
   `--max-width` est donc porte par `.hm-hero__txt`, en `vw` puisque le texte
   n'occupe pas toute la section au-dela de 768 px. */
.hm-hero{position:relative;isolation:isolate;display:grid;
  background:var(--color-dark);color:#fff;
  grid-template-columns:1fr;grid-template-rows:minmax(380px,auto) 128px;
  grid-template-areas:"main" "band"}


/* Le voile, generique : pose sur la zone « main », quelle que soit la photo
   qui s'y trouve a cette largeur. Opacites baissees a la demande d'Antoine ;
   contraste remesure apres coup par compositing canvas, pire cas 9,4:1 sur la
   ligne de contact — barre a 4,5:1, donc facteur 2,1 de marge. Le seuil de
   bascule vers le voile directionnel est un axe INDEPENDANT de l'echange de
   roles : un degrade relache a droite trahit des que la colonne de texte
   atteint ~90 % du panneau, et ca ne depend pas de quelle photo est dessous. */
.hm-hero::before{content:'';grid-area:main;z-index:1;pointer-events:none;
  background:linear-gradient(to top,rgba(9,9,9,.78) 0%,rgba(9,9,9,.75) 45%,
    rgba(9,9,9,.64) 74%,rgba(9,9,9,.52) 100%)}

@media (min-width:900px){
  .hm-hero::before{background:
    linear-gradient(100deg,rgba(9,9,9,.78) 0%,rgba(9,9,9,.73) 48%,
      rgba(9,9,9,.53) 78%,rgba(9,9,9,.29) 100%),
    /* plancher : nulle part la photo ne revient a 100 %. Protege le jour ou
       quelqu'un remonte --duo-lum ou met une photo plus claire. */
    linear-gradient(rgba(9,9,9,.17),rgba(9,9,9,.17))}}


.hm-hero__txt{grid-area:main;position:relative;z-index:2;align-self:center;
  padding:1.9rem max(var(--space-sm), (100vw - var(--max-width)) / 2)}

.hm-hero__txt > *{max-width:42rem}


/* Roles PAR DEFAUT sous 768 px : la camera en « bande » (couleur vraie), et
   l'entrepot en « principal » avec le texte pose dessus. Arbitrage d'Antoine
   du 10/08 : le seuil de bascule des ROLES est aligne sur celui de la MISE EN
   PAGE, pour que sous 768 px la composition reste TOUJOURS empilee — donc la
   bande TOUJOURS « en bas » au sens litteral. */
.hm-hero__cctv{grid-area:band;--duo-force:0;border-top:3px solid var(--color-primary)}

.hm-hero__live{grid-area:main}

.hm-hero__live img{object-position:36% 44%}

.hm-hero__cctv img{object-position:50% 44%}


@media (min-width:768px){
  .hm-hero{grid-template-columns:minmax(0,1fr) clamp(190px,30vw,460px);
    grid-template-rows:minmax(470px,auto);grid-template-areas:"main band";gap:3px}
  .hm-hero__cctv{grid-area:main;--duo-force:1;border-top:none}
  .hm-hero__live{grid-area:band;--duo-force:0;border-left:3px solid var(--color-primary)}
  .hm-hero__cctv img{object-position:30% 46%}
  .hm-hero__live img{object-position:50% 50%}}

@media (min-width:1100px){.hm-hero{grid-template-rows:minmax(510px,auto)}}


/* A partir de 1280 px, la disposition ne change PLUS : « main » (texte +
   camera) reste a gauche, « band » (etagères) a droite. Le seul effet propre a
   ce palier est le miroir sur la camera, demande explicitement par Antoine le
   11/08 — sur l'<img> SEULE, jamais sur `.duo` ni sur la section, qui portent
   le voile et le texte et ne doivent jamais etre retournes. */
@media (min-width:1280px){.hm-hero__cctv img{transform:scaleX(-1)}}


.hm-hero h1{color:#fff}

.hm-sub{color:#e6e3dc;font-size:.95rem}

.hm-cta2{display:flex;flex-direction:column;gap:.6rem;margin:1.1rem 0 .9rem}

.hm-hero .btn-tertiary{color:#fff;border-color:#fff}

.hm-contact{font-size:.875rem;color:#cfcbc2;margin-bottom:.6rem}

.hm-contact a{color:var(--color-primary);text-decoration:underline}

.hm-note{font-size:.875rem;margin:0}

.hm-hero .hm-note{color:#fff}

.hm-note span{color:var(--color-primary);letter-spacing:.05em}

/* ══ LE RACCORD HERO → TARIFS : « le chapô » ═════════════════════════════════
   Prend la place des règles `.hm-trust*`, parties avec le bandeau de
   réassurance le 2026-08-12.

   GESTE — le filet jaune répond au filet NOIR de 3 px qui ouvre le masthead des
   tarifs 40 px plus bas : la même ponctuation, dans l'autre couleur, une fois
   avant et une fois après. C'est ce qui fait lire les deux blocs comme une
   suite et pas comme deux morceaux collés.

   FER À GAUCHE ET NON CENTRÉ — le hero est fer à gauche, le masthead est fer à
   gauche. Un paragraphe centré réintroduirait une rupture d'axe là où on
   cherche exactement le contraire.

   CORPS — 1,0625 → 1,3125 rem. Au-dessus du corps courant (1 rem) parce que
   c'est un chapô et qu'il doit se lire comme une voix ; en dessous du H2 du
   masthead (1,375 rem) parce qu'il ne doit pas concurrencer le titre de la
   section qu'il annonce.

   LE FOND BEIGE EST LE POINT, pas une décoration : il fait le palier entre le
   noir du hero et le blanc du catalogue. Comme il est DÉCLARÉ, `.chp` doit
   figurer dans la liste des `:not()` de l'alternance — sinon la parité (0,2,0)
   écrase ce (0,1,0) au premier décalage de blocs.

   `padding-block` seulement : le padding horizontal de `.hm-b` porte
   l'expression de centrage et ne doit surtout pas être réécrit ici. Cette règle
   est APRÈS `.hm-b` dans la feuille, à spécificité égale — c'est l'ordre source
   qui tranche, ne la remonte pas.

   CONTRASTE — #1A1A1A sur #F8F7F4 ≈ 15,5:1. Aucun lien ici : la phrase renvoie
   à la grille juste dessous, le numéro est cliquable 200 px plus haut dans le
   hero et le sera encore en pied de page. Rien à mesurer côté cible tactile. */
.chp{background:var(--color-bg);padding-block:clamp(1.5rem,5vw,2.5rem)}

.chp__in{max-width:46ch}

/* Le filet est décoratif : <span> vide et aria-hidden côté markup. */
.chp__rule{display:block;width:2.5rem;height:3px;background:var(--color-primary);
  margin-bottom:.85rem}

.chp__p{margin:0;font-size:clamp(1.0625rem,1rem + .55vw,1.3125rem);line-height:1.5;
  color:var(--color-dark)}

/* LE SURLIGNAGE — il porte la PROMESSE, « l'espace qu'il vous faut ».
   Il a d'abord été posé sur « affiche ses prix », la chute différenciante ;
   Antoine l'a déplacé le 2026-08-12. Un seul surlignage dans la phrase, et pas
   deux : deux bandes jaunes en trente mots s'annulent l'une l'autre. Si la
   chute doit récupérer un accent un jour, ce sera un `<b>` — pas un second
   `<mark>`.

   `<mark>` et pas un `<span>` : l'élément existe pour ça, « marqué en raison de
   sa pertinence ». Sa couleur de fond par défaut (jaune vif du navigateur) est
   remplacée ici, et `color:inherit` annule le noir imposé par certains UA.

   PAS DE PSEUDO-ÉLÉMENT ABSOLU, à la différence du surligneur des chiffres
   d'étapes (options/etapes-options.html) : là-bas le trait passe derrière UN
   chiffre, qui ne se coupe jamais. Ici la locution peut tomber à cheval sur
   deux lignes selon la largeur, et un `::before` en `position:absolute` ne
   couvrirait que le premier fragment — le second sortirait nu, sans erreur ni
   symptôme au-dessus du point de rupture. Le dégradé porté par le fond de
   l'élément lui-même, plus `box-decoration-break:clone`, se répète correctement
   sur CHAQUE fragment de ligne.

   La bande monte à .62em depuis le bas : elle couvre le corps des lettres et
   laisse respirer les hampes hautes, ce qui donne le geste du surligneur plutôt
   que celui d'un bouton. Le texte reste #1A1A1A sur #F5C518 = 10,68:1 — le
   jaune ne porte pas le texte, il passe derrière.

   `white-space:nowrap` PAR-DESSUS `box-decoration-break`, et les deux servent.
   Sans lui, la mesure de 46ch coupait la locution en deux et laissait un ou deux
   mots seuls sous un bout de bande : un surlignage qui se brise ne souligne plus
   rien. Elle est donc rendue insécable.
   MARGE VÉRIFIÉE APRÈS LE DÉPLACEMENT, car la nouvelle locution est la moitié
   plus longue que l'ancienne : 195 px de large dans une boîte de contenu de
   288 px à 320 px de fenêtre, 231 px dans 464 px à 1280 px. Un seul fragment aux
   deux bouts, aucun débordement. La marge à 320 px n'est plus que de 93 px —
   c'est le point à re-mesurer si la formule s'allonge encore.
   `box-decoration-break` reste en place pour ce cas-là : le jour où la locution
   ne tiendra plus sur une ligne, elle se surlignera correctement sur deux au
   lieu de sortir nue.

   La graisse reste DM Sans 600 et non un font-weight sur Inter : le thème
   n'embarque qu'Inter 400/500 en woff2, un gras Inter serait synthétisé par le
   navigateur, ce que la doctrine polices du projet interdit. */
.chp__p mark{
  background:linear-gradient(to top,var(--color-primary) .62em,transparent .62em);
  color:inherit;padding-inline:.1em;white-space:nowrap;
  font-family:var(--font-display);font-weight:600;
  -webkit-box-decoration-break:clone;box-decoration-break:clone}


.hm-kicker{font-size:.6875rem;letter-spacing:.09em;font-weight:700;color:var(--color-gray);margin:0 0 .35rem}

/* La bande de trois photos qui a remplacé le bloc de conditions. Trois
   colonnes à TOUTES les largeurs — c'est le parti pris : à 375 px chaque
   vignette fait ~110 px, assez pour se lire comme une frise de contexte, pas
   comme trois illustrations. Le `gap` est serré exprès, pour que les trois
   forment un objet et non trois vignettes posées côte à côte. */
.hm-bande{display:grid;grid-template-columns:repeat(3,1fr);gap:.375rem;margin-top:1.25rem}

.hm-bande img{display:block;width:100%;aspect-ratio:4/3;object-fit:cover;
  border-radius:var(--radius-sm);background:var(--color-gray-light)}



/* « Le rail ». Le fil pointillé est tiré en `::before` sur chaque <li>, du bas
   de la pastille jusqu'au bas de l'item — la DERNIÈRE n'en porte pas, sinon le
   trajet continuerait dans le vide. Les pastilles font 44 px, la cible tactile
   du projet, même si rien n'est cliquable ici : c'est ce qui donne au rail son
   épaisseur lisible.

   La pastille d'arrivée passe en négatif — jaune sur noir plutôt que noir sur
   jaune. C'est l'arrivée, pas une quatrième étape, et ça se dit par un signe
   au lieu d'un mot de plus. Les deux sens valent 10,68:1, donc l'inversion ne
   coûte rien en lisibilité. */
.hm-steps ol{list-style:none;margin:0;padding:0}

.hm-steps li{position:relative;padding-left:3.75rem;padding-bottom:1.75rem}

.hm-steps li:last-child{padding-bottom:0}

.hm-steps li::before{content:'';position:absolute;left:21px;top:46px;bottom:-2px;width:2px;
  background-image:repeating-linear-gradient(to bottom,
    var(--color-dark) 0 3px, transparent 3px 9px)}

.hm-steps li:last-child::before{content:none}

.hm-num{position:absolute;left:0;top:0;width:44px;height:44px;border-radius:50%;
  display:grid;place-items:center;background:var(--color-primary);color:var(--color-dark);
  font-family:var(--font-display);font-weight:700;font-size:.9375rem}

.hm-steps li:last-child .hm-num{background:var(--color-dark);color:var(--color-primary)}

.hm-steps h3{margin-bottom:.25rem}

.hm-steps p{margin:0;font-size:.9rem;color:var(--color-gray);max-width:46ch}


/* Le fil PIVOTE : même pointillé, même épaisseur, sur l'axe horizontal. C'est
   ce pivot qui fait que le bureau et le mobile disent la même chose, au lieu
   d'une frise qui se replierait en liste. Le `right` négatif vaut exactement
   la gouttière, pour que le trait franchisse l'inter-colonne. */
@media (min-width:768px){
  .hm-steps ol{display:grid;grid-template-columns:repeat(3,1fr);gap:0 var(--space-md)}
  .hm-steps li{padding-left:0;padding-bottom:0;padding-top:3.75rem}
  .hm-steps li::before{left:52px;right:calc(var(--space-md) * -1);top:21px;bottom:auto;
    width:auto;height:2px;
    background-image:repeating-linear-gradient(to right,
      var(--color-dark) 0 3px, transparent 3px 9px)}}



/* ══ NOS AVANTAGES — le style « pastilles » ══════════════════════════════════ */
.avp { background: var(--color-bg); }

/* La respiration est le sujet : le bloc ouvre son padding vertical au-delà
   de `.hm-b` (écart assumé, même logique que le rail retenu pour les
   étapes — etapes-options.html:52). */
.avp { padding-block: clamp(2.5rem, 7vw, 4rem); }

.avp h2 { text-align: center; margin-bottom: clamp(1.5rem, 4.5vw, 2.75rem); }


/* --- Les six pastilles ----------------------------------------------------
   MOBILE (< 768 px) : des RANGÉES — pastille à gauche, label à droite. La
   grille est plafonnée à 400 px et centrée : à 375 px elle occupe toute la
   largeur utile, au-delà elle ne s'étire pas en rangées filiformes.
   La pastille descend à 60 px sur mobile : six rangées de 80 px feraient
   ~100 px de plus sur un écran où le bloc doit rester une pause, et à 60 px
   le pictogramme de 28 px reste parfaitement lisible.
   DESKTOP (≥ 768 px) : des COLONNES centrées — 3 colonnes sur 2 rangs en
   tablette, les 6 en un seul rang à partir de 1024 px (à 1200 px de contenu,
   chaque colonne fait ~180 px : « Vidéosurveillance », le label le plus
   long, tient sur sa ligne à 0,875 rem). */
.avp__grid { list-style: none; margin: 0 auto; padding: 0;
  display: grid; gap: 1.1rem; max-width: 400px; }

.avp__item { display: flex; align-items: center; gap: 1rem; }


.avp__dot { flex: 0 0 auto; width: 60px; height: 60px; border-radius: 50%;
  background: var(--color-primary); color: var(--color-dark);
  display: grid; place-items: center;
  /* L'ombre du socle, pas une ombre inventée : elle décolle le disque du
     fond — c'est elle qui fait « pastille » et pas « puce ». */
  box-shadow: var(--shadow-card); }

/* display:block corrige le vrai défaut, pas un décalage de mise en page :
   un <svg> a un display inline par défaut, donc il s'insère comme du texte
   -- il hérite du line-height ambiant et se pose sur une ligne de base qui
   lui réserve de la place sous la ligne pour les jambages (descenders),
   même s'il ne contient aucun texte. Un moteur qui blockifie mal les items
   de grille (webkit historiquement) rend alors le picto poussé vers le
   haut du disque, jamais parfaitement au centre. `display:block` retire le
   svg du contexte de ligne : il n'y a plus de line-height, plus de ligne de
   base à respecter, et `place-items:center` du parent centre alors sa
   vraie boîte de 28/34 px, sans le padding fantôme sous l'icône. */
.avp__dot svg { display: block; width: 28px; height: 28px; }


/* Le label : deux lignes, UNE en gras qui porte le bénéfice. Le gras passe
   par DM Sans 700 et non par un `font-weight:700` sur Inter : le thème
   n'embarque que Inter 400/500 en woff2, un gras Inter serait synthétisé
   par le navigateur (interdit par la doctrine polices du projet). DM Sans
   est déjà la voix des titres — le mot en gras parle comme un titre, c'est
   voulu. Ligne normale en --color-gray (#595959 : 4,96:1 sur #F8F7F4, AA),
   ligne en gras en --color-dark (~15,5:1). */
.avp__lbl { font-size: var(--font-size-small); line-height: 1.4;
  color: var(--color-gray); }

.avp__lbl b { font-family: var(--font-display); font-weight: 700;
  font-size: 0.9375rem; color: var(--color-dark); }


/* DE LA GRILLE AU FLEX, le 2026-08-12. La grille etait dessinee pour SIX items ;
   on est passe a cinq. Consequence, invisible dans le code et flagrante a
   l'ecran : `repeat(6, 1fr)` laissait la sixieme colonne VIDE, donc les cinq
   pastilles se tassaient a gauche d'un conteneur pourtant centre — mesure a
   1280 px, centre du conteneur 640 comme le titre, mais tout le contenu decale.
   Meme defaut a 768 px : `repeat(3, 1fr)` faisait une seconde rangee de deux,
   calee a gauche.
   Le flex avec `justify-content:center` centre CHAQUE rangee quel que soit le
   nombre d'items — il ne se casse plus si on en ajoute ou en retire un, ce qui
   vient d'arriver deux fois. `flex-basis` fixe la largeur de colonne que la
   grille donnait. */
@media (min-width: 768px) {
  .avp__grid { display: flex; flex-wrap: wrap; justify-content: center;
    max-width: none; gap: 2rem 1.5rem; }
  .avp__item { flex: 0 1 190px; flex-direction: column; text-align: center; gap: 0.9rem; }
  .avp__dot { width: 80px; height: 80px; }
  .avp__dot svg { width: 34px; height: 34px; }
}

@media (min-width: 1024px) {
  /* Les cinq tiennent sur une ligne : 5 x 190 + 4 x 24 = 1 046 px, sous les
     1 200 px de la colonne de contenu. `nowrap` l'impose plutot que de le
     laisser au hasard des largeurs de label. */
  .avp__grid { flex-wrap: nowrap; }
}


/* --- Les six items secondaires --------------------------------------------
   Éclairage, Anti-nuisibles, Étanche à la lumière / UV, Condensation
   limitée, Manœuvre remorque facile, Changement de taille : ils ne
   DISPARAISSENT pas, ils changent de rang. Douze pastilles diluraient les
   six arguments porteurs ; ces six-là sont des compléments, pas des
   réponses aux objections — ils passent en ligne compacte de texte sous la
   composition, séparés par des points médians. #595959 sur #F8F7F4 : 4,96:1,
   au-dessus du 4,5:1 exigé pour ce corps de texte (0,875 rem non gras). */
.avp__more { margin: clamp(1.5rem, 4vw, 2.25rem) auto 0; max-width: 62ch;
  text-align: center; font-size: var(--font-size-small);
  color: var(--color-gray); }


/* --- La bande photos (filmstrip) -------------------------------------------
   Les photos de .hm-bande ne disparaissent pas non plus : elles descendent
   SOUS les pastilles, en bande fine de 5 vignettes qui ferme le bloc — la
   preuve en images après l'argument en mots, et une transition visuelle
   vers le rail blanc qui suit. 5 colonnes à TOUTES les largeurs : à 375 px
   chaque vignette fait ~62 px — c'est une texture de preuve, pas une
   galerie, on ne lui demande pas de détail à cette taille.
   Rapport 3/2 : les trois sources 1,677 / 1,366 / 1,5 l'encadrent, `cover`
   ne rogne que les bords (même arbitrage que .hm-bande, build-home.py
   ~305-314). `aspect-ratio` réserve la boîte : décalage de mise en page nul.
   La 5e case est un EMPLACEMENT RÉSERVÉ : aplat --color-gray-light nu, même
   ratio, aucun texte, aucune icône, aria-hidden — une photo arrivera plus
   tard, la case tient sa place pour que la composition soit jugée à 5. */
.avp__strip { display: grid; grid-template-columns: repeat(5, 1fr);
  gap: 0.5rem; margin-top: clamp(1.5rem, 4vw, 2.5rem); }

.avp__clavier { object-position: 50% 42%; }

.avp__strip img, .avp__slot { width: 100%; aspect-ratio: 3 / 2;
  object-fit: cover; border-radius: var(--radius-sm); }

.avp__slot { background: var(--color-gray-light); }


/* ══ AVIS ═══════════════════════════════════════════════════════════════════
   Repris des composants de la page garde-meuble (`.car`, `.quote`, `.rev__*`),
   avec trois écarts assumés pour que le bloc ne soit pas un calque :
     · la pastille d'initiales passe en négatif (fond `--color-dark`) au lieu du
       jaune pâle — le jaune reste sur les étoiles et nulle part ailleurs ;
     · un filet vertical `--color-dark` remplace le contour complet, écho au
       filet que portaient les citations d'avant ;
     · la note globale EST le lien vers la fiche Google, au lieu d'un libellé
       inerte doublé d'un lien « voir les avis ».
   Neuf avis dans un carrousel tiennent la hauteur d'un seul : c'est ce qui rend
   le bloc plus court qu'avec trois citations empilées. */
.hm-avis .hm-note{margin:0}

.hm-avis .stars{color:var(--color-primary);letter-spacing:.06em}

.car{position:relative}

.car__head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:.5rem 1rem;margin:.85rem 0}

.car__nav{display:flex;gap:.5rem;align-items:center}

.car__btn{width:44px;height:44px;border-radius:50%;border:2px solid var(--color-dark);
  background:transparent;color:var(--color-dark);display:grid;place-items:center;cursor:pointer;
  padding:0;transition:transform var(--duration-fast) var(--ease-out),
                       opacity var(--duration-fast) var(--ease-out)}

.car__btn svg{width:20px;height:20px}

/* `[disabled]` est posé par le script, jamais dans le HTML servi : si UCSS
   supprime la règle faute de la voir dans le DOM crawlé, la flèche reste
   simplement pleinement opaque — la panne dégrade vers « visible ». */
.car__btn[disabled]{opacity:.35;cursor:default}

.car__btn:active{transform:scale(.94)}

@media (hover:hover) and (pointer:fine){
  .car__btn:not([disabled]):hover{transform:translateY(-2px)}
}

/* `proximity` et JAMAIS `mandatory` : en mandatory le navigateur ramène le
   scrollTo des flèches sur le point d'ancrage courant et le carrousel ne
   bouge plus. */
.car__track{display:grid;grid-auto-flow:column;grid-auto-columns:78%;gap:.75rem;
  overflow-x:auto;scroll-snap-type:x proximity;scroll-behavior:smooth;
  padding-bottom:.5rem;scrollbar-width:none}

.car__track::-webkit-scrollbar{display:none}

.car__track > *{scroll-snap-align:start}

/* 768 et 1024, et non plus 700 et 1050. Les deux valeurs d'origine étaient
   propres au carrousel : la page changeait donc de gabarit QUATRE fois entre
   375 et 1440 px (700, 768, 1024, 1050) alors que le projet en a déclaré deux.
   Deux d'entre elles étaient à 50 px l'une de l'autre, ce qui produisait deux
   ressauts rapprochés dont un seul était voulu. */
@media (min-width:768px){.car__track{grid-auto-columns:calc(50% - .375rem)}}

@media (min-width:1024px){.car__track{grid-auto-columns:calc(33.333% - .5rem)}}

/* position:relative : les `.visually-hidden` des avis sont en position:absolute,
   sans ancêtre positionné ils se calaient sur le bloc conteneur initial,
   échappaient au rognage de la piste et faisaient déborder la page. */
.quote{position:relative;margin:0;display:flex;flex-direction:column;gap:.35rem;
  padding:.85rem .95rem;background:var(--color-bg);border-radius:0 var(--radius-md) var(--radius-md) 0;
  border:1px solid var(--color-gray-light);border-left:3px solid var(--color-dark)}

.hm-avis:nth-child(even) .quote{background:#fff}

.quote .stars{font-size:.8rem;line-height:1}

.hm-avis .quote p{font-size:.875rem;line-height:1.5;margin:0 0 .2rem;flex:1 1 auto;
  display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow:hidden}

/* margin-top:auto aligne les pieds d'une carte à l'autre : les citations
   n'ont pas la même longueur, et « Aimable et pratique. » fait une ligne. */
.quote .rev__who{display:flex;margin-top:auto;align-items:center;gap:.45rem;min-width:0}

.quote .rev__ini{flex:0 0 1.6rem;height:1.6rem;border-radius:50%;background:var(--color-dark);
  color:#fff;display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--font-display);font-weight:700;font-size:10px}

/* nowrap + troncature : la signature la plus longue repassait à la ligne
   à 375 px et le pied de carte montait de 15 px sur cette carte seulement. */
.quote .rev__meta{display:flex;flex-wrap:nowrap;align-items:baseline;gap:.35rem;min-width:0;
  font-size:.75rem;line-height:1.3;color:var(--color-gray)}

.quote .rev__name{font-family:var(--font-display);font-weight:700;color:var(--color-dark);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.quote .rev__date{white-space:nowrap;flex:0 0 auto}

.quote .rev__sep{flex:0 0 auto}

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


.hm-faq details{border-bottom:1px solid var(--color-gray-light)}

/* 48 px et non 44 : c'est la valeur du système pour un `summary`, qui est la
   cible la plus souvent touchée d'une page et la plus large. */
.hm-faq summary{cursor:pointer;list-style:none;padding:1.05rem .25rem;font-weight:600;
  font-size:.9375rem;min-height:48px;display:flex;align-items:center;gap:.5rem}

.hm-faq summary::-webkit-details-marker{display:none}

/* Le « + » PIVOTE de 45°, il n'est pas remplacé par un « − » : un glyphe qui
   change est un saut, une rotation est un mouvement, et c'est le même signe
   qui devient sa propre croix de fermeture. */
.hm-faq summary::after{content:"+";margin-left:auto;font-weight:400;font-size:1.35rem;
  color:var(--color-gray);line-height:1;
  transition:transform var(--duration-normal) var(--ease-out)}

.hm-faq details[open] summary::after{transform:rotate(45deg)}

.hm-faq details > div{padding:0 .25rem 1rem}

.hm-faq details > div p{font-size:.9rem;margin:0}

.hm-faq-more{margin-top:1rem;font-size:.9rem}


/* Ouverture de la réponse : opacité + 4 px de translation, JAMAIS la hauteur —
   animer une hauteur sur mobile fait du jank, et `details` n'est de toute
   façon pas interpolable. Sous reduced-motion la réponse apparaît d'un coup,
   ce qui reste l'état complet et lisible. */
@media (prefers-reduced-motion: no-preference){
  .hm-faq details[open] > div{animation:faq-in var(--duration-normal) var(--ease-out)}
  @keyframes faq-in{from{opacity:0;transform:translateY(-4px)}}
}


.hm-zone table{width:100%;border-collapse:collapse;font-size:.875rem;margin-bottom:.6rem}

.hm-zone th,.hm-zone td{text-align:left;padding:.55rem .4rem;border-bottom:1px solid var(--color-gray-light)}

.hm-zone th{font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;color:var(--color-gray)}

.hm-adr{font-size:.8125rem;color:var(--color-gray)}

.hm-geo{margin-top:1rem;padding-top:1rem;border-top:1px solid var(--color-gray-light)}

.hm-geo p{font-size:.875rem;color:var(--color-gray)}


/* ══ CARTE DE LA ZONE — voie 1, fond OSM figé et auto-hébergé ══════════════
   Sous 768 px la carte passe AU-DESSUS de la prose : sept phrases de texte SEO
   avant le premier repère visuel, c'était l'ordre le plus dur à lire au pouce.
   Au-delà, une grille à deux colonnes la met à côté (règle inchangée depuis
   l'iframe Google, ci-dessous).

   `aspect-ratio` et pas la `height:400` du gabarit de phase-5 : une hauteur
   fixe donne une carte écrasée à 375 px et étirée à 1280 px, alors que le
   cadre doit garder la même forme partout — c'est précisément ce que le
   propriétaire va regarder en redimensionnant. La boîte est réservée par
   `width`/`height` ET par `aspect-ratio` (même ratio, 4/3, aux deux endroits) :
   rien ne bouge, qu'on lise l'attribut HTML avant que l'image n'arrive ou la
   règle CSS une fois qu'elle y est.

   L'image est posée en absolu et coupée par `object-fit:cover` — plus besoin
   du `:not([src])` de l'iframe (il n'y a plus de src différé : l'image est
   locale, `loading="lazy"` natif suffit). Par-dessus, le calque HTML/CSS de la
   voie 1 : épingle SVG jaune cerclée de noir, cartouche du nom, mentions des
   deux pays, barre d'adresse avec le bouton Itinéraire — repris à l'identique
   de `options/carte-options.html#voie1`. */
.hm-map{margin:0 0 1rem}

.hm-map__frame{position:relative;aspect-ratio:4/3;overflow:hidden;
  background:var(--color-gray-light);border:1px solid var(--color-gray-light);
  border-radius:var(--radius-md)}

.hm-map__img{position:absolute;inset:0;display:block;
  width:100%;height:100%;object-fit:cover}


/* L'épingle. Jaune sur fond clair = 1,52:1, illisible seule : c'est le FILET
   NOIR de 2 px qui porte le contraste (16,25:1 sur le fond crème), pas le
   jaune, qui ne fait que signer. Règle WCAG 1.4.11 (3:1 mini pour un objet
   graphique porteur d'information) largement tenue par le filet. */
.hm-map__pin{position:absolute;width:34px;height:46px;
  transform:translate(-50%,-100%);pointer-events:none;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.35))}

.hm-map__pin svg{display:block;width:100%;height:100%}


/* Cartouche du site : fond noir, texte blanc, 17,4:1. Posé SOUS l'épingle et
   décalé, pour ne jamais masquer le point exact. */
.hm-map__chip{position:absolute;transform:translate(-50%,.35rem);
  background:var(--color-dark);color:#fff;
  font-family:var(--font-display);font-weight:700;font-size:.75rem;
  padding:.25rem .5rem;border-radius:var(--radius-sm);
  white-space:nowrap;pointer-events:none;box-shadow:0 1px 4px rgba(0,0,0,.3)}

.hm-map__chip b{color:var(--color-primary);font-weight:700}


/* Les deux mentions de pays ne portent AUCUNE distance et ne dessinent aucun
   tracé : elles nomment ce que le fond montre déjà. Un croquis dessiné à la
   main a déjà été retiré de ce bloc pour avoir contredit le « 1 km de la
   frontière » de la prose voisine ; rien ici ne doit rouvrir ce dossier. */
.hm-map__pays{position:absolute;transform:translate(-50%,-50%);
  font-family:var(--font-display);font-weight:700;
  font-size:.6875rem;letter-spacing:.16em;
  color:var(--color-dark);background:rgba(250,249,246,.82);
  padding:.18rem .45rem;border-radius:var(--radius-sm);pointer-events:none}


/* Barre basse : adresse + itinéraire. Fond sombre translucide, le blanc tient
   largement. Le bouton fait 44 px de haut au doigt (cible tactile). */
.hm-map__bar{position:absolute;left:0;right:0;bottom:0;
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .75rem;
  padding:.6rem .7rem;background:rgba(26,26,26,.9);color:#fff}

.hm-map__bar p{margin:0;flex:1 1 12rem;font-size:.8125rem;color:#fff}

.hm-map__cta{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;padding:0 1rem;
  background:var(--color-primary);color:var(--color-dark);
  font-family:var(--font-display);font-weight:700;font-size:.875rem;
  border-radius:var(--radius-sm);text-decoration:none}

.hm-map__cta:hover{background:var(--color-primary-dark)}

.hm-map__cta:focus-visible{outline:3px solid #fff;outline-offset:2px}


.hm-map__attrib{margin-top:.4rem;font-size:.75rem;color:var(--color-gray)}

.hm-map__attrib a{color:var(--color-primary-text)}


@media (min-width:768px){
  .hm-geo{display:grid;grid-template-columns:minmax(0,320px) minmax(0,1fr);
    gap:1rem 1.5rem;align-items:start}
  .hm-map{margin-bottom:0}
}


.hm-usages .hm-bridge{font-size:.9rem;color:var(--color-gray)}

.hm-prodgrid{list-style:none;margin:1rem 0 0;padding:0;display:grid;gap:.75rem}

.hm-prodgrid li{padding:.9rem 1rem;background:var(--color-bg);border-radius:var(--radius-sm)}

.hm-usages:nth-child(even) .hm-prodgrid li{background:#fff}

.hm-prodgrid h3{margin:0 0 .3rem}

.hm-prodgrid p{margin:0;font-size:.8375rem;color:var(--color-gray)}


/* ══ AVANTAGES · 3 FAMILLES ═════════════════════════════════════════════════
   Transplanté de `.advfams/.advfam` (page garde-meuble). Cartes blanches à
   bordure fixe, PAS de bascule via `:nth-child(even)` comme `.hm-guides li` :
   insérer ce bloc décale la parité de toutes les sections qui le suivent, et
   une carte à fond fixe reste lisible quel que soit le fond (blanc ou
   `--color-bg`) de la section — la bordure `--color-gray-light` fait le
   contraste dans les deux cas, sans dépendre du rang. */
.hm-fams__grid{display:grid;gap:1rem;grid-template-columns:1fr;margin-top:.25rem}

@media (min-width:768px){.hm-fams__grid{grid-template-columns:repeat(3,1fr)}}

.hm-fam{background:#fff;border:1px solid var(--color-gray-light);
  border-radius:var(--radius-lg);padding:1rem 1.1rem}

.hm-fam__hd{display:flex;align-items:center;gap:.6rem;margin-bottom:.5rem}

.hm-fam__ico{width:40px;height:40px;flex:0 0 auto}

.hm-fam__hd h3{margin:0;font-size:.95rem}

.hm-fam__list{list-style:none;margin:0;padding:0;display:grid;gap:.4rem}

.hm-fam__list li{display:flex;align-items:center;gap:.5rem;font-size:.8125rem;color:var(--color-gray)}

.hm-fam__list svg{flex:0 0 auto;color:var(--color-dark)}


.hm-final{background:var(--color-dark);color:#fff;text-align:center}

.hm-final h2{color:#fff}

.hm-final p{font-size:.9rem;color:#e6e3dc}

.hm-final .btn-primary{width:100%;margin:.5rem 0}

.hm-tel a{color:var(--color-primary)}


/* ══ CIBLES TACTILES DES LIENS EN LIGNE ═════════════════════════════════════
   Un lien au fil du texte fait ~19 px de haut : injouable au pouce, dehors,
   d'une main. Le procédé du projet lui donne 24 px de rembourrage vertical
   puis les reprend en marge négative, donc la CIBLE grandit sans que le
   rythme du texte bouge d'un pixel. `inline-block` n'est pas décoratif :
   sans lui la marge verticale négative ne s'applique pas et la boîte
   n'atteint pas 44 px.
   La déclaration ci-dessous n'est pas nouvelle — c'est celle que portait
   `.tc4-callout__obsolete-nomatch`, règle morte du fragment de tuiles qui ne
   correspondait à aucun élément ; elle est reprise telle quelle et le
   sélecteur mort a été supprimé. Cette feuille en portait trois copies
   (dont deux depuis disparues avec leurs blocs), elle n'en porte plus qu'une ;
   la quatrième vit dans le fragment de tuiles (.tc4-foot a, .tc4-micro a) et
   y reste, c'est sa feuille. */
/* ÉCART ENTRE DEUX LIENS EN LIGNE CONSÉCUTIFS.
   Le procédé ci-dessous gonfle la boîte de 0,75 rem vers le HAUT et vers le
   BAS. Deux liens sur deux lignes voisines séparées par moins de 1,5 rem ont
   donc des boîtes qui SE RECOUVRENT, et le recouvrement va au dernier arrivé
   dans le DOM. Mesuré à 375 px avant correction :
     · sous-grille tarifs — ses deux liens se recouvraient de 14,4 px, et
       `elementFromPoint` au bas du premier rendait le SECOND. Ce bloc a été
       remplacé par la bande de photos le 11/08, la règle qui l'écartait est
       donc supprimée ; le cas reste documenté parce qu'il se reproduira ;
     · CTA final — le bouton et le lien tel: se recouvraient de 4 px.
   La correction NE TOUCHE PAS aux zones tactiles, qui font 46,3 px et sont
   conformes : elle écarte. L'écart visé est de 24 px ENTRE LES BOÎTES, d'où
   24 px + les deux débords de 0,75 rem entre les deux lignes de texte.
   Reste hors de portée de cette règle : les liens qui se suivent DANS un même
   paragraphe de prose (bloc « Zone desservie »), où deux lignes successives
   recouvrent leurs boîtes de 24 px par construction. Les écarter reviendrait à
   doubler l'interligne du paragraphe ; c'est un arbitrage de fond, pas un
   correctif, et il n'est pas rendu ici.
   AU PORTAGE : `:has()` décrit ici l'intention (« un lien qui suit un lien »)
   sans toucher au markup, ce qui convient à une maquette. Un sélecteur non
   compris fait tomber la règle EN SILENCE et le recouvrement revient — donc
   côté thème, poser plutôt une classe explicite sur le paragraphe. */
.hm-final .hm-tel{margin-top:calc(24px + .75rem)}


.hm-contact a,
.hm-faq details > div a,
.hm-faq-more a,
.hm-avis .hm-note a,
.hm-zone td a,
.hm-geo a,
.hm-tel a{
  display:inline-block;
  padding:0.75rem 0.35rem;
  margin:-0.75rem -0.35rem;
}

/* ---------------------------------------------------------------------------
   VALEURS DÉCLARÉES ICI, ET POURQUOI
   1. Ombres / radius / bordures du HANDOVER §3 : lab.css porte encore les
      anciennes valeurs. On ne redéclare PAS les tokens du socle, on déclare
      des variables --tc4-* sur les racines du fragment.
   2. #EFEDE7 / #F0E3B2 / #3A3A3A : dérivés du HANDOVER §3, pas une palette neuve.
   3. Grille 3 colonnes dès 768 px : contrainte de la maquette de homepage.
   4. La colonne média des tuiles de cellule passe de 46 % à 42 %. Ce n'est
      pas un choix esthétique, c'est l'égalisation des deux panneaux avec les
      NOUVEAUX dessins, qui sont plus plats que les anciens (rapport l/h de
      1,55-1,66 contre 1,21-1,49). À 375 px, contenu de tuile 311, gouttière 16 :
        46 % → photo 118 px de haut, plan du 45 m² 101 px → la photo domine
        42 % → photo 109 px,          plan du 45 m² 111 px → à 2 px près
      À 42 % la rangée est plus courte de ~8 px ET le dessin gagne 12 px de
      large, c'est-à-dire 0,8 px de corps sur ses cotes. Les deux vont dans le
      même sens, ce qui n'était pas le cas avec les dessins de la v2 initiale.
   --------------------------------------------------------------------------- */

.tc4-grid, .tc4-foot, .tc4-compact, .tc4-head {
  --tc4-shadow-card:  0 1px 2px rgba(26,26,26,.05), 0 4px 12px rgba(26,26,26,.06);
  --tc4-shadow-pop:   0 2px 6px rgba(26,26,26,.07), 0 24px 48px -16px rgba(26,26,26,.22);
  --tc4-r:      12px;
  --tc4-r-xl:   16px;
  --tc4-line:   #EFEDE7;   /* bordure de carte — l'ombre porte la profondeur */
  --tc4-plaque: #F0E3B2;   /* bordure de la plaque prix */
  --tc4-ink-2:  #3A3A3A;   /* 10,4:1 sur blanc — texte d'ancrage du coût */
}


/* --- en-tête de la grille --------------------------------------------------- */
.tc4-head { margin-bottom: var(--space-sm); }

.tc4-head p {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--font-size-small);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-primary-text);      /* #7A6200 — 5,87:1 sur blanc */
}

.tc4-head p::before {
  content: ""; display: inline-block; width: 1.5rem; height: 2px;
  background: var(--color-primary); margin-right: .5rem; vertical-align: .25em;
}


/* LA LÉGENDE GÉNÉRALE DES PLANS A ÉTÉ RETIRÉE (demande 4).
   Elle portait trois conventions : la silhouette d'1,70 m, l'échelle propre à
   chaque dessin, et la lecture de la fourchette de hauteur. Aucune n'est
   perdue : les trois sont maintenant énoncées dans le `aria-label` de CHAQUE
   plan, c'est-à-dire au plus près de l'objet qu'elles décrivent. Un lecteur
   d'écran les entend, un lecteur voyant lit un dessin qui n'est plus précédé
   d'un mode d'emploi. La seule note visible qui subsiste est celle du
   120 m²+, parce qu'elle ne décrit pas une convention de dessin : elle dit
   que la surface n'est pas due d'avance, et sans elle le dessin se lit
   « grand hangar » au lieu de « modulable ». */

/* --- grille ---------------------------------------------------------------- */
.tc4-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-sm);
  padding-top: 14px;                     /* place du badge en débord haut */
  align-items: stretch;
}

@media (min-width: 768px) {
  .tc4-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-smd) var(--space-sm); }
  .tc4-tile--lead { grid-column: 1 / -1; }
}


.tc4-tile {
  position: relative;
  background: var(--color-white);
  border: 1px solid var(--tc4-line);
  border-radius: var(--tc4-r);
  box-shadow: var(--tc4-shadow-card);
}


/* < 768 px : DEUX COLONNES, LA RANGÉE 1 EST [photo | plan], LE RESTE SUIT.
   ──────────────────────────────────────────────────────────────────────────
   Le placement explicite par numéro de rangée de la v2 initiale a été
   remplacé par un placement automatique : seuls la photo et le plan sont
   posés à la main sur la rangée 1, tout le reste s'écoule en pleine largeur
   dans l'ordre du source. C'est ce qui permet d'insérer la note du 120 m²+
   sous les visuels sans renuméroter quatre règles et leur double `:has()`.
   POURQUOI LE PLAN EST LÀ ET PAS AILLEURS — les trois pistes écartées :
   · plan en médaillon dans un angle de la photo → 60 % de 131 px = 79 px de
     dessin, cotes à 5 px : illisible, et posé SUR la photo il redevient un
     calque, ce que la révision du 05/08 avait explicitement retiré ;
   · plan en pleine largeur sous la photo → il faut le plafonner sinon il
     coûte ~165 px, et la colonne 2 de la rangée 1 reste vide. Deux fois cher ;
   · plan au survol → interdit : la silhouette d'1,70 m est une information
     UNIQUE et il n'y a pas de survol sur mobile, où passe 79 % du trafic. */
.tc4-row {
  display: grid;
  grid-template-columns: minmax(0, 42%) minmax(0, 1fr);
  column-gap: var(--space-sm);
  padding: var(--space-sm);
  align-content: start;
}

.tc4-row > *            { grid-column: 1 / -1; }

.tc4-row > .tc4-media   { grid-column: 1; grid-row: 1; align-self: start; }

.tc4-row > .tc4-planbox { grid-column: 2; grid-row: 1; }

.tc4-row > .tc4-id      { margin-top: var(--space-xs); }

.tc4-row > .tc4-rest    { margin-top: var(--space-xs); }

.tc4-row > .tc4-ctas    { margin-top: var(--space-xs); }


@media (min-width: 768px) {
  /* Une seule colonne : la photo passe en bandeau, le plan sous elle. On
     quitte la grille pour une colonne flex — `.tc4-rest` absorbe le mou
     (`flex: 1`), donc les CTA des trois cellules s'alignent au pixel sans
     qu'aucune rangée n'ait à être numérotée. */
  .tc4-row { display: flex; flex-direction: column; padding: 0; }
  /* `align-self: stretch` ANNULE le `align-self: start` de la règle de base, et
     ce n'est pas une redondance : en régime GRILLE (< 768 px) `align-self`
     gouverne l'axe de BLOC, et `start` y colle la photo en haut de sa rangée,
     ce qui est l'intention. Passé en flex COLONNE, le même mot-clé gouverne
     l'axe horizontal : la figure sortait du régime « remplir » pour tomber en
     shrink-to-fit, c'est-à-dire à la valeur littérale de son attribut `sizes`.
     Mesuré avant correction : carte 319,7 px et photo 235,0 px à 1023 px de
     viewport, soit 84,7 px de blanc à droite sur les trois cartes ; 43,7 px à
     900 px. À 768 et 1024 pile l'écart tombait à 0 par coïncidence — la valeur
     littérale y dépassait la place disponible et se faisait rogner — d'où un
     défaut invisible à ceux qui testent aux points de rupture déclarés.
     Aggravant : le liseré jaune de `.tc4-tile--feat::before` court sur toute la
     largeur de la carte ; une photo plus étroite que lui se lisait comme une
     image mal chargée. */
  .tc4-row > .tc4-media   { flex: none; align-self: stretch; border-radius: var(--tc4-r) var(--tc4-r) 0 0; }
  .tc4-row > .tc4-planbox { flex: none; margin: var(--space-sm) var(--space-sm) 0; }
  .tc4-row > .tc4-id      { padding: var(--space-xs) var(--space-sm) 0; margin-top: 0; }
  .tc4-row > .tc4-rest    { flex: 1 1 auto; padding: 0 var(--space-sm); margin-top: var(--space-xs); }
  .tc4-row > .tc4-ctas    { margin: var(--space-sm); }
}


/* MOMENT JAUNE 1/3 — le liseré 4 px en haut de la carte mise en avant.
   Sur le 45 m², le meilleur vendeur (BRIEF-V2 §0.4), pas sur le box. */
.tc4-tile--feat { box-shadow: var(--tc4-shadow-pop); }

.tc4-tile--feat::before {
  content: ""; position: absolute; top: -1px; left: -1px; right: -1px; height: 4px;
  background: var(--color-primary);
  border-radius: var(--tc4-r) var(--tc4-r) 0 0;
}

/* Le badge n'est plus POSÉ nulle part (red line du 07/08). Sa règle survit
   pour une seule raison : `GARDER_BADGE = True` dans build-home.py le
   réinjecte tel quel dans les maquettes de home. Sans ce style, le booléen
   rendrait un badge nu. À supprimer le jour où le booléen disparaît. */
.tc4-badge {
  position: absolute; top: -14px; left: var(--space-sm); z-index: 1;
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .3rem .7rem; border-radius: 999px;
  background: var(--color-dark); color: var(--color-white);   /* 17,4:1 */
  font-family: var(--font-display); font-size: var(--font-size-xs); font-weight: 700;
  letter-spacing: .03em; white-space: nowrap;
}

.tc4-badge b { color: var(--color-primary); font-weight: 700; }
  /* 10,68:1 sur #1A1A1A */

/* --- la tuile box, développée ---------------------------------------------- */
.tc4-tile--lead {
  display: grid; grid-template-columns: 1fr;
  border-radius: var(--tc4-r-xl);
  box-shadow: var(--tc4-shadow-pop);
  overflow: hidden;
}

@media (min-width: 768px) {
  .tc4-tile--lead { grid-template-columns: minmax(0, 44%) minmax(0, 1fr); align-items: center; }
}

.tc4-tile--lead .tc4-body { padding: var(--space-smd); }

@media (min-width: 1024px) { .tc4-tile--lead .tc4-body { padding: var(--space-md); } }


/* --- LES TROIS VISUELS DU BOX ----------------------------------------------
   ┌───────────────────────────────────────┐
   │  photo-box-charge, pleine largeur, 4:3│  ← la vraie photo : deux
   ├──────────────────┬────────────────────┤    personnes, un carton porté,
   │  rendu 3D 2,048  │  plan iso, maille  │    l'échelle par le corps
   └──────────────────┴────────────────────┘
   LE PROBLÈME DE COMPOSITION : les deux visuels du bas ont des ratios qui ne
   se rencontrent pas — 2,048 pour le rendu détouré, 1,64 pour le plan. Les
   mettre côte à côte à hauteur égale, c'est accepter que l'un des deux ait du
   vide vertical. La résolution tient en une observation vérifiée pixel par
   pixel : le rendu est un objet DÉTOURÉ sur un fond #FFFFFF pur (coins et
   bords testés à 255,255,255). Posé dans un panneau blanc et centré
   verticalement, son vide n'existe pas à l'œil — c'est la seule des deux
   images qui peut absorber la différence sans qu'on la voie.
   Donc : le plan commande la hauteur de la rangée, le rendu s'y centre.
   LE PARTAGE EST 44 / 56, EN FAVEUR DU PLAN, et c'est de la lisibilité, pas
   du goût : le texte d'un SVG à viewBox suit l'échelle du dessin, le corps
   rendu vaut font-size × largeur / 272. Sous 156 px de dessin les cotes
   tombent sous 9 px. Le rendu, lui, ne porte aucun texte : il peut rétrécir.
   LES DEUX PANNEAUX PORTENT LE MÊME CADRE (1 px #EFEDE7, même rayon, même
   hauteur) et des fonds différents — blanc pour l'image, crème pour le
   dessin. Même statut, deux registres : on voit d'un coup d'œil que ce ne
   sont pas deux photos. */
.tc4-pair {
  display: grid;
  grid-template-columns: minmax(0, 44%) minmax(0, 1fr);
  gap: var(--space-sm);
  align-items: stretch;
  /* Pas de marge basse sous 768 px : le `padding` de `.tc4-body` (24 px)
     sépare déjà la paire du texte, et 16 px de plus n'étaient qu'un blanc
     supplémentaire sur la tuile la plus haute de la page. À partir de 768 px
     la colonne média est centrée dans la tuile et peut en devenir la plus
     haute — la marge revient pour qu'elle ne touche pas le bord. */
  margin: var(--space-xs) var(--space-sm) 0;
}

@media (min-width: 768px) { .tc4-pair { margin-bottom: var(--space-sm); } }

.tc4-rendu {
  position: relative; margin: 0; overflow: hidden; height: 100%;
  background: var(--color-white);
  border: 1px solid var(--tc4-line);
  border-radius: var(--radius-sm);
}

.tc4-rendu > img { width: 100%; height: 100%; object-fit: contain; }


/* --- média : BOÎTE 6/5 DES TROIS CELLULES ----------------------------------
   Reprise de la v1 : les sources ont des ratios différents (1,05 / 1,33 /
   1,50), une boîte unique à 1,2 en `cover` avec un `object-position` par
   image se lit comme une décision et pas comme un accident.

   LE `sizes` DES TROIS PHOTOS DE CELLULE, EN FORMULE ET NON EN CONSTANTES.
   Trois valeurs figées (379 / 235 / 131 px) y tenaient lieu de géométrie ;
   elles étaient la CAUSE du shrink-to-fit décrit plus haut, et une fois la
   largeur rendue au conteneur elles devenaient fausses dans l'autre sens.
   La boîte se calcule, à trois régimes, en partant de la largeur de la carte :
     · < 768 px — une carte par rangée, la carte vaut 100vw − 32 (padding de
       `.hm-b`). Le `.tc4-row` est une grille de deux colonnes dont la première
       vaut 42 % du contenu de la carte, soit 100vw − 32 − 2 (bordures) − 32
       (padding de `.tc4-row`) = 100vw − 66. D'où 0,42 × (100vw − 66).
       Vérifié à 375 px : formule 129,78, mesuré 129,77.
     · 768 → 1232 px — grille de 3 colonnes, gouttière 16 px, conteneur
       100vw − 32 : la carte vaut (100vw − 64)/3, la photo 2 px de moins.
     · ≥ 1232 px — le conteneur plafonne à `--max-width` : (1200 − 64)/3 − 2
       = 387,33 px, constante. Le point de bascule est 1232 et non 1024, parce
       que c'est là que le plafond mord (1200 + 2 × 16), et qu'entre 768 et
       1232 la formule est continue : un palier à 1024 n'y décrivait rien.
   ------------------------------------------------------------------------ */
.tc4-media {
  position: relative; margin: 0; overflow: hidden;
  aspect-ratio: 6 / 5;
  background: var(--color-gray-light);
  border-radius: var(--radius-sm);
}

.tc4-media > img { width: 100%; height: 100%; object-fit: cover; object-position: center; }

.tc4-media--h45  > img { object-position: 50% 8%; }

.tc4-media--v120 > img { object-position: 45% 50%; }

.tc4-media--pont > img { object-position: 0% 50%; transform: scale(1.03); transform-origin: 0% 50%; }

.tc4-media--box  > img { object-position: 50% 45%; }

/* La photo pleine largeur du box est la SEULE à garder son ratio de source.
   Elle est livrée en 4:3 et le brief impose que la boîte suive : pas de
   recadrage, ni en 3:2 ni en 16/9. Déclarée APRÈS `.tc4-media` — les deux
   sélecteurs ont la même spécificité, c'est l'ordre qui tranche, et la
   première écriture (avant `.tc4-media`) rendait la photo en 6/5 : 28 px de
   trop et un cadrage rogné, vu au rendu, pas au calcul. */
.tc4-media--photo { aspect-ratio: 4 / 3; border-radius: 0; }

.tc4-media--photo > img { object-position: 50% 45%; }


/* --- LE PANNEAU DU PLAN ----------------------------------------------------
   Deux panneaux CÔTE À CÔTE, de même hauteur, dans la même rangée — jamais
   l'un SUR l'autre. C'est la seule réponse compatible avec la contrainte du
   45 m² : la photo est provisoire et son cadrage va changer, donc rien de ce
   qui est coté ne doit dépendre d'elle. Un plan posé à côté est indépendant
   par construction ; un plan posé dessus redevient un calque calibré en
   pixels de CE fichier, c'est-à-dire faux le jour du remplacement, et faux
   silencieusement.
   `align-self: stretch` + centrage : quand la photo est la plus haute des
   deux, le panneau s'étire et le dessin se centre — aucun blanc résiduel. */
.tc4-planbox {
  display: flex; align-items: center; justify-content: center;
  align-self: stretch;
  padding: 5px;
  background: var(--color-bg);
  border: 1px solid var(--tc4-line);
  border-radius: var(--radius-sm);
}

.tc4-plan { display: block; width: 100%; height: auto; max-width: 240px; }


/* --- LE DESSIN : conventions reprises de l'option B v2 ----------------------
   Les traits sont en `non-scaling-stroke` : un viewBox de 272 unités rendu
   entre 126 et 240 px donne un facteur de 0,46 à 0,88. Sans cela un trait de
   1,4 devient un cheveu de 0,6 px sur la tuile compacte.
   ⚠️ `non-scaling-stroke` ne fige QUE l'épaisseur : les tirets, eux, restent
   en unités utilisateur et rétrécissent. Les `stroke-dasharray` de B (4 3 et
   3 3, pensés pour un rendu à ~0,75) ont donc été rallongés à 7 5 et 5 4 pour
   rester des pointillés à 0,46. C'est la seule valeur de B qui a changé. */
.tc4-e, .tc4-c, .tc4-arrow { fill: none; vector-effect: non-scaling-stroke; stroke-linejoin: round; }

.tc4-floor     { fill: var(--color-gray-light); }

.tc4-top       { fill: var(--color-white); }

.tc4-e         { stroke: var(--color-gray); stroke-width: 1.4px; }

.tc4-e--f      { stroke: var(--color-dark);  stroke-width: 1.7px; }

.tc4-e--in     { stroke-width: 1px; }

/* La fourchette de hauteur : trait plein jusqu'à 4 m, pointillés jusqu'à 6. */
.tc4-e--max    { fill: none; stroke: var(--color-gray); stroke-width: 1.2px; stroke-dasharray: 7 5; }

/* Les cloisons mobiles du 120 m²+. POINTILLÉ FIN, volontairement différent du
   tiret de la fourchette de hauteur : les deux conventions cohabitent sur ce
   dessin et un lecteur doit pouvoir les distinguer sans légende.
   0,70 et non 0,50 d'opacité : #595959 à 50 % sur #E8E6E1 donne ~2,3:1, sous
   les 3:1 que la SC 1.4.11 demande à un objet graphique porteur de sens. */
.tc4-e--part   { fill: none; stroke: var(--color-gray); stroke-opacity: .7; stroke-width: .9px; stroke-dasharray: 5 4; }

/* La flèche à deux pointes est le SEUL trait à pointes du fragment. Les cotes
   n'ont que des traits d'attache droits : deux pointes = « ça bouge », jamais
   « ça mesure ». Convention interne de B, tenue ici sur les quatre dessins. */
.tc4-arrow     { stroke: var(--color-dark); stroke-width: 1px; stroke-opacity: .75; stroke-linecap: round; }


/* LA MAILLE DE 1 m — le réseau des points entiers du sol, période
   (1,732 k ; k). C'est elle que le client a demandée : « les petits carrés
   qui représentent les mètres ». Elle n'est utile que si une maille rend
   au-dessus de ~6 px ; sous ce seuil elle devient du moiré, ce que la V1 de
   B avait déjà qualifié de bruit à 5 px. D'où deux régimes :
     · `--on`  : toujours peinte. Box (k=21, 9,6 à 18 px de carreau mesurés),
                 45 m² (k=12, 5,6 à 13,4 px) et, depuis le 2026-08-08,
                 90 m² (k=9, 4,2 à 6,2 px sous 1024).
   ⚠️ LA GRADATION A ÉTÉ ABANDONNÉE le 2026-08-08, et voici pourquoi.
   Le 90 m² était seul à garder le régime par défaut — maille éteinte sous
   1024 px — au motif que 4,2 à 6,2 px de carreau passe sous le seuil de
   moiré estimé à ~6 px. Le seuil n'avait jamais été vérifié à l'œil : mis
   côte à côte à 375 px, DPR 2, le sol du 90 m² allumé donne du grain, pas
   du bruit, et se lit comme les deux autres. Ce qui se voyait, en revanche,
   c'était l'ABSENCE de maille sur une tuile parmi trois — Antoine l'a
   signalée spontanément comme un défaut d'affichage. Une gradation que
   personne ne lit comme une gradation est une incohérence.
   Réserve non levée : mesuré à DPR 2 seulement. Sur un écran à DPR 1, le
   trait de 0,55 px rendu peut disparaître à l'antialiasing — à recontrôler
   si un tel écran compte pour ce site.
   ⚠️ LA GRADATION NE PEUT PAS ÊTRE PLUS FINE QUE ÇA, et c'est structurel :
   un `<pattern>` vit dans `<defs>`, ses traits ne sont donc descendants
   d'aucune tuile. Un sélecteur d'ancêtre — `.tc4-compact .tc4-mesh` — ne les
   atteint jamais. Seule une media query, qui ignore le contexte, agit sur
   eux. Conséquence assumée : la variante compacte à 768 px (4 colonnes de
   126 px de dessin) garde une maille de 5,6 px sur le 45 m². C'est le seul
   des huit dessins sous le seuil, et le corriger demanderait de dupliquer
   les trois patterns pour la seule variante de labo.
   Le 120 m²+ n'a PAS de maille, et c'est du sens, pas de la lisibilité : un
   sol quadrillé est un sol comptable, donc mesurable, donc en contradiction
   avec l'absence délibérée de cote au sol sur ce palier.
   ⚠️ La maille est DÉCORATIVE au sens de la SC 1.4.11 et il faut le dire :
   son trait est de 1 unité, soit 0,55 à 0,88 px rendus, donc antialiasé
   sous son contraste nominal. Elle est à 0,70 d'opacité — #595959 à 70 % sur
   le sol #E8E6E1 donne #848382, soit 3,03:1, calculé — mais aucune mesure ne
   repose sur elle : les cotes écrites, la ligne `.tc4-dims` et l'aria-label
   portent l'information. La maille donne le grain, pas le chiffre. */
.tc4-mesh { fill: none; stroke: transparent; stroke-width: 1; }

.tc4-mesh--on { stroke: var(--color-gray); stroke-opacity: .7; }

@media (min-width: 1024px) { .tc4-mesh { stroke: var(--color-gray); stroke-opacity: .7; } }


/* LA SILHOUETTE — noire et légèrement épaissie, reprise de B. Motif mesuré :
   sur le dessin servi à k = 9 elle ne fait que 2,3 unités de large pour 15,3
   de haut. Le contour de 0,10 m — exprimé dans les mètres du repère local,
   donc projeté avec le reste — la porte à 0,50 m d'épaule et la rend visible
   sans changer sa HAUTEUR, qui est la seule chose qu'elle mesure. */
.tc4-fig { fill: var(--color-dark); stroke: var(--color-dark); stroke-width: .10; stroke-linejoin: round; }

.tc4-c   { stroke: var(--color-dark); stroke-width: 1px; }


/* LE TEXTE DE COTE. Corps rendu = font-size × largeur du SVG / 272. Trois
   régimes, calés sur les largeurs réellement mesurées, cible 9,5-11,5 px :
     · < 768 px  : 135-153 px de dessin  → 19 unités = 9,4 à 10,7 px
     · 768-1023  : 126-191 px selon le contexte, d'où les trois surcharges
     · ≥ 1024 px : tout tombe entre 236 et 240 px → 13 unités = 11,3 à 11,5 px
   Le halo (`paint-order: stroke`, liseré couleur-fond DERRIÈRE le glyphe)
   protège les cotes de sol, posées sur leur ligne de cote comme le veut la
   rotation à ±30°, des croisements avec l'arête basse du volume. */
.tc4-ct { fill: var(--color-dark); font-family: var(--font-display); font-weight: 600; font-size: 19px;
          paint-order: stroke; stroke: var(--color-bg); stroke-width: 3px; stroke-linejoin: round; }

@media (min-width: 768px) and (max-width: 1023.98px) {
  .tc4-grid .tc4-ct          { font-size: 15px; }   /* cellules, dessin ~191 px */
  .tc4-planbox--lead .tc4-ct { font-size: 19px; }   /* paire du box, dessin ~126 px */
  .tc4-compact .tc4-ct       { font-size: 19px; }   /* 4 colonnes, dessin ~128 px */
}

@media (min-width: 1024px) {
  .tc4-ct, .tc4-grid .tc4-ct, .tc4-planbox--lead .tc4-ct, .tc4-compact .tc4-ct { font-size: 13px; }
}


/* La note du 120 m²+ : la SEULE légende visible conservée. */
.tc4-plancap b { color: var(--color-dark); font-weight: 600; }


/* --- lignes de texte ------------------------------------------------------- */
.tc4-kicker {
  margin: 0 0 2px;
  font-family: var(--font-display); font-size: var(--font-size-xs); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; line-height: 1.3;
  color: var(--color-gray);              /* 7,0:1 sur blanc */
}

.tc4-name { margin: 0 0 4px; font-size: var(--font-size-h3); }

.tc4-tile--lead .tc4-name { font-size: var(--font-size-h2); letter-spacing: -.02em; }

/* Les cotes écrites RESTENT, alors que le dessin les porte aussi. Redondance
   assumée, et c'est la règle du brief : toute information portée par le
   dessin doit exister en texte. */
.tc4-dims {
  margin: 0 0 var(--space-xs);
  font-size: var(--font-size-xs); line-height: 1.4; color: var(--color-gray);
}

.tc4-dims b { font-family: var(--font-display); font-weight: 600; color: var(--color-dark); }

.tc4-usage { margin: 0 0 var(--space-xs); font-size: var(--font-size-small); line-height: 1.45; }


.tc4-terms {
  margin: 0 0 var(--space-xs);
  font-size: var(--font-size-xs); font-weight: 500; color: var(--tc4-ink-2);
}


.tc4-price {
  margin: 0;
  font-family: var(--font-display); font-size: 1.75rem; font-weight: 700;
  line-height: 1.05; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  color: var(--color-dark);
}

.tc4-price span {
  font-family: var(--font-body); font-size: var(--font-size-small);
  font-weight: 400; letter-spacing: 0; color: var(--color-gray);
}

.tc4-cond {
  margin: 4px 0 var(--space-xs);
  font-size: var(--font-size-xs); line-height: 1.35; color: var(--color-gray);
}


/* LE PALIER SANS PRIX — inchangé depuis la v1. */
.tc4-quote {
  margin: 0 0 var(--space-xs);
  padding-left: .6rem;
  border-left: 2px solid var(--color-primary);
  font-family: var(--font-display); font-size: 1.375rem; font-weight: 700;
  line-height: 1.15; letter-spacing: -.01em;
  color: var(--color-dark);
}

.tc4-quote span {
  display: block; margin-top: 2px;
  font-family: var(--font-body); font-size: var(--font-size-xs); font-weight: 400;
  line-height: 1.4; letter-spacing: 0; color: var(--color-gray);
}


/* MOMENT JAUNE 2/3 — la plaque sous le prix, sur la seule tuile développée. */
.tc4-pay {
  margin: 0 0 var(--space-xs);
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-primary-light);
  border: 1px solid var(--tc4-plaque);
  border-radius: var(--tc4-r);
}

.tc4-pay .tc4-price { font-size: 2.5rem; }

.tc4-guar { list-style: none; display: flex; flex-wrap: wrap; gap: 2px var(--space-sm); margin: 6px 0 0; }

.tc4-guar li { display: inline-flex; align-items: center; gap: .3rem; font-size: var(--font-size-xs); color: var(--tc4-ink-2); }

.tc4-guar svg { flex: none; width: 14px; height: 14px; color: var(--color-dark); }


.tc4-anchor { margin: 0 0 var(--space-xs); font-size: var(--font-size-small); font-weight: 500; color: var(--tc4-ink-2); }


.tc4-attrs { list-style: none; margin: 0 0 var(--space-sm); font-size: var(--font-size-xs);
             line-height: 1.5; color: var(--tc4-ink-2); }

.tc4-attrs li { display: inline; }

.tc4-attrs li + li::before { content: " · "; color: var(--color-gray); }


.tc4-ctas { display: flex; flex-wrap: wrap; gap: var(--space-xs); }

.tc4-ctas .btn-primary, .tc4-ctas .btn-tertiary { flex: 1 1 14rem; margin: 0; width: auto; }


/* MOMENT JAUNE 3/3 — le halo du CTA primaire (+ arête lumineuse). */
.tc4-grid .btn-primary, .tc4-compact .btn-primary {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35), 0 1px 2px rgba(26,26,26,.15),
              0 4px 14px rgba(245,197,24,.40);
}

@media (hover: hover) and (pointer: fine) {
  .tc4-grid .btn-primary:hover, .tc4-compact .btn-primary:hover {
    box-shadow: inset 0 1px 0 rgba(255,255,255,.35), 0 2px 4px rgba(26,26,26,.15),
                0 8px 22px rgba(245,197,24,.50);
  }
}


/* --- sous la grille -------------------------------------------------------
   SANS CONSOMMATEUR depuis le 2026-08-11 : le bloc `.tc4-foot` a été retiré du
   markup, ses paragraphes parce qu'ils répétaient les tuiles, sa figure parce
   que la bande de trois photos du générateur sert la même image. Les règles
   restent : elles décrivent un gabarit « figure à gauche, texte à droite au-delà
   de 768 px » qui resservira, et elles ne coûtent que leurs octets.
   La dernière règle, `.tc4-foot a, .tc4-micro a`, porte le procédé des 44 px de
   cible tactile — 0,75 rem de rembourrage repris en marge négative, pour que la
   CIBLE grandisse sans que le rythme du texte bouge. `.tc4-micro` n'a lui non
   plus aucun élément dans ce fragment : vérifié, il n'existe que dans ce
   sélecteur. C'est donc le PROCÉDÉ qui vaut d'être gardé, pas ces deux
   sélecteurs-là ; il est déjà appliqué ailleurs sous d'autres noms. */
.tc4-foot { margin-top: var(--space-smd); display: grid; gap: var(--space-sm); grid-template-columns: 1fr; }

@media (min-width: 768px) { .tc4-foot { grid-template-columns: minmax(0, 34%) minmax(0, 1fr); align-items: center; } }

.tc4-foot figure { margin: 0; }

.tc4-foot figure img {
  width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--tc4-r); box-shadow: var(--tc4-shadow-card);
}

.tc4-foot figcaption { margin-top: 4px; font-size: var(--font-size-xs); color: var(--color-gray); }

.tc4-foot p { margin: 0 0 var(--space-xs); max-width: 68ch; font-size: var(--font-size-small); color: var(--color-gray); }

.tc4-foot p:last-child { margin-bottom: 0; }

.tc4-foot strong { color: var(--color-dark); }

.tc4-foot a { color: var(--color-primary-text); }

.tc4-foot a, .tc4-micro a { display: inline-block; padding: .75rem .35rem; margin: -.75rem -.35rem; }
  /* 44 px de cible */

/* --- variante compacte : les 4 paliers au même gabarit --------------------
   La box y perd son rendu détouré et reprend le gabarit commun : photo 6/5
   en colonne 1, plan en colonne 2, exactement comme ses trois voisines.
   C'est le sens même de cette variante — « les 4 au même gabarit » — et le
   rendu 2,048 en pleine largeur était la seule exception qui l'en empêchait.
   Les trois visuels du box restent la proposition de la grille principale. */
.tc4-compact { margin-top: var(--space-md); }

.tc4-compact .tc4-grid { grid-template-columns: 1fr; }

@media (min-width: 640px) { .tc4-compact .tc4-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

@media (min-width: 768px) { .tc4-compact .tc4-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }


/* --- motion ---------------------------------------------------------------
   Rien de nouveau. Pas de hover-lift sur la tuile (elle n'est pas cliquable),
   aucune animation sur les plans : un dessin isométrique n'a rien à animer,
   et c'est précisément ce qui le rend compatible avec la contrainte « aucun
   rendu 3D lourd » du test 31. Le kill-switch reduced-motion de lab.css
   suffit ; aucune règle à ajouter. */

/* --- CTA : un primaire plein, un secondaire de navigation ---------------
   ORCHESTRATEUR 06/08. Le telephone quitte les tuiles : il etait repete
   4x pour un numero unique, deja present dans le header et la barre
   collante. A sa place, un bouton de NAVIGATION qui nomme sa destination
   — trois benefices : le visiteur sait ou il va avant de taper, chaque
   tuile porte une ancre descriptive differente vers sa page espace, et
   le clic devient mesurable par destination sans dependre de
   cta_location. Devis et telephone etaient la meme action sur deux
   canaux et se concurrencaient ; devis et navigation sont deux moments
   differents du parcours, ils trient au lieu de diluer. */
.tc4-cta2 {
  min-height: 44px;                      /* 48 pour le primaire : il reste dominant */
  font-weight: 600;
  border-width: 1px;
  border-color: var(--color-gray-light);
  color: var(--color-dark);
  box-shadow: none;                      /* pas de halo : reserve au primaire */
}

@media (hover: hover) and (pointer: fine) {
  .tc4-cta2:hover { background: var(--color-dark); color: var(--color-white); border-color: var(--color-dark); }
}


/* --- Badges d'usage : « adapté pour » ------------------------------------
   Remplacent le kicker, à la même place. Chaque usage devient un badge
   icône + libellé ; le premier — l'usage principal du palier — est teinté
   comme la plaque du prix. L'information reste du texte : l'icône décore. */
.tc4-fits { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 var(--space-xs); padding: 0; }

.tc4-fits li {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px 3px 7px;
  background: var(--color-white); border: 1px solid #EFEDE7; border-radius: 999px;
  font-family: var(--font-display); font-size: var(--font-size-xs); font-weight: 600;
  letter-spacing: .01em; color: var(--color-dark);
}

.tc4-fits svg { width: 14px; height: 14px; flex: none; fill: none; stroke: var(--color-primary-text); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }


/* --- Phrase de routage : le vocabulaire du besoin avant l'offre ---------- */
.tc4-route { margin: 0 0 var(--space-sm); max-width: 62ch; color: var(--color-gray); }


/* --- Le téléphone, une fois sous la grille — bloc sombre à lueur ---------
   Motif documenté du HANDOVER §3 : un bloc sombre porte une lueur radiale
   du jaune, pas un aplat. Le bouton jaune sur fond sombre devient
   l'élément le plus contrasté de la section (10,7:1). */
.tc4-callout {
  position: relative; overflow: hidden;
  margin-top: var(--space-md);
  padding: var(--space-md);
  background: var(--color-dark);
  border-radius: var(--radius-lg);
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-sm) var(--space-md);
}

.tc4-callout::before {
  content: ""; position: absolute; left: 50%; top: -30%;
  width: 120%; height: 70%; transform: translateX(-50%);
  pointer-events: none;
  background: radial-gradient(55% 60% at 50% 0%, rgba(245,197,24,.12), transparent 70%);
}

.tc4-callout > * { position: relative; }

.tc4-callout__ico {
  flex: none; width: 48px; height: 48px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--color-primary); color: var(--color-dark);
}

.tc4-callout__ico svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.tc4-callout__txt { flex: 1 1 16rem; }

.tc4-callout__txt strong { display: block; font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; color: var(--color-white); line-height: 1.3; }

.tc4-callout__txt p { margin: 4px 0 0; font-size: var(--font-size-small); color: #CFCCC6; }

.tc4-callout__act { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs) var(--space-sm); }

@media (min-width: 900px) { .tc4-callout__act { margin-left: auto; } }

.tc4-callout__act .btn-primary { gap: .5rem; }

.tc4-callout__act .btn-primary svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.tc4-callout__mail {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 44px; padding: 0 .5rem;
  font-family: var(--font-display); font-weight: 600;
  color: var(--color-primary);   /* jaune sur #1A1A1A : 10,7:1 — le jaune-texte n'est interdit que sur fond clair */
}

.tc4-callout__mail svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

@media (hover: hover) and (pointer: fine) { .tc4-callout__mail:hover { color: var(--color-white); } }



/* La regle « lien en ligne dans le callout » a ete supprimee : son selecteur
   ne correspondait a aucun element de ce fragment. Sa DECLARATION, elle, est
   reprise telle quelle par le selecteur groupe des liens en ligne de la home
   (CSS_HOME dans build-home.py) — meme procede que .tc4-foot a. */


/* Deux etats de badge — donnee d'Antoine du 06/08 : « bien dimensionne »
   contre « possible ». Le jaune porte ici une VRAIE information, ce qui
   justifie ce 4e moment de jaune ; mais la regle « aucune information
   portee par la seule couleur » (test 5 de la checklist) impose un
   equivalent : chaque badge annonce « Ideal pour » ou « Possible » aux
   lecteurs d'ecran, et une legende visible explique la distinction. */
.tc4-sr { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }

.tc4-fits li.is-fit { background: var(--color-primary-light); border-color: #F0E3B2; }

.tc4-fits li.is-fit svg { stroke: var(--color-primary-text); }

.tc4-fits li:not(.is-fit) { color: var(--color-gray); }

.tc4-fits li:not(.is-fit) svg { stroke: var(--color-gray); }

/* SANS CONSOMMATEUR depuis le 2026-08-11 : la légende que ces deux règles
   habillaient a été supprimée sur demande d'Antoine. On les garde parce que
   le piège qu'elles documentent est réutilisable, et coûteux à retrouver.

   `display:block` et SURTOUT PAS `flex`. La légende était un <p> mêlant un
   <span> (la pastille), du texte nu, un <strong> et encore du texte nu : en
   régime flex, CHAQUE suite de texte anonyme devient un élément flex à part
   entière, et la phrase se retrouvait éclatée en trois colonnes côte à côte,
   à TOUTES les largeurs, 375 px compris. C'était le seul défaut relevé par
   l'audit responsive qui se voyait sur téléphone. Le `gap` qui séparait la
   pastille du texte disparaît avec le flex : repris en `margin-right` sur la
   pastille. Celle-ci passe en `inline-block` — un <span> nu est `inline`,
   donc `width`/`height` ne s'y appliquent pas et il serait rendu vide — et
   se cale par `vertical-align` plutôt que par le `margin-top` en em qui
   compensait l'alignement `flex-start`. */
.tc4-legend-fits { display:block; margin:0 0 var(--space-sm); font-size: var(--font-size-small); color: var(--color-gray); }

.tc4-chip-demo { display:inline-block; vertical-align:-.1em; width:22px; height:14px; margin-right:.5rem; border-radius:999px; background: var(--color-primary-light); border:1px solid #F0E3B2; }


/* ══════════════════════════════════════════════════════════════════════════
   TUILES DE FORMATS — AJUSTEMENTS PROPRES À L'ACCUEIL (2026-08-28)
   Les tuiles (tvof) vivent dans tuiles.css, partagé avec la page Tarifs.
   Tout ce qui suit ne concerne QUE l'accueil et reste donc ici : home.css
   est enfilée après tuiles.css (cf. functions.php, chaîne de dépendances),
   donc à spécificité égale c'est cette feuille qui tranche.
   ══════════════════════════════════════════════════════════════════════════ */

/* --- DEUX ACTIONS PAR TUILE ------------------------------------------------
   Le CTA unique « Ça m'intéresse » devient un couple : « Plus d'info » en
   jaune vers la page du format, « Appel » en fantôme vers le standard.
   `flex: 1 1 0` leur donne deux moitiés égales de la rangée ; la base de
   14 rem héritée de tuiles.css les aurait empilés sous 28 rem de colonne,
   soit sur toute la plage mobile. `min-width: 0` empêche le contenu
   intrinsèque du bouton de rouvrir la rangée en dessous de sa part. */
.tvof-ctas .btn-primary,
.tvof-ctas .btn-tertiary {
  flex: 1 1 0; min-width: 0; width: auto; margin: 0; padding-inline: .75rem;
}

/* Le combiné, repris du sprite de la page (#tvof-i-phone), au gabarit du
   callout sombre. `content: none` annule la flèche que custom.css colle
   après tout `.btn-tertiary` : une flèche annonce une navigation, or ce
   bouton décroche un téléphone. */
.tvof-cta-tel svg {
  flex: none; width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.tvof-cta-tel::after { content: none; }

/* 768 → 1024 px : les trois cellules tiennent dans des colonnes de ~235 px,
   soit ~91 px par bouton, et « Plus d'info » y passait à la ligne — la
   rangée doublait de hauteur (48 → 64 px, mesuré à 768 px). On resserre le
   rembourrage et le corps du libellé. C'est du texte d'interface, pas du
   corps de page : le plancher de 16 px ne s'y applique pas. */
@media (min-width: 768px) and (max-width: 1023.98px) {
  .tvof-grid .tvof-ctas .btn-primary,
  .tvof-grid .tvof-ctas .btn-tertiary { padding-inline: .375rem; font-size: .875rem; }
  .tvof-grid .tvof-cta-tel     { gap: .25rem; }
  .tvof-grid .tvof-cta-tel svg { width: 16px; height: 16px; }
}

/* --- SOUS 768 px : LA SECTION DES FORMATS SE RESSERRE -----------------------
   La tuile du box faisait 816 px de haut à 375 px de large, soit un écran
   plein : on scrollait une page entière entre son en-tête et les visuels de
   la tuile suivante. Trois gestes, aucun retrait de contenu.

   1. LA GOUTTIÈRE COMPTÉE DEUX FOIS. `.hm-b` pose déjà 16 px de marge
      latérale et 32 px verticale, et `.tvof-wrap` les repose par-dessus :
      32 px de large mangés sur 375, et 64 px de blanc en haut comme en bas
      de la section. La tuile passe de 311 à 343 px de large, ce qui suffit
      à faire tomber `.tvof-usage` de 3 à 2 lignes et `.tvof-attrs` de 3 à 2.
      C'est le geste qui rend le plus, et il ne rétrécit rien.
   2. La photo du box passe de 4/3 à 16/9 — 232 → 192 px. Le recadrage ne
      prend que du ciel et du bitume : les deux personnes, les portes et
      l'intérieur du box restent entiers (vérifié au rendu à 375 px).
   3. Rembourrage du corps de tuile à 16 px au lieu de 24, et la liste
      d'arguments retrouve l'interligne commun des blocs.

   Aucune taille de police n'est touchée : celles de la tuile sont déjà
   posées par tuiles.css et cette passe ne les descend pas d'un pixel.
   Mesuré à 375 px : tuile 816 → 724 px (−92, −11 %), section 3038 → 2868 px
   (−170, −5,6 %). Les tuiles de cellule (442 px) tiennent déjà dans un écran
   et ne reçoivent rien de plus que la largeur gagnée au point 1. */
@media (max-width: 767.98px) {
  .tvof-section > .tvof-wrap          { padding: 0; }
  .tvof-tile--lead .tvof-body         { padding: var(--space-sm); }
  .tvof-tile--lead .tvof-media--photo { aspect-ratio: 16 / 9; }
  .tvof-tile--lead .tvof-attrs        { margin-bottom: var(--space-xs); }
}
