/* =========================================================================
   Villa Damencourt — feuille de style
   =========================================================================
   Reprise telle quelle de la version d'origine, à une inversion près, et à
   quelques ajouts nécessaires au passage en pages statiques.

   L'INVERSION. La règle d'apparition était écrite ainsi :

       [data-anim="on"] [data-reveal] { opacity: 0 }

   Autrement dit : tout ce qui doit apparaître au défilement est INVISIBLE
   par défaut, et n'existe que si le JavaScript vient le révéler. Sur ce
   site — qui téléchargeait React et Babel avant de pouvoir exécuter la
   moindre ligne — cela voulait dire plusieurs secondes de page vide, et une
   page définitivement vide si quoi que ce soit échouait en chemin. C'est ce
   que l'on voyait en disant que « les textes ne s'affichent pas ».

   Désormais le contenu est visible par défaut. C'est le JavaScript qui,
   une fois en place et seulement alors, pose « hz-anime » sur <html> et
   prend la main sur les apparitions. Sans lui, on lit la page ; avec lui,
   elle s'anime. Jamais l'inverse.
   ========================================================================= */

body { margin: 0; background: #F7F2EA; text-wrap: pretty; -webkit-font-smoothing: antialiased; }
a { color: #B3552F; text-decoration: none; }
a:hover { color: #8B3F21; }
::selection { background: #E5C9B4; }
@keyframes hzRise { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
@keyframes hzFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes hzVeil { from { opacity: 1; } to { opacity: 0; } }
@keyframes hzBurns { from { transform: scale(1); } to { transform: scale(1.09); } }
@keyframes hzDrop { 0% { transform: translateY(-100%); } 60%, 100% { transform: translateY(100%); } }
@keyframes hzWipe { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
/* Ne masque QUE si le JavaScript a pris la main (voir js/site.js). */
/* Masqué en attendant d'être révélé — MAIS avec un filet posé en CSS, et
   non en JavaScript. L'animation « hzSecours » ne fait rien pendant deux
   secondes et demie, puis remet l'opacité à 1 quoi qu'il arrive. Un
   observateur qui ne se déclenche pas, un minuteur ralenti par le
   navigateur, un script qui échoue : aucun de ces cas ne peut plus laisser
   un bloc invisible. C'est le navigateur lui-même qui garantit le retour,
   sans qu'une ligne de JavaScript ait à s'exécuter. */
html.hz-anime [data-reveal]:not(.hz-in) {
  opacity: 0;
  animation: hzSecours 0s 2.5s forwards;
}
@keyframes hzSecours { to { opacity: 1; } }
html.hz-anime [data-reveal].hz-in { animation: hzRise 1000ms both cubic-bezier(0.16, 0.84, 0.24, 1); }
html.hz-anime [data-reveal="wipe"].hz-in { animation: hzWipe 1100ms both cubic-bezier(0.16, 0.84, 0.24, 1), hzFade 600ms both; }
@keyframes hzPage { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* Parcours clavier : aucun style de focus n'existait, la navigation au clavier
   était donc invisible. Le contour reprend l'ocre de la marque. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid #B3552F;
  outline-offset: 3px;
  border-radius: 2px;
}
button, a, input, textarea, select { -webkit-tap-highlight-color: transparent; }

/* Un lien d'évitement, visible seulement au clavier. */
.hz-skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: #2B241E; color: #FFF8EF; padding: 14px 22px;
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
}
.hz-skip:focus { left: 12px; top: 12px; color: #FFF8EF; }

/* Transition douce d'une page à l'autre. */
html.hz-anime .hz-page { animation: hzPage 520ms both cubic-bezier(0.16, 0.84, 0.24, 1); }

/* Confort de lecture et cibles tactiles. */
input, textarea, select, button { font-size: 16px; }   /* évite le zoom auto sur iOS */
button { min-height: 44px; }
@media (hover: hover) {
  a, button { transition: color 300ms ease, background 300ms ease, border-color 300ms ease, transform 300ms ease; }
}

@media (prefers-reduced-motion: reduce) {
  html.hz-anime [data-reveal] { opacity: 1; animation: none !important; }
  html.hz-anime .hz-page { animation: none !important; }
  * { animation-duration: 0.001ms !important; }
}

/* ---- ajouts du passage en statique -------------------------------------- */

/* Remplace l'élément <image-slot> du runtime : même boîte, même cadrage.
   Le rapport de forme vient du style en ligne, comme avant ; l'image le
   remplit en « cover ». */
.hz-img { position: relative; overflow: hidden; }
.hz-img picture { display: contents; }
.hz-img img { position: absolute; inset: 0; width: 100%; height: 100%;
              object-fit: cover; display: block; }

/* La vidéo, désormais servie depuis ce serveur.

   Elle DÉRIVE TANT QU'ELLE NE JOUE PAS. Sur un appareil qui refuse la lecture
   automatique — économie d'énergie, mode données réduites, onglet ouvert en
   arrière-plan — un <video> muet n'affiche que son affiche, immobile. Le
   visiteur voit alors un écran mort là où on lui promettait du mouvement, et
   il défile sans rien remarquer. Un lent Ken Burns tient le rôle en
   attendant ; il s'arrête dès que la vidéo prend le relais, et ne se cumule
   donc jamais avec elle. */
.hz-video {
  display: block;
  animation: hzBurns 30s var(--hz-ease, ease-in-out) infinite alternate;
}
.hz-video.hz-joue { animation: none; }
@media (prefers-reduced-motion: reduce) { .hz-video { animation: none; } }

/* Personne n'ayant demandé d'animation ne doit en subir. */
@media (prefers-reduced-motion: reduce) {
  html.hz-anime [data-reveal] { opacity: 1 !important; animation: none !important; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ---- visionneuse --------------------------------------------------------- */
.hz-visio {
  position: fixed; inset: 0; z-index: 90; display: flex;
  align-items: center; justify-content: center; flex-direction: column; gap: 1rem;
  background: rgba(24, 20, 17, .94); padding: clamp(1rem, 4vw, 3rem);
  opacity: 0; transition: opacity .3s ease;
}
.hz-visio[data-ouvert] { opacity: 1; }
.hz-visio img { max-width: 100%; max-height: 82vh; object-fit: contain; }
.hz-visio__leg { color: #F7F2EA; font-size: .86rem; letter-spacing: .04em; margin: 0; opacity: .82; }
.hz-visio__x {
  position: absolute; top: 1rem; right: 1.2rem; z-index: 2;
  background: none; border: 0; color: #F7F2EA; font-size: 2rem; line-height: 1;
  cursor: pointer; padding: .4rem .7rem; min-width: 44px; min-height: 44px;
}

/* =========================================================================
   Mise en page mobile
   =========================================================================
   Ce site calculait sa mise en page EN JAVASCRIPT : React lisait la largeur
   de la fenêtre et posait des styles en ligne en conséquence. En figeant le
   DOM rendu à 1280 px pour en faire des pages statiques, j'ai figé les
   valeurs du bureau — et sur téléphone les grilles restaient à quatre ou six
   colonnes, comprimées dans 350 px. La page ne débordait pas, ce qui explique
   qu'un contrôle de débordement ne l'ait pas vu ; elle était simplement
   illisible.

   Les valeurs ci-dessous portent « !important » parce qu'un style en ligne
   l'emporte sur une feuille : c'est le seul moyen de reprendre la main sur ce
   que React avait inscrit dans l'attribut. Chaque sélecteur vise une grille
   précise, relevée sur les seize pages — et non toutes les grilles : celle du
   calendrier doit garder ses sept colonnes, et les petites grilles internes
   (icône + texte) sont déjà justes.
   ========================================================================= */
@media (max-width: 860px) {

  /* Les duos texte + image, et le pied de page en trois blocs : l'un sous
     l'autre. Côte à côte, chaque colonne tombait sous 170 px. */
  [style*="minmax(0px, 4fr) minmax(0px, 6fr)"],
  [style*="minmax(0px, 5fr) minmax(0px, 7fr)"],
  [style*="minmax(0px, 7fr) minmax(0px, 5fr)"],
  [style*="minmax(0px, 5fr) minmax(0px, 3fr)"],
  [style*="repeat(3, 1fr)"],
  [style*="repeat(2, minmax(0px, 1fr))"] {
    grid-template-columns: 1fr !important;
  }

  /* Les vignettes et les chiffres-clés supportent deux colonnes : ce sont des
     blocs courts, et une seule colonne étirerait la page inutilement. */
  [style*="repeat(4, 1fr)"],
  [style*="repeat(6, 1fr)"] {
    grid-template-columns: repeat(2, 1fr) !important;
  }

  /* Le tableau des tarifs : quatre colonnes deviennent deux, saison et
     période sur la première ligne, prix et minimum sur la seconde. Cette
     règle vient après la précédente, dont le sélecteur « 1fr 1fr » l'aurait
     sinon emporté par simple ordre d'écriture. */
  [style*="1.4fr 1.6fr 1fr 1fr"] {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 4px 24px !important;
  }

  /* Navigation. Les sept liens tenaient 707 px dans une barre de 390 : ils
     se chevauchaient. Ils passent dans un tiroir, ouvert par un burger. */
  nav > [data-dc-tpl="10"] { display: none !important; }
  .hz-burger { display: inline-flex !important; }
}

/* ---- burger et tiroir ---------------------------------------------------- */
.hz-burger {
  display: none; width: 44px; height: 44px; flex: 0 0 auto;
  align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer; color: inherit; padding: 0;
}
.hz-burger i {
  display: block; width: 22px; height: 1px; background: currentColor; position: relative;
}
.hz-burger i::before, .hz-burger i::after {
  content: ""; position: absolute; left: 0; width: 22px; height: 1px; background: currentColor;
}
.hz-burger i::before { top: -7px; }
.hz-burger i::after  { top: 7px; }

.hz-tiroir {
  position: fixed; inset: 0; z-index: 60; background: #F7F2EA; color: #2B241E;
  display: flex; flex-direction: column; justify-content: center; gap: .4rem;
  padding-inline: clamp(24px, 8vw, 80px);
  opacity: 0; visibility: hidden; transition: opacity .35s ease, visibility .35s;
}
/* Ouvert par l'ancre, donc sans JavaScript. */
.hz-tiroir:target { opacity: 1; visibility: visible; }
.hz-tiroir a {
  font-family: Marcellus, serif; font-size: clamp(26px, 7vw, 40px);
  color: #2B241E; padding: .28rem 0; text-decoration: none;
}
.hz-tiroir__x {
  position: absolute; top: 18px; right: 20px; background: none; border: 0;
  font-size: 2rem; line-height: 1; color: #2B241E; cursor: pointer;
  min-width: 44px; min-height: 44px;
}
@media (prefers-reduced-motion: reduce) { .hz-tiroir { transition: none; } }

@media (max-width: 860px) {

  /* La galerie. Ses vignettes portent un placement en dur — « span 2 »,
     « span 3 », « span 4 » — calculé pour six colonnes. Ramener la grille à
     deux colonnes ne suffisait donc pas : les enfants recréaient des colonnes
     implicites, et l'on retombait à quatre pistes inégales de 47 px. On leur
     rend leur placement automatique. */
  [style*="repeat(6, 1fr)"] > [style*="grid-column"] {
    grid-column: auto !important;
  }

  /* Les deux mois du calendrier, côte à côte, laissaient 140 px à chacun pour
     sept colonnes : la grille débordait de son parent. L'un sous l'autre.
     Le sélecteur nomme la propriété entière, sans quoi « 1fr 1fr » attraperait
     aussi la ligne de tarifs « 1.4fr 1.6fr 1fr 1fr ». */
  [style*="grid-template-columns: 1fr 1fr"] {
    grid-template-columns: 1fr !important;
  }
  [style*="repeat(7, 1fr)"], [style*="repeat(7, 1fr)"] > * {
    min-width: 0 !important;
  }
}

/* Le titre de l'accueil. Son plancher — 50 px — avait été choisi pour un
   écran large : « Villa Damencourt » y occupait 368 px, soit plus que la
   largeur d'un iPhone SE. Le plancher descend et la part variable monte, de
   sorte que le titre garde sa présence sans jamais être coupé. */
@media (max-width: 430px) {
  [style*="clamp(50px, 9vw, 130px)"] {
    font-size: clamp(34px, 10.5vw, 130px) !important;
  }
}

/* La barre de navigation sur téléphone.
   Une fois les sept liens rangés dans le tiroir, il restait quatre éléments :
   le nom, le burger, la langue et « Réserver ». À 375 px ils réclamaient
   396 px, et le bouton se trouvait coupé au bord droit. On resserre les
   marges, l'espacement et le nom — sans jamais toucher au bouton d'action
   lui-même, qui reste la cible la plus large de la barre. */
@media (max-width: 430px) {
  nav[data-dc-tpl="8"] {
    padding-inline: 14px !important;
    gap: 8px !important;
  }
  nav > a[data-dc-tpl="9"] {
    font-size: 13px !important;
    letter-spacing: 0.07em !important;
  }
  nav > a[data-dc-tpl="14"] {
    font-size: 10px !important;
    letter-spacing: 0.1em !important;
    padding: 12px 13px !important;
  }
  .hz-burger { width: 38px; }
}
@media (max-width: 344px) {
  /* iPhone SE et anciens Android : le nom passe en abrégé plutôt que d'être
     tronqué. La page reste identifiée, le bouton reste entier. */
  nav > a[data-dc-tpl="9"] { font-size: 11.5px !important; }
  nav > a[data-dc-tpl="14"] { padding: 12px 10px !important; }
}

/* Les deux actions de bas de tiroir : plus discrètes que les pages, mais
   pleinement lisibles — 4.5:1 sur le fond crème. */
.hz-tiroir__2 {
  font-family: Jost, sans-serif !important;
  font-size: 13px !important;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: #6B5F52 !important;
  padding-top: 1rem !important;
}
.hz-tiroir a:not(.hz-tiroir__2) + .hz-tiroir__2 {
  margin-top: 1.1rem; border-top: 1px solid #D8CEC0;
}

/* L'affiche du héros, et la vidéo qui vient par-dessus.

   La vidéo est TRANSPARENTE tant qu'elle ne joue pas. C'est le point : un
   navigateur qui refuse la lecture automatique dessine son propre bouton de
   lecture sur l'élément vidéo, et c'est ce bouton qu'il fallait presser.
   Transparent, il ne se voit plus — et ce que l'on voit à la place est
   l'affiche, qui dérive. Une lecture refusée devient alors indiscernable
   d'une lecture qui part.

   Elle ne reçoit pas non plus les clics : c'est la page entière qui écoute
   (voir js/site.js), et un clic n'importe où relance la lecture. Mieux vaut
   cela qu'une cible invisible au milieu de l'écran. */
.hz-affiche { display: contents; }
.hz-affiche img {
  animation: hzFade 1.6s ease both,
             hzBurns 30s var(--hz-ease, ease-in-out) infinite alternate;
}
.hz-video {
  opacity: 0;
  pointer-events: none;
  animation: none;
  transition: opacity 900ms ease;
}
.hz-video.hz-joue { opacity: 1; }
/* La dérive de l'affiche s'arrête quand la vidéo la recouvre : c'est alors
   elle qui porte le mouvement. Si :has() venait à manquer, l'affiche
   continuerait de dériver sous une vidéo opaque — invisible, sans dommage. */
:has(> .hz-video.hz-joue) .hz-affiche img { animation: hzFade 1.6s ease both; }
@media (prefers-reduced-motion: reduce) {
  .hz-affiche img { animation: none; }
  .hz-video { transition: none; }
}

/* La carte de réservation du héros, sur téléphone.
   Elle occupait 321 px — 38 % d'un écran de 844 — et masquait la vidéo
   qu'elle surplombe : ses quatre blocs, dessinés pour tenir sur une ligne à
   940 px, s'empilaient chacun sur la sienne. « Hôtes » n'en prenait d'ailleurs
   que 153 sur 350, sa bordure droite flottant au milieu du vide.
   Les trois champs reviennent sur une seule ligne et les hauteurs se
   resserrent ; le bouton garde toute la largeur, car c'est l'action. */
@media (max-width: 700px) {
  [style*="max-width: 940px"] > [style*="flex: 1 1 190px"],
  [style*="max-width: 940px"] > [style*="flex: 0 1 116px"] {
    flex: 1 1 0 !important;
    min-width: 0 !important;
    padding: 13px 10px !important;
  }
  [style*="max-width: 940px"] > [style*="flex: 0 1 116px"] {
    border-right: 0 !important;
  }
  /* Le bouton prend une rangée à lui seul. Sans cela sa base de 200 px
     l'emportait sur les trois champs mis à « 1 1 0 », qui tombaient à 23 px
     de large : les libellés débordaient de leur bloc. */
  [style*="max-width: 940px"] > [style*="flex: 1 1 200px"] {
    flex: 1 1 100% !important;
    padding-block: 17px !important;
  }
}

/* Le sur-titre du héros — « Le Moule · Grande-Terre, Guadeloupe ».
   Il demande 350 px sur une ligne, ce qu'un écran de 390 px offre tout juste.
   En dessous il se coupait au trait d'union de « Grande-Terre », ce qui se
   lisait mal. L'interlettrage y perd un peu : c'est ce qui coûte le moins à
   l'allure, la lettre restant plus lisible qu'un mot brisé en deux. */
@media (max-width: 389px) {
  [style*="letter-spacing: 0.36em"] {
    letter-spacing: 0.15em !important;
    font-size: 10px !important;
  }
}

/* Les boutons d'appel devenus des liens.
   Un <button> est « inline-block », un <a> est « inline ». La différence
   n'est pas cosmétique : un élément inline ignore les marges verticales, et
   son rembourrage comme sa bordure se peignent HORS de la ligne, par-dessus
   ce qui l'entoure. Le « Réserver » du pied de page, haut de 47 px pour une
   ligne de 22, recouvrait ainsi l'adresse électronique juste au-dessus — sur
   tous les téléphones, et c'était ma conversion qui l'avait causé. */
.hz-cta { display: inline-block; }
