@import url('fonts.css');

/* ==========================================================================
   Вила Катерина Делукс — warm alpine luxury
   Deep forest green + warm wood against cream, EB Garamond over Inter.
   One stylesheet, no framework, no build step.
   ========================================================================== */

:root {
  /* Colour -------------------------------------------------------------- */
  --ink: #1c1913;
  --ink-soft: #4a4438;
  --muted: #6d6555;

  --forest: #1f3d2b;
  --forest-deep: #162c1f;
  --forest-soft: #2d523a;

  --wood: #a4703c;
  --wood-deep: #85582c;
  --wood-light: #d8b183;

  --cream: #f7f2e9;
  --paper: #fffdf8;
  --sand: #ece2d2;
  --line: #ddd2be;

  --white: #ffffff;

  /* The offer strip at the very top — a light tint of the teal in the villa's
     own logo (#287379), a colour used nowhere else on the site.
     ΔE 37.9 from the page surface, ΔE 54.4 from the nav.

     It has to differ from BOTH neighbours: --forest-deep (the nav sits directly
     beneath it) and --paper / --cream (the page). Four attempts, four lessons,
     measured as perceptual colour difference (ΔE in Lab) — luminance contrast
     alone catches none of them, because it ignores hue:
       pale tan  #d8b183  ΔE 37 / 66  visible, but the hue was rejected
       dark green#1f3d2b  ΔE 78 /  8  vanished into the nav
       --paper   #fffdf8  ΔE  0 / 84  IS the page colour; read as a margin
       copper    #8c4a1e  ΔE 74 / 54  measured fine, but dark and back in the
                                      same warm-brown family as the original

     A light band can only differ from a light page through CHROMA. Paler
     teals fall away fast: #cfe3e5 is only ΔE 13 from the page, which is the
     road back to the --paper mistake. #8fc0c5 (ΔE 31) is the practical floor
     if this ever needs softening. */
  --offer: #74afb6;

  /* Type ---------------------------------------------------------------- */
  --serif: 'EB Garamond', Georgia, 'Times New Roman', serif;
  --sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* Space --------------------------------------------------------------- */
  --gap: clamp(1rem, 2.5vw, 1.75rem);
  --section-y: clamp(3.5rem, 8vw, 6.5rem);
  --wrap: 1200px;
  --wrap-narrow: 760px;

  --radius: 4px;
  --shadow: 0 1px 2px rgba(28, 25, 19, .06), 0 8px 24px rgba(28, 25, 19, .08);
  --shadow-lg: 0 4px 12px rgba(28, 25, 19, .10), 0 24px 60px rgba(28, 25, 19, .16);

  /* Height of the pinned strip + nav; kept in sync by app.js so anchor
     links never land underneath the sticky header. */
  --topbar-h: 104px;
}

/* Base --------------------------------------------------------------------- */

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--topbar-h) + 1rem);
  -webkit-text-size-adjust: 100%;
}

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

img, video, iframe { max-width: 100%; display: block; }
img { height: auto; }

/* <picture> generates no box of its own. Without this it is an auto-height
   wrapper, so `height: 100%` on the inner <img> has nothing to resolve
   against and the hero photo either overflows or falls short of its box.
   Because the <source> elements then become children of the layout parent,
   they must be hidden explicitly — otherwise they take up grid cells.
   Hiding them does not affect which image the browser picks. */
picture { display: contents; }
source { display: none; }

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.15;
  color: var(--forest-deep);
  margin: 0 0 .6em;
  letter-spacing: -.005em;
}

h1 { font-size: clamp(2.4rem, 6.5vw, 4.25rem); font-weight: 500; }
h2 { font-size: clamp(1.85rem, 4vw, 2.75rem); }
h3 { font-size: clamp(1.2rem, 2.2vw, 1.45rem); }

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--wood-deep); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--forest); }

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--forest-deep);
  color: var(--white);
  padding: .75rem 1.25rem;
}
.skip-link:focus { left: .5rem; top: .5rem; }

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

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

.wrap {
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}
.wrap--narrow { width: min(100% - 2.5rem, var(--wrap-narrow)); }

.section { padding-block: var(--section-y); }
.section--alt { background: var(--cream); }
.section--forest {
  background: var(--forest-deep);
  color: var(--sand);
}
.section--forest h2, .section--forest h3 { color: var(--white); }
.section--forest a { color: var(--wood-light); }

.section__lead {
  font-size: clamp(1.05rem, 1.6vw, 1.2rem);
  color: var(--ink-soft);
  max-width: 62ch;
}
.section--forest .section__lead { color: #d9d2c2; }

.eyebrow {
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--wood-deep);
  margin: 0 0 .9rem;
}
.section--forest .eyebrow { color: var(--wood-light); }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .95rem 1.9rem;
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1;
  border: 1.5px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease, transform .18s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

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

.btn--ghost { background: transparent; color: var(--white); border-color: rgba(255,255,255,.65); }
.btn--ghost:hover { background: rgba(255,255,255,.12); color: var(--white); border-color: var(--white); }

.btn--outline { background: transparent; color: var(--forest); border-color: var(--forest); }
.btn--outline:hover { background: var(--forest); color: var(--white); }

/* Sticky offer strip + nav -------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 60;
}

/* A light band, distinct from both the nav below it and the page surface —
   see --offer in :root for the measurements and the four failed attempts.
   ΔE 54 against the nav is its own edge, so no border is needed. */
.strip {
  background: var(--offer);
  color: var(--ink);
  font-size: .9rem;
  font-weight: 500;
}
.strip__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .35rem 1rem;
  min-height: 44px;
  padding-block: .45rem;
  text-align: center;
  /* Wraps to a second line on narrow screens rather than hiding the call to
     action. --topbar-h is measured by app.js, so the taller bar is accounted
     for automatically. */
  flex-wrap: wrap;
}
.strip__price { font-weight: 700; white-space: nowrap; }
/* Decorative (aria-hidden): visible without competing with the text. */
.strip__sep { color: var(--forest); }
/* Dark green, not the warm --wood-deep the palette would suggest: wood on this
   teal measures 2.49:1, well under AA. Green is the only palette colour that
   works on this ground, and it pairs correctly with teal. */
.strip a { color: var(--forest-deep); text-decoration: underline; font-weight: 600; }
.strip a:hover { color: var(--ink); }
/* The address itself must never break mid-way; the label around it may wrap. */
.strip__text a { white-space: nowrap; }

/* The two halves of the strip light up in turn: price, dates, price, dates,
   price, dates — then a five-second pause, and the whole sequence again.
   Three repetitions (~28.5s) and it stops for good.

   ONE keyframe drives both pills. The cycle is 9.5s: three 0.75s slots for
   each pill filling the first 4.5s, then a flat transparent tail that IS the
   five-second pause — no separate mechanism needed for it. The dates pill
   simply starts one slot (0.75s) later, and because both animations share the
   same period that offset holds for every repetition. That is what produces
   the alternation; there is no second, mirrored keyframe to keep in sync.

   The pill is LIGHT, not dark. A dark pill would force the text to cross-fade
   from dark to white, and half-way through that fade it measures 1.85:1 —
   unreadable, on every pulse. With a light pill the text stays dark and the
   contrast only ever improves: 6.05:1 at rest, 9.8:1 mid-fade, 13.3:1 at the
   peak. Both the label and the email link inside are dark, so both benefit. */
.strip__text,
.strip__cta {
  border-radius: 100px;
  animation: strip-pill-pulse 9.5s ease-in-out .8s 3 both;
}

/* Different padding for the two, on purpose. These are flex items, so their
   padding really does take horizontal space: at .5rem the long price line no
   longer fitted on one line at 390px and the strip grew from two rows to three.
   The short call to action has no such problem and keeps the roomier pill. */
.strip__text { padding: .15rem .35rem; }
.strip__cta  { padding: .18rem .5rem; }

/* One slot later, so it is lit exactly when the price pill is dark. */
.strip__cta { animation-delay: 1.55s; }

@keyframes strip-pill-pulse {
  /* slot 1 — 0.00s to 0.75s */
  0%     { background-color: rgba(247, 242, 233, 0); }
  1.6%   { background-color: rgba(247, 242, 233, 1); }
  6.3%   { background-color: rgba(247, 242, 233, 1); }
  7.9%   { background-color: rgba(247, 242, 233, 0); }
  /* slot 3 — 1.50s to 2.25s */
  15.8%  { background-color: rgba(247, 242, 233, 0); }
  17.4%  { background-color: rgba(247, 242, 233, 1); }
  22.1%  { background-color: rgba(247, 242, 233, 1); }
  23.7%  { background-color: rgba(247, 242, 233, 0); }
  /* slot 5 — 3.00s to 3.75s */
  31.6%  { background-color: rgba(247, 242, 233, 0); }
  33.2%  { background-color: rgba(247, 242, 233, 1); }
  37.9%  { background-color: rgba(247, 242, 233, 1); }
  39.5%  { background-color: rgba(247, 242, 233, 0); }
  /* 4.50s to 9.50s — the pause */
  100%   { background-color: rgba(247, 242, 233, 0); }
}

/* Respect a stated preference for less motion — no pulse at all. */
@media (prefers-reduced-motion: reduce) {
  .strip__text,
  .strip__cta { animation: none; }
}

/* Below ~62rem the long sentence shrinks to a short label, but the call to
   action keeps its own class so it survives and moves to a second line. */
.strip__long { display: none; }
@media (min-width: 62rem) { .strip__long { display: inline; } .strip__short { display: none; } }

.nav {
  background: var(--forest-deep);
  color: var(--white);
  box-shadow: 0 2px 10px rgba(28, 25, 19, .18);
}
.nav__inner {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-height: 60px;
  padding-block: .5rem;
}
.nav__brand {
  display: flex;
  align-items: center;
  gap: .65rem;
  font-family: var(--serif);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--white);
  text-decoration: none;
  letter-spacing: .01em;
  line-height: 1.2;
  margin-right: auto;
}
.nav__brand img { width: 2.25rem; height: 2.25rem; flex: 0 0 auto; }
.nav__brand-text span {
  display: block;
  font-family: var(--sans);
  font-size: .6rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--wood-light);
  font-weight: 600;
  margin-top: .15rem;
}
/* The kicker under the wordmark costs width the nav links need, and the
   Greek nav is the widest of the three — shrink the wordmark with it. */
@media (max-width: 90rem) {
  .nav__brand-text span { display: none; }
  .nav__brand { font-size: 1rem; }
  /* Keep the wordmark on one line; the links shrink instead. */
  .nav__brand-text { white-space: nowrap; }
  .nav__links { gap: .9rem; }
}
/* On the narrowest screens the emblem alone carries the brand. */
@media (max-width: 26rem) { .nav__brand-text { display: none; } }

.footer__logo { width: 8rem; height: auto; margin-bottom: 1rem; }

.nav__links { display: none; gap: 1.15rem; align-items: center; }
.nav__links a {
  color: #e7e2d6;
  text-decoration: none;
  font-size: .9rem;
  font-weight: 500;
  padding-block: .3rem;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.nav__links a:hover { color: var(--white); border-bottom-color: var(--wood); }

/* The full link row only appears once there is genuinely room for it;
   below this the disclosure menu is the better experience. */
@media (min-width: 68rem) { .nav__links { display: flex; } }

.langs { display: flex; gap: .35rem; align-items: center; }
.langs a {
  color: #cfc9ba;
  text-decoration: none;
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .06em;
  padding: .3rem .45rem;
  border-radius: 2px;
}
.langs a:hover { color: var(--white); background: rgba(255,255,255,.1); }
.langs [aria-current="true"] { color: var(--forest-deep); background: var(--wood-light); }

.nav__cta { display: none; }
@media (min-width: 46rem) {
  .nav__cta { display: inline-flex; padding: .6rem 1.2rem; font-size: .9rem; }
}

/* Small screens get a disclosure menu rather than no navigation at all. */
.nav__toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 2.75rem; height: 2.5rem;
  padding: 0 .6rem;
  background: transparent;
  border: 1px solid rgba(255,255,255,.3);
  border-radius: var(--radius);
  cursor: pointer;
}
.nav__toggle span {
  display: block;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
  transition: transform .2s ease, opacity .2s ease;
}
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
@media (min-width: 68rem) { .nav__toggle { display: none; } }

.nav__panel {
  background: var(--forest);
  border-top: 1px solid rgba(255,255,255,.14);
  max-height: min(70vh, 30rem);
  overflow-y: auto;
}
.nav__panel[hidden] { display: none; }
.nav__panel .wrap { display: flex; flex-direction: column; padding-block: .5rem 1rem; }
.nav__panel a {
  color: #e7e2d6;
  text-decoration: none;
  font-weight: 500;
  padding: .8rem .25rem;
  border-bottom: 1px solid rgba(255,255,255,.1);
}
.nav__panel a:last-child { border-bottom: 0; color: var(--wood-light); font-weight: 600; }
@media (min-width: 68rem) { .nav__panel { display: none; } }

/* Hero --------------------------------------------------------------------- */

.hero { position: relative; background: var(--forest-deep); overflow: hidden; }
.hero__media {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  overflow: hidden;
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 55%; }
.hero::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(22,44,31,.35) 0%, rgba(22,44,31,.46) 45%, rgba(22,44,31,.58) 100%);
}
.hero__body {
  position: relative;
  z-index: 1;
  padding-block: clamp(4.5rem, 16vh, 9rem);
  color: var(--white);
  text-align: center;
}
.hero h1 { color: var(--white); text-shadow: 0 2px 24px rgba(0,0,0,.35); margin-bottom: .35em; }
.hero__kicker {
  font-family: var(--sans);
  font-size: .82rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--wood-light);
  font-weight: 600;
  margin: 0 0 1.1rem;
  text-shadow: 0 1px 12px rgba(0,0,0,.5);
}
.hero__tagline {
  font-size: clamp(1.05rem, 2vw, 1.3rem);
  max-width: 40ch;
  margin-inline: auto;
  color: #f2eee4;
  text-shadow: 0 1px 14px rgba(0,0,0,.45);
}
.hero__actions {
  display: flex; flex-wrap: wrap; gap: .85rem; justify-content: center;
  margin-top: 2rem;
}

/* Availability card ---------------------------------------------------------- */

/* Sits over the bottom of the hero photo, so it needs its own solid ground —
   the wash behind it is not dark enough to carry dark text on its own.

   The white surface lives on the <details> rather than on __inner, so the card
   looks like one object whether it is collapsed to its summary or expanded to
   the fields. */
.availability {
  position: relative;
  z-index: 2;
  margin-top: clamp(-3.5rem, -4vw, -2rem);
  margin-bottom: 1.5rem;
  background: var(--paper);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.availability__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: .6rem;
  padding: .85rem;
}

/* The collapsed state on phones: one line the size of a field, so it reads as
   something you fill in rather than as a banner. booking.js keeps its text in
   step with whatever has been chosen, so collapsing never hides information. */
.availability__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  min-height: 44px;
  padding: .6rem .85rem;
  font-size: 1rem;
  color: var(--ink);
  cursor: pointer;
  list-style: none;              /* Firefox */
  border-radius: var(--radius);
}
.availability__summary::-webkit-details-marker { display: none; }
/* Own chevron instead of the browser's triangle, rotated when open. */
.availability__summary::after {
  content: '';
  flex: none;
  width: .5rem; height: .5rem;
  margin-right: .15rem;
  border-right: 2px solid var(--wood);
  border-bottom: 2px solid var(--wood);
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s ease;
}
.availability[open] .availability__summary::after {
  transform: translateY(2px) rotate(-135deg);
}
.availability__summary:focus-visible {
  outline: 2px solid var(--wood);
  outline-offset: -2px;
}
#av-summary {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.availability__label {
  display: block;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--forest);
  margin-bottom: .2rem;
}
/* Fields are deliberately generous on phones: 44px is the smallest
   comfortable touch target, and the card is stacked there anyway, so nothing
   is gained by tightening it. The compaction below starts at the tablet
   breakpoint, which is where the card was actually too heavy. */
.availability__field input,
.availability__field select,
.availability__field .datefield {
  width: 100%;
  min-height: 44px;
  font: inherit;
  font-size: 1rem;
  padding: .6rem .7rem;
  color: var(--ink);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
}
.availability__field input:focus,
.availability__field select:focus,
.availability__field .datefield:focus {
  border-color: var(--wood);
  box-shadow: 0 0 0 3px rgba(164, 112, 60, .16);
  outline: none;
}
.availability__go { white-space: nowrap; }

@media (min-width: 46rem) {
  /* Desktop never collapses: the card is one 66px row there, so a click to
     open it would buy nothing. The summary disappears and the inline script
     beside the markup leaves `open` alone above this breakpoint. */
  .availability__summary { display: none; }

  .availability__inner {
    grid-template-columns: 1fr 1fr auto auto;
    align-items: end;
    gap: .7rem;
    padding: .55rem .7rem;
  }
  .availability__inner { padding: .45rem .6rem; }
  .availability__label { font-size: .62rem; margin-bottom: .1rem; }
  .availability__field input,
  .availability__field select,
  .availability__field .datefield {
    min-height: 0;
    font-size: .92rem;
    /* The body line-height of 1.65 is what keeps these fields tall; a native
       date input inherits it and adds ~10px of dead space per field. */
    line-height: 1.2;
    padding: .35rem .55rem;
  }
  .availability__go { padding: .45rem 1.3rem; font-size: .92rem; }
}

.availability__status {
  margin: .6rem 0 0;
  font-size: .92rem;
  color: var(--ink-soft);
  display: none;
}
.availability__status.is-shown { display: block; }

.availability__status--ok { color: #1f4a22; font-weight: 600; }
.availability__status--err { color: #8a2418; font-weight: 600; }

/* Date picker --------------------------------------------------------------- */

/* booking.js hides each <input type="date"> and puts one of these in front of
   it. The input stays in the DOM so the enquiry form still posts it, and so
   the page degrades to plain date fields with JavaScript off. The button
   borrows the field styling above rather than restating it, which is why
   `.datefield` appears in those selectors: the two must not drift apart. */
.datefield {
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.datefield.is-empty { color: var(--muted); }
.availability__field input[hidden],
.field input[hidden] { display: none; }

/* The panel is a child of <body>, not of the card. The hero is overflow:hidden
   and the card sits inside it, so anything anchored to the card would be cut
   off at the hero's edge; position:fixed against the field's rect avoids that
   without touching the hero, whose overflow is load-bearing. */
.dp {
  position: fixed;
  z-index: 300;              /* above the sticky header, which is 200 */
  width: 17.5rem;
  padding: .5rem;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  font-family: var(--sans);
  color: var(--ink);
}
.dp[hidden] { display: none; }

.dp__head {
  display: flex;
  align-items: center;
  gap: .25rem;
  margin-bottom: .3rem;
}
.dp__title {
  flex: 1;
  text-align: center;
  font-size: .88rem;
  font-weight: 700;
}
.dp__nav {
  width: 1.9rem; height: 1.9rem;
  display: grid; place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: var(--radius);
  font: inherit;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--forest);
  cursor: pointer;
}
.dp__nav:hover:not(:disabled) { background: var(--cream); }
.dp__nav:disabled { opacity: .3; cursor: default; }

.dp__wd,
.dp__grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.dp__wd span {
  padding: .2rem 0;
  text-align: center;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.dp__day {
  display: grid; place-items: center;
  height: 2.05rem;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: var(--radius);
  font: inherit;
  font-size: .8rem;
  color: var(--ink);
  cursor: pointer;
}
.dp__day.is-blank { visibility: hidden; }
.dp__day:hover:not([aria-disabled="true"]) { background: var(--cream); }
.dp__day.is-today { font-weight: 700; box-shadow: inset 0 0 0 1px var(--line); }

/* Both marks mean unavailable; they differ only in why.

   PALE alone: not available for this step — a past day, or a night beyond the
   first booked one so the stay cannot reach it.
   PALE + STRUCK: not available AND booked, which is the case worth naming, so
   this is what the legend explains.

   The rule that matters is what is NOT here: a strike is never applied to a
   day that can be clicked. booking.js only adds is-taken to cells it has
   already disabled. An earlier version marked every booked night regardless,
   which crossed out 22 Aug — the one legal departure date after arriving on
   the 18th — and guests read the strike as "forbidden" and skipped it. A
   strike outranks any colour it is paired with; do not try to out-argue it. */
.dp__day.is-taken {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}
.dp__day.is-off { color: #b6ada0; cursor: default; }

/* Turnover day: the night is someone else's but the morning is still free, so
   a stay can end here even though it cannot start here. Split diagonally, with
   the shaded half at the bottom right — the day begins free and is taken from
   the afternoon, which is the order it actually happens in.

   It stays pale and unclickable while an arrival is being picked, because it
   genuinely is not a legal arrival. Making it dark to hint that "something is
   possible here" would repeat the mistake this whole rule exists to prevent,
   only mirrored. The diagonal carries the meaning; the legend names it. */
.dp__day.is-turnover {
  background: linear-gradient(to bottom right, transparent 50%, var(--sand) 50%);
}

.dp__day.is-mid { background: var(--sand); border-radius: 0; }
.dp__day.is-start,
.dp__day.is-end {
  background: var(--forest);
  color: var(--white);
  font-weight: 700;
}

.dp__day:focus-visible,
.dp__nav:focus-visible { outline: 2px solid var(--wood); outline-offset: -2px; }

.dp__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .15rem .6rem;
  margin-top: .4rem;
  padding-top: .4rem;
  border-top: 1px solid var(--line);
  font-size: .68rem;
  color: var(--muted);
}
.dp__foot--note { display: block; color: var(--ink-soft); }
.dp__legend { display: inline-flex; align-items: center; gap: .3rem; }
.dp__chip {
  position: relative;
  width: .9rem; height: .9rem;
  border-radius: 2px;
  background: var(--sand);
}
.dp__chip::after {
  content: '';
  position: absolute;
  left: 1px; right: 1px; top: 50%;
  height: 1.5px;
  background: var(--muted);
  transform: translateY(-50%);
}
/* Same diagonal as the cell it explains — no strike, since a turnover day is
   not struck out. */
.dp__chip--turnover {
  background: linear-gradient(to bottom right, var(--white) 50%, var(--sand) 50%);
  box-shadow: inset 0 0 0 1px var(--line);
}
.dp__chip--turnover::after { display: none; }

/* Roomier cells for thumbs. 18.5rem still clears a 320px screen with the 8px
   margin the script keeps on each side. */
@media (max-width: 45.99rem) {
  .dp { width: 18.5rem; }
  .dp__day { height: 2.35rem; font-size: .85rem; }
}

/* Facts bar ---------------------------------------------------------------- */

.facts {
  background: var(--forest);
  color: var(--white);
  border-top: 1px solid rgba(255,255,255,.12);
}
.facts__list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0;
  margin: 0; padding: 0;
  list-style: none;
}
@media (min-width: 46rem) { .facts__list { grid-template-columns: repeat(4, 1fr); } }
.facts__list li {
  padding: 1.15rem .75rem;
  text-align: center;
  border-right: 1px solid rgba(255,255,255,.12);
  border-bottom: 1px solid rgba(255,255,255,.12);
}
/* Two columns: no divider on the right-hand cell of each row. */
.facts__list li:nth-child(2n) { border-right: 0; }

@media (min-width: 46rem) {
  /* Four columns: every cell gets a divider except the last.
     The :nth-child(2n) rule above must be undone with a selector of EQUAL
     specificity — media queries add none, and `.facts__list li` alone loses
     to `.facts__list li:nth-child(2n)`, which is why the divider after the
     second item silently disappeared on desktop. */
  .facts__list li { border-bottom: 0; }
  .facts__list li:nth-child(2n) { border-right: 1px solid rgba(255,255,255,.12); }
  .facts__list li:last-child { border-right: 0; }
}
.facts b {
  display: block;
  font-family: var(--serif);
  font-size: 1.55rem;
  font-weight: 600;
  line-height: 1.1;
}
.facts span {
  display: block;
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #c7d2c8;
  margin-top: .3rem;
}

/* Split (text + image) ------------------------------------------------------ */

.split {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3.5rem);
  align-items: center;
}
@media (min-width: 56rem) {
  .split { grid-template-columns: 1fr 1fr; }
  .split--reverse .split__media { order: -1; }
}
.split__media img { border-radius: var(--radius); box-shadow: var(--shadow); width: 100%; }

.figure-stack { display: grid; gap: .75rem; grid-template-columns: 1fr 1fr; }
.figure-stack img { border-radius: var(--radius); box-shadow: var(--shadow); width: 100%; }
/* Marked explicitly by the builder: `display: contents` keeps each <img>
   inside its own <picture> in the DOM, so :first-of-type would match all
   three, not the first laid-out one. */
.figure-stack .figure-stack__lead { grid-column: 1 / -1; }

/* Rooms table -------------------------------------------------------------- */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: .97rem;
  min-width: 34rem;
}
table.data caption {
  text-align: left;
  color: var(--muted);
  font-size: .9rem;
  padding-bottom: .75rem;
}
table.data th, table.data td {
  text-align: left;
  padding: .95rem 1rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
table.data thead th {
  font-family: var(--sans);
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--forest);
  border-bottom: 2px solid var(--forest);
  white-space: nowrap;
}
table.data tbody th {
  font-family: var(--serif);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--forest-deep);
  white-space: nowrap;
}
table.data tbody tr:last-child td,
table.data tbody tr:last-child th { border-bottom: 0; }
table.data td small { display: block; color: var(--muted); font-size: .85rem; }

/* Amenities ---------------------------------------------------------------- */

.amenities {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: .35rem 2rem;
  list-style: none;
  margin: 0; padding: 0;
}
.amenities li {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--line);
  font-size: .98rem;
}
.section--forest .amenities li { border-bottom-color: rgba(255,255,255,.14); }
.amenities svg {
  flex: 0 0 auto;
  width: 1.25rem; height: 1.25rem;
  margin-top: .18rem;
  color: var(--wood);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.section--forest .amenities svg { color: var(--wood-light); }

/* Highlight card (the sauna, and anything else worth pulling out) ----------- */

.highlight {
  display: grid;
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: center;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 4px solid var(--wood);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 3.5vw, 2.75rem);
  box-shadow: var(--shadow);
}
@media (min-width: 56rem) { .highlight { grid-template-columns: 1.1fr 1fr; } }
.highlight img { border-radius: var(--radius); width: 100%; }
.highlight h3 { margin-top: 0; }

/* Cards -------------------------------------------------------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--gap);
  list-style: none;
  margin: 0; padding: 0;
}
.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem;
}
.section--forest .card {
  background: rgba(255,255,255,.05);
  border-color: rgba(255,255,255,.16);
}
.card h3 { font-size: 1.2rem; margin-bottom: .45rem; }
.card p { font-size: .95rem; color: var(--ink-soft); }
.section--forest .card p { color: #d5cfc0; }

/* Video facade ------------------------------------------------------------- */

.video {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  background: var(--forest-deep);
}
.video img, .video iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  object-fit: cover;
}
.video__btn {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(22,44,31,.28);
  border: 0;
  cursor: pointer;
  transition: background-color .2s ease;
}
.video__btn:hover { background: rgba(22,44,31,.12); }
.video__btn::after {
  content: '';
  width: clamp(4rem, 8vw, 5.5rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--wood) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M8 5.5v13l11-6.5z'/%3E%3C/svg%3E") center/44% no-repeat;
  box-shadow: 0 6px 28px rgba(0,0,0,.4);
  transition: transform .2s ease;
}
.video__btn:hover::after { transform: scale(1.06); }

/* Gallery ------------------------------------------------------------------ */

.gallery-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: 1.75rem;
  padding: 0;
  list-style: none;
}
.gallery-filter {
  font: inherit;
  font-size: .88rem;
  font-weight: 500;
  padding: .45rem 1rem;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-soft);
  border-radius: 100px;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.gallery-filter:hover { border-color: var(--wood); color: var(--wood-deep); }
.gallery-filter[aria-pressed="true"] {
  background: var(--forest-deep);
  border-color: var(--forest-deep);
  color: var(--white);
}

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
  gap: .75rem;
  margin: 0; padding: 0;
  list-style: none;
}
.gallery li { margin: 0; }
.gallery button {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: var(--sand);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: zoom-in;
  position: relative;
  aspect-ratio: 3 / 2;
}
.gallery img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.2,.7,.3,1), filter .3s ease;
}
.gallery button:hover img { transform: scale(1.045); filter: brightness(1.04); }
.gallery li[hidden] { display: none; }

/* Reveals the rest of the current category. Ships hidden in the markup and is
   unhidden by app.js, so a browser without JavaScript simply gets every tile
   and no button.

   Solid, because an outlined version disappeared: --paper on the section's
   --cream is 1.10:1, and the old --line border 1.34:1, so the shape had no
   contrast at all and only the lettering showed. Filled --forest is 10.7:1
   against the same ground.

   Deliberately NOT the copper of .btn--primary. A button that only unfolds
   photographs should not carry the same weight as the one that brings
   enquiries. */
.gallery-more {
  display: block;
  margin: 2rem auto 0;
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  padding: .85rem 2rem;
  border: 0;
  background: var(--forest);
  color: var(--white);
  border-radius: 100px;
  cursor: pointer;
  transition: background-color .15s ease;
}
.gallery-more:hover { background: var(--forest-deep); }
/* Copper, offset outwards: the old inset ring was invisible on a dark fill. */
.gallery-more:focus-visible { outline: 2px solid var(--wood); outline-offset: 3px; }
.gallery-more[hidden] { display: none; }

/* Lightbox ----------------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(16, 22, 18, .95);
  padding: clamp(.5rem, 3vw, 2.5rem);
}
.lightbox[hidden] { display: none; }
.lightbox__figure {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: .75rem;
  align-items: center;
}
.lightbox__figure img {
  max-width: 100%;
  max-height: 78vh;
  width: auto;
  object-fit: contain;
  border-radius: 2px;
  background: var(--forest-deep);
}
.lightbox__caption {
  color: #ded8c9;
  font-size: .92rem;
  text-align: center;
  max-width: 60ch;
}
.lightbox__count { color: #8f9b91; font-size: .82rem; }

.lightbox button {
  position: absolute;
  border: 0;
  background: rgba(255,255,255,.10);
  color: var(--white);
  width: 3rem; height: 3rem;
  border-radius: 50%;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem;
  line-height: 1;
  transition: background-color .15s ease;
}
.lightbox button:hover { background: rgba(255,255,255,.24); }
.lightbox__close { top: 1rem; right: 1rem; }
.lightbox__prev { left: clamp(.5rem, 2vw, 2rem); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: clamp(.5rem, 2vw, 2rem); top: 50%; transform: translateY(-50%); }

body.is-locked { overflow: hidden; }

/* FAQ ---------------------------------------------------------------------- */

.faq { max-width: 52rem; }
.faq details {
  border-bottom: 1px solid var(--line);
}
.faq summary {
  cursor: pointer;
  list-style: none;
  padding: 1.15rem 2.5rem 1.15rem 0;
  font-family: var(--serif);
  font-size: 1.18rem;
  font-weight: 600;
  color: var(--forest-deep);
  position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '';
  position: absolute;
  right: .35rem; top: 50%;
  width: .7rem; height: .7rem;
  border-right: 2px solid var(--wood);
  border-bottom: 2px solid var(--wood);
  transform: translateY(-70%) rotate(45deg);
  transition: transform .2s ease;
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq summary:hover { color: var(--wood-deep); }
.faq .faq__body { padding: 0 1rem 1.4rem 0; color: var(--ink-soft); }

/* House rules ---------------------------------------------------------------- */

.rules {
  margin: 0;
  padding: 0;
  display: grid;
  /* No column gap: a gap would break the horizontal rule into two segments.
     The space between term and value comes from the term's padding instead. */
  gap: 0;
  grid-template-columns: 1fr;
  max-width: 60rem;
}
.rules dt {
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--forest);
  margin: 0;
  padding-block: 1rem .25rem;
}
.rules dd {
  margin: 0;
  padding-block: 0 1rem;
  color: var(--ink-soft);
  font-size: .97rem;
  border-bottom: 1px solid var(--line);
}

/* Two columns once there is room: term and value sit on one grid row, so
   giving both the same padding and border makes the rule span the full width. */
@media (min-width: 52rem) {
  .rules { grid-template-columns: 14rem 1fr; }
  .rules dt {
    padding-block: 1rem;
    padding-right: 2rem;
    border-bottom: 1px solid var(--line);
  }
  .rules dd { padding-block: 1rem; }
}

/* Rates -------------------------------------------------------------------- */

.rate-anchor {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .6rem;
  margin-bottom: 1.25rem;
}
.rate-anchor b {
  font-family: var(--serif);
  font-size: clamp(2.5rem, 6vw, 3.5rem);
  font-weight: 600;
  line-height: 1;
  color: var(--forest-deep);
}
.section--forest .rate-anchor b { color: var(--white); }
.rate-anchor span { color: var(--muted); font-size: 1rem; }
.section--forest .rate-anchor span { color: #cdc6b6; }

.included {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  display: grid;
  gap: .4rem;
}
.included li { display: flex; gap: .6rem; align-items: baseline; }
.included li::before { content: '✓'; color: var(--wood); font-weight: 700; }
.section--forest .included li::before { color: var(--wood-light); }

/* Form --------------------------------------------------------------------- */

.enquiry {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 4vw, 2.75rem);
  box-shadow: var(--shadow);
}

.field-grid {
  display: grid;
  gap: 1.1rem;
  grid-template-columns: 1fr;
}
@media (min-width: 40rem) { .field-grid { grid-template-columns: 1fr 1fr; } }
.field--full { grid-column: 1 / -1; }

.field label {
  display: block;
  font-size: .85rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--forest);
  margin-bottom: .4rem;
}
.field input,
.field select,
.field textarea,
.field .datefield {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  padding: .8rem .9rem;
  color: var(--ink);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field input:focus,
.field select:focus,
.field textarea:focus,
.field .datefield:focus {
  border-color: var(--wood);
  box-shadow: 0 0 0 3px rgba(164, 112, 60, .16);
  outline: none;
}
.field textarea { min-height: 7rem; resize: vertical; }
.field__hint { font-size: .82rem; color: var(--muted); margin-top: .35rem; }
.field__error { font-size: .84rem; color: #a12b1e; margin-top: .35rem; font-weight: 500; }
.field input[aria-invalid="true"],
.field select[aria-invalid="true"] { border-color: #a12b1e; }

/* Honeypot — hidden from humans, left in the DOM for bots to fill in. */
.hp {
  position: absolute !important;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .85rem;
  align-items: center;
  margin-top: 1.5rem;
}
.form__note { font-size: .88rem; color: var(--muted); margin-top: 1rem; }

.form__status { margin-top: 1.25rem; padding: 1rem 1.15rem; border-radius: var(--radius); font-size: .95rem; }
.form__status[hidden] { display: none; }
.form__status--ok { background: #e8f0e6; border: 1px solid #b6ceb0; color: #1f4a22; }
.form__status--err { background: #f8e9e7; border: 1px solid #e0b6b0; color: #8a2418; }

.nights {
  font-size: .92rem;
  color: var(--forest);
  font-weight: 600;
}

/* Location ----------------------------------------------------------------- */

.map {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  background: var(--sand);
}
.map iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.map__btn {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: .75rem;
  width: 100%; height: 100%;
  border: 0;
  background: linear-gradient(rgba(31,61,43,.55), rgba(31,61,43,.7));
  color: var(--white);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.map__btn small { font-weight: 400; opacity: .85; font-size: .85rem; max-width: 30ch; text-align: center; }

/* Footer ------------------------------------------------------------------- */

.footer {
  background: var(--forest-deep);
  color: #c9c3b4;
  padding-block: clamp(2.5rem, 6vw, 4rem) 2rem;
  font-size: .93rem;
}
.footer h2, .footer h3 { color: var(--white); font-size: 1.1rem; }
.footer a { color: var(--wood-light); }
.footer a:hover { color: var(--white); }
.footer__grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  padding-bottom: 2rem;
  border-bottom: 1px solid rgba(255,255,255,.14);
}
.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.footer__bottom {
  padding-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 1.5rem;
  justify-content: space-between;
  font-size: .85rem;
  color: #9a9486;
}

/* 404 ------------------------------------------------------------------------ */

body.notfound { background: var(--cream); }
.notfound__inner {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  text-align: center;
  padding-block: 3rem;
}
.notfound__inner > img { width: 4.5rem; height: auto; }
.notfound__lang {
  padding-block: 1.25rem;
  border-top: 1px solid var(--line);
  max-width: 40rem;
}
.notfound__lang:first-of-type { border-top: 0; }
.notfound__lang h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); margin-bottom: .35em; }
.notfound__lang p { color: var(--ink-soft); margin-bottom: 1.1rem; }

/* Utilities ---------------------------------------------------------------- */

.stack > * + * { margin-top: var(--flow, 1.5rem); }
.mt-lg { margin-top: clamp(2rem, 4vw, 3rem); }
.text-center { text-align: center; }
.nowrap { white-space: nowrap; }

@media print {
  .topbar, .hero__actions, .gallery-nav, .video, .map, .enquiry { display: none; }
  body { background: #fff; }
}
