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

/* ══ Dark theme, unreachable since 2026-08-07. Kept for one cleanup pass;
      delete when confident. ═══════════════════════════════════════════════
   D7 removed the toggle, and every page now carries class="light" on <body>
   unconditionally. That makes three things in this file dead but harmless,
   and they are left exactly as they were rather than gutted in the same pass
   as eight other changes:
     1. The colour values in :root below. body.light overrides every one of
        them, so none is ever painted. The non-colour values in the same
        block (fonts, gutter, nav-h, the gradient) ARE still live, which is
        why the block cannot simply be deleted.
     2. Every default declaration that has a body.light counterpart further
        down: .site-head's background, .nav-logo .logo-light, .ph, and the
        per-page equivalents. The body.light rule always wins.
     3. .theme-btn, marked again where it is defined.
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  --teal-deep:   #16707E;
  --teal:        #2AADA8;
  --teal-light:  #3DCFD0;

  --ink:    #0e1310;
  --ink-2:  #141a16;
  --ink-3:  #1a221c;
  --mist:   #e8ede4;
  --white:  #fafaf8;
  --dim:    rgba(232, 237, 228, 0.62);
  --hairline: rgba(232, 237, 228, 0.14);

  /* ── The .com gradient, now part of the palette ── */
  --grad-1: #3C88A4;
  --grad-2: #469B94;
  --grad-3: #53A871;
  --grad-4: #7DB359;
  --grad-5: #A3C455;
  --grad-6: #DFDF5B;
  --gradient-ocean-lime: linear-gradient(90deg, var(--grad-1), var(--grad-3), var(--grad-6));

  --serif:  'Cormorant Garamond', Georgia, serif;
  --sans:   'DM Sans', system-ui, sans-serif;
  --mono:   'Space Mono', monospace;

  --gutter: 48px;
  --nav-h:  76px;

  /* ── VERTICAL RHYTHM ────────────────────────────────────────────────────
     Added 2026-08-11. There were never two spacing systems on this site -
     every section has always been 104px top and bottom. What there were,
     were four pages quietly bending it in their own <style> blocks, and no
     way to see that from anywhere else. These two values and the four
     classes below §SECTIONS are the whole vocabulary now. A page that needs
     different spacing uses a class; it does not write a padding rule. */
  --space-section: 104px;   /* the default gap. Two sections = 208px apart. */
  --space-tight:    40px;   /* two sections that are really one idea */
}

/* ── LIGHT THEME ──────────────────────────────────────────────────────────
   Same layout, same gradient. Only the variables move. Never a second
   stylesheet.
   Palette audit (of-v2-shell.md §3): all five text/background pairs pass
   WCAG AA at these values as shipped — mist/ink 14.8:1, dim/ink 5.1:1,
   teal-light/ink-2 5.7:1, white/ink 17.1:1, book-btn text/grad-6 13.4:1.
   No hex values needed adjusting.                                         */
body.light {
  --ink:    #f6f4ee;
  --ink-2:  #ffffff;
  --ink-3:  #efece2;
  --mist:   #1a221c;
  --white:  #0e1310;
  --dim:    rgba(20, 26, 22, 0.64);
  --hairline: rgba(14, 19, 16, 0.16);
  --teal-light: #16707E;
}

html { scroll-behavior: smooth; scroll-padding-top: 88px; }

body {
  background: var(--ink);
  color: var(--mist);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  transition: background 0.35s ease, color 0.35s ease;
}

a { color: inherit; }

.wrap { width: 100%; max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter); }

/* ── SKIP LINK ── */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--teal); color: #0b1210;
  padding: 12px 20px; font-family: var(--mono); font-size: 0.75rem;
}
.skip:focus { left: 12px; top: 12px; }

/* ── HEADER / NAV ───────────────────────────────────────────────────────── */
.site-head {
  position: fixed; top: 0; left: 0; right: 0; z-index: 200;
  height: var(--nav-h);
  padding: 0 var(--gutter);
  display: flex; align-items: center; gap: 26px;
  background: rgba(14, 19, 16, 0.78);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hairline);
  transition: height 0.3s ease, background 0.3s ease;
}
body.light .site-head { background: rgba(246, 244, 238, 0.9); }
.site-head.scrolled { height: 56px; }
.site-head::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--gradient-ocean-lime); opacity: 0; transition: opacity 0.3s ease;
}
.site-head.scrolled::after { opacity: 1; }

/* Logo — Eli note 61: wordmark removed, logo enlarged, and the supplied brand
   files wired in. Two files by necessity: the colour version carries dark brown
   "ECOLODGE · COSTA RICA" type that vanishes on the dark site, and the white
   version vanishes on the light one. CSS swaps them with the theme. */
.nav-logo { display: flex; align-items: center; text-decoration: none; min-width: 0; }
.nav-logo img {
  height: 54px; width: auto; max-width: 240px; object-fit: contain; display: block;
  transition: height 0.3s ease, max-width 0.3s ease;
}
.site-head.scrolled .nav-logo img { height: 40px; }
.nav-logo .logo-light { display: none; }
body.light .nav-logo .logo-dark  { display: none; }
body.light .nav-logo .logo-light { display: block; }

.nav-menu { display: flex; align-items: center; gap: 22px; margin-left: auto; }
.nav-menu a {
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--dim); text-decoration: none;
  border-bottom: 1px solid transparent; padding-bottom: 2px;
  transition: color 0.2s, border-color 0.2s; white-space: nowrap;
}
.nav-menu a:hover, .nav-menu a:focus-visible { color: var(--white); border-color: var(--teal); }
.nav-menu a.current { color: var(--white); border-color: var(--teal); }

/* ── HEADER MOUNT ─────────────────────────────────────────────────────────
   The header is built by shell.js now, into <div data-shell="header"></div>.
   That div holds the header's exact height until the real header replaces
   it, so the page cannot jump. On a static site with no build step, this
   reservation is the whole price of having one nav instead of six. */
[data-shell="header"] { display: block; height: var(--nav-h); }

/* ── ABOUT DROPDOWN ───────────────────────────────────────────────────────
   About is a link and a menu at the same time: clicking goes to the About
   page, hovering opens the three items beneath it.

   Opened by :hover on the wrapper and by :focus-within, so it works from the
   keyboard too - tabbing to About opens the panel and the next Tab lands
   inside it. Without :focus-within the menu is reachable by mouse only. */
.nav-drop { position: relative; display: inline-flex; align-items: center; }
.nav-drop-top { display: inline-flex; align-items: center; gap: 5px; }
.nav-caret { width: 12px; height: 12px; transition: transform 0.2s ease; }
.nav-drop:hover .nav-caret, .nav-drop:focus-within .nav-caret { transform: rotate(180deg); }

.nav-drop-menu {
  position: absolute; top: 100%; left: 50%; transform: translate(-50%, 4px);
  display: flex; flex-direction: column; align-items: stretch;
  min-width: 210px; padding: 8px 0; margin-top: 10px;
  background: var(--ink-2); border: 1px solid var(--hairline); border-radius: 8px;
  box-shadow: 0 18px 40px rgba(8, 14, 12, 0.28);
  opacity: 0; pointer-events: none; transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 60;
}
body.light .nav-drop-menu { background: #f6f4ee; }
/* The gap between the link and the panel would close the menu as the pointer
   crosses it. This bridges it so the trip is uninterrupted. */
.nav-drop::after {
  content: ''; position: absolute; top: 100%; left: 0; right: 0; height: 14px;
}
.nav-drop:hover .nav-drop-menu,
.nav-drop:focus-within .nav-drop-menu {
  opacity: 1; pointer-events: auto; transform: translate(-50%, 0);
}
.nav-drop-menu a {
  padding: 10px 16px; border-bottom: 0; white-space: nowrap;
  font-size: 0.68rem;
}
.nav-drop-menu a:hover, .nav-drop-menu a:focus-visible {
  color: var(--white); border-color: transparent; background: rgba(42, 173, 168, 0.1);
}

.nav-actions { display: flex; align-items: center; gap: 12px; margin-left: 20px; flex-shrink: 0; }

/* Dark theme, unreachable since 2026-08-07. Kept for one cleanup pass;
   delete when confident. D7 removed the button this styles from all six
   pages, so nothing matches these rules any more. */
.theme-btn {
  background: none; border: 1px solid var(--hairline); color: var(--mist);
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  font-size: 0.9rem; line-height: 1; display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; transition: border-color 0.2s, color 0.2s;
}
.theme-btn:hover { border-color: var(--teal); color: var(--white); }

.book-btn {
  background: var(--gradient-ocean-lime); color: #0b1210 !important;
  font-family: var(--mono); font-weight: 700; font-size: 0.7rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 10px 20px; border-radius: 24px; text-decoration: none;
  white-space: nowrap; border: 0; display: inline-block;
}
.book-btn:hover { filter: brightness(1.08); }

.burger {
  display: none; background: none; border: 1px solid var(--hairline);
  color: var(--mist); width: 34px; height: 34px; border-radius: 50%;
  cursor: pointer; align-items: center; justify-content: center; flex-shrink: 0;
}
.burger svg { width: 16px; height: 16px; }

@media (max-width: 900px) {
  :root { --gutter: 22px; }
  .burger { display: flex; }
  .nav-menu {
    position: fixed; top: var(--nav-h); left: 0; right: 0;
    flex-direction: column; align-items: flex-start; gap: 0;
    background: var(--ink-2); border-bottom: 1px solid var(--hairline);
    padding: 8px 22px 20px; margin: 0;
    transform: translateY(-8px); opacity: 0; pointer-events: none;
    transition: opacity 0.22s ease, transform 0.22s ease;
  }
  .nav-menu.open { transform: none; opacity: 1; pointer-events: auto; }
  .nav-menu a { width: 100%; padding: 15px 0; font-size: 0.8rem; border-bottom: 1px solid var(--hairline); }
  .nav-actions { margin-left: auto; }

  /* The dropdown flattens on touch. There is no hover on a phone, so a menu
     that only opens on hover is a menu that never opens; and a tap-to-expand
     inside a panel that is itself a tap-to-expand is two doors to get to the
     blog. The three items just sit under About, indented. */
  .nav-drop { display: block; width: 100%; }
  .nav-drop-top { width: 100%; }
  .nav-caret { display: none; }
  .nav-drop::after { display: none; }
  .nav-drop-menu {
    position: static; transform: none; opacity: 1; pointer-events: auto;
    min-width: 0; margin: 0; padding: 0 0 0 18px;
    background: none; border: 0; border-radius: 0; box-shadow: none;
  }
  body.light .nav-drop-menu { background: none; }
  .nav-drop-menu a { padding: 13px 0; font-size: 0.74rem; }
}
@media (max-width: 480px) {
  /* Book now must stay visible at 375px, outside the hamburger. */
  .site-head { gap: 10px; }
  .nav-logo img { max-width: 168px; height: 38px; }
  .site-head.scrolled .nav-logo img { height: 30px; }
  .book-btn { padding: 9px 13px; font-size: 0.6rem; letter-spacing: 0.06em; }
  .nav-actions { gap: 8px; margin-left: auto; }
  .theme-btn, .burger { width: 31px; height: 31px; }
}

/* ── HERO ───────────────────────────────────────────────────────────────── */
.hero {
  position: relative; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 110px 0 48px; overflow: hidden;
}
.hero-video { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.hero-video iframe {
  position: absolute; top: 50%; left: 50%;
  width: 100vw; height: 56.25vw; min-width: 177.78vh; min-height: 100vh;
  transform: translate(-50%, -50%); border: 0;
}
.hero-still { position: absolute; inset: 0; z-index: 0; background: url('/images/mosaic-sunset.jpg') center/cover no-repeat; }
.hero-scrim {
  position: absolute; inset: 0; z-index: 1;
  /* 2026-11-02, Eli: lighter overall so the film reads brighter. The shade
     now sits mostly on the left, behind the words, and fades out across the
     picture; the bottom stays dark to blend into the page. Phones keep a
     little more overall, because there the words run the full width. */
  background:
    linear-gradient(90deg,
      rgba(9, 18, 22, 0.50) 0%, rgba(9, 18, 22, 0.30) 40%, rgba(9, 18, 22, 0) 70%),
    linear-gradient(180deg,
      rgba(14, 19, 16, 0.40) 0%, rgba(14, 19, 16, 0.08) 26%,
      rgba(14, 24, 28, 0.30) 62%, rgba(9, 18, 22, 0.88) 100%);
}
@media (max-width: 768px) {
  .hero-scrim {
    background: linear-gradient(180deg,
      rgba(9, 18, 22, 0.55) 0%, rgba(9, 18, 22, 0.38) 45%,
      rgba(14, 24, 28, 0.45) 70%, rgba(9, 18, 22, 0.90) 100%);
  }
}
/* A soft shadow behind the hero words keeps them legible over bright scenes. */
.hero h1, .hero .hero-sub, .hero .eyebrow, .hero .fork-label {
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 2px 18px rgba(0, 0, 0, 0.45);
}
/* Gradient words are painted through the text, so a text-shadow would show
   through them and dull the colour; they get a drop-shadow instead. */
.hero h1 .grad-text {
  text-shadow: none;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
}
.hero-inner { position: relative; z-index: 2; width: 100%; }

.eyebrow {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--teal-light); margin-bottom: 20px; display: block;
}
.hero .eyebrow { color: #7fe3e4; }

h1 {
  font-family: var(--serif); font-size: clamp(2.9rem, 6.4vw, 5.4rem);
  font-weight: 300; line-height: 1.02; letter-spacing: -0.015em;
  color: #fafaf8; max-width: 15ch;
}
h1 em { font-style: italic; color: #bfe6d8; }

.hero-sub {
  font-size: 1.08rem; font-weight: 300; color: rgba(232, 237, 228, 0.8);
  max-width: 52ch; margin: 22px 0 0; line-height: 1.7;
}

/* ── HERO MEDIA SLOT (v2 shell only, no V1 equivalent) ─────────────────────
   .hero-media hosts the video/still that shell.js loads. Full-bleed
   placeholder uses the shared .ph pattern when neither file exists yet. */
.hero-media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero-media video, .hero-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.hero-media .ph { position: absolute; inset: 0; border-radius: 0; min-height: 100%; }
.hero-media iframe {
  position: absolute; top: 50%; left: 50%; border: 0; pointer-events: none;
  z-index: 0;
  /* Cover the hero, not the window. The old rule sized the film against the
     viewport, so whenever the hero grew taller than 16:9 of the window width
     the film letterboxed and left a band above and below it. Percentages
     here resolve against .hero-media, which is inset:0 on the hero, so the
     film is always the smallest 16:9 box that covers it. Fixed 2026-08-13,
     verified at hero heights 600, 900 and 1400. */
  width: auto; height: auto;
  min-width: 100%; min-height: 100%;
  aspect-ratio: 16 / 9;
  transform: translate(-50%, -50%);
}
.hero-media-still {
  position: absolute; inset: 0;
  background: url('/media/hero/hero-wide.jpg') center/cover no-repeat;
}
/* A page can pin its hero to a still photograph instead of the video by
   setting data-hero-image on .hero-media (C5, Arriving). shell.js paints the
   file into this element's background. */
.hero-media-photo { position: absolute; inset: 0; background-position: center; background-size: cover; background-repeat: no-repeat; }

/* ── THE FORK — ported from V1's index.html hero, structure unchanged ──────
   of-v2-revisions.md §3.1. These are V1's rules, lifted with only the classes
   the fork actually needs. The two path boxes sit ON the hero as translucent
   panels; that is the whole point of restoring them. */
.fork { position: relative; z-index: 2; margin-top: 44px; }
/* Restored 2026-08-09. Dropped in the revisions build as redundant against
   the box kickers; Mehdi's call is that it earns its place. */
.fork-label {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: rgba(232, 237, 228, 0.62); margin-bottom: 16px;
}
.fork-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

/* The monthly-rates line, rebuilt 2026-08-09 as a full-width bar beneath the
   two boxes rather than the small underlined link it was. Literal light
   colours throughout, never var(--white): this sits on the hero, over dark
   video, where body.light would flip --white to near black. */
.fork-extra {
  display: flex; align-items: center; gap: 28px; flex-wrap: wrap;
  margin-top: 14px; padding: 18px 28px; border-radius: 6px;
  text-decoration: none;
  background: rgba(9, 18, 22, 0.62);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(232, 237, 228, 0.18);
  transition: border-color 0.25s ease, background 0.25s ease;
}
.fork-extra:hover, .fork-extra:focus-visible {
  border-color: var(--teal); background: rgba(9, 18, 22, 0.42);
}
.fx-hook {
  font-family: var(--serif); font-size: 1.5rem; font-weight: 400;
  color: #fafaf8; line-height: 1.1; white-space: nowrap;
}
.fx-body { flex: 1; min-width: 220px; font-size: 0.94rem; font-weight: 300; color: rgba(232, 237, 228, 0.78); }
.fx-arrow {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: #e8ede4;
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
}
.fx-arrow svg { width: 15px; height: 15px; transition: transform 0.25s ease; }
.fork-extra:hover .fx-arrow svg { transform: translateX(5px); }
@media (max-width: 820px) {
  .fork-extra { gap: 12px; padding: 18px 20px; }
  .fx-hook { font-size: 1.3rem; }
}

.path {
  position: relative; text-decoration: none; overflow: hidden;
  min-height: 168px; padding: 26px 28px;
  border: 1px solid rgba(232, 237, 228, 0.22);
  background: rgba(9, 18, 22, 0.42);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: border-color 0.25s ease, transform 0.25s ease, background 0.25s ease;
  display: flex; flex-direction: column; justify-content: flex-end; border-radius: 6px;
}
.path::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background-size: cover; background-position: center; opacity: 0;
  transition: opacity 0.45s ease, transform 6s ease; transform: scale(1.04);
}
.path::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(9,18,22,0.25) 0%, rgba(9,18,22,0.82) 100%);
  opacity: 0; transition: opacity 0.45s ease;
}
.path-stay::before { background-image: url('/images/room-ocean-view.jpg'); }
.path-lead::before { background-image: url('/images/shala-feature.jpg'); }
.path:hover, .path:focus-visible { border-color: var(--teal); transform: translateY(-3px); background: rgba(9, 18, 22, 0.2); }
.path:hover::before, .path:focus-visible::before { opacity: 0.5; transform: scale(1); }
.path:hover::after, .path:focus-visible::after { opacity: 1; }
.path > * { position: relative; z-index: 2; }

.path-kicker {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: #7fe3e4; margin-bottom: 10px;
}
/* .path-kicker-long is gone, 2026-08-12. It set the left box's kicker in sans
   sentence case while the right box's was a mono uppercase label, so the two
   boxes sitting side by side in the hero were visibly written in two
   different languages - Mehdi: "text looks different on both boxes".

   Both are mono labels now. The sentence that used to be the left kicker was
   too long to be one, so it moved into that box's description where a
   sentence belongs. */
.path-title {
  font-family: var(--serif); font-size: clamp(1.7rem, 2.6vw, 2.35rem);
  font-weight: 300; line-height: 1.1; color: #fafaf8; margin-bottom: 8px;
  /* Two lines' worth, reserved whether the title fills them or not. "I want
     to stay" is one line and "I want to lead the retreat they'll never
     forget." is two, which pushed everything below them out of step. */
  min-height: calc(2 * 1.1em);
}
.path-desc { font-size: 0.92rem; font-weight: 300; color: rgba(232, 237, 228, 0.72); line-height: 1.6; max-width: 34ch; }
/* The whole box is a column and the arrow is pushed to the floor of it, so
   the two "Plan your stay" / "Host your retreat" lines sit level however
   long the copy above them runs. Same fix as the room cards. */
.path { display: flex; flex-direction: column; }
.path-arrow {
  margin-top: auto; padding-top: 16px;
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: #e8ede4; display: inline-flex; align-items: center; gap: 8px;
  align-self: flex-start;
}
.path-arrow svg { width: 15px; height: 15px; transition: transform 0.25s ease; }
.path:hover .path-arrow svg { transform: translateX(5px); }

@media (max-width: 820px) {
  .hero { padding-top: 96px; }
  .fork-grid { grid-template-columns: 1fr; gap: 10px; }
  .path { min-height: 0; padding: 20px 22px; }
  .path-desc { display: none; }
  .hero-sub { font-size: 1rem; margin-top: 16px; }
  .fork { margin-top: 30px; }
}

/* ── THE THREE PHOTO TREATMENTS ──────────────────────────────────────────
   of-v2-revisions.md §3.2. Reusable, so the same look can be applied later
   without reinventing it. Layout only: no parallax, no fixed attachment, no
   scroll listeners, so prefers-reduced-motion needs nothing special here. */

/* .media-bleed — the photograph runs off ONE edge of the viewport and the
   text takes the remaining column. Alternate sides down a page by adding
   .flip to every other one.
   The negative margin sits on the GRID ITSELF, not on the image: a direct
   child of .wrap has .wrap's content box as its containing block, so
   calc(50% - 50vw) is exactly the distance out to the viewport edge. A grid
   ITEM would resolve that 50% against its own column and land nowhere.
   The photo column then starts at the viewport edge and the text column
   still ends where the page's text normally ends. */
.media-bleed {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px; align-items: center;
  margin-inline-start: calc(50% - 50vw);
}
.media-bleed > * { min-width: 0; }
/* .align-bottom — the photograph's last line and the text's last line sit on
   the same rule. The photograph keeps its own proportions and, being taller
   than the paragraphs, rises above them.

   Two earlier attempts, both wrong, both worth naming so nobody repeats them:
   .align-top pinned the top and let the picture run on past the end of the
   copy; then .match-copy stretched it to the copy's exact height, which lined
   both edges up but squashed the photograph out of its own aspect ratio to do
   it. Mehdi: "Align to the bottom but don't cut the top, just move the photo
   up." So the picture is left alone and moved instead.

   align-items:end does all of it. The row takes the height of the taller
   child - the photograph - and both children are dropped to its floor.

   The bleed is untouched: Mehdi's call was "keep the bleeding part only", so
   the photograph still runs off the edge of the window. */
.media-bleed.align-bottom { align-items: end; }
.media-bleed.align-bottom .media-shot > .sl { position: relative; }
/* The dots sit ON the photograph, not under it. Under it they are part of the
   column and push the picture up by their own height, so the two bottom edges
   miss each other by about 23px - which is the one thing this class exists to
   prevent. Over it they cost nothing, and it is what .sl-band and the
   full-width bands already do, so the two read as the same component. */
.media-bleed.align-bottom .media-shot > .sl > .sl-dots {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%);
  margin-top: 0; z-index: 3;
}
.media-bleed.align-bottom .media-shot > .sl > .sl-dots button {
  border-color: rgba(250, 250, 248, 0.6); background: rgba(250, 250, 248, 0.35);
}
.media-bleed.align-bottom .media-shot > .sl > .sl-dots button[aria-current="true"] {
  background: var(--teal-light); border-color: var(--teal-light);
}

/* A slider standing in for the still photograph inside a band.

   min-height, NOT height. Written as `height: 56vh` on 2026-08-12 and that
   was wrong: a still band is sized by its data-ratio, so at 16/9 on a 1440px
   window it stands about 810px tall, and a fixed 56vh cut it to roughly 440.
   Swapping the photographs for a rotation is not licence to resize the band,
   and it visibly shrank. Mehdi: "Why is the size different from what it was?"

   These are the same two rules a still band gets - aspect ratio from
   data-ratio, floor from min-height - so a rotating band and a still one are
   now the same size as well as the same object. */
.media-band .media-shot .sl-stage { min-height: 56vh; }
@media (max-width: 720px) { .media-band .media-shot .sl-stage { min-height: 44vh; } }
.media-band .media-shot .sl-dots {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  margin-top: 0; z-index: 3;
}
.media-band .media-shot .sl-dots button {
  border-color: rgba(250, 250, 248, 0.5); background: rgba(250, 250, 248, 0.3);
}
.media-band .media-shot .sl-dots button[aria-current="true"] {
  background: var(--teal-light); border-color: var(--teal-light);
}
.media-bleed .media-shot [data-media],
.media-bleed .media-shot .ph { min-height: 60vh; border-radius: 0; }
.media-bleed .media-shot [data-media] > img { min-height: 60vh; border-radius: 0; }
.media-bleed.flip { margin-inline-start: 0; margin-inline-end: calc(50% - 50vw); }
.media-bleed.flip .media-shot { order: 2; }
@media (max-width: 820px) {
  /* Stacked: photograph full width above the text, both edges bled. */
  .media-bleed, .media-bleed.flip {
    grid-template-columns: 1fr; gap: 26px;
    margin-inline-start: calc(50% - 50vw); margin-inline-end: calc(50% - 50vw);
  }
  .media-bleed > *:not(.media-shot) { padding-inline: var(--gutter); }
  .media-bleed.flip .media-shot { order: 0; }
  .media-bleed .media-shot [data-media],
  .media-bleed .media-shot .ph,
  .media-bleed .media-shot [data-media] > img { min-height: 42vh; }
}

/* .media-band — the photograph spans the full viewport, edge to edge, with
   the text laid over it and a scrim behind the text for legibility. Below
   820px the text drops beneath the image rather than sitting on it. */
/* Fixed 2026-08-07. This rule previously carried only the negative margins and
   no width. Every .media-band on the site sits inside a .wrap, which is
   max-width 1180px with gutter padding, so the percentage in calc(50% - 50vw)
   resolved against the wrap's CONTENT width and the band came up roughly one
   gutter short on each side. It rendered as an inset box with rounded corners
   instead of running edge to edge. width:100vw forces the full span, and the
   radius resets below are raised in specificity so a generic [data-media] rule
   cannot put the corners back. */
.media-band {
  position: relative;
  width: 100vw;
  max-width: 100vw;
  margin-inline: calc(50% - 50vw);
}
/* Height set 2026-08-09, Mehdi's call, and this number IS the house
   definition of "cinematic": full viewport width, 16:9, about 56% of screen
   height, heading laid over the photograph. It was 70vh, which read as a
   photograph that was simply too big rather than as a film frame. Wider
   than tall is the whole point - if a future change pushes this back up
   past about 60vh the band stops being cinematic and becomes a wall. */
.media-band .media-shot,
.media-band .media-shot [data-media],
.media-band .media-shot .ph { min-height: 56vh; border-radius: 0 !important; }
.media-band .media-shot [data-media] > img,
.media-band .media-shot img { min-height: 56vh; border-radius: 0 !important; object-fit: cover; width: 100%; }
.media-band .media-over {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0 0 56px;
}
.media-band .media-over::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(9,18,22,0) 30%, rgba(9,18,22,0.82) 100%);
}
.media-band .media-over h2,
.media-band .media-over h3 { color: #fafaf8; }
.media-band .media-over p { color: rgba(232, 237, 228, 0.82); }
.media-band .media-over .eyebrow { color: #7fe3e4; }
@media (max-width: 820px) {
  .media-band .media-shot [data-media],
  .media-band .media-shot .ph,
  .media-band .media-shot [data-media] > img { min-height: 44vh; }
  .media-band .media-over { position: static; padding: 26px var(--gutter) 0; }
  .media-band .media-over::before { display: none; }
  .media-band .media-over h2,
  .media-band .media-over h3 { color: var(--white); }
  .media-band .media-over p { color: var(--dim); }
  .media-band .media-over .eyebrow { color: var(--teal-light); }
}

/* .media-fade — the modifier that actually removes the "box" feeling. The
   edge where the photograph meets the text dissolves into the page instead
   of stopping at a hard rectangle. Roughly 12% of the image width. */
/* A .media-shot may hold a plain <img> rather than a [data-media] host, for
   photographs that live under /images/ (V1's folder) instead of /media/. The
   sizing and the mask have to reach those too, or the treatment silently does
   nothing and the photograph renders as a plain inline image. */
.media-bleed .media-shot > img { min-height: 60vh; width: 100%; object-fit: cover; border-radius: 0; display: block; }
.media-band .media-shot > img { min-height: 56vh; width: 100%; object-fit: cover; border-radius: 0 !important; display: block; }
@media (max-width: 820px) { .media-bleed .media-shot > img { min-height: 42vh; } }

/* A .media-shot may also hold a .sl slider rather than a single photograph.
   The mask goes on .sl-stage, not on the <img> inside it: shell.js replaces
   that <img> on every advance, so a mask set on the image would be thrown
   away the first time somebody pressed an arrow. The stage persists, so the
   treatment persists. Added 2026-08-11 - the food slider on Lodging was
   sitting inside .media-bleed .media-fade with a hard edge and rounded
   corners, because none of the selectors below reached it. */
.media-fade .media-shot [data-media],
.media-fade .media-shot [data-media] > img,
.media-fade .media-shot > img,
.media-fade .media-shot .sl-stage,
.media-fade .media-shot .ph {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 88%, transparent 100%);
          mask-image: linear-gradient(90deg, #000 0%, #000 88%, transparent 100%);
}
.media-fade.flip .media-shot [data-media],
.media-fade.flip .media-shot [data-media] > img,
.media-fade.flip .media-shot > img,
.media-fade.flip .media-shot .sl-stage,
.media-fade.flip .media-shot .ph {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 12%, #000 100%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 12%, #000 100%);
}

/* A full-viewport band has no text beside it, so it fades on BOTH vertical
   edges into the page background instead. */
.media-band.media-fade .media-shot [data-media],
.media-band.media-fade .media-shot [data-media] > img,
.media-band.media-fade .media-shot .sl-stage,
.media-band.media-fade .media-shot .ph {
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
}

/* A band directly under the hero must NOT fade at the top: there is no page
   above it to dissolve into, so the fade reads as a white stripe between the
   hero and the photograph. This modifier fades downward only. Pair it with
   removing the section's top padding.

   This block sits BELOW .media-band.media-fade on purpose. The two have the
   same weight, so whichever is written last wins, and an element carrying
   both classes has to end up fading downward only - that is the whole point
   of asking for .media-fade-down. Written above, it lost, and the white
   stripe it exists to remove came back. Moved 2026-08-11. Do not reorder. */
.media-band.media-fade-down .media-shot [data-media],
.media-band.media-fade-down .media-shot [data-media] > img,
.media-band.media-fade-down .media-shot > img,
.media-band.media-fade-down .media-shot .sl-stage,
.media-band.media-fade-down .media-shot .ph {
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 88%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 88%, transparent 100%);
}

/* A slider that has been placed inside a bleed or a band is a photograph
   like any other: no rounded corners, and the arrows move off the two edges
   that are no longer readable. One edge is cut off at the viewport, the
   other is dissolving, and an arrow sitting on either is half invisible. */
.media-bleed .media-shot .sl-stage img,
.media-bleed .media-shot .sl-stage .ph,
.media-band .media-shot .sl-stage img,
.media-band .media-shot .sl-stage .ph { border-radius: 0; }

/* .media-bleed runs off the LEFT edge and fades on the right, where it meets
   the text. .flip is the mirror. The arrows follow the same mirror. */
.media-bleed .media-shot .sl-prev { left: 26px; }
.media-bleed .media-shot .sl-next { right: 14%; }
.media-bleed.flip .media-shot .sl-prev { left: 14%; }
.media-bleed.flip .media-shot .sl-next { right: 26px; }

@media (max-width: 820px) {
  /* Stacked, the photograph is full width and the fade belongs top and
     bottom on every treatment, not left and right. */
  .media-bleed.media-fade .media-shot [data-media],
  .media-bleed.media-fade .media-shot [data-media] > img,
  .media-bleed.media-fade .media-shot .sl-stage,
  .media-bleed.media-fade .media-shot .ph,
  .media-bleed.media-fade.flip .media-shot [data-media],
  .media-bleed.media-fade.flip .media-shot [data-media] > img,
  .media-bleed.media-fade.flip .media-shot .sl-stage,
  .media-bleed.media-fade.flip .media-shot .ph {
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 10%, #000 90%, transparent 100%);
            mask-image: linear-gradient(180deg, transparent 0%, #000 10%, #000 90%, transparent 100%);
  }
  /* Both edges are bled once stacked, so both arrows come in equally. */
  .media-bleed .media-shot .sl-prev,
  .media-bleed.flip .media-shot .sl-prev { left: 14px; }
  .media-bleed .media-shot .sl-next,
  .media-bleed.flip .media-shot .sl-next { right: 14px; }
}

/* ── THE FOOD SECTION — "Nourishing the Soul" ─────────────────────────────
   Moved here from lodging.html's own <style> block on 2026-08-12, because the
   section now runs on two pages.

   It was copied to Retreats the day before and its CSS was not, so on that
   page the diet chips rendered as unstyled inline SVGs the height of the
   window. The lesson is the one this shell exists for: markup that travels
   between pages has to have its styling in the shell, or it arrives naked.
   Anything used twice belongs here, not in a page.                        */
.lo-chips { display: flex; flex-wrap: wrap; gap: 12px; margin: 4px 0 40px; }
.lo-chip {
  display: inline-flex; align-items: center; gap: 9px; padding: 9px 18px; border-radius: 22px;
  border: 1px solid var(--hairline); font-family: var(--mono); font-size: 0.66rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--mist);
}
/* The width AND the height, and flex-shrink so a long label cannot squash the
   icon into an ellipse. Without a height an inline SVG takes its viewBox as a
   ratio against whatever width it is given, which is how these became
   full-page leaves. */
.lo-chip svg {
  width: 17px; height: 17px; flex: 0 0 auto; color: var(--teal-light);
}
.lo-food-quote {
  font-family: var(--serif); font-style: italic; font-size: 1.35rem;
  color: var(--white); line-height: 1.55; margin: 0 0 20px;
}
.lo-food-body { color: var(--dim); font-size: 0.98rem; font-weight: 300; line-height: 1.8; margin: 0 0 16px; }
.lo-food-body:last-child { margin-bottom: 0; }
.lo-food-copy { max-width: 62ch; }

/* ── ROOM CARDS — the house pattern for showing rooms ─────────────────────
   Moved here from index.html's inline block on 2026-08-09. Three pages show
   rooms - the home page, Lodging and Retreats - and until now each carried
   its own copy of this, which is exactly how three pages end up looking like
   three different websites. One definition, used by all three.

   The shape: photograph on top at 4/3, everything else underneath. Hovering
   swaps to a second shot and expands a short detail line. The card may be an
   <a> (home page, links to Lodging) or a <button> (Lodging and Retreats,
   opens the gallery full screen); both are styled the same, so the pattern
   does not care which job it is doing on a given page.

   Optional parts, used where they apply and simply left out where they do
   not: .hm-room-price (no price on Retreats, where a retreat is quoted as a
   package) and .hm-shot-b (a card with only one photograph). */
.hm-rooms { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; margin-top: 8px; }
@media (max-width: 900px) { .hm-rooms { grid-template-columns: 1fr; max-width: 480px; margin-left: auto; margin-right: auto; } }
/* A column, not a block, since 2026-08-11. Three cards side by side had their
   Book now buttons at three different heights, because each button sat
   directly under its own list and one card's "En-suite bathroom with natural
   ventilation" wrapped to a second line.

   Flex column plus margin-top:auto on the last thing in the card puts every
   button on one line however long the copy above it runs. That matters more
   than it sounds: three buttons at three heights is the detail that makes a
   row of cards look unfinished, and it would have come back every time
   anybody edited a bullet. Now the layout absorbs it. */
.hm-room {
  display: flex; flex-direction: column;
  width: 100%; text-align: left; font: inherit; color: inherit;
  padding: 0; text-decoration: none; border: 1px solid var(--hairline);
  border-radius: 10px; overflow: hidden; background: var(--ink-2);
  transition: border-color 0.2s, transform 0.2s;
}
.hm-room:hover, .hm-room:focus-visible { border-color: var(--teal); transform: translateY(-3px); }
/* Two stacked shots; the second fades in on hover/focus. Missing files show
   the shell's labelled placeholder in each host. */
.hm-room-media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--ink-3); }
.hm-shot { position: absolute; inset: 0; transition: opacity 0.4s ease; }
.hm-shot-b { opacity: 0; }
.hm-room.is-open .hm-shot-b { opacity: 1; }
.hm-shot .ph { border-radius: 0; }
/* flex:1 so the body takes all the height left under the photograph, and a
   column so the rule below can push the last element to the floor of it. */
.hm-room-body { padding: 22px 22px 24px; display: flex; flex-direction: column; flex: 1; }
/* The bottom-aligned thing is "Book now" on Lodging and Retreats, and
   "View room" on the home page. Both are named, rather than using
   :last-child, so a card that later ends with a paragraph does not have that
   paragraph shoved to the bottom of an over-tall card. */
.hm-room-extra { display: flex; flex-direction: column; flex: 1; }
.hm-room-extra .cta { margin-top: auto; align-self: flex-start; }
.hm-room-body > .hm-room-more { margin-top: auto; }
.hm-room-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.hm-room-top h3 { font-family: var(--serif); font-weight: 400; font-size: 1.5rem; color: var(--white); margin: 0; }
.hm-room-price { font-family: var(--serif); font-size: 1.02rem; color: var(--white); white-space: nowrap; }
.hm-room-price b { font-weight: 600; }
.hm-room-meta {
  /* Reads as a phrase ("Gardens & stream · 5 rooms · 1-5 guests each"),
     so sans, not mono. */
  display: block; margin-top: 8px; font-family: var(--sans); font-size: 0.8rem;
  letter-spacing: 0.01em; color: var(--teal-light);
}
/* The short detail expands in place on hover/focus. */
.hm-room-detail {
  color: var(--dim); font-size: 0.92rem; font-weight: 300; line-height: 1.7;
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height 0.4s ease, opacity 0.3s ease, margin-top 0.3s ease;
  margin-top: 0;
}
.hm-room.is-open .hm-room-detail { max-height: 160px; opacity: 1; margin-top: 14px; }
.hm-room-more {
  display: inline-block; margin-top: 16px; font-family: var(--mono);
  font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--white);
}
.hm-room-more::after { content: ' \203A'; }

/* The always-visible block under the hover detail. This is how one card
   serves three pages with three amounts of information (Mehdi's rule,
   2026-08-09: same component, the page decides how much). The home page and
   Retreats leave it out entirely; Lodging uses it for the room's specifics,
   its price and its Book now button, because that page is where somebody is
   actually choosing a room. */
.hm-room-extra { margin-top: 18px; }
.hm-room-extra ul { list-style: none; margin: 0 0 20px; }
.hm-room-extra li {
  position: relative; padding: 8px 0 8px 22px; font-size: 0.92rem;
  color: var(--dim); font-weight: 300; border-bottom: 1px solid var(--hairline);
}
.hm-room-extra li:last-child { border-bottom: 0; }
.hm-room-extra li::before {
  content: ''; position: absolute; left: 0; top: 16px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--teal);
}
/* The photograph is a control when it opens the lightbox. */
.hm-room-media[data-gallery] { cursor: zoom-in; border: 0; padding: 0; width: 100%; display: block; }
.hm-room-badge {
  position: absolute; left: 12px; bottom: 12px; z-index: 2;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: #fafaf8;
  background: rgba(8, 14, 12, 0.55); border-radius: 12px; padding: 4px 10px;
}
.hm-room-zoom {
  position: absolute; right: 12px; bottom: 12px; z-index: 2;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid rgba(250, 250, 248, 0.32); background: rgba(8, 14, 12, 0.55);
  color: #fafaf8; display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 0.2s;
}
.hm-room-zoom svg { width: 16px; height: 16px; }
.hm-room:hover .hm-room-zoom, .hm-room-media:focus-visible .hm-room-zoom { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .hm-room, .hm-shot, .hm-room-detail { transition: none; }
  .hm-room:hover, .hm-room:focus-visible { transform: none; }
}

/* ══ SLIDER ════════════════════════════════════════════════════════════════
   One photo slider for the site. The arrows and dots are built by shell.js,
   so a page never hand-writes them and they cannot drift apart. Add .sl-band
   for a full-viewport strip; without it the slider fills whatever column it
   is in, which is how the food and tour sliders sit beside their copy. */
.sl { position: relative; }
.sl-stage { position: relative; overflow: hidden; }
/* Every photograph in a slider is a layer filling the stage, and two of them
   exist at once during a slide. Added 2026-08-12 with the slide itself.

   All of them are absolute, so the stage carries the shape on its own —
   shell.js sets its aspect-ratio from data-ratio, and .sl-band and the band
   rules set an explicit height. If a stage ever collapses to nothing, that is
   the reason: it was given neither. */
.sl-stage > .sl-layer {
  position: absolute; inset: 0; will-change: transform;
}
.sl-stage > .sl-layer > img,
.sl-stage > .sl-layer > .ph {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* The stage may be a <button> where the slider also opens the lightbox. */
button.sl-stage { border: 0; padding: 0; width: 100%; display: block; background: none; cursor: zoom-in; }
.sl-stage img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 6px; }
.sl-stage .ph { border-radius: 6px; }
.sl-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer; z-index: 2;
  border: 1px solid rgba(250, 250, 248, 0.32);
  background: rgba(8, 14, 12, 0.55); color: #fafaf8;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.2s, border-color 0.2s;
}
.sl-arrow:hover, .sl-arrow:focus-visible { background: rgba(8, 14, 12, 0.78); border-color: var(--teal); }
.sl-arrow svg { width: 20px; height: 20px; }
.sl-prev { left: 12px; }
.sl-next { right: 12px; }
@media (max-width: 480px) {
  .sl-arrow { width: 36px; height: 36px; }
  .sl-prev { left: 8px; } .sl-next { right: 8px; }
}
.sl-dots { display: flex; gap: 9px; margin-top: 12px; }
.sl-dots button {
  width: 11px; height: 11px; padding: 0; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--hairline); background: rgba(232, 237, 228, 0.25);
}
body.light .sl-dots button { background: rgba(20, 26, 22, 0.2); }
.sl-dots button[aria-current="true"] { background: var(--teal-light); border-color: var(--teal-light); }

/* A full-viewport strip. Same width, height and edge fade as .media-band, so
   a slider and a still band read as the same family rather than two
   different components that happen to share a page. */
.sl-band { width: 100vw; max-width: 100vw; margin-inline: calc(50% - 50vw); }
.sl-band .sl-stage {
  height: 56vh; min-height: 320px;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
}
.sl-band .sl-stage img, .sl-band .sl-stage .ph { border-radius: 0; }
@media (max-width: 720px) { .sl-band .sl-stage { height: 42vh; min-height: 240px; } }
/* A shorter band for photographs that are only about 1200px wide: the taller
   the band, the harder object-fit has to crop them, which reads as zoomed. */
.sl-band-short .sl-stage { height: 48vh; min-height: 300px; }
@media (max-width: 720px) { .sl-band-short .sl-stage { height: 38vh; min-height: 220px; } }
.sl-band .sl-dots {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
  margin-top: 0; z-index: 3;
}
.sl-band .sl-dots button { border-color: rgba(250, 250, 248, 0.5); background: rgba(250, 250, 248, 0.3); }

/* Text laid OVER a slider band, the same way .media-over sits on a still
   band, so a moving band and a still one read identically. */
.sl-over {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0 0 64px; pointer-events: none;
}
.sl-over::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(9,18,22,0) 26%, rgba(9,18,22,0.86) 100%);
}
.sl-over h2, .sl-over p { color: #fafaf8; }
.sl-over .eyebrow { color: #7fe3e4; }
@media (max-width: 720px) { .sl-over { padding-bottom: 54px; } }

/* ══ LIGHTBOX ══════════════════════════════════════════════════════════════
   Built and appended by shell.js on any page that has a [data-gallery]. */
.lb[hidden] { display: none; }
.lb {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(6, 10, 9, 0.94);
  display: flex; align-items: center; justify-content: center;
  padding: 64px 76px;
}
@media (max-width: 720px) { .lb { padding: 56px 12px; } }
.lb-img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 4px; display: block; }
.lb-btn {
  position: absolute; width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  border: 1px solid rgba(250, 250, 248, 0.32); background: rgba(8, 14, 12, 0.6);
  color: #fafaf8; display: flex; align-items: center; justify-content: center;
  transition: background 0.2s, border-color 0.2s;
}
.lb-btn:hover, .lb-btn:focus-visible { background: rgba(8, 14, 12, 0.9); border-color: var(--teal); }
.lb-btn svg { width: 22px; height: 22px; }
.lb-prev { left: 18px; top: 50%; transform: translateY(-50%); }
.lb-next { right: 18px; top: 50%; transform: translateY(-50%); }
.lb-close { right: 18px; top: 18px; }
@media (max-width: 720px) {
  .lb-btn { width: 38px; height: 38px; }
  .lb-prev { left: 6px; } .lb-next { right: 6px; }
}
.lb-count {
  position: absolute; left: 50%; bottom: 20px; transform: translateX(-50%);
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: rgba(250, 250, 248, 0.72);
}
.lb-title {
  position: absolute; left: 24px; top: 26px;
  font-family: var(--serif); font-size: 1.2rem; font-weight: 400; color: #fafaf8;
}
@media (max-width: 720px) { .lb-title { font-size: 1rem; left: 14px; top: 18px; } }

/* ══ EXPANDER ══════════════════════════════════════════════════════════════
   One expand-in-place row. Replaced five near-identical families: the
   Experiences activity bars, the Lodging policies, and the Arriving and
   About FAQ lists. Exclusivity is a data attribute on the list, not a
   different component. */
.xp-list { border-top: 1px solid var(--hairline); }
.xp { border-bottom: 1px solid var(--hairline); }
.xp-head {
  width: 100%; background: none; border: 0; color: var(--mist); cursor: pointer;
  display: flex; align-items: center; gap: 16px; padding: 22px 4px; text-align: left;
}
/* An icon may sit before the name (the Lodging policies use one). It MUST be
   sized here: an inline SVG with no width renders at its viewBox scaled to
   the container, which on 2026-08-09 put a shield the height of the viewport
   on the Lodging page. That happened because the page's own `.lo-pol-head svg`
   rule was deleted with the rest of the page CSS and nothing replaced it.
   Anything this component can contain gets sized by this component. */
.xp-head svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--teal-light); }
.xp-name {
  font-family: var(--serif); font-size: 1.3rem; font-weight: 400;
  flex: 1; margin: 0; color: var(--white); transition: color 0.25s ease;
}
.xp-head:hover .xp-name { color: var(--teal-light); }
.xp-arrow { transition: transform 0.25s ease; color: var(--dim); flex-shrink: 0; font-size: 1.3rem; line-height: 1; }
/* The chevron is text, not an icon; the rule above must not catch it. */
.xp-arrow svg { width: 14px; height: 14px; }
.xp[data-open="true"] .xp-arrow { transform: rotate(90deg); }
.xp-body {
  display: none; padding: 0 4px 24px;
  color: var(--dim); font-size: 0.94rem; font-weight: 300; line-height: 1.8;
}
.xp[data-open="true"] .xp-body { display: block; }
.xp-body p { margin: 0 0 14px; }
.xp-body p:last-child { margin-bottom: 0; }
/* Answers carry links and bulleted lists - the boat fares, the packing list.
   These three rules lived in about.html until 2026-08-11, back when the FAQ
   was hand-written markup on that one page. The FAQ is a shared component
   now and mounts on the home page and on Arriving, neither of which ever had
   these rules, so the lists rendered unstyled the moment About was cleaned
   out. They belong to the component, so they belong here. */
/* Numbered clauses, for the Hold Harmless agreement. Each clause opens with
   its own name in bold so a reader can find the one that applies to them
   instead of reading nine paragraphs of law. */
.xp-body ol { margin: 0; padding-left: 22px; }
.xp-body ol li { margin: 0 0 12px; color: var(--dim); font-weight: 300; line-height: 1.8; }
.xp-body ol li b { color: var(--mist); font-weight: 500; }
.xp-body a  { color: var(--teal-light); }
.xp-body ul { margin: 0; padding-left: 20px; list-style: disc; }
.xp-body li { margin: 0 0 6px; color: var(--dim); font-weight: 300; line-height: 1.8; }
/* A sentence, so sans. Mono is for labels of a few words. */
.xp-note { font-family: var(--sans); font-size: 0.88rem; color: var(--teal-light); }
@media (prefers-reduced-motion: reduce) { .xp-arrow, .xp-name { transition: none; } }

/* ══ FIGURE ════════════════════════════════════════════════════════════════
   A standing photograph with an optional caption: the regional map on
   Arriving, the property map on Lodging, the shala on Retreats. Three
   page-local frames became this one. */
.figure { max-width: 760px; margin-top: 8px; }
/* A wide, shallow variant for a map or a panorama: fills the column and stops
   reading as a boxed portrait. The edges dissolve rather than ending on a
   hard rectangle, same idea as .media-fade. */
.figure-wide { max-width: none; }
.figure-wide [data-media] {
  border-radius: 0;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 6%, #000 94%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 6%, #000 94%, transparent 100%);
}
.figure-wide figcaption { max-width: 720px; }
.figure img, .figure [data-media] { border-radius: 6px; width: 100%; display: block; }
.figure figcaption {
  margin-top: 18px; max-width: 640px; color: var(--dim); font-size: 0.92rem;
  font-weight: 300; font-style: italic; line-height: 1.7;
}

/* ══ MORE-LINK ═════════════════════════════════════════════════════════════
   The small uppercase "go on then" line under a card or beside a heading.
   Replaced seven variants that differed only in colour and chevron. */
.more {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 16px;
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--white); text-decoration: none;
}
.more::after { content: '\203A'; transition: transform 0.25s ease; }
a.more:hover::after, button:hover .more::after, .hm-room:hover .more::after { transform: translateX(3px); }
.more-light { color: #e8ede4; }
@media (prefers-reduced-motion: reduce) { .more::after { transition: none; } }

/* ── SECTIONS ───────────────────────────────────────────────────────────── */
main { position: relative; z-index: 2; background: var(--ink); }
/* ── SECTIONS AND THE SPACING SCALE ───────────────────────────────────────
   Every section is --space-section top and bottom, so two sections sit
   208px apart. That has always been true. What follows is the vocabulary for
   the exceptions, so they stop being written into individual pages.

   FOUR CLASSES, and nothing else:

     .flush-top      no padding above  (a full-bleed photograph is there)
     .flush-bottom   no padding below
     .tight-top      --space-tight above  (this section continues the one above)
     .tight-bottom   --space-tight below

   RULE: no page may write a padding rule on a section. If none of the four
   fits, the scale is wrong and it gets fixed here, once, for everybody.

   The flush pair is applied AUTOMATICALLY by shell.js wherever a section's
   content starts or ends with a .media-band - see "BAND SPACING" there. You
   should rarely need to type it. It stays available as a class for the cases
   the detection cannot see. */
section { padding: var(--space-section) 0; }
@media (max-width: 720px) {
  :root { --space-section: 72px; --space-tight: 28px; }
}

/* Why a band takes the padding away rather than adding to it: a .media-band
   dissolves into the page at its top and bottom edges, roughly 12% of its
   height, and that fade IS the spacing. Leaving the section's own 104px on
   top of it produced about 280px of white where a text-led section produced
   170px - which is why Arriving read as a different page from the home page
   even though both were on the same 104px rule. */
.flush-top    { padding-top: 0 !important; }
.flush-bottom { padding-bottom: 0 !important; }
.tight-top    { padding-top: var(--space-tight) !important; }
.tight-bottom { padding-bottom: var(--space-tight) !important; }

.sec-head { margin-bottom: 8px; }
.sec-head h2 {
  font-family: var(--serif); font-weight: 300; line-height: 1.1;
  font-size: clamp(2rem, 4.4vw, 3.2rem); color: var(--white);
}
.grad-text { background: var(--gradient-ocean-lime); -webkit-background-clip: text; background-clip: text; color: transparent; }
.grad-bar { height: 3px; width: 72px; background: var(--gradient-ocean-lime); border: 0; margin: 22px 0 26px; border-radius: 2px; }
.lead { max-width: 640px; color: var(--dim); font-size: 1.02rem; font-weight: 300; }

/* ── MEDIA PLACEHOLDERS ── */
.ph {
  position: relative; width: 100%; height: 100%; min-height: 180px;
  background: repeating-linear-gradient(45deg, rgba(42,173,168,0.06) 0 12px, rgba(42,173,168,0.11) 12px 24px);
  border: 1px dashed rgba(42,173,168,0.55); border-radius: 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 20px; text-align: center;
}
.ph-label { font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--teal-light); }
.ph-file  { font-family: var(--mono); font-size: 0.72rem; color: var(--mist); word-break: break-all; }
.ph-note  { font-family: var(--sans); font-size: 0.72rem; color: var(--dim); }
body.light .ph {
  background: repeating-linear-gradient(45deg, rgba(22,112,126,0.06) 0 12px, rgba(22,112,126,0.12) 12px 24px);
  border-color: rgba(22,112,126,0.5);
}
/* width:100% is required — with aspect-ratio set by JS, an element sized only
   by min-height derives its WIDTH from that height and blows out the grid. */
[data-media] { width: 100%; }
[data-media] > img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 6px; }

.cta {
  align-self: flex-start; background: var(--gradient-ocean-lime); color: #0b1210;
  font-weight: 700; font-size: 0.76rem; letter-spacing: 0.12em; text-transform: uppercase;
  font-family: var(--mono); padding: 12px 24px; border-radius: 24px; border: 0;
  cursor: pointer; text-decoration: none; display: inline-block; margin-top: 6px;
}
.cta:hover { filter: brightness(1.08); }
.cta.ghost { background: none; border: 1px solid var(--hairline); color: var(--mist); font-weight: 400; }
.cta.ghost:hover { border-color: var(--teal); color: var(--white); }

/* ── GALLERY ── */
.gal { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-top: 36px; }
.gal > div { min-height: 160px; }
/* The tiles open the shared lightbox (2026-08-11). They need to look like it:
   a picture that magnifies on hover and takes a focus ring from the keyboard.
   Before this the strip was eight photographs that ignored being clicked. */
.gal > [data-gallery-start] { cursor: zoom-in; overflow: hidden; border-radius: 6px; }
.gal > [data-gallery-start] img { transition: transform 0.45s ease; }
.gal > [data-gallery-start]:hover img { transform: scale(1.05); }
.gal > [data-gallery-start]:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .gal > [data-gallery-start] img { transition: none; }
  .gal > [data-gallery-start]:hover img { transform: none; }
}
@media (max-width: 820px) { .gal { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Footer map link — not in the spec's lifted line ranges (it sits outside
   491–517 in index.html), but the footer markup contract requires the map
   link, and without this the SVG renders unstyled and full-size. */
.foot-map {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 14px;
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--teal-light); text-decoration: none;
}
.foot-map svg { width: 16px; height: 16px; }
.foot-map:hover { color: var(--white); }

/* ── THE BLOG ─────────────────────────────────────────────────────────────
   Two things only: the cards on /blog/, and the article layout on a post.
   Both live here rather than in the pages, for the same reason as everything
   else in this file - a rule written into a page is invisible from anywhere
   else, and the next post copied from the template would not have it.

   A post page carries no <style> block and no colour of its own. The
   template says so; this is what makes that possible. */

/* The waiting message, shown while POSTS in /posts.js is empty. */
.bl-empty {
  border: 1px dashed var(--hairline); border-radius: 8px;
  padding: 54px 30px; text-align: center; margin-top: 34px;
}
.bl-empty p { color: var(--dim); font-weight: 300; margin: 0; }

/* ── THE INDEX: one card per post ── */
.bl-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px; margin-top: 40px;
}
@media (max-width: 900px) { .bl-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .bl-grid { grid-template-columns: 1fr; } }

.bl-card {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--ink-2); border: 1px solid var(--hairline); border-radius: 8px;
  overflow: hidden; text-decoration: none;
  transition: border-color 0.25s ease, transform 0.25s ease;
}
.bl-card:hover, .bl-card:focus-visible { border-color: var(--teal); transform: translateY(-3px); }
.bl-card-media { aspect-ratio: 3 / 2; overflow: hidden; background: var(--ink-3); }
.bl-card-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.bl-card:hover .bl-card-media img { transform: scale(1.04); }
.bl-card-body { padding: 24px 24px 26px; display: flex; flex-direction: column; gap: 10px; }
.bl-card-body h3 {
  font-family: var(--serif); font-weight: 300; font-size: 1.45rem; line-height: 1.2;
  color: var(--white);
}
.bl-card-body p { color: var(--dim); font-size: 0.94rem; font-weight: 300; line-height: 1.7; }
.bl-more {
  margin-top: 4px; font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--teal-light);
}

/* The date, on a card and at the head of a post. */
.bl-date {
  display: block; font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--teal-light);
}

/* ── A POST ──
   Measure first. One column, capped at 68ch, which is the same measure the
   prose blocks on the About page settled on. It is what makes the template
   read correctly at 200 words and at 2000: a short post is a short column
   rather than a wide banner, and a long one never runs past the eye. */
.bl-article { max-width: 68ch; margin: 0 auto; }

.bl-back {
  display: inline-block; font-family: var(--mono); font-size: 0.64rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--teal-light);
  text-decoration: none; margin-bottom: 26px;
  border-bottom: 1px solid transparent; transition: border-color 0.2s;
}
.bl-back:hover, .bl-back:focus-visible { border-color: var(--teal-light); }
.bl-back-foot { margin: 44px 0 0; padding-top: 26px; border-top: 1px solid var(--hairline); }

.bl-article h1 {
  font-family: var(--serif); font-weight: 300; line-height: 1.1;
  font-size: clamp(2rem, 4.4vw, 3rem); color: var(--white); margin: 14px 0 0;
}
.bl-standfirst {
  font-family: var(--serif); font-size: 1.3rem; font-style: italic; color: var(--mist);
  line-height: 1.55; margin: 20px 0 0;
}
.bl-article h2 {
  font-family: var(--serif); font-weight: 400; font-size: 1.6rem; line-height: 1.25;
  color: var(--white); margin: 40px 0 14px;
}
.bl-article p {
  color: var(--dim); font-size: 0.98rem; font-weight: 300; line-height: 1.85;
  margin-bottom: 16px;
}
.bl-article a { color: var(--teal-light); }
.bl-article blockquote {
  margin: 30px 0; padding-left: 22px; border-left: 2px solid var(--teal);
}
.bl-article blockquote p {
  font-family: var(--serif); font-size: 1.18rem; font-style: italic;
  color: var(--mist); margin: 0;
}
.bl-article figure { margin: 34px 0; }
.bl-article figure img {
  width: 100%; height: auto; display: block; border-radius: 6px;
}
.bl-article figcaption {
  margin-top: 10px; font-size: 0.82rem; font-weight: 300; color: var(--dim);
}
.bl-hero { margin-top: 34px; }

/* ── FOOTER ── */
footer {
  position: relative; border-top: 1px solid var(--hairline);
  padding: 70px 0 60px; background: var(--ink-2);
}
.foot-bar { height: 4px; background: var(--gradient-ocean-lime); position: absolute; top: 0; left: 0; right: 0; }
.foot-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr)); gap: 44px; align-items: start; }
.foot-grid > div { min-width: 0; }
.foot-brand { font-family: var(--serif); font-size: 1.15rem; font-weight: 300; letter-spacing: 0.12em; text-transform: uppercase; color: var(--white); margin-bottom: 14px; }
.foot-grid > div > p { font-size: 0.9rem; font-weight: 300; color: var(--dim); max-width: 38ch; line-height: 1.75; }
.foot-grid h3 { font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--teal-light); font-weight: 400; margin-bottom: 16px; }
.foot-grid ul { list-style: none; }
.foot-grid li { margin-bottom: 10px; }
.foot-grid li a {
  font-size: 0.9rem; font-weight: 300; color: var(--dim); text-decoration: none;
  border-bottom: 1px solid transparent; transition: color 0.2s, border-color 0.2s;
}
.foot-grid li a:hover, .foot-grid li a:focus-visible { color: var(--white); border-color: var(--teal); }
.foot-bottom {
  margin-top: 52px; padding-top: 22px; border-top: 1px solid var(--hairline);
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.08em; color: var(--dim);
}
.foot-bottom a { color: var(--dim); text-decoration: none; border-bottom: 1px solid var(--hairline); }
.foot-bottom a:hover { color: var(--teal-light); border-color: var(--teal-light); }
@media (max-width: 900px) { .foot-grid { grid-template-columns: 1fr 1fr; gap: 34px; } }
@media (max-width: 560px) { .foot-grid { grid-template-columns: 1fr; } }

/* ── MOTION ── */
.reveal {
  opacity: 0; transform: translateY(22px);
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1), transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
  .reveal { opacity: 1; transform: none; }
}

:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }
[hidden] { display: none !important; }
