/* ===========================================================================
   HORIZON — fondation
   Territoire Exploration, verbe « se projeter ».
   Spec : docs/superpowers/specs/2026-09-16-horizon-design.md
   Bootstrap est retiré du global.html.twig de ce modèle : cette feuille porte
   donc sa propre réinitialisation.
   =========================================================================== */

/* Polices auto-hébergées, jamais appelées chez un tiers : tools/verif/horizon.php
   refuse tout lien sortant depuis les gabarits et cette feuille. Fichiers
   variables, sous-ensemble latin.

   Playfair Display remplace Newsreader et Jost remplace Inter (maquettes
   docs/designs/Horizon/*.png) : Newsreader est un serif de lecture à contraste
   faible et empattements trapus, Inter une grotesque d'interface — les
   maquettes montrent un serif à fort contraste et déliés en cheveu, et un sans
   géométrique ouvert. Les graisses minimales changent avec elles : Playfair
   commence à 400, Jost à 300. Tout « font-weight: 300 » posé sur le serif
   serait désormais synthétisé par le navigateur, d'où les deux corrections
   plus bas (h1 et .h-projection). */
@font-face {
  font-family: 'PlayfairHorizon';
  src: url('../fonts/playfair-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PlayfairHorizon';
  src: url('../fonts/playfair-italic-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'JostHorizon';
  src: url('../fonts/jost-latin.woff2') format('woff2');
  font-weight: 300 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Neutres — valeurs RELEVÉES AU PIXEL dans docs/designs/Horizon/*.png, pas
     estimées. Voir docs/designs/Horizon/reference.md §1.
     Les maquettes remplacent ai/brief/da-horizon.md partout où les deux
     divergent : elles utilisent notamment du blanc pur pour les cartes, que le
     brief interdisait. */
  --h-ivory:        #F8F7F5;  /* fond de page */
  --h-ivory-deep:   #F3EEE8;  /* sections alternées */
  --h-surface:      #FFFFFF;  /* cartes, panneaux, formulaires */
  --h-sand:         #E5E0D8;  /* filets, bordures de champs */
  --h-stone:        #8A8A8A;  /* légendes, sous-titres, métadonnées */
  --h-slate:        #55524E;  /* texte courant */
  --h-ink:          #1F1F1F;  /* titres */
  --h-night:        #1B1B1B;  /* navbar au défilement, pied de page */

  /* Accent laiton. Décision du propriétaire : c'est la valeur PAR DÉFAUT, pas
     une constante — il dérive de --color-primary, que theme.php produit depuis
     le .env du client, pour qu'Horizon reste thématisable. Poser
     COLOR_PRIMARY="B29167" dans le .env rend exactement la maquette.
     La couleur de texte posée dessus vient de theme.php, qui la calcule par
     comparaison des deux rapports de contraste WCAG réels : ne pas la recalculer. */
  --h-accent:       var(--color-primary, #B29167);
  --h-sur-accent:   var(--color-on-primary, #FFFFFF);

  /* Contour de focus, déclaré en jeton : les écrans des tâches suivantes le
     consomment plutôt que de redéclarer leur propre valeur. */
  --h-focus: 2px solid var(--h-ink);
  --h-focus-decalage: 3px;

  --h-serif: 'PlayfairHorizon', Georgia, 'Times New Roman', serif;
  --h-sans:  'JostHorizon', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Rythme vertical — le principal marqueur du modèle. */
  --h-gap-section: 80px;
  --h-gap-titre:    40px;
  --h-gap-cartes:   48px;
  --h-pad-carte:    32px;

  /* Pleine largeur : le contenu n'est plus enfermé dans une colonne centrée de
     1320 px, qui laissait deux réserves de blanc croissantes au-delà de cette
     largeur. Ce qui borne la lecture, ce sont les marges latérales
     (--h-marge) et les bornes en « ch » posées sur les blocs de texte
     (p, .h-titre-section, chapeaux), jamais le conteneur. « none » et non
     « 100% » : aucune règle ne doit plus faire d'arithmétique avec cette
     valeur — la seule qui le faisait (.h-approche-texte) a été simplifiée. */
  --h-contenu-max: none;
  --h-gouttiere:    32px;
  --h-marge:       100px;

  /* Hauteur réservée à l'en-tête collant des pages intérieures
     (.h-entete--clair, position: sticky, top: 0). Tout ce qui se cale
     au-dessous — la colonne latérale collante de la fiche bien, le
     scroll-margin-top de #resultats — part de cette seule valeur, pour que
     deux décalages ne divergent pas au premier changement de gabarit. */
  --h-entete-h: 88px;
}

@media (max-width: 1199px) {
  :root {
    --h-gap-section: 112px;
    --h-gap-titre:    32px;
    --h-gap-cartes:   40px;
    --h-pad-carte:    24px;
    --h-marge:        64px;
  }
}

@media (max-width: 767px) {
  :root {
    --h-gap-section: 80px;
    --h-gap-titre:   24px;
    --h-gap-cartes:  32px;
    --h-pad-carte:   20px;
    --h-marge:       24px;
  }
}

/* --- Réinitialisation (Bootstrap absent) --- */
*, *::before, *::after { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--h-ivory);
  color: var(--h-slate);
  font-family: var(--h-sans);
  font-size: 17px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
h1, h2, h3 { font-family: var(--h-serif); color: var(--h-ink); margin: 0; }
h1 { font-size: 72px; font-weight: 400; line-height: 1.05; letter-spacing: -0.02em; }
h2 { font-size: 44px; font-weight: 400; line-height: 1.15; letter-spacing: -0.015em; }
h3 { font-size: 26px; font-weight: 400; line-height: 1.25; }
p  { margin: 0 0 1em; max-width: 68ch; }
a  { color: inherit; }

@media (max-width: 767px) {
  body { font-size: 16px; }
  h1 { font-size: 40px; }
  h2 { font-size: 30px; }
  h3 { font-size: 22px; }
}

/* Contour de focus visible partout — brief §3. */
:focus-visible { outline: var(--h-focus); outline-offset: var(--h-focus-decalage); }

/* Tableaux : _shared utilise huit fois la classe « table », que Bootstrap
   portait jusqu'ici. */
table, .table { width: 100%; border-collapse: collapse; }
.table th, .table td {
  padding: 12px 16px;
  border-bottom: 1px solid var(--h-sand);
  text-align: left;
  font-variant-numeric: tabular-nums;
}

/* --- Grille : 12 colonnes, gouttière 32 px --- */
.h-contenu {
  max-width: var(--h-contenu-max);
  margin-inline: auto;
  padding-inline: var(--h-marge);
}
.h-grille {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--h-gouttiere);
}
/* Colonne mesurée : jamais plus de 8 colonnes sur 12, décalée plutôt que
   centrée. Ce décalage est l'asymétrie qui distingue Horizon. */
.h-colonne-mesuree { grid-column: 2 / span 7; }
.h-pleine-largeur  { width: 100%; }

@media (max-width: 767px) {
  .h-grille { grid-template-columns: 1fr; }
  .h-colonne-mesuree { grid-column: 1 / -1; }
}

/* --- Sections --- */
.h-section { margin-block: var(--h-gap-section); }
.h-section > h2 + * { margin-top: var(--h-gap-titre); }
.h-sombre { background: var(--h-night); color: var(--h-ivory); }
.h-sombre h1, .h-sombre h2, .h-sombre h3 { color: var(--h-ivory); }

/* --- Bouton ---
   Le filet --h-sand est INCONDITIONNEL : invisible sur une primaire sombre, il
   détache le bouton sur une primaire beige ou dorée très claire, cas que CSS ne
   sait pas détecter et que le moteur est hors périmètre de résoudre.
   La couleur du texte vient de theme.php, qui compare les deux rapports de
   contraste WCAG réels — mieux que le seuil de luminance décrit au brief. */
.h-bouton {
  display: inline-block;
  padding: 14px 32px;
  background: var(--color-primary);
  color: var(--color-on-primary);
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  font-family: var(--h-sans);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.04em;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 220ms ease, border-color 220ms ease, color 220ms ease;
}
/* Survol : le FOND change, jamais le texte.
   La feuille commune porte une règle générique « a:hover { color: rgba(
   var(--color-primary-rgb), 0.8) } » (public/assets/css/style.css:37), de
   spécificité (0,1,1) — donc PLUS FORTE que « .h-bouton » (0,1,0). Sur un
   bouton dont le fond EST la primaire, elle repeignait le texte dans la
   couleur du fond : le libellé disparaissait purement et simplement au
   passage de la souris. Réaffirmer la couleur de texte ici suffit à
   reprendre la main — « .h-bouton:hover » vaut (0,2,0) — et le changement
   d'état passe par --color-primary-hover, la même couleur décalée en clarté
   (calculée par theme.php, qui éclaircit les primaires sombres et assombrit
   les autres plutôt que d'assombrir à l'aveugle).
   :focus-visible partage la règle : l'état doit être visible au clavier
   comme à la souris. */
.h-bouton:hover,
.h-bouton:focus-visible {
  background-color: var(--color-primary-hover, #9A7C57);
  color: var(--color-on-primary, #FFFFFF);
}

/* --- Typographie de rôle --- */
.h-projection {
  font-family: var(--h-serif);
  font-style: italic;
  font-weight: 400;
  font-size: 34px;
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--h-ink);
}
.h-ville {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--h-stone);
  line-height: 1.4;
}
.h-prix {
  font-size: 21px;
  font-weight: 500;
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
  color: var(--h-ink);
}
@media (max-width: 767px) {
  .h-projection { font-size: 24px; }
  .h-prix { font-size: 19px; }
}

/* --- Carte de bien : sans conteneur visible ---
   Pas de boîte, pas de bordure, pas d'ombre. Le bien flotte sur le fond de
   page : c'est ce qui donne la galerie plutôt que le catalogue. */
.h-carte { position: relative; }
.h-carte img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: center 40%;
  border-radius: 5px;
}
.h-carte a { text-decoration: none; }
.h-bandeau {
    position: absolute;
    top: 16px;
    left: 16px;
    padding: 6px 12px;
    background: var(--h-accent);
    color: var(--h-ivory);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-radius: 999px;
}
/* Coup de cœur : un point, jamais un cœur rouge. */
.h-coup-de-coeur {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-primary);
  vertical-align: middle;
  margin-right: 8px;
}

/* --- Champs : une boîte claire posée sur l'ivoire ---
   Le filet bas d'origine laissait les <select> au rendu natif du système —
   flèche grise, hauteur imposée, encadré en relief. Les maquettes montrent
   partout un champ encadré à coins légèrement adoucis (annonces.png §panneau
   de recherche, contact.png §formulaire) : c'est cette forme qui est posée
   ici, sur input, select et textarea à la fois, pour que la ligne d'un
   formulaire ne mêle jamais deux grammaires de champ. --- */
.h-champ {
  width: 100%;
  padding: 12px 16px;
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 6px;
  font-family: var(--h-sans);
  font-size: 16px;
  line-height: 1.4;
  color: var(--h-ink);
  transition: border-color 200ms ease, box-shadow 200ms ease;
}
.h-champ::placeholder { color: var(--h-stone); }
.h-champ:hover { border-color: var(--h-stone); }
.h-champ:focus {
  outline: none;
  border-color: var(--h-accent);
  box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb, 178, 145, 103), 0.18);
}
textarea.h-champ { resize: vertical; min-height: 140px; }

/* Le <select> natif : flèche du système retirée, chevron dessiné à la place.
   « appearance: none » ne touche QUE le bouton fermé — la liste ouverte reste
   dessinée par le système d'exploitation. C'est horizon-select.js qui la
   remplace par une listbox ARIA stylable ; ce qui suit est donc à la fois le
   rendu par défaut et le repli sans JavaScript, jamais une décoration morte. */
select.h-champ {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 44px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238A8A8A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 16px 16px;
}
select.h-champ option { background: var(--h-surface); color: var(--h-ink); }
/* Choix multiple sans JavaScript : la liste est déjà déployée dans la page,
   un chevron y mentirait. Reste un champ encadré, à hauteur de son contenu. */
select[multiple].h-champ {
  background-image: none;
  padding: 8px;
  height: auto;
  cursor: default;
}
select[multiple].h-champ option { padding: 6px 8px; border-radius: 4px; }
.h-etiquette {
  display: block;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--h-stone);
}
/* Rouge sourd, choisi pour rester dans la famille chaude. */
.h-erreur { color: #8C3A32; font-size: 13px; margin-top: 8px; }

/* --- Mouvement : lent, continu, jamais spectaculaire --- */
.h-revele {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 700ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
}
.h-revele.h-visible { opacity: 1; transform: none; }
.h-carte img { transition: transform 900ms ease-out; }
.h-carte a:hover img { transform: scale(1.04); }

@media (prefers-reduced-motion: reduce) {
  .h-revele, .h-recherche-conteneur { opacity: 1; transform: none; transition: none; pointer-events: auto; }
  .h-carte img, .h-carte a:hover img { transition: none; transform: none; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; }
}

/* ===========================================================================
   NAVIGATION
   =========================================================================== */
/* L'EN-TÊTE EST COLLANT SUR TOUS LES ÉCRANS, accueil compris, et BLANC PAR
   DÉFAUT. C'est l'état servi par le gabarit, donc celui que voit un visiteur
   sans JavaScript : un menu blanc posé sur une photographie est moins beau
   qu'un menu transparent, mais il reste lisible — alors qu'un menu
   transparent qui ne basculerait jamais devient illisible dès le premier
   défilement sur du contenu clair.

   Auparavant le défaut était l'inverse : « position: absolute » et
   transparent, et seule la fiche bien posait « h-entete--clair ». Les écrans
   sans héros — contact, mentions, RGPD, honoraires, estimation, 404 —
   héritaient donc d'un en-tête flottant AU-DESSUS de leur contenu.

   « h-entete--surimpression » est posé par horizon.js, et par lui seul, sur
   les écrans qui commencent par un héros. Le script le retire dès que le
   héros est dépassé (voir la bascule dans horizon.js). En « fixed » et non
   « sticky » : le héros doit commencer au tout premier pixel de la page, donc
   l'en-tête ne doit occuper aucune place dans le flux. */
.h-entete {
  position: sticky;
  top: 0;
  /* 1200, et pas 20 : les contrôles de Leaflet montent à z-index 1000 et ses
     calques à 800. À 20, la carte des annonces comme la zone de la fiche
     passaient PAR-DESSUS le menu dès qu'on défilait. Toute valeur posée ici
     doit rester au-dessus de 1000 ; c'est la seule contrainte. */
  z-index: 1200;
  background: var(--h-ivory);
  border-bottom: 1px solid var(--h-sand);
  transition: background-color 300ms ease, border-color 300ms ease;
}
/* POSITION ET COULEUR SONT DEUX CLASSES DISTINCTES, ET C'EST TOUT LE POINT.
   « h-entete--flottant » est posée une fois pour toutes par horizon.js sur les
   écrans qui commencent par un héros, et n'est JAMAIS retirée : le héros doit
   commencer au tout premier pixel de la page, donc l'en-tête n'occupe aucune
   place dans le flux tant qu'on est sur cet écran. Seule
   « h-entete--surimpression » bascule, et elle ne touche qu'aux couleurs.

   Les deux ont été confondues et la bascule changeait « position » : retirer la
   classe rendait ses 88 px au flux, tout le document descendait d'autant, le bas
   du héros repassait sous le bord d'observation, la classe était reposée, le
   document remontait — une oscillation haut/bas de la hauteur de l'en-tête, sur
   toute la bande de défilement [hauteur du héros − 88 px, hauteur du héros[. Sur
   l'accueil, où le héros fait 100svh, elle se déclenchait à 833 px de défilement
   dans une fenêtre de 921 px de haut. Un observateur ne doit pas déplacer ce
   qu'il observe. */
.h-entete--flottant {
  position: fixed;
  inset: 0 0 auto 0;
}
.h-entete--surimpression {
  background: transparent;
  border-bottom-color: transparent;
}
/* Conservée : la fiche bien la pose encore, et un modèle repris d'Horizon
   pourrait s'y référer. Elle ne fait plus que confirmer le défaut. */
.h-entete--clair {
  position: sticky;
  top: 0;
  background: var(--h-ivory);
  border-bottom: 1px solid var(--h-sand);
}
@media (prefers-reduced-motion: reduce) {
  .h-entete { transition: none; }
}

.h-nav-inner {
  max-width: var(--h-contenu-max);
  margin-inline: auto;
  padding: 24px var(--h-marge);
  display: flex;
  align-items: center;
  gap: 40px;
}

.h-nav-marque {
  display: flex;
  flex-direction: column;
  line-height: 1;
  text-decoration: none;
  /* Le défaut de l'en-tête est BLANC (voir .h-entete plus haut) : la couleur du
     texte doit donc être sombre par défaut, et ne passer au clair que sous la
     surimpression, où le fond est le héros. L'inverse — hérité de l'époque où
     l'en-tête était transparent partout — laissait un menu blanc sur blanc sur
     tous les écrans sans héros, et sur ceux à héros dès que le script retirait
     la surimpression au premier défilement. */
  color: var(--h-ink);
}
.h-entete--clair .h-nav-marque { color: var(--h-ink); }
.h-entete--surimpression .h-nav-marque { color: var(--h-ivory); }
.h-nav-marque-nom {
  font-family: var(--h-serif);
  font-size: 22px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.h-nav-marque-sous {
  margin-top: 6px;
  font-size: 10px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  opacity: 0.72;
}

.h-nav-liste {
  display: flex;
  gap: 32px;
  list-style: none;
  margin: 0 auto;
  padding: 0;
  font-size: 14px;
  letter-spacing: 0.02em;
}
.h-nav-liste a {
  text-decoration: none;
  color: var(--h-slate);
  opacity: 1;
  padding-bottom: 4px;
  border-bottom: 1px solid transparent;
}
.h-entete--clair .h-nav-liste a { color: var(--h-slate); opacity: 1; }
.h-entete--surimpression .h-nav-liste a { color: var(--h-ivory); opacity: 0.88; }
.h-nav-liste a:hover { opacity: 1; border-bottom-color: var(--h-accent); }
.h-nav-liste a[aria-current="page"] { border-bottom-color: var(--h-accent); opacity: 1; }

.h-nav-actions { display: flex; align-items: center; gap: 16px; }
.h-bouton--accent {
  background: var(--h-accent);
  color: var(--h-sur-accent);
  border-color: transparent;
  border-radius: 999px;
  padding: 12px 26px;
}

/* --- « Nous contacter » : ton inversé, demande explicite et assumée du
   propriétaire, qui prime ici sur --h-sur-accent (choix WCAG automatique de
   theme.php).
   Repos — blanc sur laiton (#B29167) : contraste 2,94:1, SOUS le seuil AA
   (4,5:1). Le texte sombre y donnerait 6,42:1, ce qui est justement pourquoi
   theme.php choisit --color-on-primary sombre par défaut. Le propriétaire a
   été informé de ce chiffre et maintient sa demande : NE PAS « corriger » en
   revenant à --h-sur-accent, ce serait défaire un choix pris en connaissance
   de cause.
   Survol — laiton sur blanc : ~6,4:1, conforme. --- */
.h-nav-contact {
  color: #FFFFFF;
}
.h-nav-contact:hover,
.h-nav-contact:focus-visible {
  background: var(--h-surface);
  color: var(--h-accent);
}
/* Bouton de menu : jamais sur ordinateur, où la liste .h-nav-liste est déjà
   déployée en entier — il n'y avait rien de plus à y ouvrir. Il ne réapparaît
   que sous 768px, là où cette liste disparaît (voir la media query plus bas). */
.h-nav-menu {
  display: none;
  width: 40px; height: 40px;
  flex-direction: column; justify-content: center; gap: 4px;
  padding: 0 10px;
  background: transparent;
  border: 1px solid var(--h-sand);
  border-radius: 999px;
  cursor: pointer;
}
.h-entete--clair .h-nav-menu { border-color: var(--h-sand); }
.h-entete--surimpression .h-nav-menu { border-color: rgba(255, 255, 255, 0.35); }
.h-nav-menu span { display: block; height: 1px; background: var(--h-ink); }
.h-entete--clair .h-nav-menu span { background: var(--h-ink); }
.h-entete--surimpression .h-nav-menu span { background: var(--h-ivory); }

.h-nav-mobile { display: none; }

@media (max-width: 767px) {
  .h-nav-liste { display: none; }
  .h-nav-menu { display: flex; }
  .h-nav-mobile {
    display: block;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 20;
    background: var(--h-ivory);
    border-top: 1px solid var(--h-sand);
  }
  /* Cinq entrées, contre quatre auparavant : l'espacement est réparti par
     space-between dans un padding latéral, et le texte ne se coupe jamais —
     une entrée sur deux lignes ferait bondir la hauteur du filet, que
     `main { padding-bottom }` compense en dur. */
  .h-nav-mobile ul {
    display: flex;
    justify-content: space-between;
    list-style: none;
    margin: 0;
    padding: 10px 12px;
  }
  .h-nav-mobile a {
    text-decoration: none;
    color: var(--h-slate);
    font-size: 12px;
    white-space: nowrap;
  }
  .h-nav-mobile a[aria-current="page"] { color: var(--h-ink); font-weight: 500; }
  main { padding-bottom: 56px; }
}

/* ===========================================================================
   ACCUEIL — héros, recherche rapide, sélection, approche, destinations, CTA
   =========================================================================== */

/* --- Libellés de section : sur-titre en petites capitales, titre serif sur
   deux lignes (largeur mesurée plutôt que <br> forcé, pour rester correct à
   toute largeur d'écran). --- */
.h-surtitre {
  margin: 0 0 16px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--h-stone);
}
.h-titre-section { max-width: 15ch; }
.h-filet-court {
  display: block;
  width: 64px;
  height: 2px;
  background: var(--h-accent);
  margin: 24px 0;
  border: 0;
}

/* --- Bouton contour : réservé aux fonds clairs (Notre approche). Maquette :
   pastille arrondie à filet fin, nettement plus étroite que le bouton plein
   (« Découvrir nos biens »), texte centré. --- */
.h-bouton--contour {
  background: transparent;
  color: var(--h-ink);
  border: 1px solid var(--h-sand);
  border-radius: 999px;
  padding: 13px 28px;
  font-size: 14px;
  /* Le « display: inline-block » de .h-bouton ne suffit PAS ici : les trois
     emplacements de ce bouton (colonne « Notre approche » de l'accueil, les
     deux « Itinéraire » de la fiche bien) sont des conteneurs flex en colonne
     sans align-items, donc en « stretch » — le lien devient un élément
     flexible étiré sur toute la largeur, et la pastille traversait le bloc.
     fit-content le ramène à sa taille propre, celle que décrit la maquette. */
  width: fit-content;
}
.h-bouton--contour:hover { background: var(--h-ink); border-color: var(--h-ink); color: var(--h-ivory); }

/* --- Héros plein écran : carrousel Ken Burns, dégradés locaux pour la
   lisibilité du titre et du menu — la seule exception au brief §3, qui
   interdit tout filtre colorimétrique sur les photographies ailleurs.

   Ken Burns : zoom et déplacement TRÈS lents et CONTINUS — amplitude faible,
   vitesse constante, jamais spectaculaire et jamais à l'arrêt. Le mouvement
   réel est piloté par horizon.js (trajets tirés au sort, renouvelés à chaque
   changement de photographie) ; ce qui suit est le repli sans JavaScript.
   Chaque diapositive
   porte sa propre animation ; seule celle marquée --active est visible,
   la transition ENTRE diapositives est un fondu (opacity), jamais un
   glissement. Avec une seule diapositive (l'état actuel), aucun fondu ne se
   produit jamais : il n'y a rien à croiser. --- */
.h-heros {
  position: relative;
  /* 100vh plein, sans plafond : le héros occupe l'écran entier au
     chargement — photographie, Ken Burns, titre, rien d'autre. La barre de
     recherche n'y chevauche plus rien au premier rendu, elle apparaît au
     premier défilement (voir .h-recherche-conteneur). 100svh en second, pour
     les navigateurs qui le savent : il exclut la bande de chrome mobile
     rétractable, ce que 100vh seul ne fait pas. */
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}
.h-heros-diapo {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
  opacity: 0;
  transition: opacity 1800ms ease-in-out;
  /* « linear », et surtout pas ease-in-out : une courbe ease-in-out a une
     vitesse NULLE à ses deux extrémités, donc l'image s'immobilisait à chaque
     bout de cycle — un arrêt franc toutes les 22 s, pris pour un défaut
     d'affichage. En linéaire + alternate, la vitesse est constante et seul le
     SENS s'inverse au bout du trajet : le mouvement ne cesse jamais.
     C'est le repli sans JavaScript. Quand horizon.js pilote (règle
     .h-heros--kenburns-js ci-dessous), cette animation est coupée au profit
     de trajets tirés au sort, renouvelés à chaque changement de photographie. */
  animation: h-heros-kenburns 22000ms linear infinite alternate;
  will-change: transform;
}
.h-heros--kenburns-js .h-heros-diapo { animation: none; }
.h-heros-diapo--active { opacity: 1; }
.h-heros::before {
  /* Assombrissement discret sous le menu : la navbar est transparente sur
     le héros et devient illisible sur une photographie claire. Léger et
     borné en hauteur (18 %), pas un filtre sur toute l'image.
     z-index 1 : sous le contenu du héros (z-index 2 ci-dessous). ::after,
     bien qu'écrit plus loin dans la feuille, est le DERNIER enfant généré
     de .h-heros dans l'ordre de peinture — à z-index égal avec le texte, il
     se serait peint PAR-DESSUS le titre, le chapeau, les boutons et
     l'indicateur de molette, les éteignant en plus du voile lui-même. Les
     deux voiles restent à 1, tout le contenu passe à 2 : ordre des plans
     réglé, dosage inchangé. */
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to bottom, rgba(15, 13, 10, 0.38), rgba(15, 13, 10, 0) 18%);
}
.h-heros::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgba(22, 19, 15, 0.55), rgba(22, 19, 15, 0) 55%);
}
.h-heros-texte {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--h-contenu-max);
  margin-inline: auto;
  padding: 0 var(--h-marge) 96px;
}
.h-heros-texte h1 {
  /* Titre du héros seulement — le sélecteur global h1 (72px, ligne 106) sert
     aux onze écrans et ne doit pas bouger. Les deux valeurs ci-dessous étaient
     calées sur le texte de registre « Voyez plus loin. » (16 caractères) de la
     maquette (docs/designs/Horizon/home.png) : un corps plafonné à 108px et un
     max-width de 4,1em — étroit exprès pour forcer la coupure après « Voyez ».
     Avec un vrai slogan client (agence.slogan_agence, souvent plus long —
     constaté : « L'immobilier selon vous », 24 caractères), ce même cadre
     repliait le titre sur trois lignes à corps plein, débordait du cadre du
     héros et poussait tout le reste de la page vers le bas — texte trop grand,
     page décalée, défaut constaté à l'écran avec de vraies données, invisible
     avec le seul texte de démonstration. Plafond abaissé à 84px et max-width
     élargi, en ch pour rester proportionnel au corps du texte le long du
     clamp (comme .h-heros-demi .h-heros-texte h1 ci-dessous, qui applique déjà
     cette solution pour les héros demi-hauteur) : un slogan de la longueur
     constatée tient en deux lignes, jamais trois, quel que soit le texte
     réellement fourni. line-height hérite du h1 global (1.05), déjà conforme
     à la maquette. */
  color: var(--h-ivory);
  font-size: clamp(40px, 4.17vw + 17.8px, 84px);
  max-width: 14ch;
}
/* Taille du slogan (ACCUEIL_SLOGAN_TAILLE). xl = la règle ci-dessus, inchangée ; les trois
   autres la réduisent, et élargissent le cadre en proportion : un corps plus petit tient en
   moins de lignes. Spécificité (0,2,1) : passe devant .h-heros-texte h1. */
.h-heros-texte h1.h-heros-titre--lg { font-size: clamp(36px, 3.5vw + 15px, 70px); max-width: 17ch; }
.h-heros-texte h1.h-heros-titre--md { font-size: clamp(32px, 2.9vw + 13px, 56px); max-width: 21ch; }
.h-heros-texte h1.h-heros-titre--sm { font-size: clamp(28px, 2.1vw + 12px, 42px); max-width: 28ch; }
.h-heros-defiler {
  /* Remonté au-dessus de la pastille de recherche qui chevauche le bas du
     héros (.h-recherche-conteneur, margin-top: -44px) : sur cette largeur,
     le haut de la pastille mord jusqu'à 44px dans le héros, et l'indicateur
     à son ancien bottom: 28px y était en partie masqué — constaté à l'écran.
     108px dégage la pastille avec une marge nette (44px de chevauchement +
     hauteur de la pastille). En dessous de 992px, .h-recherche-conteneur ne
     chevauche plus (margin-top revient à 0) : l'indicateur peut redescendre. */
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: 108px;
  transform: translateX(-50%);
  width: 1px;
  height: 36px;
  background: rgba(250, 247, 242, 0.55);
}
@media (max-width: 991px) {
  .h-heros-defiler { bottom: 32px; }
}
.h-heros-defiler::after {
  content: "";
  position: absolute;
  left: -2px;
  top: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--h-ivory);
  animation: h-heros-defiler 2200ms ease-in-out infinite;
}
@keyframes h-heros-kenburns {
  /* Amplitude faible (4 % de zoom, 1,5 % de déplacement) sur 22 s, en boucle
     alternée : « lent, continu, jamais spectaculaire ». */
  from { transform: scale(1) translate(0, 0); }
  to   { transform: scale(1.04) translate(-1.5%, -1%); }
}
@keyframes h-heros-defiler {
  0%   { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(30px); opacity: 0; }
}
@media (max-width: 767px) {
  .h-heros-texte { padding-bottom: 56px; }
}

.h-heros-chapeau {
  margin: 20px 0 0;
  max-width: 46ch;
  font-size: 17px;
  line-height: 1.6;
  color: rgba(241, 238, 230, 0.88);
  /* Texte de bienvenue du client, de longueur libre : trois lignes au plus. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
.h-heros-filet {
  display: block;
  width: 64px;
  height: 1px;
  background: rgba(250, 247, 242, 0.55);
  margin: 28px 0 32px;
}
.h-heros-actions { display: flex; align-items: center; gap: 32px; flex-wrap: wrap; }
.h-heros-vision {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--h-ivory);
  text-decoration: none;
  font-size: 14px;
  letter-spacing: 0.02em;
}
.h-heros-vision-pastille {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid rgba(250, 247, 242, 0.55);
  border-radius: 50%;
  font-size: 12px;
}
.h-heros-vision:hover .h-heros-vision-pastille { border-color: var(--h-accent); color: var(--h-accent); }

/* --- Recherche rapide, en pastille sombre chevauchant le bas du héros ---
   Reste dans le flux du document, juste après le héros, et continue de le
   chevaucher de 44px (comme sur la maquette) : posée en fixed elle
   flotterait par-dessus tout le reste de la page pendant tout le
   défilement, et ancrée strictement sous le héros sans chevauchement elle
   perdrait le rattachement visuel à la photographie que montre la maquette.
   Absente à l'écran au chargement (le héros doit rester pur 100vh, image et
   titre seuls) et révélée en fondu + légère montée dès le tout premier
   défilement (voir horizon.js, écoute de l'événement 'scroll' natif, valable
   que Lenis pilote le défilement ou non).
   Sans JavaScript : voir la règle noscript de global.html.twig, qui neutralise
   l'état masqué exactement comme elle le fait pour .h-revele.
   prefers-reduced-motion : voir la media query plus bas — visible d'emblée,
   sans transition. */
.h-recherche-conteneur {
  position: relative;
  z-index: 5;
  max-width: var(--h-contenu-max);
  margin: -44px auto 0;
  padding-inline: var(--h-marge);
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 900ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
}
.h-recherche-conteneur.h-visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.h-recherche-pastille {
  display: flex;
  align-items: stretch;
  background: var(--h-night);
  border-radius: 999px;
  padding: 8px 8px 8px 8px;
  gap: 0;
  box-shadow: 0 24px 48px rgba(17, 15, 12, 0.28);
}
.h-recherche-champ {
  flex: 1 1 0;
  min-width: 0;
  padding: 12px 24px;
  border-right: 1px solid rgba(250, 247, 242, 0.16);
  display: flex;
  align-items: center;
}
.h-recherche-champ:last-of-type { border-right: 0; }
.h-recherche-champ select,
.h-recherche-champ input,
.h-recherche-champ .h-select-bouton {
  width: 100%;
  background: transparent;
  border: 0;
  color: var(--h-ivory);
  font-family: var(--h-sans);
  font-size: 14px;
  padding: 0;
}
.h-recherche-champ select,
.h-recherche-champ .h-select-bouton {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 20px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23F1EEE6' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right center;
  background-size: 14px 14px;
}
.h-recherche-champ .h-select-bouton { text-align: left; border: 0; box-shadow: none; }
.h-recherche-champ .h-select-chevron { display: none; }
.h-recherche-champ select option { color: var(--h-ink); }
.h-recherche-champ select:focus,
.h-recherche-champ input:focus { outline: none; }
.h-recherche-champ input::placeholder { color: rgba(241, 238, 230, 0.65); }
.h-recherche-submit {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  margin-left: 16px;
  border-radius: 50%;
  border: 0;
  background: var(--h-accent);
  color: var(--h-sur-accent);
  display: grid;
  place-items: center;
  font-size: 16px;
  cursor: pointer;
}
.h-recherche-submit:hover { filter: brightness(1.06); }

@media (max-width: 991px) {
  .h-recherche-conteneur { margin-top: 0; padding-top: 32px; }
  .h-recherche-pastille { flex-wrap: wrap; border-radius: 24px; padding: 20px; gap: 4px 0; }
  .h-recherche-champ {
    flex: 1 1 45%;
    border-right: 0;
    border-bottom: 1px solid rgba(250, 247, 242, 0.16);
    padding: 10px 8px;
  }
  .h-recherche-submit { margin: 12px auto 0; }
}

/* --- Sélection : sur-titre + titre à gauche, lien à droite --- */
.h-selection-entete {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  flex-wrap: wrap;
}
.h-lien-voir-tout {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  letter-spacing: 0.02em;
  color: var(--h-slate);
  text-decoration: none;
  white-space: nowrap;
  padding-bottom: 4px;
}
.h-lien-voir-tout:hover { color: var(--h-accent); }

/* --- Carrousel : grille qui défile, atteignable sans script (scroll natif,
   clavier). Le bouton « suivant » est une amélioration, pas une dépendance. --- */
.h-carrousel { position: relative; margin-top: var(--h-gap-titre); }
.h-carrousel-piste {
  display: grid;
  grid-auto-flow: column;
  /* Largeur de carte mesurée sur la maquette (docs/designs/Horizon/home.png,
     bande « Des lieux d'exception ») : trois cartes entières puis une
     quatrième amorcée, coupée par le bord — c'est ce débord qui signale
     qu'on peut défiler, pas un défaut de mise en page. Cartes et gouttières
     mesurées à l'identique dans l'image (225px sur 809px de large, gouttière
     8px) donnent un ratio carte/gouttières/débord de 3,231 largeurs de carte
     pour trois gouttières et un débord d'environ 23 % d'une carte — d'où le
     diviseur ci-dessous, appliqué à la largeur réelle de la piste plutôt qu'à
     un pixel fixe pour rester juste à toutes les largeurs de conteneur.
     Plancher 220px (l'ancien minimum) pour ne jamais rétrécir sous une taille
     illisible entre les points de rupture ; plafond 460px pour ne jamais
     grossir sans limite sur un très grand écran. */
  grid-auto-columns: clamp(220px, calc((100% - 3 * var(--h-gouttiere)) / 3.231), 460px);
  gap: var(--h-gouttiere);
  overflow-x: auto;
  /* Hauteur arrêtée par les cartes, jamais par ce qui dépasse : `overflow-x`
     seul fait calculer `overflow-y` en `auto`, si bien que le moindre
     débordement vertical ouvrait un second défilement — inattendu dans une
     bande horizontale. Le débordement venait des cartes 5 et 6, hors de la
     zone visible de la piste : l'IntersectionObserver ne les révèle qu'à leur
     entrée dans la fenêtre, elles restaient donc décalées de 24px par
     .h-revele et poussaient la piste d'autant. Voir aussi la règle
     .h-carrousel-item.h-revele ci-dessous, qui supprime la cause. */
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  scroll-behavior: smooth;
  padding-bottom: 8px;
  /* Barre native masquée (maquette : trois traits centrés en dessous, jamais
     la barre du navigateur) — le défilement et la navigation au clavier
     restent natifs, seule l'affordance visuelle change. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.h-carrousel-piste::-webkit-scrollbar { width: 0; height: 0; display: none; }
.h-carrousel-item { scroll-snap-align: start; }
/* Dans la piste, la révélation est un fondu et rien d'autre : la translation
   verticale de .h-revele y changeait la hauteur du contenu (voir ci-dessus) et
   n'aurait de toute façon pas de sens dans une bande qui défile en largeur. */
.h-carrousel-item.h-revele { transform: none; }
/* --- Indicateurs de position : posés par horizon.js, jamais par Twig — ils
   n'existent que si le script peut les synchroniser au défilement réel de
   .h-carrousel-piste. Sans JavaScript, aucun indicateur ne s'affiche ; le
   carrousel reste défilable et atteignable au clavier (scroll natif). --- */
.h-carrousel-indicateurs {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 24px;
}
.h-carrousel-point {
  width: 18px;
  height: 3px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: var(--h-sand);
  cursor: pointer;
  transition: background 200ms ease;
}
.h-carrousel-point:hover { background: var(--h-stone); }
.h-carrousel-point--actif { background: var(--h-accent); }
@media (prefers-reduced-motion: reduce) {
  .h-carrousel-point { transition: none; }
}
.h-carrousel-suivant {
  position: absolute;
  top: 38%;
  right: -22px;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 1px solid var(--h-sand);
  background: var(--h-surface);
  display: grid;
  place-items: center;
  cursor: pointer;
  box-shadow: 0 12px 24px rgba(17, 15, 12, 0.1);
  color: var(--h-ink);
    z-index: 4;
}
.h-carrousel-suivant:hover { border-color: var(--h-accent); color: var(--h-accent); }

@media (max-width: 767px) {
  .h-carrousel-piste { grid-auto-columns: minmax(220px, 82%); }
  .h-carrousel-suivant { display: none; }
}

/* --- Biens similaires, zone rétrécie par la colonne latérale de la fiche ---
   Entre 1024 px (où la fiche passe à deux colonnes) et 1299 px, la colonne
   latérale prend 320 px : le diviseur 3,231 ci-dessus y calcule des cartes
   sous le plancher de 220 px, et la piste en montrait presque trois, toutes
   serrées. UNE carte entière et la moitié de la suivante — le compromis est
   assumé : on montre moins de biens d'un coup pour que ceux qu'on montre
   soient lisibles, le carrousel en porte cinq et la flèche y mène.
   Le diviseur suit la même règle que plus haut : n cartes entières et une
   demie tiennent dans (100% - n * gouttière) / (n + 0,5). Sous 1024 px la
   fiche repasse sur une colonne, la zone s'élargit, et le diviseur commun
   reprend la main. --- */
@media (min-width: 1024px) and (max-width: 1299px) {
  .h-carrousel--similaires .h-carrousel-piste {
    grid-auto-columns: clamp(220px, calc((100% - var(--h-gouttiere)) / 1.5), 460px);
  }
}

/* --- Carte en surimpression : image pleine hauteur, texte bas, dégradé ---
   data-media="surimpression" n'est posé que par la bande de l'accueil (voir
   accueil.html.twig, seul appel de la macro avec le 4e paramètre à true) :
   ce bloc ne s'applique donc jamais à /annonces ni à la fiche bien. Ratio
   mesuré sur la maquette (largeur ≈ hauteur, 225px sur 225px dans l'image de
   référence) : carré, pas 3/4 (portrait) comme précédemment. --- */
.h-carte[data-media="surimpression"] img { aspect-ratio: 1 / 1; }
.h-carte[data-media="surimpression"] a {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 2px;
}
.h-carte[data-media="surimpression"] a::after {
  /* Nécessité de lisibilité (même principe que le dégradé du héros), pas un
     effet : le texte en surimpression doit rester lisible même quand le bas
     de la photographie est clair (mur blanc, ciel, façade claire). Plus
     sombre et plus concentré sur le tiers inférieur que la première version
     (qui s'étendait jusqu'à 55% et ne suffisait pas sur une photo claire) :
     trois arrêts, quasi opaque au ras du bas où vit le texte, retombant à
     zéro avant le milieu de l'image. */
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top,
    rgba(15, 13, 11, 0.88) 0%,
    rgba(15, 13, 11, 0.55) 22%,
    rgba(15, 13, 11, 0) 42%);
    border-radius: 5px;
}
.h-carte[data-media="surimpression"] .h-bandeau { z-index: 2; }
.h-carte-legende {
  position: absolute;
  left: 20px;
  right: 20px;
  bottom: 20px;
  z-index: 2;
  color: var(--h-ivory);
}
.h-carte-legende h2, .h-carte-legende h3 { color: var(--h-ivory); font-size: 21px; margin: 0 0 6px; }
/* Maquette : localisation et prix sur une même ligne de base, prix à
   droite — jamais empilés, jamais du même gabarit de taille que le titre. */
.h-carte-ligne { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.h-carte-secteur {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(241, 238, 230, 0.78);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.h-carte-legende .h-prix {
  color: var(--h-ivory);
  font-size: 13px;
  font-weight: 600;
  margin-left: auto;
  white-space: nowrap;
}

/* --- Notre approche : deux colonnes, fond alterné à gauche, photographie
   à droite avec carte sombre en surimpression portant trois arguments. --- */
.h-approche { margin-block: var(--h-gap-section); }
.h-approche-grille {
  display: grid;
  /* Proportion relevée sur la maquette (home.png) : le panneau de texte y est
     nettement plus étroit que la photographie, pas un partage 50/50. */
  grid-template-columns: 43% 57%;
  align-items: stretch;
}
.h-approche-texte {
  background: var(--h-ivory-deep);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 96px;
  /* Le contenu étant désormais pleine largeur, la colonne de texte commence à
     la marge de page, sans le rattrapage qui la réalignait autrefois sur le
     conteneur centré de 1320 px. */
  padding-inline-start: var(--h-marge);
  padding-inline-end: var(--h-gouttiere);
}
.h-approche-media { position: relative; min-height: 480px; }
.h-approche-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.h-approche-carte {
  position: absolute;
  /* Flotte à l'intérieur de la photographie, avec une marge visible sur sa
     droite (maquette : ~11% de la largeur de la colonne photo, jamais collée
     au bord) — un pourcentage plutôt qu'un pixel fixe pour que la marge
     suive la largeur réelle de la colonne, pas seulement les grands écrans. */
  right: max(48px, 9%);
  bottom: max(48px, 9%);
  z-index: 1;
  max-width: 300px;
  background: rgba(22, 19, 15, 0.88);
  color: var(--h-ivory);
  padding: 32px;
  border-radius: 15px;
    box-shadow: -10px 10px 35px -5px rgba(0, 0, 0, 0.5);
    -webkit-box-shadow: -10px 10px 35px -5px rgba(0, 0, 0, 0.5);
}
.h-approche-carte ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 20px; }
.h-approche-carte li { display: flex; gap: 14px; align-items: flex-start; }
.h-approche-carte i { color: var(--h-accent); font-size: 17px; margin-top: 2px; width: 18px; text-align: center; }
.h-approche-arg-titre { margin: 0 0 4px; font-family: var(--h-serif); font-size: 16px; color: var(--h-ivory); }
.h-approche-arg-texte { margin: 0; font-size: 13px; line-height: 1.5; color: rgba(241, 238, 230, 0.75); max-width: none; }

@media (max-width: 991px) {
  .h-approche-grille { grid-template-columns: 1fr; }
  .h-approche-texte { padding-inline-start: var(--h-marge); }
  .h-approche-media { min-height: 380px; }
  .h-approche-carte { position: static; max-width: none; margin: 0; border-radius: 0; }
}

/* --- Bloc d'appel à l'action final : fond alterné, centré, pictogramme --- */
.h-cta-finale { background: var(--h-ivory-deep); margin-block: 0; }
.h-cta-finale-inner {
  max-width: var(--h-contenu-max);
  text-align: center;
  padding-block: var(--h-gap-section);
}
.h-cta-icone {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin: 0 auto 32px;
  border: 1px solid var(--h-accent);
  border-radius: 50%;
  color: var(--h-accent);
  font-size: 20px;
}
.h-cta-finale-inner h2 { margin-bottom: 24px; }
.h-cta-finale-inner p { margin-inline: auto; margin-bottom: 40px; max-width: 52ch; }

/* --- Destinations : cadre 4:5, nom superposé en bas à gauche, sans aplat.
   Horizon dessine « magazine » et « left » et traite les autres réglages
   comme des alias — spec §5 — d'où l'absence de règle dédiée par variante. --- */
.h-destinations {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--h-gouttiere);
}
.h-destinations.h-dest-5 { grid-template-columns: repeat(5, 1fr); }
.h-destination {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 2px;
}
.h-destination img { width: 100%; height: 100%; object-fit: cover; }
.h-destination::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(22, 19, 15, 0.6), rgba(22, 19, 15, 0) 45%);
}
.h-destination figcaption {
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 1;
  font-family: var(--h-serif);
  font-size: 22px;
  color: var(--h-ivory);
}
@media (max-width: 767px) {
  .h-destinations, .h-destinations.h-dest-5 { grid-template-columns: 1fr 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .h-heros-diapo { animation: none; }
  .h-heros-defiler::after { animation: none; }
}

/* ===========================================================================
   FICHE BIEN — image principale, vignettes, onglets d'ancrage, colonne
   latérale collante (maquette docs/designs/Horizon/bien.png). Remplace la
   galerie en récit du socle, abandonnée au profit de la maquette — voir
   reference.md §5 et tools/verif/horizon.php, section « Galerie de la fiche
   bien : les neuf états ». */

.h-fiche { display: block; }

.h-fiche-topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  margin-top: 32px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.h-fiche-topbar .h-fil-ariane { margin: 0; }
.h-fiche-topbar .h-fil-ariane a { color: var(--h-slate); text-decoration: none; }
.h-fiche-topbar .h-fil-ariane a:hover { color: var(--h-accent); }
.h-fiche-topbar .h-fil-ariane li[aria-current] { color: var(--h-ink); }
/* Le séparateur « / » de .h-fil-ariane (plus bas dans cette feuille) est clair,
   pensé pour un fond sombre (héros des annonces) : invisible ici, sur l'ivoire. */
.h-fiche-topbar .h-fil-ariane li + li::before { color: var(--h-stone); }
.h-fiche-retour {
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--h-slate);
  text-decoration: none;
  white-space: nowrap;
}
.h-fiche-retour:hover { color: var(--h-accent); }

/* --- Deux colonnes : la colonne latérale vient AVANT dans le document (elle
   porte l'unique h1 de l'écran, qui doit précéder les h2 de la colonne
   principale — voir le commentaire de bien.html.twig), mais s'affiche à
   DROITE grâce à grid-column. --- */
.h-fiche-mise-en-page {
  display: grid;
  /* 320 px et non 380 : la colonne ne porte plus que le prix, le titre, la
     localisation et deux encarts — les six chiffres clés sont passés dans
     l'onglet Caractéristiques. Une colonne courte est ce qui rend le collant
     utilisable : un bloc plus haut que la fenêtre colle par son sommet et son
     bas devient inatteignable. */
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--h-gouttiere);
  align-items: start;
}
.h-fiche-lateral {
  grid-column: 2;
  grid-row: 1;
  position: sticky;
  /* L'en-tête des pages intérieures est lui-même collant (.h-entete--clair,
     top: 0) : un « top: 24px » ferait glisser la colonne DESSOUS. 88 px est
     le décalage déjà retenu par #resultats pour la même raison.
     « align-self » n'est pas posé ici parce que la grille porte déjà
     « align-items: start » — sans lui l'élément serait étiré sur toute la
     hauteur et « sticky » n'aurait aucun effet, faute d'espace où coller. */
  top: calc(var(--h-entete-h) + 24px);
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.h-fiche-principal { grid-column: 1; grid-row: 1; }
@media (max-width: 1023px) {
  .h-fiche-mise-en-page { grid-template-columns: 1fr; }
  .h-fiche-lateral { position: static; grid-column: 1; }
  .h-fiche-principal { grid-column: 1; }
}

.h-fiche-entete-prix .h-prix { display: block; font-size: 34px; margin-bottom: 8px; }
.h-fiche-entete-prix h1 { font-size: 28px; margin-bottom: 6px; }
.h-fiche-lieu { margin: 0; color: var(--h-stone); font-size: 14px; }

/* --- Galerie : image principale + vignettes --- */
.h-fiche-image-cadre { position: relative; border-radius: 2px; overflow: hidden; }
.h-fiche-image-principale {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center 40%;
}
.h-fiche-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 0;
  background: rgba(248, 247, 245, 0.9);
  color: var(--h-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.h-fiche-nav:hover { background: var(--h-surface); }
.h-fiche-nav-prec { left: 20px; }
.h-fiche-nav-suiv { right: 20px; }
.h-fiche-compteur {
  position: absolute;
  left: 20px;
  bottom: 16px;
  margin: 0;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(27, 27, 27, 0.7);
  color: var(--h-ivory);
  font-size: 12px;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  gap: 6px;
}

.h-fiche-vignettes {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 12px;
  margin-top: 12px;
}
.h-fiche-vignette {
  position: relative;
  padding: 0;
  border: 0;
  border-radius: 2px;
  overflow: hidden;
  cursor: pointer;
  background: none;
}
.h-fiche-vignette img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.h-fiche-vignette--actif { outline: 2px solid var(--h-accent); outline-offset: 2px; }
.h-fiche-vignette--plus img { filter: brightness(0.45); }
.h-fiche-vignette-plus-texte {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--h-ivory);
  font-size: 13px;
  font-weight: 500;
}
@media (max-width: 767px) {
  .h-fiche-vignettes { grid-template-columns: repeat(5, 84px); overflow-x: auto; }
}

/* --- Visionneuse plein écran ---
   La classe --zoom n'est posée que par horizon.js : sans script, l'image
   principale ne promet aucun agrandissement, donc pas de curseur qui le
   laisserait croire.

   Comme .h-modale, AUCUNE règle de mise en page hors de [open] : une règle
   non gardée écraserait le « display: none » par défaut du <dialog> et la
   visionneuse resterait ouverte en permanence. */
.h-fiche-image-principale--zoom { cursor: zoom-in; }
.h-fiche-image-principale--zoom:focus-visible { outline: 2px solid var(--h-accent); outline-offset: -4px; }

.h-zoom-ouvert { overflow: hidden; }

.h-fiche-zoom {
  padding: 0;
  border: 0;
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  background: rgba(17, 17, 17, 0.96);
  color: var(--h-ivory);
}
.h-fiche-zoom[open] {
  display: grid;
  grid-template-rows: 1fr auto;
}
.h-fiche-zoom::backdrop { background: rgba(17, 17, 17, 0.96); }

.h-fiche-zoom-fermer {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(248, 247, 245, 0.35);
  background: rgba(27, 27, 27, 0.6);
  color: var(--h-ivory);
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.h-fiche-zoom-fermer:hover,
.h-fiche-zoom-fermer:focus-visible { border-color: var(--h-accent); color: var(--h-accent); }

.h-fiche-zoom-scene {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 24px;
}
.h-fiche-zoom-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.h-fiche-zoom-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 0;
  background: rgba(248, 247, 245, 0.9);
  color: var(--h-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.h-fiche-zoom-nav:hover { background: var(--h-ivory); }
.h-fiche-zoom-nav--prec { left: 20px; }
.h-fiche-zoom-nav--suiv { right: 20px; }

.h-fiche-zoom-pied {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 20px 20px;
}
.h-fiche-zoom-bande {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  flex: 1;
  min-width: 0;
}
.h-fiche-zoom-vignette {
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  border-radius: 2px;
  overflow: hidden;
  background: none;
  cursor: pointer;
  opacity: 0.55;
}
.h-fiche-zoom-vignette img { display: block; width: 88px; aspect-ratio: 4 / 3; object-fit: cover; }
.h-fiche-zoom-vignette:hover { opacity: 0.85; }
.h-fiche-zoom-vignette--actif { opacity: 1; outline: 2px solid var(--h-accent); outline-offset: -2px; }
.h-fiche-zoom-compteur {
  margin: 0;
  flex: 0 0 auto;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: rgba(248, 247, 245, 0.75);
}
@media (max-width: 767px) {
  .h-fiche-zoom-scene { padding: 12px; }
  .h-fiche-zoom-nav { width: 40px; height: 40px; }
  .h-fiche-zoom-nav--prec { left: 8px; }
  .h-fiche-zoom-nav--suiv { right: 8px; }
  .h-fiche-zoom-vignette img { width: 64px; }
}

/* --- Onglets d'ancrage --- */
.h-fiche-onglets {
  display: flex;
  gap: 32px;
  border-bottom: 1px solid var(--h-sand);
  margin-top: var(--h-gap-titre);
  overflow-x: auto;
}
.h-fiche-onglets a {
  padding: 14px 0;
  color: var(--h-stone);
  text-decoration: none;
  font-size: 15px;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.h-fiche-onglets a:hover { color: var(--h-ink); }
.h-fiche-onglets a.h-fiche-onglet--actif {
  color: var(--h-ink);
  border-bottom-color: var(--h-accent);
}
/* Sans JavaScript, aucun onglet ne porte la classe active : on souligne le
   premier pour que la barre ne paraisse pas éteinte. horizon.js pose
   « h-fiche-onglets--js » sur la barre, ce qui retire ce repli — sans quoi le
   premier onglet resterait souligné en même temps que l'onglet réellement
   ouvert, les deux règles ayant la même spécificité. */
.h-fiche-onglets:not(.h-fiche-onglets--js) a:first-child {
  color: var(--h-ink);
  border-bottom-color: var(--h-accent);
}
.h-fiche-onglets a:focus-visible { outline: 2px solid var(--h-accent); outline-offset: 2px; }

.h-fiche-description { margin-top: var(--h-gap-titre); }
.h-fiche-description[data-cloture] { max-height: 8.5em; overflow: hidden; }
.h-fiche-voir-plus {
  background: none;
  border: 0;
  padding: 0;
  margin-top: 12px;
  color: var(--h-accent);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: underline;
}

/* Panneaux d'onglets : un seul visible à la fois, donc empilés simplement.
   L'ancienne grille .h-fiche-cartes (Caractéristiques et Situation côte à
   côte) n'a plus d'objet — les deux ne s'affichent jamais ensemble. */
.h-fiche-panneaux { margin-top: var(--h-gap-titre); }
.h-fiche-panneau[hidden] { display: none; }
.h-fiche-panneau:focus { outline: none; }
/* Les quatre panneaux portent le même cadre, Description comprise : sans quoi
   passer d une section a l autre ferait apparaitre et disparaitre la boite,
   ce qui se lit comme un defaut d affichage. La marge propre de la
   description est reprise par .h-fiche-panneaux. */
.h-fiche-panneau .h-fiche-description { margin-top: 0; }
.h-fiche-carte {
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  padding: var(--h-pad-carte);
}
.h-fiche-carte h2 { font-size: 21px; margin-bottom: 20px; }
.h-fiche-carac { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 24px; margin: 0; }
.h-fiche-carac dt { font-size: 13px; color: var(--h-stone); margin-bottom: 4px; }
.h-fiche-carac dd { margin: 0; font-weight: 500; color: var(--h-ink); font-variant-numeric: tabular-nums; }

/* --- Caractéristiques : deux cartes côte à côte, empilées quand c'est étroit.
   Le panneau lui-même n'est pas une carte (il n'a ni fond ni bordure) : ce
   sont ses deux enfants qui le sont. --- */
.h-fiche-cartes-carac {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--h-gouttiere);
  /* stretch : les cartes d'une même rangée prennent la hauteur de la plus haute. */
  align-items: stretch;
}
.h-fiche-cartes-carac[hidden] { display: none; }
/* Oui / Non d'un terrain : le « Non » est une information, il ne s'efface pas.
   L'icône double le mot, la couleur n'est jamais le seul porteur du sens. */
.h-fiche-ouinon i { width: 1.1em; margin-right: 2px; font-size: 13px; }
.h-fiche-ouinon--non { color: var(--h-stone); }
/* Ventilation des honoraires de location (frais de bail / état des lieux). */
/* width: auto : la règle globale « table { width: 100% } » écartait le libellé
   du montant jusqu'aux deux bords de la colonne. */
.h-fiche-ventilation { width: auto; border-collapse: collapse; margin-top: 6px; font-weight: 400; font-size: 14px; }
.h-fiche-ventilation th { padding: 2px 20px 2px 0; text-align: left; font-weight: 400; color: var(--h-stone); }
.h-fiche-ventilation td { padding: 2px 0; text-align: right; color: var(--h-ink); font-variant-numeric: tabular-nums; }
/* « Détail des surfaces » : pleine largeur sous les deux cartes. */
.h-fiche-cartes-carac > .h-fiche-carte--large { grid-column: 1 / -1; }
@media (max-width: 1023px) {
  .h-fiche-cartes-carac { grid-template-columns: 1fr; }
}

/* --- Zone de situation : un cercle, jamais une épingle --- */
.h-fiche-zone { margin-bottom: 20px; }
.h-fiche-zone-toile {
  height: 320px;
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  background: var(--h-ivory-deep);
}
.h-fiche-zone-note,
.h-fiche-zone-invite {
  margin: 12px 0 0;
  font-size: 13px;
  color: var(--h-stone);
}
/* La commande de zoom de Leaflet hérite sinon de la taille de police du
   modèle et ses deux boutons deviennent illisibles. */
.h-fiche-zone-toile .leaflet-control-zoom a { line-height: 26px; font-size: 18px; }
@media (max-width: 767px) {
  .h-fiche-zone-toile { height: 240px; }
}

/* --- Onglet Situation : une grille de blocs, DANS la largeur de l'onglet ---

   La maquette (docs/designs/Horizon/bien-situation.png) étalait ces blocs sur
   toute la largeur de la page, la colonne latérale escamotée. Elle ne
   s'escamote pas : le prix, le titre et l'encart de contact restent visibles
   pendant qu'on lit la situation, et la grille tient dans la place qui lui
   revient.

   Deux blocs par ligne, sauf les blocs importants — Localisation et Prix au m²
   — qui prennent la largeur entière par .h-situation-bloc--large. En dessous de
   900 px de VUE, une seule colonne ; la requête porte sur la fenêtre et non sur
   le conteneur, faute de quoi la colonne latérale d'une part et la grille
   d'autre part basculeraient à des seuils différents. */
.h-situation-chapeau {
  margin: -8px 0 28px;
  max-width: 62ch;
  color: var(--h-slate);
}
.h-situation-grille {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--h-gouttiere);
  /* stretch : les blocs d'une même rangée prennent la hauteur du plus haut. */
  align-items: stretch;
}
.h-situation-bloc--large { grid-column: 1 / -1; }
@media (max-width: 899px) {
  .h-situation-grille { grid-template-columns: 1fr; }
  .h-situation-bloc--large { grid-column: auto; }
}

.h-situation-bloc {
  background: var(--h-ivory);
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  padding: 24px;
}
/* Le bloc vit DANS une .h-fiche-carte, qui est déjà blanche : son fond ivoire
   est ce qui le détache du panneau. Sans ce contraste, les six blocs se
   fondraient en une seule nappe blanche traversée de filets. */
.h-situation-bloc-titre {
  font-size: 17px;
  margin: 0 0 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--h-sand);
}
.h-situation-sous-titre {
  margin: 22px 0 10px;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--h-stone);
}

/* Listes de couples libellé / valeur. Une colonne : ces blocs sont étroits,
   et la grille à deux colonnes de .h-fiche-carac y couperait les libellés. */
.h-situation-liste { display: grid; gap: 14px; margin: 0; }
.h-situation-liste dt { font-size: 13px; color: var(--h-stone); margin-bottom: 3px; }
.h-situation-liste dd {
  margin: 0;
  font-weight: 500;
  color: var(--h-ink);
  font-variant-numeric: tabular-nums;
}
.h-situation-pied {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 24px;
  margin: 0 0 20px;
}
.h-situation-pied dt { font-size: 13px; color: var(--h-stone); margin-bottom: 3px; }
.h-situation-pied dd { margin: 0; font-weight: 500; color: var(--h-ink); }
@media (max-width: 599px) {
  .h-situation-pied { grid-template-columns: 1fr; }
}

/* --- Performance énergétique du secteur ---
   Les couleurs de classe sont celles du diagnostic officiel, assombries pour
   tenir sur fond ivoire : un A vert vif et un C vert-jaune y passaient sous le
   seuil de lisibilité de la pastille. La lettre n'est JAMAIS portée par la
   seule couleur — elle est écrite, et l'effectif la suit en chiffres. */
.h-situation-lettre,
.h-situation-barres-lettre {
  --h-dpe: var(--h-stone);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  border-radius: 2px;
  background: var(--h-dpe);
  color: #FFFFFF;
  font-family: var(--h-sans);
  font-size: 14px;
  font-weight: 600;
}
.h-situation-lettre--a, .h-situation-barres-lettre--a { --h-dpe: #2F7A39; }
.h-situation-lettre--b, .h-situation-barres-lettre--b { --h-dpe: #4C9B3F; }
.h-situation-lettre--c, .h-situation-barres-lettre--c { --h-dpe: #7EA83A; }
.h-situation-lettre--d, .h-situation-barres-lettre--d { --h-dpe: #B39A2E; }
.h-situation-lettre--e, .h-situation-barres-lettre--e { --h-dpe: #C97C2A; }
.h-situation-lettre--f, .h-situation-barres-lettre--f { --h-dpe: #C35A28; }
.h-situation-lettre--g, .h-situation-barres-lettre--g { --h-dpe: #B02F26; }

.h-situation-dominante {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0;
  padding: 10px 12px;
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 2px;
}
.h-situation-dominante-texte { font-size: 13px; color: var(--h-slate); }

.h-situation-barres { width: 100%; border-collapse: collapse; }
.h-situation-barres th,
.h-situation-barres td { padding: 3px 0; vertical-align: middle; }
/* La pastille de lettre est ici réduite : sept d'affilée, à 30 px, écrasent le
   bloc. Elle garde son fond, donc sa lisibilité. */
.h-situation-barres-lettre {
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  font-size: 12px;
}
.h-situation-barres-piste { width: 100%; padding-left: 12px; padding-right: 12px; }
.h-situation-barre {
  display: block;
  height: 6px;
  min-width: 2px;
  border-radius: 3px;
  background: var(--h-dpe, var(--h-stone));
}
.h-situation-barre--a { --h-dpe: #2F7A39; }
.h-situation-barre--b { --h-dpe: #4C9B3F; }
.h-situation-barre--c { --h-dpe: #7EA83A; }
.h-situation-barre--d { --h-dpe: #B39A2E; }
.h-situation-barre--e { --h-dpe: #C97C2A; }
.h-situation-barre--f { --h-dpe: #C35A28; }
.h-situation-barre--g { --h-dpe: #B02F26; }
.h-situation-barres-nombre {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--h-ink);
  font-weight: 500;
  min-width: 2.5ch;
}
.h-situation-total {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--h-sand);
  font-size: 14px;
  color: var(--h-slate);
}
.h-situation-total strong { color: var(--h-ink); font-variant-numeric: tabular-nums; }

/* --- Prix au m² : la médiane porte le bloc --- */
.h-situation-mediane {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0 0 20px;
}
.h-situation-mediane strong {
  font-family: var(--h-serif);
  font-size: 34px;
  line-height: 1.1;
  color: var(--h-ink);
  font-variant-numeric: tabular-nums;
}
.h-situation-mediane span { font-size: 14px; color: var(--h-stone); }
/* Le bloc marché est large : ses trois couples tiennent en ligne, alors que
   ceux des blocs étroits s'empilent. */
.h-situation-liste--marche { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px 24px; }
@media (max-width: 599px) {
  .h-situation-liste--marche { grid-template-columns: 1fr; }
}

/* --- Risques : trois états, et la couleur ne les porte jamais seule ---
   « Risque identifié », « Pas de risque » et « Information non disponible »
   sont écrits en toutes lettres. L'accent et l'icône ne font que doubler le
   texte, pour qui distingue mal les couleurs comme pour qui lit à l'oreille. */
.h-situation-liste--risques { gap: 0; }
.h-situation-risque {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--h-sand);
}
.h-situation-risque:last-child { border-bottom: 0; padding-bottom: 0; }
.h-situation-risque dt {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 14px;
  color: var(--h-slate);
}
.h-situation-risque dt i { width: 18px; text-align: center; color: var(--h-stone); }
.h-situation-risque dd {
  margin: 0;
  font-size: 13px;
  text-align: right;
  color: var(--h-stone);
  font-weight: 500;
}
.h-situation-risque--identifie dt,
.h-situation-risque--identifie dt i,
.h-situation-risque--identifie dd { color: var(--h-accent); }
.h-situation-risque--absent dd { color: var(--h-slate); }

/* --- Squelettes d'attente ---
   Même grille, même fond, même cadre que les vrais blocs : au remplacement,
   rien ne saute. Une première version de l'écran des annonces atténuait les
   résultats en place ; elle ne se lisait pas — la page paraissait figée, donc
   en panne. Le bloc Localisation, lui, n'est jamais un squelette : sa carte
   vient du flux et s'affiche tout de suite. */
.h-situation-bloc--squelette { min-height: 190px; }
.h-situation-sq {
  display: block;
  height: 12px;
  margin-bottom: 14px;
  border-radius: 2px;
  background: var(--h-sand);
  opacity: 0.7;
  animation: h-situation-pulse 1.4s ease-in-out infinite;
}
.h-situation-sq--titre {
  height: 17px;
  width: 55%;
  margin-bottom: 26px;
  opacity: 0.85;
}
.h-situation-sq--court { width: 40%; }
@keyframes h-situation-pulse {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 0.85; }
}
/* Un battement continu est une gêne pour qui y est sensible, et il n'apporte
   rien : les boîtes disent déjà qu'on attend. */
@media (prefers-reduced-motion: reduce) {
  .h-situation-sq { animation: none; opacity: 0.6; }
}
.h-situation-attente {
  margin: 24px 0 0;
  font-size: 13px;
  color: var(--h-stone);
  text-align: center;
}
/* Le bouton « Réessayer » est ajouté dans ce paragraphe par le script. */
.h-situation-attente .h-bouton { margin-left: 10px; }

/* --- Population et revenus : la portée d'abord ---
   Le chiffre sans son échelle induit en erreur, donc l'échelle est posée avant
   les chiffres et non en note de bas de bloc. */
.h-situation-portee {
  margin: -6px 0 16px;
  font-size: 13px;
  color: var(--h-stone);
}

/* --- Urbanisme : demi-largeur, donc empilé ---
   La maquette posait zone et document à gauche, servitudes à droite, sur une
   ligne entière. Le bloc est désormais apparié à « Population et revenus »,
   tous deux courts, ce qui referme le trou que laissait la démographie seule en
   face d'un bloc bien plus haut. Les deux parties s'empilent donc, et les
   libellés de servitude — qui sont des phrases — passent sur deux lignes.
   La grille est conservée plutôt que remplacée par un simple flux : elle porte
   l'écart vertical entre les deux parties, et le jour où le bloc reprendrait la
   largeur entière, une seule valeur suffirait à rétablir les deux colonnes. */
.h-situation-urbanisme-colonnes {
  display: grid;
  grid-template-columns: 1fr;
  gap: 22px;
  align-items: start;
}
/* Le sous-titre des servitudes suit la liste zone / document : sans cette
   reprise de marge, l'écart de la grille s'ajouterait à la sienne. */
.h-situation-urbanisme-servitudes .h-situation-sous-titre { margin-top: 0; }

/* --- Urbanisme : codes en pastille --- */
.h-situation-code {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  padding: 3px 8px;
  margin-right: 8px;
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  background: var(--h-surface);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--h-ink);
}
.h-situation-servitudes { list-style: none; margin: 0; padding: 0; }
.h-situation-servitudes li {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 10px 0;
  border-bottom: 1px solid var(--h-sand);
  font-size: 14px;
  color: var(--h-slate);
}
.h-situation-servitudes li:last-child { border-bottom: 0; padding-bottom: 0; }
.h-situation-servitude-libelle { flex: 1; }
.h-situation-servitude-nombre {
  font-variant-numeric: tabular-nums;
  color: var(--h-stone);
  font-weight: 500;
}

/* Texte réservé aux lecteurs d'écran : il double un chiffre que l'œil lit dans
   son contexte visuel et que l'oreille recevrait nu (« AC1 · Monument
   historique · 70 »). Jamais display:none, qui le retirerait aussi de l'arbre
   d'accessibilité et n'annoncerait donc rien du tout. */
.h-visuellement-cache {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Pied de panneau --- */
.h-situation-mention,
.h-situation-absence {
  margin: 24px 0 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--h-stone);
  text-align: center;
  max-width: 78ch;
  margin-inline: auto;
}
.h-situation-absence { text-align: left; margin-inline: 0; }

/* --- Diagnostics : bloc dpeHtml, injecté par le moteur (contenu échappé côté
   BienController, jamais recomposé ici). --- */
.h-dpe-cadre { background: var(--h-ivory-deep); padding: 24px; border-radius: 2px; }

/* Diagnostic indisponible : échelles vides sous un filigrane en diagonale.
   Le filigrane est un <p> et non un pseudo-élément : il est lu par une
   assistance technique, les échelles décoratives, elles, sont aria-hidden. */
.h-dpe-cadre--vide { position: relative; overflow: hidden; min-height: 280px; }
.h-dpe-vide { display: grid; grid-template-columns: 1fr 1fr; gap: 24px 48px; opacity: 0.55; }
.h-dpe-vide-titre { margin: 0 0 12px; font-size: 13px; color: var(--h-stone); }
.h-dpe-vide-barre {
  display: block;
  margin-bottom: 5px;
  padding: 3px 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--h-stone);
  background: var(--h-sand);
  border-radius: 2px;
}
.h-dpe-filigrane {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0 24px;
  text-align: center;
  font-family: var(--h-police-titre, inherit);
  font-size: clamp(26px, 4.2vw, 52px);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--h-ink);
  opacity: 0.4;
  transform: rotate(-18deg);
  pointer-events: none;
  user-select: none;
}
@media (max-width: 599px) { .h-dpe-vide { grid-template-columns: 1fr; } }

/* Le moteur émet les deux étiquettes à leur taille de fichier — 1241 × 1448 px —
   et pose ces dimensions en attributs. Sans contrainte ici, le bloc Diagnostics
   occupait à lui seul plus du double de la hauteur du reste de la fiche. Les
   trois colonnes du moteur (.dpe2021-col) passent donc en grille, et les images
   sont bornées en hauteur, le rapport d'aspect suivant par `width: auto`. */
.h-dpe-cadre .dpe2021 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px 32px;
  align-items: start;
}
.h-dpe-cadre .dpe2021-col { min-width: 0; }
.h-dpe-cadre .dpe2021-col img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 260px;
  margin: 12px auto;
}
.h-dpe-cadre .dpe2021-top-label,
.h-dpe-cadre .dpe2021-bottom-label {
  margin: 0;
  font-size: 12px;
  color: var(--h-slate);
}
.h-dpe-cadre .dpe2021-values {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 32px;
  padding-top: 16px;
  border-top: 1px solid var(--h-sand);
  font-size: 14px;
  color: var(--h-slate);
}
.h-dpe-cadre .dpe2021-value-num { color: var(--h-ink); }
.h-dpe-cadre .dpe2021-costs { flex-basis: 100%; }
@media (max-width: 767px) {
  .h-dpe-cadre .dpe2021 { grid-template-columns: 1fr; }
}


/* --- Carte « Contactez-nous » --- */
/* Portrait, nom, fonction et lien de profil du conseiller résolu pour ce
   bien. La branche de repli (aucun conseiller résolu) ne porte pas ce bloc :
   elle affiche seulement une phrase et le numéro de l'agence. */
.h-fiche-contact-conseiller {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 16px;
}
.h-fiche-contact-conseiller img {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.h-fiche-contact-nom { margin: 0; font-weight: 600; color: var(--h-ink); }
.h-fiche-contact-fonction { margin: 2px 0 0; font-size: 13px; color: var(--h-stone); }
.h-fiche-contact-conseiller .h-fiche-contact-sous { margin: 4px 0 0; }
.h-fiche-contact-profil {
  display: inline-block;
  margin-top: 8px;
  font-size: 15px;
  font-weight: 500;
  color: var(--h-accent);
  text-decoration: underline;
}
.h-fiche-contact-profil:hover,
.h-fiche-contact-profil:focus-visible { color: var(--h-ink); }

.h-fiche-contact-sous { font-size: 14px; color: var(--h-stone); margin-bottom: 20px; }
/* Bouton d'ouverture de la fenêtre. Il est servi avec l'attribut « hidden » et
   révélé par horizon.js une fois le formulaire déplacé dans le <dialog> :
   sans script, c'est le formulaire en ligne qui reste, et un bouton qui
   n'ouvrirait rien ne doit jamais s'afficher. */
.h-fiche-contact-ouvrir { width: 100%; text-align: center; }

/* --- Fenêtre modale du formulaire de contact ---
   <dialog> natif ouvert par showModal() : le piège à focus, la touche Échap et
   l'inertie du fond viennent du navigateur, aucune bibliothèque n'est chargée
   pour cela. La feuille ne fait qu'habiller. --- */
.h-modale {
  width: min(560px, calc(100vw - 32px));
  max-height: min(85vh, 760px);
  padding: 0;
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  background: var(--h-surface);
  color: var(--h-ink);
  overflow: hidden;
  /* Aucune règle de mise en page ici : elle est posée sur .h-modale[open]
     seulement. Un <dialog> fermé est masqué par la feuille par défaut du
     navigateur, et toute mise en page posée sans cette garde l'écraserait — la
     fenêtre resterait alors visible en permanence, y compris sans JavaScript.
     tools/verif/horizon.php refuse la règle non gardée. */
}
.h-modale[open] { display: flex; flex-direction: column; }
.h-modale::backdrop { background: rgba(17, 17, 17, 0.55); }
.h-modale-entete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px var(--h-pad-carte);
  border-bottom: 1px solid var(--h-sand);
}
.h-modale-entete h2 { font-size: 21px; margin: 0; }
.h-modale-fermer {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border: 1px solid var(--h-sand);
  border-radius: 50%;
  background: transparent;
  color: var(--h-stone);
  cursor: pointer;
  transition: color 220ms ease, border-color 220ms ease;
}
.h-modale-fermer:hover,
.h-modale-fermer:focus-visible { color: var(--h-accent); border-color: var(--h-accent); }
.h-modale-corps { padding: var(--h-pad-carte); overflow-y: auto; }
.h-modale-corps fieldset { border: 0; padding: 0; margin: 0; }
@media (max-width: 767px) {
  .h-modale { width: 100vw; max-width: 100vw; max-height: 100dvh; height: 100dvh; border: 0; }
}
.h-fiche-carte fieldset { border: 0; padding: 0; margin: 0; }
.h-fiche-objet { margin-bottom: 4px; }

/* --- Carte « Partager ce bien » --- */
.h-fiche-partage-liste { list-style: none; margin: 0; padding: 0; display: flex; gap: 12px; }
.h-fiche-partage-item {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--h-sand);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--h-ink);
  background: var(--h-surface);
  cursor: pointer;
  text-decoration: none;
}
.h-fiche-partage-item:hover,
.h-fiche-partage-item:focus-visible { border-color: var(--h-accent); color: var(--h-accent); }
.h-fiche-partage-item--copie { border-color: var(--h-accent); color: var(--h-accent); }

/* ===========================================================================
   Annonces et recherche
   Trois colonnes (maquette annonces.png — docs/designs/Horizon/reference.md
   §3.2 et §5, qui remplace le brief d'origine : « jamais trois » y était un
   marqueur de densité faible, la maquette du propriétaire montre trois
   colonnes de cartes à conteneur). Le nombre de résultats reste en petit,
   sans emphase (.h-compte).
   =========================================================================== */
.h-liste {
  display: grid;
  /* minmax(0, 1fr) et non 1fr : « 1fr » vaut minmax(auto, 1fr), et la largeur
     intrinsèque d'une photo empêchait la colonne de rétrécir — deux colonnes
     de 711 px débordaient du conteneur à 1920 px et la troisième sortait de
     l'écran. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--h-gap-cartes) var(--h-gouttiere);
  margin-top: var(--h-gap-titre);
}
/* Alignement des deux colonnes de l'écran des annonces. La grille et la
   colonne « Affiner la recherche » sont deux enfants d'une même grille en
   « align-items: start » : le margin-top ci-dessus — 40 px — n'ayant aucun
   équivalent à gauche, la première rangée de cartes descendait d'autant sous
   le haut de l'encart. On l'annule quand la grille ouvre la zone de
   résultats, et SEULEMENT dans ce cas : quand un message la précède
   (« Rien ne correspond… »), la marge sépare toujours le texte des cartes. */
.h-annonces-resultats > .h-liste:first-child { margin-top: 0; }
@media (max-width: 991px) { .h-liste { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 767px) { .h-liste { grid-template-columns: minmax(0, 1fr); } }
/* Écran des annonces SEULEMENT : la colonne « Affiner la recherche » prend
   280 px, si bien qu'en dessous d'environ 1300 px chacune des trois colonnes
   de cartes tombe sous 280 px — prix, titre et pictogrammes s'y serrent. Deux
   colonnes donc, jusqu'à 991 px où la mise en page repasse d'elle-même sur une
   seule colonne et où .h-liste reprend la main. L'accueil et les biens
   similaires, qui n'ont pas cette colonne, gardent leurs trois colonnes.
   Le :not() est indispensable : sans lui cette règle (0,2,0), posée après
   .h-liste--liste (0,2,0), casserait la vue Liste en deux colonnes. */
@media (min-width: 992px) and (max-width: 1299px) {
  .h-annonces-mise-en-page .h-liste:not(.h-liste--liste) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
/* Ces deux surcharges de [hidden] sont INDISPENSABLES, pas décoratives :
   l'attribut « hidden » ne masque que par la feuille du navigateur, qu'une
   règle d'auteur écrase toujours. Sans elles, « display: grid » ci-dessus
   l'emporte et horizon.js a beau poser « hidden », la grille reste affichée —
   c'est ce qui laissait la liste des biens visible sous la vue Carte.
   Toute règle future qui donnerait un « display » à un élément que le
   JavaScript masque par « hidden » a besoin de la même surcharge. */
.h-liste[hidden] { display: none; }
.h-liste-item[hidden] { display: none; }

/* --- Vue Liste (bascule d'affichage, posée par horizon.js) : une colonne,
   carte posée à l'horizontale — image à gauche, contenu à droite. N'existe
   qu'avec JavaScript (voir .h-affichage plus bas) ; sans lui, .h-liste garde
   sa seule mise en page, la grille à trois colonnes ci-dessus.

   Défaut constaté à l'écran sur un grand viewport (1920px) : le corps de
   carte restait en colonne unique (comme en Grille), étiré sur toute la
   largeur restante par la grille 280px/1fr ci-dessous — prix, titre,
   secteur et pictogrammes s'empilaient dans une bande étroite à gauche, et
   tout le reste de la carte (plusieurs centaines de pixels) ne portait
   rien. .h-carte-corps passe donc lui-même en grille à deux colonnes dans
   cette vue : la colonne principale (prix/titre/secteur/pictos/action)
   garde une largeur de lecture raisonnable, et une seconde colonne — vide
   en Grille, affichée seulement ici — accueille le début du descriptif et
   le DPE/GES, pour que l'espace gagné par la mise en page horizontale soit
   réellement utilisé plutôt que laissé en blanc. */
.h-liste.h-liste--liste { grid-template-columns: 1fr; gap: var(--h-gouttiere); }
.h-liste--liste .h-carte[data-media="conteneur"] a { display: grid; grid-template-columns: 320px 1fr; }
/* L'image remplit EXACTEMENT la cellule, quelle que soit sa proportion
   réelle — défaut constaté à l'écran : avec « aspect-ratio: auto » (repli
   précédent), une photo du parc au format portrait imposait sa propre
   proportion à toute la carte, donnant une vignette démesurément haute et
   une ligne bien plus grande que la maquette
   (docs/designs/Horizon/annonces-mode-liste.png). Position absolue + objet
   recadré, comme .h-heros > img et .h-approche-media img plus haut dans
   cette feuille : la cellule (donc la hauteur de la ligne) est pilotée par
   .h-carte-corps, jamais par le fichier source de la photo. */
.h-liste--liste .h-carte[data-media="conteneur"] .h-carte-media {
  position: relative;
  height: 100%;
  min-height: 260px;
}
.h-liste--liste .h-carte[data-media="conteneur"] .h-carte-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
}
.h-liste--liste .h-carte[data-media="conteneur"] .h-carte-corps {
  display: grid;
  grid-template-columns: minmax(180px, 240px) 1fr;
  column-gap: 40px;
  align-items: start;
  justify-content: start;
}
.h-liste--liste .h-carte-corps-principal { display: flex; flex-direction: column; }
/* En vue Liste, la carte est déjà à la hauteur de son image : l'appel à
   l'action n'a pas à être plaqué en bas — une marge automatique l'emporterait
   sur l'alignement vertical centré de la colonne principale. */
.h-liste--liste .h-carte-action { margin-top: 12px; }
@media (min-width: 1600px) {
  .h-liste--liste .h-carte[data-media="conteneur"] a { grid-template-columns: 380px 1fr; }
}
@media (max-width: 767px) {
  .h-liste--liste .h-carte[data-media="conteneur"] a { grid-template-columns: 1fr; }
  .h-liste--liste .h-carte[data-media="conteneur"] .h-carte-corps { grid-template-columns: 1fr; row-gap: 12px; }
}

/* --- Décompte de photos (docs/designs/Horizon/annonces-mode-liste.png) ---
   Invisible en Grille : la vignette y est trop petite pour porter un badge
   de plus à côté du bandeau sans le masquer. */
.h-carte-photos { display: none; }
.h-liste--liste .h-carte-photos {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  position: absolute;
  right: 12px;
  bottom: 12px;
  padding: 5px 10px;
  border-radius: 999px;
  background: rgba(17, 15, 12, 0.72);
  color: var(--h-ivory);
  font-size: 12px;
}

/* --- Second bloc du corps de carte (résumé + DPE/GES) : servi dans le HTML
   des deux vues, visible seulement en Liste. Grille et Liste partagent donc
   une structure HTML unique (macros/info_principales.html.twig) ; la bascule
   reste purement CSS, comme le reste du mécanisme Grille/Liste/Carte (§2). */
.h-carte-corps-detail { display: none; }
.h-liste--liste .h-carte-corps-detail { display: flex; flex-direction: column; gap: 14px; }
.h-carte-resume {
  margin: 0;
  max-width: 62ch;
  color: var(--h-slate);
  font-size: 14px;
  line-height: 1.6;
}
.h-carte-dpe { display: flex; flex-wrap: wrap; gap: 8px; }
.h-dpe-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
}
.h-dpe-chip strong { font-size: 13px; letter-spacing: normal; text-transform: none; }
/* Couleurs mesurées sur public/assets/img/DPE2021/{DPE,GSE}/*.png
   (getpixel, hors tracé des lettres) : mêmes teintes que le schéma complet
   de la fiche bien, jamais une palette devinée. Lettres en toutes lettres
   dans le balisage, jamais portées par la seule couleur — CLAUDE.md §7. */
.h-dpe-chip--dpe[data-lettre="A"] { background: #009C6D; }
.h-dpe-chip--dpe[data-lettre="B"] { background: #52B153; }
.h-dpe-chip--dpe[data-lettre="C"] { background: #78BD76; color: #1f2a1f; }
.h-dpe-chip--dpe[data-lettre="D"] { background: #F4E70F; color: #3a3200; }
.h-dpe-chip--dpe[data-lettre="E"] { background: #F0B50F; color: #3a2400; }
.h-dpe-chip--dpe[data-lettre="F"] { background: #EB8235; }
.h-dpe-chip--dpe[data-lettre="G"] { background: #D7221F; }
.h-dpe-chip--ges[data-lettre="A"] { background: #A4DBF8; color: #0b2f45; }
.h-dpe-chip--ges[data-lettre="B"] { background: #8CB4D3; color: #0b2f45; }
.h-dpe-chip--ges[data-lettre="C"] { background: #7792B1; }
.h-dpe-chip--ges[data-lettre="D"] { background: #606F8F; }
.h-dpe-chip--ges[data-lettre="E"] { background: #4D5271; }
.h-dpe-chip--ges[data-lettre="F"] { background: #393551; }
.h-dpe-chip--ges[data-lettre="G"] { background: #281B35; }

.h-compte { color: var(--h-stone); font-size: 13px; letter-spacing: 0.08em; }

.h-section > h1 + * { margin-top: var(--h-gap-titre); }

/* --- Héros demi-hauteur des annonces : fil d'Ariane, titre, chapeau ---
   Repose sur .h-heros (dégradés, flex align-items: flex-end) et
   .h-heros-demi (hauteur) déjà définis plus haut ; ce bloc-ci ne porte que le
   texte, dans un conteneur dédié pour ne jamais hériter du clamp() de
   .h-heros-texte h1, dimensionné pour le héros plein écran de l'accueil. */
.h-heros-annonces-img {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
}
.h-heros-annonces-texte {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--h-contenu-max);
  margin-inline: auto;
  padding: 0 var(--h-marge) 72px;
  color: var(--h-ivory);
}
.h-heros-annonces-texte h1 { color: var(--h-ivory); font-size: clamp(36px, 4vw + 16px, 56px); }
.h-heros-annonces-chapeau {
  margin: 16px 0 0;
  max-width: 52ch;
  font-size: 16px;
  line-height: 1.6;
  color: rgba(241, 238, 230, 0.88);
}
.h-fil-ariane { margin-bottom: 20px; }
.h-fil-ariane ol {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: rgba(241, 238, 230, 0.72);
}
.h-fil-ariane li + li::before { content: '/'; margin-right: 8px; color: rgba(241, 238, 230, 0.45); }
.h-fil-ariane a { color: rgba(241, 238, 230, 0.88); text-decoration: none; }
.h-fil-ariane a:hover { color: var(--h-ivory); text-decoration: underline; }

/* --- Panneau de recherche blanc, chevauchant le bas du héros --- */
/* La pastille sombre de l'accueil, reprise telle quelle sur l'écran des
   annonces : seul le conteneur diffère. Elle chevauche le bas du héros, comme
   le panneau blanc qu'elle remplace, et reste bornée pour ne pas s'étirer sur
   toute la largeur de page (--h-contenu-max vaut « none »). */
.h-recherche-annonces-conteneur {
  position: relative;
  z-index: 5;
  max-width: 1180px;
  margin: -44px auto 0;
  padding-inline: var(--h-marge);
}
.h-plus-criteres { margin-top: 20px; }
.h-plus-criteres summary {
  cursor: pointer;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--h-accent);
  list-style: none;
}
.h-plus-criteres summary::-webkit-details-marker { display: none; }
.h-plus-criteres summary::before { content: '+ '; }
.h-plus-criteres[open] summary::before { content: '– '; }
.h-plus-criteres[open] summary { margin-bottom: 20px; }
.h-lien-reinitialiser { font-size: 13px; letter-spacing: 0.04em; color: var(--h-slate); text-decoration: none; }
.h-lien-reinitialiser:hover { color: var(--h-accent); }
@media (max-width: 991px) {
  .h-recherche-annonces-conteneur { margin-top: 0; padding-top: 32px; }
}

/* --- Barre d'outils : tri à gauche, bascule d'affichage à droite --- */
.h-outils {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: var(--h-gap-titre);
  padding-bottom: 20px;
  border-bottom: 1px solid var(--h-sand);
}
/* Le compteur passe en tête de la barre d'outils. « order: -1 » et non un
   déplacement dans le document : il doit être ANNONCÉ avant les commandes de
   tri, et c'est déjà son ordre dans le HTML. */
.h-outils-compte { margin: 0; font-size: 14px; color: var(--h-stone); }
.h-outils-tri { display: flex; align-items: center; gap: 12px; }
.h-outils-tri .h-etiquette { margin: 0; }
.h-outils-tri .h-champ { width: auto; min-width: 200px; padding-block: 9px; }
/* La recherche libre est plus large que le sélecteur de tri : on y tape une
   phrase, pas un choix. Elle rétrécit avant lui quand la place manque, le tri
   ayant une largeur incompressible imposée par ses libellés. */
.h-outils-tri .h-outils-mots-cles { min-width: 240px; flex: 1 1 240px; }
/* Chrome pose une croix d'effacement native sur les champs de recherche ;
   elle hérite sinon de la police du modèle et déborde du champ. */
.h-outils-mots-cles::-webkit-search-cancel-button { cursor: pointer; }
@media (max-width: 767px) {
  .h-outils-tri { flex-wrap: wrap; }
  .h-outils-tri .h-outils-mots-cles { flex-basis: 100%; }
}
.h-outils-tri-valider {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid var(--h-sand);
  border-radius: 50%;
  background: transparent;
  color: var(--h-ink);
  cursor: pointer;
}
.h-outils-tri-valider:hover { border-color: var(--h-accent); color: var(--h-accent); }
/* --- Bascule Grille / Liste : posée uniquement par horizon.js, jamais par
   Twig (amélioration, pas une dépendance — voir le commentaire sur
   .h-affichage dans annonces.html.twig). --- */
.h-affichage { display: flex; gap: 4px; background: var(--h-ivory-deep); border-radius: 999px; padding: 4px; }
.h-affichage-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font-family: var(--h-sans);
  font-size: 13px;
  color: var(--h-slate);
  cursor: pointer;
}
.h-affichage-item--actif { background: var(--h-surface); color: var(--h-ink); box-shadow: 0 2px 6px rgba(17, 15, 12, 0.1); }

/* --- Mise en page : colonne de filtres + grille de résultats --- */
/* Cible de l'ancre « #resultats » : le formulaire d'affinage s'y renvoie à
   chaque rechargement. La marge de défilement dégage la navbar collante (72 px)
   et vaut pour le saut NATIF du navigateur, script ou pas. */
#resultats { scroll-margin-top: var(--h-entete-h); }
.h-annonces-mise-en-page {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: var(--h-gap-cartes);
  align-items: start;
  margin-top: var(--h-gap-titre);
}
@media (max-width: 991px) { .h-annonces-mise-en-page { grid-template-columns: 1fr; } }

/* --- Affinage en cours : squelettes de cartes ---
   Première tentative, abandonnée : atténuer les résultats en place. Elle ne se
   lisait pas — la page paraissait figée, donc en panne. Les cartes sont donc
   retirées de la vue le temps de la réponse et remplacées par des fantômes de
   même gabarit (horizon-recherche.js), qui reprennent la grille, le format
   d'image 6/5 et le corps d'une carte réelle : la hauteur de la zone ne
   s'effondre pas et le visiteur voit que quelque chose se construit.

   La vue Carte fait exception : un squelette de cartes n'y voudrait rien dire,
   c'est la carte elle-même qui s'atténue. */
.h-annonces-resultats[aria-busy="true"] .h-carte-vue:not([hidden]) {
  opacity: 0.45;
  pointer-events: none;
  transition: opacity 180ms ease;
}

/* Le fond, le rayon et l'ombre viennent déjà de .h-carte[data-media="conteneur"],
   que le squelette porte : rien à redéclarer ici. Seul le survol est neutralisé
   — une carte fantôme qui se soulève sous le curseur invite à un clic qui ne
   mène nulle part. */
.h-carte--squelette:hover { transform: none; box-shadow: 0 8px 24px rgba(17, 15, 12, 0.08); }
/* Le squelette n'a pas de lien enveloppant : c'est l'article lui-même qui porte
   la colonne, pour tenir la même hauteur que les cartes réelles qu'il
   remplace. */
.h-carte--squelette { display: flex; flex-direction: column; }
.h-squelette-action { margin-top: auto; width: 96px; height: 13px; border-radius: 3px; }

/* Le dégradé balaie chaque bloc de gauche à droite. Teintes prises sur
   --h-ivory-deep, jamais un gris générique : le squelette appartient au modèle
   autant que la carte qu'il remplace. */
.h-squelette {
  position: relative;
  overflow: hidden;
  background: var(--h-ivory-deep);
}
.h-squelette::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  animation: h-squelette-balayage 1200ms ease-in-out infinite;
}
@keyframes h-squelette-balayage {
  100% { transform: translateX(100%); }
}

.h-squelette-image { aspect-ratio: 6 / 5; }
.h-squelette-ligne { height: 14px; border-radius: 3px; }
.h-squelette-ligne--prix { width: 42%; height: 18px; margin-bottom: 10px; }
.h-squelette-ligne--titre { width: 78%; height: 20px; margin-bottom: 8px; }
.h-squelette-ligne--secteur { width: 55%; margin-bottom: 20px; }
.h-squelette-pictos { display: flex; flex-wrap: wrap; gap: 16px; }
.h-squelette-picto { width: 54px; height: 12px; border-radius: 3px; }

/* Sous prefers-reduced-motion, les blocs restent — c'est eux qui portent
   l'information « chargement en cours » — mais le balayage s'arrête. */
@media (prefers-reduced-motion: reduce) {
  .h-squelette::after { animation: none; }
  .h-annonces-resultats[aria-busy="true"] .h-carte-vue:not([hidden]) { transition: none; }
}

/* --- Vue Carte : la carte occupe TOUT l'espace à droite des filtres ---
   Refonte demandée par le propriétaire après rendu : le découpage 2/3 – 1/3
   comprimait la carte sans que le panneau latéral gagne en utilité. La fiche du
   bien sélectionné passe en encart flottant sur la carte.
   La colonne de filtres reste visible — c'est une page de recherche, et
   restreindre le parc est précisément ce qu'on veut faire en regardant une carte. */
.h-carte-vue {
  position: relative;
  /* Contexte d'empilement propre à la carte : la mention (1200), l'encart
     (1100) et les contrôles de Leaflet (1000) restent EN DESSOUS de l'en-tête
     collant (1200), qui, à z-index égal, passait derrière la mention en
     raison de l'ordre du DOM. */
  isolation: isolate;
  height: calc(100vh - 160px);
  min-height: 560px;
  margin-top: var(--h-gap-titre);
  border-radius: 4px;
  overflow: hidden;
}
.h-carte-vue[hidden] { display: none; }
.h-carte-toile { height: 100%; background: var(--h-ivory-deep); }

/* Mention permanente, haut à droite : seul coin que Leaflet laisse libre
   (zoom en haut à gauche, attribution en bas à droite, encart en bas à gauche).
   z-index 1100 : les contrôles de Leaflet montent à 1000. */
.h-carte-avertissement {
  position: absolute;
  top: 12px;
  right: 12px;
  /* Strictement au-dessus de .h-carte-message (1100) : les deux peuvent être
     visibles ensemble — la mention est inconditionnelle et aucun des deux
     appelants du message ne la masque. À z-index égal, l'ordre du DOM ferait
     passer le message devant, et la mention disparaîtrait pendant un état
     d'erreur, alors qu'elle doit rester visible en permanence. */
  z-index: 1200;
  max-width: 340px;
  margin: 0;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.94);
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(17, 15, 12, 0.12);
  font-size: 12px;
  line-height: 1.5;
  color: var(--h-slate);
}

/* Messages d'erreur : centrés, révélés par horizon.js ou horizon-carte.js. */
.h-carte-message {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1100;
  max-width: 420px;
  margin: 0;
  padding: 20px 24px;
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 4px;
  box-shadow: 0 8px 24px rgba(17, 15, 12, 0.14);
  text-align: center;
  font-size: 15px;
  line-height: 1.5;
  color: var(--h-slate);
}

/* Encart flottant, bas à gauche. */
.h-carte-flottante {
  position: absolute;
  left: 24px;
  bottom: 24px;
  z-index: 1100;
  width: 320px;
  max-width: calc(100% - 48px);
  background: var(--h-surface);
  border-radius: 4px;
  box-shadow: 0 16px 40px rgba(17, 15, 12, 0.24);
  overflow: hidden;
}
.h-carte-fermer {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.92);
  border: 0;
  border-radius: 50%;
  color: var(--h-ink);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(17, 15, 12, 0.2);
}
.h-carte-fermer:hover { background: var(--h-surface); color: var(--h-accent); }

/* La carte de bien reprise dans l'encart occupe toute sa largeur, sans ombre
   propre — l'encart porte déjà la sienne — et sans lévitation au survol. */
.h-carte-flottante .h-carte[data-media="conteneur"] {
  box-shadow: none;
  border-radius: 0;
}
.h-carte-flottante .h-carte[data-media="conteneur"]:hover {
  transform: none;
  box-shadow: none;
}
.h-carte-flottante .h-carte[data-media="conteneur"] .h-carte-corps { padding: 16px; }
.h-carte-flottante .h-carte[data-media="conteneur"] .h-carte-corps h3 { font-size: 18px; }

@media (max-width: 991px) {
  .h-carte-vue { height: 70vh; min-height: 420px; }
  /* L'encart s'étale d'un bord à l'autre : 320 px fixes sur un téléphone
     laisseraient une marge inutile d'un côté et déborderaient de l'autre. */
  .h-carte-flottante { left: 12px; right: 12px; bottom: 12px; width: auto; max-width: none; }
  .h-carte-avertissement { top: 8px; right: 8px; left: 8px; max-width: none; }
}

/* --- Épingles : pastille laiton portant le prix. L'épingle bleue par défaut
   de Leaflet n'est pas le langage du modèle, et le prix évite un clic pour la
   seule information qui décide. --- */
.h-epingle {
  transform: translate(-50%, -50%);
  padding: 6px 12px;
  background: var(--h-accent);
  color: var(--h-ivory);
  border: 0;
  border-radius: 999px;
  font-family: var(--h-sans);
  font-size: 12px;
  letter-spacing: 0.02em;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(17, 15, 12, 0.3);
}
.h-epingle:hover { background: var(--h-ink); }
.h-epingle--active { background: var(--h-night); color: var(--h-ivory); }

/* Leaflet pose ses propres polices et couleurs de lien dans les contrôles et
   l'attribution : on les ramène au modèle. */
.h-carte-toile .leaflet-container { font-family: var(--h-sans); background: var(--h-ivory-deep); }
.h-carte-toile .leaflet-control-attribution { font-size: 10px; }
.h-carte-toile .leaflet-control-attribution a { color: var(--h-slate); }

/* Encart blanc bordé (maquette annonces.png), collant au défilement : la
   colonne de filtres est plus courte que la grille de résultats, elle
   accompagne donc la lecture au lieu de disparaître dès la deuxième rangée.
   « top » dégage la navbar collante (72 px) plus une respiration.

   « max-height » + « overflow-y » : sans eux, un catalogue portant beaucoup de
   types de biens rendait la colonne plus haute que la fenêtre — le collage
   cessait alors d'opérer et le bouton « Afficher N résultats », en bas de
   colonne, devenait inatteignable sans redescendre toute la grille. La colonne
   défile désormais sur elle-même, et « overscroll-behavior » empêche ce
   défilement d'emporter la page une fois arrivé en butée. */
.h-filtres {
  position: sticky;
  top: 96px;
  max-height: calc(100vh - 112px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 4px;
  padding: 24px;
  scrollbar-width: thin;
  scrollbar-color: var(--h-sand) transparent;
}
.h-filtres::-webkit-scrollbar { width: 6px; }
.h-filtres::-webkit-scrollbar-thumb { background: var(--h-sand); border-radius: 999px; }
@media (max-width: 991px) {
  .h-filtres { position: static; max-height: none; overflow: visible; }
}
.h-filtres-titre { font-size: 21px; margin-bottom: 24px; }
.h-affiner-submit { display: block; width: 100%; text-align: center; margin-top: 8px; }
/* La colonne se relance seule à chaque critère modifié (horizon.js) : le temps
   du rechargement, elle s'estompe et cesse d'accepter les clics — deux envois
   concurrents donneraient un résultat imprévisible. */
.h-recherche[aria-busy="true"] { opacity: 0.55; pointer-events: none; }
.h-filtres .h-lien-reinitialiser { display: block; text-align: center; margin-top: 12px; }

/* --- Panneau « Affiner » (accueil / repli éventuel) : <details> natif --- */
.h-panneau { margin-top: var(--h-gap-titre); }
.h-panneau summary.h-bouton {
  list-style: none;
}
.h-panneau summary.h-bouton::-webkit-details-marker { display: none; }
.h-panneau summary.h-bouton::marker { content: ''; }
.h-panneau[open] summary.h-bouton { margin-bottom: var(--h-gap-titre); }
.h-panneau .h-recherche { max-width: 420px; }
.h-panneau .h-recherche fieldset { border: 0; padding: 0; margin: 0; }
.h-panneau .h-recherche legend { padding: 0; margin-bottom: 16px; font-family: var(--h-serif); font-size: 21px; }
.h-panneau .h-recherche p { margin: 0 0 20px; }

/* --- Puces effaçables : un critère actif par bouton --- */
.h-puces {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: var(--h-gap-titre);
}
.h-puce {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: transparent;
  border: 1px solid var(--h-sand);
  border-radius: 999px;
  font-family: var(--h-sans);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--h-slate);
  cursor: pointer;
}
.h-puce:hover { border-color: var(--h-stone); }

/* --- Carte « conteneur » (maquette annonces.png) : encart blanc à ombre
   légère, badge sur l'image, prix avant le titre, secteur, puis trois
   métadonnées à pictogramme. Portée par l'attribut data-media="conteneur",
   jamais par une seconde classe — voir macros/info_principales.html.twig. */
.h-carte[data-media="conteneur"] {
  background: var(--h-surface);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 8px 24px rgba(17, 15, 12, 0.08);
  transition: box-shadow 200ms ease, transform 200ms ease;
}
.h-carte[data-media="conteneur"]:hover { box-shadow: 0 16px 36px rgba(17, 15, 12, 0.14); transform: translateY(-2px); }
.h-carte[data-media="conteneur"] .h-carte-media { position: relative; }
/* Format mesuré sur la maquette : ~1,17, sensiblement plus carré que le 4/3
   des autres cartes du modèle. object-fit recadre, les photographies du flux
   étant de formats hétérogènes (19 formats distincts sur 171 fichiers). */
.h-carte[data-media="conteneur"] img { border-radius: 0; aspect-ratio: 6 / 5; }
.h-carte[data-media="conteneur"] .h-bandeau { top: 12px; left: 12px; }
.h-carte[data-media="conteneur"] .h-carte-corps { padding: 24px; }
.h-carte[data-media="conteneur"] .h-carte-corps .h-prix { display: block; margin-bottom: 6px; }
.h-carte[data-media="conteneur"] .h-carte-corps h3 { font-size: 20px; margin-bottom: 4px; }
.h-carte[data-media="conteneur"] .h-carte-secteur {
  margin: 0 0 16px;
  font-size: 13px;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--h-stone);
}
/* Aucun filet au-dessus des métadonnées : la maquette n'en porte pas — c'est
   l'espace qui sépare, pas un trait. */
.h-carte-pictos {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 13px;
  color: var(--h-slate);
}
.h-carte-pictos li { display: inline-flex; align-items: center; gap: 6px; }
.h-carte-pictos i { color: var(--h-accent); font-size: 13px; }

/* --- Hauteur égale sur une rangée ---
   Les cartes ne portent pas toutes le même nombre de métadonnées — un terrain
   en a trois, un garage aucune — et le bas des encarts se décalait d'une carte
   à l'autre. La grille étire déjà chaque .h-liste-item à la hauteur de sa
   rangée (align-items: stretch, valeur par défaut) : il suffit que la carte,
   son lien et son corps suivent, et que l'appel à l'action soit poussé en bas
   par une marge automatique. Aucun « display » n'est posé sur .h-liste-item —
   il écraserait la surcharge .h-liste-item[hidden] { display: none } dont
   dépend la pagination. */
.h-carte[data-media="conteneur"] { height: 100%; }
.h-carte[data-media="conteneur"] > a { display: flex; flex-direction: column; height: 100%; }
.h-carte[data-media="conteneur"] .h-carte-corps { display: flex; flex-direction: column; flex: 1 1 auto; }

/* --- Appel à l'action « Voir le bien » ---
   Un <span> à l'intérieur du lien de la carte, pas un bouton : voir la macro
   info_principales.html.twig pour la raison. Il en a donc l'allure sans en
   avoir le comportement — c'est la carte entière qui est cliquable, et le
   survol de la carte l'anime comme s'il l'était lui-même. */
.h-carte-action {
  margin-top: auto;
  padding-top: 20px;
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 8px;
  font-family: var(--h-sans);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--h-accent);
}
.h-carte-action i { font-size: 11px; transition: transform 200ms ease; }
.h-carte[data-media="conteneur"] a:hover .h-carte-action i { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) {
  .h-carte-action i { transition: none; }
  .h-carte[data-media="conteneur"] a:hover .h-carte-action i { transform: none; }
}

/* --- Pagination numérotée, posée par horizon.js (voir annonces.html.twig :
   sans JavaScript, toutes les cartes restent visibles, l'élément reste vide
   et masqué). --- */
.h-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: var(--h-gap-titre);
}
.h-pagination-item {
  min-width: 36px;
  height: 36px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--h-sand);
  border-radius: 50%;
  background: var(--h-surface);
  font-family: var(--h-sans);
  font-size: 14px;
  color: var(--h-slate);
  cursor: pointer;
}
.h-pagination-item:hover { border-color: var(--h-accent); color: var(--h-accent); }
.h-pagination-item--actif { background: var(--h-accent); border-color: var(--h-accent); color: var(--h-sur-accent); }
.h-pagination-item:disabled { opacity: 0.35; cursor: default; }

/* --- Bloc d'inscription à l'alerte e-mail : fond alterné, formulaire réel
   (POST /api/contact, comme la fiche contact) --- */
.h-cta-alerte { background: var(--h-ivory-deep); margin-block: 0; padding-block: var(--h-gap-section); }
.h-cta-alerte-inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 32px;
}
.h-cta-alerte-inner .h-cta-icone { margin: 0; }
.h-cta-alerte-texte h2 { font-size: 30px; margin-bottom: 8px; }
.h-cta-alerte-texte p { margin: 0; max-width: 48ch; }
.h-alerte-form { min-width: 340px; }
.h-alerte-ligne { display: flex; gap: 12px; }
.h-alerte-champ { flex: 1 1 auto; background: var(--h-surface); padding: 12px 16px; border: 1px solid var(--h-sand); border-radius: 999px; }
.h-alerte-form .h-bouton { border-radius: 999px; white-space: nowrap; }
.h-alerte-consentement { display: flex; align-items: flex-start; gap: 8px; margin: 12px 0 0; font-size: 12px; color: var(--h-stone); }
.h-alerte-consentement label { max-width: 46ch; }
@media (max-width: 991px) {
  .h-cta-alerte-inner { grid-template-columns: 1fr; text-align: center; }
  .h-alerte-form { min-width: 0; }
  .h-alerte-ligne { flex-direction: column; }
  .h-alerte-consentement { text-align: left; }
}

/* --- Utilitaire d'accessibilité : texte présent, jamais visible --- */
.h-invisible {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ===========================================================================
   AGENCE — héros demi-hauteur, portraits d'équipe en 4:5
   =========================================================================== */
/* « min-height » et non « height » : .h-heros pose « overflow: hidden », et une
   hauteur fixe coupe sans le moindre signal un titre qui déborde — sur un
   téléphone étroit, ou le jour où un déploiement écrit un titre plus long que
   celui de la maquette. La proportion voulue est conservée, le héros ne fait
   que grandir s'il le faut. */
.h-heros-demi { height: auto; min-height: min(56vh, 480px); }

/* LA PHOTOGRAPHIE DU HÉROS DOIT ÊTRE POSÉE EN FOND, PAS DANS LE FLUX.
   Défaut préexistant, constaté à l'écran sur /agence et /contact : leur <img>
   ne portait AUCUNE classe, restait donc un élément flexible ordinaire, prenait
   toute la largeur du héros et près de 1 000 px de haut, et poussait
   .h-heros-texte hors du cadre — que « overflow: hidden » escamotait alors
   entièrement. Surtitre, titre, chapeau, filet et boutons : rien ne
   s'affichait, sur les deux écrans, sans la moindre erreur nulle part. Seul
   /annonces y échappait, parce que son image porte .h-heros-annonces-img, qui
   posait déjà ces six déclarations.
   La règle est écrite sur l'enfant direct plutôt que sur une classe nouvelle :
   elle couvre du même coup les deux écrans fautifs et l'écran Estimer, et tout
   héros qu'un cycle ajouterait ensuite. Les diapositives de l'accueil
   (.h-heros-diapo) ont déjà les leurs, identiques. */
.h-heros > img {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
}

/* Et la cause seconde : le h1 de .h-heros-texte est dimensionné pour le PLEIN
   écran de l'accueil (jusqu'à 108 px, maquette home.png). Sur un héros de
   moitié, ce corps-là ne tient pas. Les maquettes des écrans intérieurs
   montrent un titre deux fois plus petit — on reprend ici exactement le clamp
   déjà relevé pour /annonces (.h-heros-annonces-texte h1), qui décrit le même
   objet : deux formules pour un seul titre finiraient par diverger. */
.h-heros-demi .h-heros-texte h1 {
  font-size: clamp(36px, 4vw + 16px, 56px);
  max-width: 17ch;
}

/* Les PhotoAgent_*.jpeg du dépôt sont réellement en 300×300 (getimagesize()) :
   le cadre 4:5 est un choix visuel de mise en page, pas une supposition sur
   le fichier — width/height dans le gabarit restent les dimensions réelles. */
.h-agent-photo {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 2px;
  margin-bottom: 16px;
}

/* ===========================================================================
   ESTIMATION — seul écran entièrement sombre
   =========================================================================== */
.h-page-sombre { padding-block: var(--h-gap-section); }
.h-sombre .h-champ {
  color: var(--h-ivory);
  background: rgba(250, 247, 242, 0.04);
  border-color: rgba(250, 247, 242, 0.35);
}
.h-sombre .h-champ::placeholder { color: rgba(241, 238, 230, 0.55); }
.h-sombre .h-champ:hover { border-color: rgba(250, 247, 242, 0.55); }
.h-sombre .h-champ:focus { border-color: var(--color-primary); }
.h-sombre select.h-champ {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23F1EEE6' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
}
.h-sombre select.h-champ option { background: var(--h-night); color: var(--h-ivory); }
.h-sombre .h-etiquette { color: var(--h-stone); }

/* ===========================================================================
   CONTACT — confirmation éditoriale, jamais un message d'état
   =========================================================================== */
.h-confirmation {
  font-style: italic;
  color: var(--h-stone);
  font-size: 14px;
  margin-top: 16px;
}

/* --- Horaires et carte de l'agence, colonne gauche de /contact --- */
.h-horaires {
  margin-top: 24px;
  font-size: 14px;
  color: var(--h-slate);
}
.h-carte-agence {
  margin-top: 24px;
  aspect-ratio: 4 / 3;
  border-radius: 2px;
  overflow: hidden;
}
.h-carte-agence iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

/* ===========================================================================
   PAGES INTÉRIEURES — mentions, RGPD, honoraires, 404, 500
   Sans héros, colonne 6/12, titre réduit, filets --h-sand entre sections.
   =========================================================================== */
.h-colonne-interieure { grid-column: 2 / span 6; }
@media (max-width: 767px) { .h-colonne-interieure { grid-column: 1 / -1; } }

.h-titre-interieur {
  font-size: 44px;
  font-weight: 400;
  letter-spacing: -0.015em;
}

.h-legal-section + .h-legal-section {
  margin-top: var(--h-gap-titre);
  padding-top: var(--h-gap-titre);
  border-top: 1px solid var(--h-sand);
}

/* Tableau des honoraires : chiffres tabulaires (héritage de .table), conteneur
   qui défile plutôt que de déborder sous 768 px. */
.h-table-scroll {
  width: 100%;
  overflow-x: auto;
  margin-top: var(--h-gap-titre);
}

/* ===========================================================================
   PIED DE PAGE — reproduction de docs/designs/Horizon/*.png §2
   Il n'avait AUCUNE mise en forme : son contenu collait au bord gauche de la
   fenêtre et les liens s'empilaient en colonne. Cause : Bootstrap fournissait
   une base de mise en page aux éléments nus, et son retrait les a laissés sans
   rien. D'où les classes h- posées sur footer, main et header.
   =========================================================================== */
.h-principal { display: block; }

.h-pied {
  background: var(--h-night);
  color: var(--h-ivory);
}
.h-pied a { color: inherit; text-decoration: none; }
.h-pied a:hover { color: var(--h-accent); }

.h-pied-corps {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr 1.3fr;
  gap: 48px var(--h-gouttiere);
  padding-block: 72px 56px;
}

.h-pied-nom {
  margin: 0;
  font-family: var(--h-serif);
  font-size: 22px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.h-pied-phrase {
  margin: 16px 0 0;
  max-width: 30ch;
  font-size: 14px;
  line-height: 1.6;
  color: rgba(241, 238, 230, 0.66);
}

.h-pied-reseaux ul { display: flex; gap: 12px; margin: 24px 0 0; padding: 0; list-style: none; }
.h-pied-reseaux a {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border: 1px solid rgba(241, 238, 230, 0.28);
  border-radius: 999px;
  font-size: 13px;
  letter-spacing: 0.04em;
}
.h-pied-reseaux a:hover { border-color: var(--h-accent); }

.h-pied-titre {
  margin: 0 0 20px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(241, 238, 230, 0.52);
}
.h-pied-colonne ul { margin: 0; padding: 0; list-style: none; }
.h-pied-colonne li + li { margin-top: 12px; }
.h-pied-colonne a, .h-pied-contact p, .h-pied-contact address { font-size: 14px; line-height: 1.6; }
.h-pied-contact p { margin: 0 0 12px; }
.h-pied-contact address { font-style: normal; color: rgba(241, 238, 230, 0.66); }
.h-pied-horaire { margin-top: 16px !important; color: rgba(241, 238, 230, 0.52); }

.h-pied-barre { border-top: 1px solid rgba(241, 238, 230, 0.12); }
.h-pied-barre-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding-block: 24px;
  font-size: 13px;
  color: rgba(241, 238, 230, 0.52);
}
.h-pied-barre p { margin: 0; max-width: none; }
.h-pied-barre ul { display: flex; gap: 24px; margin: 0; padding: 0; list-style: none; }

@media (max-width: 1199px) {
  .h-pied-corps { grid-template-columns: 1fr 1fr 1fr; }
  .h-pied-marque { grid-column: 1 / -1; }
}
@media (max-width: 767px) {
  .h-pied-corps { grid-template-columns: 1fr; gap: 40px; padding-block: 56px 40px; }
  .h-pied-barre-inner { flex-direction: column; align-items: flex-start; }
  .h-nav-inner { gap: 16px; padding: 16px var(--h-marge); }
  .h-nav-contact { display: none; }
}

/* Lien d'évitement : masqué jusqu'au focus. Il portait une classe Bootstrap
   (visually-hidden-focusable) restée sans règle après le retrait de la
   bibliothèque, donc visible en permanence sur les onze écrans. */
.visually-hidden-focusable {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.visually-hidden-focusable:focus {
  position: fixed;
  top: 16px; left: 16px;
  width: auto; height: auto;
  margin: 0; padding: 12px 20px;
  overflow: visible;
  clip: auto;
  z-index: 100;
  background: var(--h-ink);
  color: var(--h-ivory);
  border-radius: 2px;
}
.h-pied-adresse { font-style: normal; color: rgba(241, 238, 230, 0.66); }
.h-pied-legal ul { display: flex; gap: 24px; margin: 0; padding: 0; list-style: none; }
.h-coord-adresse { font-style: normal; line-height: 1.7; }


/* ===========================================================================
   LISTES DÉROULANTES — bouton + listbox construits par horizon-select.js
   Le <select> natif reste dans le document (il porte name et value, donc le
   POST) ; il n'est que masqué visuellement et sorti de la tabulation. Sans
   JavaScript, aucune de ces règles ne s'applique : c'est « select.h-champ »,
   plus haut, qui fait alors tout le travail.
   =========================================================================== */
.h-select { position: relative; }

/* Masqué sans display:none ni visibility:hidden : un champ ainsi retiré du
   rendu ne participe plus à la validation native du navigateur, qui refuse
   alors de signaler un champ requis (« An invalid form control is not
   focusable »). Il garde donc une boîte d'un pixel, sous le bouton. */
.h-select-natif {
  position: absolute;
  left: 16px;
  bottom: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.h-select-bouton {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  text-align: left;
  cursor: pointer;
  /* Le bouton porte les classes du select qu'il remplace (.h-champ le plus
     souvent) : il en hérite cadre, fond et typographie. Ne reste ici que ce
     qu'un <button> impose de reprendre. */
  padding-right: 16px;
  background-image: none;
}
.h-select-valeur { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-select-chevron {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238A8A8A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  transition: transform 200ms ease;
}
.h-select--ouvert .h-select-chevron { transform: rotate(180deg); }
.h-select-bouton:focus-visible {
  outline: var(--h-focus);
  outline-offset: var(--h-focus-decalage);
}

/* « fixed », et non « absolute » : le menu doit échapper au découpage du
   panneau de filtres, qui défile sur lui-même. Position et largeur sont
   calculées par horizon-select.js (fonction placer()), y compris l'ouverture
   vers le haut quand le bas de la fenêtre est trop proche. */
.h-select-liste {
  position: fixed;
  z-index: 60;
  top: 0;
  left: 0;
  margin: 0;
  padding: 6px;
  list-style: none;
  max-height: 280px;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 6px;
  box-shadow: 0 18px 36px rgba(17, 15, 12, 0.14);
  scrollbar-width: thin;
  scrollbar-color: var(--h-sand) transparent;
}
.h-select-liste::-webkit-scrollbar { width: 6px; }
.h-select-liste::-webkit-scrollbar-thumb { background: var(--h-sand); border-radius: 999px; }

.h-select-option {
  padding: 10px 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-radius: 4px;
  font-size: 16px;
  color: var(--h-slate);
  cursor: pointer;
}
/* Survol et parcours au clavier partagent le même état : le menu ne doit
   jamais montrer deux lignes « en cours ». */
.h-select-option--actif { background: var(--h-ivory-deep); color: var(--h-ink); }
.h-select-option[aria-selected="true"] { color: var(--h-ink); font-weight: 500; }
.h-select-option[aria-selected="true"]::after {
  content: '';
  float: right;
  width: 14px;
  height: 14px;
  margin-top: 5px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23B29167' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
}
.h-select-option[aria-disabled="true"] { color: var(--h-stone); cursor: default; }

/* Écran sombre (estimation) : le menu reste une surface claire posée sur le
   fond nuit — un menu sombre sur fond sombre perdrait ses limites. Seul le
   bouton suit le registre de l'écran, par .h-sombre .h-champ plus haut. */
.h-sombre .h-select-chevron {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23F1EEE6' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
}
.h-sombre .h-select-bouton:focus-visible { outline-color: var(--h-ivory); }

/* ===========================================================================
   PAGES AGENCE ET CONTACT
   Maquettes docs/designs/Horizon/a-propos-ajouter-footer.png et contact.png.
   =========================================================================== */

/* --- Héros de page intérieure : le texte est POSÉ DANS le héros, alors que
   celui de l'accueil le pose en bas. Les deux partagent .h-heros et
   .h-heros-texte ; seules la hauteur et la justification changent. --- */
.h-agence-heros,
.h-contact-heros,
.h-estim-heros {
  align-items: center;
  /* Le texte doit passer sous l'en-tête en surimpression sans le toucher. */
  padding-top: var(--h-entete-h);
}
.h-agence-heros .h-heros-texte,
.h-contact-heros .h-heros-texte,
.h-estim-heros .h-heros-texte {
  padding-bottom: 0;
  max-width: 760px;
  margin-inline: 0;
}
.h-surtitre--clair { color: rgba(250, 247, 242, 0.72); }

/* Lien à pastille du héros (« Découvrir notre histoire »). Une seule ancre,
   jamais un lien doublé d'un bouton : la pastille fait partie du lien. */
.h-lien-fleche {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  color: var(--h-ivory);
  text-decoration: none;
  font-size: 14px;
  letter-spacing: 0.04em;
}
.h-lien-fleche-pastille {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid rgba(250, 247, 242, 0.5);
  border-radius: 50%;
  transition: background-color 220ms ease, border-color 220ms ease, color 220ms ease;
}
.h-lien-fleche:hover .h-lien-fleche-pastille {
  background: var(--h-ivory);
  border-color: var(--h-ivory);
  color: var(--h-ink);
}

/* --- Notre vision : texte / image --- */
.h-agence-vision {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--h-gap-cartes);
  align-items: center;
}
.h-agence-vision-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  /* L'arche de la maquette : un seul coin arrondi, en haut à droite. */
  border-radius: 0 180px 0 0;
}
@media (max-width: 991px) {
  .h-agence-vision { grid-template-columns: 1fr; }
  .h-agence-vision-media img { border-radius: 0 120px 0 0; }
}

/* --- Charte graphique et « Le 4 partout » : deux bandeaux centrés, propres à l'agence --- */
.h-agence-charte,
.h-agence-quatre { text-align: center; }
.h-agence-charte .h-surtitre,
.h-agence-quatre .h-surtitre { margin-inline: auto; }
.h-agence-formule {
  margin: 28px auto;
  max-width: none;
  font-family: var(--h-serif);
  font-size: clamp(28px, 4vw + 8px, 56px);
  line-height: 1.1;
  color: var(--h-accent);
}
.h-agence-charte-texte,
.h-agence-quatre-conclusion { margin-inline: auto; max-width: 62ch; }
.h-agence-quatre-liste {
  list-style: none;
  margin: var(--h-gap-titre) auto;
  padding: 0;
  max-width: 920px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 56px;
  text-align: left;
}
.h-agence-quatre-liste li {
  padding: 16px 0;
  border-top: 1px solid var(--h-sand);
}
.h-agence-quatre-conclusion {
  font-family: var(--h-serif);
  font-size: clamp(22px, 1.6vw + 12px, 32px);
  line-height: 1.25;
}
@media (max-width: 767px) {
  .h-agence-quatre-liste { grid-template-columns: 1fr; }
}

/* --- Nos engagements : quatre colonnes séparées par des filets --- */
.h-agence-engagements {
  background: var(--h-surface);
  /* Bande de fond : on remplace la marge de .h-section par une réserve
     INTÉRIEURE, sans quoi la couleur s'arrêterait au ras du texte — même
     piège que .h-estim-engagement et .h-estim-marche, corrigés plus loin
     dans cette feuille. */
  margin-block: 0;
  padding-block: var(--h-gap-section);
}
.h-agence-engagements-entete { text-align: center; margin-bottom: var(--h-gap-titre); }
.h-titre-centre { max-width: 22ch; margin-inline: auto; }
/* Le sur-titre est un <p>, donc soumis au `max-width: 68ch` posé plus haut
   sur tout <p> sans `margin-inline: auto` : sans lui, il reste calé au bord
   GAUCHE de son conteneur pendant que `text-align: center` ne centre que le
   texte À L'INTÉRIEUR de cette boîte déjà décalée — d'où un sur-titre visible
   à gauche sous un titre, lui, bien centré. Les quatre en-têtes centrées du
   modèle partagent ce piège. */
.h-agence-engagements-entete .h-surtitre,
.h-estim-formulaire-entete .h-surtitre,
.h-estim-marche-entete .h-surtitre,
.h-conseiller-portefeuille-entete .h-surtitre {
  margin-inline: auto;
}
.h-agence-engagements-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.h-agence-engagements-liste li {
  text-align: center;
  padding: 0 24px;
  /* Filets INTERNES seulement : une bordure sur chaque élément dessinerait un
     trait à gauche du premier, que la maquette ne montre pas. */
  border-left: 1px solid var(--h-sand);
}
.h-agence-engagements-liste li:first-child { border-left: 0; }
.h-agence-engagement-icone {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin: 0 auto 20px;
  border: 1px solid var(--h-accent);
  border-radius: 50%;
  color: var(--h-accent);
  font-size: 20px;
}
.h-agence-engagements-liste h3 {
  font-family: var(--h-sans);
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 12px;
}
.h-agence-engagements-liste p { font-size: 14px; color: var(--h-stone); margin: 0; }
@media (max-width: 991px) {
  .h-agence-engagements-liste { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 0; }
  .h-agence-engagements-liste li:nth-child(odd) { border-left: 0; }
}
@media (max-width: 575px) {
  .h-agence-engagements-liste { grid-template-columns: 1fr; }
  .h-agence-engagements-liste li { border-left: 0; }
}

/* --- Notre équipe : texte à gauche, trois portraits à droite --- */
.h-agence-equipe {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  gap: var(--h-gap-cartes);
  align-items: center;
}
.h-agence-equipe-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--h-gouttiere);
}
.h-agence-equipe-liste img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  /* Portraits en noir et blanc, comme la maquette. La couleur revient au
     survol : le détail se voit, sans rien promettre d'autre. */
  filter: grayscale(1);
  transition: filter 600ms ease;
}
.h-agence-equipe-liste li:hover img { filter: grayscale(0); }
.h-agence-equipe-liste h3 {
  font-size: 16px;
  margin: 16px 0 4px;
}
/* Le nom devient un lien vers la page conseiller (§4.1 de la spec) sans
   feuille de style dédiée à sa création : hérité de la commune, il tombait
   sous a { color: var(--color-primary) } / a:hover (public/assets/css/
   style.css:36-37), seul texte d'Horizon dans cette couleur. Le nom garde la
   teinte des titres, le lien se signale par le soulignement au survol.
   Spécificité : a:hover de la feuille commune vaut (0,1,1) ; la règle
   ci-dessous, un sélecteur descendant sur deux éléments sous une classe, vaut
   (0,2,2) et reprend donc la main sans avoir besoin d'une classe sur le <a>
   lui-même. */
.h-agence-equipe-liste h3 a {
  color: inherit;
  text-decoration: none;
}
.h-agence-equipe-liste h3 a:hover,
.h-agence-equipe-liste h3 a:focus-visible {
  color: inherit;
  text-decoration: underline;
}
.h-agence-equipe-liste p { font-size: 13px; color: var(--h-stone); margin: 0; }
.h-agence-equipe-tel { margin-top: 6px !important; font-variant-numeric: tabular-nums; }
.h-agence-equipe-tel a { color: var(--h-slate); text-decoration: none; }
.h-agence-equipe-tel a:hover { color: var(--h-accent); }
/* Bouton explicite vers la fiche, en plus du petit lien porté par le nom
   (celui-ci reste, exigé par tools/verif/gabarits.php — CLAUDE.md §8) : un
   visiteur qui parcourt l'équipe ne devine pas toujours qu'un nom est
   cliquable, un bouton l'est sans ambiguïté. */
.h-agence-equipe-contact { margin-top: 16px; font-size: 13px; padding: 10px 22px; }
.h-agence-equipe-texte .h-bouton { margin-top: 28px; }
@media (max-width: 991px) {
  .h-agence-equipe { grid-template-columns: 1fr; }
}
@media (max-width: 575px) {
  .h-agence-equipe-liste { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .h-agence-equipe-liste img { transition: none; }
}

/* --- Bandeau d'appel final --- */
.h-agence-appel {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 420px;
  overflow: hidden;
}
.h-agence-appel img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Voile : le texte est clair et la photographie ne l'est pas toujours. Borné à
   la moitié gauche, là où le texte se pose, plutôt qu'étendu à toute l'image. */
.h-agence-appel::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(17, 15, 12, 0.72) 0%, rgba(17, 15, 12, 0.32) 55%, rgba(17, 15, 12, 0) 100%);
  z-index: 1;
}
.h-agence-appel-texte {
  position: relative;
  z-index: 2;
  color: var(--h-ivory);
  padding-block: var(--h-gap-section);
  max-width: 620px;
  margin-inline: 0;
}
.h-agence-appel-texte h2 { color: var(--h-ivory); max-width: 18ch; }
.h-agence-appel-texte p { margin: 20px 0 32px; max-width: 46ch; }

/* --- Contact : formulaire et agence côte à côte --- */
.h-contact-reperes {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
  color: var(--h-ivory);
}
.h-contact-reperes li { display: flex; align-items: center; gap: 12px; font-size: 14px; }
.h-contact-reperes a { color: inherit; }
.h-contact-repere-libelle {
  display: block;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0.72;
  margin-bottom: 2px;
}
.h-contact-repere-icone {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex: 0 0 36px;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-size: 14px;
  opacity: 0.8;
}
.h-contact-corps {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--h-gap-cartes);
  align-items: start;
}
.h-contact-formulaire-chapeau { color: var(--h-stone); margin-bottom: 28px; }
.h-contact-formulaire fieldset { border: 0; padding: 0; margin: 0; }
.h-contact-agence-photo {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 2px;
  margin-block: 24px;
}
.h-contact-coordonnees { list-style: none; margin: 0 0 28px; padding: 0; display: grid; gap: 20px; }
.h-contact-coordonnees li { display: flex; align-items: flex-start; gap: 16px; color: var(--h-ink); }
.h-contact-coordonnees .h-contact-repere-icone { color: var(--h-accent); opacity: 1; margin-top: 2px; }
.h-contact-coordonnees address { font-style: normal; margin: 0; }
.h-contact-coordonnees a { color: inherit; text-decoration: none; }
.h-contact-coordonnees a:hover { color: var(--h-accent); }
@media (max-width: 991px) {
  .h-contact-corps { grid-template-columns: 1fr; }
  .h-contact-reperes { gap: 20px; }
}

/* --- Contact : notre territoire --- */
.h-contact-territoire {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--h-gap-cartes);
  align-items: center;
}
.h-contact-territoire-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 16px 24px;
}
.h-contact-territoire-liste li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  border: 1px solid var(--h-sand);
  border-radius: 999px;
  background: var(--h-surface);
  font-size: 14px;
}
.h-contact-territoire-liste .h-contact-repere-icone {
  width: 22px;
  height: 22px;
  flex-basis: 22px;
  border: 0;
  color: var(--h-accent);
  opacity: 1;
  font-size: 13px;
}
@media (max-width: 991px) {
  .h-contact-territoire { grid-template-columns: 1fr; }
}

/* ===========================================================================
   ÉCRAN « ESTIMER MON BIEN » — docs/designs/Horizon/estimer.png
   =========================================================================== */

/* --- Notre engagement : titre à gauche, texte à droite --- */
.h-estim-engagement {
  background: var(--h-ivory-deep);
  /* Bande de fond : on remplace la marge de .h-section par une réserve
     INTÉRIEURE, sans quoi la couleur s'arrêterait au ras du texte. */
  margin-block: 0;
  padding-block: var(--h-gap-section);
}
.h-estim-engagement-entete {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: var(--h-gap-cartes);
  align-items: end;
  margin-bottom: calc(var(--h-gap-section) * 0.7);
}
.h-estim-engagement-titre {
  max-width: 30ch;
  margin: 0;
}
.h-estim-engagement-entete > p {
  margin: 0;
  max-width: 52ch;
  font-size: 15px;
  color: var(--h-stone);
}

/* Quatre colonnes séparées par des filets internes, comme « Nos engagements »
   de la page Agence : même grammaire, deux écrans, deux jeux de règles — on ne
   réemploie pas une classe nommée d'après un autre écran, elle deviendrait
   intouchable pour tout cycle qui voudrait faire diverger l'un des deux. */
.h-estim-atouts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.h-estim-atouts li {
  text-align: center;
  padding: 0 24px;
  border-left: 1px solid var(--h-sand);
}
.h-estim-atouts li:first-child { border-left: 0; }
.h-estim-atout-icone {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin: 0 auto 20px;
  border: 1px solid var(--h-accent);
  border-radius: 50%;
  color: var(--h-accent);
  font-size: 20px;
  flex: 0 0 52px;
}
.h-estim-atouts h3 {
  font-family: var(--h-sans);
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 12px;
}
.h-estim-atouts p { font-size: 14px; color: var(--h-stone); margin: 0; }

/* --- Le formulaire --- */
.h-estim-formulaire-entete { text-align: center; margin-bottom: var(--h-gap-titre); }

/* Fil des étapes. Sans JavaScript, quatre ancres alignées : une table des
   matières du formulaire, qui reste vraie. .h-estim-fil--js, posée par le
   script, en fait une barre d'avancement. */
.h-estim-fil {
  list-style: none;
  margin: 0 auto var(--h-gap-titre);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  max-width: 1000px;
}
.h-estim-fil li { position: relative; text-align: left; }
/* Le trait de liaison, jamais après le dernier jalon. */
.h-estim-fil li:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 17px;
  left: 148px;
  right: 16px;
  height: 1px;
  background: var(--h-sand);
}
.h-estim-fil a {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--h-stone);
  text-decoration: none;
  font-size: 14px;
  transition: color 200ms ease;
}
.h-estim-fil a:hover { color: var(--h-ink); }
.h-estim-fil-num {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border: 1px solid var(--h-sand);
  border-radius: 50%;
  background: var(--h-surface);
  font-size: 14px;
  color: var(--h-stone);
  transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease;
}
.h-estim-fil-item--actif a { color: var(--h-ink); }
.h-estim-fil-item--actif .h-estim-fil-num {
  background: var(--h-accent);
  border-color: var(--h-accent);
  color: var(--h-sur-accent);
}
.h-estim-fil-item--fait .h-estim-fil-num {
  border-color: var(--h-accent);
  color: var(--h-accent);
}

.h-estim-carte {
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 8px;
  padding: calc(var(--h-pad-carte) + 8px);
  max-width: 1200px;
  margin-inline: auto;
}

/* Réinitialisation des <fieldset> : le cadre et la réserve du navigateur ne
   correspondent à aucune maquette.
   AUCUN « display » n'est posé sur .h-estim-etape — il écraserait la règle
   [hidden] ci-dessous, dont dépend tout le repliement (même piège que
   .h-liste-item[hidden] sur l'écran des annonces). */
.h-estim-etape,
.h-estim-equipements {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}
.h-estim-etape[hidden] { display: none; }
.h-estim-etape > legend {
  font-family: var(--h-serif);
  font-size: 24px;
  color: var(--h-ink);
  padding: 0;
  margin-bottom: 24px;
}
/* Le script pose .h-estim--js : le fil dit alors où l'on en est, la légende
   ferait doublon. Elle reste dans le document pour l'assistance technique. */
.h-estim--js .h-estim-etape > legend {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* Deux étapes visibles d'affilée (sans JavaScript) doivent se distinguer. */
.h-estim-etape + .h-estim-etape {
  margin-top: 40px;
  padding-top: 40px;
  border-top: 1px solid var(--h-sand);
}
.h-estim--js .h-estim-etape + .h-estim-etape {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.h-estim-etape-grille {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 6fr);
  gap: 40px;
}
.h-estim-champ { margin: 0 0 20px; }
.h-estim-champs > *:last-child { margin-bottom: 0; }
.h-estim-duo {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  margin-bottom: 20px;
}
.h-estim-duo .h-estim-champ { margin-bottom: 0; }
.h-estim-aide {
  margin: 0 0 24px;
  font-size: 14px;
  color: var(--h-stone);
}

/* Unité collée au champ (m²) : un suffixe posé DANS la boîte, pas une seconde
   étiquette — la maquette montre le champ et son unité comme un seul objet. */
.h-estim-unite { position: relative; display: block; }
.h-estim-unite .h-champ { padding-right: 52px; }
.h-estim-unite > span {
  position: absolute;
  top: 50%;
  right: 16px;
  transform: translateY(-50%);
  color: var(--h-stone);
  font-size: 14px;
  pointer-events: none;
}
/* Flèches de <input type=number> retirées : elles ramènent la grammaire du
   système d'exploitation dans un formulaire entièrement redessiné. */
.h-champ[type="number"] { appearance: textfield; -moz-appearance: textfield; }
.h-champ[type="number"]::-webkit-outer-spin-button,
.h-champ[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* --- Tuiles de type de bien ---
   Un <input type="radio"> RÉEL sous chaque tuile : sans lui, la sélection ne
   partirait pas avec le formulaire quand ce script ne tourne pas. La tuile
   n'est que l'habillage du <label>. */
.h-estim-tuiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 8px;
}
.h-estim-tuile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 26px;
  padding: 18px 16px;
  border: 1px solid var(--h-sand);
  border-radius: 6px;
  background: var(--h-surface);
  cursor: pointer;
  transition: border-color 200ms ease, background-color 200ms ease;
}
.h-estim-tuile input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.h-estim-tuile-icone { color: var(--h-stone); font-size: 20px; }
.h-estim-tuile-nom { font-size: 15px; color: var(--h-ink); }
.h-estim-tuile:hover { border-color: var(--h-stone); }
.h-estim-tuile:has(input:checked) {
  border-color: var(--h-accent);
  background: rgba(var(--color-primary-rgb, 178, 145, 103), 0.07);
}
.h-estim-tuile:has(input:checked) .h-estim-tuile-icone { color: var(--h-accent); }
/* Le focus clavier tombe sur un champ transparent : c'est la tuile qui doit le
   montrer, sans quoi la navigation au clavier serait invisible. */
.h-estim-tuile:has(input:focus-visible) {
  outline: var(--h-focus);
  outline-offset: var(--h-focus-decalage);
}
.h-estim-tuile--large {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: 12px;
}

/* --- Équipements : des pastilles à cocher --- */
.h-estim-equipements {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
/* La légende est un élément flexible comme les pastilles : sans cette base de
   100 %, elle se rangerait SUR la première ligne, à côté de « Ascenseur ». */
.h-estim-equipements > legend { flex: 0 0 100%; padding: 0; margin-bottom: 0; }
.h-estim-case {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  border: 1px solid var(--h-sand);
  border-radius: 999px;
  background: var(--h-surface);
  font-size: 14px;
  cursor: pointer;
  transition: border-color 200ms ease, background-color 200ms ease;
}
.h-estim-case input { accent-color: var(--h-accent); margin: 0; }
.h-estim-case:hover { border-color: var(--h-stone); }
.h-estim-case:has(input:checked) {
  border-color: var(--h-accent);
  background: rgba(var(--color-primary-rgb, 178, 145, 103), 0.07);
}

.h-estim-consentement {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  font-size: 14px;
  color: var(--h-stone);
}
.h-estim-consentement input { accent-color: var(--h-accent); margin-top: 5px; }

/* --- Navigation entre étapes (construite par le script) --- */
.h-estim-nav {
  display: flex;
  justify-content: flex-end;
  gap: 16px;
  margin-top: 32px;
}
.h-estim-nav:empty { display: none; }
.h-estim-continuer { min-width: 250px; text-align: center; }

.h-estim-pied {
  margin-top: 32px;
  padding-top: 28px;
  border-top: 1px solid var(--h-sand);
  text-align: center;
}
.h-estim-pied p { margin: 12px 0 0; }
.h-estim-envoyer { min-width: 250px; }
.h-estim-pied .h-erreur { margin: 0 0 16px; }

.h-estim-confirmation { text-align: center; padding: 40px 0; }
.h-estim-confirmation:focus { outline: none; }
.h-estim-confirmation h3 { font-family: var(--h-serif); font-size: 26px; margin-bottom: 12px; }
.h-estim-confirmation p { margin: 0 auto; max-width: 48ch; color: var(--h-stone); }

/* --- Comment ça marche : quatre jalons sur un fil --- */
.h-estim-marche {
  background: var(--h-ivory-deep);
  margin-block: 0;
  padding-block: var(--h-gap-section);
}
.h-estim-marche-entete { text-align: center; margin-bottom: var(--h-gap-titre); }
.h-estim-jalons {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
}
.h-estim-jalons li { position: relative; text-align: center; padding: 0 20px; }
.h-estim-jalons li:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 21px;
  left: calc(50% + 28px);
  right: calc(-50% + 28px);
  height: 1px;
  background: var(--h-sand);
}
.h-estim-jalon-num {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  margin: 0 auto 20px;
  border: 1px solid var(--h-accent);
  border-radius: 50%;
  background: var(--h-ivory-deep);
  color: var(--h-accent);
  font-size: 15px;
}
.h-estim-jalons h3 { font-family: var(--h-sans); font-size: 15px; margin-bottom: 10px; }
.h-estim-jalons p { font-size: 14px; color: var(--h-stone); margin: 0; }

/* --- Rappel final --- */
.h-estim-rappel { background: var(--h-sand); }
.h-estim-rappel-corps {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 32px;
  align-items: center;
  padding-block: 56px;
}
.h-estim-rappel-corps h2 { font-size: 28px; margin: 0 0 8px; }
.h-estim-rappel-corps p { margin: 0; font-size: 15px; color: var(--h-slate); max-width: 60ch; }
.h-estim-rappel-corps .h-estim-atout-icone { margin: 0; }

@media (max-width: 1199px) {
  .h-estim-fil li:not(:last-child)::after { left: 130px; }
}
@media (max-width: 991px) {
  .h-estim-engagement-entete { grid-template-columns: 1fr; align-items: start; }
  .h-estim-atouts { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 0; }
  .h-estim-atouts li:nth-child(odd) { border-left: 0; }
  .h-estim-etape-grille { grid-template-columns: 1fr; gap: 28px; }
  .h-estim-fil { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 0; }
  .h-estim-fil li::after { display: none; }
  .h-estim-jalons { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 0; }
  .h-estim-jalons li::after { display: none; }
  .h-estim-rappel-corps { grid-template-columns: auto minmax(0, 1fr); }
  .h-estim-rappel-corps .h-bouton { grid-column: 2; justify-self: start; }
}
@media (max-width: 767px) {
  .h-estim-atouts { grid-template-columns: 1fr; }
  .h-estim-atouts li { border-left: 0; }
  .h-estim-fil { grid-template-columns: 1fr; }
  .h-estim-duo { grid-template-columns: 1fr; }
  .h-estim-jalons { grid-template-columns: 1fr; }
  .h-estim-nav { flex-direction: column-reverse; }
  .h-estim-continuer,
  .h-estim-envoyer { min-width: 0; width: 100%; }
  .h-estim-rappel-corps { grid-template-columns: 1fr; gap: 20px; }
  .h-estim-rappel-corps .h-bouton { grid-column: 1; }
}

/* ===========================================================================
   CONSEILLER — fil d'Ariane, héros à portrait, chiffres, expertise,
   portefeuille, bandeau d'appel
   Maquette : docs/designs/Horizon/conseiller.png
   =========================================================================== */

/* Le fil d'Ariane de base est clair, pensé pour le héros sombre des annonces :
   posé ici sur l'ivoire il serait illisible. Mêmes surcharges que
   .h-fiche-topbar, qui a le même problème pour la même raison. */
.h-conseiller-topbar { margin-top: 32px; margin-bottom: 24px; }
.h-conseiller-topbar .h-fil-ariane { margin: 0; }
.h-conseiller-topbar .h-fil-ariane ol { color: var(--h-stone); }
.h-conseiller-topbar .h-fil-ariane a { color: var(--h-slate); text-decoration: none; }
.h-conseiller-topbar .h-fil-ariane a:hover { color: var(--h-accent); }
.h-conseiller-topbar .h-fil-ariane li[aria-current] { color: var(--h-ink); }
.h-conseiller-topbar .h-fil-ariane li + li::before { color: var(--h-stone); }

/* --- Héros : portrait collé au bord gauche, identité à droite ---
   Pas de .h-contenu sur la section : le portrait doit toucher le bord de la
   fenêtre (maquette). C'est la colonne de droite qui porte sa propre marge,
   et elle seule. */
.h-conseiller-heros {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--h-gap-cartes);
  align-items: center;
  margin-bottom: var(--h-gap-section);
}
/* Le fichier source mesure 300×300 (les cinq PhotoAgent_*.jpeg du parc), et le
   cadre est plus LARGE que haut. « cover » y recadrait donc verticalement : sur
   un portrait cadré serré, il emportait le haut du crâne et le menton. C'est la
   HAUTEUR qui commande, et « contain » garde le visage entier.
   Le fond du cadre est blanc, comme celui des portraits du flux : les bandes
   latérales se fondent dans la photographie au lieu de la souligner. Un flux
   dont les portraits seraient détourés sur une autre couleur les verrait —
   c'est le prix assumé pour ne jamais couper un visage. */
.h-conseiller-portrait { background: #fff; }
.h-conseiller-portrait img {
  width: 100%;
  height: clamp(320px, 42vw, 480px);
  object-fit: contain;
}
.h-conseiller-identite { padding-right: var(--h-marge); }
.h-conseiller-identite h1 { font-size: clamp(38px, 4.2vw, 58px); }
.h-conseiller-fonction {
  margin: 14px 0 0;
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--h-stone);
}
.h-conseiller-description {
  margin: 24px 0 0;
  max-width: 58ch;
  color: var(--h-slate);
}
.h-conseiller-identite .h-filet-court { margin: 28px 0; }

.h-conseiller-contacts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 18px;
}
.h-conseiller-contacts li { display: flex; align-items: flex-start; gap: 16px; }
.h-conseiller-contact-icone {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex: 0 0 36px;
  border: 1px solid var(--h-accent);
  border-radius: 50%;
  color: var(--h-accent);
  font-size: 14px;
}
.h-conseiller-contact-valeur {
  font-size: 15px;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
}
/* Les deux numéros s'empilent sous la même pastille, comme la maquette. */
.h-conseiller-contact-valeur a { display: block; color: var(--h-slate); text-decoration: none; }
.h-conseiller-contact-valeur a:hover { color: var(--h-accent); }
.h-conseiller-contact-libelle {
  display: block;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--h-stone);
  margin-bottom: 2px;
}

/* --- Bande de quatre chiffres --- */
.h-conseiller-chiffres {
  background: var(--h-ivory-deep);
  padding-block: 44px;
}
.h-conseiller-chiffres-liste {
  list-style: none;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.h-conseiller-chiffres-liste li {
  text-align: center;
  padding: 0 24px;
  /* Filets INTERNES seulement : une bordure sur chaque élément dessinerait un
     trait à gauche du premier, que la maquette ne montre pas. */
  border-left: 1px solid var(--h-sand);
}
.h-conseiller-chiffres-liste li:first-child { border-left: 0; }
.h-conseiller-chiffre-icone {
  display: block;
  color: var(--h-accent);
  font-size: 22px;
  margin-bottom: 14px;
}
.h-conseiller-chiffres-liste strong {
  display: block;
  font-family: var(--h-serif);
  font-weight: 400;
  font-size: 36px;
  line-height: 1.1;
  color: var(--h-ink);
  font-variant-numeric: tabular-nums;
}
.h-conseiller-chiffres-liste span:last-child {
  display: block;
  margin-top: 6px;
  font-size: 13px;
  color: var(--h-stone);
}

/* --- Son expertise : texte à gauche, quatre spécialités à droite --- */
.h-conseiller-expertise {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--h-gap-cartes);
  align-items: center;
}
.h-conseiller-expertise-texte p:last-child {
  font-size: 15px;
  color: var(--h-slate);
  max-width: 46ch;
  margin: 0;
}
.h-conseiller-specialites {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--h-gouttiere);
}
.h-conseiller-specialites li { text-align: center; }
.h-conseiller-specialite-icone {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin: 0 auto 18px;
  border: 1px solid var(--h-accent);
  border-radius: 50%;
  color: var(--h-accent);
  font-size: 20px;
}
.h-conseiller-specialites p {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--h-slate);
}

/* --- Portefeuille ---
   AUCUNE règle « display » sur .h-liste-item : elle écraserait la surcharge
   .h-liste-item[hidden] { display: none }, dont dépendent la pagination des
   annonces ET les onglets que horizon.js posera ici (tâche 6). Le même piège a
   déjà coûté deux corrections (.h-liste-item, .h-estim-etape). */
/* Onglets construits par horizon.js (tâche 6), insérés avant le <ul> quand au
   moins deux filtres sont non vides. Pas de fond ni de bordure de repos : seul
   [aria-selected="true"] souligne l'onglet actif, même logique que
   .h-fiche-onglets mais sans repli « premier onglet actif » — cette barre
   n'existe jamais sans JavaScript, donc jamais sans script pour poser l'état. */
.h-conseiller-onglets {
  display: flex;
  justify-content: center;
  gap: 32px;
  margin-bottom: var(--h-gap-titre);
}
.h-conseiller-onglet {
  padding: 8px 0;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  font: inherit;
  font-size: 15px;
  color: var(--h-stone);
  cursor: pointer;
}
.h-conseiller-onglet:hover { color: var(--h-ink); }
.h-conseiller-onglet[aria-selected="true"] {
  color: var(--h-ink);
  border-bottom-color: var(--h-accent);
}
.h-conseiller-onglet:focus-visible { outline: 2px solid var(--h-accent); outline-offset: 2px; }

.h-conseiller-portefeuille-entete { text-align: center; margin-bottom: var(--h-gap-titre); }
/* Quatre biens au plus, sur une seule rangée : quatre colonnes, là où la
   grille commune des annonces en pose trois. L'interdit de quatre colonnes
   que vérifie tools/verif/horizon.php porte sur CET écran-là (maquette
   annonces.png, reference.md §3.2) ; ici la maquette montre bien quatre
   cartes côte à côte, et trois en laisseraient une orpheline sur sa rangée.
   La règle ne cible que la page conseiller : elle ne touche pas /annonces. */
.h-conseiller-portefeuille { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 0; }
.h-conseiller-portefeuille-pied { text-align: center; margin: var(--h-gap-titre) 0 0; max-width: none; }
/* 1440 px et non 1300 : en dessous, chacune des quatre colonnes tombe sous
   280 px — la largeur à laquelle prix, titre et pictogrammes se serrent dans
   la carte (même constat que la grille des annonces plus haut). Deux colonnes
   de deux plutôt que trois : quatre cartes sur trois colonnes laisseraient la
   quatrième orpheline sur sa rangée. */
@media (max-width: 1439px) {
  .h-conseiller-portefeuille { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Bandeau d'appel final, sur photographie ---
   Même dessin que .h-agence-appel, mais centré : la maquette pose ici le texte
   au milieu de l'image, et non en colonne de gauche. Le voile est donc uni et
   non dégradé — un dégradé borné à gauche laisserait le bord droit du texte
   hors de sa protection. */
.h-conseiller-appel {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 420px;
  overflow: hidden;
}
.h-conseiller-appel img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.h-conseiller-appel::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(17, 15, 12, 0.55);
  z-index: 1;
}
.h-conseiller-appel-texte {
  position: relative;
  z-index: 2;
  color: var(--h-ivory);
  text-align: center;
  padding-block: var(--h-gap-section);
}
.h-conseiller-appel-texte h2 { color: var(--h-ivory); max-width: 20ch; margin-inline: auto; }
/* :not(.h-surtitre) — sans lui, cette règle (0,1,1) l'emporterait sur
   .h-surtitre (0,1,0), qui est déclarée plus haut dans la feuille, et le
   sur-titre hériterait de la marge du chapeau. */
.h-conseiller-appel-texte p:not(.h-surtitre) { margin: 20px auto 32px; max-width: 48ch; }

@media (max-width: 991px) {
  .h-conseiller-heros { grid-template-columns: 1fr; gap: var(--h-gap-titre); }
  /* Une seule colonne : le portrait ne peut plus être « collé au bord gauche »,
     il prend la largeur et la marge revient sur l'identité des deux côtés. */
  .h-conseiller-identite { padding-inline: var(--h-marge); }
  .h-conseiller-portrait img { height: clamp(280px, 56vw, 420px); }
  .h-conseiller-expertise { grid-template-columns: 1fr; }
}
@media (max-width: 899px) {
  /* Deux colonnes de deux pour la bande de chiffres : quatre tuiles côte à
     côte y tombent sous la largeur de leur libellé. */
  .h-conseiller-chiffres-liste { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px 0; }
  .h-conseiller-chiffres-liste li:nth-child(odd) { border-left: 0; }
  .h-conseiller-specialites { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px var(--h-gouttiere); }
}
@media (max-width: 767px) {
  .h-conseiller-portefeuille { grid-template-columns: 1fr; }
}
@media (max-width: 575px) {
  .h-conseiller-chiffres-liste { grid-template-columns: 1fr; }
  .h-conseiller-chiffres-liste li { border-left: 0; }
  .h-conseiller-specialites { grid-template-columns: 1fr; }
}

/* --- Contact rapide du conseiller : coordonnées + formulaire ---
   Rendu en ligne par défaut (repli sans JavaScript, CLAUDE.md §8) ; la même
   grille est déplacée telle quelle dans .h-modale--conseiller par
   horizon.js, d'où l'absence de couleur de fond ou d'ombre ici — la carte
   doit rester lisible dans les deux contextes. */
.h-conseiller-contact-rapide-grille {
  display: grid;
  grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
  gap: var(--h-gap-cartes);
  align-items: start;
  background: var(--h-surface);
  border: 1px solid var(--h-sand);
  border-radius: 2px;
  padding: var(--h-pad-carte);
}
.h-conseiller-contact-rapide-coordonnees img {
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 999px;
  margin-bottom: 16px;
}
.h-conseiller-contact-rapide-nom { font-family: var(--h-serif); font-size: 20px; margin: 0; }
.h-conseiller-contact-rapide-fonction { font-size: 14px; color: var(--h-stone); margin: 4px 0 0; }
.h-conseiller-contact-rapide-coordonnees .h-conseiller-contacts { margin-top: 20px; }
@media (max-width: 767px) {
  .h-conseiller-contact-rapide-grille { grid-template-columns: 1fr; }
}

/* --- Fenêtre modale du contact rapide ---
   Plus large que .h-modale (560px) : elle porte deux colonnes, là où la
   fenêtre de la fiche bien n'en sert qu'une (formulaire seul, coordonnées
   déjà visibles dans la colonne latérale hors modale). */
.h-modale--conseiller { width: min(760px, calc(100vw - 32px)); }
.h-modale-corps--conseiller .h-conseiller-contact-rapide-grille {
  border: 0;
  padding: 0;
  background: transparent;
}
@media (max-width: 575px) {
  .h-modale-corps--conseiller .h-conseiller-contact-rapide-grille { grid-template-columns: 1fr; }
}

/* Logo : fichier à 2x (330x120), affiché à 165x60 — les attributs width/height
   du gabarit portent les dimensions réelles du fichier, la feuille fixe la taille vue. */
.h-nav-marque img,
.h-pied-marque img {
  height: 60px;
  width: auto;
  display: block;
}
