/* ==========================================================================
   Villa Caroline, Son Bou, Menorca
   Palette, type scale and section rhythm carried over from the Framer build.
   ========================================================================== */

/* --- Fonts ---------------------------------------------------------------
   Empathy Regular (Playtype) is the display face from the original design.
   Mulish stands in for Avenir, which was only ever referenced as a local
   font and so fell back to generic sans on Windows and Android.
   To swap either face, replace the file and the family name below.        */

@font-face {
  font-family: "Empathy";
  src: url("../fonts/empathy-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Mulish";
  src: url("../fonts/mulish-var.woff2") format("woff2-variations"),
       url("../fonts/mulish-var.woff2") format("woff2");
  font-weight: 200 1000;              /* variable weight axis */
  font-style: normal;
  font-display: swap;
}

:root {
  --navy:        #0C306A;
  --navy-soft:   #7A9EDB;   /* hsl(217 56% 64%): icons, rules, meta text */
  --terracotta:  #D9896B;
  --tint-top:    #D4DFEE;   /* gradient band under the hero */
  --tint-bottom: #FDFEFE;
  --white:       #FFFFFF;

  --font-display: "Empathy", "Iowan Old Style", Georgia, serif;
  --font-body:    "Mulish", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --wrap:   1120px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --radius: 22px;

  --step-hero: clamp(2.75rem, 8.2vw, 4.875rem);   /* 44 -> 78px */
  --step-h2:   clamp(1.75rem, 4.2vw, 2.5rem);     /* 28 -> 40px */
  --step-body: 1rem;

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

  /* Height of the sticky section nav. Used for its negative offset over the
     hero and for the scroll-margin that keeps anchors clear of it. */
  --sitenav-h: 3.4rem;

  /* Hero crossfade. main.js reads --hero-fade so the two never drift apart. */
  --hero-fade: 3s;
  --hero-fade-ease: cubic-bezier(0.45, 0, 0.55, 1);   /* symmetric ease-in-out */
}

/* --- Reset --------------------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--white);
  color: var(--navy);
  font-family: var(--font-body);
  font-size: var(--step-body);
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, picture, svg { display: block; max-width: 100%; }
img { height: auto; }

h1, h2, p, figure, ul { margin: 0; padding: 0; }
ul { list-style: none; }

a { color: inherit; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

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

.skip-link {
  position: absolute;
  top: 0; left: 50%;
  transform: translate(-50%, -110%);
  z-index: 100;
  padding: 0.7rem 1.4rem;
  background: var(--navy);
  color: var(--white);
  border-radius: 0 0 12px 12px;
  text-decoration: none;
  font-size: 0.9rem;
  transition: transform 0.2s var(--ease);
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 3px;
  border-radius: 4px;
}

/* --- Layout ------------------------------------------------------------- */

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

.section { padding-block: clamp(3.5rem, 9vw, 6.5rem); }
.section--flush { padding-block: 0; }

.section--tinted {
  background: linear-gradient(var(--tint-top) 0%, var(--tint-bottom) 100%);
}

.h-display {
  font-family: var(--font-display);
  font-size: var(--step-h2);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.005em;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: clamp(1.0625rem, 1.6vw, 1.3125rem);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  padding: 0.72em 1.5em 0.62em;
  border-radius: 100px;
  border: 1px solid currentColor;
  transition: background-color 0.35s var(--ease), color 0.35s var(--ease),
              transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.btn--ghost { color: var(--white); background: transparent; }
.btn--ghost:hover,
.btn--ghost:focus-visible {
  background: var(--white);
  color: var(--navy);
  transform: translateY(-2px);
}

.btn--solid {
  color: var(--white);
  background: var(--navy);
  border-color: var(--navy);
  box-shadow: 0 6px 18px -8px rgba(12, 48, 106, 0.5);
}
.btn--solid:hover,
.btn--solid:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 12px 26px -10px rgba(12, 48, 106, 0.55);
}

/* ==========================================================================
   HERO
   ========================================================================== */

.hero {
  position: relative;
  height: clamp(30rem, 82vh, 45rem);      /* ~480 -> 720px, original was 650 */
  overflow: hidden;
  background: var(--navy);
  isolation: isolate;
}

/* Own stacking context: the slideshow raises each incoming frame's z-index as
   it cycles, and without this those values would climb past the wordmark.
   The drift lives here, on the container, rather than on each frame. All five
   photos then share one continuous transform, so a crossfade blends two images
   that are always at identical scale and offset. Per-frame drift restarted on
   every change, which snapped the outgoing photo back to its start scale while
   it was still fully visible: the pop that made transitions feel abrupt.
   `alternate` means it eases to a stop and reverses, so there is no seam at
   the end of an iteration either. */
.hero__frames {
  position: absolute;
  inset: 0;
  z-index: 0;
  isolation: isolate;
  animation: heroDrift 36s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes heroDrift {
  from { transform: scale(1.045) translate3d(-0.7%, -0.5%, 0); }
  to   { transform: scale(1.085) translate3d(0.7%, 0.5%, 0); }
}

/* Cross-dissolve: the incoming frame fades in *on top* of the outgoing one,
   which is held opaque until the fade completes. Fading both at once would
   let the navy backdrop show through at the midpoint.
   The easing is deliberately not the site's --ease: that is an ease-out, which
   front-loads most of the opacity change into the first third and reads as a
   cut. A symmetric ease-in-out ramps in and settles out instead. */
.hero__frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--hero-fade) var(--hero-fade-ease);
}
.hero__frame.is-active,
.hero__frame.is-holding { opacity: 1; }
.hero__frame.is-holding { transition: none; }

.hero__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 62%;
}

/* Gradient rising from the foot of the photo, so the section nav sitting on it
   reads clearly whatever frame the slideshow is on. Tall and soft rather than a
   band the height of the nav, which showed a visible edge. */
.hero::before {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 46%;
  z-index: 1;
  background: linear-gradient(180deg,
              rgba(6, 20, 44, 0) 0%,
              rgba(6, 20, 44, 0.28) 55%,
              rgba(6, 20, 44, 0.62) 100%);
  pointer-events: none;
}

/* Legibility scrim behind the wordmark only, keeping the photo clean below. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 62%;
  background: linear-gradient(180deg, rgba(8, 26, 56, 0.34) 0%, rgba(8, 26, 56, 0.16) 45%, rgba(8, 26, 56, 0) 100%);
  pointer-events: none;
  z-index: 1;
}

.hero__bar {
  position: absolute;
  top: clamp(1.75rem, 4.5vh, 3.25rem);
  left: 0;
  z-index: 2;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
  padding-inline: var(--gutter);
  will-change: transform;
}

.hero__wordmark {
  grid-column: 2;
  grid-row: 1;
  font-family: var(--font-display);
  font-size: var(--step-hero);
  font-weight: 400;
  line-height: 1.2;
  color: var(--white);
  text-align: center;
  text-shadow: 0 2px 28px rgba(6, 22, 48, 0.34);
}

/* Centred on its own row under the title. */
.hero__cta {
  grid-column: 2;
  grid-row: 2;
  justify-self: center;
  margin-top: clamp(0.35rem, 1vh, 0.75rem);
  backdrop-filter: blur(3px);
}

/* Language switcher: a <details> dropdown in the third column of the hero bar,
   opposite the CTA. Native disclosure, so it opens without JavaScript. */
.hero__lang {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  /* Centred against the title rather than pinned to the top of its line box. */
  align-self: center;
  position: relative;
  min-width: 0;
}

.hero__lang details { position: relative; }

/* Label and chevron only: no border, no panel. The text-shadow does the work
   of keeping it legible over the photograph instead. */
.hero__lang summary {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.15rem;
  border: 0;
  background: none;
  color: rgba(255, 255, 255, 0.88);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-shadow: 0 1px 3px rgba(6, 20, 44, 0.6), 0 1px 14px rgba(6, 20, 44, 0.5);
  cursor: pointer;
  list-style: none;                 /* hide the default disclosure triangle */
  transition: color 0.3s var(--ease);
}
.hero__lang summary::-webkit-details-marker { display: none; }

.hero__lang summary:hover,
.hero__lang summary:focus-visible { color: var(--white); }

.hero__lang-code { line-height: 1; }

/* Chevron, rotating when the panel is open. */
.hero__lang summary::after {
  content: "";
  width: 6px; height: 6px;
  margin-left: 0.05rem;
  border-right: 1.4px solid currentColor;
  border-bottom: 1.4px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.3s var(--ease);
}
.hero__lang details[open] summary::after { transform: translateY(1px) rotate(-135deg); }

/* Hangs from the right edge: the button sits in the top right corner on every
   breakpoint, so this keeps the panel on screen. */
.hero__lang ul {
  position: absolute;
  top: calc(100% + 0.4rem);
  right: 0;
  z-index: 5;
  min-width: 10rem;
  padding: 0.35rem;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 12px;
  background: rgba(8, 26, 56, 0.9);
  backdrop-filter: blur(10px);
  box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.6);
  animation: langOpen 0.22s var(--ease);
}

@keyframes langOpen {
  from { opacity: 0; transform: translateY(-5px); }
  to   { opacity: 1; transform: none; }
}

.hero__lang-option {
  display: block;
  padding: 0.42rem 0.6rem;
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.82rem;
  letter-spacing: 0;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}

.hero__lang-option:hover,
.hero__lang-option:focus-visible {
  background: rgba(255, 255, 255, 0.14);
  color: var(--white);
}

.hero__lang-option.is-current {
  color: var(--white);
  background: rgba(255, 255, 255, 0.1);
  font-weight: 600;
  cursor: default;
}

/* ==========================================================================
   SECTION NAV
   Sits over the bottom of the hero photo, then sticks to the top of the
   viewport as you scroll. It needs to stay legible over both a photograph and
   the white page beneath it, so there are two states.

   The *default* is the frosted white panel with navy text, which is readable
   anywhere. JS adds .is-over-hero to make it transparent with white text while
   it floats on the photo. That way round on purpose: if the observer is slow,
   never fires, or JS is off entirely, the bar falls back to the legible panel.
   Defaulting to white-on-transparent would have put white text on the white
   page in exactly those cases.
   ========================================================================== */

.sitenav {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Lift back over the photo it is a sibling of. */
  margin-top: calc(var(--sitenav-h) * -1);
  transition: background-color 0.35s var(--ease), box-shadow 0.35s var(--ease),
              backdrop-filter 0.35s var(--ease);
}

.sitenav__inner {
  width: 100%;
  max-width: var(--wrap);
  min-width: 0;
  height: var(--sitenav-h);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: center;
}

.sitenav ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.25rem clamp(0.35rem, 1vw, 0.9rem);
}

.sitenav li[hidden] { display: none; }

/* --- default: legible over anything -------------------------------------- */

.sitenav {
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 rgba(122, 158, 219, 0.35), 0 8px 24px -18px rgba(12, 48, 106, 0.5);
}

.sitenav a {
  display: inline-block;
  padding: 0.45rem 0.85rem;
  border-radius: 100px;
  color: var(--navy);
  font-size: 0.98rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease);
}

/* Pill fill on hover, no underline. */
.sitenav a:hover,
.sitenav a:focus-visible { background: rgba(12, 48, 106, 0.1); }

/* --- floating on the hero photo ------------------------------------------ */

.sitenav.is-over-hero {
  background: transparent;
  backdrop-filter: none;
  box-shadow: none;
}

.sitenav.is-over-hero a {
  color: var(--white);
  text-shadow: 0 1px 3px rgba(6, 20, 44, 0.6), 0 1px 16px rgba(6, 20, 44, 0.5);
}
.sitenav.is-over-hero a:hover,
.sitenav.is-over-hero a:focus-visible { background: rgba(255, 255, 255, 0.22); }

/* Anchor targets clear the sticky bar when jumped to. */
:where(section[id]) {
  scroll-margin-top: calc(var(--sitenav-h) + clamp(0.75rem, 3vh, 2rem));
}

/* ==========================================================================
   INTRO
   ========================================================================== */

.intro__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}

.intro__text p {
  margin-top: 1.1rem;
  max-width: 34ch;
}

.intro__text .btn { margin-top: 1.9rem; }

.intro__map img { width: 100%; }

/* ==========================================================================
   TERRACE
   ========================================================================== */

/* Pulled up over the tinted intro band so the photo slides across it. The white
   background matters: the export's top edge feathers out to transparent, and it
   needs white behind it to blend the way it did in the original design. */
.terrace {
  margin-top: clamp(-6rem, -5vw, -2rem);
  background: var(--white);
  will-change: transform;
}

/* No clipping and no object-fit: the photo is shown whole, so the top of the
   palm is never cut off. The section itself is what moves on scroll. */
.terrace__frame img {
  width: 100%;
  height: auto;
}

/* ==========================================================================
   POOL + COLLAGE
   ========================================================================== */

.pool__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.collage {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, auto);
}

/* Each collage export has its own rounded corners, drop shadow and ~10%
   transparent bleed baked in, so it needs no framing of its own. The negative
   margins claw back that bleed so the photos overlap as tightly as they look. */
.collage__item {
  transition: transform 0.55s var(--ease);
}
.collage__item img { width: 100%; }

/* pool at night, top left, sits behind */
.collage__item--a { grid-column: 1 / 4; grid-row: 1 / 3; z-index: 1; }
/* kitchen, the large anchor image */
.collage__item--b { grid-column: 2 / 6; grid-row: 2 / 5; z-index: 3; margin-block: -6%; }
/* villa facade, small, overlaps the bottom left */
.collage__item--c { grid-column: 1 / 3; grid-row: 4 / 6; z-index: 4; margin-top: -14%; }

/* Hovering anywhere on the collage slides the photos apart instead of popping
   one in front of another, so the overlap opens up and more of each photo shows.
   Stacking order is left alone. Gated on a real pointer, otherwise a tap would
   leave the spread stuck open. */
@media (hover: hover) and (pointer: fine) {
  .collage:hover .collage__item--a { transform: translate(-9%, -4%); }
  .collage:hover .collage__item--b { transform: translate(8%, 2%); }
  .collage:hover .collage__item--c { transform: translate(-7%, 5%); }
}

.pool__text p { margin-top: 1.1rem; max-width: 36ch; }

/* ==========================================================================
   GALLERY CAROUSEL
   ========================================================================== */

.gallery__title { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }

.carousel { position: relative; }

.carousel__track {
  display: flex;
  gap: clamp(0.75rem, 1.6vw, 1.25rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding-inline: max(var(--gutter), calc((100vw - var(--wrap)) / 2 + var(--gutter)));
  padding-block: 0.5rem 1rem;
}
.carousel__track::-webkit-scrollbar { display: none; }

.carousel__slide {
  flex: 0 0 auto;
  width: min(640px, 86vw);
  scroll-snap-align: center;
}

.carousel__slide figure {
  border-radius: var(--radius);
  overflow: hidden;
  position: relative;
}

.carousel__link {
  display: block;
  cursor: zoom-in;
  -webkit-tap-highlight-color: transparent;
}

.carousel__slide img {
  width: 100%;
  aspect-ratio: 855 / 640;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}

/* Slow push in on hover, clipped by the figure's rounded corners. */
@media (hover: hover) and (pointer: fine) {
  .carousel__link:hover img { transform: scale(1.06); }
}
.carousel__link:focus-visible img { transform: scale(1.06); }

/* Sits over the photo, so it must not swallow clicks meant for the link. */
.carousel__slide figcaption {
  position: absolute;
  inset: auto 0 0;
  padding: 2.4rem 1.15rem 0.95rem;
  color: var(--white);
  font-size: 0.85rem;
  background: linear-gradient(180deg, rgba(8, 26, 56, 0) 0%, rgba(8, 26, 56, 0.62) 100%);
  pointer-events: none;
}

.carousel__btn {
  position: absolute;
  top: calc(50% - 0.75rem);
  transform: translateY(-50%);
  z-index: 4;
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.65);
  border-radius: 50%;
  background: rgba(12, 48, 106, 0.34);
  backdrop-filter: blur(5px);
  color: var(--white);
  cursor: pointer;
  transition: background-color 0.3s var(--ease), opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.carousel__btn:hover { background: rgba(12, 48, 106, 0.62); }
.carousel__btn svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.carousel__btn--prev { left: clamp(0.5rem, 2vw, 1.5rem); }
.carousel__btn--prev svg { transform: rotate(180deg); }
.carousel__btn--next { right: clamp(0.5rem, 2vw, 1.5rem); }

.carousel__btn[disabled] { opacity: 0; pointer-events: none; }

.carousel__dots {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.carousel__dot {
  width: 7px; height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--navy);
  opacity: 0.22;
  cursor: pointer;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.carousel__dot[aria-selected="true"] { opacity: 1; transform: scale(1.5); }

/* ==========================================================================
   LIGHTBOX
   A native <dialog>, so focus trapping, Escape and the backdrop are free.
   ========================================================================== */

.lightbox {
  width: min(100vw, 100%);
  max-width: none;
  max-height: none;
  height: 100%;
  margin: 0;
  padding: clamp(0.75rem, 3vw, 2.5rem);
  border: 0;
  background: transparent;
  color: var(--white);
  overscroll-behavior: contain;
}

.lightbox:not([open]) { display: none; }

.lightbox[open] {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(0.25rem, 1.5vw, 1.25rem);
}

.lightbox::backdrop {
  background: rgba(6, 20, 44, 0.9);
  backdrop-filter: blur(6px);
}

.lightbox__figure {
  grid-column: 2;
  display: grid;
  justify-items: center;
  gap: 0.9rem;
  min-width: 0;
}

.lightbox__img {
  max-width: 100%;
  /* Leave room for the caption under the photo. */
  max-height: calc(100vh - 9rem);
  width: auto;
  height: auto;
  border-radius: 14px;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.7);
  animation: lightboxIn 0.4s var(--ease);
}

@keyframes lightboxIn {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: none; }
}

.lightbox__caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0.15rem 0.85rem;
  font-size: 0.9rem;
  text-align: center;
}

.lightbox__count {
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.6);
  font-variant-numeric: tabular-nums;
}

/* Controls */

.lightbox__close,
.lightbox__nav {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: var(--white);
  cursor: pointer;
  transition: background-color 0.3s var(--ease), opacity 0.3s var(--ease);
}
.lightbox__close:hover,
.lightbox__nav:hover { background: rgba(255, 255, 255, 0.22); }

.lightbox__close svg,
.lightbox__nav svg {
  width: 22px; height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.lightbox__close {
  position: absolute;
  top: clamp(0.75rem, 3vw, 2rem);
  right: clamp(0.75rem, 3vw, 2rem);
  z-index: 2;
}

.lightbox__nav--prev { grid-column: 1; }
.lightbox__nav--prev svg { transform: rotate(180deg); }
.lightbox__nav--next { grid-column: 3; }

.lightbox__nav[disabled] { opacity: 0.25; pointer-events: none; }

/* Stops the page behind scrolling while the viewer is open. */
html:has(.lightbox[open]) { overflow: hidden; }

@media (max-width: 539px) {
  /* Float the arrows over the photo instead of giving them their own columns,
     so the image gets the full width of a narrow screen. */
  .lightbox[open] { grid-template-columns: minmax(0, 1fr); }
  .lightbox__figure { grid-column: 1; }

  .lightbox__nav {
    position: absolute;
    top: 50%;
    z-index: 2;
    width: 40px; height: 40px;
    transform: translateY(-50%);
    background: rgba(6, 20, 44, 0.55);
  }
  .lightbox__nav--prev { left: clamp(0.4rem, 2vw, 0.9rem); }
  .lightbox__nav--next { right: clamp(0.4rem, 2vw, 0.9rem); }

  .lightbox__img { max-height: calc(100vh - 10rem); }
}

/* ==========================================================================
   LOCATION
   ========================================================================== */

.location__lead {
  margin-top: 1rem;
  max-width: 52ch;
}

.map {
  margin-top: clamp(1.75rem, 4vw, 2.75rem);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--tint-top);
  aspect-ratio: 16 / 9;
  box-shadow: 0 26px 54px -32px rgba(12, 48, 106, 0.42);
}

/* loading="lazy" on the iframe keeps the map tiles off the initial page load;
   it fetches as the section comes into view. */
.map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ==========================================================================
   AMENITIES
   ========================================================================== */

.amenities__list {
  margin-top: clamp(1.25rem, 3vw, 2rem);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.15rem clamp(1.5rem, 5vw, 4.5rem);
}

.amenities__list li {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding-block: 0.6rem;
  border-bottom: 1px solid rgba(122, 158, 219, 0.28);
  font-weight: 500;
}

.amenities__list svg {
  flex: 0 0 auto;
  width: 24px; height: 24px;
  fill: none;
  stroke: var(--navy-soft);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ==========================================================================
   AVAILABILITY
   ========================================================================== */

.availability[hidden] { display: none; }

.availability__lead {
  margin-top: 1rem;
  max-width: 52ch;
}

.availability__months {
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: clamp(1.5rem, 4vw, 2.75rem);
}

.avail-month__title {
  margin: 0 0 0.85rem;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 400;
}

.avail-month__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.avail-month__weekday {
  padding-bottom: 0.3rem;
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-align: center;
  color: var(--navy-soft);
}

.avail-day {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 7px;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}

.avail-day--pad { visibility: hidden; }

/* Free reads as open and inviting; taken is filled in. */
.avail-day.is-free {
  background: var(--white);
  border: 1px solid var(--navy);
  color: var(--navy);
  font-weight: 600;
}

.avail-day.is-taken {
  background: rgba(122, 158, 219, 0.24);
  color: rgba(12, 48, 106, 0.45);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.avail-day.is-past {
  color: rgba(12, 48, 106, 0.22);
}

.availability__foot {
  margin-top: clamp(1.5rem, 4vw, 2.25rem);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
}

.availability__note {
  flex: 1 1 18rem;
  max-width: 46ch;
  font-size: 0.85rem;
  color: var(--navy);
  opacity: 0.8;
}

/* ==========================================================================
   FAQ
   ========================================================================== */

.faq__list { margin-top: clamp(1.25rem, 3vw, 2rem); max-width: 46rem; }

.faq details {
  border-bottom: 1px solid rgba(122, 158, 219, 0.28);
}

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.05rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
  content: "";
  flex: 0 0 auto;
  width: 11px; height: 11px;
  margin-right: 3px;
  border-right: 2.2px solid var(--navy-soft);
  border-bottom: 2.2px solid var(--navy-soft);
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.3s var(--ease);
}
.faq details[open] summary::after { transform: translateY(2px) rotate(-135deg); }

.faq summary:hover::after { border-color: var(--navy); }

.faq details p {
  padding-bottom: 1.15rem;
  max-width: 60ch;
  color: var(--navy);
  opacity: 0.9;
}

.faq details[open] p { animation: faqOpen 0.4s var(--ease); }

@keyframes faqOpen {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 0.9; transform: none; }
}

/* ==========================================================================
   FOOTER
   ========================================================================== */

.footer {
  position: relative;
  margin-top: clamp(2rem, 6vw, 4rem);
  min-height: 408px;
  display: grid;
  place-items: center;
  padding: clamp(3rem, 8vw, 5rem) var(--gutter);
  background-color: var(--terracotta);
  background-image: image-set(url("../img/footer-palms-1440.webp") type("image/webp"),
                              url("../img/footer-palms-1440.jpg") type("image/jpeg"));
  background-position: center bottom;
  background-size: cover;
  background-repeat: no-repeat;
  color: var(--white);
  text-align: center;
}

.footer__inner { display: grid; justify-items: center; gap: 1.5rem; }

.footer__wordmark {
  font-family: var(--font-display);
  font-size: clamp(2rem, 5.5vw, 3.1875rem);   /* -> 51px */
  line-height: 1.2;
}

.footer__meta {
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  color: rgba(255, 255, 255, 0.82);
}

/* Balearic tourist licence and short-stay registration number. Legally required
   on the listing, so it stays legible rather than being hidden away. */
.footer__licence {
  max-width: 34rem;
  font-size: 0.72rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.72);
}

/* The registration code is one long unbroken token; let it wrap anywhere so it
   cannot push the footer sideways on a narrow screen. */
.footer__reg {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ==========================================================================
   SCROLL REVEALS
   ========================================================================== */

/* The hidden starting state is gated behind a class that only JS adds, and
   which JS also removes as a failsafe. So content is never left invisible by
   a missing IntersectionObserver, a zero-height viewport, or a JS error:
   the animation is an enhancement, never a precondition for reading the page. */
[data-reveal] {
  transition: opacity 0.85s var(--ease), transform 0.85s var(--ease);
  transition-delay: calc(var(--reveal-delay, 0) * 110ms);
}

.reveals-armed [data-reveal]:not(.is-in) {
  opacity: 0;
  transform: translateY(22px);
}

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */

@media (max-width: 809px) {
  .intro__grid,
  .pool__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.75rem, 6vw, 3rem);
  }

  /* text first, then the visual */
  .intro__map { grid-row: 2; }
  .collage { grid-row: 2; max-width: 26rem; }

  .intro__text p,
  .pool__text p { max-width: 46ch; }

  /* Title top left, language picker top right on the same line, booking button
     under the title. The sticky nav owns the bottom of the hero. */
  .hero__bar {
    bottom: auto;
    grid-template-columns: minmax(0, 1fr) auto;
    justify-items: start;
    gap: 1.1rem 0.75rem;
    text-align: left;
  }

  /* Trimmed a little so the title and the picker share one line without the
     title having to wrap to "Villa / Caroline". */
  .hero__wordmark {
    grid-column: 1;
    grid-row: 1;
    text-align: left;
    font-size: clamp(2.05rem, 9.4vw, 2.75rem);
  }

  .hero__lang {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
    align-self: center;
  }
  .hero__cta { grid-column: 1; grid-row: 2; justify-self: start; }

  /* One scrollable line rather than wrapping to two rows of pills. The scroll
     container is the inner element, which the max-width caps; on the <ul> the
     content-driven width wins instead and the row is clipped, not scrollable. */
  .sitenav__inner {
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .sitenav__inner::-webkit-scrollbar { display: none; }

  .sitenav ul {
    flex-wrap: nowrap;
    justify-content: flex-start;
    width: max-content;
    gap: 0.2rem;
  }

  .sitenav a { font-size: 0.92rem; padding: 0.4rem 0.7rem; }

  .amenities__list { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 539px) {
  .hero { height: clamp(28rem, 76vh, 34rem); }
  .carousel__btn { display: none; }
  .carousel__slide { width: 88vw; }
  .footer { min-height: 320px; }
  .terrace { margin-top: 0; }
}

/* ==========================================================================
   MOTION / PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  [data-reveal] { opacity: 1; transform: none; }
  .hero__frames { animation: none; transform: scale(1.03); }
  .carousel__track { scroll-behavior: auto; }

  /* No scroll-linked movement at all; the JS also skips binding. */
  .terrace,
  .hero__bar { transform: none !important; }
  .collage:hover .collage__item { transform: none !important; }
  .carousel__link:hover img,
  .carousel__link:focus-visible img { transform: none !important; }
  .hero__lang ul { animation: none; }
  .sitenav { transition: none; }
  .lightbox__img { animation: none; }
}

@media print {
  .hero { height: auto; }
  .hero__frame:not(.is-active), .carousel__btn, .carousel__dots, .map, .skip-link { display: none; }
  .faq details { display: block; }
  .footer { background: none; color: var(--navy); }
}
