/* ═══════════════════════════════════════════════════════════════
   VILLA ASTU — design system
   ink (steel frames) · amber (bamboo & lamplight) · petrol (pool
   & paddies) · bone (limewash walls). Type: Cardinal / Neue Haas
   Grotesk / FH Alpha (licensed — see brand-fonts.css).
   ═══════════════════════════════════════════════════════════════ */

:root{
  --ink:      #17150f;
  --ink-2:    #211e15;
  --bone:     #f1ead9;
  --bone-2:   #e7ddc4;
  --amber:    #c68a3f;
  --amber-2:  #e2ab55;
  --petrol:   #33655c;
  --petrol-d: #223f38;
  --clay:     #9c5b41;
  --t-ink-60: rgba(23,21,15,.6);
  --t-bone-2: rgba(241,234,217,.16);

  /* Brand faces first, closest free equivalents behind them.
     See css/brand-fonts.css to activate the licensed files. */
  --font-display: 'Cardinal', 'Instrument Serif', Georgia, serif;
  --font-body: 'Plus Jakarta Sans', 'Neue Haas Grotesk', system-ui, sans-serif;
  /* label/data face: no longer a monospace, which read as typewriter */
  --font-mono: 'FH Alpha', 'Plus Jakarta Sans', system-ui, sans-serif;

  --wrap: 1200px;
  --pad: clamp(1.25rem, 4vw, 3rem);
  --sec: clamp(5rem, 10vw, 9rem);
  --r: 4px;
}

*,*::before,*::after{ box-sizing:border-box; margin:0; padding:0; }
[hidden]{ display:none !important; }
html{ scroll-behavior:smooth; }
body{
  font-family:var(--font-body);
  font-weight:400;
  color:var(--ink);
  background:var(--bone);
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
img{ max-width:100%; display:block; }
a{ color:inherit; }
button{ font:inherit; cursor:pointer; }
:focus-visible{ outline:2px solid var(--amber); outline-offset:3px; }

.mono{ font-family:var(--font-mono); font-weight:500; font-size:.78rem; letter-spacing:.08em;
  font-variant-numeric:tabular-nums; }
.wrap{ max-width:var(--wrap); margin-inline:auto; padding-inline:var(--pad); }

h1,h2,h3{ font-family:var(--font-display); font-weight:400; line-height:1.08; }
h2{ font-size:clamp(2rem, 4.6vw, 3.4rem); letter-spacing:-.01em; }
h3{ font-size:clamp(1.3rem, 2.4vw, 1.7rem); }
h4{ font-weight:600; font-size:1.02rem; }

.eyebrow{
  color:var(--clay);
  text-transform:lowercase;
  margin-bottom:1rem;
  font-size:.82rem;
}
.eyebrow span{ color:inherit; opacity:.55; }
.sec-head{ max-width:44rem; margin-bottom:clamp(2.5rem,6vw,4.5rem); }
/* the village headline needs the extra measure to stay on one line */
.sec-head--wide{ max-width:60rem; }
.sec-head__sub{ margin-top:1.1rem; font-size:1.05rem; opacity:.82; max-width:38rem; }
.sec-head--light .eyebrow{ color:var(--amber-2); }

/* ── buttons ─────────────────────────────────────────────── */
.btn{
  display:inline-flex; align-items:center; gap:.5rem;
  font-family:var(--font-mono); font-size:.8rem; letter-spacing:.06em;
  padding:.85rem 1.6rem; border-radius:var(--r);
  text-decoration:none; border:1px solid transparent;
  transition:background .25s, color .25s, border-color .25s, transform .2s;
}
.btn--solid{ background:var(--amber); color:var(--ink); border-color:var(--amber); }
.btn--solid:hover{ background:var(--amber-2); border-color:var(--amber-2); transform:translateY(-2px); }
.btn--ghost{ border-color:var(--t-bone-2); color:var(--bone); background:rgba(23,21,15,.25); backdrop-filter:blur(6px); }
.btn--ghost:hover{ border-color:var(--bone); }
.btn--line{ border-color:rgba(23,21,15,.28); color:var(--ink); background:transparent; padding:.55rem 1.1rem; }
.btn--line:hover{ background:var(--ink); color:var(--bone); border-color:var(--ink); }
.btn--lg{ padding:1.05rem 2.1rem; font-size:.88rem; }

/* ── candi bentar gate ───────────────────────────────────── */
.gate{ position:fixed; inset:0; z-index:100; display:flex; pointer-events:none; }
/* --gate-fade is animated from 100% (hard seam, halves read as one gate) to
   80% as they part, dissolving the inner 20% so no clean edge floats away. */
.gate__half{
  position:relative; width:50%; height:100%; overflow:hidden;
  --gate-fade:100%;
}
.gate__half img{ width:100%; height:100%; object-fit:cover; }
/* Anchor each photo's split edge to the inner edge of its panel, so the two
   halves read as one candi bentar before they part. */
.gate__half--left img{
  object-position:right center;
  -webkit-mask-image:linear-gradient(to right, #000 var(--gate-fade), transparent 100%);
          mask-image:linear-gradient(to right, #000 var(--gate-fade), transparent 100%);
}
.gate__half--right img{
  object-position:left center;
  -webkit-mask-image:linear-gradient(to left, #000 var(--gate-fade), transparent 100%);
          mask-image:linear-gradient(to left, #000 var(--gate-fade), transparent 100%);
}
.gate__word{
  position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:1rem; color:var(--bone);
  text-shadow:0 2px 24px rgba(12,11,8,.85);
}
/* The lit stonework meets in the middle — a soft scrim keeps the mark legible */
.gate__word::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(ellipse 46% 26% at 50% 50%, rgba(12,11,8,.82), rgba(12,11,8,0) 72%);
}
.gate__om, .gate__name{ position:relative; }
.gate__om{ font-family:var(--font-mono); font-size:.8rem; letter-spacing:.35em; text-transform:uppercase; color:var(--amber-2); }
/* a line of speech, not a wordmark: the wide logotype tracking is dropped so
   it reads as a sentence, and it holds one line down to the smallest screens */
.gate__name{
  font-family:var(--font-display); font-size:clamp(1.5rem,4.6vw,3.5rem);
  letter-spacing:.05em; line-height:1.1;
  max-width:92vw; text-align:center; text-wrap:balance;
}

/* ── nav ─────────────────────────────────────────────────── */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:60;
  display:flex; align-items:center; gap:2rem;
  padding:1.1rem var(--pad);
  color:var(--bone);
  transition:background .35s, box-shadow .35s, padding .35s;
}
.nav.is-scrolled{ background:rgba(23,21,15,.9); backdrop-filter:blur(10px); padding-block:.7rem;
  box-shadow:0 1px 0 rgba(241,234,217,.08); }
.nav__brand{ font-family:var(--font-display); letter-spacing:.24em; font-size:1.05rem; text-decoration:none; }
.nav__links{ display:flex; gap:1.6rem; margin-left:auto; }
.nav__links a{
  font-family:var(--font-mono); font-size:.74rem; letter-spacing:.08em;
  text-decoration:none; opacity:.8; text-transform:uppercase;
  transition:opacity .2s;
}
.nav__links a:hover{ opacity:1; }
.nav__cta{
  font-family:var(--font-mono); font-size:.74rem; letter-spacing:.06em; text-transform:uppercase;
  text-decoration:none; border:1px solid var(--amber); color:var(--amber-2);
  padding:.55rem 1rem; border-radius:var(--r); white-space:nowrap;
  transition:background .25s, color .25s;
}
.nav__cta:hover{ background:var(--amber); color:var(--ink); }
.nav__cta-tag{ opacity:.7; }
.nav__portal{
  font-family:var(--font-mono); font-size:.72rem; letter-spacing:.06em; text-transform:uppercase;
  text-decoration:none; color:var(--bone); border:1px solid rgba(241,234,217,.32);
  padding:.55rem 1rem; border-radius:99px; white-space:nowrap; opacity:.85;
  transition:background .25s, border-color .25s, opacity .25s;
}
.nav__portal:hover{ background:rgba(241,234,217,.12); border-color:var(--bone); opacity:1; }
.nav__burger{ display:none; background:none; border:0; width:40px; height:36px;
  flex-direction:column; gap:9px; align-items:center; justify-content:center; }
.nav__burger span{ display:block; width:24px; height:1.5px; background:var(--bone); transition:transform .3s, opacity .3s; }
.nav__burger.is-open span:first-child{ transform:translateY(5.25px) rotate(45deg); }
.nav__burger.is-open span:last-child{ transform:translateY(-5.25px) rotate(-45deg); }

.mobile-menu{
  position:fixed; inset:0; z-index:55; background:var(--ink); color:var(--bone);
  display:flex; flex-direction:column; justify-content:center; padding:var(--pad);
  transform:translateY(-100%); visibility:hidden;
  transition:transform .45s cubic-bezier(.7,0,.2,1), visibility 0s .45s;
}
.mobile-menu.is-open{ transform:translateY(0); visibility:visible; transition-delay:0s; }
.mobile-menu nav{ display:flex; flex-direction:column; gap:.4rem; }
.mobile-menu a{
  font-family:var(--font-display); font-size:clamp(1.8rem,7vw,2.6rem);
  text-decoration:none; padding-block:.35rem; border-bottom:1px solid rgba(241,234,217,.08);
}
.mobile-menu__foot{ position:absolute; bottom:2rem; left:var(--pad); opacity:.6; }

/* ── hero ────────────────────────────────────────────────── */
/* The video never moves; the hero text and every section below it scroll
   up over the top, so the page reveals itself like a rising curtain. */
.herofix{ position:fixed; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
#smooth-wrapper{ position:relative; z-index:1; }
.hero{ position:relative; height:100svh; min-height:600px;
  display:flex; align-items:flex-end; color:var(--bone); background:transparent; }
.hero__video{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.hero__shade{ position:absolute; inset:0;
  background:linear-gradient(to bottom, rgba(23,21,15,.42) 0%, rgba(23,21,15,.12) 40%, rgba(23,21,15,.78) 100%); }
.hero__content{ position:relative; z-index:2; width:100%; max-width:var(--wrap);
  margin-inline:auto; padding:0 var(--pad) 7.5rem; }
.hero__eyebrow{ letter-spacing:.28em; text-transform:uppercase; color:var(--amber-2);
  margin-bottom:1.2rem; text-shadow:0 1px 14px rgba(23,21,15,.65); }
.hero__title{ line-height:0; margin:0; }
/* the hand-drawn mark, lifted off the footage by a dark shadow plus a soft
   warm bloom so the thin strokes hold on any frame */
.hero__markwrap{ position:relative; display:inline-block; line-height:0; }
.hero__mark{
  width:min(100%, 1040px); height:auto; display:block;
  filter:drop-shadow(0 3px 16px rgba(12,11,8,.72))
         drop-shadow(0 0 48px rgba(241,234,217,.3));
}
/* the sister-villa mark: the script logotype ends at ~96.5% with a low tail, so
   One nestles into the pocket beneath it, in amber like the nav pill */
.hero__one{
  position:absolute; right:-1%; bottom:1%;
  width:clamp(4.5rem, 13vw, 9rem); height:auto;
  filter:drop-shadow(0 2px 14px rgba(12,11,8,.7)) drop-shadow(0 0 26px rgba(226,171,85,.3));
  pointer-events:none;
}
/* the line sits against the buttons rather than across the hero from them */
.hero__row{
  display:flex; align-items:flex-end; justify-content:flex-end;
  gap:2rem; flex-wrap:wrap; margin-top:1.6rem;
}
.hero__line{
  font-size:clamp(1.05rem, 2vw, 1.3rem); font-weight:300; max-width:26rem;
  text-align:right;
}
.hero__actions{ display:flex; gap:.9rem; flex-wrap:nowrap; align-items:stretch; }
.hero__rail{
  position:absolute; z-index:2; right:calc(var(--pad) / 2); top:50%;
  transform:translateY(-50%); writing-mode:vertical-rl;
  letter-spacing:.3em; opacity:.55; color:var(--bone);
}
.hero__foot{
  position:absolute; z-index:2; left:0; right:0; bottom:0;
  display:flex; justify-content:space-between; align-items:center; gap:1rem;
  padding:1.2rem var(--pad);
  border-top:1px solid rgba(241,234,217,.16);
  max-width:none;
}
.hero__foot .mono{ opacity:.75; }

/* ── ambient soundtrack toggle ────────────────────────────
   See-through disc above the hero footer. The bars run only while
   audio is actually playing, so the animation is a readout of state
   rather than decoration. */
/* Sits in the hero button row; the disc itself is fully see-through, so only
   the ring and the bars read against the footage. */
.hum{
  flex:none; width:52px; height:52px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:transparent;
  border:1px solid rgba(241,234,217,.55);
  cursor:pointer; transition:border-color .28s, transform .28s;
}
.hum:hover{ border-color:rgba(241,234,217,.95); transform:scale(1.06); }

/* the same control, docked by the book pill once the hero has scrolled away,
   so the soundtrack can always be switched off */
.hum--float{
  position:fixed; right:1.3rem; bottom:1.3rem; z-index:69;
  width:46px; height:46px;
  border-color:rgba(241,234,217,.5);
  background:rgba(23,21,15,.55);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  box-shadow:0 14px 34px -12px rgba(23,21,15,.6);
  opacity:0; transform:translateY(16px); pointer-events:none;
  transition:opacity .4s, transform .4s, border-color .28s;
}
.hum--float.is-shown{ opacity:1; transform:translateY(0); pointer-events:auto; }
.hum--float.is-shown:hover{ transform:translateY(0) scale(1.06); }
/* the pill slides left to make room whenever the disc is docked */
.bookpill{ transition:opacity .4s, transform .4s, background .25s, right .4s; }
body:has(.hum--float.is-shown) .bookpill{ right:4.6rem; }
.hum:focus-visible{ outline:2px solid var(--amber-2); outline-offset:4px; }

/* Two glyphs, two states: bars while sound plays, a crossed speaker when it
   doesn't. Flattened bars alone read as four dots and say nothing about audio. */
.hum__mute{
  width:23px; height:23px; fill:var(--bone); stroke:var(--bone);
  stroke-width:1.9; stroke-linejoin:round; stroke-linecap:round; opacity:.85;
}
.hum__mute line{ fill:none; }
.hum.is-on .hum__mute{ display:none; }
.hum:not(.is-on) .hum__bars{ display:none; }
.hum:hover .hum__mute{ opacity:1; }

.hum__bars{ display:flex; align-items:center; gap:3px; height:22px; }
/* Off is the resting state: a flat line. The animation is only attached
   while sound plays, because a merely *paused* animation still wins over
   this height in the cascade and would freeze the bars at random heights. */
.hum__bars i{
  display:block; width:3px; border-radius:2px; background:var(--bone);
  height:4px; opacity:.75; transition:opacity .25s;
}
.hum.is-on .hum__bars i{
  opacity:1;
  animation:hum-wave 1.1s ease-in-out infinite alternate;
}
/* offsets must out-specify the .is-on shorthand above, which resets delay to 0 */
.hum.is-on .hum__bars i:nth-child(1){ animation-delay:-.90s; }
.hum.is-on .hum__bars i:nth-child(2){ animation-delay:-.50s; }
.hum.is-on .hum__bars i:nth-child(3){ animation-delay:-.20s; }
.hum.is-on .hum__bars i:nth-child(4){ animation-delay:-.65s; }
.hum.is-on .hum__bars i:nth-child(5){ animation-delay:-.35s; }
@keyframes hum-wave{ from{ height:4px; } to{ height:21px; } }

/* No motion: keep the control fully usable, just stop the bars moving.
   They hold mid-height so the disc still reads as "sound is on". */
html.no-motion .hum.is-on .hum__bars i,
html.no-motion .hum__bars i{ animation:none; }
html.no-motion .hum.is-on .hum__bars i{ height:13px; }
@media (prefers-reduced-motion: reduce){
  .hum.is-on .hum__bars i, .hum__bars i{ animation:none; }
  .hum.is-on .hum__bars i{ height:13px; }
  .hum{ transition:none; }
  .hum:hover{ transform:none; }
}
.hero__scroll{ width:1px; height:34px; background:rgba(241,234,217,.3); position:relative; overflow:hidden; }
.hero__scroll i{ position:absolute; left:0; top:-40%; width:100%; height:40%;
  background:var(--amber-2); animation:scrollcue 2.2s ease-in-out infinite; }
@keyframes scrollcue{ 0%{ top:-40%; } 60%,100%{ top:110%; } }

/* ── parallax backdrops ──────────────────────────────────────
   One viewport-sized image per zone, held in view while the
   content scrolls over it and drifting --drift px slower.
   The wrapper clips; only .backdrop__img moves.            */
.backdrop{
  position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none;
}
.backdrop__img{
  position:absolute; left:0; right:0;
  top:calc(var(--drift) * -1);
  height:calc(100svh + var(--drift) * 2);
  background-position:center center;
  background-size:cover;
  background-repeat:no-repeat;
  will-change:transform;
}

/* No motion: nothing drives the drift, so let the image cover its whole zone */
html.no-motion .backdrop__img{ top:0; height:100%; }
@media (prefers-reduced-motion: reduce){ .backdrop__img{ top:0; height:100%; } }

/* Balinese line-art paper (intro → gallery) */
.paperzone{ position:relative; background:var(--bone); overflow:clip; --drift:120px; }
.paper .backdrop__img{ background-image:url('../assets/img/bali-paper.jpg'); opacity:.5; }
.paperzone > section{ position:relative; z-index:1; }

/* ── intro ───────────────────────────────────────────────── */
.intro{ padding-block:var(--sec); background:transparent; }
.intro__text{
  font-size:clamp(1.5rem, 3.2vw, 2.4rem); line-height:1.35; max-width:56rem;
  letter-spacing:-.005em; text-align:center; margin-inline:auto;
}
.intro__text em{ font-style:italic; color:var(--petrol); }
.intro__rule{
  display:block; width:min(100%, 46rem); height:auto;
  margin:clamp(2.5rem,6vw,4rem) auto clamp(1.5rem,4vw,2.5rem);
  opacity:.75;
}
/* the sister-villa line, between the divider and the numbers */
.intro__villa{
  max-width:52rem; margin:0 auto clamp(2.2rem,5vw,3.4rem);
  text-align:center; font-size:clamp(1rem,1.5vw,1.15rem);
  line-height:1.7; opacity:.8;
}
.intro__stats{
  list-style:none; display:grid; grid-template-columns:repeat(4, 1fr);
  gap:1.5rem; padding-top:.5rem;
}
.intro .eyebrow{ text-align:center; }
.intro__stats li{ display:flex; flex-direction:column; gap:.3rem;
  align-items:center; text-align:center; }
.intro__stats strong{ font-family:var(--font-display); font-weight:400; font-size:clamp(1.9rem,4vw,2.8rem); }
.intro__stats strong i{ font-style:normal; font-size:.55em; }
.intro__stats .mono{ opacity:.6; }

/* ── villa features ──────────────────────────────────────── */
.villa{ padding-block:var(--sec) 0; background:transparent; }
.feature{
  position:relative;
  display:grid; grid-template-columns:7fr 5fr; gap:clamp(1.5rem,4vw,4rem);
  align-items:center; margin-bottom:clamp(4rem,9vw,8rem);
}
/* Flipped blocks move the image to the right column, so the column widths
   swap too — otherwise the right-hand images render narrower. */
.feature--flip{ grid-template-columns:5fr 7fr; }
.feature--flip .feature__img{ order:2; }
/* Hand-drawn Balinese numerals, drifting behind each feature block */
.feature__numeral{
  position:absolute; z-index:0; top:-1.5rem; right:-3.5rem;
  height:clamp(12rem, 28.5vw, 25.5rem); width:auto;
  opacity:.2; pointer-events:none; user-select:none;
}
.feature--flip .feature__numeral{ right:auto; left:-3.5rem; }
.feature__img, .feature__body{ position:relative; z-index:1; }
.feature:nth-child(even) .feature__body{ margin-top:clamp(0px, 4vw, 3.5rem); }
.feature:nth-child(odd) .feature__img{ margin-top:clamp(0px, 3vw, 2.5rem); }
.feature__img{ overflow:hidden; border-radius:var(--r); }
/* overscan has to exceed the parallax travel (±12%) or the drift would pull
   the image edge into the frame */
.feature__img img{ width:100%; height:100%; object-fit:cover; aspect-ratio:4/3;
  transform:scale(1.28); will-change:transform; }
.feature__idx{ color:var(--clay); margin-bottom:.7rem; letter-spacing:.14em; text-transform:uppercase; }
.feature__body h3{ margin-bottom:.8rem; }
.feature__body p{ opacity:.85; max-width:30rem; }
.feature__tags{ list-style:none; display:flex; flex-wrap:wrap; gap:.5rem; margin-top:1.2rem; }
.feature__tags li{
  border:1px solid rgba(23,21,15,.18); padding:.28rem .7rem; border-radius:99px;
  font-size:.7rem; opacity:.75;
}

/* ── gallery ─────────────────────────────────────────────── */
.gallery{ overflow:hidden; background:var(--ink);
  /* the section boundary lands on a fractional pixel, so paint 2px past it
     and pull the next section back up: covers the flickering hairline */
  padding-block:clamp(3rem,6vw,5rem) calc(clamp(3rem,6vw,5rem) + 2px);
  margin-bottom:-2px; }
.gallery__track{ display:flex; gap:clamp(1rem,2vw,1.8rem); width:max-content; padding-inline:var(--pad); }
.gallery__track figure{ width:clamp(240px, 30vw, 420px); flex-shrink:0; }
.gallery__track img{ aspect-ratio:3/4; object-fit:cover; width:100%; border-radius:var(--r); }
.gallery__track figcaption{ color:var(--bone); opacity:.55; margin-top:.6rem; }

/* ── film: scroll-driven reveal ──────────────────────────── */
.film{ background:var(--ink); height:460vh; position:relative; }
.film__pin{
  height:100svh; position:relative; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
}
/* The frame is viewport-sized and starts scaled down, so it grows into a
   full-bleed screen without ever animating width/height. */
.film__frame{
  position:absolute; inset:0; overflow:hidden;
  transform:scale(.3); will-change:transform;
}
.film__video{ width:100%; height:100%; object-fit:cover; display:block; }
.film__veil{
  position:absolute; inset:0; background:rgba(23,21,15,.35);
  transition:background .4s;
}
.film__words{
  position:relative; z-index:2; display:flex; align-items:center;
  gap:.28em; background:none; border:0; padding:0; color:var(--bone);
  font-family:var(--font-body); font-weight:300;
  font-size:clamp(3rem, 9vw, 8rem); line-height:1; letter-spacing:-.02em;
}
.film__word{ display:block; will-change:transform; text-shadow:0 2px 30px rgba(23,21,15,.45); }
.film__pin:hover .film__veil{ background:rgba(23,21,15,.18); }
.film__note{
  position:absolute; z-index:2; bottom:2.2rem; left:50%; transform:translateX(-50%);
  color:var(--bone); opacity:.65; white-space:nowrap; text-align:center;
}

html.no-motion .film{ height:auto; }
html.no-motion .film__frame{ transform:none; }
html.no-motion .film__pin{ height:auto; overflow:visible; }
html.no-motion .ftrack{ position:static; width:100%; flex-direction:column; transform:none !important; }
html.no-motion .ftrack__panel{ width:100%; height:auto; }
html.no-motion .ftrack__panel--film{ height:100svh; }
html.no-motion .ftrack__panel--svc{ padding-block:var(--sec); }
@media (prefers-reduced-motion: reduce){
  .film{ height:100svh; }
  .film__frame{ transform:none; }
}

/* An iframe swallows pointermove, so the custom cursor would freeze over the
   film — hand control back to the native cursor while the modal is open. */
html.film-open .cursor{ display:none; }
html.film-open.has-cursor body,
html.film-open.has-cursor a,
html.film-open.has-cursor button{ cursor:auto; }

/* the pinned view holds two panels side by side; scroll slides it left */
.ftrack{
  position:absolute; inset:0; display:flex; width:200%;
  will-change:transform;
}
.ftrack__panel{
  position:relative; width:50%; height:100%; flex:none;
  display:flex; align-items:center; justify-content:center;
}
/* The bone panel overshoots its box on the left and bottom: the slide eases
   asymptotically into place under a scrubbed trigger, so without the overlap
   a 1-3px slice of the dark film panel flickers at the edge on arrival.
   .film__pin clips the overhang, so nothing moves. */
.ftrack__panel--svc{
  background:var(--bone); color:var(--ink);
  height:calc(100% + 2px); box-shadow:-5px 0 0 0 var(--bone);
  /* clips the wordmark's bleed here rather than relying on .film__pin, which
     drops to overflow:visible on phones and in reduced motion */
  overflow:hidden;
}
/* The wordmark is near-white artwork (rgb 210,211,212), which all but
   disappears on bone. Inverted it lands at rgb 45,44,43 and reads as a
   watermark; the opacity then does the washing back, not the colour. */
.svcintro__mark{
  position:absolute; top:50%; left:50%; translate:-50% -50%;
  width:min(118%, 1900px); max-width:none; height:auto;
  filter:invert(1); opacity:.07;   /* 30% more translucent */
  pointer-events:none; user-select:none; z-index:0;
}
.svcintro{ position:relative; z-index:1; text-align:center; padding:var(--pad); max-width:44rem; }
.svcintro .eyebrow{ color:var(--clay); }
.svcintro__title{
  font-size:clamp(2.6rem, 7vw, 6rem); line-height:1.02; letter-spacing:-.015em;
  margin-bottom:1.2rem;
}
.svcintro__sub{ opacity:.72; font-size:1.02rem; max-width:26rem; margin-inline:auto; }
.svcintro__rule{
  display:block; width:min(300px, 62%); height:auto;
  margin:clamp(1.6rem,3vw,2.4rem) auto 0; opacity:.55;
}
/* the caveat sits under the statement, deliberately quieter */
.services__fineprint{
  display:block; margin-top:.9rem;
  font-family:var(--font-mono); font-size:.72rem; letter-spacing:.08em;
  text-transform:lowercase; opacity:.55;
}
.services__lead{
  max-width:42rem; margin-inline:auto; text-align:center;
  font-family:var(--font-display); font-size:clamp(1.25rem,2.4vw,1.75rem);
  line-height:1.35; opacity:.85;
  margin-bottom:clamp(2.5rem,6vw,4rem);
}

/* ── film modal: Balinese frame ──────────────────────────── */
/* Near-full-viewport: the crests are the only chrome, --chrome reserves
   exactly their height plus gaps so the screen takes everything else. */
.vmodal{
  position:fixed; inset:0; z-index:95; display:flex; align-items:center; justify-content:center;
  padding:.75rem;
  --crest:clamp(24px, 4.4vh, 48px);
  --chrome:calc(var(--crest) * 2 + 2.4rem);
}
.vmodal[hidden]{ display:none; }
.vmodal__scrim{ position:absolute; inset:0; background:rgba(12,11,8,.94); backdrop-filter:blur(6px); }
.vmodal__frame{
  position:relative; width:100%; height:100%;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.5rem;
}
.vmodal__crest{ height:var(--crest); width:auto; max-width:56%; flex:none; opacity:.85; pointer-events:none; }
.vmodal__crest--bottom{ transform:rotate(180deg); }
.vmodal__screen{
  position:relative; aspect-ratio:16/9;
  width:min(100%, calc((100svh - var(--chrome)) * 16 / 9));
  max-height:calc(100svh - var(--chrome));
  background:#000; overflow:hidden;
  border:1px solid rgba(226,171,85,.55);
  box-shadow:0 0 0 6px rgba(23,21,15,.9), 0 0 0 7px rgba(226,171,85,.28),
             0 40px 90px -30px rgba(0,0,0,.9);
}
.vmodal__screen iframe{ position:absolute; inset:0; width:100%; height:100%; border:0; }
.vmodal__x{
  position:absolute; top:-.4rem; right:-.2rem; z-index:3;
  background:none; border:0; color:var(--bone); font-size:2.4rem; line-height:1; opacity:.7;
}
.vmodal__x:hover{ opacity:1; }

/* ── location ────────────────────────────────────────────── */
.location{ background:var(--ink); color:var(--bone); padding-block:var(--sec); }
.location--photo{ position:relative; overflow:clip; --drift:120px; }
/* the village film sits exactly where the still backdrop did */
.backdrop__video{
  position:absolute; left:0; right:0;
  top:calc(var(--drift) * -1);
  height:calc(100svh + var(--drift) * 2);
  width:100%; object-fit:cover; will-change:transform;
  /* the footage is far brighter than the still it replaced, so knock it back
     before the gradient goes over the top, or the drive times wash out */
  filter:brightness(.72) saturate(.95);
}
html.no-motion .backdrop__video{ top:0; height:100%; }
@media (prefers-reduced-motion: reduce){ .backdrop__video{ top:0; height:100%; } }
/* A warm ink scrim rather than the old petrol wash: that gradient tinted the
   whole village green. Ink darkens for legibility and lets the paddies keep
   their own colour. */
.location__bg::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(to bottom,
    rgba(23,21,15,.62) 0%, rgba(23,21,15,.50) 38%, rgba(23,21,15,.93) 100%);
}
.location--photo .wrap{ position:relative; z-index:1; }
.location h2, .location h3, .location h4{ color:var(--bone); }
.location__grid{ display:grid; grid-template-columns:7fr 5fr; gap:clamp(1.5rem,3vw,3rem);
  margin-bottom:clamp(2.5rem,5vw,4rem); }
.location__map{ display:flex; flex-direction:column; gap:.8rem; }
.location__map iframe{ width:100%; height:100%; min-height:380px; border:0;
  border-radius:var(--r); filter:grayscale(.35) contrast(1.02); }
.location__coords{ opacity:.7; }
.location__coords a{ color:var(--amber-2); }
.location__dist-title{ letter-spacing:.2em; text-transform:uppercase; color:var(--amber-2); margin-bottom:1rem; }
.dist-table{ width:100%; border-collapse:collapse; }
.dist-table td{ padding:.55rem 0; border-bottom:1px solid rgba(241,234,217,.12); font-size:.8rem; }
.dist-table td:last-child{ text-align:right; color:var(--amber-2); white-space:nowrap; padding-left:1rem; }
.location__note{ margin-top:1rem; opacity:.55; }
.area-cards{ display:grid; grid-template-columns:repeat(3,1fr); gap:1.2rem; }
.area-card{
  border:1px solid rgba(241,234,217,.14); border-radius:6px; overflow:hidden;
  background:rgba(23,21,15,.3);
  transition:border-color .3s, transform .3s;
}
.area-card:hover{ border-color:rgba(226,171,85,.5); transform:translateY(-4px); }
.area-card__img{ aspect-ratio:16/9; overflow:hidden; }
.area-card__img img{ width:100%; height:100%; object-fit:cover;
  transform:scale(1.02); transition:transform .8s cubic-bezier(.2,.6,.2,1); }
.area-card:hover .area-card__img img{ transform:scale(1.1); }
.area-card__body{ padding:1.4rem 1.5rem 1.6rem; }
.area-card h4{ font-family:var(--font-display); font-weight:400; font-size:1.25rem; margin-bottom:.35rem; }
.area-card__dist{ color:var(--amber-2); margin-bottom:.7rem; }
.area-card__link{
  display:inline-flex; align-items:center; gap:.35rem; margin-bottom:.7rem;
  color:var(--bone); opacity:.72; text-decoration:none;
  border-bottom:1px solid rgba(241,234,217,.35); padding-bottom:.12rem;
  transition:opacity .25s, border-color .25s, color .25s;
}
.area-card__link:hover, .area-card__link:focus-visible{
  opacity:1; color:var(--amber-2); border-color:var(--amber-2);
}

/* ── tooltip bubble ──────────────────────────────────────── */
[data-tip]{ position:relative; }
[data-tip]::after{
  content:attr(data-tip);
  position:absolute; top:calc(100% + 7px); left:0;
  transform:translateY(-4px);
  background:var(--ink); color:var(--bone);
  border:1px solid rgba(226,171,85,.4); border-radius:4px;
  padding:.3rem .55rem; white-space:nowrap;
  font-family:var(--font-body); font-size:.72rem; font-weight:400;
  letter-spacing:0; text-transform:none; line-height:1.3;
  opacity:0; pointer-events:none; z-index:7;
  transition:opacity .18s ease, transform .18s ease;
}
[data-tip]:hover::after, [data-tip]:focus-visible::after{
  opacity:1; transform:translateY(0);
}
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.area-card p:last-child{ font-size:.92rem; opacity:.8; }

/* ── services ────────────────────────────────────────────── */
/* margin-top:-2px closes a sub-pixel seam: the boundary with the ink .film
   section above lands off-pixel at some scroll offsets and the compositor
   blends a 1px dark line across the full width. Overlap beats rounding. */
.services{
  background:var(--bone); margin-top:-2px; padding-block:var(--sec);
  position:relative; overflow:clip; --drift:120px;
  transition:background-color .5s ease;
}
.services > .wrap{ position:relative; z-index:1; }
/* the paper texture fades up into the panel above, so the join between the
   sideways slide and the list reads as one continuous surface */
.services .backdrop__img{
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 26vh);
  mask-image:linear-gradient(to bottom, transparent 0, #000 26vh);
}

.svclist{ list-style:none; border-top:1px solid rgba(23,21,15,.18); }
.svcrow{ border-bottom:1px solid rgba(23,21,15,.18); }
.svcrow__hit{
  position:relative; width:100%; display:grid;
  grid-template-columns:3.5rem 1fr auto 2.5rem;
  align-items:center; gap:1.2rem;
  padding:1.35rem .8rem; background:none; border:0; text-align:left;
  color:var(--ink); overflow:hidden;
}
.svcrow__hit::before{
  content:""; position:absolute; inset:0; background:var(--ink);
  transform:scaleY(0); transform-origin:bottom;
  transition:transform .45s cubic-bezier(.65,0,.15,1); z-index:0;
}
.svcrow__hit > *{ position:relative; z-index:1; }
.svcrow__idx{ color:var(--clay); }
.svcrow__main{ display:flex; flex-direction:column; gap:.15rem; min-width:0; }
.svcrow__name{ font-family:var(--font-display); font-size:clamp(1.3rem, 2.6vw, 2rem); line-height:1.1; }
.svcrow__blurb{ font-size:.85rem; opacity:.6; max-width:34rem; transition:opacity .35s; }
.svcrow__price{
  color:var(--clay); white-space:nowrap; display:flex; flex-direction:column;
  align-items:flex-end; gap:.12rem; line-height:1.35;
}
.svcrow__fx{ opacity:.62; font-size:.66rem; }
.svcrow__arrow{ font-size:1.1rem; opacity:.4; transform:translateX(-6px);
  transition:transform .35s, opacity .35s; }
.svcrow__hit:hover::before, .svcrow__hit:focus-visible::before{ transform:scaleY(1); }
.svcrow__hit:hover .svcrow__blurb{ opacity:.75; }
.svcrow__hit:hover .svcrow__arrow{ transform:translateX(0); opacity:1; }

.svc-preview{
  display:none; position:fixed; z-index:58; width:290px; aspect-ratio:4/3;
  border-radius:6px; overflow:hidden; pointer-events:none;
  opacity:0; top:0; left:0;
  box-shadow:0 24px 60px -20px rgba(23,21,15,.55);
}
.svc-preview img{ width:100%; height:100%; object-fit:cover; }
@media (pointer:fine){ .svc-preview{ display:block; } }

/* Hovering a row fills only that row — the section around it stays put. */
.svcrow__hit > *{ transition:color .35s ease; }
.svcrow__hit:hover > *, .svcrow__hit:focus-visible > *{ color:var(--bone); }
.svcrow__hit:hover .svcrow__idx, .svcrow__hit:focus-visible .svcrow__idx,
.svcrow__hit:hover .svcrow__price, .svcrow__hit:focus-visible .svcrow__price{ color:var(--amber-2); }

/* ── amenities ───────────────────────────────────────────── */
/* A panel, not a footnote: the amenity list is the last thing between a
   guest and the booking form, so it gets the same card treatment as the
   guest-portal block it replaced. */
.amen{
  margin-top:clamp(2.5rem,5vw,4rem);
  border:1px solid rgba(23,21,15,.16); border-radius:var(--r);
  background:#f6f1e4;
  padding:clamp(1.6rem,3.6vw,2.8rem);
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);
  gap:clamp(1.5rem,3.5vw,3rem); align-items:center;
}
.amen__head .eyebrow{ color:var(--clay); margin-bottom:.7rem; }
.amen__title{ font-size:clamp(1.5rem,2.8vw,2.1rem); margin-bottom:.4rem; }
.amen__sub{ opacity:.72; font-size:.95rem; max-width:26rem; }
.amen__head .btn{ margin-top:1.4rem; }

.amen__side{ display:flex; flex-direction:column; gap:.9rem; }
.amen__count{
  font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; opacity:.6;
  display:flex; align-items:baseline; gap:.5rem;
}
.amen__count b{
  font-family:var(--font-display); font-size:2.1rem; font-weight:400;
  letter-spacing:0; text-transform:none; color:var(--clay); line-height:1;
}
.amen__count i{ font-style:normal; opacity:.7; }

.amen__peek{ list-style:none; display:flex; flex-wrap:wrap; gap:.45rem; }
.amen__peek li{
  border:1px solid rgba(23,21,15,.2); border-radius:99px;
  padding:.34rem .85rem; font-size:.68rem; opacity:.75;
  background:rgba(241,234,217,.55);
}
/* the overflow chip reads as a count, not another amenity */
.amen__peek .amen__more{
  border-style:dashed; opacity:.55; background:none;
}

/* the practical questions guests actually ask, sitting under the chips rather
   than buried in the 56-item modal */
.amen__facts{
  grid-column:1 / -1; margin-top:clamp(1.5rem,3vw,2.2rem);
  padding-top:clamp(1.3rem,3vw,1.9rem);
  border-top:1px solid rgba(23,21,15,.16);
  display:grid; grid-template-columns:repeat(4,1fr); gap:1.4rem 2rem;
}
.amen__facts dt{
  color:var(--clay); font-size:.68rem; letter-spacing:.16em;
  text-transform:uppercase; margin-bottom:.5rem;
}
.amen__facts dd{ font-size:.88rem; line-height:1.6; opacity:.8; }
.amen__link{
  background:none; border:0; padding:0; font:inherit; color:var(--clay);
  border-bottom:1px solid rgba(156,91,65,.45); cursor:pointer;
}
.amen__link:hover{ color:var(--ink); border-color:var(--ink); }

.amodal{ position:fixed; inset:0; z-index:93; display:flex; align-items:center;
  justify-content:center; padding:clamp(1rem,3vw,2.5rem); }
.amodal[hidden]{ display:none; }
.amodal__scrim{ position:absolute; inset:0; background:rgba(12,11,8,.86); backdrop-filter:blur(5px); }
.amodal__card{
  position:relative; width:min(920px,100%); max-height:88svh;
  background:var(--bone); border-radius:8px; display:flex; flex-direction:column;
  box-shadow:0 40px 90px -34px rgba(0,0,0,.8);
}
.amodal__top{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:clamp(1.3rem,3vw,1.9rem) clamp(1.3rem,3vw,2.1rem) 1rem;
  border-bottom:1px solid rgba(23,21,15,.14);
}
.amodal__top h3{ font-size:clamp(1.3rem,2.6vw,1.8rem); }
.amodal__x{ background:none; border:0; font-size:2rem; line-height:1; color:var(--ink); opacity:.55; }
.amodal__x:hover{ opacity:1; }
.amodal__body{ overflow:auto; padding:clamp(1.3rem,3vw,2.1rem); }
.amenlist{ columns:2; column-gap:2.4rem; }
.amenlist__group{ break-inside:avoid; margin-bottom:1.5rem; }
.amenlist__cat{
  letter-spacing:.16em; text-transform:uppercase; color:var(--clay);
  font-size:.62rem; margin-bottom:.5rem;
}
.amenlist__group ul{ list-style:none; display:flex; flex-direction:column; gap:.3rem; }
.amenlist__group li{ font-size:.92rem; opacity:.85; }
.amenlist__group--not li{ opacity:.45; text-decoration:line-through; }
.amodal__note{ margin-top:.5rem; opacity:.55; }

/* ── service detail modal ────────────────────────────────── */
.smodal{ position:fixed; inset:0; z-index:92; display:flex; align-items:center;
  justify-content:center; padding:clamp(1rem,3vw,2rem); }
.smodal[hidden]{ display:none; }
.smodal__scrim{ position:absolute; inset:0; background:rgba(12,11,8,.86); backdrop-filter:blur(5px); }
.smodal__card{
  position:relative; width:min(880px,100%); max-height:88svh; overflow:visible;
  background:var(--bone); border-radius:6px;
  display:grid; grid-template-columns:5fr 6fr;
  box-shadow:0 40px 90px -34px rgba(0,0,0,.8);
}
.smodal__img{ overflow:hidden; border-radius:6px 0 0 6px; }
.smodal__img img{ width:100%; height:100%; object-fit:cover; min-height:220px; }
.smodal__body{
  padding:clamp(1.6rem,3vw,2.4rem); display:flex; flex-direction:column; gap:.35rem;
  max-height:88svh; overflow:auto; border-radius:0 6px 6px 0;
}
.smodal__body h3{ font-size:clamp(1.5rem,3vw,2.1rem); margin-bottom:.5rem; }
.smodal__detail{ opacity:.85; font-size:.97rem; }
.smodal__price{ margin-top:1rem; display:flex; gap:.9rem; align-items:baseline;
  flex-wrap:wrap; color:var(--clay); font-size:.85rem; }
.smodal__price span + span{ opacity:.62; }
.smodal__note{ margin-top:.9rem; font-size:.85rem; opacity:.62;
  border-top:1px solid rgba(23,21,15,.16); padding-top:.9rem; }
.smodal__actions{ display:flex; gap:.7rem; flex-wrap:wrap; margin-top:1.1rem; }
.smodal__nav{
  position:absolute; top:50%; transform:translateY(-50%); z-index:3;
  width:44px; height:44px; border-radius:50%;
  background:rgba(23,21,15,.82); color:var(--bone);
  border:1px solid rgba(226,171,85,.4); font-size:1rem;
  transition:background .22s, border-color .22s;
}
.smodal__nav:hover{ background:var(--ink); border-color:var(--amber-2); }
.smodal__nav--prev{ left:-56px; }
.smodal__nav--next{ right:-56px; }
@media (max-width: 1060px){
  .smodal__nav{ top:auto; bottom:.9rem; transform:none; }
  .smodal__nav--prev{ left:auto; right:4.3rem; }
  .smodal__nav--next{ right:.9rem; }
  .smodal__count{ bottom:1.6rem; right:1.4rem; }
}
.smodal__count{ position:absolute; bottom:.85rem; right:1.4rem; z-index:3;
  color:var(--clay); opacity:.7; font-size:.7rem; }
.smodal__x{ position:absolute; top:.5rem; right:.7rem; z-index:2;
  background:none; border:0; font-size:2rem; line-height:1; color:var(--ink); opacity:.55; }
.smodal__x:hover{ opacity:1; }

/* ── culture ─────────────────────────────────────────────────
   Same Balinese line-art paper as the light zones, inverted:
   bone lines on ink instead of ink lines on bone. The section
   colour sits under it so the invert stays warm, not blue.  */
.culture{
  background:var(--ink); color:var(--bone);
  padding-block:var(--sec); position:relative; overflow:clip; --drift:120px;
}
.culture > .wrap{ position:relative; z-index:1; }
.paper--inv .backdrop__img{
  background-image:url('../assets/img/bali-paper.jpg');
  /* hue-rotate cancels the blue cast inverting a warm cream leaves behind */
  filter:invert(1) hue-rotate(180deg) saturate(.85);
  opacity:.4;
}
.culture__lower{
  display:grid; grid-template-columns:1.05fr .95fr;
  gap:clamp(2rem,5vw,4rem); margin-top:clamp(3rem,7vw,5rem);
}

/* ── culture: expanding triptych ─────────────────────────── */
.trip{ display:flex; gap:.7rem; min-height:460px; }
.trip__panel{
  position:relative; flex:1; border-radius:6px; overflow:hidden;
  background:var(--img) center/cover; cursor:pointer;
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:1.8rem; color:var(--bone);
  transition:flex .75s cubic-bezier(.65,0,.15,1);
}
.trip__panel.is-open{ flex:2.6; }
.trip__veil{ position:absolute; inset:0;
  background:linear-gradient(to top, rgba(23,21,15,.88) 0%, rgba(23,21,15,.35) 55%, rgba(23,21,15,.25) 100%); }
.trip__head, .trip__body{ position:relative; z-index:1; }
.trip__head h3{ font-size:clamp(1.4rem,2.4vw,1.9rem); color:var(--bone); }
.trip__head .mono{ color:var(--amber-2); margin-top:.2rem; }
.trip__body{
  max-width:30rem; font-size:.93rem; opacity:0; max-height:0; overflow:hidden;
  transition:opacity .5s .25s, max-height .6s .1s, margin .5s .1s;
}
.trip__panel.is-open .trip__body{ opacity:.92; max-height:16rem; margin-top:.9rem; }

/* ── culture notes accordion ─────────────────────────────── */
.culture__notes{ display:flex; flex-direction:column; gap:.6rem; }
.cnote{ border:1px solid rgba(241,234,217,.16); border-radius:var(--r); background:rgba(241,234,217,.03); }
.cnote summary{
  cursor:pointer; padding:1rem 1.3rem; list-style:none;
  font-family:var(--font-display); font-size:1.15rem; color:var(--bone);
  display:flex; justify-content:space-between; align-items:center;
}
.cnote summary::after{ content:"+"; font-family:var(--font-mono); color:var(--amber-2); }
.cnote[open] summary::after{ content:"−"; }
.cnote p{ padding:0 1.3rem 1.1rem; font-size:.93rem; opacity:.8; max-width:36rem; }

/* ── seasons: cards spread from a single stack ───────────── */
.seasons{ background:var(--bone-2); height:340vh; position:relative; }
.seasons__pin{ height:100svh; position:relative; overflow:hidden;
  display:flex; flex-direction:column; align-items:center; --drift:120px; }
.seasons__pin > .backdrop{ z-index:0; }
.seasons__head, .seasons__stage, .yearbar, .seasons__hint{ position:relative; z-index:1; }
.seasons__head{
  position:relative; z-index:8; text-align:center; padding:clamp(2.2rem,5.5vh,3.6rem) var(--pad) 0;
  max-width:44rem; pointer-events:none;
}
.seasons__head h2{ font-size:clamp(1.7rem,3.4vw,2.6rem); }
.seasons__sub{ margin-top:.7rem; opacity:.75; font-size:.95rem; }
.seasons__stage{ position:absolute; inset:0; z-index:1; }
.seasons__hint{
  position:absolute; bottom:1.6rem; left:50%; transform:translateX(-50%);
  opacity:.45; letter-spacing:.2em; text-transform:uppercase; z-index:8;
}

.scard{
  position:absolute; left:50%; top:50%; margin:0; padding:0; border:0;
  width:clamp(130px, 14vw, 200px); aspect-ratio:3/4;
  transform:translate(-50%,-50%);
  border-radius:6px; overflow:hidden; background:var(--ink);
  box-shadow:0 26px 60px -28px rgba(23,21,15,.75);
  will-change:transform;
}
.scard img{ width:100%; height:100%; object-fit:cover; }
.scard__veil{
  position:absolute; inset:0;
  background:linear-gradient(to bottom, rgba(12,11,8,.92) 0%, rgba(12,11,8,.35) 52%, rgba(12,11,8,.12) 100%);
}
.scard__label{
  position:absolute; left:0; right:0; top:0; padding:.9rem 1rem 1.2rem;
  display:flex; flex-direction:column; gap:.2rem; text-align:left; color:var(--bone);
}
.scard__when{ color:var(--amber-2); letter-spacing:.14em; text-transform:uppercase; font-size:.62rem; }
.scard__name{ font-family:var(--font-display); font-size:clamp(1rem,1.5vw,1.35rem); line-height:1.15; }
.scard:not(.scard--core){
  z-index:1;
  transition:box-shadow .35s ease, filter .35s ease;
}
/* pull the hovered card clear of the pile */
.scard:not(.scard--core):hover,
.scard:not(.scard--core):focus-visible{
  z-index:9;
  box-shadow:0 34px 80px -22px rgba(23,21,15,.95);
  filter:brightness(1.08);
}
/* the scrub owns .scard's transform, so the lift lives on the image */
.scard img{ transition:transform .45s cubic-bezier(.2,.6,.2,1); }
.scard:not(.scard--core):hover img,
.scard:not(.scard--core):focus-visible img{ transform:scale(1.08); }
.scard:not(.scard--core):hover .scard__veil,
.scard:not(.scard--core):focus-visible .scard__veil{
  background:linear-gradient(to bottom, rgba(12,11,8,.86) 0%, rgba(12,11,8,.2) 55%, rgba(12,11,8,.05) 100%);
}

/* the pair in the middle never moves — green above, dry below */
.scard--core{
  z-index:6; width:clamp(306px, 34vw, 476px); aspect-ratio:3/4.2;
  display:flex; flex-direction:column; background:none; box-shadow:none;
  border-radius:0; overflow:visible; pointer-events:none;
}
.scard__half{
  position:relative; flex:1; min-height:0; border:0; padding:0; margin:0;
  overflow:hidden; background:var(--ink); pointer-events:auto;
  box-shadow:0 26px 60px -28px rgba(23,21,15,.8);
  transition:flex .5s cubic-bezier(.65,0,.15,1);
}
.scard__half--green{ border-radius:6px 6px 0 0; }
.scard__half--dry{ border-radius:0 0 6px 6px; }
.scard__half + .scard__half{ margin-top:2px; }
.scard__half:hover{ flex:1.25; }
.scard__half img{ width:100%; height:100%; object-fit:cover; }

/* ── seasons: the year at a glance ──────────────────────── */
.yearbar{
  position:absolute; top:clamp(.8rem, 2.2vh, 1.7rem); left:50%;
  transform:translateX(-50%);
  width:min(900px, 90vw); z-index:7; margin:0;
  opacity:0;                      /* fades in as the fan opens */
  pointer-events:none;
}
.yearbar__title{
  text-align:center; color:var(--clay); opacity:.7;
  letter-spacing:.2em; text-transform:uppercase; font-size:.58rem; margin-bottom:.45rem;
}
.yearbar__grid{ display:grid; grid-template-columns:repeat(12, 1fr); gap:3px; }
.yearbar__col{ display:flex; flex-direction:column; align-items:center; gap:.22rem; }
.yearbar__m{ font-size:.62rem; opacity:.55; letter-spacing:.06em; }
.yearbar__band{
  display:block; width:100%; height:6px; border-radius:2px;
  background:var(--petrol); opacity:.85;
}
.yearbar__col--dry .yearbar__band{ background:var(--amber); }
.yearbar__t{ font-size:.6rem; opacity:.5; }
/* the month you are actually in */
.yearbar__col.is-now .yearbar__m{ opacity:1; color:var(--clay); }
.yearbar__col.is-now .yearbar__band{ opacity:1; height:11px; margin-block:-2.5px; }
.yearbar__col.is-now .yearbar__t{ opacity:.95; }
.yearbar__key{
  display:flex; align-items:center; justify-content:center; gap:.4rem;
  flex-wrap:wrap; margin-top:.5rem; font-size:.58rem; opacity:.6;
}
.yearbar__dot{ width:9px; height:9px; border-radius:2px; display:inline-block; }
.yearbar__dot--green{ background:var(--petrol); }
.yearbar__dot--dry{ background:var(--amber); margin-left:.8rem; }
.yearbar__avg{ margin-left:.9rem; opacity:.8; }

/* Without motion nothing pins or fans the cards, so the section would be
   2160px of empty scroll with a pile in the middle. Lay it out flat instead,
   exactly as the phone breakpoint does. */
html.no-motion .stayzone{ height:auto; }
html.no-motion .stay--photo{ height:auto; }
html.no-motion .reviews{ margin-bottom:0; }
html.no-motion .yearbar{ opacity:1; }
@media (prefers-reduced-motion: reduce){ .yearbar{ opacity:1; } }

html.no-motion .seasons{ height:auto; padding-block:var(--sec); }
html.no-motion .seasons__pin{ height:auto; overflow:visible; }
html.no-motion .seasons__head{ padding-top:0; }
html.no-motion .seasons__prompt{ display:none; }   /* nothing to scroll open */
html.no-motion .yearbar{
  position:static; transform:none; width:min(900px, 90vw); margin:1.8rem auto 0;
}
html.no-motion .seasons__stage{
  position:static; display:grid; grid-template-columns:repeat(3, 1fr);
  gap:1rem; padding:2.2rem var(--pad) 0; max-width:var(--wrap); margin-inline:auto;
}
html.no-motion .scard{
  position:static; width:auto; transform:none !important; aspect-ratio:3/4;
}
html.no-motion .scard--core{
  grid-column:1 / -1; width:auto; aspect-ratio:16/7;
  flex-direction:row; gap:2px;
}
html.no-motion .scard--core .scard__half{ border-radius:6px; }
html.no-motion .scard__half + .scard__half{ margin-top:0; }
html.no-motion .seasons__hint{
  position:static; transform:none; text-align:center; margin-top:1.6rem;
}

/* ── reviews: testimonials arriving from both sides ──────── */
/* same light zone as guest services, paper texture and all */
.reviews{
  background:var(--bone); color:var(--ink); padding-block:var(--sec);
  position:relative; overflow:clip; --drift:120px;
}
.reviews > .wrap{ position:relative; z-index:1; }

/* Penjor: the curved Galungan bamboo the culture notes describe, flanking
   the guest voices. Sits above the paper backdrop and below the cards, and
   rides the zone slower than the paper so the two layers pull apart.    */
.reviews__deco{ position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
.reviews__pole{
  /* nearly as tall as the backdrop image (100svh + 240px), planted with its
     base below the fold so only the arch and shaft ever read as an edge */
  position:absolute; top:16svh; height:118svh; width:auto;
  opacity:.5; will-change:transform;
}
.reviews__pole--l{ left:min(-3vw, -20px); }
.reviews__pole--r{ right:min(-3vw, -20px); }

/* No motion: nothing drives the offset, so hold them mid-zone */
html.no-motion .reviews__pole{ top:50%; transform:translateY(-50%); }
@media (prefers-reduced-motion: reduce){
  .reviews__pole{ top:50%; transform:translateY(-50%); }
}

.reviews__head{ text-align:center; max-width:44rem; margin:0 auto clamp(3rem,7vw,5.5rem); }
.reviews__head .eyebrow{ color:var(--clay); }
.reviews__head h2{ margin-bottom:1.4rem; }
.reviews__score{
  display:flex; align-items:center; justify-content:center; gap:1rem;
  margin-bottom:1.1rem;
}
.reviews__num{
  font-family:var(--font-display); font-size:clamp(3rem,7vw,4.6rem);
  line-height:1; color:var(--ink);
}
.reviews__of{ display:flex; flex-direction:column; align-items:flex-start; gap:.25rem; }
.reviews__stars{ color:var(--amber); letter-spacing:.14em; font-size:.9rem; }
.reviews__of .mono{ opacity:.6; }

/* the stream: cards step down the page, alternating sides */
.tstream{ display:flex; flex-direction:column; gap:clamp(1.6rem,4vw,3rem); }
.tcard{
  width:min(560px, 88%);
  background:#f6f1e4; color:var(--ink);
  border:1px solid rgba(23,21,15,.14); border-radius:8px;
  padding:clamp(1.5rem,3vw,2.1rem);
  box-shadow:0 22px 50px -34px rgba(23,21,15,.5);
  will-change:transform;
}
.tcard--l{ align-self:flex-start; }
.tcard--r{ align-self:flex-end; }
.tcard__head{ display:flex; align-items:center; gap:.85rem; margin-bottom:1rem; }
.tcard__ava{
  flex:none; width:44px; height:44px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:radial-gradient(circle at 30% 30%, var(--petrol), var(--petrol-d));
  color:var(--bone); font-family:var(--font-display); font-size:1.15rem;
  border:1px solid var(--amber);
}
.tcard__who{ display:flex; flex-direction:column; gap:.1rem; margin-right:auto; min-width:0; }
.tcard__name{ font-weight:600; font-size:1rem; }
.tcard__meta{ opacity:.55; font-size:.68rem; }
.tcard__stars{ color:var(--amber); letter-spacing:.1em; font-size:.72rem; flex:none; }
.tcard__quote{
  font-family:var(--font-display); font-size:clamp(1.1rem,1.9vw,1.4rem);
  line-height:1.45; letter-spacing:.004em;
}
.tcard__quote::before{ content:"“"; }
.tcard__quote::after{ content:"”"; }

/* the numbers behind the words */
.tsummary{
  margin-top:clamp(3rem,7vw,5rem); padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid rgba(23,21,15,.16); text-align:center;
}
.tsummary__title{
  letter-spacing:.2em; text-transform:uppercase; color:var(--clay);
  margin-bottom:1.6rem; font-size:.68rem;
}
.tsummary__grid{
  list-style:none; display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  gap:.9rem 2.2rem; max-width:52rem; margin:0 auto 1.8rem;
}
.tscore{ display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:.7rem; }
.tscore__label{ font-size:.85rem; opacity:.8; white-space:nowrap; }
.tscore__bar{
  height:3px; border-radius:2px; background:rgba(23,21,15,.15); overflow:hidden;
}
.tscore__bar i{ display:block; height:100%; background:var(--amber); }
.tscore__val{ font-size:.72rem; color:var(--clay); }
.tsummary__note{ opacity:.72; font-size:.95rem; margin-bottom:1.5rem; }
.tsummary strong{ font-weight:600; color:var(--ink); }

/* ── stay: twilight backdrop ─────────────────────────────── */
/* Revealed from underneath: the zone starts one viewport early so the
   testimonials sit over it, and the sticky screen holds for exactly that
   viewport before releasing. The zone bounds the stickiness, otherwise the
   booking screen would stay pinned over the team, contact and footer. */
/* NOTE: position:sticky cannot be used here. ScrollSmoother puts
   overflow:hidden on its wrapper, which kills sticky for every descendant.
   The hold is done with a ScrollTrigger pin in main.js instead. */
.stayzone{ position:relative; z-index:0; height:200svh; }
.stay--photo{
  height:100svh; display:flex; align-items:center; overflow:hidden;
}
.reviews{ position:relative; z-index:1; margin-bottom:-100svh; }
.stay{ background:var(--ink); color:var(--bone); padding-block:var(--sec); }
.stay h2{ color:var(--bone); font-size:clamp(2.4rem,5.4vw,4rem); margin-bottom:1.2rem; }
.stay .eyebrow{ color:var(--amber-2); }
.stay__grid{ display:grid; grid-template-columns:6fr 5fr; gap:clamp(2rem,5vw,5rem); align-items:start; }
.stay__pitch > p{ opacity:.85; max-width:34rem; }
.stay__perks{ list-style:none; margin-block:1.6rem; display:flex; flex-direction:column; gap:.6rem; }
.stay__perks li{ padding-left:1.4rem; position:relative; opacity:.85; }
.stay__perks li::before{ content:"—"; position:absolute; left:0; color:var(--amber-2); }
.stay__price{ display:flex; align-items:baseline; gap:.8rem; flex-wrap:wrap; margin-bottom:1.8rem; }
.stay__price .mono{ opacity:.55; }
.stay__price s{ opacity:.5; font-size:1.2rem; }
.stay__price strong{ font-family:var(--font-display); font-weight:400; font-size:2.6rem; color:var(--amber-2); }
.stay__price strong i{ font-style:normal; font-size:.4em; }
.stay__actions{ display:flex; gap:.9rem; flex-wrap:wrap; }

.cal{ border:1px solid rgba(241,234,217,.16); border-radius:var(--r); padding:1.4rem; background:var(--ink-2); }
.cal__head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:1rem; }
.cal__head h3{ font-family:var(--font-mono); font-size:.85rem; letter-spacing:.18em; text-transform:uppercase; color:var(--bone); }
.cal__nav{ background:none; border:1px solid rgba(241,234,217,.2); color:var(--bone);
  width:34px; height:34px; border-radius:var(--r); transition:border-color .2s; }
.cal__nav:hover{ border-color:var(--amber-2); }
.cal__nav[disabled]{ opacity:.3; }
.cal__grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:4px; font-size:.72rem; }
.cal__grid .cal__dow{ text-align:center; opacity:.45; padding-block:.35rem; }
.cal__day{
  aspect-ratio:1; display:flex; align-items:center; justify-content:center;
  border-radius:3px; background:rgba(241,234,217,.06); position:relative;
}
.cal__day--busy{ background:rgba(156,91,65,.35); color:rgba(241,234,217,.45); text-decoration:line-through; }
.cal__day--free:hover{ background:rgba(226,171,85,.25); }
.cal__day--pad{ background:transparent; }
.cal__legend{ display:flex; gap:1.4rem; margin-top:1rem; opacity:.7; }
.cal__dot{ display:inline-block; width:9px; height:9px; border-radius:2px; margin-right:.4rem; }
.cal__dot--free{ background:rgba(241,234,217,.25); }
.cal__dot--busy{ background:rgba(156,91,65,.7); }
.cal__note{ margin-top:.8rem; opacity:.5; }

.stay__bg{
  position:absolute; inset:0;
  background:url('../assets/img/hero-twilight.jpg') center/cover;
}
.stay__bg::after{ content:""; position:absolute; inset:0;
  background:linear-gradient(100deg, rgba(23,21,15,.93) 30%, rgba(23,21,15,.78) 100%); }
.stay--photo .wrap{ position:relative; z-index:1; }
.stay--photo .cal{ background:rgba(33,30,21,.72); backdrop-filter:blur(10px); }

/* ── team: sticky photo + cards ──────────────────────────── */
.team{
  background:var(--bone); padding-block:var(--sec);
  position:relative; z-index:1; overflow:clip; --drift:120px;
}
.team > .wrap{ position:relative; z-index:1; }
.team-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:1.2rem; }
.member{
  border:1px solid rgba(23,21,15,.14); border-radius:var(--r);
  background:#f6f1e4; overflow:hidden; display:flex; flex-direction:column;
}
/* Portrait band. Placeholder art for now, sized to the final crop so real
   photography drops in without touching the layout. */
.member__photo{
  /* height:auto is load-bearing: the width/height attributes map to CSS
     presentation hints, so without it height=1000 wins over aspect-ratio */
  display:block; width:100%; height:auto; aspect-ratio:4/5; object-fit:cover;
  background:var(--petrol-d);
}
.member__body{ padding:1.5rem 1.4rem 1.7rem; }
.member h3{ font-size:1.25rem; }
.member__role{ color:var(--clay); margin:.25rem 0 .7rem; }
.member p:last-child{ font-size:.88rem; opacity:.8; }
.sec-head--center{ margin-inline:auto; text-align:center; }

/* A canang sari drifting down the left margin of the team section, the daily
   offering the housekeeping team actually lays out. Sits behind the cards and
   turns slightly as it falls, so it reads as placed rather than pasted. */
/* --gut is the margin between the viewport edge and the card column; each
   offering is centred inside its own gutter, so nothing is ever clipped. */
.team{ --gut:calc((100vw - min(1200px, 100vw)) / 2 + var(--pad)); }
.team__offering{
  position:absolute; z-index:0; pointer-events:none; user-select:none;
  height:auto; opacity:.9;
  filter:drop-shadow(0 22px 34px rgba(23,21,15,.22));
  will-change:transform;
}
.team__offering--l{
  --ow:clamp(112px, 9.5vw, 200px);
  width:var(--ow); left:calc((var(--gut) - var(--ow)) / 2); top:13%;
}
/* 60% of the left one and set lower down the section */
.team__offering--r{
  --ow:clamp(67px, 5.7vw, 120px);
  width:var(--ow); right:calc((var(--gut) - var(--ow)) / 2); top:31%;
}
@media (max-width: 1180px){ .team__offering{ opacity:.5; } }
/* behind the cards it would only muddy them at phone widths */
@media (max-width: 900px){ .team__offering{ display:none; } }

/* ── contact ─────────────────────────────────────────────── */
.contact{ background:var(--bone-2); padding-block:var(--sec); position:relative; z-index:1; }
.contact__grid{ display:grid; grid-template-columns:5fr 7fr; gap:clamp(2rem,5vw,5rem); align-items:start; }
.contact__info h2{ margin-bottom:1rem; }
.contact__info > p{ opacity:.85; max-width:26rem; }
.contact__list{ list-style:none; margin-top:2rem; display:flex; flex-direction:column; gap:1.1rem; }
.contact__list li{ display:grid; grid-template-columns:110px 1fr; gap:1rem; font-size:.82rem; }
.contact__list span{ opacity:.5; text-transform:uppercase; letter-spacing:.1em; }
.contact__list a{ color:var(--petrol); }
.contact__formhead{
  font-size:1.25rem; margin-bottom:1.4rem;
  padding-bottom:.9rem; border-bottom:1px solid rgba(23,21,15,.14);
}

/* ── forms ───────────────────────────────────────────────── */
.form{ display:flex; flex-direction:column; gap:1.1rem; }
.form[hidden]{ display:none; }
.form__row{ display:grid; grid-template-columns:1fr 1fr; gap:1.1rem; }
.form label{
  display:flex; flex-direction:column; gap:.4rem;
  font-family:var(--font-mono); font-size:.72rem; letter-spacing:.08em;
  text-transform:uppercase; opacity:.9;
}
.form input, .form select, .form textarea{
  font-family:var(--font-body); font-size:.95rem; color:var(--ink);
  padding:.8rem .9rem; border:1px solid rgba(23,21,15,.22); border-radius:var(--r);
  background:var(--bone); transition:border-color .2s;
}
.form input:focus, .form select:focus, .form textarea:focus{ outline:none; border-color:var(--petrol); }
.form textarea{ resize:vertical; }
.form .btn{ align-self:flex-start; }
.form__done{ color:var(--petrol); }

/* ── footer ──────────────────────────────────────────────── */
.footer{
  background:var(--ink); color:var(--bone);
  padding-block:clamp(3rem,6vw,4.5rem); position:relative; z-index:1;
}
.footer__mark{ overflow:hidden; text-align:center;
  margin-bottom:clamp(2rem,5vw,3.5rem); padding-inline:var(--pad); }
.footer__markwrap{ position:relative; display:inline-block; line-height:0; }
.footer__mark img:not(.footer__one){
  width:min(100%, 640px); height:auto; margin-inline:auto;
  opacity:.62; transition:opacity .7s;
  filter:drop-shadow(0 0 30px rgba(241,234,217,.16));
}
/* One tucked under the tail, kept as quiet as the faded wordmark it sits on */
.footer__one{
  position:absolute; right:-.5%; bottom:1%;
  width:clamp(2.4rem, 7vw, 4.4rem); height:auto;
  opacity:.82; pointer-events:none;
}
.footer__mark:hover .footer__one{ opacity:1; }
.footer__mark:hover img{ opacity:1; }
.footer__grid{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:2rem; align-items:start; }
.footer__brand{ font-family:var(--font-display); letter-spacing:.24em; font-size:1.3rem; margin-bottom:.8rem; }
.footer .mono{ opacity:.6; line-height:2; }
.footer__nav{ display:grid; grid-template-columns:1fr 1fr; gap:.2rem 2rem; }
.footer__nav a{ text-decoration:none; opacity:.7; }
.footer__nav a:hover{ opacity:1; }
.footer__meta a{ color:var(--amber-2); }
.footer__credit{ font-size:.62rem; opacity:.45; }

/* ── floating book pill ──────────────────────────────────── */
.bookpill{
  position:fixed; right:1.3rem; bottom:1.3rem; z-index:68;
  display:flex; align-items:center; gap:.55rem;
  font-family:var(--font-mono); font-size:.74rem; letter-spacing:.08em; text-transform:uppercase;
  background:var(--amber); color:var(--ink); text-decoration:none;
  padding:.85rem 1.25rem; border-radius:99px;
  box-shadow:0 14px 34px -12px rgba(23,21,15,.6);
  opacity:0; transform:translateY(16px); pointer-events:none;
  transition:opacity .4s, transform .4s, background .25s;
}
.bookpill.is-on{ opacity:1; transform:translateY(0); pointer-events:auto; }
.bookpill:hover{ background:var(--amber-2); }
.bookpill em{ font-style:normal; opacity:.65; }
.bookpill__dot{ width:7px; height:7px; border-radius:50%; background:var(--petrol-d);
  animation:pilldot 2s ease-in-out infinite; }
@keyframes pilldot{ 0%,100%{ opacity:.5; } 50%{ opacity:1; } }

/* ── selection ───────────────────────────────────────────── */
::selection{ background:var(--amber); color:var(--ink); }

/* ── film grain ──────────────────────────────────────────── */
.grain{
  position:fixed; inset:-50%; z-index:90; pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity:.05; animation:grain 9s steps(6) infinite;
}
@keyframes grain{
  0%,100%{ transform:translate(0,0); } 20%{ transform:translate(-6%,4%); }
  40%{ transform:translate(4%,-6%); } 60%{ transform:translate(-3%,-4%); } 80%{ transform:translate(5%,5%); }
}

/* ── custom cursor: Balinese topeng mask ─────────────────── */
@media (pointer:fine){
  .cursor{
    display:block; position:fixed; top:0; left:0; z-index:96; pointer-events:none;
    opacity:0; transition:opacity .3s;
  }
  .cursor.is-live{ opacity:1; }
  /* The mask's point sits at 6.7% / 1.2% of the artwork, so anchor that spot
     to the pointer and pivot every transform around it. */
  .cursor__mask{
    display:block; height:52px; width:auto;
    transform:translate(-6.7%, -1.2%);
    transform-origin:6.7% 1.2%;
    filter:drop-shadow(0 4px 10px rgba(23,21,15,.35));
    transition:transform .3s cubic-bezier(.34,1.56,.64,1);
  }
  .cursor.is-hover .cursor__mask{ transform:translate(-6.7%, -1.2%) scale(1.22) rotate(-7deg); }
  .cursor.is-label .cursor__mask{ transform:translate(-6.7%, -1.2%) scale(1.12) rotate(6deg); }
  .cursor__label{
    position:absolute; top:26px; left:28px;
    width:74px; height:74px; border-radius:50%;
    display:flex; align-items:center; justify-content:center; text-align:center;
    font-size:.56rem; letter-spacing:.12em; text-transform:uppercase; line-height:1.25;
    padding:.4rem; color:var(--bone);
    background:rgba(23,21,15,.34);
    backdrop-filter:blur(9px) saturate(1.3);
    -webkit-backdrop-filter:blur(9px) saturate(1.3);
    border:1px solid rgba(241,234,217,.34);
    opacity:0; transform:scale(.82); transition:opacity .22s, transform .28s cubic-bezier(.34,1.56,.64,1);
  }
  .cursor.is-label .cursor__label{ opacity:1; transform:scale(1); }
  /* Universal, not an allow-list. The previous rule named a, button and the
     gallery track, so every component that set its own cursor — the culture
     panels, the accordion summaries, form labels and fields — punched a hole
     in the illusion and showed a native hand or beam. */
  html.has-cursor, html.has-cursor *{ cursor:none; }
}
html.film-open .cursor{ display:none; }
/* the film plays in a native video frame, so the real cursor comes back —
   higher specificity than the universal rule above, deliberately */
html.film-open.has-cursor,
html.film-open.has-cursor *{ cursor:auto; }

/* ── scroll progress + nav hide ──────────────────────────── */
.progress{
  position:fixed; top:0; left:0; right:0; height:2px; z-index:66;
  background:var(--amber); transform-origin:0 50%; transform:scaleX(0);
  pointer-events:none;
}
.nav{ transition:background .35s, box-shadow .35s, padding .35s, transform .45s cubic-bezier(.4,0,.2,1); }
.nav.is-hidden{ transform:translateY(-110%); }

/* ── SplitText line masks ────────────────────────────────── */
.st-mask{ overflow:hidden; }
.st-line{ will-change:transform; }

/* ── gallery drag affordances ────────────────────────────── */
.gallery{ position:relative; }
.gallery__track{ cursor:grab; touch-action:pan-y; }
.gallery__track.is-dragging{ cursor:grabbing; }
.gallery__track figure{ position:relative; }
.gallery__track img{ pointer-events:none; }
.gallery__progress{
  position:absolute; left:var(--pad); right:var(--pad); bottom:1.6rem;
  height:1px; background:rgba(241,234,217,.15);
}
.gallery__progress i{
  display:block; height:100%; background:var(--amber-2);
  transform-origin:0 50%; transform:scaleX(.08);
}
.gallery__hint{
  position:absolute; top:1.6rem; right:var(--pad);
  color:var(--bone); opacity:.5; letter-spacing:.22em; text-transform:uppercase;
}

/* ── lightbox ────────────────────────────────────────────── */
.lightbox{
  position:fixed; inset:0; z-index:85; background:rgba(23,21,15,.96);
  display:flex; align-items:center; justify-content:center; gap:1rem;
  padding:clamp(1rem,4vw,3rem);
}
.lightbox__stage{ max-width:min(1100px, 88vw); text-align:center; }
.lightbox__stage img{
  max-height:78vh; max-width:100%; width:auto; margin-inline:auto;
  border-radius:var(--r); object-fit:contain;
}
.lightbox__stage figcaption{
  display:flex; justify-content:space-between; gap:1rem;
  color:var(--bone); opacity:.65; margin-top:1rem;
}
.lightbox__x{
  position:absolute; top:1.2rem; right:1.4rem; z-index:2;
  background:none; border:0; color:var(--bone); font-size:2.2rem; line-height:1; opacity:.7;
}
.lightbox__x:hover{ opacity:1; }
.lightbox__nav{
  flex-shrink:0; width:54px; height:54px; border-radius:50%;
  background:rgba(241,234,217,.06); border:1px solid rgba(241,234,217,.25);
  color:var(--bone); font-size:1.1rem; transition:background .25s, border-color .25s;
}
.lightbox__nav:hover{ background:rgba(226,171,85,.2); border-color:var(--amber-2); }

/* ── culture: the language table ─────────────────────────── */
.phrase__title{ letter-spacing:.2em; text-transform:uppercase; color:var(--amber-2); margin-bottom:1.2rem; }
.phrase__table{ width:100%; border-collapse:collapse; }
.phrase__table td{ padding:.6rem 0; border-bottom:1px solid rgba(241,234,217,.1); font-size:.95rem; }
.phrase__table td:first-child{ font-family:var(--font-display); font-size:1.05rem; padding-right:1.5rem; white-space:nowrap; }
.phrase__table i{ font-style:normal; opacity:.5; font-size:.7rem; }

/* ═══ responsive ═════════════════════════════════════════ */
@media (max-width: 1024px){
  .team-grid{ grid-template-columns:repeat(2,1fr); }
  .area-cards{ grid-template-columns:repeat(2,1fr); }
  /* cards now span most of the width, so pull the penjor further out */
  .reviews__pole{ height:70svh; opacity:.38; }
  .reviews__pole--l{ left:-8vw; }
  .reviews__pole--r{ right:-8vw; }
}
/* No room beside the cards on a phone: the poles would only sit behind them */
@media (max-width: 760px){ .reviews__deco{ display:none; } }
@media (max-width: 900px){
  /* No pinned film timeline below 900, so the section must not reserve 460vh
     for an animation that never runs — that reserve rendered as screens of
     bare ink. And .film__frame's scale(.3) is only ever undone by that same
     timeline, so it is reset here and re-animated by initFilmGrow(). */
  .film{ height:auto; }
  .film__pin{ height:auto; overflow:visible; }
  .film__frame{ transform:none; }
  /* matches the JS threshold: above 900 the pinned timeline slides these
     panels sideways, below it there is no animation, so they must stack */
  .ftrack{ position:static; width:100%; flex-direction:column; transform:none !important; }
  .ftrack__panel{ width:100%; height:auto; }
  .ftrack__panel--film{ height:100svh; }
  .ftrack__panel--svc{ padding-block:var(--sec); }
  .nav__links, .nav__cta, .nav__portal{ display:none; }
  /* no reveal-from-underneath on phones: keep booking in normal flow */
  .stayzone{ height:auto; }
  .stay--photo{ height:auto; }
  .reviews{ margin-bottom:0; }
  /* No room to fan on a phone — lay the year out as a legible grid instead. */
  .trip{ flex-direction:column; min-height:0; }
  .trip__panel{ min-height:150px; flex:none; }
  .trip__panel.is-open{ flex:none; }
  .nav__burger{ display:flex; margin-left:auto; }
  .feature, .feature--flip{ grid-template-columns:1fr; gap:1.4rem; }
  .feature--flip .feature__img{ order:0; }
  .location__grid{ grid-template-columns:1fr; }
  .location__map iframe{ min-height:300px; }
  .culture__lower{ grid-template-columns:1fr; }
  .stay__grid{ grid-template-columns:1fr; }
  .contact__grid{ grid-template-columns:1fr; }
  .footer__grid{ grid-template-columns:1fr; gap:2.5rem; }
}
@media (max-width: 900px){
  .hero__rail{ display:none; }
  /* no page margin to bleed into on small screens — sit at the block edge */
  .feature__numeral,
  .feature--flip .feature__numeral{
    height:clamp(9rem, 33vw, 13.5rem); top:auto; bottom:-.5rem;
    right:0; left:auto; opacity:.24;
  }
}
@media (max-width: 640px){
  .amen__facts{ grid-template-columns:1fr; gap:1.1rem; }
  /* one row at any width: the buttons share the space and wrap their own text
     rather than the toggle dropping to a second line */
  .hero__actions{ gap:.45rem; }
  .hero__actions .btn{ flex:1 1 0; min-width:0; padding:.6rem .55rem;
    font-size:.74rem; text-align:center; line-height:1.2; }
  .hero__actions .hum{ flex:0 0 auto; }
  /* two-up on phones: the card keeps desktop type otherwise, and a 20px name
     with 1.5rem padding leaves a ~90px measure that breaks every third word */
  .team-grid{ gap:.75rem; }
  .member__body{ padding:1rem .9rem 1.2rem; }
  .member h3{ font-size:1.05rem; }
  .member__role{ font-size:.72rem; margin:.2rem 0 .5rem; }
  .member p:last-child{ font-size:.8rem; line-height:1.45; }
  .intro__stats{ grid-template-columns:repeat(2,1fr); }
  .amenlist{ columns:1; }
  .tcard{ width:100%; }
  .tsummary__grid{ grid-template-columns:1fr; gap:.7rem; }
  .reviews__score{ flex-direction:column; gap:.5rem; }
  .reviews__of{ align-items:center; }
  .smodal__card{ grid-template-columns:1fr; }
  .smodal__nav{ width:38px; height:38px; }
  .smodal__img img{ max-height:32svh; }
  .film__note{ white-space:normal; width:82%; }
  .vmodal__crest{ width:70%; }
  .svcrow__hit{ grid-template-columns:2.2rem 1fr; padding:1.1rem .4rem; gap:.4rem 1rem; }
  .svcrow__arrow{ display:none; }
  .svcrow__price{ grid-column:2; justify-self:start; font-size:.7rem; }
  .quotes__mark{ font-size:6rem; }
  .bookpill{ right:.9rem; bottom:.9rem; padding:.75rem 1.05rem; }
  .area-cards{ grid-template-columns:1fr; }
  .form__row{ grid-template-columns:1fr; }
  /* two columns get cramped well before the panel runs out of room */
  .amen{ grid-template-columns:1fr; align-items:start; }
  .amen__facts{ grid-template-columns:1fr 1fr; }
  /* the row wraps to stacked blocks here, where ranged-right body text reads
     badly and there is no button beside it to align to */
  .hero__row{ justify-content:flex-start; }
  .hero__line{ text-align:left; }
  .hero__foot{ justify-content:center; }
  .hero__foot .mono:last-child{ display:none; }
  .hum{ width:46px; height:46px; }
  .hum__bars{ height:18px; gap:2.5px; }
  .hum__bars i{ width:2.5px; }
  .hum__mute{ width:20px; height:20px; }
  .hum--float{ right:.9rem; bottom:.9rem; }
  body:has(.hum--float.is-shown) .bookpill{ right:4.1rem; }
}

/* ═══ reduced motion ═════════════════════════════════════ */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *, *::before, *::after{ animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; }
  .gate{ display:none; }
  .feature__img img{ transform:none; }
}


/* The seasons fan is laid out with absolute percentage offsets tuned for a
   desktop canvas. Below ~1100px the cards land on top of the heading, so the
   grid fallback takes over there instead — this threshold must stay in step
   with the one guarding the fan in main.js. */
@media (max-width: 1100px){
}


/* The seasons fan places cards with absolute percentage offsets tuned for a
   desktop canvas; below ~1100px they land on top of the heading. The grid
   fallback takes over there instead. Keep this threshold in step with the one
   guarding the fan in main.js. */
@media (max-width: 1100px){
  .seasons{ height:auto; padding-block:var(--sec); }
  .seasons__pin{ height:auto; overflow:visible; }
  .seasons__head{ padding-top:0; }
  .seasons__sub{ opacity:.75 !important; transform:none !important; }
  .seasons__prompt{ display:none; }
  .seasons__stage{
    position:static; display:grid; grid-template-columns:1fr 1fr;
    gap:.7rem; padding:2rem var(--pad) 0; max-width:var(--wrap); margin-inline:auto;
  }
  .scard{
    position:static; width:auto; transform:none !important;
    aspect-ratio:3/4; opacity:1 !important;
  }
  .scard--core{
    grid-column:1 / -1; width:auto; aspect-ratio:16/10;
    flex-direction:row; gap:2px;
  }
  .scard--core .scard__half{ border-radius:6px; }
  .scard__half + .scard__half{ margin-top:0; }
  .scard__half:hover{ flex:1; }
  .seasons__hint{ position:static; transform:none; text-align:center; margin-top:1.4rem; }
  .yearbar{ position:static; transform:none; opacity:1 !important; width:auto;
    margin:1.6rem var(--pad) 0; }
  .yearbar__t{ display:none; }
  .yearbar__avg{ margin-left:0; width:100%; text-align:center; margin-top:.3rem; }
  .seasons .backdrop__img{ top:0; height:100%; }
}

/* ── modals on touch devices ──────────────────────────────────
   Three fixes, all only observable on a phone:

   1. Scrolling. The card stacked image-over-body and let the body carry its own
      max-height, so image + body could exceed the card while the card itself was
      overflow:visible — content ran off the bottom with nothing to scroll. The
      card is the scroll container here and the body just flows.
   2. Height. svh is the *small* viewport (toolbar showing), so sizing to it and
      padding by the safe-area inset keeps the card clear of Safari's chrome
      whether the toolbar is expanded or collapsed.
   3. The close control. It was a 19x32 ink glyph on no background, sitting over
      the photo at the top of the stacked card: invisible, and half the minimum
      tap size. It gets a legible chip and a 44px target. */
@media (max-width: 640px), (pointer: coarse) and (max-width: 900px){
  .smodal, .amodal{
    padding:.75rem;
    padding-bottom:calc(.75rem + env(safe-area-inset-bottom));
    align-items:flex-start;
  }
  .smodal__card, .amodal__card{
    max-height:calc(100svh - 1.5rem - env(safe-area-inset-bottom));
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior:contain;
    margin-top:.75rem;
  }
  /* the body no longer competes with the card for the scroll */
  .smodal__body{ max-height:none; overflow:visible; }
  .amodal__body{ overflow:visible; }
  .amodal__top{ position:sticky; top:0; z-index:2; background:var(--bone); }

  /* room for the prev/next chips pinned to the card's bottom edge */
  .smodal__body{ padding-bottom:4.2rem; }

  /* fixed, not absolute: the card is now the scroll container, so anything
     anchored to it scrolls away — on a short screen the close control vanished
     as soon as you reached the middle of a long service description. */
  .smodal__x, .vmodal__x{
    position:fixed; top:1.15rem; right:1.15rem; z-index:5;
  }
  .smodal__nav{
    position:fixed; bottom:calc(1.1rem + env(safe-area-inset-bottom)); top:auto;
    transform:none; z-index:5;
  }
  .smodal__nav--prev{ left:auto; right:4.6rem; }
  .smodal__nav--next{ right:1.15rem; }
  /* clear of the 38px prev chip, which ends at ~7rem from the right edge */
  .smodal__count{ position:fixed; bottom:calc(1.9rem + env(safe-area-inset-bottom)); right:7.8rem; z-index:5; }

  .smodal__x, .amodal__x, .vmodal__x{
    z-index:5;
    width:44px; height:44px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    font-size:1.5rem; line-height:1; opacity:1;
    color:var(--bone); background:rgba(23,21,15,.62);
    backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
    border:1px solid rgba(241,234,217,.28);
  }
  .amodal__x{ position:sticky; float:right; margin:-.4rem -.4rem 0 0; }
}

/* ── touch ergonomics ─────────────────────────────────────────
   Applies wherever the primary input is a finger, at any width.
   44px is the Apple HIG / WCAG target minimum; 16px inputs stop iOS
   zooming the page the moment a field takes focus. */
@media (pointer: coarse){
  .form input, .form select, .form textarea{ font-size:16px; min-height:44px; }
  .form textarea{ min-height:110px; }
  .btn{ min-height:44px; display:inline-flex; align-items:center; justify-content:center; }
  .nav__burger{ width:44px; height:44px; }
  .nav__brand{ display:inline-flex; align-items:center; min-height:44px; }
  .cal__nav{ width:44px; height:44px; }
  /* min-height is deterministic where guessed padding kept landing at 37-43px */
  .area-card__link,
  .contact__list a,
  .footer__nav a,
  .footer__meta a,
  .location__coords a{
    display:inline-flex; align-items:center; min-height:44px;
  }
  /* the fixed pair need clearance from the gesture bar */
  .bookpill{ bottom:calc(.9rem + env(safe-area-inset-bottom)); }
  .bookpill, .hum--float{ bottom:max(.9rem, calc(.9rem + env(safe-area-inset-bottom))); }
  .hum--float{ bottom:calc(.9rem + env(safe-area-inset-bottom)); }
}
