/* ============================================================
   VILLA 39 — VISTABELLA GOLF · design tokens & base system
   ============================================================ */

:root {
  /* --- color: STONE & BRONZE — one warm neutral family, bronze as
     the only accent. The photography carries all the colour. --- */
  --pine:        #1e1c19;  /* ink — dark sections */
  --pine-soft:   #2b2825;
  --pine-line:   rgba(236, 232, 225, 0.14);
  --limestone:   #ece8e1;  /* light sections */
  --limestone-2: #dbd5cb;
  --sand:        #cfc7ba;  /* hairlines on light */
  --grove:       #9a7f5f;  /* bronze — accent on dark */
  --grove-dark:  #756046;  /* deep bronze — accent on light, buttons */
  --fairway:     #8a7358;
  --fairway-dark:#6b573f;
  --pool:        #3f4653;  /* dusk slate — suntimer twilight tint only */
  --white:       #ffffff;
  --ink:         #1e1c19;
  --ink-70:      rgba(30, 28, 25, 0.72);
  --ink-45:      rgba(30, 28, 25, 0.5);
  --cream-70:    rgba(236, 232, 225, 0.72);
  --cream-45:    rgba(236, 232, 225, 0.5);

  /* --- type --- */
  --font-display: "Fraunces", "Iowan Old Style", serif;
  --font-body: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Space Mono", "SFMono-Regular", Menlo, monospace;

  /* --- spacing scale (standard density) --- */
  --sp-1: 0.5rem;
  --sp-2: 1rem;
  --sp-3: 1.5rem;
  --sp-4: 2rem;
  --sp-5: 3rem;
  --sp-6: 4rem;
  --sp-7: 6rem;
  --sp-8: 8rem;

  /* --- motion --- */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-expo: cubic-bezier(0.19, 1, 0.22, 1);
  --dur-fast: 220ms;
  --dur-med: 420ms;
  --dur-slow: 900ms;

  --container: 1320px;
  --radius: 2px;
}

/* ============================================================
   RESET
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

body, h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
input, textarea, select { font: inherit; color: inherit; }

body {
  background: var(--limestone);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

:focus-visible {
  outline: 2px solid var(--grove);
  outline-offset: 3px;
}

/* ============================================================
   TYPE SCALE
   ============================================================ */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
.eyebrow::before {
  content: "";
  width: 1.6em;
  height: 1px;
  background: currentColor;
  opacity: 0.6;
}

h1, .h1 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 380;
  font-style: italic;
  font-size: clamp(2.8rem, 8vw, 7rem);
  line-height: 0.98;
  letter-spacing: -0.01em;
  /* Fraunces character axes: soft terminals + a touch of wonk
     give the display type a hand-drawn, one-of-one feel */
  font-variation-settings: "SOFT" 60, "WONK" 1;
}
h2, .h2 {
  font-family: var(--font-display);
  font-weight: 460;
  font-size: clamp(1.9rem, 4.2vw, 3.4rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  font-variation-settings: "SOFT" 60, "WONK" 1;
}
h3, .h3 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.25rem, 2vw, 1.6rem);
  line-height: 1.2;
  font-variation-settings: "SOFT" 60, "WONK" 1;
}

/* ============================================================
   KLEURVERLOOP OP TITELS ("sheen")

   Twee kleuren die traag in elkaar overlopen, geklemd op de
   letters zelf. Techniek: een brede gradient, met
   background-clip: text zichtbaar gemaakt door de tekst zelf
   doorzichtig te maken, en een geanimeerde background-position
   die het verloop heen en weer laat golven.

   De twee kleuren staan in --sheen-a en --sheen-b, zodat lichte
   en donkere secties hun eigen paar kunnen zetten zonder deze
   regel te dupliceren.

   Toegepast via selectoren in plaats van een class in de HTML:
   elke kop bestaat vier keer (NL/EN/ES/FR), dus dat scheelt
   tientallen handmatige aanpassingen — en nieuwe koppen doen
   automatisch mee.
   ============================================================ */
:root {
  --sheen-a: var(--limestone);
  --sheen-b: var(--grove);
}
/* op licht: inkt die naar diep brons trekt */
.section--light { --sheen-a: var(--ink); --sheen-b: var(--grove-dark); }

.site-nav__logo,
#footer-logo,
#hero-title,
#hero-title.has-words .word,
.section-head h2,
.section-head h2.has-words .word,
.guest__gate-inner h2 {
  background-image: linear-gradient(100deg,
    var(--sheen-a) 0%,
    var(--sheen-b) 25%,
    var(--sheen-a) 50%,
    var(--sheen-b) 75%,
    var(--sheen-a) 100%);
  background-size: 300% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* vult ook kindelementen die zelf een color zetten, zoals de
     "39" in het logo — anders blijven die massief gekleurd */
  -webkit-text-fill-color: transparent;
  animation: sheenShift 9s ease infinite;

  /* Staartletters (j, g, p, y) redden.
     background-clip: text schildert het verloop alleen binnen het
     vak van het element. De koppen hebben een strakke regelafstand
     (1.05), dus de staart van een j steekt daar onderuit — en zonder
     achtergrond op die plek wordt dat stuk letter onzichtbaar.
     Extra ruimte onder én boven vergroot het geschilderde vak; de
     negatieve marge haalt die ruimte weer uit de opmaak, zodat er
     niets verschuift. */
  padding-block: 0.3em 0.36em;
  margin-block: -0.3em -0.36em;
}

/* Is de kop door JavaScript in losse woorden gesplitst, dan draagt
   elk woord zijn eigen verloop en houdt de kop zelf er geen meer.
   Reden: die woorden animeren hun eigen opacity bij het onthullen.
   Zou het verloop op de kop blijven staan, dan wordt het in een
   andere laag getekend dan de vervagende woorden en is per browser
   verschillend of het netjes mee vervaagt. Zo is het eenduidig. */
.section-head h2.has-words,
#hero-title.has-words {
  background-image: none;
  animation: none;
}

/* De hero-titel staat over een foto. Daar wisselt de achtergrond per
   pixel van felle lucht tot donkere gevel, dus geen enkele tekstkleur
   is overal even leesbaar — dat gold al voor de effen kalksteenkleur
   die hier eerst stond. Een zachte donkere gloed achter de letters
   tilt ze van het beeld zonder als schaduw op te vallen. Werkt ook
   met background-clip: text, omdat de gloed áchter de (doorzichtige)
   letters wordt getekend. */
#hero-title,
#hero-title.has-words .word {
  text-shadow: 0 2px 20px rgba(20, 18, 16, 0.55);
}

@keyframes sheenShift {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* Zonder animatie oogt een bevroren verloop rommelig; dan liever
   één effen kleur. */
@media (prefers-reduced-motion: reduce) {
  .site-nav__logo,
  #footer-logo,
  .section-head h2,
  .guest__gate-inner h2 {
    background-image: none;
    animation: none;
    color: var(--sheen-a);
    -webkit-text-fill-color: var(--sheen-a);
  }
}
p.lead {
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  line-height: 1.6;
  max-width: 42ch;
}
.data-label {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
}

/* ============================================================
   LAYOUT
   ============================================================ */
.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--sp-3);
}
@media (min-width: 768px) {
  .container { padding-inline: var(--sp-5); }
}

.section {
  position: relative;
  padding-block: var(--sp-7);
}
@media (max-width: 767px) {
  .section { padding-block: var(--sp-6); }
}
.section--dark { background: var(--pine); color: var(--limestone); }
.section--light { background: var(--limestone); color: var(--ink); }

.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
  max-width: 46rem;
}
.section--dark .eyebrow { color: var(--grove); }
.section--light .eyebrow { color: var(--fairway-dark); }

.grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-5);
}
@media (min-width: 900px) {
  .grid-2 { grid-template-columns: 1fr 1fr; gap: var(--sp-6); align-items: center; }
}

/* physical <img> background system: image sits absolute, content sits above */
.bg-photo {
  position: relative;
  overflow: hidden;
  background: var(--pine);
}
.bg-photo > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  will-change: transform;
}
.bg-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.bg-photo .bg-photo__content {
  position: relative;
  z-index: 2;
}

/* ============================================================
   BUTTONS
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  min-height: 48px;
  padding: 0.9em 1.7em;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid currentColor;
  border-radius: var(--radius);
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: color var(--dur-med) var(--ease-expo), transform var(--dur-fast) var(--ease-out), border-color var(--dur-med) var(--ease-expo);
}
/* fill wipes in from the left — quieter than a color swap */
.btn::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.55s var(--ease-expo);
}
.btn:hover::before,
.btn:focus-visible::before {
  transform: scaleX(1);
  transform-origin: left;
}
.btn:active { transform: scale(0.97); }
/* deep bronze base keeps white label at 5.97:1; the wipe deepens
   to ink rather than swapping hue */
.btn-primary {
  background: var(--grove-dark);
  border-color: var(--grove-dark);
  color: var(--white);
}
.btn-primary::before { background: var(--ink); }
.btn-primary:hover { border-color: var(--ink); }
.btn-ghost-light { color: var(--limestone); border-color: var(--cream-45); }
.btn-ghost-light::before { background: var(--limestone); }
.btn-ghost-light:hover { color: var(--pine); border-color: var(--limestone); }
.btn-ghost-dark { color: var(--pine); border-color: var(--ink-45); }
.btn-ghost-dark::before { background: var(--pine); }
.btn-ghost-dark:hover { color: var(--limestone); border-color: var(--pine); }

/* ============================================================
   NAV
   ============================================================ */
.site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  padding: var(--sp-2) 0;
  transition: background var(--dur-med) var(--ease-out), padding var(--dur-med) var(--ease-out), border-color var(--dur-med) var(--ease-out);
  border-bottom: 1px solid transparent;
}
.site-nav.is-scrolled {
  background: rgba(30, 28, 25, 0.92);
  backdrop-filter: blur(10px);
  padding: var(--sp-1) 0;
  border-color: var(--pine-line);
}
.site-nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}
.site-nav__logo {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.3rem;
  color: var(--limestone);
  font-variation-settings: "SOFT" 60, "WONK" 1;
}
.site-nav__logo span { color: var(--grove); font-style: normal; }
.site-nav__links {
  display: none;
  gap: var(--sp-4);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
@media (min-width: 980px) {
  .site-nav__links { display: flex; }
}
.site-nav__links a {
  color: var(--cream-70);
  position: relative;
  padding-bottom: 4px;
  transition: color var(--dur-fast) var(--ease-out);
}
.site-nav__links a:hover { color: var(--limestone); }
/* underline draws in from the left, exits to the right —
   direction-aware, like a pen stroke */
.site-nav__links a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  height: 1px;
  width: 100%;
  background: var(--grove);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.5s var(--ease-expo);
}
.site-nav__links a:hover::after,
.site-nav__links a:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

.site-nav__right { display: flex; align-items: center; gap: var(--sp-2); }

.lang-switch { position: relative; }
.lang-switch__btn {
  display: flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--limestone);
  border: 1px solid var(--cream-45);
  border-radius: var(--radius);
  padding: 0.5em 0.8em;
  min-height: 44px;
}
.lang-switch__menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: var(--pine-soft);
  border: 1px solid var(--pine-line);
  border-radius: var(--radius);
  padding: 0.3em;
  display: flex;
  flex-direction: column;
  min-width: 130px;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.lang-switch.is-open .lang-switch__menu {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.lang-switch__menu button {
  text-align: left;
  padding: 0.6em 0.7em;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--cream-70);
  border-radius: var(--radius);
  min-height: 44px;
}
.lang-switch__menu button:hover { background: var(--pine); color: var(--limestone); }
.lang-switch__menu button[aria-current="true"] { color: var(--grove); }

.nav-toggle {
  display: flex;
  flex-direction: column;
  gap: 5px;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
}
@media (min-width: 980px) { .nav-toggle { display: none; } }
.nav-toggle span {
  width: 22px;
  height: 1.5px;
  background: var(--limestone);
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.nav-toggle.is-open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.is-open span:nth-child(2) { opacity: 0; }
.nav-toggle.is-open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.mobile-menu {
  position: fixed;
  inset: 0;
  background: var(--pine);
  z-index: 90;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--sp-5);
  transform: translateY(-100%);
  transition: transform var(--dur-med) var(--ease-in-out);
}
.mobile-menu.is-open { transform: translateY(0); }
.mobile-menu a {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 2rem;
  color: var(--limestone);
  padding: var(--sp-1) 0;
  border-bottom: 1px solid var(--pine-line);
  font-variation-settings: "SOFT" 60, "WONK" 1;
}

/* ============================================================
   HERO
   ============================================================ */
.hero {
  height: 100svh;
  min-height: 560px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: var(--limestone);
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(30,28,25,0.55) 0%, rgba(30,28,25,0.15) 32%, rgba(30,28,25,0.15) 55%, rgba(30,28,25,0.85) 100%);
  z-index: 1;
}
/* opening veil: the photo emerges from pine darkness while the
   establishing-shot zoom (JS) settles — cinema, not a page load */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--pine);
  opacity: 0;
  z-index: 1;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .hero::before { animation: heroVeil 2.4s var(--ease-expo) both; }
}
@keyframes heroVeil {
  from { opacity: 0.6; }
  to { opacity: 0; }
}
/* ============================================================
   INTRO-TITELKAART — zwart scherm, alleen de naam, dan de plaats,
   dan trekt hij op en verschijnt de foto.

   Vier duidelijk gescheiden fases. De eerste versie liet de kaart
   vervagen terwijl de hero-titel al verscheen — je zag dan twee
   keer "Villa 39" over elkaar en dat oogde rommelig. Nu verdwijnt
   de tekst eerst helemáál, met een zwarte pauze ertussen.

     250 ms  ① "Villa 39" komt uit de onscherpte (1100 ms)
    1150 ms  ② "Vistabella Golf · Costa Blanca"
    2350 ms  ③ de titel zakt naar beneden weg (600 ms)
    2470 ms     de plaatsnaam volgt, 120 ms later
    3070 ms  ── zwart beeld, niets (330 ms) ──
    3400 ms  ④ het zwart lost op (850 ms)
    3400 ms     de hero komt eronder al op zijn plaats, zodat de
                site compleet is zodra het zwart weg is

   VEILIGHEID — de kaart staat standaard op display:none en wordt
   alleen zichtbaar binnen de no-preference media query, waar hij
   meteen ook zijn eigen optrek-animatie meekrijgt. Kan die query
   niet gelden, dan is de kaart er simpelweg niet. Er is dus geen
   enkele toestand waarin hij blijft hangen en de site blokkeert.
   Het optrekken zit bewust in CSS en niet in JavaScript, om
   dezelfde reden.
   ============================================================ */
.intro-card {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--pine);
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  text-align: center;
  padding: var(--sp-3);
  pointer-events: none;
}
.intro-card__title {
  font-family: var(--font-display);
  font-variation-settings: "SOFT" 60, "WONK" 1;
  font-weight: 300;
  font-size: clamp(2.6rem, 9vw, 6rem);
  line-height: 1;
  color: var(--limestone);
  margin: 0;
}
.intro-card__title span { color: var(--grove); }
.intro-card__place {
  font-family: var(--font-mono);
  font-size: clamp(0.62rem, 1.6vw, 0.78rem);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--cream-70);
  margin: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .intro-card {
    display: flex;
    /* Een dissolve oogt het rustigst met een symmetrische easing.
       --ease-expo is sterk voorbelast: dat maakt een fade eerst
       abrupt en daarna slepend. */
    animation: introLift 850ms var(--ease-in-out) 3400ms forwards;
  }

  /* Twee animaties per regel: eerst binnenkomen, later naar beneden
     wegzakken. De tweede staat achteraan en wint zodra hij begint.

     De easing is bewust zachter dan het huisritme --ease-expo. Dat
     token legt 90 % van zijn beweging af in het eerste derde, wat
     hier als een schok leest in plaats van als een beweging.

     will-change zet de laag vooraf klaar, zodat de eerste beeldjes
     van de blur niet hoeven te wachten op een nieuwe textuur. */
  .intro-card__title,
  .intro-card__place {
    opacity: 0;
    will-change: transform, opacity;
    animation: introTextIn 1100ms cubic-bezier(0.215, 0.61, 0.355, 1) forwards,
               introTextOut 650ms cubic-bezier(0.45, 0, 1, 0.5) forwards;
  }
  .intro-card__title { animation-delay: 250ms, 2350ms; }
  .intro-card__place { animation-delay: 1150ms, 2470ms; }

  /* TWEE KEYFRAMES, GEEN TUSSENSTAP — dit is essentieel.
     CSS past de easing toe per segment, niet over de hele animatie.
     Zet je er een stap op 55 % tussen, dan vertraagt de beweging
     naar dat punt toe en versnelt daarna opnieuw. Dat voel je als
     een hapering halverwege. Eén segment = één vloeiende curve.

     GEEN filter: blur() — dat dwingt de browser elk beeldje opnieuw
     te tekenen. transform en opacity draaien op de grafische kaart
     en kunnen daardoor niet schokken. Dit is ook werkafspraak 5. */
  @keyframes introTextIn {
    from { opacity: 0; transform: translateY(24px) scale(0.985); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes introTextOut {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateY(44px) scale(0.99); }
  }
  @keyframes introLift {
    0%   { opacity: 1; visibility: visible; }
    99%  { opacity: 0; visibility: visible; }
    100% { opacity: 0; visibility: hidden; }
  }
}

/* ============================================================
   HERO-INTRO — gelaagde opening bovenop de bestaande sluier (2,4 s)
   en zoom (3,5 s).

   Alles hangt aan de klasse .has-intro, die JavaScript zet. Draait
   het script niet, dan staat de hero gewoon meteen leesbaar op het
   scherm — de begintoestanden bestaan alleen ónder die klasse.

   Tijdlijn — de naam komt eerst en krijgt het beeld even alleen;
   pas daarna volgt de rest. Die stilte tussen 1000 en 1050 ms is
   het hele punt: zonder pauze leest het als één blok in plaats van
   als een titel met gevolg.

   Volledig leesbaar na ± 2,5 s. Bewust nog altijd korter dan de
   4,6 s van het voorbeeld waarop dit geïnspireerd is — een huurder
   wil informatie, geen wachttijd.

   Deze tijden lopen bewust ónder het oplossende zwart (3400–4250 ms).
   Zo is de hero al compleet zodra de kaart weg is, in plaats van dat
   je eerst de foto ziet en de tekst daarna nog moet inkomen:

    3400 ms  "Villa"     (woord voor woord, uit onscherpte)
    3530 ms  "39"
    3550 ms  eyebrow
    3700 ms  ondertitel
    3850 ms  kerncijfers
    3900 ms  hoekmarkeringen tekenen zich
    4000 ms  knop
    4500 ms  stofdeeltjes komen op gang
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {

  /* --- hoekmarkeringen: als een zoeker of een bouwtekening --- */
  .hero__corners {
    position: absolute;
    inset: clamp(0.9rem, 2.4vw, 2rem);
    z-index: 2;
    pointer-events: none;
  }
  .hero__corner {
    position: absolute;
    width: 44px;
    height: 44px;
  }
  .hero__corner::before,
  .hero__corner::after {
    content: "";
    position: absolute;
    background: var(--grove);
    opacity: 0.55;
    transform: scale(0);
    transition: none;
    animation: cornerDraw 1100ms cubic-bezier(0.16, 0.72, 0.24, 1) forwards;
  }
  /* horizontaal been */
  .hero__corner::before { height: 1px; width: 100%; }
  /* verticaal been */
  .hero__corner::after  { width: 1px; height: 100%; }

  .hero__corner--tl { top: 0; left: 0; }
  .hero__corner--tr { top: 0; right: 0; }
  .hero__corner--bl { bottom: 0; left: 0; }
  .hero__corner--br { bottom: 0; right: 0; }

  .hero__corner--tl::before { top: 0; left: 0; transform-origin: 0 50%; }
  .hero__corner--tl::after  { top: 0; left: 0; transform-origin: 50% 0; }
  .hero__corner--tr::before { top: 0; right: 0; transform-origin: 100% 50%; }
  .hero__corner--tr::after  { top: 0; right: 0; transform-origin: 50% 0; }
  .hero__corner--bl::before { bottom: 0; left: 0; transform-origin: 0 50%; }
  .hero__corner--bl::after  { bottom: 0; left: 0; transform-origin: 50% 100%; }
  .hero__corner--br::before { bottom: 0; right: 0; transform-origin: 100% 50%; }
  .hero__corner--br::after  { bottom: 0; right: 0; transform-origin: 50% 100%; }

  .hero__corner--tl::before { animation-delay: 3900ms; }
  .hero__corner--tl::after  { animation-delay: 3970ms; }
  .hero__corner--tr::before { animation-delay: 4040ms; }
  .hero__corner--tr::after  { animation-delay: 4110ms; }
  .hero__corner--br::before { animation-delay: 4180ms; }
  .hero__corner--br::after  { animation-delay: 4250ms; }
  .hero__corner--bl::before { animation-delay: 4320ms; }
  .hero__corner--bl::after  { animation-delay: 4390ms; }

  @keyframes cornerDraw {
    from { transform: scale(0); }
    to   { transform: scale(1); }
  }

  /* --- stofdeeltjes in het licht --- */
  .hero__mote {
    position: absolute;
    z-index: 2;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: var(--limestone);
    opacity: 0;
    pointer-events: none;
    animation: moteDrift 18s var(--ease-in-out) infinite;
  }
  @keyframes moteDrift {
    0%   { transform: translate3d(0, 0, 0);          opacity: 0; }
    15%  {                                            opacity: 0.5; }
    50%  { transform: translate3d(14px, -38px, 0);    opacity: 0.28; }
    85%  {                                            opacity: 0.42; }
    100% { transform: translate3d(-6px, -76px, 0);    opacity: 0; }
  }

  /* --- titel woord voor woord ---
     Zelfde twee regels als bij de titelkaart hierboven: twee
     keyframes zonder tussenstap, en geen blur. */
  .hero.has-intro #hero-title .word {
    display: inline-block;
    opacity: 0;
    will-change: transform, opacity;
    /* Twee animaties naast elkaar: de entree én het kleurverloop.
       Deze selector is specifieker dan die van het verloop, dus als
       hier alleen de entree stond zou het verloop stilvallen. De
       entree krijgt zijn getrapte vertraging, het verloop start
       meteen. */
    animation: heroWordAppear 950ms cubic-bezier(0.215, 0.61, 0.355, 1) forwards,
               sheenShift 9s ease infinite;
    animation-delay: calc(3400ms + var(--w, 0) * 130ms), 0ms;
  }
  @keyframes heroWordAppear {
    from { opacity: 0; transform: translateY(24px) scale(0.96); }
    to   { opacity: 1; transform: none; }
  }

  /* De rest van de hero (eyebrow, ondertitel, cijfers, knop) heeft
     zijn eigen entree die al langer bestaat — zie "hero load
     choreography" verderop. Die is daar opnieuw getimed zodat hij
     ná de titelkaart valt. Hier dus bewust niets: twee systemen op
     dezelfde elementen zou elkaar tegenwerken. */
}

.hero__content {
  position: relative;
  z-index: 2;
  padding-bottom: var(--sp-6);
}
.hero__top {
  position: absolute;
  top: var(--sp-6);
  left: 0; right: 0;
  z-index: 2;
  display: flex;
  justify-content: center;
}
.hero__facts { margin-top: var(--sp-4); }
.hero__facts-set {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) clamp(1.5rem, 4vw, 3.5rem);
}
/* phones get a designed 2x2 grid, not a squeezed row */
@media (max-width: 560px) {
  .hero__facts-set {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-3) var(--sp-2);
  }
}
.hero-fact {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
  padding-left: 0.85em;
  border-left: 2px solid var(--grove);
}
.hero-fact strong {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: clamp(1.5rem, 3.2vw, 2.3rem);
  line-height: 1;
  color: var(--limestone);
}
.hero-fact small {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--cream-70);
}
.hero__scroll {
  position: absolute;
  bottom: var(--sp-3);
  right: var(--sp-3);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.6em;
  writing-mode: vertical-rl;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cream-70);
}
.hero__scroll::after {
  content: "";
  width: 1px;
  height: 40px;
  background: var(--cream-45);
  animation: scrollLine 2.2s var(--ease-in-out) infinite;
}
@keyframes scrollLine {
  0% { transform: scaleY(0); transform-origin: top; }
  50% { transform: scaleY(1); transform-origin: top; }
  50.01% { transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}
@media (max-width: 767px) {
  .hero__scroll { display: none; }
}

/* --- hero load choreography: één samenhangende entree, puur CSS.
       De globale reduced-motion regel maakt hier instant van.

       De vertragingen liggen ná de titelkaart (die op 2200 ms begint
       op te trekken). Dit is het énige systeem dat deze elementen
       animeert — leg er geen tweede naast, ze zouden elkaar
       tegenwerken.

       Puur CSS en zonder JavaScript-klasse, dus dit werkt ook als
       het script niet draait. --- */
@media (prefers-reduced-motion: no-preference) {
  .hero__content .eyebrow { animation: heroRise 1s var(--ease-expo) 3550ms both; }
  .hero__content h1 { animation: heroTitle 1.4s var(--ease-expo) 3400ms both; }
  .hero__content .lead { animation: heroRise 1.05s var(--ease-expo) 3700ms both; }
  .hero__facts { animation: heroRise 1.05s var(--ease-expo) 3850ms both; }
  .hero__cta { animation: heroRise 1.05s var(--ease-expo) 4000ms both; }
  .hero__scroll { animation: heroFade 1.6s var(--ease-expo) 4300ms both; }

  /* Is de titel door JavaScript in woorden gesplitst, dan neemt de
     woord-voor-woord animatie het over van heroTitle hierboven —
     anders lopen beide tegelijk over hetzelfde element. */
  .hero.has-intro .hero__content h1 { animation: none; opacity: 1; }
}
@keyframes heroRise {
  from { opacity: 0; transform: translateY(26px); }
  to { opacity: 1; transform: none; }
}
@keyframes heroTitle {
  from { opacity: 0; transform: translateY(0.32em) skewY(1.4deg); clip-path: inset(-12% 0 100% 0); }
  to { opacity: 1; transform: none; clip-path: inset(-12% 0 -18% 0); }
}
@keyframes heroFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ============================================================
   ABOUT / INTRO
   ============================================================ */
.about__quote {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 380;
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  line-height: 1.35;
  color: var(--ink);
  font-variation-settings: "SOFT" 60, "WONK" 1;
}
/* key phrase: an underline draws itself once the quote is revealed */
.about__quote em {
  color: var(--fairway-dark);
  font-style: italic;
  background: linear-gradient(currentColor, currentColor) no-repeat 0 96% / 0% 1px;
  transition: background-size 1.2s var(--ease-expo) 0.65s;
}
.reveal.is-visible .about__quote em { background-size: 100% 1px; }
.about__body { margin-top: var(--sp-3); color: var(--ink-70); max-width: 48ch; }
.about__photo { aspect-ratio: 4/5; border-radius: var(--radius); }

/* --- story marquee: slow editorial ticker, decorative only --- */
.marquee {
  overflow: hidden;
  margin-top: var(--sp-7);
  border-top: 1px solid var(--sand);
  border-bottom: 1px solid var(--sand);
  padding-block: var(--sp-2);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marqueeScroll 46s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__text {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 380;
  font-size: clamp(1.3rem, 2.4vw, 1.9rem);
  font-variation-settings: "SOFT" 60, "WONK" 1;
  color: var(--ink-45);
  white-space: nowrap;
  padding-right: 0.55em;
}
.marquee__text .sep { color: var(--grove); font-style: normal; }
@keyframes marqueeScroll {
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
}

/* ============================================================
   SUNTIMER — signature piece: one cinematic frame, day and night
   photographed from the same spot, blended by a draggable
   timeline. Drag the sun from 08:00 to 24:00 and watch the villa
   change light; the sun handle cools into a moon.
   ============================================================ */
.suntimer {
  position: relative;
  overflow: hidden;
  height: clamp(440px, 82vh, 860px);
  background: var(--pine);
  --sun-yellow: #ffd60a;
  --moon-silver: #f2eee1;
}
.suntimer > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.suntimer__night { opacity: 0; transition: opacity 0.4s linear; }
.suntimer__tint {
  position: absolute;
  inset: 0;
  background: var(--pool);
  mix-blend-mode: soft-light;
  opacity: 0;
  transition: opacity 0.4s linear;
  pointer-events: none;
}
.suntimer__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(30,28,25,0.25) 0%, rgba(30,28,25,0) 30%, rgba(30,28,25,0) 48%, rgba(20,18,16,0.88) 100%);
  pointer-events: none;
}
.suntimer__clock {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  z-index: 3;
  font-family: var(--font-mono);
  font-size: clamp(1.2rem, 2.4vw, 1.9rem);
  letter-spacing: 0.08em;
  color: var(--limestone);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--cream-45);
  border-radius: var(--radius);
  padding: 0.35em 0.7em;
  background: rgba(30, 28, 25, 0.35);
  backdrop-filter: blur(6px);
}
.suntimer__label {
  position: absolute;
  left: 0;
  bottom: 118px;
  z-index: 3;
  padding: 0 var(--sp-4);
  color: var(--limestone);
  max-width: 34rem;
  transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
}
.suntimer__label .eyebrow { color: var(--grove); margin-bottom: var(--sp-1); }
.suntimer__label--night { opacity: 0; transform: translateY(10px); }
@media (min-width: 768px) {
  .suntimer__label { padding: 0 var(--sp-5); }
}

/* --- timeline UI --- */
.suntimer__ui {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 4;
  padding: 0 var(--sp-4) var(--sp-3);
}
@media (min-width: 768px) {
  .suntimer__ui { padding: 0 var(--sp-5) var(--sp-3); }
}
.suntimer__trackwrap { position: relative; }
.suntimer__range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 44px;
  margin: 0;
  background: transparent;
  cursor: ew-resize;
}
.suntimer__range:focus-visible { outline: 2px solid var(--grove); outline-offset: 4px; }
/* the native thumb stays as the (invisible) touch target;
   the visible sun/moon lives in .suntimer__handle on top */
.suntimer__range::-webkit-slider-runnable-track {
  height: 2px;
  border-radius: 1px;
  background: linear-gradient(90deg, var(--sun-yellow) 0%, var(--grove) 30%, var(--sand) 48%, var(--pool) 74%, #24211d 100%);
}
.suntimer__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 34px;
  height: 34px;
  margin-top: -16px;
  border-radius: 50%;
  background: transparent;
  border: 0;
}
.suntimer__range::-moz-range-track {
  height: 2px;
  border-radius: 1px;
  background: linear-gradient(90deg, var(--sun-yellow) 0%, var(--grove) 30%, var(--sand) 48%, var(--pool) 74%, #24211d 100%);
}
.suntimer__range::-moz-range-thumb {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: transparent;
  border: 0;
}
.suntimer__handle {
  position: absolute;
  top: 50%;
  left: 0;
  width: 34px;
  height: 34px;
  margin-top: -17px;
  pointer-events: none;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.55));
  transition: scale 0.25s var(--ease-out);
}
.suntimer__range:hover + .suntimer__handle,
.suntimer__range:active + .suntimer__handle { scale: 1.15; }
.suntimer__icon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.4s linear, transform 0.4s var(--ease-out);
}
.suntimer__icon--sun {
  color: var(--sun-yellow);
  filter: drop-shadow(0 0 7px rgba(255, 214, 10, 0.75));
  animation: sunSpin 40s linear infinite;
}
.suntimer__icon--moon { color: var(--moon-silver); opacity: 0; transform: rotate(-25deg); }
@keyframes sunSpin {
  to { transform: rotate(360deg); }
}
.suntimer__scale {
  display: flex;
  justify-content: space-between;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  color: var(--cream-45);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   FACILITIES DATA GRID
   ============================================================ */
.spec-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--sand);
  border: 1px solid var(--sand);
}
@media (min-width: 700px) {
  .spec-grid { grid-template-columns: repeat(4, 1fr); }
}
.spec-cell {
  background: var(--limestone);
  padding: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: 0.3em;
}
.spec-cell__value {
  font-family: var(--font-mono);
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  color: var(--fairway-dark);
}
.spec-cell__label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--ink-70);
  text-transform: uppercase;
}

.facility-list {
  margin-top: var(--sp-6);
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border-top: 1px solid var(--sand);
}
@media (min-width: 700px) {
  .facility-list { grid-template-columns: 1fr 1fr; }
}
.facility-item {
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--sand);
  display: flex;
  gap: var(--sp-2);
  align-items: flex-start;
}
@media (min-width: 700px) {
  .facility-item:nth-child(odd) { padding-right: var(--sp-4); border-right: 1px solid var(--sand); }
  .facility-item:nth-child(even) { padding-left: var(--sp-4); }
}
.facility-item__icon {
  width: 22px; height: 22px; flex-shrink: 0; margin-top: 3px;
  color: var(--fairway-dark);
}
.facility-item__text strong { display: block; font-family: var(--font-body); font-weight: 600; }
.facility-item__text span { color: var(--ink-70); font-size: 0.92rem; }

.facility-photos {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-5);
}
@media (min-width: 700px) {
  .facility-photos { grid-template-columns: repeat(4, 1fr); }
}
.facility-photos figure,
.facility-photos button {
  aspect-ratio: 3/4;
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  padding: 0;
  display: block;
  width: 100%;
}
.facility-photos button { cursor: zoom-in; }
.facility-photos img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--dur-slow) var(--ease-out); }
.facility-photos figure:hover img,
.facility-photos button:hover img { transform: scale(1.06); }

/* ============================================================
   GALLERY
   ============================================================ */
/* ============================================================
   GALERIJ — redactionele mozaïek

   De vorm van een vak wordt bepaald door de klasse op het item,
   niet door zijn positie in de rij. Dat is bewust: van de 28 foto's
   is er precies één staand en zijn er twee vierkant; de rest is
   liggend 3:2. Een vorm op positie toewijzen (zoals nth-child)
   dwong daardoor liggende foto's in staande vakken, waarbij de
   helft van de breedte wegviel.

   Desktop is een raster van 12 kolommen. De rijen lopen exact vol:
     8 + 4  ·  6 + 6  ·  4 + 4 + 4  ·  6 + 6

   Binnen een rij zijn de vakken ongeveer even hoog; het kleine
   verschil door de tussenruimte wordt opgevangen doordat grid-items
   standaard uitrekken tot de rijhoogte (align-items: stretch).
   ============================================================ */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
}
.gallery-item {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  aspect-ratio: 4/3;
  cursor: zoom-in;
  /* De verhouding bepaalt de rijhoogte. align-self laat een vak dat
     net iets lager uitkomt de rijhoogte alsnog vullen — de
     tussenruimte telt in een breed vak namelijk zwaarder mee dan in
     een smal, waardoor buren anders een paar pixels verschillen.

     Let op: zodra een vak hoger wordt gemaakt dan zijn verhouding,
     rekent de browser de BREEDTE uit die hoogte en valt het vak
     buiten het raster. max-width houdt het binnen zijn kolommen;
     de foto zelf vangt dat op met object-fit: cover. */
  align-self: stretch;
  max-width: 100%;
}
/* mobiel: het openingsbeeld over de volle breedte, de rest twee per rij */
.gallery-item--anchor { grid-column: span 2; aspect-ratio: 3/2; }

@media (min-width: 700px) {
  .gallery-grid { grid-template-columns: repeat(12, 1fr); }
  .gallery-item--anchor { grid-column: span 8; aspect-ratio: 3/2; }
  .gallery-item--tall   { grid-column: span 4; aspect-ratio: 3/4; }
  .gallery-item--half   { grid-column: span 6; aspect-ratio: 3/2; }
  .gallery-item--square { grid-column: span 4; aspect-ratio: 1/1; }
}
.gallery-item img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.gallery-item:hover img { transform: scale(1.07); }
.gallery-item::after {
  content: "";
  position: absolute; inset: 0;
  background: rgba(30,28,25,0);
  transition: background var(--dur-fast) var(--ease-out);
}
.gallery-item:hover::after { background: rgba(30,28,25,0.12); }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(20, 18, 16, 0.96);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  /* visibility: hidden haalt de knoppen uit de tabvolgorde zolang de
     lightbox dicht is. Zonder dit belandt een toetsenbordgebruiker op
     onzichtbare knoppen. De 0s-vertraging schakelt visibility pas om
     ná het uitvloeien, zodat de fade zichtbaar blijft. */
  visibility: hidden;
  transition: opacity var(--dur-med) var(--ease-out),
              visibility 0s linear var(--dur-med);
}
.lightbox.is-open {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity var(--dur-med) var(--ease-out), visibility 0s;
}
.lightbox img {
  max-width: min(92vw, 1200px);
  max-height: 84vh;
  width: auto;
  object-fit: contain;
  transform: scale(0.96);
  transition: transform var(--dur-med) var(--ease-out);
}
.lightbox.is-open img { transform: scale(1); }
.lightbox__close, .lightbox__prev, .lightbox__next {
  position: absolute;
  color: var(--limestone);
  width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--cream-45);
  border-radius: 50%;
}
.lightbox__close { top: var(--sp-3); right: var(--sp-3); }
.lightbox__prev { left: var(--sp-3); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: var(--sp-3); top: 50%; transform: translateY(-50%); }
.lightbox__close svg, .lightbox__prev svg, .lightbox__next svg {
  transition: transform var(--dur-fast) var(--ease-out);
}
.lightbox__prev:hover svg { transform: translateX(-3px); }
.lightbox__next:hover svg { transform: translateX(3px); }
.lightbox__close:hover svg { transform: rotate(90deg); }
.lightbox__counter {
  position: absolute;
  bottom: var(--sp-3);
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--cream-70);
  font-variant-numeric: tabular-nums;
}

/* custom cursor badge over openable photos (fine pointers only;
   attached by JS, which also sets html.has-cursor-badge) */
/* ============================================================
   SPOTLIGHT — een zachte bronzen lichtvlek die de cursor volgt
   over donkere secties. Alsof je met een zaklamp over de muur
   strijkt.

   isolation: isolate maakt van de sectie een eigen stapelcontext,
   waardoor de vlek met z-index:-1 wél boven de achtergrondkleur
   ligt maar ónder alle tekst. Zo hoeft geen enkel kindelement
   aangepast te worden en blijft de tekst perfect leesbaar.

   Aanzetten doe je met het attribuut data-spotlight op een sectie.
   JavaScript voegt het vlekje zelf toe — staat het uit (of gebruikt
   iemand touch), dan verandert er niets aan de opmaak.
   ============================================================ */
[data-spotlight], [data-grain] { position: relative; isolation: isolate; }
[data-spotlight] { overflow: hidden; }

/* In een .bg-photo sectie staat de foto op z-index 0 en de inhoud op 2.
   Vlek en korrel gaan daar dus op 1: boven de foto, onder de tekst. */
.bg-photo .spotlight,
.bg-photo .grain { z-index: 1; }

/* ============================================================
   FILMKORREL — een fijne ruislaag over donkere vlakken, zoals
   filmmateriaal. Maakt egale kleurvlakken minder digitaal.

   De ruis komt uit een SVG-filter (zie de sprite bovenaan
   index.html), niet uit een background-image — regel 1 blijft dus
   overeind. Aanzetten met data-grain op een sectie; JavaScript
   voegt de laag toe.
   ============================================================ */
.grain {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0.055;
  mix-blend-mode: overlay;
}

.spotlight {
  position: absolute;
  top: 0; left: 0;
  z-index: -1;
  width: 460px; height: 460px;
  margin: -230px 0 0 -230px;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle at center,
              rgba(154, 127, 95, 0.22) 0%,
              rgba(154, 127, 95, 0.10) 42%,
              transparent 70%);
  filter: blur(26px);
  transition: opacity 700ms var(--ease-out);
  will-change: transform, opacity;
}
.spotlight.is-lit { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .spotlight { display: none; }
}

.cursor-badge {
  position: fixed;
  top: 0; left: 0;
  z-index: 150;
  width: 52px; height: 52px;
  margin: -26px 0 0 -26px;
  border-radius: 50%;
  background: rgba(30, 28, 25, 0.82);
  border: 1px solid var(--cream-45);
  color: var(--limestone);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 1.1rem;
  font-weight: 400;
  pointer-events: none;
  opacity: 0;
  scale: 0.4;
  transition: opacity 0.35s var(--ease-expo), scale 0.35s var(--ease-expo);
}
.cursor-badge.is-active { opacity: 1; scale: 1; }
@media (pointer: fine) {
  html.has-cursor-badge [data-lightbox] { cursor: none; }
}

/* ============================================================
   SIGNATURE — DISTANCE DIAL (location data rail)
   ============================================================ */
.dial {
  margin-top: var(--sp-5);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--sp-2);
}
.dial::-webkit-scrollbar { height: 4px; }
.dial::-webkit-scrollbar-thumb { background: var(--pine-line); }
.dial__track {
  display: flex;
  min-width: max-content;
  border-top: 1px solid var(--pine-line);
  border-bottom: 1px solid var(--pine-line);
}
.dial__stop {
  flex-shrink: 0;
  width: clamp(180px, 22vw, 260px);
  padding: var(--sp-3) var(--sp-3) var(--sp-3) 0;
  border-right: 1px solid var(--pine-line);
  position: relative;
}
.dial__stop::before {
  content: "";
  position: absolute;
  top: -1px; left: 0;
  width: 10px; height: 2px;
  background: var(--grove);
}
.dial__dist {
  font-family: var(--font-mono);
  font-size: clamp(1.8rem, 3vw, 2.6rem);
  color: var(--grove);
  display: block;
}
.dial__unit { font-size: 0.9rem; color: var(--cream-70); }
.dial__name { display: block; margin-top: 0.4em; font-family: var(--font-body); }
.dial__tag { display: block; margin-top: 0.2em; font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.04em; color: var(--cream-45); text-transform: uppercase; }

/* ============================================================
   CALENDAR + RESERVATION
   ============================================================ */
.booking {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6);
}
@media (min-width: 980px) {
  .booking { grid-template-columns: 1.05fr 0.95fr; }
}

.calendar {
  border: 1px solid var(--sand);
  background: var(--white);
}
.calendar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--sand);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
}
.calendar__head button {
  /* 44px is de minimum aanraakmaat voor een vinger (WCAG 2.5.5). */
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--sand);
  border-radius: var(--radius);
  transition: background var(--dur-fast) var(--ease-out);
}
.calendar__head button:hover { background: var(--limestone-2); }
.calendar__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  background: var(--limestone-2);
}
.calendar__dow {
  background: var(--limestone);
  padding: 0.6em 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--ink-70);
  text-transform: uppercase;
}
.calendar__day {
  background: var(--white);
  aspect-ratio: 1/0.85;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  position: relative;
}
.calendar__day--muted { color: var(--sand); }
.calendar__day--booked { background: var(--limestone-2); color: var(--ink-45); text-decoration: line-through; }
.calendar__day--available { color: var(--fairway-dark); transition: background var(--dur-fast) var(--ease-out); }
.calendar__day--available:hover { background: var(--limestone); }
.calendar__day, .spec-cell__value, .dial__dist, .price-strip__value, .hero-fact strong {
  font-variant-numeric: tabular-nums;
}
.calendar__legend {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--sand);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-70);
  flex-wrap: wrap;
}
.calendar__legend > span { display: inline-flex; align-items: center; gap: 0.5em; }
.calendar__dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
.calendar__dot--available { background: var(--fairway); }
.calendar__dot--booked { background: var(--sand); }
.calendar__note {
  margin-top: var(--sp-2);
  font-size: 0.82rem;
  color: var(--ink-70);
  border-left: 2px solid var(--grove);
  padding-left: var(--sp-2);
}

.price-strip {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: var(--sp-3);
  border: 1px solid var(--sand);
  border-top: 0;
  background: var(--white);
}
.price-strip__value { font-family: var(--font-mono); font-size: 1.6rem; color: var(--grove-dark); }
.price-strip__unit { font-size: 0.8rem; color: var(--ink-70); }

.form-field { display: flex; flex-direction: column; gap: 0.5em; margin-bottom: var(--sp-3); }
.form-field label { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-70); }
.form-field input, .form-field textarea {
  min-height: 48px;
  padding: 0.8em 1em;
  border: 1px solid var(--sand);
  background: var(--white);
  border-radius: var(--radius);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.form-field textarea { min-height: 110px; resize: vertical; }
.form-field input:focus, .form-field textarea:focus { border-color: var(--fairway-dark); }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
@media (max-width: 480px) { .form-row { grid-template-columns: 1fr; } }
.form-error { color: #a13d2a; font-size: 0.8rem; min-height: 1.2em; }
.form-field.has-error input, .form-field.has-error textarea { border-color: #a13d2a; }
.form-status {
  margin-top: var(--sp-2);
  padding: var(--sp-2);
  font-size: 0.9rem;
  border-left: 2px solid var(--fairway);
  background: var(--limestone-2);
  display: none;
}
.form-status.is-visible { display: block; }
.form-status--error { border-left-color: #a13d2a; }
.form-status--error a { color: var(--fairway-dark); text-decoration: underline; }

/* Spamval — buiten beeld, maar leesbaar voor robots die de HTML uitlezen.
   Bewust niet display:none: sommige bots slaan verborgen velden over. */
.form-honeypot {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Verzenden bezig — knop uitgeschakeld, formulier licht gedimd. */
#reservation-form.is-sending { opacity: 0.6; pointer-events: none; }
#reservation-form.is-sending .btn { cursor: progress; }

/* ============================================================
   GUEST AREA — code-gated local guide
   ============================================================ */
.guest { overflow: hidden; }
.guest > img { opacity: 0.18; }
.guest::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--pine) 0%, rgba(30,28,25,0.82) 45%, var(--pine) 100%);
  pointer-events: none;
}

/* --- locked gate --- */
.guest__gate { display: flex; justify-content: center; }
.guest__gate-inner {
  max-width: 34rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
}
.guest__lock {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: 1px solid var(--pine-line);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--grove);
  margin-bottom: var(--sp-1);
}
.guest__gate-inner .eyebrow { color: var(--grove); }
.guest__intro { color: var(--cream-70); max-width: 44ch; }
.guest__form { width: 100%; max-width: 22rem; margin-top: var(--sp-2); }
.guest__form .form-field { text-align: left; }
.guest__form label { color: var(--cream-70); }
.guest__form input {
  background: rgba(236, 232, 225, 0.06);
  border-color: var(--pine-line);
  color: var(--limestone);
  font-family: var(--font-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-align: center;
  font-size: 1.05rem;
}
.guest__form input:focus { border-color: var(--grove); }
.guest__form .form-error { color: #d98b73; }
.guest__form.has-error input {
  border-color: #d98b73;
  animation: guestShake 0.42s var(--ease-out);
}
@keyframes guestShake {
  10%, 90% { transform: translateX(-2px); }
  30%, 70% { transform: translateX(4px); }
  50% { transform: translateX(-4px); }
}
.guest__submit { width: 100%; }
.guest__hint { font-size: 0.82rem; color: var(--cream-45); }

/* --- unlocked vault --- */
.guest__vault[hidden] { display: none; }
.guest__vault-head { max-width: 46rem; margin-bottom: var(--sp-5); }
.guest__vault-head .eyebrow { color: var(--grove); }
.guest__lockagain {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-height: 44px;
  margin-top: var(--sp-1);
  padding: 0.4em 0.9em 0.4em 0.7em;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cream-45);
  border: 1px solid var(--pine-line);
  border-radius: var(--radius);
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.guest__lockagain:hover { color: var(--limestone); border-color: var(--cream-45); }

.guest__group { margin-bottom: var(--sp-6); }
.guest__group:last-child { margin-bottom: 0; }
.guest__group-title {
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding-bottom: var(--sp-2);
  margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--pine-line);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--grove);
}
.guest__cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-3);
}
@media (min-width: 700px) {
  .guest__cards { grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); }
}
.guest-card {
  border-top: 1px solid var(--pine-line);
  padding-top: var(--sp-2);
  position: relative;
}
.guest-card::before {
  content: "";
  position: absolute;
  top: -1px; left: 0;
  width: 0;
  height: 1px;
  background: var(--grove);
  transition: width 0.7s var(--ease-expo);
}
.guest__cards.is-visible .guest-card::before { width: 2.2rem; }
.guest-card__name {
  font-family: var(--font-display);
  font-weight: 500;
  font-variation-settings: "SOFT" 60, "WONK" 1;
  font-size: 1.15rem;
  line-height: 1.25;
  color: var(--limestone);
  margin-bottom: 0.25em;
}
.guest-card__dist {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grove);
  margin-bottom: 0.7em;
}
.guest-card__desc { color: var(--cream-70); font-size: 0.94rem; }

/* ============================================================
   GASTENZONE — adressenlijst

   Compacte variant naast de kaarten. Bewust géén beschrijving per
   regel: naam, plaats en link zijn taalneutraal, dus deze lijst
   hoeft niet in vier talen te bestaan. Alleen de groepstitels en
   een enkele losse opmerking zijn vertaald.

   Dat is de reden dat er hier tientallen adressen bij konden zonder
   dat het bestand onbeheersbaar werd.
   ============================================================ */
.guest-list {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--pine-line);
  border-block: 1px solid var(--pine-line);
}
@media (min-width: 760px) {
  .guest-list { grid-template-columns: 1fr 1fr; }
  /* Bij een oneven aantal adressen bleef rechtsonder een cel leeg.
     De scheidingslijnen worden getekend met een raster van 1px
     kieren waar de containerachtergrond doorheen schijnt, dus zo'n
     lege cel werd zichtbaar als een lichtere rechthoek. Laat het
     laatste item in dat geval over beide kolommen lopen.
     Zo lost het zichzelf op, hoeveel adressen de klant later ook
     toevoegt of weghaalt. */
  .guest-list__item:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.guest-list__item {
  background: var(--pine);
  padding: 0.85em 0.2em;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2em 0.7em;
}
.guest-list__name {
  color: var(--limestone);
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.guest-list__name:hover,
.guest-list__name:focus-visible { color: var(--grove); border-bottom-color: var(--grove); }
/* pijltje dat aangeeft dat de link naar buiten gaat */
.guest-list__name[target="_blank"]::after {
  content: " ↗";
  font-size: 0.8em;
  opacity: 0.55;
}
.guest-list__meta {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--cream-45);
  text-transform: uppercase;
}
.guest-list__note {
  flex-basis: 100%;
  color: var(--cream-70);
  font-size: 0.88rem;
  margin: 0.15em 0 0;
}

/* ============================================================
   FOOTER
   ============================================================ */
.site-footer {
  padding-block: var(--sp-6) var(--sp-4);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-5);
  padding-bottom: var(--sp-5);
  border-bottom: 1px solid var(--pine-line);
}
@media (min-width: 700px) {
  .footer-grid { grid-template-columns: 1.3fr 1fr 1fr; }
}
.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--cream-45);
}
.footer-contact a { display: block; margin-top: 0.5em; color: var(--cream-70); transition: color var(--dur-fast); }
.footer-contact a:hover { color: var(--grove); }

/* ============================================================
   LANGUAGE VISIBILITY
   ============================================================ */
/* !important + :not() so this always wins for the hidden languages,
   whatever display value a component class sets — and never touches
   display for the active language, so that component value applies. */
html:not([lang="nl"]) [data-i18n="nl"],
html:not([lang="en"]) [data-i18n="en"],
html:not([lang="es"]) [data-i18n="es"],
html:not([lang="fr"]) [data-i18n="fr"] { display: none !important; }

/* ============================================================
   SCROLL REVEAL ANIMATION
   quiet choreography: text rises gently; headings emerge from a
   mask with a settling skew; photos unveil behind a curtain wipe
   while the image itself eases from a slight overscale.
   ============================================================ */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 1.1s var(--ease-expo), transform 1.1s var(--ease-expo);
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* headings: masked line reveal */
@media (prefers-reduced-motion: no-preference) {
  .section-head.reveal h2 {
    clip-path: inset(-14% -2% 100% -2%);
    transform: translateY(0.45em) skewY(1.2deg);
    transform-origin: 0 100%;
    transition: clip-path 1.15s var(--ease-expo) 80ms, transform 1.15s var(--ease-expo) 80ms;
  }
  .section-head.reveal.is-visible h2 {
    clip-path: inset(-14% -2% -20% -2%);
    transform: none;
  }

  /* Woord voor woord. Is de kop door JavaScript in woorden gesplitst,
     dan neemt deze animatie het over van het masker hierboven — anders
     zouden beide tegelijk lopen. Lukt het splitsen niet, dan blijft het
     masker gewoon werken. */
  .section-head.reveal h2.has-words {
    clip-path: none;
    transform: none;
    transition: none;
  }
  .section-head.reveal h2.has-words .word {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.42em) rotate(1.4deg);
    transform-origin: 0 100%;
    transition: opacity 780ms var(--ease-expo), transform 780ms var(--ease-expo);
    transition-delay: calc(var(--w, 0) * 70ms);
  }
  .section-head.reveal.is-visible h2.has-words .word {
    opacity: 1;
    transform: none;
  }
}

.reveal-stagger > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.9s var(--ease-expo), transform 0.9s var(--ease-expo);
}
.reveal-stagger.is-visible > * { opacity: 1; transform: translateY(0); }
.reveal-stagger.is-visible > *:nth-child(1) { transition-delay: 0ms; }
.reveal-stagger.is-visible > *:nth-child(2) { transition-delay: 70ms; }
.reveal-stagger.is-visible > *:nth-child(3) { transition-delay: 140ms; }
.reveal-stagger.is-visible > *:nth-child(4) { transition-delay: 210ms; }
.reveal-stagger.is-visible > *:nth-child(5) { transition-delay: 280ms; }
.reveal-stagger.is-visible > *:nth-child(6) { transition-delay: 350ms; }
.reveal-stagger.is-visible > *:nth-child(7) { transition-delay: 420ms; }
.reveal-stagger.is-visible > *:nth-child(8) { transition-delay: 490ms; }
.reveal-stagger.is-visible > *:nth-child(9) { transition-delay: 560ms; }
.reveal-stagger.is-visible > *:nth-child(10) { transition-delay: 630ms; }

/* photos: curtain unveil instead of fade-up */
@media (prefers-reduced-motion: no-preference) {
  .facility-photos.reveal-stagger > button,
  .gallery-grid.reveal-stagger > .gallery-item {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 100% 0);
    transition: clip-path 1.2s var(--ease-expo);
  }
  .facility-photos.reveal-stagger > button img,
  .gallery-grid.reveal-stagger > .gallery-item img {
    transform: scale(1.12);
    transition: transform 1.6s var(--ease-expo);
  }
  .facility-photos.reveal-stagger.is-visible > button,
  .gallery-grid.reveal-stagger.is-visible > .gallery-item { clip-path: inset(0 0 0 0); }
  .facility-photos.reveal-stagger.is-visible > button img,
  .gallery-grid.reveal-stagger.is-visible > .gallery-item img { transform: scale(1); }

  /* after the unveil, hand hover zoom back its own timing */
  .facility-photos.reveal-stagger.is-visible > button:hover img,
  .gallery-grid.reveal-stagger.is-visible > .gallery-item:hover img {
    transform: scale(1.06);
  }
}

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-stagger > * { opacity: 1; transform: none; }
  .bg-photo > img { transform: none !important; }
}

/* ============================================================
   MISC
   ============================================================ */
.skip-link {
  position: fixed;
  top: -60px; left: var(--sp-2);
  background: var(--grove);
  color: var(--white);
  padding: 0.8em 1.2em;
  z-index: 300;
  transition: top var(--dur-fast) var(--ease-out);
  border-radius: var(--radius);
}
.skip-link:focus { top: var(--sp-2); }

.divider-line { height: 1px; background: var(--pine-line); }
.section--light .divider-line { background: var(--sand); }

::selection { background: var(--grove); color: var(--ink); }
