/* ===================================================================
   Cozy Guesthouse, Upington

   Scene the palette is built from: late afternoon in a walled garden
   in Upington. White sun coming off pool water, deep shade under the
   thatch, river-green leaves against warm plaster.

   One theme (light) for the whole page. One accent (river green).
   One radius system. Two typefaces: Newsreader for display voice,
   Archivo for every piece of interface text.
   =================================================================== */

/* ---- tokens ------------------------------------------------------ */
:root {
  /* ground */
  --paper:      oklch(0.976 0.006 90);    /* warm plaster */
  --paper-2:    oklch(0.947 0.010 88);    /* sand, alternating surfaces */
  --card:       oklch(0.993 0.004 90);    /* panels sit slightly above */

  /* ink. three tones only, all tested against --paper */
  --ink:        oklch(0.255 0.021 165);   /* 12:1  primary */
  --ink-2:      oklch(0.430 0.018 168);   /* 5.5:1 secondary body */
  --ink-3:      oklch(0.470 0.016 168);   /* 4.6:1 smallest labels */

  --line:       oklch(0.888 0.010 120);
  --line-2:     oklch(0.930 0.008 100);

  /* one accent, locked across the page */
  --accent:     oklch(0.455 0.078 178);   /* river green */
  --accent-dk:  oklch(0.395 0.074 178);
  --accent-tint:oklch(0.930 0.022 178);
  --accent-line:oklch(0.855 0.036 178);

  --night:      oklch(0.245 0.030 172);   /* footer and overlays only */

  /* one radius system. nothing on this page exceeds 14px. */
  --r-xs: 4px;
  --r-sm: 8px;
  --r:    12px;
  --r-lg: 14px;
  --r-img: 3px;

  /* the only two shadows, and never on a bordered element */
  --lift:  0 1px 2px oklch(0.255 0.021 165 / 0.05), 0 8px 22px -14px oklch(0.255 0.021 165 / 0.22);
  --lift-2:0 2px 6px oklch(0.255 0.021 165 / 0.07), 0 24px 48px -24px oklch(0.255 0.021 165 / 0.28);

  /* two curves with some conviction in them. nothing on this page uses an
     ease-in, so no ease-in curve is defined to be reached for by mistake. */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  /* type */
  --serif: "Newsreader", "Iowan Old Style", Georgia, serif;
  --sans:  "Archivo", ui-sans-serif, system-ui, "Segoe UI", sans-serif;

  --t-display: clamp(2.5rem, 7.4vw, 5.25rem);
  --t-h2:      clamp(1.85rem, 3.6vw, 2.9rem);
  --t-h3:      1.3125rem;
  --t-quote:   clamp(1.45rem, 3vw, 2.2rem);
  --t-lede:    clamp(1.0625rem, 0.55vw + 0.95rem, 1.25rem);
  --t-body:    1.0625rem;
  --t-sm:      0.9375rem;
  --t-xs:      0.8125rem;

  /* rhythm, 4px base */
  --s-1: 0.25rem; --s-2: 0.5rem;  --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.5rem;  --s-6: 2rem;    --s-7: 3rem;    --s-8: 4rem;

  --wrap: 76rem;
  --pad:  clamp(1.25rem, 4.5vw, 3.5rem);
  --sec:  clamp(4.25rem, 9vw, 8rem);

  /* z scale, named, never 9999 */
  --z-head: 20;
  --z-sheet: 40;
  --z-toast: 60;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  /* clip, not hidden: hidden makes the body a scroll container and
     ScrollTrigger loses the page. */
  overflow-x: clip;
}

/* the header floats over everything, so anchored sections need to stop
   below it rather than under it */
:where(section[id], main[id]) { scroll-margin-top: 5.5rem; }

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
ul, ol { list-style: none; padding: 0; }
a { color: inherit; }

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

.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.hp { position: absolute; left: -9999px; opacity: 0; }

.skip {
  position: fixed; top: var(--s-3); left: var(--s-3); z-index: var(--z-toast);
  padding: 0.7rem 1rem; background: var(--ink); color: var(--paper);
  border-radius: var(--r-sm); font-size: var(--t-sm); font-weight: 500;
  transform: translateY(-160%);
  transition: transform 160ms var(--ease-out);
}
.skip:focus { transform: none; }

/* ---- type -------------------------------------------------------- */
.h2 {
  font-family: var(--serif);
  font-size: var(--t-h2);
  font-weight: 400;
  font-variation-settings: "opsz" 44;
  line-height: 1.1;
  letter-spacing: -0.018em;
  text-wrap: balance;
}
.h3 {
  font-family: var(--sans);
  font-size: var(--t-h3);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.008em;
}
.lede { font-size: var(--t-lede); line-height: 1.55; color: var(--ink-2); text-wrap: pretty; }
.measure { max-width: 62ch; }
.fine { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); }

/* the kicker is used twice on the whole page, where it names a real
   category. it is not scaffolding above every heading. */
.kicker {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--s-3);
}

/* ---- layout ------------------------------------------------------ */
.section { padding-inline: var(--pad); }
.sec-head, .book-head, .welcome-in, .room-rail, .house-grid,
.near-list, .book-grid, .says-in, .contact-grid, .gal-head > * {
  max-width: var(--wrap); margin-inline: auto;
}
.rooms, .house, .nearby, .says, .book, .contact, .welcome { padding-block: var(--sec); }
.sec-head { margin-bottom: clamp(2rem, 4vw, 3.25rem); }

/* ---- buttons ----------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  min-height: 46px;
  padding: 0.7rem 1.4rem;
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: 0.005em;
  text-decoration: none;
  white-space: nowrap;
  transition: transform 120ms var(--ease-out),
              background-color 160ms var(--ease-out),
              color 160ms var(--ease-out),
              border-color 160ms var(--ease-out);
}
.btn-solid { background: var(--accent); color: oklch(0.99 0.004 90); }
.btn-quiet { color: var(--ink-2); }
.btn-line  { border: 1px solid var(--line); color: var(--ink); background: var(--card); }
.btn-sm { min-height: 44px; padding: 0.55rem 1rem; }
.btn-wide { width: 100%; }

.btn:active:not(:disabled) { transform: scale(0.975); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn.is-busy { opacity: 0.7; cursor: progress; }

@media (hover: hover) and (pointer: fine) {
  .field input:hover, .field textarea:hover, .field select:hover { border-color: var(--accent-line); }
  .btn-solid:hover { background: var(--accent-dk); }
  .btn-quiet:hover { background: var(--accent-tint); color: var(--accent-dk); }
  .btn-line:hover  { border-color: var(--accent-line); color: var(--accent-dk); }
}

.icon-btn {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 999px;
  color: var(--ink-2);
  transition: background-color 150ms var(--ease-out), color 150ms var(--ease-out), transform 120ms var(--ease-out);
}
.icon-btn:active { transform: scale(0.94); }
.icon-btn:disabled { color: oklch(0.74 0.008 100); cursor: not-allowed; }
@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover:not(:disabled) { background: var(--accent-tint); color: var(--accent-dk); }
}

/* ---- header ------------------------------------------------------ */
/* fixed rather than sticky so the hero needs no negative margin to sit
   under it, which kept breaking whenever the header changed height */
.head {
  position: fixed; top: 0; left: 0; right: 0; z-index: var(--z-head);
  color: var(--ink);
}
/* The sky in the hero photograph measures L*89, so dark header text over
   it reads at about 10:1 and light text would be invisible. Dark ink is
   therefore the default and needs no scrim at all. If the owner ever
   loads a dark photograph, site.js measures it and adds .on-dark, which
   turns on light ink and the scrim that makes it legible. */
.head::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom, oklch(0.24 0.02 168 / 0.72), oklch(0.24 0.02 168 / 0));
  opacity: 0; transition: opacity 220ms var(--ease-out);
  pointer-events: none;
}
.head.on-dark { color: oklch(0.98 0.004 90); }
.head.on-dark::before { opacity: 1; }
.head-in {
  position: relative;
  max-width: var(--wrap); margin-inline: auto;
  padding: var(--s-3) var(--pad);
  display: flex; align-items: center; gap: var(--s-3);
  min-height: 64px;
}
.brand-name { white-space: nowrap; }
@media (min-width: 48rem) { .head-in { gap: var(--s-5); } }
/* once the page has moved at all, the header stops relying on the
   photograph underneath it and brings its own ground */
.head.is-stuck, .head.is-menu {
  background: oklch(0.976 0.006 90 / 0.92);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}
.head.is-menu { background: var(--paper); }
.head.is-stuck::before, .head.is-menu::before { opacity: 0; }

.brand { display: flex; align-items: center; gap: var(--s-3); text-decoration: none; }
.brand-name {
  font-family: var(--serif); font-size: 1.2rem; font-weight: 400;
  font-variation-settings: "opsz" 20; letter-spacing: -0.01em;
}
.brand-sub { font-size: var(--t-xs); opacity: 0.72; }

.nav { display: none; margin-left: auto; gap: var(--s-5); }
.nav a {
  position: relative;
  font-size: var(--t-sm);
  display: inline-flex; align-items: center;
  min-height: 44px;
  text-decoration: none;
  transition: opacity 150ms var(--ease-out);
}
.nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 2px; height: 1px;
  background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform 220ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav a:hover::after { transform: scaleX(1); }
}
.nav a[aria-current="true"]::after { transform: scaleX(1); opacity: 0.5; }

.head-act { display: flex; align-items: center; gap: var(--s-2); margin-left: auto; }
/* the booking button is the point of the site, so it is never the thing
   that gets dropped on a small screen. the label shortens instead. */
.head-book-long { display: none; }
.menu-btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: 44px; padding-inline: var(--s-2);
  font-size: var(--t-sm); font-weight: 500;
}
@media (max-width: 26rem) { .brand-sub { display: none; } }
@media (min-width: 30rem) { .head-book-long { display: inline; } }

@media (min-width: 62rem) {
  .nav { display: flex; }
  .head-act { margin-left: 0; gap: var(--s-3); }
  .menu-btn { display: none; }
}

/* mobile menu: the nav becomes a sheet under the header. anchored to the
   header itself, so it cannot drift when the header changes height. */
@media not all and (min-width: 62rem) {
  .nav.is-open {
    display: grid;
    position: absolute; top: 100%; left: 0; right: 0;
    background: var(--paper);
    color: var(--ink);
    border-bottom: 1px solid var(--line);
    padding: var(--s-4) var(--pad) var(--s-6);
    gap: 0;
    animation: sheet-down 240ms var(--ease-out);
  }
  .nav.is-open a {
    font-family: var(--serif); font-size: 1.5rem; font-weight: 400;
    font-variation-settings: "opsz" 24;
    padding-block: var(--s-3);
    border-bottom: 1px solid var(--line-2);
  }
  .nav.is-open a::after { display: none; }
}
@keyframes sheet-down {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: none; }
}

/* ---- hero -------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 5rem var(--pad) clamp(1.5rem, 4vw, 3rem);
  overflow: clip;
  isolation: isolate;
}
/* taller than the frame it sits in, so the parallax never opens a gap */
.hero-media { position: absolute; inset: -12% 0 0 0; z-index: -2; background: var(--paper-2); }
.hero-media img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 58%;
  transform: scale(1.075);
  will-change: transform;
}
.hero-media img.is-settled {
  transform: scale(1);
  transition: transform 12s cubic-bezier(0.16, 0.6, 0.2, 1);
}
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(to top, oklch(0.22 0.02 168 / 0.78) 0%, oklch(0.22 0.02 168 / 0.45) 34%, oklch(0.22 0.02 168 / 0.06) 62%),
    linear-gradient(to bottom, oklch(0.22 0.02 168 / 0.18), transparent 40%);
}

.hero-in { position: relative; width: 100%; max-width: var(--wrap); margin-inline: auto; }
.hero-title {
  font-family: var(--serif);
  font-size: var(--t-display);
  font-weight: 300;
  font-variation-settings: "opsz" 72;
  line-height: 1.03;
  letter-spacing: -0.028em;
  color: oklch(0.985 0.004 90);
  margin-bottom: var(--s-4);
}
.hero-title .mask { display: block; overflow: hidden; padding-bottom: 0.06em; }
.hero-title .mask > span { display: block; transform: translateY(105%); }
.hero.is-lit .mask > span {
  transform: none;
  transition: transform 720ms var(--ease-out);
}
.hero.is-lit .mask:nth-child(2) > span { transition-delay: 80ms; }

.hero-lede {
  max-width: 34ch;
  font-size: var(--t-lede);
  line-height: 1.5;
  color: oklch(0.94 0.008 100);
  opacity: 0; transform: translateY(10px);
}
/* a phone held sideways has no room for a sentence and a search bar.
   the search bar wins. */
@media (max-height: 34rem) {
  .hero-lede { display: none; }
  .hero-title { font-size: 2rem; }
  .hero { min-height: 100svh; padding-block: 4rem 1rem; }
}
.hero.is-lit .hero-lede {
  opacity: 1; transform: none;
  transition: opacity 620ms var(--ease-out) 240ms, transform 620ms var(--ease-out) 240ms;
}

/* ---- the search bar --------------------------------------------- */
.searchbar {
  margin-top: clamp(1.75rem, 4vw, 2.75rem);
  display: grid; gap: var(--s-2);
  padding: var(--s-3);
  background: var(--paper);
  border-radius: var(--r-lg);
  box-shadow: var(--lift-2);
  color: var(--ink);
  opacity: 0; transform: translateY(14px);
}
.hero.is-lit .searchbar {
  opacity: 1; transform: none;
  transition: opacity 640ms var(--ease-out) 380ms, transform 640ms var(--ease-out) 380ms;
}
.sb-fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2); }
.sb-guests { grid-column: 1 / -1; }

.sb-field {
  display: grid; gap: 2px; align-content: center;
  text-align: left;
  min-height: 58px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  background: var(--paper);
  transition: background-color 150ms var(--ease-out), box-shadow 150ms var(--ease-out);
}
.sb-label {
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--ink-3);
}
.sb-value { font-size: var(--t-sm); color: var(--ink-3); }
.sb-field.is-set .sb-value { color: var(--ink); font-weight: 500; }
@media (hover: hover) and (pointer: fine) {
  button.sb-field:hover { background: var(--accent-tint); }
}
.sb-select {
  appearance: none;
  border: 0;
  /* a chevron, so it reads as something you can open rather than a label */
  background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5 8l5 5 5-5' fill='none' stroke='%23566' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") right center / 14px no-repeat;
  padding-right: 1.25rem;
  cursor: pointer;
  font-size: var(--t-sm); font-weight: 500;
  padding: 0; margin-top: 1px;
  width: 100%;
}
.sb-go { min-height: 52px; }

@media (min-width: 48rem) {
  .searchbar { grid-template-columns: 1fr auto; align-items: stretch; }
  .sb-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sb-guests { grid-column: auto; }
  .sb-go { min-height: 58px; padding-inline: 1.75rem; }
}

/* ---- welcome ----------------------------------------------------- */
.welcome { background: var(--paper); }
.welcome-in { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); }
.welcome-in .h2 { max-width: 24ch; }
.welcome-cols { display: grid; gap: clamp(2rem, 4vw, 3.5rem); }

.facts { display: grid; gap: var(--s-4); align-content: start; }
.facts > div {
  display: grid; grid-template-columns: 5.5rem 1fr; gap: var(--s-4);
  align-items: baseline;
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--line-2);
}
.facts > div:last-child { border-bottom: 0; padding-bottom: 0; }
.facts dt {
  font-family: var(--serif); font-size: 1.75rem; font-weight: 400;
  font-variation-settings: "opsz" 28; line-height: 1;
  color: var(--accent);
  font-variant-numeric: lining-nums tabular-nums;
}
.facts dd { font-size: var(--t-sm); color: var(--ink-2); }

@media (min-width: 60rem) {
  .welcome-cols { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); }
  /* a deliberate indent, so the block does not sit dead centre */
  .welcome-in { padding-left: clamp(0rem, 5vw, 6rem); }
}

/* ---- rooms ------------------------------------------------------- */
.rooms { background: var(--paper-2); }
.room-rail {
  display: flex; gap: var(--s-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--pad);
  padding-inline: var(--pad);
  margin-inline: calc(var(--pad) * -1);
  padding-bottom: var(--s-3);
  scrollbar-width: thin;
}
.room {
  flex: 0 0 82vw;
  scroll-snap-align: start;
  display: grid; gap: var(--s-4);
  align-content: start;
}
.room-shot {
  position: relative; overflow: hidden;
  border-radius: var(--r-img);
  aspect-ratio: 4 / 3;
  background: var(--line-2);
}
.room-shot img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 260ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .room:hover .room-shot img { transform: scale(1.035); }
}
.room-name { font-family: var(--serif); font-size: 1.5rem; font-weight: 400;
  font-variation-settings: "opsz" 26; line-height: 1.15; letter-spacing: -0.015em; }
.room-note { font-size: var(--t-sm); color: var(--ink-2); }
.room-meta {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}
.room-rate { font-weight: 500; font-variant-numeric: tabular-nums; }
.room-rate small { display: block; font-size: var(--t-xs); font-weight: 400; color: var(--ink-3); }
.room-sleeps { font-size: var(--t-xs); color: var(--ink-3); margin-left: auto; }
.room-feats { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.room-feats li {
  font-size: var(--t-xs); color: var(--ink-2);
  padding: 0.2rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 999px;
}

@media (min-width: 48rem) {
  .room-rail {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: clamp(2rem, 4vw, 3.5rem) clamp(1.5rem, 3vw, 3rem);
    overflow: visible; padding-inline: 0; margin-inline: auto;
  }
  .room { flex: none; }
  /* the offset that keeps the pair from reading as a table */
  .room:nth-child(even) { margin-top: clamp(1.5rem, 4vw, 3.5rem); }
  .room:nth-child(3n) .room-shot { aspect-ratio: 5 / 4; }
}

/* ---- the house (varied grid) ------------------------------------ */
.house { background: var(--paper); }
.house-grid { display: grid; gap: var(--s-4); }
.h-cell { display: grid; gap: var(--s-3); align-content: start; grid-template-rows: auto auto 1fr; }
.h-shot { overflow: hidden; border-radius: var(--r-img); background: var(--line-2); aspect-ratio: 3 / 2; }
.h-shot img { width: 100%; height: 100%; object-fit: cover; }
.h-title { font-weight: 600; font-size: var(--t-body); }
.h-body { font-size: var(--t-sm); color: var(--ink-2); max-width: 44ch; }

@media (min-width: 39rem) {
  .house-grid { grid-template-columns: 1fr 1fr; gap: clamp(1.5rem, 3vw, 2.5rem); }
  .h-cell:nth-child(4n+3) .h-shot,
  .h-cell:nth-child(4n+4) .h-shot { aspect-ratio: 4 / 5; }
}
@media (min-width: 64rem) {
  /* a repeating three-row figure: wide, narrow, narrow, wide. it adds up
     to whole rows every six cells and dense flow closes any tail, so the
     grid holds whatever number of facilities the owner ends up with. */
  .house-grid { grid-template-columns: repeat(3, 1fr); grid-auto-flow: dense; }
  .h-cell:nth-child(6n+1), .h-cell:nth-child(6n+4), .h-cell:nth-child(6n+6) { grid-column: span 2; }
  .h-cell:nth-child(6n+1) .h-shot, .h-cell:nth-child(6n+4) .h-shot, .h-cell:nth-child(6n+6) .h-shot { aspect-ratio: 16 / 9; }
  .h-cell:nth-child(6n+2) .h-shot, .h-cell:nth-child(6n+3) .h-shot, .h-cell:nth-child(6n+5) .h-shot { aspect-ratio: 4 / 5; }
}

/* ---- gallery ----------------------------------------------------- */
.gallery { padding-block: var(--sec) 0; background: var(--paper-2); overflow: clip; }
.gal-head { display: grid; gap: var(--s-2); margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.gal-hint { font-size: var(--t-xs); color: var(--ink-3); }

.gal-pin {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding: 0 var(--pad) var(--sec);
  scrollbar-width: none;
}
.gal-pin::-webkit-scrollbar { display: none; }
.gal-track { display: flex; gap: var(--s-4); }
.gal-item {
  position: relative;
  flex: 0 0 auto;
  scroll-snap-align: center;
  height: 46svh;
  min-height: 260px;
  max-width: calc(100vw - var(--pad) * 2);
  overflow: hidden;
  border-radius: var(--r-img);
  background: var(--line-2);
  transition: transform 180ms var(--ease-out);
}
.gal-item img { width: 100%; height: 100%; object-fit: cover; }
.gal-item:nth-child(3n+1) { aspect-ratio: 3 / 2; }
.gal-item:nth-child(3n+2) { aspect-ratio: 4 / 5; }
.gal-item:nth-child(3n+3) { aspect-ratio: 1 / 1; }
@media (hover: hover) and (pointer: fine) {
  .gal-item:hover { transform: translateY(-4px); }
}

@media (min-width: 64rem) {
  .gal-item { height: 58svh; }
  /* when the pan is driven by scroll the strip stops being a scroller, and
     the whole section becomes exactly one viewport tall so GSAP has a
     sane thing to pin */
  .gallery.is-pinned {
    min-height: 100svh; padding-block: 0;
    display: flex; flex-direction: column; justify-content: center;
    gap: clamp(1.5rem, 3vw, 2.5rem);
  }
  .gallery.is-pinned .gal-head { margin-bottom: 0; }
  /* clip, not hidden: a hidden overflow is still a scroll container, and
     focusing a photograph would scroll the strip out from under the pan */
  .gallery.is-pinned .gal-pin {
    overflow: clip; padding-bottom: 0; min-height: 0; align-items: center;
    scroll-snap-type: none;
  }
}

/* ---- reviews ----------------------------------------------------- */
.says { background: var(--paper); }
.says-in { display: grid; gap: clamp(1.5rem, 3vw, 2.25rem); }
.quote { display: grid; }
.quote p {
  grid-area: 1 / 1;
  font-family: var(--serif);
  font-size: var(--t-quote);
  font-weight: 300;
  font-variation-settings: "opsz" 36;
  line-height: 1.28;
  letter-spacing: -0.015em;
  max-width: 46ch;
  text-wrap: pretty;
  opacity: 0;
  /* hidden from assistive technology too, so the section reads as one
     quote rather than three stacked on each other */
  visibility: hidden;
  transition: opacity 420ms var(--ease-out), visibility 420ms;
}
.quote p.is-on { opacity: 1; visibility: visible; }
.says-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--line);
}
.quote-by { font-size: var(--t-sm); color: var(--ink-2); }
.quote-by b { font-weight: 600; color: var(--ink); }
.says-nav { display: flex; gap: var(--s-1); }

/* ---- nearby ------------------------------------------------------ */
.nearby { background: var(--paper-2); }
.near-list { display: grid; }
.near-list li {
  display: grid; gap: var(--s-1) var(--s-5);
  grid-template-columns: 1fr auto;
  padding-block: clamp(1.25rem, 2.5vw, 1.75rem);
}
.near-list li + li { border-top: 1px solid var(--line); }
.near-title { font-family: var(--serif); font-size: 1.375rem; font-weight: 400;
  font-variation-settings: "opsz" 24; line-height: 1.2; }
.near-dist {
  grid-row: 1; grid-column: 2;
  font-size: var(--t-sm); font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  white-space: nowrap;
}
.near-body { grid-column: 1 / -1; font-size: var(--t-sm); color: var(--ink-2); max-width: 58ch; }
@media (min-width: 48rem) {
  .near-list li { grid-template-columns: minmax(0, 16rem) minmax(0, 1fr) auto; align-items: baseline; }
  .near-body { grid-column: 2; grid-row: 1; }
  .near-dist { grid-column: 3; }
}

/* ---- panels and fields ------------------------------------------ */
.panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: clamp(1.25rem, 3vw, 2rem);
  display: grid; gap: var(--s-4);
}
.field { display: grid; gap: var(--s-2); min-width: 0; }
.field label { font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); }
.field .opt { font-weight: 400; color: var(--ink-3); }
.field input, .field select, .field textarea {
  width: 100%;
  min-height: 46px;
  padding: 0.6rem 0.75rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color 150ms var(--ease-out), box-shadow 150ms var(--ease-out), background-color 150ms var(--ease-out);
}
.field textarea { min-height: 96px; resize: vertical; line-height: 1.5; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.field.is-bad input, .field.is-bad textarea, .field.is-bad select {
  border-color: oklch(0.52 0.16 25);
  background: oklch(0.975 0.018 25);
}
.field-note { font-size: var(--t-xs); color: oklch(0.46 0.16 25); }
.field-row { display: grid; gap: var(--s-4); }
@media (min-width: 34rem) { .field-row { grid-template-columns: 1fr 1fr; } }

.consent {
  display: grid; grid-template-columns: auto 1fr; gap: var(--s-3);
  align-items: start;
  font-size: var(--t-sm); color: var(--ink-2);
}
.consent input { width: 20px; height: 20px; margin-top: 2px; accent-color: var(--accent); }

.more { border-top: 1px solid var(--line-2); padding-top: var(--s-4); }
.more summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  min-height: 44px;
  font-size: var(--t-sm); font-weight: 500;
  cursor: pointer;
  list-style: none;
}
.more summary::-webkit-details-marker { display: none; }
.more summary svg { transition: transform 200ms var(--ease-out); flex: none; }
.more[open] summary svg { transform: rotate(180deg); }
.more-body { display: grid; gap: var(--s-4); padding-top: var(--s-4); }

/* ---- booking ----------------------------------------------------- */
.book { background: var(--paper); }
.book-head { margin-bottom: clamp(2rem, 4vw, 3rem); display: grid; gap: var(--s-3); }
.book-grid { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); align-items: start; }

.stay-panel {
  display: grid; gap: var(--s-4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: clamp(1.25rem, 3vw, 1.75rem);
}
.stay-chips { display: grid; gap: var(--s-2); }
@media (min-width: 26rem) {
  .stay-chips { grid-template-columns: 1fr auto 1fr; align-items: center; }
}
.chip {
  display: grid; gap: 2px; text-align: left;
  min-height: 66px;
  padding: var(--s-3);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color 150ms var(--ease-out), background-color 150ms var(--ease-out), transform 120ms var(--ease-out);
}
.chip:active { transform: scale(0.985); }
.chip-label {
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--ink-3);
}
.chip-value { font-size: var(--t-sm); color: var(--ink-3); }
.chip.is-set { border-color: var(--accent-line); background: var(--card); }
.chip.is-set .chip-value { color: var(--ink); font-weight: 500; }
@media (hover: hover) and (pointer: fine) {
  .chip:hover { border-color: var(--accent); background: var(--accent-tint); }
}
.chip-nights {
  font-size: var(--t-xs); color: var(--ink-3);
  padding-inline: var(--s-2); min-width: 3.5rem;
}
@media (min-width: 26rem) { .chip-nights { text-align: center; } }
.chip-nights:empty { min-width: 0; padding: 0; }
.stay-guests { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }

.book-flow { display: grid; gap: var(--s-4); }
.offers { display: grid; gap: var(--s-3); }
.offer {
  display: grid; grid-template-columns: 5.5rem 1fr;
  gap: var(--s-4);
  padding: var(--s-3);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r);
  transition: border-color 160ms var(--ease-out), transform 160ms var(--ease-out);
}
.offer.is-picked { border-color: var(--accent); background: var(--accent-tint); }
.offer-shot { overflow: hidden; border-radius: var(--r-img); aspect-ratio: 1; background: var(--line-2); }
.offer-shot img { width: 100%; height: 100%; object-fit: cover; }
.offer-in { display: grid; gap: var(--s-2); align-content: start; }
.offer-name { font-weight: 600; }
.offer-note { font-size: var(--t-xs); color: var(--ink-2); }
.offer-figs {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-4);
  font-size: var(--t-sm); font-variant-numeric: tabular-nums;
}
.offer-total { font-weight: 600; }
.offer-figs span { color: var(--ink-3); font-size: var(--t-xs); }
@media (min-width: 34rem) { .offer { grid-template-columns: 7.5rem 1fr; } }

.notice {
  padding: var(--s-4);
  background: var(--accent-tint);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  color: var(--ink);
  display: grid; gap: var(--s-3);
}
.notice a { color: var(--accent-dk); font-weight: 500; }
.skel { display: grid; gap: var(--s-3); }
.skel i {
  position: relative; display: block; height: 76px; border-radius: var(--r);
  background: var(--line-2); overflow: hidden;
}
.skel i::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--paper), transparent);
  transform: translateX(-100%);
  animation: shim 1.3s linear infinite;
}
@keyframes shim { to { transform: translateX(100%); } }
.looking { font-size: var(--t-sm); color: var(--ink-2); }

.summary { display: grid; gap: var(--s-2); padding: var(--s-4); background: var(--paper-2); border-radius: var(--r-sm); }
.summary div { display: flex; justify-content: space-between; gap: var(--s-4); font-size: var(--t-sm); }
.summary div b { font-variant-numeric: tabular-nums; }
.summary .is-total { padding-top: var(--s-2); border-top: 1px solid var(--line); font-weight: 600; }

.done { display: grid; gap: var(--s-4); text-align: left; }
.done-ref {
  font-family: var(--serif); font-size: 2rem; font-weight: 400;
  font-variation-settings: "opsz" 32; color: var(--accent);
  letter-spacing: 0.01em;
}

@media (min-width: 56rem) {
  .book-grid { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); }
  .stay-panel { position: sticky; top: 92px; }
}

/* ---- contact ----------------------------------------------------- */
.contact { background: var(--paper-2); }
.contact-grid { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
.con-list { display: grid; gap: var(--s-4); margin-top: var(--s-5); }
.con-list > div { display: grid; gap: var(--s-1); padding-bottom: var(--s-4); border-bottom: 1px solid var(--line); }
.con-list > div:last-child { border-bottom: 0; }
.con-list dt { font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.con-list dd { font-size: var(--t-body); }
.con-list a { color: var(--accent-dk); text-decoration-thickness: 1px; text-underline-offset: 3px; }
@media (min-width: 56rem) { .contact-grid { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr); } }

/* ---- footer ------------------------------------------------------ */
.foot { background: var(--night); color: oklch(0.94 0.008 100); padding: var(--sec) var(--pad) var(--s-6); }
.foot-in { max-width: var(--wrap); margin-inline: auto; display: grid; gap: clamp(2.5rem, 6vw, 5rem); }
.foot-line {
  font-family: var(--serif);
  font-size: clamp(2.5rem, 9vw, 6rem);
  font-weight: 300; font-variation-settings: "opsz" 72;
  line-height: 1; letter-spacing: -0.03em;
}
.foot-strip {
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5);
  justify-content: space-between; align-items: baseline;
  padding-top: var(--s-4);
  border-top: 1px solid oklch(0.94 0.008 100 / 0.18);
  font-size: var(--t-xs);
  color: oklch(0.94 0.008 100 / 0.72);
}
.foot-strip nav { display: flex; gap: var(--s-5); flex-wrap: wrap; }
.foot-strip a { display: inline-flex; align-items: center; min-height: 44px; text-decoration: none; }
/* A telephone number must never break across lines. Three links in a row do
   not fit a 375px phone, and the row was squeezing "054 338 0024" into three
   stacked pieces while "Management" ran off the edge. */
.foot-strip nav a { white-space: nowrap; }
@media (max-width: 34rem) {
  .foot-strip { flex-direction: column; align-items: flex-start; gap: var(--s-2); }
  .foot-strip nav { flex-direction: column; gap: 0; width: 100%; }
  /* the social marks stay a row, and stay on the left with everything else */
  .foot-strip nav.foot-social { flex-direction: row; justify-content: flex-start; }
}
@media (hover: hover) and (pointer: fine) {
  .foot-strip a:hover { text-decoration: underline; text-underline-offset: 3px; }
}

/* ---- the calendar dialog ---------------------------------------- */
.cal-dlg {
  border: 0; padding: 0;
  background: transparent;
  color: var(--ink);
  max-width: 100%; max-height: 100%;
  width: 100%;
  margin: auto auto 0;              /* a sheet on a phone */
  opacity: 0; transform: translateY(100%);
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-drawer);
}
.cal-dlg.is-open {
  opacity: 1; transform: none;
  transition: opacity 300ms var(--ease-out), transform 320ms var(--ease-drawer);
}
.cal-dlg::backdrop { background: oklch(0.22 0.02 168 / 0); transition: background-color 200ms var(--ease-out); }
.cal-dlg.is-open::backdrop { background: oklch(0.22 0.02 168 / 0.5); }

.cal-sheet {
  display: grid; gap: var(--s-4);
  background: var(--paper);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding: var(--s-5) var(--s-4) calc(var(--s-5) + env(safe-area-inset-bottom));
  max-height: 92svh; overflow-y: auto;
}
.cal-top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); }
.cal-h { font-family: var(--serif); font-size: 1.5rem; font-weight: 400; font-variation-settings: "opsz" 26; letter-spacing: -0.015em; }
.cal-x { margin-right: calc(var(--s-2) * -1); }
.cal-step { font-size: var(--t-sm); color: var(--ink-2); }
.cal-nav { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.cal-months { font-size: var(--t-sm); font-weight: 500; text-align: center; flex: 1; }

.cal-body { display: grid; gap: var(--s-6); }
.cal-mo { display: grid; gap: var(--s-3); }
.cal-mo-name { font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); text-align: center; }
.cal-dow, .cal-days { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal-dow span { font-size: 0.6875rem; color: var(--ink-3); text-align: center; padding-bottom: var(--s-1); }
.cal-days { gap: 2px 0; }

.cal-day {
  position: relative;
  display: grid; place-items: center;
  min-height: 44px;
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
  border-radius: var(--r-sm);
  transition: background-color 120ms var(--ease-out), color 120ms var(--ease-out);
}
.cal-day:focus-visible { outline-offset: -2px; }
.cal-day:disabled { color: oklch(0.78 0.008 100); cursor: not-allowed; }
.cal-day.is-blank { pointer-events: none; }
@media (hover: hover) and (pointer: fine) {
  /* Never hover a day that is already an end of the stay. The tint is almost
     white and an end cap's ink is white, so hovering the day just chosen
     rubbed the number out. On a one night stay the cursor is left sitting on
     the departure, so the whole choice looked like it had not registered, and
     tapping again to insist moved the arrival instead. */
  .cal-day:not(:disabled):not(.is-end):hover { background: var(--accent-tint); }
}
.cal-day.in-range { background: var(--accent-tint); border-radius: 0; }
.cal-day.is-end {
  background: var(--accent); color: oklch(0.99 0.004 90); font-weight: 600;
}
.cal-day.is-start { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.cal-day.is-finish { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.cal-day.is-only { border-radius: var(--r-sm); }
.cal-day.is-today::after {
  content: ""; position: absolute; bottom: 6px;
  width: 3px; height: 3px; border-radius: 999px; background: currentColor;
}
.cal-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--line);
  position: sticky; bottom: 0; background: var(--paper);
}
.cal-foot .btn-solid { min-width: 11rem; }

@media (min-width: 47rem) {
  .cal-dlg {
    width: min(44rem, calc(100vw - 3rem));
    margin: auto;
    transform: translateY(10px) scale(0.99);
    transition: opacity 150ms var(--ease-out), transform 150ms var(--ease-out);
  }
  .cal-dlg.is-open { transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out); }
  .cal-sheet { border-radius: var(--r-lg); padding: var(--s-5); max-height: 88svh; }
  .cal-body { grid-template-columns: 1fr 1fr; }
}

/* ---- lightbox ---------------------------------------------------- */
.lb {
  border: 0; padding: 0; background: transparent;
  width: 100%; height: 100%; max-width: 100%; max-height: 100%;
  margin: 0;
  place-items: center;
  opacity: 0; transition: opacity 160ms var(--ease-out);
}
.lb[open] { display: grid; }
.lb.is-open { opacity: 1; transition: opacity 220ms var(--ease-out); }
.lb::backdrop { background: oklch(0.18 0.018 168 / 0.94); }
.lb-fig { display: grid; gap: var(--s-4); padding: var(--s-5); justify-items: center; }
.lb-fig img {
  max-width: min(92vw, 78rem); max-height: 78svh;
  width: auto; border-radius: var(--r-img);
  transform: scale(0.985); opacity: 0;
  transition: transform 260ms var(--ease-out), opacity 260ms var(--ease-out);
}
.lb.is-open .lb-fig img { transform: none; opacity: 1; }
.lb-fig figcaption { font-size: var(--t-sm); color: oklch(0.9 0.008 100 / 0.8); text-align: center; }
.lb .icon-btn { color: oklch(0.95 0.006 100); }
@media (hover: hover) and (pointer: fine) {
  .lb .icon-btn:hover { background: oklch(0.95 0.006 100 / 0.14); color: oklch(0.99 0.004 90); }
}
.lb-x { position: fixed; top: var(--s-4); right: var(--s-4); }
.lb-arrow { position: fixed; top: 50%; transform: translateY(-50%); width: 52px; height: 52px; }
.lb-prev { left: var(--s-2); }
.lb-next { right: var(--s-2); }
.lb-arrow:active { transform: translateY(-50%) scale(0.94); }
@media (min-width: 48rem) { .lb-prev { left: var(--s-5); } .lb-next { right: var(--s-5); } }

/* ---- toast ------------------------------------------------------- */
.toast {
  position: fixed; z-index: var(--z-toast);
  left: 50%; bottom: calc(var(--s-5) + env(safe-area-inset-bottom));
  transform: translate(-50%, 140%);
  max-width: min(30rem, calc(100vw - 2rem));
  padding: 0.85rem 1.1rem;
  background: var(--night); color: oklch(0.96 0.006 100);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  box-shadow: var(--lift-2);
  transition: transform 260ms var(--ease-out), opacity 200ms var(--ease-out);
  opacity: 0;
}
.toast.is-on { transform: translate(-50%, 0); opacity: 1; }
.toast.is-bad { background: oklch(0.36 0.13 25); }

.offline {
  margin: 0; padding: calc(64px + var(--s-4)) var(--pad) var(--s-4);
  background: var(--accent-tint); color: var(--ink);
  font-size: var(--t-sm); text-align: center;
}
.offline a { color: var(--accent-dk); font-weight: 500; }

/* ---- reveal on approach ----------------------------------------- */
[data-reveal] { opacity: 0; transform: translateY(16px); }
[data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity 620ms var(--ease-out) var(--d, 0ms), transform 620ms var(--ease-out) var(--d, 0ms);
}

/* ---- reduced motion --------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .hero-media img, .hero-media img.is-settled { transform: none; }
  .hero-title .mask > span { transform: none; }
  .hero-lede, .searchbar { opacity: 1; transform: none; }
  [data-reveal] { opacity: 1; transform: none; }
  .cal-dlg { transform: none; }
  .lb-fig img { transform: none; opacity: 1; }
  .quote p { transition: none; }
}

/* ---- the slogan over the hero ------------------------------------ */
/* The hero sits on a photograph, so the accent ink the kicker uses
   elsewhere would not hold its contrast. Light ink, same scale. */
.hero-kicker {
  color: oklch(0.97 0.01 90);
  margin-bottom: var(--s-3);
  text-shadow: 0 1px 12px oklch(0.22 0.03 200 / 0.5);
}

/* ---- where a review came from ------------------------------------ */
.quote-src { color: var(--ink-3); }

/* ---- social marks in the footer ---------------------------------- */
.foot-social { display: flex; gap: var(--s-4); }
.foot-social a {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
  color: inherit; text-decoration: none;
}
.foot-social svg { display: block; }
@media (hover: hover) and (pointer: fine) {
  .foot-social a:hover { color: oklch(0.97 0.01 90); }
}

/* ---- the logo in the header -------------------------------------- */
/* The lockup is a stacked drawing, so it needs height to stay legible.
   60px keeps the word GUESTHOUSE readable without growing the header. */
.brand-logo { height: 60px; width: auto; }
@media (max-width: 34rem) { .brand-logo { height: 46px; } }
/* Dark ink is the default because the hero sky is pale. If the owner ever
   loads a dark photograph, site.js adds .on-dark and the black artwork would
   disappear into it, so it goes light along with the rest of the header. */
.head.on-dark .brand-logo { filter: brightness(0) invert(1); }

/* ---- who made it ------------------------------------------------- */
.foot-credit { font-size: var(--t-xs); color: oklch(0.94 0.008 100 / 0.6); }
.foot-credit a { color: oklch(0.94 0.008 100 / 0.85); text-decoration: none; border-bottom: 1px solid oklch(0.94 0.008 100 / 0.3); }
@media (hover: hover) and (pointer: fine) {
  .foot-credit a:hover { color: oklch(0.97 0.01 90); }
}
