@import url('https://fonts.googleapis.com/css2?family=Archivo:wght@300;400;500;600&display=swap');

/* ─────────────────────────────────────────────────────────────
   Meadows at Mossy Creek — landing system

   The brand is black and white. Every other colour on the page
   is extracted from the photograph at runtime (see palette.js),
   so an autumn hero and a spring hero look different without
   anyone redesigning anything.

   --accent is the only variable colour. It never touches a CTA:
   the button is always --ink so it stays recognisable everywhere.
   ───────────────────────────────────────────────────────────── */
:root {
  --ground:      #fdfef9;   /* near-white, default page          */
  --ground-alt:  #edeade;   /* bone, alternating sections        */
  --ink:         #090e06;   /* green-black. Reads as black, but  */
                            /* sits with landscape photography   */
                            /* instead of punching a hole in it. */
  --accent:      #213c14;   /* fallback; overwritten from photo  */
  --on-accent:   #fdfef9;   /* type that sits on the accent field */
  --rule:        color-mix(in srgb, var(--ink) 16%, transparent);

  --measure: 34rem;
  --gut: clamp(1.5rem, 5vw, 5rem);
}

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

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: 'Archivo', system-ui, sans-serif;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

/* ── type ─────────────────────────────────────────────────────
   One family, extreme scale range. Drama comes from size, not
   from introducing more typefaces.                             */
h1, h2 {
  font-weight: 500;
  letter-spacing: -0.022em;
  line-height: 1.08;
  margin: 0;
}
h1 { font-size: clamp(2rem, 3.4vw, 3.15rem); }
h2 { font-size: clamp(1.75rem, 3vw, 2.75rem); }

.lede {
  max-width: var(--measure);
  font-size: 1.0625rem;
  color: color-mix(in srgb, var(--ink) 78%, transparent);
  margin: 1.25rem 0 0;
}

/* Tracked micro-capitals — the connective tissue of the whole page. */
.micro {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin: 0;
  color: color-mix(in srgb, var(--ink) 62%, transparent);
}
.micro--accent { color: var(--accent); }

/* Thin accent stripe down the left edge — the single piece of colour
   that is always on screen, taken from the hero photograph. */
.edge {
  position: fixed;
  left: 0; top: 0; bottom: 0;
  width: 6px;
  background: var(--accent);
  z-index: 10;
}

/* ── hero ─────────────────────────────────────────────────────
   Scroll-linked: the image contracts and the panel follows it left,
   so the page reads as one composition being scrubbed rather than a
   stack of sections. Progressive enhancement — without scroll-driven
   animation support this is simply a static split.                 */
.hero {
  display: grid;
  grid-template-columns: 54fr 46fr;
  min-height: 100svh;
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 901px) {
    .hero {
      animation: heroSplit linear both;
      animation-timeline: scroll();
      animation-range: 0 90svh;
    }
    @keyframes heroSplit {
      from { grid-template-columns: 54fr 46fr; }
      to   { grid-template-columns: 12fr 88fr; }
    }
  }
}

.hero__media {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--ground-alt);
}
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
}

/* Credit sits on the image in the same micro-caps as everything else. */
.credit {
  position: absolute;
  left: 1.25rem; bottom: 1.1rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.82);
  text-shadow: 0 1px 12px rgba(0,0,0,0.45);
}

.hero__panel {
  display: flex;
  flex-direction: column;
  padding: 2rem var(--gut) 3rem;
}

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 3.5rem;
}
.wordmark {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.hero__body { margin: auto 0; padding: 1rem 0 0; }
.hero__body h1 { margin-top: 0.85rem; }

/* ── form ─────────────────────────────────────────────────── */
.optin { margin-top: 2.5rem; max-width: 30rem; }

.field { margin-bottom: 1.1rem; }
.field label {
  display: block;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ink) 62%, transparent);
  margin-bottom: 0.4rem;
}
.field input {
  width: 100%;
  padding: 0.72rem 0;
  font: inherit;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;              /* no rounding anywhere on this page */
  transition: border-color 0.2s;
}
.field input:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

button[type="submit"], .btn {
  display: inline-block;
  width: 100%;
  margin-top: 0.75rem;
  padding: 1.05rem 2rem;
  font: inherit;
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ground);
  background: var(--ink);        /* always ink — never the accent */
  border: 0;
  border-radius: 0;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  transition: opacity 0.2s;
}
button[type="submit"]:hover, .btn:hover { opacity: 0.86; }

.btn { width: auto; padding-inline: 3rem; }

.consent {
  margin: 1rem 0 0;
  font-size: 0.75rem;
  line-height: 1.5;
  color: color-mix(in srgb, var(--ink) 55%, transparent);
}

/* ── stats ────────────────────────────────────────────────────
   The display moment. Mersi does this with 60m²; the venue has
   better numbers than that.                                    */
.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  padding: clamp(4rem, 9vw, 8rem) var(--gut);
  background: var(--ground-alt);
}
.stat { display: flex; flex-direction: column; gap: 0.65rem; }
.stat__n {
  font-size: clamp(2.75rem, 6vw, 5.5rem);
  font-weight: 300;
  letter-spacing: -0.045em;
  line-height: 0.85;
}
.stat__n em {
  font-style: normal;
  font-size: 0.26em;
  font-weight: 500;
  letter-spacing: 0.02em;
  margin-left: 0.15em;
}

/* ── ruled list ───────────────────────────────────────────────
   Label left, numeral right, hairline under every row. This is
   the direct replacement for the flat 13-bullet spec sheet.     */
.included { padding: clamp(4rem, 9vw, 8rem) var(--gut); }
.included__intro { max-width: var(--measure); margin-bottom: 2.75rem; }
.included__intro h2 { margin-top: 0.85rem; }
.included__intro--b { margin-top: 4.5rem; }

.ruled { list-style: none; margin: 0; padding: 0; counter-reset: r; }
.ruled li {
  counter-increment: r;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  padding: 1.15rem 0;
  border-top: 1px solid var(--rule);
  font-size: 1.0625rem;
}
.ruled li:last-child { border-bottom: 1px solid var(--rule); }
.ruled li::before {
  content: "◇";
  color: var(--accent);
  font-size: 0.7em;
  margin-right: 0.9rem;
}
.ruled li span { flex: 1; }
.ruled li::after {
  content: counter(r, decimal-leading-zero);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: color-mix(in srgb, var(--ink) 45%, transparent);
  font-variant-numeric: tabular-nums;
}
.ruled--quiet li { font-size: 0.9375rem; }

/* ── close ────────────────────────────────────────────────── */
.close {
  padding: clamp(5rem, 11vw, 10rem) var(--gut);
  background: var(--ground-alt);
}
.close h2 { margin: 0.9rem 0 2.25rem; }
.close__phone { margin-top: 1.5rem; }
.close__phone a { color: inherit; }

/* ── horizontal track ─────────────────────────────────────────
   The viewport is fixed and the track slides left as you scroll
   down. Lanes sit side by side in a row; each is moved by JS at
   its own rate. Nothing here scrolls vertically.               */
.viewport {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--ground);
}
.track {
  display: flex;
  align-items: stretch;
  height: 100%;
  width: max-content;
}
.runway { pointer-events: none; }   /* height set from track width in JS */

.lane {
  position: relative;
  flex: 0 0 auto;
  height: 100%;
  will-change: transform;
  transform: translate3d(0,0,0);
  backface-visibility: hidden;
}


/* ══ 1 · the colour half ══════════════════════════════════════
   A full half of the screen, not a strip. Mark top-left, a small
   double-framed thumbnail centred, place/scale above it, caption
   below, and the name set enormous at the bottom left.          */
.lane--cover {
  width: 50vw;
  background: var(--accent);
  transition: background-color 700ms ease;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 1.9rem clamp(2rem, 3.5vw, 3.5rem) clamp(2rem, 4vh, 3.25rem);
  /* the faint grain Mersi has over its colour field */
  background-image:
    radial-gradient(rgba(255,255,255,0.05) 0.5px, transparent 0.5px),
    radial-gradient(rgba(0,0,0,0.05) 0.5px, transparent 0.5px);
  background-size: 3px 3px, 4px 4px;
  background-position: 0 0, 1px 2px;
}
.lane--cover .mark {
  font-size: 1.0625rem; font-weight: 600; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--on-accent);
}

.cover__plate {
  place-self: center;
  width: min(19vw, 290px);
}
.plate__meta {
  display: flex; justify-content: space-between;
  margin-bottom: 0.85rem;
  font-size: 0.6875rem; font-weight: 600;
  letter-spacing: 0.1em; color: var(--on-accent);
}
/* the thin double border, in a darker tint of the field itself */
.plate__frame {
  margin: 0; padding: 5px;
  border: 1px solid color-mix(in srgb, var(--on-accent) 45%, transparent);
  outline: 1px solid color-mix(in srgb, var(--on-accent) 45%, transparent);
  outline-offset: 3px;
}
.plate__frame img { width: 100%; aspect-ratio: 1; object-fit: cover; }
/* the tagline — given a little more weight than a caption, since it is
   the line the whole page is built around */
.plate__caption {
  margin: 1.6rem 0 0; text-align: center;
  font-size: clamp(0.95rem, 1.15vw, 1.15rem);
  font-weight: 500; line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--on-accent);
}

.cover__name {
  margin: 0;
  align-self: end;
  font-size: clamp(3.5rem, 8.5vw, 10rem);
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 0.82;
  color: var(--on-accent);
}

/* ══ 2 · the photograph ══════════════════════════════════════ */
.lane--photo { width: 50vw; margin: 0; }
.lane--photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ══ 3 · the panel ═══════════════════════════════════════════ */
.lane--panel {
  width: 50vw;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(4rem, 13vh, 9rem) clamp(2rem, 4vw, 4.5rem) clamp(3rem, 8vh, 6rem);
}
.lane--panel .say { max-width: 25rem; margin: 0; }
.lane--panel .ruled { align-self: center; width: min(30rem, 84%); margin: 0; }
.lane--panel .ruled li { padding: 1.15rem 0; font-size: 0.9375rem; }
.lane--panel .numeral { margin: 0; }

/* ══ 4 · finale ══════════════════════════════════════════════ */
/* ══ 4 · finale ═══════════════════════════════════════════════
   Photography fills the lane; the form floats over it as a
   contained card — a horizontal band in the middle, not a column
   running top to bottom.                                        */
.lane--finale {
  position: relative;
  width: 100vw;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;                      /* photo meets photo, no seam */
}
.col { position: relative; overflow: hidden; }
/* Frames slide vertically, and the two columns run in opposite
   directions — the left enters from the top while the right enters
   from the bottom, so the pair never moves as one block. */
.col .cf {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
  transform: translateY(-100%);
  will-change: transform;
  backface-visibility: hidden;
  transition: none;
}
/* switched on by JS once the first frame is in place */
/* Slow and unhurried. A long ease-in-out with almost no acceleration
   at either end, so the frames drift rather than travel — the movement
   should be barely noticeable until you look at it. */
.is-ready .col .cf { transition: transform 3200ms cubic-bezier(0.4, 0, 0.15, 1); }
/* a layer being repositioned for reuse must not animate across the frame */
.col .cf.no-anim { transition: none !important; }
.col[data-col="1"] .cf { transform: translateY(100%); }

.col .cf.is-on { transform: translateY(0); }

/* the outgoing frame leaves the way the incoming one is arriving from */
.col .cf.is-out { transform: translateY(100%); }
.col[data-col="1"] .cf.is-out { transform: translateY(-100%); }

.finale__form {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  width: min(52vw, 760px);
  padding: clamp(1.5rem, 2vw, 2.1rem) clamp(1.8rem, 2.5vw, 2.6rem);
  background: var(--accent);
  color: var(--on-accent);
  transition: background-color 900ms ease;
  background-image:
    radial-gradient(rgba(255,255,255,0.05) 0.5px, transparent 0.5px),
    radial-gradient(rgba(0,0,0,0.05) 0.5px, transparent 0.5px);
  background-size: 3px 3px, 4px 4px;
}
.finale__form .micro { color: color-mix(in srgb, var(--on-accent) 72%, transparent); }
/* the tagline again, sitting under the label on the card */
.finale__form .tagline {
  margin: 0.55rem 0 0;
  font-size: clamp(1.1rem, 1.4vw, 1.4rem);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--on-accent);
}
.finale__form h2 {
  margin: 0.35rem 0 0;
  font-size: clamp(1.2rem, 1.6vw, 1.6rem);
  color: var(--on-accent);
}
.finale__form .say { display: none; }          /* the card stays terse */
/* the reason the guide exists, in the couple's language rather than
   a feature list */
.finale__form .pitch {
  margin: 0.85rem 0 0;
  max-width: 34rem;
  font-size: 0.875rem;
  line-height: 1.55;
  color: color-mix(in srgb, var(--on-accent) 78%, transparent);
}
/* the kicker gets its own line and a little more weight — it is the
   bit someone will remember */
.finale__form .pitch--kicker {
  margin-top: 0.7rem;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--on-accent);
}
.finale__form .optin { margin-top: 1.4rem; max-width: none; }

/* fields side by side so the card stays a horizontal band rather than
   a tall block — Mersi's is roughly 37% wide and 15% tall */
.finale__form .optin {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  align-items: end;
  gap: 0.2rem 1.1rem;
}
/* the source question spans two, the button takes the third — kept
   optional, since a forced answer is a worse answer */
.finale__form .field--wide { grid-column: span 2; }
.finale__form select {
  width: 100%;
  padding: 0.55rem 0;
  font: inherit;
  color: var(--on-accent);
  background: transparent;
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--on-accent) 38%, transparent);
  border-radius: 0;
  appearance: none;
  cursor: pointer;
}
.finale__form select:focus { outline: none; border-bottom-color: var(--on-accent); }
.finale__form select option { color: #090e06; }   /* native menu is light */
.finale__form .optin .consent { grid-column: 1 / -1; }

/* fields sit on the coloured card, so the rules invert */
.finale__form .field { margin-bottom: 0.7rem; }
.finale__form .field label { display: none; }
.finale__form .field input {
  color: var(--on-accent);
  border-bottom-color: color-mix(in srgb, var(--on-accent) 38%, transparent);
  padding: 0.55rem 0;
}
.finale__form .field input::placeholder {
  color: color-mix(in srgb, var(--on-accent) 60%, transparent);
}
.finale__form .field input:focus { border-bottom-color: var(--on-accent); }
.finale__form button[type="submit"] {
  margin-top: 0;
  width: auto;
  white-space: nowrap;
  padding: 0.82rem 1.6rem;
  background: var(--on-accent);
  color: var(--accent);
}
.finale__form .skip {
  grid-column: 1 / -1;
  margin: 1rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
  font-size: 0.875rem;
  color: color-mix(in srgb, var(--on-accent) 70%, transparent);
}
.finale__form .skip a {
  color: var(--on-accent);
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--on-accent) 45%, transparent);
  padding-bottom: 1px;
}
.finale__form .skip a:hover { border-bottom-color: var(--on-accent); }
.finale__form .skip em {
  display: block;
  margin-top: 0.3rem;
  font-style: normal;
  font-size: 0.8125rem;
  color: color-mix(in srgb, var(--on-accent) 58%, transparent);
}

.finale__form .consent {
  margin-top: 0.8rem;
  font-size: 0.6875rem;
  line-height: 1.45;
  color: color-mix(in srgb, var(--on-accent) 62%, transparent);
}

@media (max-width: 900px) {
  .lane--finale { grid-template-columns: 1fr; }
  .col { height: 60vh; }
  .finale__form { position: static; transform: none; width: auto; }
}

/* nav — small caps, top right, over everything */
.topnav {
  position: fixed;
  top: 0; right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1.4rem;
  padding: 1.75rem clamp(1.5rem, 3vw, 3rem);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.topnav a { color: var(--ink); text-decoration: none; opacity: 0.55; transition: opacity 0.2s; }
.topnav a:hover { opacity: 1; }
.topnav a:last-child { opacity: 1; }
.topnav__rule { width: 22px; height: 1px; background: var(--ink); opacity: 0.35; }

.lane .credit { left: 1.1rem; bottom: 1rem; }

/* Below tablet the horizontal conceit stops working — fall back to a
   plain vertical stack rather than a broken sideways one. */
@media (max-width: 900px) {
  .viewport { position: static; overflow: visible; height: auto; }
  .track { display: block; width: auto; height: auto; transform: none !important; }
  .runway { display: none; }
  .lane { width: auto !important; height: auto; transform: none !important; padding-inline: var(--gut); }
  /* These were written against class names the markup no longer uses
     (--color, --loose, --ask), so the cover never got its top padding
     and the plate ran straight into the nav. */
  .lane--cover { min-height: 40vh; padding-top: 6.5rem; }
  .lane--photo { padding: 0; }
  .lane--photo img { height: 62vh; }
  .lane--panel { padding-block: clamp(3rem, 8vh, 5rem); }
}

/* ── the reel ─────────────────────────────────────────────────
   Photo-led. The stage is pinned full-bleed and the photograph
   changes beneath the text as you scroll. Words are a few at a
   time, over the image — not a document with pictures in it.    */
.fixed-head {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 8;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 1.6rem var(--gut);
  color: #fff;
  text-shadow: 0 1px 20px rgba(0,0,0,0.45);
}
.fixed-head .micro { color: rgba(255,255,255,0.85); }

.reel { position: relative; }

.reel__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: var(--ink);
}
.frame {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 900ms ease, transform 2400ms ease;
}
.frame.is-on { opacity: 1; transform: scale(1); }

/* Just enough veil to hold white type over a bright sky. */
.scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(9,14,6,0.30) 0%, rgba(9,14,6,0.08) 38%, rgba(9,14,6,0.46) 100%);
}
.reel__credit { left: var(--gut); bottom: 1.4rem; }

/* Each panel is a full screen of scroll that holds one frame. */
.panel {
  position: relative;
  z-index: 2;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 0 var(--gut) clamp(4rem, 12vh, 9rem);
  color: #fff;
}
/* Only the FIRST panel is pulled up over the pinned stage — the rest
   flow normally beneath it. Applying this to every panel stacks them
   all on top of one another. */
.panel:first-of-type { margin-top: -100svh; }
.panel .micro { color: rgba(255,255,255,0.82); }
.panel h1, .panel h2 {
  color: #fff;
  margin-top: 0.6rem;
  text-shadow: 0 2px 40px rgba(0,0,0,0.35);
}
.panel h1 { font-size: clamp(2.4rem, 6.5vw, 6rem); line-height: 0.98; }
.panel h2 { font-size: clamp(2rem, 5vw, 4.25rem); line-height: 1.02; }

/* The display numeral — the Mersi 60m² moment. */
.big {
  margin: 0;
  font-size: clamp(5rem, 17vw, 15rem);
  font-weight: 300;
  line-height: 0.8;
  letter-spacing: -0.05em;
  color: #fff;
  text-shadow: 0 2px 50px rgba(0,0,0,0.35);
}
.big em {
  font-style: normal;
  font-size: 0.22em;
  font-weight: 500;
  letter-spacing: 0;
  margin-left: 0.08em;
  vertical-align: super;
}

/* ── the ask ──────────────────────────────────────────────────
   The only text-led screen on the page, and the only one that
   asks for anything.                                            */
.ask {
  position: relative;
  z-index: 3;
  background: var(--ground);
  padding: clamp(5rem, 11vw, 10rem) var(--gut);
}
.ask__inner { max-width: 46rem; }
.ask h2 { margin: 0.85rem 0 0; font-size: clamp(2rem, 4.5vw, 3.5rem); }
.ask .optin { margin-top: 3rem; }

/* ── brought-in vendors ───────────────────────────────────────
   Offset blocks on the bone ground, deliberately asymmetric and
   hanging off the grid — the second movement in the Mersi page,
   after the split hero breaks apart.                             */
.brought { padding: clamp(4rem, 9vw, 8rem) 0 clamp(5rem, 10vw, 9rem); }
.brought__intro {
  max-width: var(--measure);
  padding: 0 var(--gut);
  margin-bottom: clamp(3rem, 6vw, 5rem);
}
.brought__intro h2 { margin-top: 0.85rem; }
.brought__intro .lede { margin-top: 1.1rem; }

.blocks { display: grid; gap: clamp(3rem, 7vw, 7rem); }
.block { margin: 0; }
.block img { width: 100%; height: 100%; object-fit: cover; }
.block figcaption { margin-top: 0.9rem; padding: 0 var(--gut); }

/* Each block sits differently. Nothing is centred, nothing is boxed,
   and two of the three bleed off an edge. */
.block--a { width: min(62%, 780px); margin-left: 0; }
.block--a img { aspect-ratio: 4 / 5; }
.block--b { width: min(46%, 560px); margin-left: auto; margin-right: var(--gut); }
.block--b img { aspect-ratio: 3 / 4; }
.block--c { width: min(78%, 1100px); margin-left: auto; margin-right: 0; }
.block--c img { aspect-ratio: 16 / 10; }

@media (max-width: 900px) {
  .block--a, .block--b, .block--c {
    width: 88%;
    margin-left: 0; margin-right: auto;
  }
  .block--b { margin-left: auto; margin-right: 0; }
}

/* ── thank-you page ───────────────────────────────────────────
   The confirmation and the ask are separated deliberately: the old
   page fused them into one sentence and neither registered.        */
.next {
  margin-top: 2.75rem;
  padding-top: 2.25rem;
  border-top: 1px solid var(--rule);
}
.next h2 { margin: 0.7rem 0 0; font-size: clamp(1.4rem, 2.2vw, 1.9rem); }
.next .lede { margin-top: 0.9rem; }
.next .btn { margin-top: 1.75rem; }

.booking { padding: clamp(4rem, 9vw, 8rem) var(--gut); background: var(--ground-alt); }
.booking__intro { max-width: var(--measure); margin-bottom: 2.75rem; }
.booking__intro h2 { margin-top: 0.85rem; }

/* Reserve the space before the embed arrives. The GHL calendar took
   ~30s to render on the old page and nothing held its place, so the
   visitor stared at a spinner with the layout collapsing around it. */
.cal {
  position: relative;
  min-height: 640px;
  background: var(--ground);
  border: 1px solid var(--rule);
}
.cal iframe {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  border: 0;
}

.fineprint {
  margin-top: 2.5rem;
  max-width: var(--measure);
  border-top: 1px solid var(--rule);
  padding-top: 1.25rem;
}
.fineprint summary { cursor: pointer; }
.fineprint p {
  font-size: 0.9375rem;
  color: color-mix(in srgb, var(--ink) 72%, transparent);
}
.fineprint a { color: inherit; }

/* ── responsive ───────────────────────────────────────────── */
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; min-height: 0; }
  .hero__media { height: 58svh; }
  .stats { grid-template-columns: repeat(2, 1fr); gap: 2.5rem 1.5rem; }
}
@media (max-width: 520px) {
  .stats { grid-template-columns: 1fr; }
  .ruled li { gap: 1rem; }
}

@media (prefers-reduced-motion: no-preference) {
  .hero__media img { transition: opacity 0.4s ease; }
}

/* ══════════════════════════════════════════════════════════════════
   STAGE — the booking and confirmation pages.

   One full-bleed photograph, a card floating over it. The card has a
   dark head carrying the type and a bone well holding the calendar:
   the GHL booking widget is a white cross-origin iframe we cannot
   restyle, so rather than fight it we give it a well that it belongs
   in. Everything above the well is ours.
   ══════════════════════════════════════════════════════════════════ */

.stage {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(5.5rem, 11vh, 9rem) var(--gut) clamp(3.5rem, 7vh, 6rem);
  overflow: clip;
}

/* two layers, crossfading — never a white gap between photographs */
.stage__bg { position: fixed; inset: 0; z-index: -2; background: var(--ink); }
.stage__bg img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 2400ms cubic-bezier(0.4, 0, 0.15, 1);
}
.stage__bg img.is-on { opacity: 1; }

/* darkened toward the centre so the card always has something to sit on,
   whichever photograph is showing */
.stage__scrim {
  position: fixed; inset: 0; z-index: -1;
  /* A flat wash plus a vignette. The library runs from quiet landscape
     to busy dance-floor crowds, and a gradient alone left the bright
     ones fighting the card at the edges. */
  background:
    radial-gradient(120% 90% at 50% 42%, rgba(9,14,6,0.22) 0%, rgba(9,14,6,0.68) 100%),
    linear-gradient(to bottom, rgba(9,14,6,0.58) 0%, rgba(9,14,6,0.34) 38%, rgba(9,14,6,0.72) 100%);
}

.stage .credit {
  position: fixed;
  left: auto;
  right: var(--gut); bottom: 1rem;
  z-index: 1;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(253,254,249,0.62);
}

/* ── the card ─────────────────────────────────────────────────── */
.card {
  position: relative;
  width: min(100%, 62rem);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 2rem 5rem rgba(9,14,6,0.42);
  animation: cardIn 900ms cubic-bezier(0.2, 0, 0.1, 1) both;
}
@keyframes cardIn { from { opacity: 0; transform: translateY(14px); } }
@media (prefers-reduced-motion: reduce) {
  .card { animation: none; }
  .stage__bg img { transition: none; }
}

.card__head {
  background: color-mix(in srgb, var(--accent) 92%, #000);
  color: var(--on-accent);
  padding: clamp(1.75rem, 4vw, 3rem) clamp(1.5rem, 4vw, 3.25rem);
}
.card__head .micro { color: rgba(253,254,249,0.60); }
.card__head h1 {
  margin: 0.5rem 0 0;
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  font-weight: 400;
  line-height: 1.03;
  letter-spacing: -0.022em;
}
.card__head .lede {
  margin: 0.85rem 0 0;
  max-width: 34rem;
  font-size: clamp(0.9375rem, 1.5vw, 1.0625rem);
  line-height: 1.5;
  color: rgba(253,254,249,0.80);
}

/* the three facts that answer "what am I agreeing to" before the calendar */
.card__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(1.25rem, 4vw, 2.75rem);
  margin: 1.5rem 0 0;
  padding: 1.1rem 0 0;
  border-top: 1px solid rgba(253,254,249,0.16);
  list-style: none;
}
.card__facts li {
  font-size: 0.75rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(253,254,249,0.72);
  padding: 0.25rem 0;
}

/* the well the widget lives in */
.card__well { background: #fff; }
.card__well iframe {
  display: block;
  width: 100%;
  min-height: 720px;
  border: 0;
}

/* Holds the space before the widget paints. The old page showed a
   headline and a bare spinner for ~30 seconds with nothing beneath it,
   so the page looked broken rather than busy. */
.card__well { position: relative; }
.card__wait {
  position: absolute; inset: 0;
  display: grid; place-content: center; gap: 0.9rem;
  justify-items: center;
  background: #fff;
  transition: opacity 500ms ease;
}
.card__wait[hidden] { display: none; }
.card__wait.is-gone { opacity: 0; pointer-events: none; }
.card__wait span {
  font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: color-mix(in srgb, var(--ink) 50%, transparent);
}
.card__wait i {
  width: 1.75rem; height: 1.75rem; border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--ink) 14%, transparent);
  border-top-color: var(--accent);
  animation: spin 850ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── under the card ───────────────────────────────────────────── */
.stage__under {
  width: min(100%, 66rem);
  margin: 1.25rem auto 0;
  color: rgba(253,254,249,0.78);
}
.stage__under summary {
  cursor: pointer;
  font-size: 0.75rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: rgba(253,254,249,0.68);
  padding: 0.6rem 0;
}
.stage__under summary:hover { color: var(--on-accent); }
.stage__under p {
  margin: 0.5rem 0 0;
  max-width: 44rem;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: rgba(253,254,249,0.74);
}
.stage__under a { color: var(--on-accent); }

/* the confirmation beat on the thank-you page */
.card__done {
  background: var(--ground);
  color: var(--ink);
  padding: clamp(1.5rem, 3.5vw, 2.5rem) clamp(1.5rem, 4vw, 3.25rem);
  border-bottom: 1px solid var(--rule);
}
.card__done h2 {
  margin: 0.4rem 0 0;
  font-size: clamp(1.35rem, 2.6vw, 1.9rem);
  font-weight: 400;
  letter-spacing: -0.018em;
}
.card__done p {
  margin: 0.6rem 0 0;
  max-width: 40rem;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: color-mix(in srgb, var(--ink) 72%, transparent);
}
.card__done a { color: var(--ink); border-bottom: 1px solid var(--rule); text-decoration: none; }

@media (max-width: 640px) {
  .stage { padding-top: 5rem; }
  .card__well iframe { min-height: 640px; }
  .stage .credit { position: static; display: block; margin: 1rem 0 0; text-align: right; }
}

/* Nav over photography rather than over the bone ground — the ink type
   from the landing page disappears into a dark frame. */
.topnav--over a { color: #fdfef9; opacity: 0.68; text-shadow: 0 1px 12px rgba(9,14,6,0.55); }
.topnav--over a:hover,
.topnav--over a:last-child { opacity: 1; }
.topnav--over .topnav__rule { background: #fdfef9; opacity: 0.45; }

/* ══════════════════════════════════════════════════════════════════
   GLASS + CHAMFER

   45° cut corners rather than rounded ones, and the card becomes a
   translucent shell holding its blocks rather than a solid slab.

   The calendar itself stays opaque: it is a cross-origin iframe with
   a white background we cannot reach into. So instead of pretending,
   the shell is inset around it — you see glass on all four edges and
   between the blocks, and the widget reads as a pane set into it.
   ══════════════════════════════════════════════════════════════════ */

.card {
  /* 66rem, not 62: the glass inset costs 20px of inner width, and the
     booking widget drops to its stacked one-column layout just under
     1000px — which buries the time slots below the calendar and adds
     a scroll before anyone can pick a time. */
  width: min(100%, 66rem);
  --chamfer: 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
  border-radius: 0;
  overflow: visible;
  background: rgba(253, 254, 249, 0.10);
  backdrop-filter: blur(22px) saturate(1.25);
  -webkit-backdrop-filter: blur(22px) saturate(1.25);
  box-shadow: 0 2rem 5rem rgba(9, 14, 6, 0.46);
  clip-path: polygon(
    var(--chamfer) 0, calc(100% - var(--chamfer)) 0,
    100% var(--chamfer), 100% calc(100% - var(--chamfer)),
    calc(100% - var(--chamfer)) 100%, var(--chamfer) 100%,
    0 calc(100% - var(--chamfer)), 0 var(--chamfer)
  );
}

/* The bevel itself: a hairline following the same eight-sided path,
   drawn as a border on a pseudo-element so it survives the clip. */
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border: 1px solid rgba(253, 254, 249, 0.22);
  clip-path: inherit;
}

/* inner blocks get the same cut, one step smaller */
.card__head,
.card__well,
.card__done {
  --chamfer: 12px;
  clip-path: polygon(
    var(--chamfer) 0, calc(100% - var(--chamfer)) 0,
    100% var(--chamfer), 100% calc(100% - var(--chamfer)),
    calc(100% - var(--chamfer)) 100%, var(--chamfer) 100%,
    0 calc(100% - var(--chamfer)), 0 var(--chamfer)
  );
}

/* the head is glass over the photograph, not a solid green panel */
.card__head {
  background: color-mix(in srgb, var(--accent) 68%, transparent);
  backdrop-filter: blur(30px) saturate(1.5);
  -webkit-backdrop-filter: blur(30px) saturate(1.5);
}

.card__done {
  background: rgba(253, 254, 249, 0.90);
  backdrop-filter: blur(30px) saturate(1.3);
  -webkit-backdrop-filter: blur(30px) saturate(1.3);
  border-bottom: 0;
}

/* Safari and Firefox without backdrop-filter would render the head at
   68% over a photograph — unreadable. Give them a solid panel. */
@supports not (backdrop-filter: blur(2px)) {
  .card { background: rgba(9, 14, 6, 0.55); }
  .card__head { background: color-mix(in srgb, var(--accent) 94%, #000); }
  .card__done { background: var(--ground); }
}

@media (max-width: 640px) {
  .card { --chamfer: 14px; padding: 7px; gap: 7px; }
  .card__head, .card__well, .card__done { --chamfer: 9px; }
}

/* honeypot — must be reachable by a bot parsing the DOM, invisible to a person */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.optin__status {
  grid-column: 1 / -1;
  margin: 0.65rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: color-mix(in srgb, var(--on-accent) 70%, transparent);
}
.optin__status.is-bad { color: #ffd9d0; }

/* ── Square, not chamfered ─────────────────────────────────────────
   The rest of the page is hard-edged throughout — full-bleed photo
   lanes, flat colour blocks, the thin ruled plate — and nothing else
   is rounded or cut. A 45° corner read as decoration the design does
   not otherwise use, so the frame goes square and the widget's own
   rounded buttons read as its rounding, not ours. */
.card,
.card::after,
.card__head,
.card__well,
.card__done {
  clip-path: none;
  border-radius: 0;
}

/* ── The opt-in form on a phone ────────────────────────────────────
   Three equal columns is right on the wide card, but it never had a
   narrow override: on a phone the name/email/phone fields were squeezed
   into a row and the source question ran underneath the button. Stack. */
@media (max-width: 900px) {
  .finale__form .optin {
    grid-template-columns: 1fr;
    gap: 0.2rem;
  }
  .finale__form .field--wide { grid-column: 1 / -1; }
  .finale__form .optin button {
    width: 100%;
    margin-top: 0.9rem;
  }
  .finale__form .field { margin-bottom: 1rem; }
}

/* The nav is fixed so it rides along the horizontal parallax on desktop.
   Once that falls back to a vertical stack there is nothing to ride, and
   a fixed bar just sits on top of whatever scrolls under it — on a phone
   it was landing across the form labels. Let it scroll away. */
@media (max-width: 900px) {
  .topnav {
    position: absolute;
    padding-top: 1.25rem;
  }
}

/* ══════════════════════════════════════════════════════════════════
   STAGE, REBUILT — photograph first.

   The previous version put a wide card in the middle of the screen,
   which covered the very thing the page is selling and buried the
   headline inside a green box. Now: the photograph runs edge to edge,
   the headline sits directly on it, and the booking panel is a narrow
   column at the right. The calendar is capped in height and scrolls
   inside its own panel — GHL's stacked layout is far taller than a
   viewport, and letting it set the page height is what made it a slab.
   ══════════════════════════════════════════════════════════════════ */

.stage {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(28rem, 38vw);
  grid-template-areas: "say card";
  align-items: end;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  padding: clamp(6rem, 12vh, 8rem) var(--gut) clamp(2.5rem, 6vh, 4rem);
  overflow: clip;
}

/* ── the words, straight on the photograph ────────────────────── */
.stage__say {
  grid-area: say;
  max-width: 42rem;
  color: #fdfef9;
  text-shadow: 0 1px 30px rgba(9, 14, 6, 0.5);
}
.stage__say .micro { color: rgba(253, 254, 249, 0.72); }
.stage__say h1 {
  margin: 0.7rem 0 0;
  font-size: clamp(2.6rem, 6.6vw, 5.6rem);
  font-weight: 400;
  line-height: 0.97;
  letter-spacing: -0.032em;
  color: #fdfef9;
}
.stage__say .lede {
  margin: 1.1rem 0 0;
  max-width: 32rem;
  font-size: clamp(0.9375rem, 1.4vw, 1.0625rem);
  line-height: 1.5;
  color: rgba(253, 254, 249, 0.84);
}

/* ── the booking panel ────────────────────────────────────────── */
.card {
  grid-area: card;
  align-self: end;
  width: 100%;
  padding: 0;
  gap: 0;
  background: rgba(9, 14, 6, 0.58);
  backdrop-filter: blur(26px) saturate(1.2);
  -webkit-backdrop-filter: blur(26px) saturate(1.2);
  border: 1px solid rgba(253, 254, 249, 0.16);
  box-shadow: 0 1.5rem 4rem rgba(9, 14, 6, 0.5);
}
.card::after { content: none; }

.card__head {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding: 1.1rem 1.25rem;
  border-bottom: 1px solid rgba(253, 254, 249, 0.16);
}
.card__head .micro { color: rgba(253, 254, 249, 0.66); }
.card__meta {
  margin: 0.3rem 0 0;
  font-size: 0.9375rem;
  color: #fdfef9;
}

/* Capped, and it scrolls itself. At this width GHL stacks to one
   column and runs well over 1000px tall; unbounded, it set the height
   of the whole page. */
.card__well {
  max-height: min(58vh, 34rem);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.card__well iframe { min-height: 900px; }

/* ── fine print, under the words ──────────────────────────────── */
.stage__under {
  width: auto;
  margin: 1.6rem 0 0;
}

@media (max-width: 900px) {
  .stage {
    grid-template-columns: 1fr;
    grid-template-areas: "say" "card";
    align-items: start;
    padding-top: clamp(5rem, 16vh, 7rem);
  }
  .stage__say { max-width: none; }
  .card { align-self: start; margin-top: 0.5rem; }
  .card__well { max-height: 60vh; }
}

/* ── the mark, locked up horizontally with the name ────────────── */
.topnav {
  left: 0;
  justify-content: space-between;
  gap: 1rem;
}
.topnav__links { display: flex; align-items: center; gap: 1.4rem; }

.lockup {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  opacity: 1 !important;
}
.lockup img {
  width: 26px;
  height: 26px;
  display: block;
  flex: none;
}
.lockup__name {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
  color: var(--ink);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
}
.lockup__name em {
  font-style: normal;
  font-size: 0.5rem;
  letter-spacing: 0.2em;
  opacity: 0.62;
}

/* over photography the mark is black on transparent, so invert it */
.topnav--over .lockup img { filter: invert(1); }
.topnav--over .lockup__name {
  color: #fdfef9;
  text-shadow: 0 1px 12px rgba(9, 14, 6, 0.55);
}

@media (max-width: 640px) {
  .lockup__name em { display: none; }   /* keep the bar to one line on a phone */
  .topnav__links { gap: 1rem; }
}

/* On a narrow phone the bar still ran past the right edge — the phone number
   measured 493.6px inside a 493px viewport, so the one tap-to-call link on the
   page was clipped in half. Drop the decorative rule and tighten the spacing
   rather than hiding a link: the number is the most valuable thing in the bar. */
@media (max-width: 540px) {
  .topnav { gap: 0.5rem; }
  .topnav__links { gap: 0.7rem; font-size: 12px; }
  .topnav__rule { display: none; }
}

/* Tightening the spacing was not enough. On a 375px phone the bar's contents
   measured 442px — the phone number began at x=348 and ran 67px past the edge,
   so "888.662.7335" rendered as "888.662.7". Shrinking further would only make
   it small and still cramped, so the secondary text links go instead: the mark
   already returns home, and tap-to-call is the one thing in that bar worth a
   thumb. Restored above 540px, where there is room for all of it. */
@media (max-width: 540px) {
  .topnav__links a:not([href^="tel:"]) { display: none; }
}

/* ── the logo wordmark ─────────────────────────────────────────────
   The Meadows lockup is set entirely in Maleah:

     Meadows          Maleah Regular
     At Mossy Creek   Maleah Bold, always smaller than "Meadows"

   Installed from the family pack's own Web Font Kit, which is what
   settles the licence question — the pack ships web formats precisely
   so the face can be embedded. Archivo remains the fallback. */
@font-face {
  font-family: 'Maleah';
  src: url('fonts/maleah.woff2') format('woff2'),
       url('fonts/maleah.woff')  format('woff'),
       url('fonts/maleah.ttf')   format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Maleah';
  src: url('fonts/maleah-bold.woff2') format('woff2'),
       url('fonts/maleah-bold.woff')  format('woff'),
       url('fonts/maleah-bold.ttf')   format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* The wordmark only — never body copy. */
.lockup__name,
.cover__name,
.mark {
  font-family: 'Maleah', 'Archivo', system-ui, sans-serif;
}
.lockup__name {
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
}
/* Bold, and set as a fraction of "Meadows" so it can never out-size it
   however the lockup is scaled. */
.lockup__name em {
  font-family: 'Maleah', 'Archivo', system-ui, sans-serif;
  font-weight: 700;
  font-style: normal;
  font-size: 0.6em;
  letter-spacing: 0.08em;
  text-transform: none;
  opacity: 0.78;
}

/* ── nav on the landing page ───────────────────────────────────────
   The horizontal track runs the nav across dark green, then
   photography, then the bone panel, then green again. Any fixed
   colour is invisible against one of them — white vanished on the
   bone panel. `difference` blends against whatever is actually
   behind it, so the bar stays legible the whole way across without
   needing a scrim over the design. */
.topnav--adaptive {
  mix-blend-mode: difference;
  isolation: auto;
}
.topnav--adaptive a,
.topnav--adaptive .lockup__name {
  color: #fff;
  opacity: 1;
  text-shadow: none;
}
.topnav--adaptive a:hover { opacity: 0.7; }
.topnav--adaptive .topnav__rule { background: #fff; opacity: 1; }
.topnav--adaptive .lockup img { filter: invert(1); }

/* ── the opt-in card, glassy ───────────────────────────────────────
   It sat between two rotating photographs as a solid green slab, so
   the photography stopped dead behind it. Translucent + blurred, the
   frames read through it and the card belongs to the lane instead of
   covering it — the same treatment as the booking panel.

   The accent still tints it, so the colour keeps stepping with the
   slideshow; only the opacity changes. */
.finale__form {
  background: color-mix(in srgb, var(--accent) 62%, transparent);
  backdrop-filter: blur(30px) saturate(1.45);
  -webkit-backdrop-filter: blur(30px) saturate(1.45);
  border: 1px solid rgba(253, 254, 249, 0.16);
  box-shadow: 0 1.5rem 4rem rgba(9, 14, 6, 0.42);
}

/* Type on 62% glass needs a touch more weight than type on a solid
   panel — the photograph behind is doing its best to compete. */
.finale__form .pitch,
.finale__form .consent,
.finale__form .skip { text-shadow: 0 1px 14px rgba(9, 14, 6, 0.45); }
.finale__form .tagline { text-shadow: 0 1px 20px rgba(9, 14, 6, 0.5); }

/* Without backdrop-filter 62% over a photograph is unreadable. */
@supports not (backdrop-filter: blur(2px)) {
  .finale__form { background: var(--accent); }
}

/* The three facts that answer "what am I agreeing to", sitting with the
   headline rather than in the panel — the booking widget already prints
   its own title and duration, and saying it twice made the panel noisy. */
.stage__facts {
  margin: 1.2rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid rgba(253, 254, 249, 0.22);
  max-width: 32rem;
  font-size: 0.75rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(253, 254, 249, 0.78);
}
/* the panel is now only the calendar, so it needs its own top edge */
.card__well { border-top: 0; }

/* ── legibility of the words on the photograph ─────────────────────
   The lede was set at 84% with a soft shadow, which held up over a
   quiet landscape and disappeared over a busy one (a crowd, dappled
   light, a bright truck). Two changes: the copy carries more weight,
   and the scrim gains a gradient down the left so the text column
   always has a darker ground to sit on regardless of the frame. */
.stage__scrim {
  background:
    linear-gradient(to right, rgba(9,14,6,0.72) 0%, rgba(9,14,6,0.34) 42%, rgba(9,14,6,0.10) 68%),
    radial-gradient(120% 90% at 50% 42%, rgba(9,14,6,0.18) 0%, rgba(9,14,6,0.62) 100%),
    linear-gradient(to bottom, rgba(9,14,6,0.52) 0%, rgba(9,14,6,0.28) 38%, rgba(9,14,6,0.70) 100%);
}
.stage__say .lede {
  color: rgba(253, 254, 249, 0.94);
  text-shadow: 0 1px 18px rgba(9, 14, 6, 0.85), 0 0 42px rgba(9, 14, 6, 0.6);
}
.stage__say h1 { text-shadow: 0 2px 34px rgba(9, 14, 6, 0.7); }
.stage__say .micro { color: rgba(253, 254, 249, 0.82); }

/* ── lockup casing ─────────────────────────────────────────────────
   The wordmark is MEADOWS in caps; "At Mossy Creek" is title case.
   Uppercasing is done in CSS rather than the markup so the HTML still
   reads as a name — which also keeps screen readers from spelling it
   out letter by letter. The subline resets the inherited transform. */
.lockup__name,
.cover__name {
  text-transform: uppercase;
  letter-spacing: 0.09em;   /* caps need more air than title case */
}
.lockup__name em {
  text-transform: none;     /* "At Mossy Creek" stays as written */
  letter-spacing: 0.06em;
}

/* "At Mossy Creek" centred beneath MEADOWS rather than flush left, and
   set smaller — it is a locality line under the name, not a second
   half of it. Still sized in em so it scales with the wordmark. */
.lockup__name {
  align-items: center;
  text-align: center;
}
.lockup__name em {
  font-size: 0.44em;
  margin-top: 0.1em;
}

/* The closing instruction, pointing at the panel beside it. */
.stage__cta {
  margin: 0.7rem 0 0;
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  font-weight: 500;
  color: #fdfef9;
  text-shadow: 0 1px 18px rgba(9, 14, 6, 0.9), 0 0 40px rgba(9, 14, 6, 0.7);
}

/* ── the photographs, uncovered ────────────────────────────────────
   The scrim had grown into a full-frame black wash plus a vignette —
   legible, but it dulled every photograph on the page, which is the
   one thing these pages are selling.

   Now the darkening is anchored to the bottom-left corner where the
   words actually sit and falls off to nothing well before the middle,
   plus a thin band under the nav. The photograph itself is untouched
   across most of the frame; the type carries its own shadow instead. */
.stage__scrim {
  background:
    radial-gradient(78% 82% at 0% 100%,
      rgba(9,14,6,0.80) 0%, rgba(9,14,6,0.42) 38%, rgba(9,14,6,0.10) 62%, rgba(9,14,6,0) 76%),
    linear-gradient(to bottom, rgba(9,14,6,0.44) 0%, rgba(9,14,6,0.10) 14%, rgba(9,14,6,0) 26%);
}

/* Less ground beneath the type means the type does more of the work. */
.stage__say h1 { text-shadow: 0 2px 12px rgba(9,14,6,0.85), 0 0 46px rgba(9,14,6,0.75); }
.stage__say .lede { text-shadow: 0 1px 12px rgba(9,14,6,0.95), 0 0 34px rgba(9,14,6,0.8); }
.stage__say .micro,
.stage__facts { text-shadow: 0 1px 12px rgba(9,14,6,0.95); }

/* ── scrim, pulled right back ──────────────────────────────────────
   Down to a soft lift under the words and a thin band under the nav.
   Across the middle and right of the frame the photograph is now
   completely untouched, which is the point of the page. */
.stage__scrim {
  background:
    linear-gradient(to top, rgba(9,14,6,0.58) 0%, rgba(9,14,6,0.22) 26%, rgba(9,14,6,0) 52%),
    linear-gradient(to bottom, rgba(9,14,6,0.30) 0%, rgba(9,14,6,0) 18%);
}

/* ── lockup, measured off the real logo ────────────────────────────
   Proportions taken from the artwork rather than guessed:

     "at mossy creek"  ≈ 0.27 of the wordmark's size
     gap between them  ≈ 0.26 of the wordmark's size
     both lines carry very wide tracking; the subline's is wider still,
     which is what makes it sit as a rule beneath the name rather than
     as a second line of it.

   It is lowercase in the logo, so the uppercase transform is undone
   here. Letter-spacing adds a trailing space after the last letter,
   which throws centred text off by half of it — the negative right
   margin takes that back so both lines are optically centred. */
.lockup__name {
  line-height: 1;
  letter-spacing: 0.34em;
  margin-right: -0.34em;
}
.lockup__name em {
  text-transform: lowercase;
  font-size: 0.27em;
  letter-spacing: 0.5em;
  margin-right: -0.5em;
  margin-top: 0.95em;     /* ≈ 0.26 of the wordmark, in subline units */
  line-height: 1;
  opacity: 0.85;
}

/* The artwork's 0.27 ratio renders the subline at ~4px in the nav, which
   is a smudge. Master logo proportions are drawn for the logo at size and
   normally get opened up for small use — so the lockup grows a little and
   the subline is set at 0.38, the smallest that still reads. Everything
   else about it (lowercase, wide tracking, centred under the name) is the
   logo's. */
.lockup__name { font-size: 1.5rem; }
.lockup__name em {
  font-size: 0.38em;
  letter-spacing: 0.38em;
  margin-right: -0.38em;
  margin-top: 0.68em;
  opacity: 0.9;
}
.lockup img { width: 30px; height: 30px; }

/* The location line sits high on the frame, above where the scrim lifts,
   so on a bright photograph it has to carry itself. */
.stage__say .micro {
  text-shadow: 0 1px 10px rgba(9,14,6,0.95), 0 0 26px rgba(9,14,6,0.85);
}

/* ══════════════════════════════════════════════════════════════════
   THE BOOKING PANEL, PROPERLY

   Three things were wrong.

   1. GHL's widget prints its own header — title, duration, timezone
      and the full description — which ate over half the panel and
      repeated what the page already says. It cannot be reached with
      CSS (cross-origin), so the well crops it off the top instead.
      The well still scrolls, so if GHL ever changes that block
      nothing is lost — it just scrolls back into view.

   2. The panel was too short: the calendar was cut mid-month and the
      time slots were never visible at all, so nobody could see there
      was anything to pick.

   3. The dark glass was pointless. The widget is an opaque white
      iframe sitting on top of it, so all the glass ever did was make
      a white box look like a mistake. The panel is honestly a pale
      card now, and the frame carries the design instead.
   ══════════════════════════════════════════════════════════════════ */

.card {
  background: rgba(253, 254, 249, 0.94);
  backdrop-filter: blur(20px) saturate(1.1);
  -webkit-backdrop-filter: blur(20px) saturate(1.1);
  border: 1px solid rgba(253, 254, 249, 0.55);
  box-shadow: 0 1.5rem 4rem rgba(9, 14, 6, 0.42);
  padding: 0;
}

.card__well {
  /* Fit the widget rather than dictate a height — a fixed one left a
     band of dead white under the calendar. It grows on its own when
     the time slots appear, and only scrolls once it runs out of room. */
  height: auto;
  max-height: min(76vh, 42rem);
  overflow-y: auto;
  background: #fff;
}
.card__well iframe {
  margin-top: -268px;      /* clears the header block and its "Show more" */
  /* form_embed.js sets the real height as the widget grows (time slots
     appear once a date is picked). Forcing a tall min-height just left
     dead white below the calendar — this is only a floor for the case
     where that script does not run. */
  min-height: 520px;
}
.card__wait { z-index: 2; }

@supports not (backdrop-filter: blur(2px)) {
  .card { background: var(--ground); }
}

@media (max-width: 900px) {
  .card__well { max-height: min(70vh, 34rem); }
}

/* ── the stage pages on a phone ────────────────────────────────────
   Two things only show up at this width.

   The scrim is anchored to the bottom-left because that is where the
   words sit on a wide screen. Stacked, the words are at the TOP and
   the panel is below, so the lift has to move with them — otherwise
   the copy sits on bare sky and the panel gets darkened for nothing.

   And the phone number was breaking across three lines in the nav. */
@media (max-width: 900px) {
  .stage__scrim {
    background:
      linear-gradient(to bottom,
        rgba(9,14,6,0.66) 0%, rgba(9,14,6,0.44) 34%,
        rgba(9,14,6,0.16) 58%, rgba(9,14,6,0) 76%);
  }
  .topnav {
    font-size: 0.5625rem;
    gap: 0.75rem;
    padding-inline: 1.1rem;
  }
  .topnav a { white-space: nowrap; }
  .topnav__rule { width: 14px; }
}

/* The mark is the logo — it should anchor the lockup, not tuck under it.
   Sized to sit a little taller than the whole text block (MEADOWS plus
   the subline together), which is how it reads in the artwork. */
.lockup { gap: 0.7rem; }
.lockup img {
  width: 46px;
  height: 46px;
  align-self: center;
}

/* ── the panel's own header ────────────────────────────────────────
   Cropping GHL's header took the duration and timezone with it, and
   the timezone in particular matters — a couple driving up from
   Atlanta needs to know the slots are Eastern. It cannot be cropped
   selectively: the long description sits underneath those rows, so
   keeping them would mean keeping it. The panel states it itself
   instead, in the page's own type, above the calendar. */
.card__head {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding: 0.9rem 1.15rem 0.75rem;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.1rem;
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
}
.card__meta span + span { position: relative; padding-left: 1.1rem; }
.card__meta span + span::before {
  content: '·';
  position: absolute;
  left: 0;
  opacity: 0.55;
}
.card__tz {
  margin: 0.35rem 0 0;
  font-size: 0.75rem;
  color: color-mix(in srgb, var(--ink) 58%, transparent);
}

/* ── the gap under MEADOWS ─────────────────────────────────────────
   The margin was set to the logo's ratio (~0.26 of the wordmark), but
   that ignored leading: with line-height 1 the wordmark's line box is
   taller than its caps, so several pixels of half-leading sat under
   the letters BEFORE the margin even started, and the pair read loose.
   The line box is pulled to the cap height and the margin trimmed to
   what is actually left over. */
.lockup__name { line-height: 0.82; }
.lockup__name em {
  margin-top: 0.34em;
  line-height: 1;
}

/* ══════════════════════════════════════════════════════════════════
   THE CALENDAR, GLASSED AND ON PALETTE

   The widget is a cross-origin iframe: its CSS is unreachable. But
   blend modes and filters apply to the iframe ELEMENT, not its
   document, so both work from out here.

   `multiply` drops the widget's white background out entirely —
   white × backdrop = backdrop — leaving only its dark type and
   coloured chips over whatever the panel is made of. That is what
   makes it glass rather than a white slab pasted over the photo.

   The hue rotation swings GHL's blue (~221°) round to the brand
   green (~95°). Greys and near-black have no hue, so the type is
   untouched; only the accents move.

   The glass underneath has to stay pale. Multiply darkens, so a dark
   panel here would leave black type on a dark photograph.
   ══════════════════════════════════════════════════════════════════ */
.card {
  background: color-mix(in srgb, var(--ground-alt) 82%, transparent);
  backdrop-filter: blur(26px) saturate(1.3);
  -webkit-backdrop-filter: blur(26px) saturate(1.3);
  border: 1px solid rgba(253, 254, 249, 0.42);
}
.card__well { background: transparent; }
.card__well iframe {
  mix-blend-mode: multiply;
  filter: hue-rotate(-126deg) saturate(0.9);
}
.card__wait { background: transparent; }

/* Without blend support the widget would sit as an opaque white block
   on a translucent card — worse than not trying. Give it a solid one. */
@supports not (mix-blend-mode: multiply) {
  .card { background: var(--ground); }
  .card__well { background: #fff; }
  .card__well iframe { filter: none; }
}

/* On a phone the widget's description wraps to more lines, so its header
   is taller and the desktop offset leaves a sliver of the info box above
   the month. Crop a little deeper there. */
@media (max-width: 900px) {
  .card__well iframe { margin-top: -292px; }
}

/* ══════════════════════════════════════════════════════════════════
   THE CALENDAR AS A WIDGET

   Rounded, fully glass, and — the part that actually matters — tall
   enough to reach the time slots.

   Loading the widget standalone showed it pre-selects a date and
   renders its slots immediately. In a narrow panel those stack BELOW
   the month, so the capped height was cutting them off entirely: a
   couple could pick a day and never see a time to pick. The panel is
   taller now and scrolls properly once it runs out of room.

   Rounding is deliberate here even though the rest of the page is
   square — this is a widget sitting on the page, not part of its
   architecture, and reading as a discrete object is the point.
   ══════════════════════════════════════════════════════════════════ */
.card {
  border-radius: 16px;
  overflow: hidden;
  background: color-mix(in srgb, var(--ground-alt) 74%, transparent);
  backdrop-filter: blur(30px) saturate(1.35);
  -webkit-backdrop-filter: blur(30px) saturate(1.35);
  border: 1px solid rgba(253, 254, 249, 0.5);
  box-shadow:
    0 1.5rem 4rem rgba(9, 14, 6, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.card__head {
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.card__well {
  /* Room for the month AND the times beneath it. */
  max-height: min(82vh, 50rem);
  border-radius: 0 0 15px 15px;
}

@media (max-width: 900px) {
  .card { border-radius: 14px; }
  .card__well { max-height: min(74vh, 38rem); border-radius: 0 0 13px 13px; }
}

/* ══════════════════════════════════════════════════════════════════
   VISBY CF — the body face.

   Maleah stays the wordmark only; everything else reads in Visby,
   with Archivo behind it as the fallback.

   NOTE ON THE FILES: these are the Fontspring DEMO cuts — 95 mapped
   codepoints, ASCII only. They are missing the em dash, the middle
   dot, the bullet and the arrow that this page uses as separators, so
   those four characters fall back to Archivo per-glyph. Nothing
   breaks, but the separators are set in a different face until the
   purchased files replace these. A full Visby CF is ~400+ glyphs and
   several times the file size.
   ══════════════════════════════════════════════════════════════════ */
@font-face { font-family:'Visby'; src:url('fonts/visby-300.otf') format('opentype'); font-weight:300; font-style:normal; font-display:swap; }
@font-face { font-family:'Visby'; src:url('fonts/visby-400.otf') format('opentype'); font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:'Visby'; src:url('fonts/visby-500.otf') format('opentype'); font-weight:500; font-style:normal; font-display:swap; }
@font-face { font-family:'Visby'; src:url('fonts/visby-600.otf') format('opentype'); font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:'Visby'; src:url('fonts/visby-700.otf') format('opentype'); font-weight:700; font-style:normal; font-display:swap; }  /* Bold */

body { font-family: 'Visby', 'Archivo', system-ui, sans-serif; }

/* the wordmark is unaffected — Maleah is set on it explicitly */

/* ── glass, all the way across ─────────────────────────────────────
   The panel was bone at 74%, which is opaque enough that only the
   very top and bottom edges read as glass — the middle looked like a
   solid card. Dropped to 52% with a heavier blur so the photograph
   carries through the whole thing, calendar included.

   How far this can go is set by the blend: the widget multiplies, so
   its type darkens against whatever is behind it. Below roughly half
   opacity a dark photograph starts to swallow the date numerals, so
   this is about as thin as it goes while staying readable. */
.card {
  background: color-mix(in srgb, var(--ground-alt) 52%, transparent);
  backdrop-filter: blur(40px) saturate(1.5) brightness(1.06);
  -webkit-backdrop-filter: blur(40px) saturate(1.5) brightness(1.06);
}

/* ── Visby Heavy carries the bold ──────────────────────────────────
   700 maps to Heavy rather than Bold, so anything set bold on these
   pages lands on the heaviest cut. 600 stays DemiBold for the small
   caps, which would go muddy at Heavy. */

/* Heavy needs something to sit on. Nothing was set to 700 — the
   emphatic bits were all 500/600 — so the face never loaded. These are
   the elements that read as bold on these pages. */
.stage__cta,
.card__meta,
.pitch--kicker,
.finale__form button,
.optin button,
strong, b {
  font-weight: 700;
}

/* Back to Bold at 700 — Heavy was too much weight for this type size.
   The extra tracking existed only to stop Heavy closing up at small
   caps sizes, so it comes back down with it. */
.card__meta,
.micro { letter-spacing: 0.09em; }

/* The one constraint someone needs BEFORE they pick a slot, not after.
   It was in GHL's description, which the crop removes, and the version
   in the collapsed fine print is not read in time to matter. */
.card__note {
  margin: 0.5rem 0 0;
  padding-top: 0.5rem;
  border-top: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  font-size: 0.75rem;
  line-height: 1.45;
  color: color-mix(in srgb, var(--ink) 64%, transparent);
}

/* ══════════════════════════════════════════════════════════════════
   FULL GLASS — no cream panel at all

   `multiply` got the widget's white background out, but it forced the
   card underneath to stay pale: multiply darkens, so its black type
   needed a light ground to read against. That pale ground WAS the
   cream panel. There was no way to remove it and keep multiply.

   So the blend flips. `invert(1)` turns the widget's white background
   black and its black type white; `screen` then drops black out
   entirely (screen leaves the backdrop untouched where the source is
   black). Net: the background disappears completely and the type
   comes through light — which reads over dark glass instead of
   needing a pale card.

   The hue rotation is 54deg rather than -126: invert already spins
   the wheel 180, so this lands GHL's blue on the brand green from the
   other direction.
   ══════════════════════════════════════════════════════════════════ */
.card {
  background: rgba(9, 14, 6, 0.42);
  backdrop-filter: blur(34px) saturate(1.3);
  -webkit-backdrop-filter: blur(34px) saturate(1.3);
  border: 1px solid rgba(253, 254, 249, 0.22);
  box-shadow:
    0 1.5rem 4rem rgba(9, 14, 6, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.card__well iframe {
  mix-blend-mode: screen;
  filter: invert(1) hue-rotate(54deg);
}

/* our own header type flips with it */
.card__head { border-bottom-color: rgba(253, 254, 249, 0.2); }
.card__meta { color: #fdfef9; }
.card__tz   { color: rgba(253, 254, 249, 0.74); }
.card__note {
  color: rgba(253, 254, 249, 0.68);
  border-top-color: rgba(253, 254, 249, 0.18);
}

/* Without blend support an inverted widget would render as a negative.
   Fall back to the plain white widget on a solid card. */
@supports not (mix-blend-mode: screen) {
  .card { background: var(--ground); }
  .card__well { background: #fff; }
  .card__well iframe { filter: none; mix-blend-mode: normal; }
  .card__meta { color: var(--accent); }
  .card__tz, .card__note { color: color-mix(in srgb, var(--ink) 62%, transparent); }
}

/* ══════════════════════════════════════════════════════════════════
   BACK TO MULTIPLY — but without the cream

   invert + screen was meant to give light type on dark glass. It did
   not work: the blend failed to drop the inverted background out and
   the calendar rendered as a solid black block. Reverted.

   multiply demonstrably works — it removed the white and let the
   photograph through. Its constraint is that the widget's type is
   dark, so it needs a light ground. Previously that ground was a
   cream fill at 52%, which read as a cream card.

   The fill is not the only way to get a light ground. `brightness`
   on the backdrop-filter lightens the PHOTOGRAPH behind the panel
   instead, so the panel itself is nearly clear — you see the actual
   image through it, just lifted enough for dark type to hold. That
   is glass rather than a tinted card.
   ══════════════════════════════════════════════════════════════════ */
.card {
  /* brightness was at 1.55, which lifted the photograph so far it went
     white under the calendar — glass in name only. This is the least
     lift that still holds dark numerals over a dark frame. */
  background: rgba(253, 254, 249, 0.14);
  backdrop-filter: blur(26px) brightness(1.22) saturate(1.2);
  -webkit-backdrop-filter: blur(26px) brightness(1.22) saturate(1.2);
  border: 1px solid rgba(253, 254, 249, 0.45);
  box-shadow:
    0 1.5rem 4rem rgba(9, 14, 6, 0.42),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
.card__well iframe {
  mix-blend-mode: multiply;
  filter: hue-rotate(-126deg) saturate(0.9);
}

/* header type back to ink, on the lifted ground */
.card__head { border-bottom-color: color-mix(in srgb, var(--ink) 14%, transparent); }
.card__meta { color: var(--accent); }
.card__tz   { color: color-mix(in srgb, var(--ink) 62%, transparent); }
.card__note {
  color: color-mix(in srgb, var(--ink) 66%, transparent);
  border-top-color: color-mix(in srgb, var(--ink) 12%, transparent);
}

/* No backdrop-filter means no lifted ground, so dark type would sit on
   the raw photograph. Give those browsers a solid panel. */
@supports not (backdrop-filter: blur(2px)) {
  .card { background: var(--ground); }
}

/* ── the calendar actually blending with the photograph ────────────
   The well paints the current frame itself, pinned to the viewport so
   it lines up with the full-bleed image behind the page. A white wash
   sits over it in the same background stack, lifting it just enough
   for the widget's dark type to hold once it multiplies down onto it.

   This is what makes the calendar glass rather than a pale card: what
   shows through the numerals is the actual photograph. */
.card__well {
  position: relative;
  background-color: transparent;
  background-image: none;
}
/* The frame goes on a pseudo-element so it can be BLURRED. As a plain
   background it came through pin-sharp and fought the numerals — a
   window, not frosted glass. The iframe still multiplies down onto it:
   same stacking context, painted underneath. */
.card::before {
  content: '';
  position: absolute;
  inset: -26px;                    /* bleed, so the blur has no soft edge */
  z-index: 0;
  background-image:
    linear-gradient(rgba(253, 254, 249, 0.76), rgba(253, 254, 249, 0.76)),
    var(--frame, none);
  background-size: auto, cover;
  background-position: center, center;
  background-attachment: scroll, fixed;
  background-repeat: no-repeat, no-repeat;
  /* Heavy enough that only colour and broad shape come through, never
     a recognisable subject competing with the numerals. It also hides
     the seam: the page image crossfades over 2.4s while this switches
     instantly, and at this blur the disagreement is invisible. */
  filter: blur(22px) saturate(1.15);
  pointer-events: none;
}
.card__well iframe { position: relative; z-index: 1; }
.card__head { position: relative; z-index: 1; }

/* The card no longer needs to carry the light ground itself. */
.card {
  background: rgba(253, 254, 249, 0.10);
  backdrop-filter: blur(26px) brightness(1.14) saturate(1.2);
  -webkit-backdrop-filter: blur(26px) brightness(1.14) saturate(1.2);
}

@supports not (backdrop-filter: blur(2px)) {
  .card { background: var(--ground); }
  .card::before { display: none; }
  .card__well { background-color: #fff; }
}

/* The frosted ground now runs the full height of the panel, so the
   header shares it with the calendar instead of sitting on whatever
   the photograph happens to be doing behind that corner — which is
   what left the small caps as dark green on a dark frame. */
.card { position: relative; }
.card__head {
  border-bottom-color: color-mix(in srgb, var(--ink) 16%, transparent);
}
.card__meta { color: color-mix(in srgb, var(--accent) 88%, #000); }
.card__tz   { color: color-mix(in srgb, var(--ink) 72%, transparent); }
.card__note { color: color-mix(in srgb, var(--ink) 74%, transparent); }

/* "Book your tour now." reads as a call to action from its position and
   its size — it does not need weight on top of that. Heavy was wrong
   there and Bold is still heavier than the line wants, so it sits at
   Medium and gains a little size instead. The other 700s (the panel's
   small caps, the buttons) stay Bold. */
.stage__cta {
  font-weight: 500;
  font-size: clamp(1.125rem, 1.8vw, 1.375rem);
  letter-spacing: -0.005em;
}

/* ══════════════════════════════════════════════════════════════════
   VISBY, SCOPED AROUND THE DEMO LOCK

   Measured: 28 ASCII characters in these demo files share one exact
   advance width — 4 ! " # $ % & ' ( ) * + - / < = > @ [ \ ] ^ _ ` { | } ~
   They are all the same substituted marker glyph. That is why "45"
   rendered as "≛5" and the phone number as "≛888≛ 662≛7335".

   unicode-range limits Visby to the characters it actually draws, so
   everything else falls back to Archivo per-glyph. Text reads correctly
   and still sits in Visby for the overwhelming majority of it.

   Replacing these files with the purchased ones and deleting this block
   restores full coverage — nothing else needs to change.
   ══════════════════════════════════════════════════════════════════ */
@font-face { font-family:'Visby'; src:url('fonts/visby-300.otf') format('opentype'); font-weight:300; font-display:swap;
  unicode-range: U+20, U+2C, U+2E, U+30-33, U+35-39, U+3A-3B, U+3F, U+41-5A, U+61-7A; }
@font-face { font-family:'Visby'; src:url('fonts/visby-400.otf') format('opentype'); font-weight:400; font-display:swap;
  unicode-range: U+20, U+2C, U+2E, U+30-33, U+35-39, U+3A-3B, U+3F, U+41-5A, U+61-7A; }
@font-face { font-family:'Visby'; src:url('fonts/visby-500.otf') format('opentype'); font-weight:500; font-display:swap;
  unicode-range: U+20, U+2C, U+2E, U+30-33, U+35-39, U+3A-3B, U+3F, U+41-5A, U+61-7A; }
@font-face { font-family:'Visby'; src:url('fonts/visby-600.otf') format('opentype'); font-weight:600; font-display:swap;
  unicode-range: U+20, U+2C, U+2E, U+30-33, U+35-39, U+3A-3B, U+3F, U+41-5A, U+61-7A; }
@font-face { font-family:'Visby'; src:url('fonts/visby-700.otf') format('opentype'); font-weight:700; font-display:swap;
  unicode-range: U+20, U+2C, U+2E, U+30-33, U+35-39, U+3A-3B, U+3F, U+41-5A, U+61-7A; }
/* Heavy, for the tagline only */
@font-face { font-family:'Visby'; src:url('fonts/visby-800.otf') format('opentype'); font-weight:800; font-display:swap;
  unicode-range: U+20, U+2C, U+2E, U+30-33, U+35-39, U+3A-3B, U+3F, U+41-5A, U+61-7A; }

/* ══════════════════════════════════════════════════════════════════
   COVER — photograph, not a flat green field

   The lane was a green block carrying a framed thumbnail, the place
   and acreage, and the name set huge. All of that is gone. The lane
   is now a photograph with one line on it: the tagline, in Heavy,
   on a green plate so it holds against whatever the image is doing.
   The mark stays where it was, in the nav.
   ══════════════════════════════════════════════════════════════════ */
.lane--cover {
  position: relative;
  background: var(--accent);
  padding: 0;
  overflow: hidden;
}
.cover__media {
  position: absolute;
  inset: 0;
  margin: 0;
}
.cover__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* the one line of type on it */
.cover__tagline {
  position: absolute;
  left: 0;
  bottom: clamp(2.5rem, 8vh, 6rem);
  z-index: 2;
  margin: 0;
  padding: clamp(1.1rem, 2.2vw, 1.9rem) clamp(1.6rem, 3.4vw, 3rem);
  background: var(--accent);
  color: var(--on-accent);
  font-family: 'Visby', 'Archivo', system-ui, sans-serif;
  font-weight: 800;                 /* Heavy */
  font-size: clamp(2rem, 4.6vw, 3.6rem);
  line-height: 1.02;
  letter-spacing: -0.015em;
}

@media (max-width: 900px) {
  .lane--cover { min-height: 68vh; padding-top: 0; }
  .cover__tagline { bottom: 2rem; font-size: clamp(1.75rem, 9vw, 2.75rem); }
}

/* ── cover: green glass over a rotating photograph ─────────────────
   The lane was a flat green field, then a bare photograph. Now it is
   both: the photograph runs full-bleed underneath and a green veil
   sits over it, blurred so it reads as glass rather than a colour
   wash. The tagline is the only type on it and needs no plate of its
   own — the veil is the plate. */
.lane--cover { position: relative; background: var(--ink); overflow: hidden; }

.cover__media { position: absolute; inset: 0; margin: 0; }
.cover__media .cf {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 2400ms cubic-bezier(0.4, 0, 0.15, 1);
}
.cover__media .cf.is-on { opacity: 1; }

.cover__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: color-mix(in srgb, var(--accent) 64%, transparent);
  backdrop-filter: blur(7px) saturate(1.25);
  -webkit-backdrop-filter: blur(7px) saturate(1.25);
  transition: background-color 900ms ease;
}
@supports not (backdrop-filter: blur(2px)) {
  .cover__veil { background: color-mix(in srgb, var(--accent) 82%, transparent); }
}

.cover__tagline {
  position: absolute;
  left: var(--gut);
  right: var(--gut);
  bottom: clamp(2.5rem, 9vh, 6rem);
  z-index: 2;
  margin: 0;
  padding: 0;
  background: none;
  color: var(--on-accent);
  font-family: 'Visby', 'Archivo', system-ui, sans-serif;
  font-weight: 800;
  font-size: clamp(2.25rem, 5.2vw, 4.25rem);
  line-height: 1.0;
  letter-spacing: -0.02em;
  text-shadow: 0 1px 30px rgba(9, 14, 6, 0.35);
}

.lane--cover .credit { z-index: 2; }

@media (max-width: 900px) {
  .lane--cover { min-height: 70vh; }
  .cover__tagline { bottom: 2.25rem; font-size: clamp(2rem, 10vw, 3rem); }
}

/* ── the tagline, centred on the lane ──────────────────────────────
   It was pinned bottom-left, which read as a caption rather than the
   thing the panel exists for. */
.cover__tagline {
  position: absolute;
  inset: 0;
  left: var(--gut);
  right: var(--gut);
  display: grid;
  place-content: center;
  text-align: center;
}

/* ── nav: no more difference blending ──────────────────────────────
   `difference` guaranteed contrast by inverting against whatever was
   behind it — which is exactly why the mark went magenta over the
   green veil. Blend applies to the element as a whole, so the logo
   cannot be opted out of it while the type keeps it.

   So the blending goes, the type is simply light, and a soft scrim at
   the top of the viewport gives it something to sit on across every
   lane — including the bone panel, which is the case the blend was
   there to survive. */
.topnav--adaptive { mix-blend-mode: normal; }
.topnav--adaptive a,
.topnav--adaptive .lockup__name {
  color: #fdfef9;
  opacity: 1;
  text-shadow: 0 1px 16px rgba(9, 14, 6, 0.65);
}
.topnav--adaptive a:hover { opacity: 0.75; }
.topnav--adaptive .topnav__rule { background: #fdfef9; opacity: 0.6; }
.topnav--adaptive .lockup img { filter: invert(1); }

/* the scrim — only the horizontal page has a .viewport */
.viewport::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: clamp(6rem, 14vh, 9rem);
  z-index: 15;
  pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(9, 14, 6, 0.5) 0%, rgba(9, 14, 6, 0.22) 45%, rgba(9, 14, 6, 0) 100%);
}
@media (max-width: 900px) {
  .viewport::before { display: none; }   /* the nav is not fixed down here */
}

/* ══════════════════════════════════════════════════════════════════
   VISBY, HELD BACK TO DISPLAY USE

   The demo files lock & ( ) ! ' + 22 more. The body copy on these
   pages uses all of them — "Pricing & Planning", "(Though we hope you
   do!)", "Don't worry" — so with Visby on body text those characters
   fall back to Archivo mid-word. An apostrophe in a different face
   inside "Don't" reads as a mistake, because it is one.

   So body copy goes back to Archivo, and Visby keeps the display lines
   that contain only letters and full stops, where it has complete
   coverage and looks right.

   WHEN THE PURCHASED FILES ARRIVE: drop them in src/fonts/ over the
   visby-*.otf files, then delete this block and the unicode-range
   block above it. Body copy returns to Visby with one line.
   ══════════════════════════════════════════════════════════════════ */
body { font-family: 'Archivo', system-ui, sans-serif; }

/* full coverage here — letters and full stops only */
.cover__tagline,
.stage__say h1 {
  font-family: 'Visby', 'Archivo', system-ui, sans-serif;
}
.stage__say h1 { font-weight: 400; }

/* ── the tagline, split across the two lanes ───────────────────────
   "Make love." sits on the green veil, "With us." on the photograph
   beside it, so the line completes as the track carries you across.
   Both are vertically centred on the same axis so they read as one
   sentence rather than two captions. */
.cover__tagline,
.photo__tagline {
  position: absolute;
  inset: 0;
  left: var(--gut);
  right: var(--gut);
  z-index: 2;
  display: grid;
  place-content: center;
  margin: 0;
  padding: 0;
  font-family: 'Visby', 'Archivo', system-ui, sans-serif;
  font-weight: 800;
  font-size: clamp(2.25rem, 5.2vw, 4.25rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--on-accent);
}
.cover__tagline { text-align: right; }

/* On the photograph there is no veil, so the type carries its own
   ground. Left-aligned, so the two halves sit close to the seam and
   read as one line rather than one per lane. */
.photo__tagline {
  text-align: left;
  color: #fdfef9;
  text-shadow: 0 1px 26px rgba(9, 14, 6, 0.75), 0 0 60px rgba(9, 14, 6, 0.5);
}

@media (max-width: 900px) {
  .cover__tagline, .photo__tagline {
    font-size: clamp(2rem, 10vw, 3rem);
  }
  /* The bottom-pin that used to live here held "with us." 2rem off the floor,
     which measured 174px below the centre of its lane while "make love." sat
     dead centre. Both are centred now, so it goes. */
}

/* ── the two halves, tight to the seam ─────────────────────────────
   Each half was centred inside a gutter-padded box, which pushed them
   to the outer edges of their lanes and left the sentence split wide
   open. Now they hug the join, so the eye reads "make love. with us."
   as one line with the seam falling where the full stop already is.

   Lowercase is done with text-transform rather than in the markup, so
   the copy itself stays "Make love. With us." — correct for the page
   title, search results and anything that reads the text rather than
   renders it. */
/* Both halves centred in their own lane, horizontally and vertically, so
   "with us." sits exactly as "make love." does. An earlier version pushed them
   toward the seam to read as one continuous line; side by side that worked,
   but each half then sat off-centre in its own panel, which looked like a
   mistake rather than a device. Symmetry wins. */
.cover__tagline,
.photo__tagline {
  left: var(--gut);
  right: var(--gut);
  padding: 0;
  place-content: center;
  text-align: center;
  text-transform: lowercase;
}

@media (max-width: 900px) {
  /* stacked or side by side, each half stays centred in its own lane */
  .cover__tagline,
  .photo__tagline {
    left: var(--gut); right: var(--gut);
    padding: 0; text-align: center; place-content: center;
  }
}

/* ── delivery, not a promise ───────────────────────────────────────
   The page said "your guidebook is on its way" and then depended on a
   GHL workflow firing to make that true — a workflow this page never
   triggers, because it creates the contact by API rather than through
   GHL's form. Two test leads received nothing at all.

   The file is now handed over on the page. The email is still worth
   sending (it is what they keep), but nobody leaves empty-handed while
   that is being wired up. */
.stage__get {
  margin: 1.25rem 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.1rem;
}
.btn-get {
  display: inline-block;
  padding: 0.85rem 1.6rem;
  background: var(--ground);
  color: var(--ink);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 2px;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  box-shadow: 0 0.5rem 1.5rem rgba(9, 14, 6, 0.3);
}
.btn-get:hover { transform: translateY(-1px); box-shadow: 0 0.75rem 2rem rgba(9, 14, 6, 0.38); }
.stage__get span {
  font-size: 0.8125rem;
  color: rgba(253, 254, 249, 0.8);
  text-shadow: 0 1px 12px rgba(9, 14, 6, 0.8);
}


/* ── the tagline, on a phone ────────────────────────────────────────
   "Make love." lives on the cover and "With us." on the photo lane below, so
   on a wide screen the eye reads one phrase across two panels. Stacked on a
   phone those halves ended up 1002px apart — a full screen of scrolling
   between them, which is not a sentence, just two fragments. Narrow screens
   get the whole line in one place and the orphaned half is dropped. */
.tagline__rest { display: none; }
@media (max-width: 720px) {
  .tagline__rest { display: inline; }
  .photo__tagline { display: none; }
}


/* ── keep heads in frame ────────────────────────────────────────────
   Every photo on the site is object-fit: cover with no object-position, so
   the browser crops from the vertical centre — taking equal bites off the top
   and bottom. In a wide, short frame the top is where faces are, which is why
   guests and couples were losing their heads.

   Biasing the focal point to 35% keeps the upper third — where people stand in
   a wedding photograph — and lets the crop eat the grass instead. It is a
   blunt instrument rather than per-image art direction, but it fails in the
   right direction: worst case you see more sky. */
.hero__media img,
.cover__media img,
.cover__media .cf,
.col .cf,
.frame,
.lane--photo img,
.plate__frame img,
.block img,
.stage__bg img { object-position: center 35%; }


/* ── both halves, centred, full stop ────────────────────────────────
   "With us." kept computing to a 48px box pinned 32px off the floor while
   "Make love." sat dead centre, and tracing which rule did it cost more than
   it was worth. This states the intent explicitly at a specificity nothing
   earlier reaches: each half fills its lane and centres inside it, at every
   width. If a future rule needs to move one of them, it should replace this
   block rather than fight it. */
.lane--cover .cover__tagline,
.lane--photo .photo__tagline {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--gut);
  right: var(--gut);
  height: auto;
  padding: 0;
  display: grid;
  place-content: center;
  text-align: center;
}

/* ── phone: one tagline, not two ───────────────────────────────────
   The block above states display:grid for .lane--photo .photo__tagline at a
   specificity that beat the ≤720px rule hiding it, so phones showed
   "make love. with us." on the cover AND "with us." again on the photo. */
@media (max-width: 720px) {
  .lane--photo .photo__tagline { display: none; }
}
