/* =========================================================
   Buttons
   ========================================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-primary);
  font-size: var(--size-12);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 14px 28px;
  border: 1px solid var(--color-primary);
  color: var(--color-primary);
  background: transparent;
  transition: var(--transition);
  white-space: nowrap;
}
.btn:hover { background: var(--color-primary); color: var(--color-white); }

.btn--solid { background: var(--color-primary); color: var(--color-white); }
.btn--solid:hover { background: var(--color-sea); border-color: var(--color-sea); color: var(--color-white); }

.txt_color_white .btn { border-color: var(--color-white); color: var(--color-white); }
.txt_color_white .btn:hover { background: var(--color-white); color: var(--color-clay); }

/* Underline link — the rule draws in from the left on hover */
.btn_underline {
  display: inline-block;
  position: relative;
  font-size: var(--size-12);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-primary);
  padding-bottom: 10px;
}
.btn_underline::before,
.btn_underline::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px;
}
.btn_underline::before { width: 100%; background: currentColor; opacity: .35; }
.btn_underline::after {
  width: 0; background: currentColor;
  transition: width .45s cubic-bezier(.22,.61,.36,1);
}
.btn_underline:hover::after, .hover-trigger:hover .btn_underline::after { width: 100%; }

/* Circular arrow button — ring of dots with an arrow sliding through */
.btn_arrow_circle {
  --size: 170px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  width: var(--size);
  height: var(--size);
  color: var(--color-terracotta);
  transition: color .3s ease;
  flex-shrink: 0;
}
.btn_arrow_circle svg { width: 100%; height: 100%; overflow: visible; }
.btn_arrow_circle .ring { transition: transform .8s cubic-bezier(.22,.61,.36,1); transform-origin: center; }
.btn_arrow_circle .arrow-line { transition: transform .45s cubic-bezier(.22,.61,.36,1); }
.btn_arrow_circle:hover, .hover-trigger:hover .btn_arrow_circle { color: var(--color-sea); }
.btn_arrow_circle:hover .ring, .hover-trigger:hover .btn_arrow_circle .ring { transform: rotate(120deg); }
.btn_arrow_circle:hover .arrow-line, .hover-trigger:hover .btn_arrow_circle .arrow-line { transform: translateX(10px); }

@media only screen and (max-width: 1024px) { .btn_arrow_circle { --size: 120px; } }
@media only screen and (max-width: 768px)  { .btn_arrow_circle { --size: 84px; } }

/* Ornament — the small rosette used as a section mark */
.ornament { display: block; margin-inline: auto; color: var(--color-terracotta); width: 34px; height: 34px; }
.ornament svg { width: 100%; height: 100%; }

/* Small rule with a centre dot, sits under an eyebrow */
.rule-dot { display: flex; align-items: center; justify-content: center; gap: 8px; color: var(--color-terracotta); }
.rule-dot::before, .rule-dot::after { content: ""; height: 1px; width: 36px; background: currentColor; opacity: .6; }
.rule-dot i { width: 5px; height: 5px; border: 1px solid currentColor; border-radius: 50%; }

/* =========================================================
   Header / navigation
   ========================================================= */
.site-header {
  height: var(--header-height);
  display: flex;
  align-items: center;
  transition: background-color .4s ease, transform .4s ease, box-shadow .4s ease;
  animation: chrome-in .8s .2s backwards ease-out;
}
.site-header__inner {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--spacing-20);
}

/* Over the hero the bar is transparent with white marks; once scrolled it fills. */
.site-sticky { color: var(--color-white); }
/* Pages whose banner is sand rather than a photograph: white marks would be
   invisible up there, so the bar starts dark instead. */
.chrome-dark .site-sticky { color: var(--color-text); }
.site-sticky.is-scrolled { color: var(--color-text); }
.site-sticky.is-scrolled .site-header {
  background-color: var(--color-chrome);
  box-shadow: 0 1px 0 rgba(54, 54, 54, .08);
}
.site-sticky.is-hidden { transform: translateY(-100%); }
.site-sticky { transition: transform .45s cubic-bezier(.22,.61,.36,1); }

/* White marks sit on whatever the hero photograph happens to be doing behind
   them. Measured against the real images the wordmark fell to 3.5:1 over the
   villa-day sky and the menu to 3.4:1 over the panorama — the per-image scrims
   are weighted for the h1 at the base of the frame, not for the bar at the top
   of it. This one belongs to the chrome instead: it travels with the bar, goes
   when the bar fills or retracts, and never darkens a picture that has no
   chrome over it. Sand-bannered pages have dark marks and do not want it. */
.site-header { position: relative; z-index: 1; }
.site-sticky::before {
  content: "";
  position: absolute; inset: 0 0 auto 0;
  height: calc(var(--header-height) * 1.7);
  background: linear-gradient(to bottom,
    rgba(13, 59, 71, .58) 0%, rgba(13, 59, 71, .38) 45%, rgba(13, 59, 71, 0) 100%);
  pointer-events: none;
  transition: opacity .4s ease;
}
.chrome-dark .site-sticky::before,
.site-sticky.is-scrolled::before { opacity: 0; }
/* The scrim handles the field of a photograph, but not a specular highlight:
   at some widths the moon in pool-night crops directly behind the wordmark on
   Enquire, and no scrim short of blacking out the hero beats it. So the marks
   carry a little of their own ground too. It reads as nothing on the dark parts
   of a frame, and is off wherever the marks are already dark. */
body:not(.chrome-dark) .site-sticky:not(.is-scrolled) .site-header__inner {
  text-shadow: 0 1px 10px rgba(13, 59, 71, .7), 0 0 4px rgba(13, 59, 71, .55);
}

.nav-toggle {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: var(--size-12); letter-spacing: .2em; text-transform: uppercase;
  color: currentColor; padding: 16px 0;
}
.nav-toggle__bars { display: block; width: 26px; height: 12px; position: relative; }
.nav-toggle__bars span {
  position: absolute; left: 0; height: 1px; width: 100%; background: currentColor;
  transition: transform .35s ease, opacity .25s ease, width .35s ease;
}
.nav-toggle__bars span:nth-child(1) { top: 0; }
.nav-toggle__bars span:nth-child(2) { top: 11px; width: 18px; }
.nav-toggle:hover .nav-toggle__bars span:nth-child(2) { width: 26px; }
.is-menu-open .nav-toggle__bars span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.is-menu-open .nav-toggle__bars span:nth-child(2) { transform: translateY(-6px) rotate(-45deg); width: 26px; }

.site-brand {
  justify-self: center;
  /* The gap sets where the type lands: the group stays centred in the bar, so
     opening it drops the type and lifts the mark by the same amount. The 65px
     bar below 1180px has no room for the wider setting. */
  display: flex; flex-direction: column; align-items: center; gap: 23px;
  text-decoration: none; color: currentColor;
}
.site-brand__mark {
  width: 30px; height: 30px; color: currentColor;
  /* Alone in the bar it sits on the centre line; as the wordmark rises to meet
     it, it lifts to its place above the type. JS drives --mark-y. */
  transform: translateY(var(--mark-y, 0px));
}
.site-brand__name {
  font-family: var(--font-secondary);
  /* Prata is a hairline serif: at 13px its thins fall under a pixel and
     antialias to pale grey, so the type measured 11.5:1 on paper and read at
     about 1.5:1 on screen. 16px is where the ink density catches up with the
     rest of the small type on the site — see DESIGN-NOTES. The vw term is
     untouched, so narrow phones keep the compact setting the bar needs. */
  font-size: clamp(10px, 2.9vw, 16px); letter-spacing: .3em; text-transform: uppercase; line-height: 1;
  margin-right: -.3em;   /* discount the trailing letter-space so the type centres */
  color: currentColor;
}
.header-actions { justify-self: end; display: flex; align-items: center; gap: var(--spacing-16); }
.site-sticky .header-actions .btn { border-color: currentColor; color: currentColor; }
.site-sticky .header-actions .btn:hover { background: var(--color-white); color: var(--color-clay); border-color: var(--color-white); }
.site-sticky.is-scrolled .header-actions .btn:hover { background: var(--color-primary); color: var(--color-white); border-color: var(--color-primary); }

@media only screen and (max-width: 768px) {
  .nav-toggle__label { display: none; }
  .header-actions .btn { padding: 11px 16px; font-size: 11px; letter-spacing: .12em; }
}

/* Slide-out panel */
.nav-panel {
  position: fixed; inset: 0 auto 0 0; z-index: 60;
  width: var(--mobile-menu-width); max-width: 88vw;
  background: var(--color-chrome);
  padding: var(--spacing-40) var(--spacing-40) var(--spacing-32);
  display: flex; flex-direction: column; gap: var(--spacing-32);
  transform: translateX(-100%);
  transition: transform .55s cubic-bezier(.76,0,.24,1);
  overflow-y: auto;
}
.is-menu-open .nav-panel { transform: translateX(0); }
.nav-panel__close {
  align-self: flex-end; color: var(--color-primary); font-size: 22px; line-height: 1;
  width: 44px; height: 44px; display: grid; place-items: center; padding: 0; margin: -8px -8px 0 0;
}

.nav-panel__list { display: flex; flex-direction: column; gap: 2px; }
.nav-panel__list a {
  font-family: var(--font-secondary);
  font-size: var(--size-24);
  color: var(--color-heading);
  text-decoration: none;
  padding: 10px 0;
  display: block;
  /* staggered entry, driven by --i set on each item */
  opacity: 0; transform: translateX(-16px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1), color .3s ease;
  transition-delay: calc(var(--i, 0) * 55ms);
}
.is-menu-open .nav-panel__list a { opacity: 1; transform: translateX(0); }
.nav-panel__list a span { position: relative; display: inline-block; }
.nav-panel__list a span::after {
  content: ""; position: absolute; left: 0; bottom: -4px; height: 1px; width: 0;
  background: currentColor; transition: width .4s cubic-bezier(.22,.61,.36,1);
}
.nav-panel__list a:hover { color: var(--color-sea); }
.nav-panel__list a:hover span::after { width: 100%; }

/* The page you are on. Terracotta only reaches 4.02:1 on sand, so the marker is
   the rule the site already draws plus a dot — not a colour change on the text. */
.nav-panel__list a[aria-current="page"] span::after { width: 100%; opacity: .55; }
.nav-panel__list a[aria-current="page"] span::before {
  content: ""; position: absolute; left: -18px; top: 50%;
  width: 5px; height: 5px; margin-top: -2px;
  border-radius: 50%; background: var(--color-terracotta);
}

.nav-panel__meta { margin-top: auto; font-size: var(--size-14); line-height: 1.9; }
.nav-panel__meta a { text-decoration: none; }

.nav-scrim {
  position: fixed; inset: 0; z-index: 50;
  background: var(--color-scrim);
  opacity: 0; visibility: hidden;
  transition: opacity .45s ease, visibility .45s;
}
.is-menu-open .nav-scrim { opacity: 1; visibility: visible; }

@media only screen and (max-width: 1180px) {
  .site-brand { gap: 9px; }
  .site-brand__mark { width: 26px; height: 26px; }
}

/* On a phone the bar has three jobs and about 330px to do them in. The wordmark
   is the expensive one — at 13px with .3em tracking it is 176px, over half the
   usable width — so the whole group is compacted rather than anything dropped.
   Measured need falls from 334px to comfortably inside a 320px screen. */
@media only screen and (max-width: 600px) {
  .site-header__inner { gap: 12px; }
}

/* =========================================================
   Hero
   ========================================================= */
.hero { position: relative; background: var(--color-sand-2); z-index: 1; }
.hero__media {
  position: relative;
  height: clamp(460px, 100svh, 1000px);
  overflow: hidden;
}
.hero__media picture { display: block; width: 100%; height: 100%; }
.hero__media img {
  width: 100%; height: 100%; object-fit: cover;
  animation: hero-image-in 1.6s cubic-bezier(.22,.61,.36,1) both;
}
/* Weighted to the base: the wordmark sits over the lit terrace, which is the
   brightest part of the frame. */
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(0,0,0,.22) 0%, rgba(0,0,0,0) 28%, rgba(0,0,0,.10) 58%, rgba(0,0,0,.52) 100%);
  pointer-events: none;
}

/* Oversized wordmark straddling the base of the image */
/* Fixed so it can travel up into the header as the page scrolls —
   JS sets --wm-y / --wm-scale / --wm-opacity each frame. */
.hero__wordmark {
  position: fixed;
  top: 0; left: 0;
  width: 100%;
  z-index: 45;
  margin: 0;
  font-family: var(--font-secondary);
  font-size: clamp(20px, 6.9vw, 104px);
  line-height: 1;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--color-chrome);
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  transform-origin: center center;
  transform: translate3d(0, var(--wm-y, 0px), 0) scale(var(--wm-scale, 1));
  will-change: transform;
  backface-visibility: hidden;
}
/* Entry animation lives on the span so it doesn't fight the scroll transform. */
/* inline-block, not block: the morph derives its target scale from this span's
   offsetWidth, and a block would report the container width instead of the
   width of the type. */
.hero__wordmark span {
  display: inline-block;
  margin-right: -.3em;   /* as above — at hero size the trailing space is ~14px */
  animation: wordmark-in 1.1s .35s cubic-bezier(.22,.61,.36,1) both;
}
/* Landed: --wm-y is constant from here, so a transition is safe and lets the
   wordmark retract with the bar instead of floating over the page. */
.hero__wordmark.is-landed {
  transition: transform .45s cubic-bezier(.22,.61,.36,1), color .4s ease;
}
/* White over the photograph, ink once the bar fills behind it. */
.is-chrome-filled .hero__wordmark { color: var(--color-text); }

/* The header brand name fades up as the big wordmark shrinks into it. */
.is-morphing .site-brand__name { visibility: hidden; }

/* Without the morph running, the wordmark just sits at the base of the image. */
.no-morph .hero__wordmark { position: absolute; bottom: auto; transform: none; }

/* =========================================================
   Page banner — the inner pages' answer to the home hero.
   Shorter, so the content behind it starts sooner.
   ========================================================= */
.page-hero { position: relative; background: var(--color-deep-sea); }
.page-hero__media { position: relative; height: clamp(300px, 52svh, 520px); overflow: hidden; }
.page-hero__media picture { display: block; width: 100%; height: 100%; }
.page-hero__media img {
  width: 100%; height: 100%; object-fit: cover;
  animation: hero-image-in 1.6s cubic-bezier(.22,.61,.36,1) both;
}
.page-hero__media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(0,0,0,.42) 0%, rgba(0,0,0,.12) 40%, rgba(13,59,71,.78) 100%);
}
.page-hero__body {
  position: absolute; left: 0; right: 0; bottom: var(--spacing-48);
  color: var(--color-white);
  animation: rv-btt .9s .25s cubic-bezier(.22,.61,.36,1) both;
}
.page-hero__body .txt_sub_title { display: block; color: var(--color-white); opacity: .82; margin-bottom: var(--spacing-12); }
.page-hero__body h1 { color: var(--color-white); max-width: 18ch; text-wrap: balance; }
.page-hero__lede { max-width: 52ch; margin-top: var(--spacing-16); margin-bottom: 0; opacity: .9; }

/* No image: type on sand, where the page's first block is the visual. */
.page-hero--plain { background: var(--color-sand-1); padding-block: calc(var(--header-height) + var(--spacing-64)) var(--spacing-56); }
.page-hero--plain .page-hero__body { position: static; color: var(--color-text); text-align: center; }
.page-hero--plain .page-hero__body .txt_sub_title { color: var(--color-primary); opacity: 1; }
.page-hero--plain .page-hero__body h1 { color: var(--color-heading); margin-inline: auto; }
.page-hero--plain .page-hero__lede { margin-inline: auto; opacity: 1; }

@media only screen and (max-width: 768px) {
  .page-hero__body { bottom: var(--spacing-32); }
  .page-hero__body h1 { max-width: none; }
}

/* =========================================================
   The view, teased — the homepage's one full-bleed moment, and
   the way in to the page that actually earns the villa its rate.
   ========================================================= */
.viewband { position: relative; }
.viewband__link { display: block; position: relative; overflow: hidden; text-decoration: none; color: var(--color-white); }
.viewband__link picture { display: block; height: clamp(280px, 38vw, 460px); }
.viewband__link img {
  width: 100%; height: 100%; object-fit: cover; object-position: center 62%;
  transition: transform 1s cubic-bezier(.22,.61,.36,1);
}
.viewband__link::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(13,59,71,.15) 0%, rgba(13,59,71,.08) 45%, rgba(13,59,71,.82) 100%);
}
.viewband__link:hover img { transform: scale(1.04); }

.viewband__body {
  position: absolute; left: 0; right: 0; bottom: var(--spacing-40);
  z-index: 2; display: block;
}
.viewband__eyebrow { display: block; color: var(--color-white); opacity: .82; margin-bottom: var(--spacing-12); }
.viewband__title {
  display: block; max-width: 24ch;
  font-family: var(--font-secondary); font-size: var(--size-h3); line-height: 1.35;
  text-wrap: balance;
}
.viewband__cue {
  display: inline-block; position: relative; margin-top: var(--spacing-20);
  font-size: var(--size-12); font-weight: 500; letter-spacing: .2em; text-transform: uppercase;
  padding-bottom: 8px;
}
.viewband__cue::before,
.viewband__cue::after { content: ""; position: absolute; left: 0; bottom: 0; height: 1px; background: currentColor; }
.viewband__cue::before { width: 100%; opacity: .4; }
.viewband__cue::after { width: 0; transition: width .45s cubic-bezier(.22,.61,.36,1); }
.viewband__link:hover .viewband__cue::after { width: 100%; }

@media only screen and (max-width: 768px) {
  .viewband__body { bottom: var(--spacing-24); }
  .viewband__title { font-size: var(--size-h4); max-width: none; }
}

/* =========================================================
   Ways in — the homepage is a hub, not a dead end. Without
   these the only route to the other five pages is the menu.
   ========================================================= */
.waysin { padding-block: var(--spacing-default); }
.waysin__grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--spacing-40);
  margin: 0; padding: 0; list-style: none;
}
.waysin__card { display: block; text-decoration: none; color: inherit; }
.waysin__frame {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 3; margin-bottom: var(--spacing-20);
  background: var(--color-sand-2);
}
.waysin__frame picture, .waysin__frame img { display: block; width: 100%; height: 100%; }
.waysin__frame img { object-fit: cover; transition: transform .7s cubic-bezier(.22,.61,.36,1); }
.waysin__frame::after {
  content: ""; position: absolute; inset: 0; background: var(--color-black);
  opacity: 0; transition: opacity .35s ease;
}
.waysin__card:hover .waysin__frame img,
.waysin__card:focus-visible .waysin__frame img { transform: scale(1.05); }
.waysin__card:hover .waysin__frame::after,
.waysin__card:focus-visible .waysin__frame::after { opacity: .18; }

.waysin__label {
  display: inline-block; position: relative;
  font-family: var(--font-secondary); font-size: var(--size-h5);
  color: var(--color-heading); padding-bottom: 6px;
}
.waysin__label::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 0;
  background: currentColor; transition: width .45s cubic-bezier(.22,.61,.36,1);
}
.waysin__card:hover .waysin__label::after,
.waysin__card:focus-visible .waysin__label::after { width: 100%; }
.waysin__note {
  display: block; margin-top: var(--spacing-8);
  font-size: var(--size-15); line-height: 1.6; max-width: 32ch;
}

@media only screen and (max-width: 900px) {
  .waysin__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-32); }
}
@media only screen and (max-width: 620px) {
  .waysin__grid { grid-template-columns: 1fr; gap: var(--spacing-40); }
}

/* Where the rating actually comes from, under the quotes. */
.reviews__source {
  margin: var(--spacing-48) 0 0; text-align: center;
  font-size: var(--size-14); color: rgba(54, 54, 54, .75);
}
.reviews__source strong { color: var(--color-primary); font-weight: 500; }
.reviews__source a { color: var(--color-primary); text-decoration: underline; text-underline-offset: 3px; }
.reviews__source a:hover { color: var(--color-sea); }

/* =========================================================
   Gallery
   ========================================================= */
.gallery { padding-block: var(--spacing-default); }
/* Column flow rather than a grid: portraits and landscapes pack without the
   dead space a row-based grid leaves under a tall photograph. Each tile keeps
   its own proportions — build.js writes --ratio from the file's real size, so
   nothing is cropped to fit a slot. */
.gallery__grid {
  columns: 3;
  column-gap: var(--spacing-24);
  margin: 0; padding: 0; list-style: none;
}
.gallery__item {
  break-inside: avoid;
  display: block;
  margin-bottom: var(--spacing-32);
}
/* The panorama earns the full width and splits the flow above and below it. */
.gallery__item.is-panoramic { column-span: all; }

.gallery__open { display: block; width: 100%; padding: 0; text-align: left; }
.gallery__frame {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: var(--ratio);
  background: var(--color-sand-2);
}
.gallery__frame picture, .gallery__frame img { width: 100%; height: 100%; }
.gallery__frame img { object-fit: cover; transition: transform .7s cubic-bezier(.22,.61,.36,1); }
.gallery__frame::after {
  content: ""; position: absolute; inset: 0; background: var(--color-black);
  opacity: 0; transition: opacity .35s ease;
}
.gallery__open:hover .gallery__frame img,
.gallery__open:focus-visible .gallery__frame img { transform: scale(1.05); }
.gallery__open:hover .gallery__frame::after,
.gallery__open:focus-visible .gallery__frame::after { opacity: .22; }

/* The caption sits below the button rather than inside it, so a tile can carry
   a second, separately-clickable link — the panorama points on to the viewer
   that names what is in it. They wrap onto their own lines when space is tight. */
.gallery__foot {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: var(--spacing-4) var(--spacing-16);
  margin-top: var(--spacing-12);
}
.gallery__caption {
  font-size: var(--size-12); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--color-primary); opacity: .75;
  transition: opacity .3s ease;
}
.gallery__item:hover .gallery__caption { opacity: 1; }
.gallery__aside {
  font-size: var(--size-12); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--color-sea);
  border-bottom: 1px solid rgba(20, 80, 95, .35);
  transition: color .3s ease, border-color .3s ease;
}
.gallery__aside:hover { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.gallery__note {
  margin-top: var(--spacing-56); text-align: center;
  font-size: var(--size-14); color: rgba(54,54,54,.7);
}
.gallery__note a { color: var(--color-primary); text-decoration: underline; text-underline-offset: 3px; }
.gallery__note a:hover { color: var(--color-sea); }

@media only screen and (max-width: 1100px) {
  .gallery__grid { columns: 2; column-gap: var(--spacing-20); }
}
@media only screen and (max-width: 700px) {
  .gallery__grid { columns: 1; }
}

/* Grouped gallery runs. */
.gallery__group { margin: var(--spacing-64) 0 var(--spacing-24); }
.gallery__group:first-child { margin-top: 0; }
.gallery__group-title { display: block; margin-bottom: var(--spacing-8); }
.gallery__group-note { margin: 0; font-size: var(--size-15); color: rgba(54, 54, 54, .72); max-width: 46ch; }

/* "Keep looking" — two cards, so no page is a dead end. */
.waysin--next { padding-block: var(--spacing-72); }
.waysin__kicker { display: block; text-align: center; margin-bottom: var(--spacing-32); }
.waysin__grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media only screen and (max-width: 620px) {
  .waysin__grid--pair { grid-template-columns: 1fr; }
}

/* =========================================================
   Lightbox
   ========================================================= */
.lightbox {
  position: fixed; inset: 0; z-index: 100;
  display: grid; grid-template-rows: auto 1fr auto;
  background: rgba(9, 34, 41, .97);
  opacity: 0; visibility: hidden;
  transition: opacity .35s ease, visibility .35s;
}
.lightbox.is-open { opacity: 1; visibility: visible; }
.lightbox__bar { display: flex; align-items: center; justify-content: space-between; padding: var(--spacing-20) var(--gap-side); }
.lightbox__count { font-size: var(--size-12); letter-spacing: .2em; color: rgba(255,255,255,.6); font-variant-numeric: tabular-nums; }
.lightbox__close { width: 44px; height: 44px; display: grid; place-items: center; color: rgba(255,255,255,.75); transition: color .3s ease; }
.lightbox__close:hover { color: #fff; }
.lightbox__close svg { width: 18px; height: 18px; }

/* The explicit minmax(0, 1fr) track is what makes the photograph fit. Left to
   an implicit `auto` track, the cell is sized *from* its content, so the img's
   `max-height: 100%` resolves against a height that depends on the img — the
   browser calls that cyclic and drops the cap, and a portrait shot runs off the
   bottom of the screen at its full height. A definite track breaks the cycle. */
.lightbox__stage {
  position: relative; display: grid;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  place-items: center; padding-inline: var(--gap-side); min-height: 0;
}
/* The stage wraps its img in a <picture> to reach the WebP set; `contents`
   keeps the img itself the grid item. Its <source> sibling becomes one too, and
   auto-placement hands that the explicit cell and pushes the img into an
   implicit row — so the img is placed by hand rather than left to fall where
   the source leaves it. */
.lightbox__stage picture { display: contents; }
.lightbox__stage img {
  grid-area: 1 / 1;
  max-width: 100%; max-height: 100%;
  width: auto; height: auto; object-fit: contain;
}
.lightbox__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 56px; height: 56px; display: grid; place-items: center;
  color: rgba(255,255,255,.75); transition: color .3s ease, transform .3s ease;
}
.lightbox__nav:hover { color: #fff; }
.lightbox__nav svg { width: 40px; height: 12px; }
.lightbox__nav--prev { left: 8px; }
.lightbox__nav--next { right: 8px; }
.lightbox__nav--prev:hover { transform: translateY(-50%) translateX(-5px); }
.lightbox__nav--next:hover { transform: translateY(-50%) translateX(5px); }

.lightbox__caption {
  padding: var(--spacing-20) var(--gap-side) var(--spacing-32);
  text-align: center;
  font-family: var(--font-secondary);
  font-size: var(--size-20); line-height: 1.5;
  color: rgba(255,255,255,.9);
}

@media only screen and (max-width: 768px) {
  .lightbox__nav { width: 44px; height: 44px; }
  .lightbox__nav svg { width: 26px; }
  .lightbox__caption { font-size: var(--size-16); padding-bottom: var(--spacing-24); }
}

/* =========================================================
   Booking bar
   ========================================================= */
.booking { padding-block: var(--spacing-64) var(--spacing-72); }
.booking__head { text-align: center; margin-bottom: var(--spacing-40); }
.booking__head .ornament { margin-bottom: var(--spacing-12); }
.booking__head .txt_sub_title { margin-bottom: var(--spacing-20); display: block; }
.booking__head h2 { max-width: 22ch; margin-inline: auto; }

.booking__form {
  position: relative; z-index: 3;
  display: grid;
  grid-template-columns: repeat(3, 1fr) auto;
  align-items: stretch;
  border: 1px solid rgba(138, 79, 45, .35);
  background: var(--color-white);
  padding: 10px;
  gap: 0;
  max-width: 1000px;
  margin-inline: auto;
}
.booking__field { position: relative; display: flex; flex-direction: column; justify-content: center; padding: 6px 20px; }
.booking__field + .booking__field { border-left: 1px solid rgba(138, 79, 45, .18); }
.booking__field label {
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--color-primary); margin-bottom: 4px;
}
.booking__field input, .booking__field select {
  border: 0; background: transparent; padding: 0;
  font-size: var(--size-14); color: var(--color-text); width: 100%;
  appearance: none; cursor: pointer;
}
.booking__field input::-webkit-calendar-picker-indicator { opacity: .45; cursor: pointer; }
.booking__field select { background-image: none; }
.booking__field::after {
  content: ""; position: absolute; right: 20px; top: 50%; width: 7px; height: 7px;
  border-right: 1px solid var(--color-primary); border-bottom: 1px solid var(--color-primary);
  transform: translateY(-25%) rotate(45deg); pointer-events: none; opacity: .7;
}
.booking__field--date::after { display: none; }
.booking__submit { padding: 16px 40px; margin: 0; }
.booking__note {
  text-align: center; max-width: 1000px; margin: var(--spacing-16) auto 0;
  font-size: var(--size-14); color: rgba(54,54,54,.7);
}
.booking__note a { color: var(--color-primary); text-decoration: underline; text-underline-offset: 3px; }
.booking__note a:hover { color: var(--color-sea); }

@media only screen and (max-width: 900px) {
  .booking__form { grid-template-columns: 1fr 1fr; gap: 2px; }
  .booking__field + .booking__field { border-left: 0; }
  .booking__field { border: 1px solid rgba(138,79,45,.14); padding: 12px 16px; }
  .booking__submit { grid-column: 1 / -1; }
}
@media only screen and (max-width: 520px) {
  .booking__form { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------
   Branded pickers. Browsers won't style their own date and
   select popups, so JS hides the native controls (which still
   carry the submitted values) and drives these instead.
   --------------------------------------------------------- */
.is-enhanced input[type="date"],
.is-enhanced select { display: none; }

.picker__trigger {
  display: flex; align-items: center; gap: var(--spacing-8);
  width: 100%; padding: 0; text-align: left; line-height: 1.4;
  font-size: var(--size-14); color: var(--color-text);
}
.picker__value.is-empty { color: rgba(54, 54, 54, .55); }
.picker__icon {
  flex: none; width: 14px; height: 14px; margin-left: auto;
  color: var(--color-primary); opacity: .7; transition: opacity .3s ease;
}
.booking__field.is-open .picker__icon { opacity: 1; }
.booking__field.is-open::after { transform: translateY(-25%) rotate(-135deg); }

.cal, .listbox {
  position: absolute; top: calc(100% + 12px); left: -1px; z-index: 20;
  background: var(--color-white);
  border: 1px solid rgba(138, 79, 45, .35);
  box-shadow: 0 30px 60px -34px rgba(13, 59, 71, .5);
}
.cal[hidden], .listbox[hidden] { display: none; }
.cal:not([hidden]), .listbox:not([hidden]) { animation: picker-in .22s 1 cubic-bezier(.22, .61, .36, 1); }

.cal { padding: var(--spacing-24); }
.cal__nav { position: absolute; top: var(--spacing-24); padding: 4px; color: var(--color-primary); opacity: .8; }
.cal__nav--prev { left: var(--spacing-24); }
.cal__nav--next { right: var(--spacing-24); }
.cal__nav svg { display: block; width: 24px; height: 10px; transition: transform .4s cubic-bezier(.22, .61, .36, 1); }
.cal__nav:hover { opacity: 1; color: var(--color-sea); }
.cal__nav--prev:hover svg { transform: translateX(-4px); }
.cal__nav--next:hover svg { transform: translateX(4px); }
.cal__nav:disabled { opacity: .2; cursor: default; }
.cal__nav:disabled:hover { color: var(--color-primary); }
.cal__nav:disabled:hover svg { transform: none; }

.cal__months { display: flex; gap: var(--spacing-32); }
.cal__month { border-collapse: collapse; }
.cal__caption {
  font-family: var(--font-secondary); font-size: var(--size-16); text-align: center;
  color: var(--color-primary); padding-bottom: var(--spacing-16); white-space: nowrap;
}
.cal__month th {
  font-size: 10px; font-weight: 500; letter-spacing: .18em; text-transform: uppercase;
  color: var(--color-primary); opacity: .7; padding-bottom: var(--spacing-8);
}
.cal__month th abbr { text-decoration: none; }
.cal__month td { padding: 0; }

.cal__day {
  position: relative; width: 40px; height: 40px;
  font-size: var(--size-14); color: var(--color-text);
  transition: background-color .25s ease, color .25s ease;
}
.cal__day:hover:not(:disabled), .cal__day.is-range { background: var(--color-sand-2); color: var(--color-primary); }
.cal__day.is-preview { background: var(--color-sand-2); color: var(--color-primary); box-shadow: inset 0 0 0 1px rgba(138, 79, 45, .4); }
.cal__day.is-start, .cal__day.is-end { background: var(--color-primary); color: var(--color-white); }
.cal__day:disabled { color: rgba(54, 54, 54, .25); cursor: default; }
.cal__day:focus-visible { outline-offset: -2px; }
.cal__day.is-today::after {
  content: ""; position: absolute; left: 50%; bottom: 7px; width: 3px; height: 3px;
  border-radius: 50%; background: var(--color-terracotta); transform: translateX(-50%);
}
.cal__day.is-start.is-today::after, .cal__day.is-end.is-today::after { background: rgba(255, 255, 255, .85); }

.cal__foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-24);
  margin-top: var(--spacing-20); padding-top: var(--spacing-16);
  border-top: 1px solid rgba(138, 79, 45, .18);
}
.cal__summary { margin: 0; font-size: var(--size-14); color: rgba(54, 54, 54, .75); }
.cal__clear { flex: none; padding-bottom: 6px; }

.listbox { top: calc(100% + 22px); right: -1px; min-width: 170px; padding: var(--spacing-8); list-style: none; }
.listbox__opt {
  padding: 10px 14px; font-size: var(--size-14); color: var(--color-text); cursor: pointer;
  transition: background-color .2s ease, color .2s ease;
}
.listbox__opt:hover { background: var(--color-sand-2); color: var(--color-primary); }
.listbox__opt[aria-selected="true"] { background: var(--color-primary); color: var(--color-white); }
.listbox__opt[aria-selected="true"]:hover { background: var(--color-sea); color: var(--color-white); }
.listbox__opt:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }

@media only screen and (max-width: 900px) {
  .cal { left: 0; right: 0; }
  .cal__months { justify-content: center; }
  .listbox { top: calc(100% + 12px); }
}
@media only screen and (max-width: 520px) {
  .cal { padding: var(--spacing-16); }
  .cal__nav { top: var(--spacing-16); }
  .cal__nav--prev { left: var(--spacing-12); }
  .cal__nav--next { right: var(--spacing-12); }
  .cal__month { width: 100%; }
  .cal__day { width: 100%; height: 44px; }
  .cal__foot { flex-direction: column; align-items: flex-start; gap: var(--spacing-12); }
}

/* =========================================================
   Feature row — narrow text column, large image bleeding right
   ========================================================= */
.feature { padding-bottom: var(--spacing-default); }
.feature__grid {
  display: grid;
  grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
  gap: var(--spacing-64);
  align-items: start;
}
.feature__text { padding-top: var(--spacing-24); }
.feature__thumb { width: 100%; max-width: 320px; margin-bottom: var(--spacing-32); }
.feature__thumb img { aspect-ratio: 4 / 3; object-fit: cover; width: 100%; }
.feature__text h2 { margin-bottom: var(--spacing-20); }
.feature__text p { font-size: var(--size-15); line-height: 1.75; }

/* Image column runs past the container to the viewport edge */
.feature__media {
  position: relative;
  margin-right: calc(var(--gap-side) * -1);
}
.feature__media img { width: 100%; aspect-ratio: 16 / 11; object-fit: cover; }

.feature--reverse .feature__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 420px); }
.feature--reverse .feature__text { order: 2; }
.feature--reverse .feature__media { order: 1; margin-right: 0; margin-left: calc(var(--gap-side) * -1); }

@media only screen and (max-width: 1024px) {
  .feature__grid, .feature--reverse .feature__grid { grid-template-columns: 1fr; gap: var(--spacing-32); }
  .feature__media, .feature--reverse .feature__media {
    order: -1; margin-inline: calc(var(--gap-side) * -1);
  }
  .feature--reverse .feature__text { order: 0; }
  .feature__thumb { display: none; }
}

/* =========================================================
   Rooms / spaces slider
   ========================================================= */
.spaces { padding-bottom: 0; }
.slider { position: relative; }
.slider__viewport { position: relative; overflow: hidden; height: clamp(320px, 52vw, 620px); }
.slider__slide {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden;
  transition: opacity .9s cubic-bezier(.22,.61,.36,1), visibility .9s;
}
.slider__slide.is-active { opacity: 1; visibility: visible; }
/* The <picture> must carry the slide's height or the img inside it sizes to the
   file's own aspect and object-fit never gets a box to cover. */
.slider__slide picture { height: 100%; }
.slider__slide img { width: 100%; height: 100%; object-fit: cover; }

/* Slow drift on the active slide */
.slider__slide.is-active img { animation: slide-drift 7s linear both; }
@keyframes slide-drift { 0% { transform: scale(1.02); } 100% { transform: scale(1.08); } }

/* A white hairline over bright photography is invisible, and these sat over a
   pool and a bleached terrace. Same problem the outlook pins have, so the same
   answer: a deep-sea plate to stand on, at the alpha those pins already use —
   which holds 3.9:1 for the arrow even against the whitest frame in the set. */
.slider__nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 84px; height: 48px; display: grid; place-items: center;
  border-radius: 999px;
  color: var(--color-white);
  background: rgba(13, 59, 71, .62);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
  transition: background-color .3s ease;
}
.slider__nav:hover { background: rgba(13, 59, 71, .82); }
/* The global focus ring squares off whatever it lands on, so restate the pill. */
.slider__nav:focus-visible { border-radius: 999px; background: rgba(13, 59, 71, .82); }
.slider__nav svg { width: 40px; height: 12px; transition: transform .4s cubic-bezier(.22,.61,.36,1); }
.slider__nav svg path { stroke-width: 1.5; }
.slider__nav--prev { left: var(--spacing-24); }
.slider__nav--next { right: var(--spacing-24); }
.slider__nav--prev:hover svg { transform: translateX(-6px); }
.slider__nav--next:hover svg { transform: translateX(6px); }

/* Caption band */
.spaces__info { background: var(--color-sand-2); padding-block: var(--spacing-48) var(--spacing-56); }
.spaces__info-grid {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr) auto;
  gap: var(--spacing-40);
  align-items: center;
}
.spaces__title { margin: 0; }
.spaces__copy p { margin-bottom: var(--spacing-24); max-width: 62ch; }

.room-specs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--spacing-24) var(--spacing-32);
}
.room-specs__item { padding-left: var(--spacing-20); border-left: 1px solid rgba(138, 79, 45, .25); }
.room-specs__label { display: block; margin-bottom: 6px; }
.room-specs__value { font-size: var(--size-15); color: var(--color-text); }

/* Cross-fade the caption text in step with the slide */
.spaces__fade { transition: opacity .35s ease; }
.spaces__fade.is-swapping { opacity: 0; }

.slider__dots { display: flex; gap: 10px; margin-top: var(--spacing-24); }
.slider__dots button {
  width: 34px; height: 2px; background: rgba(138,79,45,.3); padding: 0;
  transition: background .35s ease;
}
.slider__dots button.is-active { background: var(--color-primary); }

@media only screen and (max-width: 1024px) {
  .spaces__info-grid { grid-template-columns: 1fr; gap: var(--spacing-24); }
  .btn_arrow_circle { display: none; }
  /* Shorter plates and a stubbier arrow: there is no swipe, so these stay on
     phones, but at 84px they took a fifth of the frame on each side. */
  .slider__nav { width: 60px; height: 44px; }
  .slider__nav svg { width: 28px; }
  .slider__nav--prev { left: var(--spacing-12); }
  .slider__nav--next { right: var(--spacing-12); }
}
@media only screen and (max-width: 900px) {
  .room-specs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media only screen and (max-width: 560px) {
  .room-specs { grid-template-columns: 1fr; gap: var(--spacing-20); }
}

/* =========================================================
   At a glance — the qualifying facts, set as label/value pairs
   in the same typographic idiom as .room-specs rather than icons.
   ========================================================= */
.glance { padding-block: var(--spacing-64); }
.glance__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--spacing-40) var(--spacing-32);
}
.glance__item { padding-left: var(--spacing-24); border-left: 1px solid rgba(138, 79, 45, .25); }
.glance__item dt { margin-bottom: var(--spacing-8); }
.glance__item dd { margin: 0; font-size: var(--size-15); line-height: 1.6; max-width: 24ch; }

/* Where the terms above came from. The listing sets them and prices the dates,
   so this carries the date they were last read rather than a figure. */
.glance__source {
  margin-top: var(--spacing-56);
  text-align: center;
  font-size: var(--size-14);
  opacity: .85;
}

@media only screen and (max-width: 700px) {
  .glance__grid { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-32) var(--spacing-20); }
}
@media only screen and (max-width: 420px) {
  .glance__grid { grid-template-columns: 1fr; }
}

/* =========================================================
   The outlook — the panorama, dragged sideways, with the
   landmarks named. The one thing on this page a competitor
   can't copy, because they don't have the sightline.
   ========================================================= */
.outlook { padding-block: var(--spacing-default) var(--spacing-64); }
/* On its own page the banner does the heading, so the section starts sooner. */
.outlook--bare { padding-top: var(--spacing-56); }
.outlook__head { text-align: center; margin-bottom: var(--spacing-40); }
.outlook__head .ornament { margin-bottom: var(--spacing-12); }
.outlook__head .txt_sub_title { display: block; margin-bottom: var(--spacing-20); }
.outlook__head h2 { max-width: 20ch; margin-inline: auto; }
.outlook__lede { max-width: 54ch; margin: var(--spacing-20) auto 0; }

.outlook__frame { position: relative; }

/* The viewport holds the soft edges; the scroller inside it does the moving. */
.outlook__viewport { position: relative; }

/* The panorama goes out of focus at the edges rather than bleaching to sand —
   a wash over that sky read as a smudge. Two masked backdrop layers, the second
   blurring what the first already blurred, ramp it up like depth of field.
   The layers have to be the pseudo-elements and the box itself has to stay
   plain: backdrop-filter, mask and opacity each make an element a backdrop root,
   which would leave its children with nothing behind them to blur. That is also
   why the reveal at either end runs on the layers rather than on the box. */
.outlook__edge {
  position: absolute; top: 0; bottom: 0; width: clamp(80px, 9vw, 140px);
  pointer-events: none; z-index: 3;
}
.outlook__edge::before,
.outlook__edge::after {
  content: ""; position: absolute; inset: 0;
  transition: opacity .45s ease;
}
.outlook__edge::before {
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  mask-image: linear-gradient(to var(--out), transparent, #000 60%);
}
.outlook__edge::after {
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  mask-image: linear-gradient(to var(--out), transparent 40%, #000 100%);
}
.outlook__edge--start { left: 0; --out: left; }
.outlook__edge--end { right: 0; --out: right; }
.outlook__frame.at-start .outlook__edge--start::before,
.outlook__frame.at-start .outlook__edge--start::after,
.outlook__frame.at-end .outlook__edge--end::before,
.outlook__frame.at-end .outlook__edge--end::after { opacity: 0; }

.outlook__scroll {
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  cursor: grab;
  scrollbar-width: thin;
  scrollbar-color: rgba(138, 79, 45, .45) transparent;
}
.outlook__scroll.is-dragging { cursor: grabbing; scroll-behavior: auto; }
.outlook__scroll::-webkit-scrollbar { height: 4px; }
.outlook__scroll::-webkit-scrollbar-thumb { background: rgba(138, 79, 45, .45); }
/* Without JS the native bar is the only affordance. Once the rail is built it
   says the same thing better, so the bar comes off the photograph. */
.outlook__frame.has-rail .outlook__scroll { scrollbar-width: none; }
.outlook__frame.has-rail .outlook__scroll::-webkit-scrollbar { height: 0; }

/* Wider than the viewport on purpose — the drag is the point. Capped at the
   panorama's own 2304px so the sweep never costs sharpness. */
.outlook__stage { position: relative; width: clamp(1100px, 170vw, 2304px); }
.outlook__stage img { width: 100%; height: auto; display: block; }

.outlook__pin {
  position: absolute;
  left: var(--x); top: var(--y);
  transform: translate(-50%, -100%);
  padding: 0 0 var(--spacing-8);
  display: flex; flex-direction: column; align-items: center;
  color: var(--color-white);
  z-index: 2;
}
/* Riser from the dot up to the tag, so the label never sits on the landmark itself. */
.outlook__dot { position: relative; display: block; width: 7px; height: 7px; }
.outlook__dot::before {
  content: ""; position: absolute; inset: 0;
  border: 1px solid currentColor; border-radius: 50%;
  background: rgba(0, 0, 0, .35);
  transition: transform .3s ease, background-color .3s ease;
}
.outlook__dot::after {
  content: ""; position: absolute; left: 50%; bottom: 100%;
  width: 1px; height: 18px; background: currentColor; opacity: .7;
}
.outlook__tag {
  order: -1;
  display: block; text-align: center;
  margin-bottom: 26px;
  white-space: nowrap;
}
/* A plate rather than a text-shadow: these labels sit over bright sky and
   pale water, where a shadow alone leaves white type swimming. */
.outlook__name {
  display: inline-block;
  padding: 5px 12px 6px;
  background: rgba(13, 59, 71, .62);
  backdrop-filter: blur(2px);
  font-family: var(--font-secondary);
  font-size: var(--size-16);
  line-height: 1.2;
  letter-spacing: .02em;
}
.outlook__note {
  display: block;
  max-width: 24ch; white-space: normal;
  margin: 5px auto 0; padding: 0 10px;
  font-size: var(--size-12); line-height: 1.5;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .9), 0 0 4px rgba(0, 0, 0, .8);
  opacity: 0; max-height: 0; overflow: hidden;
  transition: opacity .3s ease, max-height .3s ease;
}

/* Where a pin sits low in the frame, the tag hangs under it instead. */
.outlook__pin--below { transform: translate(-50%, 0); padding: var(--spacing-8) 0 0; }
.outlook__pin--below .outlook__tag { order: 1; margin-bottom: 0; margin-top: 26px; }
.outlook__pin--below .outlook__dot::after { bottom: auto; top: 100%; }
.outlook__pin:hover .outlook__note,
.outlook__pin:focus-visible .outlook__note,
.outlook__pin.is-open .outlook__note { opacity: .92; max-height: 4em; }
.outlook__pin:hover .outlook__dot::before,
.outlook__pin:focus-visible .outlook__dot::before,
.outlook__pin.is-open .outlook__dot::before { transform: scale(1.5); background: var(--color-terracotta); }

/* Rail: a position track, and the landmarks as somewhere to go. */
.outlook__rail {
  max-width: calc(var(--container) + var(--gap-side) * 2);
  margin: var(--spacing-24) auto 0;
  padding-inline: var(--gap-side);
}
.outlook__track {
  position: relative; height: 2px;
  background: rgba(138, 79, 45, .18);
  margin-bottom: var(--spacing-20);
}
.outlook__thumb {
  position: absolute; top: 0; bottom: 0;
  background: var(--color-primary);
  transition: left .12s linear, width .2s ease;
}
.outlook__jump {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--spacing-8) var(--spacing-32);
  margin: 0; padding: 0; list-style: none;
}
.outlook__jump button {
  position: relative;
  padding: 6px 0;
  font-size: var(--size-12); font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--color-ink); opacity: .7;   /* .5 measured 2.69:1 on sand */
  transition: opacity .3s ease, color .3s ease;
}
.outlook__jump button::after {
  content: ""; position: absolute; left: 50%; right: 50%; bottom: 0; height: 1px;
  background: currentColor;
  transition: left .35s cubic-bezier(.22,.61,.36,1), right .35s cubic-bezier(.22,.61,.36,1);
}
.outlook__jump button:hover { opacity: 1; }
.outlook__jump button.is-active { opacity: 1; color: var(--color-primary); }
.outlook__jump button.is-active::after,
.outlook__jump button:hover::after { left: 0; right: 0; }

.outlook__hint {
  margin: var(--spacing-16) 0 0;
  text-align: center;
  font-size: var(--size-12); letter-spacing: .18em; text-transform: uppercase;
  color: var(--color-primary);   /* full clay = 5.78:1; the size and tracking keep it quiet */
  transition: opacity .5s ease;
}
.outlook__frame.is-touched .outlook__hint { opacity: 0; }

.outlook__foot { text-align: center; }
.outlook__sun {
  margin: var(--spacing-32) 0 0;
  font-family: var(--font-secondary);
  font-size: var(--size-20); line-height: 1.5;
  color: var(--color-primary);
}
.outlook__sun em { font-style: normal; color: var(--color-terracotta); }

/* A pin whose position is inferred rather than confirmed shows a ring in calibrate mode. */
.is-calibrating .outlook__pin[data-confirmed="no"] .outlook__dot::before { box-shadow: 0 0 0 6px rgba(192, 57, 43, .55); }
.is-calibrating .outlook__stage { cursor: crosshair; }

@media only screen and (max-width: 1024px) {
  .outlook__note { display: none; }
  /* A narrower edge wants a shallower ramp, and the deeper blur is the more
     expensive of the two to composite while dragging. */
  .outlook__edge { width: 56px; }
  .outlook__edge::after { -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
  .outlook__jump { gap: var(--spacing-8) var(--spacing-20); }
  .outlook__jump button { font-size: 11px; letter-spacing: .14em; }
}

/* =========================================================
   The year in light. The page has just told you what time the
   sun goes down tonight; this is the same fact for every night
   of the year, computed the same way. Daylight above, the sea
   beneath it, both drawn from real numbers rather than styled
   to look meteorological.
   ========================================================= */
.year { padding-block: var(--spacing-72) var(--spacing-64); background: var(--color-sand-1); }
.year__head { text-align: center; margin-bottom: var(--spacing-56); }
.year__head .txt_sub_title { display: block; margin-bottom: var(--spacing-20); }
.year__head p { max-width: 62ch; margin: var(--spacing-24) auto 0; font-size: var(--size-15); line-height: 1.75; }

.year__figure { position: relative; max-width: 1120px; }
.year__svg { display: block; width: 100%; height: auto; touch-action: pan-y; }

/* Night has to carry the contrast: the daylight band is the page's own sand,
   so it reads as the page opening up rather than as a block of colour. */
.year__night { fill: rgba(13, 59, 71, .19); }
.year__day { fill: var(--color-sand-1); }
.year__frame { fill: none; stroke: rgba(138, 79, 45, .22); stroke-width: 1; }
/* The hour either side of the boundary, which is the light people book for. */
.year__golden { fill: rgba(176, 106, 66, .24); }
.year__edge { fill: none; stroke: rgba(138, 79, 45, .55); stroke-width: 1; }

.year__hours line { stroke: rgba(138, 79, 45, .11); stroke-width: 1; }
.year__hours text,
.year__months text { font-size: 11px; letter-spacing: .1em; fill: var(--color-ink); opacity: .55; }
.year__tick { stroke: rgba(138, 79, 45, .13); stroke-width: 1; }

.year__sea-fill { fill: rgba(20, 80, 95, .15); }
.year__sea-line { fill: none; stroke: var(--color-sea); stroke-width: 1.4; }
.year__sea circle { fill: var(--color-sea); }
.year__sea-label { font-size: 11px; fill: var(--color-sea); opacity: .8; }

.year__dst { stroke: rgba(138, 79, 45, .5); stroke-width: 1; stroke-dasharray: 3 4; }
.year__notes text { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; fill: var(--color-primary); opacity: .7; }

.year__today line { stroke: var(--color-terracotta); stroke-width: 1.4; }

/* Sits over the chart on a wide screen and under it on a narrow one, so it
   never covers the part of the year being pointed at. */
.year__readout {
  margin: var(--spacing-16) 0 0;
  min-height: 1.5em;
  text-align: center;
  font-size: var(--size-14); line-height: 1.6;
  color: var(--color-primary);
}
.year__readout b { font-weight: inherit; color: var(--color-heading); }
.year__readout i { font-style: normal; opacity: .55; padding-inline: 5px; }

.year__foot { text-align: center; margin-top: var(--spacing-32); }
.year__source { font-size: var(--size-12); line-height: 1.6; color: var(--color-ink); opacity: .75; max-width: 56ch; margin-inline: auto; }

@media only screen and (max-width: 768px) {
  /* Twelve month labels will not fit; the chart keeps its shape and the
     readout does the naming. */
  .year__months text:nth-of-type(even) { display: none; }
  .year__notes text { display: none; }
}

/* =========================================================
   A line from the house guide. The only place on the site where
   a person who has lived there speaks, so it is set apart —
   Prata, generously leaded, on its own quiet band.
   ========================================================= */
.tip { padding-block: var(--spacing-72); background: var(--color-sand-1); }
.tip__inner { text-align: center; }
.tip__mark { display: block; width: 26px; height: 26px; margin: 0 auto var(--spacing-20); color: var(--color-terracotta); opacity: .8; }
.tip__mark svg { width: 100%; height: 100%; }
.tip__text {
  margin: 0 auto var(--spacing-20);
  max-width: 34ch;
  font-family: var(--font-secondary);
  font-size: var(--size-h4);
  line-height: 1.55;
  color: var(--color-heading);
  text-wrap: balance;
}
/* .55 gave 3.1:1 on sand; .75 is the first step that clears 4.5. */
.tip__source { display: block; color: var(--color-ink); opacity: .75; }

/* Sits against the sand-2 sections above and below it without a hard edge. */
.tip + .glance, .tip + .amenities, .tip + .waysin { border-top: 0; }

@media only screen and (max-width: 768px) {
  .tip { padding-block: var(--spacing-56); }
  .tip__text { font-size: var(--size-h5); max-width: none; }
}

/* Sunset and moon, both worked out from the villa's own coordinates. */
.outlook__moon { display: block; margin-top: var(--spacing-8); font-size: var(--size-16); opacity: .8; }
.outlook__moon em { font-style: normal; color: var(--color-terracotta); }

/* ---------------------------------------------------------------
   Sunrise and moonrise, marked on the panorama itself. The bearing
   is exact; where it lands depends on the sweep fitted in
   tools/panorama-fit.py, so the mark is a soft column rather than a
   pin — it says "about here", which is what the fit supports.
   --------------------------------------------------------------- */
.outlook__sky {
  position: absolute; left: var(--x); top: var(--y);
  transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center;
  pointer-events: none;
}
/* The riser drops from the tag to the horizon, so the mark reads as pointing
   at a place on the water rather than floating over it. Sky tags sit higher
   than the island tags, which is what keeps the two sets from colliding. */
.outlook__sky-riser {
  display: block; width: 2px; height: 124px; margin-top: 6px;
  background: linear-gradient(to bottom, currentColor, transparent);
  opacity: .85;
}
.outlook__sky-tag {
  display: block; padding: 3px 9px; white-space: nowrap;
  font-size: var(--size-12); letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-white); background: rgba(13, 59, 71, .72);
}
.outlook__sky--sun { color: #f0bd68; }
.outlook__sky--moon { color: #dbe3ec; }

@media only screen and (max-width: 700px) {
  .outlook__sky-tag { font-size: 10px; padding: 2px 6px; letter-spacing: .08em; }
}

/* =========================================================
   Skorpios
   ========================================================= */
/* The night pool beside it, rather than a lone column of prose. */
.skorpios { padding-block: var(--spacing-80); }
.skorpios__grid {
  display: grid; grid-template-columns: minmax(0, 42fr) minmax(0, 58fr);
  gap: var(--spacing-64); align-items: center;
}
.skorpios__media { align-self: stretch; display: flex; overflow: hidden; }
.skorpios__media picture { display: block; width: 100%; }
.skorpios__media img { width: 100%; height: 100%; object-fit: cover; }
.skorpios__body { max-width: 56ch; }
.skorpios .txt_sub_title { display: block; margin-bottom: var(--spacing-16); }
.skorpios h2 { margin-bottom: var(--spacing-24); }
.skorpios p { max-width: none; }
.skorpios .rule-dot { margin-top: var(--spacing-32); justify-content: flex-start; }

@media only screen and (max-width: 1024px) {
  .skorpios__grid { grid-template-columns: 1fr; gap: var(--spacing-40); }
  .skorpios__media { aspect-ratio: 4 / 3; }
}

/* =========================================================
   The hill — answering the access objection before a guest
   finds it in a review.
   ========================================================= */
.location__media--hill {
  display: flex; align-items: center; justify-content: center;
  background: var(--color-sand-1);
  padding: var(--spacing-56) var(--spacing-40);
}
.hill { width: 100%; max-width: 560px; }
.hill__title { display: block; margin-bottom: var(--spacing-24); }
.hill__svg { width: 100%; height: auto; display: block; overflow: visible; }
.hill__slope { fill: rgba(138, 79, 45, .1); }
.hill__ink { fill: none; stroke: var(--color-primary); stroke-width: 1; }
.hill__ink circle { fill: var(--color-primary); }
.hill__label {
  font-family: var(--font-primary); font-size: 9px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  fill: var(--color-ink);
}
.hill__label--mid { text-anchor: middle; }
.hill__note {
  margin: var(--spacing-24) 0 0;
  font-family: var(--font-secondary);
  font-size: var(--size-16); line-height: 1.6;
  color: var(--color-primary);
}

@media only screen and (max-width: 1024px) {
  .location__media--hill { padding: var(--spacing-48) var(--gap-side); }
}

/* =========================================================
   Amenities
   ========================================================= */
.amenities { padding-block: var(--spacing-default); }
.amenities__head { text-align: center; margin-bottom: var(--spacing-56); }
.amenities__head .ornament { margin-bottom: var(--spacing-12); }
.amenities__head .txt_sub_title { display: block; margin-bottom: var(--spacing-20); }
.amenities__head h2 { max-width: 20ch; margin-inline: auto; }

.amenities__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--spacing-40) var(--spacing-32);
}
.amenity-group__title {
  display: block;
  padding-bottom: var(--spacing-12);
  margin-bottom: var(--spacing-16);
  border-bottom: 1px solid rgba(138, 79, 45, .25);
}
.amenity-group__list { display: grid; gap: 10px; }
.amenity-group__list li { position: relative; padding-left: 18px; font-size: var(--size-15); line-height: 1.5; }
.amenity-group__list li::before {
  content: ""; position: absolute; left: 0; top: .5em;
  width: 5px; height: 5px; border: 1px solid var(--color-terracotta); border-radius: 50%;
}

/* Rules read as reassurance, not restriction — kept quiet, below the amenities. */
.house-rules {
  margin-top: var(--spacing-56);
  padding-top: var(--spacing-40);
  border-top: 1px solid rgba(138, 79, 45, .2);
}
.house-rules__title { display: block; margin-bottom: var(--spacing-20); }
.house-rules__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--spacing-12) var(--spacing-40);
}
.house-rules__list li { font-size: var(--size-14); line-height: 1.6; opacity: .85; }

@media only screen and (max-width: 700px) {
  .amenities__grid { grid-template-columns: 1fr; gap: var(--spacing-32); }
}

/* =========================================================
   Three-column gallery block
   ========================================================= */
.trio { padding-block: var(--spacing-default); }
.trio__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--spacing-56);
  align-items: center;
}
.trio__col--left .trio__thumb { max-width: 200px; margin-bottom: var(--spacing-40); }
.trio__thumb img { aspect-ratio: 3 / 4; object-fit: cover; width: 100%; }
.trio__col--left h2 { margin-bottom: var(--spacing-20); }
.trio__col--left p { max-width: 40ch; }

/* Arch-topped centre image */
.trio__arch {
  border-radius: 50vw 50vw 0 0;
  overflow: hidden;
}
/* The pool shot carries a lot of foreground tiling — bias the crop upward so
   the water and the bay stay in frame. */
.trio__arch img { aspect-ratio: 3 / 4.2; object-fit: cover; object-position: center 30%; width: 100%; }

.trio__col--right { text-align: center; }
.trio__col--right .ornament { margin-bottom: var(--spacing-12); }
.trio__col--right .txt_sub_title { display: block; margin-bottom: var(--spacing-16); line-height: 1.8; }
.trio__col--right .rule-dot { margin-bottom: var(--spacing-32); }
.trio__col--right .trio__thumb img { aspect-ratio: 4 / 3.4; }

@media only screen and (max-width: 1024px) {
  .trio__grid { grid-template-columns: 1fr; gap: var(--spacing-40); }
  .trio__col--left .trio__thumb { display: none; }
  .trio__arch { max-width: 480px; margin-inline: auto; }
  .trio__col--right .trio__thumb { max-width: 380px; margin-inline: auto; }
}

/* =========================================================
   Reviews
   ========================================================= */
.reviews { padding-block: var(--spacing-default); }
.reviews__head { text-align: center; margin-bottom: var(--spacing-56); }
.reviews__head .ornament { margin-bottom: var(--spacing-12); }
.reviews__head .txt_sub_title { display: block; margin-bottom: var(--spacing-20); }

.reviews__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--spacing-40); }
.review {
  background: var(--color-white);
  padding: var(--spacing-40) var(--spacing-32);
  display: flex; flex-direction: column; gap: var(--spacing-20);
}
.review__stars { display: flex; gap: 5px; color: var(--color-terracotta); }
.review__stars svg { width: 14px; height: 14px; }
.review blockquote { font-size: var(--size-15); line-height: 1.8; margin: 0; }
.review__by { margin-top: auto; padding-top: var(--spacing-16); border-top: 1px solid rgba(138,79,45,.18); }
.review__name { font-family: var(--font-secondary); font-size: var(--size-16); color: var(--color-heading); display: block; }
.review__when { font-size: var(--size-12); letter-spacing: .12em; text-transform: uppercase; opacity: .78; }

@media only screen and (max-width: 1024px) { .reviews__grid { grid-template-columns: 1fr; } }

/* =========================================================
   Location split
   ========================================================= */
.location { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; }
/* The media column has to match the height of the text panel beside it, so the
   figure, its <picture> and the img all stretch rather than sizing to the file. */
.location__media { height: 100%; }
.location__media picture { height: 100%; }
.location__media img { width: 100%; height: 100%; min-height: 420px; object-fit: cover; }
.location__body {
  background: var(--color-sea); color: var(--color-white);
  padding: var(--spacing-96) var(--spacing-72);
  display: flex; flex-direction: column; justify-content: center;
}
.location__body h2 { color: var(--color-white); margin-bottom: var(--spacing-24); }
.location__body .txt_sub_title { color: var(--color-white); opacity: .8; display: block; margin-bottom: var(--spacing-16); }
.location__list { display: grid; gap: var(--spacing-16); margin-top: var(--spacing-32); }
.location__list li { display: flex; gap: var(--spacing-16); font-size: var(--size-15); line-height: 1.7; }
.location__list dt { font-family: var(--font-secondary); font-size: var(--size-16); min-width: 108px; }
.location__list-row { display: flex; gap: var(--spacing-24); padding-bottom: var(--spacing-16); border-bottom: 1px solid rgba(255,255,255,.18); }
.location__list-row dt { flex: 0 0 130px; font-family: var(--font-secondary); }
.location__list-row dd { margin: 0; opacity: .88; }

@media only screen and (max-width: 1024px) {
  .location { grid-template-columns: 1fr; }
  .location__body { padding: var(--spacing-64) var(--gap-side); }
  .location__media img { min-height: 300px; }
}

/* =========================================================
   Newsletter / CTA
   ========================================================= */
.cta { padding-block: var(--spacing-80); text-align: center; }
.cta h2 { margin-bottom: var(--spacing-16); }
.cta p { margin-inline: auto; max-width: 52ch; margin-bottom: var(--spacing-32); }
.cta__actions { display: flex; flex-wrap: wrap; gap: var(--spacing-16); justify-content: center; }
.cta__actions .btn { padding: 16px 32px; }
.btn__icon { flex: none; width: 16px; height: 16px; }

@media only screen and (max-width: 480px) {
  .cta__actions { flex-direction: column; }
  .cta__actions .btn { width: 100%; }
}
.cta__address { margin-top: var(--spacing-24); font-size: var(--size-14); }
.cta__alt { margin-top: var(--spacing-32); margin-bottom: var(--spacing-12); font-size: var(--size-14); }

/* =========================================================
   Questions — each answer set beside its question. No
   accordion: someone deciding whether to book should be able
   to read the lot without opening twenty things first.
   ========================================================= */
.faq { padding-block: var(--spacing-64); }
.faq__group-title { margin-bottom: var(--spacing-48); }
.faq__item {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  gap: var(--spacing-40);
  padding-block: var(--spacing-32);
  border-top: 1px solid rgba(138, 79, 45, .2);
}
.faq__item:last-child { border-bottom: 1px solid rgba(138, 79, 45, .2); }
.faq__q { font-size: var(--size-20); line-height: 1.35; max-width: 22ch; }
.faq__a { font-size: var(--size-15); line-height: 1.75; }
.faq__a p { margin-bottom: var(--spacing-16); }

@media only screen and (max-width: 860px) {
  .faq__item { grid-template-columns: 1fr; gap: var(--spacing-12); }
  .faq__q { max-width: none; }
}

/* =========================================================
   Who sleeps where. A party of ten arrives having already had
   the argument about rooms, so the beds are set down plainly:
   the mark says double or twin at a glance, which is the only
   distinction anyone is really asking about.
   ========================================================= */
.beds__lede { max-width: 62ch; margin: var(--spacing-24) auto 0; font-size: var(--size-15); line-height: 1.75; }
.beds { max-width: 820px; margin: var(--spacing-48) auto 0; }
.beds__list { margin: 0; padding: 0; list-style: none; }
.beds__row {
  display: grid;
  grid-template-columns: 148px 46px minmax(0, 1fr) auto;
  gap: var(--spacing-24);
  align-items: center;
  padding: var(--spacing-20) var(--spacing-24);
  border-top: 1px solid rgba(138, 79, 45, .2);
}
.beds__row:last-child { border-bottom: 1px solid rgba(138, 79, 45, .2); }
.beds__room { font-family: var(--font-secondary); font-size: var(--size-16); color: var(--color-heading); }
.beds__bed { font-size: var(--size-15); }
.beds__n { font-size: var(--size-12); letter-spacing: .12em; text-transform: uppercase; color: var(--color-primary); opacity: .8; white-space: nowrap; }

.beds__mark { width: 44px; height: 22px; display: block; }
.beds__mark rect, .beds__mark path {
  fill: none; stroke: var(--color-primary); stroke-width: 1; stroke-linejoin: round;
}
/* The sofa bed is capacity on top of the ten, not one of them. */
.beds__row--extra .beds__room,
.beds__row--extra .beds__bed { opacity: .62; }
.beds__row--extra .beds__mark rect,
.beds__row--extra .beds__mark path { stroke: var(--color-ink); opacity: .45; }

.beds__note {
  max-width: 66ch; margin: var(--spacing-32) auto 0;
  text-align: center;
  font-size: var(--size-14); line-height: 1.7;
  color: var(--color-ink); opacity: .8;
}

@media only screen and (max-width: 640px) {
  .beds__row {
    grid-template-columns: 46px minmax(0, 1fr);
    gap: var(--spacing-8) var(--spacing-16);
    padding-inline: var(--spacing-12);
  }
  .beds__room { grid-column: 2; }
  .beds__mark { grid-row: span 2; align-self: start; margin-top: 3px; }
  .beds__n { grid-column: 2; }
}

/* =========================================================
   The hosts' list — set as an index rather than as cards.
   There is no photography of any of these places, and a grid
   of empty tiles would say so; a ruled list of names and
   distances reads like something kept rather than marketed.
   ========================================================= */
.places { padding-block: var(--spacing-64); }
.places__intro { text-align: center; margin-bottom: var(--spacing-64); }
.places__intro .txt_sub_title { display: block; margin-bottom: var(--spacing-20); }
.places__intro p { max-width: 60ch; margin: var(--spacing-24) auto 0; font-size: var(--size-15); line-height: 1.75; }

.places__group + .places__group { margin-top: var(--spacing-56); }
.places__group-title { display: block; margin-bottom: var(--spacing-20); padding-inline: var(--spacing-24); color: var(--color-primary); }
.places__list { margin: 0; padding: 0; list-style: none; }

.places__row {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto;
  gap: var(--spacing-24);
  align-items: baseline;
  padding-block: var(--spacing-32);
  /* The highlight fills the whole row box, so without this the text sits hard
     against the edge of the tint. The rules stay at full width and the type
     insets to meet the group heading, which is padded to match. */
  padding-inline: var(--spacing-24);
  border-top: 1px solid rgba(138, 79, 45, .2);
}
/* Matches the numbered mark on the chart, so the two read as one instrument. */
.places__n { font-size: var(--size-14); color: var(--color-primary); opacity: .7; font-variant-numeric: tabular-nums; }
.places__row:last-child { border-bottom: 1px solid rgba(138, 79, 45, .2); }
/* Arriving from a pin, and pointing at either half of the pair. */
.places__row { scroll-margin-top: calc(var(--header-height) + var(--spacing-24)); transition: background-color .25s ease; }
.places__row.is-active,
.places__row.is-picked,
.places__row:target { background: rgba(138, 79, 45, .07); }
.places__row.is-active .places__n,
.places__row.is-picked .places__n,
.places__row:target .places__n { opacity: 1; color: var(--color-terracotta); }
.places__name { display: block; font-family: var(--font-secondary); font-size: var(--size-20); line-height: 1.3; color: var(--color-heading); }
/* What the place is and roughly where, set as a label so the list can still be
   skimmed now that each entry carries a paragraph. */
.places__meta {
  display: block; margin-top: var(--spacing-8);
  font-size: var(--size-12); letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-ink); opacity: .6;
}
.places__note { display: block; margin-top: var(--spacing-12); max-width: 62ch; font-size: var(--size-15); line-height: 1.75; }
.places__link {
  display: inline-block; margin-top: var(--spacing-12);
  font-size: var(--size-14); color: var(--color-primary);
  border-bottom: 1px solid rgba(138, 79, 45, .35);
  transition: border-color .3s ease;
}
.places__link:hover { border-bottom-color: var(--color-primary); }

/* Borrowed photographs, so each carries its credit. Held to a modest width:
   they are other people's snapshots sitting near the villa's own photography,
   and the size difference is doing some of the work of saying so. */
.places__figure { display: block; margin: var(--spacing-20) 0 0; max-width: 420px; }
.places__figure img { display: block; width: 100%; height: auto; }
.places__figure figcaption {
  margin-top: var(--spacing-8);
  font-size: var(--size-12); line-height: 1.5;
  color: var(--color-ink); opacity: .6;
}
.places__figure figcaption a { color: inherit; border-bottom: 1px solid rgba(54, 54, 54, .3); }
.places__figure figcaption a:hover { color: var(--color-primary); border-bottom-color: var(--color-primary); }
/* Lining figures on a fixed advance, so the distances stack into a column
   without a table to hold them. */
.places__far {
  font-size: var(--size-14); letter-spacing: .06em; white-space: nowrap;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}
.places__far i { font-style: normal; opacity: .45; padding-inline: 2px; }

.places__foot { text-align: center; margin-top: var(--spacing-64); }
.places__foot p { max-width: 44ch; margin: 0 auto var(--spacing-24); font-size: var(--size-15); }

@media only screen and (max-width: 560px) {
  .places__row { grid-template-columns: 28px 1fr; gap: 0 var(--spacing-16); padding-inline: var(--spacing-12); }
  .places__group-title { padding-inline: var(--spacing-12); }
  .places__far { grid-column: 2; margin-top: var(--spacing-8); }
}

/* =========================================================
   The island chart. Real coastline, drawn in the villa's own
   colours rather than borrowed from a map provider — the point
   is where the villa sits in relation to everything else, and
   a tile map would bring its own branding to say it.
   ========================================================= */
/* Chart and list are one instrument, so they share one grid. The chart stays
   put while the list runs past it — otherwise pointing at an entry lights up a
   mark that scrolled off the screen ten entries ago. */
/* The chart's aspect is fixed at 620:1096, so .566 of the room left under the
   header is the widest it can be drawn and still stand in one screen. The column
   is set to that same figure rather than a round number, so the chart always
   fills its column instead of floating in it, and the list takes what is left. */
.places__layout {
  --chart-w: min(460px, calc((100vh - var(--header-height) - 118px) * .566));
  display: grid;
  grid-template-columns: var(--chart-w) minmax(0, 1fr);
  gap: var(--spacing-72);
  align-items: start;
}
.places__chart { position: sticky; top: calc(var(--header-height) + var(--spacing-24)); }
/* The sea fills the viewBox, so the rule lands exactly on the chart's edge and
   reads as a plate rather than a screenshot dropped on the page. */
.chart__figure { position: relative; border: 1px solid rgba(138, 79, 45, .22); }
.chart__caption {
  margin: var(--spacing-16) 0 0;
  text-align: center;
  font-size: var(--size-12); letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-primary); opacity: .75;
}
.chart__svg { display: block; width: 100%; height: auto; }

.chart__sea { fill: #e3eaec; }
.chart__land {
  fill: var(--color-sand-1);
  stroke: rgba(138, 79, 45, .55); stroke-width: .8; stroke-linejoin: round;
}
.chart__context text { fill: var(--color-sea); font-size: 15px; font-style: italic; opacity: .8; }
/* Where two pins would have collided the disc is nudged clear; the leader runs
   back to the exact spot so the reading stays honest. */
.chart__leader { stroke: rgba(138, 79, 45, .6); stroke-width: .8; }
.chart__spot { fill: var(--color-clay); }
.chart__pin { cursor: pointer; }
/* A 9.5px disc is a mean target, so an invisible one twice the size takes the
   pointer and the tap. */
.chart__pin-hit { fill: transparent; }
.chart__pin-disc { fill: var(--color-clay); transition: fill .25s ease, r .25s ease; }
.chart__pin text { fill: var(--color-white); font-size: 15px; text-anchor: middle; letter-spacing: .01em; }
.chart__pin:hover .chart__pin-disc,
.chart__pin.is-active .chart__pin-disc { fill: var(--color-terracotta); r: 15; }
.chart__pin:focus { outline: none; }
.chart__pin:focus-visible .chart__pin-disc {
  fill: var(--color-terracotta); r: 15;
  stroke: var(--color-sand-1); stroke-width: 2; paint-order: stroke;
}

/* Reads out of the matching entry, so a distance is only ever written once. */
.chart__callout {
  position: absolute; z-index: 2;
  transform: translate(-50%, calc(-100% - 15px));
  padding: 6px 11px 7px;
  background: var(--color-deep-sea); color: var(--color-white);
  font-size: var(--size-12); line-height: 1.35; white-space: nowrap;
  pointer-events: none;
}
.chart__callout.is-below { transform: translate(-50%, 15px); }
.chart__callout-far { margin-left: .7em; opacity: .72; font-variant-numeric: tabular-nums; }
.chart__villa-halo { fill: none; stroke: var(--color-terracotta); stroke-width: 1.3; }
.chart__villa-dot { fill: var(--color-terracotta); }
.chart__villa text { fill: var(--color-terracotta); font-size: 13px; letter-spacing: .16em; }
.chart__scale path { fill: none; stroke: var(--color-ink); stroke-width: 1; opacity: .55; }
.chart__scale text { fill: var(--color-ink); font-size: 12px; letter-spacing: .1em; opacity: .7; }

@media only screen and (max-width: 1200px) {
  /* Too narrow to hold the pair side by side: the chart goes back to being a
     plate at the head of the list, at its own size rather than the viewport's. */
  .places__layout { grid-template-columns: 1fr; gap: var(--spacing-48); }
  .places__chart { position: static; }
  .chart__figure { max-width: 520px; margin-inline: auto; }
}

/* =========================================================
   Footer
   ========================================================= */
.site-footer { background: var(--color-deep-sea); color: rgba(255,255,255,.82); }
.site-footer a { color: rgba(255,255,255,.82); text-decoration: none; }
.site-footer a:hover { color: var(--color-white); }

.footer__top { padding-block: var(--spacing-80) var(--spacing-56); }
.footer__grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.2fr; gap: var(--spacing-48); }
.footer__brand .site-brand__mark { width: 40px; height: 40px; color: var(--color-terracotta); margin-bottom: var(--spacing-16); }
.footer__brand-name {
  font-family: var(--font-secondary); font-size: var(--size-24);
  color: var(--color-white); margin-bottom: var(--spacing-16); display: block;
}
.footer__brand p { font-size: var(--size-14); line-height: 1.8; max-width: 34ch; opacity: .8; }

.footer__title {
  font-family: var(--font-primary); font-size: var(--size-12);
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--color-terracotta); margin-bottom: var(--spacing-20);
}
.footer__list { display: grid; gap: 12px; font-size: var(--size-14); }
.footer__list a { position: relative; }
.footer__list a::after {
  content: ""; position: absolute; left: 0; bottom: -3px; height: 1px; width: 0;
  background: currentColor; transition: width .4s cubic-bezier(.22,.61,.36,1);
}
.footer__list a:hover::after { width: 100%; }

.footer__socials { display: flex; gap: var(--spacing-20); margin-top: var(--spacing-24); }
.footer__socials a { display: grid; place-items: center; width: 34px; height: 34px; border: 1px solid rgba(255,255,255,.25); border-radius: 50%; transition: var(--transition); }
.footer__socials a:hover { background: var(--color-terracotta); border-color: var(--color-terracotta); color: #fff; }
.footer__socials svg { width: 15px; height: 15px; }

.footer__bottom {
  border-top: 1px solid rgba(255,255,255,.14);
  padding-block: var(--spacing-24);
  display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-20);
  font-size: var(--size-12); letter-spacing: .04em; opacity: .7;
}
/* Studio credit. Measures 5.06:1 on deep-sea even inside the row's .7, so it
   needs no special handling beyond the rule that marks it as a link. */
.footer__credit { white-space: nowrap; }
.footer__credit a {
  position: relative; text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
  opacity: .75; transition: opacity .3s ease, color .3s ease;
}
.footer__credit a:hover { opacity: 1; color: var(--color-white); }

@media only screen and (max-width: 1024px) {
  .footer__grid { grid-template-columns: 1fr 1fr; gap: var(--spacing-40); }
}
@media only screen and (max-width: 600px) {
  .footer__grid { grid-template-columns: 1fr; }
  .footer__bottom { flex-direction: column; text-align: center; }
}

/* ---------------------------------------------------------------
   The local map — the same drawing idiom as the island chart, one
   scale down. Roads carry the clay; only the sea is tinted.
   --------------------------------------------------------------- */
.lmap { padding-block: var(--spacing-default); }
.lmap__intro { margin-bottom: var(--spacing-40); }
.lmap__figure {
  border: 1px solid rgba(138, 79, 45, .22);
  max-width: 900px;
  margin-inline: auto;
}
.lmap__svg { display: block; width: 100%; height: auto; }
.lmap__land { fill: #f0e7db; }
.lmap__sea path { fill: #dbe6e9; }
.lmap__road { fill: none; stroke: var(--color-clay); stroke-linecap: round; stroke-linejoin: round; }
.lmap__road--main { stroke-width: 2.4; opacity: .85; }
.lmap__road--lane { stroke-width: 1; opacity: .45; }
.lmap__road--track { stroke-width: .6; opacity: .3; stroke-dasharray: 3 2.5; }
.lmap__places text {
  fill: var(--color-ink); font-size: 12px; font-weight: 600; letter-spacing: .01em;
}
.lmap__dot { fill: var(--color-ink); }
.lmap__water-label text {
  fill: var(--color-sea); font-size: 11px; letter-spacing: .2em; opacity: .85;
}
.lmap__villa-halo { fill: none; stroke: var(--color-terracotta); stroke-width: 1.4; }
.lmap__villa-dot { fill: var(--color-terracotta); }
.lmap__villa text { fill: var(--color-terracotta); font-size: 12px; letter-spacing: .16em; font-weight: 700; }
.lmap__scale path { fill: none; stroke: var(--color-ink); stroke-width: 1; opacity: .55; }
.lmap__scale text { fill: var(--color-ink); font-size: 11px; letter-spacing: .1em; opacity: .8; }
.lmap__foot { margin-top: var(--spacing-24); }
.lmap__source { font-size: 13px; color: rgba(54, 54, 54, .75); }

/* ---------------------------------------------------------------
   Prose bands — /the-house/ is written rather than tabulated, so it
   needs a plain reading measure the grid components don't provide.
   --------------------------------------------------------------- */
.prose { padding-block: var(--spacing-72); }
.prose .txt_sub_title { display: block; margin-bottom: var(--spacing-16); }
.prose h2 { margin-bottom: var(--spacing-24); }
.prose p { font-size: var(--size-15); line-height: 1.8; max-width: 68ch; }
.prose p + p { margin-top: var(--spacing-20); }
.prose em { font-style: italic; }
.amenities__source {
  margin-top: var(--spacing-40); font-size: var(--size-12); line-height: 1.7;
  color: rgba(54, 54, 54, .78); max-width: 62ch;
}
