@charset "UTF-8";

/* ==========================================================================
   Casa Paradisu - Composants reutilisables
   ========================================================================== */

/* ==========================================================================
   1. Boutons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  /* Hauteur, rayon et retrait horizontal viennent des jetons : tous les
     boutons du site, quelle que soit la variante ou la page, sont identiques. */
  min-height: var(--btn-h);
  /* min-height gouverne le libelle sur une ligne ; le retrait vertical ne
     sert qu'aux libelles qui passent a la ligne sur ecran etroit. */
  padding-block: var(--sp-3);
  padding-inline: var(--btn-px);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: var(--font-text);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-button);
  line-height: var(--lh-ui);
  text-align: center;
  cursor: pointer;
  transition:
    background-color var(--dur) var(--ease),
    color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

.btn--primary {
  background-color: var(--c-charcoal);
  color: var(--c-ivory);
  border-color: var(--c-charcoal);
}
.btn--primary:hover { background-color: var(--c-maquis); border-color: var(--c-maquis); }

/* Bouton secondaire : le filet doit rester nettement visible sur l'ivoire,
   sinon il se lit comme un bouton inactif. */
.btn--outline {
  background-color: transparent;
  color: var(--text-strong);
  border-color: rgba(32, 35, 31, 0.42);
}
.btn--outline:hover { border-color: var(--c-charcoal); background-color: var(--c-charcoal); color: var(--c-ivory); }
.on-dark .btn--outline { color: var(--c-ivory); border-color: rgba(244, 240, 231, 0.5); }
.on-dark .btn--outline:hover { background-color: var(--c-ivory); color: var(--c-charcoal); border-color: var(--c-ivory); }

/* Sur photo ou fond sombre */
.btn--on-image {
  background-color: transparent;
  color: var(--c-ivory);
  border-color: rgba(244, 240, 231, 0.55);
  backdrop-filter: none;
}
.btn--on-image:hover { background-color: var(--c-ivory); color: var(--c-charcoal); border-color: var(--c-ivory); }

/* Bouton clair sur fond sombre. Cette variante remplace les declarations
   inline autrefois repetees dans chaque pied de page et chaque bande sombre. */
.btn--light {
  background-color: var(--c-ivory);
  color: var(--c-charcoal);
  border-color: var(--c-ivory);
}
.btn--light:hover { background-color: var(--c-gold); border-color: var(--c-gold); color: var(--c-charcoal); }

.btn--block { width: 100%; }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; }

/* Rangee d'appels a l'action : un seul motif pour tout le site. */
.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  align-items: center;
}
.actions--stack { display: grid; gap: var(--sp-3); }

/* Lien texte souligne d'un filet fin qui s'anime */
.link-line {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;            /* cible tactile confortable */
  font-size: var(--fs-small);
  /* Lien textuel : 400. Il ne doit pas se lire comme un bouton. */
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-button);
  line-height: var(--lh-ui);
  color: var(--text-strong);
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--rule);
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.link-line:hover { border-bottom-color: var(--c-charcoal); }
.link-line .arrow { transition: transform var(--dur) var(--ease); }
.link-line:hover .arrow { transform: translateX(4px); }
.on-dark .link-line { color: var(--c-ivory); }
.on-dark .link-line:hover { border-bottom-color: var(--c-ivory); }

/* ==========================================================================
   2. En-tete et navigation
   ========================================================================== */

/* La hauteur, l'alignement et la structure de l'en-tete sont identiques sur
   toutes les pages et ne changent jamais pendant le defilement : seuls le
   fond, la couleur du texte et le filet inferieur evoluent. */
/* =============================================================================
   EN-TETE
   Une barre FIXE, hors du flux, posee sur le contenu. Elle ne prend aucune
   hauteur au document : le media de l'accueil demarre donc a y = 0 et passe
   derriere elle. Les decalages d'ancre et les elements collants du site
   (`--anchor-pad`, `.section-nav`, `.estimate`, `.contact-aside`) sont deja
   exprimes en `--header-h` : ils restent justes sans etre touches.
   ========================================================================== */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-header);
  width: 100%;
  height: var(--header-h);
  background-color: #fff;
  color: var(--c-charcoal);
  box-shadow: none;
  border-bottom: 1px solid rgba(8, 20, 38, 0.08);
}

/* Les pages interieures ouvrent sur du contenu, pas sur un media plein ecran :
   la hauteur que la barre ne prend plus leur est rendue ici. L'accueil en est
   exclu, c'est precisement ce qui fait demarrer la video tout en haut. */
body:not([data-page="accueil"]) { padding-top: var(--header-h); }

/* --- Composition en trois zones -------------------------------------------
   Colonnes laterales de largeur EGALE, colonne centrale dimensionnee par son
   contenu : le logo tombe donc au centre exact de la fenetre, quelle que soit
   la largeur du menu ou du lien de droite. Un centrage par marges serait faux
   des que les deux cotes different, ce qui est le cas ici. */
.site-header__inner {
  width: 100%;
  height: 100%;
  max-width: none;
  margin-inline: 0;
  padding-inline: 50px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-4);
}

.site-header__nav     { grid-column: 1; justify-self: start; }
.menu-toggle          { grid-column: 1; justify-self: start; }
.site-header__logo    { grid-column: 2; justify-self: center; }
.site-header__actions { grid-column: 3; justify-self: end; }

/* --- Navigation ------------------------------------------------------------ */
.nav { display: flex; align-items: center; gap: 30px; }

/* Tres petite, tres espacee, tres legere : la navigation ne dispute rien au
   titre pose sur le media. La graisse 500 est retenue plutot que 400, seule
   valeur qui tienne sur une image claire sans epaissir le dessin. */
.nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-hero);
  font-size: 11px;
  font-weight: var(--fw-medium);
  line-height: 14px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--c-charcoal);
  transition: opacity var(--dur) var(--ease);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -8px;
  width: 100%;
  height: 1px;
  background-color: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 450ms cubic-bezier(0.22, 1, 0.36, 1);
}
.nav__link:hover::after,
.nav__link:focus-visible::after,
.nav__link[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left center;
}

/* --- Logo ------------------------------------------------------------------
   Le fichier de marque est dore ; sur le blanc, un assombrissement leger le
   porte au-dela de 3:1 sans le denaturer. */
.brand { display: inline-flex; align-items: center; }
.site-header__logo img {
  display: block;
  /* Largeur seule : la hauteur suit le ratio du fichier, le dessin n'est
     jamais etire ni rogne. */
  width: 140px;
  height: auto;
  filter: brightness(0.74) saturate(1.12);
}

/* --- Demande de disponibilite ----------------------------------------------
   Un lien editorial, pas un pave encadre : meme taille et meme graisse que la
   navigation, une fleche fine, un filet qui se developpe au survol. */
.header-availability {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--c-charcoal);
  font-family: var(--font-hero);
  font-size: 11px;
  font-weight: var(--fw-medium);
  line-height: 14px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
.header-availability::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -8px;
  height: 1px;
  background-color: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 450ms cubic-bezier(0.22, 1, 0.36, 1);
}
.header-availability:hover::after,
.header-availability:focus-visible::after,
.header-availability[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left center;
}
.header-availability__arrow {
  flex: 0 0 auto;
  width: 16px;
  height: auto;
  transition: transform 450ms cubic-bezier(0.22, 1, 0.36, 1);
}
.header-availability:hover .header-availability__arrow,
.header-availability:focus-visible .header-availability__arrow {
  transform: translateX(5px);
}
.header-availability__short { display: none; }


/* --- Variante de l'accueil -------------------------------------------------
   Tant que la barre est posee sur la sequence, elle disparait completement :
   aucun fond, aucun filet, aucune ombre, aucun flou. Seuls le texte et le logo
   subsistent, en blanc. La video reste donc integralement visible, du premier
   pixel de la fenetre jusqu'au dernier.

   Un seul composant, une seule structure HTML : seules la couleur et le fond
   changent. Les pages interieures gardent le bandeau blanc. */
body[data-page="accueil"] .site-header {
  background-color: transparent;
  border-bottom: 0;
  box-shadow: none;
  backdrop-filter: none;
  transition:
    background-color 400ms var(--ease),
    border-color 400ms var(--ease);
}

/* Tout passe en blanc. La lisibilite vient de cette couleur et d'une ombre
   tres basse, jamais d'un voile pose sur l'image. */
body[data-page="accueil"] .nav__link,
body[data-page="accueil"] .header-availability {
  color: #fff;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.28);
}
body[data-page="accueil"] .site-header__logo img {
  /* Variante blanche du fichier de marque : le dore est trop sombre sur une
     image claire, et le logo n'existe qu'en un seul fichier. */
  filter: brightness(0) invert(1);
}
body[data-page="accueil"] .menu-toggle__bars span {
  background-color: #fff;
}
body[data-page="accueil"] .menu-toggle {
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.3));
}

/* --- Sortie de la sequence -------------------------------------------------
   La barre etant fixe, elle survit au hero et se retrouve sur des sections
   claires, ou du blanc sur blanc ne se lit plus. Un seul etat, pose par le
   script des que la sequence a quitte l'ecran : la barre reprend exactement
   l'apparence qu'elle a sur les pages interieures. Aucune autre logique de
   defilement n'est introduite. */
body[data-page="accueil"]:not(.menu-open) .site-header.is-solid {
  background-color: #fff;
  border-bottom: 1px solid rgba(8, 20, 38, 0.08);
}
body[data-page="accueil"] .site-header.is-solid .nav__link,
body[data-page="accueil"] .site-header.is-solid .header-availability {
  color: var(--c-charcoal);
  text-shadow: none;
}
body[data-page="accueil"]:not(.menu-open) .site-header.is-solid .site-header__logo img {
  filter: brightness(0.74) saturate(1.12);
}
/* Le menu plein ecran garde ses propres barres claires : l'etat solide ne
   s'applique qu'au repos, jamais par-dessus le panneau ouvert. */
body[data-page="accueil"]:not(.menu-open) .site-header.is-solid .menu-toggle__bars span {
  background-color: var(--c-charcoal);
}
body[data-page="accueil"] .site-header.is-solid .menu-toggle { filter: none; }

@media (prefers-reduced-motion: reduce) {
  body[data-page="accueil"] .site-header { transition-duration: 0.01ms; }
}

@media (prefers-reduced-motion: reduce) {
  .nav__link::after,
  .header-availability::after,
  .header-availability__arrow { transition-duration: 0.01ms; }
}

/* --- Bouton menu mobile --------------------------------------------------- */

.menu-toggle {
  display: none;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
  /* Il occupe la colonne de gauche : le retrait negatif aligne son trait sur
     l'axe des liens, pas sur le bord de sa zone de clic. */
  margin-left: calc(var(--sp-3) * -1);
}
.menu-toggle__bars { position: relative; width: 24px; height: 12px; }
.menu-toggle__bars span {
  position: absolute;
  left: 0;
  width: 100%; height: 1.5px;
  background-color: var(--text-strong);
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
.menu-toggle__bars span:nth-child(1) { top: 0; }
.menu-toggle__bars span:nth-child(2) { bottom: 0; }

body.menu-open .menu-toggle__bars span { background-color: var(--c-ivory); }
body.menu-open .menu-toggle__bars span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
body.menu-open .menu-toggle__bars span:nth-child(2) { transform: translateY(-5px) rotate(-45deg); }

/* --- Menu plein ecran -----------------------------------------------------
   La logique reste entierement dans `navigation.js` : il pose `is-open`,
   verrouille le defilement, piege le focus et remet `inert`. Ce bloc ne fait
   que la presentation, et n'a besoin que de cette seule classe.

   Le registre est celui de la liste « Ce qui est compris » de la page
   « La villa » : une ligne pleine largeur par entree, un numero discret, un
   filet, et un devoilement par la gauche. Ce n'est pas une citation
   decorative : c'est le meme composant, transpose sur le charbon.
   -------------------------------------------------------------------------- */

.mobile-menu {
  /* Trois reglages pour tout le panneau. Le corps de la liste d'abord.

     La borne haute n'est pas un gout : c'est une mesure. « Tarifs et
     disponibilites » est le libelle le plus long, et la colonne qui lui reste
     une fois le numero pose fait 294px sur un telephone de 375. Il y tient
     sur UNE ligne jusqu'a 35px, passe a deux des 36, et le panneau deborde a
     44. La valeur mediane s'y cale : 35px a 375 — contre 24 auparavant, soit
     un tiers de plus — et un plafond a 48 pour que la tablette ne devienne
     pas une affiche.

     Le second terme est borne par la HAUTEUR autant que par la largeur : une
     tablette couchee de 900x700 est large mais basse, et le seul calcul en vw
     y donnait 48px, soit 764px de contenu pour 700px de panneau — la liste
     se mettait a defiler. `min()` retient la plus contraignante des deux
     mesures.

     CORRECTION. Les 35px avaient ete mesures en Helvetica Neue, la police de
     l'appareil sur lequel le reglage a ete fait. Elle n'est pas embarquee
     dans le site : ailleurs — Windows, Android — c'est Inter qui prend le
     relais, et Inter est 11,5 % plus large. « Tarifs et disponibilites »
     debordait alors aux trois largeurs de telephone :

         largeur   colonne   en Helvetica   en Inter
           360px     280px        289 ✗        323 ✗
           375px     294px        289 ✓        323 ✗
           430px     344px        335 ✓        373 ✗

     Le coefficient descend donc de 9,3 a 8,4vw, seule valeur qui tienne dans
     les DEUX rendus aux trois largeurs. A 375px cela fait 31,5px — contre 24
     a l'origine, donc toujours un tiers de plus.

     Le PLANCHER descend avec lui, faute de quoi il annulerait la correction :
     un plancher a 35px l'aurait emporte sur les 31,5px calcules, et rien
     n'aurait change. A 1,75rem il ne mord qu'en dessous de 333px de large,
     c'est-a-dire nulle part. */
  --menu-corps:  clamp(1.75rem, min(8.4vw, 5.2vh), 3rem);
  --menu-pas:    54ms;    /* decalage d'une ligne a la suivante */
  --menu-course: 560ms;   /* duree du devoilement d'une ligne */

  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  background-color: var(--c-charcoal);
  color: var(--c-ivory);
  display: flex;
  flex-direction: column;
  padding: calc(var(--header-h) + clamp(24px, 6vh, 52px)) var(--gutter)
           max(var(--sp-7), env(safe-area-inset-bottom, 0px));
  /* Un telephone couche ne tient pas six lignes de 46px : la liste defile
     dans le panneau plutot que d'etre coupee. `contain` empeche le geste de
     se propager a la page verrouillee derriere. */
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur) var(--ease),
    visibility 0s linear var(--dur);
}
.mobile-menu.is-open {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

/* Le lit de maquis suit jusque dans le menu. Le trait du dessin est presque
   noir : sur le charbon il faut l'inverser pour qu'il existe, puis le ramener
   tres bas — plus bas encore que sur l'ivoire, ou il se defend seul. */
.mobile-menu::before {
  content: "";
  /* `fixed` et non `absolute` : le panneau peut defiler (telephone couche),
     et une texture qui defile avec la liste se remarquerait. Le panneau ne
     porte aucune transformation, le repere est donc la fenetre — c'est-a-dire
     exactement son propre rectangle. */
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image: url("../brand/fond-maquis.svg");
  background-size: 820px 820px;
  background-position: center;
  background-repeat: repeat;
  filter: invert(1);
  /* Plus bas que sur l'ivoire (0,07) : la sur le charbon le trait est clair
     sur fond sombre, donc il porte davantage a opacite egale. Mesure a l'oeil
     sur le panneau ouvert. */
  opacity: 0.035;
}

/* Le texte passe devant la texture. La colonne cesse de s'etirer au-dela du
   telephone : sur une tablette de 900px, le filet sous « Contact » faisait
   834px pour un mot de 36, et le bouton autant — ce n'est plus une
   navigation, c'est une banniere. La pile reste calee a gauche, comme partout
   ailleurs sur le site. Sans effet sous 520px, ou la colonne est deja plus
   etroite. */
.mobile-menu__nav,
.mobile-menu__foot { position: relative; max-width: 30rem; }

.mobile-menu__nav {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--rule-on-dark);
}

.mobile-menu__link {
  display: flex;
  /* Alignement sur la ligne de base : le numero se pose sur la premiere ligne
     du libelle, quels que soient les deux corps. */
  align-items: baseline;
  gap: clamp(14px, 4.4vw, 22px);
  padding-block: clamp(13px, 1.9vh, 22px);
  border-bottom: 1px solid var(--rule-on-dark);
  color: var(--c-ivory);
  min-height: 44px;
}

.mobile-menu__num {
  flex: 0 0 auto;
  width: 2.2em;
  font-family: var(--font-azimut, var(--font-hero));
  font-size: 11px;
  font-weight: var(--fw-medium);
  line-height: 14px;
  letter-spacing: 1.2px;
  color: var(--c-ivory-40);
  font-variant-numeric: lining-nums tabular-nums;
}

.mobile-menu__name {
  font-family: var(--font-hero);
  font-size: var(--menu-corps);
  font-weight: var(--fw-light);
  line-height: 1.04;
  letter-spacing: -1.2px;
}

/* Retour a l'appui. Il n'y a pas de survol sur un telephone : sans cet etat,
   toucher une ligne ne produit rien jusqu'au changement de page. L'opacite
   est posee sur la LIGNE, qui ne porte aucune animation d'entree — les
   masques sont sur ses enfants — donc les deux ne se genent jamais. */
.mobile-menu__link { transition: opacity var(--dur-fast) var(--ease); }
.mobile-menu__link:active { opacity: 0.55; }

/* Page courante : le numero passe a l'or avec le libelle, sinon le trait se
   lirait comme un residu de la ligne precedente. */
.mobile-menu__link[aria-current="page"] { color: var(--c-gold); }
.mobile-menu__link[aria-current="page"] .mobile-menu__num { color: var(--c-gold); }

/* --- Entree progressive ---------------------------------------------------
   Le masque est pose sur les ENFANTS de la ligne, jamais sur la ligne : sur
   elle il emporterait aussi le filet, qui doit rester en place.

   `transition: none` dans l'etat FERME est deliberé. Une transition declaree
   sur l'etat d'arrivee se joue a l'aller ; declaree sur l'etat de depart,
   elle se rejouerait aussi au retour, et la fermeture replierait les six
   lignes a l'envers sous un panneau deja efface. Ici l'etat ferme est repose,
   pas rejoue. */
.mobile-menu__link > *,
.mobile-menu__foot > * {
  opacity: 0;
  transition: none;
}
.mobile-menu__link > * { clip-path: inset(0 102% 0 0); }
.mobile-menu__foot > * { transform: translateY(12px); }

.mobile-menu.is-open .mobile-menu__link > * {
  clip-path: inset(0 0 0 0);
  opacity: 1;
  transition:
    clip-path var(--menu-course) var(--ease-out) var(--menu-retard, 0ms),
    opacity 240ms linear var(--menu-retard, 0ms);
}
/* Le libelle part un souffle apres son numero : la ligne se lit de gauche a
   droite au lieu de s'ouvrir d'un bloc. Meme valeur que sur « La villa ». */
.mobile-menu.is-open .mobile-menu__name {
  transition-delay: calc(var(--menu-retard, 0ms) + 90ms);
}

/* Le pied ne se devoile pas par la gauche : un bouton pleine largeur balaye
   se lirait comme un chargement. Il monte et se pose, apres la derniere
   ligne. */
.mobile-menu.is-open .mobile-menu__foot > * {
  opacity: 1;
  transform: none;
  transition:
    opacity 420ms linear var(--menu-retard, 0ms),
    transform 520ms var(--ease-out) var(--menu-retard, 0ms);
}

/* La cascade, en clair : rang de la ligne x le pas. Six lignes, six rangs —
   ecrits plutot que calcules en JavaScript, puisque rien ici ne depend d'une
   mesure. */
.mobile-menu__nav > :nth-child(1) { --menu-i: 0; }
.mobile-menu__nav > :nth-child(2) { --menu-i: 1; }
.mobile-menu__nav > :nth-child(3) { --menu-i: 2; }
.mobile-menu__nav > :nth-child(4) { --menu-i: 3; }
.mobile-menu__nav > :nth-child(5) { --menu-i: 4; }
.mobile-menu__nav > :nth-child(6) { --menu-i: 5; }
.mobile-menu__foot                { --menu-i: 6; }
.mobile-menu__nav > *,
.mobile-menu__foot { --menu-retard: calc(var(--menu-i, 0) * var(--menu-pas)); }

.mobile-menu__foot {
  margin-top: auto;
  padding-top: var(--sp-7);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.mobile-menu__meta {
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  color: var(--c-ivory-70);
  line-height: var(--lh-secondary);
}
.mobile-menu__meta a { border-bottom: 1px solid var(--c-gold-40); }

/* --- L'en-tete pendant que le panneau est ouvert ---------------------------
   Le panneau couvre `inset: 0` a `--z-menu`, donc AU-DESSUS de l'en-tete :
   la croix de fermeture etait recouverte et ne repondait plus au doigt.
   Verifie avant correction : `elementFromPoint` au centre du bouton renvoyait
   le panneau, et un clic reel a cet endroit ne fermait rien. Il ne restait
   que la touche Echap — et il n'y a pas de touche Echap sur un telephone —
   ou taper un lien, ce qui quitte la page.

   L'en-tete repasse donc devant, mais depouillee : plus de fond, plus de
   filet, et la disponibilite retiree, le panneau portant deja son propre
   appel a l'action en pleine largeur. Restent la croix et la marque, en
   blanc, sur le charbon. */
body.menu-open .site-header {
  z-index: calc(var(--z-menu) + 1);
  background-color: transparent;
  border-bottom-color: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
body.menu-open .site-header__logo img {
  /* La variante blanche du fichier de marque, comme au pied de page. */
  filter: brightness(0) invert(1);
  opacity: 0.92;
}
/* `visibility` plutot qu'`opacity` : le lien sort aussi de l'ordre de
   tabulation et de l'arbre d'accessibilite, au lieu de rester la, invisible
   et focalisable, sous un panneau qui a le sien. */
body.menu-open .site-header__actions { visibility: hidden; }

/* --- Retour au toucher -----------------------------------------------------
   Sans cette ligne, toucher un lien fait clignoter le rectangle bleu par
   defaut de WebKit — `rgba(51, 181, 229, 0.4)`, un bleu systeme qui n'a rien
   a voir avec l'ivoire et l'or du site, et qui se voit a CHAQUE appui.
   On garde un retour, mais dans la palette : un voile de charbon. */
html { -webkit-tap-highlight-color: rgba(32, 35, 31, 0.10); }

@media (prefers-reduced-motion: reduce) {
  .mobile-menu__link > *,
  .mobile-menu__foot > *,
  .mobile-menu.is-open .mobile-menu__link > *,
  .mobile-menu.is-open .mobile-menu__foot > * {
    clip-path: none;
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --- CTA mobile persistant ------------------------------------------------ */

.mobile-cta {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-sticky);
  display: none;
  padding: var(--sp-3) var(--gutter) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background-color: rgba(244, 240, 231, 0.94);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--rule);
  transform: translateY(110%);
  transition: transform var(--dur) var(--ease);
}
.mobile-cta.is-visible { transform: none; }
.mobile-cta.is-hidden { transform: translateY(110%); }

/* ==========================================================================
   3. Media : cadres, ratios, legendes
   ========================================================================== */

/* Cadre a ratio fixe : evite tout decalage de mise en page pendant le chargement */
/* `.frame` est souvent porte par un <span> : sans `display: block`, il reste
   inline et `aspect-ratio` ne s applique pas du tout. C etait la cause des
   rangees de hauteurs inegales dans la grille d apercus de l accueil, ou une
   photographie verticale etirait toute sa rangee. */
.frame {
  display: block;
  position: relative;
  overflow: hidden;
  background-color: var(--bg-sunken);
  border-radius: var(--radius);
}
.frame > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
}

.frame--4x3   { aspect-ratio: 4 / 3; }
.frame--3x4   { aspect-ratio: 3 / 4; }
.frame--3x2   { aspect-ratio: 3 / 2; }
.frame--2x3   { aspect-ratio: 2 / 3; }
.frame--16x9  { aspect-ratio: 16 / 9; }
.frame--1x1   { aspect-ratio: 1 / 1; }
.frame--5x7   { aspect-ratio: 5 / 7; }
.frame--tall  { aspect-ratio: 4 / 5; }
.frame--auto  { aspect-ratio: auto; }
.frame--auto > img { height: auto; }

/* Fondu discret a l'apparition des images */
.frame > img.is-loading { opacity: 0; }
.frame > img {
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}

.figure { display: flex; flex-direction: column; gap: var(--sp-3); }
.figure__caption {
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
  line-height: var(--lh-secondary);
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
}


/* Zoom tres discret au survol, uniquement sur les vignettes cliquables */
@media (hover: hover) {
  .zoomable:hover > img { transform: scale(1.028); }
}

/* ==========================================================================
   4. Compositions editoriales asymetriques
   ========================================================================== */

/* Deux colonnes explicites, jamais douze.
   Avec une grille de 12 colonnes et un placement par `grid-column`, un bloc
   place en colonnes 1-5 apres un bloc place en colonnes 7-12 est rejete sur
   une nouvelle ligne : c'est ce qui creusait la diagonale vide. Ici les deux
   colonnes sont declarees une fois pour toutes et la ligne est imposee. */
.editorial {
  display: grid;
  /* 42/53 et non 38/57 : a 38 la colonne de texte se terminait 180px avant le
     bas de la photographie et paraissait abandonnee, pendant que le titre se
     brisait en lignes trop courtes. */
  grid-template-columns: minmax(0, 42fr) minmax(0, 53fr);
  /* Rangee 1 calee sur le bloc de texte, rangee 2 absorbant tout le reste.
     Sans cette declaration, les deux rangees etaient `auto` et la
     photographie, qui les traverse, repartissait sa hauteur excedentaire
     entre les deux : la rangee du lien etait poussee vers le bas et l appel a
     l action se retrouvait a plus de 120px du paragraphe. */
  grid-template-rows: auto 1fr;
  column-gap: var(--grid-gap);
  row-gap: var(--sp-6);
  align-items: start;
}

/* --------------------------------------------------------------------------
   Paire editoriale : deux blocs de largeurs inegales.
   Volontairement definie en classes plutot qu'en `grid-column` pose a la main :
   une valeur ecrite en style inline ne peut pas etre reprise par une media
   query, ce qui casserait la mise en page sur les petits ecrans.
   -------------------------------------------------------------------------- */
.duo {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--grid-gap);
  align-items: center;
}
.duo--wide-right { grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); }
.duo--wide-left  { grid-template-columns: minmax(0, 7fr) minmax(0, 4fr); }
.duo--even       { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.duo--top        { align-items: start; }

.duo > * { min-width: 0; }


/* ==========================================================================
   5. Signature chiffree
   ========================================================================== */

/* Six cellules d une seule et meme famille graphique. Les quatre premieres
   portent un chiffre, les deux dernieres un mot : leur role visuel est le
   meme, donc leur corps, leur ligne de base et la position de leur sous-
   libelle doivent l etre aussi. La cellule est une grille de deux rangees,
   la premiere calee sur la valeur la plus haute : les six sous-libelles
   demarrent ainsi exactement sur le meme axe. */
.signature {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  border-top: 1px solid var(--rule-strong);
  border-bottom: 1px solid var(--rule-strong);
}
@supports (grid-template-rows: subgrid) {
  .signature { grid-template-rows: auto auto; }
  .signature__item { display: grid; grid-row: span 2; grid-template-rows: subgrid; row-gap: 0; }
}
.signature__item {
  padding: var(--sp-6) var(--sp-4) var(--sp-6) 0;
  border-right: 1px solid var(--rule);
}
.signature__item:last-child { border-right: 0; }
.signature__value {
  font-family: var(--font-text);
  font-weight: var(--fw-light);
  font-size: var(--fs-figure);
  line-height: var(--lh-display);
  color: var(--text-strong);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  /* La valeur se cale en bas de sa rangee : chiffres et mots partagent alors
     la meme ligne de base, quelle que soit leur chasse. */
  align-self: end;
}
/* « Piscine » et « Spa » ne sont pas des nombres mais jouent le meme role :
   ils gardent donc exactement le meme corps. Seule l approche est detendue,
   un mot ne se resserre pas comme une suite de chiffres. */
.signature__value--word { letter-spacing: -0.005em; }
.signature__label {
  margin-top: var(--sp-3);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  color: var(--text-body);
  line-height: var(--lh-secondary);
  /* 14ch coupait « niveaux independants » en deux lignes alors que la cellule
     etait assez large pour le tenir. La mesure suit maintenant la cellule ;
     seules les colonnes reellement etroites provoquent un retour. */
  max-width: 22ch;
  align-self: start;
}

/* ==========================================================================
   6. Liste de faits (equipements, informations pratiques)
   ========================================================================== */

.facts { display: grid; gap: 0; }
.facts__row {
  display: grid;
  grid-template-columns: minmax(9rem, 15rem) 1fr;
  gap: var(--sp-5);
  padding-block: var(--sp-4);
  border-top: 1px solid var(--rule-soft);
  align-items: baseline;
}
.facts__row:last-child { border-bottom: 1px solid var(--rule-soft); }
.facts__key {
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.facts__val { font-size: var(--fs-small); font-weight: var(--fw-regular); line-height: var(--lh-secondary); color: var(--text-body); }

/* Colonnes d'equipements, sans icones ni cartes */
.amenities {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--grid-gap) var(--sp-7);
}
.amenities__group h3 {
  font-family: var(--font-text);
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-ui);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-strong);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--rule);
}
.amenities__group li {
  padding-block: var(--sp-2);
  font-size: var(--fs-small);
  line-height: var(--lh-secondary);
  color: var(--text-body);
  border-bottom: 1px solid var(--rule-soft);
}

/* ==========================================================================
   9. Galerie : filtres, grille, lightbox
   ========================================================================== */

/* Deux niveaux : huit categories principales, puis les six chambres lorsque
   « Chambres » est actif. Sur mobile chaque rangee defile horizontalement
   plutot que de s'empiler sur quatre lignes de boutons. */
/* Onglets textuels, pas une rangee de boutons de formulaire. La galerie est
   editoriale : le filtre actif se marque par un filet dore, comme la
   sous-navigation de la page Villa, jamais par un aplat noir plein.

   Le defilement horizontal n est PAS conditionne a un palier de media query.
   Il l etait a 1024px, alors que la rangee cesse de tenir sur une ligne des
   1340px : entre les deux, elle se cassait en deux lignes sans possibilite de
   defiler. Declare en permanence, le conteneur ne defile que lorsqu il deborde
   reellement, quelle que soit la largeur. */
.filters {
  display: flex;
  flex-wrap: nowrap;
  gap: 0 var(--sp-6);
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.filters::-webkit-scrollbar { display: none; }
.filters .filter { flex: 0 0 auto; scroll-snap-align: start; }
.filters--sub {
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
}
.filters--sub[hidden] { display: none; }

/* Une seule ligne de base sous la rangee : les filtres n en portent plus
   chacun une. */
.filter-bar { position: relative; border-bottom: 1px solid var(--rule); }
/* Indice de debord, uniquement quand la rangee deborde vraiment : un fondu
   vers la couleur de fond, retire par le script des qu on atteint la fin. */
.filter-bar::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 2.5rem;
  pointer-events: none;
  background: linear-gradient(to right, rgba(244, 240, 231, 0), var(--bg-page));
  opacity: 1;
  transition: opacity var(--dur) var(--ease);
}
.filter-bar.is-end::after { opacity: 0; }

.filter {
  /* Cible tactile : jamais moins de 44px, sur toutes les largeurs. */
  min-height: 44px;
  padding-block: var(--sp-3);
  padding-inline: 0;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background-color: transparent;
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-button);
  line-height: var(--lh-ui);
  color: var(--text-body);
  white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.filter:hover { color: var(--text-strong); }
/* L etat actif se lit par la couleur ET par le filet : jamais par la seule
   couleur. */
.filter[aria-pressed="true"] {
  color: var(--text-strong);
  font-weight: var(--fw-medium);
  border-bottom-color: var(--c-gold);
}
.filter--sub { color: var(--text-muted); font-size: var(--fs-fine); }
/* Le compteur accompagne le libelle sans lui disputer l attention. */
.filter__count {
  margin-left: var(--sp-2);
  font-size: var(--fs-fine);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.filter[aria-pressed="true"] .filter__count { color: var(--text-body); }

/* Grille en colonnes : respecte les ratios natifs, ne recadre pas tout pareil */
.gallery-grid {
  columns: 3;
  column-gap: var(--sp-4);
  margin-top: var(--sp-6);
}
.gallery-item {
  break-inside: avoid;
  margin-bottom: var(--sp-4);
  display: block;
  width: 100%;
  position: relative;
  cursor: zoom-in;
  /* Fond de reserve, pris dans la palette : la vignette porte deja ses
     dimensions natives, donc sa place est reservee, mais la case restait
     blanche jusqu au chargement. Ce fond evite le clignotement sans rien
     animer et sans squelette. */
  background-color: var(--bg-sunken);
  border-radius: var(--radius);
  overflow: hidden;
}
.gallery-item .frame { background-color: var(--bg-sunken); }
.gallery-item[hidden] { display: none; }

/* Affordance : la vignette doit se lire comme ouvrable, sans icone, sans
   voile permanent et sans deplacer ses voisines. Le zoom est contenu par le
   `overflow: hidden` du bouton, donc la geometrie de la grille ne bouge pas. */
@media (hover: hover) {
  .gallery-item img { transition: transform 250ms var(--ease-out); }
  .gallery-item:hover img { transform: scale(1.015); }
}
.gallery-item:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .gallery-item img,
  .gallery-item:hover img { transition: none; transform: none; }
}

.gallery-empty {
  padding: var(--sp-9) 0;
  text-align: center;
  color: var(--text-muted);
}

/* `is-quiet` : le compteur reste dans le DOM et reste annonce par `aria-live`,
   mais disparait visuellement quand « Tout » est actif, ou le filtre porte deja
   le nombre. Il n est pas masque par `display: none`, ce qui le retirerait de
   l arbre d accessibilite. */
.gallery-count.is-quiet {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.gallery-count {
  margin-top: var(--sp-5);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Chargement progressif : la grille n'expose pas d'emblee 94 vignettes,
   ni dans le parcours visuel, ni dans le parcours clavier. */
.gallery-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-8);
}
.gallery-more[hidden] { display: none; }
.gallery-more__note {
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* --- Lightbox ------------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
  display: flex;
  flex-direction: column;
  /* Fond totalement opaque : sur mobile, aucune photographie de la page
     situee derriere ne doit transparaitre sous l'image ouverte. */
  background-color: #141613;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease), visibility 0s linear var(--dur);
}
.lightbox.is-open { opacity: 1; visibility: visible; transition-delay: 0s; }

.lightbox__bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--gutter);
  color: var(--c-ivory-70);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  font-variant-numeric: tabular-nums;
}

.lightbox__stage {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--gutter);
  min-height: 0;
}
.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
.lightbox__img.is-ready { opacity: 1; }

/* Indicateur de chargement : un filet dore qui tourne, visible uniquement
   tant que la grande version n'est pas decodee. */
.lightbox__spinner {
  position: absolute;
  top: 50%; left: 50%;
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid rgba(244, 240, 231, 0.22);
  border-top-color: var(--c-gold);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease);
  /* L'animation ne tourne QUE pendant le chargement. Declaree ici, elle
     tournait en permanence sur un element invisible, visionneuse fermee :
     une animation infinie garde le compositeur eveille et se paie en
     batterie sur telephone, pour quelque chose que personne ne voit. */
}
.lightbox.is-loading .lightbox__spinner {
  opacity: 1;
  animation: lb-spin 900ms linear infinite;
}
@keyframes lb-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .lightbox__spinner {
    animation: none;
    border-color: rgba(244, 240, 231, 0.35);
    border-top-color: var(--c-gold);
  }
}

.lightbox__foot {
  flex: 0 0 auto;
  padding: var(--sp-4) var(--gutter) calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
  color: var(--c-ivory-70);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  text-align: center;
  min-height: 3.5rem;
}

.lightbox__btn {
  width: 48px; height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--rule-on-dark);
  border-radius: var(--radius);
  color: var(--c-ivory);
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.lightbox__btn:hover { background-color: rgba(244, 240, 231, 0.12); border-color: var(--c-ivory-40); }
.lightbox__btn[disabled] { opacity: 0.3; }

.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}
.lightbox__nav--prev { left: var(--gutter); }
.lightbox__nav--next { right: var(--gutter); }

/* ==========================================================================
   10. Formulaires
   ========================================================================== */

.form { display: grid; gap: var(--field-gap); }

.field { display: flex; flex-direction: column; gap: var(--sp-2); }
/* Label : meme motif que `.eyebrow`, meme taille, meme graisse, meme approche. */
.field__label {
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-eyebrow);
  line-height: var(--lh-ui);
  text-transform: uppercase;
  color: var(--text-muted);
}
.field__req { color: var(--terracotta-ink); margin-left: 0.15em; }

.input,
.select,
.textarea {
  width: 100%;
  /* Meme hauteur que les boutons : les deux se cotoient partout. */
  min-height: var(--btn-h);
  padding-block: var(--sp-3);
  padding-inline: var(--sp-4);
  background-color: var(--bg-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-ui);
  color: var(--text-strong);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

/* Safari sur iPhone AGRANDIT la page des qu'on touche un champ dont le corps
   est inferieur a 16px — et il ne la reduit pas ensuite. Le visiteur se
   retrouve dans un formulaire zoome, decale, qu'il doit pincer pour revenir.
   Treize champs etaient a 15px : les neuf du formulaire de demande, les deux
   compteurs et les deux dates de la page Tarifs.

   Ce n'est pas un choix de composition, c'est une contrainte du navigateur :
   l'echelle typographique du site n'est pas touchee, seule la taille rendue
   des champs monte d'un pixel sur telephone. */
@media (max-width: 767.98px) {
  .input,
  .select,
  .textarea { font-size: 16px; }
}
.input:hover, .select:hover, .textarea:hover { border-color: var(--c-charcoal-16); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--c-maquis);
  background-color: #fff;
  box-shadow: 0 0 0 3px rgba(75, 88, 69, 0.12);
}
.textarea { min-height: 8.5rem; resize: vertical; line-height: var(--lh-body); }

.select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%2320231F' stroke-width='1.2' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-4) center;
  padding-right: var(--sp-7);
}

.field--error .input,
.field--error .select,
.field--error .textarea { border-color: var(--c-terracotta); }

.field__error {
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  color: var(--terracotta-ink);
  min-height: 0;
}
.field__hint { font-size: var(--fs-fine); font-weight: var(--fw-regular); line-height: var(--lh-secondary); color: var(--text-muted); }

.field-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--field-gap);
}

/* Case a cocher : cible tactile confortable */
.checkbox {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  cursor: pointer;
  padding-block: var(--sp-2);
}
.checkbox input {
  width: 20px; height: 20px;
  margin-top: 2px;
  accent-color: var(--c-maquis);
  cursor: pointer;
}
.checkbox span { font-size: var(--fs-fine); font-weight: var(--fw-regular); line-height: var(--lh-secondary); color: var(--text-body); }
.checkbox a { border-bottom: 1px solid var(--rule-gold); }

/* Retours d'envoi */
.form-status {
  padding: var(--sp-4) var(--sp-5);
  line-height: var(--lh-secondary);
  border-left: 2px solid var(--c-maquis);
  background-color: var(--bg-sunken);
  font-size: var(--fs-small);
}
.form-status--error { border-left-color: var(--c-terracotta); }

.form-success {
  border: 1px solid var(--rule);
  border-top: 2px solid var(--c-maquis);
  padding: var(--pad-card);
  background-color: var(--bg-raised);
}
.form-success h3 { margin-bottom: var(--gap-title); }

.recap {
  margin-top: var(--sp-5);
  border-top: 1px solid var(--rule-soft);
}
.recap__row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--rule-soft);
  font-size: var(--fs-small);
  line-height: var(--lh-secondary);
}
.recap__row dt { color: var(--text-muted); }
.recap__row dd { color: var(--text-strong); text-align: right; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   11. Calendrier et estimation
   ========================================================================== */

.calendar { display: flex; flex-direction: column; gap: var(--sp-5); }

.calendar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
}
.calendar__title {
  font-family: var(--font-text);
  font-weight: var(--fw-medium);
  font-size: var(--fs-heading-card);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  color: var(--text-strong);
  /* Le titre couvre deux mois : « Septembre 2026 a octobre 2026 ».
     `capitalize` majusculait chaque mot, y compris le mot de liaison et le
     second mois. Seule la premiere lettre doit l'etre. */
  text-transform: none;
}
.calendar__title::first-letter { text-transform: uppercase; }
.calendar__nav { display: flex; gap: var(--sp-2); }
.calendar__navbtn {
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  color: var(--text-strong);
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.calendar__navbtn:hover:not([disabled]) { background-color: var(--c-charcoal); border-color: var(--c-charcoal); color: var(--c-ivory); }
.calendar__navbtn[disabled] { opacity: 0.3; cursor: not-allowed; }

.calendar__months {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-8);
}
.calendar--compact .calendar__months { grid-template-columns: minmax(0, 1fr); }

.month__name {
  font-family: var(--font-text);
  font-weight: var(--fw-medium);
  font-size: var(--fs-heading-s);
  line-height: var(--lh-title);
  color: var(--text-strong);
  text-align: center;
  margin-bottom: var(--sp-4);
  text-transform: capitalize;
}

.month__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }

.month__dow {
  /* 12px : plancher typographique du site. Meme motif que tous les autres
     micro-labels en capitales : 12px, 500, meme approche. */
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-ui);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: center;
  padding-bottom: var(--sp-3);
}

.day {
  position: relative;
  aspect-ratio: 1;
  min-height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  font-variant-numeric: tabular-nums;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--text-body);
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.day--empty { visibility: hidden; }

/* Etats : sur demande / ferme / reserve / passe */
.day--request {
  cursor: pointer;
  background-color: var(--bg-raised);
  border-color: rgba(32, 35, 31, 0.14);
  color: var(--text-strong);
}
.day--request:hover {
  border-color: var(--c-maquis);
  background-color: #fff;
}
.day--request:focus-visible { z-index: 2; }

.day--closed,
.day--booked,
.day--past {
  color: var(--text-muted);
  cursor: not-allowed;
}
.day--past { opacity: 0.38; }
.day--closed { background-color: var(--bg-sunken); opacity: 0.7; }
.day--booked { background-color: var(--bg-sunken); }

.day--closed::after,
.day--booked::after {
  content: "";
  position: absolute;
  left: 22%; right: 22%;
  height: 1px;
  background-color: currentColor;
  transform: rotate(-18deg);
  opacity: 0.7;
}
.day--booked::after { background-color: var(--c-terracotta); opacity: 1; }

/* Bornes du sejour : pleines et arrondies vers l'exterieur de la plage. */
.day--start,
.day--end {
  background-color: var(--c-charcoal);
  border-color: var(--c-charcoal);
  color: var(--c-ivory);
  font-weight: var(--fw-medium);
  z-index: 1;
}
.day--start { border-start-start-radius: 999px; border-end-start-radius: 999px; }
.day--end   { border-start-end-radius: 999px; border-end-end-radius: 999px; }

/* Nuits comprises dans la selection */
.day--between {
  background-color: var(--c-stone);
  border-color: var(--c-stone);
  color: var(--text-strong);
  border-radius: 0;
}
/* Survol pendant le choix de la date de depart */
.day--preview {
  background-color: rgba(213, 200, 182, 0.5);
  border-color: transparent;
  color: var(--text-strong);
}

/* Legende — placee juste au-dessus du calendrier */
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-5);
  padding-bottom: var(--sp-4);
  margin-bottom: var(--sp-2);
  border-bottom: 1px solid var(--rule-soft);
}
.legend__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  color: var(--text-muted);
}
.legend__swatch {
  width: 14px; height: 14px;
  border-radius: 1px;
  border: 1px solid rgba(32, 35, 31, 0.24);
  flex: 0 0 auto;
}
.legend__swatch--request { background-color: var(--bg-raised); }
.legend__swatch--selected { background-color: var(--c-charcoal); border-color: var(--c-charcoal); }
.legend__swatch--range { background-color: var(--c-stone); border-color: var(--c-stone); }
.legend__swatch--closed { background-color: var(--bg-sunken); opacity: 0.7; }
.legend__swatch--booked { background-color: var(--bg-sunken); border-color: var(--c-terracotta); }

/* --- Panneau d'estimation ------------------------------------------------- */

.estimate {
  border: 1px solid var(--rule);
  border-top: 2px solid var(--c-charcoal);
  padding: var(--pad-card);
  background-color: var(--bg-raised);
  position: sticky;
  top: calc(var(--header-h) + var(--sp-5));
}
.estimate__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-4);
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--rule-soft);
  font-size: var(--fs-small);
  line-height: var(--lh-secondary);
}
.estimate__row dt { color: var(--text-muted); }
.estimate__row dd { font-variant-numeric: tabular-nums; color: var(--text-strong); }
.estimate__row--discount dd { color: var(--c-maquis); }
.estimate__row--total {
  border-bottom: 0;
  padding-top: var(--sp-4);
  margin-top: var(--sp-2);
  border-top: 1px solid var(--rule);
}
.estimate__row--total dt { color: var(--text-strong); font-weight: var(--fw-medium); }
.estimate__row--total dd {
  font-family: var(--font-text);
  font-weight: var(--fw-medium);
  font-size: var(--fs-heading-card);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  color: var(--text-strong);
}
.estimate__note {
  margin-top: var(--sp-4);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
  line-height: var(--lh-secondary);
}
.estimate__empty { font-size: var(--fs-small); line-height: var(--lh-secondary); color: var(--text-muted); }

/* ==========================================================================
   12. Pied de page
   ========================================================================== */

/* Le pied de page est plus sombre que la bande d'appel a l'action qui le
   precede, et un filet dore fin marque la limite : les deux zones ne forment
   plus un seul grand aplat noir. */
/* Le pied de page etait nettement plus haut que son contenu ne le demandait :
   le retrait haut valait la respiration d une section entiere et chaque lien
   portait une cible tactile de 40px doublee d un retrait de rangee. Environ
   100px ont ete repris sur des vides, sans rien compacter. */
.site-footer {
  padding-block: var(--sp-7) var(--sp-6);
  background-color: #171A16;
  border-top: 1px solid var(--c-gold-20);
}

/* La troisieme colonne porte nettement moins de contenu que les deux autres :
   elle est resserree pour ne pas se lire comme une colonne vide. */
.site-footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 0.9fr);
  gap: var(--grid-gap);
  padding-bottom: var(--sp-7);
  border-bottom: 1px solid var(--rule-on-dark);
}
.site-footer__brand img {
  width: 190px;
  filter: brightness(0) invert(1);
  opacity: 0.92;
}
.site-footer__addr {
  margin-top: var(--sp-5);
  font-size: var(--fs-small);
  color: var(--c-ivory-70);
  line-height: var(--lh-secondary);
  font-style: normal;
}
/* Le lien courriel prenait toute la largeur de la colonne : son filet
   depassait largement l adresse et ressemblait a un champ de saisie. Un
   `inline` simple ramene le soulignement a la longueur du texte. */
.site-footer__addr a {
  display: inline;
  border-bottom: 1px solid var(--c-gold-40);
}
.site-footer__addr a:focus-visible { outline-offset: 2px; }
.site-footer__addr a:hover { border-bottom-color: var(--c-ivory); }

.site-footer h2 {
  font-family: var(--font-text);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-eyebrow);
  line-height: var(--lh-ui);
  text-transform: uppercase;
  color: var(--c-gold);
  margin-bottom: var(--sp-5);
}
.site-footer__nav li { padding-block: 0; }
.site-footer__nav a {
  font-size: var(--fs-small);
  line-height: var(--lh-secondary);
  color: var(--c-ivory-70);
  transition: color var(--dur) var(--ease);
  display: inline-flex;
  align-items: center;
  /* 36px suffisent a une cible tactile confortable dans une liste serree ;
     40px sur chaque lien plus un retrait de rangee gonflaient la colonne. */
  min-height: 36px;
}
.site-footer__nav a:hover { color: var(--c-ivory); }

.site-footer__cta { margin-top: var(--sp-5); }

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-top: var(--sp-4);
  font-size: var(--fs-fine);
  font-weight: var(--fw-regular);
  line-height: var(--lh-secondary);
  color: var(--c-ivory-40);
}
.site-footer__legal { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); }
.site-footer__legal a:hover { color: var(--c-ivory); }

/* Emplacement du futur selecteur de langue (masque tant qu'il n'existe pas) */
.lang-switch[hidden] { display: none; }

/* ==========================================================================
   13. Fonds sombres : lisibilite des petits textes
   La graisse 300 tient sur ivoire, pas sur charbon : a 14 et 15px, un texte
   clair sur fond sombre perd visuellement du trait. Ces deux regles sont les
   seules du site a remonter la graisse en fonction du fond, et elles ne
   touchent que le petit texte : les grands corps restent en 300.
   ========================================================================== */
.on-dark .fine,
.on-dark .site-footer__addr,
.site-footer .fine,
.site-footer__addr,
.site-footer__nav a,
.site-footer__legal a,
.mobile-menu__meta { font-weight: var(--fw-regular); }
