/* ==========================================================================
   White Panda Hotels & Resorts - AI Demo
   Palette sampled from the brand logo artwork:
     panda black #121212 · amber #CB9F3E · deep amber #C77E08 · cream #F9F7EB
   ========================================================================== */

:root {
  --panda:       #1A1A1A;   /* panda black - primary brand dark */
  --panda-deep:  #121212;   /* deeper black for solid fills      */
  --panda-ink:   #0A0A0A;   /* near-black for scrims and shadows */
  --gold:        #CB9F3E;   /* logo gold, sampled from logo.png  */
  --gold-ink:    #7A5A16;   /* gold darkened for text on white   */
  --gold-pale:   #E6CE96;   /* soft gold for tints on dark       */
  --ink:         #1B1B1F;
  --body:        #4A4A55;
  --cream:       #FBF9F1;   /* logo roundel cream                */
  --line:        #E6E0D2;
  --white:       #FEFEFE;

  --header-h:    108px;
  /* Content width scales with the screen instead of stopping dead at a fixed
     cap. Below ~1400px it is the viewport minus the gutters; above that it
     grows gently (86vw) up to a 1680px ceiling, so a 1920px monitor is used
     properly while the line length on an ultrawide stays readable. */
  --wrap:        min(86vw, 1680px);
  --gutter:      28px;     /* the padding .wrap and .header__inner both use */

  /* Two families only: a display serif and a text sans. */
  --serif: "Cormorant Garamond", "Georgia", "Times New Roman", serif;
  --sans:  "Jost", "Helvetica Neue", Arial, sans-serif;

  /* ---- Type scale -------------------------------------------------------
     Every size on the site comes from this ladder. One token per role, so
     an eyebrow is the same size everywhere, an h2 is the same everywhere,
     and body copy never drifts between 13, 13.5, 14 and 15px.            */
  /* Type scale. Body is the anchor at 16px, the accepted minimum for sustained
     reading; everything else is a ratio of it (roughly a 1.25 major third at
     the top end, tightened for the small sizes). Nav was 17px, LARGER than
     body, which inverted the hierarchy: navigation is a label, not prose. */
  --fs-eyebrow: 12.5px;                        /* all eyebrows / labels   */
  --fs-small:   14.5px;                        /* meta, captions, fine    */
  --fs-body:    16px;                          /* all paragraph copy      */
  --fs-nav:     15px;                          /* navbar menu             */
  --fs-lead:    clamp(1.12rem, 1.35vw, 1.25rem);/* intro / lead paragraphs */
  --fs-h4:      clamp(1.05rem, 1.2vw, 1.15rem);/* small headings          */
  --fs-h3:      clamp(1.22rem, 1.6vw, 1.44rem);/* card titles             */
  --fs-h2:      clamp(1.8rem, 2.9vw, 2.4rem);  /* section headings        */
  --fs-h1:      clamp(2.4rem, 5.6vw, 4.2rem);  /* hero only               */
  --fs-display: clamp(2.1rem, 3.1vw, 2.8rem);  /* stat numbers            */

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Ambient page background ---------------------------------------------------
   One fixed video layer behind the whole document. A white veil sits over it
   so the mountains read as texture rather than a photograph. Raised to 0.93
   because body copy was hard to read over the busier frames; the footage is
   now only a faint texture. Sections needing a solid ground (cream, dark offers,
   footer) paint over it as before.
   -------------------------------------------------------------------------- */
.page-bg {
  position: fixed;
  inset: 0;
  z-index: -1;              /* behind all content, never intercepts clicks */
  overflow: hidden;
  pointer-events: none;
  background: var(--white);  /* fallback before the poster/video paints */
}
.page-bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.page-bg__veil {
  position: absolute;
  inset: 0;
  /* The veil was a flat 93% white, so only 7% of the footage showed and the
     ambient layer was effectively invisible. The footage is dark (median
     luminance 0.11), so it cannot simply be uncovered: ink text placed on it directly
     measures 2.54:1.

     Two changes buy visibility without touching legibility. First the flat
     wash drops to 82%, which still leaves ink at 14.27:1, far above the 4.5:1
     floor. Second it is no longer flat: the veil is lighter at the edges and
     denser through the middle band where most body copy sits, so the video
     reads at the margins of the page and stays quiet behind the text. */
  background:
    linear-gradient(180deg,
      rgba(254, 254, 254, 0.74) 0%,
      rgba(254, 254, 254, 0.86) 22%,
      rgba(254, 254, 254, 0.88) 78%,
      rgba(254, 254, 254, 0.74) 100%);
}

/* Let the ambient layer show through the otherwise-white sections. */
.section:not(.section--cream):not(.offers),
.booking,
.newsletter {
  background: transparent;
}

/* Users who ask for reduced motion get the still poster, no playback. */
@media (prefers-reduced-motion: reduce) {
  .page-bg video { display: none; }
  .page-bg {
    background: var(--white) url("../images/page-bg-poster.jpg") center / cover no-repeat;
  }
  .page-bg__veil { background: rgba(254, 254, 254, 0.88); }
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--body);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  color: var(--ink);
  font-weight: 600;
  line-height: 1.15;
  margin: 0 0 0.5em;
  letter-spacing: 0.01em;
}

p { margin: 0 0 1.1em; }
figure { margin: 0; }          /* UA default is 1em 40px - breaks grid cells */
img { max-width: 100%; display: block; }
a { color: var(--panda); }

.wrap {
  width: 100%;
  /* The cap has to include the gutter, or a screen only slightly narrower than
     the cap loses its margin entirely and the content runs edge to edge. That
     is what made 1280px laptops look full-bleed while 1920px monitors looked
     boxed in: below the cap there was no breathing room, above it the content
     simply stopped growing. */
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* Visually hidden, still announced by screen readers */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Accessible skip link */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--panda);
  color: #FEFEFE;
  padding: 12px 20px;
  z-index: 200;
  text-decoration: none;
}
.skip:focus { left: 12px; top: 12px; }

/* Visible keyboard focus everywhere */
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   HEADER - centred logo, navigation split either side, dark Book Now at right
   (structure mirrors the reference layout; light scrim keeps the black
   wordmark legible over the hero photograph)
   -------------------------------------------------------------------------- */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-h);
  z-index: 100;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: height 0.35s var(--ease), background 0.35s var(--ease),
              box-shadow 0.35s var(--ease), border-color 0.35s var(--ease);
}
/* A soft scrim keeps the nav legible against bright patches of the hero */
.header::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(10, 10, 10,0.42), rgba(10, 10, 10,0));
  opacity: 1;
  transition: opacity 0.35s var(--ease);
  pointer-events: none;
}
.header.is-stuck {
  height: 82px;
  background: rgba(254, 254, 254, 0.94);
  border-bottom-color: rgba(245, 168, 28, 0.28);
  box-shadow: 0 6px 28px rgba(10, 10, 10, 0.10);
}
.header.is-stuck::before { opacity: 0; }

/* Over the hero the nav is white; once the bar turns solid it returns to ink */
.header__inner { position: relative; z-index: 1; }
.header .nav a,
.header .burger span { transition: color 0.35s var(--ease), background 0.35s var(--ease); }
.header:not(.is-stuck) .nav a { color: #FEFEFE; }
.header:not(.is-stuck) .nav a:hover { color: var(--gold-pale); }
/* Below the breakpoint the nav links are no longer over the hero: they move
   into the fixed .header__nav-wrap panel, which is painted #FEFEFE. The white
   rule above would render them white on white and the whole menu read as
   empty. The panel is always light in both header states, so pin the links to
   ink there. Specificity has to match `.header:not(.is-stuck) .nav a`, hence
   the :not() is repeated. */
@media (max-width: 1023px) {
  .header:not(.is-stuck) .header__nav-wrap .nav a,
  .header.is-stuck .header__nav-wrap .nav a { color: var(--ink); }
  .header:not(.is-stuck) .header__nav-wrap .nav a:hover,
  .header.is-stuck .header__nav-wrap .nav a:hover { color: var(--panda); }
}
/* The dropdown sits on a white panel, so its links keep the ink colour
   regardless of the transparent-header rule above. Specificity must match
   `.header:not(.is-stuck) .nav a`, hence the :not() here too. */
.header:not(.is-stuck) .nav .drop a { color: var(--body); }
.header:not(.is-stuck) .nav .drop a:hover { color: var(--panda); }
.header.is-stuck .nav .drop a { color: var(--body); }
.header.is-stuck .nav .drop a:hover { color: var(--panda); }
.header:not(.is-stuck) .burger span { background: #FEFEFE; }
.header:not(.is-stuck) .btn--dark {
  background: transparent;
  border-color: rgba(254, 254, 254, 0.8);
  color: #FEFEFE;
}
.header:not(.is-stuck) .btn--dark:hover {
  background: #FEFEFE;
  border-color: #FEFEFE;
  color: var(--panda-ink);
}

/* Solid state stated explicitly, at matching specificity, so the bar never
   inherits the white-on-white combination from the transparent rules. */
.header.is-stuck .nav a { color: var(--ink); }
.header.is-stuck .nav a:hover { color: var(--panda); }
.header.is-stuck .burger span { background: var(--ink); }
.header.is-stuck .btn--dark {
  background: var(--panda-ink);
  border-color: var(--panda-ink);
  color: #FEFEFE;
}
.header.is-stuck .btn--dark:hover {
  background: var(--panda);
  border-color: var(--panda);
  color: #FEFEFE;
}

.header__inner {
  height: 100%;
  /* Same cap and gutter as .wrap so the logo, nav and page content share one
     left edge. Using the bare --wrap here put the header 28px inside the
     content on every screen. */
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 28px;
}

/* The burger is a mobile-only control; on desktop it must not consume a column */
.header__inner > .burger { display: none; }

/* On desktop the wrapper is just the left-hand nav's container:
   it occupies grid column 1 and lays its child out normally. */
.header__nav-wrap { min-width: 0; }

/* nav-right and the Book Now button share the third column */
.header__right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 30px;
}

.nav {
  display: flex;
  align-items: center;
  gap: 30px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav--right { justify-content: flex-end; }

.nav a {
  font-size: var(--fs-nav);
  letter-spacing: 0.04em;
  color: var(--ink);
  text-decoration: none;
  padding: 6px 0;
  position: relative;
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}
.nav a:hover { color: var(--panda); }
.nav a:hover::after { transform: scaleX(1); transform-origin: left; }

/* Dropdown ("Our Hotels ⌄") */
.has-drop { position: relative; }
.has-drop > a::before {
  content: "";
  position: absolute;
  right: -15px; top: 50%;
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-70%) rotate(45deg);
  transition: transform 0.3s var(--ease);
}
.has-drop { padding-right: 16px; }
.has-drop:hover > a::before,
.has-drop:focus-within > a::before { transform: translateY(-20%) rotate(225deg); }

.drop {
  position: absolute;
  top: calc(100% + 18px);
  /* Anchored to the item's left edge, not centred on it - centring pushed
     the panel off-screen for the left-most nav item and clipped the names. */
  left: 0;
  transform: translateY(10px);
  min-width: max-content;
  max-width: min(340px, calc(100vw - 32px));
  background: #FEFEFE;
  border: 1px solid var(--line);
  border-top: 2px solid var(--gold);
  box-shadow: 0 20px 48px rgba(10, 10, 10, 0.14);
  padding: 10px 0;
  margin: 0;
  list-style: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), visibility 0.3s;
}
.has-drop:hover .drop,
.has-drop:focus-within .drop {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.drop a {
  display: block;
  padding: 11px 24px;
  font-size: var(--fs-body);
  line-height: 1.45;
  color: var(--body);
  white-space: nowrap;
}
.drop a::after { display: none; }
.drop a:hover { background: var(--cream); color: var(--panda); }

.brand {
  display: block;
  justify-self: center;
  line-height: 0;
  position: relative;
}
.brand__dark { position: absolute; inset: 0; opacity: 0; transition: opacity 0.35s var(--ease); }
.brand__light { opacity: 1; transition: opacity 0.35s var(--ease); }
.header.is-stuck .brand__dark { opacity: 1; }
.header.is-stuck .brand__light { opacity: 0; }
.brand img {
  height: 74px;
  width: auto;
  transition: height 0.35s var(--ease);
}
.header.is-stuck .brand img { height: 62px; }

/* Buttons ------------------------------------------------------------------ */

.btn {
  display: inline-block;
  font-family: var(--sans);
  font-size: var(--fs-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 15px 34px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
              border-color 0.3s var(--ease), transform 0.3s var(--ease);
}
.btn--dark {
  background: var(--panda-ink);
  color: #FEFEFE;
  border-color: var(--panda-ink);
}
.btn--dark:hover {
  background: var(--panda);
  border-color: var(--panda);
  transform: translateY(-2px);
}
.btn--ghost {
  background: transparent;
  color: #FEFEFE;
  border-color: rgba(254, 254, 254, 0.75);
}
.btn--ghost:hover {
  background: #FEFEFE;
  color: var(--panda-ink);
  border-color: #FEFEFE;
}
.btn--gold {
  background: var(--gold);
  color: #23200F;
  border-color: var(--gold);
}
.btn--gold:hover {
  background: #B88E4E;
  border-color: #B88E4E;
  transform: translateY(-2px);
}
.btn--sm { padding: 12px 26px; font-size: var(--fs-small); }

.header .btn { justify-self: end; }

/* Mobile nav toggle -------------------------------------------------------- */
.burger {
  display: none;
  width: 44px; height: 44px;
  background: none;
  border: 0;
  padding: 10px;
  cursor: pointer;
}
.burger span {
  display: block;
  height: 2px;
  background: var(--ink);
  margin: 5px 0;
  transition: transform 0.3s var(--ease), opacity 0.25s var(--ease);
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* --------------------------------------------------------------------------
   HERO - full-bleed photograph, centred call to action
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  text-align: center;
  overflow: hidden;
  background: var(--panda-ink);
}
.hero__media {
  position: absolute;
  inset: 0;
}
.hero__media img,
.hero__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* The slow zoom suits a still; moving footage supplies its own motion. */
.hero__media img { animation: heroDrift 22s var(--ease) forwards; }
@keyframes heroDrift {
  from { transform: scale(1.10); }
  to   { transform: scale(1.00); }
}
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      rgba(10, 10, 10, 0.29) 0%,
      rgba(10, 10, 10,0.16) 34%,
      rgba(10, 10, 10, 0.22) 62%,
      rgba(10, 10, 10, 0.56) 100%);
}

/* Room detail heroes are shorter and their photography is brighter, so the
   shared scrim leaves the title at 4.55:1, barely over the floor. A little
   more depth on those pages only, so the main heroes stay light. */
.hero--page .hero__media::after {
  background: linear-gradient(180deg,
    rgba(10, 10, 10, 0.38) 0%,
    rgba(10, 10, 10, 0.26) 34%,
    rgba(10, 10, 10, 0.32) 62%,
    rgba(10, 10, 10, 0.60) 100%);
}
.hero__inner {
  position: relative;
  z-index: 2;
  padding: var(--header-h) 28px 40px;
  max-width: 860px;
}
.hero .eyebrow {
  color: var(--gold-pale);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  margin: 0 0 22px;
}
.hero h1 {
  color: #FEFEFE;
  font-size: var(--fs-h1);
  margin: 0 0 18px;
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.30);
}
.hero__sub {
  color: rgba(254, 254, 254, 0.92);
  font-size: var(--fs-lead);
  max-width: 620px;
  margin: 0 auto 38px;
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.34);
}
.hero__cta { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }

.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 34px;
  transform: translateX(-50%);
  z-index: 2;
  color: rgba(254, 254, 254,0.8);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  display: grid;
  justify-items: center;
  gap: 10px;
}
.scroll-cue i {
  display: block;
  width: 1px;
  height: 42px;
  background: linear-gradient(180deg, rgba(254, 254, 254,0.9), rgba(254, 254, 254,0));
  animation: cue 2.4s ease-in-out infinite;
}
@keyframes cue {
  0%, 100% { transform: scaleY(0.45); transform-origin: top; opacity: 0.5; }
  50%      { transform: scaleY(1);    transform-origin: top; opacity: 1; }
}

/* --------------------------------------------------------------------------
   BOOKING BAR
   -------------------------------------------------------------------------- */

.booking {
  position: relative;
  z-index: 5;
  margin-top: -46px;
}
.booking__panel {
  /* Illustrated cream backdrop, on every booking widget in the chain. The
     artwork carries its detail in the left and right thirds and leaves the
     middle open, so the fields keep a clean ground to sit on. Anchored to the
     bottom because the panel is only ~116px tall against a 2:1 image: a
     centred crop keeps the empty sky and throws the illustration away. The
     colour underneath is the fallback while the image loads. */
  background: #FEFEFE url("../images/booking-bg.jpg") center bottom / cover no-repeat;
  box-shadow: 0 24px 60px rgba(10, 10, 10, 0.16);
  /* 23 top vs 26 bottom: the uppercase labels leave ~3px of internal leading
     above their glyphs, so equal padding reads as top-heavy. */
  padding: 23px 28px 26px;
  display: grid;
  /* city | hotel | in | out | rooms+guests | promo | button */
  /* Hotel names are the longest values, so that column gets the most room;
     the dates only ever hold dd/mm/yyyy and need the least. */
  grid-template-columns:
    minmax(0, 0.95fr) minmax(0, 1.9fr) 150px
    150px minmax(150px, 1fr) minmax(0, 0.8fr) auto;
  column-gap: 1px;
  row-gap: 14px;
  align-items: end;
}


/* Inputs sit inside a bordered wrap with a leading icon, so every control -
   select, date, text, and the occupancy button - shares one silhouette. */
.field__wrap {
  position: relative;
  display: flex;
  align-items: center;
  /* One fixed height for every control. Native date inputs and buttons each
     compute a different intrinsic height, which left the row 7px ragged. */
  height: 44px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: #FEFEFE;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.field__wrap:focus-within {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(245, 168, 28, 0.16);
}
.field__ico {
  position: absolute;
  left: 11px;
  top: 50%;
  transform: translateY(-50%);
  width: 17px; height: 17px;
  color: var(--gold);
  /* Sits above the control, so it must not intercept the click. */
  pointer-events: none;
}
.field__wrap > select,
.field__wrap > input,
.field__wrap > .occ__toggle {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink);
  height: 100%;
  /* Left padding clears the absolutely-positioned icon; the control itself
     now spans the whole wrap, so clicking anywhere in the box works. */
  padding: 0 12px 0 37px;
  cursor: pointer;
}
.field__wrap > input { cursor: text; }
/* The whole date box opens the calendar, so show a pointer over all of it. */
.field__wrap > input[type="date"] { cursor: pointer; }
/* Native date inputs carry a fixed intrinsic width (~175px in Chrome) that
   ignores the grid track, so they burst out of their column and collide with
   the neighbour. min-width:0 lets them shrink to the track. */
.field__wrap > input[type="date"] {
  min-width: 0;
  /* Tighter gutter than the selects: a date is always dd/mm/yyyy, so the box
     can be narrower without the value ever truncating. */
  padding-left: 30px;
  padding-right: 2px;
  font-size: 13.5px;
}
.field--date { min-width: 0; }
.field--date .field__wrap { width: 100%; }
/* Chrome's calendar button has its own margin; pull it in so the date text
   keeps room inside the narrower box. */
.field__wrap > input[type="date"]::-webkit-calendar-picker-indicator {
  margin-left: 0;
  padding: 0;
  opacity: 0.55;
  cursor: pointer;
}
.field__wrap > select {
  appearance: none;
  -webkit-appearance: none;
  /* room for the chevron */
  padding-right: 26px;
  background-image: linear-gradient(45deg, transparent 50%, var(--body) 50%),
                    linear-gradient(135deg, var(--body) 50%, transparent 50%);
  background-position: calc(100% - 14px) 51%, calc(100% - 9px) 51%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.field__wrap > input::placeholder { color: #9A9AA4; }
.field__note {
  /* Absolute so the note cannot make its column taller than the others -
     with align-items:end that would lift the whole field out of line. */
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--body);
  white-space: nowrap;
  pointer-events: none;
}
.field--date { position: relative; }

/* Rooms & guests ------------------------------------------------------------ */
.occ__toggle {
  text-align: left;
  /* "1 Room, 2 Guests" must stay on one line - wrapping pushed the field
     taller than its neighbours and broke the row. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.field--occ { position: relative; }
.occ__panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 20;
  min-width: 248px;
  background: #FEFEFE;
  border: 1px solid var(--line);
  border-radius: 3px;
  box-shadow: 0 18px 44px rgba(10, 10, 10, 0.18);
  padding: 14px 16px 12px;
  max-height: min(62vh, 420px);
  overflow-y: auto;
}
/* Flipped above the field when there is no room below (JS decides). */
.occ__panel.is-up {
  top: auto;
  bottom: calc(100% + 8px);
  box-shadow: 0 -18px 44px rgba(10, 10, 10, 0.18);
}

/* Child ages ---------------------------------------------------------------- */
.occ__row span small {
  display: block;
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--body);
  text-transform: none;
}
.occ__ages {
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 8px;
}
.occ__age {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  color: var(--ink);
}
.occ__age select {
  flex: 0 0 auto;
  min-width: 96px;
  height: 32px;
  padding: 0 26px 0 10px;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--ink);
  background: #FEFEFE;
  border: 1px solid var(--line);
  border-radius: 3px;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--body) 50%),
                    linear-gradient(135deg, var(--body) 50%, transparent 50%);
  background-position: calc(100% - 14px) 51%, calc(100% - 9px) 51%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.occ__age select:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}
.occ__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 0;
  font-size: 14px;
  color: var(--ink);
}
.occ__step { display: flex; align-items: center; gap: 4px; }
.occ__step button {
  width: 28px; height: 28px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #FEFEFE;
  color: var(--panda);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease),
              color 0.2s var(--ease);
}
.occ__step button:hover:not(:disabled) {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--panda-ink);
}
.occ__step button:disabled { opacity: 0.35; cursor: not-allowed; }
.occ__step output {
  min-width: 26px;
  text-align: center;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.occ__done {
  width: 100%;
  margin-top: 10px;
  padding: 9px 0;
  border: 0;
  border-radius: 3px;
  background: var(--panda-ink);
  color: #FEFEFE;
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
}

.booking__go {
  white-space: nowrap;
  height: 44px;            /* match .field__wrap so the row sits flush */
  padding: 0 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

@media (max-width: 1180px) {
  .booking__panel { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .booking__go { grid-column: 1 / -1; }
}
/* Below 900px the inline booking bar is removed: the sticky Book Now bar and
   the header CTA both open the same form in a dialog, so keeping a second
   copy in the page was redundant and cost a screen of scrolling.
   `.booking` is hidden rather than removed so the form element still exists
   for the dialog to borrow. */
@media (max-width: 900px) {
  .booking {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    pointer-events: none;
  }
  /* Inside the dialog the form must be visible and interactive again. */
  .bookmodal__form .booking__panel { pointer-events: auto; }
  .occ__panel { left: auto; right: 0; }
}
@media (max-width: 460px) {
  .booking__panel { grid-template-columns: 1fr; }
  /* Stacked, the absolute note would sit on the next field's label. Put it
     back in flow and give the column room for it. */
  .field__note { position: static; margin-top: 4px; }
  .occ__panel { left: 0; right: 0; min-width: 0; }
}
.field { display: grid; gap: 9px; }
.field label {
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--panda);
  font-weight: 500;
  /* Body line-height (1.7) made the label box ~5px taller than its glyphs,
     which read as extra padding above the row only. */
  line-height: 1.15;
}
/* Leftover from the pre-.field__wrap booking bar. It came AFTER the new rules
   and reset padding to 12px, dragging every label under its own icon, and
   added a stray border-bottom inside the bordered wrap. The wrap now owns
   border, padding and focus ring, so only the focus outline is kept. */
.field__wrap > input:focus-visible,
.field__wrap > select:focus-visible,
.field__wrap > .occ__toggle:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}

/* --------------------------------------------------------------------------
   SECTIONS
   -------------------------------------------------------------------------- */

.section { padding: 60px 0 30px; }
.section--cream { background: var(--cream); }

.section-head {
  text-align: center;
  max-width: 680px;
  margin: 0 auto 30px;
}
.eyebrow {
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.30em;
  text-transform: uppercase;
  /* Brand amber on a light ground measures about 1.5:1, far below the 4.5:1
     floor, and an eyebrow is small uppercase type, which is the hardest case
     to read. --gold-ink is the same hue darkened for light surfaces. The pale
     amber is still used where an eyebrow sits over dark artwork; those rules
     are scoped to their own sections and override this one. */
  color: var(--gold-ink);
  margin: 0 0 16px;
}
.section-head h2 { font-size: var(--fs-h2); margin-bottom: 18px; }
.section-head p { margin: 0; }

/* Ornamental gold rule, echoing the logo's filigree divider */
.rule { width: 92px; height: 1px; margin: 22px auto 0; background: var(--gold); position: relative; }
.rule::before,
.rule::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 5px; height: 5px;
  background: var(--gold);
  transform: translateY(-50%) rotate(45deg);
}
.rule::before { left: -12px; }
.rule::after  { right: -12px; }

/* About Us ----------------------------------------------------------------- */
/* Images bracket the whole block: they flank the copy AND run down past the
   stat rule, so the rule spans the gap between them rather than sitting in a
   separate band below. Absolute positioning keeps them out of the flow so the
   copy and stats stack tightly. */
.about {
  position: relative;
  overflow: hidden;
  padding: 60px 0 30px;   /* base rhythm: every content boundary = 90px */

  /* Flank width drives both the images and the stat row's side margins, so the
     rule can never start on top of an image at any viewport width. */
  --flank: clamp(190px, 21.137vw, 303px);   /* image width (+10%) */
  --flank-gap: clamp(20px, 3.2vw, 46px);
}

/* ==========================================================================
   PAGE BACKDROP ART - opt in per page with .page--backdrop on <body>
   Two pieces in the same pale wash. The misty mountains are the default and
   carry the brand homepage and the hill properties: Karnika Resorts and Divine
   Peaks in Dharamshala, and The Heritage Kud in Patnitop. The Amritsar
   properties add .page--backdrop-amritsar for the Golden Temple companion
   piece; the mountains do not suit a plains city. Dwarka is still deliberately
   plain, neither piece suits a coastal property.

   Painted on .page-bg, which is already position:fixed behind everything, so
   the art holds still while the page scrolls over it. That fixed layer is the
   parallax; no scroll handler is involved.

   Two things had to give way for it to be visible at all. The page veil and
   the per-section veils both exist to calm the ambient background video behind
   body copy, and stacked they let roughly 3% of anything below them through.
   Every page carrying this class has had that video removed, so the veils were
   muting plain white and would now mute the artwork instead. This art is pale
   enough to carry copy on its own. Check that before adding the class to a
   page that still plays the footage.

   Everything hangs off one class on <body>, because the section veils are not
   descendants of .page-bg and need a shared ancestor to scope against.
   ========================================================================== */
.page--backdrop .page-bg {
  background: var(--white) url("../images/page-bg-art.jpg") center / cover no-repeat;
}
/* Amritsar swaps the art only; the ground, centring and cover sizing all come
   from the rule above, so this must stay after it - the two selectors carry
   equal specificity and source order is what decides. Served from Cloudinary at
   the same 2880px as the local mountain art, f_auto so browsers take the webp
   (~14KB). The parentheses in the filename are why the URL is quoted. */
.page--backdrop-amritsar .page-bg {
  background-image: url("https://assets.simplotel.com/simplotel/image/upload/f_auto,q_auto,w_2880/white-panda-hotels/amritsar_bg_(1)_9963d4d3.png");
}
.page--backdrop .page-bg__veil { background: none; }
/* Same :not() chain as the rule being overridden, so this wins on specificity
   rather than on source order. */
.page--backdrop .section:not(.section--cream):not(.offers)::before,
.page--backdrop .newsletter::before {
  background: none;
}
.about__img {
  position: absolute;
  width: var(--flank);
  margin: 0;
  z-index: 1;
}
.about__img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Images start at the same content edge as the navbar and the stat rule,
   rather than bleeding to the viewport edge. */
.about__img--left {
  left: max(var(--gutter), (100% - var(--wrap)) / 2);
  top: clamp(38px, 4.5vw, 66px);
  aspect-ratio: 0.6061;        /* tall - runs past the stat rule */
}
.about__img--right {
  right: max(var(--gutter), (100% - var(--wrap)) / 2);
  top: clamp(16px, 2vw, 30px);
  aspect-ratio: 0.9355;        /* near-square - ends above the rule */
}

.about__lead {
  position: relative;
  z-index: 2;
  max-width: 620px;
  margin: 0 auto;
  padding: 0 28px;
  text-align: center;
}
.about__lead .eyebrow { margin-bottom: 20px; }
.about__lead h2 {
  font-size: var(--fs-h2);
  line-height: 1.36;
  font-weight: 400;
  margin: 0 0 30px;
}
.about__lead .btn {
  font-size: var(--fs-eyebrow);
  padding: 13px 26px;
}

/* Stat row spans the gap between the two images (~70% of viewport) */
.about__statswrap { position: relative; z-index: 2; }
.about__stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* Right edge lines up with the navbar; the left edge starts clear of the
     tall image that runs down past this rule. Both are measured from the
     same content box, so the section stays aligned with the rest of the page. */
  width: auto;
  margin: clamp(40px, 4.4vw, 68px)
          max(var(--gutter), (100% - var(--wrap)) / 2)
          0
          calc(max(var(--gutter), (100% - var(--wrap)) / 2)
               + var(--flank) + var(--flank-gap));
  border-top: 1px solid var(--line);
  position: relative;
  z-index: 2;
}
.astat {
  text-align: center;
  padding: 40px 14px 42px;
  border-left: 1px solid var(--line);
}
.astat:first-child { border-left: 0; }
.astat b {
  display: block;
  /* Reference uses the sans face for figures, not the display serif */
  font-family: var(--sans);
  font-size: var(--fs-display);
  color: var(--panda);
  line-height: 1;
  font-weight: 300;
  letter-spacing: 0;
  margin-bottom: 14px;
  /* Cormorant defaults to oldstyle figures ("120" renders as "I2O") */
  font-variant-numeric: lining-nums tabular-nums;
  -moz-font-feature-settings: "lnum" 1;
  -webkit-font-feature-settings: "lnum" 1;
  font-feature-settings: "lnum" 1;
}
.astat span {
  display: block;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--body);
  margin-bottom: 0;
}
.astat p {
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--gold);
  margin: 0;
  max-width: 232px;
  margin-inline: auto;
}

/* Our Locations ------------------------------------------------------------ */
/* Tall portrait cards, near-flush, with the label and place name overlaid at
   the foot of each image. */
/* Single-row marquee: 3.75 cards visible so the 4th peeks at the edge.
   Position is driven by JS (see marquee() in properties.js) so the same
   track can glide continuously AND be stepped by the arrows, both wrapping
   infinitely with no gap. */
.loc-wrap {
  position: relative;
  width: calc(100% - var(--gutter) * 2);
  max-width: var(--wrap);
  margin: 0 auto;
  /* Container context lives here, not on .loc-viewport: putting it on the
     element that also clips made Chrome contain the overflowing clones, so
     they existed and measured correctly but never painted. */
  container-type: inline-size;
}
.locations { padding: 60px 0 30px; }
.locations .section-head { margin-bottom: 30px; }

.loc-viewport { overflow: hidden; }
.loc-grid {
  display: flex;
  gap: 8px;
  width: max-content;
  /* No will-change here: promoting a multi-thousand-pixel track to a single
     composited layer can exceed the GPU texture limit, and the overflow then
     fails to paint. The transform animates fine without it.
     Driven by CSS, not a JS frame loop: the compositor keeps this running
     smoothly and it cannot stall the way requestAnimationFrame can. The
     track holds exactly two copies of the card set, so translating by 50%
     lands on an identical frame and the loop is seamless. */
  animation: locScroll var(--loc-duration, 40s) linear infinite;
}
@keyframes locScroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-1 * var(--loc-cycle, 50%)), 0, 0); }
}
/* Pause on hover / keyboard focus, and honour reduced-motion */
.loc-wrap:hover .loc-grid,
.loc-wrap:focus-within .loc-grid { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .loc-grid { animation: none; }
  .loc-viewport { overflow-x: auto; }
}
.loc-grid > .loc {
  /* 3.75 across the viewport, allowing for the 8px gaps */
  flex: 0 0 calc((100cqw - 8px * 3.75) / 3.75);
  aspect-ratio: 0.836;        /* 10% taller than 0.92 */
}

/* ===========================================================================
   Section carousel arrows - ONE definition for the whole site.
   -----------------------------------------------------------------------
   Every section level carousel (destinations marquee, properties, rooms,
   gallery, offers, attractions, testimonials) draws its prev/next control
   from this block, so the size, the plate and the edge inset match wherever
   a carousel appears. The in-card photo arrows (.prop__arrow) are a separate,
   deliberately smaller control and are NOT part of this.

   Why a plate rather than the previous bare glyph: the arrows sit over
   backdrops measured anywhere from luminance 63 (dark photography) to 252
   (the near white testimonial and rooms bands). A white glyph with only a
   drop shadow disappears completely against the pale end of that range. A
   fixed dark, semi opaque disc gives the same white glyph a guaranteed
   contrast floor on every backdrop the site actually paints.
   =========================================================================== */
:root {
  --arrow-size: 56px;        /* was 44px - the brief asked for bigger */
  --arrow-glyph: 30px;
  --arrow-inset: 10px;       /* flush to the carousel edge, inside it */
}
.mq-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 5;
  width: var(--arrow-size); height: var(--arrow-size);
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
              transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.mq-arrow svg {
  width: var(--arrow-glyph); height: var(--arrow-glyph);
  /* Kept for the glyph edge against the plate, now far lighter than before. */
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}
/* Flush with the outer edge of the carousel, sitting just inside it so the
   control never spills into the page gutter or off a narrow viewport. */
.mq-arrow--prev { left: var(--arrow-inset); right: auto; }
.mq-arrow--next { right: var(--arrow-inset); left: auto; }
.mq-arrow:hover { background: none; color: var(--gold); }
.mq-arrow--prev:hover { transform: translateY(-50%) translateX(-3px); }
.mq-arrow--next:hover { transform: translateY(-50%) translateX(3px); }
.mq-arrow:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .loc-viewport { overflow-x: auto; }
}

/* Destination card ---------------------------------------------------------- */
.loc {
  position: relative;
  display: block;
  overflow: hidden;
  text-decoration: none;
  isolation: isolate;
}
.loc img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1s var(--ease);
}
/* Gradient only at the foot, so the top of the photograph stays clean */
.loc::after {
  content: "";
  position: absolute;
  inset: 0;
  /* The ramp used to reach full strength only at the very bottom edge, while
     the title sits a little above it: measured 0.93 luminance under the text,
     giving 1.07:1. The dark end now covers the whole caption band. */
  background: linear-gradient(180deg,
    rgba(10, 10, 10,0) 30%,
    rgba(10, 10, 10, 0.24) 52%,
    rgba(10, 10, 10, 0.56) 74%,
    rgba(10, 10, 10, 0.65) 100%);
}
.loc:hover img { transform: scale(1.06); }

.loc__body {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: 0 26px 30px;
  color: #FEFEFE;
}
.loc__label {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 6px;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(254, 254, 254, 0.92);
}
/* The short rule that precedes the label */
.loc__label i {
  display: block;
  width: 20px;
  height: 1px;
  background: currentColor;
  flex: none;
}
.loc__body h3 {
  margin: 0;
  color: #FEFEFE;
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: 1.1;
  text-shadow: 0 1px 20px rgba(0, 0, 0, 0.32);
}

/* Our Properties ----------------------------------------------------------- */
.prop-tabs {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: clamp(18px, 3.4vw, 52px);
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(30px, 3.6vw, 46px);
}
.prop-tab {
  position: relative;
  background: none;
  border: 0;
  padding: 0 2px 14px;
  font-family: var(--sans);
  font-size: var(--fs-body);
  color: var(--body);
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}
.prop-tab::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--panda);
  transform: scaleX(0);
  transition: transform 0.3s var(--ease);
}
.prop-tab:hover { color: var(--panda); }
.prop-tab.is-on { color: var(--panda); }
.prop-tab.is-on::after { transform: scaleX(1); }

.prop-viewport { overflow: hidden; }
.prop-track {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2.2vw, 30px);
  align-items: stretch;
}

/* 'All' becomes a continuously gliding row of every property */
.prop-track.is-marquee {
  display: flex;
  width: max-content;
  align-items: stretch;
  /* Same CSS-driven loop as the destinations row: exactly two copies of the
     card set, translated by -50%, so the wrap point is pixel-identical. */
  animation: propScroll var(--prop-duration, 40s) linear infinite;
}
@keyframes propScroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-1 * var(--prop-cycle, 50%)), 0, 0); }
}
/* Pause only over the row itself, not the whole section - hovering the tabs
   or heading used to stall the carousel and made it look stuck. */
.prop-viewport:hover .prop-track.is-marquee,
.prop-viewport:focus-within .prop-track.is-marquee { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .prop-track.is-marquee { animation: none; }
}
.prop-track.is-marquee > .prop {
  /* 3.4 across the viewport, so the next card peeks at the edge */
  flex: 0 0 calc((100cqw - clamp(18px, 2.2vw, 30px) * 3.4) / 3.4);
}
@media (prefers-reduced-motion: reduce) {
  .prop-viewport { overflow-x: auto; }
}

/* The properties viewport needs room for the arrows to sit outside it */
.properties .prop-viewport { position: relative; }
.prop-shell { position: relative; }

.prop {
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
}
/* The action row is pinned to the bottom so every card ends level */
.prop__actions { margin-top: auto; }
.prop__specs { margin-bottom: 4px; }

/* Photo carousel ----------------------------------------------------------- */
.prop__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 1.42;
  margin-bottom: 16px;
}
.prop__slides {
  display: flex;
  height: 100%;
  transition: transform 0.55s var(--ease);
}
.prop__slides img {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.prop__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 34px; height: 34px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 0;
  color: var(--ink);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.3s var(--ease), color 0.3s var(--ease);
}
.prop__arrow svg {
  width: 22px; height: 22px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6))
          drop-shadow(0 0 8px rgba(0, 0, 0, 0.45));
}
.prop__arrow--prev { left: 0; }
.prop__arrow--next { right: 0; }
.prop__media:hover .prop__arrow,
.prop__arrow:focus-visible { opacity: 1; }
.prop__arrow:hover { color: var(--gold); }

.prop__dots {
  position: absolute;
  left: 0; right: 0; bottom: 10px;
  display: flex;
  justify-content: center;
  gap: 6px;
}
.cdot {
  /* The button itself is the touch target: 24px square, the WCAG 2.5.8
     minimum. The visible dot is painted by ::before inside it. A pseudo
     element cannot be the target, which is what the old inset ::after tried
     to do: assistive tooling and Lighthouse both measure the element box. */
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  background: transparent;
  transition: transform 0.3s var(--ease);
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  position: relative;
}
.cdot::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(254, 254, 254, 0.55);
  transition: background 0.3s var(--ease), transform 0.3s var(--ease);
}
.cdot:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.cdot.is-on::before { background: #FEFEFE; transform: scale(1.25); }

/* Card text ---------------------------------------------------------------- */
.prop__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 6px;
}
.prop__head h3 {
  margin: 0;
  min-height: 2.5em;
  /* A step up from --fs-h3: hotel names are the card's headline and were
     reading smaller than the price beside them. */
  font-size: clamp(1.38rem, 1.9vw, 1.68rem);
  font-weight: 500;
  line-height: 1.25;
}
.prop__price {
  margin: 0;
  white-space: nowrap;
  color: var(--panda);
}
.prop__price b {
  font-family: var(--sans);
  font-size: var(--fs-h4);
  font-weight: 500;
  font-variant-numeric: lining-nums tabular-nums;
}
.prop__price span {
  font-size: var(--fs-eyebrow);
  /* Measured 1.57:1 at this size next to the amber price. --ink is the darkest
     text token and clears the floor without changing the visual weight. */
  color: var(--ink);
  margin-left: 3px;
}

.prop__area {
  margin: 0 0 8px;
  font-size: var(--fs-small);
  /* Brand amber on white measures 1.98:1, well under the 4.5:1 floor for body
     text. --gold-ink is the same hue darkened for use on light surfaces; the
     amber itself stays for rules, icons and large display type.
     Darkened once more: --gold-ink landed at 4.49:1 here, a hair under the
     floor, because this line sits on the cream card rather than pure white. */
  color: #7A5000;
}


.prop__specs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.prop__specs li {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  border: 1px solid var(--line);
  font-size: var(--fs-eyebrow);
  color: var(--body);
  white-space: nowrap;
}
.prop__specs svg {
  width: 15px; height: 15px;
  color: var(--panda);
  flex: none;
}

/* Card actions -------------------------------------------------------------- */
.prop__actions {
  display: flex;
  align-items: center;
  justify-content: space-between;  /* Explore left, Book Now right */
  gap: 16px;
  margin-top: 16px;
}
.prop__explore {
  font-size: var(--fs-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--panda);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--gold);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.prop__explore:hover { color: var(--gold); border-color: var(--panda); }
.prop__actions .btn { padding: 11px 22px; font-size: var(--fs-eyebrow); }

/* Newsletter ----------------------------------------------------------------- */
.newsletter {
  padding: 60px 0 30px;
  border-top: 1px solid var(--line);
}
.newsletter__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
}
.newsletter__copy h2 {
  font-size: var(--fs-h2);
  margin: 0 0 12px;
}
.newsletter__copy p {
  margin: 0;
  max-width: 46ch;
  color: var(--body);
}

/* A single rule under the field, rather than a boxed input */
.newsletter__form {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 14px;
}
.newsletter__form input {
  font-family: var(--sans);
  font-size: var(--fs-body);
  color: var(--ink);
  padding: 12px 2px;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  border-radius: 0;
  transition: border-color 0.3s var(--ease);
}
.newsletter__form input::placeholder { color: #A8A49B; }
.newsletter__form input:focus {
  outline: none;
  border-bottom-color: var(--gold);
}
.newsletter__form input:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}
.newsletter__form .btn { white-space: nowrap; }

.newsletter__note {
  grid-column: 1 / -1;
  margin: 2px 0 0;
  min-height: 1.2em;
  font-size: var(--fs-small);
  color: var(--gold);
}
.newsletter__note[data-state="error"] { color: #B4453C; }

@media (max-width: 900px) {
  .newsletter__inner { grid-template-columns: 1fr; gap: 28px; }
}
@media (max-width: 620px) {
  .newsletter__form { grid-template-columns: 1fr; align-items: stretch; }
  .newsletter__form .btn { width: 100%; }
}

/* WhatsApp (placeholder number) --------------------------------------------- */
/* Hero weather widget -------------------------------------------------------
   Sits opposite the contact rail, top-right of the hero. Glass panel so it
   reads over any frame of the video without a hard box.
   -------------------------------------------------------------------------- */
.wx {
  /* Absolute inside .hero, so it travels with the banner and scrolls away
     with it. Sits ~20% further down than the old header-relative position,
     flush to the right edge with only the left corners rounded. */
  position: absolute;
  right: 0;
  top: calc(var(--header-h) + 20vh);
  z-index: 6;
  min-width: 0;
  padding: 10px 13px 9px;
  border-radius: 4px 0 0 4px;
  border-right: 0;
  color: #FEFEFE;
  /* The panel floats over live footage, so its own fill has to guarantee the
     contrast: a bright frame underneath took the city and description lines to
     3.11:1 and 4.33:1. A denser fill fixes all three lines at once. */
  background: rgba(10, 10, 10, 0.62);
  border: 0;
  -webkit-backdrop-filter: blur(11px) saturate(1.15);
  backdrop-filter: blur(11px) saturate(1.15);
  box-shadow: 0 8px 28px rgba(10, 10, 10, 0.26);
  animation: wxIn 0.6s var(--ease) both;
}
@keyframes wxIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .wx { animation: none; } }

.wx__row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.wx__icon { font-size: 18px; line-height: 1; }
.wx__temp {
  font-family: var(--serif);
  font-size: 1.35rem;
  line-height: 1;
  letter-spacing: 0.01em;
}
.wx__city {
  margin: 5px 0 0;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-pale);
}
.wx__desc {
  margin: 2px 0 0;
  font-size: 11px;
  color: rgba(254, 254, 254, 0.88);
}

@media (max-width: 900px) {
  .wx { top: calc(var(--header-h) + 16vh); min-width: 0; padding: 8px 11px; }
  .wx__temp { font-size: 1.5rem; }
  .wx__icon { font-size: 21px; }
  .wx__desc { display: none; }
}
@media (max-width: 620px) {
  .wx { right: 0; padding: 7px 10px; }
  .wx__city { font-size: 9px; }
}

/* Booking form inside the modal --------------------------------------------
   The form is the same element as the one in the page, so it arrives with the
   7-column desktop grid. Inside the dialog it needs to stack.
   -------------------------------------------------------------------------- */
.bookmodal.has-form .bookmodal__panel { max-width: 560px; }
.bookmodal__form .booking__panel {
  box-shadow: none;
  border-top: 0;
  padding: 0;
  grid-template-columns: 1fr 1fr;
  column-gap: 12px;
  row-gap: 14px;
  /* The dialog centres its own text; the form's labels must not inherit it. */
  text-align: left;
  /* Stretch, not end-align: in two columns the nights note under Check Out
     otherwise pushed that field out of line with Check In. */
  align-items: stretch;
}
.bookmodal__form .field { align-content: start; }
.bookmodal__form .field--city,
.bookmodal__form .field--hotel,
.bookmodal__form .field--occ,
.bookmodal__form .booking__go { grid-column: 1 / -1; }
.bookmodal__form .booking__go { margin-top: 4px; height: 48px; }
/* In a dialog there is always room below, and the panel scrolls, so the
   occupancy popover should stay in flow instead of overlaying the button. */
.bookmodal__form .occ__panel {
  position: static;
  min-width: 0;
  margin-top: 8px;
  box-shadow: none;
  border-color: var(--line);
}
.bookmodal__form .field__note { position: static; margin-top: 4px; }

/* Below 900px the inline booking section is hidden and this dialog is the
   only way in, so it has to fit the screen without its own scrollbar.
   Everything below trims vertical space rather than shrinking touch targets:
   the 44px control height is kept throughout. */
@media (max-width: 900px) {
  /* Use dvh where supported so the iOS URL bar does not clip the panel. */
  .bookmodal__panel {
    width: 100%;
    max-height: 92vh;
    max-height: 92dvh;
    padding: 26px 20px 22px;
  }
  .bookmodal__panel .eyebrow { margin-bottom: 4px; }
  .bookmodal__panel h2 {
    font-size: clamp(1.4rem, 5.2vw, 1.75rem);
    margin: 0 0 16px;
  }
  .bookmodal__form .booking__panel { row-gap: 10px; column-gap: 10px; }
  .bookmodal__form .field { gap: 5px; }
  .bookmodal__form .booking__go { margin-top: 2px; }
  /* Check In and Check Out stack, one below the other. */
  .bookmodal__form .field--date { grid-column: 1 / -1; }
}

/* Short viewports at ANY width - landscape tablets and laptops included.
   The desktop dialog is comfortable at 900px tall but overflows at 768. */
@media (max-height: 820px) {
  .bookmodal__panel { max-height: 94vh; max-height: 94dvh; padding: 24px 30px 22px; }
  .bookmodal__panel h2 { font-size: 1.6rem; margin: 0 0 16px; }
  .bookmodal__form .booking__panel { row-gap: 10px; }
}

/* Very short screens: drop the heading block and tighten further. Controls
   stay at 40px - still above the 36px comfortable-touch floor - because a
   scrollbar inside the dialog is worse than 4px less padding. */
@media (max-width: 900px) and (max-height: 700px) {
  .bookmodal__panel { padding: 18px 16px 16px; }
  .bookmodal__panel .eyebrow { display: none; }
  .bookmodal__panel h2 { font-size: 1.18rem; margin: 0 0 10px; }
  .bookmodal__form .booking__panel { row-gap: 7px; column-gap: 8px; }
  .bookmodal__form .field { gap: 3px; }
  .bookmodal__form .field label { font-size: 10px; }
  .bookmodal__form .field__wrap { height: 40px; }
  .bookmodal__form .booking__go { height: 42px; margin-top: 0; }
  .bookmodal__form .field__note { font-size: 10px; }
  .bookmodal__close { top: 8px; right: 8px; }
}

@media (max-width: 460px) {
  .bookmodal__form .booking__panel { grid-template-columns: 1fr 1fr; }
  .bookmodal__form .field--city,
  .bookmodal__form .field--hotel,
  .bookmodal__form .field--occ,
  .bookmodal__form .field--promo,
  .bookmodal__form .booking__go { grid-column: 1 / -1; }
}

/* Smallest phones (iPhone SE and similar). The dates stay stacked as asked,
   so the row is recovered by pairing Rooms & Guests with Promo instead. */
@media (max-width: 380px) and (max-height: 620px) {
  .bookmodal__form .field--occ,
  .bookmodal__form .field--promo { grid-column: span 1; }
  .bookmodal__form .field--promo label { white-space: nowrap; }
  .bookmodal__form .field__note { display: none; }
}

/* Mobile sticky action bar --------------------------------------------------
   Only exists below 900px, and only shows once the footer is on screen. Two
   equal halves: Book Now (amber) and For Reservation (dark, dials the phone).
   Hidden entirely on desktop, where the header CTA is always in reach.
   -------------------------------------------------------------------------- */
.stickybar { display: none; }

@media (max-width: 900px) {
  .stickybar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 250;
    display: flex;
    background: var(--panda-ink);
    border-top: 1px solid rgba(245, 168, 28, 0.34);
    box-shadow: 0 -6px 22px rgba(10, 10, 10, 0.30);
    /* Clear the iOS home indicator */
    padding-bottom: env(safe-area-inset-bottom, 0);
    transform: translateY(100%);
    transition: transform 0.35s var(--ease);
  }
  .stickybar.is-on { transform: translateY(0); }
  /* The bar is permanently on below 900px, so the page must reserve its
     height or it sits on top of the footer's last row. The bar measures 55px,
     not 54: the buttons are min-height 54 and the bar adds a 1px top border.
     Reserving only 54 left the last row 1px under the bar. */
  body { padding-bottom: calc(55px + env(safe-area-inset-bottom, 0px)); }
  /* Anchor jumps and scrollIntoView otherwise park a target right under the
     fixed bar. This was putting the bar on top of the footer "Discover"
     heading. Keep a landing clear of the bar by its own height plus air. */
  html { scroll-padding-bottom: calc(55px + 16px + env(safe-area-inset-bottom, 0px)); }

  .stickybar__btn {
    flex: 1 1 50%;
    min-height: 54px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border: 0;
    cursor: pointer;
    font-family: var(--sans);
    font-size: 13px;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    text-decoration: none;
    transition: background 0.25s var(--ease), color 0.25s var(--ease);
  }
  .stickybar__btn svg { width: 17px; height: 17px; flex: none; }

  .stickybar__btn--book {
    background: var(--gold);
    color: var(--panda-ink);
  }
  .stickybar__btn--book:active { background: #E09A12; }

  .stickybar__btn--call {
    background: transparent;
    color: #FEFEFE;
    border-left: 1px solid rgba(254, 254, 254, 0.18);
  }
  .stickybar__btn--call:active { background: rgba(254, 254, 254, 0.09); }

  /* The bar owns the bottom edge while it is up, so lift the rail clear of it
     rather than letting the two overlap. */
  .rail.is-above-bar { bottom: calc(54px + 14px + env(safe-area-inset-bottom, 0px)); }
}

@media (prefers-reduced-motion: reduce) {
  .stickybar { transition: none; }
}

/* Contact rail -------------------------------------------------------------
   WhatsApp / call / email / scroll, stacked bottom-left. All four use the
   brand amber rather than each service's own colour, so the group reads as
   one piece of site furniture instead of four unrelated badges.
   -------------------------------------------------------------------------- */
.rail {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 240;
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: opacity 0.3s var(--ease), visibility 0.3s;
}
.rail__btn {
  position: relative;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  /* Light amber wash. It has to hold up over the dark hero video as well as
     over white sections, so the fill is opaque enough to be its own ground
     rather than a tint of whatever is behind it. */
  background: rgba(253, 240, 214, 0.94);
  color: #7A4E03;
  border: 1px solid rgba(245, 168, 28, 0.70);
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  -webkit-backdrop-filter: blur(9px) saturate(1.2);
  backdrop-filter: blur(9px) saturate(1.2);
  box-shadow: 0 6px 20px rgba(10, 10, 10, 0.14);
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
              border-color 0.3s var(--ease), transform 0.3s var(--ease),
              box-shadow 0.3s var(--ease);
}
.rail__btn svg { width: 22px; height: 22px; }

.rail__btn:hover,
.rail__btn:focus-visible {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--panda-ink);
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(245, 168, 28, 0.40);
}

/* Label appears on hover; hidden from layout but always read by AT via the
   button's own aria-label. */
.rail__tip {
  position: absolute;
  right: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%) translateX(4px);
  white-space: nowrap;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: var(--panda-ink);
  color: #FEFEFE;
  padding: 6px 11px;
  border-radius: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
}
.rail__btn:hover .rail__tip,
.rail__btn:focus-visible .rail__tip {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Flipped by JS once the reader is near the foot of the page */
.rail__btn--scroll.is-up svg { transform: rotate(180deg); }
.rail__btn--scroll svg { transition: transform 0.35s var(--ease); }

/* Steps aside with the Why Book Direct tab once the footer is on screen */
.rail.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .rail__btn, .rail__tip, .rail__btn--scroll svg { transition: none; }
}

@media (max-width: 620px) {
  .rail { right: 14px; bottom: 14px; gap: 8px; }
  .rail__btn { width: 42px; height: 42px; }
  .rail__btn svg { width: 20px; height: 20px; }
  .rail__tip { display: none; }   /* no hover on touch */
}


/* Why Book Direct - vertical sticky tab (placeholder content) --------------- */
.toaster {
  position: fixed;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 250;
  display: flex;
  align-items: center;
}

/* Tab reads bottom-to-top down the left edge */
.toaster__tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 18px 9px;
  background: var(--panda-ink);
  border: 0;
  color: #FEFEFE;
  font-family: var(--sans);
  font-size: var(--fs-small);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 8px 26px rgba(10, 10, 10, 0.28);
  transition: background 0.3s var(--ease);
}
.toaster__tab:hover { background: var(--panda); }

/* Out of the way once the footer is on screen */
.toaster.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.3s var(--ease), visibility 0.3s;
}
.toaster__tab span {
  writing-mode: vertical-rl;
  transform: rotate(180deg);      /* reads bottom-to-top */
  white-space: nowrap;
  line-height: 1;
}
.toaster__tag { width: 17px; height: 17px; color: var(--gold); flex: none; }
.toaster__chev {
  width: 14px; height: 14px;
  flex: none;
  transition: transform 0.3s var(--ease);
}
.toaster.is-open .toaster__chev { transform: rotate(180deg); }

/* Panel slides out beside the tab */
.toaster__panel {
  width: min(290px, calc(100vw - 90px));
  margin-left: 10px;
  background: #FEFEFE;
  box-shadow: 0 18px 48px rgba(10, 10, 10, 0.24);
  padding: 20px 22px 22px;
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}
.toaster__panel[hidden] { display: none; }
.toaster.is-open .toaster__panel { opacity: 1; transform: none; }

.toaster__panel .eyebrow { margin: 0 0 14px; }
.toaster__list {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
}
.toaster__list li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--body);
  padding: 5px 0;
}
.toaster__list svg {
  width: 16px; height: 16px;
  flex: none;
  margin-top: 2px;
  color: var(--gold);
}
/* Two CTAs stacked: offers first, then the booking action, so the primary
   gold button sits closest to the thumb and reads as the final step. */
.toaster__cta { display: grid; gap: 7px; }
.toaster__panel .btn {
  width: 100%;
  text-align: center;
  /* One CTA is an <a> and the other a <button>. The link inherits the body
     line-height (25.5px) while the button computes 'normal' (~18px), which
     left the pair 4px apart. An explicit line-height settles both.
     Scaled down from the site default: at the full 54px with 15px text the
     pair dominated a 290px panel and outweighed the four points above them. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 11px 14px;
  /* --fs-small is an alias of the 15px body size, so it changed nothing here.
     13px is an explicit step down for this compact panel. */
  font-size: 13px;
  letter-spacing: 0.09em;
  line-height: 1.2;
}

@media (max-width: 900px) {
  /* Sit lower than centre so the tab does not cover section content */
  .toaster { top: auto; bottom: 84px; transform: none; }
}
@media (max-width: 620px) {
  .toaster { bottom: 74px; }
  .toaster__tab { padding: 12px 6px; font-size: 10.5px; letter-spacing: 0.1em; }
  .toaster__tag { width: 14px; height: 14px; }
  .toaster__chev { width: 12px; height: 12px; }
  .toaster__panel { width: min(260px, calc(100vw - 66px)); padding: 18px 18px 20px; }
}

/* Booking property picker --------------------------------------------------- */
.bookmodal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: 24px;
}
.bookmodal[hidden] { display: none; }
.bookmodal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.62);
}
.bookmodal__panel {
  position: relative;
  width: min(560px, 100%);
  /* Was min(80vh, 720px). That sat LATER in the file than the responsive
     rules below and silently beat them, so the dialog scrolled on short
     viewports. 94dvh accounts for mobile browser chrome. */
  max-height: 94vh;
  max-height: 94dvh;
  overflow-y: auto;
  background: #FEFEFE;
  border-top: 3px solid var(--gold);
  box-shadow: 0 30px 80px rgba(10, 10, 10, 0.32);
  padding: 38px 38px 30px;
  text-align: center;
}
.bookmodal__panel h2 {
  font-size: var(--fs-h2);
  margin: 0 0 26px;
}
.bookmodal__close {
  position: absolute;
  top: 14px; right: 14px;
  width: 38px; height: 38px;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--body);
  cursor: pointer;
  transition: color 0.25s var(--ease);
}
.bookmodal__close svg { width: 18px; height: 18px; }
.bookmodal__close:hover { color: var(--panda); }

.bookmodal__list { list-style: none; margin: 0; padding: 0; text-align: left; }
.bookmodal__list li + li { border-top: 1px solid var(--line); }
.bookmodal__list a {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 6px 14px;
  padding: 16px 6px;
  text-decoration: none;
  transition: background 0.25s var(--ease), padding 0.25s var(--ease);
}
.bookmodal__list a:hover { background: var(--cream); padding-left: 14px; }
.bookmodal__name {
  font-family: var(--serif);
  font-size: var(--fs-h3);
  color: var(--ink);
  line-height: 1.25;
}
.bookmodal__where {
  grid-column: 1;
  font-size: var(--fs-eyebrow);
  color: var(--gold);
}
.bookmodal__list svg {
  grid-column: 2;
  grid-row: 1 / span 2;
  width: 18px; height: 18px;
  color: var(--panda);
}

@media (max-width: 620px) {
  .bookmodal__panel { padding: 32px 22px 24px; }
}

/* Pager - only shown when a city holds more than 3 properties --------------- */
/* In marquee mode the arrows overlay the row, centred on the imagery */
.prop-shell {
  position: relative;
  container-type: inline-size;
}
.prop-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: clamp(28px, 3vw, 42px);
}
.prop-shell .prop-nav {
  position: absolute;
  /* Half the image height from the top, less half the arrow, so the arrow's
     centre lands on the image's centre rather than its top edge. */
  top: calc((100cqw - clamp(18px, 2.2vw, 30px) * 3.4) / 3.4 / 1.42 / 2 - var(--arrow-size) / 2);
  left: 0; right: 0;
  z-index: 4;
  margin: 0;
  justify-content: space-between;
  pointer-events: none;
}
.prop-shell .prop-nav .prop-arrow { pointer-events: auto; }
.prop-shell .prop-nav .prop-dots { display: none; }
/* Flush to the left and right edge of the carousel, matching --arrow-inset
   used by the absolutely positioned .mq-arrow controls. */
.prop-shell .prop-arrow:first-of-type { margin-left: var(--arrow-inset); }
.prop-shell .prop-arrow:last-of-type { margin-right: var(--arrow-inset); }
.prop-nav[hidden] { display: none; }
/* Same plate, size and glyph as .mq-arrow so the properties carousel reads as
   the same control as every other section carousel on the site. */
.prop-arrow {
  width: var(--arrow-size); height: var(--arrow-size);
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
              transform 0.3s var(--ease);
}
.prop-arrow svg {
  width: var(--arrow-glyph); height: var(--arrow-glyph);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}
.prop-arrow:hover { background: none; color: var(--gold); }
.prop-arrow:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.prop-dots { display: flex; gap: 8px; }
.prop-dot {
  width: 8px; height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line);
  cursor: pointer;
  transition: background 0.3s var(--ease), transform 0.3s var(--ease);
}
.prop-dot.is-on { background: var(--panda); transform: scale(1.2); }

.prop-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--body);
  margin: 30px 0;
}

/* Amenities ---------------------------------------------------------------- */
/* Two columns of icon cards beside a tall media panel (~3:2). */
.amen-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(24px, 3vw, 40px);
  align-items: start;
}
.amen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 19px;
}
.amen {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 22px 22px 24px;
  background: rgba(254, 254, 254, 0.55);
  border: 1px solid transparent;      /* no outline until hovered */
  transition: background 0.35s var(--ease), border-color 0.35s var(--ease),
              transform 0.35s var(--ease);
}
.amen:hover {
  background: #FEFEFE;
  border-color: var(--gold);
  transform: translateY(-3px);
}
.amen__icon {
  flex: none;
  width: 38px;
  height: 38px;
  color: var(--panda);
}
.amen__icon svg { width: 100%; height: 100%; display: block; }
.amen h3 {
  font-size: var(--fs-h3);
  font-weight: 500;
  margin: 0 0 6px;
  line-height: 1.25;
}
.amen p {
  margin: 0;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--body);
}

/* Media panel matches the full height of the card grid */
.amen-media {
  margin: 0;
  height: 100%;
  min-height: 320px;
  overflow: hidden;
}
.amen-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Cards -------------------------------------------------------------------- */
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 34px;
}
.card {
  background: #FEFEFE;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease);
}
.card:hover {
  transform: translateY(-8px);
  box-shadow: 0 26px 56px rgba(10, 10, 10, 0.14);
}
.card__media { overflow: hidden; aspect-ratio: 4 / 3; }
.card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.85s var(--ease);
}
.card:hover .card__media img { transform: scale(1.07); }
.card__body {
  padding: 28px 28px 32px;
  display: flex;
  flex-direction: column;
  flex: 1;
  border: 1px solid var(--line);
  border-top: 0;
}
.card__body h3 {
  font-size: var(--fs-h3);
  margin-bottom: 10px;
  min-height: 2.1em;            /* keeps headings on a common baseline across a row */
  display: flex;
  align-items: flex-start;
}
.card__body p { font-size: var(--fs-body); flex: 1; }
.card__meta {
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 14px;
}
.card__link {
  font-size: var(--fs-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--panda);
  text-decoration: none;
  align-self: flex-start;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--gold);
  transition: gap 0.3s var(--ease);
}
.card__link:hover { color: var(--gold); }

/* Experience strip --------------------------------------------------------- */
.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
}
.tile {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  display: grid;
  align-items: end;
}
.tile img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease);
}
.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(10, 10, 10,0) 35%, rgba(10, 10, 10, 0.59) 100%);
}
.tile:hover img { transform: scale(1.08); }
.tile figcaption {
  position: relative;
  z-index: 2;
  padding: 26px 24px;
  color: #FEFEFE;
}
.tile h3 {
  color: #FEFEFE;
  font-size: var(--fs-h3);
  margin: 0 0 4px;
}
.tile p {
  margin: 0;
  font-size: var(--fs-small);
  color: rgba(254, 254, 254,0.85);
}

/* --------------------------------------------------------------------------
   FOOTER
   -------------------------------------------------------------------------- */

.footer {
  position: relative;
  isolation: isolate;
  background: var(--panda-ink);
  color: rgba(254, 254, 254, 0.94);
  padding: 60px 0 0;
  font-size: var(--fs-body);
  overflow: hidden;
}
/* Video backdrop, with a heavy scrim so the text keeps its contrast */
.footer__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.footer__bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The footage carries bright mist, so the footer needs a real scrim.

   The previous stops (0.46/0.34/0.26/0.44) were set against a claimed worst
   case of #595856. Re-measured by hiding every element in the footer grid and
   sampling the brightest PAINTED pixel in the grid's own box, the true worst
   case is (158,157,158), which is far brighter. At those stops the link greys
   came out at 2.46:1 and the muted sublabel at 1.55:1, well under the 4.5:1
   AA floor, so the old numbers in this comment did not describe what the page
   actually painted.

   The ramp below is set from that re-measurement. Do not lighten these stops
   without re-running the painted-pixel sample: reading a background colour off
   parentElement returns transparent over a video and reports a false pass. */
.footer__scrim {
  /* Retired. This sat on top of .footer::before, so the two compounded to
     about 84% and the footage read as a dark blur. One gradient is enough. */
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .footer__bg video { display: none; }
  .footer__bg {
    background: var(--panda-ink) url("../images/footer-poster.jpg") center / cover no-repeat;
  }
}

/* The footer film and its poster are both 16:9 landscape (the poster is
   1280x720). On a phone the footer box is roughly 390x1520 CSS px, so
   object-fit: cover scales that source about 4x vertically, and on a 2x screen
   it is painted into ~780x3040 device px. No CSS makes a 720px-tall source
   sharp at that size, which is why the mobile footer read as blurry. Below the
   stacked breakpoint the footage is dropped and the footer sits on the brand
   ground instead, so nothing is upscaled. Restore the film here only with a
   portrait-crop asset of at least 800x1600. */
@media (max-width: 720px) {
  .footer__bg video { display: none; }
  .footer__bg { background: var(--panda-ink); }
}
.footer::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Text covers only about a quarter of this footer, but a flat wash dimmed
     all of it, which is why the footage read as a dark blur. The scrim is now
     light enough to see the video through, and legibility is carried by a
     shadow on the glyphs themselves (see .footer text-shadow below). That is
     the standard fix: darken the letters, not the picture. */
  background: linear-gradient(180deg,
    rgba(10, 10, 10, 0.40) 0%,
    rgba(10, 10, 10, 0.28) 32%,
    rgba(10, 10, 10, 0.26) 64%,
    rgba(10, 10, 10, 0.44) 100%);
}

/* A tight, dark halo sits behind each glyph. It costs nothing visually on a
   dark area and rescues the text when a bright frame passes underneath, so the
   scrim above can stay light without the copy ever dropping below 4.5:1. */
.footer h4,
.footer h5,
.footer p,
.footer a,
.footer address,
.footer li,
.footer span {
  text-shadow:
    0 1px 2px rgba(10, 10, 10, 0.9),
    0 0 10px rgba(10, 10, 10, 0.75);
}
/* The logo and the send icon are art, not type. */
.footer img,
.footer svg { text-shadow: none; }

/* The address column sits over the brightest part of the footage, where a
   light scrim alone leaves the smaller type short of 4.5:1. A soft local wash
   behind just that column buys the contrast without dimming the whole video.
   The radius and blur keep it reading as depth rather than as a panel. */
.fcol--wide {
  position: relative;
}
.fcol--wide::before {
  content: "";
  position: absolute;
  inset: -18px -22px;
  z-index: -1;
  background: rgba(10, 10, 10, 0.42);
  filter: blur(18px);
  border-radius: 18px;
  pointer-events: none;
}
/* With a thinner scrim the copy needs its own contrast rather than relying
   on the overlay to carry it. */
.footer .wrap { position: relative; }
.footer p,
.footer a,
.footer address,
.footer h4,
.footer__label,
.footer__sublabel {
  text-shadow: 0 1px 12px rgba(6, 6, 6, 0.75);
}

/* Social links (placeholder targets) */
.social {
  display: flex;
  gap: 12px;
  list-style: none;
  /* The caption above owns the gap, so the row itself adds none. */
  margin: 0;
  padding: 0;
}
.social a {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border: 1px solid rgba(254, 254, 254, 0.28);
  border-radius: 50%;
  color: rgba(254, 254, 254, 0.9);
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease),
              color 0.3s var(--ease), transform 0.3s var(--ease);
}
.social svg { width: 17px; height: 17px; }
.social a:hover {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--panda-ink);
  transform: translateY(-2px);
}

.footer h4,
.footer__label {
  text-shadow: 0 1px 12px rgba(6, 6, 6, 0.75);
}
.footer__grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1.4fr;
  gap: clamp(28px, 3.4vw, 52px);
  padding-bottom: 60px;
}
.footer img {
  height: 78px;
  width: auto;
  margin-bottom: 22px;
}
.footer h4,
.footer__label {
  /* A column label rather than a section heading, so it takes the eyebrow
     size deliberately. Every real h4 on the site stays at --fs-h4. */
  color: #FEFEFE;
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.20em;
  text-transform: uppercase;
  margin: 0 0 22px;
}
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: 12px; }
.footer a {
  color: rgba(254, 254, 254,0.96);
  text-decoration: none;
  transition: color 0.25s var(--ease);
}
.footer a:hover { color: var(--gold-pale); }
.footer address {
  font-style: normal;
  line-height: 1.9;
  /* Keep each line intact rather than breaking mid-phrase */
  text-wrap: pretty;
}
.footer address a { white-space: nowrap; }

.footer__bottom {
  border-top: 1px solid rgba(254, 254, 254, 0.22);
  padding: 24px 0 30px;
  display: flex;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  font-size: var(--fs-small);
}
.footer__bottom p { margin: 0; }

/* Legal block left, build credit right. */
.footer__legal {
  display: flex;
  /* Copyright and the sitemap link share one line, wrapping only on narrow
     screens, so the bottom bar reads as a single row against the credit. */
  flex-flow: row wrap;
  align-items: baseline;
  gap: 4px 18px;
}
.footer__credit {
  margin-left: auto;
  text-align: right;
  color: rgba(254, 254, 254, 0.90);
}
/* The link sits inside a sentence and was distinguished from the text around
   it by brightness alone, which fails WCAG 1.4.1 for anyone who cannot see the
   colour difference. An underline carries the meaning without colour. */
.footer__credit a {
  color: rgba(254, 254, 254, 0.92);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.footer__credit a:hover { color: var(--gold); }

@media (max-width: 620px) {
  .footer__bottom { flex-direction: column; align-items: flex-start; }
  .footer__credit { margin-left: 0; text-align: left; }
}

/* Nearby attractions --------------------------------------------------------
   An expanding slider: cards sit in a flex row and the active one grows to
   reveal its copy while the others stay as titled tiles. Width is animated
   with flex-basis on a fixed-height track. Two things matter for smoothness:
   the track sets an explicit height (an aspect-ratio would make the card's
   height follow its animating width, resizing the whole row and shunting the
   page below it), and the cards animate flex-basis in a single pass rather
   than flex-grow, which the engine re-resolves against every sibling.
   -------------------------------------------------------------------------- */
.attr-wrap {
  position: relative;
  width: calc(100% - var(--gutter) * 2);
  max-width: var(--wrap);
  margin: 0 auto;
}
.attr-viewport { overflow: hidden; }

.attr-track {
  display: flex;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
  /* Fixed height, so an expanding card never changes the row's height.
     Two 10% reductions down from the original 0.78 aspect ratio. */
  height: clamp(324px, 30.6vw, 450px);
}

.attr {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  min-width: 0;
  height: 100%;
  contain: paint;
  /* Grow/shrink from a zero basis instead of fixed percentages: the row then
     always fills its width no matter how many cards there are. The earlier
     fixed 14.5%/42% split was tuned for five cards and left 161px of dead
     space once the list dropped to four. */
  flex: 1 1 0;
  min-width: 0;
  /* No will-change: flex-basis drives layout, which cannot be promoted to a
     compositor layer, so the hint only costs memory. */
  transition: flex-basis 0.55s var(--ease);
}
.attr.is-active { flex-grow: 3.2; }

.attr img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease);
}
.attr.is-active img { transform: scale(1.04); }

/* Foot gradient, matching the destination cards. The active card gets a
   deeper one because it carries a paragraph, not just a title. */
.attr::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(10, 10, 10, 0) 28%,
    rgba(10, 10, 10, 0.26) 50%,
    rgba(10, 10, 10, 0.58) 74%,
    rgba(10, 10, 10, 0.66) 100%);
  transition: background 0.6s var(--ease);
}
.attr.is-active::after {
  background: linear-gradient(180deg,
    rgba(10, 10, 10, 0.08) 0%,
    rgba(10, 10, 10, 0.24) 34%,
    rgba(10, 10, 10, 0.58) 58%,
    rgba(10, 10, 10, 0.67) 100%);
}

.attr__body {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: 0 26px 28px;
  color: #FEFEFE;
}
.attr__label {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 6px;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(254, 254, 254, 0.92);
  white-space: nowrap;
}
.attr__label i {
  display: block;
  width: 20px;
  height: 1px;
  background: currentColor;
  flex: none;
}
.attr__body h3 {
  font-size: var(--fs-h3);
  color: #FEFEFE;
  margin: 0;
  /* Collapsed cards are narrow; let the title wrap rather than clip. */
  text-wrap: balance;
}

/* The copy block. Collapsed cards keep it in the DOM (so the text is always
   available to search and screen readers) but closed to zero height. */
.attr__more {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 0.6s var(--ease), opacity 0.4s var(--ease),
              margin-top 0.6s var(--ease);
  margin-top: 0;
}
.attr__more > * { overflow: hidden; }
.attr.is-active .attr__more {
  grid-template-rows: 1fr;
  opacity: 1;
  margin-top: 12px;
}
.attr__more p {
  margin: 0 0 14px;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: rgba(254, 254, 254, 0.90);
  max-width: 46ch;
}
.attr__cta {
  display: inline-flex;
  justify-self: start;
  width: fit-content;
  align-items: center;
  gap: 9px;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #FEFEFE;
  border-bottom: 1px solid rgba(254, 254, 254, 0.45);
  padding-bottom: 3px;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.attr__cta svg { width: 17px; height: 17px; }
.attr:hover .attr__cta { color: var(--gold); border-bottom-color: var(--gold); }

/* Arrows reuse .mq-arrow wholesale; only the vertical placement differs.
   The glyph size override that used to live here was removed so the control
   stays identical to every other section carousel arrow. */
.attr-arrow { top: 50%; }

@media (prefers-reduced-motion: reduce) {
  .attr, .attr img, .attr::after, .attr__more { transition: none; }
}

/* Below the breakpoint an expand interaction has no hover to drive it, so the
   slider becomes a swipeable row with every card fully open. */
@media (max-width: 900px) {
  .attr-viewport {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .attr-viewport::-webkit-scrollbar { display: none; }
  .attr-track {
    gap: 14px;
    height: clamp(400px, 108vw, 560px);
  }
  .attr {
    flex: 0 0 78%;
    height: 100%;
    scroll-snap-align: center;
    will-change: auto;
    transition: none;   /* nothing expands here; avoid a stray animation */
  }
  .attr.is-active { flex-grow: 0; }
  .attr::after,
  .attr.is-active::after {
    background: linear-gradient(180deg,
      rgba(10, 10, 10, 0.10) 0%,
      rgba(10, 10, 10, 0.36) 34%,
      rgba(10, 10, 10, 0.80) 58%,
      rgba(10, 10, 10, 0.93) 100%);
  }
  .attr__more,
  .attr.is-active .attr__more {
    grid-template-rows: 1fr;
    opacity: 1;
    margin-top: 12px;
  }
  .attr-arrow { display: none; }
}

/* Explore local cuisine ----------------------------------------------------- */
/* Mirrored against the reference: copy on the left, imagery on the right. */
.dining { padding-top: 60px; }
.dining .section-head { max-width: 760px; }
.dining .section-head h2 { font-size: var(--fs-h2); }

.dining__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(40px, 5vw, 76px);
  align-items: center;
}
/* Image left, copy right - matching the reference layout */
.dining__media { order: 1; }
.dining__copy  { order: 2; }

/* Copy column -------------------------------------------------------------- */
.dining__lead {
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: 1.42;
  margin: 0 0 28px;
}
.dining__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.dining__list li {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  padding: 22px 0;
  border-bottom: 1px solid var(--line);
}
.dining__icon {
  flex: none;
  width: 40px;
  height: 40px;
  color: var(--gold);
}
.dining__icon svg { width: 100%; height: 100%; display: block; }
.dining__list h4 {
  font-family: var(--sans);
  font-size: var(--fs-h4);
  font-weight: 500;
  color: var(--ink);
  margin: 0 0 5px;
}
.dining__list p {
  margin: 0;
  /* Was --fs-small (14.5px). Contrast here already measured 6.63:1, so the
     problem was never colour: it was 14.5px of light-weight type competing
     with a background that varies 0.219 in luminance underneath it. Sustained
     reading copy sits at 16px, and the extra leading gives the letterforms
     room to separate from the texture behind them. */
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--body);
}
.dining__note {
  margin: 24px 0 0;
  font-size: var(--fs-small);
  line-height: 1.7;
  color: var(--body);
}

/* Image column ------------------------------------------------------------- */
/* Base photo with a taller egg-shaped inset hanging off its lower right,
   and the badge sitting on the seam between the two. */
.dining__media {
  position: relative;
  /* The whole composition is driven by this one ratio: the base photo is 100%
     of it and the inset is a percentage of the same box, so widening the ratio
     shrinks both by the same proportion and their relationship is preserved.
     0.92 -> 1.022 takes about 10% off the height. Text is untouched. */
  aspect-ratio: 1.062;
}
.dining__photo,
.dining__inset { margin: 0; overflow: hidden; }
.dining__photo {
  width: 79%;
  height: 100%;
}
.dining__photo img,
.dining__inset img,
.dining__photo video,
.dining__inset video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.dining__inset {
  position: absolute;
  right: 0;
  bottom: 6%;
  width: 46%;
  /* Scaled with the parent box: 0.64 -> 0.711 is the same 10% reduction, so
     the two frames keep their original relationship to each other. */
  aspect-ratio: 0.739;
  border-radius: 50%;
  z-index: 1;
}

/* Rotating badge on the seam where the two images meet */
.dining__badge {
  position: absolute;
  left: 56%;
  top: 42%;
  width: clamp(88px, 8.4vw, 116px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  background: rgba(38, 38, 44, 0.88);
  border-radius: 50%;
  color: #FEFEFE;
  z-index: 2;
}
.dining__badge svg { width: 100%; height: 100%; }
.dining__badge text {
  font-family: var(--sans);
  font-size: 9.2px;
  letter-spacing: 0.2em;
  fill: rgba(254, 254, 254, 0.92);
  text-transform: uppercase;
}
.dining__badge > svg { animation: diningSpin 18s linear infinite; }
.dining__badge-mark {
  position: absolute;
  width: 30%;
  color: #FEFEFE;
}
.dining__badge-mark svg { width: 100%; height: auto; }

@keyframes diningSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .dining__badge > svg { animation: none; }
}

/* Offers (parallax) --------------------------------------------------------- */
/* The backdrop is a taller image translated on scroll, rather than
   background-attachment: fixed, which iOS ignores. */
.offers {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding: 60px 0 30px;
}
.offers__bg {
  position: absolute;
  /* Was inset:-18% with a parallax transform. The drifting backdrop read as a
     distracting motion effect, so the image is now pinned to the section. */
  inset: 0;
  z-index: -2;
}
.offers__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Flat scrim, not a gradient: the graded version read as a vignette washing
   across the band. Held at 0.62, which still gives white copy well over 7:1
   on the brightest frame of either property's backdrop. */
.offers::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* A flat 62% wash over the whole frame was killing the photograph to protect
     copy that sits only on the left. Measured: white text needs the surface
     under it at or below ~0.18 luminance for 4.5:1, so the gradient holds that
     where the text is and releases the image entirely past the midpoint. */
  /* Strengthened over the copy: with the heading set correctly in white,
     Hotel Karnika's backdrop still measured only 4.2:1 under the H2. The two
     leading stops lift every property clear of 4.5:1 while the tail is
     unchanged, so the photograph past the midpoint reads exactly as before. */
  background: linear-gradient(100deg,
    rgba(10, 10, 10, 0.74) 0%,
    rgba(10, 10, 10, 0.67) 26%,
    rgba(10, 10, 10, 0.34) 48%,
    rgba(10, 10, 10, 0.13) 68%,
    rgba(10, 10, 10, 0.04) 100%);
}
@media (max-width: 900px) {
  /* Stacked layout puts the copy over the middle of the frame, so the ramp
     runs vertically instead. */
  .offers::after {
    background: linear-gradient(180deg,
      rgba(10, 10, 10, 0.82) 0%,
      rgba(10, 10, 10, 0.64) 40%,
      rgba(10, 10, 10, 0.30) 72%,
      rgba(10, 10, 10, 0.10) 100%);
  }
}

.offers .section-head h2,
.offers .tile h3 { color: #FEFEFE; }
.offers .section-head p { color: rgba(254, 254, 254,0.88); }
.offers .eyebrow { color: var(--gold-pale); }
.offers .rule { background: var(--gold-pale); }
.offers .rule::before,
.offers .rule::after { background: var(--gold-pale); }

.offers__inner { position: relative; z-index: 1; }
.offers__cta { text-align: center; margin: clamp(34px, 4vw, 52px) 0 0; }

@media (prefers-reduced-motion: reduce) {
  .offers__bg { transform: none !important; }
}

/* FAQ ------------------------------------------------------------------------ */
.faq {
  background: var(--cream);
  padding-top: 60px;
}
.faq__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1fr);
  gap: clamp(36px, 5vw, 66px);
  align-items: start;
}
.faq__media {
  margin: 0;
  aspect-ratio: 0.81;
  overflow: hidden;
}
.faq__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.faq__copy h2 {
  font-size: var(--fs-h2);
  margin: 0 0 16px;
}
.faq__intro {
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--body);
  margin: 0 0 30px;
  max-width: 56ch;
}

/* Accordion - native <details> so it works without JS and is keyboard-ready */
.faq__item { border-top: 1px solid var(--line); }
.faq__item:last-of-type { border-bottom: 1px solid var(--line); }

.faq__item summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 19px 2px;
  font-family: var(--serif);
  font-size: var(--fs-lead);
  color: var(--ink);
  transition: color 0.25s var(--ease);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { color: var(--panda); }
.faq__item[open] summary { color: var(--panda); }

/* + / − indicator drawn with two rules */
.faq__item summary i {
  position: relative;
  flex: none;
  width: 15px;
  height: 15px;
}
.faq__item summary i::before,
.faq__item summary i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--gold);
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.faq__item summary i::before {
  width: 15px; height: 1.5px;
  transform: translate(-50%, -50%);
}
.faq__item summary i::after {
  width: 1.5px; height: 15px;
  transform: translate(-50%, -50%);
}
.faq__item[open] summary i::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }

.faq__body {
  padding: 0 2px 22px;
  max-width: 62ch;
}
.faq__body p {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.75;
  color: var(--body);
}

@media (max-width: 900px) {
  .faq__grid { grid-template-columns: 1fr; }
  .faq__media { max-width: 460px; aspect-ratio: 1.2; }
}

/* Reveal-on-scroll --------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

/* Marquee cards must never be reveal-animated. Clones are created after the
   IntersectionObserver has run, so they are never observed and would sit at
   opacity 0 until they happened to scroll past - which showed as only the
   first few cards being visible. */
.loc-grid .reveal,
.prop-track .reveal,
.rooms-track .reveal,
.loc-grid > .loc,
.prop-track > .prop,
.rooms-track > .prop {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  .hero__media img { animation: none; }
}

/* --------------------------------------------------------------------------
   RESPONSIVE
   -------------------------------------------------------------------------- */

@media (max-width: 1080px) {
  .booking__panel { grid-template-columns: repeat(2, 1fr); }
  .booking__panel .btn { grid-column: 1 / -1; width: 100%; }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: repeat(2, 1fr); gap: 40px; }
}

/* Now 1023px (was 1152px): the desktop header is a `1fr auto 1fr`
   grid, and below ~1023px the right group hits its natural minimum
   (Meetings & Events plus Book Now) while the left column keeps
   shrinking. The columns stop being equal and the centred logo drifts
   off axis, by 56px at 1024 and 88px at 960. Collapsing to the mobile
   nav before that point means the broken band never renders. */
@media (max-width: 1023px) {
  :root { --header-h: 72px; }

  /* The burger now lives in .header__right, so the old `1fr auto 1fr` grid
     left column 1 empty and shoved the logo and actions to the left with a
     large dead gap on the right. Two columns instead: brand, then actions. */
  .header__inner {
    grid-template-columns: auto 1fr !important;
    gap: 12px;
  }
  .header__inner > .brand { justify-self: start; grid-column: 1; }
  .header__inner > .header__right { justify-self: end; grid-column: 2; }
  .header__inner > .header__nav-wrap { grid-column: 1 / -1; }
  /* Equal outer tracks, not `auto`: the burger is 44px and the right group
     (Book Now) is 112px, so `auto 1fr auto` put the centre column's midpoint
     34px off the header's own centre and the logo looked misaligned. Matching
     the two outer columns keeps the mark truly centred at every width. */
  .header__inner {
    /* The outer columns were minmax(112px, 1fr) each. On a 320px screen that
       claims 224px and leaves the brand column nothing, so the logo was
       squeezed to 0px wide and vanished; at 390px it rendered 54px wide
       against a natural 79px, which is a visibly squashed mark. The 112px
       floor now only applies where there is room for it. */
    grid-template-columns: minmax(56px, 1fr) auto minmax(56px, 1fr);
    column-gap: 8px;
  }
  .header__inner > .burger { justify-self: start; }
  .header__right { justify-self: end; }
  .brand { justify-self: center; }
  /* min-width: 0 lets the column shrink; the aspect-ratio keeps the mark in
     proportion instead of letting the grid squash it. */
  .brand { min-width: 0; }
  .brand img {
    height: 54px;
    width: auto;
    max-width: 100%;
    aspect-ratio: 353 / 240;
    object-fit: contain;
  }
  .header.is-stuck .brand img { height: 46px; }

  /* Very small phones: step the mark and the Book Now button down together so
     all three header items keep their proportions rather than one collapsing. */
  @media (max-width: 400px) {
    .header__inner { grid-template-columns: minmax(44px, 1fr) auto minmax(44px, 1fr); }
    .brand img { height: 46px; }
    .header.is-stuck .brand img { height: 40px; }
    .header .btn { padding: 9px 12px; }
  }
  .header .btn { padding: 11px 18px; font-size: var(--fs-eyebrow); }
  .header__right { gap: 0; }
  .header__nav-wrap { display: block; }

  /* Both nav groups collapse into one stacked panel.
     They are laid out in normal flow inside a fixed wrapper so the
     second group sits BELOW the first instead of on top of it. */
  .header__nav-wrap {
    position: fixed;
    top: var(--header-h);
    left: 0;
    right: 0;
    background: #FEFEFE;
    max-height: 0;
    overflow: hidden;
    border-bottom: 1px solid transparent;
    transition: max-height 0.45s var(--ease), border-color 0.45s var(--ease);
  }
  .header__nav-wrap.is-open {
    max-height: 74vh;
    overflow-y: auto;
    border-bottom-color: var(--line);
    box-shadow: 0 18px 34px rgba(10, 10, 10,0.12);
  }
  .nav {
    position: static;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
    max-height: none;
    overflow: visible;
  }
  .nav li { border-bottom: 1px solid var(--line); }
  .nav a { display: block; padding: 15px 28px; }
  .nav a::after { display: none; }

  .has-drop { padding-right: 0; }
  .has-drop > a::before { right: 28px; }
  /* Collapsed with the grid-template-rows 0fr/1fr technique rather than a
     max-height number. The old `max-height: 320px` open state was a guess that
     fitted the list when it was shorter; with 9 hotels plus 4 city labels the
     content is ~700px, so it cut the panel off mid-list and `overflow: hidden`
     made the remaining four hotels unreachable. 0fr to 1fr animates just the
     same but is sized by the content, so it can never clip. */
  .drop {
    position: static;
    transform: none;
    opacity: 1;
    visibility: visible;
    min-width: 0;
    border: 0;
    box-shadow: none;
    background: var(--cream);
    padding: 0;
    max-height: none;
    display: grid;
    grid-template-rows: 0fr;
    overflow: hidden;
    transition: grid-template-rows 0.4s var(--ease);
  }
  /* The animating child must not impose a min-content floor, or the collapsed
     panel would still show a strip of the list. */
  .drop > * { overflow: hidden; min-height: 0; }
  .has-drop.is-open .drop { grid-template-rows: 1fr; }
  /* Padding lives on a descendant, never on the 0fr grid child itself. */
  .has-drop.is-open .drop__all { padding-top: 6px; }
  .has-drop.is-open .drop__group:last-child { padding-bottom: 10px; }
  .drop a { padding-left: 44px; }

  /* Flanking images would crowd the copy - stack them below it instead */
  .about__img {
    position: static;
    width: 100%;
    height: 260px;
  }
  .about__img--left { order: 2; margin-top: 44px; }
  .about__img--right { display: none; }
  .about {
    display: flex;
    flex-direction: column;
  }
  .about__lead { order: 1; max-width: none; }
  .about__statswrap { order: 3; width: 100%; }
  /* Reset the desktop asymmetric margin - it reserved room for the flanking
     image, which leaves a large empty gap once the images stack. */
  .about__stats {
    width: calc(100% - var(--gutter) * 2);
    margin: 54px auto 0;
  }
  .about__stats { grid-template-columns: repeat(2, 1fr); }
  .astat { padding: 26px 12px; }
  /* Hairlines only between columns, not on the outer edges */
  .astat:nth-child(2n+1) { border-left: 0; }
  .astat:nth-child(n+3) { border-top: 1px solid var(--line); }
  .grid-3 { grid-template-columns: 1fr; }
  .loc-wrap { max-width: calc(100% - 40px); }
  /* Fewer, wider cards so they stay readable on tablets */
  .loc-grid > .loc { flex: 0 0 calc((100cqw - 8px * 2.4) / 2.4); }
  .prop-track.is-marquee > .prop {
    flex: 0 0 calc((100cqw - clamp(18px, 2.2vw, 30px) * 2.2) / 2.2);
  }
  /* Media panel drops below the cards before the grid gets too narrow */
  .amen-layout { grid-template-columns: 1fr; }
  .dining__grid { grid-template-columns: 1fr; gap: 44px; }
  .dining__media { order: 1; }
  .dining__copy { order: 2; }
  .dining__media { max-width: 520px; margin-inline: auto; width: 100%; }
  .prop-track { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Tabs scroll horizontally; hide the scrollbar and let them bleed to the
     screen edges so it reads as a swipeable strip rather than a clipped row. */
  .prop-tabs {
    justify-content: flex-start;
    overflow-x: auto;
    flex-wrap: nowrap;
    gap: 22px;
    padding-inline: var(--gutter);
    margin-inline: calc(var(--gutter) * -1);
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .prop-tabs::-webkit-scrollbar { display: none; }
  .prop-tab { padding-bottom: 12px; }
  .prop__arrow { opacity: 1; }
  .amen-media { min-height: 260px; max-height: 340px; }
  .section { padding: 76px 0; }
  .offers { padding: 76px 0; }   /* match .section so the boundary stays uniform */
  .footer { padding-top: 76px; }
}

@media (max-width: 620px) {
  :root { --gutter: 20px; }
  .wrap { padding: 0 var(--gutter); }

  /* Less air between sections so the page is not endless scrolling */
  .section { padding: 44px 0 26px; }
  .section-head { margin-bottom: 24px; }
  .locations { padding: 44px 0 26px; }
  .locations .section-head { margin-bottom: 24px; }

  /* Headlines step down a notch on small screens */
  .about__lead h2 { font-size: clamp(1.5rem, 7vw, 1.85rem); }
  .hero__cta .btn { width: 100%; }
  /* The cue sat on top of the CTA on short screens */
  .scroll-cue { bottom: 18px; }
  .scroll-cue i { height: 26px; }
  .booking { margin-top: -30px; }
  .booking__panel { grid-template-columns: 1fr; padding: 22px; gap: 18px; }
  .grid-4 { grid-template-columns: 1fr; }
  .amen-grid { grid-template-columns: 1fr; }
  .prop-track { grid-template-columns: 1fr; }
  .loc { aspect-ratio: 1.15; }

  /* Phones: a little over one card across, so each stays legible */
  .loc-grid > .loc { flex: 0 0 calc((100cqw - 8px * 1.2) / 1.2); }
  /* One full card with the next peeking, rather than a card wider than the
     screen bleeding off both edges. */
  .prop-track.is-marquee > .prop {
    flex: 0 0 calc((100cqw - clamp(18px, 2.2vw, 30px) * 1.25) / 1.25);
  }
  /* Phones: the pager drops below the row instead of overlaying the photos.
     At 1.25 cards across, the overlaid arrows landed on the peeking
     neighbour card with nothing behind them, so they read as part of the
     photo. This restores the static .prop-nav layout. */
  .prop-shell .prop-nav {
    position: static;
    margin-top: 22px;
    gap: 26px;
    justify-content: center;
    pointer-events: auto;
  }
  .prop-shell .prop-arrow:first-of-type,
  .prop-shell .prop-arrow:last-of-type { margin-inline: 0; }
  /* Brand block full width, then Explore + Our Hotels as a 2-up so the
     footer does not become one very long column on a phone. */
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 30px 22px;
    padding-bottom: 40px;
  }
  .footer__grid > :first-child { grid-column: 1 / -1; }
  .footer__grid > :last-child { grid-column: 1 / -1; }
  .footer { padding-top: 44px; }   /* 26 + 44 = 70, same as every other boundary */
  .footer li { margin-bottom: 9px; }
  .footer__label { margin-bottom: 14px; }
  .footer img { height: 76px; margin-bottom: 16px; }
  .about__stats { grid-template-columns: repeat(2, 1fr); }
  .astat {
    border-left: 0;
    border-top: 1px solid var(--line);
    padding: 30px 20px;
  }
  .astat:first-child { border-top: 0; }
  .hero__cta { flex-direction: column; align-items: stretch; }
  .footer__bottom { justify-content: center; text-align: center; }
}

/* Footer: brand column wider than the link columns, matching the reference.
   The shared .footer__grid is a 4-up of equal columns. */
.footer__grid {
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.2fr);
  gap: clamp(26px, 3vw, 56px);
  align-items: start;
}
/* Brand column: the identity block, deliberately NOT on the label baseline.
   The other three columns open with a label, so their headings share a top
   edge and the eye reads a row. This column opens with the logo instead, and
   forcing "Follow Us" up to that same line would mean pushing the newsletter
   below the social row, which buries the one input in the footer.

   So the decision is: three content columns share the label baseline, and the
   brand column is masthead. "Follow Us" is demoted to a quiet caption on its
   social row rather than dressed as a peer column heading, so it no longer
   reads as a fourth heading that failed to line up. */
.fcol--brand p:not(.footer__label) {
  max-width: 34ch;
  margin: 0;
  line-height: 1.7;
}

/* Inline newsletter field */
.fsub {
  display: flex;
  align-items: stretch;
  /* Was 18px, which sat the field tight under the copy. The field is a
     control, so it gets a clear step away from the sentence introducing it. */
  margin: 22px 0 0;
  max-width: 300px;
  background: rgba(10, 10, 10, 0.34);
  border: 1px solid rgba(254, 254, 254, 0.34);
}
.fsub input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  padding: 13px 14px;
  font-family: var(--sans);
  font-size: var(--fs-body);
  color: #FEFEFE;
}
/* Was 0.5 white, which measured 1.80:1 over the painted footer backdrop.
   Placeholder text still has to be readable, so it is lifted to clear AA. */
.fsub input::placeholder { color: rgba(254, 254, 254, 0.86); }
.fsub input:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
.fsub button {
  flex: none;
  width: 48px;
  border: 0;
  background: transparent;
  /* --gold measured 3.60:1 over the painted backdrop. This icon is the only
     affordance on the field, so it takes the paler amber to clear AA. */
  color: var(--gold-pale);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: color 0.25s var(--ease);
}
.fsub button svg { width: 20px; height: 20px; }
.fsub button:hover { color: var(--gold-pale); }

/* "Follow Us" is a caption for the icon row, not a column heading. It keeps
   the label's size and tracking so it still belongs to the set, but drops to
   the muted body colour so it stops competing with the three real headings it
   was never going to line up with. */
.footer__label--follow {
  color: rgba(254, 254, 254, 0.90);
  margin: 30px 0 14px;
}

/* Brand column stack: logo, copy, field, caption, socials. Each step is set
   on the element that opens it so the rhythm survives any one being absent. */
.fcol--brand img { margin-bottom: 20px; }

/* Address column: two labelled office blocks, not one run-on list ---------
   The column used to be heading, address, heading, address with only a 24px
   nudge on the second heading. At 16px body that read as stray text dropped
   into the middle of an address rather than the start of a second office, and
   it sat hard against the email line above it.

   Each office is now its own .faddr block: the label, the address, and a
   hairline rule that opens the next block. The rule is what makes the second
   heading read as a section start rather than a loose line, so the two offices
   are visibly peers instead of one being a footnote to the other. A fifth
   grid column was the other candidate, but it would squeeze the two link
   columns and break the 2-up phone pairing for no gain. */
.faddr + .faddr {
  margin-top: 26px;
  padding-top: 24px;
  border-top: 1px solid rgba(254, 254, 254, 0.18);
}
/* The office name is a sub-heading under the column label, so it takes the
   same tracking and case but a step down in weight and a muted colour. That
   keeps the single column heading as the only thing on the baseline row, and
   stops the second office reading as a stray line of body copy. */
.footer__sublabel {
  margin: 0 0 10px;
  color: rgba(254, 254, 254, 0.92);
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.fcol address { margin: 0; }
/* The phone/email run used to be pushed down by a pair of <br>s, so its gap
   was whatever line-height happened to be and the two offices did not match.
   A real block with a set margin gives every address the same step. */
.faddr__contact {
  display: block;
  margin-top: 14px;
}
/* Each contact line pairs its icon with the link. Grid rather than inline so a
   wrapped address never slides under its own icon: the text column keeps its
   own edge. The icon reuses the contact form's phone and envelope paths, so
   the footer speaks the same icon vocabulary as the rest of the site. */
.faddr__row {
  display: grid;
  grid-template-columns: 17px minmax(0, 1fr);
  align-items: start;
  gap: 10px;
  margin-top: 8px;
}
.faddr__row:first-child { margin-top: 0; }
.faddr__ico {
  width: 15px;
  height: 15px;
  /* Optical centring on the first line of text rather than the box. */
  margin-top: 4px;
  color: var(--gold-pale);
  flex: none;
}

@media (max-width: 900px) {
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fcol--brand { grid-column: 1 / -1; }
  .fsub { max-width: none; }
}
@media (max-width: 620px) {
  .footer__grid { grid-template-columns: 1fr; }
}

/* Footer link accordions (mobile only) --------------------------------------
   Explore and Discover carry 9 and 7 items, and stacked on a phone they were
   the bulk of a 1648px footer. Below 700px each label becomes a real <button>
   that folds its own list away; the two folded columns then sit side by side
   as a 2-up, so the address column moves up the page instead of starting past
   a screenful of links. No item is removed, every link stays in the DOM.

   Desktop is untouched: the button is styled back to a plain label, the panel
   has no max-height, and the toggle script never binds above 700px. The panel
   animates on grid-template-rows rather than max-height so the closed state is
   an exact 0 regardless of how many items a column holds.
   -------------------------------------------------------------------------- */
.footer__toggle {
  /* Desktop: a button that reads exactly as the old <h4> text did. */
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: left;
  cursor: default;
}
.footer__toggle-icon { display: none; }

@media (max-width: 700px) {
  /* Folded Explore and Discover pair up; brand and Reservations stay full. */
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px 18px;
  }
  .footer__grid > .fcol--brand { grid-column: 1 / -1; }
  .footer__grid > .fcol--wide { grid-column: 1 / -1; }

  .fcol--acc .footer__label { margin-bottom: 0; }
  .footer__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    /* A comfortable tap target without inflating the folded column. */
    min-height: 44px;
    padding: 4px 0;
    cursor: pointer;
  }
  .footer__toggle-icon {
    display: block;
    flex: none;
    width: 10px;
    height: 10px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform 0.25s var(--ease);
  }
  .footer__toggle[aria-expanded="true"] .footer__toggle-icon {
    transform: translateY(2px) rotate(-135deg);
  }
  .footer__toggle:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 3px;
  }

  /* Both lists are open by default on phones, as asked. Open is the resting
     state rather than something JS switches on, so first paint is already
     correct: no collapsed flash and no opening animation on load. */
  .footer__panel {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 0.3s var(--ease);
  }
  .footer__panel > ul {
    overflow: hidden;
    min-height: 0;
    padding-top: 12px;
  }
  /* The button sits inside the <h4>, so the panel is the h4's sibling and not
     the button's. Match on the column instead, and carry a JS-set class as a
     fallback for engines without :has(). Only the collapsed state needs a
     rule now, since open is the default. */
  .fcol--acc:has(.footer__toggle[aria-expanded="false"]) > .footer__panel,
  .fcol--acc.is-closed > .footer__panel {
    grid-template-rows: 0fr;
  }
  /* The closed state must stay a true 0, padding included. */
  .fcol--acc:has(.footer__toggle[aria-expanded="false"]) > .footer__panel > ul,
  .fcol--acc.is-closed > .footer__panel > ul {
    padding-top: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .footer__panel,
  .footer__toggle-icon { transition: none; }
}


/* Contact form ------------------------------------------------------------ */

.cform {
  /* Anchor target for the "Contact Us" and "Enquire about a date" links.
     The offset keeps the heading clear of the fixed header on landing. */
  scroll-margin-top: calc(var(--header-h) + 24px);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 28px 26px 26px;
}
.cform__title {
  font-family: var(--serif);
  font-size: var(--fs-h3);
  line-height: 1.25;
  color: var(--ink);
  /* The heading sits straight on top of the first field, so it owns the whole
     gap that the supporting line used to carry. */
  margin: 0 0 22px;
  font-weight: 500;
}
.cform__form { display: grid; gap: 16px; }
/* The textarea needs a taller box than the 44px .field__wrap the booking bar
   uses, so the height is released here only for the message field. */
.cform__wrap--msg { height: auto; align-items: stretch; }
.cform__wrap--msg > textarea {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--ink);
  /* Same 37px left gutter as the booking bar's inputs, clearing the icon. */
  padding: 12px 12px 12px 37px;
  resize: vertical;
  min-height: 104px;
}
.cform__wrap--msg > textarea:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}
/* The message icon sits at the top of the tall box, not centred on it. */
.cform__wrap--msg > .field__ico { top: 14px; transform: none; }
.cform__send {
  justify-self: start;
  margin-top: 2px;
}
.cform { padding: 22px 18px 20px; }

/* ==========================================================================
   RESPONSIVE SAFETY NET
   Applies to everything on the site, including sections added later, so new
   work is fluid by default rather than needing a fix afterwards. Each rule
   below exists because the pattern above it has already caused a real bug on
   this build.
   ========================================================================== */

/* Nothing may push the page sideways. A single over-wide child used to force
   a horizontal scrollbar across the whole document. */
html, body { max-width: 100%; overflow-x: hidden; }

/* Media scales down by default. An <img> or <video> without this holds its
   intrinsic width and overflows its column on small screens. */
img, video, iframe, svg, canvas { max-width: 100%; }
img, video { height: auto; }

/* Grid and flex children refuse to shrink below their content unless told.
   This is the single most common cause of overflow in a card grid. */
[class*="grid"] > *, [class*="track"] > *, [class*="layout"] > * { min-width: 0; }

/* Long words, URLs and email addresses break rather than widening a column. */
p, li, td, th, dd, address, blockquote, figcaption { overflow-wrap: anywhere; }

/* Tables scroll inside their own box instead of stretching the page. */
table { max-width: 100%; }

/* Touch targets stay reachable. Anything smaller than this is hard to hit
   accurately on a phone. */
@media (pointer: coarse) {
  a, button, [role="button"], input[type="submit"] { min-height: 32px; }
}

/* At very high browser zoom the viewport is narrow but the device is not a
   phone. Content must reflow rather than clip: WCAG 1.4.10 requires no loss
   of content or function down to a 320px equivalent width. */
@media (max-width: 400px) {
  :root { --gutter: 16px; }
}

/* ===== Blog ================================================================
   Summary grid plus the article layout. Sits on the same tokens and section
   rhythm as the rest of the site; nothing here overrides existing rules.
   ========================================================================== */
.blog-hero {
  position: relative;
  /* 70% of the viewport, matching the other inner-page banners. */
  min-height: 70vh;
  min-height: 70svh;
  display: grid;
  align-content: center;
  padding: calc(var(--header-h) + 66px) 0 56px;
  background: var(--panda-ink);
  color: #FEFEFE;
  text-align: center;
}
.blog-hero h1 { margin: 0 0 12px; color: #FEFEFE; }
.blog-hero p { margin: 0 auto; max-width: 56ch; color: rgba(254, 254, 254, 0.82); }
.blog-hero .eyebrow { color: var(--gold); }

/* Category filter. Tabs are built from the posts' own category values. */
.blog-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 0 0 38px;
  padding: 0;
  list-style: none;
}
.blog-tab {
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--body);
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 10px 16px;
  cursor: pointer;
  transition: background 0.3s var(--ease), color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.blog-tab:hover { border-color: var(--gold); color: var(--ink); }
.blog-tab.is-on { background: var(--panda-ink); border-color: var(--panda-ink); color: #FEFEFE; }
.blog-tab:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px;
}
.blog-grid > * { min-width: 0; }
@media (max-width: 1000px) { .blog-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .blog-grid { grid-template-columns: 1fr; gap: 24px; } }

.post[hidden] { display: none; }
.post {
  display: flex;
  flex-direction: column;
  background: #FEFEFE;
  border: 1px solid var(--line);
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.post:hover { transform: translateY(-4px); box-shadow: 0 18px 40px rgba(10, 10, 10, 0.12); }
.post__media { overflow: hidden; aspect-ratio: 3 / 2; }
.post__media img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 0.6s var(--ease); }
.post:hover .post__media img { transform: scale(1.05); }
.post__body { padding: 22px 22px 24px; display: flex; flex-direction: column; flex: 1; }
.post__cat {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-ink, #7A5A16);
  margin: 0 0 10px;
}
.post__body h3 { margin: 0 0 10px; font-size: 21px; line-height: 1.3; }
.post__body h3 a { color: inherit; text-decoration: none; }
.post__body h3 a:hover { color: var(--gold-ink, #7A5A16); }
.post__excerpt { margin: 0 0 16px; font-size: var(--fs-body); line-height: 1.6; color: var(--body); }
.post__meta {
  margin: auto 0 0;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--body);
  display: flex;
  align-items: center;
  gap: 8px;
}
.post__meta i { width: 3px; height: 3px; border-radius: 50%; background: var(--line); flex: none; }

/* Lead post: full width, image and copy side by side. */
.post--lead { grid-column: 1 / -1; flex-direction: row; }
.post--lead .post__media { flex: 0 0 54%; aspect-ratio: auto; }
.post--lead .post__body { padding: 40px; justify-content: center; }
.post--lead .post__body h3 { font-size: clamp(26px, 2.4vw, 34px); }
.post--lead .post__excerpt { font-size: var(--fs-lead); max-width: 46ch; }
@media (max-width: 900px) {
  .post--lead { flex-direction: column; }
  .post--lead .post__media { flex: none; aspect-ratio: 3 / 2; }
  .post--lead .post__body { padding: 26px 22px 28px; }
}

.blog-empty { text-align: center; padding: 40px 0; color: var(--body); }
.blog-empty[hidden] { display: none; }

/* ----- Article page ------------------------------------------------------- */
.article { max-width: 760px; margin: 0 auto; }
.article__meta {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--body);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 9px;
  margin: 0 0 30px;
}
.article__meta i { width: 3px; height: 3px; border-radius: 50%; background: var(--line); flex: none; }
.article p { font-size: var(--fs-body); line-height: 1.75; margin: 0 0 22px; }
.article h2 { margin: 40px 0 16px; }
.article ul { margin: 0 0 24px; padding-left: 22px; }
.article li { font-size: var(--fs-body); line-height: 1.7; margin-bottom: 9px; }
.article__lead { font-size: 19px; line-height: 1.7; color: var(--ink); }
.article blockquote {
  margin: 34px 0;
  padding: 4px 0 4px 24px;
  border-left: 3px solid var(--gold);
  font-family: var(--serif);
  font-size: 22px;
  line-height: 1.5;
  color: var(--ink);
}
.article figure { margin: 34px 0; }
.article figure img { width: 100%; height: auto; display: block; }
.article figcaption {
  margin-top: 10px;
  font-family: var(--sans);
  font-size: 13.5px;
  color: var(--body);
}
@media (max-width: 640px) {
  .article p, .article li { font-size: var(--fs-body); }
  .article__lead { font-size: 17.5px; }
  .article blockquote { font-size: 19px; padding-left: 18px; }
}

/* Key takeaways callout and the article-page hero, which carries the article's
   own artwork from the client image library. */
.article__takeaways {
  margin: 30px 0 34px;
  padding: 24px 26px 22px;
  background: var(--cream);
  border-left: 3px solid var(--gold);
}
.article__takeaways h2 { margin: 0 0 12px; font-size: 21px; }
.article__takeaways ul { margin: 0; padding-left: 20px; }
.article__takeaways li { font-size: var(--fs-body); line-height: 1.6; margin-bottom: 7px; }
/* Article hero: the artwork carries its own title, so it is shown as a plain
   image at its natural ratio rather than as a background with text over it. */
.blog-hero--art {
  padding: 0;
  background: var(--panda-ink);
  /* The article title is baked INTO this artwork, so the frame can never be
     cropped: forcing it to a fixed 70% height chopped the headline in half.
     The image therefore keeps its own 2:1 ratio and the section takes its
     height from it. The nav sits over the picture, as on every other page. */
  min-height: 0;
}
.blog-hero--art img {
  width: 100%;
  /* Show the lower 70% of the frame: the top 30% is sky and empty space, so
     trimming it lifts the subject and the baked-in title up into view. The
     aspect-ratio sets the box and object-position anchors the crop to the
     bottom, so nothing is lost from the part that carries the headline. */
  aspect-ratio: 1800 / 630;
  height: auto;
  object-fit: cover;
  object-position: center bottom;
  display: block;
}
/* FAQ accordions inside an article sit on a white page, so they need the
   shared border treatment rather than the section styling. */
.article .faq__item { border-bottom: 1px solid var(--line); }
.article .faq__item summary { padding: 18px 0; }
@media (max-width: 640px) {
  .article__takeaways { padding: 20px 20px 18px; }
  .article__takeaways li { font-size: var(--fs-small); }
}

/* Breadcrumb bar, sitting below the banner on the page ground rather than over
   the photograph. Previously only in the room pages' local <style>, so blog
   pages rendered it as raw bullets. Shared here so every page gets it. */
.crumbbar {
  border-bottom: 1px solid var(--line);
  padding: 14px 0;
}
.crumbbar .crumbs {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  justify-content: flex-start;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--body);
}
.crumbbar .crumbs a { color: var(--body); text-decoration: none; }
.crumbbar .crumbs a:hover { color: var(--gold); }
.crumbbar .crumbs li[aria-hidden] { color: var(--line); }
/* Same reason as .prop__area: brand amber on white is 1.98:1. */
.crumbbar .crumbs [aria-current] { color: var(--gold-ink); }

/* Navbar typography. This lived only in each page's inline <style>, so the
   blog pages, which have no such block, rendered the menu in title case with
   half the tracking while every other page was uppercase. Shared here so no
   page can drift again. Scoped to direct children: dropdown hotel names stay
   Title Case because they are proper nouns. */
.nav--left > li > a,
.nav--right > li > a {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.nav .drop a,
.header.is-stuck .nav .drop a,
.header .nav .drop a { font-size: var(--fs-nav); color: var(--ink); }
.nav .drop a:hover,
.header.is-stuck .nav .drop a:hover,
.header .nav .drop a:hover { color: var(--gold); background: transparent; }

/* Article headline. Sits below the breadcrumb, which is the usual order for a
   blog article: banner, then where you are, then what you are reading. It now
   lives INSIDE the content column so the rail can start level with it rather
   than 312px further down, which left the whole top right of the page empty. */
.article__title {
  margin: 0 0 22px;
  font-size: clamp(27px, 2.9vw, 40px);
  line-height: 1.18;
}
@media (max-width: 640px) {
  .article__title { margin-bottom: 18px; }
}

/* Article page: body on the left, a rail of latest posts and categories on
   the right. Collapses to a single column below the tablet breakpoint, where
   the rail follows the article rather than sitting beside it. */
.blog-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 56px;
  align-items: start;
}
.blog-layout > .article { max-width: none; margin: 0; }

.blog-rail { position: sticky; top: calc(var(--header-h) + 20px); }
.blog-rail__title {
  margin: 0 0 16px;
  font-size: 18px;
  letter-spacing: 0.02em;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--gold);
}
.blog-rail__title + * { margin-bottom: 34px; }

.mini-list, .cat-list { list-style: none; margin: 0 0 34px; padding: 0; }

.mini {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  gap: 13px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.mini:last-child { border-bottom: 0; }
.mini__img { display: block; overflow: hidden; }
.mini__img img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  transition: transform 0.5s var(--ease);
}
.mini:hover .mini__img img { transform: scale(1.06); }
.mini__body a {
  display: block;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.35;
  color: var(--ink);
  text-decoration: none;
}
.mini__body a:hover { color: var(--gold-ink); }
.mini__body time {
  display: block;
  margin-top: 5px;
  font-family: var(--sans);
  font-size: 12.5px;
  color: var(--body);
}

.cat-list li { border-bottom: 1px solid var(--line); }
.cat-list li:last-child { border-bottom: 0; }
.cat-list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 0;
  font-family: var(--sans);
  font-size: 14.5px;
  color: var(--ink);
  text-decoration: none;
  transition: color 0.25s var(--ease);
}
.cat-list a:hover { color: var(--gold-ink); }
.cat-list span {
  font-size: 12.5px;
  color: var(--body);
  background: var(--cream);
  border: 1px solid var(--line);
  min-width: 26px;
  text-align: center;
  padding: 2px 6px;
}

/* Inline booking prompt, dropped into an article where the copy turns to
   booking. Content is untouched; this sits between blocks. */
.inline-book {
  margin: 34px 0;
  padding: 22px 24px;
  background: var(--cream);
  border-left: 3px solid var(--gold);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.inline-book p {
  margin: 0;
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.4;
  color: var(--ink);
}
.inline-book .btn { flex: none; }

@media (max-width: 1000px) {
  .blog-layout { grid-template-columns: 1fr; gap: 42px; }
  .blog-rail { position: static; }
  .blog-layout > .article { max-width: 760px; margin: 0 auto; }
  .blog-rail { max-width: 760px; margin: 0 auto; width: 100%; }
}
@media (max-width: 560px) {
  .inline-book { flex-direction: column; align-items: flex-start; }
  .inline-book .btn { width: 100%; text-align: center; justify-content: center; }
}

/* Category groups on the blog summary page. */
.cat-block { margin-bottom: 56px; }
.cat-block:last-child { margin-bottom: 0; }
.cat-block .section-head { margin-bottom: 26px; }
.cat-block .section-head h2 { font-size: clamp(24px, 2.2vw, 32px); }
/* Anchored from the article rail, so leave room under the fixed header. */
.cat-block { scroll-margin-top: calc(var(--header-h) + 20px); }

/* Blog summary: photo banner, featured post, topic chips, one grid.
   Per-category stacked sections were removed because most topics hold a
   single post, so the page read as a run of near-empty sections. */
.blog-hero--photo {
  background-size: cover;
  background-position: center;
}

/* The featured card is the newest post, shown wide on its own. */
.blog-grid--feature { grid-template-columns: 1fr; }

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 32px;
}
.chip {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line);
  background: #FEFEFE;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 9px 14px;
  cursor: pointer;
  transition: background 0.25s var(--ease), border-color 0.25s var(--ease),
              color 0.25s var(--ease);
}
.chip span {
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--body);
  background: var(--cream);
  border: 1px solid var(--line);
  padding: 1px 6px;
  transition: inherit;
}
.chip:hover { border-color: var(--gold); }
.chip.is-on { background: var(--panda-ink); border-color: var(--panda-ink); color: #FEFEFE; }
.chip.is-on span { background: rgba(254, 254, 254, 0.16); border-color: transparent; color: #FEFEFE; }
.chip:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* Topic label on each card, so a post's subject is clear inside the mixed
   grid without needing a section heading above it. */
.post__cat {
  margin: 0 0 9px;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--gold-ink);
}

@media (max-width: 560px) {
  .chip { font-size: 12px; padding: 8px 11px; }
}

/* ===== Navbar overflow menu =================================================
   The bar carries five links plus Book Now; anything else lives behind the
   burger, which now sits between the right-hand links and Book Now instead of
   at the far left. On desktop the burger opens only the overflow list; below
   the collapse breakpoint it keeps its existing job of opening the whole nav.
   ========================================================================== */
/* The burger now sits inside .header__right, next to Book Now, so it is
   selected by that parent rather than by .header__inner. Keying it to the old
   parent silently left it display:none on every page. */
.header__right > .burger {
  display: grid;
  place-items: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  flex: none;
}
/* The bars were sized only inside the mobile block, so on desktop they
   computed to width:0 and the button rendered as an invisible gap. */
.header__right > .burger span {
  width: 22px;
  height: 2px;
  display: block;
  background: currentColor;
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
/* Over the hero the header is transparent with light text; once stuck it goes
   solid and the bars must follow the dark link colour. */
.header:not(.is-stuck) .header__right > .burger { color: #FEFEFE; }
.header.is-stuck .header__right > .burger { color: var(--ink); }
/* The overflow panel is always a white card, so its links stay dark in both
   header states rather than inheriting the transparent-header white. */
.header .nav--more a,
.header:not(.is-stuck) .nav--more a { color: var(--ink); }
.header .nav--more a:hover { color: var(--gold-ink); }
.header__right { align-items: center; }

/* Overflow list: hidden until the burger opens it.
   A grid 0fr collapse was tried first and is wrong here: grid-template-rows
   sizes only the FIRST row, so a menu with two items never collapsed past its
   second child. A clipped max-height is exact regardless of item count. */
.nav--more {
  position: absolute;
  top: calc(100% - 8px);
  right: var(--gutter);
  z-index: 60;
  display: block;
  min-width: 210px;
  margin: 0;
  padding: 0;
  background: #FEFEFE;
  border-top: 0 solid var(--gold);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  transition: max-height 0.35s var(--ease), opacity 0.25s var(--ease),
              visibility 0.25s;
}
.header.nav-more-open .nav--more {
  max-height: 60vh;
  overflow-y: auto;
  opacity: 1;
  visibility: visible;
  border-top-width: 3px;
  box-shadow: 0 18px 44px rgba(10, 10, 10, 0.2);
}
.nav--more li { list-style: none; }
.nav--more a {
  display: block;
  padding: 13px 20px;
  color: var(--ink);
  white-space: nowrap;
  border-bottom: 1px solid var(--line);
}
.nav--more li:last-child a { border-bottom: 0; }
.nav--more a:hover { color: var(--gold-ink); background: var(--cream); }

@media (prefers-reduced-motion: reduce) {
  .nav--more { transition: none; }
}

/* Below the collapse breakpoint the burger reverts to opening the full nav,
   and the overflow list simply joins that stacked panel. */
@media (max-width: 1023px) {
  .nav--more {
    position: static;
    grid-template-rows: 1fr;
    opacity: 1;
    visibility: visible;
    min-width: 0;
    border-top: 0;
    box-shadow: none;
    background: transparent;
    /* The base rule clips this list with max-height:0 and only releases it via
       .header.nav-more-open, which the DESKTOP burger sets. Below the collapse
       breakpoint the burger opens #nav-wrap instead and never sets that class,
       so without these two resets every overflow item stayed clipped to zero
       height and was unreachable on mobile. */
    max-height: none;
    overflow: visible;
  }
  .nav--more a { padding: 15px 28px; }
  /* In the stacked panel the overflow list is a continuation of the bar
     rather than a dropdown, so it takes the same caps treatment the bar
     links get; without this the panel reads half caps, half sentence case. */
  .nav--more > li > a { text-transform: uppercase; letter-spacing: 0.08em; }
}

/* The header is a 1fr auto 1fr grid. Once the burger joined the right-hand
   group, that column ran out of room and "Book Now" wrapped onto two lines,
   making the button 70px tall against a 44px bar. The label must never break;
   the group shrinks its gap instead. */
.header__right .btn { white-space: nowrap; flex: none; }
.header__right { gap: 14px; flex-wrap: nowrap; }
.header__right .nav--right { flex-wrap: nowrap; }
@media (max-width: 1300px) {
  .header__right { gap: 10px; }
  .header__right .btn { padding: 12px 18px; }
}

/* Header crowding between the collapse point and full width.
   At 1093 CSS px (125% zoom on a 1366 laptop) the five links fit the grid on
   paper but the centre logo sits on top of them, because `1fr auto 1fr` lets
   the side columns run right up to the brand. A real gap plus a tighter type
   scale in that band keeps them apart without collapsing the nav early. */
@media (min-width: 1024px) and (max-width: 1300px) {
  .header__inner { gap: 22px; }
  .nav--left, .nav--right { gap: 14px; }
  .nav--left > li > a,
  .nav--right > li > a { font-size: 14px; letter-spacing: 0.05em; }
  .header__right { gap: 10px; }
  .header__right .btn { padding: 11px 16px; font-size: 13px; }
}
@media (min-width: 1024px) and (max-width: 1140px) {
  .nav--left > li > a,
  .nav--right > li > a { font-size: 13px; letter-spacing: 0.03em; }
  .header__inner { gap: 16px; }
}

/* ===== Reading bands over the ambient background ===========================
   Text over the site's mountain footage was hard to read, but not because of
   contrast: it measured 6.63:1 and passed. The problem is TEXTURE. The footage
   varies about 0.22 in luminance under a line of type, and that variation
   competes with the letterforms however dark the text is. Measured across the
   site, 11 sections sat above 0.015 stdev, the point where the competition
   starts to show.

   A white card behind the copy fixes it but reads as a separate panel dropped
   into the section. Instead the background is calmed across the whole section
   band, edge to edge, with a soft vertical fade. There is no visible boundary,
   so the section still reads as one thing: the picture goes quieter where the
   words are and returns at the seams between sections.

   This is attached to the same selector that makes a section transparent, so
   any section sitting on the ambient layer gets it automatically and nothing
   has to be remembered when a new one is added.
   ========================================================================== */
.section:not(.section--cream):not(.offers),
.booking,
.newsletter {
  position: relative;
  isolation: isolate;
}
.section:not(.section--cream):not(.offers)::before,
.newsletter::before {
  content: "";
  position: absolute;
  /* Bleeds past the section edges so the fade never lines up with a boundary,
     which is what would make it read as a panel. */
  inset: -8% calc(50% - 50vw);
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(252, 251, 249, 0) 0%,
    rgba(252, 251, 249, 0.73) 14%,
    rgba(252, 251, 249, 0.80) 50%,
    rgba(252, 251, 249, 0.73) 86%,
    rgba(252, 251, 249, 0) 100%);
}
/* The hero is the one transparent section that must NOT be calmed: its whole
   job is to show the footage at full strength. */
.hero::before { content: none; }

/* Narrow screens need a slightly denser band. The stops are percentages, so on
   a short mobile section the ramp spends proportionally less of its height at
   full strength, and the same values that measure clean on desktop let the
   footage back through behind body copy. Measured: 0.78/0.85 gives stdev up to
   0.026 at 390px against a 0.015 threshold; these values bring it back under
   without touching the desktop look. */
@media (max-width: 768px) {
  .section:not(.section--cream):not(.offers)::before,
  .newsletter::before {
    background: linear-gradient(180deg,
      rgba(252, 251, 249, 0) 0%,
      rgba(252, 251, 249, 0.81) 10%,
      rgba(252, 251, 249, 0.85) 50%,
      rgba(252, 251, 249, 0.81) 90%,
      rgba(252, 251, 249, 0) 100%);
  }
}

/* Sitemap link in the footer bottom bar, opposite the Simplotel credit.
   It sits on the same line as the copyright rather than wrapping below it. */
.footer__legal-links { margin: 0; }
.footer__sitemap {
  font-family: var(--sans);
  font-size: var(--fs-small);
  color: #FEFEFE;
  text-decoration: none;
  border-bottom: 1px solid rgba(254, 254, 254, 0.42);
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease);
}
.footer__sitemap:hover,
.footer__sitemap:focus-visible { color: var(--gold-pale); border-bottom-color: var(--gold); }

/* Room card rates are provisional until the live rate feed is connected.
   Every price carries data-rate-api so the feed can find and replace them in
   one pass: "from" for a known indicative figure, "request" where the client
   has not published a rate. */
.prop__price-pre {
  font-family: var(--sans);
  font-size: var(--fs-small);
  color: var(--body);
  margin-right: 6px;
  text-transform: lowercase;
  letter-spacing: 0.02em;
}
.prop__price[data-rate-api="request"] b {
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--body);
}


/* ==========================================================================
   Our Hotels dropdown: grouped panel
   --------------------------------------------------------------------------
   These rules previously lived only in index.html's inline block, so the
   29 pages that did not carry a copy rendered the panel as a plain bulleted
   list. The markup is on all 73 pages, so the styling belongs here.
   ========================================================================== */
<style>
/* ===== Our Hotels dropdown, grouped by city ================================
   Added inline (not in style.css) because that file is being edited
   elsewhere. Covers three things the shared rules do not:
   1. The panel is now grouped (city label + hotels), so it needs its own
      internal layout on top of the shared .drop chrome.
   2. Desktop: 9 hotels plus 4 labels is tall, so the panel is capped to the
      space below the header and scrolls rather than running off screen.
   3. Mobile: the shared rule capped the open panel at a fixed height, which
      clipped the list once it grew. It now animates open with the house
      grid-template-rows technique and sizes to its content.
   ========================================================================== */
/* No padding here: on mobile this element is the 0fr grid child, and its own
   padding would set a min-content floor that keeps the collapsed panel
   visible. Desktop spacing comes from the shared .drop padding. */
.drop__inner {
  padding: 0;
}
.drop__all {
  list-style: none;
  margin: 0;
  padding: 0;
}
.drop__group {
  list-style: none;
  margin: 0;
  padding: 0;
}
.drop__group ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Grouping label, not a link. Same treatment as .footer__label. */
.drop__city {
  margin: 0;
  padding: 12px 24px 4px;
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--panda);
  opacity: 0.62;
}
.drop__group + .drop__group .drop__city {
  padding-top: 14px;
}
.drop__area {
  display: block;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.04em;
  color: var(--body);
  opacity: 0.7;
}
/* City labels are grouping labels, so they take the same uppercase treatment.
   The hotel names below stay Title Case: they are proper nouns and read badly
   in caps at this length. */
.drop__city {
  text-transform: uppercase;
}
.drop__group ul a {
  text-transform: none;
}

@media (max-width: 1023px) {
  /* Padding goes on a descendant, never on the 0fr grid child itself. */
  .has-drop.is-open .drop__all {
    padding-top: 6px;
  }
  .has-drop.is-open .drop__group:last-child {
    padding-bottom: 10px;
  }
  .drop__city {
    padding-left: 44px;
  }
  /* City labels were inheriting the 0.62 opacity set at the top of this block,
     which measured 4.79:1 on the cream panel and read as a disabled item
     rather than as a grouping heading. Full opacity in panda black is 15.9:1
     and clearly reads as a heading.

     They also sat at the same weight and the same left edge as the hotel names
     below them, so the panel read as one flat list with no visible split
     between a city and its hotels. The city is now a bold, tracked, amber-ruled
     band and the hotel names are indented under it, so the hierarchy is obvious
     at a glance. */
  .drop__city {
    opacity: 1;
    color: var(--panda);
    font-weight: 700;
    padding: 16px 24px 8px 20px;
    margin: 0 0 2px;
    border-bottom: 1px solid var(--line);
  }
  /* The amber tick marks the start of a city group. */
  .drop__city::before {
    content: '';
    display: inline-block;
    width: 14px;
    height: 2px;
    margin-right: 9px;
    vertical-align: middle;
    background: var(--gold);
  }
  /* Hotel names step in from their city heading, which is what makes the
     grouping readable without needing a box or a background change. */
  .drop__group ul a {
    padding-left: 56px;
  }
  .drop__group + .drop__group .drop__city {
    padding-top: 20px;
  }
  /* The area note under a hotel name was 0.7 opacity, measuring 3.80:1, below
     the 4.5:1 minimum for body-size text. Ink at full opacity clears it. */
  .drop__area {
    opacity: 1;
    color: var(--ink);
  }
}

@media (min-width: 1024px) {
  .drop__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0 40px;
    padding: 6px 26px 20px;
  }
  .drop__all {
    flex: 0 0 100%;
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--line);
  }
  /* Two real columns. CSS columns let the four groups flow into two tracks and
     break between groups only, so each takes just the height it needs and
     nothing is forced to a shared row height. `flex: 0 0 100%` with a left
     margin was tried first and blew the panel out to 1697px wide. */
  .drop__inner {
    display: block;
    padding: 6px 26px 20px;
  }
  .drop__cols {
    column-count: 2;
    column-gap: 44px;
  }
  .drop__group {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    display: block;
  }
  .drop__group + .drop__group {
    padding-top: 18px;
  }
  .drop__city {
    padding: 0 0 6px;
  }
  .drop__group:nth-of-type(3) .drop__city,
  .drop__group:nth-of-type(4) .drop__city {
    padding-top: 18px;
  }
  /* The shared sheet sets link colour via `.header:not(.is-stuck) .nav .drop a`,
     so the override has to carry equal specificity to win. City labels were at
     0.62 opacity, which read as disabled rather than as a heading. */
  .drop__city {
    opacity: 1;
    color: var(--gold);
    font-weight: 500;
  }
}

/* Link sizing inside the dropdown panel. Moved here with the layout
   rules above: index.html overrode .drop a inline, so the panel
   measured 633x381 there and 729x465 on every other page. */
.drop a { white-space: normal; }
.drop__group ul a { text-transform: none; }

@media (min-width: 1024px) {
  .drop { max-height: calc(100vh - var(--header-h) - 40px); overflow-y: auto; }
  .drop { width: max-content; max-width: min(660px, 92vw); max-height: none; overflow: visible; }
  .drop a { white-space: normal; padding: 5px 0; line-height: 1.45; }
  .header:not(.is-stuck) .nav .drop a,
  .header.is-stuck .nav .drop a,
  .header .nav .drop a { font-size: var(--fs-nav); color: var(--ink); }
  .header:not(.is-stuck) .nav .drop a:hover,
  .header.is-stuck .nav .drop a:hover,
  .header .nav .drop a:hover { color: var(--gold); background: transparent; }
}

@media (max-width: 1023px) {
  .drop { display: grid; grid-template-rows: 0fr; max-height: none; overflow: hidden; /* The shared rule adds vertical padding, which would leave a visible strip when collapsed. Padding moves to the inner wrapper instead. */ padding: 0; border: 0; transition: grid-template-rows 0.4s var(--ease); }
  .drop > * { overflow: hidden; min-height: 0; }
  .has-drop.is-open .drop { grid-template-rows: 1fr; }
  .drop a { padding-left: 44px; }
  /* Hotel names step in from their city heading, which is what makes the
     grouping readable without needing a box or a background change. */
  .drop__group ul a { padding-left: 56px; }
}

@media (prefers-reduced-motion: reduce) {
  .drop { transition: none; }
}

/* ---- Phone country-code picker (assets/js/country-code.js) --------------
   The picker re-parents the tel input into .ccp-field, which puts it out of
   reach of the `.field__wrap > input` rules above (direct-child selector), so
   the input fell back to the browser default: 2px inset border, white ground,
   21px tall next to its 44px siblings. Re-apply the same silhouette to the
   nested input. Left padding is 0 here because .ccp-box already occupies the
   37px icon gutter. Only .ccp-field pages (the 11 wired forms) are affected. */
.field__wrap > .ccp-field { flex: 1 1 auto; min-width: 0; height: 100%; }
.field__wrap .ccp-field > input[type="tel"] {
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink);
  height: 100%;
  padding: 0 12px 0 0;
  cursor: text;
}
.field__wrap .ccp-field > input[type="tel"]::placeholder { color: #9A9AA4; }
.field__wrap .ccp-field > input[type="tel"]:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}
