/* ===== Monde Immobilier — /realestate =====
 *
 * Direction artistique demandée par Lino le 31/07/2026 : blanc cassé, beige,
 * vert tropical — les Landes et le Costa Rica — pour de l'immobilier de LUXE.
 * La première version (vert-noir + or, effet néon sur la pastille) a été
 * refusée : trop sombre, pas premium.
 *
 * Style « Galerie » : sérif fin (Cormorant Garamond), très aéré. Retenu par
 * Lino le 31/07/2026 parmi trois propositions.
 *
 * Règle transverse : AUCUNE lueur, aucun halo, aucun néon. Le premium se joue
 * sur l'espace, les filets fins et la typographie, jamais sur l'éclat.
 *
 * --- Révision du 02/08/2026 (Lino) : PLUS DE CONTRASTE. ---
 * Le blanc cassé d'origine (#fbf9f4) était à deux doigts du blanc pur et le
 * vert (#1f5140) trop tendre : la page paraissait fade. Le fond descend donc
 * vers le SABLE DES LANDES et le vert vers le PIN / la forêt du Costa Rica.
 * Mesuré : le vert passe de 8,6:1 à 9,5:1 sur le fond, le texte de 7,2 à 7,9.
 */

@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;600&family=Outfit:wght@200;300;400;500;600;700&family=Poppins:wght@500;600;700&display=swap');

:root {
  --im-bg:      #f4eee1;   /* sable des Landes — chaud, franchement pas blanc */
  --im-bg-2:    #e7dcc6;   /* sable dense, pour détacher un bloc du reste */
  --im-ink:     #0d2a1e;   /* vert quasi noir, sert d'encre */
  --im-text:    #3c4c41;
  --im-muted:   #7d8a7f;
  --im-accent:  #14452f;   /* pin des Landes / forêt du Costa Rica */
  /* Vert foncé mais PLUS LUMINEUX (Lino, 02/08) : 2,4× la luminosité relative
     de --im-accent (11,2 % contre 4,6 %) tout en restant franchement sombre.
     Porte le mot qui se tape (vente / location) et « Offre mois d'août ».
     5,6:1 sur le sable et 6,5:1 sous du blanc — bon partout. */
  --im-accent-lit: #1f6b45;
  --im-line:    rgba(13, 42, 30, 0.16);
  /* Les remises doivent SAUTER AUX YEUX (Lino, 02/08). Une terre cuite :
     complémentaire du vert, donc elle ressort au maximum, mais c'est un
     pigment naturel (tuile, écorce de pin) — jamais un néon, ce que la
     règle de la page interdit. 4,4:1 sur le sable, largement au-dessus du
     3:1 exigé pour du grand texte. */
  --im-deal:    #b0522c;
  --im-display: "Cormorant Garamond", Georgia, serif;
  --im-sans:    "Outfit", -apple-system, "Helvetica Neue", sans-serif;
  --im-brand:   "Poppins", "Outfit", -apple-system, sans-serif;
  --im-h-weight: 300;
  --im-h-track:  -0.005em;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* Fond de page NUANCÉ (Lino, 02/08) : l'aplat sable était monotone derrière
   les trois cartouches. De larges taches très diffuses réchauffent et
   refroidissent le sable au fil de la descente — on sent que ça bouge sans
   jamais voir de dégradé franc. `fixed` pour que les nuances appartiennent à
   la page et ne défilent pas avec les cartes. Aucune lueur : on ne fait que
   déplacer du sable, jamais ajouter de la lumière. */
body {
  margin: 0;
  background:
    radial-gradient(68% 42% at 10% 14%, #fbf7ee 0%, transparent 62%),
    radial-gradient(58% 38% at 92% 38%, #ece2cd 0%, transparent 64%),
    radial-gradient(76% 46% at 26% 66%, #f8f2e6 0%, transparent 60%),
    radial-gradient(52% 34% at 86% 88%, #e8ddc6 0%, transparent 62%),
    var(--im-bg);
  background-attachment: fixed;
  color: var(--im-text);
  font-family: var(--im-sans);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
}
img, video { display: block; max-width: 100%; }
.wrap { width: min(1080px, 100% - 2.8rem); margin-inline: auto; }

/* ===== En-tête : la vidéo SEULE, plein écran =====
   Plus rien par-dessus depuis le 02/08/2026 au soir : le titre est passé
   dessous et le surlignage vert a disparu avec lui. La séquence est tournée
   en 9:16, elle est donc chez elle sur un téléphone ; sur ordinateur la
   pleine largeur n'en montre qu'une tranche centrale, c'est assumé. */
.im-head {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: calc(var(--im-vh, 1svh) * 100);
}
.im-head-bg {
  position: absolute; inset: 0; z-index: -1;
  width: 100%; height: 100%; object-fit: cover;
}

/* « Défiler » — repris tel quel de la vidéo scrollable de l'accueil : le mot
   clignote de lui-même en alternant deux couleurs, ce qui accroche l'œil sans
   poser la moindre pastille sur l'image. Ici blanc ↔ vert lumineux : la
   luminosité de la séquence va de 30 à 235, aucune couleur ne tiendrait
   seule — mais l'une des deux est toujours lisible. */
.im-hint {
  position: absolute;
  bottom: calc(5.5vh + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  display: inline-flex; flex-direction: column; align-items: center;
  font-family: var(--im-sans);
  /* grossi le 02/08/2026 (Lino) : à 0,8 rem le mot se perdait sur une vidéo
     plein écran — c'est la seule invite de la page, elle doit se voir */
  font-size: clamp(0.98rem, 3.2vw, 1.18rem); font-weight: 600;
  letter-spacing: 0.3em; text-indent: 0.3em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 16px rgba(13, 42, 30, 0.75);
  animation: im-hint-flash 1.4s steps(1) infinite;
}
@keyframes im-hint-flash {
  0%, 49%   { color: #fff; }
  50%, 100% { color: #7fd3a6; }
}
/* Trait remplacé par la flèche de scrollcue.css (03/08/2026). */
@media (prefers-reduced-motion: reduce) {
  .im-hint { animation: none; }
}

/* ⚠️ `--im-vh` VAUT 1 % DE LA HAUTEUR D'ÉCRAN, MESURÉE UNE FOIS au chargement
   par le script en tête de realestate.html (Lino, 11/08/2026). Elle remplace
   `svh` partout où une hauteur d'écran commande la géométrie de la page.
   POURQUOI : la barre d'outils du navigateur d'Instagram coulisse pendant le
   défilement et redimensionne la webview. En `svh`, la photo collée du
   parallaxe se recalculait EN PLEINE COURSE — `cover` la recadrait, et la
   remontée de `.im-over` changeait avec elle : l'image sautait, et la position
   de défilement avec. Figée en pixels, elle ne bouge plus.
   ⚠️ LE REPLI `1svh` EST OBLIGATOIRE dans chaque `var()` : sans JS, chaque
   expression retrouve exactement sa valeur d'avant. Ne jamais écrire
   `var(--im-vh)` tout court ici.
   ⚠️ Le couple `.im-stage-bg` / `.im-over` doit TOUJOURS employer le même
   nombre (100 et -100) : c'est l'invariant du parallaxe, les désaccorder
   laisse un trou ou décale tout le parcours. */
/* ===== La scène : photo figée, contenu qui passe par-dessus =====
   Tout repose sur `position: sticky` — aucun JS. La photo se cale en haut de
   l'écran dès que son bord supérieur l'atteint (donc quand le titre vient de
   passer sous la barre de menu), et y reste jusqu'au bas de `.im-stage`.
   `.im-over` remonte d'une hauteur d'écran pour se superposer à elle. */
.im-stage { position: relative; }
.im-stage-bg {
  position: sticky;
  top: 0;
  height: calc(var(--im-vh, 1svh) * 100);
  background-image: url("assets/immo/villa-mobile.jpg");
  background-size: cover;
  background-position: center;
}
.im-over {
  position: relative;
  z-index: 1;
  margin-top: calc(var(--im-vh, 1svh) * -100);   /* exactement la hauteur de la photo : on la recouvre */
}
@media (min-width: 900px) {
  .im-stage-bg { background-image: url("assets/immo/villa.jpg"); }
}

/* Le bas du titre s'est resserré le 08/08/2026 : le texte qui le suit reprend
   à son compte l'écart qui précédait la photo (voir .im-lede). */
.im-title {
  width: min(1080px, 100% - 2.8rem);
  margin: 0 auto;
  padding: clamp(60px, 12vh, 128px) 0 clamp(20px, 3.2vh, 34px);
  max-width: 20ch;
  font-family: var(--im-display);
  font-weight: var(--im-h-weight);
  font-size: clamp(2.4rem, 8vw, 4.8rem);
  line-height: 1.06;
  letter-spacing: var(--im-h-track);
  color: var(--im-ink);
}
/* le mot qui se tape, dans le vert lumineux (plus de pavé) */
.im-title b {
  font-weight: var(--im-h-weight);
  font-style: italic;
  color: var(--im-accent-lit);
}
.im-title .tw-caret { font-style: normal; color: var(--im-accent-lit); }

/* ===== Le texte sous le titre (Lino, 08/08/2026) =====
 * Deux temps, et c'est la RUPTURE entre les deux qui porte le propos :
 *   1. la scène, en texte courant — sobre, presque neutre, c'est un constat ;
 *   2. la chute, en sérif italique et dans le vert lumineux — la seule phrase
 *      de la page où Lino parle à la première personne.
 * Le filet fin qui les sépare est le seul ornement autorisé par la DA de la
 * page (« l'espace, les filets fins et la typographie, jamais l'éclat »).
 * ⚠️ Ne PAS mettre les deux paragraphes dans la même fonte : sans le
 * changement de voix, la chute n'est plus qu'une troisième phrase.
 */
/* ⚠️ La colonne est calée sur CELLE DU TITRE : même fonte, même corps, même
   `max-width: 20ch`. C'est la seule façon d'obtenir le même bord gauche —
   les deux blocs sont centrés par `margin: 0 auto`, donc leur bord gauche
   dépend de leur largeur, et `ch` se résout sur la fonte de L'ÉLÉMENT. Une
   valeur en ch posée sur du texte courant donnait une colonne plus étroite et
   le texte partait en retrait du titre, comme un décalage accidentel.
   Les paragraphes reprennent aussitôt leur propre fonte et leur propre corps. */
.im-lede,
.im-proof {
  font-family: var(--im-display);
  font-size: clamp(2.4rem, 8vw, 4.8rem);
  width: min(1080px, 100% - 2.8rem);
  max-width: 20ch;
  margin: 0 auto;
}
/* La respiration avant la photo est portée par le DERNIER bloc de la colonne,
   c'est-à-dire les chiffres — la partait avec `.im-lede` en `?hero=portrait`. */
.im-proof { padding-bottom: clamp(52px, 10vh, 104px); }
.im-lede p { margin: 0; }
.im-lede > p:first-child {
  font-family: var(--im-sans);
  font-size: clamp(1.02rem, 2.6vw, 1.22rem);
  font-weight: 300;
  line-height: 1.62;
  color: var(--im-text);
  max-width: 40ch;
}
.im-lede .im-lede-b {
  position: relative;
  margin-top: clamp(20px, 3vh, 30px);
  padding-top: clamp(18px, 2.6vh, 26px);
  font-family: var(--im-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.32rem, 3.6vw, 1.9rem);
  line-height: 1.24;
  letter-spacing: var(--im-h-track);
  color: var(--im-accent-lit);
  /* si elle passe sur deux lignes, qu'elles soient de longueur comparable —
     sans ça « seconde-là. » se retrouvait seul sur la seconde ligne, coupé
     sur son trait d'union */
  text-wrap: balance;
}
/* le filet : court, à gauche, un pixel — il marque le changement de voix */
.im-lede-b::before {
  content: "";
  position: absolute; top: 0; left: 0;
  width: clamp(34px, 6vw, 52px); height: 1px;
  background: var(--im-line);
}

/* ===== Les chiffres (08/08/2026) =====
 * Traités comme le CARTEL d'un tableau, pas comme un encadré publicitaire :
 * un filet fin, le constat, puis la source en petit. C'est cette ligne de
 * source qui fait tout le travail — elle transforme une affirmation en
 * citation, et sur une page qui vend du premium elle rassure au lieu
 * d'affaiblir. C'est aussi la seule façon de citer un chiffre de performance
 * sans tomber dans l'allégation trompeuse.
 * ⚠️ NE PAS mettre les nombres en terre cuite : `--im-deal` ne désigne QUE le
 * prix sur cette page. Un chiffre d'étude dans la couleur de la promotion se
 * lirait comme une offre.
 * ⚠️ Ne jamais grossir la source ni la retirer : sans elle, le paragraphe
 * devient une promesse de résultat.
 */
/* ⚠️ Pas de `max-width` en ch SUR CE CONTENEUR : il hérite de la fonte et du
   corps du titre (`.im-lede` les porte pour caler sa colonne), un ch y vaut
   donc trois fois ce qu'on croit. La longueur de ligne se fixe sur les
   paragraphes, qui ont leur propre corps. */
.im-proof {
  margin-top: clamp(24px, 3.6vh, 38px);
  padding-top: clamp(18px, 2.6vh, 26px);
  border-top: 1px solid var(--im-line);
  box-sizing: border-box;
}
.im-proof-p {
  margin: 0;
  max-width: 44ch;
  font-family: var(--im-sans);
  font-size: clamp(0.95rem, 2.4vw, 1.08rem);
  font-weight: 300;
  line-height: 1.6;
  color: var(--im-text);
}
/* Le bloc compte QUATRE paragraphes depuis le 15/08/2026 — l'étude, puis les
   trois du texte de Lino. `.im-proof-p` est à `margin: 0` (il était seul) :
   sans cette règle ils se toucheraient. L'écart est en `em`, il suit donc le
   corps du paragraphe d'un écran à l'autre. */
.im-proof-p + .im-proof-p { margin-top: 1.05em; }
.im-proof-p b { font-weight: 500; color: var(--im-ink); }
.im-proof-src {
  margin: 1.15em 0 0;
  max-width: 62ch;
  font-family: var(--im-sans);
  font-size: 0.74rem;
  font-weight: 300;
  line-height: 1.5;
  color: var(--im-muted);
}

/* ===== Les offres =====
 *
 * Voile progressif RETIRÉ le 02/08/2026 (Lino) : la bande crème en bas de
 * chaque section marquait trop.
 *
 * ⚠️ Retiré sans rien mettre à la place, le texte devenait ILLISIBLE — encre
 * vert foncé posée sur une vidéo claire, contrastée et mouvante (constaté sur
 * les trois sections, la pire étant les clés). Le texte est donc posé sur un
 * CARTOUCHE, comme le cartel d'un tableau : la vidéo reste entière et nette
 * derrière — c'est même la première fois qu'on la voit vraiment — et le texte
 * a son propre fond. Aucun voile ne recouvre plus l'image.
 */
/* Les offres montent par-dessus la photo figée. Le retrait du haut laisse
   voir l'image avant que la première carte n'arrive, et celui du bas laisse
   respirer avant que le contact ne recouvre tout. */
.offers {
  display: flex; flex-direction: column;
  /* Écart généreux entre les trois cartes (Lino, 02/08) : c'est lui qui laisse
     la photo réapparaître pleinement entre deux offres pendant le défilement.
     En vh et non en px — l'intervalle doit se mesurer par rapport à l'écran,
     puisque c'est le temps de respiration entre deux services. */
  gap: clamp(64px, 20vh, 200px);
  padding: calc(var(--im-vh, 1svh) * 62) 0 calc(var(--im-vh, 1svh) * 34);
}
.offer { position: relative; }
.offer-inner {
  width: min(1080px, 100% - 2.8rem);
  max-width: 62ch;
  margin-inline: auto;
  padding: clamp(28px, 5vw, 46px);
  background: var(--im-card-bg, rgba(252, 249, 242, 0.96));
  border: 1px solid var(--im-card-line, var(--im-line));
  box-shadow: var(--im-card-shadow, 0 24px 60px rgba(13, 42, 30, 0.16));
}

.offer-h {
  margin: 0 0 0.8rem; max-width: 15ch;
  font-family: var(--im-display);
  font-weight: var(--im-h-weight);
  font-size: clamp(2.05rem, 6.4vw, 3.6rem);
  line-height: 1.06; letter-spacing: 0;
  color: var(--im-ink);
}
.offer-p {
  margin: 0 0 1.7rem; max-width: 44ch;
  font-size: clamp(0.98rem, 2.2vw, 1.06rem);
  line-height: 1.68; color: var(--im-text);
}
/* Une offre peut compter PLUSIEURS paragraphes depuis le 16/08/2026 (le
   raisonnement de « Maximiser votre prix de vente » se déplie en quatre
   temps). L'écart entre eux est plus serré que celui qui sépare le dernier
   du bloc suivant : ils forment un seul argument, la marge de 1,7 rem
   dirait le contraire. */
.offer-p + .offer-p { margin-top: -0.85rem; }

/* --- CE QUI EST LIVRÉ (Lino, 11/08/2026) ---------------------------------
 * Le paragraphe au-dessus VEND, cette liste ENGAGE — nombre de fichiers,
 * heures sur place, délai. Deux registres, donc deux blocs : rallonger le
 * paragraphe aurait noyé l'argument dans l'inventaire.
 *
 * ⚠️ PAS DE COCHES, ET C'EST VOULU. Les quatre offres sont EXCLUSIVES l'une de
 * l'autre — on en choisit une, on ne les cumule pas. Des coches inviteraient à
 * comparer les listes entre elles, exactement le travers que la mise en page
 * de /pro et de /creation-site cherche à éviter. Un filet vertical suffit à
 * dire « détail de la prestation ».
 *
 * ⚠️ AUCUNE OMBRE, AUCUN FOND : règle de la page depuis le 31/07. Un fond
 * beige ferait une carte dans la carte, là où toute la page se tient sur des
 * filets d'un pixel.
 *
 * ⚠️ `max-width` PLUS LARGE que le paragraphe (52ch contre 44ch), et ce n'est
 * pas une inattention : ce sont des énumérations techniques, pas de la prose.
 * À 44ch, « Vous recevez 1 vidéo éditée captivante… » part sur quatre lignes
 * et la liste pèse plus lourd que l'offre qu'elle décrit. */
/* « Ce que vous obtenez » — l'intertitre qui coiffe la liste (Lino,
   16/08/2026). Il dit à quoi on passe : au-dessus on vend, en dessous on
   s'engage. D'où un traitement d'ÉTIQUETTE et non de titre — petites
   capitales espacées, encre pleine, aucun filet à lui : c'est celui de la
   liste qui continue sous elle.
   ⚠️⚠️ LA MARGE NÉGATIVE DE `.offer-liste` DOIT ÊTRE ANNULÉE SOUS ELLE, et
   c'est le seul piège de ce bloc. Ces −0,9 rem existent pour remonter la liste
   sous le PARAGRAPHE ; avec l'étiquette intercalée, ils la faisaient monter
   PAR-DESSUS — la première ligne s'imprimait dans le mot. Vu à l'écran avant
   correction. Toute autre chose glissée entre le paragraphe et la liste devra
   faire de même. */
.offer-liste-h {
  margin: 0;
  font-family: var(--im-sans);
  font-size: clamp(0.72rem, 1.5vw, 0.78rem);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--im-ink);
}
.offer-liste-h + .offer-liste { margin-top: 0.6rem; }
.offer-liste {
  list-style: none;
  margin: -0.9rem 0 1.7rem;
  padding: 0 0 0 1rem;
  max-width: 52ch;
  border-left: 1px solid var(--im-line);
  display: flex; flex-direction: column; gap: 0.5rem;
}
.offer-liste li {
  font-size: clamp(0.88rem, 1.9vw, 0.95rem);
  line-height: 1.5;
  color: var(--im-text);
}
/* --- DEUX NIVEAUX DE MISE EN AVANT DANS LA LISTE (Lino, 11/08/2026) -------
 * « Ces phrases, subtilement plus faciles à voir, car il s'agit du produit
 * final — je ne veux pas qu'elles éclipsent le descriptif, mais qu'elles
 * soient quand même faciles à voir. »
 *
 * D'où DEUX crans, et pas un seul :
 *   `.is-livrable` → ce que le client repart avec (la vidéo, le modèle 3D).
 *                    Encre pleine et 500, plus un épaississement du filet en
 *                    regard de la ligne.
 *   `.is-delai`    → le délai de livraison. Encre pleine et 600, sans filet.
 *
 * ⚠️ LE FILET FAIT TOUT LE TRAVAIL, et c'est pour ça que ça reste discret. La
 * page se tient sur des traits d'un pixel ; épaissir le sien en regard de deux
 * lignes parle le même langage, là où une pastille ou un fond teinté auraient
 * fabriqué une carte dans la carte. Aucune ombre, aucune lueur — règle de la
 * page depuis le 31/07.
 * ⚠️ TOUJOURS PAS DE TERRE CUITE : cet accent appartient aux prix. Un livrable
 * ou un délai dans la couleur des remises se lirait comme une promotion.
 * ⚠️ 500 pour le livrable, 600 pour le délai : l'écart est volontaire. Au même
 * poids, les deux se disputeraient le regard et la liste redeviendrait plate.
 *
 * ⚠️ CLASSES EXPLICITES, PLUS `:last-child`. La règle précédente mettait en
 * avant la dernière ligne quelle qu'elle soit — sur le combo, elle décorait
 * « Vous n'avez plus qu'à envoyer le lien », que Lino a fait dégraisser le jour
 * même. Une position n'est pas un sens : c'est le rôle de la ligne qui décide,
 * et il s'écrit dans le balisage. */
.offer-liste li.is-livrable {
  position: relative;
  color: var(--im-ink);
  font-weight: 500;
}
/* le filet de la liste, épaissi en regard de cette ligne seulement.
   ⚠️ `left: -1rem` = la marge intérieure de `.offer-liste`, et `-1px` de
   largeur en plus pour couvrir exactement le trait existant. Les désaccorder
   laisse voir un décalage d'un pixel, très visible sur un trait fin. */
.offer-liste li.is-livrable::before {
  content: "";
  position: absolute;
  left: calc(-1rem - 1px);
  top: 0.15em; bottom: 0.15em;
  width: 2px;
  border-radius: 2px;
  background: var(--im-ink);
}
.offer-liste li.is-delai {
  color: var(--im-ink);
  font-weight: 600;
}

/* Remise et bouton sur la MÊME ligne (Lino, 02/08) : le prix et le geste qui
   le déclenche se lisent d'un seul regard. Ils se replient l'un sous l'autre
   sous 560 px, où la ligne ne tient plus. */
.offer-deal {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 1rem clamp(1.4rem, 4vw, 2.6rem);
  margin: 0;
}
/* « Offre mois d'août » AU-DESSUS du prix, sur tous les écrans depuis le
   08/08/2026. Elle était à côté tant que la remise tenait en cinq caractères
   (« −30 % ») ; « 1,50 €/m² 0,80 €/m² » fait 257 px, et la ligne
   prix + pastille + bouton passait à 618 px pour 558 disponibles — le bouton
   tombait à la ligne. Or il doit rester COLLÉ AU PRIX (règle de Lino du
   02/08). C'est exactement le traitement que le téléphone avait déjà : les
   deux tailles d'écran se rejoignent, une règle en moins. */
.offer-price { display: flex; flex-direction: column-reverse;
  align-items: flex-start; gap: 0.24rem; margin: 0; }

/* ===== PRIX AU m² — remplace les pourcentages de remise (Lino, 08/08/2026) =====
 * L'ancien prix est BARRÉ EN DIAGONALE, du bas-gauche vers le haut-droite (sa
 * demande), et les deux prix sont dans la TERRE CUITE des anciennes remises :
 * sur cette page cette couleur ne sert qu'à ça, c'est elle qui signale l'offre.
 * La hiérarchie entre les deux prix se joue au CORPS et à la GRAISSE, pas en
 * délavant l'ancien — délavé, il ne se lit plus, et c'est pourtant lui qui
 * donne sa valeur au second.
 * « Images drone » n'a qu'un seul prix : le bloc marche à un ou deux enfants.
 */
.offer-amounts {
  display: inline-flex; align-items: baseline; flex-wrap: wrap;
  gap: 0.1rem 0.62rem;
}
.offer-off {
  font-family: var(--im-display);
  font-weight: 600;
  /* descendu de 2,1→1,85 rem et de 5,8→5 vw : « 0,80 €/m² » fait trois fois la
     largeur de « −30 % », il débordait du cartouche sur téléphone. */
  font-size: clamp(1.85rem, 5vw, 2.7rem);
  letter-spacing: -0.01em;
  color: var(--im-deal);
  white-space: nowrap;
}
.offer-was {
  position: relative;
  /* `<s>` porte un barré HORIZONTAL par défaut : on le retire, la diagonale
     est tracée juste en dessous. La balise reste un `<s>` pour que les
     lecteurs d'écran annoncent bien un prix supprimé — la barre CSS, elle,
     ne dit rien à personne. */
  text-decoration: none;
  font-family: var(--im-display);
  font-weight: 400;
  font-size: clamp(1.1rem, 2.9vw, 1.5rem);
  color: var(--im-deal);
  white-space: nowrap;
}
/* La barre. Rotation NÉGATIVE : l'extrémité droite monte, donc le trait part
   d'en bas à gauche. Un débord de 0,18 em de chaque côté — c'est lui qui fait
   lire un geste tracé par-dessus le prix, et non un soulignement de travers.
   1,5 px et non 2 : à ce corps, un trait épais donne un prix « annulé » là où
   on veut un prix « remplacé ». Aucune ombre, aucun éclat (règle de la page). */
.offer-was::after {
  content: "";
  position: absolute;
  left: -0.18em; right: -0.18em;
  top: 50%;
  height: 1.5px;
  border-radius: 2px;
  background: var(--im-deal);
  transform-origin: center;
  transform: translateY(-50%) rotate(-13deg);
}
/* « Offre mois d'août » dans le vert lumineux (Lino, 02/08) : en gris discret
   elle passait inaperçue alors qu'elle qualifie la remise. */
.offer-when {
  font-size: 0.62rem; font-weight: 600;
  letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--im-accent-lit);
}

/* TOUS les boutons pleins depuis le 02/08/2026 (Lino) — le combo n'a donc
   plus de marque distinctive, c'est assumé : les trois offres sont au même
   niveau et le combo se vend par son texte et son −45 %. La classe
   `is-primary` n'a plus lieu d'être, ne pas la réintroduire. */
.btn-devis {
  display: inline-flex; align-items: center; gap: 0.8em;
  padding: 16px 32px;
  border: 1px solid var(--im-accent);
  border-radius: 0;                     /* angles droits : plus architectural */
  background: var(--im-accent);
  color: var(--im-bg);
  font-family: var(--im-sans); font-size: 0.72rem; font-weight: 500;
  letter-spacing: 0.22em; text-transform: uppercase;
  cursor: pointer;
  transition: background 0.4s ease, color 0.4s ease, border-color 0.4s ease;
}
.btn-devis::after { content: "→"; letter-spacing: 0; transition: transform 0.4s ease; }
.btn-devis:hover { background: var(--im-ink); border-color: var(--im-ink); }
.btn-devis:hover::after { transform: translateX(4px); }

.offer-combo .offer-h { font-size: clamp(1.85rem, 5vw, 2.9rem); max-width: 20ch; }

/* ==========================================================================
   LES QUATRE FORFAITS DE « OBTENEZ PLUS DE MANDATS » (Lino, 16/08/2026)
   La carte des agents est la seule à vendre des VOLUMES et non une
   prestation unique : quatre forfaits, un rail de sélection, une liste par
   forfait. Même mécanique que /action, habillée à la charte d'ici — filets
   d'un pixel, angles droits, aucune ombre.
   ========================================================================== */
/* ⚠️ LE RAIL SE DIMENSIONNE SUR SON CONTENU (`fit-content`) et non sur la
   colonne : à pleine largeur, les quatre boutons s'étireraient et « Shot »
   occuperait autant de place que « Croissance ». C'est un choix, pas un
   tableau comparatif. */
.offer-opts {
  display: flex; flex-wrap: wrap;
  width: fit-content; max-width: 100%;
  margin: 0 0 1.7rem;
  border: 1px solid var(--im-line);
}
.offer-opt {
  appearance: none;
  padding: 12px clamp(14px, 3.4vw, 22px);
  border: 0;
  border-right: 1px solid var(--im-line);
  border-radius: 0;                     /* angles droits, comme .btn-devis */
  background: transparent;
  color: var(--im-text);
  font-family: var(--im-sans);
  font-size: clamp(0.66rem, 1.6vw, 0.72rem);
  font-weight: 500;
  letter-spacing: 0.16em; text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.35s ease, color 0.35s ease;
}
.offer-opt:last-child { border-right: 0; }
.offer-opt:hover { color: var(--im-ink); }
/* ⚠️ DEUX PAR LIGNE SOUS 560 px, ET PAS UN SIMPLE `flex-wrap` LIVRÉ À
   LUI-MÊME. À 375 px les quatre boutons se répartissaient 3 + 1 : la
   première ligne s'arrêtait après « Pro » en laissant une case vide bordée
   à droite, et « Max » se retrouvait seul en dessous. Deux colonnes égales
   donnent un pavé plein, et c'est le seul découpage qui tombe juste avec
   quatre forfaits.
   ⚠️ Les règles de bordure comptent SUR QUATRE ÉLÉMENTS : `2n` ferme le bord
   droit de chaque fin de ligne, `n+3` retire le trait bas de la DERNIÈRE
   ligne. Un cinquième forfait casserait les deux — les recalculer alors. */
@media (max-width: 560px) {
  .offer-opts { width: 100%; }
  .offer-opt {
    flex: 1 1 calc(50% - 1px);
    border-bottom: 1px solid var(--im-line);
  }
  .offer-opt:nth-child(2n) { border-right: 0; }
  .offer-opt:nth-child(n+3) { border-bottom: 0; }
}
/* Le forfait choisi prend le vert plein du bouton « Demander » : les deux
   gestes appartiennent à la même décision, ils ne peuvent pas avoir deux
   couleurs d'état. ⚠️ Pas de terre cuite ici — elle est réservée aux prix. */
.offer-opt.is-active { background: var(--im-accent); color: var(--im-bg); }

/* ⚠️⚠️ LES QUATRE LISTES SONT DANS LE HTML et c'est le CSS qui montre la
   bonne, d'après `data-forfait` posé sur la SECTION. Sans JS, `data-forfait`
   garde sa valeur d'origine et la liste « Shot » reste affichée : jamais un
   trou, et les quatre restent lisibles par Google.
   ⚠️ `display: flex` et non `block` : `.offer-liste` est une colonne flex, son
   `gap` de 0,5 rem en dépend. */
.offer-forfaits .offer-liste { display: none; margin-top: 0.6rem; }
.offer-forfaits[data-forfait="f1"] .offer-liste[data-pour="f1"],
.offer-forfaits[data-forfait="f2"] .offer-liste[data-pour="f2"],
.offer-forfaits[data-forfait="f3"] .offer-liste[data-pour="f3"],
.offer-forfaits[data-forfait="f4"] .offer-liste[data-pour="f4"] { display: flex; }

/* La remise en pourcentage, à côté du prix. ⚠️ ELLE NE REVIENT QUE SUR CETTE
   CARTE : la page avait remplacé les pourcentages par l'ancien prix barré le
   08/08/2026, mais un ancien prix afficherait ici la grille horaire de Lino en
   clair — ce qu'il ne veut pas. Le pourcentage dit la remise sans la publier.
   Terre cuite comme les prix : c'est la couleur de l'offre sur cette page. */
.offer-remise {
  font-family: var(--im-sans);
  font-size: clamp(0.72rem, 1.8vw, 0.82rem);
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--im-deal);
  white-space: nowrap;
}

/* ===== Contact — c'est lui qui recouvre la photo =====
   Son fond doit rester OPAQUE : c'est ce qui masque l'image quand il monte.
   Il reprend les nuances de sable du fond de page pour que la couverture ne
   se voie pas comme un rectangle rapporté. Hauteur minimale d'un écran, sinon
   il ne couvre pas entièrement la photo en fin de course. */
.im-contact {
  position: relative;
  min-height: calc(var(--im-vh, 1svh) * 100);
  padding: clamp(72px, 13vh, 128px) 0 clamp(40px, 7vh, 72px);
  background:
    radial-gradient(68% 42% at 10% 14%, #fbf7ee 0%, transparent 62%),
    radial-gradient(58% 38% at 92% 38%, #ece2cd 0%, transparent 64%),
    var(--im-bg);
}
/* Centré et nettement plus gros (Lino, 02/08) : le volet s'ouvrait sur une
   ligne minuscule alignée à gauche, on ne la voyait pas. */
.im-contact .wrap > .im-eyebrow,
.im-contact .wrap > h2 { text-align: center; }
.im-eyebrow {
  margin: 0 0 1rem;
  font-family: var(--im-sans);
  font-size: clamp(0.95rem, 2.6vw, 1.25rem); font-weight: 500;
  letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--im-accent);
}
.im-contact h2 {
  margin: 0 auto 2.4rem;
  max-width: 22ch;
  font-family: var(--im-display);
  font-weight: var(--im-h-weight);
  font-size: clamp(1.9rem, 5vw, 3rem);
  line-height: 1.12;
  letter-spacing: var(--im-h-track);
  color: var(--im-ink);
}
/* « Écrivez-moi. » ne doit pas se couper sur son trait d'union */
.im-contact h2 b { font-weight: var(--im-h-weight); font-style: italic; color: var(--im-accent); white-space: nowrap; }

.im-foot {
  display: flex; flex-wrap: wrap; gap: 10px 26px;
  margin-top: clamp(38px, 6vh, 62px);
  padding: 26px 0 44px;
  border-top: 1px solid var(--im-line);
  font-size: 0.8rem; color: var(--im-muted);
}
.im-foot a { color: var(--im-muted); text-decoration: none; }
.im-foot a:hover { color: var(--im-accent); }

/* ===== Habillage du composant ask (ask.css) =====
   ask.css est déjà clair : on ne retouche que ce qui doit suivre la palette. */
.ask-standalone { padding: clamp(22px, 4vw, 34px) 0 0; }
.ask-modal { --ask-accent: var(--im-accent); --ask-accent-2: var(--im-ink); }
.ask-panel { background: var(--im-bg); border-color: var(--im-line); border-radius: 4px; }
.ask-title, .ask-done h3 { font-family: var(--im-display); font-weight: 400; color: var(--im-ink); }
.ask-eyebrow, .ask-field > span { color: var(--im-muted); letter-spacing: 0.18em; }
.ask-eyebrow { color: var(--im-accent); }
.ask-field input, .ask-field select, .ask-field textarea {
  border-radius: 2px; border-color: var(--im-line); background: #fffdf8; color: var(--im-ink);
}
.ask-field input:focus, .ask-field select:focus, .ask-field textarea:focus {
  border-color: var(--im-accent); box-shadow: 0 0 0 2px rgba(20, 69, 47, 0.14);
}
.ask-send {
  border-radius: 0; background: var(--im-accent); color: var(--im-bg);
  letter-spacing: 0.2em; text-transform: uppercase; font-size: 0.74rem;
  box-shadow: none;
}
.ask-send:hover:not(:disabled) { background: var(--im-ink); transform: none; }
.ask-done-badge { background: var(--im-accent); box-shadow: none; }
.ask-info-btn { background: var(--im-muted); }
.ask-info-btn:hover, .ask-info.is-open .ask-info-btn { background: var(--im-accent); }

/* Le comparateur ?fond=grain|degrade|plat a été retiré le 02/08/2026 : Lino a
   retenu les « nuances de sable », qui sont désormais posées directement sur
   `body` plus haut. Le grain de papier reste récupérable dans l'historique
   git si on veut le rajouter par-dessus un jour. */

/* ==========================================================================
   CARTOUCHES D'OFFRES — trois traitements en comparaison (Lino, 02/08 au soir)
   Ils passent par-dessus la photo de la villa : c'est ce contexte qui décide.
   ?cartes=sable (défaut) · ?cartes=verre · ?cartes=vert
   À réduire à un seul dès que Lino a choisi, comme pour ?style= le 31/07.
   ========================================================================== */

/* --- 1. SABLE — panneaux opaques qui glissent sur la photo. On voit l'image
   tout autour et entre les cartes, et le texte garde le contraste maximal.
   (valeurs par défaut posées sur .offer-inner, rien à déclarer ici) --- */

/* --- 2. VERRE DÉPOLI — on devine la photo au travers. Plus spectaculaire,
   mais `backdrop-filter` coûte cher au défilement sur téléphone et le
   contraste du texte baisse : à juger en conditions réelles. --- */
body[data-cartes="verre"] .offer-inner {
  background: rgba(250, 246, 237, 0.62);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
          backdrop-filter: blur(18px) saturate(140%);
  border-color: rgba(255, 255, 255, 0.55);
}

/* --- 3. VERT FONCÉ — panneaux dans le vert de la page, texte en blanc.
   Très lisible sur la photo, mais l'ambiance de la page bascule : elle est
   claire et aérée partout ailleurs. --- */
body[data-cartes="vert"] .offer-inner {
  background: var(--im-accent);
  border-color: rgba(255, 255, 255, 0.18);
}
body[data-cartes="vert"] .offer-h { color: #fff; }
body[data-cartes="vert"] .offer-p { color: rgba(255, 255, 255, 0.86); }
body[data-cartes="vert"] .offer-off,
body[data-cartes="vert"] .offer-was { color: #f0a077; }
body[data-cartes="vert"] .offer-was::after { background: #f0a077; }
body[data-cartes="vert"] .offer-when { color: #7fd3a6; }
body[data-cartes="vert"] .btn-devis {
  background: var(--im-bg); color: var(--im-accent); border-color: var(--im-bg);
}
body[data-cartes="vert"] .btn-devis:hover {
  background: #fff; border-color: #fff; color: var(--im-ink);
}

@media (max-width: 620px) {
  /* Le prix et le bouton doivent rester SUR LA MÊME LIGNE (Lino, 02/08),
     y compris sur un téléphone. Les trois éléments côte à côte n'y tiennent
     pas : « Offre mois d'août » passe donc AU-DESSUS du prix qu'elle
     qualifie (d'où column-reverse), ce qui libère la place pour le bouton.
     Le cartouche et le bouton se resserrent d'autant. */
  .offer-inner { padding: 22px; }
  .offer-price { gap: 0.15rem; }
  /* Les deux prix s'EMPILENT aussi (08/08). Côte à côte ils font ~200 px : à
     375 px il ne reste que ~199 px une fois le bouton posé, on débordait. */
  .offer-amounts { flex-direction: column; align-items: flex-start; gap: 0.18rem; }
  .offer-deal { gap: 0.9rem; flex-wrap: nowrap; }
  /* le libellé du bouton ne doit pas se casser en deux : on le resserre
     plutôt que de le laisser passer à la ligne dans sa propre boîte */
  .btn-devis {
    padding: 13px 18px; white-space: nowrap;
    font-size: 0.66rem; letter-spacing: 0.16em;
  }
}
/* dernier recours sur les très petits écrans : on empile */
@media (max-width: 340px) {
  .offer-deal { flex-wrap: wrap; }
}

/* Ordinateur — PLEIN ÉCRAN depuis le 04/08/2026 (Lino).
   La page s'ouvrait sur une BANDE de 66 vh depuis le 02/08. La raison était
   écrite noir sur blanc : « la séquence étant verticale, la pleine largeur
   n'en montre qu'une tranche centrale ». Cette raison n'existe plus — au-delà
   de 900 px, herowide.js sert désormais une vraie bande 16:9 (2160 px natifs
   découpés dans le master 4K), qui remplit l'écran sans rien rogner.
   Garder les 66 vh reviendrait à recadrer une deuxième fois un plan déjà
   cadré pour ce format, et à jeter un tiers de l'image qu'on vient d'aller
   chercher. `min-height` retombe donc sur les 100 svh déclarés plus haut.
   ⚠️ Ne PAS y remettre une hauteur ici sans rebasculer aussi l'en-tête sur la
   verticale : les deux décisions vont ensemble. */
@media (min-width: 900px) {
  /* Les trois colonnes suivent le titre au ch près : même bord gauche, donc
     il ne faut jamais en élargir une seule. */
  .im-title, .im-lede, .im-proof { max-width: 22ch; }
}

/* ==========================================================================
   EN-TÊTE VERTICALE SUR ORDINATEUR (Lino, 08-09/08/2026) — EN LIGNE.
   Au-delà de 900 px, la vidéo NE bascule PLUS sur la bande 16:9 : elle reste
   verticale, dans un cadre au format téléphone posé à droite, et le titre
   passe à sa gauche. Le comparateur `?hero=portrait` a disparu avec la
   décision, et `herowide.js` n'est plus chargé par la page.

   ⚠️ Sous 900 px, RIEN ne change : sur un téléphone la verticale en
   plein cadre est déjà le bon traitement, il n'y a pas de place pour une
   colonne de texte à côté, et le cadre arrondi n'aurait aucun sens sur un
   écran qui EST déjà le cadre.

   ⚠️ Le poids du fichier ne change pas : c'est `hero.mp4` (1080×1920, 9,9 Mo)
   qui est servi, celui du mobile — donc plus léger que la bande 16:9 (12 Mo).
   Et cette fois il est affiché à sa taille réelle ou presque, au lieu d'être
   agrandi 2,7× : c'est le seul traitement de la page où l'image est nette
   sans avoir à encoder un second fichier.
   ========================================================================== */
/* ⚠️ HORS de l'essai, les deux enveloppes du téléphone DISPARAISSENT de l'arbre
   de rendu. `display: contents` et rien d'autre : la vidéo redevient alors
   l'enfant direct de `.im-head` et son `position: absolute; inset: 0` se
   résout bien sur l'en-tête. Leur donner une boîte, même vide, casserait
   l'en-tête plein cadre servie à tout le monde. */
.im-head-phone, .im-phone-screen { display: contents; }
/* ⚠️ CES TROIS RÈGLES DOIVENT RESTER AVANT LA MEDIA QUERY. Elles ont la même
   spécificité que celles qui les rouvrent au-delà de 900 px (une classe de
   part et d'autre — une media query n'ajoute AUCUNE spécificité), donc c'est
   l'ORDRE qui tranche. Posées après, elles annulent la mise en page laptop et
   la colonne de texte revient vide : constaté le 09/08/2026 en retirant la
   porte `?hero=portrait`, qui masquait le problème par sa spécificité. */
.im-phone-island, .im-phone-key, .im-head-copy { display: none; }

@media (min-width: 900px) {
  .im-head {
    display: grid;
    /* Les deux colonnes se dimensionnent sur leur contenu et le couple est
       CENTRÉ (Lino, 08/08) : en `1fr` pour le texte, la colonne faisait 871 px
       pour un texte de 570, et les 300 px de vide retombaient au milieu de la
       page. Le texte se décale donc vers la droite et le téléphone vers la
       gauche d'un même mouvement, sans qu'aucune marge soit écrite en dur. */
    grid-template-columns: auto auto;
    justify-content: center;
    align-items: center;
    gap: clamp(34px, 4vw, 76px);
    /* ==================================================================
       ⚠️⚠️ LE COUPLE EST CENTRÉ ENTRE LA BARRE DE MENU ET LE BAS DE L'ÉCRAN
       (Lino, 16/08/2026, et c'est une RÈGLE, pas un réglage) : « je veux que
       l'ensemble de ces éléments soit à égale distance du bas de la page héros
       et de la barre flottante du menu, pour créer quelque chose d'homogène ».

       COMMENT ÇA MARCHE, et pourquoi il ne faut pas y remettre des valeurs en
       dur : la réserve du haut vaut EXACTEMENT la hauteur de la barre de menu
       flottante (76 px, son bord bas), celle du bas vaut ZÉRO, et c'est
       `align-content: center` qui répartit le reste. Les deux écarts sont donc
       égaux par construction, quelle que soit la hauteur de l'écran et quelle
       que soit la longueur du texte. Toute valeur ajoutée en bas casse
       l'égalité ; tout écart ajouté en haut la casse aussi.
       ⚠️ 76 px N'EST PAS UNE MARGE DE CONFORT, c'est le bord bas de la barre.
       Si `menu.css` change la hauteur de la barre, cette valeur change avec.
       ⚠️ HISTORIQUE À NE PAS REJOUER : trois réglages successifs le même jour
       (94 px, puis 84, puis le téléphone remonté) ont tous échoué parce qu'ils
       traitaient des marges au lieu de poser la règle. Ce qui bloquait, c'est
       que « Défiler » était DANS la colonne et la rallongeait de 64 px : il est
       sorti du flux (voir `.im-hint` plus bas), et l'en-tête tient enfin dans
       un écran avec de la place à répartir.
       ================================================================== */
    /* ==================================================================
       ⚠️ AJOUT DU 21/08/2026 (Lino) : « descends le téléphone et le titre, ils
       ne doivent pas être collés à la barre flottante ». LA RÈGLE CI-DESSUS
       N'EST PAS ABANDONNÉE, elle est complétée, et il faut comprendre pourquoi
       elle ne suffisait plus.

       Elle reposait sur `align-content: center` pour répartir le vide. Or il
       n'y a de vide à répartir QUE SI LA COLONNE TIENT DANS L'ÉCRAN. Depuis
       que la paire de boutons s'est intercalée entre le titre et le texte, la
       colonne fait 800 px pour 754 disponibles sur un écran de 830 : plus rien
       à répartir, et le contenu se cale sur la réserve du haut — qui vaut
       exactement le bord bas de la barre. Titre et téléphone collés à la
       barre, au pixel. Mesuré à 1512 × 830, l'écran de Lino.

       LA CORRECTION GARDE L'ÉGALITÉ : on ajoute le MÊME écart en haut et en
       bas. La distance à la barre vaut donc `écart`, celle au bas de l'écran
       vaut `écart`, et quand l'écran est assez haut `align-content: center`
       ajoute la même moitié de chaque côté. Les deux restent égales par
       construction, exactement comme le 16/08.
       ⚠️ NE PAS AJOUTER L'ÉCART D'UN SEUL CÔTÉ : ce serait précisément ce que
       le paragraphe ci-dessus interdit.
       ⚠️ 76 px reste le bord bas de la barre, pas une marge de confort. Ce qui
       s'ajoute par-dessus, lui, EST la marge de confort.
       ⚠️ RÈGLE POUR LES AUTRES PAGES DE MÉTIER (demande de Lino le même jour) :
       même construction partout — réserve haute = bord bas de la barre + écart,
       réserve basse = le même écart. /action y arrive par d'autres valeurs
       (94 px / 34 px), écrites avant la règle ; à réaligner le jour où on y
       touche. */
    align-content: center;
    padding: calc(76px + clamp(20px, 3vh, 36px)) clamp(28px, 5vw, 72px)
             clamp(20px, 3vh, 36px);
  }

  /* ===== LE TÉLÉPHONE =====
     Proportions relevées sur la maquette fournie par Lino (image de 1920) :
     corps 720 × 1502, écran 680 × 1466, cadre 20, rayon 85, îlot 178 × 46.
     Tout est exprimé en fraction de `--ph-w` pour que l'objet reste juste à
     n'importe quelle taille — un rayon en px se déforme dès qu'on change la
     hauteur, et c'est exactement ce qui trahit un faux téléphone.
     ⚠️ `--ph-w` se DÉDUIT de la hauteur, pas l'inverse : c'est la hauteur
     disponible à l'écran qui commande, la largeur suit. */
  .im-head-phone {
    display: block;
    position: relative;
    box-sizing: border-box;
    /* ⚠️ LE TÉLÉPHONE EST CALÉ EN HAUT, PAS CENTRÉ (Lino, 16/08/2026 :
       « remonte encore un peu le téléphone »). `.im-head` reste en
       `align-items: center` pour la colonne de texte ; seul le cadre s'en
       détache. La colonne fait maintenant plus du double de sa hauteur : centré
       en regard d'elle, il descendait de 32 px sous le titre alors que rien ne
       l'y retenait. Il part désormais de la MÊME LIGNE que le titre, ce qui
       donne au passage un bord haut commun aux deux colonnes.
       ⚠️ Ne pas transformer ça en `align-items: start` sur `.im-head` : la
       colonne de texte, elle, doit rester centrée — c'est ce centrage qui
       rattrape les écrans hauts, où le texte ne remplit pas la hauteur. */
    align-self: start;
    /* hauteur d'écran moins les réserves haut et bas ; le plafond évite
       d'agrandir une source qui ne fait que 1080 × 1920 */
    --ph-h: min(calc(100svh - 160px), 820px);
    --ph-w: calc(var(--ph-h) * 0.4793);   /* 720 / 1502 */
    height: var(--ph-h);
    width: var(--ph-w);
    padding: calc(var(--ph-w) * 0.0278);  /* épaisseur du cadre : 20 / 720 */
    border-radius: calc(var(--ph-w) * 0.118);
    /* le corps : un noir légèrement dégradé pour que la tranche accroche la
       lumière comme du titane, plus un liseré clair d'un pixel. Aucune lueur,
       aucun halo — c'est un reflet de matière, pas un éclat. */
    background:
      linear-gradient(145deg, #3a3a3d 0%, #17171a 16%, #17171a 84%, #3a3a3d 100%);
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, 0.14),
      0 34px 80px rgba(13, 42, 30, 0.26);
  }

  .im-phone-screen {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #000;
    border-radius: calc(var(--ph-w) * 0.0902);  /* rayon extérieur − cadre */
  }

  /* ⚠️ La vidéo garde son `position: absolute` : elle se cale simplement sur
     l'écran du téléphone, qui est en `position: relative`. Rien à annuler,
     donc rien qui puisse diverger de la règle par défaut.
     ⚠️ L'écran fait 1:2,156 (le vrai rapport d'un iPhone) alors que la
     séquence est en 9:16. `cover` rogne donc ~17 % de la LARGEUR, à gauche et
     à droite. C'est du cadrage perdu, pas de la définition : on affiche
     416 px de large pour 1080 encodés. */
  .im-head-bg {
    z-index: auto;
    border-radius: inherit;
  }

  /* L'îlot dynamique et son objectif. */
  .im-phone-island {
    display: block;
    position: absolute;
    z-index: 2;
    top: calc(var(--ph-w) * 0.0306);
    left: 50%;
    transform: translateX(-50%);
    width: calc(var(--ph-w) * 0.247);
    height: calc(var(--ph-w) * 0.0639);
    border-radius: 999px;
    background: #000;
  }
  .im-phone-island i {
    position: absolute;
    top: 50%;
    right: calc(var(--ph-w) * 0.026);
    width: calc(var(--ph-w) * 0.0361);
    height: calc(var(--ph-w) * 0.0361);
    transform: translateY(-50%);
    border-radius: 50%;
    /* l'objectif : un bleu très sombre avec un reflet décentré, comme sur la
       maquette — sans lui, l'îlot n'est qu'une pilule noire */
    background:
      radial-gradient(circle at 62% 38%, #2f4f7a 0%, #16233a 46%, #05070c 78%);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
  }

  /* Les touches. Position et longueur en % de la HAUTEUR du corps, relevées
     sur la maquette. Elles débordent du cadre, d'où le `left`/`right` négatif. */
  .im-phone-key {
    display: block;
    position: absolute;
    width: calc(var(--ph-w) * 0.0139);
    background: linear-gradient(90deg, #45454a, #202024);
  }
  .k-action,
  .k-vol-up,
  .k-vol-dn {
    left: calc(var(--ph-w) * -0.0125);
    border-radius: calc(var(--ph-w) * 0.006) 0 0 calc(var(--ph-w) * 0.006);
    background: linear-gradient(270deg, #45454a, #202024);
  }
  .k-side {
    right: calc(var(--ph-w) * -0.0125);
    border-radius: 0 calc(var(--ph-w) * 0.006) calc(var(--ph-w) * 0.006) 0;
  }
  .k-action { top: 12.6%; height: 3.7%; }
  .k-vol-up { top: 20.6%; height: 6.3%; }
  .k-vol-dn { top: 29.3%; height: 6.3%; }
  .k-side   { top: 21.6%; height: 10.3%; }

  /* La colonne de texte. `--im-hero-h` est posée ICI et lue par le titre ET
     par `.im-lede` : les deux plafonnent à 22ch, et `ch` se résout sur la
     fonte de l'élément — sans un corps commun, les deux colonnes n'auraient
     plus la même largeur et le texte se décalerait du titre. Même piège que
     lors de l'ajout de `.im-lede`. */
  .im-head-copy {
    display: block;
    --im-hero-h: clamp(1.9rem, 3.4vw, 3.2rem);
    /* ===== LARGEUR DE LA COLONNE (Lino, 15/08/2026) =====
       « Fais la colonne plus large pour que le texte soit plus aplati, et
       décale le téléphone à droite pour que l'ensemble tienne dans le hero. »
       ⚠️ LE DÉCALAGE DU TÉLÉPHONE N'EST ÉCRIT NULLE PART, et il ne doit pas
       l'être : les deux colonnes de la grille se dimensionnent sur leur
       contenu et le COUPLE est centré (voir `.im-head`). Élargir le texte
       pousse donc le téléphone vers la droite tout seul — mesuré, il passe de
       828 à 981 px. Une marge écrite en dur se battrait avec ce centrage.
       ⚠️ LE PLAFOND EN `vw` N'EST PAS DÉCORATIF. À 1280 px de large, l'écran
       n'offre que 1136 px une fois les marges de l'en-tête retirées, dont 355
       pour le téléphone et 58 pour l'écart : il ne reste que 723 px. Une
       largeur fixe en rem y ferait déborder la grille.
       ⚠️ LE PLAFOND EN `rem` EST UNE MESURE DE LECTURE, pas une place
       disponible (15/08/2026, après « c'est illisible »). À 52 rem et au corps
       rétabli, la ligne dépassait 90 signes : au retour à la ligne, l'œil ne
       retrouve plus le début de la suivante. 40 rem la tient autour de 70 à
       75 signes, la limite haute du confortable. Élargir encore n'aiderait
       pas — ce serait le défaut d'aujourd'hui, en pire. */
    --im-col: min(56vw, 40rem);
  }
  /* ⚠️ `width: auto` et non `100%` : la colonne est en `auto`, elle se
     dimensionne sur son contenu — un pourcentage y serait circulaire. C'est
     `max-width: 22ch` qui fixe la longueur de ligne, comme ailleurs. */
  .im-head-copy .im-lede {
    width: auto;
    margin: 0;
    font-size: var(--im-hero-h);
  }
  /* ⚠️⚠️ LE TITRE A UNE LARGEUR FERME, ET C'EST CE QUI EMPÊCHE LE TÉLÉPHONE DE
     BOUGER (Lino, 15/08/2026 : « quand il s'écrit il fait se décaler le
     téléphone »).
     LA CAUSE. `.im-head-copy` et le cadre du téléphone sont deux éléments
     flexibles CENTRÉS ensemble : la place prise par la colonne décide donc de
     la position du téléphone. Or une colonne en `auto` se dimensionne sur son
     contenu, et son contenu est un texte qui s'écrit lettre par lettre —
     « un_ » ne fait pas la même largeur que la phrase entière. La colonne
     respirait à chaque frappe, et le téléphone glissait avec elle.
     LA PARADE. Une largeur FERME de 22ch, exactement la valeur que
     `max-width` plafonnait déjà : à l'arrêt rien ne change d'un pixel, mais
     la colonne ne dépend plus de ce qui est écrit dedans.
     ⚠️ Le `ch` se résout sur la fonte de L'ÉLÉMENT : cette valeur n'a de sens
     que parce que le titre porte `--im-display` et `--im-hero-h`. La poser sur
     `.im-head-copy`, qui hérite du sans, donnerait une tout autre largeur.
     ⚠️ `.im-lede` reste en `auto` sous son `max-width: 22ch` : c'est un bloc,
     il remplit donc déjà la colonne, et c'est le titre qui en fixe la
     largeur. Les deux gardent le même bord gauche. */
  .im-head-copy .im-title {
    width: var(--im-col);
    margin: 0;
    font-size: var(--im-hero-h);
    padding: 0 0 clamp(16px, 2.2vh, 28px);
  }
  .im-head-copy .im-lede { padding: 0; }

  /* ===== LE BLOC DE TEXTE DANS LA COLONNE (Lino, 15/08/2026) =====
     Il est monté ici, entre le titre et « Défiler » (le déplacement est fait
     par le script de `realestate.html`). Trois réglages, et un seul but : que
     l'ensemble tienne dans la hauteur d'un écran.
     ⚠️ Le `max-width: 44ch` des paragraphes est LEVÉ : c'était la mesure de
     lecture quand le bloc était seul au milieu du sable ; ici c'est la
     colonne qui la fixe, et un plafond en ch la rendrait plus étroite qu'elle
     — le texte serait aussi haut qu'avant dans une colonne deux fois plus
     large. */
  .im-head-copy .im-proof { max-width: var(--im-col); }
  .im-head-copy .im-proof-p,
  .im-head-copy .im-proof-src { max-width: 100%; }
  /* ⚠️⚠️ LE CORPS NE SE RÈGLE PLUS SUR LA HAUTEUR D'ÉCRAN (Lino, 15/08/2026 :
     « c'est illisible »). Une taille en `vh` retombait sur son plancher dès
     que la fenêtre était un peu basse : sur la sienne, le texte est descendu à
     14,4 px, et une fenêtre plus courte encore l'y aurait laissé quoi qu'il
     arrive. On ne fait pas rentrer un texte en le rendant illisible.
     ⚠️ Le corps suit donc la LARGEUR, comme partout ailleurs sur le site, et
     ne descend jamais sous 1 rem. Ce qui a été gagné pour compenser : l'écart
     sous le titre, resserré juste en dessous, et « Défiler », sorti de la
     colonne (il vaut à lui seul 85 px).
     ⚠️ Si l'ensemble déborde à nouveau de l'écran, c'est le TEXTE qu'il faut
     raccourcir. Pas le corps, pas l'interligne. */
  .im-head-copy .im-proof-p {
    font-size: clamp(1rem, 1.25vw, 1.12rem);
    line-height: 1.55;
  }
  .im-head-copy .im-proof-p + .im-proof-p { margin-top: 0.78em; }
  /* ⚠️ L'écart sous le titre est resserré ICI SEULEMENT. Dans le flux de la
     page (téléphone), `.im-proof` respire — il arrive après une longue
     descente. Dans la colonne il suit le titre immédiatement, et les 64 px de
     la règle de base y creusaient un trou que Lino a entouré. */
  .im-head-copy .im-proof {
    margin-top: clamp(8px, 1.1vh, 12px);
    padding-top: clamp(10px, 1.4vh, 15px);
  }
  /* Le titre rend lui aussi de la place : c'est l'écart CUMULÉ des trois
     réglages qui se voyait, pas l'un d'eux. */
  .im-head-copy .im-title { padding-bottom: clamp(10px, 1.4vh, 16px); }
  /* La source est repoussée au BAS DE LA COLONNE, séparée du texte (Lino,
     15/08/2026 : « les sources dans le petit rectangle en dessous »). C'est le
     cartel : il se lit après, et de loin — pas dans la foulée du dernier
     paragraphe. */
  /* ⚠️ RESSERRÉ LE 16/08/2026 avec les réserves de `.im-head` : 34 px de
     respiration au-dessus du cartel étaient le dernier gros poste réglable
     sans toucher au corps ni à l'interligne du texte, que Lino a déjà fait
     rétablir une fois (« c'est illisible »). Il reste séparé du dernier
     paragraphe — c'est ce qui le fait lire comme un cartel — mais de moins. */
  .im-head-copy .im-proof-src { margin-top: clamp(10px, 1.4vh, 18px); }

  /* ⚠️⚠️ « DÉFILER » EST HORS DU FLUX, DANS LE COIN BAS-DROIT DE L'EN-TÊTE
     (Lino, 16/08/2026, emplacement désigné au feutre rouge sur une capture).
     ET C'EST CE QUI PERMET TOUT LE RESTE : tant qu'il était dans la colonne, il
     lui ajoutait 64 px et l'en-tête débordait de l'écran — impossible alors de
     répartir quoi que ce soit à égale distance. Hors du flux, il ne pèse plus
     rien dans la hauteur du couple, et `.im-head` peut enfin faire exactement
     un écran.
     ⚠️ NE PAS LE REMETTRE DANS LA COLONNE. Deux tentatives le 16/08 : posé au
     bas de l'en-tête en absolu il tombait sous la ligne de flottaison (parce
     que l'en-tête, lui, débordait) ; remis dans le flux il rallongeait la
     colonne d'autant. C'est l'en-tête qui était trop haut, pas lui qui était
     mal placé.
     ⚠️ IL EST DANS LE VIDE À DROITE DU TÉLÉPHONE, pas sous la colonne de
     texte : c'est la seule zone de l'en-tête que rien n'occupe. Son bord droit
     s'aligne sur la marge de l'en-tête, donc sur le bord droit de la page.
     ⚠️ `.im-head` est déjà `position: relative` (la vidéo s'y cale en absolu) :
     ne pas le lui retirer, l'invite partirait se caler sur la fenêtre.
     ⚠️ Le blanc et l'ombre portée de la version vidéo laissent la place à
     l'encre : ici le mot est sur le sable, pas sur l'image. */
  /* ⚠️ LE COIN EST ÉTROIT, ET SA LARGEUR DÉPEND DE L'ÉCRAN. Le couple
     texte + téléphone est CENTRÉ : la bande libre à droite vaut donc la moitié
     de ce qui reste une fois le couple posé — 141 px à 1280, 221 px à 1440.
     À la taille de la version vidéo (1,18 rem, interlettrage 0,3 em) le mot
     fait 121 px et MORD SUR LE TÉLÉPHONE en dessous de ~1400 px de large,
     mesuré. D'où un corps et un interlettrage réduits ICI SEULEMENT : 77 px,
     qui passent partout à partir de 900 px.
     ⚠️ Ne pas lui rendre sa taille de la version vidéo en trouvant qu'il fait
     petit : sur la vidéo il est seul en plein cadre, ici il est dans une bande
     de 100 px entre le cadre du téléphone et le bord de la page. */
  .im-hint {
    position: absolute;
    left: auto;
    right: clamp(20px, 3vw, 56px);
    bottom: clamp(24px, 5vh, 48px);
    transform: none;
    margin: 0;
    display: inline-flex;
    align-items: center;
    font-size: clamp(0.8rem, 1vw, 0.95rem);
    letter-spacing: 0.24em; text-indent: 0.24em;
    color: var(--im-ink);
    text-shadow: none;
    animation-name: im-hint-flash-ink;
  }
  @keyframes im-hint-flash-ink {
    0%, 49%   { color: var(--im-ink); }
    50%, 100% { color: var(--im-accent-lit); }
  }

  /* ⚠️ LA BARRE DE MENU DOIT ÊTRE REPRISE, et c'est le seul endroit du site où
     ça arrive. Elle est en verre sombre à 34 % (menu.css), calibrée pour
     passer SUR UNE VIDÉO. Ici la vidéo n'est plus derrière elle : elle se
     retrouve sur le sable, où le verre donne un gris clair (#a8a5a0) et le
     wordmark blanc tombe à 2,2:1 — illisible, vérifié à l'écran.
     À 0,72 le fond devient #545452 : 7,1:1 pour le blanc et 5,3:1 pour le
     jaune de marque. Et plus bas dans la page, là où la barre repasse sur la
     photo de la villa, elle reste correcte — simplement moins transparente.
     ⚠️ menu.css n'est PAS touché : il reste sans dépendance de palette, comme
     prévu. C'est bien la page qui surcharge le composant, et uniquement sous
     `?hero=portrait`. */
  .menu-bar {
    background: rgba(22, 24, 27, 0.72);
    border-color: rgba(255, 255, 255, 0.16);
  }
}
/* ===== Entrée « Récupérer mes vidéos » du menu (04/08/2026) =====
   Le panneau de menu est quasi noir (rgba(20,21,23,.92)) : le vert de la page
   ne peut PAS y être repris tel quel. Mesuré sur ce fond, --im-accent (#14452f)
   tombe à 1,67:1 et --im-accent-lit (#1f6b45) à 2,83:1 — illisibles tous les
   deux. #54bd85 donne 7,83:1, soit exactement le poids visuel du corail du
   monde Sport (7,68:1), tout en restant le vert tropical de la page.
   Même raisonnement que la pastille « Offre mois d'août » du hub, éclaircie
   pour la même raison. Ne pas y remettre le vert foncé. */
.menu-item.is-accent { color: #54bd85; }
.menu-item.is-accent:hover { background: rgba(84, 189, 133, 0.14); }
