/* ==========================================================================
   Royal Paark Resort — design system
   Palette sampled from the supplied logo (navy #001848-#001860, gold
   #f0d878-#f0d890), matching the Welcome Call: "the logo's golden-and-blue
   colour palette and a standard, legible font".

   CONTRAST NOTE (measured, not assumed): white on gold is 2.42:1 and FAILS AA.
   Gold surfaces therefore always carry NAVY text, never white. Every other
   pairing used here measures 6.38:1 or better.
   ========================================================================== */

:root {
  /* ---- brand ---- */
  --navy:       #0B2154;   /* logo blue */
  --navy-deep:  #071539;
  --navy-soft:  #21386B;
  --gold:       #C9A227;   /* logo gold, darkened for text use */
  --gold-lt:    #E8C86A;
  --gold-pale:  #F3E4BC;
  /* Gold at --gold measures only 2.28:1 as SMALL TEXT on cream and fails AA.
     Bright gold stays for FILLS and large display; small gold text uses this
     darker tone (5.53:1 on cream, 5.11:1 on sand). */
  --gold-text:  #7A6213;

  --ink:        #0D1220;   /* near-black navy — the dark ground */
  --ink-2:      #131A2C;   /* second dark tone for stacked dark bands */
  --body:       #3B4150;
  --muted:      #626981;   /* 4.5:1 on BOTH paper tones (was 4.26 on paper-2) */
  --line:       #E3E6EB;

  /* COOL off-white, not warm cream. The reference pairs warm cream with GOLD;
     against this logo's NAVY the same cream reads pink. These are neutral-cool
     so the navy stays the brand colour and nothing shifts warm. */
  --paper:      #F7F8FA;
  --paper-2:    #EDF0F4;
  --white:      #FFFFFF;

  /* legacy aliases so nothing breaks mid-refactor */
  --cream:      #F7F8FA;
  --sand:       #EDF0F4;

  /* ---- type ---- */
  /* TWO fonts only.
     Head  — Playfair Display: a high-contrast serif with sharp flat serifs,
             which is what the logo wordmark "ROYAL PAARK" actually is.
     Body  — Montserrat, exactly as the design reference uses. */
  --font-head: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-body: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* ---- layout ---- */
  --maxw:      min(1280px, 80vw);
  /* Breathing room: the column is capped at 80vw, holding an extra 10% of the
     viewport back on EACH side, and still never exceeds 1280px. This lives on
     --maxw rather than --gutter because the gutter is also the small-screen
     floor and the offset for the edge-to-edge swipe carousels. */
  --gutter:    clamp(1.15rem, 4vw, 3.5rem);
  --header-h:  86px;

  /* Single sources of truth for rhythm — never re-declare these locally.
     Three card grids on three different clamp scales once drifted apart and
     never agreed at any width. */
  --card-gap:    clamp(1.1rem, 2.2vw, 1.9rem);
  /* 60px top + 60px bottom = a 120px gap between any two sections. Flat,
     not fluid, so the rhythm is identical at every viewport. */
  --section-pad: 60px;

  --shadow-sm: 0 1px 3px rgba(11,33,84,.07), 0 6px 18px rgba(11,33,84,.05);
  --shadow-lg: 0 18px 50px rgba(11,33,84,.16);
  --ease: cubic-bezier(.22,.61,.36,1);
}

*, *::before, *::after { box-sizing: border-box; }
/* The header is position:fixed, so a plain #anchor jump lands its target
   right at the very top of the viewport — directly underneath the header,
   hidden from view. scroll-padding-top reserves that space for every
   in-page anchor site-wide (facilities.html#pool, #play-area, #games-room,
   terms-and-conditions.html#privacy, #cookies, etc). */
html {
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
  /* body alone had overflow-x:hidden; some mobile browsers (iOS Safari in
     particular) still let a horizontal drag rubber-band the page unless the
     html root is locked down too, so both get it plus overscroll-behavior. */
  overflow-x: hidden; overscroll-behavior-x: none;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--body);
  background: var(--paper);
  overflow-x: hidden; overscroll-behavior-x: none;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-head);
  color: var(--ink);
  font-weight: 400;
  line-height: 1.14;
  margin: 0 0 .6rem;
  letter-spacing: -.01em;
}
h1 { font-size: clamp(2.4rem, 5.4vw, 4.2rem); }
h2 { font-size: clamp(1.9rem, 3.6vw, 3.05rem); }
h3 { font-size: clamp(1.2rem, 1.7vw, 1.55rem); }
p  { margin: 0 0 1.05rem; }
a  { color: var(--ink); text-decoration: none; }
a:hover { color: var(--gold); }
img { max-width: 100%; height: auto; display: block; }
/* lazy images fade in once loaded instead of popping straight from a gray
   box mid-scroll; JS adds .lazy-fade only to images not already cached */
img.lazy-fade { opacity: 0; transition: opacity .4s var(--ease); }
img.lazy-fade.is-loaded { opacity: 1; }

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

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }

/* The extra 10% a side is a DESKTOP luxury. On a phone, 80vw plus the gutter
   leaves only ~276px of text on a 390px screen, so small screens go back to
   using the full width and rely on the gutter alone. */
@media (max-width: 700px) {
  :root { --maxw: 1280px; }
}

/* The footer keeps its ORIGINAL width sitewide — the wider side margin is for
   the page body only, so the footer band reads exactly as it did before. */
.footer .wrap { max-width: 1280px; }
.section { padding-block: var(--section-pad); }
.section--tint { background: var(--paper-2); }
/* Dark bands carry the brand. The reference alternates dark/light strictly and
   is dark-DOMINANT (7 of 12 sections); that rhythm is what makes it feel
   considered rather than a wall of cards. */
.section--dark { background: var(--ink); color: #C7CEDC; }
.section--dark h2, .section--dark h3, .section--dark h4 { color: #fff; }
.section--dark .eyebrow { color: var(--gold-lt); }
.section--dark .lead { color: #A9B2C4; }
.section--dark .card { background: var(--ink-2); box-shadow: none; border: 1px solid rgba(255,255,255,.08); }
.section--dark .card__title { color: #fff; }
.section--dark .card p { color: #A9B2C4; }
.section--dark .card__meta { color: #939CB0; }
.section--dark .btn--outline { color: #fff; border-color: rgba(255,255,255,.45); }
.section--dark .btn--outline:hover { background: #fff; color: var(--ink); }
.section--dark .usp p { color: #A9B2C4; }
.section--navy { background: var(--ink-2); color: #C7CEDC; }
.section--navy h2, .section--navy h3 { color: #fff; }
.section--navy .eyebrow { color: var(--gold-lt); }

.center { text-align: center; }
.lead { font-size: var(--fs-lead); color: var(--muted); max-width: 62ch; }

.eyebrow {
  display: inline-flex; align-items: center; gap: .7rem;
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: var(--gold-text);
  margin-bottom: .9rem;
}
.eyebrow::before { content: ""; width: 34px; height: 1px; background: currentColor; }
.eyebrow--center::after { content: ""; width: 34px; height: 1px; background: currentColor; }

.section-head { max-width: 60ch; margin-bottom: clamp(1.8rem, 3.6vw, 2.9rem); }
.section-head.center { margin-inline: auto; }

/* "45 Rooms, Three Ways to Stay" needs 640px but 60ch caps the head at 592px,
   so it wrapped to two lines. The H2 alone may use the full column; the lead
   paragraph keeps its own comfortable measure. */
.section-head > h2 { max-width: none; text-wrap: balance; white-space: nowrap; }
/* A nowrap H2 OVERFLOWS its box rather than widening it, so a 76ch cap left
   "The Pool, the Playground, the Games Room" (871px of text in a 750px box)
   spilling ~18px past the column and reading 60px right of centre — the box
   was centred, the glyphs were not. Centred heads take the full column so the
   text has room to centre; the paragraph keeps its own readable measure. */
.section-head.center { max-width: 100%; }
.section-head.center > h2 { width: 100%; }
.section-head.center > p { max-width: 68ch; margin-inline: auto; text-wrap: balance; }
@media (max-width: 900px) { .section-head > h2 { white-space: normal; } }

/* skip link */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--navy); color: #fff; padding: .8rem 1.2rem;
}
.skip:focus { left: 0; }

/* ============ BUTTONS ============
   Gold buttons take NAVY text — white on gold measures 2.42:1 and fails AA. */
.btn {
  /* A two-word CTA must never break across lines: "BOOK NOW" was wrapping in
     the header once the content column narrowed. nowrap was previously set
     only under 700px, so desktop was unprotected. */
  white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 48px; padding: .8rem 1.7rem;
  font-family: var(--font-body); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  border: 1px solid transparent; border-radius: 0; cursor: pointer;
  transition: background .28s var(--ease), color .28s var(--ease), border-color .28s var(--ease);
}
.btn--primary { background: var(--gold); color: var(--navy); border-color: var(--gold); }
.btn--primary:hover { background: var(--gold-lt); color: var(--navy-deep); border-color: var(--gold-lt); }
.btn--outline { background: transparent; color: var(--navy); border-color: var(--navy); }
.btn--outline:hover { background: var(--navy); color: #fff; }
.btn--ghost { background: rgba(255,255,255,.12); color: #fff; border-color: rgba(255,255,255,.5); }
.btn--ghost:hover { background: #fff; color: var(--navy); border-color: #fff; }
.btn--sm { min-height: 42px; padding: .6rem 1.2rem; font-size: var(--fs-micro); }
.btn--lg { min-height: 54px; padding: .95rem 2.1rem; }
/* Icon shown only on the compact mobile header CTA (see the icon-only
   override in the max-width:700px block below) — hidden everywhere else. */
.btn__icon { display: none; }

/* ============ HEADER ============ */
.header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  background: linear-gradient(180deg, rgba(7,21,57,.82) 0%, rgba(7,21,57,.42) 62%, rgba(7,21,57,0) 100%);
  transition: background .35s var(--ease), box-shadow .35s var(--ease);
}
.header.is-scrolled { background: var(--white); box-shadow: var(--shadow-sm); }

.header__inner {
  width: 100%; max-width: var(--maxw); margin-inline: auto;
  padding-inline: var(--gutter);
  min-height: var(--header-h);
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem;
  /* NO flex-wrap. The priority-plus JS moves items into the overflow menu
     before the row can run out of room, so wrapping must never be an option —
     with it enabled the row silently wraps and every width measurement then
     reads the ALREADY-WRAPPED geometry. */
  flex-wrap: nowrap;
}
.header__inner > .nav--inline { min-width: 0; overflow: hidden; }
/* The nav is centred in the row. The flanks are unequal (logo 83px, CTA 184px),
   so equal auto margins alone would not look centred — both flanks flex from a
   zero basis and therefore claim equal free space, putting the links on the
   true centre.

   Deliberately NOT absolute positioning: the priority-plus JS sums the natural
   width of every header child and compares it with the row width. Removing the
   nav from flow would drop it out of that sum and the overflow maths would
   read more free space than exists. As a flex item with auto margins its
   measured width is unchanged. */
.header__inner > .header__brand,
.header__inner > .header__cta { flex: 1 1 0; min-width: 0; }
.header__inner > .header__cta { justify-content: flex-end; }
.header__inner > .nav--inline { flex: 0 1 auto; margin-inline: auto; }
/* When every link has moved into the menu the inline nav is empty and must stop
   claiming flex gap, or the row wraps at very narrow widths. */
.header__inner > .nav--inline.is-empty { display: none; }

.header__brand { display: flex; align-items: center; flex: none; }
.header__logo { flex: none; display: inline-flex; align-items: center; line-height: 0; }
.header__logo img { height: 68px; width: auto; flex: none; transition: height .3s var(--ease); }
.header.is-scrolled .header__logo img { height: 58px; }
@media (max-width: 880px) { .header__logo img { height: 54px; } }

/* logo is gold+navy artwork; lift it off the dark hero before scroll */
.header .header__logo img {
  filter: drop-shadow(0 0 3px rgba(255,255,255,.5)) drop-shadow(0 0 10px rgba(255,255,255,.28));
  transition: filter .35s var(--ease), height .3s var(--ease);
}
.header.is-scrolled .header__logo img { filter: none; }

.nav { display: flex; align-items: center; }
.nav__list { display: flex; align-items: center; gap: 1.5rem; list-style: none; margin: 0; padding: 0; flex-wrap: nowrap; }
.nav__link {
  display: inline-flex; align-items: center; white-space: nowrap;
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .13em; text-transform: uppercase;
  color: #fff; padding: .4rem 0; position: relative;
}
.nav__link::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -2px;
  height: 2px; background: var(--gold); transition: right .3s var(--ease);
}
.nav__link:hover::after, .nav__link[aria-current="page"]::after { right: 0; }
.header.is-scrolled .nav__link:not(.nav--menu .nav__link) { color: var(--ink); }
.header .nav__link[aria-current="page"] { color: var(--gold-lt); }
.header.is-scrolled .nav__link[aria-current="page"]:not(.nav--menu .nav__link) { color: var(--gold); }

.header__cta { display: flex; align-items: center; gap: .6rem; flex: none; }

/* The hamburger belongs WITH the nav it opens, not beside the Book Now CTA —
   two adjacent controls dilute the primary action and invite mis-taps. Order
   moves it to the left of the button, tight to the last inline link. */
.header__cta .hamburger { order: -1; margin-right: .35rem; }

/* hamburger */
.hamburger {
  width: 44px; height: 44px; display: inline-flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 5px;
  background: none; border: 0; cursor: pointer; padding: 0;
}
.hamburger span { display: block; width: 22px; height: 2px; background: #fff; transition: background .3s var(--ease); }
.header.is-scrolled .hamburger span { background: var(--ink); }
@media (max-width: 700px) {
  .hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
}

/* ---- overflow menu: a compact dropdown under the hamburger, NOT a full drawer.
   Anchored to the button and opening leftward so it grows away from the CTA. */
.nav--menu[hidden] { display: none; }
.nav--menu {
  position: absolute; top: 100%; right: var(--menu-right, var(--gutter)); left: auto;
  width: max-content; min-width: 214px; max-width: min(88vw, 320px);
  background: var(--navy-deep); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; align-items: stretch;
  padding: .35rem 0;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
  max-height: min(70vh, 520px); overflow-y: auto; z-index: 120;
}
.nav--menu.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
.nav--menu .nav__list { flex-direction: column; align-items: stretch; gap: 0; width: 100%; }
.nav--menu .nav__link {
  min-height: 44px; width: 100%; justify-content: flex-start;
  padding: .5rem 1.15rem; color: #fff; font-size: var(--fs-micro);
}
.nav--menu .nav__link::after { display: none; }
.nav--menu .nav__link:hover,
.nav--menu .nav__link:focus-visible { background: rgba(255,255,255,.1); color: #fff; }
.nav--menu .nav__link[aria-current="page"] { background: var(--gold); color: var(--navy); font-weight: 600; }
/* Home/close row and the Book Now bar only exist for the mobile full-panel
   menu (below) - the desktop dropdown doesn't need either. */
.nav--menu__head, .nav--menu__foot { display: none; }

/* Small screens: burger left / logo dead-centre on the viewport / Book Now
   right, and every link lives in the menu (the inline row is hidden outright
   so it cannot occupy a grid cell and push the CTA onto a second row).

   The logo is taken out of grid flow and absolutely centred on .header
   itself (left:50% + translateX(-50%)), so it sits at the true viewport
   centre no matter how wide the button is. .header is already
   position:fixed and spans the full viewport with no positioned element
   between it and .header__brand, so it's the containing block with no
   extra wrapper needed. Column 1 stays a plain 36px track matching the
   hamburger's footprint so nothing else starts underneath it.

   Book Now shows only its plain "Book Now" text label here (an icon was
   tried, both alone and alongside the label, and dropped per instruction).
   Because the button is wider than the hamburger, the gap to the hamburger
   and the gap to Book Now are no longer identical; the logo stays pinned to
   the true screen-centre regardless. Checked down to a 320px-wide phone —
   the label-only button stays clear of the centred logo at every width. */
@media (max-width: 700px) {
  .header__inner {
    display: grid; grid-template-columns: 36px 1fr auto;
    align-items: center; gap: .5rem;
  }
  .header__inner > .nav--inline { display: none; }
  .header__brand {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
  }
  .header__logo img { height: 38px; }
  .header__cta   { grid-column: 3; justify-self: end; gap: .45rem; }
  .header__inner > .header__cta > .hamburger {
    position: fixed; left: var(--gutter); top: 0; height: var(--header-h);
    width: 36px; display: inline-flex; align-items: center; justify-content: center; z-index: 2;
  }
  .header__inner > .header__cta > .hamburger span { width: 18px; }
  .header__cta .btn--primary { min-height: 38px; padding: .5rem .75rem; }
  .header__cta .btn { white-space: nowrap; }

  /* ---- mobile menu: a full-height panel sliding in from the left, not the
     small dropdown desktop gets. Own head (Home + close) and a Book Now bar
     pinned to the bottom - both injected by JS, hidden by default above. */
  body.nav-open { overflow: hidden; }
  /* .header (z-index:100) is its own stacking context, so a scrim above it
     would wash out the menu panel living inside .header - not just the page
     behind it. Sitting below .header's 100 keeps the panel crisp while
     still dimming the ordinary (non-fixed, unstacked) page content. */
  body.nav-open::after {
    content: ''; position: fixed; inset: 0; z-index: 95;
    background: rgba(10,14,26,.45);
  }
  .nav--menu {
    position: fixed; inset: 0 auto 0 0; top: 0;
    width: min(86vw, 340px); max-width: none; max-height: none;
    background: var(--paper); box-shadow: var(--shadow-lg);
    padding: 0; opacity: 1;
    transform: translateX(-100%);
    transition: transform .32s var(--ease), visibility .32s;
  }
  .nav--menu.is-open { transform: translateX(0); }
  .nav--menu__head, .nav--menu__foot { display: block; }
  .nav--menu__head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 1.3rem var(--gutter) 1.1rem; border-bottom: 1px solid var(--line);
  }
  .nav--menu__home {
    font-family: var(--font-head); font-size: var(--fs-h3); color: var(--ink);
  }
  .nav--menu__home:hover { color: var(--gold-text); }
  .nav--menu__close {
    display: grid; place-items: center; width: 40px; height: 40px;
    background: none; border: 0; color: var(--ink); cursor: pointer; margin-right: -.5rem;
  }
  .nav--menu .nav__list {
    padding: .3rem 0; overflow-y: auto;
    flex: 1 1 auto;
  }
  .nav--menu .nav__link {
    font-family: var(--font-head); font-size: 1.05rem; font-weight: 400;
    letter-spacing: normal; text-transform: none;
    color: var(--ink); padding: .85rem var(--gutter);
  }
  .nav--menu .nav__link:hover,
  .nav--menu .nav__link:focus-visible { background: var(--paper-2); color: var(--ink); }
  .nav--menu .nav__link[aria-current="page"] {
    background: none; color: var(--gold-text); font-weight: 500;
  }
  .nav--menu__foot {
    padding: 1rem var(--gutter) calc(1rem + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--line);
  }
  .nav--menu__foot .btn { width: 100%; }
}

/* ============ HERO ============ */
.hero { position: relative; min-height: 100svh; display: flex; align-items: flex-end; overflow: hidden; }
.hero__media { position: absolute; inset: 0; }
.hero__media > img { width: 100%; height: 100%; object-fit: cover; }


/* ---- Hero slider -------------------------------------------------------
   Slides are stacked and cross-faded via opacity, not translated, so there is
   no horizontal scroll container to fight the page and no layout shift: every
   slide occupies the same box from first paint. Only opacity and the image
   transform animate, both compositor-only properties. */
.hero__slides { position: absolute; inset: 0; }
.hero__slide {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden;
  transition: opacity 1.1s var(--ease), visibility 0s linear 1.1s;
}
.hero__slide.is-active {
  opacity: 1; visibility: visible;
  transition: opacity 1.1s var(--ease), visibility 0s;
}
.hero__slide img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* A slow, continuous push on the live slide only. It restarts on each
   activation, which is what makes a static photo feel like footage. */
.hero__slide.is-active img { animation: heroDrift 13s linear both; }
@keyframes heroDrift { from { transform: scale(1.005); } to { transform: scale(1.032); } }

/* Arrows + dots. Both sit above the scrim so they remain clickable. */
.hero__nav { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.hero__arw {
  position: absolute; top: 50%; transform: translateY(-50%);
  pointer-events: auto;
  display: grid; place-items: center;
  width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.55);
  background: rgba(7,17,40,.42); color: #fff;
  cursor: pointer; transition: background .25s var(--ease), border-color .25s var(--ease);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.hero__arw:hover { background: rgba(7,17,40,.68); border-color: #fff; }
.hero__arw:focus-visible { outline: 3px solid var(--gold-lt); outline-offset: 3px; }
.hero__arw--prev { left: clamp(.6rem, 2.2vw, 1.6rem); }
.hero__arw--next { right: clamp(.6rem, 2.2vw, 1.6rem); }

.hero__dots {
  /* The booking form owns the base of the hero and paints at z-index 3, so
     the dots cannot live at the bottom — they were measured sitting INSIDE
     the form band and were invisible. They ride just above its top edge
     instead, and outrank it so they stay clickable. */
  position: absolute; z-index: 4; left: 0; right: 0;
  display: flex; justify-content: center; gap: .55rem;
  bottom: calc(var(--bk-h, 196px) + clamp(.7rem, 1.8vh, 1.2rem));
}
.hero__dot {
  /* 10px visual pill, but a 24px hit area via padding — WCAG target size. */
  appearance: none; border: 0; background: none; cursor: pointer;
  padding: 7px; line-height: 0; border-radius: 999px;
}
.hero__dot::before {
  content: ""; display: block; width: 10px; height: 10px; border-radius: 999px;
  background: rgba(255,255,255,.44);
  box-shadow: 0 0 0 1px rgba(7,17,40,.30);
  transition: background .25s var(--ease), width .3s var(--ease);
}
.hero__dot[aria-selected="true"]::before { background: var(--gold-lt); width: 26px; }
.hero__dot:focus-visible { outline: 3px solid var(--gold-lt); outline-offset: 2px; }

/* Phones: the booking sheet and the arrows compete for the same thumb zone,
   so the arrows step aside and the dots (plus swipe) carry navigation. */
@media (max-width: 700px) {
  .hero__arw { display: none; }
}

/* Reduced motion: no drift, no cross-fade, no autoplay (JS also honours it).
   The slider still works — it just cuts between slides instead of easing. */
@media (prefers-reduced-motion: reduce) {
  .hero__slide { transition: none; }
  .hero__slide.is-active img { animation: none; }
}
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  /* The slides are real, unstaged property photos — a driveway, parked cars,
     mixed light. The scrim carries weight at the bottom, where the booking
     form sits, while the top stays open enough to read the photograph. */
  background:
    linear-gradient(180deg, rgba(7,17,40,.55) 0%, rgba(7,17,40,.28) 38%, rgba(7,17,40,.86) 100%),
    linear-gradient(90deg, rgba(7,17,40,.62) 0%, rgba(7,17,40,.18) 52%, rgba(7,17,40,0) 78%);
  z-index: 1;
}
.hero__inner {
  position: relative; z-index: 2; width: 100%;
  max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter);
  /* Content is pinned to the BOTTOM, so it must reserve room for the fixed
     header on the opposite edge or it slides under the navbar as the viewport
     gets shorter (a 1366x768 laptop leaves ~600px of usable height). */
  padding-top: calc(var(--header-h) + 2rem);
  padding-bottom: clamp(3rem, 9vh, 7rem);
}
.hero h1 { color: #fff; max-width: 16ch; text-shadow: 0 2px 26px rgba(7,21,57,.5); }
.hero .eyebrow { color: var(--gold-lt); }
.hero__sub { color: #ECEFF6; font-size: var(--fs-lead); max-width: 48ch; margin-bottom: 1.8rem; }
.hero__actions { display: flex; flex-wrap: wrap; gap: .8rem; }

/* ============ BOOKING BAR ============ */
.booking { position: relative; z-index: 5; margin-top: -46px; }
.bk-form {
  background: #fff; box-shadow: var(--shadow-lg);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 178px), 1fr));
  align-items: stretch;
}
.bk-field { padding: .95rem 1.15rem; border-right: 1px solid var(--line); min-width: 0; position: relative; }
.bk-field:last-of-type { border-right: 0; }
.bk-field__label {
  display: flex; align-items: center; gap: .4rem;
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted); margin-bottom: .3rem;
}
.bk-field__label svg { color: var(--gold); flex: none; }

/* Booking form type sizes, set explicitly rather than through the shared
   --fs-micro / --fs-body tokens: those are sitewide, and changing them would
   resize every label and paragraph on the site. Scoped here so the form can
   be tuned on its own. */
.bk-field__label { font-size: 11px; font-weight: 300; }
.bk-field input, .bk-field select, .bk-guests__trigger { font-size: 12px; font-weight: 400; }
.bk-field input, .bk-field select, .bk-guests__trigger {
  width: 100%; border: 0; background: none; padding: 0;
  font-family: var(--font-body); font-size: var(--fs-body); color: var(--ink);
  min-height: 44px;
}
.bk-field input:focus-visible, .bk-guests__trigger:focus-visible { outline-offset: 4px; }
.bk-submit { display: flex; }
.bk-submit .btn { width: 100%; min-height: 100%; }

.bk-guests { position: relative; }
.bk-guests__trigger {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  text-align: left; cursor: pointer;
}
.bk-pop {
  /* Anchor to the RIGHT edge of the field so a popover in a narrow column
     opens inward instead of running off-screen (FUN-07). At 200% zoom the
     left-anchored version overflowed the viewport by 78px. */
  position: absolute; top: calc(100% + 6px); right: 0; left: auto;
  width: min(300px, calc(100vw - 2rem)); z-index: 60;
  background: #fff; border: 1px solid var(--line); box-shadow: var(--shadow-lg);
  padding: 1rem 1.1rem;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .2s var(--ease), transform .2s var(--ease), visibility .2s;
}
.bk-guests[data-expanded="true"] .bk-pop { opacity: 1; visibility: visible; transform: translateY(0); }
.bk-row { display: flex; align-items: center; justify-content: space-between; padding: .55rem 0; border-top: 1px solid var(--line); }
.bk-row:first-child { border-top: 0; }
.bk-step { display: inline-flex; align-items: center; gap: .3rem; }
.bk-step button {
  width: 34px; height: 34px; border: 1px solid var(--line); background: #fff;
  color: var(--navy); font-size: var(--fs-body); cursor: pointer; line-height: 1;
}
.bk-step button:hover { border-color: var(--navy); }
.bk-step output { min-width: 26px; text-align: center; font-size: var(--fs-body); }

/* ============ GRID + CARDS ============ */
.grid { display: grid; gap: var(--card-gap); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: stretch; }
.grid--4 > .usp { align-self: stretch; }
@media (max-width: 900px) { .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.card { background: #fff; box-shadow: var(--shadow-sm); display: flex; flex-direction: column; min-width: 0; }
.card__media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.card:hover .card__media img { transform: scale(1.05); }
.card__badge {
  position: absolute; left: 0; bottom: 0;
  background: var(--gold); color: var(--navy);
  font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase;
  padding: .4rem .8rem; font-weight: 600;
}
.card__body { padding: 1.35rem 1.45rem 1.5rem; display: flex; flex-direction: column; flex: 1 1 auto; gap: .45rem; }
.card__title { margin: 0; }
.card__meta { display: flex; flex-wrap: wrap; gap: .4rem 1rem; font-size: var(--fs-small); color: var(--muted); }
.card__meta span { display: inline-flex; align-items: center; gap: .35rem; }
.card__meta svg { color: var(--gold); flex: none; }
.card__foot { margin-top: auto; padding-top: 1rem; display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }

/* on mobile a 3+ card grid stacks into a very tall column — opt in to a
   swipe row with grid--swipe (only where the stacked height justifies it) */
@media (max-width: 700px) {
  .grid--swipe {
    display: flex; gap: var(--card-gap);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter);
    padding-bottom: .6rem; scroll-padding-inline-start: var(--gutter);
    /* Constrain to the CONTAINER, not the viewport. 100vw is the visual
       viewport, which diverges from the layout width under browser zoom — at
       200% the row escaped its parent and overflowed by 922px. */
    max-width: calc(100% + var(--gutter) * 2);
  }
  .grid--swipe::-webkit-scrollbar { display: none; }
  .grid--swipe > * { flex: 0 0 85%; scroll-snap-align: start; min-width: 0; }
}

/* ============ SPLIT ============ */
.split { display: grid; gap: clamp(1.6rem, 4vw, 4rem); align-items: center;
         grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); }
.split__media img { width: 100%; aspect-ratio: 4/5; object-fit: cover; }

/* ============ PLACEHOLDER (photography pending) ============
   An honest, branded stand-in — NOT a borrowed photo of another property.
   Using an unrelated image here is the defect this block exists to prevent. */
/* A supplied reference image sits BEHIND the placeholder, heavily dimmed and
   desaturated, so a card reads as "a room will go here" rather than as a
   photograph of this property. The caption stays visible on top. It is
   deliberately NOT presented as Royal Paark imagery — the supplied file is a
   screenshot of another site (hill view, stone balustrade) and this property
   is in flat rural Tiruvallur. */
.ph--photo::before {
  content: ""; position: absolute; inset: 0;
  background-image: var(--ph-img); background-size: cover; background-position: center;
  filter: grayscale(.75) blur(1px); opacity: .17;
}
.ph--photo > * { position: relative; z-index: 1; }

.ph {
  position: relative; display: grid; place-items: center; text-align: center;
  overflow: hidden;
  background:
    repeating-linear-gradient(45deg, rgba(11,33,84,.035) 0 12px, transparent 12px 24px),
    linear-gradient(160deg, var(--sand), var(--gold-pale));
  color: var(--navy); padding: 2rem 1.4rem; min-height: 100%;
  border: 1px solid rgba(11,33,84,.1);
}
/* The mark is a LOGO, not a cover image. Without an explicit height:auto and
   object-fit it stretched to 1393x1155 inside the hero grid and swamped the
   whole placeholder. */
.ph .ph__mark, .ph__mark {
  width: 56px; height: auto; max-height: 56px; object-fit: contain;
  opacity: .6; margin-bottom: .7rem; flex: none;
}
.ph__t { font-family: var(--font-head); font-size: var(--fs-h3); margin-bottom: .2rem; }
.ph__s { font-size: var(--fs-micro); letter-spacing: .14em; text-transform: uppercase; color: var(--gold-text); }
/* .card__media and .hero__media set their own height (aspect-ratio / 100svh),
   so an absolute child is safe there. .split__media does NOT — its only child
   was absolute, so the box collapsed to height 0 and the placeholder escaped,
   bleeding 371px into the section below. Give the split placeholder normal
   flow and let its inline aspect-ratio size the box. */
.card__media .ph, .hero__media .ph { position: absolute; inset: 0; }
.split__media .ph { position: relative; width: 100%; }
/* The hero placeholder is a BACKDROP, so its caption must sit in the upper
   band only — centred, it collided with the H1 on a phone. */
.hero__media .ph {
  background: linear-gradient(160deg, var(--navy-deep), var(--navy) 55%, var(--navy-soft));
  color: #fff; align-content: start; padding-top: clamp(6rem, 18vh, 11rem);
}
@media (max-width: 700px) { .hero__media .ph { padding-top: 7rem; } }
.hero__media .ph .ph__t { color: #fff; }
.hero__media .ph .ph__s { color: var(--gold-lt); }

/* ============ USP STRIP ============ */
.usps { display: grid; gap: var(--card-gap);
        grid-template-columns: repeat(auto-fit, minmax(min(100%, 215px), 1fr)); }
.usp { text-align: center; padding: 1.4rem 1rem; }
.usp__icon {
  width: 52px; height: 52px; margin: 0 auto .8rem;
  display: grid; place-items: center;
  border: 1px solid var(--gold); border-radius: 50%; color: var(--gold);
}
.usp h3 { font-size: var(--fs-h3); margin-bottom: 14px; min-height: calc(1.22em * 2); }
/* never split a hyphenated term like "Wi-Fi" across two lines */
.usp h3, .usp p { overflow-wrap: break-word; }
.usp h3 { text-wrap: balance; }
.usp p { font-size: var(--fs-body); color: var(--muted); margin: 0; }

/* ============ FOOTER ============ */
/* Footer used a bespoke 67px top padding against the site's 96px section
   rhythm, and had NO bottom padding at all — the credit row sat flush on the
   page edge. Both now follow --section-pad. */
.footer {
  position: relative; isolation: isolate;
  background: var(--navy-deep); color: #C3CAD9; padding-top: var(--section-pad);
}
/* Background video. The navy above stays as the base, so a video that never
   loads leaves the footer unchanged rather than transparent. */
.footer__bg { position: absolute; inset: 0; overflow: hidden; z-index: -1; pointer-events: none; }
.footer__video {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 1.2s var(--ease);
}
.footer__video.is-ready { opacity: 1; }
/* Keeps every contact line above 4.5:1 over the brightest frames. */
.footer__scrim { position: absolute; inset: 0; background: rgba(6,12,28,.82); }
.footer > .wrap { position: relative; }
.footer a { color: #C3CAD9; }
.footer a:hover { color: var(--gold-lt); }
.footer__grid {
  display: grid; gap: clamp(1.8rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
  padding-bottom: clamp(2.2rem, 4vw, 3.2rem);
}
/* the brand column reads better a touch narrower than the link columns */
.footer__grid > *:first-child { max-width: 34ch; }
.footer__logo img { height: 92px; width: auto; }
.footer__h { color: #fff; font-family: var(--font-body); font-size: var(--fs-small); font-weight: 500;
             letter-spacing: .16em; text-transform: uppercase; margin-bottom: 1rem; }
.footer__links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.footer__links a { display: inline-flex; align-items: center; min-height: 40px; font-size: var(--fs-small); }
.footer__contact { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .55rem; font-size: var(--fs-small); }
.footer__contact li { display: flex; gap: .6rem; align-items: flex-start; }
.footer__contact svg { color: var(--gold); flex: none; margin-top: 4px; }
/* `anywhere` broke the email mid-address even when the line had room for it
   (242px needed, 432px available). `break-word` only breaks when a word genuinely
   cannot fit, so the address stays on one line wherever it can. */
.footer__contact a { overflow-wrap: break-word; }
.footer__social { display: flex; gap: .5rem; margin-top: 1rem; }
.footer__social a { width: 44px; height: 44px; display: grid; place-items: center; border: 1px solid rgba(255,255,255,.22); }
.footer__social a:hover { background: var(--gold); color: var(--navy); border-color: var(--gold); }
.footer__bottom {
  border-top: 1px solid rgba(255,255,255,.12);
  padding-block: clamp(1.2rem, 2.4vw, 1.8rem);
  display: flex; flex-wrap: wrap; gap: .6rem 1.4rem; align-items: center; justify-content: space-between;
  font-size: var(--fs-small);
}
.footer__bottom nav { display: flex; flex-wrap: wrap; gap: .3rem 1.2rem; }
.footer__bottom nav a { display: inline-flex; align-items: center; min-height: 40px; }
.powered a { display: inline-flex; align-items: center; min-height: 40px; }

/* Desktop-only: the copyright line, legal links and Simplotel credit sit on
   differently-sized boxes (plain text vs. 40px-tall link targets), so
   box-centering them leaves their text sitting at different vertical
   positions. Baseline alignment corrects that without touching heights,
   margins, gaps or the mobile/tablet layout. */
@media (min-width: 901px) {
  .footer__bottom { align-items: baseline; }
}

@media (max-width: 700px) {
  .footer__contact a, .footer__bottom nav a, .footer__links a, .powered a {
    display: inline-flex; align-items: center; min-height: 44px;
  }
}

/* ============ FLOATING ACTIONS ============ */
.fab-stack { position: fixed; right: 20px; bottom: 20px; z-index: 90; display: flex; flex-direction: column; gap: .6rem; }
.fab {
  width: 50px; height: 50px; border-radius: 50%; display: grid; place-items: center;
  box-shadow: var(--shadow-lg); color: #fff; border: 0; cursor: pointer;
}
.fab--wa { background: #25D366; }
.fab--call { background: var(--navy); }

/* The WhatsApp and Call FABs must look and behave identically in every
   interaction state — no hover, focus, or tap feedback of any kind, on any device. */
.fab--wa,
.fab--wa:link,
.fab--wa:visited,
.fab--wa:hover,
.fab--wa:focus,
.fab--wa:focus-visible,
.fab--wa:active {
  color: #fff;
  background: #25D366;
  box-shadow: var(--shadow-lg);
  outline: none;
  transform: none;
  transition: none;
  animation: none;
}
.fab--call,
.fab--call:link,
.fab--call:visited,
.fab--call:hover,
.fab--call:focus,
.fab--call:focus-visible,
.fab--call:active {
  color: #fff;
  background: var(--navy);
  box-shadow: var(--shadow-lg);
  outline: none;
  transform: none;
  transition: none;
  animation: none;
}
.fab--top {
  background: var(--gold); color: var(--ink);
  transition: background .2s var(--ease), opacity .2s var(--ease), transform .2s var(--ease);
}
.fab--top:hover, .fab--top:focus-visible { background: var(--gold-lt); }
.fab--top[hidden] { display: none; }

/* ============ REVEAL ============ */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; } }

/* ============ COOKIE CONSENT ============ */
/* The consent banner sat at bottom:16px — exactly where the booking form now
   lives at the base of the full-screen hero — and its action row intercepted
   every click on the form. A guest could not pick a date until they dismissed
   cookies. It now sits as a slim bar across the very bottom, clear of the form,
   and the hero reserves room for it. */
.cc {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 130;
  max-width: none; background: #fff; border-top: 3px solid var(--gold);
  box-shadow: 0 -8px 30px rgba(7,17,40,.16);
  padding: .85rem clamp(1rem, 4vw, 2.4rem); font-size: var(--fs-small);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .8rem 1.4rem;
}
.cc p { margin: 0; max-width: 68ch; }
.cc__actions { margin-top: 0; flex: none; }
/* while the banner is up, lift the hero form above it so nothing overlaps */
body:has(.cc:not([hidden])) .hero > .booking { padding-bottom: 7.5rem; }
/* same reason: the banner sits at z-index 130, above the fab-stack's 90, and
   is opaque and full-width, so without this the call/back-to-top icons are
   hidden behind it (found by actually loading the page — the CSS for those
   icons was correct, but the banner was drawn on top of them). */
body:has(.cc:not([hidden])) .fab-stack { bottom: 6rem; }
@media (max-width: 700px) {
  body:has(.cc:not([hidden])) .hero > .booking { padding-bottom: 10.5rem; }
  body:has(.cc:not([hidden])) .fab-stack { bottom: 10rem; }
}
.cc[hidden] { display: none; }
.cc__actions { display: flex; gap: .6rem; }

/* ============ BREADCRUMB ============ */
.breadcrumb { background: var(--sand); }
.breadcrumb__list { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
                    list-style: none; margin: 0; padding-block: .85rem; font-size: var(--fs-small); }
.breadcrumb__item + .breadcrumb__item::before { content: "›"; margin-right: .5rem; color: var(--muted); }
.breadcrumb__item--current { color: var(--muted); }

/* --- child ages in the booking widget (engine needs an age per child) --- */
.bk-ages { padding: .7rem 0 .2rem; border-top: 1px solid var(--line); }
.bk-ages__h { font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 .55rem; }
.bk-ages__list { display: flex; flex-wrap: wrap; gap: .55rem; }
.bk-age { display: flex; flex-direction: column; gap: .22rem; font-size: var(--fs-micro); color: var(--body); }
.bk-age select {
  min-height: 44px; min-width: 84px; padding: .35rem .55rem;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  font: inherit; font-size: var(--fs-small); border-radius: 0;
}
.bk-age select.is-error { border-color: #B3261E; box-shadow: 0 0 0 2px rgba(179,38,30,.15); }


/* ============ STATS BAR ============
   The reference anchors the page under the booking bar with a single row of
   headline numbers. It gives a resort scale at a glance before any scrolling. */
.stats {
  background: var(--paper-2);
  border-block: 1px solid var(--line);
}
.stats__row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(50%, 190px), 1fr));
}
/* Scoped to .stats__row specifically — .stat is also the (unrelated) item
   class for every .statbar counter widget site-wide (facilities, about-us,
   contact-us, location, offers, weddings...), which uses .stat__n/.stat__l,
   not .stat__num/.stat__lbl. These divider rules used to target the bare
   .stat class and leaked onto every one of those, adding stray border-right
   stubs and inconsistent border-bottoms once .statbar's own auto-fit grid
   collapsed to a single column on mobile. */
.stats__row .stat {
  text-align: center; padding: clamp(1.5rem, 3vw, 2.4rem) 1rem;
  border-right: 1px solid var(--line);
}
.stats__row .stat:last-child { border-right: 0; }
.stat__num {
  font-family: var(--font-head); font-size: clamp(2rem, 3.4vw, 2.9rem);
  color: var(--gold-text); line-height: 1; margin-bottom: .35rem;
}
.stat__lbl {
  font-size: var(--fs-micro); letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
@media (max-width: 700px) {
  .stats__row .stat:nth-child(2n) { border-right: 0; }
  .stats__row .stat:nth-child(-n+2) { border-bottom: 1px solid var(--line); }
}


/* Placeholders inside a dark band must read as part of it, not as a bright
   warm rectangle punched through it. Same component, dark treatment. */
.section--dark .ph {
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.03) 0 12px, transparent 12px 24px),
    linear-gradient(160deg, var(--ink-2), #1B2337);
  border-color: rgba(255,255,255,.1);
  color: #C7CEDC;
}
.section--dark .ph .ph__t { color: #E7EBF2; }
.section--dark .ph .ph__s { color: var(--gold-lt); }
.section--dark .ph--photo::before { opacity: .1; filter: grayscale(1) blur(1px); }


/* ============ RESORT ATMOSPHERE ============
   Restraint on purpose: the photography carries the resort feeling, so the
   page only adds quiet depth behind it. Two devices, both cheap and both
   decorative (aria-hidden / pseudo-elements, no extra requests):
     1. a soft palm-frond silhouette drawn in CSS, echoing the palms that
        appear in the lawn, pool and pavilion photos
     2. a faint tonal wash that keeps large light sections from reading flat  */

.section { position: relative; }

/* tonal wash — barely-there depth, never competes with content */
.section:not(.section--dark)::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(78% 52% at 88% -8%, rgba(201,162,39,.07), transparent 62%),
    radial-gradient(64% 46% at -6% 108%, rgba(11,33,84,.05), transparent 60%);
}
.section--dark::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(70% 48% at 92% 0%, rgba(201,162,39,.10), transparent 62%),
    radial-gradient(58% 44% at 0% 100%, rgba(122,160,255,.05), transparent 58%);
}
.section > .wrap { position: relative; z-index: 1; }

/* hairline gold rule between bands — the reference uses a similar seam */
.section--dark + .section:not(.section--dark),
.section:not(.section--dark) + .section--dark { border-top: 1px solid rgba(201,162,39,.22); }



/* Hero wordmark. The reference sets the property name in two tones — upright
   for the first word, italic for the second — which is what gives it presence
   without a second line of copy. */
.hero__h1 {
  font-size: var(--fs-h1);
  letter-spacing: -.02em; line-height: 1.02;
  max-width: 20ch; margin-bottom: 1rem;
}
.hero__h1 em {
  font-style: italic; font-weight: 400;
  color: var(--gold-lt); display: block;
}
@media (min-width: 901px) { .hero__h1 em { display: inline; } }


/* ============ ROOM CARD — matched to the design reference ============
   The reference does NOT stack image-above-text. The image fills the whole
   card, a veil darkens the lower half, and the copy sits on top of it:
     img (401x301, static)  +  .rcard__veil (absolute)  +  .rcard__body (absolute)
   Measured from the reference build before rebuilding this. */
.rcard {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 3; min-width: 0;
  background: var(--ink-2);
}
.rcard > img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.rcard:hover > img, .rcard:focus-within > img { transform: scale(1.06); }
.rcard__veil {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(9,14,26,0) 46%, rgba(9,14,26,.30) 66%, rgba(9,14,26,.78) 100%);
}
.rcard__body {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.3rem 1.4rem 1.35rem; color: #fff;
}
.rcard__tag {
  font-size: var(--fs-micro); letter-spacing: .2em; text-transform: uppercase;
  color: var(--gold-lt); margin-bottom: .4rem;
}
/* One reserved line so a longer title cannot shift the row off its baseline. */
.rcard__name { font-family: var(--font-head); font-size: var(--fs-h3); line-height: 1.1;
  margin: 0 0 .35rem; color: #fff; min-height: 1.1em; }
.rcard__name a { color: #fff; }
.rcard__name a:hover { color: var(--gold-lt); }
/* The body is anchored to the card's bottom edge, so a caption that wraps to
   two lines pushes its title UP and the row of titles stops aligning (card 3,
   "Table tennis, and chess, along with netted games", sat 24px higher).
   Reserving two lines keeps every title on the same baseline. */
/* min-height only sets a floor: a caption that needs 46.5px still grew past
   the reserved 45px and lifted its title 1.5px above the neighbours. A fixed
   two-line box pins every title in the row to the same baseline. */
.rcard__meta { font-size: var(--fs-small); color: #C7CEDC; margin: 0;
  line-height: 1.5; height: 3em; overflow: hidden; }
.rcard__cta {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: .8rem;
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase; color: var(--gold-lt);
}
.rcard__cta svg { transition: transform .3s var(--ease); }
.rcard:hover .rcard__cta svg { transform: translateX(4px); }
/* whole card is the link, but the CTA is the visible affordance */
.rcard__link { position: absolute; inset: 0; z-index: 2; }
.rcard__link:focus-visible { outline: 3px solid var(--gold); outline-offset: -3px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}


/* ============ PLACEHOLDER COPY NOTICE ============
   Lorem ipsum must never be mistaken for finished copy, so it is labelled. */
.ph-note {
  display: inline-block; margin-bottom: .9rem; padding: .45rem .85rem;
  background: rgba(201,162,39,.14); border-left: 3px solid var(--gold);
  font-size: var(--fs-small); color: var(--body);
}
.section--dark .ph-note { background: rgba(232,200,106,.12); color: #D8DEEA; border-left-color: var(--gold-lt); }

/* ============ OFFER CARD ============ */
.ocard {
  background: var(--ink-2); border: 1px solid rgba(255,255,255,.09);
  padding: 1.6rem 1.5rem 1.5rem; display: flex; flex-direction: column; gap: .5rem; min-width: 0;
}
.ocard__tag { font-size: var(--fs-micro); letter-spacing: .2em; text-transform: uppercase; color: var(--gold-lt); margin: 0; }
.ocard__name { font-family: var(--font-head); font-size: var(--fs-h3); color: #fff; margin: 0; }
.ocard__copy { font-size: var(--fs-small); color: #A9B2C4; margin: 0; }
.ocard__cta {
  margin-top: auto; padding-top: .9rem; display: inline-flex; align-items: center; gap: .5rem;
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase; color: var(--gold-lt);
}

/* ============ GALLERY GRID ============ */
.gal-grid {
  display: grid; gap: .7rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}
.gtile { display: block; overflow: hidden; aspect-ratio: 4/3; background: var(--paper-2); }
.gtile img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.gtile:hover img, .gtile:focus-visible img { transform: scale(1.06); }



/* ============ ROOMS: even 2-up grid ============
   4 room types now (Luxury, Jacuzzi, Classic, Premium) — a spanning "feature"
   first card left 3 ordinary cards to wrap as 2+1 with a dangling gap next to
   the last one. All 4 now sit in the same 2-column grid at the same size. */
.rgrid {
  /* Three room types now, so all three sit on one row rather than 2+1. */
  display: grid; gap: var(--card-gap);
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.rgrid > .rcard { aspect-ratio: 4 / 3; }

@media (max-width: 900px) {
  .rgrid { grid-template-columns: 1fr; }
  .rgrid > .rcard { aspect-ratio: 4 / 3; }
}
/* mobile keeps the swipe row behaviour already defined for .grid--swipe */
@media (max-width: 700px) {
  .rgrid.grid--swipe {
    display: flex; gap: var(--card-gap);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter);
    padding-bottom: .6rem; scroll-padding-inline-start: var(--gutter);
    max-width: calc(100% + var(--gutter) * 2);
  }
  .rgrid.grid--swipe::-webkit-scrollbar { display: none; }
  .rgrid.grid--swipe > .rcard { flex: 0 0 85%; scroll-snap-align: start; aspect-ratio: 4/3; }
}


/* ============ CLEAN HERO + INTRO BAND ============
   The hero is now pure photography — no copy over it — so the slides read
   without competing with type, and the H1 sits on a solid ground below where
   it is guaranteed legible regardless of which slide is showing. */
.hero { min-height: 78svh; align-items: stretch; }
.hero .hero__inner { display: none; }
/* the scrim only needs to keep the fixed header readable now */
.hero .hero__media::after {
  background: linear-gradient(180deg, rgba(7,17,40,.58) 0%, rgba(7,17,40,.12) 34%, rgba(7,17,40,.30) 100%);
}

.intro { background: var(--paper); padding-block: var(--section-pad); }
.intro .wrap { max-width: 74ch; }
.intro__h1 {
  font-family: var(--font-head);
  font-size: var(--fs-h1);
  line-height: 1.04; letter-spacing: -.02em;
  margin: 0 0 .8rem; color: var(--ink);
}
/* all three words of the property name share one treatment */
.intro__h1 em { font-style: normal; font-weight: inherit; color: inherit; }
.intro__sub { font-size: var(--fs-lead); color: var(--muted); margin: 0 auto; max-width: 56ch; }

/* The -46px overlap existed to lift the bar onto the hero image. Against a
   solid intro band it only crowds the subline, so the bar sits in flow with a
   deliberate gap and the intro loses its own bottom padding to compensate. */
.booking { margin-top: 0; }
.intro { padding-bottom: clamp(1.6rem, 3vw, 2.4rem); }
@media (max-width: 700px) { .hero { min-height: 62svh; } }

/* ---- Mobile hero: show the photograph, not a slice of it ----------------
   The slides are 16:9 but a phone viewport is ~9:19, so object-fit:cover was
   displaying only ~33% of each image's width. The media box is given the
   slide's own aspect ratio and the image switches to `contain`, so ~the whole
   frame is visible. The hero then sizes to that box rather than the viewport. */
@media (max-width: 700px) {
  .hero { min-height: 0; }
  .hero__media { position: relative; inset: auto; aspect-ratio: 16 / 9; }
  .hero__slides { position: absolute; inset: 0; }
  /* cover, not contain: the box is now slightly taller than the image, so
     contain would letterbox it. cover trims ~9% off the sides instead. */
  .hero__slide img { object-fit: cover; }
  /* the drift would letterbox unevenly against `contain`, so it steps aside */
  .hero__slide.is-active img { animation: none; }
  /* The header is fixed and transparent, so padding the hero by its height
     left a pale strip behind the navbar. The media box grows by the header
     height instead and sits UNDER it, so the photograph fills that band —
     the existing scrim keeps the logo and menu readable over it. */
  .hero { padding-top: 0; }
  /* 10% taller than the image's own 16:9 (160/99), which leaves ~91% of the
     frame visible - a small trim off the sides rather than the old ~67% crop.
     The fixed navbar overlays the top band, so no empty strip appears. */
  .hero__media { aspect-ratio: 160 / 99; height: auto; }
  /* Dots return to overlaying the picture: made static they jumped ahead of
     the media in flow order and landed above it. */
  .hero__dots { position: absolute; bottom: .6rem; }
}


/* Inline links match the plain, unstyled treatment used everywhere else on
   the site (no underline, no added weight) per explicit request. */
.section--dark .cc p a { color: var(--gold-lt); }


/* ============ FULL-SCREEN HERO WITH THE BOOKING FORM ON IT ============
   The hero fills the viewport and the form sits at its base, over the slides.
   svh (not vh) so mobile browser chrome does not push the form off-screen. */
.hero {
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  position: relative;
}
.hero > .booking {
  position: relative; z-index: 3;
  width: 100%; margin: 0;
  /* room for the control bar that sits under it */
  padding-bottom: clamp(3.4rem, 6vh, 4.6rem);
}
/* the form needs a readable ground over changing photography */
.hero > .booking .bk-form {
  background: rgba(255,255,255,.96);
  backdrop-filter: blur(6px);
  box-shadow: 0 22px 60px rgba(7,17,40,.38);
}
/* strengthen the base of the scrim so the form edge does not float on a
   bright slide, while the upper photograph stays open */
.hero .hero__media::after {
  background: linear-gradient(180deg,
    rgba(7,17,40,.56) 0%, rgba(7,17,40,.10) 30%,
    rgba(7,17,40,.34) 68%, rgba(7,17,40,.72) 100%);
}
@media (max-width: 700px) {
  /* The hero no longer fills the viewport on a phone: it sizes to the 16:9
     photograph so the whole frame is visible (see the mobile hero block
     above). Forcing 100svh here reinstated the tall crop. */
  .hero { min-height: 0; }
  .hero > .booking { padding-bottom: 3.2rem; }
}


/* On a phone the stacked 4-field form ate 54% of the hero, leaving almost no
   footage visible. Pair the dates and tighten the rows so the form reads as a
   band at the base rather than a panel covering the picture. */
@media (max-width: 700px) {
  .hero > .booking .bk-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .hero > .booking .bk-field { padding: .6rem .8rem; }
  .hero > .booking .bk-field__label { font-size: 11px; margin-bottom: .1rem; }
  .hero > .booking .bk-field input,
  .hero > .booking .bk-guests__trigger { font-size: 12px; min-height: 38px; }
  /* promo is the least-used field on a phone — hide it, the engine still
     accepts a code on its own page */
  .hero > .booking .bk-field:has(#promo) { display: none; }
  .hero > .booking .bk-submit { grid-column: 1 / -1; }
  .hero > .booking .bk-submit .btn { min-height: 48px; }
}


/* ============ BOOKING POPOVER — opens UPWARD from a hero-bottom form ========
   The form now sits at the base of a full-screen hero, so a popover that drops
   DOWNWARD lands below the viewport (measured: bottom off-screen on desktop)
   and, in a narrow column, runs off the left edge (measured: x = -106 on a
   390px phone). It now opens upward and is clamped to the viewport. */
.hero .bk-pop {
  top: auto; bottom: calc(100% + 8px);
  left: auto; right: 0;
  transform: translateY(6px);
}
.hero .bk-guests[data-expanded="true"] .bk-pop { transform: translateY(0); }

@media (max-width: 700px) {
  /* on a phone the field column is far narrower than the 300px panel, so pin
     it to the form instead of the field and let it use the full width */
  .hero .bk-pop {
    position: fixed; left: var(--gutter); right: var(--gutter);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
    width: auto; max-width: none; max-height: 62svh; overflow-y: auto;
  }
}


/* ============ WHY BOOK DIRECT ============
   A slim strip directly beneath the booking form, inside the hero — the moment
   the guest is deciding where to book is the moment the reasons matter. */
.wbd {
  position: relative; z-index: 3;
  background: rgba(13,18,32,.72); backdrop-filter: blur(6px);
  border-top: 1px solid rgba(232,200,106,.32);
  padding-block: .9rem;
}
.wbd__h {
  font-family: var(--font-body); font-size: var(--fs-micro); letter-spacing: .2em;
  text-transform: uppercase; color: var(--gold-lt);
  margin: 0 0 .55rem; text-align: center;
}
.wbd__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .5rem 2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
}
.wbd__list li {
  display: flex; align-items: flex-start; gap: .6rem;
  font-size: var(--fs-small); color: #D3D9E6; line-height: 1.45;
}
.wbd__list svg { color: var(--gold-lt); flex: none; margin-top: 2px; }
.wbd__list strong { color: #fff; font-weight: 600; }
.wbd__list a { color: var(--gold-lt); text-decoration: underline; text-underline-offset: 3px; }
/* the hero already ends at the viewport base; the strip rides above it */
.hero > .booking { padding-bottom: .9rem; }
@media (max-width: 700px) {
  .wbd { padding-block: .7rem; }
  .wbd__list { gap: .4rem; }
  .wbd__list li { font-size: var(--fs-small); }
}


/* ============ BOOK NOW CELL: rate above, why-book-direct below ============ */
.bk-submit {
  display: flex; flex-direction: column; align-items: stretch; justify-content: center;
  gap: .4rem; padding: .7rem .9rem;
  background: var(--gold);
}
.bk-submit .btn { width: 100%; min-height: 46px; }
.bk-submit .btn--primary { background: var(--ink); color: #fff; border-color: var(--ink); }
.bk-submit .btn--primary:hover { background: var(--navy); border-color: var(--navy); }
.bk-rate {
  margin: 0; text-align: center; line-height: 1.15;
  font-family: var(--font-head); font-size: var(--fs-h3); color: var(--ink);
}
.bk-rate span, .bk-rate small {
  font-family: var(--font-body); font-size: var(--fs-micro); letter-spacing: .14em;
  text-transform: uppercase; color: rgba(13,18,32,.72);
}
.bk-why {
  display: block; text-align: center;
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink); text-decoration: underline; text-underline-offset: 3px;
  min-height: 24px;
}
.bk-why:hover { color: var(--navy); }
@media (max-width: 700px) {
  .bk-submit { flex-direction: row; align-items: center; gap: .6rem; flex-wrap: wrap; }
  .bk-rate { text-align: left; font-size: var(--fs-h3); flex: 1 1 auto; }
  .bk-submit .btn { width: auto; flex: 0 0 auto; padding-inline: 1.4rem; }
  .bk-why { flex: 1 0 100%; text-align: left; }
}


/* ============ BOOKING FORM — lighter, tighter ============
   The previous version had a heavy solid-gold submit block, 97px-tall fields
   with dead space under the values, and a rate + link crowding the button.
   Now: compact rows, a hairline gold rule marking the submit cell instead of a
   colour slab, and nothing in the cell except the action. */
.hero > .booking .bk-form {
  grid-template-columns: repeat(4, minmax(0, 1fr)) auto;
  align-items: stretch;
  border: 1px solid rgba(13,18,32,.08);
}
.hero > .booking .bk-field {
  padding: .72rem 1.05rem;
  display: flex; flex-direction: column; justify-content: center;
  border-right: 1px solid var(--line);
}
.hero > .booking .bk-field__label {
  font-size: 11px; letter-spacing: .16em; margin-bottom: .12rem;
}
.hero > .booking .bk-field input,
.hero > .booking .bk-guests__trigger { min-height: 30px; font-size: 12px; }

.hero > .booking .bk-submit {
  background: none; padding: .55rem .6rem; display: flex; align-items: center;
  border-left: 2px solid var(--gold);
}
.hero > .booking .bk-submit .btn {
  width: 100%; min-height: 52px; padding-inline: 2.1rem;
  background: var(--gold); color: var(--ink); border-color: var(--gold);
  font-size: var(--fs-micro);
}
.hero > .booking .bk-submit .btn:hover { background: var(--gold-lt); border-color: var(--gold-lt); }

@media (max-width: 700px) {
  .hero > .booking .bk-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero > .booking .bk-submit { border-left: 0; border-top: 2px solid var(--gold); }
}

/* ============ WHY BOOK DIRECT — left-edge toaster ============
   A vertical tab stuck to the left of the hero. Clicking it slides out a panel;
   it never covers the booking form and costs no vertical space. */
.wbd {
  /* Sits BELOW the hero's prev arrow, which is centred at 50%. The arrow's
     lower edge is 50% + 24px. The band down to the booking form is only ~228px
     and the tab is ~220px, so the offset is tight by necessity: 26px clears
     the arrow and still leaves the form untouched. */
  position: absolute; left: 0; top: calc(50% + 32px);
  z-index: 6; display: flex; align-items: stretch;
}
.wbd__tab {
  display: flex; align-items: center; gap: .5rem;
  writing-mode: vertical-rl; transform: rotate(180deg);
  background: var(--gold); color: var(--ink); border: 0; cursor: pointer;
  padding: .55rem .55rem; font-family: var(--font-body);
  font-size: var(--fs-micro); letter-spacing: .18em; text-transform: uppercase; font-weight: 600;
  box-shadow: 0 10px 30px rgba(7,17,40,.3);
}
.wbd__tab:hover { background: var(--gold-lt); }
.wbd__tab svg { transform: rotate(90deg); }
.wbd__panel {
  position: relative;
  width: min(78vw, 320px); background: rgba(13,18,32,.94); backdrop-filter: blur(8px);
  color: #D3D9E6; padding: 1.2rem 1.3rem; box-shadow: 0 18px 50px rgba(7,17,40,.42);
  border-left: 2px solid var(--gold);
}
.wbd__panel[hidden] { display: none; }
.wbd__close {
  position: absolute; top: .3rem; right: .3rem;
  display: grid; place-items: center;
  width: 32px; height: 32px; padding: 0;
  background: none; border: 0; border-radius: 50%;
  color: var(--gold-lt); cursor: pointer;
  transition: background .2s var(--ease);
}
.wbd__close:hover, .wbd__close:focus-visible { background: rgba(232,200,106,.16); }
.wbd__h {
  font-family: var(--font-body); font-size: var(--fs-micro); letter-spacing: .2em;
  text-transform: uppercase; color: var(--gold-lt); margin: 0 0 .8rem;
}
.wbd__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; }
.wbd__list li { display: flex; gap: .6rem; font-size: var(--fs-small); line-height: 1.45; }
.wbd__list svg { color: var(--gold-lt); flex: none; margin-top: 2px; }
.wbd__list strong { color: #fff; font-weight: 600; }
.wbd__list a { color: var(--gold-lt); text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 700px) {
  /* Sit the toaster in the upper half: at bottom:20% its panel covered the
     booking form, which is the one thing it must never do. */
  /* Opens higher than 26% so the narrower panel, whose text wraps more, still
     has room to show every line inside the short mobile hero. */
  /* position:fixed so the panel is NOT trapped by the hero's
     overflow:hidden - it opens OVER the content below rather than being
     squeezed inside the short hero. Anchored below the fixed header so
     it never overlaps the hamburger. */
  /* Absolute, not fixed: the tab belongs to the hero and scrolls away with
     it rather than following the page. Offset by the header height so it
     still clears the hamburger while the hero is in view. */
  .wbd { position: absolute; top: calc(var(--header-h) + 10px);
         bottom: auto; transform: none; z-index: 6; }
  /* While the hamburger menu is open the tab must not float over it:
     both sit at z-index 120, so the tab won on source order. It is
     hidden outright, and its panel with it, until the menu closes. */
  body:has(.nav--menu.is-open) .wbd,
  body.nav-open .wbd { opacity: 0; visibility: hidden; pointer-events: none; }
  /* The tab ran 213px tall inside a ~320px hero, crowding the photograph.
     Tighter padding, tracking and type bring it to roughly half the hero
     height. The label itself is unchanged. */
  /* min-width rather than padding: padding alone left the button at 37px,
     under the 44px tap target WCAG 2.5.5 asks for. */
  .wbd__tab {
    /* A further 20% shorter (145px -> ~116px): the height is set by the
       vertical label, so the saving comes from tracking, type size and the
       icon rather than from padding, which still carries the tap target. */
    padding: .3rem .45rem; font-size: 9px; letter-spacing: .01em;
    /* 20% narrower: 44 -> 35px. The ::before below restores a 44px touch
       area so WCAG 2.5.5 still passes without widening the visible strip. */
    min-width: 35px; gap: .3rem; position: relative;
  }
  .wbd__tab svg { width: 10px; height: 10px; }
  .wbd__tab::before { content: ""; position: absolute; inset: 0 -9px 0 0; }
  /* The hero is ~309px tall on a phone and clips its overflow, so a 221px
     panel anchored partway down lost its last line (the phone number). It is
     capped to the space actually available and scrolls if a line wraps. */
  .wbd__panel {
    /* 20% narrower again (260 -> 208). That makes the text wrap more, which is
       why .wbd now opens at 14% instead of 26% - the extra ~38px of hero
       absorbs the taller content. */
    width: min(53vw, 208px); padding: .6rem .7rem;
    /* .wbd is anchored at 26% of the hero, so the panel has the remaining 74%
       MINUS the 13px it sits below .wbd's own top edge. Measured: 229px of
       hero below the tab on a 414px phone, so 0.74 - a small margin. */
    /* Bounded by the HERO now, not the viewport: the tab is absolute again,
       so the panel is clipped by the hero overflow rather than the screen. */
    max-height: calc(100vw * 0.5625 - 20px);
    overflow-y: auto;
  }
  /* 232px of content in ~208px of space meant the last line (the phone
     number) sat below the fold. Tightening the list rhythm and the heading
     gap brings the whole panel inside the hero without scrolling. */
  .wbd__panel li { margin-bottom: .22rem; line-height: 1.3; }
  .wbd__panel li:last-child { margin-bottom: 0; }
  .wbd__h { margin-bottom: .3rem; }
  .wbd__list { gap: .3rem; }

  /* Footer on a phone: the brand block spans the full width and the three
     link columns pair up two-across, so Explore and Information sit side by
     side instead of the grid stacking into one very tall column. */
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.4rem 1.2rem;
  }
  .footer__grid > *:first-child { grid-column: 1 / -1; max-width: none; }
  /* Get in Touch holds the address and phone, so it is taller than the two
     link columns and was wrapping onto a row of its own with dead space
     beside it. Spanning it full width uses that row instead of wasting it. */
  .footer__grid > *:last-child { grid-column: 1 / -1; }
  /* the brand blurb is redundant above a full address block */
  .footer__blurb { display: none; }

  /* Facilities ("What is Here") becomes a swipeable row on a phone: eight
     tiles stacked two-up made a very long column. 1.25 tiles per view leaves
     the next one peeking, which signals the row scrolls. JS advances it. */
  .grid--4.rowswipe {
    display: flex !important;
    grid-template-columns: none !important;
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    gap: 1rem;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter);
  }
  .grid--4.rowswipe::-webkit-scrollbar { display: none; }
  .grid--4.rowswipe > .usp {
    flex: 0 0 calc(80% - 1rem); scroll-snap-align: start; min-width: 0;
  }
}


/* ============ RESORT MOTIFS ============
   Hand-drawn SVG taken from what is actually in the property photographs — the
   coconut palms, the circular pool, the entrance archway, the tiled pavilion
   and the playground slide. Decorative only: aria-hidden, no extra requests
   beyond one sprite, and suppressed under reduced-motion. */
.motifs { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
/* Watermark, not wallpaper: small, faint and set in from the edge so it reads
   as a stamp rather than a background pattern. */
.motif { position: absolute; color: var(--navy); opacity: .035; }
.section--dark .motif { color: var(--gold-lt); opacity: .055; }

.motif--palm-l  { left: 2.5%;   bottom: 8%;  width: 92px;  transform: rotate(-6deg); }
.motif--palm-r  { right: 3%;    top: 12%;    width: 104px; transform: rotate(8deg) scaleX(-1); }
.motif--arch    { right: 3.5%;  bottom: 10%; width: 96px; }
.motif--water   { right: 4%;    bottom: 9%;  width: 120px; }
.motif--pav     { left: 3%;     top: 12%;    width: 104px; }
.motif--slide   { right: 3%;    bottom: 9%;  width: 90px; }

@media (max-width: 700px) {
  .motif { opacity: .03; }
  .motif--palm-l, .motif--palm-r { width: 62px; }
  .motif--arch, .motif--pav, .motif--slide, .motif--water { display: none; }
}
@media (prefers-reduced-motion: reduce) { .motifs { display: none; } }

/* ---- section divider: a small leaf mark between bands ---- */
.divider {
  display: flex; align-items: center; justify-content: center; gap: 1rem;
  padding-block: clamp(1.4rem, 3vw, 2.4rem);
  background: inherit;
}
.divider::before, .divider::after {
  content: ""; height: 1px; width: clamp(40px, 12vw, 130px);
  background: linear-gradient(90deg, transparent, var(--gold));
}
.divider::after { background: linear-gradient(90deg, var(--gold), transparent); }
.divider svg { width: 46px; color: var(--gold); flex: none; }


/* ============ INTRO / ABOUT — two columns, stacked images ============
   Matched to the supplied reference: a centred wordmark, then a left column
   carrying a pill label, heading, copy and a button, and a right column of
   three overlapping rounded photographs with a caption beneath. */
/* Use the SAME section rhythm as every other band rather than a bespoke value —
   the page reads inconsistently when one section sets its own padding. */
.intro { padding-block: var(--section-pad); }
.intro .wrap { max-width: var(--maxw); }
.intro .eyebrow { display: flex; justify-content: center; }

.intro__h1 { text-align: center; margin-bottom: .5rem; }
.intro__lead {
  text-align: center; color: var(--muted); font-size: var(--fs-body);
  max-width: 56ch; margin: 0 auto clamp(2.4rem, 4.5vw, 3.6rem);
}

.intro__cols {
  display: grid; gap: clamp(1.8rem, 4vw, 3.4rem);
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  align-items: center;
}

/* Was a rounded pill — the only 999px radius on a site that is squared-off
   throughout (buttons are explicitly border-radius:0). Now it uses the same
   eyebrow pattern as every other section label. */
.pill {
  display: inline-flex; align-items: center; gap: .7rem;
  margin-bottom: 1.1rem;
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: var(--gold-text);
}
.pill::before { content: ""; width: 34px; height: 1px; background: currentColor; }
.intro__h2 { font-size: var(--fs-h2); line-height: 1.14; margin-bottom: .8rem;
             text-wrap: balance; }
/* Below ~1200px the copy column narrows to ~340px and this heading ran to
   five lines. A fluid size tied to the viewport holds it at three until the
   layout stacks to one column at 900px. */
@media (max-width: 1200px) {
  .intro__h2 { font-size: clamp(1.55rem, 2.6vw, 2.1rem); }
}
.intro__copy p { color: var(--muted); font-size: var(--fs-body); max-width: 46ch; margin-bottom: 1.4rem; }

/* the three overlapping photographs */
.intro__stack { position: relative; min-height: clamp(300px, 34vw, 430px); }
.stk { margin: 0; position: absolute; overflow: hidden;
       box-shadow: 0 18px 44px rgba(11,33,84,.18); }
.stk img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The reference separates the photographs with clear white space; these were
   overlapping by 38-39px instead, which read as one merged block. */
/* Back to two tiles (the pool photo was dropped), so they widen to fill the
   column again — at the old 44%/25% the pair left a dead third on the right. */
.stk--1 { left: 0;     top: 0;    width: 56%; aspect-ratio: 5/6;  z-index: 3; }
/* The I-love-RPR sign is a WIDE subject: in a 4/5 portrait tile the final R
   was always cropped off, whatever the crop window. The tile is landscape now
   and wider, so the whole sign reads. */
.stk--2 { right: 0;    top: 20%;  width: 41%; aspect-ratio: 4/3;  z-index: 2; }

@media (max-width: 900px) {
  .intro__cols { grid-template-columns: 1fr; }
  .intro__stack { min-height: 340px; }
}
@media (max-width: 700px) {
  /* The desktop version is an absolutely-positioned overlapping collage; on a
     phone the two photographs sit side by side in a simple static grid. */
  .intro__stack {
    position: static; min-height: 0;
    display: grid; grid-template-columns: 1fr 1fr; gap: .6rem;
  }
  /* The desktop rules above set width as a % of .intro__stack, which still
     cascades here — reset it to fill the grid cell instead. */
  .stk { position: static; width: 100%; }
  .stk--1 { aspect-ratio: 4/5; }
  .stk--2 { aspect-ratio: 4/3; }
}


/* ============ LOCATION CARDS ============
   Each card shows only its NAME at rest; the description slides up and fades
   in on hover/focus. The description is never display:none — it keeps its
   space reserved via a transform, so nothing reflows when it appears, and it
   stays in the accessibility tree for screen readers. */
/* The section is a slider (reusing .oslider), so the cards no longer need a
   grid of their own. The card fills its slide. */
.lslider .lcard { width: 100%; }

.lcard {
  /* Started at 4/3; +25%, then +15% again = 1.4375x the original height.
     4/3 -> 64/69. */
  position: relative; overflow: hidden; aspect-ratio: 64/69;
  background: var(--ink-2); display: block;
}
.lcard__img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .8s var(--ease); }
.lcard:hover .lcard__img, .lcard:focus-within .lcard__img { transform: scale(1.06); }
.lcard__veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,14,26,0) 34%, rgba(9,14,26,.88) 100%);
  transition: background .45s var(--ease);
}
.lcard:hover .lcard__veil, .lcard:focus-within .lcard__veil {
  background: linear-gradient(180deg, rgba(9,14,26,.20) 0%, rgba(9,14,26,.92) 100%);
}
.lcard__body {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 1.1rem 1.15rem 1.15rem; color: #fff;
}
.lcard__name { color: #fff; font-family: var(--font-head); font-size: var(--fs-h3);
  margin: 0; line-height: 1.2; }
/* At rest the description collapses to zero height so the NAME sits on the
   bottom edge of the card; on hover it expands and fades in beneath it.
   grid-template-rows animates cleanly and, unlike display:none, keeps the
   text in the accessibility tree throughout. */
.lcard__descwrap {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .42s var(--ease);
}
.lcard:hover .lcard__descwrap, .lcard:focus-within .lcard__descwrap {
  grid-template-rows: 1fr;
}
.lcard__desc {
  overflow: hidden; min-height: 0;
  margin: 0; font-size: var(--fs-small); color: #E7EBF3; line-height: 1.55;
  opacity: 0; transform: translateY(8px);
  transition: opacity .42s var(--ease), transform .42s var(--ease), padding-top .42s var(--ease);
}
.lcard:hover .lcard__desc, .lcard:focus-within .lcard__desc {
  opacity: 1; transform: none; padding-top: .5rem;
}
/* The text-only cards have no photo to reveal against, so they read as normal
   cards: name and description both visible, on the site's paper surface. */
.lcard--text { aspect-ratio: auto; min-height: 100%; background: #fff; border: 1px solid var(--line); }
.lcard--text .lcard__body { position: static; color: var(--ink); padding: 1.5rem 1.4rem; }
.lcard--text .lcard__name { color: var(--ink); }
.lcard--text .lcard__descwrap { grid-template-rows: 1fr; }
.lcard--text .lcard__desc { color: var(--muted); opacity: 1; transform: none; padding-top: .5rem; }

/* Touch devices have no hover: show the description outright rather than
   hiding copy behind an interaction that cannot happen. */
@media (hover: none) {
  .lcard__descwrap { grid-template-rows: 1fr; }
  .lcard__desc { opacity: 1; transform: none; padding-top: .5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .lcard__img, .lcard__veil, .lcard__desc, .lcard__descwrap { transition: none; }
  .lcard:hover .lcard__img, .lcard:focus-within .lcard__img { transform: none; }
}

/* ============ GALLERY MOSAIC ============
   The reference staggers five columns — a tall tile, a split pair, a taller
   centre tile, a split pair, a tall tile — with the outer columns dropped so the
   row rises to the middle. Built in THIS site's language: squared corners, no
   radius, gold hairline on hover. */
.gal-mosaic {
  display: grid; gap: .8rem;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  align-items: stretch;
}
.gal-mosaic .gtile {
  display: block; overflow: hidden; position: relative;
  background: rgba(255,255,255,.06);
  min-width: 0; min-height: 0;      /* let the grid track decide, not the image */
  width: 100%;
  /* NO height here — the stagger rules below set 74% on the outer tiles, and a
     height:100% at equal specificity later in the file silently flattened them. */
}
.gal-mosaic .gtile img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.gal-mosaic .gtile:hover img, .gal-mosaic .gtile:focus-visible img { transform: scale(1.06); }
.gal-mosaic .gtile::after {
  content: ""; position: absolute; inset: 0;
  border: 1px solid transparent; transition: border-color .3s var(--ease);
}
.gal-mosaic .gtile:hover::after, .gal-mosaic .gtile:focus-visible::after { border-color: var(--gold); }

/* the stagger: outer tiles sit lower, the centre one taller */
.gtile--a  { grid-column: 1; grid-row: 1 / span 2; align-self: center; height: 74%; }
.gtile--b1 { grid-column: 2; grid-row: 1; height: 100%; }
.gtile--b2 { grid-column: 2; grid-row: 2; height: 100%; }
.gtile--c  { grid-column: 3; grid-row: 1 / span 2; height: 100%; }
.gtile--d1 { grid-column: 4; grid-row: 1; height: 100%; }
.gtile--d2 { grid-column: 4; grid-row: 2; height: 100%; }
.gtile--e  { grid-column: 5; grid-row: 1 / span 2; align-self: center; height: 74%; }

.gal-mosaic { min-height: clamp(320px, 34vw, 430px); }

@media (max-width: 900px) {
  .gal-mosaic { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(3, minmax(0, 1fr)); }
  .gtile--a  { grid-column: 1; grid-row: 1 / span 2; height: auto; align-self: stretch; }
  .gtile--b1 { grid-column: 2; grid-row: 1; height: 100%; }
  .gtile--b2 { grid-column: 3; grid-row: 1; }
  .gtile--c  { grid-column: 2 / span 2; grid-row: 2; }
  .gtile--d1 { grid-column: 1; grid-row: 3; }
  .gtile--d2 { grid-column: 2; grid-row: 3; }
  .gtile--e  { grid-column: 3; grid-row: 3; height: auto; align-self: stretch; }
  .gal-mosaic { min-height: 420px; }
}
@media (max-width: 700px) {
  .gal-mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; gap: .6rem; min-height: 0; }
  .gal-mosaic .gtile { grid-column: auto !important; grid-row: auto !important;
                       height: auto !important; align-self: stretch !important; aspect-ratio: 1; }
  .gtile--c { grid-column: 1 / -1 !important; aspect-ratio: 16/10; }
}


/* ============ WOOD SCENE ============
   A hand-drawn line scene under the first section: the jhula, a child on the
   slide, a seesaw and the games table — the play facilities the FACTS sheet
   actually lists. Drawn, not sourced from an icon library, and coloured in the
   resort's own timber tone. */
.woodscene {
  /* sits at section level, so it needs the wrap's own width and gutter */
  width: 100%; max-width: var(--maxw);
  margin-inline: auto; padding-inline: var(--gutter);
  margin-top: clamp(1.8rem, 4vw, 3.2rem);
  padding-top: clamp(1.4rem, 3vw, 2.2rem);
  border-top: 1px solid var(--line);
  color: #8A6A3C;                     /* the timber of the gate and pergola */
}
.woodscene svg { width: 100%; height: auto; display: block; opacity: .5; }
.section--dark .woodscene { border-top-color: rgba(232,200,106,.22); color: var(--gold-lt); }
.section--dark .woodscene svg { opacity: .42; }

/* the line draws itself in once, then rests — skipped under reduced-motion */
@media (prefers-reduced-motion: no-preference) {
  .woodscene .ws-wood > * {
    stroke-dasharray: 1200; stroke-dashoffset: 1200;   /* > the 860px ground line */
    transition: stroke-dashoffset 1.8s var(--ease);
  }
  .woodscene.is-in .ws-wood > * { stroke-dashoffset: 0; }
  .woodscene .ws-wood > *:nth-child(n+6)  { transition-delay: .12s; }
  .woodscene .ws-wood > *:nth-child(n+12) { transition-delay: .24s; }
  .woodscene .ws-wood > *:nth-child(n+18) { transition-delay: .36s; }
}
/* the dashed slide rails must keep their own dash pattern */
.woodscene .ws-wood > [stroke-dasharray="7 9"] { stroke-dasharray: 7 9 !important; stroke-dashoffset: 0 !important; }

@media (max-width: 700px) { .woodscene svg { opacity: .42; } }





/* ============ OFFERS SLIDER ============
   Image-led cards on a scroll-snap track, so it works with touch, the arrow
   buttons and the keyboard without a library. Squared corners and a gold rule,
   matching the rest of the site. */
.oslider { position: relative; }
.oslider__track {
  display: flex; gap: var(--card-gap);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: .4rem;
}
.oslider__track::-webkit-scrollbar { display: none; }
.oslide { flex: 0 0 calc((100% - var(--card-gap) * 2) / 3); scroll-snap-align: start; min-width: 0; }

.ocard {
  background: #fff; border: 1px solid var(--line);
  display: flex; flex-direction: column; height: 100%; min-width: 0;
  transition: box-shadow .35s var(--ease), transform .35s var(--ease);
}
.ocard:hover { box-shadow: 0 18px 44px rgba(11,33,84,.16); transform: translateY(-3px); }
.ocard__media { position: relative; aspect-ratio: 16 / 11; overflow: hidden; }
.ocard__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.ocard:hover .ocard__media img { transform: scale(1.06); }
.ocard__tag {
  position: absolute; left: 0; bottom: 0;
  background: var(--gold); color: var(--ink);
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase; font-weight: 600;
  padding: .38rem .8rem;
}
.ocard__body { padding: 1.25rem 1.3rem 1.35rem; display: flex; flex-direction: column; gap: .45rem; flex: 1 1 auto; }
.ocard__name { font-family: var(--font-head); font-size: var(--fs-h3); color: var(--ink); margin: 0; }
.ocard__copy { font-size: var(--fs-small); color: var(--muted); margin: 0; }
.ocard__cta {
  margin-top: auto; padding-top: .9rem;
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase; color: var(--gold-text);
  min-height: 24px;
}
.ocard__cta svg { transition: transform .3s var(--ease); }
.ocard:hover .ocard__cta svg { transform: translateX(4px); }
/* dark bands keep the card readable */
.section--dark .ocard { background: var(--ink-2); border-color: rgba(255,255,255,.09); }
.section--dark .ocard__name { color: #fff; }
.section--dark .ocard__copy { color: #A9B2C4; }
.section--dark .ocard__cta { color: var(--gold-lt); }

/* arrows */
.oslider__nav {
  position: absolute; top: calc(50% - 3rem); transform: translateY(-50%);
  width: 44px; height: 44px; display: grid; place-items: center;
  background: rgba(255,255,255,.95); border: 1px solid var(--line);
  color: var(--ink); cursor: pointer; z-index: 3;
  box-shadow: 0 6px 18px rgba(11,33,84,.14);
  transition: background .25s var(--ease), color .25s var(--ease), opacity .25s var(--ease);
}
.oslider__nav:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.oslider__nav--prev { left: -14px; }
.oslider__nav--next { right: -14px; }
.oslider__nav[disabled] { opacity: .32; pointer-events: none; }

/* dots — 44px element box with the small mark drawn inside */
.oslider__dots { display: flex; justify-content: center; gap: .2rem; margin-top: 1rem; }
.oslider__dot {
  width: 44px; height: 44px; padding: 0; border: 0; background: none;
  display: grid; place-items: center; cursor: pointer;
}
.oslider__dot::before {
  content: ""; width: 9px; height: 9px; border: 1px solid var(--gold-text);
  transition: background .25s var(--ease);
}
.oslider__dot.is-active::before { background: var(--gold-text); }
.section--dark .oslider__dot::before { border-color: var(--gold-lt); }
.section--dark .oslider__dot.is-active::before { background: var(--gold-lt); }

@media (max-width: 1024px) { .oslide { flex-basis: calc((100% - var(--card-gap)) / 2); } }
@media (max-width: 700px) {
  .oslide { flex-basis: 86%; }
  .oslider__nav { display: none; }        /* swipe is the affordance on touch */
  .oslider__track { margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); }
}


/* A ghost button is white-on-transparent and only legible on a dark ground.
   If one ever lands on a light section it must not disappear — scope the white
   treatment to dark bands and fall back to the outline style elsewhere. */
.btn--ghost { background: transparent; color: var(--navy); border-color: var(--navy); }
.btn--ghost:hover { background: var(--navy); color: #fff; border-color: var(--navy); }
.section--dark .btn--ghost, .hero .btn--ghost {
  background: rgba(255,255,255,.12); color: #fff; border-color: rgba(255,255,255,.5);
}
.section--dark .btn--ghost:hover, .hero .btn--ghost:hover {
  background: #fff; color: var(--navy); border-color: #fff;
}


/* even vertical rhythm inside the footer columns */
.footer__logo img { height: 82px; }
.footer__grid > div > p { margin-top: 1rem; margin-bottom: 0; font-size: var(--fs-small); line-height: 1.6; }
.footer__h { margin-bottom: 1.15rem; }
.footer__links a { min-height: 38px; }
.footer__contact { gap: .7rem; }
.footer__social { margin-top: 1.3rem; }


/* The email broke mid-word ("gmail.co / m") with overflow-wrap:anywhere, but
   word-break:normal stopped it breaking at all and it ran 18px past the
   viewport at 512px. break-word wraps at the @ / dot boundaries instead, and
   min-width:0 lets the flex item actually shrink. */
.footer__contact a[href^="mailto:"] {
  /* word-break:break-word split the address even when the line had room
     (242px needed, 432px available) - it dates from the narrow 4-column
     footer. overflow-wrap alone still prevents overflow on a genuinely
     narrow column, but keeps the address on one line wherever it fits. */
  overflow-wrap: break-word; word-break: normal; hyphens: none;
  min-width: 0; max-width: 100%;
  /* The address needs 242px but the footer column leaves 228px, so it wrapped
     onto two lines. A slightly tighter size and tracking bring it under the
     limit and keep it on one. */
  font-size: 13.5px; letter-spacing: -.01em;
}
.footer__contact li > span, .footer__contact li > a { min-width: 0; }
.footer__contact li { line-height: 1.55; }

/* The credit row sat flush on the page edge — the footer had no bottom padding
   at all, so the last line touched the browser chrome. */
.footer__bottom { padding-bottom: clamp(1.6rem, 3vw, 2.4rem); }


/* ---- hero video pause control (WCAG 2.2.2) ---- */
.hero__pause {
  position: absolute; right: var(--gutter); top: calc(var(--header-h) + 1rem);
  z-index: 4; width: 44px; height: 44px;
  display: grid; place-items: center;
  background: rgba(7,17,40,.55); color: #fff;
  border: 1px solid rgba(255,255,255,.45); cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.hero__pause[hidden] { display: none; }
.hero__pause:hover { background: rgba(7,17,40,.8); border-color: #fff; }
.hero__pause:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
.hero__pause .hero__pause-ic--play { display: none; }
.hero__pause[aria-pressed="true"] .hero__pause-ic--pause { display: none; }
.hero__pause[aria-pressed="true"] .hero__pause-ic--play { display: block; }
@media (max-width: 700px) { .hero__pause { top: calc(var(--header-h) + .6rem); } }


/* ---- mobile: taller room cards (+20%) ---- */
@media (max-width: 700px) {
  .rgrid.grid--swipe > .rcard { aspect-ratio: 10 / 9; }   /* was 4/3 -> ~20% taller */
}

/* ============ MOBILE BOOKING SHEET ============
   On a phone the header Book Now opens the booking form as a full sheet rather
   than jumping to a form squeezed under the hero. Same form, same JS — only the
   presentation changes, so there is no second implementation to drift. */
@media (max-width: 700px) {
  body.bk-open { overflow: hidden; }

  .hero > .booking.is-sheet {
    /* A CENTRED dialog rather than a bottom sheet: place-items centres the
       card on both axes and an overflowing grid item is clamped to the
       container, so the header can never end up off-screen. */
    position: fixed; inset: 0; z-index: 140;
    display: grid; place-items: center;
    background: rgba(7,17,40,.55); padding: 1rem;
  }
  .hero > .booking.is-sheet > .wrap {
    width: min(100%, 420px);
    max-height: calc(100svh - 2rem); overflow-y: auto;
    padding: 0; border-radius: 4px;
    box-shadow: 0 24px 60px rgba(7,17,40,.45);
  }
  .hero > .booking.is-sheet .bk-form {
    grid-template-columns: 1fr;
    background: #fff; border-radius: 0;
    padding: .4rem 0 max(.6rem, env(safe-area-inset-bottom));
    max-height: none;
    animation: bk-rise .28s var(--ease);
  }
  @keyframes bk-rise { from { transform: translateY(14px); opacity: .6; } to { transform: none; opacity: 1; } }

  .hero > .booking.is-sheet .bk-field { padding: .85rem 1.15rem; border-right: 0; border-bottom: 1px solid var(--line); }
  .hero > .booking.is-sheet .bk-field:has(#promo) { display: block; }   /* promo returns in the sheet */
  .hero > .booking.is-sheet .bk-field input,
  .hero > .booking.is-sheet .bk-guests__trigger { min-height: 44px; font-size: 12px; }
  .hero > .booking.is-sheet .bk-submit { padding: .8rem 1.15rem 1rem; border-top: 0; }
  .hero > .booking.is-sheet .bk-submit .btn { min-height: 52px; }

  .booking.is-sheet .bk-sheet-close {
    align-self: flex-end; margin: 0 1rem .7rem; width: 44px; height: 44px;
    display: grid; place-items: center; background: #fff; border: 0; color: var(--ink);
    cursor: pointer;
  }

  /* In the sheet the popover sits in flow rather than floating, but it still
     obeys data-expanded — it must open only when the guest taps the trigger. */
  .hero > .booking.is-sheet .bk-pop {
    position: static; width: auto; max-width: none;
    transform: none; box-shadow: none; border: 0;
    padding: 0 1.15rem; max-height: 0; overflow: hidden;
    opacity: 0; visibility: hidden;
    transition: max-height .32s var(--ease), opacity .25s var(--ease),
                padding .32s var(--ease);
  }
  .hero > .booking.is-sheet .bk-guests[data-expanded="true"] .bk-pop {
    opacity: 1; visibility: visible; max-height: 26rem;
    border-top: 1px solid var(--line); padding: .8rem 1.15rem;
  }
  /* the chevron was hidden, so the field did not read as expandable */
  .hero > .booking.is-sheet .bk-guests__trigger svg { transition: transform .3s var(--ease); }
  .hero > .booking.is-sheet .bk-guests[data-expanded="true"] .bk-guests__trigger svg {
    transform: rotate(180deg);
  }
}


/* ---- mono line marks flanking the wordmark ---- */
.wm { display: flex; align-items: center; justify-content: center; gap: clamp(.9rem, 2.6vw, 2.4rem); }
.wm .intro__h1 { margin-bottom: 0; }
.wm__ic {
  width: clamp(34px, 3.6vw, 52px); height: auto; flex: none;
  color: var(--ink); opacity: .38;          /* black-and-white, quiet */
}
.section--dark .wm__ic { color: #fff; opacity: .5; }
@media (max-width: 700px) { .wm { gap: .6rem; } .wm__ic { width: 28px; opacity: .3; } }


/* ============ TYPE SCALE — one size per level ============
   Audit found 5 distinct H3 sizes and 12 distinct paragraph sizes. A reader
   cannot infer hierarchy from a scale with twelve steps. These tokens are the
   single source of truth; local font-size overrides on headings and body copy
   are removed below.
   2026-09-23: every step raised by 1px (0.0625rem) at BOTH ends of each
   clamp, so the whole scale moves together and the hierarchy is unchanged. */
:root {
  --fs-h1: clamp(2.6625rem, 6vw, 5.0625rem);
  --fs-h2: clamp(1.9625rem, 3.4694vw, 3.1125rem);
  --fs-h3: clamp(1.2425rem, 1.5694vw, 1.5125rem);
  --fs-h4: clamp(1.0625rem, 1.2694vw, 1.1825rem);
  --fs-h5: 0.9025rem;
  --fs-lead: 1.1225rem;     /* intro + section lead lines */
  --fs-h2-sm: clamp(1.7625rem, 2.8694vw, 2.5625rem);  /* secondary display */
  /* card titles: above H3, still clearly below H2. Without this the room and
     venue titles borrowed --fs-h2-sm and rendered the same size as an H2. */
  --fs-h3-lg: clamp(1.4125rem, 1.9694vw, 1.9125rem);
  --fs-body: 0.9375rem;      /* 15px — the one body size */
  --fs-small: 0.9425rem;     /* captions, meta, footer links */
  --fs-micro: 0.7825rem;     /* eyebrows, tags, uppercase labels */
  --lh-head: 1.14;
  --lh-body: 1.65;
}

h1 { font-size: var(--fs-h1); line-height: 1.04; }
h2 { font-size: var(--fs-h2); line-height: var(--lh-head); }
h3 { font-size: var(--fs-h3); line-height: 1.22; }
h4 { font-size: var(--fs-h4); line-height: 1.3; }
h5 { font-size: var(--fs-h5); line-height: 1.35; letter-spacing: .1em; text-transform: uppercase; }
p  { font-size: var(--fs-body); line-height: var(--lh-body); }

/* the deliberate exceptions, each pinned to a scale step rather than a one-off */
.lead              { font-size: var(--fs-lead); line-height: 1.6; }
.intro__lead       { font-size: var(--fs-lead); }
.card__meta,
.rcard__meta,
.ocard__copy,
.footer__links a,
.footer__contact,
.stk__cap span,
.usp p             { font-size: var(--fs-body); line-height: 1.55; }
.eyebrow, .pill, .rcard__tag, .ocard__tag, .footer__h,
.stat__lbl, .ph__s { font-size: var(--fs-micro); }
.bk-field__label { font-size: 11px; }
.footer__bottom, .footer__bottom p  { font-size: var(--fs-small); }

/* footer headings are H2 in the markup but read as labels — keep them at the
   micro step without inheriting the H2 display size */
.footer__h { font-size: var(--fs-micro); line-height: 1.4; }
/* was an inline font-size:.9rem — the only paragraph off the scale */
.footer__blurb { margin-top: .9rem; font-size: var(--fs-small); }


/* ============ MOBILE SLIDERS ============ */
@media (max-width: 700px) {
  /* Two-row sideways scroll, for sections with enough items to need it.
     Why Guests Choose Us (.usps), What is Here (.grid--4), and the Dining
     slider (.dslider, its own single-row full-bleed scroller defined
     separately below) each get their own carousel treatment instead, so
     all three are excluded from this two-row grid. Without :not(.dslider)
     this rule's higher specificity + !important silently overrode the
     dining slider's display:flex on every screen under 700px, forcing its
     2 photos into a 2-row grid — i.e. stacked instead of swipeable. */
  .rowswipe:not(.usps):not(.grid--4):not(.dslider) {
    display: grid !important;
    grid-auto-flow: column !important;
    grid-template-columns: none !important;
    grid-template-rows: repeat(2, 1fr) !important;
    /* 72% leaves the next card peeking, which is what tells a guest the row
       swipes. At 46% four items filled two full columns and never scrolled. */
    grid-auto-columns: 72%;
    gap: 1.2rem 1rem;
    overflow-x: auto; scroll-snap-type: x proximity;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter); padding-bottom: .5rem;
    scroll-padding-inline-start: var(--gutter);
  }
  .rowswipe:not(.usps):not(.grid--4):not(.dslider)::-webkit-scrollbar { display: none; }
  .rowswipe:not(.usps):not(.grid--4):not(.dslider) > * { scroll-snap-align: start; min-width: 0; }
  /* cards fill their row so both rows share one baseline */
  .rowswipe:not(.usps):not(.grid--4):not(.dslider) > .usp { height: 100%; }

  /* Why Guests Choose Us: one card at a time, swipe for the next — icon,
     heading and description styling is untouched, only the container
     becomes a single-row snap carousel instead of a stacked grid. */
  .usps.rowswipe {
    display: flex !important;
    grid-template-columns: none;
    gap: var(--card-gap);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter); padding-bottom: .5rem;
    scroll-padding-inline-start: var(--gutter);
  }
  .usps.rowswipe::-webkit-scrollbar { display: none; }
  .usps.rowswipe > .usp {
    flex: 0 0 85%; scroll-snap-align: start; min-width: 0; height: auto;
  }

  /* What is Here: same one-card-at-a-time swipe as Why Guests Choose Us */
  .grid--4.rowswipe {
    display: flex !important;
    grid-template-columns: none;
    gap: var(--card-gap);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter); padding-bottom: .5rem;
    scroll-padding-inline-start: var(--gutter);
  }
  .grid--4.rowswipe::-webkit-scrollbar { display: none; }
  .grid--4.rowswipe > .usp {
    flex: 0 0 85%; scroll-snap-align: start; min-width: 0; height: auto;
  }

  /* Gallery: the staggered mosaic collapses to a single swipe row */
  .gal-mosaic.grid--swipe {
    /* The staggered desktop mosaic positions tiles with negative offsets. In
       this flex row those offsets made the tiles hit-testable BELOW the row,
       so they sat over the "View full gallery" button and swallowed its click
       (it opened the lightbox instead of navigating). Clipping the row to its
       own box confines the tiles to it. */
    display: flex !important;
    grid-template-columns: none; grid-template-rows: none;
    gap: .6rem; overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter); padding-bottom: .5rem;
    min-height: 0;
  }
  .gal-mosaic.grid--swipe::-webkit-scrollbar { display: none; }
  .gal-mosaic.grid--swipe { align-items: stretch; }
  .gal-mosaic.grid--swipe > .gtile {
    /* position must stay RELATIVE: `static` removed the tile as the
       containing block for its own ::after (inset:0), so the border overlay
       resolved against a distant ancestor, grew to 425px and covered the
       "View full gallery" button, swallowing its clicks. */
    flex: 0 0 68%; grid-column: auto !important; grid-row: auto !important;
    margin: 0 !important; position: relative !important; top: auto !important;
    height: auto !important; align-self: stretch !important; aspect-ratio: 4/3;
    scroll-snap-align: start;
  }
}


/* ============ WEATHER WIDGET ============ */
.wx {
  /* A square badge set lower and tighter to the right edge. */
  position: absolute; right: 1.4rem; top: calc(var(--header-h) + 2.4rem);
  z-index: 5; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .1rem;
  min-width: 84px; height: 84px; padding: .45rem .5rem; color: #fff; text-align: center;
  line-height: 1.1;
  background: rgba(7,17,40,.5); border: 1px solid rgba(255,255,255,.28);
  backdrop-filter: blur(6px);
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
}
.wx[hidden] { display: none; }
.wx__ic { color: var(--gold-lt); flex: none; }
.wx__t { letter-spacing: 0; font-size: .58rem; white-space: nowrap; }
.wx__t strong { font-size: 1.12rem; font-weight: 600; letter-spacing: 0; }
.wx__l { opacity: .75; font-size: .5rem; line-height: 1.15; letter-spacing: .06em;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wx__ic { width: 14px; height: 14px; }
@media (max-width: 700px) {
  .wx {
    top: calc(var(--header-h) + 1rem); right: 1rem;
    min-width: 0; height: auto; padding: .4rem .6rem;
    flex-direction: row; gap: .35rem;
  }
  .wx__l { display: none; }
  .wx__t strong { font-size: .95rem; }
  .wx__ic { width: 13px; height: 13px; }
}


/* ---- booking form lifted clear of the control bar ---- */
.hero > .booking { padding-bottom: clamp(4.2rem, 7vh, 5.4rem); }
@media (max-width: 700px) { .hero > .booking { padding-bottom: 4rem; } }

/* ---- footer email: allow a break, keep it inside its column ---- */
.footer__contact li { min-width: 0; }
.footer__contact a[href^="mailto:"] { display: inline-block; max-width: 100%; }


/* The sheet close button belongs to the mobile sheet only. Its hide rule was
   nested inside the max-width:700px block, so on desktop nothing hid it and an
   orphan X sat on the booking form. Hidden globally; the sheet re-shows it. */
.bk-sheet-close { display: none; }


/* ============ ROOM CARD v2 — image, then selling points + Book Now ============
   The old card wrapped everything in one link, so a Book Now inside it would be
   a nested interactive element and the card link would swallow its click. Now
   only the media is the link; the button sits outside it. */
.rcard:has(.rcard__foot) {
  aspect-ratio: auto !important; display: flex; flex-direction: column;
  background: #fff; border: 1px solid var(--line);
}
.section--dark .rcard:has(.rcard__foot) { background: var(--ink-2); border-color: rgba(255,255,255,.09); }

.rcard__media {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 3; flex: none;
}
.rcard--feature .rcard__media { aspect-ratio: 21 / 9; }
.rcard__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.rcard__media:hover img, .rcard__media:focus-visible img { transform: scale(1.06); }
.rcard__label { position: absolute; left: 0; bottom: 0; padding: 1.1rem 1.25rem; color: #fff; }
.rcard__tag  { display: block; font-size: var(--fs-micro); letter-spacing: .2em;
               text-transform: uppercase; color: var(--gold-lt); margin-bottom: .25rem; }
.rcard__name { display: block; font-family: var(--font-head); font-size: var(--fs-h3);
               line-height: 1.1; color: #fff; }
.rcard--feature .rcard__name { font-size: var(--fs-h3-lg); }

.rcard__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: 1rem 1.25rem 1.15rem; flex: 1 1 auto;
}
.rcard__points {
  list-style: none; margin: 0; padding: 0; flex: 1 1 auto; min-width: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .4rem 1rem;
}
.rcard--feature .rcard__points { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.rcard__points li {
  display: flex; align-items: center; gap: .45rem; min-width: 0;
  font-size: var(--fs-small); color: var(--muted); line-height: 1.3;
}
.rcard__points svg { color: var(--gold-text); flex: none; }
.section--dark .rcard__points li { color: #A9B2C4; }
.section--dark .rcard__points svg { color: var(--gold-lt); }
.rcard__book { flex: none; white-space: nowrap; }

@media (max-width: 900px) {
  .rcard--feature .rcard__points { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  .rgrid.grid--swipe > .rcard { aspect-ratio: auto !important; }
  .rcard__media { aspect-ratio: 16 / 10; }
  .rcard--feature .rcard__media { aspect-ratio: 16 / 10; }
  .rcard__foot { flex-direction: column; align-items: stretch; gap: .8rem; }
  .rcard__book { width: 100%; }
}


/* ============ ROOM CARD v3 ============
   Client correction: the selling points sit ON the image, above the room name,
   and View Details returns alongside Book Now. The card is NOT one big link —
   that would swallow both buttons' clicks. */
.rcard:has(.rcard__foot) .rcard__media { position: relative; overflow: hidden; aspect-ratio: 4/3; }
.rcard--feature:has(.rcard__foot) .rcard__media { aspect-ratio: 32 / 9; }
.rcard__over {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.1rem 1.25rem 1.15rem; color: #fff;
}
.rcard__over .rcard__points {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .35rem .5rem;
  /* At rest the card shows only its NAME and actions; the amenity chips
     reveal on hover. Collapsing the row to zero height (rather than
     display:none) animates smoothly, keeps the chips in the accessibility
     tree, and stops the card contents shifting when they appear. */
  overflow: hidden; max-height: 0; opacity: 0;
  transition: max-height .4s var(--ease), opacity .35s var(--ease), margin-bottom .4s var(--ease);
}
.rcard:hover .rcard__over .rcard__points,
.rcard:focus-within .rcard__over .rcard__points {
  max-height: 8rem; opacity: 1; margin-bottom: .7rem;
}
/* Touch has no hover, so the chips stay visible there rather than being
   locked behind an interaction that cannot happen. */
@media (hover: none), (max-width: 900px) {
  .rcard__over .rcard__points { max-height: 8rem; opacity: 1; margin-bottom: .7rem; }
}
@media (prefers-reduced-motion: reduce) {
  .rcard__over .rcard__points { transition: none; }
}
.rcard__over .rcard__points li {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .28rem .55rem; font-size: var(--fs-micro); line-height: 1.2;
  color: #fff; background: rgba(255,255,255,.14);
  border: 1px solid rgba(255,255,255,.24); backdrop-filter: blur(3px);
}
.rcard__over .rcard__points svg { color: var(--gold-lt); flex: none; }
.rcard__over .rcard__tag { color: var(--gold-lt); margin-bottom: .2rem; }
.rcard__over .rcard__name { margin: 0; }
.rcard__over .rcard__name a { color: #fff; }
.rcard__over .rcard__name a:hover { color: var(--gold-lt); }

.rcard__foot { display: flex; gap: .6rem; align-items: center; padding: .95rem 1.25rem 1.1rem; }
.rcard__foot .btn { flex: 1 1 auto; }

/* the veil must reach higher now that chips sit on the image */
.rcard__veil {
  background: linear-gradient(180deg,
    rgba(9,14,26,0) 24%, rgba(9,14,26,.42) 52%, rgba(9,14,26,.86) 100%) !important;
}
@media (max-width: 700px) {
  .rcard--feature:has(.rcard__foot) .rcard__media { aspect-ratio: 16/10; }
  .rcard__over .rcard__points li { font-size: .62rem; padding: .22rem .45rem; }
}


/* ============ MOBILE: no inline booking form ============
   The form is hidden in the hero on phones and only appears as the sheet, via
   Book Now. Same form, same handlers — nothing is duplicated. */
@media (max-width: 700px) {
  .hero > .booking:not(.is-sheet) { display: none; }
  .hero > .booking { padding-bottom: 0; }

  /* The sheet is the ONLY booking UI on a phone, so give it the full desktop
     field set in a comfortable single column. */
  .hero > .booking.is-sheet .bk-form { padding-top: 0; }
  .hero > .booking.is-sheet .bk-field:has(#promo) { display: block; }
  /* .wrap is the sheet's only child and holds the title, the close button and
     the form. It must be the flex column — the previous rules set `order` on
     these three while .wrap was display:block, where order is inert, so they
     stacked on three separate rows and the header looked broken. */
  .hero > .booking.is-sheet .wrap {
    /* Keeps the flex column (the sheet header relies on its order), but NOT
       justify-content:flex-end or min-height:100% - together those squashed
       the wrap below its content and pushed the header off the top of the
       screen, where it could not be scrolled to. */
    display: flex; flex-direction: column;
    padding: 0;
  }
  /* Title and close sit on ONE row. Both are order:1 flex items in the column,
     so instead of positioning them against each other they share a band: the
     title grows, the button is a fixed 44px beside it. */
  .hero > .booking.is-sheet .bk-sheet-title {
    order: 1; flex: 1 1 auto;
    display: flex; align-items: center; margin: 0;
    padding: 0 .5rem 0 1.15rem;
    font-family: var(--font-head); font-size: var(--fs-h3); color: var(--ink);
    background: none; min-width: 0;
  }
  .hero > .booking.is-sheet .bk-sheet-close {
    order: 2; flex: none; align-self: center;
    margin: 0 .5rem 0 0; width: 44px; height: 44px; background: none;
  }
  /* the band itself — white, one border, both children centred in it */
  .hero > .booking.is-sheet .bk-sheet-head {
    order: 1; flex: none; display: flex; align-items: center;
    background: #fff; min-height: 56px; border-bottom: 1px solid var(--line);
  }
  .hero > .booking.is-sheet .bk-form { order: 2; flex: none; }
}
.bk-sheet-title { display: none; }
/* the band exists only in the mobile sheet; hidden everywhere else so it
   cannot render as an empty white strip above the inline form */
.bk-sheet-head { display: none; }




/* ============ ROOM CARD v4 — client sequence ============
   Accommodation -> Room name -> icons -> [View More | Book Now], all on the
   image. The card is no longer split into media + foot, so the aspect ratio
   returns to the tile and the veil carries the whole overlay. */
.rcard { display: block; background: none; border: 0; aspect-ratio: 4/3 !important; }
/* Taller cards are for the ROOMS grid only. Applying this to .rcard itself
   also stretched the leisure cards (Pool / Play Area / Games), which share
   the class. 4/3 -> +30% -> +20% again = 100/117, 1.56x the original height. */
.rgrid > .rcard { aspect-ratio: 100/117 !important; }
.rcard--feature { aspect-ratio: 21/9 !important; }
.rcard .rcard__media { position: absolute; inset: 0; aspect-ratio: auto !important; }
.rcard__over {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.2rem 1.35rem 1.3rem; color: #fff;
  display: flex; flex-direction: column; align-items: flex-start; gap: .5rem;
}
.rcard__over .rcard__tag  { margin: 0; }
.rcard__over .rcard__name { margin: 0; }
.rcard__over .rcard__points { margin: 0; }
/* The two CTAs needed 266px in a 249px row at ~1295px wide, so flex-wrap
   stacked them and they spilled below the card. They stay on one line and the
   padding tightens instead. */
.rcard__acts { display: flex; gap: .5rem; flex-wrap: nowrap; margin-top: .25rem;
  align-items: center; }
.rcard__acts .btn { min-height: 40px; padding-inline: .85rem; white-space: nowrap; }
.rcard__acts .lnk-arrow { white-space: nowrap; flex: none; }
/* Below ~1200px the 3-up column is too narrow for both CTAs at full size, so
   the type and padding step down rather than the row wrapping or overflowing. */
@media (min-width: 901px) and (max-width: 1200px) {
  .rcard__acts { gap: .35rem; }
  .rcard__acts .btn { padding-inline: .6rem; font-size: 10px; }
  .rcard__acts .lnk-arrow { font-size: 10px; }
  .rcard__acts .lnk-arrow svg { width: 12px; }
}
/* View More is the SECONDARY action beside Book Now. As a bordered button the
   two competed at nearly equal weight; as a quiet arrow link the hierarchy is
   legible and Book Now carries the emphasis. Being unfilled, it also cannot
   borrow the photograph behind it the way the old translucent ghost did. */
.lnk-arrow {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: var(--fs-micro); letter-spacing: .18em; text-transform: uppercase;
  font-weight: 600; color: var(--gold-lt); text-decoration: none;
  min-height: 40px; padding: 0 .1rem;
  text-shadow: 0 1px 6px rgba(6,12,28,.85);   /* legible over any photo */
}
.lnk-arrow svg { transition: transform .35s var(--ease); flex: none; }
.lnk-arrow:hover, .lnk-arrow:focus-visible { color: #fff; }
.lnk-arrow:hover svg { transform: translateX(5px); }
@media (prefers-reduced-motion: reduce) { .lnk-arrow:hover svg { transform: none; } }

/* the veil must now cover tag + name + chips + buttons */
.rcard__veil {
  background: linear-gradient(180deg,
    rgba(9,14,26,0) 26%, rgba(9,14,26,.46) 56%, rgba(9,14,26,.88) 100%) !important;
}
.rcard--feature .rcard__over { padding: 1.4rem 1.6rem 1.5rem; }

@media (max-width: 700px) {
  /* +25% height: same width, so 10/9 -> 10/11.25 */
  .rgrid.grid--swipe > .rcard { aspect-ratio: 10/11.25 !important; }
  .rcard--feature { aspect-ratio: 10/11.25 !important; }
  .rcard__over { padding: 1rem 1.05rem 1.1rem; gap: .4rem; }
  .rcard__acts .btn { min-height: 38px; padding-inline: .9rem; }
}


/* ============ VENUE TILES ============
   Tall portrait tiles in the client's reference style: full-bleed photograph,
   a hairline eyebrow and a serif title at the base. They reveal one after
   another as the row enters view, using a per-tile --d delay. */
.vtiles { display: grid; gap: var(--card-gap); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.vtile {
  position: relative; overflow: hidden; min-width: 0;
  aspect-ratio: 3 / 4; background: var(--ink-2);
}
.vtile img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.vtile:hover img, .vtile:focus-within img { transform: scale(1.05); }
.vtile__veil {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(9,14,26,0) 44%, rgba(9,14,26,.48) 72%, rgba(9,14,26,.90) 100%);
}
/* Eyebrow and title are always visible at the base. On hover a two-line
   description opens beneath them, which pushes both up out of the image.
   Touch has no hover, so below 900px the description is shown at rest. */
.vtile__body {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.5rem 1.5rem 1.6rem; color: #fff;
}
.vtile__eyebrow {
  display: flex; align-items: center; gap: .6rem;
  font-size: var(--fs-micro); letter-spacing: .18em; text-transform: uppercase; color: #E7EBF2;
  margin: 0 0 .45rem;
}

/* the veil deepens on hover so the risen text stays readable */
.vtile__veil { transition: opacity .5s var(--ease); opacity: .85; }
.vtile:hover .vtile__veil, .vtile:focus-within .vtile__veil { opacity: 1; }
.vtile__eyebrow::before { content: ""; width: 26px; height: 1px; background: currentColor; flex: none; }
.vtile__title { margin: 0; font-family: var(--font-head); font-size: var(--fs-h3-lg); line-height: 1.1; }
.vtile__title a { color: #fff; }
.vtile__title a::after {            /* tile clickable, but not over the copy */
  content: ""; position: absolute; left: 0; right: 0; top: 0; bottom: 100%;
}
.vtile__body { z-index: 1; }
.vtile__title a:hover { color: var(--gold-lt); }

/* The description is what reveals. Collapsed to zero height at rest, so the
   eyebrow and title sit low; opening it lifts them both. */
.vtile__desc {
  margin: 0; color: #DDE3EC; font-size: var(--fs-small); line-height: 1.55;
  max-height: 0; opacity: 0; overflow: hidden; transform: translateY(8px);
  transition: max-height .5s var(--ease), opacity .4s var(--ease) .1s,
              margin-top .5s var(--ease), transform .45s var(--ease) .1s;
}
.vtile:hover .vtile__desc,
.vtile:focus-within .vtile__desc {
  max-height: 6em; opacity: 1; margin-top: .6rem; transform: none;
}

/* staggered reveal — each tile waits its turn */
@media (prefers-reduced-motion: no-preference) {
  .vtile { opacity: 0; transform: translateY(22px); }
  .vtile.is-in { opacity: 1; transform: none;
    transition: opacity .8s var(--ease) var(--d, 0ms), transform .8s var(--ease) var(--d, 0ms); }
}

@media (max-width: 900px) {
  .vtiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* no hover on touch — show everything at rest */
  .vtile__desc { max-height: none; opacity: 1; margin-top: .6rem; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .vtile__desc { max-height: none; opacity: 1; margin-top: .6rem; transform: none; }
}
@media (max-width: 700px) {
  .vtiles.grid--swipe {
    display: flex; gap: var(--card-gap); overflow-x: auto;
    scroll-snap-type: x mandatory; scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); padding-bottom: .5rem;
  }
  .vtiles.grid--swipe::-webkit-scrollbar { display: none; }
  .vtiles.grid--swipe > .vtile { flex: 0 0 76%; scroll-snap-align: start; aspect-ratio: 4/5; }
  .vtile__body { padding: 1.15rem 1.15rem 1.25rem; }
}


/* ============ GALLERY PAGE ============
   A page header, a filter row and a masonry-ish wall. The wall uses a plain
   responsive grid rather than CSS columns: columns reorder items top-to-bottom
   per column, which reads wrongly when a filter removes items mid-list. */
.pagehead {
  padding: calc(var(--header-h) + clamp(2.4rem, 5vw, 4rem)) 0 clamp(1.6rem, 3vw, 2.4rem);
  text-align: center; background: var(--paper);
}
.pagehead h1 { font-size: var(--fs-h2); margin: .2rem 0 .7rem; }
.pagehead .lead { max-width: 62ch; }

.gfilter {
  display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem;
  margin-bottom: 1.1rem;
}
.gchip {
  font-family: var(--font-body); font-size: var(--fs-micro);
  letter-spacing: .16em; text-transform: uppercase; font-weight: 600;
  color: var(--muted); background: none;
  border: 1px solid var(--line); padding: .6rem 1.05rem;
  min-height: 40px; cursor: pointer;
  transition: color .25s var(--ease), border-color .25s var(--ease), background .25s var(--ease);
}
.gchip:hover { color: var(--ink); border-color: var(--ink); }
/* the active chip is marked by fill AND weight, never colour alone (WCAG 1.4.1) */
.gchip.is-on { background: var(--navy); border-color: var(--navy); color: #fff; }
.gcount { text-align: center; color: var(--muted); font-size: var(--fs-small); margin: 0 0 1.4rem; }

.gwall {
  display: grid; gap: var(--card-gap);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 270px), 1fr));
}
.gcell {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 3; background: var(--ink-2);
}
.gcell img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.gcell:hover img, .gcell:focus-visible img { transform: scale(1.06); }
.gcell::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(9,14,26,0) 55%, rgba(9,14,26,.5) 100%);
  opacity: 0; transition: opacity .4s var(--ease);
}
.gcell:hover::after, .gcell:focus-visible::after { opacity: 1; }
.gcell[hidden] { display: none; }

/* ---- Lightbox ---- */
.lb {
  position: fixed; inset: 0; z-index: 200;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: clamp(.4rem, 2vw, 1.4rem); padding: clamp(.8rem, 3vw, 2rem);
  background: rgba(6,11,24,.94);
}
.lb[hidden] { display: none; }
.lb__fig { margin: 0; display: grid; justify-items: center; gap: .8rem; min-width: 0; }
.lb__img {
  max-width: 100%; max-height: 78svh; width: auto; height: auto;
  object-fit: contain; background: var(--ink-2);
}
.lb__cap { color: #D8DEE9; font-size: var(--fs-small); text-align: center; }
.lb__n { color: #98A1B5; }
.lb__close, .lb__nav {
  display: grid; place-items: center; cursor: pointer;
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.22);
  color: #fff; width: 48px; height: 48px; flex: none;
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.lb__close:hover, .lb__nav:hover { background: rgba(255,255,255,.18); border-color: #fff; }
.lb__close { position: absolute; top: clamp(.8rem, 3vw, 1.6rem); right: clamp(.8rem, 3vw, 1.6rem); }
@media (max-width: 640px) {
  .lb { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  .lb__fig { grid-row: 1; }
  .lb__nav { grid-row: 2; }
  .lb__prev { justify-self: start; }
  .lb__next { justify-self: end; grid-column: 1; grid-row: 2; }
}


/* ============ DINING SLIDER ============
   The split media column becomes a horizontal scroller. It reuses .rowswipe's
   snap behaviour, but overrides the two-row grid: dining is a single row of
   full-width slides. */
.dslider.rowswipe {
  display: flex !important;
  grid-template-columns: none !important;
  grid-template-rows: none !important;
  gap: 0; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  margin-inline: 0; padding-inline: 0;
  aspect-ratio: 4 / 5; background: var(--ink-2);
}
.dslider.rowswipe::-webkit-scrollbar { display: none; }
.dslider img {
  flex: 0 0 100%; width: 100%; height: 100%;
  object-fit: cover; scroll-snap-align: center;
}
.dslider:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* ============ GALLERY HERO ============ */
.ghero {
  position: relative; min-height: 75svh; display: grid; align-items: center;
  isolation: isolate; overflow: hidden; background: var(--ink);
}
.ghero__media { position: absolute; inset: 0; z-index: -1; }
.ghero__media img { width: 100%; height: 100%; object-fit: cover; }
.ghero__veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(6,12,28,.32) 0%, rgba(6,12,28,.38) 40%, rgba(6,12,28,.70) 100%);
}
.ghero__inner { text-align: center; color: #fff; padding-top: var(--header-h); }
.ghero h1 { color: #fff; font-size: var(--fs-h1); margin: .3rem 0 .8rem; }
.ghero .lead { color: #E7EBF2; max-width: 60ch; margin-inline: auto; }
.ghero .eyebrow { color: var(--gold-lt); }
@supports not (min-height: 75svh) { .ghero { min-height: 75vh; } }
/* dining slider dots — position indicator and control */
.ddots { display: flex; justify-content: center; gap: .5rem; margin-top: .9rem; }
/* TAP-01: the BUTTON is the tap target (44px tall, meets the 24px WCAG floor
   with room to spare); the 4px bar is drawn inside it via ::before, so the dot
   still LOOKS 4px. An ::after hit area does not count - a measured check reads
   the element's own box. */
.ddot {
  width: 34px; height: 44px; padding: 0; cursor: pointer; position: relative;
  background: none; border: 0;
}
.ddot::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 4px; margin-top: -2px;
  background: var(--line); transition: background .3s var(--ease);
}
.ddot.is-on::before { background: var(--gold); }
.ddot:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }


/* ============ INNER-PAGE ELEMENTS ============
   Two animated elements carried by every inner page, built from the existing
   design language (same tokens, same easing, same reveal hook) so they read as
   part of the site rather than bolted on.

   ELEMENT 1 — statbar: the property's numbers, counting up on first view.
   Every figure is a FACTS value; nothing is invented or rounded for effect. */
.statbar {
  display: grid; gap: var(--card-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: clamp(1.6rem, 3.4vw, 2.6rem) 0;
}
.stat { text-align: center; }
.stat__n {
  font-family: var(--font-head); font-size: var(--fs-h2-sm);
  line-height: 1; color: var(--gold-text); display: block;
  font-variant-numeric: tabular-nums;
}
.section--dark .stat__n { color: var(--gold-lt); }
.stat__l {
  display: block; margin-top: .5rem; font-size: var(--fs-micro);
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.section--dark .stat__l { color: #AEB6C7; }

/* ELEMENT 2 — a drawn rule that wipes in under each section heading. Uses the
   same gold as the eyebrow marks, so it extends the existing vocabulary. */
.drawline { display: block; height: 2px; width: 0; background: var(--gold);
  margin: .9rem auto 0; transition: width 1.1s var(--ease) .15s; }
.drawline--left { margin-inline: 0; }
.reveal.is-in .drawline, .drawline.is-in { width: 74px; }
@media (prefers-reduced-motion: reduce) { .drawline { width: 74px; transition: none; } }

/* ---- inner page shells ---- */
.phero {
  position: relative; min-height: 70svh; display: grid; align-items: center;
  isolation: isolate; overflow: hidden; background: var(--ink);
}
.phero__media { position: absolute; inset: 0; z-index: -1; }
.phero__media img { width: 100%; height: 100%; object-fit: cover; }
.phero__veil { position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(6,12,28,.34) 0%, rgba(6,12,28,.40) 40%, rgba(6,12,28,.72) 100%); }
.phero__inner { text-align: center; color: #fff; padding-top: var(--header-h); }
.phero h1 { color: #fff; font-size: var(--fs-h1); margin: .3rem 0 .7rem; }
.phero .lead { color: #E7EBF2; max-width: 58ch; margin-inline: auto; }
.phero .eyebrow { color: var(--gold-lt); }
@supports not (min-height: 70svh) { .phero { min-height: 70vh; } }

/* breadcrumbs */
.crumbs { font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); padding: 1.15rem 0 0; }
.crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .45rem; }
.crumbs li::after { content: "/"; margin-left: .45rem; color: var(--line); }
.crumbs li:last-child::after { content: none; }
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--ink); }
.crumbs [aria-current="page"] { color: var(--ink); }

/* Breadcrumbs share .wrap for horizontal inset, but .wrap's fluid --gutter
   shrinks to ~18px at narrow phone widths — tighter than the fixed 24px the
   rest of the mobile content reads against. Standardise it here, once, for
   every page, without touching desktop/tablet's existing --gutter inset. */
@media (max-width: 700px) {
  .crumbs { padding-inline: 24px; }
}

/* spec list — used by room, venue and dining detail blocks */
.spec { list-style: none; margin: 1.1rem 0 0; padding: 0;
  display: grid; gap: .55rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
.spec li { display: flex; align-items: flex-start; gap: .6rem;
  font-size: var(--fs-small); color: var(--ink-2); }
.section--dark .spec li { color: #D5DBE6; }
.spec svg { flex: none; margin-top: .15rem; color: var(--gold-text); }
.section--dark .spec svg { color: var(--gold-lt); }

/* amenity chips grid */
.amgrid { display: grid; gap: .7rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 215px), 1fr)); list-style: none; margin: 0; padding: 0; }
.amgrid li { display: flex; align-items: center; gap: .65rem;
  border: 1px solid var(--line); padding: .85rem 1rem; font-size: var(--fs-small); }
.amgrid svg { flex: none; color: var(--gold-text); }

/* FAQ accordion */
/* FAQ category headings: centred, with consistent responsive spacing
   above each section so categories read as distinct blocks. The
   questions/accordion below stay left-aligned (untouched). */
.faqcat { text-align: center; margin-top: clamp(2.4rem, 6vw, 4rem); margin-bottom: 28px; }
.faq { border-top: 1px solid var(--line); }
.faq__q { width: 100%; text-align: left; background: none; border: 0;
  border-bottom: 1px solid var(--line); padding: 1.15rem 2.6rem 1.15rem 0;
  font-family: var(--font-head); font-size: var(--fs-h3); color: var(--ink);
  cursor: pointer; position: relative; min-height: 56px; }
.faq__q::after { content: ""; position: absolute; right: .6rem; top: 50%;
  width: 11px; height: 11px; border-right: 2px solid var(--gold-text);
  border-bottom: 2px solid var(--gold-text); transform: translateY(-70%) rotate(45deg);
  transition: transform .3s var(--ease); }
.faq__q[aria-expanded="true"]::after { transform: translateY(-30%) rotate(225deg); }
.faq__a { max-height: 0; overflow: hidden; transition: max-height .4s var(--ease); }
.faq__a > div { padding: 0 0 1.2rem; color: var(--muted); font-size: var(--fs-body); }
.faq__q[aria-expanded="true"] + .faq__a { max-height: 34em; }

/* continue-exploring cards */
/* Four links in ONE row: auto-fit with a 250px floor was wrapping them to
   2x2 well before the breakpoint (at 1440px the cards were 326px, so four
   would not fit the 1152px column). Pinned to 4 columns instead. */
.nextgrid { display: grid; gap: var(--card-gap);
  grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* This is a footer-adjacent signpost, not a feature block, so the cards are
   a shallower 3/2 rather than the 4/3 used for content cards. */
.nextcard { position: relative; display: block; overflow: hidden;
  aspect-ratio: 3/2; background: var(--ink-2); }
.nextcard img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.nextcard:hover img { transform: scale(1.06); }
.nextcard__veil { position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,14,26,0) 42%, rgba(9,14,26,.86) 100%); }
.nextcard__t { position: absolute; left: 1.1rem; right: 1.1rem; bottom: 1rem;
  color: #fff; font-family: var(--font-head); font-size: var(--fs-h3); }

/* The "Continue Exploring" band is a signpost: trim its vertical padding and
   heading gap so it reads as a footer lead-in, not a full content section. */
.nextgrid-sec { padding-block: var(--section-pad); }
.nextgrid-sec .section-head { margin-bottom: clamp(1.1rem, 2vw, 1.6rem); }
.nextgrid-sec .nextcard__t { font-size: var(--fs-body); }
/* the h2 carried full section weight, which dwarfed the shrunken band */
.nextgrid-sec h2 { font-size: var(--fs-h3); }
.nextgrid-sec .drawline { margin-top: .5rem; }

/* mobile keeps the swipe row behaviour already defined for .grid--swipe —
   needs the compound selector because .nextgrid's unconditional display:grid
   (above) has the same specificity as .grid--swipe and comes later in the
   cascade, so it would otherwise win over the plain utility class */
@media (max-width: 700px) {
  .nextgrid.grid--swipe {
    display: flex; gap: var(--card-gap);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter);
    padding-bottom: .6rem; scroll-padding-inline-start: var(--gutter);
    max-width: calc(100% + var(--gutter) * 2);
  }
  .nextgrid.grid--swipe::-webkit-scrollbar { display: none; }
  .nextgrid.grid--swipe > .nextcard { flex: 0 0 85%; scroll-snap-align: start; min-width: 0; }
}

/* simple prose page (legal / policy) */
.prose { max-width: 74ch; }
.prose h2 { font-size: var(--fs-h3); margin: 2.2rem 0 .7rem; }
.prose p, .prose li { color: var(--muted); font-size: var(--fs-body); line-height: 1.75; }
.prose ul { padding-left: 1.15rem; }
.prose li { margin-bottom: .45rem; }

/* ---- contact / enquiry form ---- */
.cform { background: #fff; border: 1px solid var(--line); padding: clamp(1.3rem, 3vw, 2rem); }
.cfield { margin-bottom: 1rem; }
.cfield label { display: block; font-size: var(--fs-micro); letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted); margin-bottom: .4rem; }
.cfield input, .cfield select, .cfield textarea {
  width: 100%; min-height: 48px; padding: .7rem .85rem; font: inherit;
  font-size: var(--fs-body); color: var(--ink);
  background: var(--paper); border: 1px solid var(--line); border-radius: 0;
}
.cfield textarea { min-height: 118px; resize: vertical; }
.cfield input:focus-visible, .cfield select:focus-visible, .cfield textarea:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 1px; border-color: var(--gold); }
.cfield input.is-error, .cfield textarea.is-error { border-color: #B3261E; }
.cfield .err { display: block; margin-top: .35rem; font-size: var(--fs-micro);
  color: #B3261E; text-transform: none; letter-spacing: 0; }
.cform__consent { display: flex; gap: .6rem; align-items: flex-start; margin: 0 0 1rem; }
.cform__consent input { width: 20px; height: 20px; min-height: 0; flex: none; margin-top: .15rem; }
.cform__consent label { font-size: var(--fs-small); color: var(--muted);
  text-transform: none; letter-spacing: 0; margin: 0; }
.cform__status { margin: 0 0 .9rem; font-size: var(--fs-small); min-height: 1.2em; }
.cform__status.is-ok { color: #1B5E20; }
.cform__status.is-bad { color: #B3261E; }

/* contact page: the enquiry form and the text beside it start level */
.split:has(.cform) { align-items: start; }

/* Standalone enquiry form (meetings & events): no text column beside it, so
   the fields run two-up instead of stacking full width edge to edge. The
   message, consent line, and submit button stay full width regardless. */
.cform--2col {
  max-width: 900px; margin-inline: auto;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 1.4rem;
}
.cform--2col .cform__consent,
.cform--2col .cform__status,
.cform--2col .cfield:has(textarea),
.cform--2col button[type="submit"] { grid-column: 1 / -1; }
@media (max-width: 700px) {
  .cform--2col { grid-template-columns: 1fr; }
}


/* ============ INNER-PAGE LAYOUT SYSTEM (v2) ============
   The first inner-page build repeated one block order on every page: centred
   heading, grid of small items, dark statbar, dark CTA. Every page therefore
   looked the same, hierarchy was flat (the pool got the same weight as the
   first-aid kit), and the pages were text-and-icon where the homepage is
   image-led.

   These components fix that. They reuse the existing tokens, fonts, buttons
   and reveal system - only the STRUCTURE is new. */

/* ---- FEATURE ROW: big image + copy, alternating side ----
   The workhorse. Replaces "one more grid of tiny cells" for anything that
   deserves weight - the pool, the play area, a hall, a room type. */
.frow {
  display: grid; gap: clamp(1.6rem, 4vw, 3.4rem); align-items: center;
  grid-template-columns: 1.05fr .95fr;
  padding-block: clamp(1.5rem, 3.2vw, 2.5rem);
}
.frow + .frow { border-top: 1px solid var(--line); }
.section--dark .frow + .frow { border-top-color: rgba(255,255,255,.10); }
.frow--flip .frow__media { order: 2; }
.frow__media { position: relative; overflow: hidden; }
.frow__media img { width: 100%; height: 100%; object-fit: cover; display: block;
  /* 3/2 rather than 4/3: a wider, shorter frame sits far closer to the copy
     block's height (measured 438px vs 234px on 4/3) without shrinking the
     photograph, so the row reads balanced instead of top-heavy. */
  aspect-ratio: 3/2; transition: transform 1.1s var(--ease); }
.frow__media:hover img { transform: scale(1.04); }
/* a quiet index number, so a run of rows reads as a sequence */
.frow__n {
  display: block; font-family: var(--font-head); font-size: var(--fs-h3);
  color: var(--gold-text); line-height: 1; margin-bottom: .7rem;
}
.section--dark .frow__n { color: var(--gold-lt); }
/* h2 or h3 - a frow may be a page top-level section (then h2, for
   heading order) or a step in a sequence (then h3). Same size. */
.frow__body h2,
.frow__body h3 { font-size: var(--fs-h2-sm); margin: 0 0 .8rem; }
/* Body copy is ONE size sitewide. This row previously used --fs-lead to pad a
   short copy column out against the photograph beside it, which made the same
   plain <p> render larger here than everywhere else. The generous line-height
   stays, so the column still has presence without a second body size. */
.frow__body p { color: var(--muted); font-size: var(--fs-body); line-height: 1.75; margin: 0; }
.section--dark .frow__body p { color: #C3CAD9; }
.frow__meta {
  display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.4rem; padding: 0; list-style: none;
}
.frow__meta li {
  display: inline-flex; align-items: center; gap: .45rem;
  border: 1px solid var(--line); padding: .4rem .7rem;
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.section--dark .frow__meta li { border-color: rgba(255,255,255,.16); color: #C3CAD9; }
.frow__acts { margin-top: 1.4rem; }
@media (max-width: 860px) {
  .frow { grid-template-columns: 1fr; }
  .frow--flip .frow__media { order: 0; }
}

/* ---- EDITORIAL LEAD: an asymmetric section opener ----
   Replaces the centred eyebrow+H2+rule+lead stack that opened every section.
   Heading left, supporting copy right, so the page does not read as a column
   of centred text. */
.elead {
  display: grid; gap: clamp(1rem, 3vw, 2.6rem); align-items: end;
  grid-template-columns: 1.1fr 1fr; margin-bottom: clamp(1.4rem, 3vw, 2.4rem);
}
.elead--top { align-items: start; }
.elead h2 { margin: 0; }
.elead__side { color: var(--muted); font-size: var(--fs-body); }
.section--dark .elead__side { color: #C3CAD9; }
@media (max-width: 860px) { .elead { grid-template-columns: 1fr; align-items: start; } }

/* ---- PRACTICAL STRIP: the small stuff, honestly small ----
   Parking, wifi, power backup - real but not headline. An inline strip, not
   16 equal cards competing with the pool. */
.pstrip {
  display: grid; gap: .75rem 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 235px), 1fr));
  list-style: none; margin: 0; padding: 0;
}
.pstrip li { display: flex; align-items: flex-start; gap: .7rem;
  padding: .75rem 0; border-top: 1px solid var(--line); font-size: var(--fs-small); }
.section--dark .pstrip li { border-top-color: rgba(255,255,255,.10); color: #D5DBE6; }
.pstrip svg { flex: none; margin-top: calc((1.65rem - 17px) / 2); color: var(--gold-text); }
.pstrip svg[width="20"] { margin-top: calc((1.65rem - 20px) / 2); }
.section--dark .pstrip svg { color: var(--gold-lt); }
.pstrip b { display: block; font-weight: 600; color: var(--ink); font-size: var(--fs-body); }
.section--dark .pstrip b { color: #fff; }
.pstrip span { color: var(--muted); }
.section--dark .pstrip span { color: #AEB6C7; }

/* ---- QUOTE BAND: an editorial breather between heavy sections ---- */
.qband { text-align: center; max-width: 46ch; margin-inline: auto; }
.qband p {
  font-family: var(--font-head); font-size: var(--fs-h2-sm); line-height: 1.35;
  color: var(--ink); margin: 0;
}
.section--dark .qband p { color: #fff; }
.qband cite {
  display: block; margin-top: 1rem; font-style: normal;
  font-size: var(--fs-micro); letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
.section--dark .qband cite { color: var(--gold-lt); }

/* ---- FULL-BLEED IMAGE BAND: gives the page air and rhythm ---- */
.iband { position: relative; overflow: hidden; height: clamp(240px, 34vw, 420px); }
.iband img { width: 100%; height: 100%; object-fit: cover; display: block; }
.iband__cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 1.4rem 0;
  background: linear-gradient(180deg, rgba(9,14,26,0), rgba(9,14,26,.84));
  color: #fff;
}
.iband__cap .wrap { font-size: var(--fs-small); color: #E7EBF2; }


/* ============ ROOM SUMMARY (v2) ============
   A room summary page exists to help a guest CHOOSE. The first build showed
   three cards that used the same photograph, in a 1-big-2-small grid implying
   a hierarchy that does not exist (15 rooms of each type), with the name, four
   chips and two buttons crammed into the bottom third of a dark image.

   These rows are built for comparison: equal weight, generous photography, and
   the differences between types stated plainly rather than buried in chips. */
.rrow {
  display: grid; gap: clamp(1.4rem, 3.4vw, 3rem); align-items: center;
  grid-template-columns: 1.15fr .85fr;
  padding-block: clamp(1.6rem, 3.4vw, 2.8rem);
}
.rrow + .rrow { border-top: 1px solid var(--line); }
/* grid-template-columns is asymmetric (1.15fr .85fr) so the photo reads as
   the dominant element. .rrow--flip only reordered which track the photo
   auto-places into — the track WIDTHS stayed fixed to column position, so
   a flipped row's photo landed in the narrow .85fr track instead of the
   wide one. Every other room card (Jacuzzi, Premium) rendered with a
   visibly smaller photo than Luxury/Classic even though the image itself
   is the same 3:2 crop. Swapping the column widths alongside the order
   keeps the photo the same size on every row, flipped or not. */
.rrow--flip { grid-template-columns: .85fr 1.15fr; }
.rrow--flip .rrow__media { order: 2; }
.rrow__media { position: relative; overflow: hidden; }
.rrow__media img { width: 100%; height: 100%; object-fit: cover; display: block;
  aspect-ratio: 3/2; transition: transform 1.1s var(--ease); }
.rrow__media:hover img { transform: scale(1.04); }
/* the room count sits ON the image - it is inventory, not a headline */
.rrow__count {
  position: absolute; left: 0; top: 0; padding: .5rem .85rem;
  background: rgba(9,14,26,.78); color: #fff;
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase;
}
.rrow__name { font-size: var(--fs-h2-sm); margin: 0 0 .2rem; }
.rrow__name a { color: var(--ink); }
.rrow__name a:hover { color: var(--gold-text); }
.rrow__sub {
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase;
  color: var(--gold-text); margin: 0 0 .9rem;
}
.rrow__copy { color: var(--muted); font-size: var(--fs-body); line-height: 1.7; margin: 0 0 1.2rem; }
/* the specs that actually differ between types - a definition list, not chips */
.rspec { display: grid; grid-template-columns: repeat(2, minmax(0,1fr));
  gap: .1rem 1.2rem; margin: 0 0 1.4rem; }
.rspec div { display: flex; align-items: baseline; gap: .5rem;
  padding: .5rem 0; border-top: 1px solid var(--line); }
.rspec dt { font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); margin: 0; flex: none; }
.rspec dd { margin: 0; font-size: var(--fs-small); color: var(--ink); font-weight: 500; }
.rrow__acts { display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap; }
.rrow__acts .lnk-arrow { color: var(--gold-text); text-shadow: none; }
.rrow__acts .lnk-arrow:hover, .rrow__acts .lnk-arrow:focus-visible { color: var(--ink); }
@media (max-width: 860px) {
  .rrow { grid-template-columns: 1fr; }
  .rrow--flip .rrow__media { order: 0; }
  .rspec { grid-template-columns: 1fr; }
}

/* ---- comparison table: the one view that answers "which one?" ---- */
.rcompare { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.rcompare caption { text-align: left; color: var(--muted); font-size: var(--fs-small);
  margin-bottom: .9rem; }
.rcompare th, .rcompare td { padding: .95rem .8rem; text-align: left;
  border-bottom: 1px solid var(--line); }
.rcompare thead th {
  font-family: var(--font-head); font-size: var(--fs-h3); font-weight: 500;
  color: var(--ink); border-bottom: 2px solid var(--gold);
}
.rcompare tbody th {
  font-weight: 400; color: var(--muted);
  font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase;
}
.rcompare td { color: var(--ink); }
.rcompare tbody tr:hover td, .rcompare tbody tr:hover th { background: var(--paper-2); }
.rcompare .is-best { color: var(--gold-text); font-weight: 600; }
@media (max-width: 700px) {
  /* a table cannot usefully shrink - stack it into per-room blocks */
  .rcompare, .rcompare caption, .rcompare tbody, .rcompare tr, .rcompare td, .rcompare th { display: block; }
  .rcompare thead { display: none; }
  .rcompare tbody tr { margin-bottom: 1.4rem; border: 1px solid var(--line); padding: .3rem .9rem; }
  .rcompare tbody th { border: 0; padding-bottom: .2rem; }
  .rcompare td { border: 0; padding: .1rem 0 .7rem; }
  .rcompare td::before { content: attr(data-room) " — "; color: var(--muted);
    font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase; }
}


/* ---- scrims removed where no text sits on the image ----
   Client: remove the scrim from images; keep it only where text needs it.
   .frow and .rrow photographs sit BESIDE a copy column - nothing is printed
   over them, so any darkening was cost with no benefit. */
.frow__media::after, .rrow__media::after { content: none; }
.frow__media img, .rrow__media img { filter: none; }


/* Text sitting on a photograph carries its own shadow, so the scrim above it
   can stay light. Measured: this is what keeps white text legible over a pale
   wall or sky without darkening the whole picture. */
.phero h1, .phero .lead, .ghero h1, .ghero .lead,
.rcard__name, .rcard__tag, .vtile__title, .vtile__eyebrow, .vtile__desc,
.nextcard__t, .iband__cap .wrap {
  text-shadow: 0 1px 3px rgba(6,12,28,.9), 0 2px 14px rgba(6,12,28,.7);
}


/* ============ PAGE BACKGROUND WATERMARK ============
   A light wash of the resort background photograph behind the page grounds,
   so the white areas carry a faint texture instead of reading flat.

   Opacity is NOT a taste choice. --muted (#626981) is the weakest body tone
   on this site and sits at only 5.12:1 on --paper, against a 4.5:1 AA floor.
   Measured against the darkest region of this image (the forest, relative
   luminance ~0.005), the ground tone reaches the AA limit at exactly 0.06:

       0.05 -> --muted 4.60:1  PASS  <- used here, keeps a safety margin
       0.06 -> --muted 4.50:1  exact AA floor
       0.08 -> --muted 4.31:1  FAIL

   Raising --bg-wash-opacity past 0.06 puts body copy under WCAG 2.1 AA.

   Attached to a fixed pseudo-element on body, not to `background` itself, so
   it cannot tint form fields, focus rings, dropdowns or any other UI surface.
   Dark bands and media stay opaque and paint straight over it. */
:root { --bg-wash-opacity: .05; }

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url("https://assets.simplotel.com/simplotel/image/upload/f_auto,q_auto:good,w_1600/royal-paark-resort/bckground_creative_36131d4c.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: var(--bg-wash-opacity);
}

/* The light page grounds are opaque and would hide the wash, so let it
   through them. Every one of these is a page ground, never a UI surface. */
.intro,
.section--tint { background-color: transparent; }

/* .section--tint is the slightly darker of the two page tones. Re-create that
   step with a translucent wash so the tonal rhythm between bands survives. */
.section--tint { background-image: linear-gradient(rgba(237,240,244,.72), rgba(237,240,244,.72)); }

/* Keep the wash off small screens: it costs a 1600px download for a texture
   that is barely perceptible on a phone, and mobile already drops the motifs. */
@media (max-width: 700px) {
  body::before { display: none; }
  .intro { background-color: var(--paper); }
  .section--tint { background-color: var(--paper-2); background-image: none; }
}

/* Respect reduced-data and reduced-motion preferences, as the motif layer does. */
@media (prefers-reduced-motion: reduce) {
  body::before { display: none; }
  .intro { background-color: var(--paper); }
  .section--tint { background-color: var(--paper-2); background-image: none; }
}

/* ============ ROOMS: 4 room types (Luxury, Jacuzzi, Classic, Premium) ============
   With 4 cards the 3-column grid leaves 3 + 1 and a dangling gap. 4 across
   clips the Book Now button at 1440px, so above the 900px breakpoint the
   cards sit 2 x 2 at 4/3. Below 900px the existing swipe row is untouched. */
@media (min-width: 901px) {
  .rgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rgrid > .rcard { aspect-ratio: 4 / 3 !important; }
}

/* ============ FACILITY ROW SLIDERS ============
   The dining slider reused inside a .frow photo column. The row's photos are
   3/2, so the scroller takes that frame instead of dining's 4/5, and the
   per-image hover zoom is dropped - it would fight the swipe. */
.dslider.dslider--wide { aspect-ratio: 3 / 2; }
.frow__media .dslider img { aspect-ratio: auto; height: 100%; }
.frow__media:hover .dslider img { transform: none; }
/* Long sliders (10+ photographs) must not push the dot row past a phone's
   width; the row wraps to a second line instead. */
.ddots { flex-wrap: wrap; }

/* ============ ROOMS DROPDOWN ============
   Inline header: a small navy panel in the same language as the overflow
   menu, opened on hover or keyboard focus and placed by JS (the row is
   overflow:hidden, so the panel must be position:fixed to escape the clip).
   Overflow menu / phone panel: the room links sit open beneath Rooms. */
.nav__sub { list-style: none; margin: 0; padding: 0; }
.nav__sublink {
  display: flex; align-items: center; min-height: 44px; white-space: nowrap;
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .13em; text-transform: uppercase;
}
.nav--inline .nav__sub {
  position: fixed; left: var(--sub-left, 0); top: var(--sub-top, 0); z-index: 120;
  min-width: 214px; padding: .35rem 0;
  border-top: var(--sub-gap, 0) solid transparent; background-clip: padding-box;
  background-color: var(--navy-deep); box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
}
.nav--inline .nav__item--sub:hover .nav__sub,
.nav--inline .nav__item--sub:focus-within .nav__sub { opacity: 1; visibility: visible; transform: translateY(0); }
.nav--inline .nav__sublink { padding: .5rem 1.15rem; color: #fff; }
.nav--inline .nav__sublink:hover,
.nav--inline .nav__sublink:focus-visible { background: rgba(255,255,255,.1); color: #fff; }
.nav--inline .nav__sublink[aria-current="page"] { color: var(--gold-lt); }
/* Rooms reads as the current section while a room page is open */
.nav__link[aria-current="true"]::after { right: 0; }
.header .nav__link[aria-current="true"] { color: var(--gold-lt); }
.header.is-scrolled .nav__link[aria-current="true"]:not(.nav--menu .nav__link) { color: var(--gold); }

.nav--menu .nav__sublink { padding: .5rem 1.15rem .5rem 2.1rem; color: rgba(255,255,255,.82); }
.nav--menu .nav__sublink:hover,
.nav--menu .nav__sublink:focus-visible { background: rgba(255,255,255,.1); color: #fff; }
.nav--menu .nav__sublink[aria-current="page"] { color: var(--gold-lt); }
@media (max-width: 700px) {
  .nav--menu .nav__sublink {
    font-family: var(--font-head); font-size: .95rem; font-weight: 400;
    letter-spacing: normal; text-transform: none;
    color: var(--muted); padding: .55rem var(--gutter) .55rem calc(var(--gutter) + 1rem);
  }
  .nav--menu .nav__sublink:hover,
  .nav--menu .nav__sublink:focus-visible { background: var(--paper-2); color: var(--ink); }
  .nav--menu .nav__sublink[aria-current="page"] { color: var(--gold-text); }
}
@media (max-width: 700px) {
  /* light phone panel: the section marker uses the panel's own accent, not
     the pale gold meant for the dark header */
  .header .nav--menu .nav__link[aria-current="true"] { color: var(--gold-text); }
}

/* ============ LIVE RATE LINE ============
   Sits directly above a room's Book Now. Hidden in the markup and revealed
   only once the booking engine returns a price, so no stale or placeholder
   figure can ever show. */
.lrate { margin: 1.4rem 0 -.4rem; font-size: var(--fs-small); color: var(--muted); letter-spacing: .02em; }
.lrate[hidden] { display: none; }
.lrate__amt { font-family: var(--font-head); font-size: 1.45em; font-weight: 500; color: var(--ink); margin-inline: .15rem; }
.rrow__body .lrate { margin: 1rem 0 .2rem; }
.rcard__over .lrate { margin: .2rem 0 .6rem; color: rgba(255,255,255,.85); }
.rcard__over .lrate__amt { color: #fff; }

/* ============ PHOTO SLIDER ARROWS ============
   Same round, frosted control as the hero arrows, a size smaller to suit a
   column photograph. The frame is the positioning box; the slider inside it
   keeps every rule it had before. */
.dslider-frame { position: relative; }
.dslider__arw {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 50%; padding: 0;
  border: 1px solid rgba(255,255,255,.55);
  background: rgba(7,17,40,.42); color: #fff; cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.dslider__arw:hover { background: rgba(7,17,40,.68); border-color: #fff; }
.dslider__arw:focus-visible { outline: 3px solid var(--gold-lt); outline-offset: 3px; }
.dslider__arw--prev { left: .75rem; }
.dslider__arw--next { right: .75rem; }

/* ============ ROOM CARD PHOTO SLIDERS (.cslider) ============
   A stack of the room's photographs that cross-fades. In a room row the first
   photograph stays in flow and sets the 3/2 frame; on a homepage card the
   stack fills the card's absolute media box. Before the script runs, only the
   first photograph is visible. */
.cslider { position: relative; }
.cslider > img { transition: opacity .6s var(--ease), transform 1.1s var(--ease); }
.cslider > img + img { position: absolute; inset: 0; opacity: 0; }
.cslider.is-ready > img { opacity: 0; }
.cslider.is-ready > img.is-on { opacity: 1; }
.rcard__media .cslider { position: absolute; inset: 0; }
.rcard__media .cslider > img { position: absolute; inset: 0; }
.cslider__arw { z-index: 3; }
/* on a card the copy owns the lower half, so the arrows ride in the photo
   area above it rather than at the card's centre */
.rcard__media > .cslider__arw { top: 30%; }

/* ============ TRANSPARENT ARROW CIRCLES ============
   Client request (19 Oct): the round arrows on photographs carry no fill, just
   the white ring and chevron. A soft shadow keeps both legible over light
   walls and bright sky, where a bare white outline would disappear. */
.hero__arw,
.dslider__arw {
  background: transparent;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  border-color: rgba(255,255,255,.9);
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.55));
}
.hero__arw:hover,
.dslider__arw:hover { background: transparent; border-color: var(--gold-lt); color: var(--gold-lt); }
