/* ---------- Intro: header + hero sharing one full-screen backdrop ---------- */
.intro {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-rows: auto 1fr;
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
  /* Crops the same, without making the intro a scroll container */
  overflow: clip;
}

/* The hold: the intro sticks to the top of the screen while the reader scrolls through the
   extra distance below it, and the hero scene (components/home/HeroScene.tsx) steps towards
   the view over that distance. Then the intro scrolls away like any section. */
.intro-hold::after {
  content: "";
  display: block;
  height: var(--intro-hold, 100svh);
}

.intro-hold > .intro {
  position: sticky;
  top: 0;
  /* Lifts the intro's layer above the sections after it (which never overlap it), so the
     header bar inside it, once fixed to the top of the screen, is not painted under them */
  z-index: 3;
}

/* No hold where the scene does not move: with reduced motion, and on a phone, upright or on its
   side (the owner's direction, 5 November 2026: no parallax on a phone at all; the same query is
   PHONE in HeroScene.tsx) */
@media (prefers-reduced-motion: reduce) {
  .intro-hold::after {
    display: none;
  }
}

@media (max-width: 52rem) and (orientation: portrait),
  (orientation: landscape) and (max-height: 32rem) and (pointer: coarse) {
  .intro-hold::after {
    display: none;
  }

  .intro__layer {
    will-change: auto;
  }
}

.intro__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  container-type: size;
}

/* One 16:9 frame that covers the intro, anchored to its top left corner (the plaster wall the
   copy sits on): the sky over the island is never cut, and whatever a short screen has no room
   for comes off the terrace floor. The depth layers fill it exactly, so they stay aligned
   whatever the screen, and each scales about the same point: the island in the doorway. */
.intro__scene {
  position: absolute;
  top: 0;
  left: 0;
  width: max(100cqw, 100cqh * 16 / 9);
  aspect-ratio: 16 / 9;
}

.intro__layer {
  position: absolute;
  inset: 0;
  /* The island's middle (assets-source/hero/island/compose.py places it at 2885, 582) */
  transform-origin: 75% 27%;
  will-change: transform;
}

/* The <picture> around each layer (AVIF first) steps aside, so the image sizes to the layer */
.intro__layer picture {
  display: contents;
}

.intro__layer img {
  display: block;
  width: 100%;
  height: 100%;
}

/* The header stands on the page ground above the picture rather than over it (the owner's
   direction, 12 October 2026): the bar wears the ground and hairline it wears when it slides
   back in on scroll up, and the scene and the hero copy share the row below it, so the intro is
   still exactly one screen with the header in it. Upright phones already stack the header, the
   picture and the copy (below), so only the bar's dress applies there. */
.intro .site-header__bar {
  background-color: var(--color-ground);
  box-shadow: inset 0 -1px 0 var(--color-line);
}

@media not all and (max-width: 52rem) and (orientation: portrait) {
  .intro > .site-header {
    grid-row: 1;
    grid-column: 1;
  }

  .intro > .intro__media,
  .intro > .hero {
    grid-row: 2;
    grid-column: 1;
  }

  .intro > .intro__media {
    position: relative;
    inset: auto;
    /* A layer scaled by the hold stays inside the picture's own row */
    overflow: clip;
  }
}

/* Phones and narrow tablets held upright: covering the screen would show only the plaster wall,
   so the scene stands in the flow between the header and the copy, on the page ground, cut to the
   doorway (from the arch's left edge, 35% in, to the frame's right edge, full height: 10.4 / 9),
   with a clean foot and the band of playful lines straight under it (the owner's direction,
   15 October 2026: no fade into the ground). The intro is exactly one screen, so the button is in
   view through the hold, and the picture takes whatever height the header, the band and the copy
   leave, all of it: the doorway always spans the screen edge to edge, and on a tall screen it grows
   until it fills the height too, trimming the doors' outer edges (no gap under the header: the
   owner's direction, 15 October 2026); on a short one it crops top and bottom instead, mostly
   from the floor. There is no hold here and the layers stay still (no parallax on a phone, 5
   November 2026); the intro scrolls away like any section.
   Here the scene is the visible picture only (full width, its own height), and the layers are
   the whole photograph placed inside it. The clip sits on that one box, so no row of a scaled
   layer can slip out below the edge the reader sees. */
@media (max-width: 52rem) and (orientation: portrait) {
  .intro {
    height: 100vh;
    height: 100svh;
    grid-template-rows: auto minmax(0, 1fr) auto auto;
    grid-template-columns: minmax(0, 1fr);
    background: var(--color-ground);
  }

  .intro__media {
    position: relative;
    inset: auto;
    order: 1;
    container-type: size;
  }

  .intro > .ticker--intro {
    order: 2;
  }

  .intro > .hero {
    order: 3;
    padding-top: var(--space-s);
    padding-bottom: var(--space-l);
  }

  .intro__scene {
    --scene-width: max(100cqw / 0.65, 100cqh * 16 / 9);
    --scene-height: calc(var(--scene-width) * 9 / 16);
    --scene-spare: calc(100cqh - var(--scene-height));
    top: max(0px, var(--scene-spare));
    width: 100%;
    height: min(100%, var(--scene-height));
    aspect-ratio: auto;
    translate: none;
    overflow: clip;
  }

  /* The whole photograph: the doorway across the screen, its right-hand door at the screen's edge,
     until the picture has grown enough to centre the island (75% across) instead, so on a tall
     screen the island never slips off; a shortfall in height comes three parts from the floor to
     one from the sky */
  .intro__layer {
    inset: auto;
    top: min(0px, var(--scene-spare) / 4);
    left: max(100cqw - var(--scene-width), 50cqw - var(--scene-width) * 0.75);
    width: var(--scene-width);
    height: var(--scene-height);
  }
}

/* A short phone (an iPhone SE): the copy closes up a little, so the picture keeps more height */
@media (max-width: 52rem) and (orientation: portrait) and (max-height: 46rem) {
  .intro .hero__title {
    font-size: calc(var(--text-display) * 0.85);
  }

  .intro .hero__lead {
    margin-top: var(--space-s);
  }

  .intro .hero__actions {
    margin-top: var(--space-m);
  }

  .intro > .hero {
    padding-bottom: var(--space-m);
  }
}

/* Legibility layer; each theme paints it */
.intro::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--hero-scrim, none);
  pointer-events: none;
}

/* ---------- Site header ---------- */
/* The header holds the bar's place at the top of the page. Once that place has scrolled away
   the bar is fixed to the top of the screen, out of sight, and drops back into view whenever
   the reader scrolls up (data-pin, set by components/site/SiteHeader.tsx). */
.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  /* A tenth shorter than it was with --space-m above and below the row */
  padding: calc(var(--space-m) * 0.83) var(--gutter);
  background-color: transparent;
  box-shadow: inset 0 -1px 0 transparent;
  /* Back in its place at the top, the ground and hairline fade into whatever is behind it */
  transition:
    background-color 0.3s var(--ease-out),
    box-shadow 0.3s var(--ease-out);
}

/* Fixed to the screen it keeps its own padding, so the wordmark and links sit exactly where they
   sit at the top of the page and do not move when it settles back into its place there */
.site-header__bar[data-pin] {
  position: fixed;
  inset: 0 0 auto;
  z-index: 9;
  background-color: var(--color-ground);
  box-shadow: inset 0 -1px 0 var(--color-line);
}

/* Out of sight above the screen. Parked is the first move there, made while the reader scrolls
   down past the header, so it happens in one step rather than sliding past them. */
.site-header__bar[data-pin="parked"],
.site-header__bar[data-pin="hiding"] {
  translate: 0 -100%;
  opacity: 0;
}

.site-header__bar[data-pin="parked"] {
  transition: none;
}

.site-header__bar[data-pin="hiding"] {
  transition:
    translate 0.24s cubic-bezier(0.4, 0, 1, 1),
    opacity 0.24s cubic-bezier(0.4, 0, 1, 1);
}

/* Drops down into view; a keyboard reader tabbing into it brings it down too */
.site-header__bar[data-pin="shown"],
.site-header__bar[data-pin]:focus-within {
  translate: 0 0;
  opacity: 1;
  transition:
    translate 0.5s var(--ease-out),
    opacity 0.35s var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .site-header__bar[data-pin="parked"],
  .site-header__bar[data-pin="hiding"] {
    translate: 0 0;
    visibility: hidden;
  }

  .site-header__bar[data-pin="hiding"] {
    transition:
      opacity 0.2s linear,
      visibility 0s linear 0.2s;
  }

  .site-header__bar[data-pin="shown"],
  .site-header__bar[data-pin]:focus-within {
    visibility: visible;
    transition: opacity 0.25s linear;
  }
}

.wordmark {
  font-family: var(--font-wordmark);
  font-size: var(--text-wordmark);
  line-height: 1;
  color: var(--color-nav);
  text-decoration: none;
  white-space: nowrap;
}

/* The second word of the wordmark (header and footer) in the face's own italic, a step heavier
   than the upright so the two words read as one weight (the italic is lighter on the page at
   the same number). */
.wordmark em,
.site-footer__mark em {
  font-style: italic;
  font-weight: 600;
}

.site-nav__list {
  display: flex;
  gap: clamp(1.25rem, 0.5rem + 2.4vw, 3rem);
}

.site-nav__link {
  position: relative;
  display: inline-block;
  padding-block: var(--space-2xs);
  font-size: var(--text-nav);
  color: var(--color-nav);
  text-decoration: none;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.site-nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s var(--ease-out);
}

.site-nav__link:hover::after,
.site-nav__link[aria-current="page"]::after {
  transform: scaleX(1);
}

.site-nav__toggle {
  display: none;
}

/* The links, the language switcher and (on a narrow screen) "Menu", together at the bar's end */
.site-header__end {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 0.5rem + 2.4vw, 3rem);
}

/* ---------- Language switcher ---------- */
/* The two flags (components/site/LanguageSwitch.tsx), set off from the links by a hairline. The
   flag in use carries the nav's underline; the other rests faded and comes up on hover. Each
   link's padding gives a finger a full target without making the bar any taller. */
.lang-switch {
  /* The hairline halfway between the last link and the first flag */
  padding-inline-start: calc(clamp(1.25rem, 0.5rem + 2.4vw, 3rem) * 0.5);
  margin-inline-start: calc(clamp(1.25rem, 0.5rem + 2.4vw, 3rem) * -0.5);
  border-inline-start: 1px solid var(--color-line);
}

.lang-switch__list {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.lang-switch__link {
  position: relative;
  display: grid;
  place-items: center;
  padding: 0.75rem 0.4rem;
  margin-block: -0.75rem;
  color: var(--color-nav);
  opacity: 0.5;
  transition: opacity 0.3s var(--ease-out);
}

.lang-switch__link:hover,
.lang-switch__link:focus-visible,
.lang-switch__link[aria-current] {
  opacity: 1;
}

.lang-switch__flag {
  display: block;
  inline-size: 1.375rem;
  block-size: auto;
  aspect-ratio: 3 / 2;
  border-radius: 2px;
  /* An edge for the Italian white against the cream */
  box-shadow: 0 0 0 1px var(--color-line);
}

.lang-switch__link::after {
  content: "";
  position: absolute;
  left: 0.4rem;
  right: 0.4rem;
  bottom: 0.3rem;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s var(--ease-out);
}

.lang-switch__link:hover::after,
.lang-switch__link[aria-current]::after {
  transform: scaleX(1);
}

/* A small phone: the wordmark, the two flags and "Menu" share one row, closer together. On the
   narrowest the bars alone stand for "Menu", which a screen reader still hears. */
@media (max-width: 26rem) {
  .site-header__bar {
    gap: var(--space-s);
  }

  .site-header__end {
    gap: 0.875rem;
  }

  .lang-switch__list {
    gap: 0;
  }

  .lang-switch__link {
    padding-inline: 0.3rem;
  }

  .lang-switch__link::after {
    left: 0.3rem;
    right: 0.3rem;
  }
}

@media (max-width: 23.5rem) {
  /* The bars alone still make a full-size target (over the narrow-screen toggle rule below) */
  .site-header__end .site-nav__toggle {
    padding: 0.75rem 0.5rem;
    margin: -0.75rem -0.5rem;
  }

  .site-nav__toggle-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ---------- Hero copy ---------- */
.hero {
  display: flex;
  align-items: var(--hero-align, center);
  padding: var(--space-l) var(--gutter) var(--space-xl);
}

.hero__copy {
  max-width: var(--hero-measure, 40rem);
}

.hero__title {
  font-family: var(--font-display);
  font-size: var(--text-display);
  font-weight: var(--display-weight, 400);
  font-style: var(--display-style, normal);
  line-height: var(--display-leading, 0.98);
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--color-ink);
  text-wrap: balance;
}

.hero__lead {
  margin-top: var(--space-m);
  max-width: 30ch;
  font-size: var(--text-lead);
  font-weight: var(--lead-weight, 500);
  line-height: 1.3;
  color: var(--color-ink-soft);
}

.hero__detail {
  margin-top: var(--space-s);
  max-width: 44ch;
  font-size: var(--text-body);
  color: var(--color-ink-soft);
}

.hero__actions {
  margin-top: var(--space-l);
}

/* A phone: the two paragraphs run the full width, and HeroIntro sets their lines as one inverted
   pyramid, each line a block of its own. Everything is centred (Danylo, 5 November 2026), so the
   pyramid narrows to the middle and the button stands under it. */
@media (max-width: 40rem) {
  /* The whole width, so a title that fits on one line (the Italian) still centres on the screen
     rather than on itself */
  .hero__copy {
    width: 100%;
    text-align: center;
  }

  .hero__title {
    margin-inline: auto;
  }

  .hero__actions {
    display: flex;
    justify-content: center;
  }

  .hero__lead,
  .hero__detail {
    max-width: none;
  }

  .hero__line {
    display: block;
    white-space: nowrap;
  }

  /* The pyramid's own height, held from the first paint: until the script has set the lines, the
     browser wraps the paragraphs at full width into fewer lines, and the block grew when the
     pyramid arrived, pushing the picture and the band of lines up the screen (a layout shift that
     search engines count against the page). The counts are the pyramid's own, measured at every
     phone width on 20 October 2026: English 4 + 3 lines, 5 + 4 on the narrowest phones; Italian,
     whose first paragraph is one short sentence, 1 + 6, and 2 + 8 at the narrowest. */
  .hero__lead {
    min-height: 4lh;
  }

  .hero__detail {
    min-height: 3lh;
  }

  :lang(it) .hero__lead {
    min-height: 1lh;
  }

  :lang(it) .hero__detail {
    min-height: 6lh;
  }
}

@media (max-width: 22rem) {
  .hero__lead {
    min-height: 5lh;
  }

  .hero__detail {
    min-height: 4lh;
  }
}

@media (max-width: 23rem) {
  :lang(it) .hero__detail {
    min-height: 8lh;
  }
}

@media (max-width: 21rem) {
  :lang(it) .hero__lead {
    min-height: 2lh;
  }
}

/* ---------- Button ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.625rem;
  padding: 0.7rem 1.6rem;
  border-radius: var(--radius-cta);
  font-family: var(--font-body);
  font-size: calc(var(--text-body) * 0.72);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  /* A label that runs onto two lines on a narrow screen keeps each line centred (the owner's
     direction, 5 November 2026) */
  text-align: center;
  /* The lift is under a pixel, and text on the page's own layer snaps to whole pixels as the
     box moves between them — the label shivers against the fill. will-change keeps every
     button on a layer of its own, so the label moves and swells as one piece with it. */
  will-change: transform;
  transition:
    background-color 0.2s var(--ease-out),
    transform 0.2s var(--ease-out),
    box-shadow 0.2s var(--ease-out);
}

/* Every button answers a hover the same way, whatever its size: a 2.5% swell, a 1.5% lift and
   a soft grey-black shadow all the way round, together over 200ms. A filled button also
   takes the hover colour; the drawn one keeps its own. A button that needs less of it sets
   --btn-hover-scale and --btn-hover-shadow rather than restating the hover. */
.btn:hover {
  transform: translateY(-1.5%) scale(var(--btn-hover-scale, 1.025));
  box-shadow: 0 0.25rem 1rem rgb(0 0 0 / var(--btn-hover-shadow, 0.33));
}

.btn:active {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .btn:hover {
    transform: none;
  }
}

.btn--primary {
  background: var(--color-cta);
  color: var(--color-cta-ink);
  box-shadow: 0 0.5rem 1.5rem -0.75rem rgb(0 0 0 / 0.45);
}

.btn--primary:hover {
  background: var(--color-cta-hover);
}

/* The quieter half of a pair: same button, drawn rather than filled. It has no hover colour
   of its own yet — only the shared lift, with less swell (2.25%) and a lighter shadow (25%),
   since nothing in the fill holds it down. */
.btn--secondary {
  --btn-hover-scale: 1.0225;
  --btn-hover-shadow: 0.25;
  border: 1px solid var(--color-cta);
  background: transparent;
  color: var(--color-cta);
}

/* ---------- Carousel controls (components/shared/CarouselControls.tsx) ----------
   One arrow and one row of dots for every carousel on the site: activities, featured homes,
   guest reviews and the property gallery. Everything is drawn from one ink, so a section
   only names its own (--control-ink) and its ground (--control-ground, the arrow's colour
   on hover); the ring and the idle dots are that ink at a fifth of its strength. */
.carousel-arrow {
  display: inline-grid;
  place-items: center;
  width: clamp(2.75rem, 2.4rem + 0.8vw, 3.125rem);
  height: clamp(2.75rem, 2.4rem + 0.8vw, 3.125rem);
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--control-ink, var(--color-ink)) 22%, transparent);
  border-radius: 50%;
  background: transparent;
  color: var(--control-ink, var(--color-ink));
  cursor: pointer;
  transition:
    background-color 0.3s var(--ease-out),
    border-color 0.3s var(--ease-out),
    color 0.3s var(--ease-out);
}

/* Filled while the pointer is over it, and on a touch screen only while the finger is down: a
   phone keeps the last tapped thing "hovered", which left the arrow green after a press (the
   owner's report, 5 November 2026) */
@media (hover: hover) {
  .carousel-arrow:hover {
    border-color: var(--control-ink, var(--color-ink));
    background: var(--control-ink, var(--color-ink));
    color: var(--control-ground, var(--color-ground));
  }
}

.carousel-arrow:active {
  border-color: var(--control-ink, var(--color-ink));
  background: var(--control-ink, var(--color-ink));
  color: var(--control-ground, var(--color-ground));
}

.carousel-dots {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.carousel-dots li {
  position: relative;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--control-ink, var(--color-ink)) 22%, transparent);
}

/* The filled dot is a layer over the idle one: the leaving dot fades out at once, the
   arriving dot fades up a beat later, so the place hands over rather than travels */
.carousel-dots li::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--control-ink, var(--color-ink));
  opacity: 0;
  transition: opacity 0.3s var(--ease-out);
}

.carousel-dots li.is-current::after {
  opacity: 1;
  transition: opacity 0.4s var(--ease-out) 0.15s;
}

/* The longest row (the homepage's reviews) still fits a phone on one line */
@media (max-width: 44rem) {
  .carousel-dots {
    gap: 0.5rem;
  }
}

/* ---------- Activities carousel (below the hero) ---------- */
/* ---------- The owner's playful lines ----------
   One band straight under the hero (PhraseTicker.tsx): the five lines flow right to left at one
   steady speed, in the display face's italic and the gold that carries words, each followed by a
   brass dot so they read as separate lines. Like the hero above it, the band runs the full width
   of the screen: the lines come in at one edge and leave at the other, with no fade (the owner's
   direction, 15 October 2026). The track holds the lines twice and slides by exactly one set
   (-50%), so the loop never shows a seam. Linear on purpose: a ticker that eased would surge and
   stall. */
.ticker {
  /* One full pass of the five lines (tuned in dev-tools/motion-lab) */
  --ticker-loop: 41300ms;
  --ticker-gap: clamp(1.0625rem, 0.68rem + 1.275vw, 1.9125rem);
  padding-top: clamp(0.72rem, 0.576rem + 0.576vw, 1.08rem);
  padding-bottom: clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  overflow: clip;
  background: var(--color-ground);
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-style: italic;
  line-height: 1.3;
  color: var(--color-gold);
}

.ticker__track {
  display: flex;
  width: max-content;
  /* It keeps flowing under the pointer (it paused there until Danylo's review, 5 November 2026);
     with reduced motion it stands still, below */
  animation: ticker var(--ticker-loop) linear infinite;
}

.ticker__set {
  display: flex;
  flex-shrink: 0;
}

.ticker__phrase {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

/* The dot after every line, the last too, so the seam between the two sets reads like the rest */
.ticker__phrase::after {
  content: "·" / "";
  margin-inline: var(--ticker-gap);
  font-style: normal;
  font-weight: 700;
  color: var(--color-accent);
}

@keyframes ticker {
  to {
    translate: -50% 0;
  }
}

/* The band is drawn twice: under the intro's hold on a screen held sideways, and inside the intro,
   straight under the picture, on a phone held upright (the intro rules above place it). Only one
   is ever shown, so a screen reader meets it once. */
.ticker--intro {
  display: none;
}

@media (max-width: 52rem) and (orientation: portrait) {
  /* A tenth smaller on a phone, words, dots and padding together (the owner's direction,
     15 October 2026); it still sits straight on the copy below, and the picture takes the height
     it gives back */
  .ticker--intro {
    --ticker-gap: calc(clamp(1.0625rem, 0.68rem + 1.275vw, 1.9125rem) * 0.9);
    display: block;
    padding-top: calc(clamp(0.72rem, 0.576rem + 0.576vw, 1.08rem) * 0.9);
    padding-bottom: calc(clamp(1rem, 0.8rem + 0.8vw, 1.5rem) * 0.9);
    font-size: calc(var(--text-h4) * 0.9);
  }

  .ticker--page {
    display: none;
  }
}

/* Reduced motion: the band stands still, the lines wrapped and centred, the copy set put away */
@media (prefers-reduced-motion: reduce) {
  .ticker {
    padding-inline: var(--frame-inset);
  }

  .ticker__track {
    width: auto;
    justify-content: center;
    animation: none;
  }

  .ticker__set {
    flex-wrap: wrap;
    justify-content: center;
    flex-shrink: 1;
  }

  .ticker__set[aria-hidden] {
    display: none;
  }

  .ticker__phrase:last-child::after {
    content: none;
  }
}

.activities {
  --arrow-col: clamp(3.5rem, 1rem + 6vw, 8.5rem);
  --carousel-gap: clamp(2rem, 0.5rem + 5vw, 6rem);
  /* How long one slide takes to travel through (read by ActivitiesCarousel.tsx; the owner's pick,
     tuned in dev-tools/motion-lab) */
  --activities-slide: 1500ms;
  padding-block: var(--space-xl);
  background: var(--color-ground);
  color: var(--color-ink);
}

/* Arrow columns sit either side of the content column, so header, photo and footer share one left edge */
.activities__inner {
  display: grid;
  grid-template-columns: var(--arrow-col) minmax(0, 1fr) var(--arrow-col);
  max-width: calc(76rem + 2 * var(--arrow-col));
  margin-inline: auto;
}

.activities__header {
  grid-column: 2;
}

/* The site's one label: tracked capitals over a heading. Every page's label reads these values. */
.activity__label {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-label);
}

/* The title opens the section where its label used to stand (the label went on 15 October 2026) */
.activities__title {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.05;
  letter-spacing: var(--display-tracking, -0.01em);
  text-wrap: balance;
}

/* A phone: one line where it fits (closed up a touch, so it does on a 390px phone), and where it
   does not, plain wrapping, which with the last two words held together moves only "in Ischia" */
@media (max-width: 40rem) {
  .activities__title {
    letter-spacing: -0.025em;
    text-wrap: wrap;
  }

  /* The section's heading and its line centred on a phone; the slides' words keep to the left
     (Danylo, 5 November 2026) */
  .activities__header {
    text-align: center;
  }
}

.carousel {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  margin-top: var(--space-l);
}

.carousel__track {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  row-gap: var(--space-xl);
  touch-action: pan-y;
}

.activity {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
  column-gap: var(--carousel-gap);
}

.activity__media {
  margin: 0;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: 2px;
  background: color-mix(in srgb, var(--color-ink) 8%, transparent);
}

.activity__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--activity-focus, center);
}

/* La Mortella's photograph is 800 x 450, shipped whole: the square frame shows the owner's crop of
   it, from 167 px in on a desktop and 175 px in on a phone (crop tool, 15 October 2026; the two are
   10 px apart on screen, so each keeps its own). Position = left / (800 - 450). */
.activity__media--la-mortella {
  --activity-focus: 47.7% 50%;
}

@media (max-width: 52rem) {
  .activity__media--la-mortella {
    --activity-focus: 50% 50%;
  }
}

.activity__body {
  display: flex;
  flex-direction: column;
  /* Bottom padding keeps the copy clear of the shared counter/button bar */
  padding-block: clamp(1rem, 4%, 3.5rem) calc(2.625rem + var(--space-l));
}

/* The one heading outside the scale (owner's direction): each activity is the hero of its slide,
   so its title stands larger than the section title above it, as the approved comp set it */
.activity__title {
  margin-top: var(--space-s);
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1.5rem + 2.8vw, 4.25rem);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1;
  letter-spacing: var(--display-tracking, -0.01em);
}

.activity__title span {
  display: block;
}

/* Kept even when empty so the body copy starts at the same height on every slide */
.activity__place {
  min-height: 1.5em;
  margin-top: var(--space-m);
  font-size: var(--text-small);
  line-height: 1.5;
  color: var(--color-muted);
}

.activity__text {
  margin-top: var(--space-m);
  max-width: 38ch;
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

/* Shared across slides: sits over the bottom of the text column and never moves. Raised, because
   a sliding photograph passes beneath it on the way through. */
.carousel__bar {
  position: relative;
  z-index: 1;
  grid-column: 2;
  grid-row: 1;
  align-self: end;
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
  column-gap: var(--carousel-gap);
  pointer-events: none;
}

.carousel__meta {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  pointer-events: auto;
}

.carousel__position {
  display: flex;
  align-items: center;
  gap: var(--space-l);
}

.carousel__count {
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--color-muted);
}

/* The arrows' look is the shared .carousel-arrow; this only places them */
.carousel__button {
  grid-row: 1;
  justify-self: center;
}

.carousel__button--prev {
  grid-column: 1;
}

.carousel__button--next {
  grid-column: 3;
}

/* Sits with the heading rather than alone under the carousel */
.activities__note {
  margin-top: var(--space-s);
  max-width: 48ch;
  color: var(--color-ink-soft);
}


/* Enhanced by JS: slides share one cell, so the card keeps the height of the tallest slide */
.carousel:not(.is-ready) .carousel__button,
.carousel:not(.is-ready) .carousel__position {
  display: none;
}

/* A sideways strip seen through the content column. Photograph and copy travel together as one
   slide, the slides a gap apart as if they sat side by side on one row. The script moves them
   frame by frame (ActivitiesCarousel.tsx): it shows the one or two slides within a slide of where
   the row stands and sets how far to the side each is, --slide-at, in slide widths. The rest wait
   unseen. The counter, dots and button sit outside the track and never move. */
.carousel.is-ready .carousel__track {
  --slide-step: calc(100% + var(--carousel-gap));
  overflow: clip;
}

.carousel.is-ready .activity {
  grid-area: 1 / 1;
  visibility: hidden;
  translate: calc(var(--slide-at, 1) * var(--slide-step)) 0;
}

/* ---------- Narrow screens ---------- */
@media (max-width: 52rem) {
  /* One slim row, the wordmark and "Menu": the links open in a dialog (.modal--menu) */
  .site-header__bar {
    padding-block: var(--space-s);
  }

  .site-nav {
    display: none;
  }

  /* With the links gone into the menu, the flags stand on their own beside "Menu" */
  .lang-switch {
    padding-inline-start: 0;
    margin-inline-start: 0;
    border-inline-start: 0;
  }

  .site-nav__toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-2xs) 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--text-nav);
    color: var(--color-nav);
    cursor: pointer;
  }

  .site-nav__toggle-bars {
    display: grid;
    gap: 5px;
    width: 1.25rem;
  }

  .site-nav__toggle-bars::before,
  .site-nav__toggle-bars::after {
    content: "";
    height: 1.5px;
    background: currentColor;
  }

  .hero {
    --hero-align: end;
  }

  .activities__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    padding-inline: var(--gutter);
  }

  .activities__header {
    grid-column: 1 / -1;
  }

  .carousel__track {
    grid-column: 1 / -1;
  }

  /* Slack from the tallest slide goes to the text row, keeping the controls in one place */
  .activity {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
  }

  .activity__body {
    padding-block: var(--space-m) 0;
  }

  /* Two-line titles: a little more room between the lines, so a descender ("Up") never meets
     the ascender under it ("of") */
  .activity__title {
    line-height: 1.1;
  }

  /* Under the slides (the owner's direction, 20 October 2026): the dots centred between the two
     arrows, no counter, and the button centred beneath. The bar and its row give up their boxes,
     so the dots and the button take places of their own in the carousel's grid. An empty place
     line keeps its height, so the text starts at one level on every slide. */
  .carousel {
    grid-template-columns: auto minmax(0, 1fr) auto;
    column-gap: var(--space-s);
  }

  .carousel__bar,
  .carousel__meta {
    display: contents;
  }

  /* The arrows, dots and button stand a little closer under the longest blurb (La Mortella's):
     the row at 60% of its old space, the button at 85% of its own (the owner's direction, 5
     November 2026), the whole group about a tenth nearer */
  .carousel {
    --carousel-controls-gap: calc(var(--space-m) * 0.6);
  }

  .carousel__position {
    grid-column: 2;
    grid-row: 2;
    justify-self: center;
    margin-top: var(--carousel-controls-gap);
  }

  .carousel__count {
    display: none;
  }

  .carousel__meta .btn {
    grid-column: 1 / -1;
    grid-row: 3;
    justify-self: center;
    margin-top: calc(var(--space-l) * 0.85);
  }

  .carousel__button {
    grid-row: 2;
    margin-top: var(--carousel-controls-gap);
  }

  .carousel__button--prev {
    grid-column: 1;
  }

  .carousel__button--next {
    grid-column: 3;
  }

}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
  }

  /* The slide is simply swapped in place */
  .carousel.is-ready .activity {
    translate: none !important;
  }
}

/* ---------- Guest reviews (below the activities carousel) ---------- */
/* A white band with the warm cards on it. The --review-* roles are the site's own colours
   under this section's names, so the dialogs and the owners' reviews can retune them. */
.reviews {
  /* How long the row takes to glide to the next card (read by ReviewsCarousel.tsx; the owner's
     pick, tuned in dev-tools/motion-lab) */
  --reviews-glide: 900ms;
  --review-surface: var(--color-card);
  --review-heading: var(--color-ink);
  --review-quote: var(--color-ink-soft);
  --review-meta: var(--color-muted);
  --review-sage: var(--color-tint);
  --review-star: var(--color-accent);
  --review-rail: var(--color-line);
  --review-scrim: rgb(36 31 26 / 0.5);
  --review-gap: clamp(1rem, 0.7rem + 0.9vw, 1.375rem);
  --review-pad: clamp(1.5rem, 1.15rem + 1vw, 2rem);
  --control-ink: var(--review-heading);
  --control-ground: var(--color-section);
  padding-block: clamp(3rem, 1.8rem + 4vw, 5.5rem);
  background: var(--color-section);
  color: var(--review-quote);
}

.reviews__inner {
  /* Peppino's card and a local host's share their first two columns */
  --host-portrait: clamp(9.5rem, 5rem + 8vw, 14.5rem);
  --host-gap: clamp(1.5rem, 0.5rem + 3.4vw, 4.5rem);
  width: min(88rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
}

/* ---------- Meet your local host ----------
   Sits inside .reviews on purpose: it takes that section's palette unchanged, with no
   second set of colour variables to keep in step. Three columns — portrait, the copy
   that carries the section, then the signature and the WhatsApp CTA as one signed-off
   pair. Only a hairline separates it from the guest reviews below. */
.host {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: var(--host-gap);
  align-items: center;
  padding-bottom: clamp(2rem, 1.4rem + 2.2vw, 3.5rem);
  border-bottom: 1px solid var(--review-rail);
}

/* Centred on the block, not pinned to the eyebrow: the photograph balances the whole host card
   rather than sitting on top of the name. Upright, in its own proportions (Peppino's photograph
   cut to the owner's crop, 1087 x 1322) so nothing is cut off, with the 2px corner the site's
   other photographs carry. */
.host__portrait {
  align-self: center;
  flex: none;
  display: block;
  width: var(--host-portrait);
  height: auto;
  aspect-ratio: 1087 / 1322;
  border-radius: 2px;
  object-fit: cover;
  background: var(--review-surface);
}

.host__eyebrow {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-gold);
}

/* An h2 in the outline, a sub-heading in the scale: it names the block, the reviews' title
   below is the section's */
.host__name {
  margin-top: clamp(0.5rem, 0.4rem + 0.4vw, 0.875rem);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.1;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--review-heading);
}

/* The credentials are one line of items joined by centred dots, and a dot stranded at
   the edge of a wrapped line is worse than no dot at all. So the dotted row is asked
   for by a container query rather than a viewport one: it appears only once this column
   is wide enough to hold the whole run, and below that the credentials stack instead of
   wrapping. The threshold clears the longer of the two builds' body faces. */
.host__main {
  container-type: inline-size;
  container-name: host-main;
}

.host__facts {
  margin-top: clamp(0.625rem, 0.5rem + 0.5vw, 1rem);
  font-size: var(--text-small);
  line-height: 1.5;
  color: var(--color-gold);
}

@container host-main (min-width: 37rem) {
  .host__facts {
    display: flex;
    flex-wrap: nowrap;
    align-items: baseline;
  }

  .host__facts li {
    white-space: nowrap;
  }

  .host__facts li + li::before {
    content: "\00B7";
    margin-inline: 0.6em;
    color: color-mix(in srgb, var(--color-gold) 55%, transparent);
  }
}

.host__promise {
  margin-top: clamp(1.25rem, 1rem + 1vw, 2rem);
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.15;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--review-heading);
}

.host__text {
  max-width: 58ch;
  margin-top: clamp(0.5rem, 0.4rem + 0.4vw, 0.875rem);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--review-quote);
}

/* The signature signs off the copy and the button answers it: one column, held
   together by a gap smaller than the one separating them from the text */
.host__sign {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.25rem, 1rem + 1.2vw, 2.25rem);
  color: var(--review-heading);
}

/* Masked rather than drawn in: the ink is currentColor, so one asset serves the
   ivory-on-storm build and the ink-on-white one */
.host__signature {
  display: block;
  width: clamp(9rem, 4rem + 14vw, 17rem);
  aspect-ratio: 640 / 337;
  background-color: currentColor;
  opacity: 0.92;
  -webkit-mask: url("/assets/host/peppino-signature.png") center / contain no-repeat;
  mask: url("/assets/host/peppino-signature.png") center / contain no-repeat;
}

/* Button and its reply time read as one control, the same pairing the booking steps use */
.host__action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.5rem, 0.45rem + 0.2vw, 0.6875rem);
}

/* "More about Peppino": a quiet way through to his page, kept out of the CTA pair beside it.
   .host__action centres its column for the WhatsApp pair; this one belongs to the copy. */
.host__action--link {
  align-items: flex-start;
  margin-top: clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
}

/* Longer than the site's other buttons (the owner's direction, 15 October 2026): it is the one
   way to reach Peppino on the homepage */
.host__whatsapp {
  padding-inline: clamp(2.5rem, 2rem + 2vw, 3.5rem);
  white-space: nowrap;
  /* Held at the width it had when it read "Message Peppino" (10.46em of label, "Scrivi a
     Peppino" 10.13em), so the shorter "Message Us" keeps the button's size (16 October 2026) */
  min-width: calc(10.46em + 2 * clamp(2.5rem, 2rem + 2vw, 3.5rem));
}

:lang(it) .host__whatsapp {
  min-width: calc(10.13em + 2 * clamp(2.5rem, 2rem + 2vw, 3.5rem));
}

.host__note {
  font-size: var(--text-small);
  line-height: 1.4;
  color: var(--review-meta);
  text-align: center;
}

/* ---------- The team's welcome ----------
   Opens the white panel on a home's page in place of Peppino's card (14 October 2026). No
   portrait: heading, copy and button are centred on the panel (the owner's direction, 15 October
   2026), and the same hairline as the host cards closes it. */
.welcome {
  padding-bottom: clamp(2rem, 1.4rem + 2.2vw, 3.5rem);
  border-bottom: 1px solid var(--review-rail);
  text-align: center;
}

/* The heading in the display face's heavier weight, and the copy under it running wider than the
   heading (the owner's direction, 15 October 2026) */
.welcome__title {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--review-heading);
}

.welcome__text {
  max-width: 50em;
  margin-inline: auto;
  margin-top: clamp(0.625rem, 0.5rem + 0.5vw, 1rem);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--review-quote);
}

.welcome__action {
  margin-top: clamp(1.25rem, 1rem + 1vw, 2rem);
}

/* ---------- A home's local host ----------
   Follows Peppino's card on the four homes he does not look after himself, in its first two
   columns: the host's face (or initial) in the portrait column, centred on the copy beside it,
   and the copy in his copy column, set like his card in small: the gold label, the name, two
   sentences. Quieter than .host: no credentials, signature or CTA. The hairline under it runs
   the panel's full width, as .host's does. */
.local-host {
  --local-host-avatar: clamp(5.25rem, 3.9rem + 2.8vw, 7.25rem);
  display: grid;
  grid-template-columns: var(--host-portrait) minmax(0, 1fr);
  column-gap: var(--host-gap);
  align-items: center;
  padding-block: clamp(2rem, 1.4rem + 2.2vw, 3.5rem);
  border-bottom: 1px solid var(--review-rail);
}

/* The <picture> around a portrait (it carries the phone crop) steps aside, so the portrait itself
   stays the grid item and keeps its place in the column */
.local-host__picture {
  display: contents;
}

/* Its <source> would otherwise take a grid cell of its own and push the portrait out of its
   column; hidden, it still chooses the phone crop */
.local-host__picture source {
  display: none;
}

.local-host__portrait,
.local-host__initial {
  justify-self: center;
  width: var(--local-host-avatar);
  height: var(--local-host-avatar);
  border-radius: 50%;
}

.local-host__portrait {
  display: block;
  object-fit: cover;
  background: var(--color-media);
}

/* The guests' initial disc (.review__initial), at the host's size */
.local-host__initial {
  display: grid;
  place-items: center;
  background: var(--review-sage);
  color: var(--review-heading);
  font-family: var(--font-display);
  font-size: calc(var(--local-host-avatar) * 0.44);
  line-height: 1;
}

/* Peppino's label, in his gold (the owner's direction, 12 October 2026) */
.local-host__eyebrow {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-gold);
}

.local-host__name {
  margin-top: clamp(0.5rem, 0.4rem + 0.4vw, 0.875rem);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--display-weight, 400);
  line-height: 1.1;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--review-heading);
}

.local-host__text {
  max-width: 58ch;
  margin-top: clamp(0.625rem, 0.5rem + 0.5vw, 1rem);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--review-quote);
}

.local-host__text p + p {
  margin-top: 0.75em;
}

/* Host introduction: compact and subordinate to the heading */
.reviews__intro {
  margin-top: clamp(2.25rem, 1.6rem + 2.4vw, 4rem);
  text-align: center;
}

.reviews__title {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.05;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--review-heading);
}

.reviews__proof {
  margin-top: var(--space-xs);
  font-size: var(--text-small);
  color: var(--review-meta);
}

/* Star geometry only; nothing paints from here */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.reviews__carousel {
  margin-top: clamp(2rem, 1.4rem + 2vw, 3rem);
}

/* The homepage heading stands alone, with no proof line under it, so the cards come up closer */
.reviews__intro:not(:has(.reviews__proof)) + .reviews__carousel {
  margin-top: clamp(1.25rem, 0.9rem + 1.2vw, 2rem);
}

/* One row at every width: a snapping scroller, never a wrapping grid */
.reviews__track {
  display: flex;
  gap: var(--review-gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

/* The arrows and the snap carry the affordance; the bar would cut across the row */
.reviews__track::-webkit-scrollbar {
  display: none;
}

.review {
  /* Containing block for the visually-hidden rating label: without it the label
     is positioned against the page and drags the document's width out to card 25 */
  position: relative;
  flex: 0 0 calc((100% - 2 * var(--review-gap)) / 3);
  display: flex;
  flex-direction: column;
  padding: var(--review-pad);
  border-radius: 8px;
  background: var(--review-surface);
  scroll-snap-align: start;
}

.review__guest {
  display: flex;
  align-items: center;
  gap: 0.875rem;
}

.review__initial {
  flex: none;
  display: grid;
  place-items: center;
  width: 3.375rem;
  height: 3.375rem;
  border-radius: 50%;
  background: var(--review-sage);
  color: var(--review-heading);
  font-family: var(--font-display);
  font-style: normal;
  font-size: 1.5rem;
  line-height: 1;
}

.review__name {
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.15;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--review-heading);
}

/* Held even when a guest has no public location, so every card header is one height */
.review__location {
  min-height: 1.4em;
  margin-top: 0.125rem;
  font-size: var(--text-small);
  line-height: 1.4;
  color: var(--review-meta);
}

.review__quote {
  margin: clamp(1.25rem, 1rem + 0.8vw, 1.75rem) 0 0;
  font-size: var(--text-body);
  line-height: 1.5;
  color: var(--review-quote);
}

/* Two lines and an ellipsis; the whole review is a click away in the dialog.
   min-height holds the same quote area on every card, clamped or not. */
.review__quote p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  min-height: 3em;
  overflow: hidden;
}

/* Quotation marks are drawn, not typed, so the excerpt stays verbatim when copied */
.review__quote p::before {
  content: "\201C";
}

.review__quote p::after {
  content: "\201D";
}

/* The clamp cuts the sentence short, so the closing mark would be a lie */
.review.is-clamped .review__quote p::after {
  content: none;
}

/* Quiet by design: the review is the point, this is the way into the rest of it */
.review__action {
  margin-top: 0.875rem;
}

/* The site's one text link, for every quiet way in or way through that is not a button:
   "Read more", "More about Peppino", "See all amenities" and the Good-to-know notes all read it */
.review__more,
.host__link,
.disclosure__toggle,
.amenities__toggle {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--color-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  cursor: pointer;
  transition: text-decoration-color 0.3s var(--ease-out);
}

.review__more:hover,
.host__link:hover,
.disclosure__toggle:hover,
.amenities__toggle:hover {
  text-decoration-color: currentColor;
}

/* Airbnb's English stands in for the guest's own words, so the card says so, beside the way in */
.review__translated {
  margin-left: 0.75rem;
  font-size: 0.8125rem;
  color: var(--review-meta);
}

.modal__quote + .review__translated {
  display: block;
  margin: 1rem 0 0;
}

/* A grid, not a wrapping flex row: the stars keep one position on every card and
   a long date wraps inside its own column instead of pushing them around */
.review__footer {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: end;
  column-gap: 0.75rem;
  margin-top: auto;
  padding-top: clamp(1.25rem, 1rem + 0.8vw, 1.75rem);
}

.review__rating {
  grid-column: 1;
  display: flex;
  color: var(--review-star);
}

.review__stars {
  display: block;
  fill: currentColor;
}

/* The places past the guest's own rating: the same star, faint */
.review__star-off {
  opacity: 0.22;
}

.review__meta {
  grid-column: 2;
  font-size: var(--text-small);
  line-height: 1.4;
  text-align: right;
  color: var(--review-meta);
}

.review__date {
  white-space: nowrap;
}

.reviews__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
  margin-top: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
}

/* Sits clear of the controls so the arrows stay the obvious way through the row */
.reviews__cta {
  display: flex;
  justify-content: center;
  margin-top: clamp(1.75rem, 1.3rem + 1.6vw, 2.75rem);
}


@media (max-width: 64rem) {
  .review {
    flex-basis: calc((100% - var(--review-gap)) / 2);
  }
}

/* Three columns give out well before the cards do: the signature and CTA drop under
   the copy, and the portrait leads the block instead of flanking it. */
@media (max-width: 76rem) {
  .host {
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
    align-items: start;
  }

  /* Stays in the copy column so it still reads as that copy's sign-off, rather than
     drifting under the portrait */
  .host__sign {
    grid-column: 2;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    row-gap: clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
    gap: clamp(1.25rem, 0.8rem + 2vw, 2.5rem);
  }

  .host__text {
    max-width: 62ch;
  }
}

/* One column: the portrait sits above the copy, and the credentials stack rather than
   wrap — a dot stranded at the edge of a wrapped line is worse than no dot at all. */
@media (max-width: 52rem) {
  .host {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(1.25rem, 1rem + 1.6vw, 2rem);
  }

  .host__sign {
    grid-column: auto;
  }

  /* Peppino's card in one centred column (the owner's direction, 20 October 2026): his label and
     name first, then his portrait, his four credentials as a two-by-two grid, the copy and its
     link, and last the signature and the button. The copy column gives up its box so its parts
     take their places in the card's own grid; the gaps are theirs, not the grid's. */
  .host {
    row-gap: 0;
    justify-items: center;
    text-align: center;
  }

  .host__main {
    display: contents;
  }

  .host__eyebrow {
    order: 1;
  }

  .host__name {
    order: 2;
  }

  .host__portrait {
    order: 3;
    margin-top: var(--space-m);
  }

  .host__facts {
    order: 4;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, max-content));
    gap: 0.5rem 1.5rem;
    margin-top: var(--space-m);
    text-align: left;
  }

  /* Each credential behind a brass dot, held on its first line */
  .host__facts li {
    display: flex;
    gap: 0.55em;
  }

  .host__facts li::before {
    content: "";
    flex: none;
    width: 5px;
    height: 5px;
    margin-top: calc((1lh - 5px) / 2);
    border-radius: 50%;
    background: var(--color-accent);
  }

  .host__promise {
    order: 5;
  }

  .host__text {
    order: 6;
  }

  .host__action--link {
    order: 7;
    align-items: center;
  }

  .host__sign {
    order: 8;
    flex-direction: column;
    align-items: center;
    margin-top: var(--space-l);
  }

  /* The face above the copy, as Peppino's portrait is above his */
  .local-host {
    --local-host-avatar: 4.75rem;
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(1rem, 0.8rem + 1vw, 1.5rem);
    align-items: start;
  }

  .local-host__portrait,
  .local-host__initial {
    justify-self: start;
  }
}

/* One card plus a sliver of the next, so the row reads as scrollable */
@media (max-width: 44rem) {
  .reviews {
    --review-gap: 1rem;
  }

  /* A card a stop makes too many dots to sit between the arrows: they take their own line,
     with the arrows under them */
  .reviews__controls {
    flex-wrap: wrap;
    row-gap: 1rem;
  }

  .reviews__controls .carousel-dots {
    order: -1;
    flex-basis: 100%;
  }

  /* The next card shows only its edge: the sliver stays narrower than the card's own padding, so
     none of its words reach into view (the owner's note, 20 October 2026) */
  .review {
    flex-basis: calc(100% - var(--review-gap) - 0.875rem);
  }

  /* The home and the date on two lines with one left edge, no dot between them, the pair still
     in the corner */
  .review__meta {
    justify-self: end;
    text-align: left;
  }

  .review__meta > [aria-hidden] {
    display: none;
  }

  .review__date {
    display: block;
  }
}

/* ---------- Modal ---------- */
/* One dialog shell (components/shared/Modal.tsx): the expanded guest review, the full amenities list and the
   two Good-to-know notes.

   The palette reads the .reviews roles with the approved values as fallbacks. A dialog
   appended inside .reviews follows that section, and one appended to the body takes the page's
   roles or the default. */
.modal {
  --modal-surface: var(--review-surface, var(--color-card));
  --modal-ink: var(--review-quote, var(--color-ink-soft));
  --modal-heading: var(--review-heading, var(--color-ink));
  --modal-hover: var(--review-sage, var(--color-tint));
  --modal-width: 46rem;

  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 1rem;
  border: 0;
  background: none;
  overflow: hidden;
  /* The dialog box is the click-outside target; the panel inside is the dialog proper */
  display: grid;
  place-items: center;
}

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

.modal::backdrop {
  /* ::backdrop does not inherit from its originating element in every engine, so this one
     carries its own literal rather than reading --modal-scrim */
  background: var(--review-scrim, rgb(36 31 26 / 0.5));
  backdrop-filter: blur(3px);
}

.modal__panel {
  position: relative;
  width: min(var(--modal-width), 100%);
  max-height: 85vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  border-radius: 8px;
  background: var(--modal-surface);
  color: var(--modal-ink);
}

.modal__close {
  position: absolute;
  top: clamp(0.875rem, 0.5rem + 1vw, 1.25rem);
  right: clamp(0.875rem, 0.5rem + 1vw, 1.25rem);
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--modal-heading);
  cursor: pointer;
  transition: background-color 0.3s var(--ease-out);
}

.modal__close:hover {
  background: var(--modal-hover);
}

/* Room for the close button beside the name */
.modal__body .review__guest {
  padding-right: 2.5rem;
}

.modal__quote {
  margin: clamp(1.25rem, 1rem + 0.8vw, 1.75rem) 0 0;
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--modal-ink);
  text-wrap: pretty;
}

.modal__quote p + p {
  margin-top: 0.875em;
}

.modal__body .review__footer {
  margin-top: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  padding-top: 0;
}

/* A dialog holding markup lifted out of the page, rather than a review built from data */
.modal--wide {
  /* Wider, because the amenities run in columns — but still plainly a panel over the page,
     with the scrim reading either side of it */
  --modal-width: 64rem;
}

/* The narrow screen's menu (components/site/SiteHeader.tsx): a small white panel, the white of
   the host-and-reviews band, a centred "Menu" (the wordmark's name over it went on 20 October
   2026), then the site's links one under the other. Each link sits on a hairline as long as the longest label ("For owners"): the
   list is two columns, the labels' width and the rest of the panel, shared by every row through
   subgrid. The page you are on draws its line out in ink across the whole panel as the menu
   opens, and a link under the pointer does the same, so where you are and where you are going
   both read at a glance. Lab-ready: the draw eases with --ease-glide over --menu-draw. */
.modal--menu {
  --modal-surface: var(--color-section);
  --modal-width: 22rem;
  --menu-draw: 600ms;
  --menu-draw-delay: 150ms;
  /* Every row's line two device pixels thick, as Stays' and Contact's always drew (the owner's
     reference, 20 October 2026): one CSS pixel on a 2x screen, and on a 3x phone the same pixel
     scaled to two thirds. Scaled rather than set at two thirds of a pixel, which the browser rounds,
     so the rows would drift off the screen's pixels again. */
  --menu-line-scale: 1;
}

@media (min-resolution: 2.5dppx) {
  .modal--menu {
    --menu-line-scale: calc(2 / 3);
  }
}

.modal--menu .modal__title {
  padding-inline: 2.5rem;
  text-align: center;
}

.menu__list {
  display: grid;
  grid-template-columns: max-content 1fr;
  margin-top: var(--space-m);
}

/* Each row a whole number of pixels tall (28 + 28 + 1), so every row's line falls on the screen's
   pixels the same way. With rows of fractional height each line landed differently, and Home's and
   For owners' drew a pixel or two heavier than the rest. */
.menu__list li {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  grid-template-rows: auto 1px;
}

.menu__list .site-nav__link {
  grid-column: 1;
  padding-block: 0.875rem;
  font-size: var(--text-lead);
  line-height: 1.75rem;
}

/* The rows' own lines, not the bar's underline */
.menu__list .site-nav__link::after {
  content: none;
}

/* Every row's hairline, under the label column */
.menu__list li::after {
  content: "";
  grid-area: 2 / 1;
  height: 1px;
  background: var(--color-line);
  scale: 1 var(--menu-line-scale);
  transform-origin: left top;
}

/* The ink line, drawn from the left over the hairline, nine tenths of the row long (the owner's
   direction, 20 October 2026: the full row ran too far to the right) */
.menu__list li::before {
  content: "";
  grid-area: 2 / 1 / 3 / -1;
  z-index: 1;
  width: 90%;
  height: 1px;
  scale: 1 var(--menu-line-scale);
  background: var(--color-ink);
  transform: scaleX(0);
  transform-origin: left top;
  transition: transform var(--menu-draw) var(--ease-glide);
}

.menu__list li:has([aria-current])::before,
.menu__list li:has(.site-nav__link:hover)::before,
.menu__list li:has(.site-nav__link:focus-visible)::before {
  transform: none;
}

.menu__list .site-nav__link[aria-current] {
  font-weight: 500;
}

/* The current page's line draws out once the panel has begun to rise */
.modal--menu[open] .menu__list li:has([aria-current])::before {
  transition-delay: var(--menu-draw-delay);
}

@starting-style {
  .modal--menu[open] .menu__list li:has([aria-current])::before {
    transform: scaleX(0);
  }
}

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

.modal__title {
  margin: 0;
  padding-right: 2.5rem;
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--display-weight, 400);
  line-height: 1.1;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--modal-heading);
}

/* The grid is tuned for a full-width section; inside a panel it needs its own rhythm. Three
   columns, laid on six half-tracks with every item spanning two. A short last row, of one item or
   two, starts at the left on the same tracks as the rows above (the owner, 20 October 2026). */
.modal .amenities__grid {
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(1.25rem, 1rem + 1.2vw, 2rem) clamp(1.25rem, 0.9rem + 1.4vw, 2.25rem);
  margin-top: clamp(1.5rem, 1.2rem + 1.2vw, 2.25rem);
}

/* A label that runs to two lines breaks into two even ones, not a long line and a stray word */
.modal .amenities__grid > .amenity {
  grid-column: span 2;
  text-wrap: balance;
}

/* The note panels keep their page class; inside the dialog the dialog's type governs */
.modal .disclosure__panel {
  max-width: none;
  margin-top: clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--modal-ink);
}

/* Two across, on four half-tracks */
@media (max-width: 52rem) {
  .modal .amenities__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 34rem) {
  .modal .amenities__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .modal .amenities__grid > .amenity {
    grid-column: auto;
  }
}

/* Holds the page still behind the dialog; the gutter is reserved so nothing shifts */
body.has-modal {
  overflow: hidden;
}

/* The thank-you's entrance (see .inquiry__sent) */
@keyframes modal-in {
  from {
    opacity: 0;
    transform: translateY(0.75rem);
  }
}

/* Every dialog — the expanded review, the amenities list, the Good-to-know notes and
   the inquiry form — fades in and rises over the page while the scrim darkens and the blur
   gathers behind it, and closing plays the same thing backwards.
   Transitions rather than a keyframe entrance, because only a transition can run on close:
   display and overlay are held with allow-discrete so the dialog stays in the top layer until the
   fade is done. @starting-style gives showModal() a closed state to transition from. The open
   curve eases out; the close curve is its exact mirror, so the reverse is a true rewind. */
@media (prefers-reduced-motion: no-preference) {
  .modal,
  .modal::backdrop {
    transition:
      opacity 0.35s cubic-bezier(0.32, 0, 0.67, 0),
      backdrop-filter 0.35s cubic-bezier(0.32, 0, 0.67, 0),
      display 0.35s allow-discrete,
      overlay 0.35s allow-discrete;
  }

  .modal[open],
  .modal[open]::backdrop {
    transition-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
  }

  .modal {
    opacity: 0;
  }

  .modal::backdrop {
    opacity: 0;
    backdrop-filter: blur(0);
  }

  .modal[open] {
    opacity: 1;
  }

  .modal[open]::backdrop {
    opacity: 1;
    backdrop-filter: blur(3px);
  }

  @starting-style {
    .modal[open] {
      opacity: 0;
    }

    .modal[open]::backdrop {
      opacity: 0;
      backdrop-filter: blur(0);
    }
  }

  /* The panel rises 50px into the centre as it fades in, and sinks back as it fades out. This
     is a transition rather than a keyframe so that it can run on close. At rest it is none, not
     0 0, so an open panel is not a containing block for anything inside it. */
  .modal .modal__panel {
    translate: 0 50px;
    transition: translate 0.35s cubic-bezier(0.32, 0, 0.67, 0);
  }

  .modal[open] .modal__panel {
    translate: none;
    transition-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
  }

  @starting-style {
    .modal[open] .modal__panel {
      translate: 0 50px;
    }
  }
}

/* ---------- Inquiry form (components/shared/InquiryDialog.tsx) ----------
   The dialog shell above, carrying a form, and then — once sent — the thank-you in the same
   panel. Every colour reads the dialog's roles or the page's CTA roles, so the form follows the
   dialog with no restatement. */
.modal--inquiry {
  --inq-field: var(--review-field, #fff);
  /* Field edges hold 3:1 against both the field and the panel, as a control boundary must */
  --inq-edge: color-mix(in srgb, var(--modal-ink) 55%, transparent);
  --inq-rule: var(--review-rail, var(--color-line));
  --inq-muted: var(--review-meta, var(--color-muted));
  --inq-error: var(--review-error, #a3402b);
  --inq-accent: var(--color-cta);
  --inq-accent-ink: var(--color-cta-ink);
  --inq-range: color-mix(in srgb, var(--color-cta) 14%, transparent);
  --inq-radius: 4px;
  --inq-control: 2.875rem;
}

.modal--inquiry .modal__panel {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--modal-ink) 28%, transparent) transparent;
}

/* The home's name, centred at the head of the panel, clear of the close button either side */
.inquiry__title {
  padding-inline: 2.5rem;
  text-align: center;
  text-wrap: balance;
}

.inquiry {
  display: grid;
  gap: clamp(1.125rem, 0.95rem + 0.5vw, 1.375rem);
  margin-top: clamp(1.25rem, 1rem + 0.8vw, 1.75rem);
  font-family: var(--font-body);
  color: var(--modal-ink);
}

.inquiry__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.125rem, 0.95rem + 0.5vw, 1.375rem) 1rem;
}

.inquiry__field {
  min-width: 0;
}

.inquiry__label {
  display: block;
  margin-bottom: 0.4375rem;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0.01em;
  color: var(--modal-heading);
}

.inquiry__optional {
  font-weight: 400;
  color: var(--inq-muted);
}

.inquiry__input,
.phone {
  width: 100%;
  min-height: var(--inq-control);
  border: 1px solid var(--inq-edge);
  border-radius: var(--inq-radius);
  background: var(--inq-field);
  color: var(--modal-ink);
  transition: border-color 0.2s var(--ease-out);
}

.inquiry__input {
  display: block;
  padding: 0.6875rem 0.875rem;
  font: inherit;
  font-size: 1rem;
  line-height: 1.4;
  caret-color: var(--inq-accent);
}

.inquiry__input:hover,
.phone:hover {
  border-color: var(--modal-heading);
}

.inquiry__input:focus-visible,
.phone__number:focus-visible,
.phone__code:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: -1px;
  border-radius: var(--inq-radius);
}

/* Browser autofill paints its own yellow or blue; hold the field's colours instead */
.inquiry__input:-webkit-autofill,
.phone__number:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 100px var(--inq-field) inset;
  -webkit-text-fill-color: var(--modal-ink);
}

/* Guests: a native select dressed as the other fields, with the phone picker's chevron. The
   chevron sits in the select's right padding and lets clicks through to it. */
.inquiry__select {
  position: relative;
}

.inquiry__select select {
  appearance: none;
  padding-right: 2.5rem;
  cursor: pointer;
}

/* Until a number is chosen the prompt reads as a placeholder, not as an answer */
.inquiry__select select.is-empty {
  color: var(--inq-muted);
}

.inquiry__select option {
  color: var(--modal-ink);
}

.inquiry__chevron {
  position: absolute;
  top: 50%;
  right: 0.875rem;
  translate: 0 -50%;
  color: var(--modal-heading);
  pointer-events: none;
}

.inquiry__comments {
  min-height: 7rem;
  resize: vertical;
}

.is-invalid > .inquiry__input,
.is-invalid > .inquiry__select > .inquiry__input,
.phone.is-invalid,
.inquiry__dates.is-invalid .inquiry__date {
  border-color: var(--inq-error);
}

.inquiry__error,
.inquiry__failed {
  margin: 0.4375rem 0 0;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--inq-error);
}

.inquiry__failed {
  margin: 0;
  font-size: 0.9375rem;
}

/* Phone: the country code and the number, one field in two parts */
.phone {
  position: relative;
  display: flex;
}

.phone__code {
  display: flex;
  flex: none;
  align-items: center;
  gap: 0.375rem;
  padding: 0 0.625rem 0 0.875rem;
  border: 0;
  border-right: 1px solid var(--inq-rule);
  border-radius: var(--inq-radius) 0 0 var(--inq-radius);
  background: none;
  font: inherit;
  font-size: 1rem;
  font-variant-numeric: tabular-nums;
  color: var(--modal-ink);
  cursor: pointer;
  transition: background-color 0.2s var(--ease-out);
}

.phone__code:hover,
.phone__code[aria-expanded="true"] {
  background: color-mix(in srgb, var(--modal-hover) 55%, transparent);
}

.phone__iso {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--inq-muted);
}

.phone__chevron {
  color: var(--modal-heading);
  transition: transform 0.25s var(--ease-out);
}

.phone__code[aria-expanded="true"] .phone__chevron {
  transform: rotate(180deg);
}

.phone__number {
  flex: 1;
  min-width: 0;
  padding: 0.6875rem 0.875rem;
  border: 0;
  border-radius: 0 var(--inq-radius) var(--inq-radius) 0;
  background: none;
  font: inherit;
  font-size: 1rem;
  color: inherit;
  caret-color: var(--inq-accent);
}

.phone__menu {
  position: absolute;
  top: calc(100% + 0.375rem);
  left: -1px;
  z-index: 2;
  width: min(24rem, calc(100% + 2px));
  overflow: hidden;
  border: 1px solid var(--inq-rule);
  border-radius: 6px;
  background: var(--inq-field);
  box-shadow: 0 1.25rem 2.5rem -1.25rem rgb(20 16 12 / 0.4);
}

@media (prefers-reduced-motion: no-preference) {
  .phone__menu {
    animation: inquiry-drop 0.22s var(--ease-out) both;
  }
}

@keyframes inquiry-drop {
  from {
    opacity: 0;
    transform: translateY(-0.375rem);
  }
}

.phone__search {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0 0.875rem;
  border-bottom: 1px solid var(--inq-rule);
  color: var(--inq-muted);
}

.phone__search:focus-within {
  box-shadow: inset 0 -2px 0 var(--color-focus);
}

.phone__search input {
  flex: 1;
  min-width: 0;
  min-height: 2.875rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 1rem;
  color: var(--modal-ink);
  caret-color: var(--inq-accent);
  outline: none;
}

.phone__list {
  max-height: 15.5rem;
  padding-block: 0.3125rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--modal-ink) 28%, transparent) transparent;
}

.phone__option {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5625rem 0.875rem;
  font-size: 0.9375rem;
  line-height: 1.35;
  cursor: pointer;
}

.phone__option.is-active {
  background: var(--modal-hover);
}

.phone__option[aria-selected="true"] {
  font-weight: 500;
  color: var(--modal-heading);
}

.phone__option-dial {
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--inq-muted);
}

.phone__empty {
  margin: 0;
  padding: 0.875rem;
  font-size: 0.9375rem;
  color: var(--inq-muted);
}

/* Dates: what is chosen, then the calendar it is chosen on */
.inquiry__dates {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.inquiry__stay {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

/* A read-out, not an input: it takes the field's outline on the panel's own ground */
.inquiry__date {
  display: flex;
  align-items: center;
  min-height: var(--inq-control);
  padding: 0.6875rem 0.875rem;
  border: 1px solid var(--inq-rule);
  border-radius: var(--inq-radius);
  font-size: 1rem;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
  color: var(--modal-ink);
  transition:
    border-color 0.25s var(--ease-out),
    box-shadow 0.25s var(--ease-out);
}

/* The one the next press on the calendar will set */
.inquiry__when.is-next .inquiry__date {
  border-color: var(--inq-accent);
  box-shadow: inset 0 0 0 1px var(--inq-accent);
}

.calendar {
  position: relative;
  margin-top: clamp(1rem, 0.85rem + 0.5vw, 1.375rem);
  padding: clamp(0.875rem, 0.6rem + 0.8vw, 1.25rem);
  border: 1px solid var(--inq-rule);
  border-radius: 6px;
}

/* The arrows sit either side of the month names, level with them */
.calendar__nav {
  position: absolute;
  top: clamp(0.875rem, 0.6rem + 0.8vw, 1.25rem);
  inset-inline: clamp(0.5rem, 0.3rem + 0.6vw, 0.875rem);
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}

.calendar__step {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--modal-heading);
  cursor: pointer;
  pointer-events: auto;
  transition: background-color 0.25s var(--ease-out);
}

.calendar__step:hover:not(:disabled) {
  background: var(--modal-hover);
}

.calendar__step:disabled {
  opacity: 0.3;
  cursor: default;
}

.calendar__months {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
}

.calendar[data-months="2"] .calendar__months {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.calendar__title {
  margin: 0 0 0.375rem;
  font-family: var(--font-display);
  font-size: 1.3125rem;
  font-weight: var(--display-weight, 400);
  line-height: 2.25rem;
  letter-spacing: var(--display-tracking, -0.01em);
  text-align: center;
  color: var(--modal-heading);
}

.calendar__grid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.calendar__grid th {
  padding: 0 0 0.375rem;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-align: center;
  color: var(--inq-muted);
}

.calendar__grid td {
  padding: 1px 0;
}

/* The stay runs as one band under the days it covers, half-cells at each end */
.calendar__grid td.is-between {
  background: var(--inq-range);
}

.calendar__grid td.is-start {
  background: linear-gradient(90deg, transparent 50%, var(--inq-range) 50%);
}

.calendar__grid td.is-end {
  background: linear-gradient(270deg, transparent 50%, var(--inq-range) 50%);
}

/* Before check-out is chosen, the band follows the pointer at half strength */
.calendar__grid td.is-preview {
  --inq-range: color-mix(in srgb, var(--color-cta) 7%, transparent);
}

.calendar__day {
  display: grid;
  place-items: center;
  width: 100%;
  height: 2.625rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  font: inherit;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  color: var(--modal-ink);
  cursor: pointer;
  transition:
    background-color 0.2s var(--ease-out),
    color 0.2s var(--ease-out),
    box-shadow 0.2s var(--ease-out);
}

.calendar__day:hover:not(:disabled, .is-picked) {
  box-shadow: inset 0 0 0 1px var(--modal-heading);
}

.calendar__day:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 1px;
  border-radius: 999px;
}

.calendar__day:disabled {
  color: color-mix(in srgb, var(--modal-ink) 32%, transparent);
  cursor: default;
}

.calendar__day.is-today {
  font-weight: 600;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}

.calendar__day.is-picked {
  background: var(--inq-accent);
  font-weight: 600;
  color: var(--inq-accent-ink);
}

/* The day the pointer would make check-out, drawn but not yet filled */
.is-preview.is-end .calendar__day {
  box-shadow: inset 0 0 0 1px var(--inq-accent);
}

.inquiry__nights {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  margin-top: 0.75rem;
  font-size: 0.9375rem;
  color: var(--inq-muted);
}

.inquiry__nights p {
  margin: 0;
}

.inquiry__clear {
  padding: 0.25rem 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 500;
  color: var(--modal-heading);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--modal-heading) 40%, transparent);
  text-underline-offset: 0.25em;
  cursor: pointer;
}

.inquiry__clear:hover {
  text-decoration-color: currentColor;
}

.inquiry__submit {
  width: 100%;
  min-height: 3.25rem;
  margin-top: 0.25rem;
  font-size: 0.8125rem;
  cursor: pointer;
  border: 0;
}

.inquiry__submit[aria-disabled="true"] {
  opacity: 0.72;
  cursor: progress;
  transform: none;
}

/* Sent: the thank-you holds the form's height, centred in it */
.modal--inquiry.is-sent .modal__panel {
  display: flex;
  flex-direction: column;
  min-height: min(var(--inquiry-hold, 0px), 85vh);
}

.modal--inquiry.is-sent .modal__body {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.inquiry__sent {
  display: grid;
  flex: 1;
  align-content: center;
  justify-items: center;
  gap: 1rem;
  max-width: 30rem;
  margin-inline: auto;
  padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem);
  text-align: center;
}

.inquiry__tick {
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: 0.5rem;
  color: var(--inq-accent);
}

.inquiry__thanks {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--display-weight, 400);
  line-height: 1.1;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--modal-heading);
  outline: none;
}

.inquiry__received {
  margin: 0;
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--modal-ink);
  text-wrap: pretty;
}

/* The booking terms under the send button, quiet, in a new tab */
.inquiry__terms {
  margin: 0;
  font-size: var(--text-small);
  line-height: 1.5;
  text-align: center;
}

.inquiry__terms-link {
  color: var(--modal-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  transition: text-decoration-color 0.3s var(--ease-out);
}

.inquiry__terms-link:hover {
  text-decoration-color: currentColor;
}

/* A footnote to the thank-you: the tourist tax is not in the price */
.inquiry__note {
  margin: 0;
  font-size: var(--text-small);
  line-height: 1.5;
  color: var(--inq-muted);
}

@media (prefers-reduced-motion: no-preference) {
  .inquiry__sent {
    animation: modal-in 0.45s var(--ease-out) both;
  }

  /* The tick draws itself once, the one moment the form allows itself */
  .inquiry__tick circle,
  .inquiry__tick path {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: inquiry-draw 0.7s var(--ease-out) forwards;
  }

  .inquiry__tick path {
    animation-delay: 0.35s;
  }
}

@keyframes inquiry-draw {
  to {
    stroke-dashoffset: 0;
  }
}

/* A phone gets the whole height for the form, and the pairs stack */
@media (max-width: 40rem) {
  .modal--inquiry {
    padding: 0.5rem;
  }

  .modal--inquiry .modal__panel {
    max-height: calc(100dvh - 1rem);
  }

  .modal--inquiry.is-sent .modal__panel {
    min-height: min(var(--inquiry-hold, 0px), calc(100dvh - 1rem));
  }
}

@media (max-width: 30rem) {
  .inquiry__pair {
    grid-template-columns: minmax(0, 1fr);
  }

  .inquiry__stay {
    gap: 0.625rem;
  }

  .calendar {
    padding-inline: 0.5rem;
  }
}

/* ---------- How to stay with us (below the guest reviews) ---------- */
/* On the page ground, in the site's own colours. The numerals are the ink faded back towards
   the ground, decoration rather than text. */
.how {
  --how-bg: var(--color-ground);
  --how-ink: var(--color-ink);
  --how-body: var(--color-ink-soft);
  --how-muted: var(--color-muted);
  --how-number: color-mix(in srgb, var(--color-ink) 22%, var(--color-ground));
  /* Named so a theme can place decoration against the numerals and the gutters between steps */
  --how-number-size: clamp(4rem, 2rem + 4.2vw, 7.375rem);
  --how-col-gap: clamp(2.5rem, -1rem + 12.4vw, 11.5625rem);
  --color-focus: var(--how-ink);
  padding-block: clamp(3rem, 2.2rem + 2.9vw, 6rem) clamp(3rem, 2.2rem + 2.6vw, 5.5rem);
  background: var(--how-bg);
  color: var(--how-body);
}

.how__inner {
  width: min(88.75rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
}

.how__intro {
  text-align: center;
}

.how__title {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.05;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--how-ink);
  text-wrap: balance;
}

.how__lead {
  max-width: 48.75rem;
  margin: clamp(0.875rem, 0.7rem + 0.6vw, 1.5rem) auto 0;
  font-size: var(--text-body);
  line-height: 1.5;
  text-wrap: balance;
}

.how__steps {
  /* The visible 01/02/03 carry the sequence, so the markers and their indent go */
  margin: clamp(2rem, 1.4rem + 2vw, 3.5rem) 0 0;
  padding: 0;
  list-style: none;
  /* Three equal columns on one top line, equal gaps between them, the row centred on the page:
     each column is as wide as its step, so no step leaves empty space on one side of the row */
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 21.875rem));
  justify-content: center;
  align-items: start;
  column-gap: var(--how-col-gap);
}

.how-step__number {
  font-family: var(--font-display);
  font-size: var(--how-number-size);
  font-weight: 300;
  font-style: normal;
  line-height: 0.9;
  /* Cormorant defaults to old-style figures; the comp's numerals are full height */
  font-variant-numeric: lining-nums;
  letter-spacing: 0.01em;
  color: var(--how-number);
}

.how-step__number::before {
  content: attr(data-number);
}

.how-step__title {
  margin-top: clamp(0.5rem, 0.3rem + 0.6vw, 1rem);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.1;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--how-ink);
}

.how-step__text {
  margin-top: clamp(0.5rem, 0.35rem + 0.5vw, 0.875rem);
  font-size: var(--text-body);
  line-height: 1.5;
}

/* The saving, "10%", inside its sentence: two pixels larger than the words round it and bold,
   in step 03 and in the footer's offer (Danylo, 5 November 2026; until then step 03 set it large
   in the display face on a line of its own). Its line keeps the paragraph's spacing. */
.saving {
  font-size: calc(1em + 0.125rem);
  font-weight: 600;
  line-height: 1;
}

/* The note belongs to the WhatsApp button, so it rides in that button's column */
.how__actions {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(0.75rem, 0.6rem + 0.4vw, 1.25rem);
  margin-top: clamp(1.75rem, 1.1rem + 1.6vw, 3.25rem);
}

/* The note is taken out of the flow and its height reserved below: it runs wider than
   the button it belongs to, and in flow that extra width pushes the pair off centre. */
.how__action {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-bottom: 2rem;
}

.how__note {
  position: absolute;
  bottom: 0;
  left: 50%;
  translate: -50% 0;
  width: max-content;
  max-width: 100vw;
  font-size: var(--text-small);
  line-height: 1.4;
  color: var(--how-muted);
  text-align: center;
}

/* The drawn button is filled with the section's own ground, so it still reads as empty. A
   see-through button's layer has nothing solid under its label, and the browser smooths text
   differently there while the hover moves it: the label flickers against the frame. On a
   solid layer it is drawn the way the filled buttons' labels are, as one piece with the box. */
.how .btn--secondary {
  background: var(--how-bg);
}

/* ---------- Three columns give out: one clean sequence instead of miniature columns ---------- */
@media (max-width: 64rem) {
  .how__steps {
    grid-template-columns: minmax(0, 30rem);
    justify-content: center;
    row-gap: clamp(2rem, 1.4rem + 2vw, 3rem);
  }
}

/* A narrow screen keeps the pair side by side, as a wide one does (Danylo, 5 November 2026; it
   stacked them at 85% of the width from 20 October): two equal columns across the page, the note
   back in the flow under its own button. The buttons share the first row (the note's column is a
   subgrid of the pair's two rows), so a label that runs to two lines makes both buttons that
   tall. The same pair closes About, For owners and Contact (their page sheets). */
@media (max-width: 52rem) {
  .how__actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto auto;
    column-gap: var(--pair-gap);
    /* The note's distance from its button is its own margin, the one every pair's line under a
       button keeps on a narrow screen (Contact's, Danylo, 5 November 2026) */
    row-gap: 0;
    width: min(100%, 30rem);
    margin-inline: auto;
  }

  .how__actions > .btn {
    grid-row: 1;
  }

  .how__action {
    position: static;
    display: grid;
    grid-row: 1 / span 2;
    grid-template-rows: subgrid;
    align-items: stretch;
    padding-bottom: 0;
  }

  .how__note {
    position: static;
    width: auto;
    max-width: none;
    margin-top: 0.5rem;
    translate: none;
    font-size: var(--pair-note);
  }

  /* A 44px touch target; a long label wraps inside its button rather than out of it */
  .how__actions .btn {
    width: 100%;
    min-width: 0;
    min-height: 2.75rem;
    padding-inline: var(--pair-pad);
    white-space: normal;
    text-wrap: balance;
    line-height: 1.3;
  }
}

/* ---------- See where you could stay (between the activities carousel and the guest reviews) ---------- */
/* In the site's own colours, on the page ground.
   An unlabelled photo gallery on purpose — no names, captions or facts. /stays/ carries those. */
.homes {
  /* No colour change at the seam: the section carries on the ground of the one above it */
  --homes-bg: var(--color-ground);
  --homes-ink: var(--color-ink);
  --homes-body: var(--color-ink-soft);
  --homes-meta: var(--color-muted);
  /* The arrows and dots are the shared carousel controls, in this section's ink */
  --control-ink: var(--homes-ink);
  /* The comp's 828 : 63 : 592 column rhythm, held as one gap token so the halves stay in step */
  --homes-gap: clamp(1.25rem, 0.3rem + 3.5vw, 3.5rem);
  --homes-thumb-gap: clamp(0.625rem, 0.3rem + 1.6vw, 1.5625rem);
  --color-focus: var(--homes-ink);
  /* Read by components/home/HomesGallery.tsx: how long a photograph takes to fly between the
     collage and the frame, and to slide from one place in the collage to the next (the owner's
     picks, tuned in dev-tools/motion-lab) */
  --homes-glide: 900ms;
  --homes-step: 590ms;
  /* The phone's plain row (HomesStrip.tsx): one photograph's glide, as long as the reviews' */
  --homes-strip-glide: 900ms;
  padding-block: clamp(1.5rem, 1.1rem + 1.2vw, 2.5rem) clamp(1.5rem, 1.1rem + 1.6vw, 3rem);
  background: var(--homes-bg);
  color: var(--homes-body);
}

/* Introduction, collage and controls read down the left; the photograph they feed sits
   on the right and spans both rows, so the section keeps one top edge */
.homes__inner {
  position: relative;
  width: min(74rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 592fr) minmax(0, 828fr);
  column-gap: var(--homes-gap);
  align-items: start;
}

.homes__intro {
  grid-column: 1;
  grid-row: 1;
}

.homes__stage {
  grid-column: 2;
  grid-row: 1 / span 2;
}

.homes__gallery {
  grid-column: 1;
  grid-row: 2;
  /* Drops the collage to the comp's height, which lands the arrow row beside the rule
     under the photograph rather than above it */
  margin-top: clamp(1.75rem, 1rem + 3.2vw, 4.25rem);
}

/* ---------- Left: the active photograph ---------- */
/* Slides share one cell, so the frame never resizes between photographs. The zero
   minimums keep a portrait photograph from stretching the frame past its ratio. */
.homes__frame {
  display: grid;
  aspect-ratio: 828 / 790;
  min-height: 0;
  margin: 0;
  overflow: hidden;
}

.homes__slide {
  grid-area: 1 / 1;
  min-width: 0;
  min-height: 0;
}

.homes__photo {
  width: 100%;
  height: 100%;
  border-radius: 2px;
  object-fit: cover;
  /* Every photograph in the supplied set reads correctly on a centred crop */
  object-position: center;
}

/* The counter alone under the photograph, on the outer edge of the composition so it
   sits with the photograph rather than drifting towards the collage */
.homes__counter {
  margin-top: clamp(0.875rem, 0.6rem + 0.9vw, 1.375rem);
  text-align: right;
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0.06em;
  color: var(--homes-meta);
}

/* ---------- Right: introduction, collage, controls ---------- */
.homes__title {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--display-weight, 400);
  font-style: normal;
  line-height: 1.05;
  letter-spacing: var(--display-tracking, -0.01em);
  color: var(--homes-ink);
}

/* Two lines, broken where the comp breaks them rather than wherever the column ends */
.homes__title span {
  display: block;
}

.homes__lead {
  margin-top: clamp(0.625rem, 0.4rem + 0.7vw, 1.125rem);
  font-size: var(--text-body);
  color: var(--homes-body);
}

.homes__thumbs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--homes-thumb-gap);
}

/* The thumbnails are listed in the conveyor's order, newest first, and placed round the square so
   every step along it is straight across or straight up or down: in at the bottom left, up, across
   the top, down to the bottom right, and from there into the frame */
.homes__thumbs > :nth-child(1) {
  grid-area: 2 / 1;
}

.homes__thumbs > :nth-child(2) {
  grid-area: 1 / 1;
}

.homes__thumbs > :nth-child(3) {
  grid-area: 1 / 2;
}

.homes__thumbs > :nth-child(4) {
  grid-area: 2 / 2;
}

.homes__thumb {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: none;
  cursor: pointer;
}

.homes__thumb img {
  width: 100%;
  height: auto;
  aspect-ratio: 283 / 219;
  border-radius: 2px;
  object-fit: cover;
  transition: opacity 0.3s var(--ease-out);
}

.homes__thumb:hover img {
  opacity: 0.86;
}

.homes__controls {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  margin-top: clamp(1.25rem, 0.8rem + 1.6vw, 2.5rem);
}

/* The shared .carousel-arrow and .carousel-dots, placed: arrows out at the ends, one dot per
   photograph centred between them */
.homes__button--prev {
  justify-self: start;
}

.homes__button--next {
  justify-self: end;
}

/* Enhanced once hydrated (components/home/HomesGallery.tsx): until then the stage, the collage
   and the controls stay hidden */
.homes:not(.is-ready) .homes__stage,
.homes:not(.is-ready) .homes__thumbs,
.homes:not(.is-ready) .homes__controls {
  display: none;
}

/* The frame swaps outright: the change always happens beneath a flying copy (HomesGallery.tsx) */
.homes.is-ready .homes__slide {
  visibility: hidden;
}

.homes.is-ready .homes__slide.is-active {
  visibility: visible;
}

/* The copies in flight (HomesGallery.tsx), over the whole section and never in the way of a click.
   The script moves and sizes each one; cover keeps the photograph unstretched at every size between
   the thumbnail's shape and the frame's. */
.homes__flights {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.homes__flight {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;
  border-radius: 2px;
  object-fit: cover;
}

/* ---------- The collage runs out of room before the photograph does ---------- */
/* Two columns hold while a thumbnail is still worth looking at; below that the section
   becomes one sequence, which also gives the photograph the full width */
@media (max-width: 60rem) {
  .homes__inner {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Heading first, then the photograph, its counter, the collage and the controls */
  .homes__intro,
  .homes__stage,
  .homes__gallery {
    grid-column: 1;
    grid-row: auto;
  }

  .homes__stage {
    margin-top: clamp(1.25rem, 0.9rem + 1.6vw, 2rem);
  }

  /* One column: the counter goes back under the start of the photograph */
  .homes__counter {
    text-align: left;
  }

  .homes__frame {
    aspect-ratio: 4 / 3;
  }

  .homes__gallery {
    margin-top: clamp(1.5rem, 1.1rem + 1.8vw, 2.25rem);
  }

  /* Stacked, the collage has the whole width: one row of four rather than a deep grid, and the
     conveyor simply runs along it, left to right */
  .homes__thumbs {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .homes__thumbs > :nth-child(n) {
    grid-area: auto;
  }
}

/* Four across would leave stamps; two keeps the photographs readable on a phone. The square route
   returns with them, turned so it ends at the top left: the frame is above the collage here, and a
   photograph leaving for it goes straight up, so every place it passes must already be empty. In
   at the bottom left, across, up, across the top, and up into the frame. */
@media (max-width: 34rem) {
  .homes__thumbs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .homes__thumbs > :nth-child(1) {
    grid-area: 2 / 1;
  }

  .homes__thumbs > :nth-child(2) {
    grid-area: 2 / 2;
  }

  .homes__thumbs > :nth-child(3) {
    grid-area: 1 / 2;
  }

  .homes__thumbs > :nth-child(4) {
    grid-area: 1 / 1;
  }
}

/* ---------- Where you can also find us (components/shared/FindUs.tsx) ----------
   Instagram and Facebook as two cards side by side, each its icon over its name (the owner's
   reference, 5 November 2026): white cards on the cream with a hairline edge, the icon in the
   buttons' green. On hover a card lifts a little, as the buttons do, and its edge firms up. The
   heading's look and the space around it belong to each page (contact.css, property.css). */
.find-us {
  text-align: center;
}

.find-us__list {
  display: flex;
  justify-content: center;
  gap: clamp(0.75rem, 0.5rem + 0.8vw, 1.25rem);
  margin-top: var(--space-m);
}

.find-us__card {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 0.85rem;
  width: clamp(9.25rem, 7.5rem + 4.4vw, 12.5rem);
  aspect-ratio: 5 / 4;
  background: var(--color-section);
  border: 1px solid var(--color-line);
  border-radius: 8px;
  color: var(--color-ink);
  text-decoration: none;
  transition:
    transform 0.3s var(--ease-out),
    box-shadow 0.3s var(--ease-out),
    border-color 0.3s var(--ease-out);
}

.find-us__card:hover {
  transform: translateY(-3px);
  border-color: rgb(41 60 53 / 0.3);
  box-shadow: 0 0.5rem 1.5rem rgb(41 60 53 / 0.1);
}

.find-us__icon {
  width: clamp(2.25rem, 2rem + 0.8vw, 2.75rem);
  height: clamp(2.25rem, 2rem + 0.8vw, 2.75rem);
  color: var(--color-cta);
}

.find-us__name {
  font-size: var(--text-body);
  font-weight: 500;
  line-height: 1.2;
}

@media (prefers-reduced-motion: reduce) {
  .find-us__card:hover {
    transform: none;
  }
}

/* Smaller on a phone, where the two read as big tiles at the desktop's size (the owner's
   direction, 5 November 2026) */
@media (max-width: 40rem) {
  .find-us__list {
    gap: 0.625rem;
  }

  .find-us__card {
    gap: 0.5rem;
    width: 7.5rem;
    aspect-ratio: 4 / 3;
  }

  .find-us__icon {
    width: 1.875rem;
    height: 1.875rem;
  }

  .find-us__name {
    font-size: var(--text-small);
  }
}

/* ---------- Footer (components/site/SiteFooter.tsx) ----------
   From the owner's wireframe and notes of 6 October 2026. Small and orderly: the name centred
   over a short sitemap, the offer and the numbers on the right, and the legal lines quietest of
   all at the bottom.

   It stands on the page ground like every section above it, so the whole bottom of the page
   reads as one field and the hairline is the only edge. */
.site-footer {
  --footer-bg: var(--color-ground);
  --footer-ink: var(--color-ink);
  --footer-body: var(--color-ink-soft);
  --footer-muted: var(--color-muted);
  --footer-line: var(--color-line);
  /* The top 10% under its first value (8 November 2026), so the logo sits closer to the hairline */
  padding-block: clamp(2.7rem, 1.98rem + 2.34vw, 4.5rem) clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  background: var(--footer-bg);
  color: var(--footer-body);
  border-top: 1px solid var(--footer-line);
  font-size: clamp(0.875rem, 0.85rem + 0.1vw, 0.9375rem);
  line-height: 1.4;
}

.site-footer__inner {
  width: min(88.75rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
}

/* The old round logo over the name (8 November 2026): centred, with its own room above the name */
.site-footer__logo {
  display: block;
  width: 4.05rem;
  height: auto;
  margin: 0 auto clamp(1.35rem, 1.08rem + 0.9vw, 2.025rem);
}

.site-footer__mark {
  font-family: var(--font-wordmark);
  font-size: clamp(1.75rem, 1.35rem + 1.3vw, 2.625rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.005em;
  color: var(--footer-ink);
  text-align: center;
  margin-bottom: clamp(2.5rem, 1.8rem + 2.4vw, 4.5rem);
}

/* Every text link here; the button keeps its own colours. Each answers a hover the way the
   header's links do: a hairline draws in under it from the left.
   The line is the link's own background, grown from nothing to its full width, rather than a
   scaled pseudo-element: a scaled line is drawn on a layer of its own while it moves and back
   on the page when it stops, and the two land on different pixels, so the line visibly
   thickened the moment it finished. Painted as a background it is drawn one way throughout. */
.site-footer a:not(.btn) {
  display: inline-block;
  /* A grid item stretches to its column; the line belongs to the words, so the link hugs them */
  width: fit-content;
  /* The line sits inside the link's own box, so the pointer never crosses a gap between the
     words and the line. The negative margin hands the room back, so nothing below moves. */
  padding-bottom: 0.2em;
  margin-bottom: -0.2em;
  background: linear-gradient(currentColor, currentColor) left bottom / 0 1px no-repeat;
  color: inherit;
  text-decoration: none;
  transition: background-size 0.4s var(--ease-out);
}

.site-footer a:not(.btn):hover,
.site-footer a:not(.btn):focus-visible {
  background-size: 100% 1px;
}

/* The sitemap on the left; on the right the offer level with its headings and the numbers
   level with its last home */
.site-footer__main {
  display: grid;
  /* The sitemap keeps its width; the offer takes what is left, up to its own measure */
  grid-template-columns: max-content minmax(0, auto);
  justify-content: space-between;
  gap: var(--space-l);
}

/* Home, About and Contact stacked in the first column, the homes in the second, For owners alone
   in the third, set apart at the same gap. The fourth row takes the homes' extra height, so the
   three links stay together on top. */
.site-footer__sitemap {
  display: grid;
  grid-template-columns: repeat(3, max-content);
  grid-template-rows: repeat(3, auto) 1fr;
  align-items: start;
  column-gap: clamp(2.5rem, 0.8rem + 4.6vw, 6.5rem);
  row-gap: 1rem;
}

.site-footer__group {
  grid-column: 1;
}

.site-footer__group--stays {
  grid-column: 2;
  grid-row: 1 / span 4;
}

.site-footer__group--owners {
  grid-column: 3;
  grid-row: 1;
}

/* A phone has no room for a third column: Collaborations goes back under Contact. On the
   narrowest screens the first column gives way, so a longer link wraps rather than pushing the
   homes off the edge. */
@media (max-width: 40rem) {
  .site-footer__sitemap {
    grid-template-columns: minmax(0, max-content) max-content;
    grid-template-rows: repeat(4, auto) 1fr;
  }

  .site-footer__group--stays {
    grid-row: 1 / span 5;
  }

  .site-footer__group--owners {
    grid-column: 1;
    grid-row: 4;
  }
}

.site-footer__head {
  font-size: clamp(0.9375rem, 0.9rem + 0.15vw, 1.0625rem);
  font-weight: 500;
  color: var(--footer-ink);
}

.site-footer__homes {
  display: grid;
  gap: 0.8125rem;
  margin-top: 1rem;
}

.site-footer__homes li {
  display: grid;
  gap: 0.125rem;
}

.site-footer__home {
  color: var(--footer-body);
}

.site-footer__cin {
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--footer-muted);
}

.site-footer__aside {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-l);
}

.site-footer__offer {
  display: grid;
  justify-items: end;
  gap: var(--space-s);
}

.site-footer__offer-text {
  /* Two lines in both languages, not three (Danylo, 5 November 2026; it was 42ch), where the
     sitemap leaves the room */
  max-width: 60ch;
  font-size: clamp(0.9375rem, 0.9rem + 0.15vw, 1.0625rem);
  line-height: 1.45;
  color: var(--footer-ink);
  text-align: right;
  text-wrap: balance;
}

/* Label beside value, each label set flush against the number or address it names */
.site-footer__contact {
  display: grid;
  grid-template-columns: auto auto;
  column-gap: 1.25rem;
  row-gap: 0.75rem;
  align-items: baseline;
}

.site-footer__contact li {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: baseline;
}

.site-footer__label {
  justify-self: end;
  font-size: 0.8125rem;
  color: var(--footer-muted);
}

/* Each value ends at the footer's right edge, under the icons and the button (Danylo, 6 November
   2026): the number is shorter than the email, so it moves over rather than hanging off the labels */
.site-footer__value {
  justify-self: end;
  font-size: clamp(0.9375rem, 0.9rem + 0.15vw, 1.0625rem);
  color: var(--footer-ink);
  font-variant-numeric: tabular-nums;
}

/* Our Instagram and Facebook, two icons and no words (5 November 2026): between the offer and the
   numbers, flush right with both, in the footer's green. Each icon stands in a 44px target; the
   negative margin hands the target's spare room back, so the drawn edge lines up with the text.
   A phone shows the copy under the name instead (below). */
.site-footer__social {
  display: flex;
  gap: 0.25rem;
  margin-inline: -0.5625rem;
}

.site-footer__social--top {
  display: none;
}

.site-footer a.site-footer__social-link {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  margin: 0;
  background: none;
  border-radius: 50%;
  color: var(--footer-ink);
  transition:
    color 0.3s var(--ease-out),
    transform 0.3s var(--ease-out);
}

.site-footer a.site-footer__social-link:hover {
  color: var(--color-cta-hover);
  transform: translateY(-2px);
}

.site-footer__social-icon {
  width: 1.625rem;
  height: 1.625rem;
}

.social-icon__light {
  fill: var(--color-accent);
}

@media (prefers-reduced-motion: reduce) {
  .site-footer a.site-footer__social-link:hover {
    transform: none;
  }
}

/* The fine print: address, copyright and rights on the left, policies on the right, on the
   address's line (Danylo, 6 November 2026; they stood on the last line, the rights', before) */
.site-footer__base {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-s) var(--space-l);
  margin-top: clamp(3rem, 2rem + 3vw, 5.5rem);
  font-size: clamp(0.75rem, 0.72rem + 0.12vw, 0.8125rem);
  line-height: 1.5;
  color: var(--footer-muted);
}

.site-footer__legal {
  display: grid;
  gap: 0.25rem;
  min-width: 0;
}

.site-footer__legal p:first-child {
  margin-bottom: 0.5rem;
}

.site-footer__policies {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  column-gap: clamp(1rem, 0.6rem + 1.2vw, 2rem);
  row-gap: 0.375rem;
}

/* Below this the right-hand side stops fitting beside the sitemap: everything stacks on the
   left edge */
@media (max-width: 68rem) {
  .site-footer__main {
    grid-template-columns: 1fr;
  }

  .site-footer__aside,
  .site-footer__offer {
    align-items: flex-start;
    justify-items: start;
  }

  .site-footer__offer-text {
    text-align: left;
  }

  .site-footer__label,
  .site-footer__value {
    justify-self: start;
  }

  .site-footer__base {
    flex-direction: column;
    align-items: flex-start;
  }

  .site-footer__policies {
    justify-content: flex-start;
  }
}

@media (max-width: 40rem) {
  /* Two columns shared by the sitemap and the two ways in (the owner's direction, 5 November
     2026): the first as wide as its widest line, which is "International WhatsApp", so the homes
     start exactly where that label ends, in either language; the second takes the rest. Every
     box between the footer's main grid and the lines is a subgrid of its columns. Each label sits
     on one line at the left and its value at the right edge (20 October 2026). */
  .site-footer__main {
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: 0;
  }

  .site-footer__nav,
  .site-footer__aside,
  .site-footer__sitemap,
  .site-footer__contact {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    column-gap: 0;
  }

  .site-footer__aside {
    align-items: start;
  }

  /* Home, About, Contact and Collaborations keep a little room before the homes, should one of
     them ever run wider than the label */
  .site-footer__group:not(.site-footer__group--stays) {
    padding-inline-end: var(--space-s);
  }

  .site-footer__contact li {
    grid-template-columns: subgrid;
    align-items: baseline;
  }

  /* A step smaller than before, so the address fits beside its label on a 360px phone (the
     owner's direction, 5 November 2026: the email read too large) */
  .site-footer__label {
    grid-column: 1;
    font-size: 0.78125rem;
    white-space: nowrap;
  }

  .site-footer__value {
    grid-column: 2;
    justify-self: end;
    font-size: 0.8125rem;
  }

  /* A small footer on a phone (Danylo, 5 November 2026): the offer and its button go, the
     sitemap and the two ways in stay */
  .site-footer__offer {
    display: none;
  }

  /* The two icons open the footer, centred under the name, and everything else moves down by
     their row (the owner's direction, 5 November 2026) */
  .site-footer__logo {
    width: 3.15rem;
    margin-bottom: 1.125rem;
  }

  .site-footer__mark {
    margin-bottom: var(--space-xs);
  }

  .site-footer__social--top {
    display: flex;
    justify-content: center;
    margin: 0 0 clamp(2rem, 1.6rem + 1.6vw, 2.5rem);
  }

  .site-footer__social--aside {
    display: none;
  }

  /* The fine print (the owner's direction, 5 November 2026): the name on a line of its own and the
     street under it, at the left; then the two policies side by side, centred and set as heavy as
     the sitemap's links; then, after a little space, the copyright and the rights centred. The
     legal block gives up its box so the policies can stand among its lines. */
  .site-footer__base {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.25rem;
    margin-top: var(--space-l);
  }

  .site-footer__legal {
    display: contents;
  }

  .site-footer__address-name,
  .site-footer__address-street {
    display: block;
  }

  .site-footer__address-comma {
    display: none;
  }

  /* Two columns, whatever the language: where the pair cannot share a line (the Italian), each
     name breaks onto two lines in its own column rather than one dropping under the other */
  .site-footer__policies {
    order: 1;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, max-content));
    justify-content: center;
    align-items: start;
    column-gap: var(--space-l);
    margin-top: var(--space-m);
    text-align: center;
    text-wrap: balance;
  }

  .site-footer a.site-footer__policy {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--footer-ink);
  }

  .site-footer__legal p:not(:first-child) {
    order: 2;
    text-align: center;
  }

  .site-footer__legal p:nth-child(2) {
    margin-top: var(--space-l);
  }
}

/* The narrowest phones, where a row cannot hold both: the value drops under its label, still at
   the right edge (20 October 2026). The label then spans the row too, so it no longer sets the
   first column's width and the homes keep room for their CIN codes on one line. */
@media (max-width: 21.5rem) {
  .site-footer__label,
  .site-footer__value {
    grid-column: 1 / -1;
  }
}

/* ---------- The gap before it ----------
   The breathing room belongs to the section above, not to the footer: that keeps the
   footer thin and the ground unbroken all the way down to the hairline.

   Three shapes reach the footer, and until now only the first of them opened a gap at all —
   a section that is the footer's own sibling (both homepages), a <main> that is (the two
   Stays indexes), and a <main> whose last section is (Beach House, where .how is inside
   <main> and the adjacency silently failed). All three pay the same token. */
.how:has(+ .site-footer),
.stays:has(+ .site-footer),
.property main:has(+ .site-footer) > :last-child {
  padding-bottom: var(--space-prefooter);
}

/* The homepage on a phone: a quarter more room between the third step and the
   buttons (the owner's direction, 20 October 2026). The homepage's section stands straight in the
   body; a home's page holds its own inside <main>. */
@media (max-width: 40rem) {
  body > .how .how__actions {
    margin-top: calc(clamp(1.75rem, 1.1rem + 1.6vw, 3.25rem) * 1.25);
  }
}

/* ---------- Two buttons, one width ----------
   Wherever a page closes on a pair of buttons, the two are one width, the wider one's, so the
   pair stands even about its middle in either language (the owner's direction, 15 October 2026):
   How to stay with us here; the About page's close, the contact page's two ways in and For owners'
   in their own page sheets.
   The row is as wide as its content and centred; equal grid columns size both to the larger.
   Where the pairs stack on a phone, their own rules apply. */
@media not all and (max-width: 52rem) {
  .how__actions {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    width: fit-content;
    margin-inline: auto;
  }

  .how__actions .btn {
    width: 100%;
  }
}


/* ---------- See where you could stay, on a phone ---------- */
/* The heading and its line centred, and the heading on one line where the phone is wide enough
   (Danylo, 5 November 2026). Each half holds together (HomesGallery.tsx), so a narrower phone, or
   the longer Italian, still breaks it only where the two lines meet. */
@media (max-width: 40rem) {
  .homes__intro {
    text-align: center;
  }

  .homes__title span {
    display: inline;
  }
}


/* The owner's direction, 20 October 2026: the frame, collage and flying photographs give way to a
   plain row moved like the guest reviews (HomesStrip.tsx). One photograph and a sliver of the next,
   and under them the dots centred between the two arrows. */
.homes-strip {
  display: none;
}

@media (max-width: 40rem) {
  .homes__stage,
  .homes__gallery {
    display: none;
  }

  .homes-strip {
    display: block;
    margin-top: clamp(1.25rem, 0.9rem + 1.6vw, 2rem);
  }
}

.homes-strip__track {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.homes-strip__track::-webkit-scrollbar {
  display: none;
}

.homes-strip__slide {
  flex: 0 0 88%;
  scroll-snap-align: start;
}

.homes-strip__slide img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  border-radius: 2px;
  object-fit: cover;
  background: var(--color-media);
}

.homes-strip__controls {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-s);
  margin-top: clamp(1.25rem, 0.8rem + 1.6vw, 2.5rem);
}

/* Until the script is live the row is a plain scroller a finger can still swipe */
.homes:not(.is-ready) .homes-strip__controls {
  display: none;
}
