:root {
  /* Warm 38° axis, but saturation is kept low on the mid-tones. At mid lightness
     a given saturation shows far more colour cast than it does near-white — so
     matching the paper's saturation would make the text read gold. These are
     tuned by R-B channel spread instead: bg is 5, text 4-10. Reads as grey with
     warmth in it, not as a colour. */
  --bg:    #f2f0ed;  /* L 94% — spread  5 */
  --ink:   #2b2a27;  /* L 16% — spread  4 — 12.6:1 on bg (AAA) */
  --muted: #68655f;  /* L 39% — spread  9 —  5.1:1 on bg (AA)  */
  --muted-soft: #75716b; /* L 44% — spread 10 — 4.3:1, a step fainter */
  --rule:  #dcd8d0;  /* L 84% — hairlines only */
  --hairline: #eae8e3; /* L 90.5% — 1.08:1 on bg, barely-there divider */
  --sidebar-w: 250px;
  --pad: 28px;      /* sidebar left/right */
  --pad-y: 64px;    /* sidebar top/bottom — deliberately generous */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  background: var(--ink); color: var(--bg); padding: 10px 14px;
}
.skip:focus { left: 8px; top: 8px; }

/* ---------- sidebar ---------- */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: var(--sidebar-w);
  padding: var(--pad-y) var(--pad);
  display: flex;
  flex-direction: column;
  /* logo + identity sit at the top in normal flow; .nav and .social are pulled
     out of flow below and pinned independently. */
  border-right: 1px solid var(--hairline);
  background: var(--bg);
  z-index: 10;
}

.mark { display: block; width: 34px; margin: 0 auto; }
.mark img { width: 100%; height: auto; display: block; }

.menu-toggle {
  display: none;
  position: absolute; top: var(--pad); right: var(--pad);
  background: none; border: 0; padding: 4px;
  font: inherit; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink); cursor: pointer;
}

.sidebar-body { margin-top: auto; display: contents; }

.identity { margin-top: 28px; text-align: center; }
/* Even vertical rhythm across the three identity lines. The wordmark sets at a
   smaller size than the body lines, so it gets a nudge to equalize baselines. */
.identity p { margin: 0 0 4px; }
/* margin-left offsets the trailing letter-space after the final F, which
   text-align:center would otherwise count as content and shift the glyphs left. */
.identity .name { margin-bottom: 5px; margin-left: .16em; }
.identity .tagline { margin-bottom: 0; }
.name {
  font-weight: 500;
  letter-spacing: .16em;
  font-size: 12px;
  white-space: nowrap; /* wordmark must never break across lines */
}
.tagline { color: var(--muted-soft); }
.tagline span { display: block; }
.email a { border-bottom: 1px solid transparent; }
.email a:hover { border-bottom-color: var(--muted); }

/* pinned to the true vertical centre of the page, independent of how tall the
   identity block above it happens to be */
.nav {
  position: absolute;
  top: 50%;
  left: var(--pad); right: var(--pad);
  transform: translateY(-50%);
  margin: 0;
  text-align: center;
}
.nav ul { list-style: none; margin: 0; padding: 0; }
.nav li { margin: 0 0 9px; }
.nav a {
  color: var(--muted);
  transition: color .15s ease;
}
.nav a:hover { color: var(--ink); }
.nav a[aria-current="page"] { color: var(--ink); font-weight: 500; }

.social {
  list-style: none; padding: 0;
  /* auto top margin pushes the row to the bottom of the sidebar flex column */
  /* out of flow so the centered group above is centred on the page, not on the
     leftover space above the icons */
  position: absolute;
  left: var(--pad); right: var(--pad); bottom: var(--pad-y);
  margin: 0;
  display: flex; gap: 10px;
  justify-content: center;
}
.social a {
  display: grid; place-items: center;
  /* box stays larger than the glyph to keep a comfortable tap target */
  width: 26px; height: 26px;
  margin: -3px;
  color: var(--muted);
  transition: color .15s ease;
}
.social a:hover { color: var(--ink); }
.social svg { width: 20px; height: 20px; }

/* ---------- stage ---------- */

.stage {
  margin-left: var(--sidebar-w);
  min-height: 100%;
  outline: none;
  /* section-to-section cross-fade; FADE_MS in main.js must match */
  opacity: 1;
  transition: opacity .22s ease;
}
.stage.is-fading { opacity: 0; }

/* gallery */

.gallery {
  position: relative;
  height: 100vh;
  display: grid;
  place-items: center;
  /* side gutters reserve a lane for the fixed-position arrows */
  padding: 40px 100px;
}

.slides {
  position: relative;
  width: 100%; height: 100%;
  display: grid; place-items: center;
}

.slide {
  position: absolute;
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  opacity: 0;
  transition: opacity .5s ease;
  pointer-events: none;
  will-change: opacity;
}
.slide.is-active { opacity: 1; pointer-events: auto; }

/* Direction classes are kept so the JS can stay direction-aware, but they carry
   no travel — every change is a straight cross-fade. */
.slide.from-right, .slide.to-right,
.slide.from-left,  .slide.to-left { opacity: 0; }

.arrow {
  position: absolute; top: 50%;
  transform: translateY(-50%);
  /* faint disc behind the chevron — reads as a target without drawing a button */
  background: rgba(43, 42, 39, .045);
  border: 0; border-radius: 50%;
  width: 54px; height: 54px;
  padding: 0 0 4px;              /* optical nudge: chevron glyphs sit low */
  display: grid; place-items: center;
  color: var(--muted);
  font-size: 34px; line-height: 1;
  cursor: pointer;
  opacity: .85;
  transition: background .2s ease, color .2s ease;
}
.arrow:hover, .arrow:focus-visible {
  background: rgba(43, 42, 39, .085);
  color: var(--ink);
}
/* Fixed spot in the gutter, the same on every slide. The gallery's side padding
   is wide enough that no photo can reach them, so they never overlap the image
   and never jump between a wide frame and a narrow one. */
.arrow--prev { left: 22px; }
.arrow--next { right: 22px; }

/* text pages */

.page {
  /* block is centred in the stage both ways; the prose inside stays left-aligned
     so line starts remain predictable to read down */
  max-width: 620px;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 40px;
}
.page-title {
  font-size: 26px; font-weight: 400;
  margin: 0 0 34px;
  display: inline-block;
}
.page p { margin: 0 0 18px; max-width: 55ch; }
/* trailing margin would count as content and throw the vertical centring off */
.page > :last-child { margin-bottom: 0; }

/* ---------- booking form ---------- */

.form { margin: 26px 0 0; max-width: 420px; }

.hp { position: absolute; left: -9999px; }   /* honeypot, hidden from people */

/* Proximity: the gap BETWEEN fields must exceed the gap inside one, or each
   underline reads as belonging to the label below it rather than its own. */
/* .page p sets an 18px bottom margin and outranks a bare .field selector,
   so this needs the extra specificity to win. */
.page .field { margin: 0 0 38px; }
.field label {
  display: block;
  margin-bottom: 1px;
  color: var(--muted);
  line-height: 1.4;
}
.field input,
.field textarea,
.field select {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  padding: 2px 0 5px;
  border-radius: 0;              /* iOS adds one otherwise */
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .15s ease;
}
.field textarea { resize: vertical; line-height: 1.55; }
.field input:focus,
.field textarea:focus,
.field select:focus {
  outline: none;
  border-bottom-color: var(--ink);
}

/* chevron drawn in, since appearance:none removes the native one */
.field select {
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: right 6px center, right 1px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 20px;
  cursor: pointer;
}
/* the unchosen placeholder reads as muted, like a real placeholder */
.field select:invalid { color: var(--muted-soft); }

.form button {
  font: inherit;
  color: var(--bg);
  background: var(--ink);
  border: 0;
  padding: 10px 22px;
  /* sits apart from the last field, not attached to it */
  margin-top: 4px;
  cursor: pointer;
  transition: opacity .15s ease;
}
.form button:hover { opacity: .85; }
.form button:disabled { opacity: .45; cursor: default; }

/* status sits above the button; collapses entirely when there's nothing to say
   so it doesn't reserve dead space in the resting state */
.form-status { margin: 4px 0 26px; color: var(--muted); }
.form-status:empty { display: none; }
.form-status.is-ok  { color: #2f6b45; }   /* 5.6:1 on bg */
.form-status.is-err { color: #8c3a2b; }

.entry { margin: 0 0 22px; }
.entry-title { font-weight: 600; }
.entry-meta { color: var(--ink); }
.entry-meta em { color: var(--muted); }
.entry-year { color: var(--ink); }

/* ---------- responsive ---------- */

/* ---------- mobile ----------
   The sidebar becomes a sticky header: mark on top, categories in a row beneath
   it. No hidden menu — every section is one tap. Icons pin to the bottom of the
   viewport, and the chevrons sit as a centred pair below the photo rather than
   hanging off the screen edges. */

@media (max-width: 760px) {
  :root {
    --m-header: 58px;   /* sticky header height */
    /* must match the rendered .social height below (padding + icon + border),
       or the gallery centres against a box that runs behind the bar */
    --m-icons: 73px;
  }

  body { padding-bottom: var(--m-icons); }

  .sidebar {
    position: sticky;
    top: 0;
    inset: auto;
    width: 100%;
    display: block;
    height: var(--m-header);
    padding: 14px 16px;
    border-right: 0;
    border-bottom: 1px solid var(--hairline);
    z-index: 10;
  }

  /* contact icons pinned to the bottom edge, with generous breathing room */
  .social {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    margin: 0;
    padding: 26px 16px;
    gap: 26px;
    background: var(--bg);
    border-top: 1px solid var(--hairline);
    z-index: 10;
  }

  .sidebar { padding: 14px 16px; }
  .mark { width: 26px; }
  .identity { display: none; }

  /* ----- hamburger: two bars that cross into an X ----- */
  .menu-toggle {
    display: grid;
    place-items: center;
    position: absolute;
    top: 8px; right: 10px;
    width: 44px; height: 44px;   /* tap target */
    padding: 0;
    z-index: 30;                 /* stays clickable above the open overlay */
  }
  .menu-toggle .bar {
    position: absolute;
    width: 22px; height: 1.5px;
    background: var(--ink);
    transition: transform .28s cubic-bezier(.4, 0, .2, 1);
  }
  .menu-toggle .bar:nth-child(1) { transform: translateY(-3.5px); }
  .menu-toggle .bar:nth-child(2) { transform: translateY(3.5px); }
  .sidebar.is-open .menu-toggle .bar:nth-child(1) { transform: rotate(45deg); }
  .sidebar.is-open .menu-toggle .bar:nth-child(2) { transform: rotate(-45deg); }

  /* ----- full-page menu -----
     .sidebar-body is display:contents so its children position independently:
     the contact bar stays pinned at the bottom while .nav becomes the overlay. */
  .sidebar-body { display: contents; }

  .nav { display: none; }
  .sidebar.is-open .nav {
    display: grid;
    place-items: center;
    position: fixed;
    inset: 0;
    z-index: 20;
    transform: none;
    left: 0; right: 0;
    margin: 0;
    background: var(--bg);
  }
  .sidebar.is-open .nav ul { display: block; }
  .sidebar.is-open .nav li { margin: 0 0 26px; }
  .sidebar.is-open .nav li:last-child { margin-bottom: 0; }
  .sidebar.is-open .nav a { font-size: 22px; }

  /* icons sit above the overlay so they stay reachable with the menu open */
  .social { z-index: 25; }

  /* ----- gallery: photo fills the space between header and icon bar ----- */
  .stage { margin-left: 0; }
  .gallery {
    /* dvh tracks the collapsing browser chrome; vh is the fallback */
    height: calc(100vh - var(--m-header) - var(--m-icons));
    height: calc(100dvh - var(--m-header) - var(--m-icons));
    min-height: 0;
    /* tight gutters: a portrait photo is width-constrained on a phone, so every
       pixel of width taken by the chevrons costs 1.5x that in height */
    padding: 10px 40px;
  }
  .slides { min-height: 0; height: 100%; }

  /* chevrons flank the photo, vertically centred on it. No disc here — they sit
     on the page background in the gutter, so there's nothing to separate from. */
  .arrow {
    font-size: 22px;
    width: 36px; height: 36px;
    top: 50%; bottom: auto;
    transform: translateY(-50%);
    background: none;
  }
  .arrow:hover, .arrow:focus-visible { background: none; }
  /* box is 36px wide in a 40px gutter, so it clears the photo edge */
  .arrow--prev { left: 2px; right: auto; }
  .arrow--next { right: 2px; left: auto; }

  .page { display: block; min-height: 0; padding: 24px 20px 32px; }

  /* iOS Safari zooms the viewport when a focused input is under 16px */
  .field input, .field textarea, .field select { font-size: 16px; }
  .form button { font-size: 15px; padding: 12px 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .slide { transition: opacity .15s ease; }
  .stage { transition: opacity .1s ease; }
}
